Postboy Help

PostboyService Reference

Reference page for PostboyService — the central message bus of @artstesh/postboy (applies to v3.5.x). For the conceptual model see Concepts; this page documents the exact API.

All routing is keyed by the static ID declared on message and executor classes — not by class identity. Every bus mutation is performed by executing an infrastructure message (see Infrastructure Messages Reference) through exec.

import { PostboyService } from '@artstesh/postboy'; const postboy = new PostboyService();

Constructor

constructor(resolver?: PostboyDependencyResolver)

Omit the argument in application code — it exists to inject test doubles (the testing toolkit uses it), not to pass configuration. new PostboyService() registers the handlers for all infrastructure messages automatically.

Method overview

Method

Signature

Returns

Purpose

fire

fire(message: PostboyGenericMessage)

void

Publish a message to all current subscribers

fireCallback

fireCallback<T>(message: PostboyCallbackMessage<T>, action?: (e: T) => void)

Observable<T>

Async request/response

sub

sub<T extends PostboyGenericMessage>(type: MessageType<T>)

Observable<T>

Stream of a registered message type

once

once<T extends PostboyGenericMessage>(type: MessageType<T>)

Observable<T>

First message only — sub(type).pipe(first())

exec

exec<T>(executor: PostboyExecutor<T>)

T

Execute a synchronous command

dispose

dispose()

void

Tear down the whole bus

fire

fire(message: PostboyGenericMessage): void

Publishes a message to all current subscribers of its type.

  • Middleware: Publish-stage before hooks → delivery → after hooks (see the Middleware Reference).

  • A locked type (see Infrastructure Messages Reference) is silently skipped — subscribers receive nothing, and both middleware hooks still run.

  • Throws CancelError when a before hook returns an interrupt decision.

  • Throws There is no registered event <ClassName> when the type is not registered.

fireCallback

fireCallback<T>(message: PostboyCallbackMessage<T>, action?: (e: T) => void): Observable<T>

Fires a callback message and returns an observable of its result (async request/response). The responder subscribes to the message type via sub and produces the result with message.next(...)/message.finish(...).

Dispatch semantics by action:

  • with action — the message is dispatched immediately; action is invoked exactly once per emitted result value, regardless of subscriptions to the returned observable.

  • without action — dispatch is lazy: it happens on the first subscription to the returned observable. Pass action (or subscribe immediately) when the request must be sent right away.

In both modes the message is dispatched at most once per fireCallback call: further subscriptions to the returned observable never re-send the request.

Middleware: Callback-stage before hooks run at call time; after hooks run on every emitted result value. The result observable completes when the type is disconnected (DisconnectMessage) or the bus is disposed. Locked types are silently skipped. Throws CancelError on interrupt, and synchronously for unregistered types.

See Callbacks for the full request/response model.

sub

sub<T extends PostboyGenericMessage>(type: MessageType<T>): Observable<T>

Returns the observable stream of a registered message type — a view of the registered subject, or of its pipe when registered with one. It is an Observable, never a Subject: emit via fire. Subscribers only receive messages fired after their subscription, unless the type was registered with a replay or behavior subject. Throws when the class has no static ID or the type is not registered.

once

once<T extends PostboyGenericMessage>(type: MessageType<T>): Observable<T>

Like sub, but completes right after the first message of the type arrives — the equivalent of sub(type).pipe(first()).

exec

exec<T>(executor: PostboyExecutor<T>): T

Synchronously executes a registered executor command and returns its result — never await it. For async results use PostboyCallbackMessage + fireCallback.

This is also the entry point for the infrastructure messages themselves (ConnectMessage, AddMiddleware, …) — they pass through the Execute stage like any command.

Middleware: Execute-stage before hooks → handler → after hooks with the handler's return value. Throws CancelError on interrupt; throws There is no registered executor with id <id> when no handler is registered.

dispose

dispose(): void

Tears down the whole bus: calls down() on every namespace registrator (completing everything they registered), completes all remaining message subscriptions and callback results, disposes every middleware, and releases all locked ids. Infrastructure registrations are re-created only by constructing a new service.

PostboySubscription

import { PostboySubscription } from '@artstesh/postboy'; class PostboySubscription<T> { constructor(subscription: Subject<T>, pipe?: (s: Subject<T>) => Observable<T>); sub(): Observable<T>; // the (piped) view handed out by PostboyService.sub fire(data: T): void; // internal: deliver a message to the subject finish(): void; // internal: complete the subject }

The registration record kept by the message store: a subject plus an optional pipe that shapes the observable subscribers receive. sub() and finish() are bus-internal machinery — applications never construct or drive a PostboySubscription directly.

Deprecated since v3

Still present, scheduled for removal in the next major line — replace with the infrastructure messages:

Deprecated method

Replacement

record(type, sub)/recordWithPipe(type, sub, pipe)

exec(new ConnectMessage(type, sub, pipe?))

recordExecutor(type, fn)

exec(new ConnectExecutor(type, fn))

recordHandler(ctor, handler)

exec(new ConnectHandler(ctor, handler))

The chainable record* methods on PostboyAbstractRegistrator are not deprecated — see the Registrators and Namespaces Reference.

Removed in v3.5: lock, unlock, addMiddleware, removeMiddleware, addNamespace, eliminateNamespace, unregister — see the Infrastructure Messages Reference and Versions.

07 September 2026