3.9 KiB
Capability Spec Delta: api-events-worker-proxy (api-events-worker-proxy)
Package: @suaveplan/api-events-worker-proxy
Status: PROPOSED
Every requirement below carries a
**Verified by:**line at authoring time.
ADDED Requirements
Requirement: Proxy preserves the EventBusLike surface from @suaveplan/events
The package SHALL expose createEventsProxyClient(port) returning a value that satisfies WorkerProxyOf<EventBusLike> where EventBusLike is the EXISTING type from @suaveplan/events. No new contract layer SHALL be introduced — worker-side plugin code that worked against the direct bus MUST also work against the proxy with no source change beyond async-await wrapping (which WorkerProxyOf already enforces by promise-wrapping return types).
Scenario: proxy type matches WorkerProxyOf
- WHEN
expectTypeOf<ReturnType<typeof createEventsProxyClient>>().toEqualTypeOf<WorkerProxyOf<EventBusLike>>()is checked - THEN the assertion passes
Verified by: src/client/client.spec-conformance.test.ts::"proxy type matches WorkerProxyOf<EventBusLike>"
Requirement: Disallowed-topic emit throws reconstructed SuaveplanError
The package SHALL marshal emit(topic, payload) calls to the main-process bus where topic-allow checks are enforced per design doc §5.2b. If the main side rejects with a disallow signal, the proxy MUST surface EVENTS_PROXY_TOPIC_NOT_ALLOWED as a SuaveplanError reconstructed via api-worker-rpc's error-reconstruction.
Scenario: allowed topic emit round-trips
- WHEN a plugin manifests
publishes: ["billing.invoice.created"]AND callsemit("billing.invoice.created", payload) - THEN the main-side bus receives the event AND the call resolves successfully
Scenario: disallowed topic throws TOPIC_NOT_ALLOWED
- WHEN the plugin calls
emit("foreign.topic", payload)with no matching manifest entry - THEN the proxy call rejects with
SuaveplanErrorof codeEVENTS_PROXY_TOPIC_NOT_ALLOWED
Verified by: src/publisher/publisher.test.ts::"allowed topic emit round-trips" AND src/publisher/publisher.test.ts::"disallowed topic throws TOPIC_NOT_ALLOWED"
Requirement: Subscription delivers events from main bus to worker handler with backpressure
The package SHALL marshal on(topic, handler) so that events emitted on the main-process bus are delivered to the worker-side handler. Worker-side handler throws MUST surface main-side as EVENTS_PROXY_HANDLER_THROW. The main-side dispatcher MUST respect api-worker-rpc's backpressure budget — when the worker is slow, main-side delivery throttles rather than buffering unbounded.
Scenario: event delivered to worker handler
- WHEN the main bus emits
topicAND the worker handler is registered - THEN the handler observes the event payload
Scenario: slow handler backpressures producer
- WHEN the worker handler takes 100ms per call AND main emits 100 events in a burst
- THEN the main-side dispatcher pauses at the backpressure budget rather than buffering all 100 in memory
Verified by: src/subscriber/subscriber.test.ts::"event delivered to handler" AND src/subscriber/subscriber.test.ts::"slow handler backpressures producer"
Requirement: Conformance suite passes against this proxy
The package SHALL be runnable as the surface argument to runEventsBusConformance from @suaveplan/events/testing. Every conformance scenario (FIFO ordering, interceptors, idempotent listeners) MUST pass identically to a direct in-process bus. This is the Stage-4-precondition gate.
Scenario: runEventsBusConformance passes
- WHEN
runEventsBusConformance("worker-proxy", makeFactory)runs - THEN every scenario passes
Verified by: tests/conformance/run-events-bus-conformance.test.ts::"runEventsBusConformance passes against proxy"