Files
pubsub/docs/architecture/api-surface.md
glm-5.1 8c025c3433 Set up project structure, source files, and architecture docs
- Copy core source from alkhub_ts/packages/core/pubsub/ with import path fixups
  (typed_event_target.ts → types.ts, .ts → .js extensions)
- Make PubSubPublishArgsByKey exported (was private type, needed by barrel)
- Add package.json with sub-path exports and optional peer deps (ioredis)
- Add tsup.config.ts with multi-entry + splitting for tree-shaking
- Add tsconfig.json, vitest.config.ts, .gitignore
- Add AGENTS.md with project conventions and adapter checklist
- Add architecture docs following taskgraph/alkhub pattern:
  docs/architecture/README.md, api-surface.md, event-targets.md,
  iroh-transport.md, build-distribution.md
- Add ADRs: 001-graphql-yoga-fork, 002-tree-shake-pattern
- Copy migration research doc to docs/research/migration.md
- Dual-license MIT OR Apache-2.0 (matching taskgraph)
2026-04-30 10:20:41 +00:00

3.6 KiB

status, last_updated
status last_updated
draft 2026-04-30

API Surface

Core pubsub creation, types, and operators. No transport dependencies.

createPubSub

function createPubSub<TPubSubPublishArgsByKey extends PubSubPublishArgsByKey>(
  config?: PubSubConfig<TPubSubPublishArgsByKey>,
): PubSub<TPubSubPublishArgsByKey>;

Factory function. Accepts an optional eventTarget config. If none is provided, uses new EventTarget() (in-process).

Topic Scoping

Topics can be scoped with an id:

  • pubsub.publish("session.status", projectId, payload) → dispatches to topic session.status:{projectId}
  • pubsub.subscribe("session.status", projectId) → subscribes to topic session.status:{projectId} only
  • pubsub.publish("session.status", payload) → dispatches to topic session.status (unscoped)
  • pubsub.subscribe("session.status") → subscribes to topic session.status (unscoped)

The topic string is either the routing key directly (unscoped) or {routingKey}:{id} (scoped). This maps naturally to Redis channel naming and WebSocket message routing.

PubSubPublishArgsByKey

The type parameter that defines the event map:

type PubSubPublishArgsByKey = {
  [key: string]: [] | [unknown] | [number | string, unknown];
};
  • [] — event with no payload (trigger only)
  • [payload] — unscoped event with payload
  • [id, payload] — scoped event with id and payload

PubSub.subscribe()

Returns a Repeater<unknown> (async iterable). Consumers iterate with for await:

for await (const payload of pubsub.subscribe("session.status")) {
  // handle payload
}

The Repeater automatically cleans up its addEventListener when the consumer breaks out of the loop (the stop promise resolves).

Types

Export Source Description
TypedEvent<TType, TDetail> types.ts Event with typed type and detail. Omits CustomEvent's untyped fields.
TypedEventTarget<TEvent> types.ts Extends EventTarget with typed addEventListener, dispatchEvent, removeEventListener.
TypedEventListener<TEvent> types.ts (evt: TEvent) => void
TypedEventListenerObject<TEvent> types.ts { handleEvent(object: TEvent): void }
TypedEventListenerOrEventListenerObject<TEvent> types.ts Union of the above
PubSub<TPubSubPublishArgsByKey> create_pubsub.ts { publish, subscribe }
PubSubConfig<TPubSubPublishArgsByKey> create_pubsub.ts { eventTarget?: PubSubEventTarget }
PubSubEvent<TPubSubPublishArgsByKey, TKey> create_pubsub.ts Derived TypedEvent for a specific event key
PubSubEventTarget<TPubSubPublishArgsByKey> create_pubsub.ts TypedEventTarget<PubSubEvent<...>>

Operators

All operators return Repeater instances and work with any async iterable.

filter

function filter<T>(filterFn: (value: T) => Promise<boolean> | boolean): (source: AsyncIterable<T>) => Repeater<T>;

Type-narrowing overload available: filter<T, U extends T>(fn: (input: T) => input is U).

map

function map<T, O>(mapper: (input: T) => Promise<O> | O): (source: AsyncIterable<T>) => Repeater<O>;

pipe

function pipe<A, B>(a: A, ab: (a: A) => B): B;
function pipe<A, B, C>(a: A, ab: (a: A) => B, bc: (b: B) => C): C;
// up to 5 arguments

Compose operators: pipe(pubsub.subscribe("myEvent"), filter(isRelevant), map(transform))

Attribution

createPubSub and operators are adapted from @graphql-yoga/subscription (MIT). TypedEventTarget types are adapted from @graphql-yoga/typed-event-target (MIT). See file headers for full license text.