@hotmeshio/hotmesh 0.12.1 → 0.14.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 (202) hide show
  1. package/README.md +18 -22
  2. package/build/modules/enums.d.ts +60 -5
  3. package/build/modules/enums.js +62 -7
  4. package/build/modules/errors.d.ts +15 -2
  5. package/build/modules/errors.js +17 -1
  6. package/build/modules/storage.d.ts +1 -0
  7. package/build/modules/storage.js +2 -1
  8. package/build/package.json +8 -2
  9. package/build/services/activities/activity/context.d.ts +22 -0
  10. package/build/services/activities/activity/context.js +76 -0
  11. package/build/services/activities/activity/index.d.ts +116 -0
  12. package/build/services/activities/activity/index.js +299 -0
  13. package/build/services/activities/activity/mapping.d.ts +12 -0
  14. package/build/services/activities/activity/mapping.js +63 -0
  15. package/build/services/activities/activity/process.d.ts +28 -0
  16. package/build/services/activities/activity/process.js +100 -0
  17. package/build/services/activities/activity/protocol.d.ts +39 -0
  18. package/build/services/activities/activity/protocol.js +151 -0
  19. package/build/services/activities/activity/state.d.ts +40 -0
  20. package/build/services/activities/activity/state.js +143 -0
  21. package/build/services/activities/activity/transition.d.ts +23 -0
  22. package/build/services/activities/activity/transition.js +71 -0
  23. package/build/services/activities/activity/verify.d.ts +22 -0
  24. package/build/services/activities/activity/verify.js +85 -0
  25. package/build/services/activities/await.d.ts +1 -4
  26. package/build/services/activities/await.js +2 -36
  27. package/build/services/activities/cycle.d.ts +1 -11
  28. package/build/services/activities/cycle.js +3 -46
  29. package/build/services/activities/hook.d.ts +2 -11
  30. package/build/services/activities/hook.js +30 -50
  31. package/build/services/activities/interrupt.d.ts +2 -4
  32. package/build/services/activities/interrupt.js +4 -38
  33. package/build/services/activities/signal.d.ts +1 -11
  34. package/build/services/activities/signal.js +3 -48
  35. package/build/services/activities/trigger.d.ts +1 -3
  36. package/build/services/activities/trigger.js +0 -3
  37. package/build/services/activities/worker.d.ts +3 -6
  38. package/build/services/activities/worker.js +4 -40
  39. package/build/services/connector/factory.d.ts +6 -0
  40. package/build/services/connector/factory.js +24 -0
  41. package/build/services/dba/index.d.ts +14 -4
  42. package/build/services/dba/index.js +57 -18
  43. package/build/services/durable/activity.d.ts +30 -0
  44. package/build/services/durable/activity.js +46 -0
  45. package/build/services/durable/client.d.ts +26 -31
  46. package/build/services/durable/client.js +26 -31
  47. package/build/services/durable/connection.d.ts +13 -7
  48. package/build/services/durable/connection.js +13 -7
  49. package/build/services/durable/exporter.d.ts +2 -2
  50. package/build/services/durable/exporter.js +27 -12
  51. package/build/services/durable/handle.d.ts +59 -41
  52. package/build/services/durable/handle.js +61 -41
  53. package/build/services/durable/index.d.ts +152 -283
  54. package/build/services/durable/index.js +161 -289
  55. package/build/services/durable/interceptor.d.ts +43 -33
  56. package/build/services/durable/interceptor.js +59 -39
  57. package/build/services/durable/schemas/factory.d.ts +2 -3
  58. package/build/services/durable/schemas/factory.js +180 -30
  59. package/build/services/durable/telemetry.d.ts +80 -0
  60. package/build/services/durable/telemetry.js +137 -0
  61. package/build/services/durable/worker.d.ts +100 -21
  62. package/build/services/durable/worker.js +314 -60
  63. package/build/services/durable/workflow/all.d.ts +1 -1
  64. package/build/services/durable/workflow/all.js +1 -1
  65. package/build/services/durable/workflow/cancellationScope.d.ts +104 -0
  66. package/build/services/durable/workflow/cancellationScope.js +139 -0
  67. package/build/services/durable/workflow/common.d.ts +5 -4
  68. package/build/services/durable/workflow/common.js +6 -1
  69. package/build/services/durable/workflow/{waitFor.d.ts → condition.d.ts} +9 -8
  70. package/build/services/durable/workflow/{waitFor.js → condition.js} +44 -11
  71. package/build/services/durable/workflow/continueAsNew.d.ts +65 -0
  72. package/build/services/durable/workflow/continueAsNew.js +92 -0
  73. package/build/services/durable/workflow/didRun.d.ts +2 -2
  74. package/build/services/durable/workflow/didRun.js +4 -4
  75. package/build/services/durable/workflow/enrich.d.ts +5 -0
  76. package/build/services/durable/workflow/enrich.js +5 -0
  77. package/build/services/durable/workflow/entityMethods.d.ts +7 -0
  78. package/build/services/durable/workflow/entityMethods.js +7 -0
  79. package/build/services/durable/workflow/execHook.js +3 -3
  80. package/build/services/durable/workflow/execHookBatch.js +2 -2
  81. package/build/services/durable/workflow/{execChild.d.ts → executeChild.d.ts} +4 -40
  82. package/build/services/durable/workflow/{execChild.js → executeChild.js} +36 -45
  83. package/build/services/durable/workflow/hook.d.ts +1 -1
  84. package/build/services/durable/workflow/hook.js +4 -3
  85. package/build/services/durable/workflow/index.d.ts +45 -50
  86. package/build/services/durable/workflow/index.js +46 -51
  87. package/build/services/durable/workflow/interruption.d.ts +7 -6
  88. package/build/services/durable/workflow/interruption.js +11 -7
  89. package/build/services/durable/workflow/patched.d.ts +72 -0
  90. package/build/services/durable/workflow/patched.js +110 -0
  91. package/build/services/durable/workflow/proxyActivities.d.ts +7 -7
  92. package/build/services/durable/workflow/proxyActivities.js +51 -15
  93. package/build/services/durable/workflow/searchMethods.d.ts +7 -0
  94. package/build/services/durable/workflow/searchMethods.js +7 -0
  95. package/build/services/durable/workflow/signal.d.ts +4 -4
  96. package/build/services/durable/workflow/signal.js +4 -4
  97. package/build/services/durable/workflow/{sleepFor.d.ts → sleep.d.ts} +7 -7
  98. package/build/services/durable/workflow/{sleepFor.js → sleep.js} +39 -10
  99. package/build/services/durable/workflow/terminate.d.ts +55 -0
  100. package/build/services/durable/workflow/{interrupt.js → terminate.js} +21 -21
  101. package/build/services/durable/workflow/trace.js +2 -2
  102. package/build/services/durable/workflow/uuid4.d.ts +14 -0
  103. package/build/services/durable/workflow/uuid4.js +39 -0
  104. package/build/services/durable/workflow/{context.d.ts → workflowInfo.d.ts} +5 -5
  105. package/build/services/durable/workflow/{context.js → workflowInfo.js} +7 -7
  106. package/build/services/engine/compiler.d.ts +19 -0
  107. package/build/services/engine/compiler.js +20 -0
  108. package/build/services/engine/completion.d.ts +46 -0
  109. package/build/services/engine/completion.js +145 -0
  110. package/build/services/engine/dispatch.d.ts +24 -0
  111. package/build/services/engine/dispatch.js +98 -0
  112. package/build/services/engine/index.d.ts +49 -81
  113. package/build/services/engine/index.js +175 -573
  114. package/build/services/engine/init.d.ts +42 -0
  115. package/build/services/engine/init.js +74 -0
  116. package/build/services/engine/pubsub.d.ts +50 -0
  117. package/build/services/engine/pubsub.js +118 -0
  118. package/build/services/engine/reporting.d.ts +20 -0
  119. package/build/services/engine/reporting.js +38 -0
  120. package/build/services/engine/schema.d.ts +23 -0
  121. package/build/services/engine/schema.js +62 -0
  122. package/build/services/engine/signal.d.ts +57 -0
  123. package/build/services/engine/signal.js +117 -0
  124. package/build/services/engine/state.d.ts +35 -0
  125. package/build/services/engine/state.js +61 -0
  126. package/build/services/engine/version.d.ts +31 -0
  127. package/build/services/engine/version.js +73 -0
  128. package/build/services/hotmesh/deployment.d.ts +21 -0
  129. package/build/services/hotmesh/deployment.js +25 -0
  130. package/build/services/hotmesh/index.d.ts +142 -533
  131. package/build/services/hotmesh/index.js +223 -674
  132. package/build/services/hotmesh/init.d.ts +42 -0
  133. package/build/services/hotmesh/init.js +93 -0
  134. package/build/services/hotmesh/jobs.d.ts +67 -0
  135. package/build/services/hotmesh/jobs.js +99 -0
  136. package/build/services/hotmesh/pubsub.d.ts +38 -0
  137. package/build/services/hotmesh/pubsub.js +54 -0
  138. package/build/services/hotmesh/quorum.d.ts +30 -0
  139. package/build/services/hotmesh/quorum.js +62 -0
  140. package/build/services/hotmesh/validation.d.ts +6 -0
  141. package/build/services/hotmesh/validation.js +28 -0
  142. package/build/services/quorum/index.js +1 -0
  143. package/build/services/router/consumption/index.d.ts +11 -5
  144. package/build/services/router/consumption/index.js +24 -17
  145. package/build/services/router/error-handling/index.d.ts +2 -2
  146. package/build/services/router/error-handling/index.js +14 -14
  147. package/build/services/router/index.d.ts +1 -1
  148. package/build/services/router/index.js +2 -2
  149. package/build/services/serializer/index.d.ts +22 -0
  150. package/build/services/serializer/index.js +39 -1
  151. package/build/services/store/index.d.ts +1 -0
  152. package/build/services/store/providers/postgres/exporter-sql.d.ts +2 -2
  153. package/build/services/store/providers/postgres/exporter-sql.js +4 -4
  154. package/build/services/store/providers/postgres/kvtables.js +7 -6
  155. package/build/services/store/providers/postgres/kvtypes/hash/basic.js +67 -52
  156. package/build/services/store/providers/postgres/kvtypes/hash/jsonb.js +87 -72
  157. package/build/services/store/providers/postgres/kvtypes/hash/udata.js +106 -79
  158. package/build/services/store/providers/postgres/kvtypes/hash/utils.d.ts +16 -0
  159. package/build/services/store/providers/postgres/kvtypes/hash/utils.js +29 -16
  160. package/build/services/store/providers/postgres/postgres.d.ts +1 -0
  161. package/build/services/store/providers/postgres/postgres.js +14 -4
  162. package/build/services/stream/factory.d.ts +3 -1
  163. package/build/services/stream/factory.js +2 -2
  164. package/build/services/stream/index.d.ts +1 -0
  165. package/build/services/stream/providers/nats/nats.d.ts +1 -0
  166. package/build/services/stream/providers/nats/nats.js +1 -0
  167. package/build/services/stream/providers/postgres/credentials.d.ts +56 -0
  168. package/build/services/stream/providers/postgres/credentials.js +129 -0
  169. package/build/services/stream/providers/postgres/kvtables.js +18 -0
  170. package/build/services/stream/providers/postgres/messages.js +7 -7
  171. package/build/services/stream/providers/postgres/notifications.js +16 -2
  172. package/build/services/stream/providers/postgres/postgres.d.ts +7 -0
  173. package/build/services/stream/providers/postgres/postgres.js +35 -4
  174. package/build/services/stream/providers/postgres/procedures.d.ts +21 -0
  175. package/build/services/stream/providers/postgres/procedures.js +213 -0
  176. package/build/services/stream/providers/postgres/secured.d.ts +34 -0
  177. package/build/services/stream/providers/postgres/secured.js +146 -0
  178. package/build/services/stream/providers/postgres/stats.d.ts +1 -0
  179. package/build/services/stream/providers/postgres/stats.js +1 -0
  180. package/build/services/stream/registry.d.ts +1 -1
  181. package/build/services/stream/registry.js +5 -2
  182. package/build/services/telemetry/index.d.ts +10 -1
  183. package/build/services/telemetry/index.js +40 -7
  184. package/build/services/worker/credentials.d.ts +51 -0
  185. package/build/services/worker/credentials.js +87 -0
  186. package/build/services/worker/index.d.ts +2 -2
  187. package/build/services/worker/index.js +7 -6
  188. package/build/types/codec.d.ts +84 -0
  189. package/build/types/codec.js +2 -0
  190. package/build/types/dba.d.ts +39 -3
  191. package/build/types/durable.d.ts +123 -25
  192. package/build/types/error.d.ts +10 -0
  193. package/build/types/exporter.d.ts +1 -1
  194. package/build/types/hotmesh.d.ts +67 -4
  195. package/build/types/index.d.ts +2 -1
  196. package/build/types/provider.d.ts +2 -2
  197. package/build/types/quorum.d.ts +35 -1
  198. package/build/types/stream.d.ts +12 -6
  199. package/package.json +8 -2
  200. package/build/services/activities/activity.d.ts +0 -192
  201. package/build/services/activities/activity.js +0 -786
  202. package/build/services/durable/workflow/interrupt.d.ts +0 -55
