@dudousxd/nestjs-durable-testing 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -9,6 +9,94 @@ declare function assertStepsRan(store: StateStore, runId: string, names: string[
9
9
  /** Assert a step ran exactly the given number of attempts (e.g. to verify retries). */
10
10
  declare function assertStepAttempts(store: StateStore, runId: string, name: string, attempts: number): Promise<void>;
11
11
 
12
+ /**
13
+ * The canonical physical column names for the durable tables, keyed by table → entity property →
14
+ * column. This is the cross-adapter contract: a run written by one store adapter must be readable by
15
+ * another, so EVERY adapter (TypeORM, MikroORM, Prisma, Drizzle) must map these properties to these
16
+ * exact columns. The canonical convention is `snake_case`.
17
+ *
18
+ * Each adapter has a spec that asserts its physical columns against this map (see `assertDurableColumns`).
19
+ * Without it, adapters silently diverge — one defaulting to its ORM's `snake_case` naming strategy,
20
+ * another keeping the verbatim camelCase property name — and a store swap fails against an existing
21
+ * table with "Unknown column" only at runtime. The map exists so that divergence is a failing unit
22
+ * test, not a production incident.
23
+ *
24
+ * The camelCase ("preserve") naming is simply the property names themselves (the object keys), so no
25
+ * separate map is needed for it.
26
+ */
27
+ declare const DURABLE_CANONICAL_COLUMNS: {
28
+ readonly durable_workflow_runs: {
29
+ readonly id: "id";
30
+ readonly workflow: "workflow";
31
+ readonly workflowVersion: "workflow_version";
32
+ readonly status: "status";
33
+ readonly input: "input";
34
+ readonly output: "output";
35
+ readonly error: "error";
36
+ readonly wakeAt: "wake_at";
37
+ readonly lockedBy: "locked_by";
38
+ readonly lockedUntil: "locked_until";
39
+ readonly recoveryAttempts: "recovery_attempts";
40
+ readonly tags: "tags";
41
+ readonly searchAttributes: "search_attributes";
42
+ readonly createdAt: "created_at";
43
+ readonly updatedAt: "updated_at";
44
+ };
45
+ readonly durable_step_checkpoints: {
46
+ readonly runId: "run_id";
47
+ readonly seq: "seq";
48
+ readonly name: "name";
49
+ readonly kind: "kind";
50
+ readonly stepId: "step_id";
51
+ readonly status: "status";
52
+ readonly input: "input";
53
+ readonly output: "output";
54
+ readonly error: "error";
55
+ readonly events: "events";
56
+ readonly attempts: "attempts";
57
+ readonly workerGroup: "worker_group";
58
+ readonly wakeAt: "wake_at";
59
+ readonly enqueuedAt: "enqueued_at";
60
+ readonly startedAt: "started_at";
61
+ readonly finishedAt: "finished_at";
62
+ };
63
+ readonly durable_run_attributes: {
64
+ readonly runId: "run_id";
65
+ readonly key: "key";
66
+ readonly strValue: "str_value";
67
+ readonly numValue: "num_value";
68
+ };
69
+ readonly durable_signal_waiters: {
70
+ readonly token: "token";
71
+ readonly runId: "run_id";
72
+ readonly seq: "seq";
73
+ };
74
+ readonly durable_buffered_signals: {
75
+ readonly id: "id";
76
+ readonly token: "token";
77
+ readonly payload: "payload";
78
+ };
79
+ };
80
+ type DurableColumnMap = typeof DURABLE_CANONICAL_COLUMNS;
81
+ /** A single column-name disagreement found by {@link assertDurableColumns}. */
82
+ interface DurableColumnMismatch {
83
+ table: string;
84
+ property: string;
85
+ expected: string;
86
+ actual: string | undefined;
87
+ }
88
+ /**
89
+ * Walk every (table, property) in the canonical contract and compare it to what an adapter actually
90
+ * maps, via the supplied `resolve(table, property) => columnName`. Returns the list of mismatches
91
+ * (empty when the adapter is canonical) so a spec can `expect(assertDurableColumns(resolve)).toEqual([])`.
92
+ *
93
+ * Pass `expected = DURABLE_CANONICAL_COLUMNS` (default) for the snake_case contract, or a map of the
94
+ * property names to themselves to assert the camelCase ("preserve") naming.
95
+ */
96
+ declare function assertDurableColumns(resolve: (table: string, property: string) => string | undefined, expected?: Record<string, Record<string, string>>): DurableColumnMismatch[];
97
+ /** The "preserve" (camelCase) expectation: every property maps to a column of the same name. */
98
+ declare function preserveColumnExpectation(): Record<string, Record<string, string>>;
99
+
12
100
  /** A clock you control, for testing durable sleeps without real time. */
13
101
  declare class MutableClock {
14
102
  private current;
@@ -127,4 +215,4 @@ type HandleableTransport = Transport & {
127
215
  */
128
216
  declare function assertTransportConformance(transport: HandleableTransport, idPrefix?: string): Promise<void>;
129
217
 
130
- export { type HandleableTransport, MutableClock, type RunHistory, type StateStoreContext, type StateStoreFactory, StateStoreUnavailableError, type TestEngine, assertOutput, assertReplayable, assertRunStatus, assertStepAttempts, assertStepsRan, assertTransportConformance, createTestEngine, failOnce, failTimes, recordedSteps, runStateStoreContract };
218
+ export { DURABLE_CANONICAL_COLUMNS, type DurableColumnMap, type DurableColumnMismatch, type HandleableTransport, MutableClock, type RunHistory, type StateStoreContext, type StateStoreFactory, StateStoreUnavailableError, type TestEngine, assertDurableColumns, assertOutput, assertReplayable, assertRunStatus, assertStepAttempts, assertStepsRan, assertTransportConformance, createTestEngine, failOnce, failTimes, preserveColumnExpectation, recordedSteps, runStateStoreContract };
package/dist/index.js CHANGED
@@ -48,6 +48,88 @@ async function assertStepAttempts(store, runId, name, attempts) {
48
48
  }
49
49
  __name(assertStepAttempts, "assertStepAttempts");
50
50
 
51
+ // src/durable-columns.ts
52
+ var DURABLE_CANONICAL_COLUMNS = {
53
+ durable_workflow_runs: {
54
+ id: "id",
55
+ workflow: "workflow",
56
+ workflowVersion: "workflow_version",
57
+ status: "status",
58
+ input: "input",
59
+ output: "output",
60
+ error: "error",
61
+ wakeAt: "wake_at",
62
+ lockedBy: "locked_by",
63
+ lockedUntil: "locked_until",
64
+ recoveryAttempts: "recovery_attempts",
65
+ tags: "tags",
66
+ searchAttributes: "search_attributes",
67
+ createdAt: "created_at",
68
+ updatedAt: "updated_at"
69
+ },
70
+ durable_step_checkpoints: {
71
+ runId: "run_id",
72
+ seq: "seq",
73
+ name: "name",
74
+ kind: "kind",
75
+ stepId: "step_id",
76
+ status: "status",
77
+ input: "input",
78
+ output: "output",
79
+ error: "error",
80
+ events: "events",
81
+ attempts: "attempts",
82
+ workerGroup: "worker_group",
83
+ wakeAt: "wake_at",
84
+ enqueuedAt: "enqueued_at",
85
+ startedAt: "started_at",
86
+ finishedAt: "finished_at"
87
+ },
88
+ durable_run_attributes: {
89
+ runId: "run_id",
90
+ key: "key",
91
+ strValue: "str_value",
92
+ numValue: "num_value"
93
+ },
94
+ durable_signal_waiters: {
95
+ token: "token",
96
+ runId: "run_id",
97
+ seq: "seq"
98
+ },
99
+ durable_buffered_signals: {
100
+ id: "id",
101
+ token: "token",
102
+ payload: "payload"
103
+ }
104
+ };
105
+ function assertDurableColumns(resolve, expected = DURABLE_CANONICAL_COLUMNS) {
106
+ const mismatches = [];
107
+ for (const [table, props] of Object.entries(expected)) {
108
+ for (const [property, column] of Object.entries(props)) {
109
+ const actual = resolve(table, property);
110
+ if (actual !== column) mismatches.push({
111
+ table,
112
+ property,
113
+ expected: column,
114
+ actual
115
+ });
116
+ }
117
+ }
118
+ return mismatches;
119
+ }
120
+ __name(assertDurableColumns, "assertDurableColumns");
121
+ function preserveColumnExpectation() {
122
+ const out = {};
123
+ for (const [table, props] of Object.entries(DURABLE_CANONICAL_COLUMNS)) {
124
+ out[table] = Object.fromEntries(Object.keys(props).map((p) => [
125
+ p,
126
+ p
127
+ ]));
128
+ }
129
+ return out;
130
+ }
131
+ __name(preserveColumnExpectation, "preserveColumnExpectation");
132
+
51
133
  // src/harness.ts
52
134
  import { InMemoryStateStore, InMemoryTransport, WorkflowEngine } from "@dudousxd/nestjs-durable-core";
53
135
  var MutableClock = class {
@@ -5418,8 +5500,10 @@ async function assertTransportConformance(transport, idPrefix = "conf") {
5418
5500
  }
5419
5501
  __name(assertTransportConformance, "assertTransportConformance");
5420
5502
  export {
5503
+ DURABLE_CANONICAL_COLUMNS,
5421
5504
  MutableClock,
5422
5505
  StateStoreUnavailableError,
5506
+ assertDurableColumns,
5423
5507
  assertOutput,
5424
5508
  assertReplayable,
5425
5509
  assertRunStatus,
@@ -5429,6 +5513,7 @@ export {
5429
5513
  createTestEngine,
5430
5514
  failOnce,
5431
5515
  failTimes,
5516
+ preserveColumnExpectation,
5432
5517
  recordedSteps,
5433
5518
  runStateStoreContract
5434
5519
  };