@workflow/core 5.0.0-beta.40 → 5.0.0-beta.41

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 (70) hide show
  1. package/dist/events-consumer.d.ts +127 -6
  2. package/dist/events-consumer.d.ts.map +1 -1
  3. package/dist/events-consumer.js +364 -50
  4. package/dist/private.d.ts +87 -18
  5. package/dist/private.d.ts.map +1 -1
  6. package/dist/private.js +116 -44
  7. package/dist/runtime/constants.d.ts +15 -1
  8. package/dist/runtime/constants.d.ts.map +1 -1
  9. package/dist/runtime/constants.js +22 -3
  10. package/dist/runtime/helpers.d.ts +116 -8
  11. package/dist/runtime/helpers.d.ts.map +1 -1
  12. package/dist/runtime/helpers.js +174 -2
  13. package/dist/runtime/quickjs-assets.generated.d.ts.map +1 -1
  14. package/dist/runtime/quickjs-assets.generated.js +2 -2
  15. package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -1
  16. package/dist/runtime/quickjs-entrypoint.js +13 -5
  17. package/dist/runtime/quickjs-runtime.d.ts +36 -1
  18. package/dist/runtime/quickjs-runtime.d.ts.map +1 -1
  19. package/dist/runtime/quickjs-runtime.js +613 -185
  20. package/dist/runtime/quickjs-serde.d.ts +107 -0
  21. package/dist/runtime/quickjs-serde.d.ts.map +1 -0
  22. package/dist/runtime/quickjs-serde.js +2098 -0
  23. package/dist/runtime/replay-budget.d.ts +5 -14
  24. package/dist/runtime/replay-budget.d.ts.map +1 -1
  25. package/dist/runtime/replay-budget.js +19 -72
  26. package/dist/runtime/resume-hook.d.ts.map +1 -1
  27. package/dist/runtime/resume-hook.js +5 -1
  28. package/dist/runtime/runs.d.ts.map +1 -1
  29. package/dist/runtime/runs.js +3 -4
  30. package/dist/runtime/start.js +2 -7
  31. package/dist/runtime/step-executor.d.ts.map +1 -1
  32. package/dist/runtime/step-executor.js +1 -4
  33. package/dist/runtime/suspension-handler.d.ts +7 -0
  34. package/dist/runtime/suspension-handler.d.ts.map +1 -1
  35. package/dist/runtime/suspension-handler.js +58 -11
  36. package/dist/runtime/world-compatibility.d.ts +15 -0
  37. package/dist/runtime/world-compatibility.d.ts.map +1 -1
  38. package/dist/runtime/world-compatibility.js +25 -5
  39. package/dist/runtime.d.ts.map +1 -1
  40. package/dist/runtime.js +474 -418
  41. package/dist/serialization/codec-devalue-vm.d.ts +7 -0
  42. package/dist/serialization/codec-devalue-vm.d.ts.map +1 -1
  43. package/dist/serialization/codec-devalue-vm.js +12 -1
  44. package/dist/serialization/workflow-vm.d.ts +8 -3
  45. package/dist/serialization/workflow-vm.d.ts.map +1 -1
  46. package/dist/serialization/workflow-vm.js +9 -4
  47. package/dist/step.js +2 -2
  48. package/dist/telemetry/semantic-conventions.d.ts +23 -0
  49. package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
  50. package/dist/telemetry/semantic-conventions.js +18 -1
  51. package/dist/version.d.ts +1 -1
  52. package/dist/version.js +2 -2
  53. package/dist/vm/index.d.ts.map +1 -1
  54. package/dist/vm/index.js +9 -6
  55. package/dist/workflow/abort-controller.d.ts.map +1 -1
  56. package/dist/workflow/abort-controller.js +4 -6
  57. package/dist/workflow/attribute-dispatcher.js +2 -2
  58. package/dist/workflow/hook.js +2 -2
  59. package/dist/workflow/sleep.js +2 -2
  60. package/dist/workflow.d.ts +10 -0
  61. package/dist/workflow.d.ts.map +1 -1
  62. package/dist/workflow.js +60 -19
  63. package/docs/how-it-works/event-sourcing.mdx +11 -3
  64. package/package.json +6 -6
  65. package/dist/correlation-id.d.ts +0 -109
  66. package/dist/correlation-id.d.ts.map +0 -1
  67. package/dist/correlation-id.js +0 -139
  68. package/dist/serialization/vm-bundle-entry.d.ts +0 -12
  69. package/dist/serialization/vm-bundle-entry.d.ts.map +0 -1
  70. package/dist/serialization/vm-bundle-entry.js +0 -58
@@ -6,6 +6,15 @@ import { type Event } from '@workflow/world';
6
6
  * in host). Any subscribe() arriving during this window cancels the check.
7
7
  */
8
8
  export declare const DEFERRED_CHECK_DELAY_MS = 100;
9
+ /**
10
+ * Floor for the deferred-check delay, so a too-low override can't manufacture
11
+ * spurious divergence (each false positive burns a divergence-recovery retry
12
+ * and can escalate to a terminal `CorruptedEventLogError`).
13
+ *
14
+ * Exported so tests needing the shortest legal delay can ask for it instead of
15
+ * hardcoding a number this floor would silently clamp up.
16
+ */
17
+ export declare const MIN_DEFERRED_CHECK_DELAY_MS = 10;
9
18
  export declare enum EventConsumerResult {
10
19
  /**
11
20
  * Callback consumed the event, but should not be removed from the callbacks list
@@ -43,18 +52,72 @@ export interface EventsConsumerOptions {
43
52
  * deserialization delays the resolve() that triggers the next subscribe().
44
53
  */
45
54
  getPromiseQueue: () => Promise<void>;
55
+ /**
56
+ * Whether no data delivery is in flight (`isDeliveryIdle` in private.ts).
57
+ * The unconsumed-event check waits for this before it fires: a delivery in
58
+ * flight means the workflow VM is mid-reaction, and an event it has not
59
+ * claimed yet is an event it has not reached yet.
60
+ *
61
+ * Required rather than defaulting to always-idle: always-idle is exactly the
62
+ * pre-gate behaviour, so a defaulted option would let a construction site opt
63
+ * a whole replay path back out without saying so. Tests that drive a consumer
64
+ * with no orchestrator context pass `() => true` to keep the pre-existing
65
+ * timing, and say so at the call site.
66
+ */
67
+ isDeliveryIdle: () => boolean;
46
68
  }
47
69
  export declare class EventsConsumer {
48
70
  eventIndex: number;
49
71
  readonly events: Event[];
50
72
  readonly callbacks: EventConsumerCallback[];
73
+ /**
74
+ * Events the ordered walk stepped over because nobody claimed them and their
75
+ * type carries no ordering claim. Each keeps the index it held in the log:
76
+ * consumers read {@link eventIndex} at consumption time to order their
77
+ * delivery against the rest of the log, and a late delivery must still make
78
+ * the claim its position gave it.
79
+ *
80
+ * Held in log order, drained in log order, and drained before every offer so
81
+ * a consumer registered after the walk passed the event still receives it.
82
+ */
83
+ private readonly parked;
84
+ /**
85
+ * Correlation ids of the {@link ONE_SHOT_EVENT_TYPES} events consumed so
86
+ * far, so a second resolution for one of them is recognized as unclaimable
87
+ * rather than parked for a consumer that cannot exist.
88
+ */
89
+ private readonly resolved;
51
90
  private onConsumedEvent?;
52
91
  private onUnconsumedEvent;
53
92
  private getPromiseQueue;
93
+ private isDeliveryIdle;
54
94
  private pendingUnconsumedCheck;
55
95
  private pendingUnconsumedTimeout;
56
96
  private unconsumedCheckVersion;
57
97
  constructor(events: Event[], options: EventsConsumerOptions);
98
+ /**
99
+ * The oldest event the walk stepped over that no consumer has claimed yet,
100
+ * if any. Parking is a bet that a consumer will be registered later, so at
101
+ * any point where no consumer ever will be again — the replay finishing is
102
+ * the definitive one — this answers which event the bet lost on.
103
+ */
104
+ get strandedEvent(): Event | undefined;
105
+ /**
106
+ * What the walk is still holding, or `undefined` when it holds nothing.
107
+ *
108
+ * Read at every point a replay stops, including the suspensions that are not
109
+ * settling points, so the held state reaches telemetry. A replay cannot tell
110
+ * a delivery awaiting a later consumer from one no consumer will ever
111
+ * register, so it reports rather than decides: the same `eventId` reported on
112
+ * suspension after suspension of one run is the shape that says the bet
113
+ * parking made is not going to pay off, and that shape is only visible across
114
+ * replays.
115
+ */
116
+ get parkedSummary(): {
117
+ count: number;
118
+ eventId: string;
119
+ eventType: Event['eventType'];
120
+ } | undefined;
58
121
  append(events: Event[]): void;
59
122
  /**
60
123
  * Registers a callback function to be called after an event has been consumed
@@ -70,13 +133,71 @@ export declare class EventsConsumer {
70
133
  private consume;
71
134
  /**
72
135
  * Offer `currentEvent` to each registered callback in turn. Returns true
73
- * when a callback consumed a real (non-null) event and the drain should
74
- * advance to the next event in the same synchronous pass; false otherwise
75
- * (nothing consumed it, or the consumed event was the end-of-events
76
- * sentinel).
136
+ * when a callback consumed it. Does not move {@link eventIndex}: the ordered
137
+ * walk and the parked drain advance differently, so each does its own.
138
+ */
139
+ private offer;
140
+ /**
141
+ * Offer everything parked, oldest first, until a pass claims nothing.
142
+ *
143
+ * Each offer runs with {@link eventIndex} moved back to the position the
144
+ * parked event held in the log, because that is the position its consumer
145
+ * will register a delivery barrier under. Restoring the walk pointer
146
+ * afterwards is what keeps the two pointers from interfering.
147
+ */
148
+ private drainParked;
149
+ /**
150
+ * Step the ordered walk over an event nobody claimed, holding on to it for a
151
+ * later consumer. Returns false when the event's type makes its position a
152
+ * decision record, which is the one case where nobody claiming it means the
153
+ * replay diverged.
154
+ */
155
+ private park;
156
+ private handleEndOfLog;
157
+ private scheduleUnconsumedCheck;
158
+ /**
159
+ * Run `fn` once no data delivery is in flight, polling the way
160
+ * `scheduleWhenIdle` does: let the promise queue drain, re-check a timer
161
+ * tick later, repeat.
162
+ *
163
+ * Without this the check is a bet that every delivery the walk is running
164
+ * ahead of lands inside a fixed window. Consumption is synchronous while the
165
+ * resolution it triggers is not: a step result hydrates in the host, resolves
166
+ * from a detached continuation behind `awaitEarlierDeliveries`, and only then
167
+ * does VM code run far enough to subscribe the next consumer. Replaying a
168
+ * batch of N parallel step results leaves N-1 of them on that detached path
169
+ * with the queue already drained, so the walk sits on the ordered event the
170
+ * VM is about to draw and the window is the only thing standing between a
171
+ * healthy run and `ReplayDivergenceError`.
172
+ *
173
+ * Shortening the window shows that mechanism directly: on identical event logs
174
+ * the local race repro corrupts 34 of 42 runs at a 10ms window and 0 of 114 at
175
+ * the 100ms default. That measures how the bet loses, not that the default
176
+ * loses it, and no measurement of a delivery outrunning 100ms exists either
177
+ * way. So read this as retiring the bet rather than as repairing an observed
178
+ * failure of that number: the delay is a user-settable env override, which
179
+ * leaves the old behaviour one configuration away from losing on any backend.
180
+ *
181
+ * Termination is `hasParkedCommittedDelivery`'s: it counts only deliveries
182
+ * that resolve on their own, so nothing here can gate its own retirement. A
183
+ * genuinely orphaned event has no delivery to wait on and reaches `fn` on the
184
+ * first poll.
185
+ *
186
+ * What the gate gives up: for the ordered events that still reach
187
+ * `onUnconsumedEvent` rather than {@link park}, this stops being the thing
188
+ * that catches a diverged log while a delivery is in flight. The suspension
189
+ * and this check now wake from the same `isDeliveryIdle` edge, and
190
+ * `scheduleWhenIdle` fires on the first timer tick after idle while this waits
191
+ * a further `getDeferredCheckDelayMs()`. So a run with a pending `sleep()`
192
+ * suspends first, and `onWorkflowError` drops the divergence arriving second
193
+ * (its `'suspended'` branch demotes to `'replay'` and surfaces nothing),
194
+ * leaving a later `resume()` to decline into a cold replay. Pre-gate the
195
+ * suspension already won that race whenever the delivery landed inside the
196
+ * fixed window, so what changed is that the outcome stopped depending on
197
+ * timing. Nothing should treat this check as the mechanism that reports
198
+ * divergence on a log the run is still delivering into.
77
199
  */
78
- private consumeOne;
79
- private handleUnconsumed;
200
+ private whenDeliveryIdle;
80
201
  }
