@adonis-agora/durable 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/assets/dashboard.html +116 -3
  3. package/dist/commands/durable_worker.d.ts +25 -0
  4. package/dist/commands/durable_worker.d.ts.map +1 -0
  5. package/dist/commands/durable_worker.js +113 -0
  6. package/dist/commands/durable_worker.js.map +1 -0
  7. package/dist/commands/main.d.ts +6 -5
  8. package/dist/commands/main.d.ts.map +1 -1
  9. package/dist/commands/main.js +11 -4
  10. package/dist/commands/main.js.map +1 -1
  11. package/dist/providers/dashboard_provider.d.ts +37 -0
  12. package/dist/providers/dashboard_provider.d.ts.map +1 -1
  13. package/dist/providers/dashboard_provider.js +98 -9
  14. package/dist/providers/dashboard_provider.js.map +1 -1
  15. package/dist/providers/durable_provider.d.ts +24 -16
  16. package/dist/providers/durable_provider.d.ts.map +1 -1
  17. package/dist/providers/durable_provider.js +195 -20
  18. package/dist/providers/durable_provider.js.map +1 -1
  19. package/dist/src/config_types.d.ts +92 -0
  20. package/dist/src/config_types.d.ts.map +1 -0
  21. package/dist/src/config_types.js +2 -0
  22. package/dist/src/config_types.js.map +1 -0
  23. package/dist/src/dashboard/compat-view.d.ts +13 -0
  24. package/dist/src/dashboard/compat-view.d.ts.map +1 -0
  25. package/dist/src/dashboard/compat-view.js +32 -0
  26. package/dist/src/dashboard/compat-view.js.map +1 -0
  27. package/dist/src/dashboard/compat.d.ts +76 -0
  28. package/dist/src/dashboard/compat.d.ts.map +1 -0
  29. package/dist/src/dashboard/compat.js +130 -0
  30. package/dist/src/dashboard/compat.js.map +1 -0
  31. package/dist/src/dashboard/diagnostics-recorder.d.ts +59 -0
  32. package/dist/src/dashboard/diagnostics-recorder.d.ts.map +1 -0
  33. package/dist/src/dashboard/diagnostics-recorder.js +75 -0
  34. package/dist/src/dashboard/diagnostics-recorder.js.map +1 -0
  35. package/dist/src/dashboard/gateway-adapter.d.ts +37 -0
  36. package/dist/src/dashboard/gateway-adapter.d.ts.map +1 -0
  37. package/dist/src/dashboard/gateway-adapter.js +49 -0
  38. package/dist/src/dashboard/gateway-adapter.js.map +1 -0
  39. package/dist/src/dashboard/handlers.d.ts +31 -8
  40. package/dist/src/dashboard/handlers.d.ts.map +1 -1
  41. package/dist/src/dashboard/handlers.js +2 -1
  42. package/dist/src/dashboard/handlers.js.map +1 -1
  43. package/dist/src/dashboard/index.d.ts +10 -3
  44. package/dist/src/dashboard/index.d.ts.map +1 -1
  45. package/dist/src/dashboard/index.js +8 -2
  46. package/dist/src/dashboard/index.js.map +1 -1
  47. package/dist/src/define_config.d.ts +31 -5
  48. package/dist/src/define_config.d.ts.map +1 -1
  49. package/dist/src/define_config.js +4 -3
  50. package/dist/src/define_config.js.map +1 -1
  51. package/dist/src/dispatch-routing.d.ts +105 -0
  52. package/dist/src/dispatch-routing.d.ts.map +1 -0
  53. package/dist/src/dispatch-routing.js +114 -0
  54. package/dist/src/dispatch-routing.js.map +1 -0
  55. package/dist/src/engine.d.ts +65 -2
  56. package/dist/src/engine.d.ts.map +1 -1
  57. package/dist/src/engine.js +131 -3
  58. package/dist/src/engine.js.map +1 -1
  59. package/dist/src/handshake/descriptor.d.ts +128 -0
  60. package/dist/src/handshake/descriptor.d.ts.map +1 -0
  61. package/dist/src/handshake/descriptor.js +133 -0
  62. package/dist/src/handshake/descriptor.js.map +1 -0
  63. package/dist/src/handshake/negotiate.d.ts +83 -0
  64. package/dist/src/handshake/negotiate.d.ts.map +1 -0
  65. package/dist/src/handshake/negotiate.js +108 -0
  66. package/dist/src/handshake/negotiate.js.map +1 -0
  67. package/dist/src/handshake/routing.d.ts +51 -0
  68. package/dist/src/handshake/routing.d.ts.map +1 -0
  69. package/dist/src/handshake/routing.js +57 -0
  70. package/dist/src/handshake/routing.js.map +1 -0
  71. package/dist/src/index.d.ts +14 -2
  72. package/dist/src/index.d.ts.map +1 -1
  73. package/dist/src/index.js +12 -1
  74. package/dist/src/index.js.map +1 -1
  75. package/dist/src/interfaces.d.ts +168 -2
  76. package/dist/src/interfaces.d.ts.map +1 -1
  77. package/dist/src/remote-workflow-executor.d.ts +25 -1
  78. package/dist/src/remote-workflow-executor.d.ts.map +1 -1
  79. package/dist/src/remote-workflow-executor.js +41 -0
  80. package/dist/src/remote-workflow-executor.js.map +1 -1
  81. package/dist/src/role_bindings.d.ts +85 -0
  82. package/dist/src/role_bindings.d.ts.map +1 -0
  83. package/dist/src/role_bindings.js +73 -0
  84. package/dist/src/role_bindings.js.map +1 -0
  85. package/dist/src/run-gateway/interface.d.ts +89 -0
  86. package/dist/src/run-gateway/interface.d.ts.map +1 -0
  87. package/dist/src/run-gateway/interface.js +2 -0
  88. package/dist/src/run-gateway/interface.js.map +1 -0
  89. package/dist/src/run-gateway/proxy-run-gateway.d.ts +84 -0
  90. package/dist/src/run-gateway/proxy-run-gateway.d.ts.map +1 -0
  91. package/dist/src/run-gateway/proxy-run-gateway.js +142 -0
  92. package/dist/src/run-gateway/proxy-run-gateway.js.map +1 -0
  93. package/dist/src/run-gateway/run-request-responder.d.ts +67 -0
  94. package/dist/src/run-gateway/run-request-responder.d.ts.map +1 -0
  95. package/dist/src/run-gateway/run-request-responder.js +228 -0
  96. package/dist/src/run-gateway/run-request-responder.js.map +1 -0
  97. package/dist/src/run-gateway/store-run-gateway.d.ts +90 -0
  98. package/dist/src/run-gateway/store-run-gateway.d.ts.map +1 -0
  99. package/dist/src/run-gateway/store-run-gateway.js +80 -0
  100. package/dist/src/run-gateway/store-run-gateway.js.map +1 -0
  101. package/dist/src/run-gateway/tenant-auth.d.ts +19 -0
  102. package/dist/src/run-gateway/tenant-auth.d.ts.map +1 -0
  103. package/dist/src/run-gateway/tenant-auth.js +71 -0
  104. package/dist/src/run-gateway/tenant-auth.js.map +1 -0
  105. package/dist/src/services/main.d.ts +16 -3
  106. package/dist/src/services/main.d.ts.map +1 -1
  107. package/dist/src/services/main.js +23 -4
  108. package/dist/src/services/main.js.map +1 -1
  109. package/dist/src/step-name-symbol.d.ts +3 -0
  110. package/dist/src/step-name-symbol.d.ts.map +1 -1
  111. package/dist/src/step-name-symbol.js.map +1 -1
  112. package/dist/src/step-ref.d.ts +4 -0
  113. package/dist/src/step-ref.d.ts.map +1 -1
  114. package/dist/src/step-ref.js +2 -0
  115. package/dist/src/step-ref.js.map +1 -1
  116. package/dist/src/transports/bullmq/bullmq-transport.d.ts +130 -0
  117. package/dist/src/transports/bullmq/bullmq-transport.d.ts.map +1 -0
  118. package/dist/src/transports/bullmq/bullmq-transport.js +562 -0
  119. package/dist/src/transports/bullmq/bullmq-transport.js.map +1 -0
  120. package/dist/src/transports/bullmq/deps.d.ts +59 -0
  121. package/dist/src/transports/bullmq/deps.d.ts.map +1 -0
  122. package/dist/src/transports/bullmq/deps.js +41 -0
  123. package/dist/src/transports/bullmq/deps.js.map +1 -0
  124. package/dist/src/transports/bullmq/index.d.ts +5 -0
  125. package/dist/src/transports/bullmq/index.d.ts.map +1 -0
  126. package/dist/src/transports/bullmq/index.js +5 -0
  127. package/dist/src/transports/bullmq/index.js.map +1 -0
  128. package/dist/src/transports/bullmq/naming.d.ts +71 -0
  129. package/dist/src/transports/bullmq/naming.d.ts.map +1 -0
  130. package/dist/src/transports/bullmq/naming.js +101 -0
  131. package/dist/src/transports/bullmq/naming.js.map +1 -0
  132. package/dist/src/transports/bullmq/serialization.d.ts +56 -0
  133. package/dist/src/transports/bullmq/serialization.d.ts.map +1 -0
  134. package/dist/src/transports/bullmq/serialization.js +101 -0
  135. package/dist/src/transports/bullmq/serialization.js.map +1 -0
  136. package/dist/src/transports/factory.d.ts +31 -0
  137. package/dist/src/transports/factory.d.ts.map +1 -1
  138. package/dist/src/transports/factory.js +21 -0
  139. package/dist/src/transports/factory.js.map +1 -1
  140. package/dist/src/worker-runtime/index.d.ts +22 -0
  141. package/dist/src/worker-runtime/index.d.ts.map +1 -0
  142. package/dist/src/worker-runtime/index.js +27 -0
  143. package/dist/src/worker-runtime/index.js.map +1 -0
  144. package/dist/src/worker-runtime/naming.d.ts +24 -0
  145. package/dist/src/worker-runtime/naming.d.ts.map +1 -0
  146. package/dist/src/worker-runtime/naming.js +28 -0
  147. package/dist/src/worker-runtime/naming.js.map +1 -0
  148. package/dist/src/worker-runtime/registry.d.ts +81 -0
  149. package/dist/src/worker-runtime/registry.d.ts.map +1 -0
  150. package/dist/src/worker-runtime/registry.js +44 -0
  151. package/dist/src/worker-runtime/registry.js.map +1 -0
  152. package/dist/src/worker-runtime/worker-runtime.d.ts +155 -0
  153. package/dist/src/worker-runtime/worker-runtime.d.ts.map +1 -0
  154. package/dist/src/worker-runtime/worker-runtime.js +265 -0
  155. package/dist/src/worker-runtime/worker-runtime.js.map +1 -0
  156. package/dist/src/workflow-ctx.d.ts.map +1 -1
  157. package/dist/src/workflow-ctx.js +3 -0
  158. package/dist/src/workflow-ctx.js.map +1 -1
  159. package/dist/src/workflow-turn.d.ts +167 -0
  160. package/dist/src/workflow-turn.d.ts.map +1 -0
  161. package/dist/src/workflow-turn.js +372 -0
  162. package/dist/src/workflow-turn.js.map +1 -0
  163. package/package.json +7 -1
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Container binding tokens for the role-branched, store-less cluster wiring (design §5). Each active
3
+ * role publishes exactly the objects its topology needs under these keys, so app/dashboard/command code
4
+ * resolves the SAME abstract token regardless of whether a store is present:
5
+ *
6
+ * - {@link DURABLE_RUN_GATEWAY} — the active role's {@link import('./run-gateway/interface.js').RunGateway}:
7
+ * a `StoreRunGateway` on `standalone`/`control-plane`, a `ProxyRunGateway` on `tenant`.
8
+ * - {@link DURABLE_WORKER_RUNTIME} — bound ONLY on `tenant`: the store-less
9
+ * {@link import('./worker-runtime/index.js').WorkerRuntime} the `durable:worker` command drives.
10
+ * - {@link DURABLE_RUN_REQUEST_RESPONDER} — bound on store roles whose transport carries the P4 methods:
11
+ * the operator-side {@link import('./run-gateway/run-request-responder.js').RunRequestResponder} tenant
12
+ * pods round-trip to.
13
+ *
14
+ * They are plain string tokens (like `'router'`/`'logger'`) rather than class constructors because the
15
+ * RunGateway is an INTERFACE with two concrete impls chosen by role — there is no single class to key on.
16
+ */
17
+ export const DURABLE_RUN_GATEWAY = '@adonis-agora/durable:run-gateway';
18
+ export const DURABLE_WORKER_RUNTIME = '@adonis-agora/durable:worker-runtime';
19
+ export const DURABLE_RUN_REQUEST_RESPONDER = '@adonis-agora/durable:run-request-responder';
20
+ /**
21
+ * The store role's active task {@link import('./interfaces.js').Transport}, published so store-agnostic
22
+ * consumers (the dashboard's fleet-health panel) can enumerate the LIVE worker fleet off it
23
+ * (`listWorkerGroups`/`listWorkerDescriptors`) without reaching into the engine. Bound ONLY on store roles
24
+ * (`standalone`/`control-plane`); a `tenant` pod never binds it, so its panel degrades to diagnostics-only.
25
+ */
26
+ export const DURABLE_TRANSPORT = '@adonis-agora/durable:transport';
27
+ /**
28
+ * A no-op {@link RunDispatcher}: a freshly-`start`ed run stays `pending` in the store for a worker's
29
+ * `runPending` poll to pick up, instead of running inline on this instance (design §3 pure coordinator).
30
+ * The `control-plane` role uses this so `start()` never executes a body on the coordinator — only the
31
+ * store-backed dispatch/recover/timers loop drives runs forward. `standalone` keeps the engine's default
32
+ * in-process (microtask) dispatcher (today's embedded-worker behavior).
33
+ */
34
+ export const NOOP_RUN_DISPATCHER = { dispatch: () => { } };
35
+ /**
36
+ * Capability-check for {@link DescriptorRedisProvider.createDescriptorRedis} and, when present, mint the
37
+ * descriptor Redis client from the tenant transport. Returns `null` when the transport can't back a real
38
+ * registry — the caller then uses {@link import('./worker-runtime/index.js').NoopWorkerRegistry}.
39
+ */
40
+ export function descriptorRedisFrom(transport) {
41
+ const t = transport;
42
+ if (t && typeof t.createDescriptorRedis === 'function')
43
+ return t.createDescriptorRedis();
44
+ return null;
45
+ }
46
+ /**
47
+ * Capability-check the operator side of the P4 protocol on a transport (design §8). The four methods are
48
+ * OPTIONAL on the full `Transport` (only broker transports carry them), so the provider probes for all
49
+ * four before constructing a {@link import('./run-gateway/run-request-responder.js').RunRequestResponder}
50
+ * over it — the aviary narrowing pattern. Narrows to {@link ResponderTransport} on success.
51
+ */
52
+ export function hasResponderCapability(transport) {
53
+ const t = transport;
54
+ return (!!t &&
55
+ typeof t.onRunRequest === 'function' &&
56
+ typeof t.onStartRun === 'function' &&
57
+ typeof t.publishRunReply === 'function' &&
58
+ typeof t.publishTenantEvent === 'function');
59
+ }
60
+ /**
61
+ * Capability-check the tenant side of the P4 protocol on a transport (design §8). Narrows to
62
+ * {@link ProxyTransport} on success. A `tenant` pod whose transport lacks these can't reach the control
63
+ * plane at all, so the provider throws a loud, actionable error rather than binding a dead gateway.
64
+ */
65
+ export function hasProxyCapability(transport) {
66
+ const t = transport;
67
+ return (!!t &&
68
+ typeof t.dispatchStartRun === 'function' &&
69
+ typeof t.dispatchRunRequest === 'function' &&
70
+ typeof t.onRunReply === 'function' &&
71
+ typeof t.onTenantEvent === 'function');
72
+ }
73
+ //# sourceMappingURL=role_bindings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"role_bindings.js","sourceRoot":"","sources":["../../src/role_bindings.ts"],"names":[],"mappings":"AAwBA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,mCAAmC,CAAC;AACvE,MAAM,CAAC,MAAM,sBAAsB,GAAG,sCAAsC,CAAC;AAC7E,MAAM,CAAC,MAAM,6BAA6B,GAAG,6CAA6C,CAAC;AAC3F;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,iCAAiC,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAkB,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC;AAezE;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,SAAkB;IACpD,MAAM,CAAC,GAAG,SAAuD,CAAC;IAClE,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,qBAAqB,KAAK,UAAU;QAAE,OAAO,CAAC,CAAC,qBAAqB,EAAE,CAAC;IACzF,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,SAAkB;IACvD,MAAM,CAAC,GAAG,SAA2D,CAAC;IACtE,OAAO,CACL,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,CAAC,YAAY,KAAK,UAAU;QACpC,OAAO,CAAC,CAAC,UAAU,KAAK,UAAU;QAClC,OAAO,CAAC,CAAC,eAAe,KAAK,UAAU;QACvC,OAAO,CAAC,CAAC,kBAAkB,KAAK,UAAU,CAC3C,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAkB;IACnD,MAAM,CAAC,GAAG,SAAuD,CAAC;IAClE,OAAO,CACL,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,CAAC,gBAAgB,KAAK,UAAU;QACxC,OAAO,CAAC,CAAC,kBAAkB,KAAK,UAAU;QAC1C,OAAO,CAAC,CAAC,UAAU,KAAK,UAAU;QAClC,OAAO,CAAC,CAAC,aAAa,KAAK,UAAU,CACtC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,89 @@
1
+ import type { StartOptions } from '../engine.js';
2
+ import type { EngineEvent, GroupHealth, RunQuery, RunResult, SearchAttributes, StepCheckpoint, WorkflowRun } from '../interfaces.js';
3
+ import type { WorkflowRef } from '../workflow-ref.js';
4
+ /**
5
+ * Which durable topology a gateway speaks for — surfaced so an operator/consumer can tell a control
6
+ * plane from a tenant (or a single-process standalone) at a glance. Cheap, synchronous, LOCAL
7
+ * knowledge: no round-trip. Byte-compatible with aviary's `DurableTopology`, plus a `standalone` role
8
+ * for the single-process deployment this package targets first (aviary is cluster-only, so it never
9
+ * needed one). The store-backed gateway ({@link RunGateway} via `StoreRunGateway`) is the operator; a
10
+ * later `ProxyRunGateway` is the `tenant`.
11
+ */
12
+ export interface DurableTopology {
13
+ role: 'control-plane' | 'standalone' | 'tenant';
14
+ /** The tenant's isolation partition name; set only when `role` is 'tenant'. */
15
+ tenant?: string | undefined;
16
+ }
17
+ /**
18
+ * Options for {@link RunGateway.start}. Extends the engine's {@link StartOptions} with an OPTIONAL
19
+ * `runId`: the gateway mints one (idempotency key) when the caller doesn't supply it, so a gateway
20
+ * `start` reads `start(workflow, input, opts?)` — one fewer positional than the engine's
21
+ * `start(workflow, input, runId, opts?)` — matching §8's verb shape while staying idempotent-by-id.
22
+ */
23
+ export interface StartRunOptions extends StartOptions {
24
+ /** Explicit run id (idempotency key). Omit to have the gateway mint a fresh one. */
25
+ runId?: string | undefined;
26
+ }
27
+ /**
28
+ * The bounded read / control / stream surface a consumer (a controller, the dashboard, a CLI) needs,
29
+ * intended to be satisfied by BOTH durable topologies: a `standalone` / `control-plane` deployment
30
+ * binds the store-backed `StoreRunGateway` (delegates to the local {@link WorkflowEngine}); a `tenant`
31
+ * deployment will later bind a `ProxyRunGateway` that round-trips these same verbs over the transport
32
+ * to the control plane (Wave 2 — NOT built here). The interface is deliberately transport-agnostic —
33
+ * every verb is `Promise`-returning (or a synchronous unsubscribe for `subscribe`) so a proxy can
34
+ * implement it without changing a single signature.
35
+ *
36
+ * Verb set follows the store-less cluster design §8. Names/shapes are kept byte-compatible with
37
+ * aviary's `RunGateway` where the same verb exists there (`topology`, `listRuns`, `cancel`,
38
+ * `redispatchPending`, `subscribe`); the §8-only verbs (`getRun`, `getCheckpoints`, `signal`,
39
+ * `start`, `getSearchAttributes`) take engine-faithful shapes.
40
+ */
41
+ export interface RunGateway {
42
+ /** This deployment's durable role — synchronous, local metadata (no store/transport hit). */
43
+ topology(): DurableTopology;
44
+ /** Read a run's current persisted state, or null if unknown. */
45
+ getRun(runId: string): Promise<WorkflowRun | null>;
46
+ /** List runs matching `query` (paged via `limit`/`offset`, filtered by workflow/status/tag/search
47
+ * attributes), newest activity first per the store's ordering. */
48
+ listRuns(query: RunQuery): Promise<WorkflowRun[]>;
49
+ /** A run's step checkpoints in execution order — its timeline / history (the detail-view body). */
50
+ getCheckpoints(runId: string): Promise<StepCheckpoint[]>;
51
+ /** The ids of the runs this run spawned (parent→child tree) — the detail view's children list. Empty
52
+ * for a leaf run (or an unknown one). A `ProxyRunGateway` round-trips this over the P4 wire. */
53
+ getRunChildren(runId: string): Promise<string[]>;
54
+ /** Typed, queryable run data (`searchAttributes`) stamped on the run, or undefined if it has none. */
55
+ getSearchAttributes(runId: string): Promise<SearchAttributes | undefined>;
56
+ /** Per-group worker health (queue backlog + live worker heartbeats). On a control plane this is
57
+ * every group; a tenant proxy scopes it to the tenant's own groups. */
58
+ workerHealth(): Promise<GroupHealth[]>;
59
+ /**
60
+ * Start a new run and return its result (carrying the `runId` — minted when `opts.runId` is
61
+ * omitted). Idempotent by run id: a redelivered start for the same id returns the existing run's
62
+ * state instead of creating a duplicate.
63
+ */
64
+ start(workflow: WorkflowRef, input: unknown, opts?: StartRunOptions): Promise<RunResult>;
65
+ /**
66
+ * Deliver an external `signal` (by name/token) with `payload` to the run addressed by `runId`,
67
+ * resuming a run parked on it. Returns the run result, or null if nothing was waiting (the payload
68
+ * is buffered for the next waiter — reliable signals). `runId` addresses the target run for a proxy
69
+ * to route to its owning control plane.
70
+ */
71
+ signal(runId: string, signal: string, payload?: unknown): Promise<RunResult | null>;
72
+ /** Cancel a run. Pass `{ compensate: true }` to run the saga undo first. Returns the run result, or
73
+ * null if the run is unknown. */
74
+ cancel(runId: string, opts?: {
75
+ compensate?: boolean;
76
+ }): Promise<RunResult | null>;
77
+ /**
78
+ * Re-dispatch every remote step of a run stuck `pending` — the operator recovery for a LOST step
79
+ * dispatch (crashed worker / dropped job) that no automatic path re-drives. Returns the run's status
80
+ * plus how many steps were re-dispatched, or null if the run is unknown / the deployment can't
81
+ * re-dispatch. Byte-compatible with aviary's `redispatchPending`.
82
+ */
83
+ redispatchPending(runId: string): Promise<(RunResult & {
84
+ redispatched: number;
85
+ }) | null>;
86
+ /** Live lifecycle events for ONE run; returns an unsubscribe fn. Framework-agnostic (no rxjs). */
87
+ subscribe(runId: string, onEvent: (event: EngineEvent) => void): () => void;
88
+ }
89
+ //# sourceMappingURL=interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../../src/run-gateway/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,QAAQ,EACR,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,GAAG,YAAY,GAAG,QAAQ,CAAC;IAChD,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,oFAAoF;IACpF,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,UAAU;IACzB,6FAA6F;IAC7F,QAAQ,IAAI,eAAe,CAAC;IAE5B,gEAAgE;IAChE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAEnD;uEACmE;IACnE,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAElD,mGAAmG;IACnG,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAEzD;qGACiG;IACjG,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEjD,sGAAsG;IACtG,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAC;IAE1E;4EACwE;IACxE,YAAY,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAEvC;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAEzF;;;;;OAKG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAEpF;sCACkC;IAClC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAElF;;;;;OAKG;IACH,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,SAAS,GAAG;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IAEzF,kGAAkG;IAClG,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAC7E"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../../src/run-gateway/interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,84 @@
1
+ import type { EngineEvent, GroupHealth, RunQuery, RunReply, RunRequest, RunResult, SearchAttributes, StartRunMessage, StepCheckpoint, TenantEvent, WorkflowRun } from '../interfaces.js';
2
+ import type { WorkflowRef } from '../workflow-ref.js';
3
+ import type { DurableTopology, RunGateway, StartRunOptions } from './interface.js';
4
+ /**
5
+ * The narrow slice of {@link import('../interfaces.js').Transport} the {@link ProxyRunGateway} needs —
6
+ * the P4 store-less protocol methods, here declared NON-optional. They are all optional on the full
7
+ * `Transport` (only broker transports carry P4), so the wiring code capability-checks
8
+ * (`transport.dispatchRunRequest ? … : …`) before handing the transport in — the same pattern the
9
+ * operator-side responder uses. Mirrors aviary's `ProxyRunGateway` transport dependency.
10
+ */
11
+ export interface ProxyTransport {
12
+ dispatchStartRun(msg: StartRunMessage): Promise<void>;
13
+ dispatchRunRequest(msg: RunRequest): Promise<void>;
14
+ onRunReply(handler: (reply: RunReply) => void): void;
15
+ onTenantEvent(tenant: string, handler: (evt: TenantEvent) => void): () => void;
16
+ }
17
+ /** Options for {@link ProxyRunGateway}. */
18
+ export interface ProxyRunGatewayOptions {
19
+ /**
20
+ * Which tenant/partition this pod is — the human namespace name (NOT the signed token). Stamped on
21
+ * {@link DurableTopology.tenant}, and it is the channel the proxy live-tails
22
+ * (`${P}-tenant-events-<partition>`), because the control plane re-publishes a run's events keyed by
23
+ * its resolved NAMESPACE (which equals this partition), never by the token.
24
+ */
25
+ partition: string;
26
+ /**
27
+ * The pod's signed claim, presented verbatim in the `tenant` field of every {@link RunRequest} /
28
+ * {@link StartRunMessage}. The responder verifies it and DERIVES the real tenant from it, ignoring
29
+ * the body (spec §9). Omit to run token-less on prefix/network isolation alone (aviary-compatible) —
30
+ * then the raw `partition` travels in the `tenant` field and the responder trusts it directly.
31
+ */
32
+ token?: string | undefined;
33
+ /** Round-trip timeout (ms) for a proxied read/control/start. Default 10_000. Spec §8: on timeout the
34
+ * proxy fails fast with a clear error rather than hanging a request forever. */
35
+ requestTimeoutMs?: number | undefined;
36
+ }
37
+ /**
38
+ * Tenant-side {@link RunGateway} — a store-less pod's read/control/start surface, implemented ENTIRELY
39
+ * over the wire. It owns NO store (structural isolation, spec §5): every verb round-trips to the
40
+ * control plane's `RunRequestResponder` and back.
41
+ *
42
+ * - read/control (`getRun`/`listRuns`/`getCheckpoints`/`getSearchAttributes`/`workerHealth`/`signal`/
43
+ * `cancel`/`redispatchPending`) → publish a {@link RunRequest} correlated by a minted `requestId`,
44
+ * await the {@link RunReply} within `requestTimeoutMs`;
45
+ * - `start` → publish a {@link StartRunMessage} (its own channel, byte-compatible with aviary), then
46
+ * await the reply the responder correlates by the minted `runId`;
47
+ * - `subscribe` → bridge onto the transport's per-tenant event stream (`${P}-tenant-events-<partition>`);
48
+ * - `topology` → `{ role: 'tenant', tenant: partition }` — synchronous local metadata, no round-trip.
49
+ *
50
+ * Fail-fast: a request whose reply never arrives within the timeout (a down/unreachable control plane,
51
+ * a dropped reply) rejects with a clear, verb-named error instead of hanging forever.
52
+ *
53
+ * Idiomatic AdonisJS: a plain class constructed with its transport dependency, wired by the package's
54
+ * provider for the `tenant` role. The counterpart to the operator-side `StoreRunGateway`.
55
+ */
56
+ export declare class ProxyRunGateway implements RunGateway {
57
+ #private;
58
+ constructor(transport: ProxyTransport, options: ProxyRunGatewayOptions);
59
+ topology(): DurableTopology;
60
+ getRun(runId: string): Promise<WorkflowRun | null>;
61
+ listRuns(query: RunQuery): Promise<WorkflowRun[]>;
62
+ getCheckpoints(runId: string): Promise<StepCheckpoint[]>;
63
+ getRunChildren(runId: string): Promise<string[]>;
64
+ getSearchAttributes(runId: string): Promise<SearchAttributes | undefined>;
65
+ /** Round-trips to the operator, which scopes the result to this tenant's own `@<partition>` groups. */
66
+ workerHealth(): Promise<GroupHealth[]>;
67
+ /**
68
+ * Publish a {@link StartRunMessage} (its own `${P}-start-run` channel) and await the reply the
69
+ * responder correlates by the minted `runId`. The proxy ALWAYS mints/forwards a `runId` (idempotency
70
+ * key) so the fire-and-forget aviary `StartRunMessage` can carry a correlated answer back without
71
+ * changing its bytes.
72
+ */
73
+ start(workflow: WorkflowRef, input: unknown, opts?: StartRunOptions): Promise<RunResult>;
74
+ signal(runId: string, signal: string, payload?: unknown): Promise<RunResult | null>;
75
+ cancel(runId: string, opts?: {
76
+ compensate?: boolean;
77
+ }): Promise<RunResult | null>;
78
+ redispatchPending(runId: string): Promise<(RunResult & {
79
+ redispatched: number;
80
+ }) | null>;
81
+ /** Live-tail ONE run by bridging onto this tenant's event channel and filtering by `runId`. */
82
+ subscribe(runId: string, onEvent: (event: EngineEvent) => void): () => void;
83
+ }
84
+ //# sourceMappingURL=proxy-run-gateway.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-run-gateway.d.ts","sourceRoot":"","sources":["../../../src/run-gateway/proxy-run-gateway.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,UAAU,EAEV,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,WAAW,EACX,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEnF;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,gBAAgB,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,kBAAkB,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,UAAU,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI,CAAC;IACrD,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAChF;AAED,2CAA2C;AAC3C,MAAM,WAAW,sBAAsB;IACrC;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B;qFACiF;IACjF,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAeD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,eAAgB,YAAW,UAAU;;gBAOpC,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,sBAAsB;IA0DtE,QAAQ,IAAI,eAAe;IAI3B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAIlD,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAIjD,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAIxD,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAIhD,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC;IAIzE,uGAAuG;IACvG,YAAY,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAItC;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IAexF,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAQnF,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAMjF,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,SAAS,GAAG;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;IAOxF,+FAA+F;IAC/F,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI;CAK5E"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Tenant-side {@link RunGateway} — a store-less pod's read/control/start surface, implemented ENTIRELY
3
+ * over the wire. It owns NO store (structural isolation, spec §5): every verb round-trips to the
4
+ * control plane's `RunRequestResponder` and back.
5
+ *
6
+ * - read/control (`getRun`/`listRuns`/`getCheckpoints`/`getSearchAttributes`/`workerHealth`/`signal`/
7
+ * `cancel`/`redispatchPending`) → publish a {@link RunRequest} correlated by a minted `requestId`,
8
+ * await the {@link RunReply} within `requestTimeoutMs`;
9
+ * - `start` → publish a {@link StartRunMessage} (its own channel, byte-compatible with aviary), then
10
+ * await the reply the responder correlates by the minted `runId`;
11
+ * - `subscribe` → bridge onto the transport's per-tenant event stream (`${P}-tenant-events-<partition>`);
12
+ * - `topology` → `{ role: 'tenant', tenant: partition }` — synchronous local metadata, no round-trip.
13
+ *
14
+ * Fail-fast: a request whose reply never arrives within the timeout (a down/unreachable control plane,
15
+ * a dropped reply) rejects with a clear, verb-named error instead of hanging forever.
16
+ *
17
+ * Idiomatic AdonisJS: a plain class constructed with its transport dependency, wired by the package's
18
+ * provider for the `tenant` role. The counterpart to the operator-side `StoreRunGateway`.
19
+ */
20
+ export class ProxyRunGateway {
21
+ #transport;
22
+ #partition;
23
+ #wireTenant;
24
+ #timeoutMs;
25
+ #pending = new Map();
26
+ constructor(transport, options) {
27
+ this.#transport = transport;
28
+ this.#partition = options.partition;
29
+ // The signed token (verified + tenant-derived by the responder) travels in the `tenant` field; with
30
+ // no token, the raw partition does (prefix-isolation-only, aviary-compatible).
31
+ this.#wireTenant = options.token ?? options.partition;
32
+ this.#timeoutMs = options.requestTimeoutMs ?? 10_000;
33
+ // One reply subscription for the whole gateway; every RunReply is matched to its pending call by id.
34
+ this.#transport.onRunReply((reply) => this.#handleReply(reply));
35
+ }
36
+ #handleReply(reply) {
37
+ const pending = this.#pending.get(reply.requestId);
38
+ if (!pending)
39
+ return; // an unknown/expired id (or another pod's reply on the shared channel) — ignore
40
+ clearTimeout(pending.timer);
41
+ this.#pending.delete(reply.requestId);
42
+ if (reply.result.ok) {
43
+ pending.resolve(reply.result.data);
44
+ }
45
+ else {
46
+ const err = new Error(reply.result.error.message);
47
+ if (reply.result.error.code !== undefined)
48
+ err.code = reply.result.error.code;
49
+ pending.reject(err);
50
+ }
51
+ }
52
+ /** Register a pending reply keyed by `correlationId`, arm the fail-fast timeout, and run `send` (the
53
+ * publish). A publish rejection settles the pending call immediately; a missing reply trips the timer. */
54
+ #awaitReply(correlationId, verbLabel, send) {
55
+ return new Promise((resolve, reject) => {
56
+ const timer = setTimeout(() => {
57
+ this.#pending.delete(correlationId);
58
+ reject(new Error(`durable control plane did not answer ${verbLabel} within ${this.#timeoutMs}ms`));
59
+ }, this.#timeoutMs);
60
+ // Don't keep the event loop alive just waiting on a reply.
61
+ timer.unref?.();
62
+ this.#pending.set(correlationId, { resolve: resolve, reject, timer });
63
+ send().catch((error) => {
64
+ const stillPending = this.#pending.get(correlationId);
65
+ if (!stillPending)
66
+ return; // already settled (timed out / replied) — don't double-reject
67
+ clearTimeout(stillPending.timer);
68
+ this.#pending.delete(correlationId);
69
+ stillPending.reject(error instanceof Error ? error : new Error(String(error)));
70
+ });
71
+ });
72
+ }
73
+ /** Publish a read/control {@link RunRequest} with a freshly minted `requestId` and await its reply. */
74
+ #request(body) {
75
+ const requestId = globalThis.crypto.randomUUID();
76
+ return this.#awaitReply(requestId, body.kind, () => this.#transport.dispatchRunRequest({ requestId, tenant: this.#wireTenant, body }));
77
+ }
78
+ topology() {
79
+ return { role: 'tenant', tenant: this.#partition };
80
+ }
81
+ getRun(runId) {
82
+ return this.#request({ kind: 'getRun', runId });
83
+ }
84
+ listRuns(query) {
85
+ return this.#request({ kind: 'listRuns', query });
86
+ }
87
+ getCheckpoints(runId) {
88
+ return this.#request({ kind: 'getCheckpoints', runId });
89
+ }
90
+ getRunChildren(runId) {
91
+ return this.#request({ kind: 'getRunChildren', runId });
92
+ }
93
+ getSearchAttributes(runId) {
94
+ return this.#request({ kind: 'getSearchAttributes', runId });
95
+ }
96
+ /** Round-trips to the operator, which scopes the result to this tenant's own `@<partition>` groups. */
97
+ workerHealth() {
98
+ return this.#request({ kind: 'workerHealth' });
99
+ }
100
+ /**
101
+ * Publish a {@link StartRunMessage} (its own `${P}-start-run` channel) and await the reply the
102
+ * responder correlates by the minted `runId`. The proxy ALWAYS mints/forwards a `runId` (idempotency
103
+ * key) so the fire-and-forget aviary `StartRunMessage` can carry a correlated answer back without
104
+ * changing its bytes.
105
+ */
106
+ start(workflow, input, opts) {
107
+ const runId = opts?.runId ?? globalThis.crypto.randomUUID();
108
+ const msg = {
109
+ tenant: this.#wireTenant,
110
+ // A `WorkflowRef` is a class or a string; the wire carries the registered NAME. The engine's
111
+ // string overload accepts both at runtime, so resolve to the string form on the wire.
112
+ workflow: workflow,
113
+ input,
114
+ runId,
115
+ ...(opts?.tags !== undefined ? { tags: opts.tags } : {}),
116
+ ...(opts?.searchAttributes !== undefined ? { searchAttributes: opts.searchAttributes } : {}),
117
+ };
118
+ return this.#awaitReply(runId, 'start', () => this.#transport.dispatchStartRun(msg));
119
+ }
120
+ signal(runId, signal, payload) {
121
+ return this.#request(payload === undefined
122
+ ? { kind: 'signal', runId, signal }
123
+ : { kind: 'signal', runId, signal, payload });
124
+ }
125
+ cancel(runId, opts) {
126
+ return this.#request(opts === undefined ? { kind: 'cancel', runId } : { kind: 'cancel', runId, opts });
127
+ }
128
+ redispatchPending(runId) {
129
+ return this.#request({
130
+ kind: 'redispatch',
131
+ runId,
132
+ });
133
+ }
134
+ /** Live-tail ONE run by bridging onto this tenant's event channel and filtering by `runId`. */
135
+ subscribe(runId, onEvent) {
136
+ return this.#transport.onTenantEvent(this.#partition, (evt) => {
137
+ if (evt.event.runId === runId)
138
+ onEvent(evt.event);
139
+ });
140
+ }
141
+ }
142
+ //# sourceMappingURL=proxy-run-gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-run-gateway.js","sourceRoot":"","sources":["../../../src/run-gateway/proxy-run-gateway.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import type { TenantVerifier } from '../config_types.js';
2
+ import type { EngineEvent, RunReply, RunRequest, StartRunMessage, TenantEvent } from '../interfaces.js';
3
+ import type { RunGateway } from './interface.js';
4
+ /**
5
+ * The narrow slice of {@link import('../interfaces.js').Transport} the {@link RunRequestResponder}
6
+ * consumes — the control-plane side of the P4 protocol, declared NON-optional. All four are optional
7
+ * on the full `Transport` (only broker transports carry P4), so the wiring code capability-checks
8
+ * before constructing the responder. Mirrors aviary's `RunRequestTransport` narrowing convention.
9
+ */
10
+ export interface ResponderTransport {
11
+ onRunRequest(handler: (msg: RunRequest) => Promise<void>): void;
12
+ onStartRun(handler: (msg: StartRunMessage) => Promise<void>): void;
13
+ publishRunReply(reply: RunReply): Promise<void>;
14
+ publishTenantEvent(evt: TenantEvent): Promise<void>;
15
+ }
16
+ /** Options for {@link RunRequestResponder}. */
17
+ export interface RunRequestResponderOptions {
18
+ /**
19
+ * Verifies a tenant's signed claim and DERIVES the real tenant from it (spec §9). Absent → the pod
20
+ * runs on prefix/network isolation alone and the wire `tenant` is trusted verbatim (aviary-compatible);
21
+ * present → an invalid/tampered/absent token is REJECTED with an `unauthorized` error reply, and the
22
+ * body's tenant claim is discarded in favour of the verified one.
23
+ */
24
+ verifyTenant?: TenantVerifier | undefined;
25
+ /**
26
+ * The engine's GLOBAL lifecycle-event source (typically `engine.subscribe`). The responder
27
+ * re-publishes each event, scoped by the run's namespace, as a {@link TenantEvent} so a store-less
28
+ * tenant can live-tail its OWN runs. Omit to disable tenant-events republishing (e.g. a control plane
29
+ * that only answers read/control, with live-tail served elsewhere).
30
+ */
31
+ subscribeEngineEvents?: ((listener: (event: EngineEvent) => void) => () => void) | undefined;
32
+ }
33
+ /**
34
+ * Operator-side consumer of a store-less tenant's P4 traffic — the TRUST BOUNDARY of the tenant run
35
+ * gateway (spec §8/§9). It answers each {@link RunRequest}/{@link StartRunMessage} against a
36
+ * store-backed {@link RunGateway} (typically `StoreRunGateway`), and re-publishes the engine's
37
+ * lifecycle events to each tenant's channel.
38
+ *
39
+ * Enforcement, per request, BEFORE any run is touched:
40
+ * 1. **Authenticate + derive tenant.** With a {@link RunRequestResponderOptions.verifyTenant}, the
41
+ * signed token (carried in the wire `tenant` field) is verified and the real tenant is DERIVED from
42
+ * it; the body's claim is ignored. An invalid token short-circuits to an `unauthorized` reply.
43
+ * 2. **`listRuns` is namespace-forced** to the derived tenant — the client's `namespace` is discarded,
44
+ * never merely validated, so a tenant cannot enumerate another's runs.
45
+ * 3. **`workerHealth` is group-scoped** to the tenant's own `@<tenant>` queues.
46
+ * 4. **Every runId-bearing verb** (`getRun`/`getCheckpoints`/`getSearchAttributes`/`signal`/`cancel`/
47
+ * `redispatch`) loads the run FIRST and rejects with `cross-tenant` when `run.namespace` isn't the
48
+ * derived tenant — anti-IDOR, so a tenant can never read OR act on another tenant's run.
49
+ * 5. **`start` forces the run's namespace** to the derived tenant, so a started run is owned by, and
50
+ * later only reachable by, that tenant.
51
+ * 6. **Unknown verbs are rejected** rather than silently ignored.
52
+ *
53
+ * Do not weaken any of these — they are the isolation guarantee of the store-less cluster.
54
+ */
55
+ export declare class RunRequestResponder {
56
+ #private;
57
+ constructor(transport: ResponderTransport, gateway: RunGateway, options?: RunRequestResponderOptions);
58
+ /**
59
+ * Register the consumers on the transport (idempotent per transport). Each request is answered
60
+ * independently; a handler failure never throws back into the transport — every error is captured
61
+ * into an error reply. If an engine-event source was given, starts re-publishing tenant events.
62
+ */
63
+ start(): void;
64
+ /** Stop re-publishing tenant events (the transport consumers are torn down with the transport). */
65
+ stop(): void;
66
+ }
67
+ //# sourceMappingURL=run-request-responder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-request-responder.d.ts","sourceRoot":"","sources":["../../../src/run-gateway/run-request-responder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EAER,UAAU,EAEV,eAAe,EACf,WAAW,EAEZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,YAAY,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAChE,UAAU,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACnE,eAAe,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,kBAAkB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD;AAED,+CAA+C;AAC/C,MAAM,WAAW,0BAA0B;IACzC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IAC1C;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CAC9F;AASD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,mBAAmB;;gBAe5B,SAAS,EAAE,kBAAkB,EAC7B,OAAO,EAAE,UAAU,EACnB,OAAO,GAAE,0BAA+B;IAQ1C;;;;OAIG;IACH,KAAK,IAAI,IAAI;IAgBb,mGAAmG;IACnG,IAAI,IAAI,IAAI;CA4Kb"}