@dudousxd/nestjs-durable-store-prisma 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -28,6 +28,13 @@ module.exports = __toCommonJS(index_exports);
28
28
 
29
29
  // src/prisma-state-store.ts
30
30
  var import_nestjs_durable_core = require("@dudousxd/nestjs-durable-core");
31
+ function namespaceWhere(namespace) {
32
+ if (namespace === void 0) return {};
33
+ return {
34
+ namespace
35
+ };
36
+ }
37
+ __name(namespaceWhere, "namespaceWhere");
31
38
  var PrismaStateStore = class {
32
39
  static {
33
40
  __name(this, "PrismaStateStore");
@@ -136,7 +143,7 @@ var PrismaStateStore = class {
136
143
  }, "saveCheckpoint")
137
144
  }));
138
145
  }
139
- async listIncompleteRuns() {
146
+ async listIncompleteRuns(namespace) {
140
147
  const rows = await this.db.durableWorkflowRun.findMany({
141
148
  where: {
142
149
  status: {
@@ -144,15 +151,17 @@ var PrismaStateStore = class {
144
151
  "running",
145
152
  "cancelling"
146
153
  ]
147
- }
154
+ },
155
+ ...namespaceWhere(namespace)
148
156
  }
149
157
  });
150
158
  return rows.map(fromRunRow);
151
159
  }