@@ -1,66 +1,61 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WorkflowService = void 0;
4
- const context_1 = require("./context");
4
+ const workflowInfo_1 = require("./workflowInfo");
5
5
  const didRun_1 = require("./didRun");
6
6
  const isSideEffectAllowed_1 = require("./isSideEffectAllowed");
7
7
  const trace_1 = require("./trace");
8
8
  const enrich_1 = require("./enrich");
9
9
  const emit_1 = require("./emit");
10
- const execChild_1 = require("./execChild");
10
+ const executeChild_1 = require("./executeChild");
11
11
  const execHook_1 = require("./execHook");
12
12
  const execHookBatch_1 = require("./execHookBatch");
13
13
  const proxyActivities_1 = require("./proxyActivities");
14
14
  const searchMethods_1 = require("./searchMethods");
15
15
  const random_1 = require("./random");
16
+ const uuid4_1 = require("./uuid4");
16
17
  const signal_1 = require("./signal");
17
18
  const hook_1 = require("./hook");
18
- const interrupt_1 = require("./interrupt");
19
+ const terminate_1 = require("./terminate");
19
20
  const interruption_1 = require("./interruption");
20
21
  const all_1 = require("./all");
21
- const sleepFor_1 = require("./sleepFor");
22
- const waitFor_1 = require("./waitFor");
22
+ const sleep_1 = require("./sleep");
23
+ const condition_1 = require("./condition");
24
+ const continueAsNew_1 = require("./continueAsNew");
25
+ const patched_1 = require("./patched");
26
+ const cancellationScope_1 = require("./cancellationScope");
23
27
  const common_1 = require("./common");