81
202
  export {};
82
203
  //# sourceMappingURL=events-consumer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"events-consumer.d.ts","sourceRoot":"","sources":["../src/events-consumer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAa,MAAM,iBAAiB,CAAC;AAGxD;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAmB3C,oBAAY,mBAAmB;IAC7B;;OAEG;IACH,QAAQ,IAAA;IACR;;OAEG;IACH,WAAW,IAAA;IACX;;OAEG;IACH,QAAQ,IAAA;CACT;AAED,KAAK,qBAAqB,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,KAAK,mBAAmB,CAAC;AAE1E,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACzC;;;;;;OAMG;IACH,iBAAiB,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC1C;;;;;OAKG;IACH,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAED,qBAAa,cAAc;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,qBAAqB,EAAE,CAAM;IACjD,OAAO,CAAC,eAAe,CAAC,CAAyB;IACjD,OAAO,CAAC,iBAAiB,CAAyB;IAClD,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,sBAAsB,CAA8B;IAC5D,OAAO,CAAC,wBAAwB,CAA8C;IAC9E,OAAO,CAAC,sBAAsB,CAAK;gBAEvB,MAAM,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,qBAAqB;IAW3D,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI;IAK7B;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,EAAE,qBAAqB;IAgBnC,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,OAAO,CA0Bb;IAEF;;;;;;OAMG;IACH,OAAO,CAAC,UAAU;IAgClB,OAAO,CAAC,gBAAgB;CAqCzB"}
1
+ {"version":3,"file":"events-consumer.d.ts","sourceRoot":"","sources":["../src/events-consumer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAa,MAAM,iBAAiB,CAAC;AAGxD;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAgG9C,oBAAY,mBAAmB;IAC7B;;OAEG;IACH,QAAQ,IAAA;IACR;;OAEG;IACH,WAAW,IAAA;IACX;;OAEG;IACH,QAAQ,IAAA;CACT;AAED,KAAK,qBAAqB,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,KAAK,mBAAmB,CAAC;AAE1E,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACzC;;;;;;OAMG;IACH,iBAAiB,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC1C;;;;;OAKG;IACH,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC;;;;;;;;;;;OAWG;IACH,cAAc,EAAE,MAAM,OAAO,CAAC;CAC/B;AAED,qBAAa,cAAc;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,qBAAqB,EAAE,CAAM;IACjD;;;;;;;;;OASG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyC;IAChE;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,eAAe,CAAC,CAAyB;IACjD,OAAO,CAAC,iBAAiB,CAAyB;IAClD,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,sBAAsB,CAA8B;IAC5D,OAAO,CAAC,wBAAwB,CAA8C;IAC9E,OAAO,CAAC,sBAAsB,CAAK;gBAEvB,MAAM,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,qBAAqB;IAY3D;;;;;OAKG;IACH,IAAI,aAAa,IAAI,KAAK,GAAG,SAAS,CAErC;IAED;;;;;;;;;;OAUG;IACH,IAAI,aAAa,IACb;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,KAAK,CAAC,WAAW,CAAC,CAAA;KAAE,GACjE,SAAS,CAUZ;IAED,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI;IAK7B;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,EAAE,qBAAqB;IAgBnC,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,OAAO,CA4Cb;IAEF;;;;OAIG;IACH,OAAO,CAAC,KAAK;IAmCb;;;;;;;OAOG;IACH,OAAO,CAAC,WAAW;IAyBnB;;;;;OAKG;IACH,OAAO,CAAC,IAAI;IAqBZ,OAAO,CAAC,cAAc;IA2BtB,OAAO,CAAC,uBAAuB;IAqD/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyCG;IACH,OAAO,CAAC,gBAAgB;CA2BzB"}