feat: createHierarchicalPubSub<E> — typed + hierarchical bus#93
Merged
Conversation
Fills the last capability gap: createPubSub is flat-typed, the PubSub singleton
is hierarchical-untyped — this is both. Publishing 'a.b.c' also notifies 'a.b'
and 'a' subscribers, with full payload typing.
- `DescendantKey<E, K>` (template-literal type): the keys a subscription to K
receives — K plus dotted descendants ('order' matches 'order.created', not
'orders'); symbol keys match only themselves. Adversarially reviewed with tsc.
- `HierarchicalPubSub<E>` interface + `createHierarchicalPubSub<E>(options?)`
factory (reuses the existing hierarchical runtime). subscribe/on/subscribeOnce
use a defaulted `D` param so the descendant union is computed once.
- Caveats (documented): a handler's `data` is narrowed by a property check, not
by `token` (TS can't correlate the two params); only declared keys publish/sub.
Testing infra: `vitest --typecheck` type-level tests (`test:types` script, CI
step, no new deps) — `hierarchical.test-d.ts` pins DescendantKey edge cases
(prefix exclusion, symbols, leaf) + publish/subscribe/getSnapshot typing. Plus
runtime tests for delivery, retained getSnapshot, and onError.
Additive/non-breaking. 146 runtime tests + 7 type tests, 100% coverage, lint
clean, e2e 12/12, attw + publint clean, size within budget. README documented.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adversarial review fixes: - MAJOR: tsdown entry excluded *.spec.ts but not *.test-d.ts, so the type-test file (and its bundled vitest/expect-type chunks) was shipped to npm. Add '!src/**/*.test-d.ts' to the entry — dist is clean again, tarball back to size. (attw/publint didn't catch it — they only validate declared exports.) - index.spec asserts createHierarchicalPubSub + useBusState in the public API. - e2e (CJS+ESM) import-smoke createHierarchicalPubSub + useBusState. - hierarchical.spec adds subscribeOnce + on()/AbortSignal coverage so the spec is self-contained (not only via the singleton tests). 148 runtime tests + 7 type tests, 100% coverage, lint clean, e2e 12/12, attw + publint clean, no test artifacts in dist. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fills the last capability gap:
createPubSubis flat-typed, thePubSubsingleton is hierarchical-untyped — this is both. Publishingorder.createdalso notifiesorder, with full payload typing. Additive/non-breaking.DescendantKey<E, K>(template-literal type): the keys a subscription toKreceives —K+ dotted descendants (ordermatchesorder.created, notorders); symbols match only themselves. Design adversarially reviewed withtscproofs.HierarchicalPubSub<E>+createHierarchicalPubSub<E>(options?)(reuses the existing hierarchical runtime;subscribe/on/subscribeOnceuse a defaultedDparam so the descendant union is computed once).datais narrowed by a property check, not bytoken(TS can't correlate the two params); only declared keys publish/subscribe.New CI infra:
vitest --typechecktype-level tests (test:typesscript + CI step, no new deps).hierarchical.test-d.tspins DescendantKey edge cases + publish/subscribe/getSnapshot typing; runtime spec covers delivery, retainedgetSnapshot, andonError.146 runtime tests + 7 type tests, 100% coverage, lint clean, e2e 12/12, attw 🌟 + publint clean, bundle within budget. README documented.
🤖 Generated with Claude Code