@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,128 @@
1
+ /**
2
+ * Worker/control-plane handshake descriptor — the single source of truth for routing, compatibility
3
+ * and observability across a store-less durable cluster (design §7.1). Pure data + a deterministic,
4
+ * order-insensitive content hash; NO transport, NO I/O. Every field is part of the cross-language
5
+ * wire contract (the nestjs + python SDKs build the byte-identical shape, design §7.8).
6
+ */
7
+ /**
8
+ * A worker's (or control-plane's) advertised identity, wire-protocol support, feature capabilities
9
+ * and registered handlers. Published on startup + on change (design §7.2) and consumed by
10
+ * {@link negotiate} (compat) and the capability-aware router (design §7.5). Exactly the §7.1 shape.
11
+ */
12
+ export interface WorkerDescriptor {
13
+ /** Stable id for this process in the fleet (mirrors aviary's per-instance heartbeat key). */
14
+ instanceId: string;
15
+ /** Execution runtime — a `python` worker and a `node` control-plane interoperate over the wire. */
16
+ runtime: 'node' | 'python';
17
+ /** Which SDK + version produced this descriptor. Observability only; never gates dispatch. */
18
+ sdk: {
19
+ name: string;
20
+ version: string;
21
+ };
22
+ /**
23
+ * Wire-protocol majors this side speaks. `version` is its preferred/current major; `range` is the
24
+ * inclusive `[min, max]` band it can negotiate down/up to. Overlap of two ranges is what makes two
25
+ * sides compatible (design §7.4); `version` is informational.
26
+ */
27
+ protocol: {
28
+ version: number;
29
+ range: [number, number];
30
+ };
31
+ /** Named features advertised: `'saga'`, `'signals'`, `'search-attr-v2'`, `'priority'`, … A modern
32
+ * worker MAY advertise `[]` (no named features); an ABSENT field means "legacy v1" — see
33
+ * {@link normalizeDescriptor}. Order-insensitive: treated as a set. */
34
+ capabilities: string[];
35
+ /** Registered workflow handler names → routing targets. Order-insensitive (a set). */
36
+ workflows: string[];
37
+ /** Registered step handler names → routing targets. Order-insensitive (a set). */
38
+ steps: string[];
39
+ /** Optional routing partition (queue/group sharding). */
40
+ partition?: string;
41
+ /** Optional tenant namespace this instance serves. */
42
+ namespace?: string;
43
+ /** Process start time (epoch ms) — a restart changes it, so it participates in the content hash. */
44
+ startedAt: number;
45
+ }
46
+ /**
47
+ * The current wire-protocol major. The whole protocol as it exists today is defined as **v1**; the
48
+ * handshake exists so a future **v2 breaking change** is detectable rather than silently corrupting
49
+ * (design §7.7).
50
+ */
51
+ export declare const CURRENT_PROTOCOL_VERSION = 1;
52
+ /**
53
+ * The protocol band assumed for a descriptor that omits `protocol` entirely — an existing aviary
54
+ * worker that predates the handshake. Absence = **legacy v1 baseline, assume compatible** (§7.7).
55
+ */
56
+ export declare const LEGACY_V1_PROTOCOL: WorkerDescriptor['protocol'];
57
+ /**
58
+ * The feature set a legacy (pre-handshake) worker is assumed to advertise when its `capabilities`
59
+ * field is ABSENT. These are the durable primitives that have existed since v1, so a legacy worker
60
+ * can still be routed work that `requires` them (design §7.5/§7.7).
61
+ *
62
+ * This is the canonical aviary v1 execution surface, byte-for-byte identical across the Adonis,
63
+ * nestjs-durable, and Python SDKs (verified against the aviary codebase). `search-attr-v2` and other
64
+ * modern features are layered ON TOP and are NOT part of the v1 baseline — a legacy worker guarantees
65
+ * only the v1 `search-attributes` surface. Keep this list in lockstep with the other two SDKs.
66
+ */
67
+ export declare const LEGACY_V1_CAPABILITIES: readonly string[];
68
+ /**
69
+ * A raw, possibly-partial descriptor as it may arrive off the wire from an older SDK: `protocol`
70
+ * and/or `capabilities` may be missing. {@link normalizeDescriptor} fills the legacy-v1 defaults.
71
+ */
72
+ export type RawWorkerDescriptor = Omit<Partial<WorkerDescriptor>, 'instanceId' | 'runtime'> & {
73
+ instanceId: string;
74
+ runtime: 'node' | 'python';
75
+ };
76
+ /**
77
+ * True when a descriptor predates the handshake — it carries no `protocol` field. Such a descriptor
78
+ * is treated as legacy v1 and assumed compatible (design §7.7).
79
+ */
80
+ export declare function isLegacyDescriptor(raw: RawWorkerDescriptor | WorkerDescriptor): boolean;
81
+ /**
82
+ * Fill legacy-v1 defaults so downstream logic always sees a complete {@link WorkerDescriptor}:
83
+ * - absent `protocol` → {@link LEGACY_V1_PROTOCOL} (assume-compatible v1 baseline),
84
+ * - absent `capabilities` → {@link LEGACY_V1_CAPABILITIES} (a modern `[]` is preserved as-is),
85
+ * - absent `workflows`/`steps` → `[]`, absent `sdk` → an `unknown` marker, absent `startedAt` → `0`.
86
+ *
87
+ * The undefined-vs-`[]` distinction is deliberate: an absent field means "legacy, doesn't advertise
88
+ * this axis"; an explicit empty array means "modern SDK that genuinely advertises nothing".
89
+ */
90
+ export declare function normalizeDescriptor(raw: RawWorkerDescriptor | WorkerDescriptor): WorkerDescriptor;
91
+ /**
92
+ * Compact, liveness lifecycle status carried on the cheap steady-state heartbeat (design §7.2).
93
+ * Distinct from aviary's rich `WorkerStatus` object (owned by the transport layer): this is the
94
+ * lightweight two-tier advertisement, whose job is to carry the {@link descriptorHash} ETag.
95
+ */
96
+ export type WorkerLifecycle = 'up' | 'draining' | 'quiescing' | 'stopped';
97
+ /**
98
+ * The two-tier heartbeat payload (design §7.2): a cheap `{ ts, status, descriptorHash }` beaten every
99
+ * ~10s. The `descriptorHash` is an **ETag** — the control-plane re-reads the full (expensive)
100
+ * descriptor only when this hash changes, keeping steady-state chatter tiny.
101
+ */
102
+ export interface HeartbeatStatus {
103
+ /** Beat time, epoch ms. */
104
+ ts: number;
105
+ /** Compact lifecycle status. */
106
+ status: WorkerLifecycle;
107
+ /** ETag over the full descriptor — see {@link descriptorHash}. */
108
+ descriptorHash: string;
109
+ }
110
+ /**
111
+ * Stable ETag over a descriptor's content (design §7.2). **Order-insensitive** over the set-valued
112
+ * fields (`capabilities`/`workflows`/`steps`) — the same members in any order yield the same hash —
113
+ * and stable across the object's key insertion order. Any change to a routing/compat-relevant field
114
+ * (including `startedAt` on restart) changes the hash, which is what triggers a full re-read.
115
+ *
116
+ * Accepts a raw/partial descriptor too: it is normalized first, so a legacy descriptor hashes as its
117
+ * v1 baseline.
118
+ */
119
+ export declare function descriptorHash(descriptor: RawWorkerDescriptor | WorkerDescriptor): string;
120
+ /**
121
+ * Build the compact two-tier heartbeat for a descriptor, stamping the ETag (design §7.2). `ts`
122
+ * defaults to now and `status` to `'up'`.
123
+ */
124
+ export declare function heartbeatStatus(descriptor: RawWorkerDescriptor | WorkerDescriptor, opts?: {
125
+ ts?: number;
126
+ status?: WorkerLifecycle;
127
+ }): HeartbeatStatus;
128
+ //# sourceMappingURL=descriptor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"descriptor.d.ts","sourceRoot":"","sources":["../../../src/handshake/descriptor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6FAA6F;IAC7F,UAAU,EAAE,MAAM,CAAC;IACnB,mGAAmG;IACnG,OAAO,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC3B,8FAA8F;IAC9F,GAAG,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC;;;;OAIG;IACH,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IACvD;;4EAEwE;IACxE,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,sFAAsF;IACtF,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,kFAAkF;IAClF,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oGAAoG;IACpG,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,gBAAgB,CAAC,UAAU,CAAiC,CAAC;AAE9F;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAYlD,CAAC;AAEH;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC,GAAG;IAC5F,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC5B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,mBAAmB,GAAG,gBAAgB,GAAG,OAAO,CAEvF;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,mBAAmB,GAAG,gBAAgB,GAAG,gBAAgB,CAajG;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,CAAC;AAE1E;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,2BAA2B;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,MAAM,EAAE,eAAe,CAAC;IACxB,kEAAkE;IAClE,cAAc,EAAE,MAAM,CAAC;CACxB;AA0CD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,mBAAmB,GAAG,gBAAgB,GAAG,MAAM,CAGzF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,mBAAmB,GAAG,gBAAgB,EAClD,IAAI,GAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,eAAe,CAAA;CAAO,GACnD,eAAe,CAMjB"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Worker/control-plane handshake descriptor — the single source of truth for routing, compatibility
3
+ * and observability across a store-less durable cluster (design §7.1). Pure data + a deterministic,
4
+ * order-insensitive content hash; NO transport, NO I/O. Every field is part of the cross-language
5
+ * wire contract (the nestjs + python SDKs build the byte-identical shape, design §7.8).
6
+ */
7
+ /**
8
+ * The current wire-protocol major. The whole protocol as it exists today is defined as **v1**; the
9
+ * handshake exists so a future **v2 breaking change** is detectable rather than silently corrupting
10
+ * (design §7.7).
11
+ */
12
+ export const CURRENT_PROTOCOL_VERSION = 1;
13
+ /**
14
+ * The protocol band assumed for a descriptor that omits `protocol` entirely — an existing aviary
15
+ * worker that predates the handshake. Absence = **legacy v1 baseline, assume compatible** (§7.7).
16
+ */
17
+ export const LEGACY_V1_PROTOCOL = { version: 1, range: [1, 1] };
18
+ /**
19
+ * The feature set a legacy (pre-handshake) worker is assumed to advertise when its `capabilities`
20
+ * field is ABSENT. These are the durable primitives that have existed since v1, so a legacy worker
21
+ * can still be routed work that `requires` them (design §7.5/§7.7).
22
+ *
23
+ * This is the canonical aviary v1 execution surface, byte-for-byte identical across the Adonis,
24
+ * nestjs-durable, and Python SDKs (verified against the aviary codebase). `search-attr-v2` and other
25
+ * modern features are layered ON TOP and are NOT part of the v1 baseline — a legacy worker guarantees
26
+ * only the v1 `search-attributes` surface. Keep this list in lockstep with the other two SDKs.
27
+ */
28
+ export const LEGACY_V1_CAPABILITIES = Object.freeze([
29
+ 'saga',
30
+ 'signals',
31
+ 'search-attributes',
32
+ 'priority',
33
+ 'entities',
34
+ 'child-workflows',
35
+ 'singleton',
36
+ 'schedules',
37
+ 'continue-as-new',
38
+ 'queries',
39
+ 'cancellation',
40
+ ]);
41
+ /**
42
+ * True when a descriptor predates the handshake — it carries no `protocol` field. Such a descriptor
43
+ * is treated as legacy v1 and assumed compatible (design §7.7).
44
+ */
45
+ export function isLegacyDescriptor(raw) {
46
+ return raw.protocol === undefined;
47
+ }
48
+ /**
49
+ * Fill legacy-v1 defaults so downstream logic always sees a complete {@link WorkerDescriptor}:
50
+ * - absent `protocol` → {@link LEGACY_V1_PROTOCOL} (assume-compatible v1 baseline),
51
+ * - absent `capabilities` → {@link LEGACY_V1_CAPABILITIES} (a modern `[]` is preserved as-is),
52
+ * - absent `workflows`/`steps` → `[]`, absent `sdk` → an `unknown` marker, absent `startedAt` → `0`.
53
+ *
54
+ * The undefined-vs-`[]` distinction is deliberate: an absent field means "legacy, doesn't advertise
55
+ * this axis"; an explicit empty array means "modern SDK that genuinely advertises nothing".
56
+ */
57
+ export function normalizeDescriptor(raw) {
58
+ return {
59
+ instanceId: raw.instanceId,
60
+ runtime: raw.runtime,
61
+ sdk: raw.sdk ?? { name: 'unknown', version: '0' },
62
+ protocol: raw.protocol ?? { ...LEGACY_V1_PROTOCOL },
63
+ capabilities: raw.capabilities ?? [...LEGACY_V1_CAPABILITIES],
64
+ workflows: raw.workflows ?? [],
65
+ steps: raw.steps ?? [],
66
+ ...(raw.partition !== undefined ? { partition: raw.partition } : {}),
67
+ ...(raw.namespace !== undefined ? { namespace: raw.namespace } : {}),
68
+ startedAt: raw.startedAt ?? 0,
69
+ };
70
+ }
71
+ /** Canonical, order-insensitive projection of a descriptor used for hashing. The three set-valued
72
+ * fields are sorted + de-duplicated so member order can never change the hash; scalar fields are
73
+ * taken verbatim; optional fields collapse to `null` so present-with-undefined and absent agree. */
74
+ function canonicalizeForHash(d) {
75
+ const set = (xs) => [...new Set(xs)].sort();
76
+ // Keys are emitted in a FIXED order (this literal's order) so the stringify below is stable
77
+ // regardless of the input object's key insertion order.
78
+ return {
79
+ instanceId: d.instanceId,
80
+ runtime: d.runtime,
81
+ sdk: { name: d.sdk.name, version: d.sdk.version },
82
+ protocol: { version: d.protocol.version, range: [d.protocol.range[0], d.protocol.range[1]] },
83
+ capabilities: set(d.capabilities),
84
+ workflows: set(d.workflows),
85
+ steps: set(d.steps),
86
+ partition: d.partition ?? null,
87
+ namespace: d.namespace ?? null,
88
+ startedAt: d.startedAt,
89
+ };
90
+ }
91
+ /**
92
+ * Deterministic 64-bit FNV-1a hash of a string → 16-char lowercase hex. Chosen over a crypto digest
93
+ * because it is trivially reproducible in every SDK (TS/Python/…) with no dependency, keeping the
94
+ * ETag scheme portable for cross-language conformance (design §7.8).
95
+ */
96
+ function fnv1a64Hex(input) {
97
+ const OFFSET = 0xcbf29ce484222325n;
98
+ const PRIME = 0x100000001b3n;
99
+ const MASK = 0xffffffffffffffffn;
100
+ let hash = OFFSET;
101
+ for (let i = 0; i < input.length; i += 1) {
102
+ hash ^= BigInt(input.charCodeAt(i) & 0xff);
103
+ // charCodeAt can exceed a byte; fold the high byte in too so non-ASCII still contributes.
104
+ hash ^= BigInt((input.charCodeAt(i) >> 8) & 0xff);
105
+ hash = (hash * PRIME) & MASK;
106
+ }
107
+ return hash.toString(16).padStart(16, '0');
108
+ }
109
+ /**
110
+ * Stable ETag over a descriptor's content (design §7.2). **Order-insensitive** over the set-valued
111
+ * fields (`capabilities`/`workflows`/`steps`) — the same members in any order yield the same hash —
112
+ * and stable across the object's key insertion order. Any change to a routing/compat-relevant field
113
+ * (including `startedAt` on restart) changes the hash, which is what triggers a full re-read.
114
+ *
115
+ * Accepts a raw/partial descriptor too: it is normalized first, so a legacy descriptor hashes as its
116
+ * v1 baseline.
117
+ */
118
+ export function descriptorHash(descriptor) {
119
+ const canonical = canonicalizeForHash(normalizeDescriptor(descriptor));
120
+ return fnv1a64Hex(JSON.stringify(canonical));
121
+ }
122
+ /**
123
+ * Build the compact two-tier heartbeat for a descriptor, stamping the ETag (design §7.2). `ts`
124
+ * defaults to now and `status` to `'up'`.
125
+ */
126
+ export function heartbeatStatus(descriptor, opts = {}) {
127
+ return {
128
+ ts: opts.ts ?? Date.now(),
129
+ status: opts.status ?? 'up',
130
+ descriptorHash: descriptorHash(descriptor),
131
+ };
132
+ }
133
+ //# sourceMappingURL=descriptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"descriptor.js","sourceRoot":"","sources":["../../../src/handshake/descriptor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Bilateral compatibility negotiation between two handshake descriptors (design §7.3/§7.4). Pure
3
+ * logic: given a local and a remote {@link WorkerDescriptor}, compute the negotiated session (highest
4
+ * common protocol major + capability intersection) and classify it into one of three outcomes with a
5
+ * precise, structured reason — never a bare boolean (design §7.6).
6
+ */
7
+ import { type RawWorkerDescriptor, type WorkerDescriptor } from './descriptor.js';
8
+ /**
9
+ * The three compatibility outcomes (design §7.4):
10
+ * - `compatible` — protocol ranges intersect + full capability parity → dispatch freely.
11
+ * - `degraded` — ranges intersect but a capability is missing on one side → dispatch, but route
12
+ * capability-requiring work only to capable workers (soft warning).
13
+ * - `incompatible` — no protocol-range overlap → do NOT dispatch; red flag with the exact reason.
14
+ */
15
+ export type NegotiationOutcome = 'compatible' | 'degraded' | 'incompatible';
16
+ /** Structured failure/warning payload — carries the precise delta so a diagnostics event can render
17
+ * it on the timeline + dashboard health panel (design §7.6). Never a bare boolean. */
18
+ export interface NegotiationReason {
19
+ /** Stable machine code for alerting/telescope. */
20
+ code: 'protocol.incompatible' | 'capability.unavailable';
21
+ /** Human-readable one-liner (dashboard/telescope copy). */
22
+ message: string;
23
+ /** The exact delta: which protocol ranges failed to overlap, or which capabilities are missing. */
24
+ detail: {
25
+ localRange?: [number, number];
26
+ remoteRange?: [number, number];
27
+ /** Capabilities the local side advertises that the remote lacks. */
28
+ missingOnRemote?: string[];
29
+ /** Capabilities the remote side advertises that the local lacks. */
30
+ missingOnLocal?: string[];
31
+ /** Explicitly-required capabilities not satisfied by the negotiated session. */
32
+ missingRequired?: string[];
33
+ };
34
+ }
35
+ /** The negotiated session + full delta between two sides. Carries both normalized descriptors so a
36
+ * downstream diagnostics event can attach them wholesale (design §7.6). */
37
+ export interface NegotiationResult {
38
+ outcome: NegotiationOutcome;
39
+ /** Highest common protocol major, or `null` when ranges do not overlap (incompatible). */
40
+ negotiatedProtocol: number | null;
41
+ protocol: {
42
+ localRange: [number, number];
43
+ remoteRange: [number, number];
44
+ };
45
+ capabilities: {
46
+ /** Intersection — the capabilities the negotiated session can rely on everywhere. */
47
+ shared: string[];
48
+ /** Local advertises, remote lacks. */
49
+ missingOnRemote: string[];
50
+ /** Remote advertises, local lacks. */
51
+ missingOnLocal: string[];
52
+ };
53
+ /** Present for `degraded` + `incompatible`; absent for `compatible`. */
54
+ reason?: NegotiationReason;
55
+ local: WorkerDescriptor;
56
+ remote: WorkerDescriptor;
57
+ }
58
+ export interface NegotiateOptions {
59
+ /**
60
+ * Capabilities the local side needs the negotiated session to provide. A required capability the
61
+ * remote lacks degrades the session (dispatch generally, but capability-requiring runs park via
62
+ * the router, design §7.5) — it never, on its own, makes the pair *incompatible*: only a protocol
63
+ * range gap does that (design §7.4).
64
+ */
65
+ required?: string[];
66
+ }
67
+ /**
68
+ * Negotiate compatibility between `local` and `remote` (design §7.3/§7.4). Accepts raw/partial
69
+ * descriptors (a missing `protocol`/`capabilities` is normalized to the legacy-v1 baseline, so a
70
+ * legacy peer negotiates as **assume-compatible**, design §7.7).
71
+ *
72
+ * Outcome logic:
73
+ * 1. no protocol-range overlap → `incompatible` (`protocol.incompatible`);
74
+ * 2. else if a `required` capability is missing on the remote → `degraded` (`capability.unavailable`);
75
+ * 3. else if the capability sets differ at all (either direction) → `degraded`;
76
+ * 4. else full parity → `compatible`.
77
+ *
78
+ * **Bilateral-symmetric** on outcome for the parity path: `negotiate(a, b).outcome ===
79
+ * negotiate(b, a).outcome` (the `missingOnLocal`/`missingOnRemote` delta swaps). `required` is the
80
+ * caller's own need and intentionally asymmetric.
81
+ */
82
+ export declare function negotiate(localRaw: RawWorkerDescriptor | WorkerDescriptor, remoteRaw: RawWorkerDescriptor | WorkerDescriptor, opts?: NegotiateOptions): NegotiationResult;
83
+ //# sourceMappingURL=negotiate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"negotiate.d.ts","sourceRoot":"","sources":["../../../src/handshake/negotiate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EAEtB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,UAAU,GAAG,cAAc,CAAC;AAE5E;uFACuF;AACvF,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,IAAI,EAAE,uBAAuB,GAAG,wBAAwB,CAAC;IACzD,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,mGAAmG;IACnG,MAAM,EAAE;QACN,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC9B,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/B,oEAAoE;QACpE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3B,oEAAoE;QACpE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,gFAAgF;QAChF,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;KAC5B,CAAC;CACH;AAED;4EAC4E;AAC5E,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,kBAAkB,CAAC;IAC5B,0FAA0F;IAC1F,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,EAAE;QAAE,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IAC1E,YAAY,EAAE;QACZ,qFAAqF;QACrF,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,sCAAsC;QACtC,eAAe,EAAE,MAAM,EAAE,CAAC;QAC1B,sCAAsC;QACtC,cAAc,EAAE,MAAM,EAAE,CAAC;KAC1B,CAAC;IACF,wEAAwE;IACxE,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,KAAK,EAAE,gBAAgB,CAAC;IACxB,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAeD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,mBAAmB,GAAG,gBAAgB,EAChD,SAAS,EAAE,mBAAmB,GAAG,gBAAgB,EACjD,IAAI,GAAE,gBAAqB,GAC1B,iBAAiB,CAgFnB"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Bilateral compatibility negotiation between two handshake descriptors (design §7.3/§7.4). Pure
3
+ * logic: given a local and a remote {@link WorkerDescriptor}, compute the negotiated session (highest
4
+ * common protocol major + capability intersection) and classify it into one of three outcomes with a
5
+ * precise, structured reason — never a bare boolean (design §7.6).
6
+ */
7
+ import { normalizeDescriptor, } from './descriptor.js';
8
+ const rangesOverlap = (a, b) => Math.max(a[0], b[0]) <= Math.min(a[1], b[1]);
9
+ const difference = (a, b) => {
10
+ const bset = new Set(b);
11
+ return [...new Set(a)].filter((x) => !bset.has(x)).sort();
12
+ };
13
+ const intersection = (a, b) => {
14
+ const bset = new Set(b);
15
+ return [...new Set(a)].filter((x) => bset.has(x)).sort();
16
+ };
17
+ /**
18
+ * Negotiate compatibility between `local` and `remote` (design §7.3/§7.4). Accepts raw/partial
19
+ * descriptors (a missing `protocol`/`capabilities` is normalized to the legacy-v1 baseline, so a
20
+ * legacy peer negotiates as **assume-compatible**, design §7.7).
21
+ *
22
+ * Outcome logic:
23
+ * 1. no protocol-range overlap → `incompatible` (`protocol.incompatible`);
24
+ * 2. else if a `required` capability is missing on the remote → `degraded` (`capability.unavailable`);
25
+ * 3. else if the capability sets differ at all (either direction) → `degraded`;
26
+ * 4. else full parity → `compatible`.
27
+ *
28
+ * **Bilateral-symmetric** on outcome for the parity path: `negotiate(a, b).outcome ===
29
+ * negotiate(b, a).outcome` (the `missingOnLocal`/`missingOnRemote` delta swaps). `required` is the
30
+ * caller's own need and intentionally asymmetric.
31
+ */
32
+ export function negotiate(localRaw, remoteRaw, opts = {}) {
33
+ const local = normalizeDescriptor(localRaw);
34
+ const remote = normalizeDescriptor(remoteRaw);
35
+ const localRange = local.protocol.range;
36
+ const remoteRange = remote.protocol.range;
37
+ const shared = intersection(local.capabilities, remote.capabilities);
38
+ const missingOnRemote = difference(local.capabilities, remote.capabilities);
39
+ const missingOnLocal = difference(remote.capabilities, local.capabilities);
40
+ const capabilities = { shared, missingOnRemote, missingOnLocal };
41
+ // (1) Protocol range gap → incompatible. This is the ONLY path that blocks dispatch outright.
42
+ if (!rangesOverlap(localRange, remoteRange)) {
43
+ return {
44
+ outcome: 'incompatible',
45
+ negotiatedProtocol: null,
46
+ protocol: { localRange, remoteRange },
47
+ capabilities,
48
+ reason: {
49
+ code: 'protocol.incompatible',
50
+ message: `no common protocol major: local speaks [${localRange[0]}, ${localRange[1]}], ` +
51
+ `remote speaks [${remoteRange[0]}, ${remoteRange[1]}]`,
52
+ detail: { localRange, remoteRange },
53
+ },
54
+ local,
55
+ remote,
56
+ };
57
+ }
58
+ const negotiatedProtocol = Math.min(localRange[1], remoteRange[1]);
59
+ // (2) A required capability the remote cannot provide → degraded (router parks the specific run).
60
+ const required = opts.required ?? [];
61
+ const missingRequired = difference(required, remote.capabilities);
62
+ if (missingRequired.length > 0) {
63
+ return {
64
+ outcome: 'degraded',
65
+ negotiatedProtocol,
66
+ protocol: { localRange, remoteRange },
67
+ capabilities,
68
+ reason: {
69
+ code: 'capability.unavailable',
70
+ message: `remote is missing required capability(ies): ${missingRequired.join(', ')}`,
71
+ detail: { missingRequired, missingOnRemote, missingOnLocal },
72
+ },
73
+ local,
74
+ remote,
75
+ };
76
+ }
77
+ // (3) Any capability asymmetry → degraded (soft; route capability-requiring work carefully).
78
+ if (missingOnRemote.length > 0 || missingOnLocal.length > 0) {
79
+ const parts = [];
80
+ if (missingOnRemote.length > 0)
81
+ parts.push(`remote lacks ${missingOnRemote.join(', ')}`);
82
+ if (missingOnLocal.length > 0)
83
+ parts.push(`local lacks ${missingOnLocal.join(', ')}`);
84
+ return {
85
+ outcome: 'degraded',
86
+ negotiatedProtocol,
87
+ protocol: { localRange, remoteRange },
88
+ capabilities,
89
+ reason: {
90
+ code: 'capability.unavailable',
91
+ message: `capability mismatch: ${parts.join('; ')}`,
92
+ detail: { missingOnRemote, missingOnLocal },
93
+ },
94
+ local,
95
+ remote,
96
+ };
97
+ }
98
+ // (4) Ranges overlap + full capability parity → compatible.
99
+ return {
100
+ outcome: 'compatible',
101
+ negotiatedProtocol,
102
+ protocol: { localRange, remoteRange },
103
+ capabilities,
104
+ local,
105
+ remote,
106
+ };
107
+ }
108
+ //# sourceMappingURL=negotiate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"negotiate.js","sourceRoot":"","sources":["../../../src/handshake/negotiate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Capability-aware routing (design §7.5). A workflow/step handler may declare
3
+ * `requires: ['saga', 'search-attr-v2']`; the control-plane dispatches only to workers whose
4
+ * descriptor advertises every required capability. If no live capable worker exists the run must
5
+ * **park as `blocked`** with a precise reason (visible in the dashboard) — never a silent hang.
6
+ *
7
+ * Pure logic: no transport, no store. Consumers (the dispatcher/provider) feed live descriptors in.
8
+ */
9
+ import { type RawWorkerDescriptor, type WorkerDescriptor } from './descriptor.js';
10
+ /** A handler's capability demand — either a bare list, or anything carrying a `requires` array
11
+ * (a workflow/step ref). An absent/empty list means "runs anywhere" (design §7.5). */
12
+ export type CapabilityRequirement = string[] | {
13
+ requires?: string[];
14
+ };
15
+ /** Normalize the two accepted shapes to a de-duplicated list of required capability names. */
16
+ export declare function requiredCapabilities(handler: CapabilityRequirement): string[];
17
+ /**
18
+ * Can `worker` run a handler with these requirements? True iff the worker's (normalized) descriptor
19
+ * advertises **every** required capability. A legacy worker (no `capabilities` field) is normalized
20
+ * to the v1 baseline first (design §7.7), so it can still run baseline-only work.
21
+ */
22
+ export declare function canRoute(handler: CapabilityRequirement, worker: RawWorkerDescriptor | WorkerDescriptor): boolean;
23
+ /**
24
+ * The capabilities a handler requires that `worker` does NOT advertise — the precise routing delta.
25
+ * Empty iff {@link canRoute} is true.
26
+ */
27
+ export declare function missingCapabilities(handler: CapabilityRequirement, worker: RawWorkerDescriptor | WorkerDescriptor): string[];
28
+ /** Filter a fleet down to the workers that can run a handler (design §7.5). */
29
+ export declare function capableWorkers<T extends RawWorkerDescriptor | WorkerDescriptor>(handler: CapabilityRequirement, workers: readonly T[]): T[];
30
+ /** A run is dispatchable — at least one live worker can execute the handler. */
31
+ export interface RoutableResolution {
32
+ status: 'routable';
33
+ /** The normalized subset of the fleet that can run it. */
34
+ workers: WorkerDescriptor[];
35
+ requires: string[];
36
+ }
37
+ /** No live capable worker — the run parks as `blocked` with a human reason (design §7.5). */
38
+ export interface BlockedResolution {
39
+ status: 'blocked';
40
+ /** Exactly the dashboard copy: `blocked: no compatible worker (requires <caps>)`. */
41
+ reason: string;
42
+ requires: string[];
43
+ }
44
+ export type RoutingResolution = RoutableResolution | BlockedResolution;
45
+ /**
46
+ * Decide whether a handler can be dispatched to the given live fleet (design §7.5). Returns
47
+ * `routable` with the capable subset, or `blocked` with a precise reason when nobody can run it —
48
+ * so the run parks visibly instead of hanging silently. An empty fleet always blocks.
49
+ */
50
+ export declare function resolveRouting(handler: CapabilityRequirement, workers: readonly (RawWorkerDescriptor | WorkerDescriptor)[]): RoutingResolution;
51
+ //# sourceMappingURL=routing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../../src/handshake/routing.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EAEtB,MAAM,iBAAiB,CAAC;AAEzB;uFACuF;AACvF,MAAM,MAAM,qBAAqB,GAAG,MAAM,EAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEvE,8FAA8F;AAC9F,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,EAAE,CAG7E;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,OAAO,EAAE,qBAAqB,EAC9B,MAAM,EAAE,mBAAmB,GAAG,gBAAgB,GAC7C,OAAO,CAKT;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,qBAAqB,EAC9B,MAAM,EAAE,mBAAmB,GAAG,gBAAgB,GAC7C,MAAM,EAAE,CAGV;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,CAAC,SAAS,mBAAmB,GAAG,gBAAgB,EAC7E,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,SAAS,CAAC,EAAE,GACpB,CAAC,EAAE,CAEL;AAED,gFAAgF;AAChF,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,UAAU,CAAC;IACnB,0DAA0D;IAC1D,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,6FAA6F;AAC7F,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,SAAS,CAAC;IAClB,qFAAqF;IACrF,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,GAAG,iBAAiB,CAAC;AAEvE;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,SAAS,CAAC,mBAAmB,GAAG,gBAAgB,CAAC,EAAE,GAC3D,iBAAiB,CAcnB"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Capability-aware routing (design §7.5). A workflow/step handler may declare
3
+ * `requires: ['saga', 'search-attr-v2']`; the control-plane dispatches only to workers whose
4
+ * descriptor advertises every required capability. If no live capable worker exists the run must
5
+ * **park as `blocked`** with a precise reason (visible in the dashboard) — never a silent hang.
6
+ *
7
+ * Pure logic: no transport, no store. Consumers (the dispatcher/provider) feed live descriptors in.
8
+ */
9
+ import { normalizeDescriptor, } from './descriptor.js';
10
+ /** Normalize the two accepted shapes to a de-duplicated list of required capability names. */
11
+ export function requiredCapabilities(handler) {
12
+ const list = Array.isArray(handler) ? handler : (handler.requires ?? []);
13
+ return [...new Set(list)];
14
+ }
15
+ /**
16
+ * Can `worker` run a handler with these requirements? True iff the worker's (normalized) descriptor
17
+ * advertises **every** required capability. A legacy worker (no `capabilities` field) is normalized
18
+ * to the v1 baseline first (design §7.7), so it can still run baseline-only work.
19
+ */
20
+ export function canRoute(handler, worker) {
21
+ const required = requiredCapabilities(handler);
22
+ if (required.length === 0)
23
+ return true;
24
+ const advertised = new Set(normalizeDescriptor(worker).capabilities);
25
+ return required.every((cap) => advertised.has(cap));
26
+ }
27
+ /**
28
+ * The capabilities a handler requires that `worker` does NOT advertise — the precise routing delta.
29
+ * Empty iff {@link canRoute} is true.
30
+ */
31
+ export function missingCapabilities(handler, worker) {
32
+ const advertised = new Set(normalizeDescriptor(worker).capabilities);
33
+ return requiredCapabilities(handler).filter((cap) => !advertised.has(cap));
34
+ }
35
+ /** Filter a fleet down to the workers that can run a handler (design §7.5). */
36
+ export function capableWorkers(handler, workers) {
37
+ return workers.filter((w) => canRoute(handler, w));
38
+ }
39
+ /**
40
+ * Decide whether a handler can be dispatched to the given live fleet (design §7.5). Returns
41
+ * `routable` with the capable subset, or `blocked` with a precise reason when nobody can run it —
42
+ * so the run parks visibly instead of hanging silently. An empty fleet always blocks.
43
+ */
44
+ export function resolveRouting(handler, workers) {
45
+ const requires = requiredCapabilities(handler);
46
+ const capable = capableWorkers(handler, workers).map(normalizeDescriptor);
47
+ if (capable.length > 0) {
48
+ return { status: 'routable', workers: capable, requires };
49
+ }
50
+ const suffix = requires.length > 0 ? ` (requires ${requires.join(', ')})` : '';
51
+ return {
52
+ status: 'blocked',
53
+ reason: `blocked: no compatible worker${suffix}`,
54
+ requires,
55
+ };
56
+ }
57
+ //# sourceMappingURL=routing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.js","sourceRoot":"","sources":["../../../src/handshake/routing.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAGL,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAMzB,8FAA8F;AAC9F,MAAM,UAAU,oBAAoB,CAAC,OAA8B;IACjE,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IACzE,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CACtB,OAA8B,EAC9B,MAA8C;IAE9C,MAAM,QAAQ,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC/C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IACrE,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAA8B,EAC9B,MAA8C;IAE9C,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IACrE,OAAO,oBAAoB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,cAAc,CAC5B,OAA8B,EAC9B,OAAqB;IAErB,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;AAoBD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,OAA8B,EAC9B,OAA4D;IAE5D,MAAM,QAAQ,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAE1E,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAC5D,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/E,OAAO;QACL,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,gCAAgC,MAAM,EAAE;QAChD,QAAQ;KACT,CAAC;AACJ,CAAC"}
@@ -1,5 +1,5 @@
1
1
  /** Keep in sync with this package's `version` in package.json. */
