@adonis-agora/durable 0.9.1 → 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.
- package/CHANGELOG.md +12 -0
- package/dist/assets/dashboard.html +116 -3
- package/dist/commands/durable_worker.d.ts +25 -0
- package/dist/commands/durable_worker.d.ts.map +1 -0
- package/dist/commands/durable_worker.js +113 -0
- package/dist/commands/durable_worker.js.map +1 -0
- package/dist/commands/main.d.ts +6 -5
- package/dist/commands/main.d.ts.map +1 -1
- package/dist/commands/main.js +11 -4
- package/dist/commands/main.js.map +1 -1
- package/dist/providers/dashboard_provider.d.ts +38 -0
- package/dist/providers/dashboard_provider.d.ts.map +1 -1
- package/dist/providers/dashboard_provider.js +103 -10
- package/dist/providers/dashboard_provider.js.map +1 -1
- package/dist/providers/durable_provider.d.ts +24 -16
- package/dist/providers/durable_provider.d.ts.map +1 -1
- package/dist/providers/durable_provider.js +195 -20
- package/dist/providers/durable_provider.js.map +1 -1
- package/dist/src/config_types.d.ts +92 -0
- package/dist/src/config_types.d.ts.map +1 -0
- package/dist/src/config_types.js +2 -0
- package/dist/src/config_types.js.map +1 -0
- package/dist/src/dashboard/compat-view.d.ts +13 -0
- package/dist/src/dashboard/compat-view.d.ts.map +1 -0
- package/dist/src/dashboard/compat-view.js +32 -0
- package/dist/src/dashboard/compat-view.js.map +1 -0
- package/dist/src/dashboard/compat.d.ts +76 -0
- package/dist/src/dashboard/compat.d.ts.map +1 -0
- package/dist/src/dashboard/compat.js +130 -0
- package/dist/src/dashboard/compat.js.map +1 -0
- package/dist/src/dashboard/diagnostics-recorder.d.ts +59 -0
- package/dist/src/dashboard/diagnostics-recorder.d.ts.map +1 -0
- package/dist/src/dashboard/diagnostics-recorder.js +75 -0
- package/dist/src/dashboard/diagnostics-recorder.js.map +1 -0
- package/dist/src/dashboard/gateway-adapter.d.ts +37 -0
- package/dist/src/dashboard/gateway-adapter.d.ts.map +1 -0
- package/dist/src/dashboard/gateway-adapter.js +49 -0
- package/dist/src/dashboard/gateway-adapter.js.map +1 -0
- package/dist/src/dashboard/handlers.d.ts +38 -8
- package/dist/src/dashboard/handlers.d.ts.map +1 -1
- package/dist/src/dashboard/handlers.js +17 -1
- package/dist/src/dashboard/handlers.js.map +1 -1
- package/dist/src/dashboard/index.d.ts +10 -3
- package/dist/src/dashboard/index.d.ts.map +1 -1
- package/dist/src/dashboard/index.js +8 -2
- package/dist/src/dashboard/index.js.map +1 -1
- package/dist/src/define_config.d.ts +31 -5
- package/dist/src/define_config.d.ts.map +1 -1
- package/dist/src/define_config.js +4 -3
- package/dist/src/define_config.js.map +1 -1
- package/dist/src/dispatch-routing.d.ts +105 -0
- package/dist/src/dispatch-routing.d.ts.map +1 -0
- package/dist/src/dispatch-routing.js +114 -0
- package/dist/src/dispatch-routing.js.map +1 -0
- package/dist/src/engine.d.ts +129 -3
- package/dist/src/engine.d.ts.map +1 -1
- package/dist/src/engine.js +354 -12
- package/dist/src/engine.js.map +1 -1
- package/dist/src/handshake/descriptor.d.ts +128 -0
- package/dist/src/handshake/descriptor.d.ts.map +1 -0
- package/dist/src/handshake/descriptor.js +133 -0
- package/dist/src/handshake/descriptor.js.map +1 -0
- package/dist/src/handshake/negotiate.d.ts +83 -0
- package/dist/src/handshake/negotiate.d.ts.map +1 -0
- package/dist/src/handshake/negotiate.js +108 -0
- package/dist/src/handshake/negotiate.js.map +1 -0
- package/dist/src/handshake/routing.d.ts +51 -0
- package/dist/src/handshake/routing.d.ts.map +1 -0
- package/dist/src/handshake/routing.js +57 -0
- package/dist/src/handshake/routing.js.map +1 -0
- package/dist/src/index.d.ts +14 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +12 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/interfaces.d.ts +184 -7
- package/dist/src/interfaces.d.ts.map +1 -1
- package/dist/src/remote-workflow-executor.d.ts +25 -1
- package/dist/src/remote-workflow-executor.d.ts.map +1 -1
- package/dist/src/remote-workflow-executor.js +41 -0
- package/dist/src/remote-workflow-executor.js.map +1 -1
- package/dist/src/role_bindings.d.ts +85 -0
- package/dist/src/role_bindings.d.ts.map +1 -0
- package/dist/src/role_bindings.js +73 -0
- package/dist/src/role_bindings.js.map +1 -0
- package/dist/src/run-gateway/interface.d.ts +89 -0
- package/dist/src/run-gateway/interface.d.ts.map +1 -0
- package/dist/src/run-gateway/interface.js +2 -0
- package/dist/src/run-gateway/interface.js.map +1 -0
- package/dist/src/run-gateway/proxy-run-gateway.d.ts +84 -0
- package/dist/src/run-gateway/proxy-run-gateway.d.ts.map +1 -0
- package/dist/src/run-gateway/proxy-run-gateway.js +142 -0
- package/dist/src/run-gateway/proxy-run-gateway.js.map +1 -0
- package/dist/src/run-gateway/run-request-responder.d.ts +67 -0
- package/dist/src/run-gateway/run-request-responder.d.ts.map +1 -0
- package/dist/src/run-gateway/run-request-responder.js +228 -0
- package/dist/src/run-gateway/run-request-responder.js.map +1 -0
- package/dist/src/run-gateway/store-run-gateway.d.ts +90 -0
- package/dist/src/run-gateway/store-run-gateway.d.ts.map +1 -0
- package/dist/src/run-gateway/store-run-gateway.js +80 -0
- package/dist/src/run-gateway/store-run-gateway.js.map +1 -0
- package/dist/src/run-gateway/tenant-auth.d.ts +19 -0
- package/dist/src/run-gateway/tenant-auth.d.ts.map +1 -0
- package/dist/src/run-gateway/tenant-auth.js +71 -0
- package/dist/src/run-gateway/tenant-auth.js.map +1 -0
- package/dist/src/services/main.d.ts +16 -3
- package/dist/src/services/main.d.ts.map +1 -1
- package/dist/src/services/main.js +23 -4
- package/dist/src/services/main.js.map +1 -1
- package/dist/src/step-name-symbol.d.ts +3 -0
- package/dist/src/step-name-symbol.d.ts.map +1 -1
- package/dist/src/step-name-symbol.js.map +1 -1
- package/dist/src/step-ref.d.ts +4 -0
- package/dist/src/step-ref.d.ts.map +1 -1
- package/dist/src/step-ref.js +2 -0
- package/dist/src/step-ref.js.map +1 -1
- package/dist/src/transports/bullmq/bullmq-transport.d.ts +130 -0
- package/dist/src/transports/bullmq/bullmq-transport.d.ts.map +1 -0
- package/dist/src/transports/bullmq/bullmq-transport.js +562 -0
- package/dist/src/transports/bullmq/bullmq-transport.js.map +1 -0
- package/dist/src/transports/bullmq/deps.d.ts +59 -0
- package/dist/src/transports/bullmq/deps.d.ts.map +1 -0
- package/dist/src/transports/bullmq/deps.js +41 -0
- package/dist/src/transports/bullmq/deps.js.map +1 -0
- package/dist/src/transports/bullmq/index.d.ts +5 -0
- package/dist/src/transports/bullmq/index.d.ts.map +1 -0
- package/dist/src/transports/bullmq/index.js +5 -0
- package/dist/src/transports/bullmq/index.js.map +1 -0
- package/dist/src/transports/bullmq/naming.d.ts +71 -0
- package/dist/src/transports/bullmq/naming.d.ts.map +1 -0
- package/dist/src/transports/bullmq/naming.js +101 -0
- package/dist/src/transports/bullmq/naming.js.map +1 -0
- package/dist/src/transports/bullmq/serialization.d.ts +56 -0
- package/dist/src/transports/bullmq/serialization.d.ts.map +1 -0
- package/dist/src/transports/bullmq/serialization.js +101 -0
- package/dist/src/transports/bullmq/serialization.js.map +1 -0
- package/dist/src/transports/factory.d.ts +31 -0
- package/dist/src/transports/factory.d.ts.map +1 -1
- package/dist/src/transports/factory.js +21 -0
- package/dist/src/transports/factory.js.map +1 -1
- package/dist/src/worker-runtime/index.d.ts +22 -0
- package/dist/src/worker-runtime/index.d.ts.map +1 -0
- package/dist/src/worker-runtime/index.js +27 -0
- package/dist/src/worker-runtime/index.js.map +1 -0
- package/dist/src/worker-runtime/naming.d.ts +24 -0
- package/dist/src/worker-runtime/naming.d.ts.map +1 -0
- package/dist/src/worker-runtime/naming.js +28 -0
- package/dist/src/worker-runtime/naming.js.map +1 -0
- package/dist/src/worker-runtime/registry.d.ts +81 -0
- package/dist/src/worker-runtime/registry.d.ts.map +1 -0
- package/dist/src/worker-runtime/registry.js +44 -0
- package/dist/src/worker-runtime/registry.js.map +1 -0
- package/dist/src/worker-runtime/worker-runtime.d.ts +155 -0
- package/dist/src/worker-runtime/worker-runtime.d.ts.map +1 -0
- package/dist/src/worker-runtime/worker-runtime.js +265 -0
- package/dist/src/worker-runtime/worker-runtime.js.map +1 -0
- package/dist/src/workflow-ctx.d.ts +9 -0
- package/dist/src/workflow-ctx.d.ts.map +1 -1
- package/dist/src/workflow-ctx.js +78 -27
- package/dist/src/workflow-ctx.js.map +1 -1
- package/dist/src/workflow-turn.d.ts +167 -0
- package/dist/src/workflow-turn.d.ts.map +1 -0
- package/dist/src/workflow-turn.js +372 -0
- package/dist/src/workflow-turn.js.map +1 -0
- package/package.json +7 -1
|
@@ -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 @@
|
|
|
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"}
|