# 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` 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>().toEqualTypeOf>()` is checked - **THEN** the assertion passes **Verified by:** `src/client/client.spec-conformance.test.ts::"proxy type matches WorkerProxyOf"` --- ### 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 calls `emit("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 `SuaveplanError` of code `EVENTS_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 `topic` AND 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"`