@dudousxd/nestjs-durable-store-drizzle 0.18.1 → 0.19.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pg/index.ts","../../src/pg/ddl.ts","../../src/pg/drizzle-pg-state-store.ts","../../src/pg/schema.ts","../../src/pg/executor.ts"],"sourcesContent":["// `@dudousxd/nestjs-durable-store-drizzle/pg` — the PostgreSQL flavour of the Drizzle store.\n// The package root (`@dudousxd/nestjs-durable-store-drizzle`) stays the SQLite / libSQL store.\nexport * from './ddl';\nexport * from './drizzle-pg-state-store';\nexport * from './executor';\nexport * from './schema';\n","import { sql } from 'drizzle-orm';\nimport type { PgDatabase } from 'drizzle-orm/pg-core';\n\n/**\n * The durable tables as idempotent Postgres DDL — the exact SQL twin of the `pgTable` definitions in\n * `./schema` (same tables, columns, types, defaults, primary keys and index names; a spec pins the two\n * against each other on a real Postgres, so they cannot drift).\n *\n * Every statement is `IF NOT EXISTS`, so the list is safe to run on every boot\n * ({@link ensureDrizzlePgDurableSchema}, which `DrizzlePgStateStore.ensureSchema()` calls when the\n * module's `autoSchema` is on) or to paste into a hand-written migration:\n *\n * ```ts\n * // drizzle/0007_durable.sql — or a custom migration step\n * import { DURABLE_PG_DDL } from '@dudousxd/nestjs-durable-store-drizzle/pg';\n * console.log(DURABLE_PG_DDL.join(';\\n') + ';');\n * ```\n *\n * A column added by a future version is appended here as `ALTER TABLE … ADD COLUMN IF NOT EXISTS`, so\n * an existing database heals on the next boot exactly like the MikroORM / TypeORM auto-schema does.\n */\nexport const DURABLE_PG_DDL: readonly string[] = [\n `CREATE TABLE IF NOT EXISTS \"durable_workflow_runs\" (\n \"id\" text PRIMARY KEY NOT NULL,\n \"workflow\" text NOT NULL,\n \"workflow_version\" text NOT NULL,\n \"status\" text NOT NULL,\n \"input\" jsonb,\n \"output\" jsonb,\n \"error\" jsonb,\n \"wake_at\" timestamp with time zone,\n \"locked_by\" text,\n \"locked_until\" timestamp with time zone,\n \"awaiting_decision_task_id\" text,\n \"recovery_attempts\" integer,\n \"tags\" jsonb,\n \"search_attributes\" jsonb,\n \"priority\" integer,\n \"namespace\" text DEFAULT 'default' NOT NULL,\n \"origin\" text,\n \"created_at\" timestamp with time zone NOT NULL,\n \"updated_at\" timestamp with time zone NOT NULL\n)`,\n `CREATE TABLE IF NOT EXISTS \"durable_step_checkpoints\" (\n \"run_id\" text NOT NULL,\n \"seq\" integer NOT NULL,\n \"name\" text NOT NULL,\n \"kind\" text NOT NULL,\n \"step_id\" text NOT NULL,\n \"status\" text NOT NULL,\n \"input\" jsonb,\n \"output\" jsonb,\n \"error\" jsonb,\n \"events\" jsonb,\n \"attempts\" integer NOT NULL,\n \"worker_group\" text,\n \"parallel_group\" text,\n \"wake_at\" timestamp with time zone,\n \"enqueued_at\" timestamp with time zone,\n \"started_at\" timestamp with time zone NOT NULL,\n \"finished_at\" timestamp with time zone NOT NULL,\n CONSTRAINT \"durable_step_checkpoints_run_id_seq_pk\" PRIMARY KEY(\"run_id\",\"seq\")\n)`,\n `CREATE TABLE IF NOT EXISTS \"durable_run_attributes\" (\n \"run_id\" text NOT NULL,\n \"key\" text NOT NULL,\n \"str_value\" text,\n \"num_value\" double precision,\n CONSTRAINT \"durable_run_attributes_run_id_key_pk\" PRIMARY KEY(\"run_id\",\"key\")\n)`,\n `CREATE TABLE IF NOT EXISTS \"durable_signal_waiters\" (\n \"token\" text PRIMARY KEY NOT NULL,\n \"run_id\" text NOT NULL,\n \"seq\" integer NOT NULL,\n \"parallel_group\" text\n)`,\n `CREATE TABLE IF NOT EXISTS \"durable_buffered_signals\" (\n \"id\" bigserial PRIMARY KEY NOT NULL,\n \"token\" text NOT NULL,\n \"payload\" jsonb\n)`,\n `CREATE TABLE IF NOT EXISTS \"durable_buffered_events\" (\n \"id\" text PRIMARY KEY NOT NULL,\n \"name\" text NOT NULL,\n \"payload\" jsonb,\n \"published_at\" timestamp with time zone NOT NULL\n)`,\n `CREATE TABLE IF NOT EXISTS \"durable_schedules\" (\n \"id\" text PRIMARY KEY NOT NULL,\n \"namespace\" text DEFAULT 'default' NOT NULL,\n \"workflow\" text NOT NULL,\n \"paused\" boolean DEFAULT false NOT NULL,\n \"next_fire_at\" timestamp with time zone,\n \"tags\" jsonb,\n \"spec\" jsonb NOT NULL,\n \"state\" jsonb NOT NULL,\n \"created_at\" timestamp with time zone NOT NULL,\n \"updated_at\" timestamp with time zone NOT NULL\n)`,\n `CREATE INDEX IF NOT EXISTS \"durable_runs_status_idx\" ON \"durable_workflow_runs\" USING btree (\"status\",\"wake_at\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_runs_workflow_status_idx\" ON \"durable_workflow_runs\" USING btree (\"workflow\",\"status\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_workflow_runs_namespace_status_idx\" ON \"durable_workflow_runs\" USING btree (\"namespace\",\"status\",\"created_at\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_runs_tags_gin_idx\" ON \"durable_workflow_runs\" USING gin (\"tags\" jsonb_path_ops)`,\n `CREATE INDEX IF NOT EXISTS \"durable_runs_status_updated_idx\" ON \"durable_workflow_runs\" USING btree (\"status\",\"updated_at\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_run_attributes_num_idx\" ON \"durable_run_attributes\" USING btree (\"key\",\"num_value\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_run_attributes_str_idx\" ON \"durable_run_attributes\" USING btree (\"key\",\"str_value\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_signal_waiters_run_id_idx\" ON \"durable_signal_waiters\" USING btree (\"run_id\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_buffered_signals_token_idx\" ON \"durable_buffered_signals\" USING btree (\"token\",\"id\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_buffered_events_name_published_at_idx\" ON \"durable_buffered_events\" USING btree (\"name\",\"published_at\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_schedules_due_idx\" ON \"durable_schedules\" USING btree (\"paused\",\"next_fire_at\")`,\n];\n\n/** Key for the transaction-scoped advisory lock that serializes concurrent heals (several pods\n * booting at once would otherwise race `CREATE INDEX IF NOT EXISTS` into a duplicate-key error). */\nconst SCHEMA_LOCK_KEY = 'durable_schema';\n\n/**\n * Idempotently create the durable tables + indexes on `db` (any drizzle Postgres driver). Runs in one\n * transaction under a `pg_advisory_xact_lock`, so N pods booting together heal the schema once and\n * the rest see it done. Only ever touches the `durable_*` tables.\n */\nexport async function ensureDrizzlePgDurableSchema(db: PgDatabase<any, any, any>): Promise<void> {\n await db.transaction(async (tx) => {\n await tx.execute(sql`SELECT pg_advisory_xact_lock(hashtext(${SCHEMA_LOCK_KEY}))`);\n for (const statement of DURABLE_PG_DDL) await tx.execute(sql.raw(statement));\n });\n}\n","import {\n type AttributeFilter,\n RUN_VALUE_FACET_SCAN,\n type RetentionPolicy,\n type RunFacetQuery,\n type RunFacetRow,\n type RunQuery,\n type RunStatus,\n type RunValueAxis,\n type RunValueFacetOptions,\n type RunValueFacetRow,\n SINGLETON_ACTIVE_STATUSES,\n type ScheduleQuery,\n type ScheduleRecord,\n type SignalWaiter,\n type StateStore,\n type StepCheckpoint,\n type StepError,\n type StepEvent,\n type StoreTransaction,\n TERMINAL_RUN_STATUSES,\n type WorkflowRun,\n attributePredicateOperands,\n axisIsRunColumn,\n clearTerminalSingletonAdmission,\n mergeRunFacetRows,\n mergeRunValueFacetRows,\n normalizeAttributeRows,\n parseDuration,\n runValueFacetsFromRuns,\n singletonAdmissionDenialPatch,\n singletonAdmissionTags,\n} from '@dudousxd/nestjs-durable-core';\nimport {\n type SQL,\n and,\n asc,\n desc,\n eq,\n exists,\n inArray,\n isNotNull,\n isNull,\n like,\n lt,\n lte,\n or,\n sql,\n} from 'drizzle-orm';\nimport type { PgDatabase } from 'drizzle-orm/pg-core';\nimport { ensureDrizzlePgDurableSchema } from './ddl';\nimport {\n DEFAULT_NAMESPACE,\n durableBufferedEvents as bufferedEvents,\n durableBufferedSignals as bufferedSignals,\n durableRunAttributes as runAttributes,\n durableSchedules as schedules,\n durableSignalWaiters as signalWaiters,\n durableStepCheckpoints as stepCheckpoints,\n durableWorkflowRuns as workflowRuns,\n} from './schema';\n\ntype RunRow = typeof workflowRuns.$inferSelect;\ntype RunInsert = typeof workflowRuns.$inferInsert;\ntype CheckpointRow = typeof stepCheckpoints.$inferSelect;\n\n/**\n * Any drizzle Postgres database — `drizzle-orm/node-postgres`, `drizzle-orm/postgres-js`,\n * `drizzle-orm/pglite`, Neon, … — built with or without a relational schema. The store only uses the\n * query builder (never `db.query.*`), so you do not have to register the durable tables on it.\n */\nexport type DrizzlePgDatabase = PgDatabase<any, any, any>;\n\nexport interface DrizzlePgStateStoreOptions {\n /**\n * Confine every RUN read (`getRun`, `listRuns`, facets, and the pending / incomplete / due-timer\n * polls) to one namespace — a tenant-boundary view of the store. Omit for the operator\n * (control-plane) view that sees every namespace. The NestJS module's `scopeReads` option applies\n * this for you via {@link DrizzlePgStateStore.withScope}.\n */\n scope?: { namespace?: string | undefined } | undefined;\n}\n\n/** OR a set of conditions where an EMPTY set means \"matches nothing\" (every plural `RunQuery`\n * predicate's contract) — `or()` of nothing would be dropped by `and()` and match everything. */\nfunction anyOf(conditions: (SQL | undefined)[]): SQL {\n const present = conditions.filter((c): c is SQL => c !== undefined);\n return present.length ? (or(...present) as SQL) : sql`1 = 0`;\n}\n\n/** `undefined` = no restriction (the operator view), never `namespace IS NULL`. The column is\n * NOT NULL DEFAULT 'default', so plain equality is exact. */\nfunction namespaceFilter(namespace: string | undefined): SQL | undefined {\n return namespace === undefined ? undefined : eq(workflowRuns.namespace, namespace);\n}\n\n/** `tags @> '[\"tag\"]'::jsonb` — exact element containment (so `etl` never matches `etl-foo`), and\n * served by the `durable_runs_tags_gin_idx` GIN (`jsonb_path_ops`) index. */\nfunction hasTag(tag: string): SQL {\n return sql`${workflowRuns.tags} @> ${JSON.stringify([tag])}::jsonb`;\n}\n\nconst date = (ms: number | undefined | null): Date | null => (ms == null ? null : new Date(ms));\nconst ms = (d: Date | null): number | undefined => (d == null ? undefined : d.getTime());\n\n/**\n * Drizzle `StateStore` for **PostgreSQL**. Pass any drizzle Postgres db (see {@link DrizzlePgDatabase});\n * the durable tables come from `./schema` (drizzle-kit) or {@link ensureSchema} (auto-schema).\n *\n * Postgres-specific behaviour, beyond the shared contract:\n * - leases (`tryLockRun` / `renewRunLock`) are a single conditional `UPDATE … RETURNING`, so two\n * instances racing for the same run serialize on the row lock and exactly one wins;\n * - `takeSignalWaiter` is one `DELETE … RETURNING` (atomic take), and `takeBufferedSignal` claims the\n * oldest row with `FOR UPDATE SKIP LOCKED`, so concurrent takers each get a DIFFERENT signal\n * instead of blocking or double-delivering;\n * - `pruneTerminalRuns` (retention) selects its batch with `FOR UPDATE SKIP LOCKED`, so several\n * pods sweeping at once split the backlog instead of contending on it;\n * - tag filters are jsonb containment (GIN-indexed) and attribute filters push down as EXISTS\n * probes on the indexed side table.\n */\nexport class DrizzlePgStateStore implements StateStore {\n private readonly scopeNamespace: string | undefined;\n\n constructor(\n private readonly db: DrizzlePgDatabase,\n private readonly options: DrizzlePgStateStoreOptions = {},\n ) {\n this.scopeNamespace = options.scope?.namespace;\n }\n\n /** A store confined to `scope.namespace`, sharing this store's db (no new connection). Used by the\n * NestJS module's `scopeReads`; `{ namespace: undefined }` is the unscoped operator view. */\n withScope(scope: { namespace?: string | undefined }): DrizzlePgStateStore {\n return new DrizzlePgStateStore(this.db, { ...this.options, scope });\n }\n\n /** Idempotent CREATE TABLE / INDEX IF NOT EXISTS under an advisory lock — called on boot when the\n * module's `autoSchema` is on. Turn `autoSchema` off if drizzle-kit owns these tables. */\n async ensureSchema(): Promise<void> {\n await ensureDrizzlePgDurableSchema(this.db);\n }\n\n /** The read-scope predicate on the runs table (undefined when the store is unscoped). */\n private scope(): SQL | undefined {\n return namespaceFilter(this.scopeNamespace);\n }\n\n async tryAdmitSingleton(\n runId: string,\n tag: string,\n workflow: string,\n limit: number,\n retryWakeAt?: number,\n ): Promise<boolean> {\n return this.db.transaction(async (tx) => {\n const where = and(\n eq(workflowRuns.workflow, workflow),\n inArray(workflowRuns.status, SINGLETON_ACTIVE_STATUSES),\n this.scope(),\n );\n await tx.update(workflowRuns).set({ workflow }).where(where);\n const rows = await tx.select().from(workflowRuns).where(where);\n const runs = rows.map(fromRunRow);\n const tags = singletonAdmissionTags(runs, runId, tag, workflow, limit);\n if (!tags) {\n const patch = singletonAdmissionDenialPatch(runs, runId, tag, workflow, retryWakeAt);\n if (patch)\n await tx.update(workflowRuns).set(toRunPatch(patch)).where(eq(workflowRuns.id, runId));\n return false;\n }\n await tx.update(workflowRuns).set({ tags }).where(eq(workflowRuns.id, runId));\n return true;\n });\n }\n\n async createRun(run: WorkflowRun): Promise<void> {\n // One transaction: a run is never visible without its attribute rows (or vice versa).\n await this.db.transaction(async (tx) => {\n await tx.insert(workflowRuns).values(toRunRow(run));\n await reindexAttributes(tx, run.id, run.searchAttributes);\n });\n }\n\n async updateRun(runId: string, inputPatch: Partial<WorkflowRun>): Promise<void> {\n // Writes are unscoped, so preserve tags even when settling a run outside the read scope.\n const patch =\n inputPatch.status && TERMINAL_RUN_STATUSES.includes(inputPatch.status)\n ? await clearTerminalSingletonAdmission(runId, inputPatch, (id) =>\n this.withScope({}).getRun(id),\n )\n : inputPatch;\n const row = toRunPatch(patch);\n const reindex = 'searchAttributes' in patch;\n if (!Object.keys(row).length && !reindex) return;\n await this.db.transaction(async (tx) => {\n // Drizzle throws on `.set({})`; skip the UPDATE when no mapped column changed.\n if (Object.keys(row).length)\n await tx.update(workflowRuns).set(row).where(eq(workflowRuns.id, runId));\n if (reindex) await reindexAttributes(tx, runId, patch.searchAttributes);\n });\n }\n\n async getRun(runId: string): Promise<WorkflowRun | null> {\n const rows = await this.db\n .select()\n .from(workflowRuns)\n .where(and(eq(workflowRuns.id, runId), this.scope()))\n .limit(1);\n return rows[0] ? fromRunRow(rows[0]) : null;\n }\n\n async deleteRun(runId: string): Promise<void> {\n await this.db.transaction(async (tx) => {\n await deleteRunsCascade(tx, [runId]);\n });\n }\n\n async deleteRuns(runIds: string[]): Promise<void> {\n if (runIds.length === 0) return;\n await this.db.transaction(async (tx) => {\n await deleteRunsCascade(tx, runIds);\n });\n }\n\n async pruneTerminalRuns(policy: RetentionPolicy, nowMs: number, limit: number): Promise<number> {\n // Only terminal statuses are ever eligible — a policy naming a live status would race the engine.\n const statuses = policy.statuses.filter((s) => TERMINAL_RUN_STATUSES.includes(s));\n if (statuses.length === 0 || limit <= 0) return 0;\n if (policy.maxAge == null && policy.maxCount == null) return 0;\n // A scoped policy only ever sees (and, for maxCount, counts) the runs its scope matches.\n const scoped = this.runFilters({ ...(policy.scope ?? {}), statuses });\n return this.db.transaction(async (tx) => {\n const ids = new Set<string>();\n if (policy.maxAge != null) {\n const cutoff = new Date(nowMs - parseDuration(policy.maxAge));\n const rows = await tx\n .select({ id: workflowRuns.id })\n .from(workflowRuns)\n .where(and(...scoped, lt(workflowRuns.updatedAt, cutoff)))\n .orderBy(asc(workflowRuns.updatedAt)) // oldest first\n .limit(limit)\n .for('update', { skipLocked: true });\n for (const r of rows) ids.add(r.id);\n }\n if (policy.maxCount != null && ids.size < limit) {\n // Everything past the newest `maxCount` rows of the status set. The kept window is skipped by\n // OFFSET (no row lock there), and only the rows past it are locked for deletion.\n const rows = await tx\n .select({ id: workflowRuns.id })\n .from(workflowRuns)\n .where(and(...scoped))\n .orderBy(desc(workflowRuns.updatedAt), desc(workflowRuns.id))\n .limit(limit)\n .offset(policy.maxCount)\n .for('update', { skipLocked: true });\n for (const r of rows) {\n if (ids.size >= limit) break;\n ids.add(r.id);\n }\n }\n if (ids.size === 0) return 0;\n const idList = [...ids].slice(0, limit);\n await deleteRunsCascade(tx, idList);\n return idList.length;\n });\n }\n\n async getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null> {\n const rows = await this.db\n .select()\n .from(stepCheckpoints)\n .where(and(eq(stepCheckpoints.runId, runId), eq(stepCheckpoints.seq, seq)))\n .limit(1);\n return rows[0] ? fromCheckpointRow(rows[0]) : null;\n }\n\n async saveCheckpoint(checkpoint: StepCheckpoint): Promise<void> {\n await upsertCheckpoint(this.db, checkpoint);\n }\n\n async transaction<T>(work: (tx: StoreTransaction) => Promise<T>): Promise<T> {\n return this.db.transaction(async (tx) =>\n work({ raw: tx, saveCheckpoint: (cp) => upsertCheckpoint(tx, cp) }),\n );\n }\n\n /** Crash recovery. Namespace-scoped: a worker re-drives only its own tenant's runs. */\n async listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]> {\n const rows = await this.db\n .select()\n .from(workflowRuns)\n .where(\n and(\n inArray(workflowRuns.status, ['running', 'cancelling']),\n namespaceFilter(namespace),\n this.scope(),\n ),\n );\n return rows.map(fromRunRow);\n }\n\n /** FIFO pick-up, served by `durable_workflow_runs_namespace_status_idx`. The engine then leases\n * each run with {@link tryLockRun}; the listing itself takes no locks (it runs outside a tx). */\n async listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]> {\n const rows = await this.db\n .select()\n .from(workflowRuns)\n .where(and(eq(workflowRuns.status, 'pending'), namespaceFilter(namespace), this.scope()))\n .orderBy(asc(workflowRuns.createdAt))\n .limit(limit);\n return rows.map(fromRunRow);\n }\n\n async listDueTimers(nowMs: number, namespace?: string): Promise<WorkflowRun[]> {\n const rows = await this.db\n .select()\n .from(workflowRuns)\n .where(\n and(\n eq(workflowRuns.status, 'suspended'),\n isNotNull(workflowRuns.wakeAt),\n lte(workflowRuns.wakeAt, new Date(nowMs)),\n namespaceFilter(namespace),\n this.scope(),\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 // One conditional UPDATE: under READ COMMITTED a concurrent contender blocks on the row lock,\n // then re-evaluates the WHERE against the winner's committed row and matches nothing.\n const rows = await this.db\n .update(workflowRuns)\n .set({ lockedBy: owner, lockedUntil: new Date(leaseUntilMs) })\n .where(\n and(\n eq(workflowRuns.id, runId),\n or(isNull(workflowRuns.lockedUntil), lte(workflowRuns.lockedUntil, new Date(nowMs))),\n ),\n )\n .returning({ id: workflowRuns.id });\n return rows.length === 1;\n }\n\n async releaseRunLock(runId: string): Promise<void> {\n await this.db\n .update(workflowRuns)\n .set({ lockedBy: null, lockedUntil: null })\n .where(eq(workflowRuns.id, runId));\n }\n\n async renewRunLock(runId: string, owner: string, leaseUntilMs: number): Promise<boolean> {\n const rows = await this.db\n .update(workflowRuns)\n .set({ lockedUntil: new Date(leaseUntilMs) })\n .where(and(eq(workflowRuns.id, runId), eq(workflowRuns.lockedBy, owner)))\n .returning({ id: workflowRuns.id });\n return rows.length === 1;\n }\n\n /** The predicates every run query shares — {@link listRuns} pages them, the facets group them. */\n private runFilters(query: RunQuery): SQL[] {\n return [\n this.scope(),\n query.workflow ? eq(workflowRuns.workflow, query.workflow) : undefined,\n query.workflows\n ? query.workflows.length\n ? inArray(workflowRuns.workflow, query.workflows)\n : sql`1 = 0`\n : undefined,\n // The tenant boundary. Also the engine's execution-timeout sweep path\n // (`listRuns({ workflow, status, namespace })`) — unscoped, it would cancel another tenant's runs.\n namespaceFilter(query.namespace),\n query.namespaces\n ? query.namespaces.length\n ? inArray(workflowRuns.namespace, query.namespaces)\n : sql`1 = 0`\n : undefined,\n // `null` selects the unattributed bucket; a value never matches a NULL origin.\n query.origin === null\n ? isNull(workflowRuns.origin)\n : query.origin !== undefined\n ? eq(workflowRuns.origin, query.origin)\n : undefined,\n query.origins\n ? anyOf(\n query.origins.map((o) =>\n o === null ? isNull(workflowRuns.origin) : eq(workflowRuns.origin, o),\n ),\n )\n : undefined,\n query.status ? eq(workflowRuns.status, query.status) : undefined,\n query.statuses\n ? query.statuses.length\n ? inArray(workflowRuns.status, query.statuses)\n : sql`1 = 0`\n : undefined,\n query.tag ? hasTag(query.tag) : undefined,\n query.tags ? anyOf(query.tags.map(hasTag)) : undefined,\n // One EXISTS per attribute predicate against the normalized side table (ANDed).\n ...(query.attributes?.map((f) => this.attributeExists(f)) ?? []),\n ].filter((f): f is SQL => f !== undefined);\n }\n\n async listRuns(query: RunQuery): Promise<WorkflowRun[]> {\n const filters = this.runFilters(query);\n const base = this.db\n .select()\n .from(workflowRuns)\n .where(filters.length ? and(...filters) : undefined)\n // newest first; id breaks created_at ties so limit/offset pages are stable\n .orderBy(desc(workflowRuns.createdAt), desc(workflowRuns.id))\n .$dynamic();\n if (query.limit != null) base.limit(query.limit);\n if (query.offset != null) base.offset(query.offset);\n const rows = await base;\n return rows.map(fromRunRow);\n }\n\n async countRuns(query: Omit<RunQuery, 'limit' | 'offset'>): Promise<number> {\n const filters = this.runFilters(query);\n const rows = await this.db\n .select({ count: sql<number>`count(*)`.mapWith(Number) })\n .from(workflowRuns)\n .where(filters.length ? and(...filters) : undefined);\n return rows[0]?.count ?? 0;\n }\n\n async runFacets(query: RunFacetQuery): Promise<RunFacetRow[]> {\n const filters = this.runFilters(query);\n const rows = await this.db\n .select({\n status: workflowRuns.status,\n origin: workflowRuns.origin,\n count: sql<number>`count(*)`.mapWith(Number),\n })\n .from(workflowRuns)\n .where(filters.length ? and(...filters) : undefined)\n .groupBy(workflowRuns.status, workflowRuns.origin);\n return mergeRunFacetRows(\n rows.map((r) => ({ status: r.status as RunStatus, origin: r.origin, count: r.count })),\n );\n }\n\n /** Run-table axes are an exact `GROUP BY`; the tag / attribute axes are counted over a bounded\n * page of runs (see `RunValueFacetOptions.scan`), like the TypeORM and SQLite Drizzle adapters. */\n async runValueFacets(\n axis: RunValueAxis,\n query: RunFacetQuery,\n opts?: RunValueFacetOptions,\n ): Promise<RunValueFacetRow[]> {\n if (!axisIsRunColumn(axis)) {\n const runs = await this.listRuns({ ...query, limit: opts?.scan ?? RUN_VALUE_FACET_SCAN });\n return runValueFacetsFromRuns(runs, axis, opts);\n }\n const column = workflowRuns[axis.field];\n const filters = this.runFilters(query);\n const rows = await this.db\n .select({ value: column, count: sql<number>`count(*)`.mapWith(Number) })\n .from(workflowRuns)\n .where(filters.length ? and(...filters) : undefined)\n .groupBy(column);\n return mergeRunValueFacetRows(\n rows.map((r) => ({ value: (r.value as string | null) ?? null, count: r.count })),\n opts,\n );\n }\n\n /** One attribute predicate as an EXISTS on the side table, correlated to the outer run. `ne` also\n * excludes runs lacking the key (EXISTS requires the row). Numbers compare `num_value`, strings\n * and booleans `str_value`; an `in` set ORs its members inside the one EXISTS. */\n private attributeExists(f: AttributeFilter): SQL {\n const comparisons = attributePredicateOperands(f).map(\n ({ column, comparator, operand }) =>\n sql`${column === 'numValue' ? runAttributes.numValue : runAttributes.strValue} ${sql.raw(comparator)} ${operand}`,\n );\n return exists(\n this.db\n .select({ one: sql`1` })\n .from(runAttributes)\n .where(\n and(\n eq(runAttributes.runId, workflowRuns.id),\n eq(runAttributes.key, f.key),\n anyOf(comparisons),\n ),\n ),\n );\n }\n\n // ---- persisted schedules ----------------------------------------------------------------------\n\n async saveSchedule(record: ScheduleRecord): Promise<void> {\n const row = toScheduleRow(record);\n await this.db\n .insert(schedules)\n .values(row)\n .onConflictDoUpdate({ target: schedules.id, set: row });\n }\n\n async getSchedule(id: string): Promise<ScheduleRecord | null> {\n const rows = await this.db.select().from(schedules).where(eq(schedules.id, id)).limit(1);\n return rows[0] ? fromScheduleRow(rows[0]) : null;\n }\n\n /** A single conditional `UPDATE … RETURNING`: the compare-and-set on `next_fire_at` is atomic. */\n async updateSchedule(\n id: string,\n patch: Partial<Omit<ScheduleRecord, 'id' | 'createdAt'>>,\n expectedNextFireAt?: number | null,\n ): Promise<boolean> {\n const set = toSchedulePatch(patch);\n if (!Object.keys(set).length) return (await this.getSchedule(id)) !== null;\n const rows = await this.db\n .update(schedules)\n .set(set)\n .where(\n and(\n eq(schedules.id, id),\n expectedNextFireAt === undefined\n ? undefined\n : expectedNextFireAt === null\n ? isNull(schedules.nextFireAt)\n : eq(schedules.nextFireAt, new Date(expectedNextFireAt)),\n ),\n )\n .returning({ id: schedules.id });\n return rows.length > 0;\n }\n\n async deleteSchedule(id: string): Promise<boolean> {\n const rows = await this.db\n .delete(schedules)\n .where(eq(schedules.id, id))\n .returning({ id: schedules.id });\n return rows.length > 0;\n }\n\n async listSchedules(query: ScheduleQuery): Promise<ScheduleRecord[]> {\n const base = this.db\n .select()\n .from(schedules)\n .where(\n and(\n query.namespace !== undefined ? eq(schedules.namespace, query.namespace) : undefined,\n query.workflow !== undefined ? eq(schedules.workflow, query.workflow) : undefined,\n query.paused !== undefined ? eq(schedules.paused, query.paused) : undefined,\n query.tag !== undefined\n ? sql`${schedules.tags} @> ${JSON.stringify([query.tag])}::jsonb`\n : undefined,\n query.dueBy !== undefined\n ? and(eq(schedules.paused, false), lte(schedules.nextFireAt, new Date(query.dueBy)))\n : undefined,\n ),\n )\n // Soonest-due first, never-firing (NULL) last, id as the stable tie-break.\n .orderBy(sql`${schedules.nextFireAt} ASC NULLS LAST`, asc(schedules.id))\n .$dynamic();\n if (query.limit != null) base.limit(query.limit);\n if (query.offset != null) base.offset(query.offset);\n return (await base).map(fromScheduleRow);\n }\n\n async listCheckpoints(runId: string): Promise<StepCheckpoint[]> {\n const rows = await this.db\n .select()\n .from(stepCheckpoints)\n .where(eq(stepCheckpoints.runId, runId))\n .orderBy(asc(stepCheckpoints.seq));\n return rows.map(fromCheckpointRow);\n }\n\n async getLatestCheckpointByName(\n runId: string,\n name: string,\n ): Promise<StepCheckpoint | undefined> {\n const rows = await this.db\n .select()\n .from(stepCheckpoints)\n .where(and(eq(stepCheckpoints.runId, runId), eq(stepCheckpoints.name, name)))\n .orderBy(desc(stepCheckpoints.seq))\n .limit(1);\n return rows[0] ? fromCheckpointRow(rows[0]) : undefined;\n }\n\n async listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]> {\n if (prefixes.length === 0) return [];\n const rows = await this.db\n .select()\n .from(stepCheckpoints)\n .where(\n and(\n eq(stepCheckpoints.runId, runId),\n or(...prefixes.map((p) => like(stepCheckpoints.name, `${escapeLike(p)}%`))),\n ),\n )\n .orderBy(asc(stepCheckpoints.seq));\n return rows.map(fromCheckpointRow);\n }\n\n async putSignalWaiter(waiter: SignalWaiter): Promise<void> {\n const set = {\n runId: waiter.runId,\n seq: waiter.seq,\n parallelGroup: waiter.parallelGroup ?? null,\n };\n await this.db\n .insert(signalWaiters)\n .values({ token: waiter.token, ...set })\n .onConflictDoUpdate({ target: signalWaiters.token, set });\n }\n\n async takeSignalWaiter(token: string): Promise<SignalWaiter | null> {\n // Atomic take: one DELETE … RETURNING, so two concurrent signals for the same token can never\n // both resume the run.\n const rows = await this.db\n .delete(signalWaiters)\n .where(eq(signalWaiters.token, token))\n .returning();\n const row = rows[0];\n return row ? fromWaiterRow(row) : null;\n }\n\n async listSignalWaiters(prefix: string): Promise<SignalWaiter[]> {\n const rows = await this.db\n .select()\n .from(signalWaiters)\n .where(like(signalWaiters.token, `${escapeLike(prefix)}%`));\n return rows.map(fromWaiterRow);\n }\n\n async removeSignalWaiter(waiter: SignalWaiter): Promise<void> {\n // Exact match — never remove a row a DIFFERENT run has since claimed the token with.\n await this.db\n .delete(signalWaiters)\n .where(\n and(\n eq(signalWaiters.token, waiter.token),\n eq(signalWaiters.runId, waiter.runId),\n eq(signalWaiters.seq, waiter.seq),\n ),\n );\n }\n\n async bufferSignal(token: string, payload: unknown): Promise<void> {\n await this.db.insert(bufferedSignals).values({ token, payload: payload ?? null });\n }\n\n async takeBufferedSignal(token: string): Promise<{ payload: unknown } | null> {\n // Claim the oldest buffered signal for `token` with SKIP LOCKED and delete it in the same\n // statement: concurrent takers each get a different row (FIFO), none blocks, none double-reads.\n const oldest = this.db\n .select({ id: bufferedSignals.id })\n .from(bufferedSignals)\n .where(eq(bufferedSignals.token, token))\n .orderBy(asc(bufferedSignals.id))\n .limit(1)\n .for('update', { skipLocked: true });\n const rows = await this.db\n .delete(bufferedSignals)\n .where(inArray(bufferedSignals.id, oldest))\n .returning({ payload: bufferedSignals.payload });\n const row = rows[0];\n return row ? { payload: row.payload ?? undefined } : null;\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.insert(bufferedEvents).values({\n id: input.id,\n name: input.name,\n payload: input.payload ?? null,\n publishedAt: new Date(input.publishedAt),\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\n .select()\n .from(bufferedEvents)\n .where(eq(bufferedEvents.name, name))\n .orderBy(asc(bufferedEvents.publishedAt), asc(bufferedEvents.id))\n .limit(limit);\n return rows.map((r) => ({\n id: r.id,\n payload: r.payload ?? undefined,\n publishedAt: r.publishedAt.getTime(),\n }));\n }\n\n async removeBufferedEvent(id: string): Promise<boolean> {\n const rows = await this.db\n .delete(bufferedEvents)\n .where(eq(bufferedEvents.id, id))\n .returning({ id: bufferedEvents.id });\n return rows.length === 1;\n }\n}\n\n/** Escape LIKE metacharacters so a literal prefix (`event:50%_off`) matches only itself. */\nfunction escapeLike(value: string): string {\n return value.replace(/[\\\\%_]/g, (c) => `\\\\${c}`);\n}\n\nasync function upsertCheckpoint(db: DrizzlePgDatabase, cp: StepCheckpoint): Promise<void> {\n const row = toCheckpointRow(cp);\n await db\n .insert(stepCheckpoints)\n .values(row)\n .onConflictDoUpdate({ target: [stepCheckpoints.runId, stepCheckpoints.seq], set: row });\n}\n\n/** Rewrite a run's normalized attribute rows so the side table mirrors its live searchAttributes. */\nasync function reindexAttributes(\n db: DrizzlePgDatabase,\n runId: string,\n attributes: WorkflowRun['searchAttributes'],\n): Promise<void> {\n await db.delete(runAttributes).where(eq(runAttributes.runId, runId));\n const rows = normalizeAttributeRows(runId, attributes);\n if (rows.length) await db.insert(runAttributes).values(rows);\n}\n\n/** Children first, then the runs — checkpoints, waiters, attribute rows. Call inside a tx. */\nasync function deleteRunsCascade(db: DrizzlePgDatabase, runIds: string[]): Promise<void> {\n await db.delete(stepCheckpoints).where(inArray(stepCheckpoints.runId, runIds));\n await db.delete(signalWaiters).where(inArray(signalWaiters.runId, runIds));\n await db.delete(runAttributes).where(inArray(runAttributes.runId, runIds));\n await db.delete(workflowRuns).where(inArray(workflowRuns.id, runIds));\n}\n\nfunction fromWaiterRow(row: typeof signalWaiters.$inferSelect): SignalWaiter {\n return {\n token: row.token,\n runId: row.runId,\n seq: row.seq,\n parallelGroup: row.parallelGroup ?? undefined,\n };\n}\n\nfunction toRunRow(run: WorkflowRun): RunInsert {\n return {\n id: run.id,\n workflow: run.workflow,\n workflowVersion: run.workflowVersion,\n status: run.status,\n input: run.input ?? null,\n output: run.output ?? null,\n error: run.error ?? null,\n wakeAt: date(run.wakeAt),\n lockedBy: run.lockedBy ?? null,\n lockedUntil: date(run.lockedUntil),\n awaitingDecisionTaskId: run.awaitingDecisionTaskId ?? null,\n recoveryAttempts: run.recoveryAttempts ?? null,\n tags: run.tags ?? null,\n searchAttributes: run.searchAttributes ?? null,\n priority: run.priority ?? null,\n namespace: run.namespace ?? DEFAULT_NAMESPACE,\n origin: run.origin ?? null,\n createdAt: run.createdAt,\n updatedAt: run.updatedAt,\n };\n}\n\n/** Presence (`'x' in patch`) semantics, so a patch can CLEAR a nullable column (`{ error: undefined }`\n * → NULL), matching the other adapters and the in-memory reference store. */\nfunction toRunPatch(patch: Partial<WorkflowRun>): Partial<RunInsert> {\n const row: Partial<RunInsert> = {};\n if (patch.workflow !== undefined) row.workflow = patch.workflow;\n if (patch.workflowVersion !== undefined) row.workflowVersion = patch.workflowVersion;\n if (patch.status !== undefined) row.status = patch.status;\n if ('input' in patch) row.input = patch.input ?? null;\n if ('output' in patch) row.output = patch.output ?? null;\n if ('error' in patch) row.error = patch.error ?? null;\n if ('wakeAt' in patch) row.wakeAt = date(patch.wakeAt);\n if ('lockedBy' in patch) row.lockedBy = patch.lockedBy ?? null;\n if ('lockedUntil' in patch) row.lockedUntil = date(patch.lockedUntil);\n if ('awaitingDecisionTaskId' in patch)\n row.awaitingDecisionTaskId = patch.awaitingDecisionTaskId ?? null;\n if ('recoveryAttempts' in patch) row.recoveryAttempts = patch.recoveryAttempts ?? null;\n if ('tags' in patch) row.tags = patch.tags ?? null;\n if ('searchAttributes' in patch) row.searchAttributes = patch.searchAttributes ?? null;\n if ('priority' in patch) row.priority = patch.priority ?? null;\n // Never cleared to NULL: an undefined namespace means the default one.\n if ('namespace' in patch) row.namespace = patch.namespace ?? DEFAULT_NAMESPACE;\n if ('origin' in patch) row.origin = patch.origin ?? null;\n if (patch.createdAt != null) row.createdAt = patch.createdAt;\n if (patch.updatedAt != null) row.updatedAt = patch.updatedAt;\n return row;\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 RunStatus,\n input: row.input ?? undefined,\n output: row.output ?? undefined,\n error: (row.error ?? undefined) as StepError | undefined,\n wakeAt: ms(row.wakeAt),\n lockedBy: row.lockedBy ?? undefined,\n lockedUntil: ms(row.lockedUntil),\n awaitingDecisionTaskId: row.awaitingDecisionTaskId ?? undefined,\n recoveryAttempts: row.recoveryAttempts ?? undefined,\n tags: row.tags ?? undefined,\n searchAttributes: row.searchAttributes ?? undefined,\n priority: row.priority ?? undefined,\n namespace: row.namespace,\n origin: row.origin ?? undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction toCheckpointRow(cp: StepCheckpoint): CheckpointRow {\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: cp.input ?? null,\n output: cp.output ?? null,\n error: cp.error ?? null,\n events: cp.events ?? null,\n attempts: cp.attempts,\n workerGroup: cp.workerGroup ?? null,\n parallelGroup: cp.parallelGroup ?? null,\n wakeAt: date(cp.wakeAt),\n enqueuedAt: cp.enqueuedAt ?? cp.startedAt,\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: ms(row.wakeAt),\n // Older rows may lack enqueued_at; treat the start as enqueue time (queue-wait reads zero).\n enqueuedAt: row.enqueuedAt ?? row.startedAt,\n startedAt: row.startedAt,\n finishedAt: row.finishedAt,\n };\n}\n\ntype ScheduleRow = typeof schedules.$inferSelect;\n\nfunction toScheduleRow(r: ScheduleRecord): ScheduleRow {\n return {\n id: r.id,\n namespace: r.namespace,\n workflow: r.workflow,\n paused: r.paused,\n nextFireAt: r.nextFireAt == null ? null : new Date(r.nextFireAt),\n tags: r.tags ?? null,\n spec: r.spec,\n state: r.state,\n createdAt: r.createdAt,\n updatedAt: r.updatedAt,\n };\n}\n\nfunction toSchedulePatch(\n patch: Partial<Omit<ScheduleRecord, 'id' | 'createdAt'>>,\n): Partial<ScheduleRow> {\n const set: Partial<ScheduleRow> = {};\n if (patch.namespace !== undefined) set.namespace = patch.namespace;\n if (patch.workflow !== undefined) set.workflow = patch.workflow;\n if (patch.paused !== undefined) set.paused = patch.paused;\n if ('nextFireAt' in patch)\n set.nextFireAt = patch.nextFireAt == null ? null : new Date(patch.nextFireAt);\n if ('tags' in patch) set.tags = patch.tags ?? null;\n if (patch.spec !== undefined) set.spec = patch.spec;\n if (patch.state !== undefined) set.state = patch.state;\n if (patch.updatedAt !== undefined) set.updatedAt = patch.updatedAt;\n return set;\n}\n\nfunction fromScheduleRow(row: ScheduleRow): ScheduleRecord {\n return {\n id: row.id,\n namespace: row.namespace,\n workflow: row.workflow,\n paused: row.paused,\n nextFireAt: row.nextFireAt ? row.nextFireAt.getTime() : null,\n ...(row.tags ? { tags: row.tags } : {}),\n spec: row.spec ?? {},\n state: row.state ?? {},\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n","import { getTableName } from 'drizzle-orm';\nimport {\n bigserial,\n boolean,\n doublePrecision,\n index,\n integer,\n jsonb,\n pgTable,\n primaryKey,\n text,\n timestamp,\n} from 'drizzle-orm/pg-core';\n\n// PostgreSQL schema for the durable tables. Physical table + column names are the canonical\n// cross-adapter ones (`DURABLE_CANONICAL_COLUMNS` in -testing) — the same ones the SQLite schema in\n// `../schema`, the MikroORM, TypeORM and Prisma adapters use. The Postgres-native choices:\n// - timestamps / `wake_at` / `locked_until` are `timestamptz` (like the TypeORM + MikroORM PG DDL),\n// - JSON payloads are `jsonb` (like MikroORM's PG mapping) — which is what lets `tags` be matched\n// with the GIN-indexable `@>` containment operator instead of a leading-wildcard LIKE,\n// - every string is `text` (Postgres has no `varchar(n)` speed advantage, and a signal/event token\n// can be longer than the `varchar(191)` MySQL forces on the TypeORM DDL).\n//\n// Spread `durablePgSchema` (or re-export the individual tables) from the schema file your\n// `drizzle.config.ts` points at, and drizzle-kit generates the migration for you. Or skip drizzle-kit\n// for these tables and let `DrizzlePgStateStore.ensureSchema()` create them — `./ddl` is the same DDL\n// as SQL, and a spec pins the two against each other so they can never drift.\n\n/** The namespace a run belongs to when its creating engine named none (column DEFAULT below). */\nexport const DEFAULT_NAMESPACE = 'default';\n\nconst tstz = (name: string) => timestamp(name, { withTimezone: true, mode: 'date' });\n\nexport const durableWorkflowRuns = pgTable(\n 'durable_workflow_runs',\n {\n id: text('id').primaryKey(),\n workflow: text('workflow').notNull(),\n workflowVersion: text('workflow_version').notNull(),\n status: text('status').notNull(),\n input: jsonb('input'),\n output: jsonb('output'),\n error: jsonb('error'),\n wakeAt: tstz('wake_at'),\n lockedBy: text('locked_by'),\n lockedUntil: tstz('locked_until'),\n // REMOTE turn the engine suspended on awaiting a decision; matched by completeRemoteDecision so\n // only the currently-awaited turn's decision is applied. Nullable: cleared when a decision lands.\n awaitingDecisionTaskId: text('awaiting_decision_task_id'),\n recoveryAttempts: integer('recovery_attempts'),\n tags: jsonb('tags').$type<string[]>(),\n searchAttributes: jsonb('search_attributes').$type<Record<string, string | number | boolean>>(),\n priority: integer('priority'),\n // The worker-pool partition (tenant) — THE isolation boundary every poll predicate filters on.\n // NOT NULL DEFAULT 'default' so a row can never fall outside every worker's namespace.\n namespace: text('namespace').notNull().default(DEFAULT_NAMESPACE),\n // Which package declared the workflow. Nullable, no default: NULL = unknown, never guessed.\n origin: text('origin'),\n createdAt: tstz('created_at').notNull(),\n updatedAt: tstz('updated_at').notNull(),\n },\n (t) => [\n // Timer poller (`listDueTimers`) + recovery (`listIncompleteRuns`). Same name as the TypeORM DDL.\n index('durable_runs_status_idx').on(t.status, t.wakeAt),\n // Dashboard `listRuns({ workflow, status })` and the singleton gate's per-workflow scans.\n index('durable_runs_workflow_status_idx').on(t.workflow, t.status),\n // Every namespaced poll tick: `namespace = $1 AND status = $2 ORDER BY created_at` (FIFO pick-up).\n // Name matches the MikroORM adapter + the SQLite drizzle schema so a store swap keeps the index.\n index('durable_workflow_runs_namespace_status_idx').on(t.namespace, t.status, t.createdAt),\n // `listRuns({ tag })` compiles to `tags @> '[\"tag\"]'`, which a `jsonb_path_ops` GIN index serves —\n // this is what keeps the singleton gate (`tag: singleton:<key>`, e.g. a per-tenant concurrency\n // key) an index probe instead of a scan of every run the workflow ever had.\n index('durable_runs_tags_gin_idx').using('gin', t.tags.op('jsonb_path_ops')),\n // Retention (`pruneTerminalRuns`) orders a status set by `updated_at`.\n index('durable_runs_status_updated_idx').on(t.status, t.updatedAt),\n ],\n);\n\nexport const durableStepCheckpoints = pgTable(\n 'durable_step_checkpoints',\n {\n runId: text('run_id').notNull(),\n seq: integer('seq').notNull(),\n name: text('name').notNull(),\n kind: text('kind').notNull(),\n stepId: text('step_id').notNull(),\n status: text('status').notNull(),\n input: jsonb('input'),\n output: jsonb('output'),\n error: jsonb('error'),\n events: jsonb('events'),\n attempts: integer('attempts').notNull(),\n workerGroup: text('worker_group'),\n parallelGroup: text('parallel_group'),\n wakeAt: tstz('wake_at'),\n enqueuedAt: tstz('enqueued_at'),\n startedAt: tstz('started_at').notNull(),\n finishedAt: tstz('finished_at').notNull(),\n },\n // (run_id, seq) is the primary key, so listCheckpoints / getEvent already hit an index.\n (t) => [primaryKey({ columns: [t.runId, t.seq] })],\n);\n\n// Normalized search-attribute side-table: one row per (run, key), so attribute predicates push DOWN\n// into SQL as an EXISTS probe on the (key, value) indexes below instead of scan + in-process filter.\nexport const durableRunAttributes = pgTable(\n 'durable_run_attributes',\n {\n runId: text('run_id').notNull(),\n key: text('key').notNull(),\n strValue: text('str_value'),\n numValue: doublePrecision('num_value'),\n },\n (t) => [\n primaryKey({ columns: [t.runId, t.key] }),\n index('durable_run_attributes_num_idx').on(t.key, t.numValue),\n index('durable_run_attributes_str_idx').on(t.key, t.strValue),\n ],\n);\n\nexport const durableSignalWaiters = pgTable(\n 'durable_signal_waiters',\n {\n token: text('token').primaryKey(),\n runId: text('run_id').notNull(),\n seq: integer('seq').notNull(),\n parallelGroup: text('parallel_group'),\n },\n // deleteRun / pruneTerminalRuns delete a run's waiters by run_id.\n (t) => [index('durable_signal_waiters_run_id_idx').on(t.runId)],\n);\n\nexport const durableBufferedSignals = pgTable(\n 'durable_buffered_signals',\n {\n id: bigserial('id', { mode: 'number' }).primaryKey(),\n token: text('token').notNull(),\n payload: jsonb('payload'),\n },\n // Taken FIFO per token (smallest id first).\n (t) => [index('durable_buffered_signals_token_idx').on(t.token, t.id)],\n);\n\n// A published event that matched no live waiter. Keyed by a caller-minted id (engine.publishEvent)\n// so removeBufferedEvent can target that exact row.\nexport const durableBufferedEvents = pgTable(\n 'durable_buffered_events',\n {\n id: text('id').primaryKey(),\n name: text('name').notNull(),\n payload: jsonb('payload'),\n publishedAt: tstz('published_at').notNull(),\n },\n (t) => [index('durable_buffered_events_name_published_at_idx').on(t.name, t.publishedAt)],\n);\n\n// Persisted schedules (`engine.schedules`): the store filters on the columns; `spec`/`state` are\n// engine-owned JSON documents it keeps verbatim.\nexport const durableSchedules = pgTable(\n 'durable_schedules',\n {\n id: text('id').primaryKey(),\n namespace: text('namespace').notNull().default(DEFAULT_NAMESPACE),\n workflow: text('workflow').notNull(),\n paused: boolean('paused').notNull().default(false),\n nextFireAt: tstz('next_fire_at'),\n tags: jsonb('tags').$type<string[]>(),\n spec: jsonb('spec').$type<Record<string, unknown>>().notNull(),\n state: jsonb('state').$type<Record<string, unknown>>().notNull(),\n createdAt: tstz('created_at').notNull(),\n updatedAt: tstz('updated_at').notNull(),\n },\n // The poll's \"due by T\" scan: `paused = false AND next_fire_at <= T ORDER BY next_fire_at`.\n (t) => [index('durable_schedules_due_idx').on(t.paused, t.nextFireAt)],\n);\n\n/**\n * Every durable table, keyed by the name to export it under. Spread into your drizzle-kit schema file\n * (`export const { durableWorkflowRuns, ... } = durablePgSchema;` or `export * from` the `/pg` entry)\n * so `drizzle-kit generate` emits the durable DDL alongside your own tables.\n */\nexport const durablePgSchema = {\n durableWorkflowRuns,\n durableStepCheckpoints,\n durableRunAttributes,\n durableSignalWaiters,\n durableBufferedSignals,\n durableBufferedEvents,\n durableSchedules,\n};\n\n/**\n * The durable table names, derived from {@link durablePgSchema} (one list, never drifts). Feed to a\n * migration tool's exclude list — e.g. drizzle-kit `tablesFilter: ['!durable_*']` — if you let\n * `ensureSchema()` own these tables instead of drizzle-kit.\n */\nexport function durablePgManagedTables(): string[] {\n return Object.values(durablePgSchema).map((table) => getTableName(table));\n}\n","import { type SQL, sql } from 'drizzle-orm';\nimport type { DrizzlePgDatabase } from './drizzle-pg-state-store';\n\n/**\n * The structural `SqlExecutor` surface `@dudousxd/nestjs-durable-transport-db`'s `DbTransport` rides\n * (declared here, not imported, so this package takes no dependency on the transport).\n */\nexport interface DrizzlePgSqlExecutor {\n readonly dialect: 'postgres';\n escapeId(id: string): string;\n query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;\n transaction<T>(\n fn: (tx: { query<U = unknown>(sql: string, params?: unknown[]): Promise<U[]> }) => Promise<T>,\n ): Promise<T>;\n}\n\n/** Turn a `$1`-placeholder SQL string + params into a parameterized drizzle `SQL` object, so it runs\n * through whatever driver the drizzle db wraps (node-postgres, postgres-js, PGlite, Neon, …). */\nexport function toDrizzleSql(text: string, params: unknown[] = []): SQL {\n const chunks: SQL[] = [];\n let last = 0;\n for (const match of text.matchAll(/\\$(\\d+)/g)) {\n const index = Number(match[1]) - 1;\n if (index < 0 || index >= params.length)\n throw new Error(`placeholder ${match[0]} has no bound parameter`);\n chunks.push(sql.raw(text.slice(last, match.index)), sql`${params[index]}`);\n last = (match.index ?? 0) + match[0].length;\n }\n chunks.push(sql.raw(text.slice(last)));\n return sql.join(chunks);\n}\n\n/** node-postgres / PGlite hand back `{ rows }`; postgres-js hands back the row array itself. */\nfunction rowsOf<T>(result: unknown): T[] {\n if (Array.isArray(result)) return result as T[];\n return ((result as { rows?: T[] } | undefined)?.rows ?? []) as T[];\n}\n\n/**\n * Build a `DbTransport` executor from your drizzle Postgres db — the broker-less, DBOS-style\n * transport (remote steps as rows, claimed with `SELECT … FOR UPDATE SKIP LOCKED`) on the SAME\n * connection pool your app and the durable store already use:\n *\n * ```ts\n * import { DbTransport } from '@dudousxd/nestjs-durable-transport-db';\n * import { DrizzlePgStateStore, drizzlePgExecutor } from '@dudousxd/nestjs-durable-store-drizzle/pg';\n *\n * DurableModule.forRoot({\n * store: new DrizzlePgStateStore(db),\n * transport: new DbTransport({ executor: drizzlePgExecutor(db), group: 'api' }),\n * });\n * ```\n */\nexport function drizzlePgExecutor(db: DrizzlePgDatabase): DrizzlePgSqlExecutor {\n return {\n dialect: 'postgres',\n escapeId: (id) => `\"${id.replace(/\"/g, '\"\"')}\"`,\n query: async <T>(text: string, params?: unknown[]) =>\n rowsOf<T>(await db.execute(toDrizzleSql(text, params))),\n transaction: <T>(fn: Parameters<DrizzlePgSqlExecutor['transaction']>[0]) =>\n db.transaction((tx) =>\n fn({\n query: async <U>(text: string, params?: unknown[]) =>\n rowsOf<U>(await tx.execute(toDrizzleSql(text, params))),\n }),\n ) as Promise<T>,\n };\n}\n"],"mappings":"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","names":["DURABLE_PG_DDL","SCHEMA_LOCK_KEY","ensureDrizzlePgDurableSchema","db","transaction","tx","execute","sql","statement","raw","import_drizzle_orm","import_drizzle_orm","DEFAULT_NAMESPACE","tstz","name","timestamp","withTimezone","mode","durableWorkflowRuns","pgTable","id","text","primaryKey","workflow","notNull","workflowVersion","status","input","jsonb","output","error","wakeAt","lockedBy","lockedUntil","awaitingDecisionTaskId","recoveryAttempts","integer","tags","$type","searchAttributes","priority","namespace","default","origin","createdAt","updatedAt","t","index","on","using","op","durableStepCheckpoints","runId","seq","kind","stepId","events","attempts","workerGroup","parallelGroup","enqueuedAt","startedAt","finishedAt","columns","durableRunAttributes","key","strValue","numValue","doublePrecision","durableSignalWaiters","token","durableBufferedSignals","bigserial","payload","durableBufferedEvents","publishedAt","durableSchedules","paused","boolean","nextFireAt","spec","state","durablePgSchema","durablePgManagedTables","Object","values","map","table","getTableName","anyOf","conditions","present","filter","c","undefined","length","or","sql","namespaceFilter","namespace","eq","workflowRuns","hasTag","tag","tags","JSON","stringify","date","ms","Date","d","getTime","DrizzlePgStateStore","scopeNamespace","db","options","scope","withScope","ensureSchema","ensureDrizzlePgDurableSchema","tryAdmitSingleton","runId","workflow","limit","retryWakeAt","transaction","tx","where","and","inArray","status","SINGLETON_ACTIVE_STATUSES","update","set","rows","select","from","runs","map","fromRunRow","singletonAdmissionTags","patch","singletonAdmissionDenialPatch","toRunPatch","id","createRun","run","insert","values","toRunRow","reindexAttributes","searchAttributes","updateRun","inputPatch","TERMINAL_RUN_STATUSES","includes","clearTerminalSingletonAdmission","getRun","row","reindex","Object","keys","deleteRun","deleteRunsCascade","deleteRuns","runIds","pruneTerminalRuns","policy","nowMs","statuses","s","maxAge","maxCount","scoped","runFilters","ids","Set","cutoff","parseDuration","lt","updatedAt","orderBy","asc","for","skipLocked","r","add","size","desc","offset","idList","slice","getCheckpoint","seq","stepCheckpoints","fromCheckpointRow","saveCheckpoint","checkpoint","upsertCheckpoint","work","raw","cp","listIncompleteRuns","listPendingRuns","createdAt","listDueTimers","isNotNull","wakeAt","lte","tryLockRun","owner","leaseUntilMs","lockedBy","lockedUntil","isNull","returning","releaseRunLock","renewRunLock","query","workflows","namespaces","origin","origins","o","attributes","f","attributeExists","listRuns","filters","base","$dynamic","countRuns","count","mapWith","Number","runFacets","groupBy","mergeRunFacetRows","runValueFacets","axis","opts","axisIsRunColumn","scan","RUN_VALUE_FACET_SCAN","runValueFacetsFromRuns","column","field","value","mergeRunValueFacetRows","comparisons","attributePredicateOperands","comparator","operand","runAttributes","numValue","strValue","exists","one","key","saveSchedule","record","toScheduleRow","schedules","onConflictDoUpdate","target","getSchedule","fromScheduleRow","updateSchedule","expectedNextFireAt","toSchedulePatch","nextFireAt","deleteSchedule","delete","listSchedules","paused","dueBy","listCheckpoints","getLatestCheckpointByName","name","listCheckpointsByNamePrefix","prefixes","p","like","escapeLike","putSignalWaiter","waiter","parallelGroup","signalWaiters","token","takeSignalWaiter","fromWaiterRow","listSignalWaiters","prefix","removeSignalWaiter","bufferSignal","payload","bufferedSignals","takeBufferedSignal","oldest","bufferEvent","input","bufferedEvents","publishedAt","listBufferedEvents","removeBufferedEvent","replace","toCheckpointRow","normalizeAttributeRows","workflowVersion","output","error","awaitingDecisionTaskId","recoveryAttempts","priority","DEFAULT_NAMESPACE","kind","stepId","events","attempts","workerGroup","enqueuedAt","startedAt","finishedAt","spec","state","import_drizzle_orm","toDrizzleSql","text","params","chunks","last","match","matchAll","index","Number","length","Error","push","sql","raw","slice","join","rowsOf","result","Array","isArray","rows","drizzlePgExecutor","db","dialect","escapeId","id","replace","query","execute","transaction","fn","tx"]}
1
+ {"version":3,"sources":["../../src/pg/index.ts","../../src/pg/ddl.ts","../../src/pg/drizzle-pg-state-store.ts","../../src/pg/schema.ts","../../src/pg/executor.ts"],"sourcesContent":["// `@dudousxd/nestjs-durable-store-drizzle/pg` — the PostgreSQL flavour of the Drizzle store.\n// The package root (`@dudousxd/nestjs-durable-store-drizzle`) stays the SQLite / libSQL store.\nexport * from './ddl';\nexport * from './drizzle-pg-state-store';\nexport * from './executor';\nexport * from './schema';\n","import { sql } from 'drizzle-orm';\nimport type { PgDatabase } from 'drizzle-orm/pg-core';\n\n/**\n * The durable tables as idempotent Postgres DDL — the exact SQL twin of the `pgTable` definitions in\n * `./schema` (same tables, columns, types, defaults, primary keys and index names; a spec pins the two\n * against each other on a real Postgres, so they cannot drift).\n *\n * Every statement is `IF NOT EXISTS`, so the list is safe to run on every boot\n * ({@link ensureDrizzlePgDurableSchema}, which `DrizzlePgStateStore.ensureSchema()` calls when the\n * module's `autoSchema` is on) or to paste into a hand-written migration:\n *\n * ```ts\n * // drizzle/0007_durable.sql — or a custom migration step\n * import { DURABLE_PG_DDL } from '@dudousxd/nestjs-durable-store-drizzle/pg';\n * console.log(DURABLE_PG_DDL.join(';\\n') + ';');\n * ```\n *\n * A column added by a future version is appended here as `ALTER TABLE … ADD COLUMN IF NOT EXISTS`, so\n * an existing database heals on the next boot exactly like the MikroORM / TypeORM auto-schema does.\n */\nexport const DURABLE_PG_DDL: readonly string[] = [\n `CREATE TABLE IF NOT EXISTS \"durable_workflow_runs\" (\n \"id\" text PRIMARY KEY NOT NULL,\n \"workflow\" text NOT NULL,\n \"workflow_version\" text NOT NULL,\n \"status\" text NOT NULL,\n \"input\" jsonb,\n \"output\" jsonb,\n \"error\" jsonb,\n \"wake_at\" timestamp with time zone,\n \"locked_by\" text,\n \"locked_until\" timestamp with time zone,\n \"awaiting_decision_task_id\" text,\n \"recovery_attempts\" integer,\n \"tags\" jsonb,\n \"search_attributes\" jsonb,\n \"priority\" integer,\n \"namespace\" text DEFAULT 'default' NOT NULL,\n \"origin\" text,\n \"created_at\" timestamp with time zone NOT NULL,\n \"updated_at\" timestamp with time zone NOT NULL\n)`,\n `CREATE TABLE IF NOT EXISTS \"durable_step_checkpoints\" (\n \"run_id\" text NOT NULL,\n \"seq\" integer NOT NULL,\n \"name\" text NOT NULL,\n \"kind\" text NOT NULL,\n \"step_id\" text NOT NULL,\n \"status\" text NOT NULL,\n \"input\" jsonb,\n \"output\" jsonb,\n \"error\" jsonb,\n \"events\" jsonb,\n \"attempts\" integer NOT NULL,\n \"worker_group\" text,\n \"parallel_group\" text,\n \"wake_at\" timestamp with time zone,\n \"enqueued_at\" timestamp with time zone,\n \"started_at\" timestamp with time zone NOT NULL,\n \"finished_at\" timestamp with time zone NOT NULL,\n CONSTRAINT \"durable_step_checkpoints_run_id_seq_pk\" PRIMARY KEY(\"run_id\",\"seq\")\n)`,\n `CREATE TABLE IF NOT EXISTS \"durable_run_attributes\" (\n \"run_id\" text NOT NULL,\n \"key\" text NOT NULL,\n \"str_value\" text,\n \"num_value\" double precision,\n CONSTRAINT \"durable_run_attributes_run_id_key_pk\" PRIMARY KEY(\"run_id\",\"key\")\n)`,\n `CREATE TABLE IF NOT EXISTS \"durable_signal_waiters\" (\n \"token\" text PRIMARY KEY NOT NULL,\n \"run_id\" text NOT NULL,\n \"seq\" integer NOT NULL,\n \"parallel_group\" text\n)`,\n `CREATE TABLE IF NOT EXISTS \"durable_buffered_signals\" (\n \"id\" bigserial PRIMARY KEY NOT NULL,\n \"token\" text NOT NULL,\n \"payload\" jsonb\n)`,\n `CREATE TABLE IF NOT EXISTS \"durable_buffered_events\" (\n \"id\" text PRIMARY KEY NOT NULL,\n \"name\" text NOT NULL,\n \"payload\" jsonb,\n \"published_at\" timestamp with time zone NOT NULL\n)`,\n `CREATE TABLE IF NOT EXISTS \"durable_schedules\" (\n \"id\" text PRIMARY KEY NOT NULL,\n \"namespace\" text DEFAULT 'default' NOT NULL,\n \"workflow\" text NOT NULL,\n \"paused\" boolean DEFAULT false NOT NULL,\n \"next_fire_at\" timestamp with time zone,\n \"tags\" jsonb,\n \"spec\" jsonb NOT NULL,\n \"state\" jsonb NOT NULL,\n \"created_at\" timestamp with time zone NOT NULL,\n \"updated_at\" timestamp with time zone NOT NULL\n)`,\n `CREATE INDEX IF NOT EXISTS \"durable_runs_status_idx\" ON \"durable_workflow_runs\" USING btree (\"status\",\"wake_at\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_runs_workflow_status_idx\" ON \"durable_workflow_runs\" USING btree (\"workflow\",\"status\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_workflow_runs_namespace_status_idx\" ON \"durable_workflow_runs\" USING btree (\"namespace\",\"status\",\"created_at\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_runs_tags_gin_idx\" ON \"durable_workflow_runs\" USING gin (\"tags\" jsonb_path_ops)`,\n `CREATE INDEX IF NOT EXISTS \"durable_runs_status_updated_idx\" ON \"durable_workflow_runs\" USING btree (\"status\",\"updated_at\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_run_attributes_num_idx\" ON \"durable_run_attributes\" USING btree (\"key\",\"num_value\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_run_attributes_str_idx\" ON \"durable_run_attributes\" USING btree (\"key\",\"str_value\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_signal_waiters_run_id_idx\" ON \"durable_signal_waiters\" USING btree (\"run_id\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_buffered_signals_token_idx\" ON \"durable_buffered_signals\" USING btree (\"token\",\"id\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_buffered_events_name_published_at_idx\" ON \"durable_buffered_events\" USING btree (\"name\",\"published_at\")`,\n `CREATE INDEX IF NOT EXISTS \"durable_schedules_due_idx\" ON \"durable_schedules\" USING btree (\"paused\",\"next_fire_at\")`,\n];\n\n/** Key for the transaction-scoped advisory lock that serializes concurrent heals (several pods\n * booting at once would otherwise race `CREATE INDEX IF NOT EXISTS` into a duplicate-key error). */\nconst SCHEMA_LOCK_KEY = 'durable_schema';\n\n/**\n * Idempotently create the durable tables + indexes on `db` (any drizzle Postgres driver). Runs in one\n * transaction under a `pg_advisory_xact_lock`, so N pods booting together heal the schema once and\n * the rest see it done. Only ever touches the `durable_*` tables.\n */\nexport async function ensureDrizzlePgDurableSchema(db: PgDatabase<any, any, any>): Promise<void> {\n await db.transaction(async (tx) => {\n await tx.execute(sql`SELECT pg_advisory_xact_lock(hashtext(${SCHEMA_LOCK_KEY}))`);\n for (const statement of DURABLE_PG_DDL) await tx.execute(sql.raw(statement));\n });\n}\n","import {\n type AttributeFilter,\n type ChildWait,\n RUN_VALUE_FACET_SCAN,\n type RetentionPolicy,\n type RunFacetQuery,\n type RunFacetRow,\n type RunQuery,\n type RunStatus,\n type RunValueAxis,\n type RunValueFacetOptions,\n type RunValueFacetRow,\n SINGLETON_ACTIVE_STATUSES,\n type ScheduleQuery,\n type ScheduleRecord,\n type SignalWaiter,\n type StateStore,\n type StepCheckpoint,\n type StepError,\n type StepEvent,\n type StoreTransaction,\n TERMINAL_RUN_STATUSES,\n type WorkflowRun,\n attributePredicateOperands,\n axisIsRunColumn,\n clearTerminalSingletonAdmission,\n mergeRunFacetRows,\n mergeRunValueFacetRows,\n normalizeAttributeRows,\n parseDuration,\n runValueFacetsFromRuns,\n singletonAdmissionDenialPatch,\n singletonAdmissionTags,\n} from '@dudousxd/nestjs-durable-core';\nimport {\n type SQL,\n type Table,\n and,\n asc,\n desc,\n eq,\n exists,\n getTableColumns,\n gte,\n inArray,\n isNotNull,\n isNull,\n like,\n lt,\n lte,\n or,\n sql,\n} from 'drizzle-orm';\nimport type { PgDatabase } from 'drizzle-orm/pg-core';\nimport { ensureDrizzlePgDurableSchema } from './ddl';\nimport {\n DEFAULT_NAMESPACE,\n durableBufferedEvents as bufferedEvents,\n durableBufferedSignals as bufferedSignals,\n durableRunAttributes as runAttributes,\n durableSchedules as schedules,\n durableSignalWaiters as signalWaiters,\n durableStepCheckpoints as stepCheckpoints,\n durableWorkflowRuns as workflowRuns,\n} from './schema';\n\ntype RunRow = typeof workflowRuns.$inferSelect;\ntype RunInsert = typeof workflowRuns.$inferInsert;\ntype CheckpointRow = typeof stepCheckpoints.$inferSelect;\n\n/**\n * Any drizzle Postgres database — `drizzle-orm/node-postgres`, `drizzle-orm/postgres-js`,\n * `drizzle-orm/pglite`, Neon, … — built with or without a relational schema. The store only uses the\n * query builder (never `db.query.*`), so you do not have to register the durable tables on it.\n */\nexport type DrizzlePgDatabase = PgDatabase<any, any, any>;\n\nexport interface DrizzlePgStateStoreOptions {\n /**\n * Confine every RUN read (`getRun`, `listRuns`, facets, and the pending / incomplete / due-timer\n * polls) to one namespace — a tenant-boundary view of the store. Omit for the operator\n * (control-plane) view that sees every namespace. The NestJS module's `scopeReads` option applies\n * this for you via {@link DrizzlePgStateStore.withScope}.\n */\n scope?: { namespace?: string | undefined } | undefined;\n}\n\n/** OR a set of conditions where an EMPTY set means \"matches nothing\" (every plural `RunQuery`\n * predicate's contract) — `or()` of nothing would be dropped by `and()` and match everything. */\nfunction anyOf(conditions: (SQL | undefined)[]): SQL {\n const present = conditions.filter((c): c is SQL => c !== undefined);\n return present.length ? (or(...present) as SQL) : sql`1 = 0`;\n}\n\n/** `undefined` = no restriction (the operator view), never `namespace IS NULL`. The column is\n * NOT NULL DEFAULT 'default', so plain equality is exact. */\nfunction namespaceFilter(namespace: string | undefined): SQL | undefined {\n return namespace === undefined ? undefined : eq(workflowRuns.namespace, namespace);\n}\n\n/** `tags @> '[\"tag\"]'::jsonb` — exact element containment (so `etl` never matches `etl-foo`), and\n * served by the `durable_runs_tags_gin_idx` GIN (`jsonb_path_ops`) index. */\nfunction hasTag(tag: string): SQL {\n return sql`${workflowRuns.tags} @> ${JSON.stringify([tag])}::jsonb`;\n}\n\nconst date = (ms: number | undefined | null): Date | null => (ms == null ? null : new Date(ms));\nconst ms = (d: Date | null): number | undefined => (d == null ? undefined : d.getTime());\n\n/**\n * Drizzle `StateStore` for **PostgreSQL**. Pass any drizzle Postgres db (see {@link DrizzlePgDatabase});\n * the durable tables come from `./schema` (drizzle-kit) or {@link ensureSchema} (auto-schema).\n *\n * Postgres-specific behaviour, beyond the shared contract:\n * - leases (`tryLockRun` / `renewRunLock`) are a single conditional `UPDATE … RETURNING`, so two\n * instances racing for the same run serialize on the row lock and exactly one wins;\n * - `takeSignalWaiter` is one `DELETE … RETURNING` (atomic take), and `takeBufferedSignal` claims the\n * oldest row with `FOR UPDATE SKIP LOCKED`, so concurrent takers each get a DIFFERENT signal\n * instead of blocking or double-delivering;\n * - `pruneTerminalRuns` (retention) selects its batch with `FOR UPDATE SKIP LOCKED`, so several\n * pods sweeping at once split the backlog instead of contending on it;\n * - tag filters are jsonb containment (GIN-indexed) and attribute filters push down as EXISTS\n * probes on the indexed side table.\n */\nexport class DrizzlePgStateStore implements StateStore {\n private readonly scopeNamespace: string | undefined;\n\n constructor(\n private readonly db: DrizzlePgDatabase,\n private readonly options: DrizzlePgStateStoreOptions = {},\n ) {\n this.scopeNamespace = options.scope?.namespace;\n }\n\n /** A store confined to `scope.namespace`, sharing this store's db (no new connection). Used by the\n * NestJS module's `scopeReads`; `{ namespace: undefined }` is the unscoped operator view. */\n withScope(scope: { namespace?: string | undefined }): DrizzlePgStateStore {\n return new DrizzlePgStateStore(this.db, { ...this.options, scope });\n }\n\n /** Idempotent CREATE TABLE / INDEX IF NOT EXISTS under an advisory lock — called on boot when the\n * module's `autoSchema` is on. Turn `autoSchema` off if drizzle-kit owns these tables. */\n async ensureSchema(): Promise<void> {\n await ensureDrizzlePgDurableSchema(this.db);\n }\n\n /** The read-scope predicate on the runs table (undefined when the store is unscoped). */\n private scope(): SQL | undefined {\n return namespaceFilter(this.scopeNamespace);\n }\n\n async tryAdmitSingleton(\n runId: string,\n tag: string,\n workflow: string,\n limit: number,\n retryWakeAt?: number,\n ): Promise<boolean> {\n return this.db.transaction(async (tx) => {\n const where = and(\n eq(workflowRuns.workflow, workflow),\n inArray(workflowRuns.status, SINGLETON_ACTIVE_STATUSES),\n this.scope(),\n );\n await tx.update(workflowRuns).set({ workflow }).where(where);\n const rows = await tx.select().from(workflowRuns).where(where);\n const runs = rows.map(fromRunRow);\n const tags = singletonAdmissionTags(runs, runId, tag, workflow, limit);\n if (!tags) {\n const patch = singletonAdmissionDenialPatch(runs, runId, tag, workflow, retryWakeAt);\n if (patch)\n await tx.update(workflowRuns).set(toRunPatch(patch)).where(eq(workflowRuns.id, runId));\n return false;\n }\n await tx.update(workflowRuns).set({ tags }).where(eq(workflowRuns.id, runId));\n return true;\n });\n }\n\n async createRun(run: WorkflowRun): Promise<void> {\n // One transaction: a run is never visible without its attribute rows (or vice versa).\n await this.db.transaction(async (tx) => {\n await tx.insert(workflowRuns).values(toRunRow(run));\n await reindexAttributes(tx, run.id, run.searchAttributes);\n });\n }\n\n async updateRun(runId: string, inputPatch: Partial<WorkflowRun>): Promise<void> {\n // Writes are unscoped, so preserve tags even when settling a run outside the read scope.\n const patch =\n inputPatch.status && TERMINAL_RUN_STATUSES.includes(inputPatch.status)\n ? await clearTerminalSingletonAdmission(runId, inputPatch, (id) =>\n this.withScope({}).getRun(id),\n )\n : inputPatch;\n const row = toRunPatch(patch);\n const reindex = 'searchAttributes' in patch;\n if (!Object.keys(row).length && !reindex) return;\n await this.db.transaction(async (tx) => {\n // Drizzle throws on `.set({})`; skip the UPDATE when no mapped column changed.\n if (Object.keys(row).length)\n await tx.update(workflowRuns).set(row).where(eq(workflowRuns.id, runId));\n if (reindex) await reindexAttributes(tx, runId, patch.searchAttributes);\n });\n }\n\n async getRun(runId: string): Promise<WorkflowRun | null> {\n const rows = await this.db\n .select()\n .from(workflowRuns)\n .where(and(eq(workflowRuns.id, runId), this.scope()))\n .limit(1);\n return rows[0] ? fromRunRow(rows[0]) : null;\n }\n\n async deleteRun(runId: string): Promise<void> {\n await this.db.transaction(async (tx) => {\n await deleteRunsCascade(tx, [runId]);\n });\n }\n\n async deleteRuns(runIds: string[]): Promise<void> {\n if (runIds.length === 0) return;\n await this.db.transaction(async (tx) => {\n await deleteRunsCascade(tx, runIds);\n });\n }\n\n async pruneTerminalRuns(policy: RetentionPolicy, nowMs: number, limit: number): Promise<number> {\n // Only terminal statuses are ever eligible — a policy naming a live status would race the engine.\n const statuses = policy.statuses.filter((s) => TERMINAL_RUN_STATUSES.includes(s));\n if (statuses.length === 0 || limit <= 0) return 0;\n if (policy.maxAge == null && policy.maxCount == null) return 0;\n // A scoped policy only ever sees (and, for maxCount, counts) the runs its scope matches.\n const scoped = this.runFilters({ ...(policy.scope ?? {}), statuses });\n return this.db.transaction(async (tx) => {\n const ids = new Set<string>();\n if (policy.maxAge != null) {\n const cutoff = new Date(nowMs - parseDuration(policy.maxAge));\n const rows = await tx\n .select({ id: workflowRuns.id })\n .from(workflowRuns)\n .where(and(...scoped, lt(workflowRuns.updatedAt, cutoff)))\n .orderBy(asc(workflowRuns.updatedAt)) // oldest first\n .limit(limit)\n .for('update', { skipLocked: true });\n for (const r of rows) ids.add(r.id);\n }\n if (policy.maxCount != null && ids.size < limit) {\n // Everything past the newest `maxCount` rows of the status set. The kept window is skipped by\n // OFFSET (no row lock there), and only the rows past it are locked for deletion.\n const rows = await tx\n .select({ id: workflowRuns.id })\n .from(workflowRuns)\n .where(and(...scoped))\n .orderBy(desc(workflowRuns.updatedAt), desc(workflowRuns.id))\n .limit(limit)\n .offset(policy.maxCount)\n .for('update', { skipLocked: true });\n for (const r of rows) {\n if (ids.size >= limit) break;\n ids.add(r.id);\n }\n }\n if (ids.size === 0) return 0;\n const idList = [...ids].slice(0, limit);\n await deleteRunsCascade(tx, idList);\n return idList.length;\n });\n }\n\n async getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null> {\n const rows = await this.db\n .select()\n .from(stepCheckpoints)\n .where(and(eq(stepCheckpoints.runId, runId), eq(stepCheckpoints.seq, seq)))\n .limit(1);\n return rows[0] ? fromCheckpointRow(rows[0]) : null;\n }\n\n async saveCheckpoint(checkpoint: StepCheckpoint): Promise<void> {\n await upsertCheckpoint(this.db, checkpoint);\n }\n\n async transaction<T>(work: (tx: StoreTransaction) => Promise<T>): Promise<T> {\n return this.db.transaction(async (tx) =>\n work({ raw: tx, saveCheckpoint: (cp) => upsertCheckpoint(tx, cp) }),\n );\n }\n\n /** Crash recovery. Namespace-scoped: a worker re-drives only its own tenant's runs. */\n async listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]> {\n const rows = await this.db\n .select()\n .from(workflowRuns)\n .where(\n and(\n inArray(workflowRuns.status, ['running', 'cancelling']),\n namespaceFilter(namespace),\n this.scope(),\n ),\n );\n return rows.map(fromRunRow);\n }\n\n /** FIFO pick-up, served by `durable_workflow_runs_namespace_status_idx`. The engine then leases\n * each run with {@link tryLockRun}; the listing itself takes no locks (it runs outside a tx). */\n async listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]> {\n const rows = await this.db\n .select()\n .from(workflowRuns)\n .where(and(eq(workflowRuns.status, 'pending'), namespaceFilter(namespace), this.scope()))\n .orderBy(asc(workflowRuns.createdAt))\n .limit(limit);\n return rows.map(fromRunRow);\n }\n\n async listDueTimers(nowMs: number, namespace?: string): Promise<WorkflowRun[]> {\n const rows = await this.db\n .select()\n .from(workflowRuns)\n .where(\n and(\n eq(workflowRuns.status, 'suspended'),\n isNotNull(workflowRuns.wakeAt),\n lte(workflowRuns.wakeAt, new Date(nowMs)),\n namespaceFilter(namespace),\n this.scope(),\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 // One conditional UPDATE: under READ COMMITTED a concurrent contender blocks on the row lock,\n // then re-evaluates the WHERE against the winner's committed row and matches nothing.\n const rows = await this.db\n .update(workflowRuns)\n .set({ lockedBy: owner, lockedUntil: new Date(leaseUntilMs) })\n .where(\n and(\n eq(workflowRuns.id, runId),\n or(isNull(workflowRuns.lockedUntil), lte(workflowRuns.lockedUntil, new Date(nowMs))),\n ),\n )\n .returning({ id: workflowRuns.id });\n return rows.length === 1;\n }\n\n async releaseRunLock(runId: string): Promise<void> {\n await this.db\n .update(workflowRuns)\n .set({ lockedBy: null, lockedUntil: null })\n .where(eq(workflowRuns.id, runId));\n }\n\n async renewRunLock(runId: string, owner: string, leaseUntilMs: number): Promise<boolean> {\n const rows = await this.db\n .update(workflowRuns)\n .set({ lockedUntil: new Date(leaseUntilMs) })\n .where(and(eq(workflowRuns.id, runId), eq(workflowRuns.lockedBy, owner)))\n .returning({ id: workflowRuns.id });\n return rows.length === 1;\n }\n\n /** The predicates every run query shares — {@link listRuns} pages them, the facets group them. */\n private runFilters(query: RunQuery): SQL[] {\n return [\n this.scope(),\n query.workflow ? eq(workflowRuns.workflow, query.workflow) : undefined,\n query.workflows\n ? query.workflows.length\n ? inArray(workflowRuns.workflow, query.workflows)\n : sql`1 = 0`\n : undefined,\n // The tenant boundary. Also the engine's execution-timeout sweep path\n // (`listRuns({ workflow, status, namespace })`) — unscoped, it would cancel another tenant's runs.\n namespaceFilter(query.namespace),\n query.namespaces\n ? query.namespaces.length\n ? inArray(workflowRuns.namespace, query.namespaces)\n : sql`1 = 0`\n : undefined,\n // `null` selects the unattributed bucket; a value never matches a NULL origin.\n query.origin === null\n ? isNull(workflowRuns.origin)\n : query.origin !== undefined\n ? eq(workflowRuns.origin, query.origin)\n : undefined,\n query.origins\n ? anyOf(\n query.origins.map((o) =>\n o === null ? isNull(workflowRuns.origin) : eq(workflowRuns.origin, o),\n ),\n )\n : undefined,\n query.status ? eq(workflowRuns.status, query.status) : undefined,\n query.statuses\n ? query.statuses.length\n ? inArray(workflowRuns.status, query.statuses)\n : sql`1 = 0`\n : undefined,\n query.tag ? hasTag(query.tag) : undefined,\n query.tags ? anyOf(query.tags.map(hasTag)) : undefined,\n // One EXISTS per attribute predicate against the normalized side table (ANDed).\n ...(query.attributes?.map((f) => this.attributeExists(f)) ?? []),\n ].filter((f): f is SQL => f !== undefined);\n }\n\n async listRuns(query: RunQuery): Promise<WorkflowRun[]> {\n const filters = this.runFilters(query);\n const base = this.db\n .select()\n .from(workflowRuns)\n .where(filters.length ? and(...filters) : undefined)\n // newest first; id breaks created_at ties so limit/offset pages are stable\n .orderBy(desc(workflowRuns.createdAt), desc(workflowRuns.id))\n .$dynamic();\n if (query.limit != null) base.limit(query.limit);\n if (query.offset != null) base.offset(query.offset);\n const rows = await base;\n return rows.map(fromRunRow);\n }\n\n async countRuns(query: Omit<RunQuery, 'limit' | 'offset'>): Promise<number> {\n const filters = this.runFilters(query);\n const rows = await this.db\n .select({ count: sql<number>`count(*)`.mapWith(Number) })\n .from(workflowRuns)\n .where(filters.length ? and(...filters) : undefined);\n return rows[0]?.count ?? 0;\n }\n\n async runFacets(query: RunFacetQuery): Promise<RunFacetRow[]> {\n const filters = this.runFilters(query);\n const rows = await this.db\n .select({\n status: workflowRuns.status,\n origin: workflowRuns.origin,\n count: sql<number>`count(*)`.mapWith(Number),\n })\n .from(workflowRuns)\n .where(filters.length ? and(...filters) : undefined)\n .groupBy(workflowRuns.status, workflowRuns.origin);\n return mergeRunFacetRows(\n rows.map((r) => ({ status: r.status as RunStatus, origin: r.origin, count: r.count })),\n );\n }\n\n /** Run-table axes are an exact `GROUP BY`; the tag / attribute axes are counted over a bounded\n * page of runs (see `RunValueFacetOptions.scan`), like the TypeORM and SQLite Drizzle adapters. */\n async runValueFacets(\n axis: RunValueAxis,\n query: RunFacetQuery,\n opts?: RunValueFacetOptions,\n ): Promise<RunValueFacetRow[]> {\n if (!axisIsRunColumn(axis)) {\n const runs = await this.listRuns({ ...query, limit: opts?.scan ?? RUN_VALUE_FACET_SCAN });\n return runValueFacetsFromRuns(runs, axis, opts);\n }\n const column = workflowRuns[axis.field];\n const filters = this.runFilters(query);\n const rows = await this.db\n .select({ value: column, count: sql<number>`count(*)`.mapWith(Number) })\n .from(workflowRuns)\n .where(filters.length ? and(...filters) : undefined)\n .groupBy(column);\n return mergeRunValueFacetRows(\n rows.map((r) => ({ value: (r.value as string | null) ?? null, count: r.count })),\n opts,\n );\n }\n\n /** One attribute predicate as an EXISTS on the side table, correlated to the outer run. `ne` also\n * excludes runs lacking the key (EXISTS requires the row). Numbers compare `num_value`, strings\n * and booleans `str_value`; an `in` set ORs its members inside the one EXISTS. */\n private attributeExists(f: AttributeFilter): SQL {\n const comparisons = attributePredicateOperands(f).map(\n ({ column, comparator, operand }) =>\n sql`${column === 'numValue' ? runAttributes.numValue : runAttributes.strValue} ${sql.raw(comparator)} ${operand}`,\n );\n return exists(\n this.db\n .select({ one: sql`1` })\n .from(runAttributes)\n .where(\n and(\n eq(runAttributes.runId, workflowRuns.id),\n eq(runAttributes.key, f.key),\n anyOf(comparisons),\n ),\n ),\n );\n }\n\n // ---- persisted schedules ----------------------------------------------------------------------\n\n async saveSchedule(record: ScheduleRecord): Promise<void> {\n const row = toScheduleRow(record);\n await this.db\n .insert(schedules)\n .values(row)\n .onConflictDoUpdate({ target: schedules.id, set: row });\n }\n\n async getSchedule(id: string): Promise<ScheduleRecord | null> {\n const rows = await this.db.select().from(schedules).where(eq(schedules.id, id)).limit(1);\n return rows[0] ? fromScheduleRow(rows[0]) : null;\n }\n\n /** A single conditional `UPDATE … RETURNING`: the compare-and-set on `next_fire_at` is atomic. */\n async updateSchedule(\n id: string,\n patch: Partial<Omit<ScheduleRecord, 'id' | 'createdAt'>>,\n expectedNextFireAt?: number | null,\n ): Promise<boolean> {\n const set = toSchedulePatch(patch);\n if (!Object.keys(set).length) return (await this.getSchedule(id)) !== null;\n const rows = await this.db\n .update(schedules)\n .set(set)\n .where(\n and(\n eq(schedules.id, id),\n expectedNextFireAt === undefined\n ? undefined\n : expectedNextFireAt === null\n ? isNull(schedules.nextFireAt)\n : eq(schedules.nextFireAt, new Date(expectedNextFireAt)),\n ),\n )\n .returning({ id: schedules.id });\n return rows.length > 0;\n }\n\n async deleteSchedule(id: string): Promise<boolean> {\n const rows = await this.db\n .delete(schedules)\n .where(eq(schedules.id, id))\n .returning({ id: schedules.id });\n return rows.length > 0;\n }\n\n async listSchedules(query: ScheduleQuery): Promise<ScheduleRecord[]> {\n const base = this.db\n .select()\n .from(schedules)\n .where(\n and(\n query.namespace !== undefined ? eq(schedules.namespace, query.namespace) : undefined,\n query.workflow !== undefined ? eq(schedules.workflow, query.workflow) : undefined,\n query.paused !== undefined ? eq(schedules.paused, query.paused) : undefined,\n query.tag !== undefined\n ? sql`${schedules.tags} @> ${JSON.stringify([query.tag])}::jsonb`\n : undefined,\n query.dueBy !== undefined\n ? and(eq(schedules.paused, false), lte(schedules.nextFireAt, new Date(query.dueBy)))\n : undefined,\n ),\n )\n // Soonest-due first, never-firing (NULL) last, id as the stable tie-break.\n .orderBy(sql`${schedules.nextFireAt} ASC NULLS LAST`, asc(schedules.id))\n .$dynamic();\n if (query.limit != null) base.limit(query.limit);\n if (query.offset != null) base.offset(query.offset);\n return (await base).map(fromScheduleRow);\n }\n\n async listCheckpoints(runId: string): Promise<StepCheckpoint[]> {\n const rows = await this.db\n .select()\n .from(stepCheckpoints)\n .where(eq(stepCheckpoints.runId, runId))\n .orderBy(asc(stepCheckpoints.seq));\n return rows.map(fromCheckpointRow);\n }\n\n async getLatestCheckpointByName(\n runId: string,\n name: string,\n ): Promise<StepCheckpoint | undefined> {\n const rows = await this.db\n .select()\n .from(stepCheckpoints)\n .where(and(eq(stepCheckpoints.runId, runId), eq(stepCheckpoints.name, name)))\n .orderBy(desc(stepCheckpoints.seq))\n .limit(1);\n return rows[0] ? fromCheckpointRow(rows[0]) : undefined;\n }\n\n async listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]> {\n if (prefixes.length === 0) return [];\n const rows = await this.db\n .select()\n .from(stepCheckpoints)\n .where(\n and(\n eq(stepCheckpoints.runId, runId),\n or(...prefixes.map((p) => like(stepCheckpoints.name, `${escapeLike(p)}%`))),\n ),\n )\n .orderBy(asc(stepCheckpoints.seq));\n return rows.map(fromCheckpointRow);\n }\n\n async putSignalWaiter(waiter: SignalWaiter): Promise<void> {\n const set = {\n runId: waiter.runId,\n seq: waiter.seq,\n parallelGroup: waiter.parallelGroup ?? null,\n };\n await this.db\n .insert(signalWaiters)\n .values({ token: waiter.token, ...set })\n .onConflictDoUpdate({ target: signalWaiters.token, set });\n }\n\n async takeSignalWaiter(token: string): Promise<SignalWaiter | null> {\n // Atomic take: one DELETE … RETURNING, so two concurrent signals for the same token can never\n // both resume the run.\n const rows = await this.db\n .delete(signalWaiters)\n .where(eq(signalWaiters.token, token))\n .returning();\n const row = rows[0];\n return row ? fromWaiterRow(row) : null;\n }\n\n async listSignalWaiters(prefix: string): Promise<SignalWaiter[]> {\n const rows = await this.db\n .select()\n .from(signalWaiters)\n .where(like(signalWaiters.token, `${escapeLike(prefix)}%`));\n return rows.map(fromWaiterRow);\n }\n\n async registerChildWaits(entries: ChildWait[]): Promise<void> {\n if (entries.length === 0) return;\n await this.db.transaction(async (tx) => {\n await tx\n .insert(signalWaiters)\n .values(\n entries.map(({ waiter }) => ({\n token: waiter.token,\n runId: waiter.runId,\n seq: waiter.seq,\n parallelGroup: waiter.parallelGroup ?? null,\n })),\n )\n .onConflictDoUpdate({\n target: signalWaiters.token,\n set: excludedSet(signalWaiters, ['runId', 'seq', 'parallelGroup']),\n });\n await tx\n .insert(stepCheckpoints)\n .values(entries.map(({ checkpoint }) => toCheckpointRow(checkpoint)))\n .onConflictDoUpdate({\n target: [stepCheckpoints.runId, stepCheckpoints.seq],\n set: excludedSet(stepCheckpoints),\n });\n });\n }\n\n async compactCheckpoints(\n runId: string,\n fromSeq: number,\n toSeq: number,\n into: StepCheckpoint,\n ): Promise<void> {\n await this.db.transaction(async (tx) => {\n await tx\n .delete(stepCheckpoints)\n .where(\n and(\n eq(stepCheckpoints.runId, runId),\n gte(stepCheckpoints.seq, fromSeq),\n lte(stepCheckpoints.seq, toSeq),\n ),\n );\n await upsertCheckpoint(tx, into);\n });\n }\n\n async listSignalWaitersByRun(runIds: string[]): Promise<SignalWaiter[]> {\n if (runIds.length === 0) return [];\n const rows = await this.db\n .select()\n .from(signalWaiters)\n .where(inArray(signalWaiters.runId, runIds));\n return rows.map(fromWaiterRow);\n }\n\n async hasSignalWaiter(runId: string, tokenPrefix: string): Promise<boolean> {\n const rows = await this.db\n .select({ token: signalWaiters.token })\n .from(signalWaiters)\n .where(\n and(\n eq(signalWaiters.runId, runId),\n like(signalWaiters.token, `${escapeLike(tokenPrefix)}%`),\n ),\n )\n .limit(1);\n return rows.length > 0;\n }\n\n async removeSignalWaiter(waiter: SignalWaiter): Promise<void> {\n // Exact match — never remove a row a DIFFERENT run has since claimed the token with.\n await this.db\n .delete(signalWaiters)\n .where(\n and(\n eq(signalWaiters.token, waiter.token),\n eq(signalWaiters.runId, waiter.runId),\n eq(signalWaiters.seq, waiter.seq),\n ),\n );\n }\n\n async bufferSignal(token: string, payload: unknown): Promise<void> {\n await this.db.insert(bufferedSignals).values({ token, payload: payload ?? null });\n }\n\n async takeBufferedSignal(token: string): Promise<{ payload: unknown } | null> {\n // Claim the oldest buffered signal for `token` with SKIP LOCKED and delete it in the same\n // statement: concurrent takers each get a different row (FIFO), none blocks, none double-reads.\n const oldest = this.db\n .select({ id: bufferedSignals.id })\n .from(bufferedSignals)\n .where(eq(bufferedSignals.token, token))\n .orderBy(asc(bufferedSignals.id))\n .limit(1)\n .for('update', { skipLocked: true });\n const rows = await this.db\n .delete(bufferedSignals)\n .where(inArray(bufferedSignals.id, oldest))\n .returning({ payload: bufferedSignals.payload });\n const row = rows[0];\n return row ? { payload: row.payload ?? undefined } : null;\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.insert(bufferedEvents).values({\n id: input.id,\n name: input.name,\n payload: input.payload ?? null,\n publishedAt: new Date(input.publishedAt),\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\n .select()\n .from(bufferedEvents)\n .where(eq(bufferedEvents.name, name))\n .orderBy(asc(bufferedEvents.publishedAt), asc(bufferedEvents.id))\n .limit(limit);\n return rows.map((r) => ({\n id: r.id,\n payload: r.payload ?? undefined,\n publishedAt: r.publishedAt.getTime(),\n }));\n }\n\n async removeBufferedEvent(id: string): Promise<boolean> {\n const rows = await this.db\n .delete(bufferedEvents)\n .where(eq(bufferedEvents.id, id))\n .returning({ id: bufferedEvents.id });\n return rows.length === 1;\n }\n}\n\n/** Escape LIKE metacharacters so a literal prefix (`event:50%_off`) matches only itself. */\nfunction escapeLike(value: string): string {\n return value.replace(/[\\\\%_]/g, (c) => `\\\\${c}`);\n}\n\nasync function upsertCheckpoint(db: DrizzlePgDatabase, cp: StepCheckpoint): Promise<void> {\n const row = toCheckpointRow(cp);\n await db\n .insert(stepCheckpoints)\n .values(row)\n .onConflictDoUpdate({ target: [stepCheckpoints.runId, stepCheckpoints.seq], set: row });\n}\n\n/** Rewrite a run's normalized attribute rows so the side table mirrors its live searchAttributes. */\nasync function reindexAttributes(\n db: DrizzlePgDatabase,\n runId: string,\n attributes: WorkflowRun['searchAttributes'],\n): Promise<void> {\n await db.delete(runAttributes).where(eq(runAttributes.runId, runId));\n const rows = normalizeAttributeRows(runId, attributes);\n if (rows.length) await db.insert(runAttributes).values(rows);\n}\n\n/** Children first, then the runs — checkpoints, waiters, attribute rows. Call inside a tx. */\nasync function deleteRunsCascade(db: DrizzlePgDatabase, runIds: string[]): Promise<void> {\n await db.delete(stepCheckpoints).where(inArray(stepCheckpoints.runId, runIds));\n await db.delete(signalWaiters).where(inArray(signalWaiters.runId, runIds));\n await db.delete(runAttributes).where(inArray(runAttributes.runId, runIds));\n await db.delete(workflowRuns).where(inArray(workflowRuns.id, runIds));\n}\n\nfunction fromWaiterRow(row: typeof signalWaiters.$inferSelect): SignalWaiter {\n return {\n token: row.token,\n runId: row.runId,\n seq: row.seq,\n parallelGroup: row.parallelGroup ?? undefined,\n };\n}\n\nfunction toRunRow(run: WorkflowRun): RunInsert {\n return {\n id: run.id,\n workflow: run.workflow,\n workflowVersion: run.workflowVersion,\n status: run.status,\n input: run.input ?? null,\n output: run.output ?? null,\n error: run.error ?? null,\n wakeAt: date(run.wakeAt),\n lockedBy: run.lockedBy ?? null,\n lockedUntil: date(run.lockedUntil),\n awaitingDecisionTaskId: run.awaitingDecisionTaskId ?? null,\n recoveryAttempts: run.recoveryAttempts ?? null,\n tags: run.tags ?? null,\n searchAttributes: run.searchAttributes ?? null,\n priority: run.priority ?? null,\n namespace: run.namespace ?? DEFAULT_NAMESPACE,\n origin: run.origin ?? null,\n createdAt: run.createdAt,\n updatedAt: run.updatedAt,\n };\n}\n\n/** Presence (`'x' in patch`) semantics, so a patch can CLEAR a nullable column (`{ error: undefined }`\n * → NULL), matching the other adapters and the in-memory reference store. */\nfunction toRunPatch(patch: Partial<WorkflowRun>): Partial<RunInsert> {\n const row: Partial<RunInsert> = {};\n if (patch.workflow !== undefined) row.workflow = patch.workflow;\n if (patch.workflowVersion !== undefined) row.workflowVersion = patch.workflowVersion;\n if (patch.status !== undefined) row.status = patch.status;\n if ('input' in patch) row.input = patch.input ?? null;\n if ('output' in patch) row.output = patch.output ?? null;\n if ('error' in patch) row.error = patch.error ?? null;\n if ('wakeAt' in patch) row.wakeAt = date(patch.wakeAt);\n if ('lockedBy' in patch) row.lockedBy = patch.lockedBy ?? null;\n if ('lockedUntil' in patch) row.lockedUntil = date(patch.lockedUntil);\n if ('awaitingDecisionTaskId' in patch)\n row.awaitingDecisionTaskId = patch.awaitingDecisionTaskId ?? null;\n if ('recoveryAttempts' in patch) row.recoveryAttempts = patch.recoveryAttempts ?? null;\n if ('tags' in patch) row.tags = patch.tags ?? null;\n if ('searchAttributes' in patch) row.searchAttributes = patch.searchAttributes ?? null;\n if ('priority' in patch) row.priority = patch.priority ?? null;\n // Never cleared to NULL: an undefined namespace means the default one.\n if ('namespace' in patch) row.namespace = patch.namespace ?? DEFAULT_NAMESPACE;\n if ('origin' in patch) row.origin = patch.origin ?? null;\n if (patch.createdAt != null) row.createdAt = patch.createdAt;\n if (patch.updatedAt != null) row.updatedAt = patch.updatedAt;\n return row;\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 RunStatus,\n input: row.input ?? undefined,\n output: row.output ?? undefined,\n error: (row.error ?? undefined) as StepError | undefined,\n wakeAt: ms(row.wakeAt),\n lockedBy: row.lockedBy ?? undefined,\n lockedUntil: ms(row.lockedUntil),\n awaitingDecisionTaskId: row.awaitingDecisionTaskId ?? undefined,\n recoveryAttempts: row.recoveryAttempts ?? undefined,\n tags: row.tags ?? undefined,\n searchAttributes: row.searchAttributes ?? undefined,\n priority: row.priority ?? undefined,\n namespace: row.namespace,\n origin: row.origin ?? undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction toCheckpointRow(cp: StepCheckpoint): CheckpointRow {\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: cp.input ?? null,\n output: cp.output ?? null,\n error: cp.error ?? null,\n events: cp.events ?? null,\n attempts: cp.attempts,\n workerGroup: cp.workerGroup ?? null,\n parallelGroup: cp.parallelGroup ?? null,\n wakeAt: date(cp.wakeAt),\n enqueuedAt: cp.enqueuedAt ?? cp.startedAt,\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: ms(row.wakeAt),\n // Older rows may lack enqueued_at; treat the start as enqueue time (queue-wait reads zero).\n enqueuedAt: row.enqueuedAt ?? row.startedAt,\n startedAt: row.startedAt,\n finishedAt: row.finishedAt,\n };\n}\n\ntype ScheduleRow = typeof schedules.$inferSelect;\n\nfunction toScheduleRow(r: ScheduleRecord): ScheduleRow {\n return {\n id: r.id,\n namespace: r.namespace,\n workflow: r.workflow,\n paused: r.paused,\n nextFireAt: r.nextFireAt == null ? null : new Date(r.nextFireAt),\n tags: r.tags ?? null,\n spec: r.spec,\n state: r.state,\n createdAt: r.createdAt,\n updatedAt: r.updatedAt,\n };\n}\n\nfunction toSchedulePatch(\n patch: Partial<Omit<ScheduleRecord, 'id' | 'createdAt'>>,\n): Partial<ScheduleRow> {\n const set: Partial<ScheduleRow> = {};\n if (patch.namespace !== undefined) set.namespace = patch.namespace;\n if (patch.workflow !== undefined) set.workflow = patch.workflow;\n if (patch.paused !== undefined) set.paused = patch.paused;\n if ('nextFireAt' in patch)\n set.nextFireAt = patch.nextFireAt == null ? null : new Date(patch.nextFireAt);\n if ('tags' in patch) set.tags = patch.tags ?? null;\n if (patch.spec !== undefined) set.spec = patch.spec;\n if (patch.state !== undefined) set.state = patch.state;\n if (patch.updatedAt !== undefined) set.updatedAt = patch.updatedAt;\n return set;\n}\n\nfunction fromScheduleRow(row: ScheduleRow): ScheduleRecord {\n return {\n id: row.id,\n namespace: row.namespace,\n workflow: row.workflow,\n paused: row.paused,\n nextFireAt: row.nextFireAt ? row.nextFireAt.getTime() : null,\n ...(row.tags ? { tags: row.tags } : {}),\n spec: row.spec ?? {},\n state: row.state ?? {},\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\n/**\n * The `ON CONFLICT DO UPDATE` set for a multi-row upsert: each column (or each of `only`) takes the\n * value the conflicting row proposed.\n */\nfunction excludedSet<T extends Table>(table: T, only?: string[]): Record<string, SQL> {\n return Object.fromEntries(\n Object.entries(getTableColumns(table))\n .filter(([key]) => !only || only.includes(key))\n .map(([key, column]) => [key, sql.raw(`excluded.\"${column.name}\"`)]),\n );\n}\n","import { getTableName } from 'drizzle-orm';\nimport {\n bigserial,\n boolean,\n doublePrecision,\n index,\n integer,\n jsonb,\n pgTable,\n primaryKey,\n text,\n timestamp,\n} from 'drizzle-orm/pg-core';\n\n// PostgreSQL schema for the durable tables. Physical table + column names are the canonical\n// cross-adapter ones (`DURABLE_CANONICAL_COLUMNS` in -testing) — the same ones the SQLite schema in\n// `../schema`, the MikroORM, TypeORM and Prisma adapters use. The Postgres-native choices:\n// - timestamps / `wake_at` / `locked_until` are `timestamptz` (like the TypeORM + MikroORM PG DDL),\n// - JSON payloads are `jsonb` (like MikroORM's PG mapping) — which is what lets `tags` be matched\n// with the GIN-indexable `@>` containment operator instead of a leading-wildcard LIKE,\n// - every string is `text` (Postgres has no `varchar(n)` speed advantage, and a signal/event token\n// can be longer than the `varchar(191)` MySQL forces on the TypeORM DDL).\n//\n// Spread `durablePgSchema` (or re-export the individual tables) from the schema file your\n// `drizzle.config.ts` points at, and drizzle-kit generates the migration for you. Or skip drizzle-kit\n// for these tables and let `DrizzlePgStateStore.ensureSchema()` create them — `./ddl` is the same DDL\n// as SQL, and a spec pins the two against each other so they can never drift.\n\n/** The namespace a run belongs to when its creating engine named none (column DEFAULT below). */\nexport const DEFAULT_NAMESPACE = 'default';\n\nconst tstz = (name: string) => timestamp(name, { withTimezone: true, mode: 'date' });\n\nexport const durableWorkflowRuns = pgTable(\n 'durable_workflow_runs',\n {\n id: text('id').primaryKey(),\n workflow: text('workflow').notNull(),\n workflowVersion: text('workflow_version').notNull(),\n status: text('status').notNull(),\n input: jsonb('input'),\n output: jsonb('output'),\n error: jsonb('error'),\n wakeAt: tstz('wake_at'),\n lockedBy: text('locked_by'),\n lockedUntil: tstz('locked_until'),\n // REMOTE turn the engine suspended on awaiting a decision; matched by completeRemoteDecision so\n // only the currently-awaited turn's decision is applied. Nullable: cleared when a decision lands.\n awaitingDecisionTaskId: text('awaiting_decision_task_id'),\n recoveryAttempts: integer('recovery_attempts'),\n tags: jsonb('tags').$type<string[]>(),\n searchAttributes: jsonb('search_attributes').$type<Record<string, string | number | boolean>>(),\n priority: integer('priority'),\n // The worker-pool partition (tenant) — THE isolation boundary every poll predicate filters on.\n // NOT NULL DEFAULT 'default' so a row can never fall outside every worker's namespace.\n namespace: text('namespace').notNull().default(DEFAULT_NAMESPACE),\n // Which package declared the workflow. Nullable, no default: NULL = unknown, never guessed.\n origin: text('origin'),\n createdAt: tstz('created_at').notNull(),\n updatedAt: tstz('updated_at').notNull(),\n },\n (t) => [\n // Timer poller (`listDueTimers`) + recovery (`listIncompleteRuns`). Same name as the TypeORM DDL.\n index('durable_runs_status_idx').on(t.status, t.wakeAt),\n // Dashboard `listRuns({ workflow, status })` and the singleton gate's per-workflow scans.\n index('durable_runs_workflow_status_idx').on(t.workflow, t.status),\n // Every namespaced poll tick: `namespace = $1 AND status = $2 ORDER BY created_at` (FIFO pick-up).\n // Name matches the MikroORM adapter + the SQLite drizzle schema so a store swap keeps the index.\n index('durable_workflow_runs_namespace_status_idx').on(t.namespace, t.status, t.createdAt),\n // `listRuns({ tag })` compiles to `tags @> '[\"tag\"]'`, which a `jsonb_path_ops` GIN index serves —\n // this is what keeps the singleton gate (`tag: singleton:<key>`, e.g. a per-tenant concurrency\n // key) an index probe instead of a scan of every run the workflow ever had.\n index('durable_runs_tags_gin_idx').using('gin', t.tags.op('jsonb_path_ops')),\n // Retention (`pruneTerminalRuns`) orders a status set by `updated_at`.\n index('durable_runs_status_updated_idx').on(t.status, t.updatedAt),\n ],\n);\n\nexport const durableStepCheckpoints = pgTable(\n 'durable_step_checkpoints',\n {\n runId: text('run_id').notNull(),\n seq: integer('seq').notNull(),\n name: text('name').notNull(),\n kind: text('kind').notNull(),\n stepId: text('step_id').notNull(),\n status: text('status').notNull(),\n input: jsonb('input'),\n output: jsonb('output'),\n error: jsonb('error'),\n events: jsonb('events'),\n attempts: integer('attempts').notNull(),\n workerGroup: text('worker_group'),\n parallelGroup: text('parallel_group'),\n wakeAt: tstz('wake_at'),\n enqueuedAt: tstz('enqueued_at'),\n startedAt: tstz('started_at').notNull(),\n finishedAt: tstz('finished_at').notNull(),\n },\n // (run_id, seq) is the primary key, so listCheckpoints / getEvent already hit an index.\n (t) => [primaryKey({ columns: [t.runId, t.seq] })],\n);\n\n// Normalized search-attribute side-table: one row per (run, key), so attribute predicates push DOWN\n// into SQL as an EXISTS probe on the (key, value) indexes below instead of scan + in-process filter.\nexport const durableRunAttributes = pgTable(\n 'durable_run_attributes',\n {\n runId: text('run_id').notNull(),\n key: text('key').notNull(),\n strValue: text('str_value'),\n numValue: doublePrecision('num_value'),\n },\n (t) => [\n primaryKey({ columns: [t.runId, t.key] }),\n index('durable_run_attributes_num_idx').on(t.key, t.numValue),\n index('durable_run_attributes_str_idx').on(t.key, t.strValue),\n ],\n);\n\nexport const durableSignalWaiters = pgTable(\n 'durable_signal_waiters',\n {\n token: text('token').primaryKey(),\n runId: text('run_id').notNull(),\n seq: integer('seq').notNull(),\n parallelGroup: text('parallel_group'),\n },\n // deleteRun / pruneTerminalRuns delete a run's waiters by run_id.\n (t) => [index('durable_signal_waiters_run_id_idx').on(t.runId)],\n);\n\nexport const durableBufferedSignals = pgTable(\n 'durable_buffered_signals',\n {\n id: bigserial('id', { mode: 'number' }).primaryKey(),\n token: text('token').notNull(),\n payload: jsonb('payload'),\n },\n // Taken FIFO per token (smallest id first).\n (t) => [index('durable_buffered_signals_token_idx').on(t.token, t.id)],\n);\n\n// A published event that matched no live waiter. Keyed by a caller-minted id (engine.publishEvent)\n// so removeBufferedEvent can target that exact row.\nexport const durableBufferedEvents = pgTable(\n 'durable_buffered_events',\n {\n id: text('id').primaryKey(),\n name: text('name').notNull(),\n payload: jsonb('payload'),\n publishedAt: tstz('published_at').notNull(),\n },\n (t) => [index('durable_buffered_events_name_published_at_idx').on(t.name, t.publishedAt)],\n);\n\n// Persisted schedules (`engine.schedules`): the store filters on the columns; `spec`/`state` are\n// engine-owned JSON documents it keeps verbatim.\nexport const durableSchedules = pgTable(\n 'durable_schedules',\n {\n id: text('id').primaryKey(),\n namespace: text('namespace').notNull().default(DEFAULT_NAMESPACE),\n workflow: text('workflow').notNull(),\n paused: boolean('paused').notNull().default(false),\n nextFireAt: tstz('next_fire_at'),\n tags: jsonb('tags').$type<string[]>(),\n spec: jsonb('spec').$type<Record<string, unknown>>().notNull(),\n state: jsonb('state').$type<Record<string, unknown>>().notNull(),\n createdAt: tstz('created_at').notNull(),\n updatedAt: tstz('updated_at').notNull(),\n },\n // The poll's \"due by T\" scan: `paused = false AND next_fire_at <= T ORDER BY next_fire_at`.\n (t) => [index('durable_schedules_due_idx').on(t.paused, t.nextFireAt)],\n);\n\n/**\n * Every durable table, keyed by the name to export it under. Spread into your drizzle-kit schema file\n * (`export const { durableWorkflowRuns, ... } = durablePgSchema;` or `export * from` the `/pg` entry)\n * so `drizzle-kit generate` emits the durable DDL alongside your own tables.\n */\nexport const durablePgSchema = {\n durableWorkflowRuns,\n durableStepCheckpoints,\n durableRunAttributes,\n durableSignalWaiters,\n durableBufferedSignals,\n durableBufferedEvents,\n durableSchedules,\n};\n\n/**\n * The durable table names, derived from {@link durablePgSchema} (one list, never drifts). Feed to a\n * migration tool's exclude list — e.g. drizzle-kit `tablesFilter: ['!durable_*']` — if you let\n * `ensureSchema()` own these tables instead of drizzle-kit.\n */\nexport function durablePgManagedTables(): string[] {\n return Object.values(durablePgSchema).map((table) => getTableName(table));\n}\n","import { type SQL, sql } from 'drizzle-orm';\nimport type { DrizzlePgDatabase } from './drizzle-pg-state-store';\n\n/**\n * The structural `SqlExecutor` surface `@dudousxd/nestjs-durable-transport-db`'s `DbTransport` rides\n * (declared here, not imported, so this package takes no dependency on the transport).\n */\nexport interface DrizzlePgSqlExecutor {\n readonly dialect: 'postgres';\n escapeId(id: string): string;\n query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;\n transaction<T>(\n fn: (tx: { query<U = unknown>(sql: string, params?: unknown[]): Promise<U[]> }) => Promise<T>,\n ): Promise<T>;\n}\n\n/** Turn a `$1`-placeholder SQL string + params into a parameterized drizzle `SQL` object, so it runs\n * through whatever driver the drizzle db wraps (node-postgres, postgres-js, PGlite, Neon, …). */\nexport function toDrizzleSql(text: string, params: unknown[] = []): SQL {\n const chunks: SQL[] = [];\n let last = 0;\n for (const match of text.matchAll(/\\$(\\d+)/g)) {\n const index = Number(match[1]) - 1;\n if (index < 0 || index >= params.length)\n throw new Error(`placeholder ${match[0]} has no bound parameter`);\n chunks.push(sql.raw(text.slice(last, match.index)), sql`${params[index]}`);\n last = (match.index ?? 0) + match[0].length;\n }\n chunks.push(sql.raw(text.slice(last)));\n return sql.join(chunks);\n}\n\n/** node-postgres / PGlite hand back `{ rows }`; postgres-js hands back the row array itself. */\nfunction rowsOf<T>(result: unknown): T[] {\n if (Array.isArray(result)) return result as T[];\n return ((result as { rows?: T[] } | undefined)?.rows ?? []) as T[];\n}\n\n/**\n * Build a `DbTransport` executor from your drizzle Postgres db — the broker-less, DBOS-style\n * transport (remote steps as rows, claimed with `SELECT … FOR UPDATE SKIP LOCKED`) on the SAME\n * connection pool your app and the durable store already use:\n *\n * ```ts\n * import { DbTransport } from '@dudousxd/nestjs-durable-transport-db';\n * import { DrizzlePgStateStore, drizzlePgExecutor } from '@dudousxd/nestjs-durable-store-drizzle/pg';\n *\n * DurableModule.forRoot({\n * store: new DrizzlePgStateStore(db),\n * transport: new DbTransport({ executor: drizzlePgExecutor(db), group: 'api' }),\n * });\n * ```\n */\nexport function drizzlePgExecutor(db: DrizzlePgDatabase): DrizzlePgSqlExecutor {\n return {\n dialect: 'postgres',\n escapeId: (id) => `\"${id.replace(/\"/g, '\"\"')}\"`,\n query: async <T>(text: string, params?: unknown[]) =>\n rowsOf<T>(await db.execute(toDrizzleSql(text, params))),\n transaction: <T>(fn: Parameters<DrizzlePgSqlExecutor['transaction']>[0]) =>\n db.transaction((tx) =>\n fn({\n query: async <U>(text: string, params?: unknown[]) =>\n rowsOf<U>(await tx.execute(toDrizzleSql(text, params))),\n }),\n ) as Promise<T>,\n };\n}\n"],"mappings":"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","names":["DURABLE_PG_DDL","SCHEMA_LOCK_KEY","ensureDrizzlePgDurableSchema","db","transaction","tx","execute","sql","statement","raw","import_drizzle_orm","import_drizzle_orm","DEFAULT_NAMESPACE","tstz","name","timestamp","withTimezone","mode","durableWorkflowRuns","pgTable","id","text","primaryKey","workflow","notNull","workflowVersion","status","input","jsonb","output","error","wakeAt","lockedBy","lockedUntil","awaitingDecisionTaskId","recoveryAttempts","integer","tags","$type","searchAttributes","priority","namespace","default","origin","createdAt","updatedAt","t","index","on","using","op","durableStepCheckpoints","runId","seq","kind","stepId","events","attempts","workerGroup","parallelGroup","enqueuedAt","startedAt","finishedAt","columns","durableRunAttributes","key","strValue","numValue","doublePrecision","durableSignalWaiters","token","durableBufferedSignals","bigserial","payload","durableBufferedEvents","publishedAt","durableSchedules","paused","boolean","nextFireAt","spec","state","durablePgSchema","durablePgManagedTables","Object","values","map","table","getTableName","anyOf","conditions","present","filter","c","undefined","length","or","sql","namespaceFilter","namespace","eq","workflowRuns","hasTag","tag","tags","JSON","stringify","date","ms","Date","d","getTime","DrizzlePgStateStore","scopeNamespace","db","options","scope","withScope","ensureSchema","ensureDrizzlePgDurableSchema","tryAdmitSingleton","runId","workflow","limit","retryWakeAt","transaction","tx","where","and","inArray","status","SINGLETON_ACTIVE_STATUSES","update","set","rows","select","from","runs","map","fromRunRow","singletonAdmissionTags","patch","singletonAdmissionDenialPatch","toRunPatch","id","createRun","run","insert","values","toRunRow","reindexAttributes","searchAttributes","updateRun","inputPatch","TERMINAL_RUN_STATUSES","includes","clearTerminalSingletonAdmission","getRun","row","reindex","Object","keys","deleteRun","deleteRunsCascade","deleteRuns","runIds","pruneTerminalRuns","policy","nowMs","statuses","s","maxAge","maxCount","scoped","runFilters","ids","Set","cutoff","parseDuration","lt","updatedAt","orderBy","asc","for","skipLocked","r","add","size","desc","offset","idList","slice","getCheckpoint","seq","stepCheckpoints","fromCheckpointRow","saveCheckpoint","checkpoint","upsertCheckpoint","work","raw","cp","listIncompleteRuns","listPendingRuns","createdAt","listDueTimers","isNotNull","wakeAt","lte","tryLockRun","owner","leaseUntilMs","lockedBy","lockedUntil","isNull","returning","releaseRunLock","renewRunLock","query","workflows","namespaces","origin","origins","o","attributes","f","attributeExists","listRuns","filters","base","$dynamic","countRuns","count","mapWith","Number","runFacets","groupBy","mergeRunFacetRows","runValueFacets","axis","opts","axisIsRunColumn","scan","RUN_VALUE_FACET_SCAN","runValueFacetsFromRuns","column","field","value","mergeRunValueFacetRows","comparisons","attributePredicateOperands","comparator","operand","runAttributes","numValue","strValue","exists","one","key","saveSchedule","record","toScheduleRow","schedules","onConflictDoUpdate","target","getSchedule","fromScheduleRow","updateSchedule","expectedNextFireAt","toSchedulePatch","nextFireAt","deleteSchedule","delete","listSchedules","paused","dueBy","listCheckpoints","getLatestCheckpointByName","name","listCheckpointsByNamePrefix","prefixes","p","like","escapeLike","putSignalWaiter","waiter","parallelGroup","signalWaiters","token","takeSignalWaiter","fromWaiterRow","listSignalWaiters","prefix","registerChildWaits","entries","excludedSet","toCheckpointRow","compactCheckpoints","fromSeq","toSeq","into","gte","listSignalWaitersByRun","hasSignalWaiter","tokenPrefix","removeSignalWaiter","bufferSignal","payload","bufferedSignals","takeBufferedSignal","oldest","bufferEvent","input","bufferedEvents","publishedAt","listBufferedEvents","removeBufferedEvent","replace","normalizeAttributeRows","workflowVersion","output","error","awaitingDecisionTaskId","recoveryAttempts","priority","DEFAULT_NAMESPACE","kind","stepId","events","attempts","workerGroup","enqueuedAt","startedAt","finishedAt","spec","state","table","only","fromEntries","getTableColumns","import_drizzle_orm","toDrizzleSql","text","params","chunks","last","match","matchAll","index","Number","length","Error","push","sql","raw","slice","join","rowsOf","result","Array","isArray","rows","drizzlePgExecutor","db","dialect","escapeId","id","replace","query","execute","transaction","fn","tx"]}
@@ -1,6 +1,6 @@
1
1
  import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
