Fix critical publish() bug, address review findings

CRITICAL: createPubSub.publish() was dispatching CustomEvent with
just the event type (e.g. 'call.responded') instead of the composite
topic string ('call.responded:uuid-123'). This broke all adapters
that rely on topic-scoped dispatch — Redis subscribe/publish
channels didn't match, and WS server fan-out routing would fail.
Fixed to dispatch with the full type:id composite.

Other fixes:
- Add __ prefix runtime guard in publish() (reserved for control)
- Add Redis barrel re-export to src/index.ts (ADR-002 compliance)
- Clarify WS server: adapter's onclose calls removeConnection
  internally; user doesn't need to
- WS client: document null callback no-op, removeEventListener
  edge cases (unregistered callback, null callback)
- WS server: document dispatchEvent always returns true
- Redis spec: document in-flight message edge case after unsubscribe
- Worker adapter: rename createMainThreadEventTarget to
  createWorkerThreadEventTarget, createWorkerEventTarget to
  createWorkerHostEventTarget (fix inverted naming)
- api-surface.md: add PubSub.publish() section documenting the
  type:id composite and __ guard
This commit is contained in:
2026-05-08 05:17:43 +00:00
parent e60f0a1aa0
commit be7fe67145
7 changed files with 52 additions and 20 deletions

View File

@@ -1,6 +1,6 @@
---
status: draft
last_updated: 2026-05-01
last_updated: 2026-05-08
---
# API Surface
@@ -33,7 +33,7 @@ The envelope is the cross-platform serialization contract. All transport adapter
### Reserved Event Types
Event types starting with `__` (double underscore) are reserved for adapter control messages (e.g., `__subscribe`, `__unsubscribe`). User code must not define event types with this prefix. Control events use the empty string `""` for the `id` field by convention — they use the `topic` field in their `payload` for routing instead. See [ADR-003](decisions/003-subscription-control-protocol.md).
Event types starting with `__` (double underscore) are reserved for adapter control messages (e.g., `__subscribe`, `__unsubscribe`). User code must not define event types with this prefix. Control events use the empty string `""` for the `id` field by convention — they use the `topic` field in their `payload` for routing instead. `createPubSub.publish()` should reject or warn on event types starting with `__`. See [ADR-003](decisions/003-subscription-control-protocol.md).
### Topic Scoping
@@ -59,6 +59,17 @@ type PubSubEventMap = {
};
```
### `PubSub.publish()`
Publishes an event to the pubsub. Throws if the event type starts with `__` (reserved for adapter control messages).
```ts
pubsub.publish("call.responded", requestId, { output });
// → dispatches event with CustomEvent type "call.responded:{requestId}", detail = { type, id, payload }
```
The `CustomEvent.type` is the composite `type:id` string. This is the key that `addEventListener` and `dispatchEvent` use for matching. The `EventEnvelope` in `detail` preserves the separate `type` and `id` fields for transport adapters that need them.
### `PubSub.subscribe()`
Returns a `Repeater<EventEnvelope<TKey, TPayload>>` (async iterable). Consumers iterate with `for await`: