@dudousxd/nestjs-durable-core 0.51.0 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +198 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +125 -1
- package/dist/index.d.ts +125 -1
- package/dist/index.js +196 -54
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -22,6 +22,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
22
22
|
// src/index.ts
|
|
23
23
|
var index_exports = {};
|
|
24
24
|
__export(index_exports, {
|
|
25
|
+
CONTROL_FLOW_SIGNAL: () => CONTROL_FLOW_SIGNAL,
|
|
25
26
|
CodecStateStore: () => CodecStateStore,
|
|
26
27
|
ContinueAsNew: () => ContinueAsNew,
|
|
27
28
|
DURABLE_OPTIONS: () => DURABLE_OPTIONS,
|
|
@@ -67,6 +68,7 @@ __export(index_exports, {
|
|
|
67
68
|
eventPrefix: () => eventPrefix,
|
|
68
69
|
eventToken: () => eventToken,
|
|
69
70
|
indexWaitersByRun: () => indexWaitersByRun,
|
|
71
|
+
isWorkflowControlFlowSignal: () => isWorkflowControlFlowSignal,
|
|
70
72
|
matchesAttributes: () => matchesAttributes,
|
|
71
73
|
normalizeAttributeRows: () => normalizeAttributeRows,
|
|
72
74
|
parseDuration: () => parseDuration,
|
|
@@ -259,6 +261,13 @@ function currentWorkflowCtx() {
|
|
|
259
261
|
}
|
|
260
262
|
__name(currentWorkflowCtx, "currentWorkflowCtx");
|
|
261
263
|
|
|
264
|
+
// src/control-flow-signal.ts
|
|
265
|
+
var CONTROL_FLOW_SIGNAL = Symbol.for("aviary:durable:control-flow");
|
|
266
|
+
function isWorkflowControlFlowSignal(error) {
|
|
267
|
+
return typeof error === "object" && error !== null && error[CONTROL_FLOW_SIGNAL] === true;
|
|
268
|
+
}
|
|
269
|
+
__name(isWorkflowControlFlowSignal, "isWorkflowControlFlowSignal");
|
|
270
|
+
|
|
262
271
|
// src/errors.ts
|
|
263
272
|
var FatalError = class extends Error {
|
|
264
273
|
static {
|
|
@@ -357,6 +366,8 @@ var WorkflowSuspended = class extends Error {
|
|
|
357
366
|
}
|
|
358
367
|
/** Epoch ms to auto-resume (durable sleep), or undefined when waiting on an external signal. */
|
|
359
368
|
wakeAt;
|
|
369
|
+
/** Marks this as a control-flow signal — see {@link isWorkflowControlFlowSignal}. */
|
|
370
|
+
[CONTROL_FLOW_SIGNAL] = true;
|
|
360
371
|
constructor(wakeAt) {
|
|
361
372
|
super("workflow suspended");
|
|
362
373
|
this.name = "WorkflowSuspended";
|
|
@@ -368,6 +379,8 @@ var ContinueAsNew = class extends Error {
|
|
|
368
379
|
__name(this, "ContinueAsNew");
|
|
369
380
|
}
|
|
370
381
|
input;
|
|
382
|
+
/** Marks this as a control-flow signal — see {@link isWorkflowControlFlowSignal}. */
|
|
383
|
+
[CONTROL_FLOW_SIGNAL] = true;
|
|
371
384
|
constructor(input) {
|
|
372
385
|
super("workflow continued as new"), this.input = input;
|
|
373
386
|
this.name = "ContinueAsNew";
|
|
@@ -940,6 +953,47 @@ var RemoteWorkflowExecutor = class {
|
|
|
940
953
|
}
|
|
941
954
|
};
|
|
942
955
|
|
|
956
|
+
// src/run-waiting.ts
|
|
957
|
+
var WEBHOOK_PREFIX = "wh:";
|
|
958
|
+
var CHILD_PREFIX = "child:";
|
|
959
|
+
var BREAKPOINT_PREFIX = "bp:";
|
|
960
|
+
var EVENT_PREFIX = "event:";
|
|
961
|
+
function classifyWaiterToken(token) {
|
|
962
|
+
if (token.startsWith(WEBHOOK_PREFIX)) return {
|
|
963
|
+
on: "webhook",
|
|
964
|
+
name: token
|
|
965
|
+
};
|
|
966
|
+
if (token.startsWith(BREAKPOINT_PREFIX)) return {
|
|
967
|
+
on: "breakpoint",
|
|
968
|
+
name: "breakpoint"
|
|
969
|
+
};
|
|
970
|
+
if (token.startsWith(CHILD_PREFIX)) return {
|
|
971
|
+
on: "child",
|
|
972
|
+
name: token.slice(CHILD_PREFIX.length)
|
|
973
|
+
};
|
|
974
|
+
if (token.startsWith(EVENT_PREFIX)) return {
|
|
975
|
+
on: "signal",
|
|
976
|
+
name: eventNameOf(token)
|
|
977
|
+
};
|
|
978
|
+
return {
|
|
979
|
+
on: "signal",
|
|
980
|
+
name: token
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
__name(classifyWaiterToken, "classifyWaiterToken");
|
|
984
|
+
function resolveRunWaiting(run, waiterByRun) {
|
|
985
|
+
if (run.status !== "suspended") return void 0;
|
|
986
|
+
const waiter = waiterByRun.get(run.id);
|
|
987
|
+
return waiter ? classifyWaiterToken(waiter.token) : void 0;
|
|
988
|
+
}
|
|
989
|
+
__name(resolveRunWaiting, "resolveRunWaiting");
|
|
990
|
+
function indexWaitersByRun(waiters) {
|
|
991
|
+
const byRun = /* @__PURE__ */ new Map();
|
|
992
|
+
for (const w of waiters) if (!byRun.has(w.runId)) byRun.set(w.runId, w);
|
|
993
|
+
return byRun;
|
|
994
|
+
}
|
|
995
|
+
__name(indexWaitersByRun, "indexWaitersByRun");
|
|
996
|
+
|
|
943
997
|
// src/singleton-gate.ts
|
|
944
998
|
var SINGLETON_RETRY_MS = 1e3;
|
|
945
999
|
var SINGLETON_RETRY_JITTER_MS = 250;
|
|
@@ -1395,6 +1449,15 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
1395
1449
|
runId,
|
|
1396
1450
|
seq: current
|
|
1397
1451
|
});
|
|
1452
|
+
const lateBuffered2 = await consumeBuffered(token, current);
|
|
1453
|
+
if (lateBuffered2) {
|
|
1454
|
+
await store.removeSignalWaiter({
|
|
1455
|
+
token,
|
|
1456
|
+
runId,
|
|
1457
|
+
seq: current
|
|
1458
|
+
});
|
|
1459
|
+
return lateBuffered2.value;
|
|
1460
|
+
}
|
|
1398
1461
|
throw new WorkflowSuspended();
|
|
1399
1462
|
}
|
|
1400
1463
|
const timeoutMs = opts.timeoutMs;
|
|
@@ -1406,7 +1469,11 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
1406
1469
|
const buffered = await consumeBuffered(token, waitSeq);
|
|
1407
1470
|
if (buffered) return buffered.value;
|
|
1408
1471
|
if (host.clock() >= deadline) {
|
|
1409
|
-
await store.
|
|
1472
|
+
await store.removeSignalWaiter({
|
|
1473
|
+
token,
|
|
1474
|
+
runId,
|
|
1475
|
+
seq: waitSeq
|
|
1476
|
+
}).catch(() => void 0);
|
|
1410
1477
|
throw new SignalTimeoutError(token, timeoutMs);
|
|
1411
1478
|
}
|
|
1412
1479
|
await store.putSignalWaiter({
|
|
@@ -1414,6 +1481,15 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
1414
1481
|
runId,
|
|
1415
1482
|
seq: waitSeq
|
|
1416
1483
|
});
|
|
1484
|
+
const lateBuffered = await consumeBuffered(token, waitSeq);
|
|
1485
|
+
if (lateBuffered) {
|
|
1486
|
+
await store.removeSignalWaiter({
|
|
1487
|
+
token,
|
|
1488
|
+
runId,
|
|
1489
|
+
seq: waitSeq
|
|
1490
|
+
});
|
|
1491
|
+
return lateBuffered.value;
|
|
1492
|
+
}
|
|
1417
1493
|
throw new WorkflowSuspended(deadline);
|
|
1418
1494
|
}, "waitForSignal");
|
|
1419
1495
|
const waitForEvent = /* @__PURE__ */ __name(async (name, opts) => {
|
|
@@ -1437,7 +1513,11 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
1437
1513
|
const waited = await readCheckpoint(waitSeq);
|
|
1438
1514
|
if (waited && waited.status === "completed") return waited.output;
|
|
1439
1515
|
if (host.clock() >= deadline) {
|
|
1440
|
-
await store.
|
|
1516
|
+
await store.removeSignalWaiter({
|
|
1517
|
+
token,
|
|
1518
|
+
runId,
|
|
1519
|
+
seq: waitSeq
|
|
1520
|
+
}).catch(() => void 0);
|
|
1441
1521
|
throw new SignalTimeoutError(`event:${name}`, timeoutMs);
|
|
1442
1522
|
}
|
|
1443
1523
|
await store.putSignalWaiter({
|
|
@@ -2583,9 +2663,46 @@ var WorkflowEngine = class {
|
|
|
2583
2663
|
/**
|
|
2584
2664
|
* Resume every suspended run whose durable timer is due. Call periodically (a poller) and on
|
|
2585
2665
|
* boot. A run still not due re-suspends cheaply without running new work.
|
|
2666
|
+
*
|
|
2667
|
+
* Piggy-backs the signal-waiter reconcile safety net (see {@link reconcileSignalWaiter}): a crash
|
|
2668
|
+
* between the waiter/buffer pairing ops on EITHER side (this run's own `putSignalWaiter` →
|
|
2669
|
+
* `takeBufferedSignal`, or a signaler's `takeSignalWaiter` → `bufferSignal` → re-check — see
|
|
2670
|
+
* `signal`'s interleaving proof) can leave both rows stranded with nothing left to pair them: the
|
|
2671
|
+
* waiter's turn already suspended, the signaler that buffered it already returned. Event-wait
|
|
2672
|
+
* suspends already carry a `reconcileMs` fallback `wakeAt` (see {@link reconcileWakeAt}) precisely so
|
|
2673
|
+
* they show up HERE — that's what makes this due-timer pass the natural place for the sweep. One
|
|
2674
|
+
* bulk waiter scan, filtered to just this tick's batch, keeps it cheap regardless of store size.
|
|
2586
2675
|
*/
|
|
2587
2676
|
async resumeDueTimers(nowMs = this.clock()) {
|
|
2588
|
-
|
|
2677
|
+
const due = await this.store.listDueTimers(nowMs, this.namespace);
|
|
2678
|
+
if (due.length === 0) return [];
|
|
2679
|
+
const waiterByRun = indexWaitersByRun(await this.store.listSignalWaiters(""));
|
|
2680
|
+
return this.resumeLeased(due, nowMs, (run) => this.reconcileSignalWaiter(run, waiterByRun.get(run.id)));
|
|
2681
|
+
}
|
|
2682
|
+
/**
|
|
2683
|
+
* The reconcile safety net's per-run check (see {@link resumeDueTimers}): if this suspended run has
|
|
2684
|
+
* a registered signal waiter AND its token already has a buffered payload, pair and deliver them
|
|
2685
|
+
* directly instead of falling through to a full replay. Event/child/breakpoint waiter tokens are
|
|
2686
|
+
* never buffered (`publishEvent` doesn't buffer, and a child/breakpoint notifies via `signal` only
|
|
2687
|
+
* once its counterpart is already registered) — so `takeBufferedSignal` on those is a guaranteed
|
|
2688
|
+
* miss, and this is naturally signal-only without needing to classify the token.
|
|
2689
|
+
*
|
|
2690
|
+
* Returns `undefined` (not settled — `resumeLeased` proceeds with its normal `resume`) when there's
|
|
2691
|
+
* no waiter or no buffered hit. Deliberately never returns `null`: a delivered signal always resumes
|
|
2692
|
+
* via {@link deliverSignal}, and even a `NamespaceMismatch` there is reported as a real (non-nullish)
|
|
2693
|
+
* result — returning `null` would read as "not settled" to `resumeLeased`'s `??` fallback and
|
|
2694
|
+
* trigger a second, redundant `resume` call on the same run.
|
|
2695
|
+
*/
|
|
2696
|
+
async reconcileSignalWaiter(run, waiter) {
|
|
2697
|
+
if (!waiter) return void 0;
|
|
2698
|
+
const buffered = await this.store.takeBufferedSignal(waiter.token);
|
|
2699
|
+
if (!buffered) return void 0;
|
|
2700
|
+
await this.store.removeSignalWaiter(waiter);
|
|
2701
|
+
const settled = await this.deliverSignal(waiter, buffered.payload);
|
|
2702
|
+
return settled ?? {
|
|
2703
|
+
runId: run.id,
|
|
2704
|
+
status: run.status
|
|
2705
|
+
};
|
|
2589
2706
|
}
|
|
2590
2707
|
/**
|
|
2591
2708
|
* Lease and execute one run by id — the worker side of dispatch. Acquires the recovery lease (so
|
|
@@ -2803,16 +2920,17 @@ var WorkflowEngine = class {
|
|
|
2803
2920
|
}
|
|
2804
2921
|
return touched;
|
|
2805
2922
|
}
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2923
|
+
/**
|
|
2924
|
+
* Deliver a signal to an already-known waiter: write its resolving `signal:<token>` checkpoint and
|
|
2925
|
+
* resume the run. Shared by {@link signal}'s direct hit, its post-buffer re-check reclaim, and the
|
|
2926
|
+
* due-timer reconcile sweep ({@link reconcileSignalWaiter}) — all three resolve a waiter the exact
|
|
2927
|
+
* same way.
|
|
2928
|
+
*/
|
|
2929
|
+
async deliverSignal(waiter, payload) {
|
|
2812
2930
|
await this.store.saveCheckpoint(instantCheckpoint({
|
|
2813
2931
|
runId: waiter.runId,
|
|
2814
2932
|
seq: waiter.seq,
|
|
2815
|
-
name: `signal:${token}`,
|
|
2933
|
+
name: `signal:${waiter.token}`,
|
|
2816
2934
|
kind: "signal",
|
|
2817
2935
|
output: payload,
|
|
2818
2936
|
// Carry the awaiting command's fan group (set when a `ctx.gather_children`/`ctx.all` fan-out
|
|
@@ -2827,6 +2945,42 @@ var WorkflowEngine = class {
|
|
|
2827
2945
|
});
|
|
2828
2946
|
}
|
|
2829
2947
|
/**
|
|
2948
|
+
* Deliver an external signal to the run waiting on `token`, resume it with `payload`, and return
|
|
2949
|
+
* the run result — or null if no run is (or ends up) waiting for it.
|
|
2950
|
+
*
|
|
2951
|
+
* Race with the waiter side (`waitForSignal`'s check → `putSignalWaiter` → re-check, same shape in
|
|
2952
|
+
* the remote `waitSignal` command): a waiter can register in the sliver between this method's
|
|
2953
|
+
* initial `takeSignalWaiter` miss and its `bufferSignal` write, and the naive old flow (buffer and
|
|
2954
|
+
* return) would then leave BOTH a buffered payload and a registered waiter sitting in the store with
|
|
2955
|
+
* nothing left to pair them — a lost wake, forever suspended.
|
|
2956
|
+
*
|
|
2957
|
+
* The interleaving proof: the waiter side does check → put → re-check, this side does take → buffer
|
|
2958
|
+
* → re-check. Whichever side's SECOND look runs last is guaranteed to observe the other side's
|
|
2959
|
+
* write, because it always follows that write in real time:
|
|
2960
|
+
* - If the waiter's `put` lands before this method's first `take`, the take just finds it directly
|
|
2961
|
+
* (the pre-existing, non-racy path).
|
|
2962
|
+
* - If the waiter's `put` lands after this method's `bufferSignal`, our re-check below either sees
|
|
2963
|
+
* it (if `put` also lands before the re-check) or the waiter's OWN post-put re-check sees our
|
|
2964
|
+
* buffer (if `put` lands after our re-check but the waiter hasn't re-checked yet either — its
|
|
2965
|
+
* re-check strictly follows its own put).
|
|
2966
|
+
* - If the waiter's `put` lands between this method's `take` and its re-`take`, the re-check below
|
|
2967
|
+
* catches it.
|
|
2968
|
+
* Either way, the destructive `take*` ops (on the waiter row, on the buffer) arbitrate: whichever
|
|
2969
|
+
* side actually removes the row is the one that delivers, so a signal is never delivered twice.
|
|
2970
|
+
*/
|
|
2971
|
+
async signal(token, payload) {
|
|
2972
|
+
const waiter = await this.store.takeSignalWaiter(token);
|
|
2973
|
+
if (waiter) return this.deliverSignal(waiter, payload);
|
|
2974
|
+
await this.store.bufferSignal(token, payload);
|
|
2975
|
+
const lateWaiter = await this.store.takeSignalWaiter(token);
|
|
2976
|
+
if (!lateWaiter) return null;
|
|
2977
|
+
const reclaimed = await this.store.takeBufferedSignal(token);
|
|
2978
|
+
if (!reclaimed) {
|
|
2979
|
+
return null;
|
|
2980
|
+
}
|
|
2981
|
+
return this.deliverSignal(lateWaiter, reclaimed.payload);
|
|
2982
|
+
}
|
|
2983
|
+
/**
|
|
2830
2984
|
* Ensure a run exists for `runId`, then deliver a signal to it — atomically race-free thanks to
|
|
2831
2985
|
* signal buffering: if the run is new (or busy / not yet waiting), the signal is buffered and
|
|
2832
2986
|
* consumed when it reaches `waitForSignal(token)`. The canonical **durable-entity / accumulator**
|
|
@@ -3299,6 +3453,14 @@ var WorkflowEngine = class {
|
|
|
3299
3453
|
error: outcome.error
|
|
3300
3454
|
};
|
|
3301
3455
|
}
|
|
3456
|
+
const latest = await this.store.getRun(run.id);
|
|
3457
|
+
if (latest?.status === "cancelled") {
|
|
3458
|
+
return {
|
|
3459
|
+
runId: run.id,
|
|
3460
|
+
status: "cancelled",
|
|
3461
|
+
error: latest.error
|
|
3462
|
+
};
|
|
3463
|
+
}
|
|
3302
3464
|
await this.store.updateRun(run.id, {
|
|
3303
3465
|
status: "suspended",
|
|
3304
3466
|
wakeAt: this.reconcileWakeAt(outcome.wakeAt),
|
|
@@ -3641,22 +3803,34 @@ var WorkflowEngine = class {
|
|
|
3641
3803
|
}));
|
|
3642
3804
|
wakeAt = wakeAt == null ? deadline : Math.min(wakeAt, deadline);
|
|
3643
3805
|
} else if (cmd.kind === "waitSignal") {
|
|
3644
|
-
const
|
|
3645
|
-
if (buffered) {
|
|
3806
|
+
const deliverBuffered = /* @__PURE__ */ __name(async (payload) => {
|
|
3646
3807
|
await this.store.saveCheckpoint(instantCheckpoint({
|
|
3647
3808
|
runId: run.id,
|
|
3648
3809
|
seq: cmd.seq,
|
|
3649
3810
|
name: `signal:${cmd.signal}`,
|
|
3650
3811
|
kind: "signal",
|
|
3651
|
-
output:
|
|
3812
|
+
output: payload
|
|
3652
3813
|
}));
|
|
3653
3814
|
setTimeout(() => void this.resume(run.id).catch(() => void 0), 0);
|
|
3815
|
+
}, "deliverBuffered");
|
|
3816
|
+
const buffered = await this.store.takeBufferedSignal(cmd.signal);
|
|
3817
|
+
if (buffered) {
|
|
3818
|
+
await deliverBuffered(buffered.payload);
|
|
3654
3819
|
} else {
|
|
3655
3820
|
await this.store.putSignalWaiter({
|
|
3656
3821
|
token: cmd.signal,
|
|
3657
3822
|
runId: run.id,
|
|
3658
3823
|
seq: cmd.seq
|
|
3659
3824
|
});
|
|
3825
|
+
const lateBuffered = await this.store.takeBufferedSignal(cmd.signal);
|
|
3826
|
+
if (lateBuffered) {
|
|
3827
|
+
await this.store.removeSignalWaiter({
|
|
3828
|
+
token: cmd.signal,
|
|
3829
|
+
runId: run.id,
|
|
3830
|
+
seq: cmd.seq
|
|
3831
|
+
});
|
|
3832
|
+
await deliverBuffered(lateBuffered.payload);
|
|
3833
|
+
}
|
|
3660
3834
|
}
|
|
3661
3835
|
} else if (cmd.kind === "startChild") {
|
|
3662
3836
|
const childId = `${run.id}.child.${cmd.seq}`;
|
|
@@ -4516,47 +4690,6 @@ var TERMINAL_RUN_STATUSES = [
|
|
|
4516
4690
|
"dead"
|
|
4517
4691
|
];
|
|
4518
4692
|
|
|
4519
|
-
// src/run-waiting.ts
|
|
4520
|
-
var WEBHOOK_PREFIX = "wh:";
|
|
4521
|
-
var CHILD_PREFIX = "child:";
|
|
4522
|
-
var BREAKPOINT_PREFIX = "bp:";
|
|
4523
|
-
var EVENT_PREFIX = "event:";
|
|
4524
|
-
function classifyWaiterToken(token) {
|
|
4525
|
-
if (token.startsWith(WEBHOOK_PREFIX)) return {
|
|
4526
|
-
on: "webhook",
|
|
4527
|
-
name: token
|
|
4528
|
-
};
|
|
4529
|
-
if (token.startsWith(BREAKPOINT_PREFIX)) return {
|
|
4530
|
-
on: "breakpoint",
|
|
4531
|
-
name: "breakpoint"
|
|
4532
|
-
};
|
|
4533
|
-
if (token.startsWith(CHILD_PREFIX)) return {
|
|
4534
|
-
on: "child",
|
|
4535
|
-
name: token.slice(CHILD_PREFIX.length)
|
|
4536
|
-
};
|
|
4537
|
-
if (token.startsWith(EVENT_PREFIX)) return {
|
|
4538
|
-
on: "signal",
|
|
4539
|
-
name: eventNameOf(token)
|
|
4540
|
-
};
|
|
4541
|
-
return {
|
|
4542
|
-
on: "signal",
|
|
4543
|
-
name: token
|
|
4544
|
-
};
|
|
4545
|
-
}
|
|
4546
|
-
__name(classifyWaiterToken, "classifyWaiterToken");
|
|
4547
|
-
function resolveRunWaiting(run, waiterByRun) {
|
|
4548
|
-
if (run.status !== "suspended") return void 0;
|
|
4549
|
-
const waiter = waiterByRun.get(run.id);
|
|
4550
|
-
return waiter ? classifyWaiterToken(waiter.token) : void 0;
|
|
4551
|
-
}
|
|
4552
|
-
__name(resolveRunWaiting, "resolveRunWaiting");
|
|
4553
|
-
function indexWaitersByRun(waiters) {
|
|
4554
|
-
const byRun = /* @__PURE__ */ new Map();
|
|
4555
|
-
for (const w of waiters) if (!byRun.has(w.runId)) byRun.set(w.runId, w);
|
|
4556
|
-
return byRun;
|
|
4557
|
-
}
|
|
4558
|
-
__name(indexWaitersByRun, "indexWaitersByRun");
|
|
4559
|
-
|
|
4560
4693
|
// src/codec-state-store.ts
|
|
4561
4694
|
var CodecStateStore = class {
|
|
4562
4695
|
static {
|
|
@@ -4664,6 +4797,9 @@ var CodecStateStore = class {
|
|
|
4664
4797
|
listSignalWaiters(prefix) {
|
|
4665
4798
|
return this.inner.listSignalWaiters(prefix);
|
|
4666
4799
|
}
|
|
4800
|
+
removeSignalWaiter(waiter) {
|
|
4801
|
+
return this.inner.removeSignalWaiter(waiter);
|
|
4802
|
+
}
|
|
4667
4803
|
bufferSignal(token, payload) {
|
|
4668
4804
|
return this.inner.bufferSignal(token, this.enc(payload));
|
|
4669
4805
|
}
|
|
@@ -5116,6 +5252,12 @@ var InMemoryStateStore = class {
|
|
|
5116
5252
|
...w
|
|
5117
5253
|
}));
|
|
5118
5254
|
}
|
|
5255
|
+
async removeSignalWaiter(waiter) {
|
|
5256
|
+
const current = this.signalWaiters.get(waiter.token);
|
|
5257
|
+
if (current && current.runId === waiter.runId && current.seq === waiter.seq) {
|
|
5258
|
+
this.signalWaiters.delete(waiter.token);
|
|
5259
|
+
}
|
|
5260
|
+
}
|
|
5119
5261
|
// No real DB transaction (there's no DB) — run the work and save the checkpoint. Exactly-once
|
|
5120
5262
|
// across a crash needs a SQL store; this keeps `ctx.transaction` usable in tests / local dev.
|
|
5121
5263
|
async transaction(work) {
|
|
@@ -5290,6 +5432,7 @@ var InMemoryTransport = class {
|
|
|
5290
5432
|
};
|
|
5291
5433
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5292
5434
|
0 && (module.exports = {
|
|
5435
|
+
CONTROL_FLOW_SIGNAL,
|
|
5293
5436
|
CodecStateStore,
|
|
5294
5437
|
ContinueAsNew,
|
|
5295
5438
|
DURABLE_OPTIONS,
|
|
@@ -5335,6 +5478,7 @@ var InMemoryTransport = class {
|
|
|
5335
5478
|
eventPrefix,
|
|
5336
5479
|
eventToken,
|
|
5337
5480
|
indexWaitersByRun,
|
|
5481
|
+
isWorkflowControlFlowSignal,
|
|
5338
5482
|
matchesAttributes,
|
|
5339
5483
|
normalizeAttributeRows,
|
|
5340
5484
|
parseDuration,
|