2
- export declare const VERSION = "0.10.0";
2
+ export declare const VERSION = "0.11.0";
3
3
  export * from './admission.js';
4
4
  export * from './control-flow-signal.js';
5
5
  export * from './duration.js';
@@ -11,6 +11,7 @@ export * from './interfaces.js';
11
11
  export * from './protocol.js';
12
12
  export * from './queue.js';
13
13
  export * from './remote-workflow-executor.js';
14
+ export * from './workflow-turn.js';
14
15
  export * from './tenant-group.js';
15
16
  export { DURABLE_STEP_CONFIG, DURABLE_STEP_NAME, type StepConfig, type StepRef, stepConfigOf, stepNameOf, } from './step-name-symbol.js';
16
17
  export * from './step-ref.js';
@@ -30,10 +31,11 @@ export { getCurrentWorkflowCtx, workflowAls } from './workflow-als.js';
30
31
  export { InMemoryStateStore } from './testing/in-memory-state-store.js';
31
32
  export { InMemoryTransport } from './testing/in-memory-transport.js';
32
33
  export { transports } from './transports/factory.js';
33
- export type { TransportContext, TransportFactory, MemoryTransportConfig, EventEmitterTransportConfig, QueueTransportConfig, DbTransportConfig, } from './transports/factory.js';
34
+ export type { TransportContext, TransportFactory, MemoryTransportConfig, EventEmitterTransportConfig, QueueTransportConfig, BullMQTransportConfig, DbTransportConfig, } from './transports/factory.js';
34
35
  export { EventEmitterTransport, type EventEmitterTransportOptions, } from './transports/event-emitter.js';
