@dudousxd/nestjs-durable-testing 0.11.0 → 0.13.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.d.ts CHANGED
@@ -68,6 +68,7 @@ declare const DURABLE_CANONICAL_COLUMNS: {
68
68
  readonly wakeAt: "wake_at";
69
69
  readonly lockedBy: "locked_by";
70
70
  readonly lockedUntil: "locked_until";
71
+ readonly awaitingDecisionTaskId: "awaiting_decision_task_id";
71
72
  readonly recoveryAttempts: "recovery_attempts";
72
73
  readonly tags: "tags";
73
74
  readonly searchAttributes: "search_attributes";
@@ -90,6 +91,7 @@ declare const DURABLE_CANONICAL_COLUMNS: {
90
91
  readonly events: "events";
91
92
  readonly attempts: "attempts";
92
93
  readonly workerGroup: "worker_group";
94
+ readonly parallelGroup: "parallel_group";
93
95
  readonly wakeAt: "wake_at";
94
96
  readonly enqueuedAt: "enqueued_at";
95
97
  readonly startedAt: "started_at";
@@ -105,6 +107,7 @@ declare const DURABLE_CANONICAL_COLUMNS: {
105
107
  readonly token: "token";
106
108
  readonly runId: "run_id";
107
109
  readonly seq: "seq";
110
+ readonly parallelGroup: "parallel_group";
108
111
  };
109
112
  readonly durable_buffered_signals: {
110
113
  readonly id: "id";
package/dist/index.js CHANGED
@@ -221,6 +221,11 @@ var DURABLE_CANONICAL_COLUMNS = {
221
221
  wakeAt: "wake_at",
222
222
  lockedBy: "locked_by",
223
223
  lockedUntil: "locked_until",
224
+ // The REMOTE turn the engine suspended on; `completeRemoteDecision` matches against it so only
225
+ // the currently-awaited turn's decision is applied. A store swap that lost this column would not
226
+ // fail loudly — it would apply a stale decision to the wrong turn — which is why it is pinned
227
+ // rather than left to each adapter's own spec.
228
+ awaitingDecisionTaskId: "awaiting_decision_task_id",
224
229
  recoveryAttempts: "recovery_attempts",
225
230
  tags: "tags",
226
231
  searchAttributes: "search_attributes",
@@ -249,6 +254,10 @@ var DURABLE_CANONICAL_COLUMNS = {
249
254
  events: "events",
250
255
  attempts: "attempts",
251
256
  workerGroup: "worker_group",
257
+ // A `ctx.gather`/`ctx.all` fan tags every sibling step with the same group so the dashboard can
258
+ // render them as one parallel group. Same physical name in the waiter table below — two tables,
259
+ // one column name, which is precisely the kind of near-duplicate that drifts if unpinned.
260
+ parallelGroup: "parallel_group",
252
261
  wakeAt: "wake_at",
253
262
  enqueuedAt: "enqueued_at",
254
263
  startedAt: "started_at",
@@ -263,7 +272,10 @@ var DURABLE_CANONICAL_COLUMNS = {
263
272
  durable_signal_waiters: {
264
273
  token: "token",
265
274
  runId: "run_id",
266
- seq: "seq"
275
+ seq: "seq",
276
+ // The fan-out group threaded onto a child waiter, so the resolving `signal:child:` checkpoint
277
+ // carries it. Only fan-out child waiters populate it, but every adapter declares the column.
278
+ parallelGroup: "parallel_group"
267
279
  },
268
280
  durable_buffered_signals: {
269
281
  id: "id",
@@ -975,6 +987,99 @@ function runStateStoreContract(name, makeStore) {
975
987
  "c"
976
988
  ]);
977
989
  });
990
+ t("selects the UNATTRIBUTED runs when `origin` is null \u2014 the one thing a value cannot", async () => {
991
+ await store.createRun(run({
992
+ id: "a",
993
+ origin: "@dudousxd/nestjs-agent"
994
+ }));
995
+ await store.createRun(run({
996
+ id: "b"
997
+ }));
998
+ await store.createRun(run({
999
+ id: "c"
1000
+ }));
1001
+ expect2((await store.listRuns({
1002
+ origin: null
1003
+ })).map((r) => r.id).sort()).toEqual([
1004
+ "b",
1005
+ "c"
1006
+ ]);
1007
+ await store.createRun(run({
1008
+ id: "d",
1009
+ status: "dead"
1010
+ }));
1011
+ expect2((await store.listRuns({
1012
+ origin: null,
1013
+ status: "dead"
1014
+ })).map((r) => r.id)).toEqual([
1015
+ "d"
1016
+ ]);
1017
+ });
1018
+ t("counts runs by (status, origin) without returning them", async () => {
1019
+ if (!store.runFacets) return;
1020
+ await store.createRun(run({
1021
+ id: "a",
1022
+ status: "completed",
1023
+ origin: "pkg-a"
1024
+ }));
1025
+ await store.createRun(run({
1026
+ id: "b",
1027
+ status: "completed",
1028
+ origin: "pkg-a"
1029
+ }));
1030
+ await store.createRun(run({
1031
+ id: "c",
1032
+ status: "failed",
1033
+ origin: "pkg-b"
1034
+ }));
1035
+ await store.createRun(run({
1036
+ id: "d",
1037
+ status: "failed"
1038
+ }));
1039
+ await store.createRun(run({
1040
+ id: "e",
1041
+ status: "failed"
1042
+ }));
1043
+ const facets = await store.runFacets({});
1044
+ expect2(facets).toContainEqual({
1045
+ status: "completed",
1046
+ origin: "pkg-a",
1047
+ count: 2
1048
+ });
1049
+ expect2(facets).toContainEqual({
1050
+ status: "failed",
1051
+ origin: "pkg-b",
1052
+ count: 1
1053
+ });
1054
+ expect2(facets).toContainEqual({
1055
+ status: "failed",
1056
+ origin: null,
1057
+ count: 2
1058
+ });
1059
+ expect2(facets.reduce((n, f) => n + f.count, 0)).toBe(5);
1060
+ });
1061
+ t("narrows runFacets on the same predicates listRuns pages", async () => {
1062
+ if (!store.runFacets) return;
1063
+ await store.createRun(run({
1064
+ id: "a",
1065
+ status: "failed",
1066
+ namespace: "acme"
1067
+ }));
1068
+ await store.createRun(run({
1069
+ id: "b",
1070
+ status: "failed",
1071
+ namespace: "globex"
1072
+ }));
1073
+ expect2(await store.runFacets({
1074
+ namespace: "acme"
1075
+ })).toEqual([
1076
+ {
1077
+ status: "failed",
1078
+ origin: null,
1079
+ count: 1
1080
+ }
1081
+ ]);
1082
+ });
978
1083
  t("orders listRuns newest-first and paginates with limit/offset", async () => {
979
1084
  await store.createRun(run({
980
1085
  id: "old",
@@ -1475,6 +1580,71 @@ function runStateStoreContract(name, makeStore) {
1475
1580
  expect2(resumed.output).toBe(15);
1476
1581
  expect2(aRuns).toBe(1);
1477
1582
  });
1583
+ t("starts the version the caller pinned, and refuses one that is not registered", async () => {
1584
+ const engine = new WorkflowEngine3({
1585
+ store
1586
+ });
1587
+ const ran = [];
1588
+ engine.register("vwf", "1", async () => {
1589
+ ran.push("v1");
1590
+ return "v1-output";
1591
+ });
1592
+ engine.register("vwf", "2", async () => {
1593
+ ran.push("v2");
1594
+ return "v2-output";
1595
+ });
1596
+ await engine.start("vwf", {}, "pinned-run", {
1597
+ version: "1"
1598
+ });
1599
+ const pinned = await engine.waitForRun("pinned-run", {
1600
+ timeoutMs: 2e4
1601
+ });
1602
+ expect2(pinned.output).toBe("v1-output");
1603
+ expect2(ran).toEqual([
1604
+ "v1"
1605
+ ]);
1606
+ expect2((await store.getRun("pinned-run"))?.workflowVersion).toBe("1");
1607
+ await engine.start("vwf", {}, "newest-run");
1608
+ expect2((await engine.waitForRun("newest-run", {
1609
+ timeoutMs: 2e4
1610
+ })).output).toBe("v2-output");
1611
+ await expect2(engine.start("vwf", {}, "ghost-run", {
1612
+ version: "9"
1613
+ })).rejects.toThrow(/vwf@9 is not registered/);
1614
+ expect2(await store.getRun("ghost-run")).toBeNull();
1615
+ });
1616
+ t("cancels a timed-out run\u2019s live child subtree, not just the run itself", async () => {
1617
+ const engine = new WorkflowEngine3({
1618
+ store
1619
+ });
1620
+ engine.register("t-grandchild", "1", async (ctx) => ctx.waitForSignal("never"));
1621
+ engine.register("t-child", "1", async (ctx) => {
1622
+ await ctx.startChild("t-grandchild", {}, "tgc");
1623
+ return ctx.waitForSignal("never");
1624
+ });
1625
+ engine.register("t-parent", "1", async (ctx) => {
1626
+ await ctx.startChild("t-child", {}, "tc");
1627
+ return ctx.waitForSignal("never");
1628
+ }, {
1629
+ executionTimeout: "1h"
1630
+ });
1631
+ await engine.start("t-parent", {}, "tp");
1632
+ for (const id of [
1633
+ "tp",
1634
+ "tc",
1635
+ "tgc"
1636
+ ]) {
1637
+ expect2((await engine.waitForRun(id, {
1638
+ timeoutMs: 2e4
1639
+ })).status).toBe("suspended");
1640
+ }
1641
+ await engine.sweepTimeouts(Date.now() + 37e5);
1642
+ const parent = await store.getRun("tp");
1643
+ expect2(parent?.status).toBe("cancelled");
1644
+ expect2(parent?.error?.code).toBe("execution_timeout");
1645
+ expect2((await store.getRun("tc"))?.status).toBe("cancelled");
1646
+ expect2((await store.getRun("tgc"))?.status).toBe("cancelled");
1647
+ });
1478
1648
  });
1479
1649
  }
1480
1650
  __name(runStateStoreContract, "runStateStoreContract");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/admission-backend-conformance.ts","../src/assertions.ts","../src/durable-columns.ts","../src/harness.ts","../src/replay.ts","../src/state-store-conformance.ts","../src/steps.ts","../src/transport-conformance.ts"],"sourcesContent":["import type { AdmissionBackend, QueueConfig } from '@dudousxd/nestjs-durable-core';\nimport { describe, expect, it } from 'vitest';\n\n/**\n * Builds an {@link AdmissionBackend} bound to the given test clock. Implementations that hold their\n * own resources (e.g. a Redis connection) should register the instance for teardown out-of-band.\n */\nexport type AdmissionBackendFactory = (clock: () => number) => AdmissionBackend;\n\n/**\n * The SHARED cross-backend behavioural contract for the flow-control admission gate. Both the\n * in-process `InMemoryAdmissionBackend` and the Redis `RedisAdmissionBackend` run it, so their\n * concurrency / rate-limit / ordering semantics can never silently drift apart — backend-specific\n * concerns (leases, pub/sub, cross-pod globality) live in each adapter's own spec.\n *\n * The engine always passes a stable `waiterId`, so every gated call is order-tracked: ties with no\n * priority/fairness fall back to arrival FIFO (or LIFO when configured). These cases assert exactly\n * that, on ONE backend instance.\n */\nexport function runAdmissionBackendContract(\n name: string,\n makeBackend: AdmissionBackendFactory,\n): void {\n describe(`AdmissionBackend contract: ${name}`, () => {\n let now = 1_000_000;\n const make = (config: QueueConfig) => {\n now = 1_000_000;\n const backend = makeBackend(() => now);\n backend.register(config);\n return backend;\n };\n\n it('caps concurrency: a second call blocks until the first releases', async () => {\n const b = make({ name: 'q', concurrency: 1 });\n expect((await b.tryAdmit('q', { waiterId: 'a' })).ok).toBe(true);\n expect((await b.tryAdmit('q', { waiterId: 'b' })).ok).toBe(false);\n await b.release('q', 'a');\n expect((await b.tryAdmit('q', { waiterId: 'b' })).ok).toBe(true);\n });\n\n it('enforces a fixed-window rate limit', async () => {\n const b = make({ name: 'q', rateLimit: { limit: 2, periodMs: 1000 } });\n expect((await b.tryAdmit('q', { waiterId: '1' })).ok).toBe(true);\n expect((await b.tryAdmit('q', { waiterId: '2' })).ok).toBe(true);\n expect((await b.tryAdmit('q', { waiterId: '3' })).ok).toBe(false);\n now += 1001;\n expect((await b.tryAdmit('q', { waiterId: '4' })).ok).toBe(true);\n });\n\n it('admits the highest-priority waiter first when a slot frees', async () => {\n const b = make({ name: 'q', concurrency: 1 });\n expect((await b.tryAdmit('q', { waiterId: 'holder' })).ok).toBe(true);\n expect((await b.tryAdmit('q', { waiterId: 'low', priority: 1 })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'high', priority: 9 })).ok).toBe(false);\n await b.release('q', 'holder');\n expect((await b.tryAdmit('q', { waiterId: 'low', priority: 1 })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'high', priority: 9 })).ok).toBe(true);\n });\n\n it('orders plain-concurrency waiters by arrival (FIFO) — no priority/fairness configured', async () => {\n const b = make({ name: 'q', concurrency: 1 });\n expect((await b.tryAdmit('q', { waiterId: 'holder' })).ok).toBe(true);\n expect((await b.tryAdmit('q', { waiterId: 'first' })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'second' })).ok).toBe(false);\n await b.release('q', 'holder');\n // The earlier arrival wins the freed slot, on every backend.\n expect((await b.tryAdmit('q', { waiterId: 'second' })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'first' })).ok).toBe(true);\n });\n\n it('admits the most-recent arrival first when order is LIFO', async () => {\n const b = make({ name: 'q', concurrency: 1, order: 'lifo' });\n expect((await b.tryAdmit('q', { waiterId: 'holder' })).ok).toBe(true);\n expect((await b.tryAdmit('q', { waiterId: 'first' })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'second' })).ok).toBe(false);\n await b.release('q', 'holder');\n expect((await b.tryAdmit('q', { waiterId: 'first' })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'second' })).ok).toBe(true);\n });\n\n it('round-robins a contended slot across fairness keys', async () => {\n const b = make({ name: 'q', concurrency: 1, fairness: 'key' });\n expect((await b.tryAdmit('q', { waiterId: 'a0', key: 'A' })).ok).toBe(true);\n expect((await b.tryAdmit('q', { waiterId: 'a1', key: 'A' })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'b0', key: 'B' })).ok).toBe(false);\n await b.release('q', 'a0');\n // B (never served) wins over A (just served), not arrival order.\n expect((await b.tryAdmit('q', { waiterId: 'a1', key: 'A' })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'b0', key: 'B' })).ok).toBe(true);\n });\n\n it('leaves an unregistered queue ungated', async () => {\n const b = make({ name: 'q', concurrency: 1 });\n expect((await b.tryAdmit('other', { waiterId: 'x' })).ok).toBe(true);\n expect((await b.tryAdmit('other', { waiterId: 'y' })).ok).toBe(true);\n });\n });\n}\n","import type { RunStatus, StateStore } from '@dudousxd/nestjs-durable-core';\n\nasync function requireRun(store: StateStore, runId: string) {\n const run = await store.getRun(runId);\n if (!run) throw new Error(`assertion failed: run ${runId} not found`);\n return run;\n}\n\nexport async function assertRunStatus(\n store: StateStore,\n runId: string,\n status: RunStatus,\n): Promise<void> {\n const run = await requireRun(store, runId);\n if (run.status !== status) {\n throw new Error(`expected run ${runId} to be \"${status}\", but it was \"${run.status}\"`);\n }\n}\n\nexport async function assertOutput(\n store: StateStore,\n runId: string,\n expected: unknown,\n): Promise<void> {\n const run = await requireRun(store, runId);\n if (JSON.stringify(run.output) !== JSON.stringify(expected)) {\n throw new Error(\n `expected run ${runId} output ${JSON.stringify(expected)}, got ${JSON.stringify(run.output)}`,\n );\n }\n}\n\n/** The names of the steps that have run, in order. */\nexport async function recordedSteps(store: StateStore, runId: string): Promise<string[]> {\n return (await store.listCheckpoints(runId)).map((cp) => cp.name);\n}\n\n/** Assert every named step ran (in any order). */\nexport async function assertStepsRan(\n store: StateStore,\n runId: string,\n names: string[],\n): Promise<void> {\n const ran = await recordedSteps(store, runId);\n for (const name of names) {\n if (!ran.includes(name)) {\n throw new Error(`expected step \"${name}\" to have run; ran: [${ran.join(', ')}]`);\n }\n }\n}\n\n/** Assert a step ran exactly the given number of attempts (e.g. to verify retries). */\nexport async function assertStepAttempts(\n store: StateStore,\n runId: string,\n name: string,\n attempts: number,\n): Promise<void> {\n const cp = (await store.listCheckpoints(runId)).find((c) => c.name === name);\n if (!cp) throw new Error(`expected step \"${name}\" to have run, but it did not`);\n if (cp.attempts !== attempts) {\n throw new Error(`expected step \"${name}\" to take ${attempts} attempt(s), took ${cp.attempts}`);\n }\n}\n","/**\n * The canonical physical column names for the durable tables, keyed by table → entity property →\n * column. This is the cross-adapter contract: a run written by one store adapter must be readable by\n * another, so EVERY adapter (TypeORM, MikroORM, Prisma, Drizzle) must map these properties to these\n * exact columns. The canonical convention is `snake_case`.\n *\n * Each adapter has a spec that asserts its physical columns against this map (see `assertDurableColumns`).\n * Without it, adapters silently diverge — one defaulting to its ORM's `snake_case` naming strategy,\n * another keeping the verbatim camelCase property name — and a store swap fails against an existing\n * table with \"Unknown column\" only at runtime. The map exists so that divergence is a failing unit\n * test, not a production incident.\n *\n * The camelCase (\"preserve\") naming is simply the property names themselves (the object keys), so no\n * separate map is needed for it.\n *\n * A property belongs here only when EVERY adapter declares it — the assertion walks this map and\n * reports a missing property as a mismatch, so listing a column one adapter doesn't have would fail\n * that adapter for a divergence it isn't guilty of. An absence here therefore records one of two\n * different things, and telling them apart matters: a naming question nobody has settled, or a\n * capability one adapter has and the others do not.\n *\n * `WorkflowRun.namespace` was the standing example of the second kind, and it is worth keeping the\n * story because of how it ended. Only the MikroORM adapter had the column; the other three did not\n * declare the `namespace` parameter on `listPendingRuns`/`listIncompleteRuns`/`listDueTimers` at\n * all, which TypeScript permits, so they satisfied `StateStore` while ignoring the tenant boundary\n * entirely. The gap was real and this map was right to stay quiet about it — but \"this map is quiet\"\n * was also the only thing standing between that and a cross-tenant incident. All four adapters carry\n * the column now, so it is pinned below, and the conformance suite asserts the boundary itself\n * rather than only the column's name.\n */\nexport const DURABLE_CANONICAL_COLUMNS = {\n durable_workflow_runs: {\n id: 'id',\n workflow: 'workflow',\n workflowVersion: 'workflow_version',\n status: 'status',\n input: 'input',\n output: 'output',\n error: 'error',\n wakeAt: 'wake_at',\n lockedBy: 'locked_by',\n lockedUntil: 'locked_until',\n recoveryAttempts: 'recovery_attempts',\n tags: 'tags',\n searchAttributes: 'search_attributes',\n priority: 'priority',\n // Which library registered the workflow. Single-word, so `snake_case` and `preserve` agree and\n // an adapter can look canonical by accident — which is exactly why it is pinned here rather than\n // left to four per-adapter assertions to keep saying the same thing.\n origin: 'origin',\n // The tenant a run belongs to, and the predicate on every poll tick. Pinned here\n // now that all four adapters carry the column — see the note above, which used to\n // name this as the standing example of a capability gap the map cannot express.\n namespace: 'namespace',\n createdAt: 'created_at',\n updatedAt: 'updated_at',\n },\n durable_step_checkpoints: {\n runId: 'run_id',\n seq: 'seq',\n name: 'name',\n kind: 'kind',\n stepId: 'step_id',\n status: 'status',\n input: 'input',\n output: 'output',\n error: 'error',\n events: 'events',\n attempts: 'attempts',\n workerGroup: 'worker_group',\n wakeAt: 'wake_at',\n enqueuedAt: 'enqueued_at',\n startedAt: 'started_at',\n finishedAt: 'finished_at',\n },\n durable_run_attributes: {\n runId: 'run_id',\n key: 'key',\n strValue: 'str_value',\n numValue: 'num_value',\n },\n durable_signal_waiters: {\n token: 'token',\n runId: 'run_id',\n seq: 'seq',\n },\n durable_buffered_signals: {\n id: 'id',\n token: 'token',\n payload: 'payload',\n },\n durable_buffered_events: {\n id: 'id',\n name: 'name',\n payload: 'payload',\n publishedAt: 'published_at',\n },\n} as const;\n\nexport type DurableColumnMap = typeof DURABLE_CANONICAL_COLUMNS;\n\n/** A single column-name disagreement found by {@link assertDurableColumns}. */\nexport interface DurableColumnMismatch {\n table: string;\n property: string;\n expected: string;\n actual: string | undefined;\n}\n\n/**\n * Walk every (table, property) in the canonical contract and compare it to what an adapter actually\n * maps, via the supplied `resolve(table, property) => columnName`. Returns the list of mismatches\n * (empty when the adapter is canonical) so a spec can `expect(assertDurableColumns(resolve)).toEqual([])`.\n *\n * Pass `expected = DURABLE_CANONICAL_COLUMNS` (default) for the snake_case contract, or a map of the\n * property names to themselves to assert the camelCase (\"preserve\") naming.\n */\nexport function assertDurableColumns(\n resolve: (table: string, property: string) => string | undefined,\n expected: Record<string, Record<string, string>> = DURABLE_CANONICAL_COLUMNS,\n): DurableColumnMismatch[] {\n const mismatches: DurableColumnMismatch[] = [];\n for (const [table, props] of Object.entries(expected)) {\n for (const [property, column] of Object.entries(props)) {\n const actual = resolve(table, property);\n if (actual !== column) mismatches.push({ table, property, expected: column, actual });\n }\n }\n return mismatches;\n}\n\n/** The \"preserve\" (camelCase) expectation: every property maps to a column of the same name. */\nexport function preserveColumnExpectation(): Record<string, Record<string, string>> {\n const out: Record<string, Record<string, string>> = {};\n for (const [table, props] of Object.entries(DURABLE_CANONICAL_COLUMNS)) {\n out[table] = Object.fromEntries(Object.keys(props).map((p) => [p, p]));\n }\n return out;\n}\n","import {\n InMemoryStateStore,\n InMemoryTransport,\n type RunResult,\n type StartOptions,\n WorkflowEngine,\n type WorkflowRef,\n} from '@dudousxd/nestjs-durable-core';\n\n/** A clock you control, for testing durable sleeps without real time. */\nexport class MutableClock {\n constructor(private current = 1_000) {}\n readonly now = (): number => this.current;\n set(ms: number): void {\n this.current = ms;\n }\n advance(ms: number): void {\n this.current += ms;\n }\n}\n\nexport interface TestEngine {\n engine: WorkflowEngine;\n store: InMemoryStateStore;\n transport: InMemoryTransport;\n clock: MutableClock;\n /** Advance the clock by `ms` and resume any durable sleeps now due. */\n tick(ms: number): Promise<RunResult[]>;\n /**\n * Enqueue a run and wait for it to settle (terminal or suspended). `engine.start` only enqueues\n * now (dispatch model), so use this when a test needs the outcome synchronously.\n */\n run(\n workflow: WorkflowRef,\n input: unknown,\n runId: string,\n opts?: StartOptions,\n ): Promise<RunResult>;\n}\n\n/**\n * A self-contained engine wired to in-memory store + transport and a controllable clock — run a\n * whole workflow in a unit test, with no Postgres, no Redis, and no real time.\n */\nexport function createTestEngine(): TestEngine {\n const store = new InMemoryStateStore();\n const transport = new InMemoryTransport();\n const clock = new MutableClock();\n const engine = new WorkflowEngine({ store, transport, clock: clock.now });\n return {\n engine,\n store,\n transport,\n clock,\n async tick(ms: number): Promise<RunResult[]> {\n clock.advance(ms);\n return engine.resumeDueTimers(clock.now());\n },\n async run(workflow, input, runId, opts): Promise<RunResult> {\n // `start` is overloaded per ref kind; a `WorkflowRef` union fits neither overload directly, so\n // resolve to the string overload (the engine accepts a class or name at runtime).\n await engine.start(workflow as string, input, runId, opts);\n return engine.waitForRun(runId);\n },\n };\n}\n","import {\n InMemoryStateStore,\n type StepCheckpoint,\n WorkflowEngine,\n type WorkflowRun,\n} from '@dudousxd/nestjs-durable-core';\n\nexport interface RunHistory {\n run: WorkflowRun;\n checkpoints: StepCheckpoint[];\n}\n\n/**\n * Replay a recorded run's history against the CURRENT workflow code and throw if they diverged.\n *\n * Capture a real (ideally in-flight or representative) run from production —\n * `{ run: await store.getRun(id), checkpoints: await store.listCheckpoints(id) }` — commit it as a\n * fixture, and assert here in CI. If a code change renamed/reordered/removed a step at a position the\n * history already recorded, the engine raises a `NonDeterminismError` on replay and this rethrows it,\n * catching the break *before* it reaches an in-flight run on deploy (the moment you'd otherwise\n * silently replay the wrong checkpoint into the wrong step). Register the workflow exactly as the app\n * does:\n *\n * ```ts\n * await assertReplayable((engine) => engine.register('pipeline', '1', pipeline.run), fixture);\n * ```\n */\nexport async function assertReplayable(\n register: (engine: WorkflowEngine) => void,\n history: RunHistory,\n): Promise<void> {\n const store = new InMemoryStateStore();\n // Seed as a suspended run with no lock so resume() replays the body against the recorded\n // checkpoints — no transport is wired, so nothing new is dispatched.\n await store.createRun({\n ...history.run,\n status: 'suspended',\n lockedBy: undefined,\n lockedUntil: undefined,\n });\n for (const cp of history.checkpoints) await store.saveCheckpoint(cp);\n\n const engine = new WorkflowEngine({ store });\n register(engine);\n const result = await engine.resume(history.run.id);\n if (result.status === 'failed' && result.error?.message?.startsWith('non-determinism')) {\n const err = new Error(result.error.message);\n err.name = 'NonDeterminismError';\n throw err;\n }\n}\n","import {\n type StateStore,\n type StepCheckpoint,\n WorkflowEngine,\n type WorkflowRun,\n} from '@dudousxd/nestjs-durable-core';\nimport { beforeEach, describe, expect, it } from 'vitest';\n\n/**\n * A freshly provisioned, empty {@link StateStore} plus a `cleanup` to release its resources (close\n * the connection, drop the schema, etc.). The conformance suite asks for one before each test so\n * every case starts from a clean slate — exactly like the per-store specs that build a `:memory:` DB.\n */\nexport interface StateStoreContext {\n store: StateStore;\n cleanup: () => Promise<void>;\n /**\n * Whether the store's optional `transaction` can run an ASYNC work callback. Defaults to `true`.\n * Set `false` only for a driver that genuinely can't — e.g. Drizzle on the SYNCHRONOUS\n * `better-sqlite3` driver, whose `transaction()` rejects a promise-returning callback (\"Transaction\n * function cannot return a promise\"). The same Drizzle adapter on an async driver (libSQL) works,\n * and the contract still asserts `transaction` for every other store, so this never hides drift.\n */\n supportsAsyncTransaction?: boolean;\n /**\n * Whether the store can filter `listRuns({ tag })`. Defaults to `true`. Set `false` ONLY for\n * Prisma-on-SQLite: the Prisma adapter filters tags with the `array_contains` JSON predicate, which\n * Prisma supports on its real targets (Postgres + MySQL) but NOT on SQLite. SQLite is only the\n * adapter's local TEST database, so the tag case is skipped there; every other store (and Prisma on\n * a real engine) still asserts it, so this doesn't hide drift in the supported configurations.\n */\n supportsTagFilter?: boolean;\n}\n\n/** Builds a fresh, empty store for one test. Called once per `it` (in `beforeEach`). */\nexport type StateStoreFactory = () => Promise<StateStoreContext>;\n\n/**\n * Thrown by a {@link StateStoreFactory} to SKIP the contract for an unavailable backend instead of\n * failing it — e.g. a testcontainers DB spec when Docker isn't running. Every contract case catches\n * it, logs once, and returns (a no-op pass), so `pnpm test:db` is green-with-skips off a dev box\n * without Docker rather than red.\n */\nexport class StateStoreUnavailableError extends Error {\n readonly isStateStoreUnavailable = true;\n constructor(message: string) {\n super(message);\n this.name = 'StateStoreUnavailableError';\n }\n}\n\nfunction isUnavailable(err: unknown): err is StateStoreUnavailableError {\n return !!err && typeof err === 'object' && 'isStateStoreUnavailable' in err;\n}\n\nconst at = new Date('2026-06-11T00:00:00.000Z');\n\nconst run = (over: Partial<WorkflowRun> = {}): WorkflowRun => ({\n id: 'r1',\n workflow: 'checkout',\n workflowVersion: '1',\n status: 'running',\n input: { orderId: 'o1' },\n createdAt: at,\n updatedAt: at,\n ...over,\n});\n\nconst checkpoint = (over: Partial<StepCheckpoint> = {}): StepCheckpoint => ({\n runId: 'r1',\n seq: 0,\n name: 'reserve',\n kind: 'local',\n stepId: 'r1:0',\n status: 'completed',\n output: { ok: true },\n attempts: 1,\n enqueuedAt: at,\n startedAt: at,\n finishedAt: at,\n ...over,\n});\n\n/**\n * The SHARED behavioral contract every `StateStore` must satisfy — in-memory and each ORM adapter\n * alike. Registered as a vitest `describe`; pass a `name` and a {@link StateStoreFactory} that builds\n * a fresh, empty store. The same assertions run against SQLite/in-memory under `pnpm test` and\n * against real Postgres/MySQL (via testcontainers) under `pnpm test:db`, so any drift between an\n * adapter and the canonical (in-memory) semantics — especially the search-attribute side-table\n * pushdown, which is implemented per-store — fails here instead of silently in production.\n *\n * Each adapter's own spec keeps its dialect-specific tests (DDL/longtext/EXISTS-SQL/JSON-tolerance);\n * this suite owns the cross-store behavior so those never drift apart.\n */\nexport function runStateStoreContract(name: string, makeStore: StateStoreFactory): void {\n describe(`StateStore contract: ${name}`, () => {\n let store: StateStore;\n let cleanup: (() => Promise<void>) | undefined;\n let supportsAsyncTransaction = true;\n let supportsTagFilter = true;\n let skipReason: string | undefined;\n let loggedSkip = false;\n\n beforeEach(async () => {\n try {\n const ctx = await makeStore();\n store = ctx.store;\n cleanup = ctx.cleanup;\n supportsAsyncTransaction = ctx.supportsAsyncTransaction ?? true;\n supportsTagFilter = ctx.supportsTagFilter ?? true;\n skipReason = undefined;\n } catch (err) {\n if (isUnavailable(err)) {\n // Backend unavailable (e.g. no Docker for a testcontainers spec): skip — don't fail.\n skipReason = err.message;\n if (!loggedSkip) {\n console.warn(`[state-store-contract] SKIPPING \"${name}\": ${skipReason}`);\n loggedSkip = true;\n }\n return;\n }\n throw err;\n }\n return async () => {\n await cleanup?.();\n };\n });\n\n /** Register a contract case that no-ops (passes) when the backend was reported unavailable. */\n const t = (label: string, fn: () => Promise<void>): void => {\n it(label, async () => {\n if (skipReason) return;\n await fn();\n });\n };\n\n // ---- create / get / update --------------------------------------------------------------\n\n t('creates a run and reads it back with its JSON input', async () => {\n await store.createRun(run());\n const loaded = await store.getRun('r1');\n expect(loaded?.workflow).toBe('checkout');\n expect(loaded?.input).toEqual({ orderId: 'o1' });\n });\n\n t('returns null for a missing run', async () => {\n expect(await store.getRun('nope')).toBeNull();\n });\n\n t('updates a run (status/output) and round-trips recoveryAttempts + dead status', async () => {\n await store.createRun(run({ recoveryAttempts: 3 }));\n await store.updateRun('r1', {\n status: 'completed',\n output: { total: 42 },\n updatedAt: at,\n });\n const done = await store.getRun('r1');\n expect(done?.status).toBe('completed');\n expect(done?.output).toEqual({ total: 42 });\n expect(done?.recoveryAttempts).toBe(3);\n\n await store.updateRun('r1', { status: 'dead', recoveryAttempts: 4 });\n const dead = await store.getRun('r1');\n expect(dead?.status).toBe('dead');\n expect(dead?.recoveryAttempts).toBe(4);\n });\n\n t('round-trips a run dispatch priority', async () => {\n await store.createRun(run({ id: 'withprio', priority: 7 }));\n await store.createRun(run({ id: 'noprio' }));\n expect((await store.getRun('withprio'))?.priority).toBe(7);\n expect((await store.getRun('noprio'))?.priority).toBeUndefined();\n });\n\n t('deleteRun removes the run and all its rows (checkpoints, waiters, attributes)', async () => {\n await store.createRun(run({ searchAttributes: { tier: 'pro' } }));\n await store.saveCheckpoint(checkpoint());\n await store.putSignalWaiter({ token: 'approve-r1', runId: 'r1', seq: 0 });\n\n await store.deleteRun('r1');\n\n // The run and every child row are gone — not merely marked terminal.\n expect(await store.getRun('r1')).toBeNull();\n expect(await store.listCheckpoints('r1')).toEqual([]);\n expect(await store.listSignalWaiters('approve-')).toEqual([]);\n // The normalized attribute side-table no longer matches it.\n expect(\n await store.listRuns({\n attributes: [{ key: 'tier', op: 'eq', value: 'pro' }],\n }),\n ).toEqual([]);\n });\n\n t('deleteRun is a no-op for a missing run', async () => {\n await expect(store.deleteRun('nope')).resolves.toBeUndefined();\n });\n\n t(\n 'updateRun maps every patchable field — clears error and patches tags/lockedBy/input/timers',\n async () => {\n // Guards against per-adapter patch-whitelist drift: a store that maps only a subset of fields\n // (or ignores `undefined` instead of clearing) would silently no-op these and fail here.\n await store.createRun(\n run({ status: 'failed', error: { message: 'boom' }, tags: ['old'], lockedBy: 'owner-1' }),\n );\n await store.updateRun('r1', {\n status: 'completed',\n output: { ok: true },\n error: undefined, // completion CLEARS the prior error\n input: { orderId: 'o2' },\n tags: ['x', 'y'],\n lockedBy: 'owner-2',\n wakeAt: 123_456,\n lockedUntil: 222_222,\n updatedAt: at,\n });\n const r = await store.getRun('r1');\n expect(r?.status).toBe('completed');\n expect(r?.output).toEqual({ ok: true });\n expect(r?.error).toBeUndefined();\n expect(r?.input).toEqual({ orderId: 'o2' });\n expect(r?.tags).toEqual(['x', 'y']);\n expect(r?.lockedBy).toBe('owner-2');\n expect(r?.wakeAt).toBe(123_456);\n expect(r?.lockedUntil).toBe(222_222);\n\n // The multi-instance REMOTE-decision marker must round-trip AND clear: the engine sets it\n // when it suspends on an awaited turn and clears it (`undefined`) when the decision lands. An\n // adapter that drops it on read, or ignores `undefined` instead of writing NULL, would silently\n // break completeRemoteDecision (it reads back the stale/absent marker and discards the decision).\n await store.updateRun('r1', { awaitingDecisionTaskId: 'turn-7' });\n expect((await store.getRun('r1'))?.awaitingDecisionTaskId).toBe('turn-7');\n await store.updateRun('r1', { awaitingDecisionTaskId: undefined });\n expect((await store.getRun('r1'))?.awaitingDecisionTaskId).toBeUndefined();\n },\n );\n\n // ---- checkpoints ------------------------------------------------------------------------\n\n t(\n 'upserts checkpoints, reads them by (runId, seq), and lists them ordered by seq',\n async () => {\n await store.createRun(run());\n await store.saveCheckpoint(checkpoint());\n await store.saveCheckpoint(\n checkpoint({ seq: 1, name: 'charge', output: { chargeId: 'ch_1' } }),\n );\n // Re-save seq 0 with a new output — upsert, not a duplicate row.\n await store.saveCheckpoint(checkpoint({ output: { ok: true, again: true } }));\n\n expect((await store.getCheckpoint('r1', 0))?.output).toEqual({ ok: true, again: true });\n expect((await store.getCheckpoint('r1', 1))?.name).toBe('charge');\n const list = await store.listCheckpoints('r1');\n expect(list.map((c) => c.seq)).toEqual([0, 1]);\n },\n );\n\n t(\n 'getLatestCheckpointByName returns the highest-seq match (and undefined for none)',\n async () => {\n await store.createRun(run());\n await store.saveCheckpoint(\n checkpoint({ seq: 0, name: 'event:progress', output: { pct: 10 } }),\n );\n await store.saveCheckpoint(checkpoint({ seq: 1, name: 'charge', output: { id: 'c1' } }));\n await store.saveCheckpoint(\n checkpoint({ seq: 2, name: 'event:progress', output: { pct: 50 } }),\n );\n await store.saveCheckpoint(\n checkpoint({ seq: 3, name: 'event:progress', output: { pct: 90 } }),\n );\n\n // Optional on the interface (the engine has a fallback), but a conformant store MUST provide\n // it — assert presence, then exercise the fast path.\n const getLatestCheckpointByName = store.getLatestCheckpointByName;\n expect(getLatestCheckpointByName).toBeDefined();\n if (!getLatestCheckpointByName) return;\n\n const latest = await getLatestCheckpointByName.call(store, 'r1', 'event:progress');\n expect(latest?.seq).toBe(3);\n expect(latest?.output).toEqual({ pct: 90 });\n expect(await getLatestCheckpointByName.call(store, 'r1', 'event:missing')).toBeUndefined();\n },\n );\n\n t(\n 'listCheckpointsByNamePrefix returns prefix matches ordered by seq (empty => none)',\n async () => {\n await store.createRun(run());\n await store.saveCheckpoint(checkpoint({ seq: 0, name: 'reserve' }));\n await store.saveCheckpoint(checkpoint({ seq: 1, name: 'spawn:0', output: 'child-a' }));\n await store.saveCheckpoint(checkpoint({ seq: 2, name: 'signal:child:c2' }));\n await store.saveCheckpoint(checkpoint({ seq: 3, name: 'event:progress' }));\n await store.saveCheckpoint(checkpoint({ seq: 4, name: 'spawn:1', output: 'child-b' }));\n\n // Optional on the interface (the engine has a fallback), but a conformant store MUST provide\n // it — assert presence, then exercise the fast path.\n const listCheckpointsByNamePrefix = store.listCheckpointsByNamePrefix;\n expect(listCheckpointsByNamePrefix).toBeDefined();\n if (!listCheckpointsByNamePrefix) return;\n\n const matches = await listCheckpointsByNamePrefix.call(store, 'r1', [\n 'signal:child:',\n 'spawn:',\n ]);\n expect(matches.map((c) => c.name)).toEqual(['spawn:0', 'signal:child:c2', 'spawn:1']);\n expect(await listCheckpointsByNamePrefix.call(store, 'r1', [])).toEqual([]);\n },\n );\n\n t('round-trips checkpoint events and reads back a missing checkpoint as null', async () => {\n await store.createRun(run());\n await store.saveCheckpoint(\n checkpoint({\n events: [{ at: 1, level: 'error', message: 'p-3 failed', name: 'p-3', status: 'failed' }],\n }),\n );\n expect((await store.getCheckpoint('r1', 0))?.events).toEqual([\n { at: 1, level: 'error', message: 'p-3 failed', name: 'p-3', status: 'failed' },\n ]);\n expect(await store.getCheckpoint('r1', 99)).toBeNull();\n });\n\n // ---- recovery / dispatch / timer scans --------------------------------------------------\n\n t('lists incomplete runs, pending runs (FIFO), and due timers', async () => {\n await store.createRun(run({ id: 'running1', status: 'running' }));\n await store.createRun(run({ id: 'suspended1', status: 'suspended', wakeAt: 5_000 }));\n await store.createRun(run({ id: 'done1', status: 'completed' }));\n await store.createRun(\n run({ id: 'pending2', status: 'pending', createdAt: new Date('2026-06-11T00:00:02.000Z') }),\n );\n await store.createRun(\n run({ id: 'pending1', status: 'pending', createdAt: new Date('2026-06-11T00:00:01.000Z') }),\n );\n\n expect((await store.listIncompleteRuns()).map((r) => r.id)).toEqual(['running1']);\n // FIFO by createdAt.\n expect((await store.listPendingRuns(10)).map((r) => r.id)).toEqual(['pending1', 'pending2']);\n expect((await store.listPendingRuns(1)).map((r) => r.id)).toEqual(['pending1']);\n expect((await store.listDueTimers(10_000)).map((r) => r.id)).toEqual(['suspended1']);\n expect(await store.listDueTimers(1_000)).toHaveLength(0);\n });\n\n t('keeps a worker inside its own namespace on every path that picks work up', async () => {\n // The boundary `WorkflowRun.namespace` documents: \"A worker only picks up /\n // recovers / resumes-timers-for / times-out runs in its own namespace.\"\n //\n // This case exists because that sentence was true of exactly one adapter. The\n // other three did not declare the `namespace` parameter at all — and TypeScript\n // lets an implementation take fewer parameters than the interface promises, so\n // three stores silently ignored the argument and still satisfied `StateStore`.\n // A worker serving one tenant listed, recovered and — through `sweepTimeouts`,\n // which selects its cancellation candidates with `listRuns` — CANCELLED another\n // tenant's runs. The last of those is a write, which is why this is asserted on\n // all four paths rather than on the two that name `namespace` in their signature.\n await store.createRun(run({ id: 'a-pending', status: 'pending', namespace: 'alpha' }));\n await store.createRun(run({ id: 'b-pending', status: 'pending', namespace: 'beta' }));\n await store.createRun(run({ id: 'a-running', status: 'running', namespace: 'alpha' }));\n await store.createRun(run({ id: 'b-running', status: 'running', namespace: 'beta' }));\n await store.createRun(\n run({ id: 'a-timer', status: 'suspended', wakeAt: 5_000, namespace: 'alpha' }),\n );\n await store.createRun(\n run({ id: 'b-timer', status: 'suspended', wakeAt: 5_000, namespace: 'beta' }),\n );\n\n expect((await store.listPendingRuns(10, 'alpha')).map((r) => r.id)).toEqual(['a-pending']);\n expect((await store.listIncompleteRuns('alpha')).map((r) => r.id)).toEqual(['a-running']);\n expect((await store.listDueTimers(10_000, 'alpha')).map((r) => r.id)).toEqual(['a-timer']);\n expect(\n (await store.listRuns({ namespace: 'alpha', status: 'running' })).map((r) => r.id),\n ).toEqual(['a-running']);\n\n // Foreign runs must not eat the FIFO budget either. Asking for one row while\n // `beta` holds the oldest pending run has to return `alpha`'s, not nothing:\n // a store that filtered AFTER applying the limit would answer with an empty\n // page and look exactly like an idle tenant.\n expect((await store.listPendingRuns(1, 'alpha')).map((r) => r.id)).toEqual(['a-pending']);\n\n // `undefined` is NOT \"namespace is null\" — it is the operator view, every\n // tenant at once. A store that read it as a null predicate would pass every\n // single-tenant test written above and hide every run in a deployment that\n // actually sets `DURABLE_TENANT`.\n expect((await store.listPendingRuns(10)).map((r) => r.id).sort()).toEqual([\n 'a-pending',\n 'b-pending',\n ]);\n expect((await store.listIncompleteRuns()).map((r) => r.id).sort()).toEqual([\n 'a-running',\n 'b-running',\n ]);\n expect((await store.listDueTimers(10_000)).map((r) => r.id).sort()).toEqual([\n 'a-timer',\n 'b-timer',\n ]);\n });\n\n // ---- lease / lock -----------------------------------------------------------------------\n\n t('tryLockRun is atomic and respects lease expiry', async () => {\n await store.createRun(run({ id: 'r1' }));\n expect(await store.tryLockRun('r1', 'A', 2_000, 1_000)).toBe(true);\n // B can't take it while A's lease is live.\n expect(await store.tryLockRun('r1', 'B', 3_000, 1_500)).toBe(false);\n // Once A's lease (2_000) has passed, B reclaims it.\n expect(await store.tryLockRun('r1', 'B', 4_000, 2_500)).toBe(true);\n // Release lets anyone re-acquire immediately.\n await store.releaseRunLock('r1');\n expect(await store.tryLockRun('r1', 'C', 9_000, 2_600)).toBe(true);\n });\n\n t('renewRunLock only succeeds for the current owner', async () => {\n await store.createRun(run({ id: 'r1' }));\n expect(await store.tryLockRun('r1', 'A', 2_000, 1_000)).toBe(true);\n // The holder heartbeats and keeps the lease.\n expect(await store.renewRunLock('r1', 'A', 5_000)).toBe(true);\n // A different instance can't renew a lease it doesn't hold.\n expect(await store.renewRunLock('r1', 'B', 9_000)).toBe(false);\n // And the renewed lease is honored: B still can't steal it before it expires.\n expect(await store.tryLockRun('r1', 'B', 6_000, 4_000)).toBe(false);\n });\n\n // ---- list filters: status / statuses / tag / origin --------------------------------------\n\n t('filters listRuns by workflow and by status', async () => {\n await store.createRun(run({ id: 'a', workflow: 'checkout', status: 'running' }));\n await store.createRun(run({ id: 'b', workflow: 'refund', status: 'running' }));\n await store.createRun(run({ id: 'c', workflow: 'checkout', status: 'completed' }));\n\n expect((await store.listRuns({ workflow: 'checkout' })).map((r) => r.id).sort()).toEqual([\n 'a',\n 'c',\n ]);\n expect((await store.listRuns({ status: 'running' })).map((r) => r.id).sort()).toEqual([\n 'a',\n 'b',\n ]);\n expect(\n (await store.listRuns({ workflow: 'checkout', status: 'running' })).map((r) => r.id),\n ).toEqual(['a']);\n });\n\n t('filters listRuns by a status set (status IN ...) for singleton admission', async () => {\n await store.createRun(run({ id: 'a', status: 'running' }));\n await store.createRun(run({ id: 'b', status: 'suspended' }));\n await store.createRun(run({ id: 'c', status: 'completed' }));\n await store.createRun(run({ id: 'd', status: 'pending' }));\n\n expect(\n (await store.listRuns({ statuses: ['running', 'suspended'] })).map((r) => r.id).sort(),\n ).toEqual(['a', 'b']);\n // Single + set are ANDed (the narrower set wins).\n expect(\n (await store.listRuns({ status: 'running', statuses: ['running', 'suspended'] })).map(\n (r) => r.id,\n ),\n ).toEqual(['a']);\n // Empty set matches nothing.\n expect(await store.listRuns({ statuses: [] })).toHaveLength(0);\n });\n\n t('filters listRuns by an exact tag (no substring match)', async () => {\n if (!supportsTagFilter) return; // Prisma + SQLite: array_contains is unsupported there (see flag doc)\n await store.createRun(run({ id: 'a', tags: ['etl', 'critical'] }));\n await store.createRun(run({ id: 'b', tags: ['etl-foo'] }));\n await store.createRun(run({ id: 'c' })); // no tags\n\n expect((await store.getRun('a'))?.tags).toEqual(['etl', 'critical']);\n expect((await store.listRuns({ tag: 'etl' })).map((r) => r.id)).toEqual(['a']);\n expect((await store.listRuns({ tag: 'etl-foo' })).map((r) => r.id)).toEqual(['b']);\n expect(await store.listRuns({ tag: 'nope' })).toHaveLength(0);\n });\n\n t(\n 'round-trips a run origin and filters listRuns by it, never matching an absent one',\n async () => {\n // `origin` (which library registered the workflow) is derived at registration, never declared,\n // so ABSENCE is a first-class value: `undefined` means UNKNOWN — a row written before the\n // column existed, a `registerRemote`, convention routing, an unresolvable package. It must\n // survive the round trip as `undefined` rather than as any plausible-looking stand-in, which a\n // real registration would then be indistinguishable from.\n await store.createRun(run({ id: 'a', origin: '@dudousxd/nestjs-catalog-pipeline' }));\n await store.createRun(run({ id: 'b', origin: '@dudousxd/nestjs-agent' }));\n await store.createRun(run({ id: 'c' })); // unattributed — unknown origin\n\n expect((await store.getRun('a'))?.origin).toBe('@dudousxd/nestjs-catalog-pipeline');\n expect((await store.getRun('c'))?.origin).toBeUndefined();\n\n // `RunQuery.origin` is plain equality, so the unattributed run matches NO origin value — it is\n // excluded here exactly as `b` is, and is never folded into a bucket to make a facet look\n // complete. A store that widened this to `= x OR IS NULL` would return `c` and fail.\n expect(\n (await store.listRuns({ origin: '@dudousxd/nestjs-catalog-pipeline' })).map((r) => r.id),\n ).toEqual(['a']);\n // Nor does it answer to a name invented for it.\n expect(await store.listRuns({ origin: 'unknown' })).toEqual([]);\n // Which is why \"all origins\" has to stay the default view: with the filter off — and only\n // then — the unattributed run is reachable.\n expect((await store.listRuns({})).map((r) => r.id).sort()).toEqual(['a', 'b', 'c']);\n },\n );\n\n t('orders listRuns newest-first and paginates with limit/offset', async () => {\n await store.createRun(run({ id: 'old', createdAt: new Date('2026-06-11T00:00:00.000Z') }));\n await store.createRun(run({ id: 'mid', createdAt: new Date('2026-06-11T00:00:01.000Z') }));\n await store.createRun(run({ id: 'new', createdAt: new Date('2026-06-11T00:00:02.000Z') }));\n\n expect((await store.listRuns({})).map((r) => r.id)).toEqual(['new', 'mid', 'old']);\n expect((await store.listRuns({ limit: 2 })).map((r) => r.id)).toEqual(['new', 'mid']);\n expect((await store.listRuns({ limit: 2, offset: 1 })).map((r) => r.id)).toEqual([\n 'mid',\n 'old',\n ]);\n });\n\n // ---- search-attribute pushdown (range + equality + the missing-key contract) ------------\n\n t('round-trips searchAttributes and answers equality + range attribute queries', async () => {\n await store.createRun(run({ id: 'a', searchAttributes: { amount: 30, tier: 'free' } }));\n await store.createRun(run({ id: 'b', searchAttributes: { amount: 200, tier: 'pro' } }));\n await store.createRun(run({ id: 'c', searchAttributes: { amount: 500, tier: 'pro' } }));\n\n expect((await store.getRun('b'))?.searchAttributes).toEqual({ amount: 200, tier: 'pro' });\n\n // Range (numeric).\n expect(\n (await store.listRuns({ attributes: [{ key: 'amount', op: 'gte', value: 200 }] }))\n .map((r) => r.id)\n .sort(),\n ).toEqual(['b', 'c']);\n // Two ANDed predicates (string eq + numeric range).\n expect(\n (\n await store.listRuns({\n attributes: [\n { key: 'tier', op: 'eq', value: 'pro' },\n { key: 'amount', op: 'lt', value: 300 },\n ],\n })\n ).map((r) => r.id),\n ).toEqual(['b']);\n // `ne` excludes the matching value AND absent keys (missing-key-never-matches contract).\n expect(\n (await store.listRuns({ attributes: [{ key: 'tier', op: 'ne', value: 'free' }] }))\n .map((r) => r.id)\n .sort(),\n ).toEqual(['b', 'c']);\n });\n\n t('matches a boolean search attribute by eq/ne', async () => {\n await store.createRun(run({ id: 'a', searchAttributes: { vip: true } }));\n await store.createRun(run({ id: 'b', searchAttributes: { vip: false } }));\n await store.createRun(run({ id: 'c', searchAttributes: { other: 1 } })); // no `vip`\n\n expect(\n (await store.listRuns({ attributes: [{ key: 'vip', op: 'eq', value: true }] })).map(\n (r) => r.id,\n ),\n ).toEqual(['a']);\n // ne=true matches the explicit false but NOT the run missing `vip` (missing-key contract).\n expect(\n (await store.listRuns({ attributes: [{ key: 'vip', op: 'ne', value: true }] })).map(\n (r) => r.id,\n ),\n ).toEqual(['b']);\n });\n\n t('a predicate on an absent key matches nothing (every op)', async () => {\n await store.createRun(run({ id: 'a', searchAttributes: { amount: 100 } }));\n for (const op of ['eq', 'ne', 'gt', 'gte', 'lt', 'lte'] as const) {\n expect(\n await store.listRuns({ attributes: [{ key: 'missing', op, value: 1 }] }),\n ).toHaveLength(0);\n }\n });\n\n t(\n 're-indexes the search-attribute side-table on update (old values stop matching)',\n async () => {\n await store.createRun(run({ id: 'a', searchAttributes: { tier: 'free', amount: 10 } }));\n expect(\n (await store.listRuns({ attributes: [{ key: 'tier', op: 'eq', value: 'free' }] })).map(\n (r) => r.id,\n ),\n ).toEqual(['a']);\n\n await store.updateRun('a', { searchAttributes: { tier: 'pro' } });\n expect(\n (await store.listRuns({ attributes: [{ key: 'tier', op: 'eq', value: 'pro' }] })).map(\n (r) => r.id,\n ),\n ).toEqual(['a']);\n // Old key/value pairs are gone.\n expect(\n await store.listRuns({ attributes: [{ key: 'tier', op: 'eq', value: 'free' }] }),\n ).toHaveLength(0);\n expect(\n await store.listRuns({ attributes: [{ key: 'amount', op: 'eq', value: 10 }] }),\n ).toHaveLength(0);\n },\n );\n\n t('combines an attribute predicate with a coarse status filter and paginates', async () => {\n await store.createRun(run({ id: 'a', status: 'running', searchAttributes: { amount: 300 } }));\n await store.createRun(\n run({ id: 'b', status: 'completed', searchAttributes: { amount: 400 } }),\n );\n await store.createRun(run({ id: 'c', status: 'running', searchAttributes: { amount: 50 } }));\n\n const res = await store.listRuns({\n status: 'running',\n attributes: [{ key: 'amount', op: 'gte', value: 100 }],\n limit: 10,\n });\n expect(res.map((r) => r.id)).toEqual(['a']);\n });\n\n // ---- signal waiters & buffered signals --------------------------------------------------\n\n t('stores, lists by prefix, and atomically takes a signal waiter', async () => {\n await store.putSignalWaiter({ token: 'approve-1', runId: 'r1', seq: 3 });\n await store.putSignalWaiter({ token: 'approve-2', runId: 'r2', seq: 4 });\n await store.putSignalWaiter({ token: 'other-1', runId: 'r3', seq: 5 });\n\n expect((await store.listSignalWaiters('approve-')).map((w) => w.token).sort()).toEqual([\n 'approve-1',\n 'approve-2',\n ]);\n expect((await store.takeSignalWaiter('approve-1'))?.seq).toBe(3);\n // Taken exactly once.\n expect(await store.takeSignalWaiter('approve-1')).toBeNull();\n });\n\n t(\n 'round-trips a signal waiter parallelGroup (child-fan tag) through put → take → list',\n async () => {\n // A remote `gather_children` fan threads its group onto each child waiter so the resolving\n // `signal:child:` checkpoint carries it; the store must persist it on the waiter row.\n await store.putSignalWaiter({\n token: 'child:r.child.0',\n runId: 'r',\n seq: 0,\n parallelGroup: 'gather:0',\n });\n // A lone (non-fan) child await carries no group.\n await store.putSignalWaiter({ token: 'child:r.child.9', runId: 'r', seq: 9 });\n\n const listed = await store.listSignalWaiters('child:');\n expect(listed.find((w) => w.token === 'child:r.child.0')?.parallelGroup).toBe('gather:0');\n expect(listed.find((w) => w.token === 'child:r.child.9')?.parallelGroup).toBeUndefined();\n\n expect((await store.takeSignalWaiter('child:r.child.0'))?.parallelGroup).toBe('gather:0');\n expect((await store.takeSignalWaiter('child:r.child.9'))?.parallelGroup).toBeUndefined();\n },\n );\n\n t(\n \"removeSignalWaiter deletes only the exact (token, runId, seq) row, never a different run's\",\n async () => {\n // A stale identity for a token that's since been superseded (`token` is the store's primary\n // key — a later `putSignalWaiter` for the same token replaces the row) must be a no-op: it\n // must NOT steal the new owner's row out from under it.\n await store.putSignalWaiter({ token: 'approve-1', runId: 'r1', seq: 3 });\n await store.putSignalWaiter({ token: 'approve-1', runId: 'r2', seq: 7 });\n await store.removeSignalWaiter({ token: 'approve-1', runId: 'r1', seq: 3 });\n expect((await store.listSignalWaiters('approve-')).map((w) => w.runId)).toEqual(['r2']);\n\n // A mismatched runId/seq against the CURRENT row is also a no-op.\n await store.removeSignalWaiter({ token: 'approve-1', runId: 'r2', seq: 999 });\n expect((await store.listSignalWaiters('approve-')).map((w) => w.runId)).toEqual(['r2']);\n\n // The exact match deletes it.\n await store.removeSignalWaiter({ token: 'approve-1', runId: 'r2', seq: 7 });\n expect(await store.listSignalWaiters('approve-')).toEqual([]);\n\n // Removing an absent row entirely is a no-op, not an error.\n await store.removeSignalWaiter({ token: 'never-registered', runId: 'r1', seq: 0 });\n },\n );\n\n t('buffers signals and takes them FIFO per token', async () => {\n await store.bufferSignal('sig', { n: 1 });\n await store.bufferSignal('sig', { n: 2 });\n await store.bufferSignal('other', { n: 9 });\n\n expect(await store.takeBufferedSignal('sig')).toEqual({ payload: { n: 1 } });\n expect(await store.takeBufferedSignal('sig')).toEqual({ payload: { n: 2 } });\n expect(await store.takeBufferedSignal('sig')).toBeNull();\n expect(await store.takeBufferedSignal('other')).toEqual({ payload: { n: 9 } });\n });\n\n t('buffers events per name, oldest-first, and lists them without consuming', async () => {\n await store.bufferEvent({\n name: 'order.paid',\n payload: { n: 1 },\n id: 'e1',\n publishedAt: 100,\n });\n await store.bufferEvent({\n name: 'order.paid',\n payload: { n: 2 },\n id: 'e2',\n publishedAt: 200,\n });\n await store.bufferEvent({\n name: 'other.event',\n payload: { n: 9 },\n id: 'e3',\n publishedAt: 50,\n });\n\n const listed = await store.listBufferedEvents('order.paid', 10);\n expect(listed.map((e) => e.payload)).toEqual([{ n: 1 }, { n: 2 }]); // oldest (publishedAt) first\n expect(listed.map((e) => e.id)).toEqual(['e1', 'e2']);\n expect(listed[0]?.publishedAt).toBe(100);\n // listing does not consume — the same rows are still there.\n expect(await store.listBufferedEvents('order.paid', 10)).toHaveLength(2);\n expect(await store.listBufferedEvents('other.event', 10)).toEqual([\n { id: 'e3', payload: { n: 9 }, publishedAt: 50 },\n ]);\n });\n\n t('listBufferedEvents caps at `limit`', async () => {\n await store.bufferEvent({ name: 'evt', payload: 1, id: 'a', publishedAt: 1 });\n await store.bufferEvent({ name: 'evt', payload: 2, id: 'b', publishedAt: 2 });\n await store.bufferEvent({ name: 'evt', payload: 3, id: 'c', publishedAt: 3 });\n\n expect(await store.listBufferedEvents('evt', 2)).toHaveLength(2);\n });\n\n t(\n 'removeBufferedEvent atomically deletes by id — true iff a row existed, false on a repeat/absent id',\n async () => {\n await store.bufferEvent({ name: 'evt', payload: { ok: true }, id: 'x1', publishedAt: 1 });\n\n expect(await store.removeBufferedEvent('x1')).toBe(true);\n expect(await store.listBufferedEvents('evt', 10)).toEqual([]);\n // Already gone — a second attempt (the concurrent-claim arbiter) reports false, not an error.\n expect(await store.removeBufferedEvent('x1')).toBe(false);\n expect(await store.removeBufferedEvent('never-buffered')).toBe(false);\n },\n );\n\n // ---- transaction (optional) -------------------------------------------------------------\n\n t('transaction commits the checkpoint atomically and returns the work result', async () => {\n if (!store.transaction) return; // store without transactions (rare); skip\n if (!supportsAsyncTransaction) return; // sync driver (Drizzle + better-sqlite3); skip — see flag doc\n await store.createRun(run());\n const result = await store.transaction(async (tx) => {\n await tx.saveCheckpoint(checkpoint({ seq: 7, name: 'tx-step', output: { paid: true } }));\n return 'ok';\n });\n expect(result).toBe('ok');\n const cp = await store.getCheckpoint('r1', 7);\n expect(cp?.name).toBe('tx-step');\n expect(cp?.output).toEqual({ paid: true });\n });\n\n // ---- engine end-to-end durability -------------------------------------------------------\n\n t(\n 'runs the engine end-to-end durably, resuming without re-running completed steps',\n async () => {\n const engine = new WorkflowEngine({ store });\n let aRuns = 0;\n let failOnce = true;\n engine.register('wf', '1', async (ctx) => {\n const a = await ctx.localStep('a', async () => {\n aRuns += 1;\n return 10;\n });\n const b = await ctx.localStep('b', async () => {\n if (failOnce) {\n failOnce = false;\n throw new Error('boom');\n }\n return a + 5;\n });\n return b;\n });\n await engine.start('wf', { x: 1 }, 'run1');\n expect((await engine.waitForRun('run1')).status).toBe('failed');\n const resumed = await engine.resume('run1');\n expect(resumed.status).toBe('completed');\n expect(resumed.output).toBe(15);\n // Step `a` checkpointed `completed` the first turn, so replay returns it instead of re-running.\n expect(aRuns).toBe(1);\n },\n );\n });\n}\n","/** A step body that throws once, then returns `value` — drives a retry, or a crash-then-resume. */\nexport function failOnce<T>(\n value: T,\n error: Error = new Error('injected failure'),\n): () => Promise<T> {\n return failTimes(1, value, error);\n}\n\n/** A step body that throws the first `n` times, then returns `value`. */\nexport function failTimes<T>(\n n: number,\n value: T,\n error: Error = new Error('injected failure'),\n): () => Promise<T> {\n let calls = 0;\n return async () => {\n calls += 1;\n if (calls <= n) throw error;\n return value;\n };\n}\n","import { InMemoryStateStore, type Transport, WorkflowEngine } from '@dudousxd/nestjs-durable-core';\n\n/** A transport that can register worker handlers (every shipped transport does). */\nexport type HandleableTransport = Transport & {\n handle(name: string, fn: (input: unknown) => Promise<unknown>): void;\n close?(): Promise<void>;\n};\n\nconst ECHO_STEP_NAME = 'conformance.echo';\n\n/**\n * A durable `ctx.call` suspends the run; the worker result resumes it asynchronously (on whatever\n * tick/poll the transport delivers on). Poll the store until the run reaches a terminal state —\n * with a generous budget so a poll-based transport (DB/SQS) has time to round-trip.\n */\nasync function settle(store: InMemoryStateStore, runId: string, timeoutMs = 15_000) {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n const run = await store.getRun(runId);\n if (run && run.status !== 'pending' && run.status !== 'running' && run.status !== 'suspended')\n return run;\n await new Promise((r) => setTimeout(r, 25));\n }\n throw new Error(`run ${runId} did not settle within ${timeoutMs}ms`);\n}\n\n/**\n * The contract every `Transport` must satisfy: a remote step dispatched through it round-trips to a\n * worker and back (success), and a throwing handler surfaces as a failed run (failure). Point it at\n * a freshly constructed transport (engine-side + worker `group` in one instance) to prove parity —\n * useful when adding a new transport. Throws on any mismatch; closes the transport when done.\n *\n * `idPrefix` keeps run ids unique across invocations against real, shared infra (queues/tables).\n */\nexport async function assertTransportConformance(\n transport: HandleableTransport,\n idPrefix = 'conf',\n): Promise<void> {\n try {\n // One engine/store/transport — a durable remote step routes its result back to this engine,\n // which resumes the run. (Two engines on one transport would fight over the result stream.)\n const store = new InMemoryStateStore();\n const engine = new WorkflowEngine({ store, transport });\n engine.register(\n 'conf-ok',\n '1',\n async (ctx) => (await ctx.step<{ doubled: number }>(ECHO_STEP_NAME, { n: 21 })).doubled,\n );\n engine.register('conf-fail', '1', async (ctx) => ctx.step(ECHO_STEP_NAME, { n: 1 }));\n\n // success: the worker doubles the input\n transport.handle(ECHO_STEP_NAME, async (input) => ({\n doubled: (input as { n: number }).n * 2,\n }));\n await engine.start('conf-ok', {}, `${idPrefix}-ok`);\n const ok = await settle(store, `${idPrefix}-ok`);\n if (ok.status !== 'completed' || ok.output !== 42) {\n throw new Error(`expected completed/42, got ${JSON.stringify(ok)}`);\n }\n\n // failure: a throwing handler surfaces as a failed run (re-register the same step to throw)\n transport.handle(ECHO_STEP_NAME, async () => {\n throw new Error('handler boom');\n });\n await engine.start('conf-fail', {}, `${idPrefix}-fail`);\n const failed = await settle(store, `${idPrefix}-fail`);\n if (failed.status !== 'failed') {\n throw new Error(`expected failed, got ${JSON.stringify(failed)}`);\n }\n } finally {\n await transport.close?.();\n }\n}\n"],"mappings":"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","names":["describe","expect","it","runAdmissionBackendContract","name","makeBackend","describe","now","make","config","backend","register","it","b","concurrency","expect","tryAdmit","waiterId","ok","toBe","release","rateLimit","limit","periodMs","priority","order","fairness","key","requireRun","store","runId","run","getRun","Error","assertRunStatus","status","assertOutput","expected","JSON","stringify","output","recordedSteps","listCheckpoints","map","cp","name","assertStepsRan","names","ran","includes","join","assertStepAttempts","attempts","find","c","DURABLE_CANONICAL_COLUMNS","durable_workflow_runs","id","workflow","workflowVersion","status","input","output","error","wakeAt","lockedBy","lockedUntil","recoveryAttempts","tags","searchAttributes","priority","origin","namespace","createdAt","updatedAt","durable_step_checkpoints","runId","seq","name","kind","stepId","events","attempts","workerGroup","enqueuedAt","startedAt","finishedAt","durable_run_attributes","key","strValue","numValue","durable_signal_waiters","token","durable_buffered_signals","payload","durable_buffered_events","publishedAt","assertDurableColumns","resolve","expected","mismatches","table","props","Object","entries","property","column","actual","push","preserveColumnExpectation","out","fromEntries","keys","map","p","InMemoryStateStore","InMemoryTransport","WorkflowEngine","MutableClock","current","now","set","ms","advance","createTestEngine","store","InMemoryStateStore","transport","InMemoryTransport","clock","engine","WorkflowEngine","tick","resumeDueTimers","run","workflow","input","runId","opts","start","waitForRun","InMemoryStateStore","WorkflowEngine","assertReplayable","register","history","store","InMemoryStateStore","createRun","run","status","lockedBy","undefined","lockedUntil","cp","checkpoints","saveCheckpoint","engine","WorkflowEngine","result","resume","id","error","message","startsWith","err","Error","name","WorkflowEngine","beforeEach","describe","expect","it","StateStoreUnavailableError","Error","isStateStoreUnavailable","message","name","isUnavailable","err","at","Date","run","over","id","workflow","workflowVersion","status","input","orderId","createdAt","updatedAt","checkpoint","runId","seq","kind","stepId","output","ok","attempts","enqueuedAt","startedAt","finishedAt","runStateStoreContract","makeStore","describe","store","cleanup","supportsAsyncTransaction","supportsTagFilter","skipReason","loggedSkip","beforeEach","ctx","undefined","console","warn","t","label","fn","it","createRun","loaded","getRun","expect","toBe","toEqual","toBeNull","recoveryAttempts","updateRun","total","done","dead","priority","toBeUndefined","searchAttributes","tier","saveCheckpoint","putSignalWaiter","token","deleteRun","listCheckpoints","listSignalWaiters","listRuns","attributes","key","op","value","resolves","error","tags","lockedBy","wakeAt","lockedUntil","r","awaitingDecisionTaskId","chargeId","again","getCheckpoint","list","map","c","pct","getLatestCheckpointByName","toBeDefined","latest","call","listCheckpointsByNamePrefix","matches","events","level","listIncompleteRuns","listPendingRuns","listDueTimers","toHaveLength","namespace","sort","tryLockRun","releaseRunLock","renewRunLock","statuses","tag","origin","limit","offset","amount","vip","other","res","w","takeSignalWaiter","parallelGroup","listed","find","removeSignalWaiter","bufferSignal","n","takeBufferedSignal","payload","bufferEvent","publishedAt","listBufferedEvents","e","removeBufferedEvent","transaction","result","tx","paid","cp","engine","WorkflowEngine","aRuns","failOnce","register","a","localStep","b","start","x","waitForRun","resumed","resume","failOnce","value","error","Error","failTimes","n","calls","InMemoryStateStore","WorkflowEngine","ECHO_STEP_NAME","settle","store","runId","timeoutMs","deadline","Date","now","run","getRun","status","Promise","r","setTimeout","Error","assertTransportConformance","transport","idPrefix","InMemoryStateStore","engine","WorkflowEngine","register","ctx","step","n","doubled","handle","input","start","ok","output","JSON","stringify","failed","close"]}
1
+ {"version":3,"sources":["../src/admission-backend-conformance.ts","../src/assertions.ts","../src/durable-columns.ts","../src/harness.ts","../src/replay.ts","../src/state-store-conformance.ts","../src/steps.ts","../src/transport-conformance.ts"],"sourcesContent":["import type { AdmissionBackend, QueueConfig } from '@dudousxd/nestjs-durable-core';\nimport { describe, expect, it } from 'vitest';\n\n/**\n * Builds an {@link AdmissionBackend} bound to the given test clock. Implementations that hold their\n * own resources (e.g. a Redis connection) should register the instance for teardown out-of-band.\n */\nexport type AdmissionBackendFactory = (clock: () => number) => AdmissionBackend;\n\n/**\n * The SHARED cross-backend behavioural contract for the flow-control admission gate. Both the\n * in-process `InMemoryAdmissionBackend` and the Redis `RedisAdmissionBackend` run it, so their\n * concurrency / rate-limit / ordering semantics can never silently drift apart — backend-specific\n * concerns (leases, pub/sub, cross-pod globality) live in each adapter's own spec.\n *\n * The engine always passes a stable `waiterId`, so every gated call is order-tracked: ties with no\n * priority/fairness fall back to arrival FIFO (or LIFO when configured). These cases assert exactly\n * that, on ONE backend instance.\n */\nexport function runAdmissionBackendContract(\n name: string,\n makeBackend: AdmissionBackendFactory,\n): void {\n describe(`AdmissionBackend contract: ${name}`, () => {\n let now = 1_000_000;\n const make = (config: QueueConfig) => {\n now = 1_000_000;\n const backend = makeBackend(() => now);\n backend.register(config);\n return backend;\n };\n\n it('caps concurrency: a second call blocks until the first releases', async () => {\n const b = make({ name: 'q', concurrency: 1 });\n expect((await b.tryAdmit('q', { waiterId: 'a' })).ok).toBe(true);\n expect((await b.tryAdmit('q', { waiterId: 'b' })).ok).toBe(false);\n await b.release('q', 'a');\n expect((await b.tryAdmit('q', { waiterId: 'b' })).ok).toBe(true);\n });\n\n it('enforces a fixed-window rate limit', async () => {\n const b = make({ name: 'q', rateLimit: { limit: 2, periodMs: 1000 } });\n expect((await b.tryAdmit('q', { waiterId: '1' })).ok).toBe(true);\n expect((await b.tryAdmit('q', { waiterId: '2' })).ok).toBe(true);\n expect((await b.tryAdmit('q', { waiterId: '3' })).ok).toBe(false);\n now += 1001;\n expect((await b.tryAdmit('q', { waiterId: '4' })).ok).toBe(true);\n });\n\n it('admits the highest-priority waiter first when a slot frees', async () => {\n const b = make({ name: 'q', concurrency: 1 });\n expect((await b.tryAdmit('q', { waiterId: 'holder' })).ok).toBe(true);\n expect((await b.tryAdmit('q', { waiterId: 'low', priority: 1 })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'high', priority: 9 })).ok).toBe(false);\n await b.release('q', 'holder');\n expect((await b.tryAdmit('q', { waiterId: 'low', priority: 1 })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'high', priority: 9 })).ok).toBe(true);\n });\n\n it('orders plain-concurrency waiters by arrival (FIFO) — no priority/fairness configured', async () => {\n const b = make({ name: 'q', concurrency: 1 });\n expect((await b.tryAdmit('q', { waiterId: 'holder' })).ok).toBe(true);\n expect((await b.tryAdmit('q', { waiterId: 'first' })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'second' })).ok).toBe(false);\n await b.release('q', 'holder');\n // The earlier arrival wins the freed slot, on every backend.\n expect((await b.tryAdmit('q', { waiterId: 'second' })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'first' })).ok).toBe(true);\n });\n\n it('admits the most-recent arrival first when order is LIFO', async () => {\n const b = make({ name: 'q', concurrency: 1, order: 'lifo' });\n expect((await b.tryAdmit('q', { waiterId: 'holder' })).ok).toBe(true);\n expect((await b.tryAdmit('q', { waiterId: 'first' })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'second' })).ok).toBe(false);\n await b.release('q', 'holder');\n expect((await b.tryAdmit('q', { waiterId: 'first' })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'second' })).ok).toBe(true);\n });\n\n it('round-robins a contended slot across fairness keys', async () => {\n const b = make({ name: 'q', concurrency: 1, fairness: 'key' });\n expect((await b.tryAdmit('q', { waiterId: 'a0', key: 'A' })).ok).toBe(true);\n expect((await b.tryAdmit('q', { waiterId: 'a1', key: 'A' })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'b0', key: 'B' })).ok).toBe(false);\n await b.release('q', 'a0');\n // B (never served) wins over A (just served), not arrival order.\n expect((await b.tryAdmit('q', { waiterId: 'a1', key: 'A' })).ok).toBe(false);\n expect((await b.tryAdmit('q', { waiterId: 'b0', key: 'B' })).ok).toBe(true);\n });\n\n it('leaves an unregistered queue ungated', async () => {\n const b = make({ name: 'q', concurrency: 1 });\n expect((await b.tryAdmit('other', { waiterId: 'x' })).ok).toBe(true);\n expect((await b.tryAdmit('other', { waiterId: 'y' })).ok).toBe(true);\n });\n });\n}\n","import type { RunStatus, StateStore } from '@dudousxd/nestjs-durable-core';\n\nasync function requireRun(store: StateStore, runId: string) {\n const run = await store.getRun(runId);\n if (!run) throw new Error(`assertion failed: run ${runId} not found`);\n return run;\n}\n\nexport async function assertRunStatus(\n store: StateStore,\n runId: string,\n status: RunStatus,\n): Promise<void> {\n const run = await requireRun(store, runId);\n if (run.status !== status) {\n throw new Error(`expected run ${runId} to be \"${status}\", but it was \"${run.status}\"`);\n }\n}\n\nexport async function assertOutput(\n store: StateStore,\n runId: string,\n expected: unknown,\n): Promise<void> {\n const run = await requireRun(store, runId);\n if (JSON.stringify(run.output) !== JSON.stringify(expected)) {\n throw new Error(\n `expected run ${runId} output ${JSON.stringify(expected)}, got ${JSON.stringify(run.output)}`,\n );\n }\n}\n\n/** The names of the steps that have run, in order. */\nexport async function recordedSteps(store: StateStore, runId: string): Promise<string[]> {\n return (await store.listCheckpoints(runId)).map((cp) => cp.name);\n}\n\n/** Assert every named step ran (in any order). */\nexport async function assertStepsRan(\n store: StateStore,\n runId: string,\n names: string[],\n): Promise<void> {\n const ran = await recordedSteps(store, runId);\n for (const name of names) {\n if (!ran.includes(name)) {\n throw new Error(`expected step \"${name}\" to have run; ran: [${ran.join(', ')}]`);\n }\n }\n}\n\n/** Assert a step ran exactly the given number of attempts (e.g. to verify retries). */\nexport async function assertStepAttempts(\n store: StateStore,\n runId: string,\n name: string,\n attempts: number,\n): Promise<void> {\n const cp = (await store.listCheckpoints(runId)).find((c) => c.name === name);\n if (!cp) throw new Error(`expected step \"${name}\" to have run, but it did not`);\n if (cp.attempts !== attempts) {\n throw new Error(`expected step \"${name}\" to take ${attempts} attempt(s), took ${cp.attempts}`);\n }\n}\n","/**\n * The canonical physical column names for the durable tables, keyed by table → entity property →\n * column. This is the cross-adapter contract: a run written by one store adapter must be readable by\n * another, so EVERY adapter (TypeORM, MikroORM, Prisma, Drizzle) must map these properties to these\n * exact columns. The canonical convention is `snake_case`.\n *\n * Each adapter has a spec that asserts its physical columns against this map (see `assertDurableColumns`).\n * Without it, adapters silently diverge — one defaulting to its ORM's `snake_case` naming strategy,\n * another keeping the verbatim camelCase property name — and a store swap fails against an existing\n * table with \"Unknown column\" only at runtime. The map exists so that divergence is a failing unit\n * test, not a production incident.\n *\n * The camelCase (\"preserve\") naming is simply the property names themselves (the object keys), so no\n * separate map is needed for it.\n *\n * A property belongs here only when EVERY adapter declares it — the assertion walks this map and\n * reports a missing property as a mismatch, so listing a column one adapter doesn't have would fail\n * that adapter for a divergence it isn't guilty of. An absence here therefore records one of two\n * different things, and telling them apart matters: a naming question nobody has settled, or a\n * capability one adapter has and the others do not.\n *\n * `WorkflowRun.namespace` was the standing example of the second kind, and it is worth keeping the\n * story because of how it ended. Only the MikroORM adapter had the column; the other three did not\n * declare the `namespace` parameter on `listPendingRuns`/`listIncompleteRuns`/`listDueTimers` at\n * all, which TypeScript permits, so they satisfied `StateStore` while ignoring the tenant boundary\n * entirely. The gap was real and this map was right to stay quiet about it — but \"this map is quiet\"\n * was also the only thing standing between that and a cross-tenant incident. All four adapters carry\n * the column now, so it is pinned below, and the conformance suite asserts the boundary itself\n * rather than only the column's name.\n */\nexport const DURABLE_CANONICAL_COLUMNS = {\n durable_workflow_runs: {\n id: 'id',\n workflow: 'workflow',\n workflowVersion: 'workflow_version',\n status: 'status',\n input: 'input',\n output: 'output',\n error: 'error',\n wakeAt: 'wake_at',\n lockedBy: 'locked_by',\n lockedUntil: 'locked_until',\n // The REMOTE turn the engine suspended on; `completeRemoteDecision` matches against it so only\n // the currently-awaited turn's decision is applied. A store swap that lost this column would not\n // fail loudly — it would apply a stale decision to the wrong turn — which is why it is pinned\n // rather than left to each adapter's own spec.\n awaitingDecisionTaskId: 'awaiting_decision_task_id',\n recoveryAttempts: 'recovery_attempts',\n tags: 'tags',\n searchAttributes: 'search_attributes',\n priority: 'priority',\n // Which library registered the workflow. Single-word, so `snake_case` and `preserve` agree and\n // an adapter can look canonical by accident — which is exactly why it is pinned here rather than\n // left to four per-adapter assertions to keep saying the same thing.\n origin: 'origin',\n // The tenant a run belongs to, and the predicate on every poll tick. Pinned here\n // now that all four adapters carry the column — see the note above, which used to\n // name this as the standing example of a capability gap the map cannot express.\n namespace: 'namespace',\n createdAt: 'created_at',\n updatedAt: 'updated_at',\n },\n durable_step_checkpoints: {\n runId: 'run_id',\n seq: 'seq',\n name: 'name',\n kind: 'kind',\n stepId: 'step_id',\n status: 'status',\n input: 'input',\n output: 'output',\n error: 'error',\n events: 'events',\n attempts: 'attempts',\n workerGroup: 'worker_group',\n // A `ctx.gather`/`ctx.all` fan tags every sibling step with the same group so the dashboard can\n // render them as one parallel group. Same physical name in the waiter table below — two tables,\n // one column name, which is precisely the kind of near-duplicate that drifts if unpinned.\n parallelGroup: 'parallel_group',\n wakeAt: 'wake_at',\n enqueuedAt: 'enqueued_at',\n startedAt: 'started_at',\n finishedAt: 'finished_at',\n },\n durable_run_attributes: {\n runId: 'run_id',\n key: 'key',\n strValue: 'str_value',\n numValue: 'num_value',\n },\n durable_signal_waiters: {\n token: 'token',\n runId: 'run_id',\n seq: 'seq',\n // The fan-out group threaded onto a child waiter, so the resolving `signal:child:` checkpoint\n // carries it. Only fan-out child waiters populate it, but every adapter declares the column.\n parallelGroup: 'parallel_group',\n },\n durable_buffered_signals: {\n id: 'id',\n token: 'token',\n payload: 'payload',\n },\n durable_buffered_events: {\n id: 'id',\n name: 'name',\n payload: 'payload',\n publishedAt: 'published_at',\n },\n} as const;\n\nexport type DurableColumnMap = typeof DURABLE_CANONICAL_COLUMNS;\n\n/** A single column-name disagreement found by {@link assertDurableColumns}. */\nexport interface DurableColumnMismatch {\n table: string;\n property: string;\n expected: string;\n actual: string | undefined;\n}\n\n/**\n * Walk every (table, property) in the canonical contract and compare it to what an adapter actually\n * maps, via the supplied `resolve(table, property) => columnName`. Returns the list of mismatches\n * (empty when the adapter is canonical) so a spec can `expect(assertDurableColumns(resolve)).toEqual([])`.\n *\n * Pass `expected = DURABLE_CANONICAL_COLUMNS` (default) for the snake_case contract, or a map of the\n * property names to themselves to assert the camelCase (\"preserve\") naming.\n */\nexport function assertDurableColumns(\n resolve: (table: string, property: string) => string | undefined,\n expected: Record<string, Record<string, string>> = DURABLE_CANONICAL_COLUMNS,\n): DurableColumnMismatch[] {\n const mismatches: DurableColumnMismatch[] = [];\n for (const [table, props] of Object.entries(expected)) {\n for (const [property, column] of Object.entries(props)) {\n const actual = resolve(table, property);\n if (actual !== column) mismatches.push({ table, property, expected: column, actual });\n }\n }\n return mismatches;\n}\n\n/** The \"preserve\" (camelCase) expectation: every property maps to a column of the same name. */\nexport function preserveColumnExpectation(): Record<string, Record<string, string>> {\n const out: Record<string, Record<string, string>> = {};\n for (const [table, props] of Object.entries(DURABLE_CANONICAL_COLUMNS)) {\n out[table] = Object.fromEntries(Object.keys(props).map((p) => [p, p]));\n }\n return out;\n}\n","import {\n InMemoryStateStore,\n InMemoryTransport,\n type RunResult,\n type StartOptions,\n WorkflowEngine,\n type WorkflowRef,\n} from '@dudousxd/nestjs-durable-core';\n\n/** A clock you control, for testing durable sleeps without real time. */\nexport class MutableClock {\n constructor(private current = 1_000) {}\n readonly now = (): number => this.current;\n set(ms: number): void {\n this.current = ms;\n }\n advance(ms: number): void {\n this.current += ms;\n }\n}\n\nexport interface TestEngine {\n engine: WorkflowEngine;\n store: InMemoryStateStore;\n transport: InMemoryTransport;\n clock: MutableClock;\n /** Advance the clock by `ms` and resume any durable sleeps now due. */\n tick(ms: number): Promise<RunResult[]>;\n /**\n * Enqueue a run and wait for it to settle (terminal or suspended). `engine.start` only enqueues\n * now (dispatch model), so use this when a test needs the outcome synchronously.\n */\n run(\n workflow: WorkflowRef,\n input: unknown,\n runId: string,\n opts?: StartOptions,\n ): Promise<RunResult>;\n}\n\n/**\n * A self-contained engine wired to in-memory store + transport and a controllable clock — run a\n * whole workflow in a unit test, with no Postgres, no Redis, and no real time.\n */\nexport function createTestEngine(): TestEngine {\n const store = new InMemoryStateStore();\n const transport = new InMemoryTransport();\n const clock = new MutableClock();\n const engine = new WorkflowEngine({ store, transport, clock: clock.now });\n return {\n engine,\n store,\n transport,\n clock,\n async tick(ms: number): Promise<RunResult[]> {\n clock.advance(ms);\n return engine.resumeDueTimers(clock.now());\n },\n async run(workflow, input, runId, opts): Promise<RunResult> {\n // `start` is overloaded per ref kind; a `WorkflowRef` union fits neither overload directly, so\n // resolve to the string overload (the engine accepts a class or name at runtime).\n await engine.start(workflow as string, input, runId, opts);\n return engine.waitForRun(runId);\n },\n };\n}\n","import {\n InMemoryStateStore,\n type StepCheckpoint,\n WorkflowEngine,\n type WorkflowRun,\n} from '@dudousxd/nestjs-durable-core';\n\nexport interface RunHistory {\n run: WorkflowRun;\n checkpoints: StepCheckpoint[];\n}\n\n/**\n * Replay a recorded run's history against the CURRENT workflow code and throw if they diverged.\n *\n * Capture a real (ideally in-flight or representative) run from production —\n * `{ run: await store.getRun(id), checkpoints: await store.listCheckpoints(id) }` — commit it as a\n * fixture, and assert here in CI. If a code change renamed/reordered/removed a step at a position the\n * history already recorded, the engine raises a `NonDeterminismError` on replay and this rethrows it,\n * catching the break *before* it reaches an in-flight run on deploy (the moment you'd otherwise\n * silently replay the wrong checkpoint into the wrong step). Register the workflow exactly as the app\n * does:\n *\n * ```ts\n * await assertReplayable((engine) => engine.register('pipeline', '1', pipeline.run), fixture);\n * ```\n */\nexport async function assertReplayable(\n register: (engine: WorkflowEngine) => void,\n history: RunHistory,\n): Promise<void> {\n const store = new InMemoryStateStore();\n // Seed as a suspended run with no lock so resume() replays the body against the recorded\n // checkpoints — no transport is wired, so nothing new is dispatched.\n await store.createRun({\n ...history.run,\n status: 'suspended',\n lockedBy: undefined,\n lockedUntil: undefined,\n });\n for (const cp of history.checkpoints) await store.saveCheckpoint(cp);\n\n const engine = new WorkflowEngine({ store });\n register(engine);\n const result = await engine.resume(history.run.id);\n if (result.status === 'failed' && result.error?.message?.startsWith('non-determinism')) {\n const err = new Error(result.error.message);\n err.name = 'NonDeterminismError';\n throw err;\n }\n}\n","import {\n type StateStore,\n type StepCheckpoint,\n WorkflowEngine,\n type WorkflowRun,\n} from '@dudousxd/nestjs-durable-core';\nimport { beforeEach, describe, expect, it } from 'vitest';\n\n/**\n * A freshly provisioned, empty {@link StateStore} plus a `cleanup` to release its resources (close\n * the connection, drop the schema, etc.). The conformance suite asks for one before each test so\n * every case starts from a clean slate — exactly like the per-store specs that build a `:memory:` DB.\n */\nexport interface StateStoreContext {\n store: StateStore;\n cleanup: () => Promise<void>;\n /**\n * Whether the store's optional `transaction` can run an ASYNC work callback. Defaults to `true`.\n * Set `false` only for a driver that genuinely can't — e.g. Drizzle on the SYNCHRONOUS\n * `better-sqlite3` driver, whose `transaction()` rejects a promise-returning callback (\"Transaction\n * function cannot return a promise\"). The same Drizzle adapter on an async driver (libSQL) works,\n * and the contract still asserts `transaction` for every other store, so this never hides drift.\n */\n supportsAsyncTransaction?: boolean;\n /**\n * Whether the store can filter `listRuns({ tag })`. Defaults to `true`. Set `false` ONLY for\n * Prisma-on-SQLite: the Prisma adapter filters tags with the `array_contains` JSON predicate, which\n * Prisma supports on its real targets (Postgres + MySQL) but NOT on SQLite. SQLite is only the\n * adapter's local TEST database, so the tag case is skipped there; every other store (and Prisma on\n * a real engine) still asserts it, so this doesn't hide drift in the supported configurations.\n */\n supportsTagFilter?: boolean;\n}\n\n/** Builds a fresh, empty store for one test. Called once per `it` (in `beforeEach`). */\nexport type StateStoreFactory = () => Promise<StateStoreContext>;\n\n/**\n * Thrown by a {@link StateStoreFactory} to SKIP the contract for an unavailable backend instead of\n * failing it — e.g. a testcontainers DB spec when Docker isn't running. Every contract case catches\n * it, logs once, and returns (a no-op pass), so `pnpm test:db` is green-with-skips off a dev box\n * without Docker rather than red.\n */\nexport class StateStoreUnavailableError extends Error {\n readonly isStateStoreUnavailable = true;\n constructor(message: string) {\n super(message);\n this.name = 'StateStoreUnavailableError';\n }\n}\n\nfunction isUnavailable(err: unknown): err is StateStoreUnavailableError {\n return !!err && typeof err === 'object' && 'isStateStoreUnavailable' in err;\n}\n\nconst at = new Date('2026-06-11T00:00:00.000Z');\n\nconst run = (over: Partial<WorkflowRun> = {}): WorkflowRun => ({\n id: 'r1',\n workflow: 'checkout',\n workflowVersion: '1',\n status: 'running',\n input: { orderId: 'o1' },\n createdAt: at,\n updatedAt: at,\n ...over,\n});\n\nconst checkpoint = (over: Partial<StepCheckpoint> = {}): StepCheckpoint => ({\n runId: 'r1',\n seq: 0,\n name: 'reserve',\n kind: 'local',\n stepId: 'r1:0',\n status: 'completed',\n output: { ok: true },\n attempts: 1,\n enqueuedAt: at,\n startedAt: at,\n finishedAt: at,\n ...over,\n});\n\n/**\n * The SHARED behavioral contract every `StateStore` must satisfy — in-memory and each ORM adapter\n * alike. Registered as a vitest `describe`; pass a `name` and a {@link StateStoreFactory} that builds\n * a fresh, empty store. The same assertions run against SQLite/in-memory under `pnpm test` and\n * against real Postgres/MySQL (via testcontainers) under `pnpm test:db`, so any drift between an\n * adapter and the canonical (in-memory) semantics — especially the search-attribute side-table\n * pushdown, which is implemented per-store — fails here instead of silently in production.\n *\n * Each adapter's own spec keeps its dialect-specific tests (DDL/longtext/EXISTS-SQL/JSON-tolerance);\n * this suite owns the cross-store behavior so those never drift apart.\n */\nexport function runStateStoreContract(name: string, makeStore: StateStoreFactory): void {\n describe(`StateStore contract: ${name}`, () => {\n let store: StateStore;\n let cleanup: (() => Promise<void>) | undefined;\n let supportsAsyncTransaction = true;\n let supportsTagFilter = true;\n let skipReason: string | undefined;\n let loggedSkip = false;\n\n beforeEach(async () => {\n try {\n const ctx = await makeStore();\n store = ctx.store;\n cleanup = ctx.cleanup;\n supportsAsyncTransaction = ctx.supportsAsyncTransaction ?? true;\n supportsTagFilter = ctx.supportsTagFilter ?? true;\n skipReason = undefined;\n } catch (err) {\n if (isUnavailable(err)) {\n // Backend unavailable (e.g. no Docker for a testcontainers spec): skip — don't fail.\n skipReason = err.message;\n if (!loggedSkip) {\n console.warn(`[state-store-contract] SKIPPING \"${name}\": ${skipReason}`);\n loggedSkip = true;\n }\n return;\n }\n throw err;\n }\n return async () => {\n await cleanup?.();\n };\n });\n\n /** Register a contract case that no-ops (passes) when the backend was reported unavailable. */\n const t = (label: string, fn: () => Promise<void>): void => {\n it(label, async () => {\n if (skipReason) return;\n await fn();\n });\n };\n\n // ---- create / get / update --------------------------------------------------------------\n\n t('creates a run and reads it back with its JSON input', async () => {\n await store.createRun(run());\n const loaded = await store.getRun('r1');\n expect(loaded?.workflow).toBe('checkout');\n expect(loaded?.input).toEqual({ orderId: 'o1' });\n });\n\n t('returns null for a missing run', async () => {\n expect(await store.getRun('nope')).toBeNull();\n });\n\n t('updates a run (status/output) and round-trips recoveryAttempts + dead status', async () => {\n await store.createRun(run({ recoveryAttempts: 3 }));\n await store.updateRun('r1', {\n status: 'completed',\n output: { total: 42 },\n updatedAt: at,\n });\n const done = await store.getRun('r1');\n expect(done?.status).toBe('completed');\n expect(done?.output).toEqual({ total: 42 });\n expect(done?.recoveryAttempts).toBe(3);\n\n await store.updateRun('r1', { status: 'dead', recoveryAttempts: 4 });\n const dead = await store.getRun('r1');\n expect(dead?.status).toBe('dead');\n expect(dead?.recoveryAttempts).toBe(4);\n });\n\n t('round-trips a run dispatch priority', async () => {\n await store.createRun(run({ id: 'withprio', priority: 7 }));\n await store.createRun(run({ id: 'noprio' }));\n expect((await store.getRun('withprio'))?.priority).toBe(7);\n expect((await store.getRun('noprio'))?.priority).toBeUndefined();\n });\n\n t('deleteRun removes the run and all its rows (checkpoints, waiters, attributes)', async () => {\n await store.createRun(run({ searchAttributes: { tier: 'pro' } }));\n await store.saveCheckpoint(checkpoint());\n await store.putSignalWaiter({ token: 'approve-r1', runId: 'r1', seq: 0 });\n\n await store.deleteRun('r1');\n\n // The run and every child row are gone — not merely marked terminal.\n expect(await store.getRun('r1')).toBeNull();\n expect(await store.listCheckpoints('r1')).toEqual([]);\n expect(await store.listSignalWaiters('approve-')).toEqual([]);\n // The normalized attribute side-table no longer matches it.\n expect(\n await store.listRuns({\n attributes: [{ key: 'tier', op: 'eq', value: 'pro' }],\n }),\n ).toEqual([]);\n });\n\n t('deleteRun is a no-op for a missing run', async () => {\n await expect(store.deleteRun('nope')).resolves.toBeUndefined();\n });\n\n t(\n 'updateRun maps every patchable field — clears error and patches tags/lockedBy/input/timers',\n async () => {\n // Guards against per-adapter patch-whitelist drift: a store that maps only a subset of fields\n // (or ignores `undefined` instead of clearing) would silently no-op these and fail here.\n await store.createRun(\n run({ status: 'failed', error: { message: 'boom' }, tags: ['old'], lockedBy: 'owner-1' }),\n );\n await store.updateRun('r1', {\n status: 'completed',\n output: { ok: true },\n error: undefined, // completion CLEARS the prior error\n input: { orderId: 'o2' },\n tags: ['x', 'y'],\n lockedBy: 'owner-2',\n wakeAt: 123_456,\n lockedUntil: 222_222,\n updatedAt: at,\n });\n const r = await store.getRun('r1');\n expect(r?.status).toBe('completed');\n expect(r?.output).toEqual({ ok: true });\n expect(r?.error).toBeUndefined();\n expect(r?.input).toEqual({ orderId: 'o2' });\n expect(r?.tags).toEqual(['x', 'y']);\n expect(r?.lockedBy).toBe('owner-2');\n expect(r?.wakeAt).toBe(123_456);\n expect(r?.lockedUntil).toBe(222_222);\n\n // The multi-instance REMOTE-decision marker must round-trip AND clear: the engine sets it\n // when it suspends on an awaited turn and clears it (`undefined`) when the decision lands. An\n // adapter that drops it on read, or ignores `undefined` instead of writing NULL, would silently\n // break completeRemoteDecision (it reads back the stale/absent marker and discards the decision).\n await store.updateRun('r1', { awaitingDecisionTaskId: 'turn-7' });\n expect((await store.getRun('r1'))?.awaitingDecisionTaskId).toBe('turn-7');\n await store.updateRun('r1', { awaitingDecisionTaskId: undefined });\n expect((await store.getRun('r1'))?.awaitingDecisionTaskId).toBeUndefined();\n },\n );\n\n // ---- checkpoints ------------------------------------------------------------------------\n\n t(\n 'upserts checkpoints, reads them by (runId, seq), and lists them ordered by seq',\n async () => {\n await store.createRun(run());\n await store.saveCheckpoint(checkpoint());\n await store.saveCheckpoint(\n checkpoint({ seq: 1, name: 'charge', output: { chargeId: 'ch_1' } }),\n );\n // Re-save seq 0 with a new output — upsert, not a duplicate row.\n await store.saveCheckpoint(checkpoint({ output: { ok: true, again: true } }));\n\n expect((await store.getCheckpoint('r1', 0))?.output).toEqual({ ok: true, again: true });\n expect((await store.getCheckpoint('r1', 1))?.name).toBe('charge');\n const list = await store.listCheckpoints('r1');\n expect(list.map((c) => c.seq)).toEqual([0, 1]);\n },\n );\n\n t(\n 'getLatestCheckpointByName returns the highest-seq match (and undefined for none)',\n async () => {\n await store.createRun(run());\n await store.saveCheckpoint(\n checkpoint({ seq: 0, name: 'event:progress', output: { pct: 10 } }),\n );\n await store.saveCheckpoint(checkpoint({ seq: 1, name: 'charge', output: { id: 'c1' } }));\n await store.saveCheckpoint(\n checkpoint({ seq: 2, name: 'event:progress', output: { pct: 50 } }),\n );\n await store.saveCheckpoint(\n checkpoint({ seq: 3, name: 'event:progress', output: { pct: 90 } }),\n );\n\n // Optional on the interface (the engine has a fallback), but a conformant store MUST provide\n // it — assert presence, then exercise the fast path.\n const getLatestCheckpointByName = store.getLatestCheckpointByName;\n expect(getLatestCheckpointByName).toBeDefined();\n if (!getLatestCheckpointByName) return;\n\n const latest = await getLatestCheckpointByName.call(store, 'r1', 'event:progress');\n expect(latest?.seq).toBe(3);\n expect(latest?.output).toEqual({ pct: 90 });\n expect(await getLatestCheckpointByName.call(store, 'r1', 'event:missing')).toBeUndefined();\n },\n );\n\n t(\n 'listCheckpointsByNamePrefix returns prefix matches ordered by seq (empty => none)',\n async () => {\n await store.createRun(run());\n await store.saveCheckpoint(checkpoint({ seq: 0, name: 'reserve' }));\n await store.saveCheckpoint(checkpoint({ seq: 1, name: 'spawn:0', output: 'child-a' }));\n await store.saveCheckpoint(checkpoint({ seq: 2, name: 'signal:child:c2' }));\n await store.saveCheckpoint(checkpoint({ seq: 3, name: 'event:progress' }));\n await store.saveCheckpoint(checkpoint({ seq: 4, name: 'spawn:1', output: 'child-b' }));\n\n // Optional on the interface (the engine has a fallback), but a conformant store MUST provide\n // it — assert presence, then exercise the fast path.\n const listCheckpointsByNamePrefix = store.listCheckpointsByNamePrefix;\n expect(listCheckpointsByNamePrefix).toBeDefined();\n if (!listCheckpointsByNamePrefix) return;\n\n const matches = await listCheckpointsByNamePrefix.call(store, 'r1', [\n 'signal:child:',\n 'spawn:',\n ]);\n expect(matches.map((c) => c.name)).toEqual(['spawn:0', 'signal:child:c2', 'spawn:1']);\n expect(await listCheckpointsByNamePrefix.call(store, 'r1', [])).toEqual([]);\n },\n );\n\n t('round-trips checkpoint events and reads back a missing checkpoint as null', async () => {\n await store.createRun(run());\n await store.saveCheckpoint(\n checkpoint({\n events: [{ at: 1, level: 'error', message: 'p-3 failed', name: 'p-3', status: 'failed' }],\n }),\n );\n expect((await store.getCheckpoint('r1', 0))?.events).toEqual([\n { at: 1, level: 'error', message: 'p-3 failed', name: 'p-3', status: 'failed' },\n ]);\n expect(await store.getCheckpoint('r1', 99)).toBeNull();\n });\n\n // ---- recovery / dispatch / timer scans --------------------------------------------------\n\n t('lists incomplete runs, pending runs (FIFO), and due timers', async () => {\n await store.createRun(run({ id: 'running1', status: 'running' }));\n await store.createRun(run({ id: 'suspended1', status: 'suspended', wakeAt: 5_000 }));\n await store.createRun(run({ id: 'done1', status: 'completed' }));\n await store.createRun(\n run({ id: 'pending2', status: 'pending', createdAt: new Date('2026-06-11T00:00:02.000Z') }),\n );\n await store.createRun(\n run({ id: 'pending1', status: 'pending', createdAt: new Date('2026-06-11T00:00:01.000Z') }),\n );\n\n expect((await store.listIncompleteRuns()).map((r) => r.id)).toEqual(['running1']);\n // FIFO by createdAt.\n expect((await store.listPendingRuns(10)).map((r) => r.id)).toEqual(['pending1', 'pending2']);\n expect((await store.listPendingRuns(1)).map((r) => r.id)).toEqual(['pending1']);\n expect((await store.listDueTimers(10_000)).map((r) => r.id)).toEqual(['suspended1']);\n expect(await store.listDueTimers(1_000)).toHaveLength(0);\n });\n\n t('keeps a worker inside its own namespace on every path that picks work up', async () => {\n // The boundary `WorkflowRun.namespace` documents: \"A worker only picks up /\n // recovers / resumes-timers-for / times-out runs in its own namespace.\"\n //\n // This case exists because that sentence was true of exactly one adapter. The\n // other three did not declare the `namespace` parameter at all — and TypeScript\n // lets an implementation take fewer parameters than the interface promises, so\n // three stores silently ignored the argument and still satisfied `StateStore`.\n // A worker serving one tenant listed, recovered and — through `sweepTimeouts`,\n // which selects its cancellation candidates with `listRuns` — CANCELLED another\n // tenant's runs. The last of those is a write, which is why this is asserted on\n // all four paths rather than on the two that name `namespace` in their signature.\n await store.createRun(run({ id: 'a-pending', status: 'pending', namespace: 'alpha' }));\n await store.createRun(run({ id: 'b-pending', status: 'pending', namespace: 'beta' }));\n await store.createRun(run({ id: 'a-running', status: 'running', namespace: 'alpha' }));\n await store.createRun(run({ id: 'b-running', status: 'running', namespace: 'beta' }));\n await store.createRun(\n run({ id: 'a-timer', status: 'suspended', wakeAt: 5_000, namespace: 'alpha' }),\n );\n await store.createRun(\n run({ id: 'b-timer', status: 'suspended', wakeAt: 5_000, namespace: 'beta' }),\n );\n\n expect((await store.listPendingRuns(10, 'alpha')).map((r) => r.id)).toEqual(['a-pending']);\n expect((await store.listIncompleteRuns('alpha')).map((r) => r.id)).toEqual(['a-running']);\n expect((await store.listDueTimers(10_000, 'alpha')).map((r) => r.id)).toEqual(['a-timer']);\n expect(\n (await store.listRuns({ namespace: 'alpha', status: 'running' })).map((r) => r.id),\n ).toEqual(['a-running']);\n\n // Foreign runs must not eat the FIFO budget either. Asking for one row while\n // `beta` holds the oldest pending run has to return `alpha`'s, not nothing:\n // a store that filtered AFTER applying the limit would answer with an empty\n // page and look exactly like an idle tenant.\n expect((await store.listPendingRuns(1, 'alpha')).map((r) => r.id)).toEqual(['a-pending']);\n\n // `undefined` is NOT \"namespace is null\" — it is the operator view, every\n // tenant at once. A store that read it as a null predicate would pass every\n // single-tenant test written above and hide every run in a deployment that\n // actually sets `DURABLE_TENANT`.\n expect((await store.listPendingRuns(10)).map((r) => r.id).sort()).toEqual([\n 'a-pending',\n 'b-pending',\n ]);\n expect((await store.listIncompleteRuns()).map((r) => r.id).sort()).toEqual([\n 'a-running',\n 'b-running',\n ]);\n expect((await store.listDueTimers(10_000)).map((r) => r.id).sort()).toEqual([\n 'a-timer',\n 'b-timer',\n ]);\n });\n\n // ---- lease / lock -----------------------------------------------------------------------\n\n t('tryLockRun is atomic and respects lease expiry', async () => {\n await store.createRun(run({ id: 'r1' }));\n expect(await store.tryLockRun('r1', 'A', 2_000, 1_000)).toBe(true);\n // B can't take it while A's lease is live.\n expect(await store.tryLockRun('r1', 'B', 3_000, 1_500)).toBe(false);\n // Once A's lease (2_000) has passed, B reclaims it.\n expect(await store.tryLockRun('r1', 'B', 4_000, 2_500)).toBe(true);\n // Release lets anyone re-acquire immediately.\n await store.releaseRunLock('r1');\n expect(await store.tryLockRun('r1', 'C', 9_000, 2_600)).toBe(true);\n });\n\n t('renewRunLock only succeeds for the current owner', async () => {\n await store.createRun(run({ id: 'r1' }));\n expect(await store.tryLockRun('r1', 'A', 2_000, 1_000)).toBe(true);\n // The holder heartbeats and keeps the lease.\n expect(await store.renewRunLock('r1', 'A', 5_000)).toBe(true);\n // A different instance can't renew a lease it doesn't hold.\n expect(await store.renewRunLock('r1', 'B', 9_000)).toBe(false);\n // And the renewed lease is honored: B still can't steal it before it expires.\n expect(await store.tryLockRun('r1', 'B', 6_000, 4_000)).toBe(false);\n });\n\n // ---- list filters: status / statuses / tag / origin --------------------------------------\n\n t('filters listRuns by workflow and by status', async () => {\n await store.createRun(run({ id: 'a', workflow: 'checkout', status: 'running' }));\n await store.createRun(run({ id: 'b', workflow: 'refund', status: 'running' }));\n await store.createRun(run({ id: 'c', workflow: 'checkout', status: 'completed' }));\n\n expect((await store.listRuns({ workflow: 'checkout' })).map((r) => r.id).sort()).toEqual([\n 'a',\n 'c',\n ]);\n expect((await store.listRuns({ status: 'running' })).map((r) => r.id).sort()).toEqual([\n 'a',\n 'b',\n ]);\n expect(\n (await store.listRuns({ workflow: 'checkout', status: 'running' })).map((r) => r.id),\n ).toEqual(['a']);\n });\n\n t('filters listRuns by a status set (status IN ...) for singleton admission', async () => {\n await store.createRun(run({ id: 'a', status: 'running' }));\n await store.createRun(run({ id: 'b', status: 'suspended' }));\n await store.createRun(run({ id: 'c', status: 'completed' }));\n await store.createRun(run({ id: 'd', status: 'pending' }));\n\n expect(\n (await store.listRuns({ statuses: ['running', 'suspended'] })).map((r) => r.id).sort(),\n ).toEqual(['a', 'b']);\n // Single + set are ANDed (the narrower set wins).\n expect(\n (await store.listRuns({ status: 'running', statuses: ['running', 'suspended'] })).map(\n (r) => r.id,\n ),\n ).toEqual(['a']);\n // Empty set matches nothing.\n expect(await store.listRuns({ statuses: [] })).toHaveLength(0);\n });\n\n t('filters listRuns by an exact tag (no substring match)', async () => {\n if (!supportsTagFilter) return; // Prisma + SQLite: array_contains is unsupported there (see flag doc)\n await store.createRun(run({ id: 'a', tags: ['etl', 'critical'] }));\n await store.createRun(run({ id: 'b', tags: ['etl-foo'] }));\n await store.createRun(run({ id: 'c' })); // no tags\n\n expect((await store.getRun('a'))?.tags).toEqual(['etl', 'critical']);\n expect((await store.listRuns({ tag: 'etl' })).map((r) => r.id)).toEqual(['a']);\n expect((await store.listRuns({ tag: 'etl-foo' })).map((r) => r.id)).toEqual(['b']);\n expect(await store.listRuns({ tag: 'nope' })).toHaveLength(0);\n });\n\n t(\n 'round-trips a run origin and filters listRuns by it, never matching an absent one',\n async () => {\n // `origin` (which library registered the workflow) is derived at registration, never declared,\n // so ABSENCE is a first-class value: `undefined` means UNKNOWN — a row written before the\n // column existed, a `registerRemote`, convention routing, an unresolvable package. It must\n // survive the round trip as `undefined` rather than as any plausible-looking stand-in, which a\n // real registration would then be indistinguishable from.\n await store.createRun(run({ id: 'a', origin: '@dudousxd/nestjs-catalog-pipeline' }));\n await store.createRun(run({ id: 'b', origin: '@dudousxd/nestjs-agent' }));\n await store.createRun(run({ id: 'c' })); // unattributed — unknown origin\n\n expect((await store.getRun('a'))?.origin).toBe('@dudousxd/nestjs-catalog-pipeline');\n expect((await store.getRun('c'))?.origin).toBeUndefined();\n\n // `RunQuery.origin` is plain equality, so the unattributed run matches NO origin value — it is\n // excluded here exactly as `b` is, and is never folded into a bucket to make a facet look\n // complete. A store that widened this to `= x OR IS NULL` would return `c` and fail.\n expect(\n (await store.listRuns({ origin: '@dudousxd/nestjs-catalog-pipeline' })).map((r) => r.id),\n ).toEqual(['a']);\n // Nor does it answer to a name invented for it.\n expect(await store.listRuns({ origin: 'unknown' })).toEqual([]);\n // Which is why \"all origins\" has to stay the default view: with the filter off — and only\n // then — the unattributed run is reachable.\n expect((await store.listRuns({})).map((r) => r.id).sort()).toEqual(['a', 'b', 'c']);\n },\n );\n\n t(\n 'selects the UNATTRIBUTED runs when `origin` is null — the one thing a value cannot',\n async () => {\n // The console needs an \"unknown origin\" facet, and the same absence that makes `origin` match\n // no value makes it unfilterable by one. `null` asks for `origin IS NULL` instead, which is what\n // lets that facet page server-side rather than by holding every run in the browser.\n await store.createRun(run({ id: 'a', origin: '@dudousxd/nestjs-agent' }));\n await store.createRun(run({ id: 'b' }));\n await store.createRun(run({ id: 'c' }));\n\n expect((await store.listRuns({ origin: null })).map((r) => r.id).sort()).toEqual([\n 'b',\n 'c',\n ]);\n // And it stays ANDed with the other predicates rather than replacing them.\n await store.createRun(run({ id: 'd', status: 'dead' }));\n expect((await store.listRuns({ origin: null, status: 'dead' })).map((r) => r.id)).toEqual([\n 'd',\n ]);\n },\n );\n\n t('counts runs by (status, origin) without returning them', async () => {\n // The aggregate behind a console's chips. It exists so the run LIST can be paged: the page\n // bounds what is rendered, this bounds nothing — so a store that quietly applied the same limit\n // would report the page size as the deployment's totals.\n if (!store.runFacets) return; // optional on the port; every SQL adapter implements it\n await store.createRun(run({ id: 'a', status: 'completed', origin: 'pkg-a' }));\n await store.createRun(run({ id: 'b', status: 'completed', origin: 'pkg-a' }));\n await store.createRun(run({ id: 'c', status: 'failed', origin: 'pkg-b' }));\n await store.createRun(run({ id: 'd', status: 'failed' })); // unattributed\n await store.createRun(run({ id: 'e', status: 'failed' })); // unattributed\n\n const facets = await store.runFacets({});\n\n expect(facets).toContainEqual({ status: 'completed', origin: 'pkg-a', count: 2 });\n expect(facets).toContainEqual({ status: 'failed', origin: 'pkg-b', count: 1 });\n // Runs with no origin are a real, countable cell here — `null`, not a stand-in name.\n expect(facets).toContainEqual({ status: 'failed', origin: null, count: 2 });\n expect(facets.reduce((n, f) => n + f.count, 0)).toBe(5);\n });\n\n t('narrows runFacets on the same predicates listRuns pages', async () => {\n // A facet count that did not obey the tenant/tag the operator has typed would label the page\n // with a number taken over a different set.\n if (!store.runFacets) return;\n await store.createRun(run({ id: 'a', status: 'failed', namespace: 'acme' }));\n await store.createRun(run({ id: 'b', status: 'failed', namespace: 'globex' }));\n\n expect(await store.runFacets({ namespace: 'acme' })).toEqual([\n { status: 'failed', origin: null, count: 1 },\n ]);\n });\n\n t('orders listRuns newest-first and paginates with limit/offset', async () => {\n await store.createRun(run({ id: 'old', createdAt: new Date('2026-06-11T00:00:00.000Z') }));\n await store.createRun(run({ id: 'mid', createdAt: new Date('2026-06-11T00:00:01.000Z') }));\n await store.createRun(run({ id: 'new', createdAt: new Date('2026-06-11T00:00:02.000Z') }));\n\n expect((await store.listRuns({})).map((r) => r.id)).toEqual(['new', 'mid', 'old']);\n expect((await store.listRuns({ limit: 2 })).map((r) => r.id)).toEqual(['new', 'mid']);\n expect((await store.listRuns({ limit: 2, offset: 1 })).map((r) => r.id)).toEqual([\n 'mid',\n 'old',\n ]);\n });\n\n // ---- search-attribute pushdown (range + equality + the missing-key contract) ------------\n\n t('round-trips searchAttributes and answers equality + range attribute queries', async () => {\n await store.createRun(run({ id: 'a', searchAttributes: { amount: 30, tier: 'free' } }));\n await store.createRun(run({ id: 'b', searchAttributes: { amount: 200, tier: 'pro' } }));\n await store.createRun(run({ id: 'c', searchAttributes: { amount: 500, tier: 'pro' } }));\n\n expect((await store.getRun('b'))?.searchAttributes).toEqual({ amount: 200, tier: 'pro' });\n\n // Range (numeric).\n expect(\n (await store.listRuns({ attributes: [{ key: 'amount', op: 'gte', value: 200 }] }))\n .map((r) => r.id)\n .sort(),\n ).toEqual(['b', 'c']);\n // Two ANDed predicates (string eq + numeric range).\n expect(\n (\n await store.listRuns({\n attributes: [\n { key: 'tier', op: 'eq', value: 'pro' },\n { key: 'amount', op: 'lt', value: 300 },\n ],\n })\n ).map((r) => r.id),\n ).toEqual(['b']);\n // `ne` excludes the matching value AND absent keys (missing-key-never-matches contract).\n expect(\n (await store.listRuns({ attributes: [{ key: 'tier', op: 'ne', value: 'free' }] }))\n .map((r) => r.id)\n .sort(),\n ).toEqual(['b', 'c']);\n });\n\n t('matches a boolean search attribute by eq/ne', async () => {\n await store.createRun(run({ id: 'a', searchAttributes: { vip: true } }));\n await store.createRun(run({ id: 'b', searchAttributes: { vip: false } }));\n await store.createRun(run({ id: 'c', searchAttributes: { other: 1 } })); // no `vip`\n\n expect(\n (await store.listRuns({ attributes: [{ key: 'vip', op: 'eq', value: true }] })).map(\n (r) => r.id,\n ),\n ).toEqual(['a']);\n // ne=true matches the explicit false but NOT the run missing `vip` (missing-key contract).\n expect(\n (await store.listRuns({ attributes: [{ key: 'vip', op: 'ne', value: true }] })).map(\n (r) => r.id,\n ),\n ).toEqual(['b']);\n });\n\n t('a predicate on an absent key matches nothing (every op)', async () => {\n await store.createRun(run({ id: 'a', searchAttributes: { amount: 100 } }));\n for (const op of ['eq', 'ne', 'gt', 'gte', 'lt', 'lte'] as const) {\n expect(\n await store.listRuns({ attributes: [{ key: 'missing', op, value: 1 }] }),\n ).toHaveLength(0);\n }\n });\n\n t(\n 're-indexes the search-attribute side-table on update (old values stop matching)',\n async () => {\n await store.createRun(run({ id: 'a', searchAttributes: { tier: 'free', amount: 10 } }));\n expect(\n (await store.listRuns({ attributes: [{ key: 'tier', op: 'eq', value: 'free' }] })).map(\n (r) => r.id,\n ),\n ).toEqual(['a']);\n\n await store.updateRun('a', { searchAttributes: { tier: 'pro' } });\n expect(\n (await store.listRuns({ attributes: [{ key: 'tier', op: 'eq', value: 'pro' }] })).map(\n (r) => r.id,\n ),\n ).toEqual(['a']);\n // Old key/value pairs are gone.\n expect(\n await store.listRuns({ attributes: [{ key: 'tier', op: 'eq', value: 'free' }] }),\n ).toHaveLength(0);\n expect(\n await store.listRuns({ attributes: [{ key: 'amount', op: 'eq', value: 10 }] }),\n ).toHaveLength(0);\n },\n );\n\n t('combines an attribute predicate with a coarse status filter and paginates', async () => {\n await store.createRun(run({ id: 'a', status: 'running', searchAttributes: { amount: 300 } }));\n await store.createRun(\n run({ id: 'b', status: 'completed', searchAttributes: { amount: 400 } }),\n );\n await store.createRun(run({ id: 'c', status: 'running', searchAttributes: { amount: 50 } }));\n\n const res = await store.listRuns({\n status: 'running',\n attributes: [{ key: 'amount', op: 'gte', value: 100 }],\n limit: 10,\n });\n expect(res.map((r) => r.id)).toEqual(['a']);\n });\n\n // ---- signal waiters & buffered signals --------------------------------------------------\n\n t('stores, lists by prefix, and atomically takes a signal waiter', async () => {\n await store.putSignalWaiter({ token: 'approve-1', runId: 'r1', seq: 3 });\n await store.putSignalWaiter({ token: 'approve-2', runId: 'r2', seq: 4 });\n await store.putSignalWaiter({ token: 'other-1', runId: 'r3', seq: 5 });\n\n expect((await store.listSignalWaiters('approve-')).map((w) => w.token).sort()).toEqual([\n 'approve-1',\n 'approve-2',\n ]);\n expect((await store.takeSignalWaiter('approve-1'))?.seq).toBe(3);\n // Taken exactly once.\n expect(await store.takeSignalWaiter('approve-1')).toBeNull();\n });\n\n t(\n 'round-trips a signal waiter parallelGroup (child-fan tag) through put → take → list',\n async () => {\n // A remote `gather_children` fan threads its group onto each child waiter so the resolving\n // `signal:child:` checkpoint carries it; the store must persist it on the waiter row.\n await store.putSignalWaiter({\n token: 'child:r.child.0',\n runId: 'r',\n seq: 0,\n parallelGroup: 'gather:0',\n });\n // A lone (non-fan) child await carries no group.\n await store.putSignalWaiter({ token: 'child:r.child.9', runId: 'r', seq: 9 });\n\n const listed = await store.listSignalWaiters('child:');\n expect(listed.find((w) => w.token === 'child:r.child.0')?.parallelGroup).toBe('gather:0');\n expect(listed.find((w) => w.token === 'child:r.child.9')?.parallelGroup).toBeUndefined();\n\n expect((await store.takeSignalWaiter('child:r.child.0'))?.parallelGroup).toBe('gather:0');\n expect((await store.takeSignalWaiter('child:r.child.9'))?.parallelGroup).toBeUndefined();\n },\n );\n\n t(\n \"removeSignalWaiter deletes only the exact (token, runId, seq) row, never a different run's\",\n async () => {\n // A stale identity for a token that's since been superseded (`token` is the store's primary\n // key — a later `putSignalWaiter` for the same token replaces the row) must be a no-op: it\n // must NOT steal the new owner's row out from under it.\n await store.putSignalWaiter({ token: 'approve-1', runId: 'r1', seq: 3 });\n await store.putSignalWaiter({ token: 'approve-1', runId: 'r2', seq: 7 });\n await store.removeSignalWaiter({ token: 'approve-1', runId: 'r1', seq: 3 });\n expect((await store.listSignalWaiters('approve-')).map((w) => w.runId)).toEqual(['r2']);\n\n // A mismatched runId/seq against the CURRENT row is also a no-op.\n await store.removeSignalWaiter({ token: 'approve-1', runId: 'r2', seq: 999 });\n expect((await store.listSignalWaiters('approve-')).map((w) => w.runId)).toEqual(['r2']);\n\n // The exact match deletes it.\n await store.removeSignalWaiter({ token: 'approve-1', runId: 'r2', seq: 7 });\n expect(await store.listSignalWaiters('approve-')).toEqual([]);\n\n // Removing an absent row entirely is a no-op, not an error.\n await store.removeSignalWaiter({ token: 'never-registered', runId: 'r1', seq: 0 });\n },\n );\n\n t('buffers signals and takes them FIFO per token', async () => {\n await store.bufferSignal('sig', { n: 1 });\n await store.bufferSignal('sig', { n: 2 });\n await store.bufferSignal('other', { n: 9 });\n\n expect(await store.takeBufferedSignal('sig')).toEqual({ payload: { n: 1 } });\n expect(await store.takeBufferedSignal('sig')).toEqual({ payload: { n: 2 } });\n expect(await store.takeBufferedSignal('sig')).toBeNull();\n expect(await store.takeBufferedSignal('other')).toEqual({ payload: { n: 9 } });\n });\n\n t('buffers events per name, oldest-first, and lists them without consuming', async () => {\n await store.bufferEvent({\n name: 'order.paid',\n payload: { n: 1 },\n id: 'e1',\n publishedAt: 100,\n });\n await store.bufferEvent({\n name: 'order.paid',\n payload: { n: 2 },\n id: 'e2',\n publishedAt: 200,\n });\n await store.bufferEvent({\n name: 'other.event',\n payload: { n: 9 },\n id: 'e3',\n publishedAt: 50,\n });\n\n const listed = await store.listBufferedEvents('order.paid', 10);\n expect(listed.map((e) => e.payload)).toEqual([{ n: 1 }, { n: 2 }]); // oldest (publishedAt) first\n expect(listed.map((e) => e.id)).toEqual(['e1', 'e2']);\n expect(listed[0]?.publishedAt).toBe(100);\n // listing does not consume — the same rows are still there.\n expect(await store.listBufferedEvents('order.paid', 10)).toHaveLength(2);\n expect(await store.listBufferedEvents('other.event', 10)).toEqual([\n { id: 'e3', payload: { n: 9 }, publishedAt: 50 },\n ]);\n });\n\n t('listBufferedEvents caps at `limit`', async () => {\n await store.bufferEvent({ name: 'evt', payload: 1, id: 'a', publishedAt: 1 });\n await store.bufferEvent({ name: 'evt', payload: 2, id: 'b', publishedAt: 2 });\n await store.bufferEvent({ name: 'evt', payload: 3, id: 'c', publishedAt: 3 });\n\n expect(await store.listBufferedEvents('evt', 2)).toHaveLength(2);\n });\n\n t(\n 'removeBufferedEvent atomically deletes by id — true iff a row existed, false on a repeat/absent id',\n async () => {\n await store.bufferEvent({ name: 'evt', payload: { ok: true }, id: 'x1', publishedAt: 1 });\n\n expect(await store.removeBufferedEvent('x1')).toBe(true);\n expect(await store.listBufferedEvents('evt', 10)).toEqual([]);\n // Already gone — a second attempt (the concurrent-claim arbiter) reports false, not an error.\n expect(await store.removeBufferedEvent('x1')).toBe(false);\n expect(await store.removeBufferedEvent('never-buffered')).toBe(false);\n },\n );\n\n // ---- transaction (optional) -------------------------------------------------------------\n\n t('transaction commits the checkpoint atomically and returns the work result', async () => {\n if (!store.transaction) return; // store without transactions (rare); skip\n if (!supportsAsyncTransaction) return; // sync driver (Drizzle + better-sqlite3); skip — see flag doc\n await store.createRun(run());\n const result = await store.transaction(async (tx) => {\n await tx.saveCheckpoint(checkpoint({ seq: 7, name: 'tx-step', output: { paid: true } }));\n return 'ok';\n });\n expect(result).toBe('ok');\n const cp = await store.getCheckpoint('r1', 7);\n expect(cp?.name).toBe('tx-step');\n expect(cp?.output).toEqual({ paid: true });\n });\n\n // ---- engine end-to-end durability -------------------------------------------------------\n\n t(\n 'runs the engine end-to-end durably, resuming without re-running completed steps',\n async () => {\n const engine = new WorkflowEngine({ store });\n let aRuns = 0;\n let failOnce = true;\n engine.register('wf', '1', async (ctx) => {\n const a = await ctx.localStep('a', async () => {\n aRuns += 1;\n return 10;\n });\n const b = await ctx.localStep('b', async () => {\n if (failOnce) {\n failOnce = false;\n throw new Error('boom');\n }\n return a + 5;\n });\n return b;\n });\n await engine.start('wf', { x: 1 }, 'run1');\n expect((await engine.waitForRun('run1')).status).toBe('failed');\n const resumed = await engine.resume('run1');\n expect(resumed.status).toBe('completed');\n expect(resumed.output).toBe(15);\n // Step `a` checkpointed `completed` the first turn, so replay returns it instead of re-running.\n expect(aRuns).toBe(1);\n },\n );\n\n t('starts the version the caller pinned, and refuses one that is not registered', async () => {\n const engine = new WorkflowEngine({ store });\n const ran: string[] = [];\n engine.register('vwf', '1', async () => {\n ran.push('v1');\n return 'v1-output';\n });\n engine.register('vwf', '2', async () => {\n ran.push('v2');\n return 'v2-output';\n });\n\n await engine.start('vwf', {}, 'pinned-run', { version: '1' });\n const pinned = await engine.waitForRun('pinned-run', { timeoutMs: 20_000 });\n\n // The OLDER body ran and the store recorded the older version — so this run's every future\n // resume replays v1 too. Asserted against a real store because the version is what the row\n // must carry, not just what the in-process registry believed at start.\n expect(pinned.output).toBe('v1-output');\n expect(ran).toEqual(['v1']);\n expect((await store.getRun('pinned-run'))?.workflowVersion).toBe('1');\n\n // Unpinned is unchanged: newest wins.\n await engine.start('vwf', {}, 'newest-run');\n expect((await engine.waitForRun('newest-run', { timeoutMs: 20_000 })).output).toBe(\n 'v2-output',\n );\n\n // An unregistered version fails BEFORE a row exists — never a silent fall back to v2.\n await expect(engine.start('vwf', {}, 'ghost-run', { version: '9' })).rejects.toThrow(\n /vwf@9 is not registered/,\n );\n expect(await store.getRun('ghost-run')).toBeNull();\n });\n\n t('cancels a timed-out run’s live child subtree, not just the run itself', async () => {\n const engine = new WorkflowEngine({ store });\n // Only the parent is timed: a child reaching a terminal state can only be the cascade.\n engine.register('t-grandchild', '1', async (ctx) => ctx.waitForSignal('never'));\n engine.register('t-child', '1', async (ctx) => {\n await ctx.startChild('t-grandchild', {}, 'tgc');\n return ctx.waitForSignal('never');\n });\n engine.register(\n 't-parent',\n '1',\n async (ctx) => {\n await ctx.startChild('t-child', {}, 'tc');\n return ctx.waitForSignal('never');\n },\n { executionTimeout: '1h' },\n );\n\n await engine.start('t-parent', {}, 'tp');\n for (const id of ['tp', 'tc', 'tgc']) {\n expect((await engine.waitForRun(id, { timeoutMs: 20_000 })).status).toBe('suspended');\n }\n\n await engine.sweepTimeouts(Date.now() + 3_700_000);\n\n const parent = await store.getRun('tp');\n expect(parent?.status).toBe('cancelled');\n expect(parent?.error?.code).toBe('execution_timeout');\n // Both levels — the cascade is the same recursive walk an explicit `cancel` uses.\n expect((await store.getRun('tc'))?.status).toBe('cancelled');\n expect((await store.getRun('tgc'))?.status).toBe('cancelled');\n });\n });\n}\n","/** A step body that throws once, then returns `value` — drives a retry, or a crash-then-resume. */\nexport function failOnce<T>(\n value: T,\n error: Error = new Error('injected failure'),\n): () => Promise<T> {\n return failTimes(1, value, error);\n}\n\n/** A step body that throws the first `n` times, then returns `value`. */\nexport function failTimes<T>(\n n: number,\n value: T,\n error: Error = new Error('injected failure'),\n): () => Promise<T> {\n let calls = 0;\n return async () => {\n calls += 1;\n if (calls <= n) throw error;\n return value;\n };\n}\n","import { InMemoryStateStore, type Transport, WorkflowEngine } from '@dudousxd/nestjs-durable-core';\n\n/** A transport that can register worker handlers (every shipped transport does). */\nexport type HandleableTransport = Transport & {\n handle(name: string, fn: (input: unknown) => Promise<unknown>): void;\n close?(): Promise<void>;\n};\n\nconst ECHO_STEP_NAME = 'conformance.echo';\n\n/**\n * A durable `ctx.call` suspends the run; the worker result resumes it asynchronously (on whatever\n * tick/poll the transport delivers on). Poll the store until the run reaches a terminal state —\n * with a generous budget so a poll-based transport (DB/SQS) has time to round-trip.\n */\nasync function settle(store: InMemoryStateStore, runId: string, timeoutMs = 15_000) {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n const run = await store.getRun(runId);\n if (run && run.status !== 'pending' && run.status !== 'running' && run.status !== 'suspended')\n return run;\n await new Promise((r) => setTimeout(r, 25));\n }\n throw new Error(`run ${runId} did not settle within ${timeoutMs}ms`);\n}\n\n/**\n * The contract every `Transport` must satisfy: a remote step dispatched through it round-trips to a\n * worker and back (success), and a throwing handler surfaces as a failed run (failure). Point it at\n * a freshly constructed transport (engine-side + worker `group` in one instance) to prove parity —\n * useful when adding a new transport. Throws on any mismatch; closes the transport when done.\n *\n * `idPrefix` keeps run ids unique across invocations against real, shared infra (queues/tables).\n */\nexport async function assertTransportConformance(\n transport: HandleableTransport,\n idPrefix = 'conf',\n): Promise<void> {\n try {\n // One engine/store/transport — a durable remote step routes its result back to this engine,\n // which resumes the run. (Two engines on one transport would fight over the result stream.)\n const store = new InMemoryStateStore();\n const engine = new WorkflowEngine({ store, transport });\n engine.register(\n 'conf-ok',\n '1',\n async (ctx) => (await ctx.step<{ doubled: number }>(ECHO_STEP_NAME, { n: 21 })).doubled,\n );\n engine.register('conf-fail', '1', async (ctx) => ctx.step(ECHO_STEP_NAME, { n: 1 }));\n\n // success: the worker doubles the input\n transport.handle(ECHO_STEP_NAME, async (input) => ({\n doubled: (input as { n: number }).n * 2,\n }));\n await engine.start('conf-ok', {}, `${idPrefix}-ok`);\n const ok = await settle(store, `${idPrefix}-ok`);\n if (ok.status !== 'completed' || ok.output !== 42) {\n throw new Error(`expected completed/42, got ${JSON.stringify(ok)}`);\n }\n\n // failure: a throwing handler surfaces as a failed run (re-register the same step to throw)\n transport.handle(ECHO_STEP_NAME, async () => {\n throw new Error('handler boom');\n });\n await engine.start('conf-fail', {}, `${idPrefix}-fail`);\n const failed = await settle(store, `${idPrefix}-fail`);\n if (failed.status !== 'failed') {\n throw new Error(`expected failed, got ${JSON.stringify(failed)}`);\n }\n } finally {\n await transport.close?.();\n }\n}\n"],"mappings":"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","names":["describe","expect","it","runAdmissionBackendContract","name","makeBackend","describe","now","make","config","backend","register","it","b","concurrency","expect","tryAdmit","waiterId","ok","toBe","release","rateLimit","limit","periodMs","priority","order","fairness","key","requireRun","store","runId","run","getRun","Error","assertRunStatus","status","assertOutput","expected","JSON","stringify","output","recordedSteps","listCheckpoints","map","cp","name","assertStepsRan","names","ran","includes","join","assertStepAttempts","attempts","find","c","DURABLE_CANONICAL_COLUMNS","durable_workflow_runs","id","workflow","workflowVersion","status","input","output","error","wakeAt","lockedBy","lockedUntil","awaitingDecisionTaskId","recoveryAttempts","tags","searchAttributes","priority","origin","namespace","createdAt","updatedAt","durable_step_checkpoints","runId","seq","name","kind","stepId","events","attempts","workerGroup","parallelGroup","enqueuedAt","startedAt","finishedAt","durable_run_attributes","key","strValue","numValue","durable_signal_waiters","token","durable_buffered_signals","payload","durable_buffered_events","publishedAt","assertDurableColumns","resolve","expected","mismatches","table","props","Object","entries","property","column","actual","push","preserveColumnExpectation","out","fromEntries","keys","map","p","InMemoryStateStore","InMemoryTransport","WorkflowEngine","MutableClock","current","now","set","ms","advance","createTestEngine","store","InMemoryStateStore","transport","InMemoryTransport","clock","engine","WorkflowEngine","tick","resumeDueTimers","run","workflow","input","runId","opts","start","waitForRun","InMemoryStateStore","WorkflowEngine","assertReplayable","register","history","store","InMemoryStateStore","createRun","run","status","lockedBy","undefined","lockedUntil","cp","checkpoints","saveCheckpoint","engine","WorkflowEngine","result","resume","id","error","message","startsWith","err","Error","name","WorkflowEngine","beforeEach","describe","expect","it","StateStoreUnavailableError","Error","isStateStoreUnavailable","message","name","isUnavailable","err","at","Date","run","over","id","workflow","workflowVersion","status","input","orderId","createdAt","updatedAt","checkpoint","runId","seq","kind","stepId","output","ok","attempts","enqueuedAt","startedAt","finishedAt","runStateStoreContract","makeStore","describe","store","cleanup","supportsAsyncTransaction","supportsTagFilter","skipReason","loggedSkip","beforeEach","ctx","undefined","console","warn","t","label","fn","it","createRun","loaded","getRun","expect","toBe","toEqual","toBeNull","recoveryAttempts","updateRun","total","done","dead","priority","toBeUndefined","searchAttributes","tier","saveCheckpoint","putSignalWaiter","token","deleteRun","listCheckpoints","listSignalWaiters","listRuns","attributes","key","op","value","resolves","error","tags","lockedBy","wakeAt","lockedUntil","r","awaitingDecisionTaskId","chargeId","again","getCheckpoint","list","map","c","pct","getLatestCheckpointByName","toBeDefined","latest","call","listCheckpointsByNamePrefix","matches","events","level","listIncompleteRuns","listPendingRuns","listDueTimers","toHaveLength","namespace","sort","tryLockRun","releaseRunLock","renewRunLock","statuses","tag","origin","runFacets","facets","toContainEqual","count","reduce","n","f","limit","offset","amount","vip","other","res","w","takeSignalWaiter","parallelGroup","listed","find","removeSignalWaiter","bufferSignal","takeBufferedSignal","payload","bufferEvent","publishedAt","listBufferedEvents","e","removeBufferedEvent","transaction","result","tx","paid","cp","engine","WorkflowEngine","aRuns","failOnce","register","a","localStep","b","start","x","waitForRun","resumed","resume","ran","push","version","pinned","timeoutMs","rejects","toThrow","waitForSignal","startChild","executionTimeout","sweepTimeouts","now","parent","code","failOnce","value","error","Error","failTimes","n","calls","InMemoryStateStore","WorkflowEngine","ECHO_STEP_NAME","settle","store","runId","timeoutMs","deadline","Date","now","run","getRun","status","Promise","r","setTimeout","Error","assertTransportConformance","transport","idPrefix","InMemoryStateStore","engine","WorkflowEngine","register","ctx","step","n","doubled","handle","input","start","ok","output","JSON","stringify","failed","close"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dudousxd/nestjs-durable-testing",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Testing utilities for nestjs-durable — a test engine harness, crash/flaky-step injection, and replay assertions",
5
5
  "license": "MIT",
6
6
  "author": "Davide Carvalho",
@@ -28,7 +28,7 @@
28
28
  "typescript": "5.9.3",
29
29
  "vitest": "2.1.9",
30
30
  "tsup": "8.3.5",
31
- "@dudousxd/nestjs-durable-core": "^0.64.0"
31
+ "@dudousxd/nestjs-durable-core": "^0.67.0"
32
32
  },
33
33
  "module": "./dist/index.js",
34
34
  "exports": {