@multiplier-labs/stepflow 0.3.1 → 0.3.3

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.
Files changed (84) hide show
  1. package/.codekin/reports/comments/2026-04-04_comment-assessment.md +179 -0
  2. package/.codekin/reports/complexity/2026-04-03_complexity-report.md +152 -0
  3. package/.codekin/reports/dependencies/2026-04-04_dependency-health.md +94 -0
  4. package/.codekin/reports/docs-audit/2026-04-04_docs-audit.md +10 -0
  5. package/.codekin/reports/security/2026-04-03_security-audit.md +208 -0
  6. package/.github/CODEOWNERS +15 -0
  7. package/.github/dependabot.yml +23 -0
  8. package/.github/workflows/ci.yml +38 -0
  9. package/.github/workflows/publish.yml +11 -5
  10. package/.github/workflows/security.yml +29 -0
  11. package/CHANGELOG.md +34 -0
  12. package/README.md +24 -0
  13. package/SECURITY.md +40 -0
  14. package/dist/{chunk-FQCT3I2A.js → chunk-4VOKMGP6.js} +23 -42
  15. package/dist/chunk-4VOKMGP6.js.map +1 -0
  16. package/dist/{chunk-XCF4PLN7.js → chunk-GYPNJBDP.js} +12 -16
  17. package/dist/chunk-GYPNJBDP.js.map +1 -0
  18. package/dist/{chunk-U5QGN3RT.js → chunk-KHTUWLVZ.js} +14 -47
  19. package/dist/chunk-KHTUWLVZ.js.map +1 -0
  20. package/dist/{chunk-GXY66V7Q.js → chunk-ML35PIHX.js} +1 -1
  21. package/dist/chunk-ML35PIHX.js.map +1 -0
  22. package/dist/events/index.d.ts +4 -4
  23. package/dist/events/index.js +1 -1
  24. package/dist/{index-CPfGsmrp.d.ts → index-Dzr437iW.d.ts} +6 -6
  25. package/dist/index.d.ts +14 -12
  26. package/dist/index.js +40 -82
  27. package/dist/index.js.map +1 -1
  28. package/dist/scheduler/index.d.ts +4 -4
  29. package/dist/scheduler/index.js +2 -2
  30. package/dist/storage/index.d.ts +13 -13
  31. package/dist/storage/index.js +2 -2
  32. package/dist/{types-BlwFEGzj.d.ts → types-DSEjiLMj.d.ts} +16 -15
  33. package/dist/{types-DzkEqnQJ.d.ts → types-DZUdWmCc.d.ts} +2 -2
  34. package/dist/{types-BVShq7zT.d.ts → types-K5Gjk3H_.d.ts} +4 -4
  35. package/docs/stepflow-api-reference.md +2 -3
  36. package/package.json +7 -6
  37. package/src/core/engine.test.ts +466 -522
  38. package/src/core/engine.ts +42 -67
  39. package/src/core/index.ts +3 -3
  40. package/src/core/orchestrator.ts +64 -83
  41. package/src/core/types.ts +7 -29
  42. package/src/events/index.ts +4 -4
  43. package/src/events/memory.test.ts +39 -41
  44. package/src/events/memory.ts +7 -10
  45. package/src/events/socketio.test.ts +112 -162
  46. package/src/events/socketio.ts +20 -27
  47. package/src/events/types.ts +16 -19
  48. package/src/events/webhook.test.ts +197 -235
  49. package/src/events/webhook.ts +44 -71
  50. package/src/index.ts +19 -19
  51. package/src/planning/index.ts +6 -3
  52. package/src/planning/planner.ts +66 -91
  53. package/src/planning/planning.test.ts +303 -366
  54. package/src/planning/registry.test.ts +204 -251
  55. package/src/planning/registry.ts +39 -43
  56. package/src/planning/types.ts +23 -27
  57. package/src/scheduler/cron.test.ts +141 -150
  58. package/src/scheduler/cron.ts +32 -67
  59. package/src/scheduler/index.ts +4 -14
  60. package/src/scheduler/postgres-persistence.ts +71 -99
  61. package/src/scheduler/sqlite-persistence.test.ts +96 -96
  62. package/src/scheduler/sqlite-persistence.ts +12 -19
  63. package/src/scheduler/types.ts +4 -9
  64. package/src/storage/index.ts +5 -5
  65. package/src/storage/memory.test.ts +133 -183
  66. package/src/storage/memory.ts +21 -42
  67. package/src/storage/postgres.ts +197 -393
  68. package/src/storage/sqlite.test.ts +154 -281
  69. package/src/storage/sqlite.ts +50 -85
  70. package/src/storage/types.ts +33 -58
  71. package/src/utils/errors.test.ts +78 -80
  72. package/src/utils/errors.ts +27 -57
  73. package/src/utils/id.ts +3 -3
  74. package/src/utils/index.ts +4 -4
  75. package/src/utils/logger.test.ts +52 -58
  76. package/src/utils/logger.ts +4 -4
  77. package/src/utils/postgres-deps.ts +4 -4
  78. package/src/utils/retry.test.ts +47 -67
  79. package/src/utils/retry.ts +9 -9
  80. package/dist/chunk-FQCT3I2A.js.map +0 -1
  81. package/dist/chunk-GXY66V7Q.js.map +0 -1
  82. package/dist/chunk-U5QGN3RT.js.map +0 -1
  83. package/dist/chunk-XCF4PLN7.js.map +0 -1
  84. package/src/scheduler/postgres-persistence.test.ts +0 -906
