Namespaces
A namespace is a named registrator obtained from the bus rather than constructed by you. postboy.exec(new AddNamespace('space')) creates it and returns the PostboyAbstractRegistrator; you record messages and executors on that registrator, and postboy.exec(new EliminateNamespace('space')) tears everything it recorded down in one step. Because registrations live in a single shared store keyed by message ID, namespaces group lifecycle — they do not give each scope its own copy of a message type.
Creating a namespace
AddNamespace is an infrastructure executor: exec returns the created registrator. Repeating AddNamespace with the same name returns the existing registrator without recreating it.
Calling record* on the returned registrator registers immediately and remembers the ID, exactly as on a registrator you subclass yourself (see Lifecycle Management). The returned registrator has an empty _up(), so the record* calls themselves are the whole wiring; there is nothing to activate with up().
Tearing a namespace down
EliminateNamespace calls down() on the namespace's registrator — attached services first, then a DisconnectMessage for each recorded ID — and removes the namespace from the store. Subscriber streams complete, and further fire/sub for the disconnected IDs throw until they are registered again. Eliminating an unknown name does nothing.
postboy.dispose() eliminates every namespace as part of tearing the whole bus down.
The name is free afterwards: a new AddNamespace('user-filter') creates a fresh, empty registrator with no memory of the previous registrations.
Critical semantics: one shared store
Registrations live in a single store keyed by the message class's static ID — not per namespace. Two consequences follow.
1. The same ID under a second namespace overwrites the earlier registration. The store logs a warning and keeps only the last registration. The replaced subject is dropped without being completed, so its subscribers simply stop receiving messages.
Eliminating scope-a afterwards still disconnects 'filter.applied' — the registrator remembers the ID it recorded, not the registration that currently sits under it.
2. There is no per-namespace routing. fire and sub resolve a message class to the one registration currently stored under its ID. Firing FilterAppliedMessage reaches the subscribers of that single registration regardless of which namespace recorded it. You cannot address "the FilterAppliedMessage of scope-a" as opposed to "the one of scope-b".
The rule: namespaces group lifecycle, not message identity. If two features need independent streams of the same kind of event, define two message classes with distinct IDs.
Scoping strategy
One namespace per scope. Match namespace boundaries to ownership boundaries: a component instance, a service, a feature module.
Use unique names. Namespace names are global. If several instances of the same class need their own namespace, suffix the name with an instance identifier.
Eliminate what you add. Pair every
AddNamespacewith anEliminateNamespacein the owner's destroy hook (ngOnDestroy,componentWillUnmount, adestroy()method). Registrations otherwise live until the bus is disposed.The name is only a label. Read it back from
filter.namespace; routing never consults it.Directly created registrators are not namespaces.
new MyRegistrator(postboy, 'cart')only labels the registrator; the namespace store knows exclusively whatAddNamespacecreated.EliminateNamespace('cart')ignores it — use the registrator's owndown().
Namespace or subclassed registrator?
Namespace | Subclassed registrator | |
|---|---|---|
Creation |
|
|
Wiring |
|
|
Dependent services | no | yes — |
Teardown |
|
|
Use a namespace for small, local scopes wired in place. Use a subclassed registrator when a feature has many bindings, dependent services, or needs a reusable wiring unit.
Pitfalls
Two namespaces, one message ID — the second registration replaces the first; see the shared-store rules above. Use distinct message classes per scope.
One giant namespace — putting everything into a single namespace defeats scoping: you can only eliminate all of it at once.
Forgetting
EliminateNamespace— the registrations and their subscribers live on untildispose().Expecting isolation — namespaces never isolate message delivery; they only bundle teardown.
Next steps
Lifecycle Management — subclassed registrators and dependent services.
Infrastructure Messages —
AddNamespace,EliminateNamespace, and the rest of the bus-mutating executors.Best Practices and Caveats — cross-cutting rules and pitfalls.