2
2
  import { PgDatabase } from 'drizzle-orm/pg-core';
3
- import { StateStore, WorkflowRun, RetentionPolicy, StepCheckpoint, StoreTransaction, RunQuery, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, ScheduleRecord, ScheduleQuery, SignalWaiter } from '@dudousxd/nestjs-durable-core';
3
+ import { StateStore, WorkflowRun, RetentionPolicy, StepCheckpoint, StoreTransaction, RunQuery, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, ScheduleRecord, ScheduleQuery, SignalWaiter, ChildWait } from '@dudousxd/nestjs-durable-core';
4
4
  import { SQL } from 'drizzle-orm';
5
5
 
6
6
  /**
@@ -119,6 +119,10 @@ declare class DrizzlePgStateStore implements StateStore {
119
119
  putSignalWaiter(waiter: SignalWaiter): Promise<void>;
120
120
  takeSignalWaiter(token: string): Promise<SignalWaiter | null>;
121
121
  listSignalWaiters(prefix: string): Promise<SignalWaiter[]>;
122
+ registerChildWaits(entries: ChildWait[]): Promise<void>;
123
+ compactCheckpoints(runId: string, fromSeq: number, toSeq: number, into: StepCheckpoint): Promise<void>;
124
+ listSignalWaitersByRun(runIds: string[]): Promise<SignalWaiter[]>;
125
+ hasSignalWaiter(runId: string, tokenPrefix: string): Promise<boolean>;
122
126
  removeSignalWaiter(waiter: SignalWaiter): Promise<void>;
123
127
  bufferSignal(token: string, payload: unknown): Promise<void>;
124
128
  takeBufferedSignal(token: string): Promise<{
@@ -1,6 +1,6 @@
1
1
  import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
2
2
  import { PgDatabase } from 'drizzle-orm/pg-core';
3
- import { StateStore, WorkflowRun, RetentionPolicy, StepCheckpoint, StoreTransaction, RunQuery, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, ScheduleRecord, ScheduleQuery, SignalWaiter } from '@dudousxd/nestjs-durable-core';
3
+ import { StateStore, WorkflowRun, RetentionPolicy, StepCheckpoint, StoreTransaction, RunQuery, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, ScheduleRecord, ScheduleQuery, SignalWaiter, ChildWait } from '@dudousxd/nestjs-durable-core';
4
4
  import { SQL } from 'drizzle-orm';
5
5
 
6
6
  /**
@@ -119,6 +119,10 @@ declare class DrizzlePgStateStore implements StateStore {
119
119
  putSignalWaiter(waiter: SignalWaiter): Promise<void>;
120
120
  takeSignalWaiter(token: string): Promise<SignalWaiter | null>;
121
121
  listSignalWaiters(prefix: string): Promise<SignalWaiter[]>;
122
+ registerChildWaits(entries: ChildWait[]): Promise<void>;
123
+ compactCheckpoints(runId: string, fromSeq: number, toSeq: number, into: StepCheckpoint): Promise<void>;
124
+ listSignalWaitersByRun(runIds: string[]): Promise<SignalWaiter[]>;
125
+ hasSignalWaiter(runId: string, tokenPrefix: string): Promise<boolean>;
122
126
  removeSignalWaiter(waiter: SignalWaiter): Promise<void>;
123
127
  bufferSignal(token: string, payload: unknown): Promise<void>;
124
128
  takeBufferedSignal(token: string): Promise<{
package/dist/pg/index.js CHANGED
@@ -104,7 +104,7 @@ __name(ensureDrizzlePgDurableSchema, "ensureDrizzlePgDurableSchema");
104
104
 
105
105
  // src/pg/drizzle-pg-state-store.ts
106
106
  import { RUN_VALUE_FACET_SCAN, SINGLETON_ACTIVE_STATUSES, TERMINAL_RUN_STATUSES, attributePredicateOperands, axisIsRunColumn, clearTerminalSingletonAdmission, mergeRunFacetRows, mergeRunValueFacetRows, normalizeAttributeRows, parseDuration, runValueFacetsFromRuns, singletonAdmissionDenialPatch, singletonAdmissionTags } from "@dudousxd/nestjs-durable-core";
107
- import { and, asc, desc, eq, exists, inArray, isNotNull, isNull, like, lt, lte, or, sql as sql2 } from "drizzle-orm";
107
+ import { and, asc, desc, eq, exists, getTableColumns, gte, inArray, isNotNull, isNull, like, lt, lte, or, sql as sql2 } from "drizzle-orm";
108
108
 
109
109
  // src/pg/schema.ts
110
110
  import { getTableName } from "drizzle-orm";
@@ -610,6 +610,48 @@ var DrizzlePgStateStore = class _DrizzlePgStateStore {
610
610
  const rows = await this.db.select().from(durableSignalWaiters).where(like(durableSignalWaiters.token, `${escapeLike(prefix)}%`));
611
611
  return rows.map(fromWaiterRow);
612
612
  }
613
+ async registerChildWaits(entries) {
614
+ if (entries.length === 0) return;
615
+ await this.db.transaction(async (tx) => {
616
+ await tx.insert(durableSignalWaiters).values(entries.map(({ waiter }) => ({
617
+ token: waiter.token,
618
+ runId: waiter.runId,
619
+ seq: waiter.seq,
620
+ parallelGroup: waiter.parallelGroup ?? null
621
+ }))).onConflictDoUpdate({
622
+ target: durableSignalWaiters.token,
623
+ set: excludedSet(durableSignalWaiters, [
624
+ "runId",
625
+ "seq",
626
+ "parallelGroup"
627
+ ])
628
+ });
629
+ await tx.insert(durableStepCheckpoints).values(entries.map(({ checkpoint }) => toCheckpointRow(checkpoint))).onConflictDoUpdate({
630
+ target: [
631
+ durableStepCheckpoints.runId,
632
+ durableStepCheckpoints.seq
633
+ ],
634
+ set: excludedSet(durableStepCheckpoints)
635
+ });
636
+ });
637
+ }
638
+ async compactCheckpoints(runId, fromSeq, toSeq, into) {
639
+ await this.db.transaction(async (tx) => {
640
+ await tx.delete(durableStepCheckpoints).where(and(eq(durableStepCheckpoints.runId, runId), gte(durableStepCheckpoints.seq, fromSeq), lte(durableStepCheckpoints.seq, toSeq)));
641
+ await upsertCheckpoint(tx, into);
642
+ });
643
+ }
644
+ async listSignalWaitersByRun(runIds) {
645
+ if (runIds.length === 0) return [];
646
+ const rows = await this.db.select().from(durableSignalWaiters).where(inArray(durableSignalWaiters.runId, runIds));
647
+ return rows.map(fromWaiterRow);
648
+ }
649
+ async hasSignalWaiter(runId, tokenPrefix) {
650
+ const rows = await this.db.select({
651
+ token: durableSignalWaiters.token
652
+ }).from(durableSignalWaiters).where(and(eq(durableSignalWaiters.runId, runId), like(durableSignalWaiters.token, `${escapeLike(tokenPrefix)}%`))).limit(1);
653
+ return rows.length > 0;
654
+ }
613
655
  async removeSignalWaiter(waiter) {
614
656
  await this.db.delete(durableSignalWaiters).where(and(eq(durableSignalWaiters.token, waiter.token), eq(durableSignalWaiters.runId, waiter.runId), eq(durableSignalWaiters.seq, waiter.seq)));
615
657
  }
@@ -854,6 +896,13 @@ function fromScheduleRow(row) {
854
896
  };
855
897
  }
856
898
  __name(fromScheduleRow, "fromScheduleRow");
899
+ function excludedSet(table, only) {
900
+ return Object.fromEntries(Object.entries(getTableColumns(table)).filter(([key]) => !only || only.includes(key)).map(([key, column]) => [
901
+ key,
902
+ sql2.raw(`excluded."${column.name}"`)
903
+ ]));
904
+ }
905
+ __name(excludedSet, "excludedSet");
857
906
 
858
907
  // src/pg/executor.ts
859
908
  import { sql as sql3 } from "drizzle-orm";