24
28
  const entityMethods_1 = require("./entityMethods");
25
29
  /**
26
- * The workflow-internal API surface, exposed as `Durable.workflow`. Every
27
- * method on this class is designed to be called **inside** a workflow
28
- * functionthey participate in deterministic replay and durable state
29
- * management.
30
+ * In-workflow API surface, exposed as `Durable.workflow`. Every method
31
+ * is called **inside** a workflow function and participates in
32
+ * deterministic replay results are persisted and returned instantly
33
+ * on recovery without re-executing side effects.
30
34
  *
31
- * ## Core Primitives
35
+ * ## Primitives
32
36
  *
33
37
  * | Method | Purpose |
34
38
  * |--------|---------|
35
- * | {@link proxyActivities} | Create durable activity proxies with retry |
36
- * | {@link sleepFor} | Durable, crash-safe sleep |
37
- * | {@link waitFor} | Pause until a signal is received |
38
- * | {@link signal} | Send data to a waiting workflow |
39
- * | {@link execChild} | Spawn and await a child workflow |
40
- * | {@link startChild} | Spawn a child workflow (fire-and-forget) |
41
- * | {@link execHook} | Spawn a hook and await its signal response |
42
- * | {@link execHookBatch} | Spawn multiple hooks in parallel |
43
- * | {@link hook} | Low-level hook spawning |
44
- * | {@link interrupt} | Terminate a running workflow |
45
- *
46
- * ## Data & Observability
47
- *
48
- * | Method | Purpose |
49
- * |--------|---------|
50
- * | {@link search} | Read/write flat HASH key-value data |
51
- * | {@link enrich} | One-shot HASH enrichment |
52
- * | {@link entity} | Structured JSONB document storage |
53
- * | {@link emit} | Publish events to the event bus |
54
- * | {@link trace} | Emit OpenTelemetry trace spans |
39
+ * | {@link proxyActivities} | Execute activities with automatic retry |
40
+ * | {@link sleep} | Durable timer (survives restarts) |
41
+ * | {@link condition} | Pause until a named signal arrives (optional timeout) |
42
+ * | {@link signal} | Deliver data to a waiting `condition` |
43
+ * | {@link executeChild} | Spawn a child workflow and await its result |
44
+ * | {@link startChild} | Fire-and-forget child workflow |
45
+ * | {@link continueAsNew} | Restart with new args (resets history) |
46
+ * | {@link patched} / {@link deprecatePatch} | Safe versioning for in-flight code changes |
47
+ * | {@link CancellationScope} | Shield cleanup code from cancellation |
48
+ * | {@link isCancellation} | Detect `CancelledFailure` errors |
55
49
  *
56
50
  * ## Utilities
57
51
  *
58
52
  * | Method | Purpose |
59
53
  * |--------|---------|
60
- * | {@link getContext} | Access workflow ID, namespace, replay state |
54
+ * | {@link workflowInfo} | Access workflow ID, namespace, replay state |
61
55
  * | {@link random} | Deterministic pseudo-random numbers |
56
+ * | {@link uuid4} | Deterministic UUID v4 generation |
62
57
  * | {@link all} | Workflow-safe `Promise.all` |
63
- * | {@link didInterrupt} | Type guard for engine control-flow errors |
58
+ * | {@link didInterrupt} | Detect engine control-flow errors |
64
59
  *
65
60
  * ## Example
66
61
  *
@@ -69,26 +64,20 @@ const entityMethods_1 = require("./entityMethods");
69
64
  * import * as activities from './activities';
70
65
  *
71
66
  * export async function orderWorkflow(orderId: string): Promise<string> {
72
- * // Proxy activities for durable execution
73
67
  * const { validateOrder, processPayment, sendReceipt } =
74
68
  * Durable.workflow.proxyActivities<typeof activities>({
75
69
  * activities,
76
- * retryPolicy: { maximumAttempts: 3 },
70
+ * retry: { maximumAttempts: 3 },
77
71
  * });
78
72
  *
79
73
  * await validateOrder(orderId);
80
- *
81
- * // Durable sleep (survives restarts)
82
- * await Durable.workflow.sleepFor('5 seconds');
83
- *
74
+ * await Durable.workflow.sleep('5 seconds');
84
75
  * const receipt = await processPayment(orderId);
85
76
  *
86
- * // Store searchable metadata
87
- * await Durable.workflow.enrich({ orderId, status: 'paid' });
88
- *
89
- * // Wait for external approval signal
90
- * const approval = await Durable.workflow.waitFor<{ ok: boolean }>('approve');
91
- * if (!approval.ok) return 'cancelled';
77
+ * // Wait for external approval signal (with 1-hour timeout)
78
+ * const approval = await Durable.workflow.condition<{ ok: boolean }>('approve', '1 hour');
79
+ * if (!approval) return 'timed-out';
80
+ * if (!approval.ok) return 'rejected';
92
81
  *
93
82
  * await sendReceipt(orderId, receipt);
94
83
  * return receipt;
@@ -117,26 +106,32 @@ class WorkflowService {
117
106
  });
118
107
  }
119
108
  }
120
- WorkflowService.getContext = context_1.getContext;
109
+ WorkflowService.workflowInfo = workflowInfo_1.workflowInfo;
121
110
  WorkflowService.didRun = didRun_1.didRun;
122
111
  WorkflowService.isSideEffectAllowed = isSideEffectAllowed_1.isSideEffectAllowed;
123
112
  WorkflowService.trace = trace_1.trace;
124
113
  WorkflowService.enrich = enrich_1.enrich;
125
114
  WorkflowService.emit = emit_1.emit;
126
- WorkflowService.execChild = execChild_1.execChild;
127
- WorkflowService.executeChild = execChild_1.executeChild;
128
- WorkflowService.startChild = execChild_1.startChild;
115
+ WorkflowService.executeChild = executeChild_1.executeChild;
116
+ WorkflowService.startChild = executeChild_1.startChild;
129
117
  WorkflowService.execHook = execHook_1.execHook;
130
118
  WorkflowService.execHookBatch = execHookBatch_1.execHookBatch;
131
119
  WorkflowService.proxyActivities = proxyActivities_1.proxyActivities;
132
120
  WorkflowService.search = searchMethods_1.search;
133
121
  WorkflowService.entity = entityMethods_1.entity;
134
122
  WorkflowService.random = random_1.random;
123
+ WorkflowService.uuid4 = uuid4_1.uuid4;
135
124
  WorkflowService.signal = signal_1.signal;
136
125
  WorkflowService.hook = hook_1.hook;
137
126
  WorkflowService.didInterrupt = interruption_1.didInterrupt;
138
- WorkflowService.interrupt = interrupt_1.interrupt;
127
+ WorkflowService.terminate = terminate_1.terminate;
139
128
  WorkflowService.all = all_1.all;
140
- WorkflowService.sleepFor = sleepFor_1.sleepFor;
141
- WorkflowService.waitFor = waitFor_1.waitFor;
129
+ WorkflowService.sleep = sleep_1.sleep;
130
+ WorkflowService.condition = condition_1.condition;
131
+ WorkflowService.continueAsNew = continueAsNew_1.continueAsNew;
132
+ WorkflowService.patched = patched_1.patched;
133
+ WorkflowService.deprecatePatch = patched_1.deprecatePatch;
134
+ WorkflowService.CancellationScope = cancellationScope_1.CancellationScope;
135
+ WorkflowService.CancelledFailure = cancellationScope_1.CancelledFailure;
136
+ WorkflowService.isCancellation = cancellationScope_1.isCancellation;
142
137
  exports.WorkflowService = WorkflowService;
@@ -3,8 +3,8 @@
3
3
  * control-flow signal rather than a genuine application error.
4
4
  *
5
5
  * Durable uses thrown errors internally to suspend workflow execution
6
- * for durable operations like `sleepFor`, `waitFor`, `proxyActivities`,
7
- * and `execChild`. These errors must be re-thrown (not swallowed) so
6
+ * for durable operations like `sleep`, `condition`, `proxyActivities`,
7
+ * and `executeChild`. These errors must be re-thrown (not swallowed) so
8
8
  * the engine can persist state and schedule the next step.
9
9
  *
10
10
  * **Always use `didInterrupt` in `catch` blocks inside workflow
@@ -12,9 +12,10 @@
12
12
  *
13
13
  * ## Recognized Error Types
14
14
  *
15
- * `DurableChildError`, `DurableFatalError`, `DurableMaxedError`,
16
- * `DurableProxyError`, `DurableRetryError`, `DurableSleepError`,
17
- * `DurableTimeoutError`, `DurableWaitForError`, `DurableWaitForAllError`
15
+ * `DurableChildError`, `DurableContinueAsNewError`, `DurableFatalError`,
16
+ * `DurableMaxedError`, `DurableProxyError`, `DurableRetryError`,
17
+ * `DurableSleepError`, `DurableTimeoutError`, `DurableWaitForError`,
18
+ * `DurableWaitForAllError`, `CancelledFailure`
18
19
  *
19
20
  * ## Examples
20
21
  *
@@ -39,7 +40,7 @@
39
40
  *
40
41
  * ```typescript
41
42
  * // Common pattern in interceptors
42
- * const interceptor: WorkflowInterceptor = {
43
+ * const interceptor: WorkflowInboundCallsInterceptor = {
43
44
  * async execute(ctx, next) {
44
45
  * try {
45
46
  * return await next();
@@ -2,13 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.didInterrupt = void 0;
4
4
  const errors_1 = require("../../../modules/errors");
5
+ const cancellationScope_1 = require("./cancellationScope");
5
6
  /**
6
7
  * Type guard that returns `true` if an error is a Durable engine
7
8
  * control-flow signal rather than a genuine application error.
8
9
  *
9
10
  * Durable uses thrown errors internally to suspend workflow execution
10
- * for durable operations like `sleepFor`, `waitFor`, `proxyActivities`,
11
- * and `execChild`. These errors must be re-thrown (not swallowed) so
11
+ * for durable operations like `sleep`, `condition`, `proxyActivities`,
12
+ * and `executeChild`. These errors must be re-thrown (not swallowed) so
12
13
  * the engine can persist state and schedule the next step.
13
14
  *
14
15
  * **Always use `didInterrupt` in `catch` blocks inside workflow
@@ -16,9 +17,10 @@ const errors_1 = require("../../../modules/errors");
16
17
  *
17
18
  * ## Recognized Error Types
18
19
  *
19
- * `DurableChildError`, `DurableFatalError`, `DurableMaxedError`,
20
- * `DurableProxyError`, `DurableRetryError`, `DurableSleepError`,
21
- * `DurableTimeoutError`, `DurableWaitForError`, `DurableWaitForAllError`
20
+ * `DurableChildError`, `DurableContinueAsNewError`, `DurableFatalError`,
21
+ * `DurableMaxedError`, `DurableProxyError`, `DurableRetryError`,
22
+ * `DurableSleepError`, `DurableTimeoutError`, `DurableWaitForError`,
23
+ * `DurableWaitForAllError`, `CancelledFailure`
22
24
  *
23
25
  * ## Examples
24
26
  *
@@ -43,7 +45,7 @@ const errors_1 = require("../../../modules/errors");
43
45
  *
44
46
  * ```typescript
45
47
  * // Common pattern in interceptors
46
- * const interceptor: WorkflowInterceptor = {
48
+ * const interceptor: WorkflowInboundCallsInterceptor = {
47
49
  * async execute(ctx, next) {
48
50
  * try {
49
51
  * return await next();
@@ -64,6 +66,7 @@ const errors_1 = require("../../../modules/errors");
64
66
  */
