--- status: draft last_updated: 2026-05-01 --- # Build & Distribution Dependencies, project structure, tree-shaking, sub-path exports, and build targets. ## Dependencies No runtime dependencies. The `Repeater` class is inlined from `@repeaterjs/repeater` (MIT) — no external package required. | Package | Type | Purpose | |---------|------|---------| | (none) | runtime | — | | `ioredis` | peer (optional) | Redis client. Only imported by `event-target-redis.ts`. Type-only import at compile time. | | `@rayhanadev/iroh` | peer (optional, future) | Iroh NAPI-RS binding. Only imported by `event-target-iroh.ts`. | No logger dependency. No TypeBox dependency (call protocol and schemas moved to `@alkdev/operations`). ## Project Structure ``` @alkdev/pubsub/ src/ index.ts # Barrel: re-exports core API + operators types.ts # TypedEvent, TypedEventTarget, EventEnvelope create_pubsub.ts # createPubSub factory (adapted from graphql-yoga) operators.ts # filter, map, pipe, take, reduce, toArray, # batch, dedupe, window, flat, groupBy, chain, join repeater.ts # Inlined from @repeaterjs/repeater (MIT) event-target-redis.ts # createRedisEventTarget (peer dep: ioredis) event-target-websocket-client.ts # createWebSocketClientEventTarget event-target-websocket-server.ts # createWebSocketServerEventTarget, WebSocketLike, SpokeEventTarget event-target-worker.ts # createWorkerHostEventTarget, createWorkerThreadEventTarget # Future adapters: # event-target-iroh.ts # (peer dep: @rayhanadev/iroh) test/ create_pubsub.test.ts operators.test.ts event-target-redis.test.ts event-target-websocket-client.test.ts event-target-websocket-server.test.ts event-target-worker.test.ts integration-pubsub-redis.test.ts integration-websocket.test.ts docs/ architecture/ architecture/ research/ package.json tsconfig.json tsup.config.ts vitest.config.ts ``` ## Sub-Path Exports We use explicit sub-path exports rather than barrel-only + tree-shaking. Each adapter is importable by its own path: ```json { "exports": { ".": { ... }, "./event-target-redis": { ... }, "./event-target-websocket-client": { ... }, "./event-target-websocket-server": { ... }, "./event-target-worker": { ... }, "./event-target-iroh": { ... } } } ``` ### Why Sub-Path Exports - **Explicit** — doesn't rely on bundler tree-shaking behavior - **Peer dep isolation** — `import from '@alkdev/pubsub/event-target-redis'` makes the dependency on ioredis explicit at the import site - **Consistent with typemap pattern** — typemap's peer deps (zod, valibot, typebox) are each their own module; sub-path exports make this explicit at the package boundary Sub-path entries are added as adapters are implemented. The barrel `index.ts` also re-exports everything for convenience — consumers who want tree-shaking can import from the barrel and rely on their bundler. ## Peer Dependencies | Peer Dep | Required By | Optional | |----------|-------------|----------| | `ioredis@^5.0.0` | `event-target-redis` | Yes | | `@rayhanadev/iroh` | `event-target-iroh` (future) | Yes | Optional peer deps means `npm install @alkdev/pubsub` does NOT install ioredis or iroh. Consumers opt in by installing the peer dep and importing from the sub-path. ## Build - **Tool**: `tsup` — produces dual ESM + CJS with declarations automatically - **Entry points**: `src/index.ts`, `src/event-target-redis.ts`, plus future adapters - **Format**: ESM + CJS - **Target**: `es2022` - **Splitting**: enabled (tsup code splitting for shared chunks) ## Testing - **Runner**: `vitest` — matches taskgraph, natural fit with tsup/Node build pipeline - **Config**: `vitest.config.ts` with `globals: true` ## Targets - **Publish**: npm (`@alkdev/pubsub`) - **Runtime**: Node 18+, Deno, Bun — pure JS (except iroh adapter which requires NAPI-RS) - **Deno compatibility**: Source is standard TypeScript with no Deno-specific APIs. Deno can import from npm or JSR.