@bratsos/workflow-engine 0.0.11 → 0.1.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.
@@ -0,0 +1,344 @@
1
+ /**
2
+ * Persistence Interfaces for Workflow Engine
3
+ *
4
+ * These interfaces abstract database operations to enable:
5
+ * - Testing with mock implementations
6
+ * - Future extraction into @bratsos/workflow-engine package
7
+ * - Alternative database backends
8
+ *
9
+ * Implementations:
10
+ * - PrismaWorkflowPersistence (default, in ./prisma/)
11
+ * - InMemoryPersistence (for testing)
12
+ */
13
+ /**
14
+ * Unified status type for workflows, stages, and jobs.
15
+ *
16
+ * - PENDING: Not started yet
17
+ * - RUNNING: Currently executing
18
+ * - SUSPENDED: Paused, waiting for external event (e.g., batch job completion)
19
+ * - COMPLETED: Finished successfully
20
+ * - FAILED: Finished with error
21
+ * - CANCELLED: Manually stopped by user
22
+ * - SKIPPED: Stage-specific - bypassed due to condition
23
+ */
24
+ type Status = "PENDING" | "RUNNING" | "SUSPENDED" | "COMPLETED" | "FAILED" | "CANCELLED" | "SKIPPED";
25
+ /** @deprecated Use Status instead */
26
+ type WorkflowStatus = Status;
27
+ /** @deprecated Use Status instead */
28
+ type WorkflowStageStatus = Status;
29
+ /** @deprecated Use Status instead. Note: PROCESSING is now RUNNING. */
30
+ type JobStatus = Status;
31
+ type LogLevel = "DEBUG" | "INFO" | "WARN" | "ERROR";
32
+ type ArtifactType = "STAGE_OUTPUT" | "ARTIFACT" | "METADATA";
33
+ interface WorkflowRunRecord {
34
+ id: string;
35
+ createdAt: Date;
36
+ updatedAt: Date;
37
+ workflowId: string;
38
+ workflowName: string;
39
+ workflowType: string;
40
+ status: WorkflowStatus;
41
+ startedAt: Date | null;
42
+ completedAt: Date | null;
43
+ duration: number | null;
44
+ input: unknown;
45
+ output: unknown | null;
46
+ config: unknown;
47
+ totalCost: number;
48
+ totalTokens: number;
49
+ priority: number;
50
+ }
51
+ interface WorkflowStageRecord {
52
+ id: string;
53
+ createdAt: Date;
54
+ updatedAt: Date;
55
+ workflowRunId: string;
56
+ stageId: string;
57
+ stageName: string;
58
+ stageNumber: number;
59
+ executionGroup: number;
60
+ status: WorkflowStageStatus;
61
+ startedAt: Date | null;
62
+ completedAt: Date | null;
63
+ duration: number | null;
64
+ inputData: unknown | null;
65
+ outputData: unknown | null;
66
+ config: unknown | null;
67
+ suspendedState: unknown | null;
68
+ resumeData: unknown | null;
69
+ nextPollAt: Date | null;
70
+ pollInterval: number | null;
71
+ maxWaitUntil: Date | null;
72
+ metrics: unknown | null;
73
+ embeddingInfo: unknown | null;
74
+ errorMessage: string | null;
75
+ }
76
+ interface WorkflowLogRecord {
77
+ id: string;
78
+ createdAt: Date;
79
+ workflowStageId: string | null;
80
+ workflowRunId: string | null;
81
+ level: LogLevel;
82
+ message: string;
83
+ metadata: unknown | null;
84
+ }
85
+ interface WorkflowArtifactRecord {
86
+ id: string;
87
+ createdAt: Date;
88
+ updatedAt: Date;
89
+ workflowRunId: string;
90
+ workflowStageId: string | null;
91
+ key: string;
92
+ type: ArtifactType;
93
+ data: unknown;
94
+ size: number;
95
+ metadata: unknown | null;
96
+ }
97
+ interface AICallRecord {
98
+ id: string;
99
+ createdAt: Date;
100
+ topic: string;
101
+ callType: string;
102
+ modelKey: string;
103
+ modelId: string;
104
+ prompt: string;
105
+ response: string;
106
+ inputTokens: number;
107
+ outputTokens: number;
108
+ cost: number;
109
+ metadata: unknown | null;
110
+ }
111
+ interface JobRecord {
112
+ id: string;
113
+ createdAt: Date;
114
+ updatedAt: Date;
115
+ workflowRunId: string;
116
+ stageId: string;
117
+ status: JobStatus;
118
+ priority: number;
119
+ workerId: string | null;
120
+ lockedAt: Date | null;
121
+ startedAt: Date | null;
122
+ completedAt: Date | null;
123
+ attempt: number;
124
+ maxAttempts: number;
125
+ lastError: string | null;
126
+ nextPollAt: Date | null;
127
+ payload: Record<string, unknown>;
128
+ }
129
+ interface CreateRunInput {
130
+ id?: string;
131
+ workflowId: string;
132
+ workflowName: string;
133
+ workflowType: string;
134
+ input: unknown;
135
+ config?: unknown;
136
+ priority?: number;
137
+ /** Optional metadata for domain-specific fields */
138
+ metadata?: Record<string, unknown>;
139
+ }
140
+ interface UpdateRunInput {
141
+ status?: WorkflowStatus;
142
+ startedAt?: Date;
143
+ completedAt?: Date;
144
+ duration?: number;
145
+ output?: unknown;
146
+ totalCost?: number;
147
+ totalTokens?: number;
148
+ }
149
+ interface CreateStageInput {
150
+ workflowRunId: string;
151
+ stageId: string;
152
+ stageName: string;
153
+ stageNumber: number;
154
+ executionGroup: number;
155
+ status?: WorkflowStageStatus;
156
+ startedAt?: Date;
157
+ config?: unknown;
158
+ inputData?: unknown;
159
+ }
160
+ interface UpdateStageInput {
161
+ status?: WorkflowStageStatus;
162
+ startedAt?: Date;
163
+ completedAt?: Date;
164
+ duration?: number;
165
+ outputData?: unknown;
166
+ config?: unknown;
167
+ suspendedState?: unknown;
168
+ resumeData?: unknown;
169
+ nextPollAt?: Date | null;
170
+ pollInterval?: number;
171
+ maxWaitUntil?: Date;
172
+ metrics?: unknown;
173
+ embeddingInfo?: unknown;
174
+ artifacts?: unknown;
175
+ errorMessage?: string;
176
+ }
177
+ interface UpsertStageInput {
178
+ workflowRunId: string;
179
+ stageId: string;
180
+ create: CreateStageInput;
181
+ update: UpdateStageInput;
182
+ }
183
+ interface CreateLogInput {
184
+ workflowRunId?: string;
185
+ workflowStageId?: string;
186
+ level: LogLevel;
187
+ message: string;
188
+ metadata?: unknown;
189
+ }
190
+ interface SaveArtifactInput {
191
+ workflowRunId: string;
192
+ workflowStageId?: string;
193
+ key: string;
194
+ type: ArtifactType;
195
+ data: unknown;
196
+ size: number;
197
+ metadata?: unknown;
198
+ }
199
+ interface CreateAICallInput {
200
+ topic: string;
201
+ callType: string;
202
+ modelKey: string;
203
+ modelId: string;
204
+ prompt: string;
205
+ response: string;
206
+ inputTokens: number;
207
+ outputTokens: number;
208
+ cost: number;
209
+ metadata?: unknown;
210
+ }
211
+ interface EnqueueJobInput {
212
+ workflowRunId: string;
213
+ stageId: string;
214
+ priority?: number;
215
+ payload?: Record<string, unknown>;
216
+ scheduledFor?: Date;
217
+ }
218
+ interface DequeueResult {
219
+ jobId: string;
220
+ workflowRunId: string;
221
+ stageId: string;
222
+ priority: number;
223
+ attempt: number;
224
+ payload: Record<string, unknown>;
225
+ }
226
+ interface WorkflowPersistence {
227
+ createRun(data: CreateRunInput): Promise<WorkflowRunRecord>;
228
+ updateRun(id: string, data: UpdateRunInput): Promise<void>;
229
+ getRun(id: string): Promise<WorkflowRunRecord | null>;
230
+ getRunStatus(id: string): Promise<WorkflowStatus | null>;
231
+ getRunsByStatus(status: WorkflowStatus): Promise<WorkflowRunRecord[]>;
232
+ /**
233
+ * Atomically claim a pending workflow run for processing.
234
+ * Uses atomic update with WHERE status = 'PENDING' to prevent race conditions.
235
+ *
236
+ * @param id - The workflow run ID to claim
237
+ * @returns true if successfully claimed, false if already claimed by another worker
238
+ */
239
+ claimPendingRun(id: string): Promise<boolean>;
240
+ /**
241
+ * Atomically find and claim the next pending workflow run.
242
+ * Uses FOR UPDATE SKIP LOCKED pattern (in Postgres) to prevent race conditions
243
+ * when multiple workers try to claim workflows simultaneously.
244
+ *
245
+ * Priority ordering: higher priority first, then oldest (FIFO within same priority).
246
+ *
247
+ * @returns The claimed workflow run (now with status RUNNING), or null if no pending runs
248
+ */
249
+ claimNextPendingRun(): Promise<WorkflowRunRecord | null>;
250
+ createStage(data: CreateStageInput): Promise<WorkflowStageRecord>;
251
+ upsertStage(data: UpsertStageInput): Promise<WorkflowStageRecord>;
252
+ updateStage(id: string, data: UpdateStageInput): Promise<void>;
253
+ updateStageByRunAndStageId(workflowRunId: string, stageId: string, data: UpdateStageInput): Promise<void>;
254
+ getStage(runId: string, stageId: string): Promise<WorkflowStageRecord | null>;
255
+ getStageById(id: string): Promise<WorkflowStageRecord | null>;
256
+ getStagesByRun(runId: string, options?: {
257
+ status?: WorkflowStageStatus;
258
+ orderBy?: "asc" | "desc";
259
+ }): Promise<WorkflowStageRecord[]>;
260
+ getSuspendedStages(beforeDate: Date): Promise<WorkflowStageRecord[]>;
261
+ getFirstSuspendedStageReadyToResume(runId: string): Promise<WorkflowStageRecord | null>;
262
+ getFirstFailedStage(runId: string): Promise<WorkflowStageRecord | null>;
263
+ getLastCompletedStage(runId: string): Promise<WorkflowStageRecord | null>;
264
+ getLastCompletedStageBefore(runId: string, executionGroup: number): Promise<WorkflowStageRecord | null>;
265
+ deleteStage(id: string): Promise<void>;
266
+ createLog(data: CreateLogInput): Promise<void>;
267
+ saveArtifact(data: SaveArtifactInput): Promise<void>;
268
+ loadArtifact(runId: string, key: string): Promise<unknown>;
269
+ hasArtifact(runId: string, key: string): Promise<boolean>;
270
+ deleteArtifact(runId: string, key: string): Promise<void>;
271
+ listArtifacts(runId: string): Promise<WorkflowArtifactRecord[]>;
272
+ getStageIdForArtifact(runId: string, stageId: string): Promise<string | null>;
273
+ saveStageOutput(runId: string, workflowType: string, stageId: string, output: unknown): Promise<string>;
274
+ }
275
+ interface AIHelperStats {
276
+ totalCalls: number;
277
+ totalInputTokens: number;
278
+ totalOutputTokens: number;
279
+ totalCost: number;
280
+ perModel: Record<string, {
281
+ calls: number;
282
+ inputTokens: number;
283
+ outputTokens: number;
284
+ cost: number;
285
+ }>;
286
+ }
287
+ interface AICallLogger {
288
+ /**
289
+ * Log a single AI call (fire and forget)
290
+ */
291
+ logCall(call: CreateAICallInput): void;
292
+ /**
293
+ * Log batch results (for recording batch API results)
294
+ */
295
+ logBatchResults(batchId: string, results: CreateAICallInput[]): Promise<void>;
296
+ /**
297
+ * Get aggregated stats for a topic prefix
298
+ */
299
+ getStats(topicPrefix: string): Promise<AIHelperStats>;
300
+ /**
301
+ * Check if batch results are already recorded
302
+ */
303
+ isRecorded(batchId: string): Promise<boolean>;
304
+ }
305
+ interface JobQueue {
306
+ /**
307
+ * Add a new job to the queue
308
+ */
309
+ enqueue(options: EnqueueJobInput): Promise<string>;
310
+ /**
311
+ * Enqueue multiple stages in parallel (same execution group)
312
+ */
313
+ enqueueParallel(jobs: EnqueueJobInput[]): Promise<string[]>;
314
+ /**
315
+ * Atomically dequeue the next available job
316
+ */
317
+ dequeue(): Promise<DequeueResult | null>;
318
+ /**
319
+ * Mark job as completed
320
+ */
321
+ complete(jobId: string): Promise<void>;
322
+ /**
323
+ * Mark job as suspended (for async-batch)
324
+ */
325
+ suspend(jobId: string, nextPollAt: Date): Promise<void>;
326
+ /**
327
+ * Mark job as failed
328
+ */
329
+ fail(jobId: string, error: string, shouldRetry?: boolean): Promise<void>;
330
+ /**
331
+ * Get suspended jobs that are ready to be checked
332
+ */
333
+ getSuspendedJobsReadyToPoll(): Promise<Array<{
334
+ jobId: string;
335
+ stageId: string;
336
+ workflowRunId: string;
337
+ }>>;
338
+ /**
339
+ * Release stale locks (for crashed workers)
340
+ */
341
+ releaseStaleJobs(staleThresholdMs?: number): Promise<number>;
342
+ }
343
+
344
+ export type { AICallLogger as A, CreateAICallInput as C, DequeueResult as D, EnqueueJobInput as E, JobQueue as J, LogLevel as L, SaveArtifactInput as S, UpdateRunInput as U, WorkflowPersistence as W, AIHelperStats as a, AICallRecord as b, JobRecord as c, JobStatus as d, CreateRunInput as e, WorkflowRunRecord as f, WorkflowStatus as g, CreateStageInput as h, WorkflowStageRecord as i, UpsertStageInput as j, UpdateStageInput as k, WorkflowStageStatus as l, CreateLogInput as m, WorkflowArtifactRecord as n, WorkflowLogRecord as o, ArtifactType as p, Status as q };
@@ -0,0 +1,2 @@
1
+ export { A as AICallLogger, b as AICallRecord, a as AIHelperStats, p as ArtifactType, C as CreateAICallInput, m as CreateLogInput, e as CreateRunInput, h as CreateStageInput, D as DequeueResult, E as EnqueueJobInput, J as JobQueue, c as JobRecord, d as JobStatus, L as LogLevel, S as SaveArtifactInput, q as Status, U as UpdateRunInput, k as UpdateStageInput, j as UpsertStageInput, n as WorkflowArtifactRecord, o as WorkflowLogRecord, W as WorkflowPersistence, f as WorkflowRunRecord, i as WorkflowStageRecord, l as WorkflowStageStatus, g as WorkflowStatus } from '../interface-Cv22wvLG.js';
2
+ export { P as PrismaAICallLogger, a as PrismaJobQueue, c as PrismaWorkflowPersistence, e as createPrismaAICallLogger, f as createPrismaJobQueue, g as createPrismaWorkflowPersistence } from '../index-DmR3E8D7.js';
@@ -0,0 +1,5 @@
1
+ import '../chunk-D7RVRRM2.js';
2
+ export { PrismaAICallLogger, PrismaJobQueue, PrismaWorkflowPersistence, createPrismaAICallLogger, createPrismaJobQueue, createPrismaWorkflowPersistence } from '../chunk-7IITBLFY.js';
3
+ import '../chunk-MUWP5SF2.js';
4
+ //# sourceMappingURL=index.js.map
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,37 @@
1
+ export { D as DatabaseType, P as PrismaAICallLogger, a as PrismaJobQueue, b as PrismaJobQueueOptions, c as PrismaWorkflowPersistence, d as PrismaWorkflowPersistenceOptions, e as createPrismaAICallLogger, f as createPrismaJobQueue, g as createPrismaWorkflowPersistence } from '../../index-DmR3E8D7.js';
2
+ import '../../interface-Cv22wvLG.js';
3
+
4
+ /**
5
+ * Prisma Enum Compatibility Layer
6
+ *
7
+ * Provides compatibility between Prisma 6.x (string enums) and Prisma 7.x (typed enums).
8
+ * Prisma 7.x introduced runtime enum validation, requiring actual enum values instead of strings.
9
+ *
10
+ * This utility resolves enum values from the Prisma client's $Enums property when available,
11
+ * falling back to string values for older Prisma versions.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const helper = createEnumHelper(prisma);
16
+ *
17
+ * // Instead of: status: "PENDING"
18
+ * // Use: status: helper.status("PENDING")
19
+ * ```
20
+ */
21
+ type PrismaClient = any;
22
+ interface PrismaEnumHelper {
23
+ /** Resolve Status enum value (unified enum for workflows, stages, and jobs) */
24
+ status(value: string): unknown;
25
+ /** Resolve ArtifactType enum value */
26
+ artifactType(value: string): unknown;
27
+ /** Resolve LogLevel enum value */
28
+ logLevel(value: string): unknown;
29
+ }
30
+ /**
31
+ * Creates an enum helper that resolves enum values from the Prisma client.
32
+ *
33
+ * Supports both Prisma 6.x (returns string) and Prisma 7.x (returns typed enum).
34
+ */
35
+ declare function createEnumHelper(prisma: PrismaClient): PrismaEnumHelper;
36
+
37
+ export { type PrismaEnumHelper, createEnumHelper };
@@ -0,0 +1,4 @@
1
+ export { PrismaAICallLogger, PrismaJobQueue, PrismaWorkflowPersistence, createEnumHelper, createPrismaAICallLogger, createPrismaJobQueue, createPrismaWorkflowPersistence } from '../../chunk-7IITBLFY.js';
2
+ import '../../chunk-MUWP5SF2.js';
3
+ //# sourceMappingURL=index.js.map
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,242 @@
1
+ import { A as AICallLogger, C as CreateAICallInput, a as AIHelperStats, b as AICallRecord, J as JobQueue, E as EnqueueJobInput, D as DequeueResult, c as JobRecord, d as JobStatus, W as WorkflowPersistence, e as CreateRunInput, f as WorkflowRunRecord, U as UpdateRunInput, g as WorkflowStatus, h as CreateStageInput, i as WorkflowStageRecord, j as UpsertStageInput, k as UpdateStageInput, l as WorkflowStageStatus, m as CreateLogInput, S as SaveArtifactInput, n as WorkflowArtifactRecord, o as WorkflowLogRecord } from '../interface-Cv22wvLG.js';
2
+
3
+ /**
4
+ * In-Memory AI Call Logger
5
+ *
6
+ * A complete in-memory implementation of AICallLogger for testing.
7
+ * Tracks all AI calls with full cost/token tracking and topic-based aggregation.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { InMemoryAICallLogger } from '@bratsos/workflow-engine/testing';
12
+ *
13
+ * const aiLogger = new InMemoryAICallLogger();
14
+ * // Use in tests...
15
+ * aiLogger.clear(); // Reset between tests
16
+ * ```
17
+ */
18
+
19
+ declare class InMemoryAICallLogger implements AICallLogger {
20
+ private calls;
21
+ private recordedBatches;
22
+ /**
23
+ * Log a single AI call (fire and forget)
24
+ */
25
+ logCall(call: CreateAICallInput): void;
26
+ /**
27
+ * Log batch results (for recording batch API results)
28
+ */
29
+ logBatchResults(batchId: string, results: CreateAICallInput[]): Promise<void>;
30
+ /**
31
+ * Get aggregated stats for a topic prefix
32
+ */
33
+ getStats(topicPrefix: string): Promise<AIHelperStats>;
34
+ /**
35
+ * Check if batch results are already recorded
36
+ */
37
+ isRecorded(batchId: string): Promise<boolean>;
38
+ /**
39
+ * Clear all data - useful between tests
40
+ */
41
+ clear(): void;
42
+ /**
43
+ * Get all calls for inspection
44
+ */
45
+ getAllCalls(): AICallRecord[];
46
+ /**
47
+ * Get calls by topic for inspection
48
+ */
49
+ getCallsByTopic(topic: string): AICallRecord[];
50
+ /**
51
+ * Get calls by topic prefix for inspection
52
+ */
53
+ getCallsByTopicPrefix(prefix: string): AICallRecord[];
54
+ /**
55
+ * Get calls by model for inspection
56
+ */
57
+ getCallsByModel(modelKey: string): AICallRecord[];
58
+ /**
59
+ * Get calls by call type for inspection
60
+ */
61
+ getCallsByType(callType: string): AICallRecord[];
62
+ /**
63
+ * Get total cost across all calls
64
+ */
65
+ getTotalCost(): number;
66
+ /**
67
+ * Get total tokens across all calls
68
+ */
69
+ getTotalTokens(): {
70
+ input: number;
71
+ output: number;
72
+ };
73
+ /**
74
+ * Get call count
75
+ */
76
+ getCallCount(): number;
77
+ /**
78
+ * Get all recorded batch IDs
79
+ */
80
+ getRecordedBatchIds(): string[];
81
+ /**
82
+ * Get the last call made (useful for assertions)
83
+ */
84
+ getLastCall(): AICallRecord | null;
85
+ /**
86
+ * Assert a call was made with specific properties
87
+ */
88
+ hasCallMatching(predicate: (call: AICallRecord) => boolean): boolean;
89
+ }
90
+
91
+ /**
92
+ * In-Memory Job Queue
93
+ *
94
+ * A complete in-memory implementation of JobQueue for testing.
95
+ * Supports priority ordering, locking, and stale job recovery.
96
+ *
97
+ * @example
98
+ * ```typescript
99
+ * import { InMemoryJobQueue } from '@bratsos/workflow-engine/testing';
100
+ *
101
+ * const jobQueue = new InMemoryJobQueue();
102
+ * // Use in tests...
103
+ * jobQueue.clear(); // Reset between tests
104
+ * ```
105
+ */
106
+
107
+ declare class InMemoryJobQueue implements JobQueue {
108
+ private jobs;
109
+ private workerId;
110
+ private defaultMaxAttempts;
111
+ constructor(workerId?: string);
112
+ enqueue(options: EnqueueJobInput): Promise<string>;
113
+ enqueueParallel(jobs: EnqueueJobInput[]): Promise<string[]>;
114
+ dequeue(): Promise<DequeueResult | null>;
115
+ complete(jobId: string): Promise<void>;
116
+ suspend(jobId: string, nextPollAt: Date): Promise<void>;
117
+ fail(jobId: string, error: string, shouldRetry?: boolean): Promise<void>;
118
+ getSuspendedJobsReadyToPoll(): Promise<Array<{
119
+ jobId: string;
120
+ stageId: string;
121
+ workflowRunId: string;
122
+ }>>;
123
+ releaseStaleJobs(staleThresholdMs?: number): Promise<number>;
124
+ /**
125
+ * Clear all jobs - useful between tests
126
+ */
127
+ clear(): void;
128
+ /**
129
+ * Get all jobs for inspection
130
+ */
131
+ getAllJobs(): JobRecord[];
132
+ /**
133
+ * Get jobs by status for inspection
134
+ */
135
+ getJobsByStatus(status: JobStatus): JobRecord[];
136
+ /**
137
+ * Get a specific job by ID
138
+ */
139
+ getJob(jobId: string): JobRecord | null;
140
+ /**
141
+ * Get the worker ID for this queue instance
142
+ */
143
+ getWorkerId(): string;
144
+ /**
145
+ * Set max attempts for new jobs
146
+ */
147
+ setDefaultMaxAttempts(maxAttempts: number): void;
148
+ /**
149
+ * Simulate a worker crash by releasing a job's lock without completing it
150
+ */
151
+ simulateCrash(jobId: string): void;
152
+ /**
153
+ * Move a suspended job back to pending (for manual resume testing)
154
+ */
155
+ resumeJob(jobId: string): void;
156
+ /**
157
+ * Set lockedAt for testing stale job scenarios
158
+ */
159
+ setJobLockedAt(jobId: string, lockedAt: Date): void;
160
+ /**
161
+ * Set nextPollAt for testing suspended job polling
162
+ */
163
+ setJobNextPollAt(jobId: string, nextPollAt: Date | null): void;
164
+ }
165
+
166
+ /**
167
+ * In-Memory Workflow Persistence
168
+ *
169
+ * A complete in-memory implementation of WorkflowPersistence for testing.
170
+ * All data is stored in Maps and lost when the instance is garbage collected.
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * import { InMemoryWorkflowPersistence } from '@bratsos/workflow-engine/testing';
175
+ *
176
+ * const persistence = new InMemoryWorkflowPersistence();
177
+ * // Use in tests...
178
+ * persistence.clear(); // Reset between tests
179
+ * ```
180
+ */
181
+
182
+ declare class InMemoryWorkflowPersistence implements WorkflowPersistence {
183
+ private runs;
184
+ private stages;
185
+ private logs;
186
+ private artifacts;
187
+ private stageKey;
188
+ private artifactKey;
189
+ createRun(data: CreateRunInput): Promise<WorkflowRunRecord>;
190
+ updateRun(id: string, data: UpdateRunInput): Promise<void>;
191
+ getRun(id: string): Promise<WorkflowRunRecord | null>;
192
+ getRunStatus(id: string): Promise<WorkflowStatus | null>;
193
+ getRunsByStatus(status: WorkflowStatus): Promise<WorkflowRunRecord[]>;
194
+ claimPendingRun(id: string): Promise<boolean>;
195
+ claimNextPendingRun(): Promise<WorkflowRunRecord | null>;
196
+ createStage(data: CreateStageInput): Promise<WorkflowStageRecord>;
197
+ upsertStage(data: UpsertStageInput): Promise<WorkflowStageRecord>;
198
+ updateStage(id: string, data: UpdateStageInput): Promise<void>;
199
+ updateStageByRunAndStageId(workflowRunId: string, stageId: string, data: UpdateStageInput): Promise<void>;
200
+ getStage(runId: string, stageId: string): Promise<WorkflowStageRecord | null>;
201
+ getStageById(id: string): Promise<WorkflowStageRecord | null>;
202
+ getStagesByRun(runId: string, options?: {
203
+ status?: WorkflowStageStatus;
204
+ orderBy?: "asc" | "desc";
205
+ }): Promise<WorkflowStageRecord[]>;
206
+ getSuspendedStages(beforeDate: Date): Promise<WorkflowStageRecord[]>;
207
+ getFirstSuspendedStageReadyToResume(runId: string): Promise<WorkflowStageRecord | null>;
208
+ getFirstFailedStage(runId: string): Promise<WorkflowStageRecord | null>;
209
+ getLastCompletedStage(runId: string): Promise<WorkflowStageRecord | null>;
210
+ getLastCompletedStageBefore(runId: string, executionGroup: number): Promise<WorkflowStageRecord | null>;
211
+ deleteStage(id: string): Promise<void>;
212
+ createLog(data: CreateLogInput): Promise<void>;
213
+ saveArtifact(data: SaveArtifactInput): Promise<void>;
214
+ loadArtifact(runId: string, key: string): Promise<unknown>;
215
+ hasArtifact(runId: string, key: string): Promise<boolean>;
216
+ deleteArtifact(runId: string, key: string): Promise<void>;
217
+ listArtifacts(runId: string): Promise<WorkflowArtifactRecord[]>;
218
+ getStageIdForArtifact(runId: string, stageId: string): Promise<string | null>;
219
+ saveStageOutput(runId: string, workflowType: string, stageId: string, output: unknown): Promise<string>;
220
+ /**
221
+ * Clear all data - useful between tests
222
+ */
223
+ clear(): void;
224
+ /**
225
+ * Get all runs for inspection
226
+ */
227
+ getAllRuns(): WorkflowRunRecord[];
228
+ /**
229
+ * Get all stages for inspection
230
+ */
231
+ getAllStages(): WorkflowStageRecord[];
232
+ /**
233
+ * Get all logs for inspection
234
+ */
235
+ getAllLogs(): WorkflowLogRecord[];
236
+ /**
237
+ * Get all artifacts for inspection
238
+ */
239
+ getAllArtifacts(): WorkflowArtifactRecord[];
240
+ }
241
+
242
+ export { InMemoryAICallLogger, InMemoryJobQueue, InMemoryWorkflowPersistence };