65
67
  function didInterrupt(error) {
66
68
  return (error instanceof errors_1.DurableChildError ||
69
+ error instanceof errors_1.DurableContinueAsNewError ||
67
70
  error instanceof errors_1.DurableFatalError ||
68
71
  error instanceof errors_1.DurableMaxedError ||
69
72
  error instanceof errors_1.DurableProxyError ||
@@ -71,6 +74,7 @@ function didInterrupt(error) {
71
74
  error instanceof errors_1.DurableSleepError ||
72
75
  error instanceof errors_1.DurableTimeoutError ||
73
76
  error instanceof errors_1.DurableWaitForError ||
74
- error instanceof errors_1.DurableWaitForAllError);
77
+ error instanceof errors_1.DurableWaitForAllError ||
78
+ error instanceof cancellationScope_1.CancelledFailure);
75
79
  }
76
80
  exports.didInterrupt = didInterrupt;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Enables safe code changes to running workflows by branching on a named
3
+ * change marker. On first execution of a new workflow, `patched` records
4
+ * the marker and returns `true` — the workflow takes the new code path.
5
+ * On replay of a workflow that was started **before** the patch existed,
6
+ * no marker is found and `patched` returns `false` — the old code path
7
+ * is followed.
8
+ *
9
+ * Markers are accumulated in the workflow context and written to the job
10
+ * hash by the engine (via the YAML schema's `job.maps`) when the worker
11
+ * responds — no direct hash writes from the worker.
12
+ *
13
+ * `patched` does **not** increment the execution counter, so it can be
14
+ * inserted into existing workflow code without shifting the replay
15
+ * positions of other durable operations.
16
+ *
17
+ * ## Lifecycle
18
+ *
19
+ * 1. **Add the patch:** wrap the new behavior with `if (await patched('id'))`.
20
+ * Keep the old behavior in the `else` branch.
21
+ * 2. **Wait for drain:** once all workflows started before the patch have
22
+ * completed, the `else` branch is dead code.
23
+ * 3. **Deprecate:** replace `patched` with `deprecatePatch` and remove the
24
+ * `else` branch.
25
+ * 4. **Clean up:** remove both `deprecatePatch` and the `if` wrapper,
26
+ * leaving only the new code.
27
+ *
28
+ * ## Examples
29
+ *
30
+ * ```typescript
31
+ * import { Durable } from '@hotmeshio/hotmesh';
32
+ *
33
+ * export async function orderWorkflow(orderId: string): Promise<string> {
34
+ * const acts = Durable.workflow.proxyActivities<typeof activities>({
35
+ * activities,
36
+ * retry: { maximumAttempts: 3 },
37
+ * });
38
+ *
39
+ * if (await Durable.workflow.patched('v2-validation')) {
40
+ * // New path: stricter validation
41
+ * await acts.validateOrderV2(orderId);
42
+ * } else {
43
+ * // Old path: legacy validation (for in-flight workflows)
44
+ * await acts.validateOrder(orderId);
45
+ * }
46
+ *
47
+ * return await acts.processOrder(orderId);
48
+ * }
49
+ * ```
50
+ *
51
+ * @param {string} changeId - A unique, stable identifier for this code change.
52
+ * Must not be reused across different changes.
53
+ * @returns {Promise<boolean>} `true` for new workflows (take new path),
54
+ * `false` for pre-patch workflows being replayed (take old path).
55
+ */
56
+ export declare function patched(changeId: string): Promise<boolean>;
57
+ /**
58
+ * Declares that all workflows started before a given patch have drained
59
+ * and the old code path can be removed. This is a **no-op** at runtime —
60
+ * it exists purely as a migration signal in source code.
61
+ *
62
+ * ## Migration Steps
63
+ *
64
+ * 1. Replace `if (await patched('id')) { new } else { old }` with
65
+ * `deprecatePatch('id'); new`.
66
+ * 2. Deploy and verify.
67
+ * 3. In a subsequent release, remove both `deprecatePatch('id')` and
68
+ * the surrounding wrapper, leaving only the new code.
69
+ *
70
+ * @param {string} _changeId - The change ID being deprecated (unused at runtime).
71
+ */
72
+ export declare function deprecatePatch(_changeId: string): void;
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deprecatePatch = exports.patched = void 0;
4
+ const common_1 = require("./common");
5
+ /**
6
+ * Enables safe code changes to running workflows by branching on a named
7
+ * change marker. On first execution of a new workflow, `patched` records
8
+ * the marker and returns `true` — the workflow takes the new code path.
9
+ * On replay of a workflow that was started **before** the patch existed,
10
+ * no marker is found and `patched` returns `false` — the old code path
11
+ * is followed.
12
+ *
13
+ * Markers are accumulated in the workflow context and written to the job
14
+ * hash by the engine (via the YAML schema's `job.maps`) when the worker
15
+ * responds — no direct hash writes from the worker.
16
+ *
17
+ * `patched` does **not** increment the execution counter, so it can be
18
+ * inserted into existing workflow code without shifting the replay
19
+ * positions of other durable operations.
20
+ *
21
+ * ## Lifecycle
22
+ *
23
+ * 1. **Add the patch:** wrap the new behavior with `if (await patched('id'))`.
24
+ * Keep the old behavior in the `else` branch.
25
+ * 2. **Wait for drain:** once all workflows started before the patch have
26
+ * completed, the `else` branch is dead code.
27
+ * 3. **Deprecate:** replace `patched` with `deprecatePatch` and remove the
28
+ * `else` branch.
29
+ * 4. **Clean up:** remove both `deprecatePatch` and the `if` wrapper,
30
+ * leaving only the new code.
31
+ *
32
+ * ## Examples
33
+ *
34
+ * ```typescript
35
+ * import { Durable } from '@hotmeshio/hotmesh';
36
+ *
37
+ * export async function orderWorkflow(orderId: string): Promise<string> {
38
+ * const acts = Durable.workflow.proxyActivities<typeof activities>({
39
+ * activities,
40
+ * retry: { maximumAttempts: 3 },
41
+ * });
42
+ *
43
+ * if (await Durable.workflow.patched('v2-validation')) {
44
+ * // New path: stricter validation
45
+ * await acts.validateOrderV2(orderId);
46
+ * } else {
47
+ * // Old path: legacy validation (for in-flight workflows)
48
+ * await acts.validateOrder(orderId);
49
+ * }
50
+ *
51
+ * return await acts.processOrder(orderId);
52
+ * }
53
+ * ```
54
+ *
55
+ * @param {string} changeId - A unique, stable identifier for this code change.
56
+ * Must not be reused across different changes.
57
+ * @returns {Promise<boolean>} `true` for new workflows (take new path),
58
+ * `false` for pre-patch workflows being replayed (take old path).
59
+ */
60
+ async function patched(changeId) {
61
+ const store = common_1.asyncLocalStorage.getStore();
62
+ const replay = store.get('replay');
63
+ const workflowDimension = store.get('workflowDimension') ?? '';
64
+ const patchKey = `-patch${workflowDimension}-${changeId}-`;
65
+ // Marker exists from a previous execution — take new path
66
+ if (patchKey in replay) {
67
+ return true;
68
+ }
69
+ // Marker not found. Distinguish first execution from pre-patch replay
70
+ // by checking for non-patch replay entries. On first execution, no
71
+ // durable operations have completed yet, so only patch markers (from
72
+ // earlier patched() calls in this same execution) can exist.
73
+ const patchPrefix = `-patch${workflowDimension}-`;
74
+ const hasNonPatchEntries = Object.keys(replay).some((key) => !key.startsWith(patchPrefix));
75
+ if (hasNonPatchEntries) {
76
+ // Pre-patch workflow: replay has entries from prior operations but
77
+ // no marker for this change — follow the old code path
78
+ return false;
79
+ }
80
+ // First execution of a new workflow: accumulate the marker in context.
81
+ // The engine writes it to the job hash via the YAML schema's job.maps
82
+ // when the worker responds (for any response code).
83
+ const patchMarkers = store.get('patchMarkers');
84
+ patchMarkers[patchKey] = common_1.SerializerService.toString(true);
85
+ // Update in-memory replay so subsequent patched() calls in this
86
+ // execution see the marker without waiting for the engine round-trip
87
+ replay[patchKey] = patchMarkers[patchKey];
88
+ return true;
89
+ }
90
+ exports.patched = patched;
91
+ /**
92
+ * Declares that all workflows started before a given patch have drained
93
+ * and the old code path can be removed. This is a **no-op** at runtime —
94
+ * it exists purely as a migration signal in source code.
95
+ *
96
+ * ## Migration Steps
97
+ *
98
+ * 1. Replace `if (await patched('id')) { new } else { old }` with
99
+ * `deprecatePatch('id'); new`.
100
+ * 2. Deploy and verify.
101
+ * 3. In a subsequent release, remove both `deprecatePatch('id')` and
102
+ * the surrounding wrapper, leaving only the new code.
103
+ *
104
+ * @param {string} _changeId - The change ID being deprecated (unused at runtime).
105
+ */
106
+ function deprecatePatch(_changeId) {
107
+ // No-op: all pre-patch workflows have completed.
108
+ // Safe to remove the old code path.
109
+ }
110
+ exports.deprecatePatch = deprecatePatch;
@@ -1,10 +1,10 @@
1
1
  import { ActivityConfig, ProxyType, DurableProxyErrorType } from './common';
2
- import { getContext } from './context';
2
+ import { workflowInfo } from './workflowInfo';
3
3
  /**
4
4
  * Constructs payload for spawning a proxyActivity job.
5
5
  * @private
6
6
  */
7
- declare function getProxyInterruptPayload(context: ReturnType<typeof getContext>, activityName: string, execIndex: number, args: any[], options?: ActivityConfig): DurableProxyErrorType;
7
+ declare function getProxyInterruptPayload(context: ReturnType<typeof workflowInfo>, activityName: string, execIndex: number, args: any[], options?: ActivityConfig): DurableProxyErrorType;
8
8
  /**
9
9
  * Wraps a single activity in a proxy, orchestrating its execution and replay.
10
10
  * @private
@@ -47,7 +47,7 @@ declare function wrapActivity<T>(activityName: string, options?: ActivityConfig)
47
47
  * const { validateOrder, chargePayment, sendConfirmation } =
48
48
  * Durable.workflow.proxyActivities<typeof activities>({
49
49
  * activities,
50
- * retryPolicy: {
50
+ * retry: {
51
51
  * maximumAttempts: 3,
52
52
  * backoffCoefficient: 2,
53
53
  * maximumInterval: '30s',
@@ -72,7 +72,7 @@ declare function wrapActivity<T>(activityName: string, options?: ActivityConfig)
72
72
  * const { refundPayment } =
73
73
  * Durable.workflow.proxyActivities<PaymentActivities>({
74
74
  * taskQueue: 'payments',
75
- * retryPolicy: { maximumAttempts: 5 },
75
+ * retry: { maximumAttempts: 5 },
76
76
  * });
77
77
  *
78
78
  * await refundPayment(txId);
@@ -81,13 +81,13 @@ declare function wrapActivity<T>(activityName: string, options?: ActivityConfig)
81
81
  *
82
82
  * ```typescript
83
83
  * // Interceptor with shared activity pool
84
- * const auditInterceptor: WorkflowInterceptor = {
84
+ * const auditInterceptor: WorkflowInboundCallsInterceptor = {
85
85
  * async execute(ctx, next) {
86
86
  * const { auditLog } = Durable.workflow.proxyActivities<{
87
87
  * auditLog: (id: string, action: string) => Promise<void>;
88
88
  * }>({
89
89
  * taskQueue: 'shared-audit',
90
- * retryPolicy: { maximumAttempts: 3 },
90
+ * retry: { maximumAttempts: 3 },
91
91
  * });
92
92
  *
93
93
  * await auditLog(ctx.get('workflowId'), 'started');
@@ -102,7 +102,7 @@ declare function wrapActivity<T>(activityName: string, options?: ActivityConfig)
102
102
  * // Graceful error handling (no throw)
103
103
  * const { riskyOperation } = Durable.workflow.proxyActivities<typeof activities>({
104
104
  * activities,
105
- * retryPolicy: { maximumAttempts: 1, throwOnError: false },
105
+ * retry: { maximumAttempts: 1, throwOnError: false },
106
106
  * });
107
107
  *
108
108
  * const result = await riskyOperation();
@@ -2,7 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getProxyInterruptPayload = exports.wrapActivity = exports.proxyActivities = void 0;
4
4
  const common_1 = require("./common");
5
- const context_1 = require("./context");
5
+ const cancellationScope_1 = require("./cancellationScope");
6
+ const workflowInfo_1 = require("./workflowInfo");
6
7
  const didRun_1 = require("./didRun");
7
8
  /**
8
9
  * Constructs payload for spawning a proxyActivity job.
@@ -16,11 +17,20 @@ function getProxyInterruptPayload(context, activityName, execIndex, args, option
16
17
  : `${taskQueue}-activity`;
17
18
  const activityJobId = `-${workflowId}-$${activityName}${workflowDimension}-${execIndex}`;
18
19
  let maximumInterval;
19
- if (options?.retryPolicy?.maximumInterval) {
20
- maximumInterval = (0, common_1.s)(options.retryPolicy.maximumInterval);
20
+ if (options?.retry?.maximumInterval) {
21
+ maximumInterval = (0, common_1.s)(options.retry.maximumInterval);
22
+ }
23
+ let initialInterval;
24
+ if (options?.retry?.initialInterval) {
25
+ initialInterval = (0, common_1.s)(options.retry.initialInterval);
26
+ }
27
+ let startToCloseTimeout;
28
+ if (options?.startToCloseTimeout) {
29
+ startToCloseTimeout = (0, common_1.s)(options.startToCloseTimeout);
21
30
  }
22
31
  return {
23
32
  arguments: args,
33
+ headers: options?.headers ?? undefined,
24
34
  workflowDimension,
25
35
  index: execIndex,
26
36
  originJobId: originJobId || workflowId,
@@ -29,9 +39,11 @@ function getProxyInterruptPayload(context, activityName, execIndex, args, option
29
39
  workflowTopic: activityTopic,
30
40
  activityName,
31
41
  expire: options?.expire ?? expire,
32
- backoffCoefficient: options?.retryPolicy?.backoffCoefficient ?? undefined,
33
- maximumAttempts: options?.retryPolicy?.maximumAttempts ?? undefined,
42
+ backoffCoefficient: options?.retry?.backoffCoefficient ?? undefined,
43
+ initialInterval: initialInterval ?? undefined,
44
+ maximumAttempts: options?.retry?.maximumAttempts ?? undefined,
34
45
  maximumInterval: maximumInterval ?? undefined,
46
+ startToCloseTimeout: startToCloseTimeout ?? undefined,
35
47
  };
36
48
  }
37
49
  exports.getProxyInterruptPayload = getProxyInterruptPayload;
@@ -43,7 +55,9 @@ function wrapActivity(activityName, options) {
43
55
  return async function (...args) {
44
56
  // Increment counter first for deterministic replay ordering
45
57
  const [didRunAlready, execIndex, result] = await (0, didRun_1.didRun)('proxy');
46
- const context = (0, context_1.getContext)();
58
+ // Check cancellation AFTER counter increment to preserve replay positions
59
+ (0, cancellationScope_1.checkCancellation)();
60
+ const context = (0, workflowInfo_1.workflowInfo)();
47
61
  const { interruptionRegistry } = context;
48
62
  // Build activityCtx so interceptors can inspect/modify args
49
63
  const activityCtx = { activityName, args, options };
@@ -52,8 +66,19 @@ function wrapActivity(activityName, options) {
52
66
  // from activityCtx so "before" interceptors can modify them.
53
67
  const coreFunction = async () => {
54
68
  if (didRunAlready) {
69
+ // Emit RETURN span in debug mode
70
+ if (common_1.DurableTelemetryService.isVerbose() && result) {
71
+ const { workflowTrace, workflowSpan } = context;
72
+ if (workflowTrace && workflowSpan && result.ac && result.au) {
73
+ common_1.DurableTelemetryService.emitDurationSpan(workflowTrace, workflowSpan, `RETURN/proxy/${activityName}/${execIndex}`, common_1.DurableTelemetryService.parseTimestamp(result.ac), common_1.DurableTelemetryService.parseTimestamp(result.au), {
74
+ 'durable.operation.type': 'proxy',
75
+ 'durable.activity.name': activityName,
76
+ 'durable.exec.index': execIndex,
77
+ });
78
+ }
79
+ }
55
80
  if (result?.$error) {
56
- if (options?.retryPolicy?.throwOnError !== false) {
81
+ if (activityCtx.options?.retry?.throwOnError !== false) {
57
82
  const code = result.$error.code;
58
83
  const message = result.$error.message;
59
84
  const stack = result.$error.stack;
@@ -74,7 +99,18 @@ function wrapActivity(activityName, options) {
74
99
  }
75
100
  return result.data;
76
101
  }
77
- const interruptionMessage = getProxyInterruptPayload(context, activityName, execIndex, activityCtx.args, options);
102
+ // Emit DISPATCH span in debug mode
103
+ if (common_1.DurableTelemetryService.isVerbose()) {
104
+ const { workflowTrace, workflowSpan } = context;
105
+ if (workflowTrace && workflowSpan) {
106
+ common_1.DurableTelemetryService.emitPointSpan(workflowTrace, workflowSpan, `DISPATCH/proxy/${activityName}/${execIndex}`, {
107
+ 'durable.operation.type': 'proxy',
108
+ 'durable.activity.name': activityName,
109
+ 'durable.exec.index': execIndex,
110
+ });
111
+ }
112
+ }
113
+ const interruptionMessage = getProxyInterruptPayload(context, activityName, execIndex, activityCtx.args, activityCtx.options);
78
114
  interruptionRegistry.push({
79
115
  code: common_1.HMSH_CODE_DURABLE_PROXY,
80
116
  type: 'DurableProxyError',
@@ -86,8 +122,8 @@ function wrapActivity(activityName, options) {
86
122
  // Run through interceptor chain if interceptors exist
87
123
  const store = common_1.asyncLocalStorage.getStore();
88
124
  const interceptorService = store?.get('activityInterceptorService');
89
- if (interceptorService?.activityInterceptors?.length > 0) {
90
- return await interceptorService.executeActivityChain(activityCtx, store, coreFunction);
125
+ if (interceptorService?.outbound?.length > 0) {
126
+ return await interceptorService.executeOutboundChain(activityCtx, store, coreFunction);
91
127
  }
92
128
  return await coreFunction();
93
129
  };
@@ -130,7 +166,7 @@ exports.wrapActivity = wrapActivity;
130
166
  * const { validateOrder, chargePayment, sendConfirmation } =
131
167
  * Durable.workflow.proxyActivities<typeof activities>({
132
168
  * activities,
133
- * retryPolicy: {
169
+ * retry: {
134
170
  * maximumAttempts: 3,
135
171
  * backoffCoefficient: 2,
136
172
  * maximumInterval: '30s',
@@ -155,7 +191,7 @@ exports.wrapActivity = wrapActivity;
155
191
  * const { refundPayment } =
156
192
  * Durable.workflow.proxyActivities<PaymentActivities>({
157
193
  * taskQueue: 'payments',
158
- * retryPolicy: { maximumAttempts: 5 },
194
+ * retry: { maximumAttempts: 5 },
159
195
  * });
160
196
  *
161
197
  * await refundPayment(txId);
@@ -164,13 +200,13 @@ exports.wrapActivity = wrapActivity;
164
200
  *
165
201
  * ```typescript
166
202
  * // Interceptor with shared activity pool
167
- * const auditInterceptor: WorkflowInterceptor = {
203
+ * const auditInterceptor: WorkflowInboundCallsInterceptor = {
168
204
  * async execute(ctx, next) {
169
205
  * const { auditLog } = Durable.workflow.proxyActivities<{
170
206
  * auditLog: (id: string, action: string) => Promise<void>;
171
207
  * }>({
172
208
  * taskQueue: 'shared-audit',
173
- * retryPolicy: { maximumAttempts: 3 },
209
+ * retry: { maximumAttempts: 3 },
174
210
  * });
175
211
  *
176
212
  * await auditLog(ctx.get('workflowId'), 'started');
@@ -185,7 +221,7 @@ exports.wrapActivity = wrapActivity;
185
221
  * // Graceful error handling (no throw)
186
222
  * const { riskyOperation } = Durable.workflow.proxyActivities<typeof activities>({
187
223
  * activities,
188
- * retryPolicy: { maximumAttempts: 1, throwOnError: false },
224
+ * retry: { maximumAttempts: 1, throwOnError: false },
189
225
  * });
190
226
  *
191
227
  * const result = await riskyOperation();
@@ -48,6 +48,13 @@ import { Search } from './common';
48
48
  * }
49
49
  * ```
50
50
  *
51
+ * **Not available with `workerCredentials`.** This method writes directly
52
+ * to the `jobs` and `jobs_attributes` tables, bypassing the SECURITY
53
+ * DEFINER stored procedures that scoped worker roles are restricted to.
54
+ * Workers connecting with `workerCredentials` will receive a permission
55
+ * error. Use `search()` only in workflows running with full database
56
+ * credentials.
57
+ *
51
58
  * @returns {Promise<Search>} A search session scoped to the current workflow job.
52
59
  */
53
60
  export declare function search(): Promise<Search>;