@dudousxd/nestjs-durable-store-mikro-orm 0.23.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/entities.ts","../src/repositories.ts","../src/mikro-orm-state-store.ts","../src/schema.ts"],"sourcesContent":["import type { RunStatus, StepKind } from '@dudousxd/nestjs-durable-core';\nimport { EntityRepositoryType, EntitySchema } from '@mikro-orm/core';\nimport {\n BufferedEventRepository,\n BufferedSignalRepository,\n RunAttributeRepository,\n SignalWaiterRepository,\n StepCheckpointRepository,\n WorkflowRunRepository,\n} from './repositories';\n\n/**\n * How property names map to physical column names. The durable tables are adapter-agnostic: a run\n * written by one store adapter must be readable by another, so every adapter has to agree on the\n * physical column names. The default is `'snake_case'` (the canonical, matched by the TypeORM,\n * Prisma and Drizzle adapters). `'preserve'` keeps the camelCase property name verbatim (what the\n * old TypeORM/Prisma adapters produced before they were pinned). A function lets you supply any\n * custom mapping.\n *\n * The choice is pinned EXPLICITLY onto the entity schema rather than left to the host ORM's naming\n * strategy — depending on the host strategy is what silently diverged the adapters and broke a store\n * swap against an existing table.\n */\nexport type DurableColumnNaming = 'snake_case' | 'preserve' | ((property: string) => string);\n\nfunction snakeCase(property: string): string {\n return property.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);\n}\n\nfunction columnNamer(naming: DurableColumnNaming): (property: string) => string {\n if (naming === 'snake_case') return snakeCase;\n if (naming === 'preserve') return (property) => property;\n return naming;\n}\n\n// Plain classes (no decorators): the schema/column mapping lives on the EntitySchema built by\n// `durableEntities`, so the same class can be registered under different column names. The store\n// still references these classes for `em.create`/`getMetadata`.\n\nexport class WorkflowRunEntity {\n [EntityRepositoryType]?: WorkflowRunRepository;\n\n id!: string;\n workflow!: string;\n workflowVersion!: string;\n status!: RunStatus;\n input?: unknown;\n output?: unknown;\n error?: unknown;\n wakeAt?: Date;\n lockedBy?: string;\n lockedUntil?: Date;\n awaitingDecisionTaskId?: string;\n recoveryAttempts?: number;\n tags?: string[] | null;\n searchAttributes?: Record<string, string | number | boolean> | null;\n priority?: number | null;\n namespace!: string;\n origin?: string | null;\n createdAt!: Date;\n updatedAt!: Date;\n}\n\nexport class StepCheckpointEntity {\n [EntityRepositoryType]?: StepCheckpointRepository;\n\n runId!: string;\n seq!: number;\n name!: string;\n kind!: StepKind;\n stepId!: string;\n status!: 'pending' | 'running' | 'completed' | 'failed';\n input?: unknown;\n output?: unknown;\n error?: unknown;\n events?: unknown;\n attempts!: number;\n workerGroup?: string;\n parallelGroup?: string;\n wakeAt?: Date;\n enqueuedAt?: Date;\n startedAt!: Date;\n finishedAt!: Date;\n}\n\n/**\n * Normalized side-table for search attributes: one row per (run, key), so range/equality predicates\n * push DOWN into SQL (an EXISTS join indexed on `(key, numValue)` / `(key, strValue)`) instead of a\n * coarse scan + in-process filter. Maintained on every createRun/updateRun. Numbers land in\n * `numValue`, strings/booleans in `strValue` (booleans as \"true\"/\"false\"); see normalizeAttributeRows.\n */\nexport class RunAttributeEntity {\n [EntityRepositoryType]?: RunAttributeRepository;\n\n runId!: string;\n key!: string;\n strValue?: string | null;\n numValue?: number | null;\n}\n\nexport class SignalWaiterEntity {\n [EntityRepositoryType]?: SignalWaiterRepository;\n\n token!: string;\n runId!: string;\n seq!: number;\n parallelGroup?: string | null;\n}\n\nexport class BufferedSignalEntity {\n [EntityRepositoryType]?: BufferedSignalRepository;\n\n id!: number;\n token!: string;\n payload?: unknown;\n}\n\n/** A published event that matched no live waiter (see `engine.publishEvent`'s buffering). Keyed by a\n * caller-minted `id` (a uuid, not autoincrement — `removeBufferedEvent` targets it directly), not by\n * `runId`: events are name-based pub/sub, not tied to any one run. */\nexport class BufferedEventEntity {\n [EntityRepositoryType]?: BufferedEventRepository;\n\n id!: string;\n name!: string;\n payload?: unknown;\n publishedAt!: Date;\n}\n\n/**\n * Build the durable MikroORM entity schemas with column names pinned per `naming` (default\n * `'snake_case'`). Register the result in your MikroORM config / `MikroOrmModule.forFeature`.\n *\n * ```ts\n * entities: durableEntities({ naming: 'snake_case' })\n * ```\n */\n/**\n * MikroORM global filter condition for the `namespace` read boundary. Returns `{}` (no restriction)\n * when `namespace` is undefined — the operator (control plane) sees all tenants. Returns a\n * `{ namespace }` equality predicate otherwise, confining the query to that tenant's rows.\n */\nfunction namespaceFilterCond(args?: { namespace?: string }): { namespace?: string } {\n if (args?.namespace === undefined) return {};\n return { namespace: args.namespace };\n}\n\nexport function durableEntities(options: { naming?: DurableColumnNaming } = {}): EntitySchema[] {\n const col = columnNamer(options.naming ?? 'snake_case');\n\n const workflowRuns = new EntitySchema<WorkflowRunEntity>({\n class: WorkflowRunEntity,\n tableName: 'durable_workflow_runs',\n // Wired per schema rather than once on the class: `durableEntities` can be called again with a\n // different `naming`, and each call builds a distinct EntitySchema over the same class.\n repository: () => WorkflowRunRepository,\n // Global filter: confines every read to the tenant's namespace when the store is scoped.\n // The `cond` returns `{}` (no-op) when the `namespace` arg is `undefined`, so an unscoped\n // (operator / control-plane) store sees all rows unchanged — existing behaviour is preserved.\n filters: {\n namespace: {\n name: 'namespace',\n cond: namespaceFilterCond,\n default: true,\n // Optional args: the store's own forks set the scope via `setFilterParams` (undefined =\n // operator, sees all), but an external consumer that shares this ORM (an operator app reading\n // WorkflowRunEntity through its own EntityManager) never sets it. Without this, MikroORM\n // throws \"No arguments provided for filter 'namespace'\" on those queries. `args: false` makes\n // the param optional — cond then receives `undefined` and no-ops (sees all), which is exactly\n // the operator view, while a scoped store still passes its namespace through.\n args: false,\n },\n },\n // Indexes mirror the Prisma adapter so a store swap keeps the same plan. The poller hits these\n // every tick: `(status, wakeAt)` serves both the due-timer scan (status='suspended' AND wakeAt<=now)\n // and, via its `status` prefix, the pending/incomplete status lookups; `(workflow, status)` serves\n // the per-workflow timeout sweep. Without them every poll is a full scan of a table that only grows.\n indexes: [\n { name: 'durable_workflow_runs_status_wake_at_idx', properties: ['status', 'wakeAt'] },\n { name: 'durable_workflow_runs_workflow_status_idx', properties: ['workflow', 'status'] },\n {\n name: 'durable_workflow_runs_namespace_status_idx',\n properties: ['namespace', 'status', 'createdAt'],\n },\n ],\n properties: {\n id: { type: 'string', primary: true, fieldName: col('id') },\n workflow: { type: 'string', fieldName: col('workflow') },\n workflowVersion: { type: 'string', fieldName: col('workflowVersion') },\n status: { type: 'string', fieldName: col('status') },\n input: { type: 'json', nullable: true, fieldName: col('input') },\n output: { type: 'json', nullable: true, fieldName: col('output') },\n error: { type: 'json', nullable: true, fieldName: col('error') },\n wakeAt: { type: 'Date', nullable: true, fieldName: col('wakeAt') },\n lockedBy: { type: 'string', nullable: true, fieldName: col('lockedBy') },\n lockedUntil: { type: 'Date', nullable: true, fieldName: col('lockedUntil') },\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: {\n type: 'string',\n nullable: true,\n fieldName: col('awaitingDecisionTaskId'),\n },\n recoveryAttempts: { type: 'integer', nullable: true, fieldName: col('recoveryAttempts') },\n tags: { type: 'json', nullable: true, fieldName: col('tags') },\n searchAttributes: { type: 'json', nullable: true, fieldName: col('searchAttributes') },\n priority: { type: 'integer', nullable: true, fieldName: col('priority') },\n namespace: { type: 'string', default: 'default', fieldName: col('namespace') },\n // Which library/module registered the workflow this run belongs to (e.g.\n // `@dudousxd/nestjs-catalog-pipeline`), derived at registration time — never caller input.\n //\n // NULLABLE WITH NO DEFAULT, deliberately unlike `namespace` above. `namespace` can honestly\n // default a pre-existing row to `'default'` (that IS the namespace an unscoped engine ran it\n // in); an origin cannot be reconstructed after the fact, so a row written before this column\n // existed must read back as `undefined` = \"unknown\". Stamping it `'app'`/`'unknown'` would be\n // indistinguishable from a real registration in the dashboard's facet — a wrong origin is worse\n // than an absent one. Two MikroORM specifics reinforce it: a `default` here would NOT be\n // back-filled onto existing rows anyway (the DDL default only applies to new inserts, and a\n // TypeScript field initialiser never runs for rows the ORM did not create), so a default would\n // buy nothing but a lie for future rows.\n //\n // No index, unlike `namespace`. That one is on the HOT path — every poll tick filters\n // `listPendingRuns`/`listDueTimers`/`listIncompleteRuns` by it, hence\n // `durable_workflow_runs_namespace_status_idx`. Nothing filters by `origin` except the\n // dashboard's `listRuns`, where it is ANDed with the `status`/`workflow` predicates that\n // `durable_workflow_runs_status_wake_at_idx` / `..._workflow_status_idx` already bound. If a\n // deployment ever makes origin-filtered listings hot, add the composite index in your own\n // migration rather than here.\n origin: { type: 'string', nullable: true, fieldName: col('origin') },\n createdAt: { type: 'Date', fieldName: col('createdAt') },\n updatedAt: { type: 'Date', fieldName: col('updatedAt') },\n },\n });\n\n const stepCheckpoints = new EntitySchema<StepCheckpointEntity>({\n class: StepCheckpointEntity,\n tableName: 'durable_step_checkpoints',\n repository: () => StepCheckpointRepository,\n properties: {\n runId: { type: 'string', primary: true, fieldName: col('runId') },\n seq: { type: 'integer', primary: true, fieldName: col('seq') },\n name: { type: 'string', fieldName: col('name') },\n kind: { type: 'string', fieldName: col('kind') },\n stepId: { type: 'string', fieldName: col('stepId') },\n status: { type: 'string', fieldName: col('status') },\n input: { type: 'json', nullable: true, fieldName: col('input') },\n output: { type: 'json', nullable: true, fieldName: col('output') },\n error: { type: 'json', nullable: true, fieldName: col('error') },\n events: { type: 'json', nullable: true, fieldName: col('events') },\n attempts: { type: 'integer', fieldName: col('attempts') },\n workerGroup: { type: 'string', nullable: true, fieldName: col('workerGroup') },\n // A ctx.gather/ctx.all fan tags every sibling step with the same group string so the dashboard\n // renders them as one \"ran in parallel\" group. The core engine sets it (incl. from a remote\n // worker's recordStep), but it was never persisted here — so the fan always rendered as N\n // sequential singles. Nullable: only fan-out steps carry it.\n parallelGroup: { type: 'string', nullable: true, fieldName: col('parallelGroup') },\n wakeAt: { type: 'Date', nullable: true, fieldName: col('wakeAt') },\n enqueuedAt: { type: 'Date', nullable: true, fieldName: col('enqueuedAt') },\n startedAt: { type: 'Date', fieldName: col('startedAt') },\n finishedAt: { type: 'Date', fieldName: col('finishedAt') },\n },\n });\n\n const runAttributes = new EntitySchema<RunAttributeEntity>({\n class: RunAttributeEntity,\n tableName: 'durable_run_attributes',\n repository: () => RunAttributeRepository,\n // The search-attribute EXISTS join (see the class docstring) pushes equality/range predicates down\n // onto `(key, numValue)` / `(key, strValue)`; mirror the Prisma adapter so those scans stay indexed.\n indexes: [\n { name: 'durable_run_attributes_key_num_idx', properties: ['key', 'numValue'] },\n { name: 'durable_run_attributes_key_str_idx', properties: ['key', 'strValue'] },\n ],\n properties: {\n runId: { type: 'string', primary: true, fieldName: col('runId') },\n key: { type: 'string', primary: true, fieldName: col('key') },\n strValue: { type: 'string', nullable: true, fieldName: col('strValue') },\n // `float`/`double` is portable across SQLite/MySQL/Postgres for numeric range scans.\n numValue: { type: 'float', nullable: true, fieldName: col('numValue') },\n },\n });\n\n const signalWaiters = new EntitySchema<SignalWaiterEntity>({\n class: SignalWaiterEntity,\n tableName: 'durable_signal_waiters',\n repository: () => SignalWaiterRepository,\n properties: {\n token: { type: 'string', primary: true, fieldName: col('token') },\n runId: { type: 'string', fieldName: col('runId') },\n seq: { type: 'integer', fieldName: col('seq') },\n // A ctx.gather_children/ctx.all child fan-out tags every awaited child with the same group; the\n // engine threads it onto the waiter so the resolving `signal:child:` checkpoint carries it and the\n // dashboard renders the fan as one parallel group. Nullable: only fan-out child waiters carry it.\n parallelGroup: { type: 'string', nullable: true, fieldName: col('parallelGroup') },\n },\n });\n\n const bufferedSignals = new EntitySchema<BufferedSignalEntity>({\n class: BufferedSignalEntity,\n tableName: 'durable_buffered_signals',\n repository: () => BufferedSignalRepository,\n properties: {\n id: { type: 'integer', primary: true, autoincrement: true, fieldName: col('id') },\n token: { type: 'string', index: true, fieldName: col('token') },\n payload: { type: 'json', nullable: true, fieldName: col('payload') },\n },\n });\n\n const bufferedEvents = new EntitySchema<BufferedEventEntity>({\n class: BufferedEventEntity,\n tableName: 'durable_buffered_events',\n repository: () => BufferedEventRepository,\n // `(name, publishedAt)` serves both `listBufferedEvents`'s name-scoped scan and its oldest-first\n // ordering in one index.\n indexes: [\n {\n name: 'durable_buffered_events_name_published_at_idx',\n properties: ['name', 'publishedAt'],\n },\n ],\n properties: {\n // Caller-minted uuid (engine.publishEvent), not autoincrement — removeBufferedEvent targets it\n // directly and needs to be handed the SAME id it was buffered with.\n id: { type: 'string', primary: true, fieldName: col('id') },\n name: { type: 'string', fieldName: col('name') },\n payload: { type: 'json', nullable: true, fieldName: col('payload') },\n publishedAt: { type: 'Date', fieldName: col('publishedAt') },\n },\n });\n\n return [\n workflowRuns,\n stepCheckpoints,\n runAttributes,\n signalWaiters,\n bufferedSignals,\n bufferedEvents,\n ];\n}\n\n/** Durable entity schemas with the canonical `'snake_case'` column names. */\nexport const ENTITIES = durableEntities();\n","import { EntityRepository } from '@mikro-orm/core';\nimport type {\n BufferedEventEntity,\n BufferedSignalEntity,\n RunAttributeEntity,\n SignalWaiterEntity,\n StepCheckpointEntity,\n WorkflowRunEntity,\n} from './entities';\n\n/**\n * Custom repositories for the durable entities, so a host app can `@InjectRepository`/inject a\n * `WorkflowRunRepository` by type instead of repeating `em.find(WorkflowRunEntity, …)` with the\n * entity class as the first argument everywhere.\n *\n * They are wired per-schema inside `durableEntities()` (not with a decorator), because that factory\n * can be called more than once with different column naming and each call must produce schemas that\n * still point at these classes. Each entity also declares `[EntityRepositoryType]`, which is what\n * makes `em.getRepository(WorkflowRunEntity)` resolve to the specific type rather than the base\n * `EntityRepository`.\n *\n * The bodies are intentionally empty: the durable engine's own queries go through\n * `MikroOrmStateStore`, and a durable-owned query added here would be a second, unversioned read\n * path over the same tables. They exist as an injectable, correctly-typed handle for host code.\n */\nexport class WorkflowRunRepository extends EntityRepository<WorkflowRunEntity> {}\n\nexport class StepCheckpointRepository extends EntityRepository<StepCheckpointEntity> {}\n\nexport class RunAttributeRepository extends EntityRepository<RunAttributeEntity> {}\n\nexport class SignalWaiterRepository extends EntityRepository<SignalWaiterEntity> {}\n\nexport class BufferedSignalRepository extends EntityRepository<BufferedSignalEntity> {}\n\nexport class BufferedEventRepository extends EntityRepository<BufferedEventEntity> {}\n","import {\n type AttributeFilter,\n type RetentionPolicy,\n type RunFacetQuery,\n type RunFacetRow,\n type RunQuery,\n type RunStatus,\n type SignalWaiter,\n type StateStore,\n type StepCheckpoint,\n type StepError,\n type StepEvent,\n type WorkflowRun,\n attributeColumnFor,\n attributeOperand,\n mergeRunFacetRows,\n normalizeAttributeRows,\n parseDuration,\n sqlComparator,\n} from '@dudousxd/nestjs-durable-core';\nimport { raw } from '@mikro-orm/core';\nimport type { EntityManager, MikroORM } from '@mikro-orm/core';\n\n/** Minimal structural surface of the SQL EntityManager's QueryBuilder (from `@mikro-orm/knex`),\n * typed here so the adapter needn't add a hard dependency on the knex types — a real SQL-driver EM\n * satisfies it at runtime. */\ninterface DurableQueryBuilder<T> {\n where(cond: Record<string, unknown>): DurableQueryBuilder<T>;\n andWhere(cond: string): DurableQueryBuilder<T>;\n orderBy(cond: Record<string, unknown>): DurableQueryBuilder<T>;\n limit(n: number): DurableQueryBuilder<T>;\n offset(n: number): DurableQueryBuilder<T>;\n getResultList(): Promise<T[]>;\n // Aggregate verbs — used only by `runFacets`' GROUP BY, which returns raw rows rather than entities.\n // `addSelect` takes `unknown` because the count is a `raw()` expression, not a field name: passing\n // it as a string makes the builder qualify it with the root alias (`r.count(*)`), which is not a\n // column and fails on every engine.\n select(fields: string[]): DurableQueryBuilder<T>;\n addSelect(field: unknown): DurableQueryBuilder<T>;\n groupBy(fields: string[]): DurableQueryBuilder<T>;\n execute<R>(): Promise<R>;\n}\ntype SqlEm = EntityManager & {\n createQueryBuilder<T>(entity: unknown, alias: string): DurableQueryBuilder<T>;\n};\n\n/** Resolved side-table column names (per the active naming strategy) for the raw EXISTS pushdown. */\ninterface AttributeColumns {\n table: string;\n /** Side-table FK column (the run id on `durable_run_attributes`). */\n runId: string;\n /** Run table PK column (the `id` on `durable_workflow_runs`) used for the outer correlation. */\n runPk: string;\n key: string;\n strValue: string;\n numValue: string;\n}\nimport {\n BufferedEventEntity,\n BufferedSignalEntity,\n RunAttributeEntity,\n SignalWaiterEntity,\n StepCheckpointEntity,\n WorkflowRunEntity,\n} from './entities';\nimport { ensureMikroOrmDurableSchema } from './schema';\n\n/** Options for scoping a `MikroOrmStateStore` to a single tenant namespace. */\nexport interface MikroOrmStateStoreOptions {\n /**\n * When set, every forked `EntityManager` activates the `namespace` global filter with this value,\n * so reads are confined to the given tenant's rows. Omit (or pass `undefined`) for the operator\n * (control-plane) view that sees all namespaces.\n */\n scope?: {\n namespace?: string;\n };\n}\n\n/**\n * MikroORM-backed `StateStore`. Works on any MikroORM driver — Postgres, MySQL, SQLite (tested);\n * timestamps and `wakeAt` use native datetime columns. Each operation runs on a forked\n * EntityManager so it owns its unit of work.\n *\n * Pass `opts.scope.namespace` to confine all reads to a single tenant namespace. Omit for the\n * unscoped operator view (control plane — all namespaces visible).\n */\nexport class MikroOrmStateStore implements StateStore {\n private readonly scopeNamespace: string | undefined;\n\n constructor(\n private readonly orm: MikroORM,\n opts?: MikroOrmStateStoreOptions,\n ) {\n this.scopeNamespace = opts?.scope?.namespace;\n }\n\n /**\n * Derive a store confined to a single tenant `scope.namespace`, sharing this store's ORM (no new\n * connection). Turns the operator (unscoped) store into a tenant-boundary view at wiring time —\n * used by the NestJS module's `scopeReads` option, which receives a pre-built store and can't\n * reconstruct it. Pass `{ namespace: undefined }` for the unscoped operator view.\n */\n withScope(scope: { namespace?: string }): MikroOrmStateStore {\n return new MikroOrmStateStore(this.orm, { scope });\n }\n\n /**\n * Create a forked EntityManager and activate the `namespace` global filter with the store's\n * scope (if any). All read operations go through this so the tenant boundary is applied\n * uniformly. Write operations (nativeDelete, nativeUpdate, upsert, insertMany) bypass global\n * filters in MikroORM and are unaffected.\n */\n private fork() {\n const em = this.orm.em.fork();\n em.setFilterParams('namespace', { namespace: this.scopeNamespace });\n return em;\n }\n\n async ensureSchema(): Promise<void> {\n await ensureMikroOrmDurableSchema(this.orm);\n }\n\n async createRun(run: WorkflowRun): Promise<void> {\n const em = this.fork();\n em.create(WorkflowRunEntity, toRunEntity(run));\n await em.flush();\n await this.reindexAttributes(run.id, run.searchAttributes);\n }\n\n async updateRun(runId: string, patch: Partial<WorkflowRun>): Promise<void> {\n const em = this.fork();\n const entity = await em.findOneOrFail(WorkflowRunEntity, { id: runId });\n Object.assign(entity, toRunEntity({ ...fromRunEntity(entity), ...patch } as WorkflowRun));\n await em.flush();\n // Keep the side-table in step with the run's attributes whenever they're patched.\n if ('searchAttributes' in patch) await this.reindexAttributes(runId, patch.searchAttributes);\n }\n\n /** Rewrite a run's normalized attribute rows: delete the old set, insert the current one. Mirrors\n * the in-memory store's reindex so the side-table always reflects the run's live searchAttributes. */\n private async reindexAttributes(\n runId: string,\n attributes: WorkflowRun['searchAttributes'],\n forked?: EntityManager,\n ): Promise<void> {\n const em = forked ?? this.fork();\n await em.nativeDelete(RunAttributeEntity, { runId });\n const rows = normalizeAttributeRows(runId, attributes);\n if (rows.length) await em.insertMany(RunAttributeEntity, rows);\n }\n\n async getRun(runId: string): Promise<WorkflowRun | null> {\n const em = this.fork();\n const entity = await em.findOne(WorkflowRunEntity, { id: runId });\n return entity ? fromRunEntity(entity) : null;\n }\n\n async deleteRun(runId: string): Promise<void> {\n const em = this.fork();\n // Children first, then the run row — checkpoints, signal waiters, and the normalized\n // attribute side-table, so nothing dangles after the run is gone.\n await em.nativeDelete(StepCheckpointEntity, { runId });\n await em.nativeDelete(SignalWaiterEntity, { runId });\n await em.nativeDelete(RunAttributeEntity, { runId });\n await em.nativeDelete(WorkflowRunEntity, { id: runId });\n }\n\n async pruneTerminalRuns(policy: RetentionPolicy, nowMs: number, limit: number): Promise<number> {\n if (policy.statuses.length === 0 || limit <= 0) return 0;\n const em = this.fork();\n const status = { $in: policy.statuses };\n // Collect ids that violate EITHER bound (most-restrictive keep): too old, or past the count cap.\n const ids = new Set<string>();\n\n if (policy.maxAge != null) {\n const cutoff = new Date(nowMs - parseDuration(policy.maxAge));\n const rows = await em.find(\n WorkflowRunEntity,\n { status, updatedAt: { $lt: cutoff } },\n { fields: ['id'], orderBy: { updatedAt: 'asc' }, limit }, // oldest first\n );\n for (const r of rows) ids.add(r.id);\n }\n\n if (policy.maxCount != null && ids.size < limit) {\n // Everything beyond the newest `maxCount` rows in the status set — skip the kept window via offset.\n const rows = await em.find(\n WorkflowRunEntity,\n { status },\n {\n fields: ['id'],\n orderBy: { updatedAt: 'desc', id: 'desc' },\n limit,\n offset: policy.maxCount,\n },\n );\n for (const r of rows) {\n ids.add(r.id);\n if (ids.size >= limit) break;\n }\n }\n\n if (ids.size === 0) return 0;\n const idList = [...ids].slice(0, limit);\n const runId = { $in: idList };\n // Cascade children then runs (mirrors deleteRun) in one transaction so a pruned run never dangles.\n await em.transactional(async (tem) => {\n await tem.nativeDelete(StepCheckpointEntity, { runId });\n await tem.nativeDelete(SignalWaiterEntity, { runId });\n await tem.nativeDelete(RunAttributeEntity, { runId });\n await tem.nativeDelete(WorkflowRunEntity, { id: runId });\n });\n return idList.length;\n }\n\n async getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null> {\n const em = this.fork();\n const entity = await em.findOne(StepCheckpointEntity, { runId, seq });\n return entity ? fromCheckpointEntity(entity) : null;\n }\n\n async saveCheckpoint(checkpoint: StepCheckpoint): Promise<void> {\n const em = this.fork();\n await em.upsert(StepCheckpointEntity, toCheckpointEntity(checkpoint));\n await em.flush();\n }\n\n async transaction<T>(\n work: (tx: {\n raw: unknown;\n saveCheckpoint: (cp: StepCheckpoint) => Promise<void>;\n }) => Promise<T>,\n ): Promise<T> {\n return this.fork().transactional(async (em) =>\n work({\n raw: em,\n saveCheckpoint: async (cp) => {\n await em.upsert(StepCheckpointEntity, toCheckpointEntity(cp));\n },\n }),\n );\n }\n\n async listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]> {\n const em = this.fork();\n const rows = await em.find(WorkflowRunEntity, {\n status: { $in: ['running', 'cancelling'] },\n ...(namespace !== undefined ? { namespace } : {}),\n });\n return rows.map(fromRunEntity);\n }\n\n async listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]> {\n const em = this.fork();\n const rows = await em.find(\n WorkflowRunEntity,\n { status: 'pending', ...(namespace !== undefined ? { namespace } : {}) },\n { orderBy: { createdAt: 'asc' }, limit }, // FIFO dispatch\n );\n return rows.map(fromRunEntity);\n }\n\n async listDueTimers(nowMs: number, namespace?: string): Promise<WorkflowRun[]> {\n const em = this.fork();\n const rows = await em.find(WorkflowRunEntity, {\n status: 'suspended',\n wakeAt: { $ne: null, $lte: new Date(nowMs) },\n ...(namespace !== undefined ? { namespace } : {}),\n });\n return rows.map(fromRunEntity);\n }\n\n async tryLockRun(\n runId: string,\n owner: string,\n leaseUntilMs: number,\n nowMs: number,\n ): Promise<boolean> {\n const em = this.fork();\n const affected = await em.nativeUpdate(\n WorkflowRunEntity,\n { id: runId, $or: [{ lockedUntil: null }, { lockedUntil: { $lte: new Date(nowMs) } }] },\n { lockedBy: owner, lockedUntil: new Date(leaseUntilMs) },\n );\n return affected === 1;\n }\n\n async releaseRunLock(runId: string): Promise<void> {\n const em = this.fork();\n await em.nativeUpdate(WorkflowRunEntity, { id: runId }, { lockedBy: null, lockedUntil: null });\n }\n\n async renewRunLock(runId: string, owner: string, leaseUntilMs: number): Promise<boolean> {\n const em = this.fork();\n const affected = await em.nativeUpdate(\n WorkflowRunEntity,\n { id: runId, lockedBy: owner },\n { lockedUntil: new Date(leaseUntilMs) },\n );\n return affected === 1;\n }\n\n /** The `where` every run query shares — {@link listRuns} pages it, {@link runFacets} groups it.\n * Only the predicates MikroORM can express declaratively; `tag`/`attributes` need raw SQL and are\n * applied by the QueryBuilder path in both callers. */\n private runWhere(query: RunQuery): Record<string, unknown> {\n const where: Record<string, unknown> = {};\n if (query.workflow) where.workflow = query.workflow;\n if (query.namespace !== undefined) where.namespace = query.namespace;\n // Plain equality on the origin column, exactly like `namespace` above. A run whose origin is NULL\n // (created before the column existed, or registered through a path the derivation could not\n // classify) matches NO origin value — it is never folded into some bucket to make the facet look\n // complete. Passing `null` asks for exactly that bucket (`origin IS NULL`), which is how a\n // paginated console offers an \"unknown\" chip without holding every run in the browser.\n if (query.origin !== undefined) where.origin = query.origin;\n // `status IN (...)`; an empty set matches nothing (mirrors the in-memory store). When both the\n // single `status` and `statuses` are set, AND them so the narrower set wins.\n if (query.status && query.statuses) {\n where.$and = [{ status: query.status }, { status: { $in: query.statuses } }];\n } else if (query.status) {\n where.status = query.status;\n } else if (query.statuses) {\n where.status = { $in: query.statuses };\n }\n return where;\n }\n\n async listRuns(query: RunQuery): Promise<WorkflowRun[]> {\n const em = this.fork();\n const where = this.runWhere(query);\n const orderBy = { createdAt: 'desc' as const }; // newest first — recent runs on top in the dashboard\n // `tags`/attributes need raw SQL pushed through the QueryBuilder:\n // - tag: `tags` is a JSON column (native json/jsonb on PG/MySQL), and MikroORM JSON-serializes a\n // `{ $like }` operand (wrapping/escaping the LIKE pattern) so a plain where corrupts it to no\n // matches. A raw LIKE on the column-as-text matches the quoted token so `etl` doesn't match\n // `etl-foo`. Postgres `jsonb` rejects `LIKE` directly, so cast to text per dialect.\n // - attributes: each filter becomes a raw EXISTS against the normalized side-table, so the DB\n // filters AND paginates — no full scan + in-process filter (ANDed: one EXISTS per filter).\n // Use a QueryBuilder with a fixed root alias `r` so the raw correlations are stable across drivers.\n if (query.tag || query.attributes?.length) {\n const qb = this.runQueryBuilder(em, query, where).orderBy(orderBy);\n if (query.limit != null) qb.limit(query.limit);\n if (query.offset != null) qb.offset(query.offset);\n const rows = await qb.getResultList();\n return rows.map(fromRunEntity);\n }\n const rows = await em.find(WorkflowRunEntity, where, {\n ...(query.limit != null ? { limit: query.limit } : {}),\n ...(query.offset != null ? { offset: query.offset } : {}),\n orderBy,\n });\n return rows.map(fromRunEntity);\n }\n\n /** A QueryBuilder over `durable_workflow_runs` (root alias `r`) carrying `where` plus the two\n * predicates only raw SQL can express — the `tag` JSON LIKE and one EXISTS per attribute filter.\n * Shared so a facet count and the page it labels are taken over the SAME set. */\n private runQueryBuilder(\n em: EntityManager,\n query: RunQuery,\n where: Record<string, unknown>,\n ): DurableQueryBuilder<WorkflowRunEntity> {\n // MikroORM global filters do not auto-apply to createQueryBuilder, so enforce the scope here\n // explicitly. Mirrors the filter cond's semantics: undefined = no restriction (operator view).\n if (this.scopeNamespace !== undefined) where.namespace = this.scopeNamespace;\n const quote = this.idQuote(em);\n const cols = this.attributeColumns(em);\n const qb = (em as SqlEm)\n .createQueryBuilder<WorkflowRunEntity>(WorkflowRunEntity, 'r')\n .where(where);\n if (query.tag) {\n const tagsCol = this.tagsColumn(em);\n const pattern = `%\"${query.tag.replace(/'/g, \"''\")}\"%`;\n const colExpr = this.jsonAsText(em, `${quote('r')}.${quote(tagsCol)}`);\n qb.andWhere(`${colExpr} LIKE '${pattern}'`);\n }\n for (const f of query.attributes ?? []) {\n qb.andWhere(this.attributeExistsSql(f, quote, 'r', cols));\n }\n return qb;\n }\n\n /** `GROUP BY status, origin` over the same predicates {@link listRuns} pages — one aggregate, so a\n * console can show whole-set counts next to a bounded page instead of downloading every run to\n * count them in the browser. */\n async runFacets(query: RunFacetQuery): Promise<RunFacetRow[]> {\n const em = this.fork();\n const meta = em.getMetadata().get(WorkflowRunEntity);\n const statusCol = meta.properties.status?.fieldNames?.[0] ?? 'status';\n const originCol = meta.properties.origin?.fieldNames?.[0] ?? 'origin';\n const rows = await this.runQueryBuilder(em, query, this.runWhere(query))\n .select([`r.${statusCol}`, `r.${originCol}`])\n .addSelect(raw('count(*) as count'))\n .groupBy([`r.${statusCol}`, `r.${originCol}`])\n .execute<{ status: RunStatus; origin: string | null; count: number | string }[]>();\n // MySQL returns `count(*)` as a string on some drivers; normalise before merging.\n return mergeRunFacetRows(rows.map((r) => ({ ...r, count: Number(r.count) })));\n }\n\n /** One attribute predicate as a raw EXISTS subquery on the side-table, correlated to the outer run\n * alias. `<>` (ne) also excludes runs where the attribute is absent (missing-key-never-matches):\n * EXISTS already requires a present row, so EXISTS(... <> ...) is exactly ne-with-present. Numeric\n * operands compare the num column, everything else the str column. Identifiers are quoted per\n * driver and operands are inlined as literals (string operands are escaped by doubling quotes). */\n private attributeExistsSql(\n f: AttributeFilter,\n quote: (id: string) => string,\n alias: string,\n cols: AttributeColumns,\n ): string {\n const col = attributeColumnFor(f) === 'numValue' ? cols.numValue : cols.strValue;\n const cmp = sqlComparator(f.op);\n const operand = attributeOperand(f);\n const literal =\n typeof operand === 'number' ? String(operand) : `'${String(operand).replace(/'/g, \"''\")}'`;\n const a = quote(cols.table);\n const sub = quote('a');\n const outerId = `${quote(alias)}.${quote(cols.runPk)}`; // run PK column on the outer alias\n return `EXISTS (SELECT 1 FROM ${a} ${sub} WHERE ${sub}.${quote(cols.runId)} = ${outerId} AND ${sub}.${quote(cols.key)} = '${f.key.replace(/'/g, \"''\")}' AND ${sub}.${quote(col)} ${cmp} ${literal})`;\n }\n\n /** Resolve the side-table's actual column names from MikroORM metadata, so the raw EXISTS matches\n * the active naming strategy (underscore vs camelCase) rather than guessing. The run PK column is\n * reused for BOTH the outer correlation and the side-table FK (they share the same fieldName). */\n private attributeColumns(em: EntityManager): AttributeColumns {\n const meta = em.getMetadata().get(RunAttributeEntity);\n const field = (prop: string) =>\n meta.props.find((p) => p.name === prop)?.fieldNames?.[0] ?? prop;\n const runMeta = em.getMetadata().get(WorkflowRunEntity);\n const runPk = runMeta.properties.id?.fieldNames?.[0] ?? 'id';\n return {\n table: meta.tableName,\n runId: field('runId'),\n runPk,\n key: field('key'),\n strValue: field('strValue'),\n numValue: field('numValue'),\n };\n }\n\n /** Resolve the `tags` column name from metadata (per the active naming strategy), for the raw LIKE. */\n private tagsColumn(em: EntityManager): string {\n const runMeta = em.getMetadata().get(WorkflowRunEntity);\n return runMeta.properties.tags?.fieldNames?.[0] ?? 'tags';\n }\n\n /** Wrap a JSON column reference so it can be `LIKE`d as text. Postgres `jsonb`/`json` rejects `LIKE`\n * directly (`operator does not exist: jsonb ~~ unknown`) — cast to `text`; MySQL JSON needs an\n * explicit `CHAR` cast; SQLite stores JSON as text already, so no cast. */\n private jsonAsText(em: EntityManager, colRef: string): string {\n const platform = String(em.getPlatform().constructor.name).toLowerCase();\n if (platform.includes('postgre')) return `${colRef}::text`;\n if (platform.includes('mysql') || platform.includes('mariadb'))\n return `CAST(${colRef} AS CHAR)`;\n return colRef;\n }\n\n /** Quote an identifier per the active SQL driver (MySQL/MariaDB backtick, others double-quote). */\n private idQuote(em: EntityManager): (id: string) => string {\n const platform = String(em.getPlatform().constructor.name).toLowerCase();\n const isMysql = platform.includes('mysql') || platform.includes('mariadb');\n const ch = isMysql ? '`' : '\"';\n return (id: string) => `${ch}${id}${ch}`;\n }\n\n async listCheckpoints(runId: string): Promise<StepCheckpoint[]> {\n const em = this.fork();\n const rows = await em.find(StepCheckpointEntity, { runId }, { orderBy: { seq: 'asc' } });\n return rows.map(fromCheckpointEntity);\n }\n\n async getLatestCheckpointByName(\n runId: string,\n name: string,\n ): Promise<StepCheckpoint | undefined> {\n const em = this.fork();\n const entity = await em.findOne(\n StepCheckpointEntity,\n { runId, name },\n { orderBy: { seq: 'desc' } },\n );\n return entity ? fromCheckpointEntity(entity) : undefined;\n }\n\n async listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]> {\n if (prefixes.length === 0) return [];\n const em = this.fork();\n const rows = await em.find(\n StepCheckpointEntity,\n { runId, $or: prefixes.map((p) => ({ name: { $like: `${p}%` } })) },\n { orderBy: { seq: 'asc' } },\n );\n return rows.map(fromCheckpointEntity);\n }\n\n async putSignalWaiter(waiter: SignalWaiter): Promise<void> {\n const em = this.fork();\n await em.upsert(SignalWaiterEntity, {\n token: waiter.token,\n runId: waiter.runId,\n seq: waiter.seq,\n parallelGroup: waiter.parallelGroup ?? null,\n });\n await em.flush();\n }\n\n async takeSignalWaiter(token: string): Promise<SignalWaiter | null> {\n const em = this.fork();\n const entity = await em.findOne(SignalWaiterEntity, { token });\n if (!entity) return null;\n const waiter: SignalWaiter = {\n token: entity.token,\n runId: entity.runId,\n seq: entity.seq,\n parallelGroup: entity.parallelGroup ?? undefined,\n };\n await em.remove(entity).flush();\n return waiter;\n }\n\n async listSignalWaiters(prefix: string): Promise<SignalWaiter[]> {\n const em = this.fork();\n const rows = await em.find(SignalWaiterEntity, { token: { $like: `${prefix}%` } });\n return rows.map((e) => ({\n token: e.token,\n runId: e.runId,\n seq: e.seq,\n parallelGroup: e.parallelGroup ?? undefined,\n }));\n }\n\n async removeSignalWaiter(waiter: SignalWaiter): Promise<void> {\n const em = this.fork();\n // Exact-match delete (token AND runId AND seq) — deleting by `token` alone would remove whatever\n // row currently owns it, even if a different run has since claimed the same token.\n await em.nativeDelete(SignalWaiterEntity, {\n token: waiter.token,\n runId: waiter.runId,\n seq: waiter.seq,\n });\n }\n\n async bufferSignal(token: string, payload: unknown): Promise<void> {\n const em = this.fork();\n const e = new BufferedSignalEntity();\n e.token = token;\n e.payload = payload ?? null;\n em.persist(e);\n await em.flush();\n }\n\n async takeBufferedSignal(token: string): Promise<{ payload: unknown } | null> {\n const em = this.fork();\n const entity = await em.findOne(BufferedSignalEntity, { token }, { orderBy: { id: 'asc' } });\n if (!entity) return null;\n const payload = entity.payload ?? undefined;\n await em.remove(entity).flush();\n return { payload };\n }\n\n async bufferEvent(input: {\n name: string;\n payload: unknown;\n id: string;\n publishedAt: number;\n }): Promise<void> {\n const em = this.fork();\n const e = new BufferedEventEntity();\n e.id = input.id;\n e.name = input.name;\n e.payload = input.payload ?? null;\n e.publishedAt = new Date(input.publishedAt);\n em.persist(e);\n await em.flush();\n }\n\n async listBufferedEvents(\n name: string,\n limit: number,\n ): Promise<Array<{ id: string; payload: unknown; publishedAt: number }>> {\n const em = this.fork();\n const rows = await em.find(\n BufferedEventEntity,\n { name },\n { orderBy: { publishedAt: 'asc' }, limit }, // oldest first\n );\n return rows.map((e) => ({\n id: e.id,\n payload: e.payload ?? undefined,\n publishedAt: e.publishedAt.getTime(),\n }));\n }\n\n async removeBufferedEvent(id: string): Promise<boolean> {\n const em = this.fork();\n const affected = await em.nativeDelete(BufferedEventEntity, { id });\n return affected > 0;\n }\n}\n\nfunction toRunEntity(run: WorkflowRun): WorkflowRunEntity {\n const e = new WorkflowRunEntity();\n e.id = run.id;\n e.workflow = run.workflow;\n e.workflowVersion = run.workflowVersion;\n e.status = run.status;\n e.input = run.input ?? null;\n e.output = run.output ?? null;\n e.error = run.error ?? null;\n if (run.wakeAt != null) e.wakeAt = new Date(run.wakeAt);\n if (run.lockedBy !== undefined) e.lockedBy = run.lockedBy;\n if (run.lockedUntil != null) e.lockedUntil = new Date(run.lockedUntil);\n // Mirror lockedBy: leave the fresh entity's own-`undefined` field untouched when the patch clears\n // the marker, so Object.assign(entity, e) writes NULL (the engine clears it when a decision lands).\n if (run.awaitingDecisionTaskId !== undefined)\n e.awaitingDecisionTaskId = run.awaitingDecisionTaskId;\n if (run.recoveryAttempts !== undefined) e.recoveryAttempts = run.recoveryAttempts;\n e.tags = run.tags ?? null;\n e.searchAttributes = run.searchAttributes ?? null;\n e.priority = run.priority ?? null;\n e.namespace = run.namespace ?? 'default';\n // NOT `?? 'default'` like the line above: an absent origin is genuinely UNKNOWN and must stay NULL\n // (see the column's docblock in ./entities). `null` — not left-undefined — so `Object.assign` in\n // updateRun writes SQL NULL rather than skipping the column.\n e.origin = run.origin ?? null;\n e.createdAt = run.createdAt;\n e.updatedAt = run.updatedAt;\n return e;\n}\n\nfunction fromRunEntity(e: WorkflowRunEntity): WorkflowRun {\n return {\n id: e.id,\n workflow: e.workflow,\n workflowVersion: e.workflowVersion,\n status: e.status,\n input: e.input ?? undefined,\n output: e.output ?? undefined,\n error: (e.error ?? undefined) as StepError | undefined,\n wakeAt: e.wakeAt?.getTime(),\n lockedBy: e.lockedBy ?? undefined,\n lockedUntil: e.lockedUntil?.getTime(),\n awaitingDecisionTaskId: e.awaitingDecisionTaskId ?? undefined,\n recoveryAttempts: e.recoveryAttempts ?? undefined,\n tags: e.tags ?? undefined,\n searchAttributes: e.searchAttributes ?? undefined,\n priority: e.priority ?? undefined,\n namespace: e.namespace,\n // NULL (a row written before the column existed) surfaces as `undefined` = unknown origin.\n origin: e.origin ?? undefined,\n createdAt: e.createdAt,\n updatedAt: e.updatedAt,\n };\n}\n\nfunction toCheckpointEntity(cp: StepCheckpoint): StepCheckpointEntity {\n const e = new StepCheckpointEntity();\n e.runId = cp.runId;\n e.seq = cp.seq;\n e.name = cp.name;\n e.kind = cp.kind;\n e.stepId = cp.stepId;\n e.status = cp.status;\n e.input = cp.input ?? null;\n e.output = cp.output ?? null;\n e.error = cp.error ?? null;\n e.events = cp.events ?? null;\n e.attempts = cp.attempts;\n if (cp.workerGroup !== undefined) e.workerGroup = cp.workerGroup;\n if (cp.parallelGroup !== undefined) e.parallelGroup = cp.parallelGroup;\n if (cp.wakeAt != null) e.wakeAt = new Date(cp.wakeAt);\n e.enqueuedAt = cp.enqueuedAt;\n e.startedAt = cp.startedAt;\n e.finishedAt = cp.finishedAt;\n return e;\n}\n\nfunction fromCheckpointEntity(e: StepCheckpointEntity): StepCheckpoint {\n return {\n runId: e.runId,\n seq: e.seq,\n name: e.name,\n kind: e.kind,\n stepId: e.stepId,\n status: e.status,\n input: e.input ?? undefined,\n output: e.output ?? undefined,\n error: (e.error ?? undefined) as StepError | undefined,\n events: (e.events ?? undefined) as StepEvent[] | undefined,\n attempts: e.attempts,\n workerGroup: e.workerGroup ?? undefined,\n parallelGroup: e.parallelGroup ?? undefined,\n wakeAt: e.wakeAt?.getTime(),\n enqueuedAt: e.enqueuedAt ?? e.startedAt,\n startedAt: e.startedAt,\n finishedAt: e.finishedAt,\n };\n}\n","import { createHash } from 'node:crypto';\nimport type { MikroORM } from '@mikro-orm/core';\n\n/**\n * The tables this store owns. Kept in sync with the `tableName`s in `./entities`. Used to scope\n * schema management to our own tables (see {@link ensureMikroOrmDurableSchema}).\n */\nconst DURABLE_TABLE_NAMES = new Set([\n 'durable_workflow_runs',\n 'durable_step_checkpoints',\n 'durable_run_attributes',\n 'durable_signal_waiters',\n 'durable_buffered_signals',\n 'durable_buffered_events',\n]);\n\n/**\n * Tables this store creates and manages at boot (autoSchema). Feed to your ORM's migration differ\n * exclude/skipTables so it never tries to drop them.\n *\n * ```ts\n * await MikroORM.init({\n * // ...your entities/driver config\n * schemaGenerator: { skipTables: durableManagedTables() },\n * });\n * ```\n *\n * Derived from the same {@link DURABLE_TABLE_NAMES} set `ensureMikroOrmDurableSchema` scopes its own\n * heal to — one list, so a consumer's denylist can never drift from what this store actually owns.\n */\nexport function durableManagedTables(): string[] {\n return [...DURABLE_TABLE_NAMES];\n}\n\n/**\n * Marker table that records the fingerprint of the durable schema last applied to this database. A\n * single row (`id = 'durable'`) lets every boot decide — with two cheap round-trips — whether the\n * durable tables already match the entity metadata, so steady-state boots skip the expensive\n * whole-app introspection (`getUpdateSchemaSQL`) and per-table collation probes entirely.\n */\nconst MARKER_TABLE = 'durable_schema_meta';\nconst MARKER_ROW_ID = 'durable';\n\n/** The advisory-lock name used to serialize the heal across pods (MySQL `GET_LOCK` / PG advisory). */\nconst SCHEMA_LOCK_NAME = 'durable_schema';\n\n/**\n * Hand-bump escape hatch for DDL changes that are NOT visible in the entity metadata and so wouldn't\n * change the computed fingerprint on their own — e.g. the collation-alignment logic in\n * {@link alignDurableCollation}, or a change to the heal's filtering. Bumping this value changes every\n * computed fingerprint, which forces a one-time re-heal on the next boot of every pod against every\n * database (the stored marker no longer matches), then settles back to the cheap steady-state path.\n */\nconst SCHEMA_REVISION = 1;\n\n/** A JSON value the canonical serializer understands. No `any`: the fingerprint input is plain data. */\ntype JsonScalar = string | number | boolean | null;\ntype JsonValue = JsonScalar | JsonValue[] | { [key: string]: JsonValue };\n\n/** The SQL dialect, derived from the ORM platform, used to branch the lock + marker-table DDL/upsert. */\ntype SqlDialect = 'mysql' | 'postgres' | 'sqlite' | 'unknown';\n\n/** Stable string compare (locale-independent) so sorted serializations are deterministic. */\nfunction compareStrings(a: string, b: string): number {\n return a < b ? -1 : a > b ? 1 : 0;\n}\n\n/**\n * The table a DDL statement targets, lower-cased; undefined otherwise. Recognizes `create table` /\n * `alter table` (the table name follows immediately) and standalone `create [unique] index ... on\n * <table>` (the table follows `on`). MikroORM adds an index to an EXISTING table as `alter table ...\n * add index` on MySQL but as a standalone `create index ... on ...` on Postgres/SQLite — without the\n * second form those index statements would be dropped by the durable-table filter and never applied.\n */\nfunction targetTable(statement: string): string | undefined {\n const match = statement.match(\n /^(?:create\\s+(?:unique\\s+)?index\\s+.+?\\s+on\\s+|(?:create|alter)\\s+table\\s+(?:if\\s+not\\s+exists\\s+)?)[`\"']?([\\w$]+)[`\"']?/i,\n );\n return match?.[1]?.toLowerCase();\n}\n\n/**\n * Whether a statement adds structure the store REQUIRES — a failure here is fatal (the store can't\n * run without the table/column/index). A column TYPE alignment (`modify`/`alter column ... type`)\n * is best-effort: the column already holds the data (the store serializes JSON to/from it regardless\n * of the declared type), so failing to converge its type — e.g. a legacy `longtext` value that won't\n * cast to `json` because it was truncated under an older `text` column — must NOT crash boot.\n */\nfunction isRequiredStructure(statement: string): boolean {\n return /\\b(?:create\\s+table|create\\s+(?:unique\\s+)?index|add\\s+(?:column|index|constraint|key|unique|fulltext))\\b/i.test(\n statement,\n );\n}\n\n/** Map the ORM's platform class name onto the dialect we branch lock + DDL syntax on. */\nfunction detectSqlDialect(orm: MikroORM): SqlDialect {\n const platform = String(orm.em.getPlatform().constructor.name).toLowerCase();\n if (platform.includes('mysql') || platform.includes('maria')) return 'mysql';\n if (platform.includes('postgre')) return 'postgres';\n if (platform.includes('sqlite') || platform.includes('libsql')) return 'sqlite';\n return 'unknown';\n}\n\n/** Normalize a MikroORM index `properties` value (string | string[] | undefined) to an array. */\nfunction normalizeIndexProperties(properties: string | string[] | undefined): string[] {\n if (properties === undefined) return [];\n if (Array.isArray(properties)) return properties.map((property) => String(property));\n return [String(properties)];\n}\n\n/**\n * A content fingerprint of the durable tables AS DESCRIBED BY THE ENTITY METADATA — pure, in-memory,\n * no database round-trip. Filters the ORM metadata to the tables this store owns, builds a CANONICAL\n * (sorted tables, sorted columns, sorted indexes, sorted object keys) serialization of each table's\n * structural shape, then appends the configured `collate` and {@link SCHEMA_REVISION} and hashes it.\n *\n * Object enumeration order is never trusted — every array is sorted and every object key is sorted by\n * the serializer — so the same metadata always yields the same hash regardless of declaration order.\n * A change to any column/index/type/nullability/default, the configured collation, or the revision\n * changes the hash, which is exactly when the stored marker should be considered stale and re-healed.\n */\nfunction computeExpectedFingerprint(orm: MikroORM, ownedTableNames: Set<string>): string {\n const ownedMetadata = [...orm.getMetadata().getAll().values()]\n .filter((meta) => ownedTableNames.has(meta.tableName))\n .sort((a, b) => compareStrings(a.tableName, b.tableName));\n\n const tables: JsonValue = ownedMetadata.map((meta) => {\n const columns: JsonValue = [...meta.props]\n .map((prop) => ({ prop, columnName: prop.fieldNames[0] ?? String(prop.name) }))\n .sort((a, b) => compareStrings(a.columnName, b.columnName))\n .map(({ prop, columnName }) => ({\n name: columnName,\n type: prop.columnTypes[0] ?? String(prop.type),\n nullable: prop.nullable === true,\n primary: prop.primary === true,\n default: prop.default ?? null,\n autoincrement: prop.autoincrement === true,\n }));\n\n const indexes: JsonValue = [...meta.indexes]\n .map((index) => ({\n name: index.name ?? '',\n properties: normalizeIndexProperties(index.properties),\n }))\n .sort((a, b) => compareStrings(a.name, b.name));\n\n return { tableName: meta.tableName, columns, indexes };\n });\n\n const canonical = `${canonicalize(tables)}|collate=${String(orm.config.get('collate') ?? '')}|rev=${SCHEMA_REVISION}`;\n return createHash('sha256').update(canonical).digest('hex');\n}\n\n/** Deterministic JSON: arrays keep order (already sorted by the caller); object keys are sorted. */\nfunction canonicalize(value: JsonValue): string {\n if (Array.isArray(value)) {\n return `[${value.map(canonicalize).join(',')}]`;\n }\n if (value !== null && typeof value === 'object') {\n const entries = Object.entries(value).sort(([a], [b]) => compareStrings(a, b));\n return `{${entries.map(([key, val]) => `${JSON.stringify(key)}:${canonicalize(val)}`).join(',')}}`;\n }\n return JSON.stringify(value);\n}\n\n/** `CREATE TABLE IF NOT EXISTS` for the marker — portable across MySQL/Postgres/SQLite, no introspection. */\nfunction createMarkerTableSql(): string {\n return `create table if not exists ${MARKER_TABLE} (id varchar(32) not null primary key, fingerprint varchar(64) not null, applied_at bigint not null)`;\n}\n\n/** Read the single marker row's fingerprint (one PK lookup), or undefined when the row is absent. */\nasync function readStoredFingerprint(orm: MikroORM): Promise<string | undefined> {\n const rows: Array<{ fingerprint?: string | null }> = await orm.em\n .getConnection()\n .execute(`select fingerprint from ${MARKER_TABLE} where id = ?`, [MARKER_ROW_ID]);\n return rows[0]?.fingerprint ?? undefined;\n}\n\n/** Upsert the marker row with the new fingerprint + apply time (epoch-ms bigint, driver-portable). */\nasync function writeFingerprint(\n orm: MikroORM,\n dialect: SqlDialect,\n fingerprint: string,\n): Promise<void> {\n const upsert =\n dialect === 'mysql'\n ? `insert into ${MARKER_TABLE} (id, fingerprint, applied_at) values (?, ?, ?) on duplicate key update fingerprint = values(fingerprint), applied_at = values(applied_at)`\n : `insert into ${MARKER_TABLE} (id, fingerprint, applied_at) values (?, ?, ?) on conflict (id) do update set fingerprint = excluded.fingerprint, applied_at = excluded.applied_at`;\n await orm.em.getConnection().execute(upsert, [MARKER_ROW_ID, fingerprint, Date.now()]);\n}\n\n/**\n * Best-effort cross-pod lock around the heal: MySQL `GET_LOCK`, Postgres `pg_advisory_lock`. Skipped\n * on SQLite/unknown drivers (single-writer / no portable advisory lock). A failure to acquire — lock\n * unsupported, timed out, permission denied — is warned and swallowed so the heal still proceeds; the\n * heal itself is idempotent (additive DDL + a re-check of the fingerprint after acquiring).\n */\nasync function acquireSchemaLock(orm: MikroORM, dialect: SqlDialect): Promise<void> {\n try {\n if (dialect === 'mysql') {\n await orm.em.getConnection().execute(`select get_lock('${SCHEMA_LOCK_NAME}', 10)`);\n } else if (dialect === 'postgres') {\n await orm.em\n .getConnection()\n .execute(`select pg_advisory_lock(hashtext('${SCHEMA_LOCK_NAME}'))`);\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.warn(\n `[nestjs-durable-store-mikro-orm] could not acquire the durable-schema advisory lock (proceeding without it): ${message}`,\n );\n }\n}\n\n/** Release the advisory lock acquired by {@link acquireSchemaLock} (best-effort, never throws). */\nasync function releaseSchemaLock(orm: MikroORM, dialect: SqlDialect): Promise<void> {\n try {\n if (dialect === 'mysql') {\n await orm.em.getConnection().execute(`select release_lock('${SCHEMA_LOCK_NAME}')`);\n } else if (dialect === 'postgres') {\n await orm.em\n .getConnection()\n .execute(`select pg_advisory_unlock(hashtext('${SCHEMA_LOCK_NAME}'))`);\n }\n } catch {\n // Releasing a lock we may never have held (acquire was best-effort) must not crash boot.\n }\n}\n\n/**\n * Idempotently create/extend ONLY the durable tables (additive — never drops). Safe to run on every\n * boot (auto-schema) and from a MikroORM migration when you disable auto-schema:\n *\n * ```ts\n * export class AddDurableTables extends Migration {\n * async up() { await ensureMikroOrmDurableSchema(this.getEntityManager().getOrm()); }\n * }\n * ```\n *\n * It does NOT run a whole-ORM `schema.update()`. When the store shares the host app's ORM (the\n * recommended setup — a single ORM avoids MikroORM's global-metadata clobber between instances),\n * a full `schema.update()` would try to reconcile EVERY app table to the entity metadata: on a\n * migration-managed schema that means recreating the migrations table and dropping app foreign keys.\n * Instead we compute the safe additive diff and execute only the statements that target our own\n * `durable_*` tables. `getUpdateSchemaSQL` already emits a `create table` only for a missing table\n * and `alter table ... add` only for missing columns, so existing tables — and the entire rest of\n * the host schema — are left untouched.\n *\n * This runs on every boot of every pod, and `getUpdateSchemaSQL({ safe: true })` introspects the\n * WHOLE database's `information_schema` (the store shares the app ORM) before string-filtering down\n * to our tables — wasted round-trips when nothing changed. So a fingerprint GATE fronts it: a marker\n * table records the fingerprint of the metadata last applied; if the in-memory expected fingerprint\n * matches the stored one we return after two cheap round-trips (a `CREATE TABLE IF NOT EXISTS` for\n * the marker + one PK read), skipping BOTH the introspection AND the collation probes. Only a fresh\n * DB (no marker), an entity change, or a {@link SCHEMA_REVISION} bump runs the full heal — under a\n * best-effort advisory lock, with a re-check in case a sibling pod healed while we waited.\n */\nexport async function ensureMikroOrmDurableSchema(orm: MikroORM): Promise<void> {\n const dialect = detectSqlDialect(orm);\n\n // 1. Bootstrap the marker table. Idempotent, no introspection — works on a brand-new empty DB,\n // which is what makes the fresh-DB / CI path zero-config.\n await orm.em.getConnection().execute(createMarkerTableSql());\n\n // 2. Compare the in-memory expected fingerprint against the stored one (a single PK read).\n const expected = computeExpectedFingerprint(orm, DURABLE_TABLE_NAMES);\n const stored = await readStoredFingerprint(orm);\n\n // 3. Steady-state hot path: nothing changed → skip getUpdateSchemaSQL AND alignDurableCollation.\n if (stored === expected) {\n return;\n }\n\n // 4. Heal under a best-effort cross-pod lock; re-check after acquiring in case a peer healed first.\n await acquireSchemaLock(orm, dialect);\n try {\n if ((await readStoredFingerprint(orm)) === expected) {\n return;\n }\n await healDurableSchema(orm);\n await writeFingerprint(orm, dialect, expected);\n } finally {\n await releaseSchemaLock(orm, dialect);\n }\n}\n\n/**\n * The additive heal itself: compute the safe diff, execute only the statements targeting our durable\n * tables, then converge their collation. Extracted from {@link ensureMikroOrmDurableSchema} so the\n * fingerprint gate can skip it wholesale in steady state.\n */\nasync function healDurableSchema(orm: MikroORM): Promise<void> {\n const sql = await orm.schema.getUpdateSchemaSQL({ safe: true });\n const ours = sql\n .split(';')\n .map((statement) => statement.trim())\n .filter((statement) => {\n const table = targetTable(statement);\n return table !== undefined && DURABLE_TABLE_NAMES.has(table);\n });\n const connection = orm.em.getConnection();\n for (const statement of ours) {\n try {\n await connection.execute(statement);\n } catch (err) {\n // Required structure (create table / add column / add index) must succeed — rethrow.\n if (isRequiredStructure(statement)) {\n throw err;\n }\n // A best-effort type alignment (e.g. legacy `longtext` → `json`) failed, typically because an\n // existing column holds a value that can't cast to the target type (a relic of an older column\n // type). The column already stores the data and the store reads/writes it via serialization, so\n // leave it as-is and continue rather than crashing boot. Surfaced so the data can be repaired\n // out of band (e.g. `UPDATE … SET col = NULL WHERE JSON_VALID(col) = 0` for a disposable column).\n const message = err instanceof Error ? err.message : String(err);\n console.warn(\n `[nestjs-durable-store-mikro-orm] skipped a non-structural durable-schema statement that failed; the column is left as-is (functional) — repair the data out of band to converge its type. Statement: ${statement} — ${message}`,\n );\n }\n }\n\n // Converge collation last, once the tables exist (whether just created above or pre-existing).\n await alignDurableCollation(orm);\n}\n\n/** A MySQL identifier we are willing to interpolate into DDL (charset / collation names). */\nfunction isSafeSqlIdentifier(value: string): boolean {\n return /^[A-Za-z0-9_]+$/.test(value);\n}\n\n/**\n * Align each durable table's collation to the ORM's configured `collate` (MySQL/MariaDB only).\n *\n * MikroORM's auto-schema (`getUpdateSchemaSQL`) creates tables with the server's DEFAULT collation —\n * on MySQL 8.4 that's `utf8mb4_0900_ai_ci` — and ignores the `collate` config option. When the host\n * app pins a different collation on its own tables (commonly `utf8mb4_unicode_ci` via migrations), a\n * JOIN between a durable table and an app table throws \"Illegal mix of collations\". We converge it\n * here: read the configured collation and `CONVERT` only the durable tables whose collation differs.\n *\n * Idempotent (matching tables are skipped), non-fatal (a CONVERT failure is warned, never crashes\n * boot), and a no-op when no `collate` is configured or the platform isn't MySQL/MariaDB.\n */\nasync function alignDurableCollation(orm: MikroORM): Promise<void> {\n const platform = String(orm.em.getPlatform().constructor.name).toLowerCase();\n if (!platform.includes('mysql') && !platform.includes('maria')) {\n return;\n }\n const collate = orm.config.get('collate');\n if (typeof collate !== 'string' || !isSafeSqlIdentifier(collate)) {\n return;\n }\n // utf8mb4_unicode_ci → utf8mb4. CONVERT TO needs the charset that owns the collation.\n const charset = collate.split('_')[0];\n if (!charset || !isSafeSqlIdentifier(charset)) {\n return;\n }\n const connection = orm.em.getConnection();\n for (const table of DURABLE_TABLE_NAMES) {\n try {\n const rows = (await connection.execute(\n 'select table_collation as collation from information_schema.tables where table_schema = database() and table_name = ? limit 1',\n [table],\n )) as Array<{ collation?: string | null }>;\n const current = rows[0]?.collation;\n // Table absent (nothing to align) or already at the target collation — skip.\n if (current == null || current === collate) {\n continue;\n }\n await connection.execute(\n `alter table \\`${table}\\` convert to character set ${charset} collate ${collate}`,\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.warn(\n `[nestjs-durable-store-mikro-orm] could not align collation for \\`${table}\\` to ${collate} (left as-is): ${message}`,\n );\n }\n }\n}\n"],"mappings":"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","names":["EntityRepositoryType","EntitySchema","EntityRepository","WorkflowRunRepository","EntityRepository","StepCheckpointRepository","RunAttributeRepository","SignalWaiterRepository","BufferedSignalRepository","BufferedEventRepository","snakeCase","property","replace","c","toLowerCase","columnNamer","naming","WorkflowRunEntity","EntityRepositoryType","id","workflow","workflowVersion","status","input","output","error","wakeAt","lockedBy","lockedUntil","awaitingDecisionTaskId","recoveryAttempts","tags","searchAttributes","priority","namespace","origin","createdAt","updatedAt","StepCheckpointEntity","runId","seq","name","kind","stepId","events","attempts","workerGroup","parallelGroup","enqueuedAt","startedAt","finishedAt","RunAttributeEntity","key","strValue","numValue","SignalWaiterEntity","token","BufferedSignalEntity","payload","BufferedEventEntity","publishedAt","namespaceFilterCond","args","undefined","durableEntities","options","col","workflowRuns","EntitySchema","class","tableName","repository","WorkflowRunRepository","filters","cond","default","indexes","properties","type","primary","fieldName","nullable","stepCheckpoints","StepCheckpointRepository","runAttributes","RunAttributeRepository","signalWaiters","SignalWaiterRepository","bufferedSignals","BufferedSignalRepository","autoincrement","index","bufferedEvents","BufferedEventRepository","ENTITIES","attributeColumnFor","attributeOperand","mergeRunFacetRows","normalizeAttributeRows","parseDuration","sqlComparator","raw","createHash","DURABLE_TABLE_NAMES","Set","durableManagedTables","MARKER_TABLE","MARKER_ROW_ID","SCHEMA_LOCK_NAME","SCHEMA_REVISION","compareStrings","a","b","targetTable","statement","match","toLowerCase","isRequiredStructure","test","detectSqlDialect","orm","platform","String","em","getPlatform","name","includes","normalizeIndexProperties","properties","undefined","Array","isArray","map","property","computeExpectedFingerprint","ownedTableNames","ownedMetadata","getMetadata","getAll","values","filter","meta","has","tableName","sort","tables","columns","props","prop","columnName","fieldNames","type","columnTypes","nullable","primary","default","autoincrement","indexes","index","canonical","canonicalize","config","get","createHash","update","digest","value","join","entries","Object","key","val","JSON","stringify","createMarkerTableSql","readStoredFingerprint","rows","getConnection","execute","fingerprint","writeFingerprint","dialect","upsert","Date","now","acquireSchemaLock","err","message","Error","console","warn","releaseSchemaLock","ensureMikroOrmDurableSchema","expected","stored","healDurableSchema","sql","schema","getUpdateSchemaSQL","safe","ours","split","trim","table","connection","alignDurableCollation","isSafeSqlIdentifier","collate","charset","current","collation","MikroOrmStateStore","scopeNamespace","orm","opts","scope","namespace","withScope","fork","em","setFilterParams","ensureSchema","ensureMikroOrmDurableSchema","createRun","run","create","WorkflowRunEntity","toRunEntity","flush","reindexAttributes","id","searchAttributes","updateRun","runId","patch","entity","findOneOrFail","Object","assign","fromRunEntity","attributes","forked","nativeDelete","RunAttributeEntity","rows","normalizeAttributeRows","length","insertMany","getRun","findOne","deleteRun","StepCheckpointEntity","SignalWaiterEntity","pruneTerminalRuns","policy","nowMs","limit","statuses","status","$in","ids","Set","maxAge","cutoff","Date","parseDuration","find","updatedAt","$lt","fields","orderBy","r","add","maxCount","size","offset","idList","slice","transactional","tem","getCheckpoint","seq","fromCheckpointEntity","saveCheckpoint","checkpoint","upsert","toCheckpointEntity","transaction","work","raw","cp","listIncompleteRuns","undefined","map","listPendingRuns","createdAt","listDueTimers","wakeAt","$ne","$lte","tryLockRun","owner","leaseUntilMs","affected","nativeUpdate","$or","lockedUntil","lockedBy","releaseRunLock","renewRunLock","runWhere","query","where","workflow","origin","$and","listRuns","tag","qb","runQueryBuilder","getResultList","quote","idQuote","cols","attributeColumns","createQueryBuilder","tagsCol","tagsColumn","pattern","replace","colExpr","jsonAsText","andWhere","f","attributeExistsSql","runFacets","meta","getMetadata","get","statusCol","properties","fieldNames","originCol","select","addSelect","groupBy","execute","mergeRunFacetRows","count","Number","alias","col","attributeColumnFor","numValue","strValue","cmp","sqlComparator","op","operand","attributeOperand","literal","String","a","table","sub","outerId","runPk","key","field","prop","props","p","name","runMeta","tableName","tags","colRef","platform","getPlatform","toLowerCase","includes","isMysql","ch","listCheckpoints","getLatestCheckpointByName","listCheckpointsByNamePrefix","prefixes","$like","putSignalWaiter","waiter","token","parallelGroup","takeSignalWaiter","remove","listSignalWaiters","prefix","e","removeSignalWaiter","bufferSignal","payload","BufferedSignalEntity","persist","takeBufferedSignal","bufferEvent","input","BufferedEventEntity","publishedAt","listBufferedEvents","getTime","removeBufferedEvent","workflowVersion","output","error","awaitingDecisionTaskId","recoveryAttempts","priority","kind","stepId","events","attempts","workerGroup","enqueuedAt","startedAt","finishedAt"]}
1
+ {"version":3,"sources":["../src/entities.ts","../src/repositories.ts","../src/mikro-orm-state-store.ts","../src/schema.ts"],"sourcesContent":["import type { RunStatus, StepKind } from '@dudousxd/nestjs-durable-core';\nimport { EntityRepositoryType, EntitySchema } from '@mikro-orm/core';\nimport {\n BufferedEventRepository,\n BufferedSignalRepository,\n RunAttributeRepository,\n SignalWaiterRepository,\n StepCheckpointRepository,\n WorkflowRunRepository,\n} from './repositories';\n\n/**\n * How property names map to physical column names. The durable tables are adapter-agnostic: a run\n * written by one store adapter must be readable by another, so every adapter has to agree on the\n * physical column names. The default is `'snake_case'` (the canonical, matched by the TypeORM,\n * Prisma and Drizzle adapters). `'preserve'` keeps the camelCase property name verbatim (what the\n * old TypeORM/Prisma adapters produced before they were pinned). A function lets you supply any\n * custom mapping.\n *\n * The choice is pinned EXPLICITLY onto the entity schema rather than left to the host ORM's naming\n * strategy — depending on the host strategy is what silently diverged the adapters and broke a store\n * swap against an existing table.\n */\nexport type DurableColumnNaming = 'snake_case' | 'preserve' | ((property: string) => string);\n\nfunction snakeCase(property: string): string {\n return property.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);\n}\n\nfunction columnNamer(naming: DurableColumnNaming): (property: string) => string {\n if (naming === 'snake_case') return snakeCase;\n if (naming === 'preserve') return (property) => property;\n return naming;\n}\n\n// Plain classes (no decorators): the schema/column mapping lives on the EntitySchema built by\n// `durableEntities`, so the same class can be registered under different column names. The store\n// still references these classes for `em.create`/`getMetadata`.\n\nexport class WorkflowRunEntity {\n [EntityRepositoryType]?: WorkflowRunRepository;\n\n id!: string;\n workflow!: string;\n workflowVersion!: string;\n status!: RunStatus;\n input?: unknown;\n output?: unknown;\n error?: unknown;\n wakeAt?: Date;\n lockedBy?: string;\n lockedUntil?: Date;\n awaitingDecisionTaskId?: string;\n recoveryAttempts?: number;\n tags?: string[] | null;\n searchAttributes?: Record<string, string | number | boolean> | null;\n priority?: number | null;\n namespace!: string;\n origin?: string | null;\n createdAt!: Date;\n updatedAt!: Date;\n}\n\nexport class StepCheckpointEntity {\n [EntityRepositoryType]?: StepCheckpointRepository;\n\n runId!: string;\n seq!: number;\n name!: string;\n kind!: StepKind;\n stepId!: string;\n status!: 'pending' | 'running' | 'completed' | 'failed';\n input?: unknown;\n output?: unknown;\n error?: unknown;\n events?: unknown;\n attempts!: number;\n workerGroup?: string;\n parallelGroup?: string;\n wakeAt?: Date;\n enqueuedAt?: Date;\n startedAt!: Date;\n finishedAt!: Date;\n}\n\n/**\n * Normalized side-table for search attributes: one row per (run, key), so range/equality predicates\n * push DOWN into SQL (an EXISTS join indexed on `(key, numValue)` / `(key, strValue)`) instead of a\n * coarse scan + in-process filter. Maintained on every createRun/updateRun. Numbers land in\n * `numValue`, strings/booleans in `strValue` (booleans as \"true\"/\"false\"); see normalizeAttributeRows.\n */\nexport class RunAttributeEntity {\n [EntityRepositoryType]?: RunAttributeRepository;\n\n runId!: string;\n key!: string;\n strValue?: string | null;\n numValue?: number | null;\n}\n\nexport class SignalWaiterEntity {\n [EntityRepositoryType]?: SignalWaiterRepository;\n\n token!: string;\n runId!: string;\n seq!: number;\n parallelGroup?: string | null;\n}\n\nexport class BufferedSignalEntity {\n [EntityRepositoryType]?: BufferedSignalRepository;\n\n id!: number;\n token!: string;\n payload?: unknown;\n}\n\n/** A published event that matched no live waiter (see `engine.publishEvent`'s buffering). Keyed by a\n * caller-minted `id` (a uuid, not autoincrement — `removeBufferedEvent` targets it directly), not by\n * `runId`: events are name-based pub/sub, not tied to any one run. */\nexport class BufferedEventEntity {\n [EntityRepositoryType]?: BufferedEventRepository;\n\n id!: string;\n name!: string;\n payload?: unknown;\n publishedAt!: Date;\n}\n\n/**\n * Build the durable MikroORM entity schemas with column names pinned per `naming` (default\n * `'snake_case'`). Register the result in your MikroORM config / `MikroOrmModule.forFeature`.\n *\n * ```ts\n * entities: durableEntities({ naming: 'snake_case' })\n * ```\n */\n/**\n * MikroORM global filter condition for the `namespace` read boundary. Returns `{}` (no restriction)\n * when `namespace` is undefined — the operator (control plane) sees all tenants. Returns a\n * `{ namespace }` equality predicate otherwise, confining the query to that tenant's rows.\n */\nfunction namespaceFilterCond(args?: { namespace?: string }): { namespace?: string } {\n if (args?.namespace === undefined) return {};\n return { namespace: args.namespace };\n}\n\nexport function durableEntities(options: { naming?: DurableColumnNaming } = {}): EntitySchema[] {\n const col = columnNamer(options.naming ?? 'snake_case');\n\n const workflowRuns = new EntitySchema<WorkflowRunEntity>({\n class: WorkflowRunEntity,\n tableName: 'durable_workflow_runs',\n // Wired per schema rather than once on the class: `durableEntities` can be called again with a\n // different `naming`, and each call builds a distinct EntitySchema over the same class.\n repository: () => WorkflowRunRepository,\n // Global filter: confines every read to the tenant's namespace when the store is scoped.\n // The `cond` returns `{}` (no-op) when the `namespace` arg is `undefined`, so an unscoped\n // (operator / control-plane) store sees all rows unchanged — existing behaviour is preserved.\n filters: {\n namespace: {\n name: 'namespace',\n cond: namespaceFilterCond,\n default: true,\n // Optional args: the store's own forks set the scope via `setFilterParams` (undefined =\n // operator, sees all), but an external consumer that shares this ORM (an operator app reading\n // WorkflowRunEntity through its own EntityManager) never sets it. Without this, MikroORM\n // throws \"No arguments provided for filter 'namespace'\" on those queries. `args: false` makes\n // the param optional — cond then receives `undefined` and no-ops (sees all), which is exactly\n // the operator view, while a scoped store still passes its namespace through.\n args: false,\n },\n },\n // Indexes mirror the Prisma adapter so a store swap keeps the same plan. The poller hits these\n // every tick: `(status, wakeAt)` serves both the due-timer scan (status='suspended' AND wakeAt<=now)\n // and, via its `status` prefix, the pending/incomplete status lookups; `(workflow, status)` serves\n // the per-workflow timeout sweep. Without them every poll is a full scan of a table that only grows.\n indexes: [\n { name: 'durable_workflow_runs_status_wake_at_idx', properties: ['status', 'wakeAt'] },\n { name: 'durable_workflow_runs_workflow_status_idx', properties: ['workflow', 'status'] },\n {\n name: 'durable_workflow_runs_namespace_status_idx',\n properties: ['namespace', 'status', 'createdAt'],\n },\n ],\n properties: {\n id: { type: 'string', primary: true, fieldName: col('id') },\n workflow: { type: 'string', fieldName: col('workflow') },\n workflowVersion: { type: 'string', fieldName: col('workflowVersion') },\n status: { type: 'string', fieldName: col('status') },\n input: { type: 'json', nullable: true, fieldName: col('input') },\n output: { type: 'json', nullable: true, fieldName: col('output') },\n error: { type: 'json', nullable: true, fieldName: col('error') },\n wakeAt: { type: 'Date', nullable: true, fieldName: col('wakeAt') },\n lockedBy: { type: 'string', nullable: true, fieldName: col('lockedBy') },\n lockedUntil: { type: 'Date', nullable: true, fieldName: col('lockedUntil') },\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: {\n type: 'string',\n nullable: true,\n fieldName: col('awaitingDecisionTaskId'),\n },\n recoveryAttempts: { type: 'integer', nullable: true, fieldName: col('recoveryAttempts') },\n tags: { type: 'json', nullable: true, fieldName: col('tags') },\n searchAttributes: { type: 'json', nullable: true, fieldName: col('searchAttributes') },\n priority: { type: 'integer', nullable: true, fieldName: col('priority') },\n namespace: { type: 'string', default: 'default', fieldName: col('namespace') },\n // Which library/module registered the workflow this run belongs to (e.g.\n // `@dudousxd/nestjs-catalog-pipeline`), derived at registration time — never caller input.\n //\n // NULLABLE WITH NO DEFAULT, deliberately unlike `namespace` above. `namespace` can honestly\n // default a pre-existing row to `'default'` (that IS the namespace an unscoped engine ran it\n // in); an origin cannot be reconstructed after the fact, so a row written before this column\n // existed must read back as `undefined` = \"unknown\". Stamping it `'app'`/`'unknown'` would be\n // indistinguishable from a real registration in the dashboard's facet — a wrong origin is worse\n // than an absent one. Two MikroORM specifics reinforce it: a `default` here would NOT be\n // back-filled onto existing rows anyway (the DDL default only applies to new inserts, and a\n // TypeScript field initialiser never runs for rows the ORM did not create), so a default would\n // buy nothing but a lie for future rows.\n //\n // No index, unlike `namespace`. That one is on the HOT path — every poll tick filters\n // `listPendingRuns`/`listDueTimers`/`listIncompleteRuns` by it, hence\n // `durable_workflow_runs_namespace_status_idx`. Nothing filters by `origin` except the\n // dashboard's `listRuns`, where it is ANDed with the `status`/`workflow` predicates that\n // `durable_workflow_runs_status_wake_at_idx` / `..._workflow_status_idx` already bound. If a\n // deployment ever makes origin-filtered listings hot, add the composite index in your own\n // migration rather than here.\n origin: { type: 'string', nullable: true, fieldName: col('origin') },\n createdAt: { type: 'Date', fieldName: col('createdAt') },\n updatedAt: { type: 'Date', fieldName: col('updatedAt') },\n },\n });\n\n const stepCheckpoints = new EntitySchema<StepCheckpointEntity>({\n class: StepCheckpointEntity,\n tableName: 'durable_step_checkpoints',\n repository: () => StepCheckpointRepository,\n properties: {\n runId: { type: 'string', primary: true, fieldName: col('runId') },\n seq: { type: 'integer', primary: true, fieldName: col('seq') },\n name: { type: 'string', fieldName: col('name') },\n kind: { type: 'string', fieldName: col('kind') },\n stepId: { type: 'string', fieldName: col('stepId') },\n status: { type: 'string', fieldName: col('status') },\n input: { type: 'json', nullable: true, fieldName: col('input') },\n output: { type: 'json', nullable: true, fieldName: col('output') },\n error: { type: 'json', nullable: true, fieldName: col('error') },\n events: { type: 'json', nullable: true, fieldName: col('events') },\n attempts: { type: 'integer', fieldName: col('attempts') },\n workerGroup: { type: 'string', nullable: true, fieldName: col('workerGroup') },\n // A ctx.gather/ctx.all fan tags every sibling step with the same group string so the dashboard\n // renders them as one \"ran in parallel\" group. The core engine sets it (incl. from a remote\n // worker's recordStep), but it was never persisted here — so the fan always rendered as N\n // sequential singles. Nullable: only fan-out steps carry it.\n parallelGroup: { type: 'string', nullable: true, fieldName: col('parallelGroup') },\n wakeAt: { type: 'Date', nullable: true, fieldName: col('wakeAt') },\n enqueuedAt: { type: 'Date', nullable: true, fieldName: col('enqueuedAt') },\n startedAt: { type: 'Date', fieldName: col('startedAt') },\n finishedAt: { type: 'Date', fieldName: col('finishedAt') },\n },\n });\n\n const runAttributes = new EntitySchema<RunAttributeEntity>({\n class: RunAttributeEntity,\n tableName: 'durable_run_attributes',\n repository: () => RunAttributeRepository,\n // The search-attribute EXISTS join (see the class docstring) pushes equality/range predicates down\n // onto `(key, numValue)` / `(key, strValue)`; mirror the Prisma adapter so those scans stay indexed.\n indexes: [\n { name: 'durable_run_attributes_key_num_idx', properties: ['key', 'numValue'] },\n { name: 'durable_run_attributes_key_str_idx', properties: ['key', 'strValue'] },\n ],\n properties: {\n runId: { type: 'string', primary: true, fieldName: col('runId') },\n key: { type: 'string', primary: true, fieldName: col('key') },\n strValue: { type: 'string', nullable: true, fieldName: col('strValue') },\n // `float`/`double` is portable across SQLite/MySQL/Postgres for numeric range scans.\n numValue: { type: 'float', nullable: true, fieldName: col('numValue') },\n },\n });\n\n const signalWaiters = new EntitySchema<SignalWaiterEntity>({\n class: SignalWaiterEntity,\n tableName: 'durable_signal_waiters',\n repository: () => SignalWaiterRepository,\n properties: {\n token: { type: 'string', primary: true, fieldName: col('token') },\n runId: { type: 'string', fieldName: col('runId') },\n seq: { type: 'integer', fieldName: col('seq') },\n // A ctx.gather_children/ctx.all child fan-out tags every awaited child with the same group; the\n // engine threads it onto the waiter so the resolving `signal:child:` checkpoint carries it and the\n // dashboard renders the fan as one parallel group. Nullable: only fan-out child waiters carry it.\n parallelGroup: { type: 'string', nullable: true, fieldName: col('parallelGroup') },\n },\n });\n\n const bufferedSignals = new EntitySchema<BufferedSignalEntity>({\n class: BufferedSignalEntity,\n tableName: 'durable_buffered_signals',\n repository: () => BufferedSignalRepository,\n properties: {\n id: { type: 'integer', primary: true, autoincrement: true, fieldName: col('id') },\n token: { type: 'string', index: true, fieldName: col('token') },\n payload: { type: 'json', nullable: true, fieldName: col('payload') },\n },\n });\n\n const bufferedEvents = new EntitySchema<BufferedEventEntity>({\n class: BufferedEventEntity,\n tableName: 'durable_buffered_events',\n repository: () => BufferedEventRepository,\n // `(name, publishedAt)` serves both `listBufferedEvents`'s name-scoped scan and its oldest-first\n // ordering in one index.\n indexes: [\n {\n name: 'durable_buffered_events_name_published_at_idx',\n properties: ['name', 'publishedAt'],\n },\n ],\n properties: {\n // Caller-minted uuid (engine.publishEvent), not autoincrement — removeBufferedEvent targets it\n // directly and needs to be handed the SAME id it was buffered with.\n id: { type: 'string', primary: true, fieldName: col('id') },\n name: { type: 'string', fieldName: col('name') },\n payload: { type: 'json', nullable: true, fieldName: col('payload') },\n publishedAt: { type: 'Date', fieldName: col('publishedAt') },\n },\n });\n\n return [\n workflowRuns,\n stepCheckpoints,\n runAttributes,\n signalWaiters,\n bufferedSignals,\n bufferedEvents,\n ];\n}\n\n/** Durable entity schemas with the canonical `'snake_case'` column names. */\nexport const ENTITIES = durableEntities();\n","import { EntityRepository } from '@mikro-orm/core';\nimport type {\n BufferedEventEntity,\n BufferedSignalEntity,\n RunAttributeEntity,\n SignalWaiterEntity,\n StepCheckpointEntity,\n WorkflowRunEntity,\n} from './entities';\n\n/**\n * Custom repositories for the durable entities, so a host app can `@InjectRepository`/inject a\n * `WorkflowRunRepository` by type instead of repeating `em.find(WorkflowRunEntity, …)` with the\n * entity class as the first argument everywhere.\n *\n * They are wired per-schema inside `durableEntities()` (not with a decorator), because that factory\n * can be called more than once with different column naming and each call must produce schemas that\n * still point at these classes. Each entity also declares `[EntityRepositoryType]`, which is what\n * makes `em.getRepository(WorkflowRunEntity)` resolve to the specific type rather than the base\n * `EntityRepository`.\n *\n * The bodies are intentionally empty: the durable engine's own queries go through\n * `MikroOrmStateStore`, and a durable-owned query added here would be a second, unversioned read\n * path over the same tables. They exist as an injectable, correctly-typed handle for host code.\n */\nexport class WorkflowRunRepository extends EntityRepository<WorkflowRunEntity> {}\n\nexport class StepCheckpointRepository extends EntityRepository<StepCheckpointEntity> {}\n\nexport class RunAttributeRepository extends EntityRepository<RunAttributeEntity> {}\n\nexport class SignalWaiterRepository extends EntityRepository<SignalWaiterEntity> {}\n\nexport class BufferedSignalRepository extends EntityRepository<BufferedSignalEntity> {}\n\nexport class BufferedEventRepository extends EntityRepository<BufferedEventEntity> {}\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 type SignalWaiter,\n type StateStore,\n type StepCheckpoint,\n type StepError,\n type StepEvent,\n type WorkflowRun,\n attributePredicateOperands,\n axisIsRunColumn,\n mergeRunFacetRows,\n mergeRunValueFacetRows,\n normalizeAttributeRows,\n parseDuration,\n runValueFacetsFromRuns,\n} from '@dudousxd/nestjs-durable-core';\nimport { raw } from '@mikro-orm/core';\nimport type { EntityManager, MikroORM } from '@mikro-orm/core';\n\n/** Minimal structural surface of the SQL EntityManager's QueryBuilder (from `@mikro-orm/knex`),\n * typed here so the adapter needn't add a hard dependency on the knex types — a real SQL-driver EM\n * satisfies it at runtime. */\ninterface DurableQueryBuilder<T> {\n where(cond: Record<string, unknown>): DurableQueryBuilder<T>;\n andWhere(cond: string): DurableQueryBuilder<T>;\n orderBy(cond: Record<string, unknown>): DurableQueryBuilder<T>;\n limit(n: number): DurableQueryBuilder<T>;\n offset(n: number): DurableQueryBuilder<T>;\n getResultList(): Promise<T[]>;\n // Aggregate verbs — used only by `runFacets`' GROUP BY, which returns raw rows rather than entities.\n // `addSelect` takes `unknown` because the count is a `raw()` expression, not a field name: passing\n // it as a string makes the builder qualify it with the root alias (`r.count(*)`), which is not a\n // column and fails on every engine.\n select(fields: string[]): DurableQueryBuilder<T>;\n addSelect(field: unknown): DurableQueryBuilder<T>;\n groupBy(fields: string[]): DurableQueryBuilder<T>;\n execute<R>(): Promise<R>;\n}\ntype SqlEm = EntityManager & {\n createQueryBuilder<T>(entity: unknown, alias: string): DurableQueryBuilder<T>;\n};\n\n/** Resolved side-table column names (per the active naming strategy) for the raw EXISTS pushdown. */\ninterface AttributeColumns {\n table: string;\n /** Side-table FK column (the run id on `durable_run_attributes`). */\n runId: string;\n /** Run table PK column (the `id` on `durable_workflow_runs`) used for the outer correlation. */\n runPk: string;\n key: string;\n strValue: string;\n numValue: string;\n}\nimport {\n BufferedEventEntity,\n BufferedSignalEntity,\n RunAttributeEntity,\n SignalWaiterEntity,\n StepCheckpointEntity,\n WorkflowRunEntity,\n} from './entities';\nimport { ensureMikroOrmDurableSchema } from './schema';\n\n/** Options for scoping a `MikroOrmStateStore` to a single tenant namespace. */\nexport interface MikroOrmStateStoreOptions {\n /**\n * When set, every forked `EntityManager` activates the `namespace` global filter with this value,\n * so reads are confined to the given tenant's rows. Omit (or pass `undefined`) for the operator\n * (control-plane) view that sees all namespaces.\n */\n scope?: {\n namespace?: string;\n };\n}\n\n/**\n * MikroORM-backed `StateStore`. Works on any MikroORM driver — Postgres, MySQL, SQLite (tested);\n * timestamps and `wakeAt` use native datetime columns. Each operation runs on a forked\n * EntityManager so it owns its unit of work.\n *\n * Pass `opts.scope.namespace` to confine all reads to a single tenant namespace. Omit for the\n * unscoped operator view (control plane — all namespaces visible).\n */\nexport class MikroOrmStateStore implements StateStore {\n private readonly scopeNamespace: string | undefined;\n\n constructor(\n private readonly orm: MikroORM,\n opts?: MikroOrmStateStoreOptions,\n ) {\n this.scopeNamespace = opts?.scope?.namespace;\n }\n\n /**\n * Derive a store confined to a single tenant `scope.namespace`, sharing this store's ORM (no new\n * connection). Turns the operator (unscoped) store into a tenant-boundary view at wiring time —\n * used by the NestJS module's `scopeReads` option, which receives a pre-built store and can't\n * reconstruct it. Pass `{ namespace: undefined }` for the unscoped operator view.\n */\n withScope(scope: { namespace?: string }): MikroOrmStateStore {\n return new MikroOrmStateStore(this.orm, { scope });\n }\n\n /**\n * Create a forked EntityManager and activate the `namespace` global filter with the store's\n * scope (if any). All read operations go through this so the tenant boundary is applied\n * uniformly. Write operations (nativeDelete, nativeUpdate, upsert, insertMany) bypass global\n * filters in MikroORM and are unaffected.\n */\n private fork() {\n const em = this.orm.em.fork();\n em.setFilterParams('namespace', { namespace: this.scopeNamespace });\n return em;\n }\n\n async ensureSchema(): Promise<void> {\n await ensureMikroOrmDurableSchema(this.orm);\n }\n\n async createRun(run: WorkflowRun): Promise<void> {\n const em = this.fork();\n em.create(WorkflowRunEntity, toRunEntity(run));\n await em.flush();\n await this.reindexAttributes(run.id, run.searchAttributes);\n }\n\n async updateRun(runId: string, patch: Partial<WorkflowRun>): Promise<void> {\n const em = this.fork();\n const entity = await em.findOneOrFail(WorkflowRunEntity, { id: runId });\n Object.assign(entity, toRunEntity({ ...fromRunEntity(entity), ...patch } as WorkflowRun));\n await em.flush();\n // Keep the side-table in step with the run's attributes whenever they're patched.\n if ('searchAttributes' in patch) await this.reindexAttributes(runId, patch.searchAttributes);\n }\n\n /** Rewrite a run's normalized attribute rows: delete the old set, insert the current one. Mirrors\n * the in-memory store's reindex so the side-table always reflects the run's live searchAttributes. */\n private async reindexAttributes(\n runId: string,\n attributes: WorkflowRun['searchAttributes'],\n forked?: EntityManager,\n ): Promise<void> {\n const em = forked ?? this.fork();\n await em.nativeDelete(RunAttributeEntity, { runId });\n const rows = normalizeAttributeRows(runId, attributes);\n if (rows.length) await em.insertMany(RunAttributeEntity, rows);\n }\n\n async getRun(runId: string): Promise<WorkflowRun | null> {\n const em = this.fork();\n const entity = await em.findOne(WorkflowRunEntity, { id: runId });\n return entity ? fromRunEntity(entity) : null;\n }\n\n async deleteRun(runId: string): Promise<void> {\n const em = this.fork();\n // Children first, then the run row — checkpoints, signal waiters, and the normalized\n // attribute side-table, so nothing dangles after the run is gone.\n await em.nativeDelete(StepCheckpointEntity, { runId });\n await em.nativeDelete(SignalWaiterEntity, { runId });\n await em.nativeDelete(RunAttributeEntity, { runId });\n await em.nativeDelete(WorkflowRunEntity, { id: runId });\n }\n\n async pruneTerminalRuns(policy: RetentionPolicy, nowMs: number, limit: number): Promise<number> {\n if (policy.statuses.length === 0 || limit <= 0) return 0;\n const em = this.fork();\n const status = { $in: policy.statuses };\n // Collect ids that violate EITHER bound (most-restrictive keep): too old, or past the count cap.\n const ids = new Set<string>();\n\n if (policy.maxAge != null) {\n const cutoff = new Date(nowMs - parseDuration(policy.maxAge));\n const rows = await em.find(\n WorkflowRunEntity,\n { status, updatedAt: { $lt: cutoff } },\n { fields: ['id'], orderBy: { updatedAt: 'asc' }, limit }, // oldest first\n );\n for (const r of rows) ids.add(r.id);\n }\n\n if (policy.maxCount != null && ids.size < limit) {\n // Everything beyond the newest `maxCount` rows in the status set — skip the kept window via offset.\n const rows = await em.find(\n WorkflowRunEntity,\n { status },\n {\n fields: ['id'],\n orderBy: { updatedAt: 'desc', id: 'desc' },\n limit,\n offset: policy.maxCount,\n },\n );\n for (const r of rows) {\n ids.add(r.id);\n if (ids.size >= limit) break;\n }\n }\n\n if (ids.size === 0) return 0;\n const idList = [...ids].slice(0, limit);\n const runId = { $in: idList };\n // Cascade children then runs (mirrors deleteRun) in one transaction so a pruned run never dangles.\n await em.transactional(async (tem) => {\n await tem.nativeDelete(StepCheckpointEntity, { runId });\n await tem.nativeDelete(SignalWaiterEntity, { runId });\n await tem.nativeDelete(RunAttributeEntity, { runId });\n await tem.nativeDelete(WorkflowRunEntity, { id: runId });\n });\n return idList.length;\n }\n\n async getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null> {\n const em = this.fork();\n const entity = await em.findOne(StepCheckpointEntity, { runId, seq });\n return entity ? fromCheckpointEntity(entity) : null;\n }\n\n async saveCheckpoint(checkpoint: StepCheckpoint): Promise<void> {\n const em = this.fork();\n await em.upsert(StepCheckpointEntity, toCheckpointEntity(checkpoint));\n await em.flush();\n }\n\n async transaction<T>(\n work: (tx: {\n raw: unknown;\n saveCheckpoint: (cp: StepCheckpoint) => Promise<void>;\n }) => Promise<T>,\n ): Promise<T> {\n return this.fork().transactional(async (em) =>\n work({\n raw: em,\n saveCheckpoint: async (cp) => {\n await em.upsert(StepCheckpointEntity, toCheckpointEntity(cp));\n },\n }),\n );\n }\n\n async listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]> {\n const em = this.fork();\n const rows = await em.find(WorkflowRunEntity, {\n status: { $in: ['running', 'cancelling'] },\n ...(namespace !== undefined ? { namespace } : {}),\n });\n return rows.map(fromRunEntity);\n }\n\n async listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]> {\n const em = this.fork();\n const rows = await em.find(\n WorkflowRunEntity,\n { status: 'pending', ...(namespace !== undefined ? { namespace } : {}) },\n { orderBy: { createdAt: 'asc' }, limit }, // FIFO dispatch\n );\n return rows.map(fromRunEntity);\n }\n\n async listDueTimers(nowMs: number, namespace?: string): Promise<WorkflowRun[]> {\n const em = this.fork();\n const rows = await em.find(WorkflowRunEntity, {\n status: 'suspended',\n wakeAt: { $ne: null, $lte: new Date(nowMs) },\n ...(namespace !== undefined ? { namespace } : {}),\n });\n return rows.map(fromRunEntity);\n }\n\n async tryLockRun(\n runId: string,\n owner: string,\n leaseUntilMs: number,\n nowMs: number,\n ): Promise<boolean> {\n const em = this.fork();\n const affected = await em.nativeUpdate(\n WorkflowRunEntity,\n { id: runId, $or: [{ lockedUntil: null }, { lockedUntil: { $lte: new Date(nowMs) } }] },\n { lockedBy: owner, lockedUntil: new Date(leaseUntilMs) },\n );\n return affected === 1;\n }\n\n async releaseRunLock(runId: string): Promise<void> {\n const em = this.fork();\n await em.nativeUpdate(WorkflowRunEntity, { id: runId }, { lockedBy: null, lockedUntil: null });\n }\n\n async renewRunLock(runId: string, owner: string, leaseUntilMs: number): Promise<boolean> {\n const em = this.fork();\n const affected = await em.nativeUpdate(\n WorkflowRunEntity,\n { id: runId, lockedBy: owner },\n { lockedUntil: new Date(leaseUntilMs) },\n );\n return affected === 1;\n }\n\n /** The `where` every run query shares — {@link listRuns} pages it, {@link runFacets} groups it.\n * Only the predicates MikroORM can express declaratively; `tag`/`attributes` need raw SQL and are\n * applied by the QueryBuilder path in both callers. */\n private runWhere(query: RunQuery): Record<string, unknown> {\n const where: Record<string, unknown> = {};\n // The single and the plural form of an axis are ANDed when both are set (the single narrows the\n // set), and an empty plural matches nothing — same contract as `status`/`statuses` below. They go\n // through `and()` rather than onto `where` directly because a key can only hold one condition.\n const and: Record<string, unknown>[] = [];\n if (query.workflow) where.workflow = query.workflow;\n if (query.workflows) and.push({ workflow: { $in: query.workflows } });\n if (query.namespace !== undefined) where.namespace = query.namespace;\n if (query.namespaces) and.push({ namespace: { $in: query.namespaces } });\n // Plain equality on the origin column, exactly like `namespace` above. A run whose origin is NULL\n // (created before the column existed, or registered through a path the derivation could not\n // classify) matches NO origin value — it is never folded into some bucket to make the facet look\n // complete. Passing `null` asks for exactly that bucket (`origin IS NULL`), which is how a\n // paginated console offers an \"unknown\" chip without holding every run in the browser.\n if (query.origin !== undefined) where.origin = query.origin;\n // A set of origins may include `null` (the unattributed bucket). SQL `IN` cannot carry it —\n // `IN (NULL)` is never true — so the absent bucket becomes its own ORed `IS NULL` branch and the\n // named values stay in the `IN`. An empty set produces an empty `$or`, which matches nothing.\n if (query.origins) {\n const named = query.origins.filter((o): o is string => o !== null);\n const branches: Record<string, unknown>[] = [];\n if (named.length) branches.push({ origin: { $in: named } });\n if (query.origins.some((o) => o === null)) branches.push({ origin: null });\n and.push(branches.length ? { $or: branches } : { origin: { $in: [] } });\n }\n // `status IN (...)`; an empty set matches nothing (mirrors the in-memory store). When both the\n // single `status` and `statuses` are set, AND them so the narrower set wins.\n if (query.status && query.statuses) {\n and.push({ status: query.status }, { status: { $in: query.statuses } });\n } else if (query.status) {\n where.status = query.status;\n } else if (query.statuses) {\n where.status = { $in: query.statuses };\n }\n if (and.length) where.$and = and;\n return where;\n }\n\n async listRuns(query: RunQuery): Promise<WorkflowRun[]> {\n const em = this.fork();\n const where = this.runWhere(query);\n const orderBy = { createdAt: 'desc' as const }; // newest first — recent runs on top in the dashboard\n // `tags`/attributes need raw SQL pushed through the QueryBuilder:\n // - tag: `tags` is a JSON column (native json/jsonb on PG/MySQL), and MikroORM JSON-serializes a\n // `{ $like }` operand (wrapping/escaping the LIKE pattern) so a plain where corrupts it to no\n // matches. A raw LIKE on the column-as-text matches the quoted token so `etl` doesn't match\n // `etl-foo`. Postgres `jsonb` rejects `LIKE` directly, so cast to text per dialect.\n // - attributes: each filter becomes a raw EXISTS against the normalized side-table, so the DB\n // filters AND paginates — no full scan + in-process filter (ANDed: one EXISTS per filter).\n // Use a QueryBuilder with a fixed root alias `r` so the raw correlations are stable across drivers.\n if (query.tag || query.tags || query.attributes?.length) {\n const qb = this.runQueryBuilder(em, query, where).orderBy(orderBy);\n if (query.limit != null) qb.limit(query.limit);\n if (query.offset != null) qb.offset(query.offset);\n const rows = await qb.getResultList();\n return rows.map(fromRunEntity);\n }\n const rows = await em.find(WorkflowRunEntity, where, {\n ...(query.limit != null ? { limit: query.limit } : {}),\n ...(query.offset != null ? { offset: query.offset } : {}),\n orderBy,\n });\n return rows.map(fromRunEntity);\n }\n\n /** A QueryBuilder over `durable_workflow_runs` (root alias `r`) carrying `where` plus the two\n * predicates only raw SQL can express — the `tag` JSON LIKE and one EXISTS per attribute filter.\n * Shared so a facet count and the page it labels are taken over the SAME set. */\n private runQueryBuilder(\n em: EntityManager,\n query: RunQuery,\n where: Record<string, unknown>,\n ): DurableQueryBuilder<WorkflowRunEntity> {\n // MikroORM global filters do not auto-apply to createQueryBuilder, so enforce the scope here\n // explicitly. Mirrors the filter cond's semantics: undefined = no restriction (operator view).\n if (this.scopeNamespace !== undefined) where.namespace = this.scopeNamespace;\n const quote = this.idQuote(em);\n const cols = this.attributeColumns(em);\n const qb = (em as SqlEm)\n .createQueryBuilder<WorkflowRunEntity>(WorkflowRunEntity, 'r')\n .where(where);\n if (query.tag) qb.andWhere(this.tagLikeSql(em, query.tag, quote));\n // ANY of the tags: one LIKE per tag, ORed. An empty set matches nothing, which has to be said\n // explicitly — skipping the clause would WIDEN the query to every run.\n if (query.tags) {\n const branches = query.tags.map((t) => this.tagLikeSql(em, t, quote));\n qb.andWhere(branches.length ? `(${branches.join(' OR ')})` : '1 = 0');\n }\n for (const f of query.attributes ?? []) {\n qb.andWhere(this.attributeExistsSql(f, quote, 'r', cols));\n }\n return qb;\n }\n\n /** `tags LIKE '%\"etl\"%'` — the quoted token, so `etl` doesn't match `etl-foo`. See the note in\n * {@link listRuns} for why this is raw SQL rather than a MikroORM condition. */\n private tagLikeSql(em: EntityManager, tag: string, quote: (id: string) => string): string {\n const pattern = `%\"${tag.replace(/'/g, \"''\")}\"%`;\n const colExpr = this.jsonAsText(em, `${quote('r')}.${quote(this.tagsColumn(em))}`);\n return `${colExpr} LIKE '${pattern}'`;\n }\n\n /** `GROUP BY status, origin` over the same predicates {@link listRuns} pages — one aggregate, so a\n * console can show whole-set counts next to a bounded page instead of downloading every run to\n * count them in the browser. */\n async runFacets(query: RunFacetQuery): Promise<RunFacetRow[]> {\n const em = this.fork();\n const meta = em.getMetadata().get(WorkflowRunEntity);\n const statusCol = meta.properties.status?.fieldNames?.[0] ?? 'status';\n const originCol = meta.properties.origin?.fieldNames?.[0] ?? 'origin';\n const rows = await this.runQueryBuilder(em, query, this.runWhere(query))\n .select([`r.${statusCol}`, `r.${originCol}`])\n .addSelect(raw('count(*) as count'))\n .groupBy([`r.${statusCol}`, `r.${originCol}`])\n .execute<{ status: RunStatus; origin: string | null; count: number | string }[]>();\n // MySQL returns `count(*)` as a string on some drivers; normalise before merging.\n return mergeRunFacetRows(rows.map((r) => ({ ...r, count: Number(r.count) })));\n }\n\n /** Distinct values of one filter axis over the same predicates {@link listRuns} pages. A run-table\n * column is a `GROUP BY` like {@link runFacets}, exact over the whole matching set; the tag and\n * attribute axes live outside the row (json array / side table) and are counted from a bounded\n * page of runs instead — see {@link RunValueFacetOptions.scan}. */\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 em = this.fork();\n const meta = em.getMetadata().get(WorkflowRunEntity);\n const col = meta.properties[axis.field]?.fieldNames?.[0] ?? axis.field;\n const rows = await this.runQueryBuilder(em, query, this.runWhere(query))\n .select([`r.${col}`])\n .addSelect(raw('count(*) as count'))\n .groupBy([`r.${col}`])\n .execute<Record<string, unknown>[]>();\n return mergeRunValueFacetRows(\n rows.map((row) => ({\n value: (row[axis.field] as string | null | undefined) ?? null,\n count: Number(row.count),\n })),\n opts,\n );\n }\n\n /** One attribute predicate as a raw EXISTS subquery on the side-table, correlated to the outer run\n * alias. `<>` (ne) also excludes runs where the attribute is absent (missing-key-never-matches):\n * EXISTS already requires a present row, so EXISTS(... <> ...) is exactly ne-with-present. Numeric\n * operands compare the num column, everything else the str column. `in` contributes one comparison\n * per member, ORed inside the single EXISTS — one subquery either way, and an `in` over no values\n * yields no comparison and so matches nothing. Identifiers are quoted per driver and operands are\n * inlined as literals (string operands are escaped by doubling quotes). */\n private attributeExistsSql(\n f: AttributeFilter,\n quote: (id: string) => string,\n alias: string,\n cols: AttributeColumns,\n ): string {\n const comparisons = attributePredicateOperands(f).map(({ column, comparator, operand }) => {\n const col = column === 'numValue' ? cols.numValue : cols.strValue;\n const literal =\n typeof operand === 'number' ? String(operand) : `'${String(operand).replace(/'/g, \"''\")}'`;\n return `${quote('a')}.${quote(col)} ${comparator} ${literal}`;\n });\n if (comparisons.length === 0) return '1 = 0';\n const a = quote(cols.table);\n const sub = quote('a');\n const outerId = `${quote(alias)}.${quote(cols.runPk)}`; // run PK column on the outer alias\n const match = comparisons.length === 1 ? comparisons[0] : `(${comparisons.join(' OR ')})`;\n return `EXISTS (SELECT 1 FROM ${a} ${sub} WHERE ${sub}.${quote(cols.runId)} = ${outerId} AND ${sub}.${quote(cols.key)} = '${f.key.replace(/'/g, \"''\")}' AND ${match})`;\n }\n\n /** Resolve the side-table's actual column names from MikroORM metadata, so the raw EXISTS matches\n * the active naming strategy (underscore vs camelCase) rather than guessing. The run PK column is\n * reused for BOTH the outer correlation and the side-table FK (they share the same fieldName). */\n private attributeColumns(em: EntityManager): AttributeColumns {\n const meta = em.getMetadata().get(RunAttributeEntity);\n const field = (prop: string) =>\n meta.props.find((p) => p.name === prop)?.fieldNames?.[0] ?? prop;\n const runMeta = em.getMetadata().get(WorkflowRunEntity);\n const runPk = runMeta.properties.id?.fieldNames?.[0] ?? 'id';\n return {\n table: meta.tableName,\n runId: field('runId'),\n runPk,\n key: field('key'),\n strValue: field('strValue'),\n numValue: field('numValue'),\n };\n }\n\n /** Resolve the `tags` column name from metadata (per the active naming strategy), for the raw LIKE. */\n private tagsColumn(em: EntityManager): string {\n const runMeta = em.getMetadata().get(WorkflowRunEntity);\n return runMeta.properties.tags?.fieldNames?.[0] ?? 'tags';\n }\n\n /** Wrap a JSON column reference so it can be `LIKE`d as text. Postgres `jsonb`/`json` rejects `LIKE`\n * directly (`operator does not exist: jsonb ~~ unknown`) — cast to `text`; MySQL JSON needs an\n * explicit `CHAR` cast; SQLite stores JSON as text already, so no cast. */\n private jsonAsText(em: EntityManager, colRef: string): string {\n const platform = String(em.getPlatform().constructor.name).toLowerCase();\n if (platform.includes('postgre')) return `${colRef}::text`;\n if (platform.includes('mysql') || platform.includes('mariadb'))\n return `CAST(${colRef} AS CHAR)`;\n return colRef;\n }\n\n /** Quote an identifier per the active SQL driver (MySQL/MariaDB backtick, others double-quote). */\n private idQuote(em: EntityManager): (id: string) => string {\n const platform = String(em.getPlatform().constructor.name).toLowerCase();\n const isMysql = platform.includes('mysql') || platform.includes('mariadb');\n const ch = isMysql ? '`' : '\"';\n return (id: string) => `${ch}${id}${ch}`;\n }\n\n async listCheckpoints(runId: string): Promise<StepCheckpoint[]> {\n const em = this.fork();\n const rows = await em.find(StepCheckpointEntity, { runId }, { orderBy: { seq: 'asc' } });\n return rows.map(fromCheckpointEntity);\n }\n\n async getLatestCheckpointByName(\n runId: string,\n name: string,\n ): Promise<StepCheckpoint | undefined> {\n const em = this.fork();\n const entity = await em.findOne(\n StepCheckpointEntity,\n { runId, name },\n { orderBy: { seq: 'desc' } },\n );\n return entity ? fromCheckpointEntity(entity) : undefined;\n }\n\n async listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]> {\n if (prefixes.length === 0) return [];\n const em = this.fork();\n const rows = await em.find(\n StepCheckpointEntity,\n { runId, $or: prefixes.map((p) => ({ name: { $like: `${p}%` } })) },\n { orderBy: { seq: 'asc' } },\n );\n return rows.map(fromCheckpointEntity);\n }\n\n async putSignalWaiter(waiter: SignalWaiter): Promise<void> {\n const em = this.fork();\n await em.upsert(SignalWaiterEntity, {\n token: waiter.token,\n runId: waiter.runId,\n seq: waiter.seq,\n parallelGroup: waiter.parallelGroup ?? null,\n });\n await em.flush();\n }\n\n async takeSignalWaiter(token: string): Promise<SignalWaiter | null> {\n const em = this.fork();\n const entity = await em.findOne(SignalWaiterEntity, { token });\n if (!entity) return null;\n const waiter: SignalWaiter = {\n token: entity.token,\n runId: entity.runId,\n seq: entity.seq,\n parallelGroup: entity.parallelGroup ?? undefined,\n };\n await em.remove(entity).flush();\n return waiter;\n }\n\n async listSignalWaiters(prefix: string): Promise<SignalWaiter[]> {\n const em = this.fork();\n const rows = await em.find(SignalWaiterEntity, { token: { $like: `${prefix}%` } });\n return rows.map((e) => ({\n token: e.token,\n runId: e.runId,\n seq: e.seq,\n parallelGroup: e.parallelGroup ?? undefined,\n }));\n }\n\n async removeSignalWaiter(waiter: SignalWaiter): Promise<void> {\n const em = this.fork();\n // Exact-match delete (token AND runId AND seq) — deleting by `token` alone would remove whatever\n // row currently owns it, even if a different run has since claimed the same token.\n await em.nativeDelete(SignalWaiterEntity, {\n token: waiter.token,\n runId: waiter.runId,\n seq: waiter.seq,\n });\n }\n\n async bufferSignal(token: string, payload: unknown): Promise<void> {\n const em = this.fork();\n const e = new BufferedSignalEntity();\n e.token = token;\n e.payload = payload ?? null;\n em.persist(e);\n await em.flush();\n }\n\n async takeBufferedSignal(token: string): Promise<{ payload: unknown } | null> {\n const em = this.fork();\n const entity = await em.findOne(BufferedSignalEntity, { token }, { orderBy: { id: 'asc' } });\n if (!entity) return null;\n const payload = entity.payload ?? undefined;\n await em.remove(entity).flush();\n return { payload };\n }\n\n async bufferEvent(input: {\n name: string;\n payload: unknown;\n id: string;\n publishedAt: number;\n }): Promise<void> {\n const em = this.fork();\n const e = new BufferedEventEntity();\n e.id = input.id;\n e.name = input.name;\n e.payload = input.payload ?? null;\n e.publishedAt = new Date(input.publishedAt);\n em.persist(e);\n await em.flush();\n }\n\n async listBufferedEvents(\n name: string,\n limit: number,\n ): Promise<Array<{ id: string; payload: unknown; publishedAt: number }>> {\n const em = this.fork();\n const rows = await em.find(\n BufferedEventEntity,\n { name },\n { orderBy: { publishedAt: 'asc' }, limit }, // oldest first\n );\n return rows.map((e) => ({\n id: e.id,\n payload: e.payload ?? undefined,\n publishedAt: e.publishedAt.getTime(),\n }));\n }\n\n async removeBufferedEvent(id: string): Promise<boolean> {\n const em = this.fork();\n const affected = await em.nativeDelete(BufferedEventEntity, { id });\n return affected > 0;\n }\n}\n\nfunction toRunEntity(run: WorkflowRun): WorkflowRunEntity {\n const e = new WorkflowRunEntity();\n e.id = run.id;\n e.workflow = run.workflow;\n e.workflowVersion = run.workflowVersion;\n e.status = run.status;\n e.input = run.input ?? null;\n e.output = run.output ?? null;\n e.error = run.error ?? null;\n if (run.wakeAt != null) e.wakeAt = new Date(run.wakeAt);\n if (run.lockedBy !== undefined) e.lockedBy = run.lockedBy;\n if (run.lockedUntil != null) e.lockedUntil = new Date(run.lockedUntil);\n // Mirror lockedBy: leave the fresh entity's own-`undefined` field untouched when the patch clears\n // the marker, so Object.assign(entity, e) writes NULL (the engine clears it when a decision lands).\n if (run.awaitingDecisionTaskId !== undefined)\n e.awaitingDecisionTaskId = run.awaitingDecisionTaskId;\n if (run.recoveryAttempts !== undefined) e.recoveryAttempts = run.recoveryAttempts;\n e.tags = run.tags ?? null;\n e.searchAttributes = run.searchAttributes ?? null;\n e.priority = run.priority ?? null;\n e.namespace = run.namespace ?? 'default';\n // NOT `?? 'default'` like the line above: an absent origin is genuinely UNKNOWN and must stay NULL\n // (see the column's docblock in ./entities). `null` — not left-undefined — so `Object.assign` in\n // updateRun writes SQL NULL rather than skipping the column.\n e.origin = run.origin ?? null;\n e.createdAt = run.createdAt;\n e.updatedAt = run.updatedAt;\n return e;\n}\n\nfunction fromRunEntity(e: WorkflowRunEntity): WorkflowRun {\n return {\n id: e.id,\n workflow: e.workflow,\n workflowVersion: e.workflowVersion,\n status: e.status,\n input: e.input ?? undefined,\n output: e.output ?? undefined,\n error: (e.error ?? undefined) as StepError | undefined,\n wakeAt: e.wakeAt?.getTime(),\n lockedBy: e.lockedBy ?? undefined,\n lockedUntil: e.lockedUntil?.getTime(),\n awaitingDecisionTaskId: e.awaitingDecisionTaskId ?? undefined,\n recoveryAttempts: e.recoveryAttempts ?? undefined,\n tags: e.tags ?? undefined,\n searchAttributes: e.searchAttributes ?? undefined,\n priority: e.priority ?? undefined,\n namespace: e.namespace,\n // NULL (a row written before the column existed) surfaces as `undefined` = unknown origin.\n origin: e.origin ?? undefined,\n createdAt: e.createdAt,\n updatedAt: e.updatedAt,\n };\n}\n\nfunction toCheckpointEntity(cp: StepCheckpoint): StepCheckpointEntity {\n const e = new StepCheckpointEntity();\n e.runId = cp.runId;\n e.seq = cp.seq;\n e.name = cp.name;\n e.kind = cp.kind;\n e.stepId = cp.stepId;\n e.status = cp.status;\n e.input = cp.input ?? null;\n e.output = cp.output ?? null;\n e.error = cp.error ?? null;\n e.events = cp.events ?? null;\n e.attempts = cp.attempts;\n if (cp.workerGroup !== undefined) e.workerGroup = cp.workerGroup;\n if (cp.parallelGroup !== undefined) e.parallelGroup = cp.parallelGroup;\n if (cp.wakeAt != null) e.wakeAt = new Date(cp.wakeAt);\n e.enqueuedAt = cp.enqueuedAt;\n e.startedAt = cp.startedAt;\n e.finishedAt = cp.finishedAt;\n return e;\n}\n\nfunction fromCheckpointEntity(e: StepCheckpointEntity): StepCheckpoint {\n return {\n runId: e.runId,\n seq: e.seq,\n name: e.name,\n kind: e.kind,\n stepId: e.stepId,\n status: e.status,\n input: e.input ?? undefined,\n output: e.output ?? undefined,\n error: (e.error ?? undefined) as StepError | undefined,\n events: (e.events ?? undefined) as StepEvent[] | undefined,\n attempts: e.attempts,\n workerGroup: e.workerGroup ?? undefined,\n parallelGroup: e.parallelGroup ?? undefined,\n wakeAt: e.wakeAt?.getTime(),\n enqueuedAt: e.enqueuedAt ?? e.startedAt,\n startedAt: e.startedAt,\n finishedAt: e.finishedAt,\n };\n}\n","import { createHash } from 'node:crypto';\nimport type { MikroORM } from '@mikro-orm/core';\n\n/**\n * The tables this store owns. Kept in sync with the `tableName`s in `./entities`. Used to scope\n * schema management to our own tables (see {@link ensureMikroOrmDurableSchema}).\n */\nconst DURABLE_TABLE_NAMES = new Set([\n 'durable_workflow_runs',\n 'durable_step_checkpoints',\n 'durable_run_attributes',\n 'durable_signal_waiters',\n 'durable_buffered_signals',\n 'durable_buffered_events',\n]);\n\n/**\n * Tables this store creates and manages at boot (autoSchema). Feed to your ORM's migration differ\n * exclude/skipTables so it never tries to drop them.\n *\n * ```ts\n * await MikroORM.init({\n * // ...your entities/driver config\n * schemaGenerator: { skipTables: durableManagedTables() },\n * });\n * ```\n *\n * Derived from the same {@link DURABLE_TABLE_NAMES} set `ensureMikroOrmDurableSchema` scopes its own\n * heal to — one list, so a consumer's denylist can never drift from what this store actually owns.\n */\nexport function durableManagedTables(): string[] {\n return [...DURABLE_TABLE_NAMES];\n}\n\n/**\n * Marker table that records the fingerprint of the durable schema last applied to this database. A\n * single row (`id = 'durable'`) lets every boot decide — with two cheap round-trips — whether the\n * durable tables already match the entity metadata, so steady-state boots skip the expensive\n * whole-app introspection (`getUpdateSchemaSQL`) and per-table collation probes entirely.\n */\nconst MARKER_TABLE = 'durable_schema_meta';\nconst MARKER_ROW_ID = 'durable';\n\n/** The advisory-lock name used to serialize the heal across pods (MySQL `GET_LOCK` / PG advisory). */\nconst SCHEMA_LOCK_NAME = 'durable_schema';\n\n/**\n * Hand-bump escape hatch for DDL changes that are NOT visible in the entity metadata and so wouldn't\n * change the computed fingerprint on their own — e.g. the collation-alignment logic in\n * {@link alignDurableCollation}, or a change to the heal's filtering. Bumping this value changes every\n * computed fingerprint, which forces a one-time re-heal on the next boot of every pod against every\n * database (the stored marker no longer matches), then settles back to the cheap steady-state path.\n */\nconst SCHEMA_REVISION = 1;\n\n/** A JSON value the canonical serializer understands. No `any`: the fingerprint input is plain data. */\ntype JsonScalar = string | number | boolean | null;\ntype JsonValue = JsonScalar | JsonValue[] | { [key: string]: JsonValue };\n\n/** The SQL dialect, derived from the ORM platform, used to branch the lock + marker-table DDL/upsert. */\ntype SqlDialect = 'mysql' | 'postgres' | 'sqlite' | 'unknown';\n\n/** Stable string compare (locale-independent) so sorted serializations are deterministic. */\nfunction compareStrings(a: string, b: string): number {\n return a < b ? -1 : a > b ? 1 : 0;\n}\n\n/**\n * The table a DDL statement targets, lower-cased; undefined otherwise. Recognizes `create table` /\n * `alter table` (the table name follows immediately) and standalone `create [unique] index ... on\n * <table>` (the table follows `on`). MikroORM adds an index to an EXISTING table as `alter table ...\n * add index` on MySQL but as a standalone `create index ... on ...` on Postgres/SQLite — without the\n * second form those index statements would be dropped by the durable-table filter and never applied.\n */\nfunction targetTable(statement: string): string | undefined {\n const match = statement.match(\n /^(?:create\\s+(?:unique\\s+)?index\\s+.+?\\s+on\\s+|(?:create|alter)\\s+table\\s+(?:if\\s+not\\s+exists\\s+)?)[`\"']?([\\w$]+)[`\"']?/i,\n );\n return match?.[1]?.toLowerCase();\n}\n\n/**\n * Whether a statement adds structure the store REQUIRES — a failure here is fatal (the store can't\n * run without the table/column/index). A column TYPE alignment (`modify`/`alter column ... type`)\n * is best-effort: the column already holds the data (the store serializes JSON to/from it regardless\n * of the declared type), so failing to converge its type — e.g. a legacy `longtext` value that won't\n * cast to `json` because it was truncated under an older `text` column — must NOT crash boot.\n */\nfunction isRequiredStructure(statement: string): boolean {\n return /\\b(?:create\\s+table|create\\s+(?:unique\\s+)?index|add\\s+(?:column|index|constraint|key|unique|fulltext))\\b/i.test(\n statement,\n );\n}\n\n/** Map the ORM's platform class name onto the dialect we branch lock + DDL syntax on. */\nfunction detectSqlDialect(orm: MikroORM): SqlDialect {\n const platform = String(orm.em.getPlatform().constructor.name).toLowerCase();\n if (platform.includes('mysql') || platform.includes('maria')) return 'mysql';\n if (platform.includes('postgre')) return 'postgres';\n if (platform.includes('sqlite') || platform.includes('libsql')) return 'sqlite';\n return 'unknown';\n}\n\n/** Normalize a MikroORM index `properties` value (string | string[] | undefined) to an array. */\nfunction normalizeIndexProperties(properties: string | string[] | undefined): string[] {\n if (properties === undefined) return [];\n if (Array.isArray(properties)) return properties.map((property) => String(property));\n return [String(properties)];\n}\n\n/**\n * A content fingerprint of the durable tables AS DESCRIBED BY THE ENTITY METADATA — pure, in-memory,\n * no database round-trip. Filters the ORM metadata to the tables this store owns, builds a CANONICAL\n * (sorted tables, sorted columns, sorted indexes, sorted object keys) serialization of each table's\n * structural shape, then appends the configured `collate` and {@link SCHEMA_REVISION} and hashes it.\n *\n * Object enumeration order is never trusted — every array is sorted and every object key is sorted by\n * the serializer — so the same metadata always yields the same hash regardless of declaration order.\n * A change to any column/index/type/nullability/default, the configured collation, or the revision\n * changes the hash, which is exactly when the stored marker should be considered stale and re-healed.\n */\nfunction computeExpectedFingerprint(orm: MikroORM, ownedTableNames: Set<string>): string {\n const ownedMetadata = [...orm.getMetadata().getAll().values()]\n .filter((meta) => ownedTableNames.has(meta.tableName))\n .sort((a, b) => compareStrings(a.tableName, b.tableName));\n\n const tables: JsonValue = ownedMetadata.map((meta) => {\n const columns: JsonValue = [...meta.props]\n .map((prop) => ({ prop, columnName: prop.fieldNames[0] ?? String(prop.name) }))\n .sort((a, b) => compareStrings(a.columnName, b.columnName))\n .map(({ prop, columnName }) => ({\n name: columnName,\n type: prop.columnTypes[0] ?? String(prop.type),\n nullable: prop.nullable === true,\n primary: prop.primary === true,\n default: prop.default ?? null,\n autoincrement: prop.autoincrement === true,\n }));\n\n const indexes: JsonValue = [...meta.indexes]\n .map((index) => ({\n name: index.name ?? '',\n properties: normalizeIndexProperties(index.properties),\n }))\n .sort((a, b) => compareStrings(a.name, b.name));\n\n return { tableName: meta.tableName, columns, indexes };\n });\n\n const canonical = `${canonicalize(tables)}|collate=${String(orm.config.get('collate') ?? '')}|rev=${SCHEMA_REVISION}`;\n return createHash('sha256').update(canonical).digest('hex');\n}\n\n/** Deterministic JSON: arrays keep order (already sorted by the caller); object keys are sorted. */\nfunction canonicalize(value: JsonValue): string {\n if (Array.isArray(value)) {\n return `[${value.map(canonicalize).join(',')}]`;\n }\n if (value !== null && typeof value === 'object') {\n const entries = Object.entries(value).sort(([a], [b]) => compareStrings(a, b));\n return `{${entries.map(([key, val]) => `${JSON.stringify(key)}:${canonicalize(val)}`).join(',')}}`;\n }\n return JSON.stringify(value);\n}\n\n/** `CREATE TABLE IF NOT EXISTS` for the marker — portable across MySQL/Postgres/SQLite, no introspection. */\nfunction createMarkerTableSql(): string {\n return `create table if not exists ${MARKER_TABLE} (id varchar(32) not null primary key, fingerprint varchar(64) not null, applied_at bigint not null)`;\n}\n\n/** Read the single marker row's fingerprint (one PK lookup), or undefined when the row is absent. */\nasync function readStoredFingerprint(orm: MikroORM): Promise<string | undefined> {\n const rows: Array<{ fingerprint?: string | null }> = await orm.em\n .getConnection()\n .execute(`select fingerprint from ${MARKER_TABLE} where id = ?`, [MARKER_ROW_ID]);\n return rows[0]?.fingerprint ?? undefined;\n}\n\n/** Upsert the marker row with the new fingerprint + apply time (epoch-ms bigint, driver-portable). */\nasync function writeFingerprint(\n orm: MikroORM,\n dialect: SqlDialect,\n fingerprint: string,\n): Promise<void> {\n const upsert =\n dialect === 'mysql'\n ? `insert into ${MARKER_TABLE} (id, fingerprint, applied_at) values (?, ?, ?) on duplicate key update fingerprint = values(fingerprint), applied_at = values(applied_at)`\n : `insert into ${MARKER_TABLE} (id, fingerprint, applied_at) values (?, ?, ?) on conflict (id) do update set fingerprint = excluded.fingerprint, applied_at = excluded.applied_at`;\n await orm.em.getConnection().execute(upsert, [MARKER_ROW_ID, fingerprint, Date.now()]);\n}\n\n/**\n * Best-effort cross-pod lock around the heal: MySQL `GET_LOCK`, Postgres `pg_advisory_lock`. Skipped\n * on SQLite/unknown drivers (single-writer / no portable advisory lock). A failure to acquire — lock\n * unsupported, timed out, permission denied — is warned and swallowed so the heal still proceeds; the\n * heal itself is idempotent (additive DDL + a re-check of the fingerprint after acquiring).\n */\nasync function acquireSchemaLock(orm: MikroORM, dialect: SqlDialect): Promise<void> {\n try {\n if (dialect === 'mysql') {\n await orm.em.getConnection().execute(`select get_lock('${SCHEMA_LOCK_NAME}', 10)`);\n } else if (dialect === 'postgres') {\n await orm.em\n .getConnection()\n .execute(`select pg_advisory_lock(hashtext('${SCHEMA_LOCK_NAME}'))`);\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.warn(\n `[nestjs-durable-store-mikro-orm] could not acquire the durable-schema advisory lock (proceeding without it): ${message}`,\n );\n }\n}\n\n/** Release the advisory lock acquired by {@link acquireSchemaLock} (best-effort, never throws). */\nasync function releaseSchemaLock(orm: MikroORM, dialect: SqlDialect): Promise<void> {\n try {\n if (dialect === 'mysql') {\n await orm.em.getConnection().execute(`select release_lock('${SCHEMA_LOCK_NAME}')`);\n } else if (dialect === 'postgres') {\n await orm.em\n .getConnection()\n .execute(`select pg_advisory_unlock(hashtext('${SCHEMA_LOCK_NAME}'))`);\n }\n } catch {\n // Releasing a lock we may never have held (acquire was best-effort) must not crash boot.\n }\n}\n\n/**\n * Idempotently create/extend ONLY the durable tables (additive — never drops). Safe to run on every\n * boot (auto-schema) and from a MikroORM migration when you disable auto-schema:\n *\n * ```ts\n * export class AddDurableTables extends Migration {\n * async up() { await ensureMikroOrmDurableSchema(this.getEntityManager().getOrm()); }\n * }\n * ```\n *\n * It does NOT run a whole-ORM `schema.update()`. When the store shares the host app's ORM (the\n * recommended setup — a single ORM avoids MikroORM's global-metadata clobber between instances),\n * a full `schema.update()` would try to reconcile EVERY app table to the entity metadata: on a\n * migration-managed schema that means recreating the migrations table and dropping app foreign keys.\n * Instead we compute the safe additive diff and execute only the statements that target our own\n * `durable_*` tables. `getUpdateSchemaSQL` already emits a `create table` only for a missing table\n * and `alter table ... add` only for missing columns, so existing tables — and the entire rest of\n * the host schema — are left untouched.\n *\n * This runs on every boot of every pod, and `getUpdateSchemaSQL({ safe: true })` introspects the\n * WHOLE database's `information_schema` (the store shares the app ORM) before string-filtering down\n * to our tables — wasted round-trips when nothing changed. So a fingerprint GATE fronts it: a marker\n * table records the fingerprint of the metadata last applied; if the in-memory expected fingerprint\n * matches the stored one we return after two cheap round-trips (a `CREATE TABLE IF NOT EXISTS` for\n * the marker + one PK read), skipping BOTH the introspection AND the collation probes. Only a fresh\n * DB (no marker), an entity change, or a {@link SCHEMA_REVISION} bump runs the full heal — under a\n * best-effort advisory lock, with a re-check in case a sibling pod healed while we waited.\n */\nexport async function ensureMikroOrmDurableSchema(orm: MikroORM): Promise<void> {\n const dialect = detectSqlDialect(orm);\n\n // 1. Bootstrap the marker table. Idempotent, no introspection — works on a brand-new empty DB,\n // which is what makes the fresh-DB / CI path zero-config.\n await orm.em.getConnection().execute(createMarkerTableSql());\n\n // 2. Compare the in-memory expected fingerprint against the stored one (a single PK read).\n const expected = computeExpectedFingerprint(orm, DURABLE_TABLE_NAMES);\n const stored = await readStoredFingerprint(orm);\n\n // 3. Steady-state hot path: nothing changed → skip getUpdateSchemaSQL AND alignDurableCollation.\n if (stored === expected) {\n return;\n }\n\n // 4. Heal under a best-effort cross-pod lock; re-check after acquiring in case a peer healed first.\n await acquireSchemaLock(orm, dialect);\n try {\n if ((await readStoredFingerprint(orm)) === expected) {\n return;\n }\n await healDurableSchema(orm);\n await writeFingerprint(orm, dialect, expected);\n } finally {\n await releaseSchemaLock(orm, dialect);\n }\n}\n\n/**\n * The additive heal itself: compute the safe diff, execute only the statements targeting our durable\n * tables, then converge their collation. Extracted from {@link ensureMikroOrmDurableSchema} so the\n * fingerprint gate can skip it wholesale in steady state.\n */\nasync function healDurableSchema(orm: MikroORM): Promise<void> {\n const sql = await orm.schema.getUpdateSchemaSQL({ safe: true });\n const ours = sql\n .split(';')\n .map((statement) => statement.trim())\n .filter((statement) => {\n const table = targetTable(statement);\n return table !== undefined && DURABLE_TABLE_NAMES.has(table);\n });\n const connection = orm.em.getConnection();\n for (const statement of ours) {\n try {\n await connection.execute(statement);\n } catch (err) {\n // Required structure (create table / add column / add index) must succeed — rethrow.\n if (isRequiredStructure(statement)) {\n throw err;\n }\n // A best-effort type alignment (e.g. legacy `longtext` → `json`) failed, typically because an\n // existing column holds a value that can't cast to the target type (a relic of an older column\n // type). The column already stores the data and the store reads/writes it via serialization, so\n // leave it as-is and continue rather than crashing boot. Surfaced so the data can be repaired\n // out of band (e.g. `UPDATE … SET col = NULL WHERE JSON_VALID(col) = 0` for a disposable column).\n const message = err instanceof Error ? err.message : String(err);\n console.warn(\n `[nestjs-durable-store-mikro-orm] skipped a non-structural durable-schema statement that failed; the column is left as-is (functional) — repair the data out of band to converge its type. Statement: ${statement} — ${message}`,\n );\n }\n }\n\n // Converge collation last, once the tables exist (whether just created above or pre-existing).\n await alignDurableCollation(orm);\n}\n\n/** A MySQL identifier we are willing to interpolate into DDL (charset / collation names). */\nfunction isSafeSqlIdentifier(value: string): boolean {\n return /^[A-Za-z0-9_]+$/.test(value);\n}\n\n/**\n * Align each durable table's collation to the ORM's configured `collate` (MySQL/MariaDB only).\n *\n * MikroORM's auto-schema (`getUpdateSchemaSQL`) creates tables with the server's DEFAULT collation —\n * on MySQL 8.4 that's `utf8mb4_0900_ai_ci` — and ignores the `collate` config option. When the host\n * app pins a different collation on its own tables (commonly `utf8mb4_unicode_ci` via migrations), a\n * JOIN between a durable table and an app table throws \"Illegal mix of collations\". We converge it\n * here: read the configured collation and `CONVERT` only the durable tables whose collation differs.\n *\n * Idempotent (matching tables are skipped), non-fatal (a CONVERT failure is warned, never crashes\n * boot), and a no-op when no `collate` is configured or the platform isn't MySQL/MariaDB.\n */\nasync function alignDurableCollation(orm: MikroORM): Promise<void> {\n const platform = String(orm.em.getPlatform().constructor.name).toLowerCase();\n if (!platform.includes('mysql') && !platform.includes('maria')) {\n return;\n }\n const collate = orm.config.get('collate');\n if (typeof collate !== 'string' || !isSafeSqlIdentifier(collate)) {\n return;\n }\n // utf8mb4_unicode_ci → utf8mb4. CONVERT TO needs the charset that owns the collation.\n const charset = collate.split('_')[0];\n if (!charset || !isSafeSqlIdentifier(charset)) {\n return;\n }\n const connection = orm.em.getConnection();\n for (const table of DURABLE_TABLE_NAMES) {\n try {\n const rows = (await connection.execute(\n 'select table_collation as collation from information_schema.tables where table_schema = database() and table_name = ? limit 1',\n [table],\n )) as Array<{ collation?: string | null }>;\n const current = rows[0]?.collation;\n // Table absent (nothing to align) or already at the target collation — skip.\n if (current == null || current === collate) {\n continue;\n }\n await connection.execute(\n `alter table \\`${table}\\` convert to character set ${charset} collate ${collate}`,\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.warn(\n `[nestjs-durable-store-mikro-orm] could not align collation for \\`${table}\\` to ${collate} (left as-is): ${message}`,\n );\n }\n }\n}\n"],"mappings":"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","names":["EntityRepositoryType","EntitySchema","EntityRepository","WorkflowRunRepository","EntityRepository","StepCheckpointRepository","RunAttributeRepository","SignalWaiterRepository","BufferedSignalRepository","BufferedEventRepository","snakeCase","property","replace","c","toLowerCase","columnNamer","naming","WorkflowRunEntity","EntityRepositoryType","id","workflow","workflowVersion","status","input","output","error","wakeAt","lockedBy","lockedUntil","awaitingDecisionTaskId","recoveryAttempts","tags","searchAttributes","priority","namespace","origin","createdAt","updatedAt","StepCheckpointEntity","runId","seq","name","kind","stepId","events","attempts","workerGroup","parallelGroup","enqueuedAt","startedAt","finishedAt","RunAttributeEntity","key","strValue","numValue","SignalWaiterEntity","token","BufferedSignalEntity","payload","BufferedEventEntity","publishedAt","namespaceFilterCond","args","undefined","durableEntities","options","col","workflowRuns","EntitySchema","class","tableName","repository","WorkflowRunRepository","filters","cond","default","indexes","properties","type","primary","fieldName","nullable","stepCheckpoints","StepCheckpointRepository","runAttributes","RunAttributeRepository","signalWaiters","SignalWaiterRepository","bufferedSignals","BufferedSignalRepository","autoincrement","index","bufferedEvents","BufferedEventRepository","ENTITIES","RUN_VALUE_FACET_SCAN","attributePredicateOperands","axisIsRunColumn","mergeRunFacetRows","mergeRunValueFacetRows","normalizeAttributeRows","parseDuration","runValueFacetsFromRuns","raw","createHash","DURABLE_TABLE_NAMES","Set","durableManagedTables","MARKER_TABLE","MARKER_ROW_ID","SCHEMA_LOCK_NAME","SCHEMA_REVISION","compareStrings","a","b","targetTable","statement","match","toLowerCase","isRequiredStructure","test","detectSqlDialect","orm","platform","String","em","getPlatform","name","includes","normalizeIndexProperties","properties","undefined","Array","isArray","map","property","computeExpectedFingerprint","ownedTableNames","ownedMetadata","getMetadata","getAll","values","filter","meta","has","tableName","sort","tables","columns","props","prop","columnName","fieldNames","type","columnTypes","nullable","primary","default","autoincrement","indexes","index","canonical","canonicalize","config","get","createHash","update","digest","value","join","entries","Object","key","val","JSON","stringify","createMarkerTableSql","readStoredFingerprint","rows","getConnection","execute","fingerprint","writeFingerprint","dialect","upsert","Date","now","acquireSchemaLock","err","message","Error","console","warn","releaseSchemaLock","ensureMikroOrmDurableSchema","expected","stored","healDurableSchema","sql","schema","getUpdateSchemaSQL","safe","ours","split","trim","table","connection","alignDurableCollation","isSafeSqlIdentifier","collate","charset","current","collation","MikroOrmStateStore","scopeNamespace","orm","opts","scope","namespace","withScope","fork","em","setFilterParams","ensureSchema","ensureMikroOrmDurableSchema","createRun","run","create","WorkflowRunEntity","toRunEntity","flush","reindexAttributes","id","searchAttributes","updateRun","runId","patch","entity","findOneOrFail","Object","assign","fromRunEntity","attributes","forked","nativeDelete","RunAttributeEntity","rows","normalizeAttributeRows","length","insertMany","getRun","findOne","deleteRun","StepCheckpointEntity","SignalWaiterEntity","pruneTerminalRuns","policy","nowMs","limit","statuses","status","$in","ids","Set","maxAge","cutoff","Date","parseDuration","find","updatedAt","$lt","fields","orderBy","r","add","maxCount","size","offset","idList","slice","transactional","tem","getCheckpoint","seq","fromCheckpointEntity","saveCheckpoint","checkpoint","upsert","toCheckpointEntity","transaction","work","raw","cp","listIncompleteRuns","undefined","map","listPendingRuns","createdAt","listDueTimers","wakeAt","$ne","$lte","tryLockRun","owner","leaseUntilMs","affected","nativeUpdate","$or","lockedUntil","lockedBy","releaseRunLock","renewRunLock","runWhere","query","where","and","workflow","workflows","push","namespaces","origin","origins","named","filter","o","branches","some","$and","listRuns","tag","tags","qb","runQueryBuilder","getResultList","quote","idQuote","cols","attributeColumns","createQueryBuilder","andWhere","tagLikeSql","t","join","f","attributeExistsSql","pattern","replace","colExpr","jsonAsText","tagsColumn","runFacets","meta","getMetadata","get","statusCol","properties","fieldNames","originCol","select","addSelect","groupBy","execute","mergeRunFacetRows","count","Number","runValueFacets","axis","axisIsRunColumn","runs","scan","RUN_VALUE_FACET_SCAN","runValueFacetsFromRuns","col","field","mergeRunValueFacetRows","row","value","alias","comparisons","attributePredicateOperands","column","comparator","operand","numValue","strValue","literal","String","a","table","sub","outerId","runPk","match","key","prop","props","p","name","runMeta","tableName","colRef","platform","getPlatform","toLowerCase","includes","isMysql","ch","listCheckpoints","getLatestCheckpointByName","listCheckpointsByNamePrefix","prefixes","$like","putSignalWaiter","waiter","token","parallelGroup","takeSignalWaiter","remove","listSignalWaiters","prefix","e","removeSignalWaiter","bufferSignal","payload","BufferedSignalEntity","persist","takeBufferedSignal","bufferEvent","input","BufferedEventEntity","publishedAt","listBufferedEvents","getTime","removeBufferedEvent","workflowVersion","output","error","awaitingDecisionTaskId","recoveryAttempts","priority","kind","stepId","events","attempts","workerGroup","enqueuedAt","startedAt","finishedAt"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dudousxd/nestjs-durable-store-mikro-orm",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "description": "MikroORM adapter for the nestjs-durable StateStore (reference ORM adapter)",
5
5
  "license": "MIT",
6
6
  "author": "Davide Carvalho",
@@ -31,8 +31,8 @@
31
31
  "reflect-metadata": "0.2.2",
32
32
  "tsup": "8.3.5",
33
33
  "typescript": "5.9.3",
34
- "@dudousxd/nestjs-durable-core": "^0.67.1",
35
- "@dudousxd/nestjs-durable-testing": "^0.13.0"
34
+ "@dudousxd/nestjs-durable-testing": "^0.14.0",
35
+ "@dudousxd/nestjs-durable-core": "^0.68.0"
36
36
  },
37
37
  "module": "./dist/index.js",
38
38
  "exports": {