@multiplier-labs/stepflow 0.3.4 → 0.3.6

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 (99) hide show
  1. package/README.md +9 -0
  2. package/dist/{chunk-U3PCVK6O.js → chunk-D5HW7VEG.js} +4 -2
  3. package/dist/chunk-D5HW7VEG.js.map +1 -0
  4. package/dist/{chunk-5XJBAPXF.js → chunk-JUPZEBR3.js} +3 -1
  5. package/dist/{chunk-5XJBAPXF.js.map → chunk-JUPZEBR3.js.map} +1 -1
  6. package/dist/events/index.d.ts +2 -0
  7. package/dist/events/index.js +1 -1
  8. package/dist/index.js +2 -2
  9. package/dist/storage/index.js +1 -1
  10. package/package.json +23 -12
  11. package/.codekin/reports/code-review/2026-04-11_code-review-daily.md +0 -146
  12. package/.codekin/reports/code-review/2026-04-13_code-review-daily.md +0 -74
  13. package/.codekin/reports/comments/2026-04-04_comment-assessment.md +0 -179
  14. package/.codekin/reports/comments/2026-04-11_comment-assessment.md +0 -161
  15. package/.codekin/reports/comments/2026-04-14_comment-assessment.md +0 -34
  16. package/.codekin/reports/complexity/2026-04-03_complexity-report.md +0 -152
  17. package/.codekin/reports/complexity/2026-04-11_complexity-report.md +0 -152
  18. package/.codekin/reports/complexity/2026-04-14_complexity-report.md +0 -34
  19. package/.codekin/reports/dependencies/2026-04-04_dependency-health.md +0 -94
  20. package/.codekin/reports/dependencies/2026-04-11_dependency-health.md +0 -93
  21. package/.codekin/reports/docs-audit/2026-04-04_docs-audit.md +0 -10
  22. package/.codekin/reports/docs-audit/2026-04-11_docs-audit.md +0 -138
  23. package/.codekin/reports/docs-audit/2026-04-13_docs-audit.md +0 -121
  24. package/.codekin/reports/security/2026-04-03_security-audit.md +0 -208
  25. package/.codekin/reports/security/2026-04-11_security-audit.md +0 -297
  26. package/.github/CODEOWNERS +0 -15
  27. package/.github/dependabot.yml +0 -23
  28. package/.github/workflows/ci.yml +0 -38
  29. package/.github/workflows/publish.yml +0 -42
  30. package/.github/workflows/security.yml +0 -29
  31. package/CHANGELOG.md +0 -34
  32. package/SECURITY.md +0 -40
  33. package/dist/chunk-U3PCVK6O.js.map +0 -1
  34. package/docs/github-packages-setup.md +0 -97
  35. package/docs/stepflow-api-reference.md +0 -1663
  36. package/src/core/engine/concurrency.ts +0 -229
  37. package/src/core/engine/lifecycle.ts +0 -176
  38. package/src/core/engine.test.ts +0 -1435
  39. package/src/core/engine.ts +0 -598
  40. package/src/core/index.ts +0 -7
  41. package/src/core/orchestrator/persistence.ts +0 -165
  42. package/src/core/orchestrator/plan-resolution.ts +0 -140
  43. package/src/core/orchestrator/state-transitions.ts +0 -109
  44. package/src/core/orchestrator/step-runner.ts +0 -427
  45. package/src/core/orchestrator.ts +0 -252
  46. package/src/core/types.ts +0 -220
  47. package/src/events/index.ts +0 -8
  48. package/src/events/memory.test.ts +0 -107
  49. package/src/events/memory.ts +0 -92
  50. package/src/events/socketio.test.ts +0 -378
  51. package/src/events/socketio.ts +0 -262
  52. package/src/events/types.ts +0 -118
  53. package/src/events/webhook.test.ts +0 -949
  54. package/src/events/webhook.ts +0 -807
  55. package/src/index.ts +0 -270
  56. package/src/planning/evaluate-condition.test.ts +0 -153
  57. package/src/planning/evaluate-condition.ts +0 -105
  58. package/src/planning/index.ts +0 -55
  59. package/src/planning/planner.ts +0 -494
  60. package/src/planning/planning.test.ts +0 -727
  61. package/src/planning/registry.test.ts +0 -398
  62. package/src/planning/registry.ts +0 -283
  63. package/src/planning/types.ts +0 -566
  64. package/src/scheduler/cron.test.ts +0 -479
  65. package/src/scheduler/cron.ts +0 -438
  66. package/src/scheduler/index.ts +0 -8
  67. package/src/scheduler/postgres-persistence.ts +0 -530
  68. package/src/scheduler/sqlite-persistence.test.ts +0 -235
  69. package/src/scheduler/sqlite-persistence.ts +0 -286
  70. package/src/scheduler/types.ts +0 -73
  71. package/src/storage/index.ts +0 -27
  72. package/src/storage/memory.test.ts +0 -349
  73. package/src/storage/memory.ts +0 -227
  74. package/src/storage/postgres-core.ts +0 -550
  75. package/src/storage/postgres-migration.test.ts +0 -69
  76. package/src/storage/postgres-transaction-pagination.test.ts +0 -107
  77. package/src/storage/postgres.ts +0 -835
  78. package/src/storage/sqlite-core.ts +0 -151
  79. package/src/storage/sqlite.test.ts +0 -642
  80. package/src/storage/sqlite.ts +0 -717
  81. package/src/storage/types.ts +0 -343
  82. package/src/utils/errors.test.ts +0 -150
  83. package/src/utils/errors.ts +0 -161
  84. package/src/utils/id.ts +0 -21
  85. package/src/utils/index.ts +0 -10
  86. package/src/utils/logger.test.ts +0 -121
  87. package/src/utils/logger.ts +0 -96
  88. package/src/utils/pinned-fetch.test.ts +0 -84
  89. package/src/utils/pinned-fetch.ts +0 -118
  90. package/src/utils/postgres-deps.ts +0 -79
  91. package/src/utils/retry.test.ts +0 -177
  92. package/src/utils/retry.ts +0 -121
  93. package/src/utils/safe-json.test.ts +0 -166
  94. package/src/utils/safe-json.ts +0 -107
  95. package/src/utils/webhook-signature.test.ts +0 -111
  96. package/src/utils/webhook-signature.ts +0 -74
  97. package/tsconfig.json +0 -21
  98. package/tsup.config.ts +0 -14
  99. package/vitest.config.ts +0 -9