@@ -1,15 +1,15 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import Database from "better-sqlite3";
3
- import { SQLiteStorageAdapter } from "./sqlite";
4
- import type { WorkflowRunRecord, WorkflowRunStepRecord } from "./types";
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import Database from 'better-sqlite3';
3
+ import { SQLiteStorageAdapter } from './sqlite';
4
+ import type { WorkflowRunRecord, WorkflowRunStepRecord } from './types';
5
5
 
6
- describe("SQLiteStorageAdapter", () => {
6
+ describe('SQLiteStorageAdapter', () => {
7
7
  let db: Database.Database;
8
8
  let storage: SQLiteStorageAdapter;
9
9
 
10
10
  beforeEach(() => {
11
11
  // Use in-memory database for testing
12
- db = new Database(":memory:");
12
+ db = new Database(':memory:');
13
13
  storage = new SQLiteStorageAdapter({ db });
14
14
  });
15
15
 
@@ -17,35 +17,35 @@ describe("SQLiteStorageAdapter", () => {
17
17
  storage.close();
18
18
  });
19
19
 
20
- describe("createRun", () => {
21
- it("should create a run and return it with generated id and createdAt", async () => {
20
+ describe('createRun', () => {
21
+ it('should create a run and return it with generated id and createdAt', async () => {
22
22
  const run = await storage.createRun({
23
- kind: "test.workflow",
24
- status: "queued",
25
- input: { foo: "bar" },
26
- metadata: { userId: "user1" },
23
+ kind: 'test.workflow',
24
+ status: 'queued',
25
+ input: { foo: 'bar' },
26
+ metadata: { userId: 'user1' },
27
27
  context: {},
28
28
  });
29
29
 
30
30
  expect(run.id).toBeDefined();
31
- expect(run.kind).toBe("test.workflow");
32
- expect(run.status).toBe("queued");
33
- expect(run.input).toEqual({ foo: "bar" });
34
- expect(run.metadata).toEqual({ userId: "user1" });
31
+ expect(run.kind).toBe('test.workflow');
32
+ expect(run.status).toBe('queued');
33
+ expect(run.input).toEqual({ foo: 'bar' });
34
+ expect(run.metadata).toEqual({ userId: 'user1' });
35
35
  expect(run.createdAt).toBeInstanceOf(Date);
36
36
  });
37
37
  });
38
38
 
39
- describe("getRun", () => {
40
- it("should return null for non-existent run", async () => {
41
- const run = await storage.getRun("nonexistent");
39
+ describe('getRun', () => {
40
+ it('should return null for non-existent run', async () => {
41
+ const run = await storage.getRun('nonexistent');
42
42
  expect(run).toBeNull();
43
43
  });
44
44
 
45
- it("should retrieve a created run", async () => {
45
+ it('should retrieve a created run', async () => {
46
46
  const created = await storage.createRun({
47
- kind: "test.workflow",
48
- status: "queued",
47
+ kind: 'test.workflow',
48
+ status: 'queued',
49
49
  input: { value: 123 },
50
50
  metadata: {},
51
51
  context: {},
@@ -58,119 +58,92 @@ describe("SQLiteStorageAdapter", () => {
58
58
  });
59
59
  });
60
60
 
61
- describe("updateRun", () => {
62
- it("should update run status", async () => {
61
+ describe('updateRun', () => {
62
+ it('should update run status', async () => {
63
63
  const run = await storage.createRun({
64
- kind: "test.workflow",
65
- status: "queued",
64
+ kind: 'test.workflow',
65
+ status: 'queued',
66
66
  input: {},
67
67
  metadata: {},
68
68
  context: {},
69
69
  });
70
70
 
71
- await storage.updateRun(run.id, { status: "running" });
71
+ await storage.updateRun(run.id, { status: 'running' });
72
72
 
73
73
  const updated = await storage.getRun(run.id);
74
- expect(updated!.status).toBe("running");
74
+ expect(updated!.status).toBe('running');
75
75
  });
76
76
 
77
- it("should update run context", async () => {
77
+ it('should update run context', async () => {
78
78
  const run = await storage.createRun({
79
- kind: "test.workflow",
80
- status: "running",
79
+ kind: 'test.workflow',
80
+ status: 'running',
81
81
  input: {},
82
82
  metadata: {},
83
- context: { step1: "result1" },
83
+ context: { step1: 'result1' },
84
84
  });
85
85
 
86
86
  await storage.updateRun(run.id, {
87
- context: { step1: "result1", step2: "result2" },
87
+ context: { step1: 'result1', step2: 'result2' },
88
88
  });
89
89
 
90
90
  const updated = await storage.getRun(run.id);
91
- expect(updated!.context).toEqual({ step1: "result1", step2: "result2" });
91
+ expect(updated!.context).toEqual({ step1: 'result1', step2: 'result2' });
92
92
  });
93
93
 
94
- it("should update run error", async () => {
94
+ it('should update run error', async () => {
95
95
  const run = await storage.createRun({
96
- kind: "test.workflow",
97
- status: "running",
96
+ kind: 'test.workflow',
97
+ status: 'running',
98
98
  input: {},
99
99
  metadata: {},
100
100
  context: {},
101
101
  });
102
102
 
103
103
  await storage.updateRun(run.id, {
104
- status: "failed",
105
- error: { code: "TEST_ERROR", message: "Something went wrong" },
104
+ status: 'failed',
105
+ error: { code: 'TEST_ERROR', message: 'Something went wrong' },
106
106
  });
107
107
 
108
108
  const updated = await storage.getRun(run.id);
109
- expect(updated!.status).toBe("failed");
110
- expect(updated!.error).toEqual({
111
- code: "TEST_ERROR",
112
- message: "Something went wrong",
113
- });
109
+ expect(updated!.status).toBe('failed');
110
+ expect(updated!.error).toEqual({ code: 'TEST_ERROR', message: 'Something went wrong' });
114
111
  });
115
112
  });
116
113
 
117
- describe("listRuns", () => {
114
+ describe('listRuns', () => {
118
115
  beforeEach(async () => {
119
116
  // Create some test runs
120
- await storage.createRun({
121
- kind: "workflow.a",
122
- status: "succeeded",
123
- input: {},
124
- metadata: {},
125
- context: {},
126
- });
127
- await storage.createRun({
128
- kind: "workflow.a",
129
- status: "failed",
130
- input: {},
131
- metadata: {},
132
- context: {},
133
- });
134
- await storage.createRun({
135
- kind: "workflow.b",
136
- status: "running",
137
- input: {},
138
- metadata: {},
139
- context: {},
140
- });
141
- await storage.createRun({
142
- kind: "workflow.b",
143
- status: "queued",
144
- input: {},
145
- metadata: {},
146
- context: {},
147
- });
117
+ await storage.createRun({ kind: 'workflow.a', status: 'succeeded', input: {}, metadata: {}, context: {} });
118
+ await storage.createRun({ kind: 'workflow.a', status: 'failed', input: {}, metadata: {}, context: {} });
119
+ await storage.createRun({ kind: 'workflow.b', status: 'running', input: {}, metadata: {}, context: {} });
120
+ await storage.createRun({ kind: 'workflow.b', status: 'queued', input: {}, metadata: {}, context: {} });
148
121
  });
149
122
 
150
- it("should list all runs", async () => {
123
+ it('should list all runs', async () => {
151
124
  const result = await storage.listRuns();
152
125
  expect(result.items).toHaveLength(4);
153
126
  expect(result.total).toBe(4);
154
127
  });
155
128
 
156
- it("should filter by kind", async () => {
157
- const result = await storage.listRuns({ kind: "workflow.a" });
129
+ it('should filter by kind', async () => {
130
+ const result = await storage.listRuns({ kind: 'workflow.a' });
158
131
  expect(result.items).toHaveLength(2);
159
- expect(result.items.every((r) => r.kind === "workflow.a")).toBe(true);
132
+ expect(result.items.every(r => r.kind === 'workflow.a')).toBe(true);
160
133
  });
161
134
 
162
- it("should filter by single status", async () => {
163
- const result = await storage.listRuns({ status: "running" });
135
+ it('should filter by single status', async () => {
136
+ const result = await storage.listRuns({ status: 'running' });
164
137
  expect(result.items).toHaveLength(1);
165
- expect(result.items[0].status).toBe("running");
138
+ expect(result.items[0].status).toBe('running');
166
139
  });
167
140
 
168
- it("should filter by multiple statuses", async () => {
169
- const result = await storage.listRuns({ status: ["queued", "running"] });
141
+ it('should filter by multiple statuses', async () => {
142
+ const result = await storage.listRuns({ status: ['queued', 'running'] });
170
143
  expect(result.items).toHaveLength(2);
171
144
  });
172
145
 
173
- it("should support pagination", async () => {
146
+ it('should support pagination', async () => {
174
147
  const page1 = await storage.listRuns({ limit: 2, offset: 0 });
175
148
  const page2 = await storage.listRuns({ limit: 2, offset: 2 });
176
149
 
@@ -180,13 +153,13 @@ describe("SQLiteStorageAdapter", () => {
180
153
  });
181
154
  });
182
155
 
183
- describe("step operations", () => {
156
+ describe('step operations', () => {
184
157
  let runId: string;
185
158
 
186
159
  beforeEach(async () => {
187
160
  const run = await storage.createRun({
188
- kind: "test.workflow",
189
- status: "running",
161
+ kind: 'test.workflow',
162
+ status: 'running',
190
163
  input: {},
191
164
  metadata: {},
192
165
  context: {},
@@ -194,83 +167,62 @@ describe("SQLiteStorageAdapter", () => {
194
167
  runId = run.id;
195
168
  });
196
169
 
197
- it("should create and retrieve a step", async () => {
170
+ it('should create and retrieve a step', async () => {
198
171
  const step = await storage.createStep({
199
172
  runId,
200
- stepKey: "step1",
201
- stepName: "First Step",
202
- status: "running",
173
+ stepKey: 'step1',
174
+ stepName: 'First Step',
175
+ status: 'running',
203
176
  attempt: 1,
204
177
  startedAt: new Date(),
205
178
  });
206
179
 
207
180
  expect(step.id).toBeDefined();
208
- expect(step.stepKey).toBe("step1");
181
+ expect(step.stepKey).toBe('step1');
209
182
 
210
183
  const retrieved = await storage.getStep(step.id);
211
184
  expect(retrieved).not.toBeNull();
212
- expect(retrieved!.stepKey).toBe("step1");
185
+ expect(retrieved!.stepKey).toBe('step1');
213
186
  });
214
187
 
215
- it("should update step status and result", async () => {
188
+ it('should update step status and result', async () => {
216
189
  const step = await storage.createStep({
217
190
  runId,
218
- stepKey: "step1",
219
- stepName: "First Step",
220
- status: "running",
191
+ stepKey: 'step1',
192
+ stepName: 'First Step',
193
+ status: 'running',
221
194
  attempt: 1,
222
195
  startedAt: new Date(),
223
196
  });
224
197
 
225
198
  await storage.updateStep(step.id, {
226
- status: "succeeded",
199
+ status: 'succeeded',
227
200
  result: { data: [1, 2, 3] },
228
201
  finishedAt: new Date(),
229
202
  });
230
203
 
231
204
  const updated = await storage.getStep(step.id);
232
- expect(updated!.status).toBe("succeeded");
205
+ expect(updated!.status).toBe('succeeded');
233
206
  expect(updated!.result).toEqual({ data: [1, 2, 3] });
234
207
  });
235
208
 
236
- it("should get all steps for a run", async () => {
237
- await storage.createStep({
238
- runId,
239
- stepKey: "step1",
240
- stepName: "Step 1",
241
- status: "succeeded",
242
- attempt: 1,
243
- startedAt: new Date(),
244
- });
245
- await storage.createStep({
246
- runId,
247
- stepKey: "step2",
248
- stepName: "Step 2",
249
- status: "succeeded",
250
- attempt: 1,
251
- startedAt: new Date(),
252
- });
253
- await storage.createStep({
254
- runId,
255
- stepKey: "step3",
256
- stepName: "Step 3",
257
- status: "running",
258
- attempt: 1,
259
- startedAt: new Date(),
260
- });
209
+ it('should get all steps for a run', async () => {
210
+ await storage.createStep({ runId, stepKey: 'step1', stepName: 'Step 1', status: 'succeeded', attempt: 1, startedAt: new Date() });
211
+ await storage.createStep({ runId, stepKey: 'step2', stepName: 'Step 2', status: 'succeeded', attempt: 1, startedAt: new Date() });
212
+ await storage.createStep({ runId, stepKey: 'step3', stepName: 'Step 3', status: 'running', attempt: 1, startedAt: new Date() });
261
213
 
262
214
  const steps = await storage.getStepsForRun(runId);
263
215
  expect(steps).toHaveLength(3);
264
216
  });
265
217
  });
266
218
 
267
- describe("event operations", () => {
219
+ describe('event operations', () => {
268
220
  let runId: string;
269
221
 
270
222
  beforeEach(async () => {
271
223
  const run = await storage.createRun({
272
- kind: "test.workflow",
273
- status: "running",
224
+ kind: 'test.workflow',
225
+ status: 'running',
274
226
  input: {},
275
227
  metadata: {},
276
228
  context: {},
@@ -278,127 +230,86 @@ describe("SQLiteStorageAdapter", () => {
278
230
  runId = run.id;
279
231
  });
280
232
 
281
- it("should save and retrieve events", async () => {
233
+ it('should save and retrieve events', async () => {
282
234
  await storage.saveEvent({
283
235
  runId,
284
- eventType: "run.started",
285
- level: "info",
236
+ eventType: 'run.started',
237
+ level: 'info',
286
238
  timestamp: new Date(),
287
239
  });
288
240
 
289
241
  await storage.saveEvent({
290
242
  runId,
291
- stepKey: "step1",
292
- eventType: "step.completed",
293
- level: "info",
294
- payload: { result: "success" },
243
+ stepKey: 'step1',
244
+ eventType: 'step.completed',
245
+ level: 'info',
246
+ payload: { result: 'success' },
295
247
  timestamp: new Date(),
296
248
  });
297
249
 
298
250
  const events = await storage.getEventsForRun(runId);
299
251
  expect(events).toHaveLength(2);
300
- expect(events[0].eventType).toBe("run.started");
301
- expect(events[1].eventType).toBe("step.completed");
252
+ expect(events[0].eventType).toBe('run.started');
253
+ expect(events[1].eventType).toBe('step.completed');
302
254
  });
303
255
 
304
- it("should filter events by step", async () => {
305
- await storage.saveEvent({
306
- runId,
307
- eventType: "run.started",
308
- level: "info",
309
- timestamp: new Date(),
310
- });
311
- await storage.saveEvent({
312
- runId,
313
- stepKey: "step1",
314
- eventType: "step.started",
315
- level: "info",
316
- timestamp: new Date(),
317
- });
318
- await storage.saveEvent({
319
- runId,
320
- stepKey: "step1",
321
- eventType: "step.completed",
322
- level: "info",
323
- timestamp: new Date(),
324
- });
325
- await storage.saveEvent({
326
- runId,
327
- stepKey: "step2",
328
- eventType: "step.started",
329
- level: "info",
330
- timestamp: new Date(),
331
- });
256
+ it('should filter events by step', async () => {
257
+ await storage.saveEvent({ runId, eventType: 'run.started', level: 'info', timestamp: new Date() });
258
+ await storage.saveEvent({ runId, stepKey: 'step1', eventType: 'step.started', level: 'info', timestamp: new Date() });
259
+ await storage.saveEvent({ runId, stepKey: 'step1', eventType: 'step.completed', level: 'info', timestamp: new Date() });
260
+ await storage.saveEvent({ runId, stepKey: 'step2', eventType: 'step.started', level: 'info', timestamp: new Date() });
332
261
 
333
- const step1Events = await storage.getEventsForRun(runId, {
334
- stepKey: "step1",
335
- });
262
+ const step1Events = await storage.getEventsForRun(runId, { stepKey: 'step1' });
336
263
  expect(step1Events).toHaveLength(2);
337
264
  });
338
265
 
339
- it("should filter events by level", async () => {
340
- await storage.saveEvent({
341
- runId,
342
- eventType: "run.started",
343
- level: "info",
344
- timestamp: new Date(),
345
- });
346
- await storage.saveEvent({
347
- runId,
348
- eventType: "step.failed",
349
- level: "error",
350
- timestamp: new Date(),
351
- });
352
- await storage.saveEvent({
353
- runId,
354
- eventType: "step.retry",
355
- level: "warn",
356
- timestamp: new Date(),
357
- });
266
+ it('should filter events by level', async () => {
267
+ await storage.saveEvent({ runId, eventType: 'run.started', level: 'info', timestamp: new Date() });
268
+ await storage.saveEvent({ runId, eventType: 'step.failed', level: 'error', timestamp: new Date() });
269
+ await storage.saveEvent({ runId, eventType: 'step.retry', level: 'warn', timestamp: new Date() });
358
270
 
359
- const errorEvents = await storage.getEventsForRun(runId, {
360
- level: "error",
361
- });
271
+ const errorEvents = await storage.getEventsForRun(runId, { level: 'error' });
362
272
  expect(errorEvents).toHaveLength(1);
363
- expect(errorEvents[0].eventType).toBe("step.failed");
273
+ expect(errorEvents[0].eventType).toBe('step.failed');
364
274
  });
365
275
  });
366
276
 
367
- describe("transaction", () => {
368
- it("should execute operations within a synchronous transaction", () => {
277
+ describe('transaction', () => {
278
+ it('should execute operations within a synchronous transaction', () => {
369
279
  // Use the synchronous transaction method for better-sqlite3
370
280
  const result = storage.transactionSync(() => {
371
281
  // Note: We access the underlying sync methods via the statements
372
- const id = "test-tx-run";
373
- storage["stmts"]!.insertRun.run(
282
+ const id = 'test-tx-run';
283
+ storage['stmts']!.insertRun.run(
374
284
  id,
375
- "test.workflow",
376
- "queued",
285
+ 'test.workflow',
286
+ 'queued',
377
287
  null,
378
288
  JSON.stringify({}),
379
289
  JSON.stringify({}),
380
290
  JSON.stringify({}),
381
291
  null,
382
- new Date().toISOString(),
383
292
  null,
293
+ new Date().toISOString(),
384
294
  null,
295
+ null
385
296
  );
386
- storage["stmts"]!.updateRun.run("running", null, null, null, null, id);
297
+ storage['stmts']!.updateRun.run('running', null, null, null, null, null, id);
387
298
  return id;
388
299
  });
389
300
 
390
- expect(result).toBe("test-tx-run");
301
+ expect(result).toBe('test-tx-run');
391
302
  });
392
303
 
393
- it("should rollback on error", async () => {
304
+ it('should rollback on error', async () => {
394
305
  const initialStats = storage.getStats();
395
306
 
396
307
  try {
397
308
  storage.transactionSync(() => {
398
- storage["stmts"]!.insertRun.run(
399
- "rollback-test",
400
- "test.workflow",
401
- "queued",
309
+ storage['stmts']!.insertRun.run(
310
+ 'rollback-test',
311
+ 'test.workflow',
312
+ 'queued',
402
313
  null,
403
314
  JSON.stringify({}),
404
315
  JSON.stringify({}),
@@ -406,9 +317,9 @@ describe("SQLiteStorageAdapter", () => {
406
317
  null,
407
318
  new Date().toISOString(),
408
319
  null,
409
- null,
320
+ null
410
321
  );
411
- throw new Error("Simulated error");
322
+ throw new Error('Simulated error');
412
323
  });
413
324
  } catch {
414
325
  // Expected
@@ -419,12 +330,12 @@ describe("SQLiteStorageAdapter", () => {
419
330
  });
420
331
  });
421
332
 
422
- describe("deleteOldRuns", () => {
423
- it("should delete runs older than the specified date", async () => {
333
+ describe('deleteOldRuns', () => {
334
+ it('should delete runs older than the specified date', async () => {
424
335
  // Create a run
425
336
  const run = await storage.createRun({
426
- kind: "test.workflow",
427
- status: "succeeded",
337
+ kind: 'test.workflow',
338
+ status: 'succeeded',
428
339
  input: {},
429
340
  metadata: {},
430
341
  context: {},
@@ -433,17 +344,17 @@ describe("SQLiteStorageAdapter", () => {
433
344
  // Create a step for the run
434
345
  await storage.createStep({
435
346
  runId: run.id,
436
- stepKey: "step1",
437
- stepName: "Step 1",
438
- status: "succeeded",
347
+ stepKey: 'step1',
348
+ stepName: 'Step 1',
349
+ status: 'succeeded',
439
350
  attempt: 1,
440
351
  });
441
352
 
442
353
  // Create an event for the run
443
354
  await storage.saveEvent({
444
355
  runId: run.id,
445
- eventType: "run.completed",
446
- level: "info",
356
+ eventType: 'run.completed',
357
+ level: 'info',
447
358
  timestamp: new Date(),
448
359
  });
449
360
 
@@ -467,48 +378,22 @@ describe("SQLiteStorageAdapter", () => {
467
378
  });
468
379
  });
469
380
 
470
- describe("resume support", () => {
471
- it("should get interrupted runs", async () => {
472
- await storage.createRun({
473
- kind: "workflow.a",
474
- status: "succeeded",
475
- input: {},
476
- metadata: {},
477
- context: {},
478
- });
479
- await storage.createRun({
480
- kind: "workflow.a",
481
- status: "running",
482
- input: {},
483
- metadata: {},
484
- context: {},
485
- });
486
- await storage.createRun({
487
- kind: "workflow.b",
488
- status: "queued",
489
- input: {},
490
- metadata: {},
491
- context: {},
492
- });
493
- await storage.createRun({
494
- kind: "workflow.b",
495
- status: "failed",
496
- input: {},
497
- metadata: {},
498
- context: {},
499
- });
381
+ describe('resume support', () => {
382
+ it('should get interrupted runs', async () => {
383
+ await storage.createRun({ kind: 'workflow.a', status: 'succeeded', input: {}, metadata: {}, context: {} });
384
+ await storage.createRun({ kind: 'workflow.a', status: 'running', input: {}, metadata: {}, context: {} });
385
+ await storage.createRun({ kind: 'workflow.b', status: 'queued', input: {}, metadata: {}, context: {} });
386
+ await storage.createRun({ kind: 'workflow.b', status: 'failed', input: {}, metadata: {}, context: {} });
500
387
 
501
388
  const interrupted = await storage.getInterruptedRuns();
502
389
  expect(interrupted).toHaveLength(2);
503
- expect(
504
- interrupted.every((r) => ["queued", "running"].includes(r.status)),
505
- ).toBe(true);
390
+ expect(interrupted.every(r => ['queued', 'running'].includes(r.status))).toBe(true);
506
391
  });
507
392
 
508
- it("should get last completed step", async () => {
393
+ it('should get last completed step', async () => {
509
394
  const run = await storage.createRun({
510
- kind: "test.workflow",
511
- status: "running",
395
+ kind: 'test.workflow',
396
+ status: 'running',
512
397
  input: {},
513
398
  metadata: {},
514
399
  context: {},
@@ -517,9 +402,9 @@ describe("SQLiteStorageAdapter", () => {
517
402
  const now = new Date();
518
403
  await storage.createStep({
519
404
  runId: run.id,
520
- stepKey: "step1",
521
- stepName: "Step 1",
522
- status: "succeeded",
405
+ stepKey: 'step1',
406
+ stepName: 'Step 1',
407
+ status: 'succeeded',
523
408
  attempt: 1,
524
409
  startedAt: now,
525
410
  finishedAt: new Date(now.getTime() + 100),
@@ -527,9 +412,9 @@ describe("SQLiteStorageAdapter", () => {
527
412
 
528
413
  await storage.createStep({
529
414
  runId: run.id,
530
- stepKey: "step2",
531
- stepName: "Step 2",
532
- status: "succeeded",
415
+ stepKey: 'step2',
416
+ stepName: 'Step 2',
417
+ status: 'succeeded',
533
418
  attempt: 1,
534
419
  startedAt: new Date(now.getTime() + 200),
535
420
  finishedAt: new Date(now.getTime() + 300),
@@ -537,52 +422,40 @@ describe("SQLiteStorageAdapter", () => {
537
422
 
538
423
  await storage.createStep({
539
424
  runId: run.id,
540
- stepKey: "step3",
541
- stepName: "Step 3",
542
- status: "running",
425
+ stepKey: 'step3',
426
+ stepName: 'Step 3',
427
+ status: 'running',
543
428
  attempt: 1,
544
429
  startedAt: new Date(now.getTime() + 400),
545
430
  });
546
431
 
547
432
  const lastCompleted = await storage.getLastCompletedStep(run.id);
548
433
  expect(lastCompleted).not.toBeNull();
549
- expect(lastCompleted!.stepKey).toBe("step2");
434
+ expect(lastCompleted!.stepKey).toBe('step2');
550
435
  });
551
436
  });
552
437
 
553
- describe("deprecated transaction() returns callback result", () => {
554
- it("should return the callback result for sync operations", async () => {
438
+ describe('deprecated transaction() returns callback result', () => {
439
+ it('should return the callback result for sync operations', async () => {
555
440
  const result = await storage.transaction(async () => {
556
441
  return 42;
557
442
  });
558
443
  expect(result).toBe(42);
559
444
  });
560
445
 
561
- it("should return the callback result when awaiting resolved promises", async () => {
446
+ it('should return the callback result when awaiting resolved promises', async () => {
562
447
  const result = await storage.transaction(async () => {
563
448
  await Promise.resolve();
564
- return "hello";
449
+ return 'hello';
565
450
  });
566
- expect(result).toBe("hello");
451
+ expect(result).toBe('hello');
567
452
  });
568
453
  });
569
454
 
570
- describe("getStats", () => {
571
- it("should return database statistics", async () => {
572
- await storage.createRun({
573
- kind: "test",
574
- status: "queued",
575
- input: {},
576
- metadata: {},
577
- context: {},
578
- });
579
- await storage.createRun({
580
- kind: "test",
581
- status: "queued",
582
- input: {},
583
- metadata: {},
584
- context: {},
585
- });
455
+ describe('getStats', () => {
456
+ it('should return database statistics', async () => {
457
+ await storage.createRun({ kind: 'test', status: 'queued', input: {}, metadata: {}, context: {} });
458
+ await storage.createRun({ kind: 'test', status: 'queued', input: {}, metadata: {}, context: {} });
586
459
 
587
460
  const stats = storage.getStats();
588
461
  expect(stats.runs).toBe(2);