35
36
  export { QueueTransport, type QueueTransportOptions } from './transports/queue.js';
36
37
  export { DbTransport, type DbTransportOptions } from './transports/db.js';
38
+ export { BullMQTransport, type BullMQTransportOptions, type BullMQDeps, createBullMQDeps, } from './transports/bullmq/index.js';
37
39
  export { TRANSPORT_TABLES, createDurableTransportTables, dropDurableTransportTables, } from './transports/db-schema.js';
38
40
  export { stores } from './stores/factory.js';
39
41
  export type { StoreContext, StoreFactory, LucidStoreConfig } from './stores/factory.js';
@@ -44,4 +46,14 @@ export type { ControlPlaneContext, ControlPlaneFactory, RedisControlPlaneConfig,
44
46
  export { RedisControlPlane, type RedisControlPlaneOptions, type RedisPubSub, } from './control-plane-redis/redis-control-plane.js';
45
47
  export { defineConfig } from './define_config.js';
46
48
  export type { DurableConfig } from './define_config.js';
49
+ export type { StandaloneConfig, ControlPlaneConfig, TenantConfig, TenantVerifier, VerifiedTenant, } from './config_types.js';
50
+ export type { RunGateway, DurableTopology, StartRunOptions } from './run-gateway/interface.js';
51
+ export { StoreRunGateway, type RunGatewayEngine, type StoreRunGatewayOptions, } from './run-gateway/store-run-gateway.js';
52
+ export { ProxyRunGateway, type ProxyTransport, type ProxyRunGatewayOptions, } from './run-gateway/proxy-run-gateway.js';
53
+ export { RunRequestResponder, type ResponderTransport, type RunRequestResponderOptions, } from './run-gateway/run-request-responder.js';
54
+ export { signTenantToken, hmacTenantVerifier } from './run-gateway/tenant-auth.js';
55
+ export * from './handshake/descriptor.js';
56
+ export * from './handshake/negotiate.js';
57
+ export * from './handshake/routing.js';
58
+ export * from './dispatch-routing.js';
47
59
  //# sourceMappingURL=index.d.ts.map