@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,415 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { S as Stage } from './stage-BPw7m9Wx.js';
|
|
3
|
+
import { P as Persistence, B as BlobStore, J as JobTransport, E as EventSink, S as Scheduler, C as Clock, a as KernelEventType, K as KernelEvent } from './ports-tU3rzPXJ.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Workflow Builder - Fluent API for composing type-safe workflows
|
|
7
|
+
*
|
|
8
|
+
* Workflows are composed of stages that are executed sequentially or in parallel.
|
|
9
|
+
* The builder ensures type safety: output of one stage matches input of next stage.
|
|
10
|
+
*
|
|
11
|
+
* ## Type System Features
|
|
12
|
+
*
|
|
13
|
+
* ### Automatic Context Inference
|
|
14
|
+
* The workflow context type is automatically accumulated as you pipe stages.
|
|
15
|
+
* Use `InferWorkflowContext<typeof workflow>` to extract the context type.
|
|
16
|
+
*
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const workflow = new WorkflowBuilder(...)
|
|
19
|
+
* .pipe(stage1)
|
|
20
|
+
* .pipe(stage2)
|
|
21
|
+
* .build();
|
|
22
|
+
*
|
|
23
|
+
* // Auto-generated type
|
|
24
|
+
* type MyContext = InferWorkflowContext<typeof workflow>;
|
|
25
|
+
* // = { "stage-1": Stage1Output, "stage-2": Stage2Output }
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* ### Stage ID Constants
|
|
29
|
+
* Use `workflow.stageIds` for type-safe stage ID references.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
interface StageNode {
|
|
33
|
+
stage: Stage<any, any, any>;
|
|
34
|
+
executionGroup: number;
|
|
35
|
+
}
|
|
36
|
+
declare class Workflow<TInput extends z.ZodTypeAny, TOutput extends z.ZodTypeAny, TContext extends Record<string, unknown> = {}> {
|
|
37
|
+
readonly id: string;
|
|
38
|
+
readonly name: string;
|
|
39
|
+
readonly description: string;
|
|
40
|
+
readonly inputSchema: TInput;
|
|
41
|
+
readonly outputSchema: TOutput;
|
|
42
|
+
private readonly stages;
|
|
43
|
+
readonly contextType?: TContext | undefined;
|
|
44
|
+
constructor(id: string, name: string, description: string, inputSchema: TInput, outputSchema: TOutput, stages: StageNode[], contextType?: TContext | undefined);
|
|
45
|
+
/**
|
|
46
|
+
* Get execution plan as groups of stages
|
|
47
|
+
* Stages in the same group can be executed in parallel
|
|
48
|
+
*/
|
|
49
|
+
getExecutionPlan(): StageNode[][];
|
|
50
|
+
/**
|
|
51
|
+
* Get a specific stage by ID
|
|
52
|
+
*/
|
|
53
|
+
getStage(stageId: string): Stage<any, any, any> | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* Get all stages in order
|
|
56
|
+
*/
|
|
57
|
+
getAllStages(): StageNode[];
|
|
58
|
+
/**
|
|
59
|
+
* Get a visual representation of the workflow execution order
|
|
60
|
+
*/
|
|
61
|
+
getExecutionOrder(): string;
|
|
62
|
+
/**
|
|
63
|
+
* Get all stage IDs in execution order
|
|
64
|
+
*
|
|
65
|
+
* @returns Array of stage IDs
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const ids = workflow.getStageIds();
|
|
70
|
+
* // ["data-extraction", "guidelines", "generator"]
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
getStageIds(): string[];
|
|
74
|
+
/**
|
|
75
|
+
* Check if a stage ID exists in this workflow
|
|
76
|
+
*
|
|
77
|
+
* @param stageId - The stage ID to check
|
|
78
|
+
* @returns true if the stage exists
|
|
79
|
+
*/
|
|
80
|
+
hasStage(stageId: string): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Validate workflow configuration before execution
|
|
83
|
+
* Checks that all stage configs match their schemas
|
|
84
|
+
*
|
|
85
|
+
* @param config - Configuration object with keys matching stage IDs
|
|
86
|
+
* @returns Validation result with any errors
|
|
87
|
+
*/
|
|
88
|
+
validateConfig(config: Record<string, unknown>): {
|
|
89
|
+
valid: boolean;
|
|
90
|
+
errors: Array<{
|
|
91
|
+
stageId: string;
|
|
92
|
+
error: string;
|
|
93
|
+
}>;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Estimate total cost for the workflow
|
|
97
|
+
*/
|
|
98
|
+
estimateCost(input: z.infer<TInput>, config: Record<string, unknown>): number;
|
|
99
|
+
/**
|
|
100
|
+
* Get configuration schemas for all stages in this workflow
|
|
101
|
+
* Returns a map of stageId → { schema, defaults, name, description }
|
|
102
|
+
*/
|
|
103
|
+
getStageConfigs(): Record<string, {
|
|
104
|
+
schema: z.ZodTypeAny;
|
|
105
|
+
defaults: Record<string, unknown>;
|
|
106
|
+
name: string;
|
|
107
|
+
description?: string;
|
|
108
|
+
}>;
|
|
109
|
+
/**
|
|
110
|
+
* Generate default configuration object for all stages
|
|
111
|
+
* Automatically discovers all stage configs - add/remove stages and this updates automatically
|
|
112
|
+
*/
|
|
113
|
+
getDefaultConfig(): Record<string, Record<string, unknown>>;
|
|
114
|
+
/**
|
|
115
|
+
* Get all stages in a specific execution group
|
|
116
|
+
*/
|
|
117
|
+
getStagesInExecutionGroup(groupIndex: number): Stage<any, any, any>[];
|
|
118
|
+
/**
|
|
119
|
+
* Get the sequential index of a stage (0-based)
|
|
120
|
+
*/
|
|
121
|
+
getStageIndex(stageId: string): number;
|
|
122
|
+
/**
|
|
123
|
+
* Get the execution group index for a stage
|
|
124
|
+
*/
|
|
125
|
+
getExecutionGroupIndex(stageId: string): number;
|
|
126
|
+
/**
|
|
127
|
+
* Get the ID of the stage immediately preceding the given stage
|
|
128
|
+
*/
|
|
129
|
+
getPreviousStageId(stageId: string): string | undefined;
|
|
130
|
+
}
|
|
131
|
+
declare class WorkflowBuilder<TInput extends z.ZodTypeAny, TCurrentOutput extends z.ZodTypeAny, TContext extends Record<string, unknown> = {}> {
|
|
132
|
+
private id;
|
|
133
|
+
private name;
|
|
134
|
+
private description;
|
|
135
|
+
private inputSchema;
|
|
136
|
+
private currentOutputSchema;
|
|
137
|
+
private stages;
|
|
138
|
+
private currentExecutionGroup;
|
|
139
|
+
constructor(id: string, name: string, description: string, inputSchema: TInput, currentOutputSchema: TCurrentOutput);
|
|
140
|
+
/**
|
|
141
|
+
* Add a stage to the workflow (sequential execution)
|
|
142
|
+
*
|
|
143
|
+
* Automatically accumulates the stage's output in the context under its stage ID.
|
|
144
|
+
* This provides type-safe access to all previous stage outputs.
|
|
145
|
+
*
|
|
146
|
+
* Note: This accepts any stage regardless of strict input type matching.
|
|
147
|
+
* This is necessary because stages using passthrough() can accept objects
|
|
148
|
+
* with additional fields beyond what's declared in their input schema.
|
|
149
|
+
* Runtime validation via Zod ensures type safety at execution time.
|
|
150
|
+
*
|
|
151
|
+
* Validates that all declared dependencies exist in the workflow.
|
|
152
|
+
*/
|
|
153
|
+
pipe<TStageInput extends z.ZodTypeAny, TStageOutput extends z.ZodTypeAny, TStageConfig extends z.ZodTypeAny, TStageContext extends Record<string, unknown>>(stage: Stage<TStageInput, TStageOutput, TStageConfig, TStageContext>): WorkflowBuilder<TInput, TStageOutput, TContext & {
|
|
154
|
+
[x: string]: z.infer<TStageOutput>;
|
|
155
|
+
}>;
|
|
156
|
+
/**
|
|
157
|
+
* Add a stage with strict input type checking
|
|
158
|
+
*
|
|
159
|
+
* Note: pipeStrict() and pipeLoose() have been removed as they were
|
|
160
|
+
* just aliases for pipe(). Use pipe() for all stage chaining.
|
|
161
|
+
*/
|
|
162
|
+
/**
|
|
163
|
+
* Add multiple stages that execute in parallel
|
|
164
|
+
*
|
|
165
|
+
* All stages receive the same input (current output)
|
|
166
|
+
* Their outputs are merged into an object by index AND accumulated in context by stage ID.
|
|
167
|
+
*
|
|
168
|
+
* Note: This accepts stages regardless of strict input type matching.
|
|
169
|
+
* This is necessary because stages using passthrough() can accept objects
|
|
170
|
+
* with additional fields. Runtime validation via Zod ensures type safety.
|
|
171
|
+
*
|
|
172
|
+
* Validates that all declared dependencies exist in the workflow.
|
|
173
|
+
*/
|
|
174
|
+
parallel<TStages extends {
|
|
175
|
+
id: string;
|
|
176
|
+
outputSchema: z.ZodTypeAny;
|
|
177
|
+
dependencies?: string[];
|
|
178
|
+
}[]>(stages: [...TStages]): WorkflowBuilder<TInput, z.ZodTypeAny, TContext & {
|
|
179
|
+
[K in TStages[number]["id"]]: TStages[number] extends {
|
|
180
|
+
outputSchema: infer O;
|
|
181
|
+
} ? O extends z.ZodTypeAny ? z.infer<O> : never : never;
|
|
182
|
+
}>;
|
|
183
|
+
/**
|
|
184
|
+
* Build the final workflow
|
|
185
|
+
*/
|
|
186
|
+
build(): Workflow<TInput, TCurrentOutput, TContext>;
|
|
187
|
+
/**
|
|
188
|
+
* Get current stage count
|
|
189
|
+
*/
|
|
190
|
+
getStageCount(): number;
|
|
191
|
+
/**
|
|
192
|
+
* Get execution group count
|
|
193
|
+
*/
|
|
194
|
+
getExecutionGroupCount(): number;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Extract stage IDs as a union type from a Workflow instance
|
|
198
|
+
*
|
|
199
|
+
* Useful for creating type-safe stage ID references.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* type StageId = InferWorkflowStageIds<typeof myWorkflow>;
|
|
204
|
+
* // = "data-extraction" | "guidelines" | "generator"
|
|
205
|
+
*
|
|
206
|
+
* function getStageOutput(stageId: StageId) { ... }
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
type InferWorkflowStageIds<W> = W extends Workflow<any, any, infer C> ? keyof C & string : never;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Kernel Command Types
|
|
213
|
+
*
|
|
214
|
+
* Discriminated union of commands accepted by the kernel's dispatch
|
|
215
|
+
* interface, together with a conditional `CommandResult` type that maps
|
|
216
|
+
* each command to its corresponding result.
|
|
217
|
+
*
|
|
218
|
+
* This file contains ONLY types -- no runtime code.
|
|
219
|
+
*/
|
|
220
|
+
/** Creates a new workflow run. */
|
|
221
|
+
interface RunCreateCommand {
|
|
222
|
+
readonly type: "run.create";
|
|
223
|
+
readonly idempotencyKey: string;
|
|
224
|
+
readonly workflowId: string;
|
|
225
|
+
readonly input: Record<string, unknown>;
|
|
226
|
+
readonly config?: Record<string, unknown>;
|
|
227
|
+
readonly priority?: number;
|
|
228
|
+
readonly metadata?: Record<string, unknown>;
|
|
229
|
+
}
|
|
230
|
+
/** Result of a `run.create` command. */
|
|
231
|
+
interface RunCreateResult {
|
|
232
|
+
readonly workflowRunId: string;
|
|
233
|
+
readonly status: "PENDING";
|
|
234
|
+
}
|
|
235
|
+
/** Claims pending runs and enqueues first-stage jobs. */
|
|
236
|
+
interface RunClaimPendingCommand {
|
|
237
|
+
readonly type: "run.claimPending";
|
|
238
|
+
readonly workerId: string;
|
|
239
|
+
readonly maxClaims?: number;
|
|
240
|
+
}
|
|
241
|
+
/** Result of a `run.claimPending` command. */
|
|
242
|
+
interface RunClaimPendingResult {
|
|
243
|
+
readonly claimed: ReadonlyArray<{
|
|
244
|
+
readonly workflowRunId: string;
|
|
245
|
+
readonly workflowId: string;
|
|
246
|
+
readonly jobIds: string[];
|
|
247
|
+
}>;
|
|
248
|
+
}
|
|
249
|
+
/** Advances a workflow to the next stage group or completes it. */
|
|
250
|
+
interface RunTransitionCommand {
|
|
251
|
+
readonly type: "run.transition";
|
|
252
|
+
readonly workflowRunId: string;
|
|
253
|
+
}
|
|
254
|
+
/** Result of a `run.transition` command. */
|
|
255
|
+
interface RunTransitionResult {
|
|
256
|
+
readonly action: "advanced" | "completed" | "failed" | "noop";
|
|
257
|
+
readonly nextGroup?: number;
|
|
258
|
+
}
|
|
259
|
+
/** Cancels a running workflow. */
|
|
260
|
+
interface RunCancelCommand {
|
|
261
|
+
readonly type: "run.cancel";
|
|
262
|
+
readonly workflowRunId: string;
|
|
263
|
+
readonly reason?: string;
|
|
264
|
+
}
|
|
265
|
+
/** Result of a `run.cancel` command. */
|
|
266
|
+
interface RunCancelResult {
|
|
267
|
+
readonly cancelled: boolean;
|
|
268
|
+
}
|
|
269
|
+
/** Reruns a workflow from a specific stage, deleting stages at/after that point. */
|
|
270
|
+
interface RunRerunFromCommand {
|
|
271
|
+
readonly type: "run.rerunFrom";
|
|
272
|
+
readonly workflowRunId: string;
|
|
273
|
+
readonly fromStageId: string;
|
|
274
|
+
}
|
|
275
|
+
/** Result of a `run.rerunFrom` command. */
|
|
276
|
+
interface RunRerunFromResult {
|
|
277
|
+
readonly workflowRunId: string;
|
|
278
|
+
readonly fromStageId: string;
|
|
279
|
+
readonly deletedStages: string[];
|
|
280
|
+
}
|
|
281
|
+
/** Executes a single stage within a workflow run. */
|
|
282
|
+
interface JobExecuteCommand {
|
|
283
|
+
readonly type: "job.execute";
|
|
284
|
+
readonly idempotencyKey?: string;
|
|
285
|
+
readonly workflowRunId: string;
|
|
286
|
+
readonly workflowId: string;
|
|
287
|
+
readonly stageId: string;
|
|
288
|
+
readonly config: Record<string, unknown>;
|
|
289
|
+
}
|
|
290
|
+
/** Result of a `job.execute` command. */
|
|
291
|
+
interface JobExecuteResult {
|
|
292
|
+
readonly outcome: "completed" | "suspended" | "failed";
|
|
293
|
+
readonly output?: unknown;
|
|
294
|
+
readonly error?: string;
|
|
295
|
+
readonly nextPollAt?: Date;
|
|
296
|
+
}
|
|
297
|
+
/** Polls suspended stages to check if they can be resumed. */
|
|
298
|
+
interface StagePollSuspendedCommand {
|
|
299
|
+
readonly type: "stage.pollSuspended";
|
|
300
|
+
readonly maxChecks?: number;
|
|
301
|
+
}
|
|
302
|
+
/** Result of a `stage.pollSuspended` command. */
|
|
303
|
+
interface StagePollSuspendedResult {
|
|
304
|
+
readonly checked: number;
|
|
305
|
+
readonly resumed: number;
|
|
306
|
+
readonly failed: number;
|
|
307
|
+
readonly resumedWorkflowRunIds: string[];
|
|
308
|
+
}
|
|
309
|
+
/** Releases stale job leases that have exceeded the threshold. */
|
|
310
|
+
interface LeaseReapStaleCommand {
|
|
311
|
+
readonly type: "lease.reapStale";
|
|
312
|
+
readonly staleThresholdMs: number;
|
|
313
|
+
}
|
|
314
|
+
/** Result of a `lease.reapStale` command. */
|
|
315
|
+
interface LeaseReapStaleResult {
|
|
316
|
+
readonly released: number;
|
|
317
|
+
}
|
|
318
|
+
/** Publishes pending outbox events through EventSink. */
|
|
319
|
+
interface OutboxFlushCommand {
|
|
320
|
+
readonly type: "outbox.flush";
|
|
321
|
+
readonly maxEvents?: number;
|
|
322
|
+
}
|
|
323
|
+
/** Result of an `outbox.flush` command. */
|
|
324
|
+
interface OutboxFlushResult {
|
|
325
|
+
readonly published: number;
|
|
326
|
+
}
|
|
327
|
+
/** Replays DLQ outbox events for reprocessing. */
|
|
328
|
+
interface PluginReplayDLQCommand {
|
|
329
|
+
readonly type: "plugin.replayDLQ";
|
|
330
|
+
readonly maxEvents?: number;
|
|
331
|
+
}
|
|
332
|
+
/** Result of a `plugin.replayDLQ` command. */
|
|
333
|
+
interface PluginReplayDLQResult {
|
|
334
|
+
readonly replayed: number;
|
|
335
|
+
}
|
|
336
|
+
/** Discriminated union of every kernel command. */
|
|
337
|
+
type KernelCommand = RunCreateCommand | RunClaimPendingCommand | RunTransitionCommand | RunCancelCommand | RunRerunFromCommand | JobExecuteCommand | StagePollSuspendedCommand | LeaseReapStaleCommand | OutboxFlushCommand | PluginReplayDLQCommand;
|
|
338
|
+
/** String literal union of all kernel command type discriminants. */
|
|
339
|
+
type KernelCommandType = KernelCommand["type"];
|
|
340
|
+
/** Maps a `KernelCommand` to its corresponding result type. */
|
|
341
|
+
type CommandResult<T extends KernelCommand> = T extends RunCreateCommand ? RunCreateResult : T extends RunClaimPendingCommand ? RunClaimPendingResult : T extends RunTransitionCommand ? RunTransitionResult : T extends RunCancelCommand ? RunCancelResult : T extends RunRerunFromCommand ? RunRerunFromResult : T extends JobExecuteCommand ? JobExecuteResult : T extends StagePollSuspendedCommand ? StagePollSuspendedResult : T extends LeaseReapStaleCommand ? LeaseReapStaleResult : T extends OutboxFlushCommand ? OutboxFlushResult : T extends PluginReplayDLQCommand ? PluginReplayDLQResult : never;
|
|
342
|
+
|
|
343
|
+
declare class IdempotencyInProgressError extends Error {
|
|
344
|
+
readonly key: string;
|
|
345
|
+
readonly commandType: string;
|
|
346
|
+
constructor(key: string, commandType: string);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Kernel Factory
|
|
351
|
+
*
|
|
352
|
+
* Creates a Kernel instance with a typed `dispatch` method that routes
|
|
353
|
+
* commands to their corresponding handlers. Events are written to a
|
|
354
|
+
* transactional outbox (not emitted directly). Use the `outbox.flush`
|
|
355
|
+
* command to publish pending outbox events through EventSink.
|
|
356
|
+
*
|
|
357
|
+
* Commands with idempotency keys are deduplicated: a replay returns the
|
|
358
|
+
* cached result without re-executing the handler.
|
|
359
|
+
*/
|
|
360
|
+
|
|
361
|
+
interface WorkflowRegistry {
|
|
362
|
+
getWorkflow(id: string): Workflow<any, any> | undefined;
|
|
363
|
+
}
|
|
364
|
+
interface KernelConfig {
|
|
365
|
+
persistence: Persistence;
|
|
366
|
+
blobStore: BlobStore;
|
|
367
|
+
jobTransport: JobTransport;
|
|
368
|
+
eventSink: EventSink;
|
|
369
|
+
scheduler: Scheduler;
|
|
370
|
+
clock: Clock;
|
|
371
|
+
registry: WorkflowRegistry;
|
|
372
|
+
}
|
|
373
|
+
interface Kernel {
|
|
374
|
+
dispatch<T extends KernelCommand>(command: T): Promise<CommandResult<T>>;
|
|
375
|
+
}
|
|
376
|
+
interface KernelDeps {
|
|
377
|
+
persistence: Persistence;
|
|
378
|
+
blobStore: BlobStore;
|
|
379
|
+
jobTransport: JobTransport;
|
|
380
|
+
eventSink: EventSink;
|
|
381
|
+
scheduler: Scheduler;
|
|
382
|
+
clock: Clock;
|
|
383
|
+
registry: WorkflowRegistry;
|
|
384
|
+
}
|
|
385
|
+
declare function createKernel(config: KernelConfig): Kernel;
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Plugin Runner
|
|
389
|
+
*
|
|
390
|
+
* A concrete EventSink implementation that routes kernel events
|
|
391
|
+
* to registered plugin handlers. Used as the eventSink when the
|
|
392
|
+
* consumer wants domain side-effects on workflow events.
|
|
393
|
+
*/
|
|
394
|
+
|
|
395
|
+
interface PluginDefinition<T extends KernelEventType = KernelEventType> {
|
|
396
|
+
readonly id: string;
|
|
397
|
+
readonly name: string;
|
|
398
|
+
readonly on: readonly T[];
|
|
399
|
+
handle(event: Extract<KernelEvent, {
|
|
400
|
+
type: T;
|
|
401
|
+
}>): Promise<void>;
|
|
402
|
+
}
|
|
403
|
+
interface PluginRunnerConfig {
|
|
404
|
+
plugins: PluginDefinition[];
|
|
405
|
+
/** Max retries before an event moves to DLQ (default: 3). */
|
|
406
|
+
maxRetries?: number;
|
|
407
|
+
}
|
|
408
|
+
interface PluginRunner extends EventSink {
|
|
409
|
+
/** Max retries before DLQ. Exposed so outbox.flush can read it. */
|
|
410
|
+
readonly maxRetries: number;
|
|
411
|
+
}
|
|
412
|
+
declare function definePlugin<T extends KernelEventType>(definition: PluginDefinition<T>): PluginDefinition<T>;
|
|
413
|
+
declare function createPluginRunner(config: PluginRunnerConfig): PluginRunner;
|
|
414
|
+
|
|
415
|
+
export { WorkflowBuilder as A, type CommandResult as C, IdempotencyInProgressError as I, type JobExecuteCommand as J, type KernelDeps as K, type LeaseReapStaleCommand as L, type OutboxFlushCommand as O, type PluginDefinition as P, type RunCancelCommand as R, type StagePollSuspendedCommand as S, type WorkflowRegistry as W, type JobExecuteResult as a, type Kernel as b, type KernelCommand as c, type KernelCommandType as d, type KernelConfig as e, type LeaseReapStaleResult as f, type OutboxFlushResult as g, type PluginReplayDLQCommand as h, type PluginReplayDLQResult as i, type PluginRunner as j, type PluginRunnerConfig as k, type RunCancelResult as l, type RunClaimPendingCommand as m, type RunClaimPendingResult as n, type RunCreateCommand as o, type RunCreateResult as p, type RunRerunFromCommand as q, type RunRerunFromResult as r, type RunTransitionCommand as s, type RunTransitionResult as t, type StagePollSuspendedResult as u, createKernel as v, createPluginRunner as w, definePlugin as x, type InferWorkflowStageIds as y, Workflow as z };
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { E as EnqueueJobInput, D as DequeueResult, a as CreateRunInput, W as WorkflowRunRecord, U as UpdateRunInput, S as Status, b as CreateStageInput, c as WorkflowStageRecord, d as UpsertStageInput, e as UpdateStageInput, f as CreateLogInput, C as CreateOutboxEventInput, O as OutboxRecord } from './interface-MMqhfQQK.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Kernel Event Types
|
|
5
|
+
*
|
|
6
|
+
* Discriminated union of all events emitted by the workflow kernel.
|
|
7
|
+
* Each event carries a string literal `type` discriminant, a `timestamp`,
|
|
8
|
+
* and a `workflowRunId` that scopes the event to a specific run.
|
|
9
|
+
*
|
|
10
|
+
* This file contains ONLY types -- no runtime code.
|
|
11
|
+
*/
|
|
12
|
+
/** Emitted when a new workflow run record is created. */
|
|
13
|
+
interface WorkflowCreatedEvent {
|
|
14
|
+
readonly type: "workflow:created";
|
|
15
|
+
readonly timestamp: Date;
|
|
16
|
+
readonly workflowRunId: string;
|
|
17
|
+
readonly workflowId: string;
|
|
18
|
+
}
|
|
19
|
+
/** Emitted when a workflow run begins execution. */
|
|
20
|
+
interface WorkflowStartedEvent {
|
|
21
|
+
readonly type: "workflow:started";
|
|
22
|
+
readonly timestamp: Date;
|
|
23
|
+
readonly workflowRunId: string;
|
|
24
|
+
}
|
|
25
|
+
/** Emitted when a workflow run finishes successfully. */
|
|
26
|
+
interface WorkflowCompletedEvent {
|
|
27
|
+
readonly type: "workflow:completed";
|
|
28
|
+
readonly timestamp: Date;
|
|
29
|
+
readonly workflowRunId: string;
|
|
30
|
+
readonly duration?: number;
|
|
31
|
+
readonly totalCost?: number;
|
|
32
|
+
readonly totalTokens?: number;
|
|
33
|
+
readonly output?: unknown;
|
|
34
|
+
}
|
|
35
|
+
/** Emitted when a workflow run terminates due to an unrecoverable error. */
|
|
36
|
+
interface WorkflowFailedEvent {
|
|
37
|
+
readonly type: "workflow:failed";
|
|
38
|
+
readonly timestamp: Date;
|
|
39
|
+
readonly workflowRunId: string;
|
|
40
|
+
readonly error: string;
|
|
41
|
+
}
|
|
42
|
+
/** Emitted when a workflow run is cancelled by an external request. */
|
|
43
|
+
interface WorkflowCancelledEvent {
|
|
44
|
+
readonly type: "workflow:cancelled";
|
|
45
|
+
readonly timestamp: Date;
|
|
46
|
+
readonly workflowRunId: string;
|
|
47
|
+
readonly reason?: string;
|
|
48
|
+
}
|
|
49
|
+
/** Emitted when a workflow run suspends, waiting on an external signal. */
|
|
50
|
+
interface WorkflowSuspendedEvent {
|
|
51
|
+
readonly type: "workflow:suspended";
|
|
52
|
+
readonly timestamp: Date;
|
|
53
|
+
readonly workflowRunId: string;
|
|
54
|
+
readonly stageId: string;
|
|
55
|
+
}
|
|
56
|
+
/** Emitted when a stage begins execution. */
|
|
57
|
+
interface StageStartedEvent {
|
|
58
|
+
readonly type: "stage:started";
|
|
59
|
+
readonly timestamp: Date;
|
|
60
|
+
readonly workflowRunId: string;
|
|
61
|
+
readonly stageId: string;
|
|
62
|
+
readonly stageName: string;
|
|
63
|
+
readonly stageNumber: number;
|
|
64
|
+
}
|
|
65
|
+
/** Emitted when a stage completes successfully. */
|
|
66
|
+
interface StageCompletedEvent {
|
|
67
|
+
readonly type: "stage:completed";
|
|
68
|
+
readonly timestamp: Date;
|
|
69
|
+
readonly workflowRunId: string;
|
|
70
|
+
readonly stageId: string;
|
|
71
|
+
readonly stageName: string;
|
|
72
|
+
readonly duration: number;
|
|
73
|
+
}
|
|
74
|
+
/** Emitted when a stage suspends, awaiting a future poll. */
|
|
75
|
+
interface StageSuspendedEvent {
|
|
76
|
+
readonly type: "stage:suspended";
|
|
77
|
+
readonly timestamp: Date;
|
|
78
|
+
readonly workflowRunId: string;
|
|
79
|
+
readonly stageId: string;
|
|
80
|
+
readonly stageName: string;
|
|
81
|
+
readonly nextPollAt: Date;
|
|
82
|
+
}
|
|
83
|
+
/** Emitted when a stage fails with an error. */
|
|
84
|
+
interface StageFailedEvent {
|
|
85
|
+
readonly type: "stage:failed";
|
|
86
|
+
readonly timestamp: Date;
|
|
87
|
+
readonly workflowRunId: string;
|
|
88
|
+
readonly stageId: string;
|
|
89
|
+
readonly stageName: string;
|
|
90
|
+
readonly error: string;
|
|
91
|
+
}
|
|
92
|
+
/** Emitted to report incremental progress within a stage. */
|
|
93
|
+
interface StageProgressEvent {
|
|
94
|
+
readonly type: "stage:progress";
|
|
95
|
+
readonly timestamp: Date;
|
|
96
|
+
readonly workflowRunId: string;
|
|
97
|
+
readonly stageId: string;
|
|
98
|
+
readonly progress: number;
|
|
99
|
+
readonly message: string;
|
|
100
|
+
readonly details?: Record<string, unknown>;
|
|
101
|
+
}
|
|
102
|
+
/** Discriminated union of every kernel event. */
|
|
103
|
+
type KernelEvent = WorkflowCreatedEvent | WorkflowStartedEvent | WorkflowCompletedEvent | WorkflowFailedEvent | WorkflowCancelledEvent | WorkflowSuspendedEvent | StageStartedEvent | StageCompletedEvent | StageSuspendedEvent | StageFailedEvent | StageProgressEvent;
|
|
104
|
+
/** String literal union of all kernel event type discriminants. */
|
|
105
|
+
type KernelEventType = KernelEvent["type"];
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Kernel Port Interfaces
|
|
109
|
+
*
|
|
110
|
+
* These interfaces define the dependency-inversion boundary for the workflow
|
|
111
|
+
* kernel. Every external capability the kernel needs is expressed as a port
|
|
112
|
+
* interface here. Concrete implementations are injected at composition time,
|
|
113
|
+
* making the kernel fully testable with in-memory fakes.
|
|
114
|
+
*
|
|
115
|
+
* Ports:
|
|
116
|
+
* - Clock – injectable time source
|
|
117
|
+
* - Persistence – metadata storage (runs, stages, logs, artifacts)
|
|
118
|
+
* - BlobStore – large payload storage
|
|
119
|
+
* - JobTransport – job queue abstraction
|
|
120
|
+
* - EventSink – event publishing
|
|
121
|
+
* - Scheduler – deferred command triggers
|
|
122
|
+
*/
|
|
123
|
+
|
|
124
|
+
/** Injectable time source. */
|
|
125
|
+
interface Clock {
|
|
126
|
+
now(): Date;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Metadata storage port.
|
|
130
|
+
*
|
|
131
|
+
* Run, stage, and log CRUD operations. Artifact payloads are handled
|
|
132
|
+
* by the BlobStore port.
|
|
133
|
+
*/
|
|
134
|
+
interface Persistence {
|
|
135
|
+
/** Execute operations within a transaction boundary. */
|
|
136
|
+
withTransaction<T>(fn: (tx: Persistence) => Promise<T>): Promise<T>;
|
|
137
|
+
createRun(data: CreateRunInput): Promise<WorkflowRunRecord>;
|
|
138
|
+
updateRun(id: string, data: UpdateRunInput): Promise<void>;
|
|
139
|
+
getRun(id: string): Promise<WorkflowRunRecord | null>;
|
|
140
|
+
getRunStatus(id: string): Promise<Status | null>;
|
|
141
|
+
getRunsByStatus(status: Status): Promise<WorkflowRunRecord[]>;
|
|
142
|
+
/**
|
|
143
|
+
* Atomically claim a pending workflow run for processing.
|
|
144
|
+
* Uses atomic update with WHERE status = 'PENDING' to prevent race conditions.
|
|
145
|
+
*/
|
|
146
|
+
claimPendingRun(id: string): Promise<boolean>;
|
|
147
|
+
/**
|
|
148
|
+
* Atomically find and claim the next pending workflow run.
|
|
149
|
+
* Uses FOR UPDATE SKIP LOCKED pattern (in Postgres) to prevent race conditions
|
|
150
|
+
* when multiple workers try to claim workflows simultaneously.
|
|
151
|
+
*
|
|
152
|
+
* Priority ordering: higher priority first, then oldest (FIFO within same priority).
|
|
153
|
+
*/
|
|
154
|
+
claimNextPendingRun(): Promise<WorkflowRunRecord | null>;
|
|
155
|
+
createStage(data: CreateStageInput): Promise<WorkflowStageRecord>;
|
|
156
|
+
upsertStage(data: UpsertStageInput): Promise<WorkflowStageRecord>;
|
|
157
|
+
updateStage(id: string, data: UpdateStageInput): Promise<void>;
|
|
158
|
+
updateStageByRunAndStageId(workflowRunId: string, stageId: string, data: UpdateStageInput): Promise<void>;
|
|
159
|
+
getStage(runId: string, stageId: string): Promise<WorkflowStageRecord | null>;
|
|
160
|
+
getStageById(id: string): Promise<WorkflowStageRecord | null>;
|
|
161
|
+
getStagesByRun(runId: string, options?: {
|
|
162
|
+
status?: Status;
|
|
163
|
+
orderBy?: "asc" | "desc";
|
|
164
|
+
}): Promise<WorkflowStageRecord[]>;
|
|
165
|
+
getSuspendedStages(beforeDate: Date): Promise<WorkflowStageRecord[]>;
|
|
166
|
+
getFirstSuspendedStageReadyToResume(runId: string): Promise<WorkflowStageRecord | null>;
|
|
167
|
+
getFirstFailedStage(runId: string): Promise<WorkflowStageRecord | null>;
|
|
168
|
+
getLastCompletedStage(runId: string): Promise<WorkflowStageRecord | null>;
|
|
169
|
+
getLastCompletedStageBefore(runId: string, executionGroup: number): Promise<WorkflowStageRecord | null>;
|
|
170
|
+
deleteStage(id: string): Promise<void>;
|
|
171
|
+
createLog(data: CreateLogInput): Promise<void>;
|
|
172
|
+
/** Write events to the outbox. Sequences are auto-assigned per workflowRunId. */
|
|
173
|
+
appendOutboxEvents(events: CreateOutboxEventInput[]): Promise<void>;
|
|
174
|
+
/** Read unpublished events ordered by (workflowRunId, sequence). */
|
|
175
|
+
getUnpublishedOutboxEvents(limit?: number): Promise<OutboxRecord[]>;
|
|
176
|
+
/** Mark events as published. */
|
|
177
|
+
markOutboxEventsPublished(ids: string[]): Promise<void>;
|
|
178
|
+
/** Increment retry count for a failed outbox event. Returns new count. */
|
|
179
|
+
incrementOutboxRetryCount(id: string): Promise<number>;
|
|
180
|
+
/** Move an outbox event to DLQ (sets dlqAt). */
|
|
181
|
+
moveOutboxEventToDLQ(id: string): Promise<void>;
|
|
182
|
+
/** Reset DLQ events so they can be reprocessed by outbox.flush. Returns count reset. */
|
|
183
|
+
replayDLQEvents(maxEvents: number): Promise<number>;
|
|
184
|
+
/** Atomically acquire an idempotency key for command execution. */
|
|
185
|
+
acquireIdempotencyKey(key: string, commandType: string): Promise<{
|
|
186
|
+
status: "acquired";
|
|
187
|
+
} | {
|
|
188
|
+
status: "replay";
|
|
189
|
+
result: unknown;
|
|
190
|
+
} | {
|
|
191
|
+
status: "in_progress";
|
|
192
|
+
}>;
|
|
193
|
+
/** Mark an idempotency key as completed and cache the command result. */
|
|
194
|
+
completeIdempotencyKey(key: string, commandType: string, result: unknown): Promise<void>;
|
|
195
|
+
/** Release an in-progress idempotency key after command failure. */
|
|
196
|
+
releaseIdempotencyKey(key: string, commandType: string): Promise<void>;
|
|
197
|
+
}
|
|
198
|
+
/** Large payload storage. */
|
|
199
|
+
interface BlobStore {
|
|
200
|
+
put(key: string, data: unknown): Promise<void>;
|
|
201
|
+
get(key: string): Promise<unknown>;
|
|
202
|
+
has(key: string): Promise<boolean>;
|
|
203
|
+
delete(key: string): Promise<void>;
|
|
204
|
+
list(prefix: string): Promise<string[]>;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Job queue abstraction.
|
|
208
|
+
*
|
|
209
|
+
* Same shape as the existing `JobQueue` interface so that current
|
|
210
|
+
* implementations (`InMemoryJobQueue`, `PrismaJobQueue`) structurally satisfy
|
|
211
|
+
* this port without adapters.
|
|
212
|
+
*/
|
|
213
|
+
interface JobTransport {
|
|
214
|
+
/** Add a new job to the queue. */
|
|
215
|
+
enqueue(options: EnqueueJobInput): Promise<string>;
|
|
216
|
+
/** Enqueue multiple stages in parallel (same execution group). */
|
|
217
|
+
enqueueParallel(jobs: EnqueueJobInput[]): Promise<string[]>;
|
|
218
|
+
/** Atomically dequeue the next available job. */
|
|
219
|
+
dequeue(): Promise<DequeueResult | null>;
|
|
220
|
+
/** Mark job as completed. */
|
|
221
|
+
complete(jobId: string): Promise<void>;
|
|
222
|
+
/** Mark job as suspended (for async-batch). */
|
|
223
|
+
suspend(jobId: string, nextPollAt: Date): Promise<void>;
|
|
224
|
+
/** Mark job as failed. */
|
|
225
|
+
fail(jobId: string, error: string, shouldRetry?: boolean): Promise<void>;
|
|
226
|
+
/** Get suspended jobs that are ready to be checked. */
|
|
227
|
+
getSuspendedJobsReadyToPoll(): Promise<Array<{
|
|
228
|
+
jobId: string;
|
|
229
|
+
stageId: string;
|
|
230
|
+
workflowRunId: string;
|
|
231
|
+
}>>;
|
|
232
|
+
/** Release stale locks (for crashed workers). */
|
|
233
|
+
releaseStaleJobs(staleThresholdMs?: number): Promise<number>;
|
|
234
|
+
}
|
|
235
|
+
/** Event publishing (replaces global EventBus). */
|
|
236
|
+
interface EventSink {
|
|
237
|
+
emit(event: KernelEvent): Promise<void>;
|
|
238
|
+
}
|
|
239
|
+
/** Deferred command triggers (minimal in Phase 1). */
|
|
240
|
+
interface Scheduler {
|
|
241
|
+
schedule(commandType: string, payload: unknown, runAt: Date): Promise<void>;
|
|
242
|
+
cancel(commandType: string, correlationId: string): Promise<void>;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export type { BlobStore as B, Clock as C, EventSink as E, JobTransport as J, KernelEvent as K, Persistence as P, Scheduler as S, WorkflowCancelledEvent as W, KernelEventType as a, StageCompletedEvent as b, StageFailedEvent as c, StageProgressEvent as d, StageStartedEvent as e, StageSuspendedEvent as f, WorkflowCompletedEvent as g, WorkflowCreatedEvent as h, WorkflowFailedEvent as i, WorkflowStartedEvent as j, WorkflowSuspendedEvent as k };
|