- Create docs/architecture/event-targets/ with individual specs: in-process, redis, websocket-client, websocket-server, worker, iroh-spoke, iroh-hub - Update event-targets.md to serve as index with topology model (symmetric vs fan-out) and adapter status table - Update architecture.md index to reference new directory
status, last_updated
| status | last_updated |
|---|---|
| draft | 2026-05-01 |
@alkdev/pubsub Architecture
Type-safe publish/subscribe with pluggable event target adapters. The core (createPubSub + TypedEventTarget + EventEnvelope + operators) has no transport dependency. Each adapter (Redis, WebSocket, Worker, Iroh) is an isolated module that only imports its own peer dependency.
This package is a transport layer only. It carries events between processes and does not prescribe what those events mean or how downstream systems coordinate. Higher-level protocols (call/response, operation invocation, workflow coordination) belong in downstream packages like @alkdev/operations.
Core Principle
The TypedEventTarget interface is the contract. All transports implement the same addEventListener / dispatchEvent / removeEventListener surface. createPubSub doesn't know or care which transport is in use — it just dispatches events to whatever TypedEventTarget it was given.
The EventEnvelope is the cross-platform format. Every event dispatched through pubsub is { type, id, payload }. This is a minimal, JSON-serializable envelope that any transport adapter can route and any downstream consumer can interpret. Domain-specific data lives in payload. Correlation lives in id. The event type lives in type. No parent field — causal relationships are managed by downstream coordination layers, not the transport.
Swapping transports is a one-line config change:
const pubsub = createPubSub<MyEventMap>({
eventTarget: createRedisEventTarget({ publishClient, subscribeClient }),
});
Why This Exists
Extracted from @alkdev/alkhub_ts/packages/core/pubsub/, which itself was adapted from @graphql-yoga/subscription and @graphql-yoga/typed-event-target. The pubsub module was already self-contained within alkhub — zero cross-module imports from operations, config, logger, or MCP. Extracting it into a standalone package:
- Reduces coupling — alkhub depends on pubsub, not the other way around
- Enables reuse — multiple alkhub packages can share the same pubsub instance
- Isolates peer deps — Redis and Iroh are heavy native dependencies; consumers that don't need them shouldn't carry them
- Matches established pattern —
@alkdev/taskgraphand@alkdev/typemapalready use the standalone-package pattern
What This Package Provides
- Core —
createPubSub,TypedEventTarget,TypedEvent,EventEnvelope, stream operators (filter,map,pipe,take,reduce,toArray,batch,dedupe,window,flat,groupBy,chain,join),Repeater(inlined from @repeaterjs/repeater) - Adapters (each is a peer-dep island, importable via sub-path export):
- In-process (default
EventTarget, no adapter needed) - Redis (
@alkdev/pubsub/event-target-redis, peer dep:ioredis) - WebSocket (future:
@alkdev/pubsub/event-target-websocket) - Worker (future:
@alkdev/pubsub/event-target-worker) - Iroh (future:
@alkdev/pubsub/event-target-iroh, peer dep:@rayhanadev/iroh)
- In-process (default
What This Package Does NOT Provide
- Call protocol — request/response coordination,
PendingRequestMap,CallEventSchema, andCallErrorhave been moved to@alkdev/operations. The pubsub transport is substrate-agnostic. - Workflow coordination — causal chains, parent/child relationships, and abort cascading are domain-level concerns managed by downstream packages.
- Abort/cancellation primitives — these belong in the coordination layer, not the transport. The
EventEnvelopeintentionally omits aparentfield to avoid conflating transport with coordination semantics.
Consumer Context
alkhub (hub-spoke coordinator)
The hub uses pubsub for event routing between operations, runners, and the SSE interface. Transport choice depends on deployment:
| Deployment | Transport |
|---|---|
| Single-process hub | In-process (default) |
| Hub + worker processes | Redis |
| Hub + remote spokes | WebSocket or Iroh |
Downstream packages
@alkdev/operationsusescreatePubSubwith its own event maps for call/response coordination. It defines its own event schemas andPendingRequestMapon top of the pubsub transport.@alkdev/taskgraphwill use pubsub events for task lifecycle notifications and workflow coordination.
Threat Model
- Fork provenance — core pubsub and typed event target are adapted from graphql-yoga (MIT). All original copyright notices are preserved in file headers. See ADR-001.
- Peer dep isolation — Redis and Iroh are optional peer dependencies. A consumer that only needs in-process transport installs zero extra packages. A consumer using Redis but not Iroh installs
ioredisonly. - Type-only imports —
event-target-redis.tsimportsioredistypes only at compile time. At runtime, the consumer must provide the actualRedis/Clusterinstances. - Minimal envelope — the
EventEnvelopeformat ({ type, id, payload }) is intentionally minimal and JSON-serializable. Any platform that supports JSON can produce or consume these events (Rust, Python, etc.).
Architecture Documents
| Document | Content |
|---|---|
| api-surface.md | createPubSub factory, EventEnvelope, PubSub types, operators, TypedEventTarget types |
| event-targets.md | In-process, Redis, WebSocket, Worker adapters — interface, configuration, limitations |
| iroh-transport.md | Iroh P2P QUIC transport — protocol, framing, identity, hub/spoke sides, reconnection |
| build-distribution.md | Dependencies, project structure, tree-shaking, sub-path exports, targets |
Document Lifecycle
Architecture documents use YAML frontmatter with status and last_updated fields:
---
status: draft | stable | deprecated
last_updated: YYYY-MM-DD
---
| Status | Meaning | Transitions |
|---|---|---|
draft |
Under active development. Content may change. | → stable when implementation is complete and tests verify API contract. |
stable |
API contracts are locked. Changes require review cycle. | → deprecated when superseded. |
deprecated |
Superseded. Kept for reference. | Removed when no longer referenced. |
References
- Source:
@alkdev/alkhub_ts/packages/core/pubsub/ - Upstream:
@graphql-yoga/subscriptionand@graphql-yoga/typed-event-target(MIT) - alkhub pubsub-redis doc:
@alkdev/alkhub_ts/docs/architecture/pubsub-redis.md - alkhub spoke-runner doc:
@alkdev/alkhub_ts/docs/architecture/spoke-runner.md - Migration research:
docs/research/migration.md - Research: Event sourcing types —
docs/research/event_sourcing/(not in this repo, in global workspace)