152
- async listPendingRuns(limit) {
160
+ async listPendingRuns(limit, namespace) {
153
161
  const rows = await this.db.durableWorkflowRun.findMany({
154
162
  where: {
155
- status: "pending"
163
+ status: "pending",
164
+ ...namespaceWhere(namespace)
156
165
  },
157
166
  orderBy: {
158
167
  createdAt: "asc"
@@ -161,14 +170,15 @@ var PrismaStateStore = class {
161
170
  });
162
171
  return rows.map(fromRunRow);
163
172
  }
164
- async listDueTimers(nowMs) {
173
+ async listDueTimers(nowMs, namespace) {
165
174
  const rows = await this.db.durableWorkflowRun.findMany({
166
175
  where: {
167
176
  status: "suspended",
168
177
  wakeAt: {
169
178
  not: null,
170
179
  lte: BigInt(nowMs)
171
- }
180
+ },
181
+ ...namespaceWhere(namespace)
172
182
  }
173
183
  });
174
184
  return rows.map(fromRunRow);
@@ -219,8 +229,11 @@ var PrismaStateStore = class {
219
229
  return result.count === 1;
220
230
  }
221
231
  async listRuns(query) {
222
- const where = {};
232
+ const where = {
233
+ ...namespaceWhere(query.namespace)
234
+ };
223
235
  if (query.workflow) where.workflow = query.workflow;
236
+ if (query.origin !== void 0) where.origin = query.origin;
224
237
  if (query.status && query.statuses) {
225
238
  where.AND = [
226
239
  {
@@ -461,6 +474,12 @@ function toRunData(run) {
461
474
  tags: jsonOrNull(run.tags),
462
475
  searchAttributes: jsonOrNull(run.searchAttributes),
463
476
  priority: run.priority ?? null,
477
+ // An absent namespace IS `'default'` — unlike `origin` below, this is a reconstruction and not a
478
+ // guess: an engine started without a namespace stamps its runs and routes its workers as
479
+ // `'default'`, so writing anything else (or NULL) would put the run in a partition no worker polls.
480
+ namespace: run.namespace ?? "default",
481
+ // Absent origin stays SQL NULL — "unknown", never coerced into a real-looking library name.
482
+ origin: run.origin ?? null,
464
483
  createdAt: run.createdAt,
465
484
  updatedAt: run.updatedAt
466
485
  };
@@ -482,6 +501,8 @@ function toRunPatch(patch) {
482
501
  if ("tags" in patch) data.tags = jsonOrNull(patch.tags);
483
502
  if ("searchAttributes" in patch) data.searchAttributes = jsonOrNull(patch.searchAttributes);
484
503
  if ("priority" in patch) data.priority = patch.priority ?? null;
504
+ if ("namespace" in patch) data.namespace = patch.namespace ?? "default";
505
+ if ("origin" in patch) data.origin = patch.origin ?? null;
485
506
  if (patch.createdAt != null) data.createdAt = patch.createdAt;
486
507
  if (patch.updatedAt != null) data.updatedAt = patch.updatedAt;
487
508
  return data;
@@ -504,6 +525,14 @@ function fromRunRow(row) {
504
525
  tags: row.tags ?? void 0,
505
526
  searchAttributes: row.searchAttributes ?? void 0,
506
527
  priority: row.priority ?? void 0,
528
+ // Read back verbatim, with NO `?? 'default'` fallback. The column is NOT NULL and the migration
529
+ // back-fills old rows, so there is nothing legitimate to fall back FROM; a fallback would only fire
530
+ // on a deployment that added the column nullable without back-filling, and there it would lie —
531
+ // the dashboard would show `default` for a row whose stored NULL keeps every `default` worker's
532
+ // `WHERE namespace = 'default'` from ever picking it up.
533
+ namespace: row.namespace,
534
+ // NULL (a row written before the column existed) surfaces as `undefined` = unknown origin.
535
+ origin: row.origin ?? void 0,
507
536
  createdAt: row.createdAt,
508
537
  updatedAt: row.updatedAt
509
538
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/prisma-state-store.ts","../src/schema.ts"],"sourcesContent":["export * from './prisma-state-store';\nexport * from './schema';\n","import {\n type AttributeFilter,\n type RunQuery,\n type SignalWaiter,\n type StateStore,\n type StepCheckpoint,\n type StepError,\n type StepEvent,\n type WorkflowRun,\n attributeColumnFor,\n attributeOperand,\n normalizeAttributeRows,\n} from '@dudousxd/nestjs-durable-core';\n\n/* The Prisma client is generated per-schema, so the adapter can't import a concrete one. Instead\n it depends on this structural surface — the three model delegates and the methods it uses. A\n real `PrismaClient` (with the models from prisma/schema.prisma added) satisfies it. Query-arg\n shapes are Prisma's own generics, so they're left as `any` at this single boundary; the row\n return types are precise, which is what the mapping code below relies on. */\n\ninterface RunRow {\n id: string;\n workflow: string;\n workflowVersion: string;\n status: string;\n input: unknown;\n output: unknown;\n error: unknown;\n wakeAt: bigint | null;\n lockedBy: string | null;\n lockedUntil: Date | null;\n awaitingDecisionTaskId: string | null;\n recoveryAttempts: number | null;\n tags: unknown;\n searchAttributes: unknown;\n priority: number | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\ninterface CheckpointRow {\n runId: string;\n seq: number;\n name: string;\n kind: string;\n stepId: string;\n status: string;\n input: unknown;\n output: unknown;\n error: unknown;\n events: unknown;\n attempts: number;\n workerGroup: string | null;\n parallelGroup: string | null;\n wakeAt: bigint | null;\n enqueuedAt: Date | null;\n startedAt: Date;\n finishedAt: Date;\n}\n\ninterface WaiterRow {\n token: string;\n runId: string;\n seq: number;\n parallelGroup: string | null;\n}\n\ninterface RunAttributeRow {\n runId: string;\n key: string;\n strValue: string | null;\n numValue: number | null;\n}\n\ninterface BufferedSignalRow {\n id: bigint;\n token: string;\n payload: unknown;\n}\n\ninterface BufferedEventRow {\n id: string;\n name: string;\n payload: unknown;\n publishedAt: bigint;\n}\n\n// Prisma's per-model query args are generated generics; left as `any` at this single boundary.\ntype Args = any;\n\ninterface Delegate<Row> {\n create(args: Args): Promise<Row>;\n createMany(args: Args): Promise<{ count: number }>;\n findUnique(args: Args): Promise<Row | null>;\n findFirst(args?: Args): Promise<Row | null>;\n findMany(args?: Args): Promise<Row[]>;\n update(args: Args): Promise<Row>;\n updateMany(args: Args): Promise<{ count: number }>;\n upsert(args: Args): Promise<Row>;\n delete(args: Args): Promise<Row>;\n deleteMany(args?: Args): Promise<{ count: number }>;\n}\n\nexport interface DurablePrismaTx {\n durableWorkflowRun: Delegate<RunRow>;\n durableStepCheckpoint: Delegate<CheckpointRow>;\n durableRunAttribute: Delegate<RunAttributeRow>;\n durableSignalWaiter: Delegate<WaiterRow>;\n durableBufferedSignal: Delegate<BufferedSignalRow>;\n durableBufferedEvent: Delegate<BufferedEventRow>;\n}\n\nexport interface DurablePrismaClient extends DurablePrismaTx {\n /** Prisma's interactive-transaction form: runs `fn` with a tx-scoped client and commits on resolve. */\n $transaction<T>(fn: (tx: DurablePrismaTx) => Promise<T>): Promise<T>;\n}\n\n/**\n * Prisma-backed `StateStore`. Pass your `PrismaClient` after adding the models from\n * `prisma/schema.prisma` to your schema. JSON columns carry the run/step payloads directly;\n * `wakeAt` is a `BigInt` (epoch ms).\n */\nexport class PrismaStateStore implements StateStore {\n constructor(private readonly db: DurablePrismaClient) {}\n\n async createRun(run: WorkflowRun): Promise<void> {\n await this.db.durableWorkflowRun.create({ data: toRunData(run) });\n await this.reindexAttributes(run.id, run.searchAttributes);\n }\n\n async updateRun(runId: string, patch: Partial<WorkflowRun>): Promise<void> {\n await this.db.durableWorkflowRun.update({ where: { id: runId }, data: toRunPatch(patch) });\n // Keep the side-table in step with the run's attributes whenever they're patched.\n if ('searchAttributes' in patch) await this.reindexAttributes(runId, patch.searchAttributes);\n }\n\n /** Rewrite a run's normalized attribute rows: delete the old set, insert the current one. Mirrors\n * the in-memory store's reindex so the side-table always reflects the run's live searchAttributes. */\n private async reindexAttributes(\n runId: string,\n attributes: WorkflowRun['searchAttributes'],\n ): Promise<void> {\n await this.db.durableRunAttribute.deleteMany({ where: { runId } });\n const rows = normalizeAttributeRows(runId, attributes);\n if (rows.length) await this.db.durableRunAttribute.createMany({ data: rows });\n }\n\n async getRun(runId: string): Promise<WorkflowRun | null> {\n const row = await this.db.durableWorkflowRun.findUnique({ where: { id: runId } });\n return row ? fromRunRow(row) : null;\n }\n\n async deleteRun(runId: string): Promise<void> {\n // Child rows first, then the run — checkpoints, signal waiters, attribute rows.\n await this.db.durableStepCheckpoint.deleteMany({ where: { runId } });\n await this.db.durableSignalWaiter.deleteMany({ where: { runId } });\n await this.db.durableRunAttribute.deleteMany({ where: { runId } });\n await this.db.durableWorkflowRun.deleteMany({ where: { id: runId } });\n }\n\n async getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null> {\n const row = await this.db.durableStepCheckpoint.findUnique({\n where: { runId_seq: { runId, seq } },\n });\n return row ? fromCheckpointRow(row) : null;\n }\n\n async saveCheckpoint(checkpoint: StepCheckpoint): Promise<void> {\n const data = toCheckpointData(checkpoint);\n await this.db.durableStepCheckpoint.upsert({\n where: { runId_seq: { runId: checkpoint.runId, seq: checkpoint.seq } },\n create: data,\n update: data,\n });\n }\n\n async transaction<T>(\n work: (tx: {\n raw: unknown;\n saveCheckpoint: (cp: StepCheckpoint) => Promise<void>;\n }) => Promise<T>,\n ): Promise<T> {\n return this.db.$transaction(async (tx) =>\n work({\n raw: tx,\n saveCheckpoint: async (cp) => {\n const data = toCheckpointData(cp);\n await tx.durableStepCheckpoint.upsert({\n where: { runId_seq: { runId: cp.runId, seq: cp.seq } },\n create: data,\n update: data,\n });\n },\n }),\n );\n }\n\n async listIncompleteRuns(): Promise<WorkflowRun[]> {\n const rows = await this.db.durableWorkflowRun.findMany({\n where: { status: { in: ['running', 'cancelling'] } },\n });\n return rows.map(fromRunRow);\n }\n\n async listPendingRuns(limit: number): Promise<WorkflowRun[]> {\n const rows = await this.db.durableWorkflowRun.findMany({\n where: { status: 'pending' },\n orderBy: { createdAt: 'asc' }, // FIFO dispatch\n take: limit,\n });\n return rows.map(fromRunRow);\n }\n\n async listDueTimers(nowMs: number): Promise<WorkflowRun[]> {\n const rows = await this.db.durableWorkflowRun.findMany({\n where: { status: 'suspended', wakeAt: { not: null, lte: BigInt(nowMs) } },\n });\n return rows.map(fromRunRow);\n }\n\n async tryLockRun(\n runId: string,\n owner: string,\n leaseUntilMs: number,\n nowMs: number,\n ): Promise<boolean> {\n const result = await this.db.durableWorkflowRun.updateMany({\n where: {\n id: runId,\n OR: [{ lockedUntil: null }, { lockedUntil: { lte: new Date(nowMs) } }],\n },\n data: { lockedBy: owner, lockedUntil: new Date(leaseUntilMs) },\n });\n return result.count === 1;\n }\n\n async releaseRunLock(runId: string): Promise<void> {\n // Idempotent by design: releasing the lease on a run that no longer exists is a no-op, not an\n // error. The engine calls this best-effort in a `finally` AFTER the run has settled, so it can\n // race a concurrent purge/teardown — Prisma's `update({ where: { id } })` would throw P2025\n // (\"No record was found for an update\") on that race and, since the call is fire-and-forget on\n // the engine's terminal path, surface as an unhandled rejection. `updateMany` matches a 0-row\n // WHERE to an empty result (no throw), mirroring the in-memory store's `if (run)` guard and the\n // set-where semantics of every sibling adapter (TypeORM/MikroORM/Drizzle).\n await this.db.durableWorkflowRun.updateMany({\n where: { id: runId },\n data: { lockedBy: null, lockedUntil: null },\n });\n }\n\n async renewRunLock(runId: string, owner: string, leaseUntilMs: number): Promise<boolean> {\n const result = await this.db.durableWorkflowRun.updateMany({\n where: { id: runId, lockedBy: owner },\n data: { lockedUntil: new Date(leaseUntilMs) },\n });\n return result.count === 1;\n }\n\n async listRuns(query: RunQuery): Promise<WorkflowRun[]> {\n const where: Record<string, unknown> = {};\n if (query.workflow) where.workflow = query.workflow;\n // `status IN (...)`; an empty set matches nothing (mirrors the in-memory store). Combined with the\n // single-value `status` via AND when both are present, so the narrower set wins.\n if (query.status && query.statuses) {\n where.AND = [{ status: query.status }, { status: { in: query.statuses } }];\n } else if (query.status) {\n where.status = query.status;\n } else if (query.statuses) {\n where.status = { in: query.statuses };\n }\n if (query.tag) where.tags = { array_contains: query.tag };\n // Typed/range attribute predicates push DOWN into SQL: each filter becomes a relation `some`\n // (EXISTS) on the normalized `durable_run_attributes` side-table, so the DB filters AND paginates\n // — no full scan + in-process filter. ANDed: a run must match every filter, so one `some` each.\n if (query.attributes?.length) {\n const existing = (where.AND as unknown[] | undefined) ?? [];\n where.AND = [...existing, ...query.attributes.map((f) => attributeSome(f))];\n }\n const orderBy = { createdAt: 'desc' as const }; // newest first — recent runs on top in the dashboard\n const rows = await this.db.durableWorkflowRun.findMany({\n where,\n take: query.limit,\n skip: query.offset,\n orderBy,\n });\n return rows.map(fromRunRow);\n }\n\n async listCheckpoints(runId: string): Promise<StepCheckpoint[]> {\n const rows = await this.db.durableStepCheckpoint.findMany({\n where: { runId },\n orderBy: { seq: 'asc' },\n });\n return rows.map(fromCheckpointRow);\n }\n\n async getLatestCheckpointByName(\n runId: string,\n name: string,\n ): Promise<StepCheckpoint | undefined> {\n const row = await this.db.durableStepCheckpoint.findFirst({\n where: { runId, name },\n orderBy: { seq: 'desc' },\n });\n return row ? fromCheckpointRow(row) : undefined;\n }\n\n async listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]> {\n if (prefixes.length === 0) return [];\n const rows = await this.db.durableStepCheckpoint.findMany({\n where: { runId, OR: prefixes.map((p) => ({ name: { startsWith: p } })) },\n orderBy: { seq: 'asc' },\n });\n return rows.map(fromCheckpointRow);\n }\n\n async putSignalWaiter(waiter: SignalWaiter): Promise<void> {\n await this.db.durableSignalWaiter.upsert({\n where: { token: waiter.token },\n create: {\n token: waiter.token,\n runId: waiter.runId,\n seq: waiter.seq,\n parallelGroup: waiter.parallelGroup ?? null,\n },\n update: {\n runId: waiter.runId,\n seq: waiter.seq,\n parallelGroup: waiter.parallelGroup ?? null,\n },\n });\n }\n\n async takeSignalWaiter(token: string): Promise<SignalWaiter | null> {\n const row = await this.db.durableSignalWaiter.findUnique({ where: { token } });\n if (!row) return null;\n await this.db.durableSignalWaiter.delete({ where: { token } });\n return {\n token: row.token,\n runId: row.runId,\n seq: row.seq,\n parallelGroup: row.parallelGroup ?? undefined,\n };\n }\n\n async listSignalWaiters(prefix: string): Promise<SignalWaiter[]> {\n const rows = await this.db.durableSignalWaiter.findMany({\n where: { token: { startsWith: prefix } },\n });\n return rows.map((r) => ({\n token: r.token,\n runId: r.runId,\n seq: r.seq,\n parallelGroup: r.parallelGroup ?? undefined,\n }));\n }\n\n async removeSignalWaiter(waiter: SignalWaiter): Promise<void> {\n // Exact-match delete (token AND runId AND seq): `token` is the only unique column, so a plain\n // `delete({ where: { token } })` would remove whatever row currently owns it, even if a different\n // run has since claimed the same token — `deleteMany` with all three fields is a safe no-op then.\n await this.db.durableSignalWaiter.deleteMany({\n where: { token: waiter.token, runId: waiter.runId, seq: waiter.seq },\n });\n }\n\n async bufferSignal(token: string, payload: unknown): Promise<void> {\n await this.db.durableBufferedSignal.create({ data: { token, payload: jsonOrNull(payload) } });\n }\n\n async takeBufferedSignal(token: string): Promise<{ payload: unknown } | null> {\n const row = await this.db.durableBufferedSignal.findFirst({\n where: { token },\n orderBy: { id: 'asc' },\n });\n if (!row) return null;\n await this.db.durableBufferedSignal.delete({ where: { id: row.id } });\n return { payload: row.payload ?? undefined };\n }\n\n async bufferEvent(input: {\n name: string;\n payload: unknown;\n id: string;\n publishedAt: number;\n }): Promise<void> {\n await this.db.durableBufferedEvent.create({\n data: {\n id: input.id,\n name: input.name,\n payload: jsonOrNull(input.payload),\n publishedAt: BigInt(input.publishedAt),\n },\n });\n }\n\n async listBufferedEvents(\n name: string,\n limit: number,\n ): Promise<Array<{ id: string; payload: unknown; publishedAt: number }>> {\n const rows = await this.db.durableBufferedEvent.findMany({\n where: { name },\n orderBy: { publishedAt: 'asc' }, // oldest first\n take: limit,\n });\n return rows.map((r) => ({\n id: r.id,\n payload: r.payload ?? undefined,\n publishedAt: Number(r.publishedAt),\n }));\n }\n\n async removeBufferedEvent(id: string): Promise<boolean> {\n // deleteMany's `where: { id }` matches at most one row (id is the PK) and is a safe no-op if it's\n // already gone — unlike `delete({ where: { id } })`, which throws P2025 on a missing row (the same\n // reasoning as releaseRunLock's updateMany above).\n const result = await this.db.durableBufferedEvent.deleteMany({ where: { id } });\n return result.count === 1;\n }\n}\n\n/**\n * One attribute predicate as a Prisma relation `some` filter on the side-table — compiles to an\n * EXISTS, so the predicate runs in SQL. `<>` (ne) maps to `{ not }`, which under `some` also excludes\n * runs where the attribute is absent (the missing-key-never-matches contract): `some` already\n * requires a matching row to exist. Numeric operands compare `numValue`, everything else `strValue`.\n */\nfunction attributeSome(f: AttributeFilter): { attributes: { some: Record<string, unknown> } } {\n const col = attributeColumnFor(f); // 'numValue' | 'strValue'\n const operand = attributeOperand(f);\n const condition =\n f.op === 'eq' ? operand : f.op === 'ne' ? { not: operand } : { [f.op]: operand }; // gt/gte/lt/lte map 1:1 to Prisma operators\n return { attributes: { some: { key: f.key, [col]: condition } } };\n}\n\nconst bigOrNull = (n: number | undefined) => (n == null ? null : BigInt(n));\nconst numOrUndef = (n: bigint | null) => (n == null ? undefined : Number(n));\nconst jsonOrNull = (v: unknown) => v ?? null;\n\nfunction toRunData(run: WorkflowRun) {\n return {\n id: run.id,\n workflow: run.workflow,\n workflowVersion: run.workflowVersion,\n status: run.status,\n input: jsonOrNull(run.input),\n output: jsonOrNull(run.output),\n error: jsonOrNull(run.error),\n wakeAt: bigOrNull(run.wakeAt),\n lockedBy: run.lockedBy ?? null,\n lockedUntil: run.lockedUntil == null ? null : new Date(run.lockedUntil),\n awaitingDecisionTaskId: run.awaitingDecisionTaskId ?? null,\n recoveryAttempts: run.recoveryAttempts ?? null,\n tags: jsonOrNull(run.tags),\n searchAttributes: jsonOrNull(run.searchAttributes),\n priority: run.priority ?? null,\n createdAt: run.createdAt,\n updatedAt: run.updatedAt,\n };\n}\n\nfunction toRunPatch(patch: Partial<WorkflowRun>) {\n // Map EVERY patchable field, using presence (`'x' in patch`) semantics for the nullable ones so a\n // patch can CLEAR a column (e.g. `{ error: undefined }` on completion sets it to NULL — matching\n // the TypeORM / MikroORM / in-memory stores). The two non-null Date fields use a defined-guard\n // since they are never cleared. Previously only 7 fields were mapped, so `updateRun({ tags })` /\n // `{ lockedBy }` / clearing `error` silently no-opped on this adapter.\n const data: Record<string, unknown> = {};\n if ('workflow' in patch) data.workflow = patch.workflow;\n if ('workflowVersion' in patch) data.workflowVersion = patch.workflowVersion;\n if ('status' in patch) data.status = patch.status;\n if ('input' in patch) data.input = jsonOrNull(patch.input);\n if ('output' in patch) data.output = jsonOrNull(patch.output);\n if ('error' in patch) data.error = jsonOrNull(patch.error);\n if ('wakeAt' in patch) data.wakeAt = bigOrNull(patch.wakeAt);\n if ('lockedBy' in patch) data.lockedBy = patch.lockedBy ?? null;\n if ('lockedUntil' in patch)\n data.lockedUntil = patch.lockedUntil == null ? null : new Date(patch.lockedUntil);\n if ('awaitingDecisionTaskId' in patch)\n data.awaitingDecisionTaskId = patch.awaitingDecisionTaskId ?? null;\n if ('recoveryAttempts' in patch) data.recoveryAttempts = patch.recoveryAttempts ?? null;\n if ('tags' in patch) data.tags = jsonOrNull(patch.tags);\n if ('searchAttributes' in patch) data.searchAttributes = jsonOrNull(patch.searchAttributes);\n if ('priority' in patch) data.priority = patch.priority ?? null;\n if (patch.createdAt != null) data.createdAt = patch.createdAt;\n if (patch.updatedAt != null) data.updatedAt = patch.updatedAt;\n return data;\n}\n\nfunction fromRunRow(row: RunRow): WorkflowRun {\n return {\n id: row.id,\n workflow: row.workflow,\n workflowVersion: row.workflowVersion,\n status: row.status as WorkflowRun['status'],\n input: row.input ?? undefined,\n output: row.output ?? undefined,\n error: (row.error ?? undefined) as StepError | undefined,\n wakeAt: numOrUndef(row.wakeAt),\n lockedBy: row.lockedBy ?? undefined,\n lockedUntil: row.lockedUntil == null ? undefined : row.lockedUntil.getTime(),\n awaitingDecisionTaskId: row.awaitingDecisionTaskId ?? undefined,\n recoveryAttempts: row.recoveryAttempts ?? undefined,\n tags: (row.tags as string[] | null) ?? undefined,\n searchAttributes:\n (row.searchAttributes as Record<string, string | number | boolean> | null) ?? undefined,\n priority: row.priority ?? undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction toCheckpointData(cp: StepCheckpoint) {\n return {\n runId: cp.runId,\n seq: cp.seq,\n name: cp.name,\n kind: cp.kind,\n stepId: cp.stepId,\n status: cp.status,\n input: jsonOrNull(cp.input),\n output: jsonOrNull(cp.output),\n error: jsonOrNull(cp.error),\n events: jsonOrNull(cp.events),\n attempts: cp.attempts,\n workerGroup: cp.workerGroup ?? null,\n parallelGroup: cp.parallelGroup ?? null,\n wakeAt: bigOrNull(cp.wakeAt),\n enqueuedAt: cp.enqueuedAt,\n startedAt: cp.startedAt,\n finishedAt: cp.finishedAt,\n };\n}\n\nfunction fromCheckpointRow(row: CheckpointRow): StepCheckpoint {\n return {\n runId: row.runId,\n seq: row.seq,\n name: row.name,\n kind: row.kind as StepCheckpoint['kind'],\n stepId: row.stepId,\n status: row.status as StepCheckpoint['status'],\n input: row.input ?? undefined,\n output: row.output ?? undefined,\n error: (row.error ?? undefined) as StepError | undefined,\n events: (row.events ?? undefined) as StepEvent[] | undefined,\n attempts: row.attempts,\n workerGroup: row.workerGroup ?? undefined,\n parallelGroup: row.parallelGroup ?? undefined,\n wakeAt: numOrUndef(row.wakeAt),\n enqueuedAt: row.enqueuedAt ?? row.startedAt,\n startedAt: row.startedAt,\n finishedAt: row.finishedAt,\n };\n}\n","/**\n * Tables this store's durable models own, physically. UNLIKE the other store adapters, this store\n * doesn't create or manage them at boot: the models in `prisma/schema.prisma` are meant to be copied\n * into YOUR OWN `schema.prisma` (see that file's header comment), and Prisma Migrate diffs whatever\n * models live in your schema — so a consumer who copied the models in already has them accounted for\n * and never needs a denylist for Prisma Migrate itself.\n *\n * This is exported anyway for the same reason the other adapters export it: any OTHER tooling that\n * introspects the database outside of `prisma migrate diff` (a raw schema dump, a second ORM/CLI\n * pointed at the same database, a linter that flags \"table not in any model\") needs the same fixed\n * list of table names this store's models declare via `@@map(...)`.\n *\n * ```ts\n * const skipTables = new Set(durableManagedTables());\n * ```\n *\n * Kept in sync with the `@@map(...)` table names in `prisma/schema.prisma` by `schema.spec.ts`,\n * which parses that file and asserts the two lists match — there is no single TypeScript source to\n * derive from (the schema is a `.prisma` text file copied into the consumer's own schema, not\n * imported at runtime), so the list here is intentionally a literal mirror.\n */\nexport function durableManagedTables(): string[] {\n return [\n 'durable_workflow_runs',\n 'durable_step_checkpoints',\n 'durable_run_attributes',\n 'durable_signal_waiters',\n 'durable_buffered_signals',\n 'durable_buffered_events',\n ];\n}\n"],"mappings":"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","names":["PrismaStateStore","db","createRun","run","durableWorkflowRun","create","data","toRunData","reindexAttributes","id","searchAttributes","updateRun","runId","patch","update","where","toRunPatch","attributes","durableRunAttribute","deleteMany","rows","normalizeAttributeRows","length","createMany","getRun","row","findUnique","fromRunRow","deleteRun","durableStepCheckpoint","durableSignalWaiter","getCheckpoint","seq","runId_seq","fromCheckpointRow","saveCheckpoint","checkpoint","toCheckpointData","upsert","transaction","work","$transaction","tx","raw","cp","listIncompleteRuns","findMany","status","in","map","listPendingRuns","limit","orderBy","createdAt","take","listDueTimers","nowMs","wakeAt","not","lte","BigInt","tryLockRun","owner","leaseUntilMs","result","updateMany","OR","lockedUntil","Date","lockedBy","count","releaseRunLock","renewRunLock","listRuns","query","workflow","statuses","AND","tag","tags","array_contains","existing","f","attributeSome","skip","offset","listCheckpoints","getLatestCheckpointByName","name","findFirst","undefined","listCheckpointsByNamePrefix","prefixes","p","startsWith","putSignalWaiter","waiter","token","parallelGroup","takeSignalWaiter","delete","listSignalWaiters","prefix","r","removeSignalWaiter","bufferSignal","payload","durableBufferedSignal","jsonOrNull","takeBufferedSignal","bufferEvent","input","durableBufferedEvent","publishedAt","listBufferedEvents","Number","removeBufferedEvent","col","attributeColumnFor","operand","attributeOperand","condition","op","some","key","bigOrNull","n","numOrUndef","v","workflowVersion","output","error","awaitingDecisionTaskId","recoveryAttempts","priority","updatedAt","getTime","kind","stepId","events","attempts","workerGroup","enqueuedAt","startedAt","finishedAt","durableManagedTables"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/prisma-state-store.ts","../src/schema.ts"],"sourcesContent":["export * from './prisma-state-store';\nexport * from './schema';\n","import {\n type AttributeFilter,\n type RunQuery,\n type SignalWaiter,\n type StateStore,\n type StepCheckpoint,\n type StepError,\n type StepEvent,\n type WorkflowRun,\n attributeColumnFor,\n attributeOperand,\n normalizeAttributeRows,\n} from '@dudousxd/nestjs-durable-core';\n\n/* The Prisma client is generated per-schema, so the adapter can't import a concrete one. Instead\n it depends on this structural surface — the three model delegates and the methods it uses. A\n real `PrismaClient` (with the models from prisma/schema.prisma added) satisfies it. Query-arg\n shapes are Prisma's own generics, so they're left as `any` at this single boundary; the row\n return types are precise, which is what the mapping code below relies on. */\n\ninterface RunRow {\n id: string;\n workflow: string;\n workflowVersion: string;\n status: string;\n input: unknown;\n output: unknown;\n error: unknown;\n wakeAt: bigint | null;\n lockedBy: string | null;\n lockedUntil: Date | null;\n awaitingDecisionTaskId: string | null;\n recoveryAttempts: number | null;\n tags: unknown;\n searchAttributes: unknown;\n priority: number | null;\n /** NOT NULL in the schema (defaulted to `'default'`), so every row carries a real namespace. */\n namespace: string;\n origin: string | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\ninterface CheckpointRow {\n runId: string;\n seq: number;\n name: string;\n kind: string;\n stepId: string;\n status: string;\n input: unknown;\n output: unknown;\n error: unknown;\n events: unknown;\n attempts: number;\n workerGroup: string | null;\n parallelGroup: string | null;\n wakeAt: bigint | null;\n enqueuedAt: Date | null;\n startedAt: Date;\n finishedAt: Date;\n}\n\ninterface WaiterRow {\n token: string;\n runId: string;\n seq: number;\n parallelGroup: string | null;\n}\n\ninterface RunAttributeRow {\n runId: string;\n key: string;\n strValue: string | null;\n numValue: number | null;\n}\n\ninterface BufferedSignalRow {\n id: bigint;\n token: string;\n payload: unknown;\n}\n\ninterface BufferedEventRow {\n id: string;\n name: string;\n payload: unknown;\n publishedAt: bigint;\n}\n\n// Prisma's per-model query args are generated generics; left as `any` at this single boundary.\ntype Args = any;\n\ninterface Delegate<Row> {\n create(args: Args): Promise<Row>;\n createMany(args: Args): Promise<{ count: number }>;\n findUnique(args: Args): Promise<Row | null>;\n findFirst(args?: Args): Promise<Row | null>;\n findMany(args?: Args): Promise<Row[]>;\n update(args: Args): Promise<Row>;\n updateMany(args: Args): Promise<{ count: number }>;\n upsert(args: Args): Promise<Row>;\n delete(args: Args): Promise<Row>;\n deleteMany(args?: Args): Promise<{ count: number }>;\n}\n\nexport interface DurablePrismaTx {\n durableWorkflowRun: Delegate<RunRow>;\n durableStepCheckpoint: Delegate<CheckpointRow>;\n durableRunAttribute: Delegate<RunAttributeRow>;\n durableSignalWaiter: Delegate<WaiterRow>;\n durableBufferedSignal: Delegate<BufferedSignalRow>;\n durableBufferedEvent: Delegate<BufferedEventRow>;\n}\n\nexport interface DurablePrismaClient extends DurablePrismaTx {\n /** Prisma's interactive-transaction form: runs `fn` with a tx-scoped client and commits on resolve. */\n $transaction<T>(fn: (tx: DurablePrismaTx) => Promise<T>): Promise<T>;\n}\n\n/**\n * The `namespace` read boundary as a spreadable Prisma `where` fragment.\n *\n * `undefined` means NO RESTRICTION — `{}` — because that is the operator (control-plane) view that\n * sees every tenant, and it is what the engine passes when it runs unscoped. It does NOT mean\n * \"namespace IS NULL\": the column is NOT NULL, so `{ namespace: undefined }` would be Prisma's\n * \"ignore this predicate\" anyway, but `{ namespace: null }` would match nothing in production while\n * still looking correct in a single-tenant test where every worker polls unscoped.\n *\n * A named namespace is plain equality, so a worker sees only its own tenant's rows — the boundary\n * {@link WorkflowRun.namespace} promises for the four worker paths (pick up, recover, resume timers,\n * time out).\n */\nfunction namespaceWhere(namespace?: string): { namespace?: string } {\n if (namespace === undefined) return {};\n return { namespace };\n}\n\n/**\n * Prisma-backed `StateStore`. Pass your `PrismaClient` after adding the models from\n * `prisma/schema.prisma` to your schema. JSON columns carry the run/step payloads directly;\n * `wakeAt` is a `BigInt` (epoch ms).\n *\n * Every path a worker acts on is namespace-scoped when it is given one — `listPendingRuns` (pick up),\n * `listIncompleteRuns` (recover), `listDueTimers` (resume timers) and `listRuns`'s `namespace`\n * (the engine's timeout sweep). Omit it for the operator view across all tenants. Point-reads\n * (`getRun`, checkpoints) are deliberately NOT scoped, per {@link StateStore}.\n */\nexport class PrismaStateStore implements StateStore {\n constructor(private readonly db: DurablePrismaClient) {}\n\n async createRun(run: WorkflowRun): Promise<void> {\n await this.db.durableWorkflowRun.create({ data: toRunData(run) });\n await this.reindexAttributes(run.id, run.searchAttributes);\n }\n\n async updateRun(runId: string, patch: Partial<WorkflowRun>): Promise<void> {\n await this.db.durableWorkflowRun.update({ where: { id: runId }, data: toRunPatch(patch) });\n // Keep the side-table in step with the run's attributes whenever they're patched.\n if ('searchAttributes' in patch) await this.reindexAttributes(runId, patch.searchAttributes);\n }\n\n /** Rewrite a run's normalized attribute rows: delete the old set, insert the current one. Mirrors\n * the in-memory store's reindex so the side-table always reflects the run's live searchAttributes. */\n private async reindexAttributes(\n runId: string,\n attributes: WorkflowRun['searchAttributes'],\n ): Promise<void> {\n await this.db.durableRunAttribute.deleteMany({ where: { runId } });\n const rows = normalizeAttributeRows(runId, attributes);\n if (rows.length) await this.db.durableRunAttribute.createMany({ data: rows });\n }\n\n async getRun(runId: string): Promise<WorkflowRun | null> {\n const row = await this.db.durableWorkflowRun.findUnique({ where: { id: runId } });\n return row ? fromRunRow(row) : null;\n }\n\n async deleteRun(runId: string): Promise<void> {\n // Child rows first, then the run — checkpoints, signal waiters, attribute rows.\n await this.db.durableStepCheckpoint.deleteMany({ where: { runId } });\n await this.db.durableSignalWaiter.deleteMany({ where: { runId } });\n await this.db.durableRunAttribute.deleteMany({ where: { runId } });\n await this.db.durableWorkflowRun.deleteMany({ where: { id: runId } });\n }\n\n async getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null> {\n const row = await this.db.durableStepCheckpoint.findUnique({\n where: { runId_seq: { runId, seq } },\n });\n return row ? fromCheckpointRow(row) : null;\n }\n\n async saveCheckpoint(checkpoint: StepCheckpoint): Promise<void> {\n const data = toCheckpointData(checkpoint);\n await this.db.durableStepCheckpoint.upsert({\n where: { runId_seq: { runId: checkpoint.runId, seq: checkpoint.seq } },\n create: data,\n update: data,\n });\n }\n\n async transaction<T>(\n work: (tx: {\n raw: unknown;\n saveCheckpoint: (cp: StepCheckpoint) => Promise<void>;\n }) => Promise<T>,\n ): Promise<T> {\n return this.db.$transaction(async (tx) =>\n work({\n raw: tx,\n saveCheckpoint: async (cp) => {\n const data = toCheckpointData(cp);\n await tx.durableStepCheckpoint.upsert({\n where: { runId_seq: { runId: cp.runId, seq: cp.seq } },\n create: data,\n update: data,\n });\n },\n }),\n );\n }\n\n async listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]> {\n const rows = await this.db.durableWorkflowRun.findMany({\n where: { status: { in: ['running', 'cancelling'] }, ...namespaceWhere(namespace) },\n });\n return rows.map(fromRunRow);\n }\n\n async listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]> {\n const rows = await this.db.durableWorkflowRun.findMany({\n where: { status: 'pending', ...namespaceWhere(namespace) },\n orderBy: { createdAt: 'asc' }, // FIFO dispatch\n take: limit,\n });\n return rows.map(fromRunRow);\n }\n\n async listDueTimers(nowMs: number, namespace?: string): Promise<WorkflowRun[]> {\n const rows = await this.db.durableWorkflowRun.findMany({\n where: {\n status: 'suspended',\n wakeAt: { not: null, lte: BigInt(nowMs) },\n ...namespaceWhere(namespace),\n },\n });\n return rows.map(fromRunRow);\n }\n\n async tryLockRun(\n runId: string,\n owner: string,\n leaseUntilMs: number,\n nowMs: number,\n ): Promise<boolean> {\n const result = await this.db.durableWorkflowRun.updateMany({\n where: {\n id: runId,\n OR: [{ lockedUntil: null }, { lockedUntil: { lte: new Date(nowMs) } }],\n },\n data: { lockedBy: owner, lockedUntil: new Date(leaseUntilMs) },\n });\n return result.count === 1;\n }\n\n async releaseRunLock(runId: string): Promise<void> {\n // Idempotent by design: releasing the lease on a run that no longer exists is a no-op, not an\n // error. The engine calls this best-effort in a `finally` AFTER the run has settled, so it can\n // race a concurrent purge/teardown — Prisma's `update({ where: { id } })` would throw P2025\n // (\"No record was found for an update\") on that race and, since the call is fire-and-forget on\n // the engine's terminal path, surface as an unhandled rejection. `updateMany` matches a 0-row\n // WHERE to an empty result (no throw), mirroring the in-memory store's `if (run)` guard and the\n // set-where semantics of every sibling adapter (TypeORM/MikroORM/Drizzle).\n await this.db.durableWorkflowRun.updateMany({\n where: { id: runId },\n data: { lockedBy: null, lockedUntil: null },\n });\n }\n\n async renewRunLock(runId: string, owner: string, leaseUntilMs: number): Promise<boolean> {\n const result = await this.db.durableWorkflowRun.updateMany({\n where: { id: runId, lockedBy: owner },\n data: { lockedUntil: new Date(leaseUntilMs) },\n });\n return result.count === 1;\n }\n\n async listRuns(query: RunQuery): Promise<WorkflowRun[]> {\n // The tenant boundary, and NOT only a dashboard facet: the engine's `sweepTimeouts` finds the runs\n // it may cancel through `listRuns({ workflow, status, namespace })`, so an unfiltered `namespace`\n // here lets a worker serving one tenant time out another tenant's runs — a write, not a stale\n // read. Same `undefined` = no restriction rule as the poll paths above (see `namespaceWhere`),\n // which is what keeps the operator's dashboard showing every tenant by default.\n const where: Record<string, unknown> = { ...namespaceWhere(query.namespace) };\n if (query.workflow) where.workflow = query.workflow;\n // Which library registered the workflow. Plain equality, so a run whose origin is NULL (created\n // before the column existed, or registered through a path the derivation could not classify)\n // matches NO origin value — it is never folded into a bucket to make the facet look complete.\n // Unknown-origin runs are reachable only with the filter OFF, so \"all origins\" must stay the\n // default view; a dashboard that filtered by default would make those runs look deleted.\n if (query.origin !== undefined) where.origin = query.origin;\n // `status IN (...)`; an empty set matches nothing (mirrors the in-memory store). Combined with the\n // single-value `status` via AND when both are present, so the narrower set wins.\n if (query.status && query.statuses) {\n where.AND = [{ status: query.status }, { status: { in: query.statuses } }];\n } else if (query.status) {\n where.status = query.status;\n } else if (query.statuses) {\n where.status = { in: query.statuses };\n }\n if (query.tag) where.tags = { array_contains: query.tag };\n // Typed/range attribute predicates push DOWN into SQL: each filter becomes a relation `some`\n // (EXISTS) on the normalized `durable_run_attributes` side-table, so the DB filters AND paginates\n // — no full scan + in-process filter. ANDed: a run must match every filter, so one `some` each.\n if (query.attributes?.length) {\n const existing = (where.AND as unknown[] | undefined) ?? [];\n where.AND = [...existing, ...query.attributes.map((f) => attributeSome(f))];\n }\n const orderBy = { createdAt: 'desc' as const }; // newest first — recent runs on top in the dashboard\n const rows = await this.db.durableWorkflowRun.findMany({\n where,\n take: query.limit,\n skip: query.offset,\n orderBy,\n });\n return rows.map(fromRunRow);\n }\n\n async listCheckpoints(runId: string): Promise<StepCheckpoint[]> {\n const rows = await this.db.durableStepCheckpoint.findMany({\n where: { runId },\n orderBy: { seq: 'asc' },\n });\n return rows.map(fromCheckpointRow);\n }\n\n async getLatestCheckpointByName(\n runId: string,\n name: string,\n ): Promise<StepCheckpoint | undefined> {\n const row = await this.db.durableStepCheckpoint.findFirst({\n where: { runId, name },\n orderBy: { seq: 'desc' },\n });\n return row ? fromCheckpointRow(row) : undefined;\n }\n\n async listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]> {\n if (prefixes.length === 0) return [];\n const rows = await this.db.durableStepCheckpoint.findMany({\n where: { runId, OR: prefixes.map((p) => ({ name: { startsWith: p } })) },\n orderBy: { seq: 'asc' },\n });\n return rows.map(fromCheckpointRow);\n }\n\n async putSignalWaiter(waiter: SignalWaiter): Promise<void> {\n await this.db.durableSignalWaiter.upsert({\n where: { token: waiter.token },\n create: {\n token: waiter.token,\n runId: waiter.runId,\n seq: waiter.seq,\n parallelGroup: waiter.parallelGroup ?? null,\n },\n update: {\n runId: waiter.runId,\n seq: waiter.seq,\n parallelGroup: waiter.parallelGroup ?? null,\n },\n });\n }\n\n async takeSignalWaiter(token: string): Promise<SignalWaiter | null> {\n const row = await this.db.durableSignalWaiter.findUnique({ where: { token } });\n if (!row) return null;\n await this.db.durableSignalWaiter.delete({ where: { token } });\n return {\n token: row.token,\n runId: row.runId,\n seq: row.seq,\n parallelGroup: row.parallelGroup ?? undefined,\n };\n }\n\n async listSignalWaiters(prefix: string): Promise<SignalWaiter[]> {\n const rows = await this.db.durableSignalWaiter.findMany({\n where: { token: { startsWith: prefix } },\n });\n return rows.map((r) => ({\n token: r.token,\n runId: r.runId,\n seq: r.seq,\n parallelGroup: r.parallelGroup ?? undefined,\n }));\n }\n\n async removeSignalWaiter(waiter: SignalWaiter): Promise<void> {\n // Exact-match delete (token AND runId AND seq): `token` is the only unique column, so a plain\n // `delete({ where: { token } })` would remove whatever row currently owns it, even if a different\n // run has since claimed the same token — `deleteMany` with all three fields is a safe no-op then.\n await this.db.durableSignalWaiter.deleteMany({\n where: { token: waiter.token, runId: waiter.runId, seq: waiter.seq },\n });\n }\n\n async bufferSignal(token: string, payload: unknown): Promise<void> {\n await this.db.durableBufferedSignal.create({ data: { token, payload: jsonOrNull(payload) } });\n }\n\n async takeBufferedSignal(token: string): Promise<{ payload: unknown } | null> {\n const row = await this.db.durableBufferedSignal.findFirst({\n where: { token },\n orderBy: { id: 'asc' },\n });\n if (!row) return null;\n await this.db.durableBufferedSignal.delete({ where: { id: row.id } });\n return { payload: row.payload ?? undefined };\n }\n\n async bufferEvent(input: {\n name: string;\n payload: unknown;\n id: string;\n publishedAt: number;\n }): Promise<void> {\n await this.db.durableBufferedEvent.create({\n data: {\n id: input.id,\n name: input.name,\n payload: jsonOrNull(input.payload),\n publishedAt: BigInt(input.publishedAt),\n },\n });\n }\n\n async listBufferedEvents(\n name: string,\n limit: number,\n ): Promise<Array<{ id: string; payload: unknown; publishedAt: number }>> {\n const rows = await this.db.durableBufferedEvent.findMany({\n where: { name },\n orderBy: { publishedAt: 'asc' }, // oldest first\n take: limit,\n });\n return rows.map((r) => ({\n id: r.id,\n payload: r.payload ?? undefined,\n publishedAt: Number(r.publishedAt),\n }));\n }\n\n async removeBufferedEvent(id: string): Promise<boolean> {\n // deleteMany's `where: { id }` matches at most one row (id is the PK) and is a safe no-op if it's\n // already gone — unlike `delete({ where: { id } })`, which throws P2025 on a missing row (the same\n // reasoning as releaseRunLock's updateMany above).\n const result = await this.db.durableBufferedEvent.deleteMany({ where: { id } });\n return result.count === 1;\n }\n}\n\n/**\n * One attribute predicate as a Prisma relation `some` filter on the side-table — compiles to an\n * EXISTS, so the predicate runs in SQL. `<>` (ne) maps to `{ not }`, which under `some` also excludes\n * runs where the attribute is absent (the missing-key-never-matches contract): `some` already\n * requires a matching row to exist. Numeric operands compare `numValue`, everything else `strValue`.\n */\nfunction attributeSome(f: AttributeFilter): { attributes: { some: Record<string, unknown> } } {\n const col = attributeColumnFor(f); // 'numValue' | 'strValue'\n const operand = attributeOperand(f);\n const condition =\n f.op === 'eq' ? operand : f.op === 'ne' ? { not: operand } : { [f.op]: operand }; // gt/gte/lt/lte map 1:1 to Prisma operators\n return { attributes: { some: { key: f.key, [col]: condition } } };\n}\n\nconst bigOrNull = (n: number | undefined) => (n == null ? null : BigInt(n));\nconst numOrUndef = (n: bigint | null) => (n == null ? undefined : Number(n));\nconst jsonOrNull = (v: unknown) => v ?? null;\n\nfunction toRunData(run: WorkflowRun) {\n return {\n id: run.id,\n workflow: run.workflow,\n workflowVersion: run.workflowVersion,\n status: run.status,\n input: jsonOrNull(run.input),\n output: jsonOrNull(run.output),\n error: jsonOrNull(run.error),\n wakeAt: bigOrNull(run.wakeAt),\n lockedBy: run.lockedBy ?? null,\n lockedUntil: run.lockedUntil == null ? null : new Date(run.lockedUntil),\n awaitingDecisionTaskId: run.awaitingDecisionTaskId ?? null,\n recoveryAttempts: run.recoveryAttempts ?? null,\n tags: jsonOrNull(run.tags),\n searchAttributes: jsonOrNull(run.searchAttributes),\n priority: run.priority ?? null,\n // An absent namespace IS `'default'` — unlike `origin` below, this is a reconstruction and not a\n // guess: an engine started without a namespace stamps its runs and routes its workers as\n // `'default'`, so writing anything else (or NULL) would put the run in a partition no worker polls.\n namespace: run.namespace ?? 'default',\n // Absent origin stays SQL NULL — \"unknown\", never coerced into a real-looking library name.\n origin: run.origin ?? null,\n createdAt: run.createdAt,\n updatedAt: run.updatedAt,\n };\n}\n\nfunction toRunPatch(patch: Partial<WorkflowRun>) {\n // Map EVERY patchable field, using presence (`'x' in patch`) semantics for the nullable ones so a\n // patch can CLEAR a column (e.g. `{ error: undefined }` on completion sets it to NULL — matching\n // the TypeORM / MikroORM / in-memory stores). The two non-null Date fields use a defined-guard\n // since they are never cleared. Previously only 7 fields were mapped, so `updateRun({ tags })` /\n // `{ lockedBy }` / clearing `error` silently no-opped on this adapter.\n const data: Record<string, unknown> = {};\n if ('workflow' in patch) data.workflow = patch.workflow;\n if ('workflowVersion' in patch) data.workflowVersion = patch.workflowVersion;\n if ('status' in patch) data.status = patch.status;\n if ('input' in patch) data.input = jsonOrNull(patch.input);\n if ('output' in patch) data.output = jsonOrNull(patch.output);\n if ('error' in patch) data.error = jsonOrNull(patch.error);\n if ('wakeAt' in patch) data.wakeAt = bigOrNull(patch.wakeAt);\n if ('lockedBy' in patch) data.lockedBy = patch.lockedBy ?? null;\n if ('lockedUntil' in patch)\n data.lockedUntil = patch.lockedUntil == null ? null : new Date(patch.lockedUntil);\n if ('awaitingDecisionTaskId' in patch)\n data.awaitingDecisionTaskId = patch.awaitingDecisionTaskId ?? null;\n if ('recoveryAttempts' in patch) data.recoveryAttempts = patch.recoveryAttempts ?? null;\n if ('tags' in patch) data.tags = jsonOrNull(patch.tags);\n if ('searchAttributes' in patch) data.searchAttributes = jsonOrNull(patch.searchAttributes);\n if ('priority' in patch) data.priority = patch.priority ?? null;\n // `?? 'default'` rather than `?? null` like its neighbours: the column is NOT NULL, and clearing a\n // run's namespace means \"back to the unscoped partition\", which is what `'default'` names. A patch\n // that does not mention `namespace` leaves the stored one alone — a status update must never move a\n // run between tenants.\n if ('namespace' in patch) data.namespace = patch.namespace ?? 'default';\n if ('origin' in patch) data.origin = patch.origin ?? null;\n if (patch.createdAt != null) data.createdAt = patch.createdAt;\n if (patch.updatedAt != null) data.updatedAt = patch.updatedAt;\n return data;\n}\n\nfunction fromRunRow(row: RunRow): WorkflowRun {\n return {\n id: row.id,\n workflow: row.workflow,\n workflowVersion: row.workflowVersion,\n status: row.status as WorkflowRun['status'],\n input: row.input ?? undefined,\n output: row.output ?? undefined,\n error: (row.error ?? undefined) as StepError | undefined,\n wakeAt: numOrUndef(row.wakeAt),\n lockedBy: row.lockedBy ?? undefined,\n lockedUntil: row.lockedUntil == null ? undefined : row.lockedUntil.getTime(),\n awaitingDecisionTaskId: row.awaitingDecisionTaskId ?? undefined,\n recoveryAttempts: row.recoveryAttempts ?? undefined,\n tags: (row.tags as string[] | null) ?? undefined,\n searchAttributes:\n (row.searchAttributes as Record<string, string | number | boolean> | null) ?? undefined,\n priority: row.priority ?? undefined,\n // Read back verbatim, with NO `?? 'default'` fallback. The column is NOT NULL and the migration\n // back-fills old rows, so there is nothing legitimate to fall back FROM; a fallback would only fire\n // on a deployment that added the column nullable without back-filling, and there it would lie —\n // the dashboard would show `default` for a row whose stored NULL keeps every `default` worker's\n // `WHERE namespace = 'default'` from ever picking it up.\n namespace: row.namespace,\n // NULL (a row written before the column existed) surfaces as `undefined` = unknown origin.\n origin: row.origin ?? undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction toCheckpointData(cp: StepCheckpoint) {\n return {\n runId: cp.runId,\n seq: cp.seq,\n name: cp.name,\n kind: cp.kind,\n stepId: cp.stepId,\n status: cp.status,\n input: jsonOrNull(cp.input),\n output: jsonOrNull(cp.output),\n error: jsonOrNull(cp.error),\n events: jsonOrNull(cp.events),\n attempts: cp.attempts,\n workerGroup: cp.workerGroup ?? null,\n parallelGroup: cp.parallelGroup ?? null,\n wakeAt: bigOrNull(cp.wakeAt),\n enqueuedAt: cp.enqueuedAt,\n startedAt: cp.startedAt,\n finishedAt: cp.finishedAt,\n };\n}\n\nfunction fromCheckpointRow(row: CheckpointRow): StepCheckpoint {\n return {\n runId: row.runId,\n seq: row.seq,\n name: row.name,\n kind: row.kind as StepCheckpoint['kind'],\n stepId: row.stepId,\n status: row.status as StepCheckpoint['status'],\n input: row.input ?? undefined,\n output: row.output ?? undefined,\n error: (row.error ?? undefined) as StepError | undefined,\n events: (row.events ?? undefined) as StepEvent[] | undefined,\n attempts: row.attempts,\n workerGroup: row.workerGroup ?? undefined,\n parallelGroup: row.parallelGroup ?? undefined,\n wakeAt: numOrUndef(row.wakeAt),\n enqueuedAt: row.enqueuedAt ?? row.startedAt,\n startedAt: row.startedAt,\n finishedAt: row.finishedAt,\n };\n}\n","/**\n * Tables this store's durable models own, physically. UNLIKE the other store adapters, this store\n * doesn't create or manage them at boot: the models in `prisma/schema.prisma` are meant to be copied\n * into YOUR OWN `schema.prisma` (see that file's header comment), and Prisma Migrate diffs whatever\n * models live in your schema — so a consumer who copied the models in already has them accounted for\n * and never needs a denylist for Prisma Migrate itself.\n *\n * This is exported anyway for the same reason the other adapters export it: any OTHER tooling that\n * introspects the database outside of `prisma migrate diff` (a raw schema dump, a second ORM/CLI\n * pointed at the same database, a linter that flags \"table not in any model\") needs the same fixed\n * list of table names this store's models declare via `@@map(...)`.\n *\n * ```ts\n * const skipTables = new Set(durableManagedTables());\n * ```\n *\n * Kept in sync with the `@@map(...)` table names in `prisma/schema.prisma` by `schema.spec.ts`,\n * which parses that file and asserts the two lists match — there is no single TypeScript source to\n * derive from (the schema is a `.prisma` text file copied into the consumer's own schema, not\n * imported at runtime), so the list here is intentionally a literal mirror.\n */\nexport function durableManagedTables(): string[] {\n return [\n 'durable_workflow_runs',\n 'durable_step_checkpoints',\n 'durable_run_attributes',\n 'durable_signal_waiters',\n 'durable_buffered_signals',\n 'durable_buffered_events',\n ];\n}\n"],"mappings":"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","names":["namespaceWhere","namespace","undefined","PrismaStateStore","db","createRun","run","durableWorkflowRun","create","data","toRunData","reindexAttributes","id","searchAttributes","updateRun","runId","patch","update","where","toRunPatch","attributes","durableRunAttribute","deleteMany","rows","normalizeAttributeRows","length","createMany","getRun","row","findUnique","fromRunRow","deleteRun","durableStepCheckpoint","durableSignalWaiter","getCheckpoint","seq","runId_seq","fromCheckpointRow","saveCheckpoint","checkpoint","toCheckpointData","upsert","transaction","work","$transaction","tx","raw","cp","listIncompleteRuns","findMany","status","in","map","listPendingRuns","limit","orderBy","createdAt","take","listDueTimers","nowMs","wakeAt","not","lte","BigInt","tryLockRun","owner","leaseUntilMs","result","updateMany","OR","lockedUntil","Date","lockedBy","count","releaseRunLock","renewRunLock","listRuns","query","workflow","origin","statuses","AND","tag","tags","array_contains","existing","f","attributeSome","skip","offset","listCheckpoints","getLatestCheckpointByName","name","findFirst","listCheckpointsByNamePrefix","prefixes","p","startsWith","putSignalWaiter","waiter","token","parallelGroup","takeSignalWaiter","delete","listSignalWaiters","prefix","r","removeSignalWaiter","bufferSignal","payload","durableBufferedSignal","jsonOrNull","takeBufferedSignal","bufferEvent","input","durableBufferedEvent","publishedAt","listBufferedEvents","Number","removeBufferedEvent","col","attributeColumnFor","operand","attributeOperand","condition","op","some","key","bigOrNull","n","numOrUndef","v","workflowVersion","output","error","awaitingDecisionTaskId","recoveryAttempts","priority","updatedAt","getTime","kind","stepId","events","attempts","workerGroup","enqueuedAt","startedAt","finishedAt","durableManagedTables"]}
package/dist/index.d.cts CHANGED
@@ -16,6 +16,9 @@ interface RunRow {
16
16
  tags: unknown;
17
17
  searchAttributes: unknown;
18
18
  priority: number | null;
19
+ /** NOT NULL in the schema (defaulted to `'default'`), so every row carries a real namespace. */
20
+ namespace: string;
21
+ origin: string | null;
19
22
  createdAt: Date;
20
23
  updatedAt: Date;
21
24
  }
@@ -96,6 +99,11 @@ interface DurablePrismaClient extends DurablePrismaTx {
96
99
  * Prisma-backed `StateStore`. Pass your `PrismaClient` after adding the models from
97
100
  * `prisma/schema.prisma` to your schema. JSON columns carry the run/step payloads directly;
98
101
  * `wakeAt` is a `BigInt` (epoch ms).
102
+ *
103
+ * Every path a worker acts on is namespace-scoped when it is given one — `listPendingRuns` (pick up),
104
+ * `listIncompleteRuns` (recover), `listDueTimers` (resume timers) and `listRuns`'s `namespace`
105
+ * (the engine's timeout sweep). Omit it for the operator view across all tenants. Point-reads
106
+ * (`getRun`, checkpoints) are deliberately NOT scoped, per {@link StateStore}.
99
107
  */
100
108
  declare class PrismaStateStore implements StateStore {
101
109
  private readonly db;
@@ -113,9 +121,9 @@ declare class PrismaStateStore implements StateStore {
113
121
  raw: unknown;
114
122
  saveCheckpoint: (cp: StepCheckpoint) => Promise<void>;
115
123
  }) => Promise<T>): Promise<T>;
116
- listIncompleteRuns(): Promise<WorkflowRun[]>;
117
- listPendingRuns(limit: number): Promise<WorkflowRun[]>;
118
- listDueTimers(nowMs: number): Promise<WorkflowRun[]>;
124
+ listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
125
+ listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]>;
126
+ listDueTimers(nowMs: number, namespace?: string): Promise<WorkflowRun[]>;
119
127
  tryLockRun(runId: string, owner: string, leaseUntilMs: number, nowMs: number): Promise<boolean>;
120
128
  releaseRunLock(runId: string): Promise<void>;
121
129
  renewRunLock(runId: string, owner: string, leaseUntilMs: number): Promise<boolean>;
package/dist/index.d.ts CHANGED
@@ -16,6 +16,9 @@ interface RunRow {
16
16
  tags: unknown;
17
17
  searchAttributes: unknown;
18
18
  priority: number | null;
19
+ /** NOT NULL in the schema (defaulted to `'default'`), so every row carries a real namespace. */
20
+ namespace: string;
21
+ origin: string | null;
19
22
  createdAt: Date;
20
23
  updatedAt: Date;
21
24
  }
@@ -96,6 +99,11 @@ interface DurablePrismaClient extends DurablePrismaTx {
96
99
  * Prisma-backed `StateStore`. Pass your `PrismaClient` after adding the models from
97
100
  * `prisma/schema.prisma` to your schema. JSON columns carry the run/step payloads directly;
98
101
  * `wakeAt` is a `BigInt` (epoch ms).
102
+ *
103
+ * Every path a worker acts on is namespace-scoped when it is given one — `listPendingRuns` (pick up),
104
+ * `listIncompleteRuns` (recover), `listDueTimers` (resume timers) and `listRuns`'s `namespace`
105
+ * (the engine's timeout sweep). Omit it for the operator view across all tenants. Point-reads
106
+ * (`getRun`, checkpoints) are deliberately NOT scoped, per {@link StateStore}.
99
107
  */
100
108
  declare class PrismaStateStore implements StateStore {
101
109
  private readonly db;
@@ -113,9 +121,9 @@ declare class PrismaStateStore implements StateStore {
113
121
  raw: unknown;
114
122
  saveCheckpoint: (cp: StepCheckpoint) => Promise<void>;
115
123
  }) => Promise<T>): Promise<T>;
116
- listIncompleteRuns(): Promise<WorkflowRun[]>;
117
- listPendingRuns(limit: number): Promise<WorkflowRun[]>;
118
- listDueTimers(nowMs: number): Promise<WorkflowRun[]>;
124
+ listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
125
+ listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]>;
126
+ listDueTimers(nowMs: number, namespace?: string): Promise<WorkflowRun[]>;
119
127
  tryLockRun(runId: string, owner: string, leaseUntilMs: number, nowMs: number): Promise<boolean>;
120
128
  releaseRunLock(runId: string): Promise<void>;
121
129
  renewRunLock(runId: string, owner: string, leaseUntilMs: number): Promise<boolean>;
package/dist/index.js CHANGED
@@ -3,6 +3,13 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
3
3
 
4
4
  // src/prisma-state-store.ts
5
5
  import { attributeColumnFor, attributeOperand, normalizeAttributeRows } from "@dudousxd/nestjs-durable-core";
6
+ function namespaceWhere(namespace) {
7
+ if (namespace === void 0) return {};
8
+ return {
9
+ namespace
10
+ };
11
+ }
12
+ __name(namespaceWhere, "namespaceWhere");
6
13
  var PrismaStateStore = class {
7
14
  static {
8
15
  __name(this, "PrismaStateStore");
@@ -111,7 +118,7 @@ var PrismaStateStore = class {
111
118
  }, "saveCheckpoint")
112
119
  }));
113
120
  }
114
- async listIncompleteRuns() {
121
+ async listIncompleteRuns(namespace) {
115
122
  const rows = await this.db.durableWorkflowRun.findMany({
116
123
  where: {
117
124
  status: {
@@ -119,15 +126,17 @@ var PrismaStateStore = class {
119
126
  "running",
120
127
  "cancelling"
121
128
  ]
122
- }
129
+ },
130
+ ...namespaceWhere(namespace)
123
131
  }
124
132
  });
125
133
  return rows.map(fromRunRow);
126
134
  }
127
- async listPendingRuns(limit) {
135
+ async listPendingRuns(limit, namespace) {
128
136
  const rows = await this.db.durableWorkflowRun.findMany({
129
137
  where: {
130
- status: "pending"
138
+ status: "pending",
139
+ ...namespaceWhere(namespace)
131
140
  },
132
141
  orderBy: {
133
142
  createdAt: "asc"
@@ -136,14 +145,15 @@ var PrismaStateStore = class {
136
145
  });
137
146
  return rows.map(fromRunRow);
138
147
  }
139
- async listDueTimers(nowMs) {
148
+ async listDueTimers(nowMs, namespace) {
140
149
  const rows = await this.db.durableWorkflowRun.findMany({
141
150
  where: {
142
151
  status: "suspended",
143
152
  wakeAt: {
144
153
  not: null,
145
154
  lte: BigInt(nowMs)
146
- }
155
+ },
156
+ ...namespaceWhere(namespace)
147
157
  }
148
158
  });
149
159
  return rows.map(fromRunRow);
@@ -194,8 +204,11 @@ var PrismaStateStore = class {
194
204
  return result.count === 1;
195
205
  }
196
206
  async listRuns(query) {
197
- const where = {};
207
+ const where = {
208
+ ...namespaceWhere(query.namespace)
209
+ };
198
210
  if (query.workflow) where.workflow = query.workflow;
211
+ if (query.origin !== void 0) where.origin = query.origin;
199
212
  if (query.status && query.statuses) {
200
213
  where.AND = [
201
214
  {
@@ -436,6 +449,12 @@ function toRunData(run) {
436
449
  tags: jsonOrNull(run.tags),
437
450
  searchAttributes: jsonOrNull(run.searchAttributes),
438
451
  priority: run.priority ?? null,
452
+ // An absent namespace IS `'default'` — unlike `origin` below, this is a reconstruction and not a
453
+ // guess: an engine started without a namespace stamps its runs and routes its workers as
454
+ // `'default'`, so writing anything else (or NULL) would put the run in a partition no worker polls.
455
+ namespace: run.namespace ?? "default",
456
+ // Absent origin stays SQL NULL — "unknown", never coerced into a real-looking library name.
457
+ origin: run.origin ?? null,
439
458
  createdAt: run.createdAt,
440
459
  updatedAt: run.updatedAt
441
460
  };
@@ -457,6 +476,8 @@ function toRunPatch(patch) {
457
476
  if ("tags" in patch) data.tags = jsonOrNull(patch.tags);
458
477
  if ("searchAttributes" in patch) data.searchAttributes = jsonOrNull(patch.searchAttributes);
459
478
  if ("priority" in patch) data.priority = patch.priority ?? null;
479
+ if ("namespace" in patch) data.namespace = patch.namespace ?? "default";
480
+ if ("origin" in patch) data.origin = patch.origin ?? null;
460
481
  if (patch.createdAt != null) data.createdAt = patch.createdAt;
461
482
  if (patch.updatedAt != null) data.updatedAt = patch.updatedAt;
462
483
  return data;
@@ -479,6 +500,14 @@ function fromRunRow(row) {
479
500
  tags: row.tags ?? void 0,
480
501
  searchAttributes: row.searchAttributes ?? void 0,
481
502
  priority: row.priority ?? void 0,
503
+ // Read back verbatim, with NO `?? 'default'` fallback. The column is NOT NULL and the migration
504
+ // back-fills old rows, so there is nothing legitimate to fall back FROM; a fallback would only fire
505
+ // on a deployment that added the column nullable without back-filling, and there it would lie —
506
+ // the dashboard would show `default` for a row whose stored NULL keeps every `default` worker's
507
+ // `WHERE namespace = 'default'` from ever picking it up.
508
+ namespace: row.namespace,
509
+ // NULL (a row written before the column existed) surfaces as `undefined` = unknown origin.
510
+ origin: row.origin ?? void 0,
482
511
  createdAt: row.createdAt,
483
512
  updatedAt: row.updatedAt
484
513
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/prisma-state-store.ts","../src/schema.ts"],"sourcesContent":["import {\n type AttributeFilter,\n type RunQuery,\n type SignalWaiter,\n type StateStore,\n type StepCheckpoint,\n type StepError,\n type StepEvent,\n type WorkflowRun,\n attributeColumnFor,\n attributeOperand,\n normalizeAttributeRows,\n} from '@dudousxd/nestjs-durable-core';\n\n/* The Prisma client is generated per-schema, so the adapter can't import a concrete one. Instead\n it depends on this structural surface — the three model delegates and the methods it uses. A\n real `PrismaClient` (with the models from prisma/schema.prisma added) satisfies it. Query-arg\n shapes are Prisma's own generics, so they're left as `any` at this single boundary; the row\n return types are precise, which is what the mapping code below relies on. */\n\ninterface RunRow {\n id: string;\n workflow: string;\n workflowVersion: string;\n status: string;\n input: unknown;\n output: unknown;\n error: unknown;\n wakeAt: bigint | null;\n lockedBy: string | null;\n lockedUntil: Date | null;\n awaitingDecisionTaskId: string | null;\n recoveryAttempts: number | null;\n tags: unknown;\n searchAttributes: unknown;\n priority: number | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\ninterface CheckpointRow {\n runId: string;\n seq: number;\n name: string;\n kind: string;\n stepId: string;\n status: string;\n input: unknown;\n output: unknown;\n error: unknown;\n events: unknown;\n attempts: number;\n workerGroup: string | null;\n parallelGroup: string | null;\n wakeAt: bigint | null;\n enqueuedAt: Date | null;\n startedAt: Date;\n finishedAt: Date;\n}\n\ninterface WaiterRow {\n token: string;\n runId: string;\n seq: number;\n parallelGroup: string | null;\n}\n\ninterface RunAttributeRow {\n runId: string;\n key: string;\n strValue: string | null;\n numValue: number | null;\n}\n\ninterface BufferedSignalRow {\n id: bigint;\n token: string;\n payload: unknown;\n}\n\ninterface BufferedEventRow {\n id: string;\n name: string;\n payload: unknown;\n publishedAt: bigint;\n}\n\n// Prisma's per-model query args are generated generics; left as `any` at this single boundary.\ntype Args = any;\n\ninterface Delegate<Row> {\n create(args: Args): Promise<Row>;\n createMany(args: Args): Promise<{ count: number }>;\n findUnique(args: Args): Promise<Row | null>;\n findFirst(args?: Args): Promise<Row | null>;\n findMany(args?: Args): Promise<Row[]>;\n update(args: Args): Promise<Row>;\n updateMany(args: Args): Promise<{ count: number }>;\n upsert(args: Args): Promise<Row>;\n delete(args: Args): Promise<Row>;\n deleteMany(args?: Args): Promise<{ count: number }>;\n}\n\nexport interface DurablePrismaTx {\n durableWorkflowRun: Delegate<RunRow>;\n durableStepCheckpoint: Delegate<CheckpointRow>;\n durableRunAttribute: Delegate<RunAttributeRow>;\n durableSignalWaiter: Delegate<WaiterRow>;\n durableBufferedSignal: Delegate<BufferedSignalRow>;\n durableBufferedEvent: Delegate<BufferedEventRow>;\n}\n\nexport interface DurablePrismaClient extends DurablePrismaTx {\n /** Prisma's interactive-transaction form: runs `fn` with a tx-scoped client and commits on resolve. */\n $transaction<T>(fn: (tx: DurablePrismaTx) => Promise<T>): Promise<T>;\n}\n\n/**\n * Prisma-backed `StateStore`. Pass your `PrismaClient` after adding the models from\n * `prisma/schema.prisma` to your schema. JSON columns carry the run/step payloads directly;\n * `wakeAt` is a `BigInt` (epoch ms).\n */\nexport class PrismaStateStore implements StateStore {\n constructor(private readonly db: DurablePrismaClient) {}\n\n async createRun(run: WorkflowRun): Promise<void> {\n await this.db.durableWorkflowRun.create({ data: toRunData(run) });\n await this.reindexAttributes(run.id, run.searchAttributes);\n }\n\n async updateRun(runId: string, patch: Partial<WorkflowRun>): Promise<void> {\n await this.db.durableWorkflowRun.update({ where: { id: runId }, data: toRunPatch(patch) });\n // Keep the side-table in step with the run's attributes whenever they're patched.\n if ('searchAttributes' in patch) await this.reindexAttributes(runId, patch.searchAttributes);\n }\n\n /** Rewrite a run's normalized attribute rows: delete the old set, insert the current one. Mirrors\n * the in-memory store's reindex so the side-table always reflects the run's live searchAttributes. */\n private async reindexAttributes(\n runId: string,\n attributes: WorkflowRun['searchAttributes'],\n ): Promise<void> {\n await this.db.durableRunAttribute.deleteMany({ where: { runId } });\n const rows = normalizeAttributeRows(runId, attributes);\n if (rows.length) await this.db.durableRunAttribute.createMany({ data: rows });\n }\n\n async getRun(runId: string): Promise<WorkflowRun | null> {\n const row = await this.db.durableWorkflowRun.findUnique({ where: { id: runId } });\n return row ? fromRunRow(row) : null;\n }\n\n async deleteRun(runId: string): Promise<void> {\n // Child rows first, then the run — checkpoints, signal waiters, attribute rows.\n await this.db.durableStepCheckpoint.deleteMany({ where: { runId } });\n await this.db.durableSignalWaiter.deleteMany({ where: { runId } });\n await this.db.durableRunAttribute.deleteMany({ where: { runId } });\n await this.db.durableWorkflowRun.deleteMany({ where: { id: runId } });\n }\n\n async getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null> {\n const row = await this.db.durableStepCheckpoint.findUnique({\n where: { runId_seq: { runId, seq } },\n });\n return row ? fromCheckpointRow(row) : null;\n }\n\n async saveCheckpoint(checkpoint: StepCheckpoint): Promise<void> {\n const data = toCheckpointData(checkpoint);\n await this.db.durableStepCheckpoint.upsert({\n where: { runId_seq: { runId: checkpoint.runId, seq: checkpoint.seq } },\n create: data,\n update: data,\n });\n }\n\n async transaction<T>(\n work: (tx: {\n raw: unknown;\n saveCheckpoint: (cp: StepCheckpoint) => Promise<void>;\n }) => Promise<T>,\n ): Promise<T> {\n return this.db.$transaction(async (tx) =>\n work({\n raw: tx,\n saveCheckpoint: async (cp) => {\n const data = toCheckpointData(cp);\n await tx.durableStepCheckpoint.upsert({\n where: { runId_seq: { runId: cp.runId, seq: cp.seq } },\n create: data,\n update: data,\n });\n },\n }),\n );\n }\n\n async listIncompleteRuns(): Promise<WorkflowRun[]> {\n const rows = await this.db.durableWorkflowRun.findMany({\n where: { status: { in: ['running', 'cancelling'] } },\n });\n return rows.map(fromRunRow);\n }\n\n async listPendingRuns(limit: number): Promise<WorkflowRun[]> {\n const rows = await this.db.durableWorkflowRun.findMany({\n where: { status: 'pending' },\n orderBy: { createdAt: 'asc' }, // FIFO dispatch\n take: limit,\n });\n return rows.map(fromRunRow);\n }\n\n async listDueTimers(nowMs: number): Promise<WorkflowRun[]> {\n const rows = await this.db.durableWorkflowRun.findMany({\n where: { status: 'suspended', wakeAt: { not: null, lte: BigInt(nowMs) } },\n });\n return rows.map(fromRunRow);\n }\n\n async tryLockRun(\n runId: string,\n owner: string,\n leaseUntilMs: number,\n nowMs: number,\n ): Promise<boolean> {\n const result = await this.db.durableWorkflowRun.updateMany({\n where: {\n id: runId,\n OR: [{ lockedUntil: null }, { lockedUntil: { lte: new Date(nowMs) } }],\n },\n data: { lockedBy: owner, lockedUntil: new Date(leaseUntilMs) },\n });\n return result.count === 1;\n }\n\n async releaseRunLock(runId: string): Promise<void> {\n // Idempotent by design: releasing the lease on a run that no longer exists is a no-op, not an\n // error. The engine calls this best-effort in a `finally` AFTER the run has settled, so it can\n // race a concurrent purge/teardown — Prisma's `update({ where: { id } })` would throw P2025\n // (\"No record was found for an update\") on that race and, since the call is fire-and-forget on\n // the engine's terminal path, surface as an unhandled rejection. `updateMany` matches a 0-row\n // WHERE to an empty result (no throw), mirroring the in-memory store's `if (run)` guard and the\n // set-where semantics of every sibling adapter (TypeORM/MikroORM/Drizzle).\n await this.db.durableWorkflowRun.updateMany({\n where: { id: runId },\n data: { lockedBy: null, lockedUntil: null },\n });\n }\n\n async renewRunLock(runId: string, owner: string, leaseUntilMs: number): Promise<boolean> {\n const result = await this.db.durableWorkflowRun.updateMany({\n where: { id: runId, lockedBy: owner },\n data: { lockedUntil: new Date(leaseUntilMs) },\n });\n return result.count === 1;\n }\n\n async listRuns(query: RunQuery): Promise<WorkflowRun[]> {\n const where: Record<string, unknown> = {};\n if (query.workflow) where.workflow = query.workflow;\n // `status IN (...)`; an empty set matches nothing (mirrors the in-memory store). Combined with the\n // single-value `status` via AND when both are present, so the narrower set wins.\n if (query.status && query.statuses) {\n where.AND = [{ status: query.status }, { status: { in: query.statuses } }];\n } else if (query.status) {\n where.status = query.status;\n } else if (query.statuses) {\n where.status = { in: query.statuses };\n }\n if (query.tag) where.tags = { array_contains: query.tag };\n // Typed/range attribute predicates push DOWN into SQL: each filter becomes a relation `some`\n // (EXISTS) on the normalized `durable_run_attributes` side-table, so the DB filters AND paginates\n // — no full scan + in-process filter. ANDed: a run must match every filter, so one `some` each.\n if (query.attributes?.length) {\n const existing = (where.AND as unknown[] | undefined) ?? [];\n where.AND = [...existing, ...query.attributes.map((f) => attributeSome(f))];\n }\n const orderBy = { createdAt: 'desc' as const }; // newest first — recent runs on top in the dashboard\n const rows = await this.db.durableWorkflowRun.findMany({\n where,\n take: query.limit,\n skip: query.offset,\n orderBy,\n });\n return rows.map(fromRunRow);\n }\n\n async listCheckpoints(runId: string): Promise<StepCheckpoint[]> {\n const rows = await this.db.durableStepCheckpoint.findMany({\n where: { runId },\n orderBy: { seq: 'asc' },\n });\n return rows.map(fromCheckpointRow);\n }\n\n async getLatestCheckpointByName(\n runId: string,\n name: string,\n ): Promise<StepCheckpoint | undefined> {\n const row = await this.db.durableStepCheckpoint.findFirst({\n where: { runId, name },\n orderBy: { seq: 'desc' },\n });\n return row ? fromCheckpointRow(row) : undefined;\n }\n\n async listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]> {\n if (prefixes.length === 0) return [];\n const rows = await this.db.durableStepCheckpoint.findMany({\n where: { runId, OR: prefixes.map((p) => ({ name: { startsWith: p } })) },\n orderBy: { seq: 'asc' },\n });\n return rows.map(fromCheckpointRow);\n }\n\n async putSignalWaiter(waiter: SignalWaiter): Promise<void> {\n await this.db.durableSignalWaiter.upsert({\n where: { token: waiter.token },\n create: {\n token: waiter.token,\n runId: waiter.runId,\n seq: waiter.seq,\n parallelGroup: waiter.parallelGroup ?? null,\n },\n update: {\n runId: waiter.runId,\n seq: waiter.seq,\n parallelGroup: waiter.parallelGroup ?? null,\n },\n });\n }\n\n async takeSignalWaiter(token: string): Promise<SignalWaiter | null> {\n const row = await this.db.durableSignalWaiter.findUnique({ where: { token } });\n if (!row) return null;\n await this.db.durableSignalWaiter.delete({ where: { token } });\n return {\n token: row.token,\n runId: row.runId,\n seq: row.seq,\n parallelGroup: row.parallelGroup ?? undefined,\n };\n }\n\n async listSignalWaiters(prefix: string): Promise<SignalWaiter[]> {\n const rows = await this.db.durableSignalWaiter.findMany({\n where: { token: { startsWith: prefix } },\n });\n return rows.map((r) => ({\n token: r.token,\n runId: r.runId,\n seq: r.seq,\n parallelGroup: r.parallelGroup ?? undefined,\n }));\n }\n\n async removeSignalWaiter(waiter: SignalWaiter): Promise<void> {\n // Exact-match delete (token AND runId AND seq): `token` is the only unique column, so a plain\n // `delete({ where: { token } })` would remove whatever row currently owns it, even if a different\n // run has since claimed the same token — `deleteMany` with all three fields is a safe no-op then.\n await this.db.durableSignalWaiter.deleteMany({\n where: { token: waiter.token, runId: waiter.runId, seq: waiter.seq },\n });\n }\n\n async bufferSignal(token: string, payload: unknown): Promise<void> {\n await this.db.durableBufferedSignal.create({ data: { token, payload: jsonOrNull(payload) } });\n }\n\n async takeBufferedSignal(token: string): Promise<{ payload: unknown } | null> {\n const row = await this.db.durableBufferedSignal.findFirst({\n where: { token },\n orderBy: { id: 'asc' },\n });\n if (!row) return null;\n await this.db.durableBufferedSignal.delete({ where: { id: row.id } });\n return { payload: row.payload ?? undefined };\n }\n\n async bufferEvent(input: {\n name: string;\n payload: unknown;\n id: string;\n publishedAt: number;\n }): Promise<void> {\n await this.db.durableBufferedEvent.create({\n data: {\n id: input.id,\n name: input.name,\n payload: jsonOrNull(input.payload),\n publishedAt: BigInt(input.publishedAt),\n },\n });\n }\n\n async listBufferedEvents(\n name: string,\n limit: number,\n ): Promise<Array<{ id: string; payload: unknown; publishedAt: number }>> {\n const rows = await this.db.durableBufferedEvent.findMany({\n where: { name },\n orderBy: { publishedAt: 'asc' }, // oldest first\n take: limit,\n });\n return rows.map((r) => ({\n id: r.id,\n payload: r.payload ?? undefined,\n publishedAt: Number(r.publishedAt),\n }));\n }\n\n async removeBufferedEvent(id: string): Promise<boolean> {\n // deleteMany's `where: { id }` matches at most one row (id is the PK) and is a safe no-op if it's\n // already gone — unlike `delete({ where: { id } })`, which throws P2025 on a missing row (the same\n // reasoning as releaseRunLock's updateMany above).\n const result = await this.db.durableBufferedEvent.deleteMany({ where: { id } });\n return result.count === 1;\n }\n}\n\n/**\n * One attribute predicate as a Prisma relation `some` filter on the side-table — compiles to an\n * EXISTS, so the predicate runs in SQL. `<>` (ne) maps to `{ not }`, which under `some` also excludes\n * runs where the attribute is absent (the missing-key-never-matches contract): `some` already\n * requires a matching row to exist. Numeric operands compare `numValue`, everything else `strValue`.\n */\nfunction attributeSome(f: AttributeFilter): { attributes: { some: Record<string, unknown> } } {\n const col = attributeColumnFor(f); // 'numValue' | 'strValue'\n const operand = attributeOperand(f);\n const condition =\n f.op === 'eq' ? operand : f.op === 'ne' ? { not: operand } : { [f.op]: operand }; // gt/gte/lt/lte map 1:1 to Prisma operators\n return { attributes: { some: { key: f.key, [col]: condition } } };\n}\n\nconst bigOrNull = (n: number | undefined) => (n == null ? null : BigInt(n));\nconst numOrUndef = (n: bigint | null) => (n == null ? undefined : Number(n));\nconst jsonOrNull = (v: unknown) => v ?? null;\n\nfunction toRunData(run: WorkflowRun) {\n return {\n id: run.id,\n workflow: run.workflow,\n workflowVersion: run.workflowVersion,\n status: run.status,\n input: jsonOrNull(run.input),\n output: jsonOrNull(run.output),\n error: jsonOrNull(run.error),\n wakeAt: bigOrNull(run.wakeAt),\n lockedBy: run.lockedBy ?? null,\n lockedUntil: run.lockedUntil == null ? null : new Date(run.lockedUntil),\n awaitingDecisionTaskId: run.awaitingDecisionTaskId ?? null,\n recoveryAttempts: run.recoveryAttempts ?? null,\n tags: jsonOrNull(run.tags),\n searchAttributes: jsonOrNull(run.searchAttributes),\n priority: run.priority ?? null,\n createdAt: run.createdAt,\n updatedAt: run.updatedAt,\n };\n}\n\nfunction toRunPatch(patch: Partial<WorkflowRun>) {\n // Map EVERY patchable field, using presence (`'x' in patch`) semantics for the nullable ones so a\n // patch can CLEAR a column (e.g. `{ error: undefined }` on completion sets it to NULL — matching\n // the TypeORM / MikroORM / in-memory stores). The two non-null Date fields use a defined-guard\n // since they are never cleared. Previously only 7 fields were mapped, so `updateRun({ tags })` /\n // `{ lockedBy }` / clearing `error` silently no-opped on this adapter.\n const data: Record<string, unknown> = {};\n if ('workflow' in patch) data.workflow = patch.workflow;\n if ('workflowVersion' in patch) data.workflowVersion = patch.workflowVersion;\n if ('status' in patch) data.status = patch.status;\n if ('input' in patch) data.input = jsonOrNull(patch.input);\n if ('output' in patch) data.output = jsonOrNull(patch.output);\n if ('error' in patch) data.error = jsonOrNull(patch.error);\n if ('wakeAt' in patch) data.wakeAt = bigOrNull(patch.wakeAt);\n if ('lockedBy' in patch) data.lockedBy = patch.lockedBy ?? null;\n if ('lockedUntil' in patch)\n data.lockedUntil = patch.lockedUntil == null ? null : new Date(patch.lockedUntil);\n if ('awaitingDecisionTaskId' in patch)\n data.awaitingDecisionTaskId = patch.awaitingDecisionTaskId ?? null;\n if ('recoveryAttempts' in patch) data.recoveryAttempts = patch.recoveryAttempts ?? null;\n if ('tags' in patch) data.tags = jsonOrNull(patch.tags);\n if ('searchAttributes' in patch) data.searchAttributes = jsonOrNull(patch.searchAttributes);\n if ('priority' in patch) data.priority = patch.priority ?? null;\n if (patch.createdAt != null) data.createdAt = patch.createdAt;\n if (patch.updatedAt != null) data.updatedAt = patch.updatedAt;\n return data;\n}\n\nfunction fromRunRow(row: RunRow): WorkflowRun {\n return {\n id: row.id,\n workflow: row.workflow,\n workflowVersion: row.workflowVersion,\n status: row.status as WorkflowRun['status'],\n input: row.input ?? undefined,\n output: row.output ?? undefined,\n error: (row.error ?? undefined) as StepError | undefined,\n wakeAt: numOrUndef(row.wakeAt),\n lockedBy: row.lockedBy ?? undefined,\n lockedUntil: row.lockedUntil == null ? undefined : row.lockedUntil.getTime(),\n awaitingDecisionTaskId: row.awaitingDecisionTaskId ?? undefined,\n recoveryAttempts: row.recoveryAttempts ?? undefined,\n tags: (row.tags as string[] | null) ?? undefined,\n searchAttributes:\n (row.searchAttributes as Record<string, string | number | boolean> | null) ?? undefined,\n priority: row.priority ?? undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction toCheckpointData(cp: StepCheckpoint) {\n return {\n runId: cp.runId,\n seq: cp.seq,\n name: cp.name,\n kind: cp.kind,\n stepId: cp.stepId,\n status: cp.status,\n input: jsonOrNull(cp.input),\n output: jsonOrNull(cp.output),\n error: jsonOrNull(cp.error),\n events: jsonOrNull(cp.events),\n attempts: cp.attempts,\n workerGroup: cp.workerGroup ?? null,\n parallelGroup: cp.parallelGroup ?? null,\n wakeAt: bigOrNull(cp.wakeAt),\n enqueuedAt: cp.enqueuedAt,\n startedAt: cp.startedAt,\n finishedAt: cp.finishedAt,\n };\n}\n\nfunction fromCheckpointRow(row: CheckpointRow): StepCheckpoint {\n return {\n runId: row.runId,\n seq: row.seq,\n name: row.name,\n kind: row.kind as StepCheckpoint['kind'],\n stepId: row.stepId,\n status: row.status as StepCheckpoint['status'],\n input: row.input ?? undefined,\n output: row.output ?? undefined,\n error: (row.error ?? undefined) as StepError | undefined,\n events: (row.events ?? undefined) as StepEvent[] | undefined,\n attempts: row.attempts,\n workerGroup: row.workerGroup ?? undefined,\n parallelGroup: row.parallelGroup ?? undefined,\n wakeAt: numOrUndef(row.wakeAt),\n enqueuedAt: row.enqueuedAt ?? row.startedAt,\n startedAt: row.startedAt,\n finishedAt: row.finishedAt,\n };\n}\n","/**\n * Tables this store's durable models own, physically. UNLIKE the other store adapters, this store\n * doesn't create or manage them at boot: the models in `prisma/schema.prisma` are meant to be copied\n * into YOUR OWN `schema.prisma` (see that file's header comment), and Prisma Migrate diffs whatever\n * models live in your schema — so a consumer who copied the models in already has them accounted for\n * and never needs a denylist for Prisma Migrate itself.\n *\n * This is exported anyway for the same reason the other adapters export it: any OTHER tooling that\n * introspects the database outside of `prisma migrate diff` (a raw schema dump, a second ORM/CLI\n * pointed at the same database, a linter that flags \"table not in any model\") needs the same fixed\n * list of table names this store's models declare via `@@map(...)`.\n *\n * ```ts\n * const skipTables = new Set(durableManagedTables());\n * ```\n *\n * Kept in sync with the `@@map(...)` table names in `prisma/schema.prisma` by `schema.spec.ts`,\n * which parses that file and asserts the two lists match — there is no single TypeScript source to\n * derive from (the schema is a `.prisma` text file copied into the consumer's own schema, not\n * imported at runtime), so the list here is intentionally a literal mirror.\n */\nexport function durableManagedTables(): string[] {\n return [\n 'durable_workflow_runs',\n 'durable_step_checkpoints',\n 'durable_run_attributes',\n 'durable_signal_waiters',\n 'durable_buffered_signals',\n 'durable_buffered_events',\n ];\n}\n"],"mappings":"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","names":["attributeColumnFor","attributeOperand","normalizeAttributeRows","PrismaStateStore","db","createRun","run","durableWorkflowRun","create","data","toRunData","reindexAttributes","id","searchAttributes","updateRun","runId","patch","update","where","toRunPatch","attributes","durableRunAttribute","deleteMany","rows","normalizeAttributeRows","length","createMany","getRun","row","findUnique","fromRunRow","deleteRun","durableStepCheckpoint","durableSignalWaiter","getCheckpoint","seq","runId_seq","fromCheckpointRow","saveCheckpoint","checkpoint","toCheckpointData","upsert","transaction","work","$transaction","tx","raw","cp","listIncompleteRuns","findMany","status","in","map","listPendingRuns","limit","orderBy","createdAt","take","listDueTimers","nowMs","wakeAt","not","lte","BigInt","tryLockRun","owner","leaseUntilMs","result","updateMany","OR","lockedUntil","Date","lockedBy","count","releaseRunLock","renewRunLock","listRuns","query","workflow","statuses","AND","tag","tags","array_contains","existing","f","attributeSome","skip","offset","listCheckpoints","getLatestCheckpointByName","name","findFirst","undefined","listCheckpointsByNamePrefix","prefixes","p","startsWith","putSignalWaiter","waiter","token","parallelGroup","takeSignalWaiter","delete","listSignalWaiters","prefix","r","removeSignalWaiter","bufferSignal","payload","durableBufferedSignal","jsonOrNull","takeBufferedSignal","bufferEvent","input","durableBufferedEvent","publishedAt","listBufferedEvents","Number","removeBufferedEvent","col","attributeColumnFor","operand","attributeOperand","condition","op","some","key","bigOrNull","n","numOrUndef","v","workflowVersion","output","error","awaitingDecisionTaskId","recoveryAttempts","priority","updatedAt","getTime","kind","stepId","events","attempts","workerGroup","enqueuedAt","startedAt","finishedAt","durableManagedTables"]}
1
+ {"version":3,"sources":["../src/prisma-state-store.ts","../src/schema.ts"],"sourcesContent":["import {\n type AttributeFilter,\n type RunQuery,\n type SignalWaiter,\n type StateStore,\n type StepCheckpoint,\n type StepError,\n type StepEvent,\n type WorkflowRun,\n attributeColumnFor,\n attributeOperand,\n normalizeAttributeRows,\n} from '@dudousxd/nestjs-durable-core';\n\n/* The Prisma client is generated per-schema, so the adapter can't import a concrete one. Instead\n it depends on this structural surface — the three model delegates and the methods it uses. A\n real `PrismaClient` (with the models from prisma/schema.prisma added) satisfies it. Query-arg\n shapes are Prisma's own generics, so they're left as `any` at this single boundary; the row\n return types are precise, which is what the mapping code below relies on. */\n\ninterface RunRow {\n id: string;\n workflow: string;\n workflowVersion: string;\n status: string;\n input: unknown;\n output: unknown;\n error: unknown;\n wakeAt: bigint | null;\n lockedBy: string | null;\n lockedUntil: Date | null;\n awaitingDecisionTaskId: string | null;\n recoveryAttempts: number | null;\n tags: unknown;\n searchAttributes: unknown;\n priority: number | null;\n /** NOT NULL in the schema (defaulted to `'default'`), so every row carries a real namespace. */\n namespace: string;\n origin: string | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\ninterface CheckpointRow {\n runId: string;\n seq: number;\n name: string;\n kind: string;\n stepId: string;\n status: string;\n input: unknown;\n output: unknown;\n error: unknown;\n events: unknown;\n attempts: number;\n workerGroup: string | null;\n parallelGroup: string | null;\n wakeAt: bigint | null;\n enqueuedAt: Date | null;\n startedAt: Date;\n finishedAt: Date;\n}\n\ninterface WaiterRow {\n token: string;\n runId: string;\n seq: number;\n parallelGroup: string | null;\n}\n\ninterface RunAttributeRow {\n runId: string;\n key: string;\n strValue: string | null;\n numValue: number | null;\n}\n\ninterface BufferedSignalRow {\n id: bigint;\n token: string;\n payload: unknown;\n}\n\ninterface BufferedEventRow {\n id: string;\n name: string;\n payload: unknown;\n publishedAt: bigint;\n}\n\n// Prisma's per-model query args are generated generics; left as `any` at this single boundary.\ntype Args = any;\n\ninterface Delegate<Row> {\n create(args: Args): Promise<Row>;\n createMany(args: Args): Promise<{ count: number }>;\n findUnique(args: Args): Promise<Row | null>;\n findFirst(args?: Args): Promise<Row | null>;\n findMany(args?: Args): Promise<Row[]>;\n update(args: Args): Promise<Row>;\n updateMany(args: Args): Promise<{ count: number }>;\n upsert(args: Args): Promise<Row>;\n delete(args: Args): Promise<Row>;\n deleteMany(args?: Args): Promise<{ count: number }>;\n}\n\nexport interface DurablePrismaTx {\n durableWorkflowRun: Delegate<RunRow>;\n durableStepCheckpoint: Delegate<CheckpointRow>;\n durableRunAttribute: Delegate<RunAttributeRow>;\n durableSignalWaiter: Delegate<WaiterRow>;\n durableBufferedSignal: Delegate<BufferedSignalRow>;\n durableBufferedEvent: Delegate<BufferedEventRow>;\n}\n\nexport interface DurablePrismaClient extends DurablePrismaTx {\n /** Prisma's interactive-transaction form: runs `fn` with a tx-scoped client and commits on resolve. */\n $transaction<T>(fn: (tx: DurablePrismaTx) => Promise<T>): Promise<T>;\n}\n\n/**\n * The `namespace` read boundary as a spreadable Prisma `where` fragment.\n *\n * `undefined` means NO RESTRICTION — `{}` — because that is the operator (control-plane) view that\n * sees every tenant, and it is what the engine passes when it runs unscoped. It does NOT mean\n * \"namespace IS NULL\": the column is NOT NULL, so `{ namespace: undefined }` would be Prisma's\n * \"ignore this predicate\" anyway, but `{ namespace: null }` would match nothing in production while\n * still looking correct in a single-tenant test where every worker polls unscoped.\n *\n * A named namespace is plain equality, so a worker sees only its own tenant's rows — the boundary\n * {@link WorkflowRun.namespace} promises for the four worker paths (pick up, recover, resume timers,\n * time out).\n */\nfunction namespaceWhere(namespace?: string): { namespace?: string } {\n if (namespace === undefined) return {};\n return { namespace };\n}\n\n/**\n * Prisma-backed `StateStore`. Pass your `PrismaClient` after adding the models from\n * `prisma/schema.prisma` to your schema. JSON columns carry the run/step payloads directly;\n * `wakeAt` is a `BigInt` (epoch ms).\n *\n * Every path a worker acts on is namespace-scoped when it is given one — `listPendingRuns` (pick up),\n * `listIncompleteRuns` (recover), `listDueTimers` (resume timers) and `listRuns`'s `namespace`\n * (the engine's timeout sweep). Omit it for the operator view across all tenants. Point-reads\n * (`getRun`, checkpoints) are deliberately NOT scoped, per {@link StateStore}.\n */\nexport class PrismaStateStore implements StateStore {\n constructor(private readonly db: DurablePrismaClient) {}\n\n async createRun(run: WorkflowRun): Promise<void> {\n await this.db.durableWorkflowRun.create({ data: toRunData(run) });\n await this.reindexAttributes(run.id, run.searchAttributes);\n }\n\n async updateRun(runId: string, patch: Partial<WorkflowRun>): Promise<void> {\n await this.db.durableWorkflowRun.update({ where: { id: runId }, data: toRunPatch(patch) });\n // Keep the side-table in step with the run's attributes whenever they're patched.\n if ('searchAttributes' in patch) await this.reindexAttributes(runId, patch.searchAttributes);\n }\n\n /** Rewrite a run's normalized attribute rows: delete the old set, insert the current one. Mirrors\n * the in-memory store's reindex so the side-table always reflects the run's live searchAttributes. */\n private async reindexAttributes(\n runId: string,\n attributes: WorkflowRun['searchAttributes'],\n ): Promise<void> {\n await this.db.durableRunAttribute.deleteMany({ where: { runId } });\n const rows = normalizeAttributeRows(runId, attributes);\n if (rows.length) await this.db.durableRunAttribute.createMany({ data: rows });\n }\n\n async getRun(runId: string): Promise<WorkflowRun | null> {\n const row = await this.db.durableWorkflowRun.findUnique({ where: { id: runId } });\n return row ? fromRunRow(row) : null;\n }\n\n async deleteRun(runId: string): Promise<void> {\n // Child rows first, then the run — checkpoints, signal waiters, attribute rows.\n await this.db.durableStepCheckpoint.deleteMany({ where: { runId } });\n await this.db.durableSignalWaiter.deleteMany({ where: { runId } });\n await this.db.durableRunAttribute.deleteMany({ where: { runId } });\n await this.db.durableWorkflowRun.deleteMany({ where: { id: runId } });\n }\n\n async getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null> {\n const row = await this.db.durableStepCheckpoint.findUnique({\n where: { runId_seq: { runId, seq } },\n });\n return row ? fromCheckpointRow(row) : null;\n }\n\n async saveCheckpoint(checkpoint: StepCheckpoint): Promise<void> {\n const data = toCheckpointData(checkpoint);\n await this.db.durableStepCheckpoint.upsert({\n where: { runId_seq: { runId: checkpoint.runId, seq: checkpoint.seq } },\n create: data,\n update: data,\n });\n }\n\n async transaction<T>(\n work: (tx: {\n raw: unknown;\n saveCheckpoint: (cp: StepCheckpoint) => Promise<void>;\n }) => Promise<T>,\n ): Promise<T> {\n return this.db.$transaction(async (tx) =>\n work({\n raw: tx,\n saveCheckpoint: async (cp) => {\n const data = toCheckpointData(cp);\n await tx.durableStepCheckpoint.upsert({\n where: { runId_seq: { runId: cp.runId, seq: cp.seq } },\n create: data,\n update: data,\n });\n },\n }),\n );\n }\n\n async listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]> {\n const rows = await this.db.durableWorkflowRun.findMany({\n where: { status: { in: ['running', 'cancelling'] }, ...namespaceWhere(namespace) },\n });\n return rows.map(fromRunRow);\n }\n\n async listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]> {\n const rows = await this.db.durableWorkflowRun.findMany({\n where: { status: 'pending', ...namespaceWhere(namespace) },\n orderBy: { createdAt: 'asc' }, // FIFO dispatch\n take: limit,\n });\n return rows.map(fromRunRow);\n }\n\n async listDueTimers(nowMs: number, namespace?: string): Promise<WorkflowRun[]> {\n const rows = await this.db.durableWorkflowRun.findMany({\n where: {\n status: 'suspended',\n wakeAt: { not: null, lte: BigInt(nowMs) },\n ...namespaceWhere(namespace),\n },\n });\n return rows.map(fromRunRow);\n }\n\n async tryLockRun(\n runId: string,\n owner: string,\n leaseUntilMs: number,\n nowMs: number,\n ): Promise<boolean> {\n const result = await this.db.durableWorkflowRun.updateMany({\n where: {\n id: runId,\n OR: [{ lockedUntil: null }, { lockedUntil: { lte: new Date(nowMs) } }],\n },\n data: { lockedBy: owner, lockedUntil: new Date(leaseUntilMs) },\n });\n return result.count === 1;\n }\n\n async releaseRunLock(runId: string): Promise<void> {\n // Idempotent by design: releasing the lease on a run that no longer exists is a no-op, not an\n // error. The engine calls this best-effort in a `finally` AFTER the run has settled, so it can\n // race a concurrent purge/teardown — Prisma's `update({ where: { id } })` would throw P2025\n // (\"No record was found for an update\") on that race and, since the call is fire-and-forget on\n // the engine's terminal path, surface as an unhandled rejection. `updateMany` matches a 0-row\n // WHERE to an empty result (no throw), mirroring the in-memory store's `if (run)` guard and the\n // set-where semantics of every sibling adapter (TypeORM/MikroORM/Drizzle).\n await this.db.durableWorkflowRun.updateMany({\n where: { id: runId },\n data: { lockedBy: null, lockedUntil: null },\n });\n }\n\n async renewRunLock(runId: string, owner: string, leaseUntilMs: number): Promise<boolean> {\n const result = await this.db.durableWorkflowRun.updateMany({\n where: { id: runId, lockedBy: owner },\n data: { lockedUntil: new Date(leaseUntilMs) },\n });\n return result.count === 1;\n }\n\n async listRuns(query: RunQuery): Promise<WorkflowRun[]> {\n // The tenant boundary, and NOT only a dashboard facet: the engine's `sweepTimeouts` finds the runs\n // it may cancel through `listRuns({ workflow, status, namespace })`, so an unfiltered `namespace`\n // here lets a worker serving one tenant time out another tenant's runs — a write, not a stale\n // read. Same `undefined` = no restriction rule as the poll paths above (see `namespaceWhere`),\n // which is what keeps the operator's dashboard showing every tenant by default.\n const where: Record<string, unknown> = { ...namespaceWhere(query.namespace) };\n if (query.workflow) where.workflow = query.workflow;\n // Which library registered the workflow. Plain equality, so a run whose origin is NULL (created\n // before the column existed, or registered through a path the derivation could not classify)\n // matches NO origin value — it is never folded into a bucket to make the facet look complete.\n // Unknown-origin runs are reachable only with the filter OFF, so \"all origins\" must stay the\n // default view; a dashboard that filtered by default would make those runs look deleted.\n if (query.origin !== undefined) where.origin = query.origin;\n // `status IN (...)`; an empty set matches nothing (mirrors the in-memory store). Combined with the\n // single-value `status` via AND when both are present, so the narrower set wins.\n if (query.status && query.statuses) {\n where.AND = [{ status: query.status }, { status: { in: query.statuses } }];\n } else if (query.status) {\n where.status = query.status;\n } else if (query.statuses) {\n where.status = { in: query.statuses };\n }\n if (query.tag) where.tags = { array_contains: query.tag };\n // Typed/range attribute predicates push DOWN into SQL: each filter becomes a relation `some`\n // (EXISTS) on the normalized `durable_run_attributes` side-table, so the DB filters AND paginates\n // — no full scan + in-process filter. ANDed: a run must match every filter, so one `some` each.\n if (query.attributes?.length) {\n const existing = (where.AND as unknown[] | undefined) ?? [];\n where.AND = [...existing, ...query.attributes.map((f) => attributeSome(f))];\n }\n const orderBy = { createdAt: 'desc' as const }; // newest first — recent runs on top in the dashboard\n const rows = await this.db.durableWorkflowRun.findMany({\n where,\n take: query.limit,\n skip: query.offset,\n orderBy,\n });\n return rows.map(fromRunRow);\n }\n\n async listCheckpoints(runId: string): Promise<StepCheckpoint[]> {\n const rows = await this.db.durableStepCheckpoint.findMany({\n where: { runId },\n orderBy: { seq: 'asc' },\n });\n return rows.map(fromCheckpointRow);\n }\n\n async getLatestCheckpointByName(\n runId: string,\n name: string,\n ): Promise<StepCheckpoint | undefined> {\n const row = await this.db.durableStepCheckpoint.findFirst({\n where: { runId, name },\n orderBy: { seq: 'desc' },\n });\n return row ? fromCheckpointRow(row) : undefined;\n }\n\n async listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]> {\n if (prefixes.length === 0) return [];\n const rows = await this.db.durableStepCheckpoint.findMany({\n where: { runId, OR: prefixes.map((p) => ({ name: { startsWith: p } })) },\n orderBy: { seq: 'asc' },\n });\n return rows.map(fromCheckpointRow);\n }\n\n async putSignalWaiter(waiter: SignalWaiter): Promise<void> {\n await this.db.durableSignalWaiter.upsert({\n where: { token: waiter.token },\n create: {\n token: waiter.token,\n runId: waiter.runId,\n seq: waiter.seq,\n parallelGroup: waiter.parallelGroup ?? null,\n },\n update: {\n runId: waiter.runId,\n seq: waiter.seq,\n parallelGroup: waiter.parallelGroup ?? null,\n },\n });\n }\n\n async takeSignalWaiter(token: string): Promise<SignalWaiter | null> {\n const row = await this.db.durableSignalWaiter.findUnique({ where: { token } });\n if (!row) return null;\n await this.db.durableSignalWaiter.delete({ where: { token } });\n return {\n token: row.token,\n runId: row.runId,\n seq: row.seq,\n parallelGroup: row.parallelGroup ?? undefined,\n };\n }\n\n async listSignalWaiters(prefix: string): Promise<SignalWaiter[]> {\n const rows = await this.db.durableSignalWaiter.findMany({\n where: { token: { startsWith: prefix } },\n });\n return rows.map((r) => ({\n token: r.token,\n runId: r.runId,\n seq: r.seq,\n parallelGroup: r.parallelGroup ?? undefined,\n }));\n }\n\n async removeSignalWaiter(waiter: SignalWaiter): Promise<void> {\n // Exact-match delete (token AND runId AND seq): `token` is the only unique column, so a plain\n // `delete({ where: { token } })` would remove whatever row currently owns it, even if a different\n // run has since claimed the same token — `deleteMany` with all three fields is a safe no-op then.\n await this.db.durableSignalWaiter.deleteMany({\n where: { token: waiter.token, runId: waiter.runId, seq: waiter.seq },\n });\n }\n\n async bufferSignal(token: string, payload: unknown): Promise<void> {\n await this.db.durableBufferedSignal.create({ data: { token, payload: jsonOrNull(payload) } });\n }\n\n async takeBufferedSignal(token: string): Promise<{ payload: unknown } | null> {\n const row = await this.db.durableBufferedSignal.findFirst({\n where: { token },\n orderBy: { id: 'asc' },\n });\n if (!row) return null;\n await this.db.durableBufferedSignal.delete({ where: { id: row.id } });\n return { payload: row.payload ?? undefined };\n }\n\n async bufferEvent(input: {\n name: string;\n payload: unknown;\n id: string;\n publishedAt: number;\n }): Promise<void> {\n await this.db.durableBufferedEvent.create({\n data: {\n id: input.id,\n name: input.name,\n payload: jsonOrNull(input.payload),\n publishedAt: BigInt(input.publishedAt),\n },\n });\n }\n\n async listBufferedEvents(\n name: string,\n limit: number,\n ): Promise<Array<{ id: string; payload: unknown; publishedAt: number }>> {\n const rows = await this.db.durableBufferedEvent.findMany({\n where: { name },\n orderBy: { publishedAt: 'asc' }, // oldest first\n take: limit,\n });\n return rows.map((r) => ({\n id: r.id,\n payload: r.payload ?? undefined,\n publishedAt: Number(r.publishedAt),\n }));\n }\n\n async removeBufferedEvent(id: string): Promise<boolean> {\n // deleteMany's `where: { id }` matches at most one row (id is the PK) and is a safe no-op if it's\n // already gone — unlike `delete({ where: { id } })`, which throws P2025 on a missing row (the same\n // reasoning as releaseRunLock's updateMany above).\n const result = await this.db.durableBufferedEvent.deleteMany({ where: { id } });\n return result.count === 1;\n }\n}\n\n/**\n * One attribute predicate as a Prisma relation `some` filter on the side-table — compiles to an\n * EXISTS, so the predicate runs in SQL. `<>` (ne) maps to `{ not }`, which under `some` also excludes\n * runs where the attribute is absent (the missing-key-never-matches contract): `some` already\n * requires a matching row to exist. Numeric operands compare `numValue`, everything else `strValue`.\n */\nfunction attributeSome(f: AttributeFilter): { attributes: { some: Record<string, unknown> } } {\n const col = attributeColumnFor(f); // 'numValue' | 'strValue'\n const operand = attributeOperand(f);\n const condition =\n f.op === 'eq' ? operand : f.op === 'ne' ? { not: operand } : { [f.op]: operand }; // gt/gte/lt/lte map 1:1 to Prisma operators\n return { attributes: { some: { key: f.key, [col]: condition } } };\n}\n\nconst bigOrNull = (n: number | undefined) => (n == null ? null : BigInt(n));\nconst numOrUndef = (n: bigint | null) => (n == null ? undefined : Number(n));\nconst jsonOrNull = (v: unknown) => v ?? null;\n\nfunction toRunData(run: WorkflowRun) {\n return {\n id: run.id,\n workflow: run.workflow,\n workflowVersion: run.workflowVersion,\n status: run.status,\n input: jsonOrNull(run.input),\n output: jsonOrNull(run.output),\n error: jsonOrNull(run.error),\n wakeAt: bigOrNull(run.wakeAt),\n lockedBy: run.lockedBy ?? null,\n lockedUntil: run.lockedUntil == null ? null : new Date(run.lockedUntil),\n awaitingDecisionTaskId: run.awaitingDecisionTaskId ?? null,\n recoveryAttempts: run.recoveryAttempts ?? null,\n tags: jsonOrNull(run.tags),\n searchAttributes: jsonOrNull(run.searchAttributes),\n priority: run.priority ?? null,\n // An absent namespace IS `'default'` — unlike `origin` below, this is a reconstruction and not a\n // guess: an engine started without a namespace stamps its runs and routes its workers as\n // `'default'`, so writing anything else (or NULL) would put the run in a partition no worker polls.\n namespace: run.namespace ?? 'default',\n // Absent origin stays SQL NULL — \"unknown\", never coerced into a real-looking library name.\n origin: run.origin ?? null,\n createdAt: run.createdAt,\n updatedAt: run.updatedAt,\n };\n}\n\nfunction toRunPatch(patch: Partial<WorkflowRun>) {\n // Map EVERY patchable field, using presence (`'x' in patch`) semantics for the nullable ones so a\n // patch can CLEAR a column (e.g. `{ error: undefined }` on completion sets it to NULL — matching\n // the TypeORM / MikroORM / in-memory stores). The two non-null Date fields use a defined-guard\n // since they are never cleared. Previously only 7 fields were mapped, so `updateRun({ tags })` /\n // `{ lockedBy }` / clearing `error` silently no-opped on this adapter.\n const data: Record<string, unknown> = {};\n if ('workflow' in patch) data.workflow = patch.workflow;\n if ('workflowVersion' in patch) data.workflowVersion = patch.workflowVersion;\n if ('status' in patch) data.status = patch.status;\n if ('input' in patch) data.input = jsonOrNull(patch.input);\n if ('output' in patch) data.output = jsonOrNull(patch.output);\n if ('error' in patch) data.error = jsonOrNull(patch.error);\n if ('wakeAt' in patch) data.wakeAt = bigOrNull(patch.wakeAt);\n if ('lockedBy' in patch) data.lockedBy = patch.lockedBy ?? null;\n if ('lockedUntil' in patch)\n data.lockedUntil = patch.lockedUntil == null ? null : new Date(patch.lockedUntil);\n if ('awaitingDecisionTaskId' in patch)\n data.awaitingDecisionTaskId = patch.awaitingDecisionTaskId ?? null;\n if ('recoveryAttempts' in patch) data.recoveryAttempts = patch.recoveryAttempts ?? null;\n if ('tags' in patch) data.tags = jsonOrNull(patch.tags);\n if ('searchAttributes' in patch) data.searchAttributes = jsonOrNull(patch.searchAttributes);\n if ('priority' in patch) data.priority = patch.priority ?? null;\n // `?? 'default'` rather than `?? null` like its neighbours: the column is NOT NULL, and clearing a\n // run's namespace means \"back to the unscoped partition\", which is what `'default'` names. A patch\n // that does not mention `namespace` leaves the stored one alone — a status update must never move a\n // run between tenants.\n if ('namespace' in patch) data.namespace = patch.namespace ?? 'default';\n if ('origin' in patch) data.origin = patch.origin ?? null;\n if (patch.createdAt != null) data.createdAt = patch.createdAt;\n if (patch.updatedAt != null) data.updatedAt = patch.updatedAt;\n return data;\n}\n\nfunction fromRunRow(row: RunRow): WorkflowRun {\n return {\n id: row.id,\n workflow: row.workflow,\n workflowVersion: row.workflowVersion,\n status: row.status as WorkflowRun['status'],\n input: row.input ?? undefined,\n output: row.output ?? undefined,\n error: (row.error ?? undefined) as StepError | undefined,\n wakeAt: numOrUndef(row.wakeAt),\n lockedBy: row.lockedBy ?? undefined,\n lockedUntil: row.lockedUntil == null ? undefined : row.lockedUntil.getTime(),\n awaitingDecisionTaskId: row.awaitingDecisionTaskId ?? undefined,\n recoveryAttempts: row.recoveryAttempts ?? undefined,\n tags: (row.tags as string[] | null) ?? undefined,\n searchAttributes:\n (row.searchAttributes as Record<string, string | number | boolean> | null) ?? undefined,\n priority: row.priority ?? undefined,\n // Read back verbatim, with NO `?? 'default'` fallback. The column is NOT NULL and the migration\n // back-fills old rows, so there is nothing legitimate to fall back FROM; a fallback would only fire\n // on a deployment that added the column nullable without back-filling, and there it would lie —\n // the dashboard would show `default` for a row whose stored NULL keeps every `default` worker's\n // `WHERE namespace = 'default'` from ever picking it up.\n namespace: row.namespace,\n // NULL (a row written before the column existed) surfaces as `undefined` = unknown origin.\n origin: row.origin ?? undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction toCheckpointData(cp: StepCheckpoint) {\n return {\n runId: cp.runId,\n seq: cp.seq,\n name: cp.name,\n kind: cp.kind,\n stepId: cp.stepId,\n status: cp.status,\n input: jsonOrNull(cp.input),\n output: jsonOrNull(cp.output),\n error: jsonOrNull(cp.error),\n events: jsonOrNull(cp.events),\n attempts: cp.attempts,\n workerGroup: cp.workerGroup ?? null,\n parallelGroup: cp.parallelGroup ?? null,\n wakeAt: bigOrNull(cp.wakeAt),\n enqueuedAt: cp.enqueuedAt,\n startedAt: cp.startedAt,\n finishedAt: cp.finishedAt,\n };\n}\n\nfunction fromCheckpointRow(row: CheckpointRow): StepCheckpoint {\n return {\n runId: row.runId,\n seq: row.seq,\n name: row.name,\n kind: row.kind as StepCheckpoint['kind'],\n stepId: row.stepId,\n status: row.status as StepCheckpoint['status'],\n input: row.input ?? undefined,\n output: row.output ?? undefined,\n error: (row.error ?? undefined) as StepError | undefined,\n events: (row.events ?? undefined) as StepEvent[] | undefined,\n attempts: row.attempts,\n workerGroup: row.workerGroup ?? undefined,\n parallelGroup: row.parallelGroup ?? undefined,\n wakeAt: numOrUndef(row.wakeAt),\n enqueuedAt: row.enqueuedAt ?? row.startedAt,\n startedAt: row.startedAt,\n finishedAt: row.finishedAt,\n };\n}\n","/**\n * Tables this store's durable models own, physically. UNLIKE the other store adapters, this store\n * doesn't create or manage them at boot: the models in `prisma/schema.prisma` are meant to be copied\n * into YOUR OWN `schema.prisma` (see that file's header comment), and Prisma Migrate diffs whatever\n * models live in your schema — so a consumer who copied the models in already has them accounted for\n * and never needs a denylist for Prisma Migrate itself.\n *\n * This is exported anyway for the same reason the other adapters export it: any OTHER tooling that\n * introspects the database outside of `prisma migrate diff` (a raw schema dump, a second ORM/CLI\n * pointed at the same database, a linter that flags \"table not in any model\") needs the same fixed\n * list of table names this store's models declare via `@@map(...)`.\n *\n * ```ts\n * const skipTables = new Set(durableManagedTables());\n * ```\n *\n * Kept in sync with the `@@map(...)` table names in `prisma/schema.prisma` by `schema.spec.ts`,\n * which parses that file and asserts the two lists match — there is no single TypeScript source to\n * derive from (the schema is a `.prisma` text file copied into the consumer's own schema, not\n * imported at runtime), so the list here is intentionally a literal mirror.\n */\nexport function durableManagedTables(): string[] {\n return [\n 'durable_workflow_runs',\n 'durable_step_checkpoints',\n 'durable_run_attributes',\n 'durable_signal_waiters',\n 'durable_buffered_signals',\n 'durable_buffered_events',\n ];\n}\n"],"mappings":"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","names":["attributeColumnFor","attributeOperand","normalizeAttributeRows","namespaceWhere","namespace","undefined","PrismaStateStore","db","createRun","run","durableWorkflowRun","create","data","toRunData","reindexAttributes","id","searchAttributes","updateRun","runId","patch","update","where","toRunPatch","attributes","durableRunAttribute","deleteMany","rows","normalizeAttributeRows","length","createMany","getRun","row","findUnique","fromRunRow","deleteRun","durableStepCheckpoint","durableSignalWaiter","getCheckpoint","seq","runId_seq","fromCheckpointRow","saveCheckpoint","checkpoint","toCheckpointData","upsert","transaction","work","$transaction","tx","raw","cp","listIncompleteRuns","findMany","status","in","map","listPendingRuns","limit","orderBy","createdAt","take","listDueTimers","nowMs","wakeAt","not","lte","BigInt","tryLockRun","owner","leaseUntilMs","result","updateMany","OR","lockedUntil","Date","lockedBy","count","releaseRunLock","renewRunLock","listRuns","query","workflow","origin","statuses","AND","tag","tags","array_contains","existing","f","attributeSome","skip","offset","listCheckpoints","getLatestCheckpointByName","name","findFirst","listCheckpointsByNamePrefix","prefixes","p","startsWith","putSignalWaiter","waiter","token","parallelGroup","takeSignalWaiter","delete","listSignalWaiters","prefix","r","removeSignalWaiter","bufferSignal","payload","durableBufferedSignal","jsonOrNull","takeBufferedSignal","bufferEvent","input","durableBufferedEvent","publishedAt","listBufferedEvents","Number","removeBufferedEvent","col","attributeColumnFor","operand","attributeOperand","condition","op","some","key","bigOrNull","n","numOrUndef","v","workflowVersion","output","error","awaitingDecisionTaskId","recoveryAttempts","priority","updatedAt","getTime","kind","stepId","events","attempts","workerGroup","enqueuedAt","startedAt","finishedAt","durableManagedTables"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dudousxd/nestjs-durable-store-prisma",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "Prisma adapter for the nestjs-durable StateStore",
5
5
  "license": "MIT",
6
6
  "author": "Davide Carvalho",
@@ -26,8 +26,8 @@
26
26
  "prisma": "6.19.3",
27
27
  "typescript": "5.9.3",
28
28
  "tsup": "8.3.5",
29
- "@dudousxd/nestjs-durable-core": "^0.54.0",
30
- "@dudousxd/nestjs-durable-testing": "^0.9.0"
29
+ "@dudousxd/nestjs-durable-core": "^0.64.0",
30
+ "@dudousxd/nestjs-durable-testing": "^0.11.0"
31
31
  },
32
32
  "module": "./dist/index.js",
33
33
  "exports": {
@@ -17,6 +17,32 @@ model DurableWorkflowRun {
17
17
  tags Json?
18
18
  searchAttributes Json? @map("search_attributes")
19
19
  priority Int? @map("priority")
20
+ // The worker-pool partition that owns this run — the tenant boundary. A worker only picks up /
21
+ // recovers / resumes-timers-for / times-out runs in its own namespace, so this column sits on the
22
+ // predicate of every poll tick.
23
+ //
24
+ // NOT NULL WITH A DEFAULT, deliberately unlike `origin` below. A row written before this column
25
+ // existed was executed by an engine with no namespace, and such an engine stamps and routes as
26
+ // `'default'` — so `'default'` is that row's TRUE namespace, reconstructed rather than invented.
27
+ // Leaving old rows NULL is the option that breaks: a `'default'` worker polls
28
+ // `WHERE namespace = 'default'`, a NULL row never matches it, and the run is never picked up,
29
+ // recovered or timed out again. So the migration must back-fill (see below), and this adapter
30
+ // never coerces NULL to `'default'` on the way out — that would show a healthy namespace in the
31
+ // dashboard for a row no worker can see.
32
+ //
33
+ // Existing deployment (Prisma Migrate generates exactly this from the field):
34
+ // ALTER TABLE durable_workflow_runs ADD COLUMN namespace TEXT NOT NULL DEFAULT 'default';
35
+ // CREATE INDEX durable_workflow_runs_namespace_status_idx
36
+ // ON durable_workflow_runs (namespace, status, created_at);
37
+ // The ADD COLUMN back-fills every existing row with `'default'` in one statement on
38
+ // Postgres/MySQL/SQLite alike. Use `VARCHAR(255)` for MySQL.
39
+ namespace String @default("default") @map("namespace")
40
+ // Which library/module registered the workflow this run belongs to (e.g.
41
+ // `@dudousxd/nestjs-catalog-pipeline`), derived at registration time — never caller input.
42
+ // Nullable with NO default: an origin cannot be reconstructed for a row written before this
43
+ // column existed, so it stays NULL and reads back as `undefined` = "unknown". A real-looking
44
+ // default would be indistinguishable from a genuine registration in the dashboard facet.
45
+ origin String? @map("origin")
20
46
  createdAt DateTime @map("created_at")
21
47
  updatedAt DateTime @map("updated_at")
22
48
 
@@ -24,6 +50,17 @@ model DurableWorkflowRun {
24
50
 
25
51
  @@index([status, wakeAt])
26
52
  @@index([workflow, status])
53
+ // The tenant-scoped poll. `listPendingRuns`/`listIncompleteRuns`/`listDueTimers` all run
54
+ // `namespace = ? AND status ...` on every tick, and the pending scan then orders by `created_at`
55
+ // (FIFO) — hence the three columns in that order. `origin` gets no index for the mirror-image
56
+ // reason: nothing but the dashboard's `listRuns` filters by it.
57
+ //
58
+ // Named explicitly because Prisma would otherwise derive
59
+ // `durable_workflow_runs_namespace_status_created_at_idx`, while the MikroORM adapter declares
60
+ // this same index as `durable_workflow_runs_namespace_status_idx`; pinning the name keeps a store
61
+ // swap from dropping and rebuilding it. The two indexes above already agree by accident — Prisma's
62
+ // derived names happen to be the ones MikroORM declares.
63
+ @@index([namespace, status, createdAt], map: "durable_workflow_runs_namespace_status_idx")
27
64
  @@map("durable_workflow_runs")
28
65
  }
29
66