@bratsos/workflow-engine 0.0.11 → 0.2.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/README.md +270 -513
- package/dist/chunk-D7RVRRM2.js +3 -0
- package/dist/chunk-D7RVRRM2.js.map +1 -0
- package/dist/chunk-HL3OJG7W.js +1033 -0
- package/dist/chunk-HL3OJG7W.js.map +1 -0
- package/dist/chunk-MUWP5SF2.js +33 -0
- package/dist/chunk-MUWP5SF2.js.map +1 -0
- package/dist/chunk-NYKMT46J.js +1143 -0
- package/dist/chunk-NYKMT46J.js.map +1 -0
- package/dist/chunk-P4KMGCT3.js +2292 -0
- package/dist/chunk-P4KMGCT3.js.map +1 -0
- package/dist/chunk-SPXBCZLB.js +17 -0
- package/dist/chunk-SPXBCZLB.js.map +1 -0
- package/dist/cli/sync-models.d.ts +1 -0
- package/dist/cli/sync-models.js +210 -0
- package/dist/cli/sync-models.js.map +1 -0
- package/dist/client-D4PoxADF.d.ts +798 -0
- package/dist/client.d.ts +5 -0
- package/dist/client.js +4 -0
- package/dist/client.js.map +1 -0
- package/dist/index-DAzCfO1R.d.ts +217 -0
- package/dist/index.d.ts +569 -0
- package/dist/index.js +399 -0
- package/dist/index.js.map +1 -0
- package/dist/interface-MMqhfQQK.d.ts +411 -0
- package/dist/kernel/index.d.ts +26 -0
- package/dist/kernel/index.js +3 -0
- package/dist/kernel/index.js.map +1 -0
- package/dist/kernel/testing/index.d.ts +44 -0
- package/dist/kernel/testing/index.js +85 -0
- package/dist/kernel/testing/index.js.map +1 -0
- package/dist/persistence/index.d.ts +2 -0
- package/dist/persistence/index.js +6 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/persistence/prisma/index.d.ts +37 -0
- package/dist/persistence/prisma/index.js +5 -0
- package/dist/persistence/prisma/index.js.map +1 -0
- package/dist/plugins-BCnDUwIc.d.ts +415 -0
- package/dist/ports-tU3rzPXJ.d.ts +245 -0
- package/dist/stage-BPw7m9Wx.d.ts +144 -0
- package/dist/testing/index.d.ts +264 -0
- package/dist/testing/index.js +920 -0
- package/dist/testing/index.js.map +1 -0
- package/package.json +11 -1
- package/skills/workflow-engine/SKILL.md +234 -348
- package/skills/workflow-engine/references/03-runtime-setup.md +111 -426
- package/skills/workflow-engine/references/05-persistence-setup.md +32 -0
- package/skills/workflow-engine/references/07-testing-patterns.md +141 -474
- package/skills/workflow-engine/references/08-common-patterns.md +118 -431
|
@@ -0,0 +1,411 @@
|
|
|
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
|
+
declare class StaleVersionError extends Error {
|
|
34
|
+
readonly entity: string;
|
|
35
|
+
readonly id: string;
|
|
36
|
+
readonly expected: number;
|
|
37
|
+
readonly actual: number;
|
|
38
|
+
constructor(entity: string, id: string, expected: number, actual: number);
|
|
39
|
+
}
|
|
40
|
+
interface WorkflowRunRecord {
|
|
41
|
+
id: string;
|
|
42
|
+
createdAt: Date;
|
|
43
|
+
updatedAt: Date;
|
|
44
|
+
version: number;
|
|
45
|
+
workflowId: string;
|
|
46
|
+
workflowName: string;
|
|
47
|
+
workflowType: string;
|
|
48
|
+
status: WorkflowStatus;
|
|
49
|
+
startedAt: Date | null;
|
|
50
|
+
completedAt: Date | null;
|
|
51
|
+
duration: number | null;
|
|
52
|
+
input: unknown;
|
|
53
|
+
output: unknown | null;
|
|
54
|
+
config: unknown;
|
|
55
|
+
totalCost: number;
|
|
56
|
+
totalTokens: number;
|
|
57
|
+
priority: number;
|
|
58
|
+
}
|
|
59
|
+
interface WorkflowStageRecord {
|
|
60
|
+
id: string;
|
|
61
|
+
createdAt: Date;
|
|
62
|
+
updatedAt: Date;
|
|
63
|
+
version: number;
|
|
64
|
+
workflowRunId: string;
|
|
65
|
+
stageId: string;
|
|
66
|
+
stageName: string;
|
|
67
|
+
stageNumber: number;
|
|
68
|
+
executionGroup: number;
|
|
69
|
+
status: WorkflowStageStatus;
|
|
70
|
+
startedAt: Date | null;
|
|
71
|
+
completedAt: Date | null;
|
|
72
|
+
duration: number | null;
|
|
73
|
+
inputData: unknown | null;
|
|
74
|
+
outputData: unknown | null;
|
|
75
|
+
config: unknown | null;
|
|
76
|
+
suspendedState: unknown | null;
|
|
77
|
+
resumeData: unknown | null;
|
|
78
|
+
nextPollAt: Date | null;
|
|
79
|
+
pollInterval: number | null;
|
|
80
|
+
maxWaitUntil: Date | null;
|
|
81
|
+
metrics: unknown | null;
|
|
82
|
+
embeddingInfo: unknown | null;
|
|
83
|
+
errorMessage: string | null;
|
|
84
|
+
}
|
|
85
|
+
interface WorkflowLogRecord {
|
|
86
|
+
id: string;
|
|
87
|
+
createdAt: Date;
|
|
88
|
+
workflowStageId: string | null;
|
|
89
|
+
workflowRunId: string | null;
|
|
90
|
+
level: LogLevel;
|
|
91
|
+
message: string;
|
|
92
|
+
metadata: unknown | null;
|
|
93
|
+
}
|
|
94
|
+
interface WorkflowArtifactRecord {
|
|
95
|
+
id: string;
|
|
96
|
+
createdAt: Date;
|
|
97
|
+
updatedAt: Date;
|
|
98
|
+
workflowRunId: string;
|
|
99
|
+
workflowStageId: string | null;
|
|
100
|
+
key: string;
|
|
101
|
+
type: ArtifactType;
|
|
102
|
+
data: unknown;
|
|
103
|
+
size: number;
|
|
104
|
+
metadata: unknown | null;
|
|
105
|
+
}
|
|
106
|
+
interface OutboxRecord {
|
|
107
|
+
id: string;
|
|
108
|
+
workflowRunId: string;
|
|
109
|
+
sequence: number;
|
|
110
|
+
eventType: string;
|
|
111
|
+
payload: unknown;
|
|
112
|
+
causationId: string;
|
|
113
|
+
occurredAt: Date;
|
|
114
|
+
publishedAt: Date | null;
|
|
115
|
+
retryCount: number;
|
|
116
|
+
dlqAt: Date | null;
|
|
117
|
+
}
|
|
118
|
+
interface CreateOutboxEventInput {
|
|
119
|
+
workflowRunId: string;
|
|
120
|
+
eventType: string;
|
|
121
|
+
payload: unknown;
|
|
122
|
+
causationId: string;
|
|
123
|
+
occurredAt: Date;
|
|
124
|
+
}
|
|
125
|
+
interface IdempotencyRecord {
|
|
126
|
+
key: string;
|
|
127
|
+
commandType: string;
|
|
128
|
+
result: unknown;
|
|
129
|
+
createdAt: Date;
|
|
130
|
+
}
|
|
131
|
+
interface AICallRecord {
|
|
132
|
+
id: string;
|
|
133
|
+
createdAt: Date;
|
|
134
|
+
topic: string;
|
|
135
|
+
callType: string;
|
|
136
|
+
modelKey: string;
|
|
137
|
+
modelId: string;
|
|
138
|
+
prompt: string;
|
|
139
|
+
response: string;
|
|
140
|
+
inputTokens: number;
|
|
141
|
+
outputTokens: number;
|
|
142
|
+
cost: number;
|
|
143
|
+
metadata: unknown | null;
|
|
144
|
+
}
|
|
145
|
+
interface JobRecord {
|
|
146
|
+
id: string;
|
|
147
|
+
createdAt: Date;
|
|
148
|
+
updatedAt: Date;
|
|
149
|
+
workflowRunId: string;
|
|
150
|
+
workflowId: string;
|
|
151
|
+
stageId: string;
|
|
152
|
+
status: JobStatus;
|
|
153
|
+
priority: number;
|
|
154
|
+
workerId: string | null;
|
|
155
|
+
lockedAt: Date | null;
|
|
156
|
+
startedAt: Date | null;
|
|
157
|
+
completedAt: Date | null;
|
|
158
|
+
attempt: number;
|
|
159
|
+
maxAttempts: number;
|
|
160
|
+
lastError: string | null;
|
|
161
|
+
nextPollAt: Date | null;
|
|
162
|
+
payload: Record<string, unknown>;
|
|
163
|
+
}
|
|
164
|
+
interface CreateRunInput {
|
|
165
|
+
id?: string;
|
|
166
|
+
workflowId: string;
|
|
167
|
+
workflowName: string;
|
|
168
|
+
workflowType: string;
|
|
169
|
+
input: unknown;
|
|
170
|
+
config?: unknown;
|
|
171
|
+
priority?: number;
|
|
172
|
+
/** Optional metadata for domain-specific fields */
|
|
173
|
+
metadata?: Record<string, unknown>;
|
|
174
|
+
}
|
|
175
|
+
interface UpdateRunInput {
|
|
176
|
+
status?: WorkflowStatus;
|
|
177
|
+
startedAt?: Date;
|
|
178
|
+
completedAt?: Date | null;
|
|
179
|
+
duration?: number;
|
|
180
|
+
output?: unknown;
|
|
181
|
+
totalCost?: number;
|
|
182
|
+
totalTokens?: number;
|
|
183
|
+
expectedVersion?: number;
|
|
184
|
+
}
|
|
185
|
+
interface CreateStageInput {
|
|
186
|
+
workflowRunId: string;
|
|
187
|
+
stageId: string;
|
|
188
|
+
stageName: string;
|
|
189
|
+
stageNumber: number;
|
|
190
|
+
executionGroup: number;
|
|
191
|
+
status?: WorkflowStageStatus;
|
|
192
|
+
startedAt?: Date;
|
|
193
|
+
config?: unknown;
|
|
194
|
+
inputData?: unknown;
|
|
195
|
+
}
|
|
196
|
+
interface UpdateStageInput {
|
|
197
|
+
status?: WorkflowStageStatus;
|
|
198
|
+
startedAt?: Date;
|
|
199
|
+
completedAt?: Date;
|
|
200
|
+
duration?: number;
|
|
201
|
+
outputData?: unknown;
|
|
202
|
+
config?: unknown;
|
|
203
|
+
suspendedState?: unknown;
|
|
204
|
+
resumeData?: unknown;
|
|
205
|
+
nextPollAt?: Date | null;
|
|
206
|
+
pollInterval?: number;
|
|
207
|
+
maxWaitUntil?: Date;
|
|
208
|
+
metrics?: unknown;
|
|
209
|
+
embeddingInfo?: unknown;
|
|
210
|
+
artifacts?: unknown;
|
|
211
|
+
errorMessage?: string;
|
|
212
|
+
expectedVersion?: number;
|
|
213
|
+
}
|
|
214
|
+
interface UpsertStageInput {
|
|
215
|
+
workflowRunId: string;
|
|
216
|
+
stageId: string;
|
|
217
|
+
create: CreateStageInput;
|
|
218
|
+
update: UpdateStageInput;
|
|
219
|
+
}
|
|
220
|
+
interface CreateLogInput {
|
|
221
|
+
workflowRunId?: string;
|
|
222
|
+
workflowStageId?: string;
|
|
223
|
+
level: LogLevel;
|
|
224
|
+
message: string;
|
|
225
|
+
metadata?: unknown;
|
|
226
|
+
}
|
|
227
|
+
interface SaveArtifactInput {
|
|
228
|
+
workflowRunId: string;
|
|
229
|
+
workflowStageId?: string;
|
|
230
|
+
key: string;
|
|
231
|
+
type: ArtifactType;
|
|
232
|
+
data: unknown;
|
|
233
|
+
size: number;
|
|
234
|
+
metadata?: unknown;
|
|
235
|
+
}
|
|
236
|
+
interface CreateAICallInput {
|
|
237
|
+
topic: string;
|
|
238
|
+
callType: string;
|
|
239
|
+
modelKey: string;
|
|
240
|
+
modelId: string;
|
|
241
|
+
prompt: string;
|
|
242
|
+
response: string;
|
|
243
|
+
inputTokens: number;
|
|
244
|
+
outputTokens: number;
|
|
245
|
+
cost: number;
|
|
246
|
+
metadata?: unknown;
|
|
247
|
+
}
|
|
248
|
+
interface EnqueueJobInput {
|
|
249
|
+
workflowRunId: string;
|
|
250
|
+
workflowId: string;
|
|
251
|
+
stageId: string;
|
|
252
|
+
priority?: number;
|
|
253
|
+
payload?: Record<string, unknown>;
|
|
254
|
+
scheduledFor?: Date;
|
|
255
|
+
}
|
|
256
|
+
interface DequeueResult {
|
|
257
|
+
jobId: string;
|
|
258
|
+
workflowRunId: string;
|
|
259
|
+
workflowId: string;
|
|
260
|
+
stageId: string;
|
|
261
|
+
priority: number;
|
|
262
|
+
attempt: number;
|
|
263
|
+
maxAttempts: number;
|
|
264
|
+
payload: Record<string, unknown>;
|
|
265
|
+
}
|
|
266
|
+
interface WorkflowPersistence {
|
|
267
|
+
/** Execute operations within a transaction boundary. */
|
|
268
|
+
withTransaction<T>(fn: (tx: WorkflowPersistence) => Promise<T>): Promise<T>;
|
|
269
|
+
createRun(data: CreateRunInput): Promise<WorkflowRunRecord>;
|
|
270
|
+
updateRun(id: string, data: UpdateRunInput): Promise<void>;
|
|
271
|
+
getRun(id: string): Promise<WorkflowRunRecord | null>;
|
|
272
|
+
getRunStatus(id: string): Promise<WorkflowStatus | null>;
|
|
273
|
+
getRunsByStatus(status: WorkflowStatus): Promise<WorkflowRunRecord[]>;
|
|
274
|
+
/**
|
|
275
|
+
* Atomically claim a pending workflow run for processing.
|
|
276
|
+
* Uses atomic update with WHERE status = 'PENDING' to prevent race conditions.
|
|
277
|
+
*
|
|
278
|
+
* @param id - The workflow run ID to claim
|
|
279
|
+
* @returns true if successfully claimed, false if already claimed by another worker
|
|
280
|
+
*/
|
|
281
|
+
claimPendingRun(id: string): Promise<boolean>;
|
|
282
|
+
/**
|
|
283
|
+
* Atomically find and claim the next pending workflow run.
|
|
284
|
+
* Uses FOR UPDATE SKIP LOCKED pattern (in Postgres) to prevent race conditions
|
|
285
|
+
* when multiple workers try to claim workflows simultaneously.
|
|
286
|
+
*
|
|
287
|
+
* Priority ordering: higher priority first, then oldest (FIFO within same priority).
|
|
288
|
+
*
|
|
289
|
+
* @returns The claimed workflow run (now with status RUNNING), or null if no pending runs
|
|
290
|
+
*/
|
|
291
|
+
claimNextPendingRun(): Promise<WorkflowRunRecord | null>;
|
|
292
|
+
createStage(data: CreateStageInput): Promise<WorkflowStageRecord>;
|
|
293
|
+
upsertStage(data: UpsertStageInput): Promise<WorkflowStageRecord>;
|
|
294
|
+
updateStage(id: string, data: UpdateStageInput): Promise<void>;
|
|
295
|
+
updateStageByRunAndStageId(workflowRunId: string, stageId: string, data: UpdateStageInput): Promise<void>;
|
|
296
|
+
getStage(runId: string, stageId: string): Promise<WorkflowStageRecord | null>;
|
|
297
|
+
getStageById(id: string): Promise<WorkflowStageRecord | null>;
|
|
298
|
+
getStagesByRun(runId: string, options?: {
|
|
299
|
+
status?: WorkflowStageStatus;
|
|
300
|
+
orderBy?: "asc" | "desc";
|
|
301
|
+
}): Promise<WorkflowStageRecord[]>;
|
|
302
|
+
getSuspendedStages(beforeDate: Date): Promise<WorkflowStageRecord[]>;
|
|
303
|
+
getFirstSuspendedStageReadyToResume(runId: string): Promise<WorkflowStageRecord | null>;
|
|
304
|
+
getFirstFailedStage(runId: string): Promise<WorkflowStageRecord | null>;
|
|
305
|
+
getLastCompletedStage(runId: string): Promise<WorkflowStageRecord | null>;
|
|
306
|
+
getLastCompletedStageBefore(runId: string, executionGroup: number): Promise<WorkflowStageRecord | null>;
|
|
307
|
+
deleteStage(id: string): Promise<void>;
|
|
308
|
+
createLog(data: CreateLogInput): Promise<void>;
|
|
309
|
+
saveArtifact(data: SaveArtifactInput): Promise<void>;
|
|
310
|
+
loadArtifact(runId: string, key: string): Promise<unknown>;
|
|
311
|
+
hasArtifact(runId: string, key: string): Promise<boolean>;
|
|
312
|
+
deleteArtifact(runId: string, key: string): Promise<void>;
|
|
313
|
+
listArtifacts(runId: string): Promise<WorkflowArtifactRecord[]>;
|
|
314
|
+
getStageIdForArtifact(runId: string, stageId: string): Promise<string | null>;
|
|
315
|
+
saveStageOutput(runId: string, workflowType: string, stageId: string, output: unknown): Promise<string>;
|
|
316
|
+
/** Increment retry count for a failed outbox event. Returns new count. */
|
|
317
|
+
incrementOutboxRetryCount(id: string): Promise<number>;
|
|
318
|
+
/** Move an outbox event to DLQ (sets dlqAt). */
|
|
319
|
+
moveOutboxEventToDLQ(id: string): Promise<void>;
|
|
320
|
+
/** Reset DLQ events so they can be reprocessed by outbox.flush. Returns count reset. */
|
|
321
|
+
replayDLQEvents(maxEvents: number): Promise<number>;
|
|
322
|
+
/** Write events to the outbox. Sequences are auto-assigned per workflowRunId. */
|
|
323
|
+
appendOutboxEvents(events: CreateOutboxEventInput[]): Promise<void>;
|
|
324
|
+
/** Read unpublished events ordered by (workflowRunId, sequence). */
|
|
325
|
+
getUnpublishedOutboxEvents(limit?: number): Promise<OutboxRecord[]>;
|
|
326
|
+
/** Mark events as published. */
|
|
327
|
+
markOutboxEventsPublished(ids: string[]): Promise<void>;
|
|
328
|
+
/** Atomically acquire an idempotency key for command execution. */
|
|
329
|
+
acquireIdempotencyKey(key: string, commandType: string): Promise<{
|
|
330
|
+
status: "acquired";
|
|
331
|
+
} | {
|
|
332
|
+
status: "replay";
|
|
333
|
+
result: unknown;
|
|
334
|
+
} | {
|
|
335
|
+
status: "in_progress";
|
|
336
|
+
}>;
|
|
337
|
+
/** Mark an idempotency key as completed and cache the command result. */
|
|
338
|
+
completeIdempotencyKey(key: string, commandType: string, result: unknown): Promise<void>;
|
|
339
|
+
/** Release an in-progress idempotency key after command failure. */
|
|
340
|
+
releaseIdempotencyKey(key: string, commandType: string): Promise<void>;
|
|
341
|
+
}
|
|
342
|
+
interface AIHelperStats {
|
|
343
|
+
totalCalls: number;
|
|
344
|
+
totalInputTokens: number;
|
|
345
|
+
totalOutputTokens: number;
|
|
346
|
+
totalCost: number;
|
|
347
|
+
perModel: Record<string, {
|
|
348
|
+
calls: number;
|
|
349
|
+
inputTokens: number;
|
|
350
|
+
outputTokens: number;
|
|
351
|
+
cost: number;
|
|
352
|
+
}>;
|
|
353
|
+
}
|
|
354
|
+
interface AICallLogger {
|
|
355
|
+
/**
|
|
356
|
+
* Log a single AI call (fire and forget)
|
|
357
|
+
*/
|
|
358
|
+
logCall(call: CreateAICallInput): void;
|
|
359
|
+
/**
|
|
360
|
+
* Log batch results (for recording batch API results)
|
|
361
|
+
*/
|
|
362
|
+
logBatchResults(batchId: string, results: CreateAICallInput[]): Promise<void>;
|
|
363
|
+
/**
|
|
364
|
+
* Get aggregated stats for a topic prefix
|
|
365
|
+
*/
|
|
366
|
+
getStats(topicPrefix: string): Promise<AIHelperStats>;
|
|
367
|
+
/**
|
|
368
|
+
* Check if batch results are already recorded
|
|
369
|
+
*/
|
|
370
|
+
isRecorded(batchId: string): Promise<boolean>;
|
|
371
|
+
}
|
|
372
|
+
interface JobQueue {
|
|
373
|
+
/**
|
|
374
|
+
* Add a new job to the queue
|
|
375
|
+
*/
|
|
376
|
+
enqueue(options: EnqueueJobInput): Promise<string>;
|
|
377
|
+
/**
|
|
378
|
+
* Enqueue multiple stages in parallel (same execution group)
|
|
379
|
+
*/
|
|
380
|
+
enqueueParallel(jobs: EnqueueJobInput[]): Promise<string[]>;
|
|
381
|
+
/**
|
|
382
|
+
* Atomically dequeue the next available job
|
|
383
|
+
*/
|
|
384
|
+
dequeue(): Promise<DequeueResult | null>;
|
|
385
|
+
/**
|
|
386
|
+
* Mark job as completed
|
|
387
|
+
*/
|
|
388
|
+
complete(jobId: string): Promise<void>;
|
|
389
|
+
/**
|
|
390
|
+
* Mark job as suspended (for async-batch)
|
|
391
|
+
*/
|
|
392
|
+
suspend(jobId: string, nextPollAt: Date): Promise<void>;
|
|
393
|
+
/**
|
|
394
|
+
* Mark job as failed
|
|
395
|
+
*/
|
|
396
|
+
fail(jobId: string, error: string, shouldRetry?: boolean): Promise<void>;
|
|
397
|
+
/**
|
|
398
|
+
* Get suspended jobs that are ready to be checked
|
|
399
|
+
*/
|
|
400
|
+
getSuspendedJobsReadyToPoll(): Promise<Array<{
|
|
401
|
+
jobId: string;
|
|
402
|
+
stageId: string;
|
|
403
|
+
workflowRunId: string;
|
|
404
|
+
}>>;
|
|
405
|
+
/**
|
|
406
|
+
* Release stale locks (for crashed workers)
|
|
407
|
+
*/
|
|
408
|
+
releaseStaleJobs(staleThresholdMs?: number): Promise<number>;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export { type AICallLogger as A, type CreateOutboxEventInput as C, type DequeueResult as D, type EnqueueJobInput as E, type IdempotencyRecord as I, type JobQueue as J, type LogLevel as L, type OutboxRecord as O, type Status as S, type UpdateRunInput as U, type WorkflowRunRecord as W, type CreateRunInput as a, type CreateStageInput as b, type WorkflowStageRecord as c, type UpsertStageInput as d, type UpdateStageInput as e, type CreateLogInput as f, type CreateAICallInput as g, type AIHelperStats as h, type AICallRecord as i, type JobRecord as j, type JobStatus as k, type WorkflowPersistence as l, type WorkflowStatus as m, type WorkflowStageStatus as n, type SaveArtifactInput as o, type WorkflowArtifactRecord as p, type WorkflowLogRecord as q, type ArtifactType as r, StaleVersionError as s };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { K as KernelDeps } from '../plugins-BCnDUwIc.js';
|
|
2
|
+
export { C as CommandResult, I as IdempotencyInProgressError, J as JobExecuteCommand, a as JobExecuteResult, b as Kernel, c as KernelCommand, d as KernelCommandType, e as KernelConfig, L as LeaseReapStaleCommand, f as LeaseReapStaleResult, O as OutboxFlushCommand, g as OutboxFlushResult, P as PluginDefinition, h as PluginReplayDLQCommand, i as PluginReplayDLQResult, j as PluginRunner, k as PluginRunnerConfig, R as RunCancelCommand, l as RunCancelResult, m as RunClaimPendingCommand, n as RunClaimPendingResult, o as RunCreateCommand, p as RunCreateResult, q as RunRerunFromCommand, r as RunRerunFromResult, s as RunTransitionCommand, t as RunTransitionResult, S as StagePollSuspendedCommand, u as StagePollSuspendedResult, W as WorkflowRegistry, v as createKernel, w as createPluginRunner, x as definePlugin } from '../plugins-BCnDUwIc.js';
|
|
3
|
+
export { B as BlobStore, C as Clock, E as EventSink, J as JobTransport, K as KernelEvent, a as KernelEventType, P as Persistence, S as Scheduler, b as StageCompletedEvent, c as StageFailedEvent, d as StageProgressEvent, e as StageStartedEvent, f as StageSuspendedEvent, W as WorkflowCancelledEvent, g as WorkflowCompletedEvent, h as WorkflowCreatedEvent, i as WorkflowFailedEvent, j as WorkflowStartedEvent, k as WorkflowSuspendedEvent } from '../ports-tU3rzPXJ.js';
|
|
4
|
+
export { C as CreateOutboxEventInput, I as IdempotencyRecord, O as OutboxRecord } from '../interface-MMqhfQQK.js';
|
|
5
|
+
import 'zod';
|
|
6
|
+
import '../stage-BPw7m9Wx.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Load workflow context from completed stages.
|
|
10
|
+
*
|
|
11
|
+
* For each completed stage, loads the output from BlobStore using
|
|
12
|
+
* the _artifactKey stored in stage.outputData.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
declare function loadWorkflowContext(workflowRunId: string, deps: KernelDeps): Promise<Record<string, unknown>>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Save stage output to BlobStore and return the blob key.
|
|
19
|
+
*
|
|
20
|
+
* The key is stored in stage.outputData._artifactKey so that
|
|
21
|
+
* loadWorkflowContext() can retrieve it later.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
declare function saveStageOutput(runId: string, workflowType: string, stageId: string, output: unknown, deps: KernelDeps): Promise<string>;
|
|
25
|
+
|
|
26
|
+
export { loadWorkflowContext, saveStageOutput };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { E as EventSink, K as KernelEvent, a as KernelEventType, C as Clock, B as BlobStore, S as Scheduler } from '../../ports-tU3rzPXJ.js';
|
|
2
|
+
import '../../interface-MMqhfQQK.js';
|
|
3
|
+
|
|
4
|
+
declare class CollectingEventSink implements EventSink {
|
|
5
|
+
readonly events: KernelEvent[];
|
|
6
|
+
emit(event: KernelEvent): Promise<void>;
|
|
7
|
+
getByType<T extends KernelEventType>(type: T): Extract<KernelEvent, {
|
|
8
|
+
type: T;
|
|
9
|
+
}>[];
|
|
10
|
+
clear(): void;
|
|
11
|
+
get length(): number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
declare class FakeClock implements Clock {
|
|
15
|
+
private currentTime;
|
|
16
|
+
constructor(initialTime?: Date);
|
|
17
|
+
now(): Date;
|
|
18
|
+
advance(ms: number): void;
|
|
19
|
+
set(time: Date): void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
declare class InMemoryBlobStore implements BlobStore {
|
|
23
|
+
private store;
|
|
24
|
+
put(key: string, data: unknown): Promise<void>;
|
|
25
|
+
get(key: string): Promise<unknown>;
|
|
26
|
+
has(key: string): Promise<boolean>;
|
|
27
|
+
delete(key: string): Promise<void>;
|
|
28
|
+
list(prefix: string): Promise<string[]>;
|
|
29
|
+
clear(): void;
|
|
30
|
+
size(): number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
declare class NoopScheduler implements Scheduler {
|
|
34
|
+
readonly scheduled: Array<{
|
|
35
|
+
commandType: string;
|
|
36
|
+
payload: unknown;
|
|
37
|
+
runAt: Date;
|
|
38
|
+
}>;
|
|
39
|
+
schedule(commandType: string, payload: unknown, runAt: Date): Promise<void>;
|
|
40
|
+
cancel(_commandType: string, _correlationId: string): Promise<void>;
|
|
41
|
+
clear(): void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { CollectingEventSink, FakeClock, InMemoryBlobStore, NoopScheduler };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// src/kernel/testing/collecting-event-sink.ts
|
|
2
|
+
var CollectingEventSink = class {
|
|
3
|
+
events = [];
|
|
4
|
+
async emit(event) {
|
|
5
|
+
this.events.push(event);
|
|
6
|
+
}
|
|
7
|
+
getByType(type) {
|
|
8
|
+
return this.events.filter(
|
|
9
|
+
(e) => e.type === type
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
clear() {
|
|
13
|
+
this.events.length = 0;
|
|
14
|
+
}
|
|
15
|
+
get length() {
|
|
16
|
+
return this.events.length;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// src/kernel/testing/fake-clock.ts
|
|
21
|
+
var FakeClock = class {
|
|
22
|
+
currentTime;
|
|
23
|
+
constructor(initialTime) {
|
|
24
|
+
this.currentTime = initialTime ?? /* @__PURE__ */ new Date("2025-01-01T00:00:00Z");
|
|
25
|
+
}
|
|
26
|
+
now() {
|
|
27
|
+
return new Date(this.currentTime.getTime());
|
|
28
|
+
}
|
|
29
|
+
advance(ms) {
|
|
30
|
+
this.currentTime = new Date(this.currentTime.getTime() + ms);
|
|
31
|
+
}
|
|
32
|
+
set(time) {
|
|
33
|
+
this.currentTime = new Date(time.getTime());
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// src/kernel/testing/in-memory-blob-store.ts
|
|
38
|
+
function deepClone(value) {
|
|
39
|
+
return JSON.parse(JSON.stringify(value));
|
|
40
|
+
}
|
|
41
|
+
var InMemoryBlobStore = class {
|
|
42
|
+
store = /* @__PURE__ */ new Map();
|
|
43
|
+
async put(key, data) {
|
|
44
|
+
this.store.set(key, deepClone(data));
|
|
45
|
+
}
|
|
46
|
+
async get(key) {
|
|
47
|
+
if (!this.store.has(key)) {
|
|
48
|
+
throw new Error(`Blob not found: ${key}`);
|
|
49
|
+
}
|
|
50
|
+
return deepClone(this.store.get(key));
|
|
51
|
+
}
|
|
52
|
+
async has(key) {
|
|
53
|
+
return this.store.has(key);
|
|
54
|
+
}
|
|
55
|
+
async delete(key) {
|
|
56
|
+
this.store.delete(key);
|
|
57
|
+
}
|
|
58
|
+
async list(prefix) {
|
|
59
|
+
return [...this.store.keys()].filter((k) => k.startsWith(prefix));
|
|
60
|
+
}
|
|
61
|
+
// Test helpers
|
|
62
|
+
clear() {
|
|
63
|
+
this.store.clear();
|
|
64
|
+
}
|
|
65
|
+
size() {
|
|
66
|
+
return this.store.size;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// src/kernel/testing/noop-scheduler.ts
|
|
71
|
+
var NoopScheduler = class {
|
|
72
|
+
scheduled = [];
|
|
73
|
+
async schedule(commandType, payload, runAt) {
|
|
74
|
+
this.scheduled.push({ commandType, payload, runAt });
|
|
75
|
+
}
|
|
76
|
+
async cancel(_commandType, _correlationId) {
|
|
77
|
+
}
|
|
78
|
+
clear() {
|
|
79
|
+
this.scheduled.length = 0;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export { CollectingEventSink, FakeClock, InMemoryBlobStore, NoopScheduler };
|
|
84
|
+
//# sourceMappingURL=index.js.map
|
|
85
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/kernel/testing/collecting-event-sink.ts","../../../src/kernel/testing/fake-clock.ts","../../../src/kernel/testing/in-memory-blob-store.ts","../../../src/kernel/testing/noop-scheduler.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { KernelEvent, KernelEventType } from \"../events\";\nimport type { EventSink } from \"../ports\";\n\nexport class CollectingEventSink implements EventSink {\n readonly events: KernelEvent[] = [];\n\n async emit(event: KernelEvent): Promise<void> {\n this.events.push(event);\n }\n\n getByType<T extends KernelEventType>(\n type: T,\n ): Extract<KernelEvent, { type: T }>[] {\n return this.events.filter(\n (e): e is Extract<KernelEvent, { type: T }> => e.type === type,\n );\n }\n\n clear(): void {\n this.events.length = 0;\n }\n\n get length(): number {\n return this.events.length;\n }\n}\n","import type { Clock } from \"../ports\";\n\nexport class FakeClock implements Clock {\n private currentTime: Date;\n\n constructor(initialTime?: Date) {\n this.currentTime = initialTime ?? new Date(\"2025-01-01T00:00:00Z\");\n }\n\n now(): Date {\n return new Date(this.currentTime.getTime());\n }\n\n advance(ms: number): void {\n this.currentTime = new Date(this.currentTime.getTime() + ms);\n }\n\n set(time: Date): void {\n this.currentTime = new Date(time.getTime());\n }\n}\n","import type { BlobStore } from \"../ports\";\n\nfunction deepClone<T>(value: T): T {\n return JSON.parse(JSON.stringify(value)) as T;\n}\n\nexport class InMemoryBlobStore implements BlobStore {\n private store = new Map<string, unknown>();\n\n async put(key: string, data: unknown): Promise<void> {\n this.store.set(key, deepClone(data));\n }\n\n async get(key: string): Promise<unknown> {\n if (!this.store.has(key)) {\n throw new Error(`Blob not found: ${key}`);\n }\n return deepClone(this.store.get(key));\n }\n\n async has(key: string): Promise<boolean> {\n return this.store.has(key);\n }\n\n async delete(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n async list(prefix: string): Promise<string[]> {\n return [...this.store.keys()].filter((k) => k.startsWith(prefix));\n }\n\n // Test helpers\n clear(): void {\n this.store.clear();\n }\n\n size(): number {\n return this.store.size;\n }\n}\n","import type { Scheduler } from \"../ports\";\n\nexport class NoopScheduler implements Scheduler {\n readonly scheduled: Array<{\n commandType: string;\n payload: unknown;\n runAt: Date;\n }> = [];\n\n async schedule(\n commandType: string,\n payload: unknown,\n runAt: Date,\n ): Promise<void> {\n this.scheduled.push({ commandType, payload, runAt });\n }\n\n async cancel(_commandType: string, _correlationId: string): Promise<void> {\n // No-op in Phase 1\n }\n\n clear(): void {\n this.scheduled.length = 0;\n }\n}\n"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { A as AICallLogger, i as AICallRecord, h as AIHelperStats, r as ArtifactType, g as CreateAICallInput, f as CreateLogInput, a as CreateRunInput, b as CreateStageInput, D as DequeueResult, E as EnqueueJobInput, J as JobQueue, j as JobRecord, k as JobStatus, L as LogLevel, o as SaveArtifactInput, S as Status, U as UpdateRunInput, e as UpdateStageInput, d as UpsertStageInput, p as WorkflowArtifactRecord, q as WorkflowLogRecord, l as WorkflowPersistence, W as WorkflowRunRecord, c as WorkflowStageRecord, n as WorkflowStageStatus, m as WorkflowStatus } from '../interface-MMqhfQQK.js';
|
|
2
|
+
export { P as PrismaAICallLogger, a as PrismaJobQueue, c as PrismaWorkflowPersistence, e as createPrismaAICallLogger, f as createPrismaJobQueue, g as createPrismaWorkflowPersistence } from '../index-DAzCfO1R.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import '../chunk-D7RVRRM2.js';
|
|
2
|
+
export { PrismaAICallLogger, PrismaJobQueue, PrismaWorkflowPersistence, createPrismaAICallLogger, createPrismaJobQueue, createPrismaWorkflowPersistence } from '../chunk-NYKMT46J.js';
|
|
3
|
+
import '../chunk-MUWP5SF2.js';
|
|
4
|
+
import '../chunk-SPXBCZLB.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
6
|
+
//# 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-DAzCfO1R.js';
|
|
2
|
+
import '../../interface-MMqhfQQK.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,5 @@
|
|
|
1
|
+
export { PrismaAICallLogger, PrismaJobQueue, PrismaWorkflowPersistence, createEnumHelper, createPrismaAICallLogger, createPrismaJobQueue, createPrismaWorkflowPersistence } from '../../chunk-NYKMT46J.js';
|
|
2
|
+
import '../../chunk-MUWP5SF2.js';
|
|
3
|
+
import '../../chunk-SPXBCZLB.js';
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|