@@ -1,235 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import Database from 'better-sqlite3';
3
- import { SQLiteSchedulePersistence } from './sqlite-persistence';
4
- import type { WorkflowSchedule } from './types';
5
-
6
- describe('SQLiteSchedulePersistence', () => {
7
- let db: Database.Database;
8
- let persistence: SQLiteSchedulePersistence;
9
-
10
- beforeEach(() => {
11
- // Use in-memory database for testing
12
- db = new Database(':memory:');
13
- persistence = new SQLiteSchedulePersistence({ db });
14
- });
15
-
16
- afterEach(() => {
17
- db.close();
18
- });
19
-
20
- describe('saveSchedule', () => {
21
- it('should save a cron schedule', async () => {
22
- const schedule: WorkflowSchedule = {
23
- id: 'test-1',
24
- workflowKind: 'test.workflow',
25
- triggerType: 'cron',
26
- cronExpression: '0 * * * *',
27
- timezone: 'UTC',
28
- enabled: true,
29
- input: { foo: 'bar' },
30
- metadata: { user: 'test' },
31
- };
32
-
33
- await persistence.saveSchedule(schedule);
34
-
35
- const loaded = await persistence.loadSchedules();
36
- expect(loaded).toHaveLength(1);
37
- expect(loaded[0].id).toBe('test-1');
38
- expect(loaded[0].cronExpression).toBe('0 * * * *');
39
- expect(loaded[0].input).toEqual({ foo: 'bar' });
40
- });
41
-
42
- it('should save a workflow completion trigger', async () => {
43
- const schedule: WorkflowSchedule = {
44
- id: 'test-2',
45
- workflowKind: 'notification.send',
46
- triggerType: 'workflow_completed',
47
- triggerOnWorkflowKind: 'order.process',
48
- triggerOnStatus: ['succeeded', 'failed'],
49
- enabled: true,
50
- };
51
-
52
- await persistence.saveSchedule(schedule);
53
-
54
- const loaded = await persistence.loadSchedules();
55
- expect(loaded).toHaveLength(1);
56
- expect(loaded[0].triggerType).toBe('workflow_completed');
57
- expect(loaded[0].triggerOnWorkflowKind).toBe('order.process');
58
- expect(loaded[0].triggerOnStatus).toEqual(['succeeded', 'failed']);
59
- });
60
-
61
- it('should save schedule with dates', async () => {
62
- const lastRunAt = new Date('2024-01-01T12:00:00Z');
63
- const nextRunAt = new Date('2024-01-01T13:00:00Z');
64
-
65
- const schedule: WorkflowSchedule = {
66
- id: 'test-3',
67
- workflowKind: 'test.workflow',
68
- triggerType: 'cron',
69
- cronExpression: '0 * * * *',
70
- enabled: true,
71
- lastRunAt,
72
- lastRunId: 'run-123',
73
- nextRunAt,
74
- };
75
-
76
- await persistence.saveSchedule(schedule);
77
-
78
- const loaded = await persistence.loadSchedules();
79
- expect(loaded[0].lastRunAt).toEqual(lastRunAt);
80
- expect(loaded[0].lastRunId).toBe('run-123');
81
- expect(loaded[0].nextRunAt).toEqual(nextRunAt);
82
- });
83
- });
84
-
85
- describe('loadSchedules', () => {
86
- it('should return empty array when no schedules', async () => {
87
- const schedules = await persistence.loadSchedules();
88
- expect(schedules).toHaveLength(0);
89
- });
90
-
91
- it('should load multiple schedules', async () => {
92
- await persistence.saveSchedule({
93
- id: 'schedule-1',
94
- workflowKind: 'workflow.a',
95
- triggerType: 'cron',
96
- cronExpression: '0 * * * *',
97
- enabled: true,
98
- });
99
-
100
- await persistence.saveSchedule({
101
- id: 'schedule-2',
102
- workflowKind: 'workflow.b',
103
- triggerType: 'manual',
104
- enabled: false,
105
- });
106
-
107
- const schedules = await persistence.loadSchedules();
108
- expect(schedules).toHaveLength(2);
109
- });
110
- });
111
-
112
- describe('updateSchedule', () => {
113
- it('should update enabled status', async () => {
114
- await persistence.saveSchedule({
115
- id: 'update-1',
116
- workflowKind: 'test.workflow',
117
- triggerType: 'cron',
118
- cronExpression: '0 * * * *',
119
- enabled: true,
120
- });
121
-
122
- await persistence.updateSchedule('update-1', { enabled: false });
123
-
124
- const loaded = await persistence.loadSchedules();
125
- expect(loaded[0].enabled).toBe(false);
126
- });
127
-
128
- it('should update cron expression', async () => {
129
- await persistence.saveSchedule({
130
- id: 'update-2',
131
- workflowKind: 'test.workflow',
132
- triggerType: 'cron',
133
- cronExpression: '0 * * * *',
134
- enabled: true,
135
- });
136
-
137
- await persistence.updateSchedule('update-2', {
138
- cronExpression: '30 * * * *',
139
- });
140
-
141
- const loaded = await persistence.loadSchedules();
142
- expect(loaded[0].cronExpression).toBe('30 * * * *');
143
- });
144
-
145
- it('should update lastRunAt and lastRunId', async () => {
146
- await persistence.saveSchedule({
147
- id: 'update-3',
148
- workflowKind: 'test.workflow',
149
- triggerType: 'cron',
150
- cronExpression: '0 * * * *',
151
- enabled: true,
152
- });
153
-
154
- const now = new Date();
155
- await persistence.updateSchedule('update-3', {
156
- lastRunAt: now,
157
- lastRunId: 'run-456',
158
- });
159
-
160
- const loaded = await persistence.loadSchedules();
161
- expect(loaded[0].lastRunAt).toEqual(now);
162
- expect(loaded[0].lastRunId).toBe('run-456');
163
- });
164
-
165
- it('should throw for non-existent schedule', async () => {
166
- await expect(
167
- persistence.updateSchedule('nonexistent', { enabled: false })
168
- ).rejects.toThrow('Schedule not found');
169
- });
170
- });
171
-
172
- describe('deleteSchedule', () => {
173
- it('should delete a schedule', async () => {
174
- await persistence.saveSchedule({
175
- id: 'delete-1',
176
- workflowKind: 'test.workflow',
177
- triggerType: 'cron',
178
- cronExpression: '0 * * * *',
179
- enabled: true,
180
- });
181
-
182
- await persistence.deleteSchedule('delete-1');
183
-
184
- const loaded = await persistence.loadSchedules();
185
- expect(loaded).toHaveLength(0);
186
- });
187
-
188
- it('should handle deleting non-existent schedule gracefully', async () => {
189
- // This should not throw
190
- await persistence.deleteSchedule('nonexistent');
191
- });
192
- });
193
-
194
- describe('data integrity', () => {
195
- it('should preserve all fields through save/load cycle', async () => {
196
- const schedule: WorkflowSchedule = {
197
- id: 'integrity-1',
198
- workflowKind: 'complex.workflow',
199
- triggerType: 'workflow_completed',
200
- triggerOnWorkflowKind: 'parent.workflow',
201
- triggerOnStatus: ['succeeded'],
202
- input: { nested: { value: 123 } },
203
- metadata: { tags: ['a', 'b'] },
204
- enabled: true,
205
- lastRunAt: new Date('2024-06-15T10:30:00Z'),
206
- lastRunId: 'run-789',
207
- nextRunAt: new Date('2024-06-15T11:00:00Z'),
208
- };
209
-
210
- await persistence.saveSchedule(schedule);
211
-
212
- const loaded = await persistence.loadSchedules();
213
- expect(loaded[0]).toEqual(schedule);
214
- });
215
-
216
- it('should handle null/undefined values correctly', async () => {
217
- const schedule: WorkflowSchedule = {
218
- id: 'nullable-1',
219
- workflowKind: 'test.workflow',
220
- triggerType: 'manual',
221
- enabled: false,
222
- // All other optional fields are undefined
223
- };
224
-
225
- await persistence.saveSchedule(schedule);
226
-
227
- const loaded = await persistence.loadSchedules();
228
- expect(loaded[0].cronExpression).toBeUndefined();
229
- expect(loaded[0].timezone).toBeUndefined();
230
- expect(loaded[0].input).toBeUndefined();
231
- expect(loaded[0].metadata).toBeUndefined();
232
- expect(loaded[0].lastRunAt).toBeUndefined();
233
- });
234
- });
235
- });
@@ -1,286 +0,0 @@
1
- /**
2
- * SQLite persistence adapter for schedules.
3
- *
4
- * Stores workflow schedules in a SQLite database table.
5
- */
6
-
7
- import type { Database, Statement } from 'better-sqlite3';
8
- import type { WorkflowSchedule } from './types';
9
- import type { SchedulePersistence } from './cron';
10
- import type { Logger, RunStatus } from '../core/types';
11
- import { generateId } from '../utils/id';
12
- import { safeJsonParse as sharedSafeJsonParse } from '../utils/safe-json';
13
-
14
- // ============================================================================
15
- // Configuration Types
16
- // ============================================================================
17
-
18
- /**
19
- * Configuration for SQLiteSchedulePersistence.
20
- */
21
- export interface SQLiteSchedulePersistenceConfig {
22
- /** SQLite database instance */
23
- db: Database;
24
-
25
- /** Table name for schedules (default: workflow_schedules) */
26
- tableName?: string;
27
-
28
- /**
29
- * Optional structured logger used to surface JSON corruption events.
30
- * Without one, parse failures still increment the corruption counter
31
- * exposed via `getJsonParseCorruptionCount()` but produce no log output.
32
- */
33
- logger?: Logger;
34
- }
35
-
36
- // ============================================================================
37
- // SQLiteSchedulePersistence Class
38
- // ============================================================================
39
-
40
- /**
41
- * SQLite-based persistence for workflow schedules.
42
- *
43
- * @example
44
- * ```typescript
45
- * import Database from 'better-sqlite3';
46
- *
47
- * const db = new Database('workflow.db');
48
- * const persistence = new SQLiteSchedulePersistence({ db });
49
- *
50
- * const scheduler = new CronScheduler({
51
- * engine,
52
- * persistence,
53
- * });
54
- * ```
55
- */
56
- export class SQLiteSchedulePersistence implements SchedulePersistence {
57
- private db: Database;
58
- private tableName: string;
59
- private logger: Logger | undefined;
60
- private stmts: {
61
- insert: Statement;
62
- update: Statement;
63
- delete: Statement;
64
- getAll: Statement;
65
- getById: Statement;
66
- } | null = null;
67
-
68
- constructor(config: SQLiteSchedulePersistenceConfig) {
69
- this.db = config.db;
70
- this.tableName = config.tableName ?? 'workflow_schedules';
71
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(this.tableName)) {
72
- throw new Error(`Invalid table name: ${this.tableName}`);
73
- }
74
- this.logger = config.logger;
75
- this.initializeDatabase();
76
- }
77
-
78
- // ============================================================================
79
- // Database Initialization
80
- // ============================================================================
81
-
82
- private initializeDatabase(): void {
83
- // Create schedules table.
84
- // Schema layout:
85
- // id — unique schedule identifier (TEXT PK)
86
- // workflow_kind — target workflow type to spawn
87
- // trigger_type — 'cron', 'workflow_completed', or 'manual'
88
- // cron_expression — cron expression for time-based triggers (nullable)
89
- // timezone — IANA timezone for cron evaluation (nullable)
90
- // trigger_on_* — fields for workflow-completion triggers
91
- // input / metadata — JSON-serialized payloads for spawned runs
92
- // enabled — whether this schedule is active (0/1)
93
- // last_run_at/id — most recent execution tracking
94
- // next_run_at — next scheduled execution time
95
- // created_at/updated_at — audit timestamps
96
- // No migration strategy is currently implemented; table is created idempotently.
97
- this.db.exec(`
98
- CREATE TABLE IF NOT EXISTS ${this.tableName} (
99
- id TEXT PRIMARY KEY,
100
- workflow_kind TEXT NOT NULL,
101
- trigger_type TEXT NOT NULL,
102
- cron_expression TEXT,
103
- timezone TEXT,
104
- trigger_on_workflow_kind TEXT,
105
- trigger_on_status TEXT,
106
- input TEXT,
107
- metadata TEXT,
108
- enabled INTEGER NOT NULL DEFAULT 1,
109
- last_run_at TEXT,
110
- last_run_id TEXT,
111
- next_run_at TEXT,
112
- created_at TEXT NOT NULL DEFAULT (datetime('now')),
113
- updated_at TEXT NOT NULL DEFAULT (datetime('now'))
114
- )
115
- `);
116
-
117
- // Create indexes
118
- this.db.exec(`
119
- CREATE INDEX IF NOT EXISTS idx_${this.tableName}_workflow_kind
120
- ON ${this.tableName}(workflow_kind);
121
-
122
- CREATE INDEX IF NOT EXISTS idx_${this.tableName}_enabled
123
- ON ${this.tableName}(enabled);
124
-
125
- CREATE INDEX IF NOT EXISTS idx_${this.tableName}_trigger_type
126
- ON ${this.tableName}(trigger_type);
127
- `);
128
-
129
- // Prepare statements
130
- this.stmts = {
131
- insert: this.db.prepare(`
132
- INSERT INTO ${this.tableName} (
133
- id, workflow_kind, trigger_type, cron_expression, timezone,
134
- trigger_on_workflow_kind, trigger_on_status, input, metadata,
135
- enabled, last_run_at, last_run_id, next_run_at
136
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
137
- `),
138
- update: this.db.prepare(`
139
- UPDATE ${this.tableName}
140
- SET workflow_kind = COALESCE(?, workflow_kind),
141
- trigger_type = COALESCE(?, trigger_type),
142
- cron_expression = ?,
143
- timezone = ?,
144
- trigger_on_workflow_kind = ?,
145
- trigger_on_status = ?,
146
- input = ?,
147
- metadata = ?,
148
- enabled = COALESCE(?, enabled),
149
- last_run_at = ?,
150
- last_run_id = ?,
151
- next_run_at = ?,
152
- updated_at = datetime('now')
153
- WHERE id = ?
154
- `),
155
- delete: this.db.prepare(`
156
- DELETE FROM ${this.tableName} WHERE id = ?
157
- `),
158
- getAll: this.db.prepare(`
159
- SELECT * FROM ${this.tableName}
160
- `),
161
- getById: this.db.prepare(`
162
- SELECT * FROM ${this.tableName} WHERE id = ?
163
- `),
164
- };
165
- }
166
-
167
- // ============================================================================
168
- // SchedulePersistence Interface Implementation
169
- // ============================================================================
170
-
171
- async loadSchedules(): Promise<WorkflowSchedule[]> {
172
- const rows = this.stmts!.getAll.all() as ScheduleRow[];
173
- return rows.map(row => this.rowToSchedule(row));
174
- }
175
-
176
- async saveSchedule(schedule: WorkflowSchedule): Promise<void> {
177
- this.stmts!.insert.run(
178
- schedule.id,
179
- schedule.workflowKind,
180
- schedule.triggerType,
181
- schedule.cronExpression ?? null,
182
- schedule.timezone ?? null,
183
- schedule.triggerOnWorkflowKind ?? null,
184
- schedule.triggerOnStatus ? JSON.stringify(schedule.triggerOnStatus) : null,
185
- schedule.input ? JSON.stringify(schedule.input) : null,
186
- schedule.metadata ? JSON.stringify(schedule.metadata) : null,
187
- schedule.enabled ? 1 : 0,
188
- schedule.lastRunAt?.toISOString() ?? null,
189
- schedule.lastRunId ?? null,
190
- schedule.nextRunAt?.toISOString() ?? null
191
- );
192
- }
193
-
194
- async updateSchedule(scheduleId: string, updates: Partial<WorkflowSchedule>): Promise<void> {
195
- // Get existing schedule to merge with updates
196
- const existing = this.stmts!.getById.get(scheduleId) as ScheduleRow | undefined;
197
- if (!existing) {
198
- throw new Error(`Schedule not found: ${scheduleId}`);
199
- }
200
-
201
- const merged = {
202
- ...this.rowToSchedule(existing),
203
- ...updates,
204
- };
205
-
206
- this.stmts!.update.run(
207
- updates.workflowKind ?? null,
208
- updates.triggerType ?? null,
209
- merged.cronExpression ?? null,
210
- merged.timezone ?? null,
211
- merged.triggerOnWorkflowKind ?? null,
212
- merged.triggerOnStatus ? JSON.stringify(merged.triggerOnStatus) : null,
213
- merged.input ? JSON.stringify(merged.input) : null,
214
- merged.metadata ? JSON.stringify(merged.metadata) : null,
215
- updates.enabled !== undefined ? (updates.enabled ? 1 : 0) : null,
216
- merged.lastRunAt?.toISOString() ?? null,
217
- merged.lastRunId ?? null,
218
- merged.nextRunAt?.toISOString() ?? null,
219
- scheduleId
220
- );
221
- }
222
-
223
- async deleteSchedule(scheduleId: string): Promise<void> {
224
- this.stmts!.delete.run(scheduleId);
225
- }
226
-
227
- // ============================================================================
228
- // Helper Methods
229
- // ============================================================================
230
-
231
- private safeJsonParse(
232
- json: string,
233
- fallback: unknown,
234
- rowId: string,
235
- column: string,
236
- ): unknown {
237
- return sharedSafeJsonParse(json, fallback, {
238
- component: 'SQLiteSchedulePersistence',
239
- rowId,
240
- column,
241
- logger: this.logger,
242
- });
243
- }
244
-
245
- private rowToSchedule(row: ScheduleRow): WorkflowSchedule {
246
- return {
247
- id: row.id,
248
- workflowKind: row.workflow_kind,
249
- triggerType: row.trigger_type as WorkflowSchedule['triggerType'],
250
- cronExpression: row.cron_expression ?? undefined,
251
- timezone: row.timezone ?? undefined,
252
- triggerOnWorkflowKind: row.trigger_on_workflow_kind ?? undefined,
253
- triggerOnStatus: row.trigger_on_status
254
- ? this.safeJsonParse(row.trigger_on_status, undefined, row.id, 'trigger_on_status') as RunStatus[] | undefined
255
- : undefined,
256
- input: row.input ? this.safeJsonParse(row.input, undefined, row.id, 'input') as Record<string, unknown> | undefined : undefined,
257
- metadata: row.metadata ? this.safeJsonParse(row.metadata, undefined, row.id, 'metadata') as Record<string, unknown> | undefined : undefined,
258
- enabled: row.enabled === 1,
259
- lastRunAt: row.last_run_at ? new Date(row.last_run_at) : undefined,
260
- lastRunId: row.last_run_id ?? undefined,
261
- nextRunAt: row.next_run_at ? new Date(row.next_run_at) : undefined,
262
- };
263
- }
264
- }
265
-
266
- // ============================================================================
267
- // Types
268
- // ============================================================================
269
-
270
- interface ScheduleRow {
271
- id: string;
272
- workflow_kind: string;
273
- trigger_type: string;
274
- cron_expression: string | null;
275
- timezone: string | null;
276
- trigger_on_workflow_kind: string | null;
277
- trigger_on_status: string | null;
278
- input: string | null;
279
- metadata: string | null;
280
- enabled: number;
281
- last_run_at: string | null;
282
- last_run_id: string | null;
283
- next_run_at: string | null;
284
- created_at: string;
285
- updated_at: string;
286
- }
@@ -1,73 +0,0 @@
1
- /**
2
- * Scheduler types for the workflow engine.
3
- * Defines the type contracts for the cron and workflow-completion trigger
4
- * scheduler, implemented by {@link CronScheduler}, {@link SQLiteSchedulePersistence},
5
- * and {@link PostgresSchedulePersistence}.
6
- */
7
-
8
- import type { WorkflowKind, RunStatus } from '../core/types';
9
-
10
- /**
11
- * Schedule trigger types.
12
- */
13
- export type TriggerType = 'cron' | 'workflow_completed' | 'manual';
14
-
15
- /**
16
- * Schedule definition.
17
- */
18
- export interface WorkflowSchedule {
19
- id: string;
20
- workflowKind: WorkflowKind;
21
- triggerType: TriggerType;
22
-
23
- /** Cron expression for time-based triggers (e.g. `0 0 * * *` for daily). Only used when triggerType is 'cron'. */
24
- cronExpression?: string;
25
- /** IANA timezone for cron evaluation (e.g. 'America/New_York'). Defaults to 'UTC'. */
26
- timezone?: string;
27
-
28
- /** Workflow kind that triggers this schedule on completion. Only used when triggerType is 'workflow_completed'. */
29
- triggerOnWorkflowKind?: WorkflowKind;
30
- /** Run statuses that activate the completion trigger. If empty, any terminal status triggers. */
31
- triggerOnStatus?: RunStatus[];
32
-
33
- /** Input payload passed to the spawned workflow run. */
34
- input?: Record<string, unknown>;
35
- /** Arbitrary metadata attached to the spawned workflow run. */
36
- metadata?: Record<string, unknown>;
37
-
38
- /** Whether this schedule is active. Disabled schedules are not evaluated. */
39
- enabled: boolean;
40
- /** Timestamp of the most recent run spawned by this schedule. */
41
- lastRunAt?: Date;
42
- /** Run ID of the most recent run spawned by this schedule. */
43
- lastRunId?: string;
44
- /** Next scheduled execution time, computed from the cron expression and timezone. */
45
- nextRunAt?: Date;
46
- }
47
-
48
- /**
49
- * Scheduler interface.
50
- * Implement this to create custom schedulers.
51
- */
52
- export interface Scheduler {
53
- /** Start the scheduler */
54
- start(): Promise<void>;
55
-
56
- /** Stop the scheduler */
57
- stop(): Promise<void>;
58
-
59
- /** Add a schedule */
60
- addSchedule(schedule: Omit<WorkflowSchedule, 'id'>): Promise<WorkflowSchedule>;
61
-
62
- /** Remove a schedule */
63
- removeSchedule(scheduleId: string): Promise<void>;
64
-
65
- /** Update a schedule */
66
- updateSchedule(scheduleId: string, updates: Partial<WorkflowSchedule>): Promise<void>;
67
-
68
- /** Get all schedules */
69
- getSchedules(): Promise<WorkflowSchedule[]>;
70
-
71
- /** Manually trigger a scheduled workflow */
72
- triggerNow(scheduleId: string): Promise<string>;
73
- }
@@ -1,27 +0,0 @@
1
- /**
2
- * Storage module exports.
3
- */
4
-
5
- export * from './types';
6
- export * from './memory';
7
- export * from './sqlite';
8
- export * from './postgres';
9
-
10
- // Re-export specific types for convenience
11
- export type {
12
- WorkflowStorage,
13
- WorkflowRunRecord,
14
- CreateRunInput,
15
- UpdateRunInput,
16
- ListRunsOptions,
17
- PaginatedResult,
18
- StepResult,
19
- StepRecord,
20
- ExtendedWorkflowRunRecord,
21
- ExtendedRunStatus,
22
- ExtendedStepStatus,
23
- ExtendedListRunsOptions,
24
- StepflowRunsTable,
25
- StepflowStepResultsTable,
26
- StepflowDatabase,
27
- } from './types';