@db-lyon/flowkit 0.11.1 → 0.12.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,430 @@
1
+ # API reference
2
+
3
+ Complete reference for all public exports from `@db-lyon/flowkit`.
4
+
5
+ ## Config
6
+
7
+ *Import from `@db-lyon/flowkit` or `@db-lyon/flowkit/config`*
8
+
9
+ ### `loadConfig(options)`
10
+
11
+ Load, layer, and validate YAML configuration files.
12
+
13
+ ```typescript
14
+ function loadConfig<T extends z.ZodType>(
15
+ options: LoadConfigOptions<T>,
16
+ ): LoadedConfig<z.infer<T>>
17
+ ```
18
+
19
+ **`LoadConfigOptions<T>`**
20
+
21
+ | Field | Type | Required | Description |
22
+ |-------|------|----------|-------------|
23
+ | `filename` | `string` | yes | Primary config filename (e.g., `'app.yml'`) |
24
+ | `schema` | `z.ZodType` | yes | Zod schema applied after merging all layers |
25
+ | `defaults` | `unknown` | no | Built-in defaults merged under the project file |
26
+ | `env` | `string` | no | Environment name — loads `{base}.{env}.{ext}` overlay |
27
+ | `envVar` | `string` | no | Env var to read environment name from when `env` is not passed |
28
+ | `configDir` | `string` | no | Directory to search (default: `process.cwd()`) |
29
+
30
+ **`LoadedConfig<T>`**
31
+
32
+ | Field | Type | Description |
33
+ |-------|------|-------------|
34
+ | `config` | `T` | The validated, merged configuration object |
35
+ | `configDir` | `string` | The directory the config was loaded from |
36
+
37
+ ---
38
+
39
+ ### `findConfigFile(filename, startDir?)`
40
+
41
+ Walk up parent directories looking for a file by name.
42
+
43
+ ```typescript
44
+ function findConfigFile(filename: string, startDir?: string): string
45
+ ```
46
+
47
+ Returns the absolute path. Throws if not found.
48
+
49
+ ---
50
+
51
+ ### `loadRawYaml(filePath)`
52
+
53
+ Parse a YAML file and return the raw result (no schema validation).
54
+
55
+ ```typescript
56
+ function loadRawYaml(filePath: string): unknown
57
+ ```
58
+
59
+ ---
60
+
61
+ ### `deepMerge(base, override)`
62
+
63
+ Recursively merge two values. Objects merge key-by-key, arrays replace (unless `__merge: 'append'`), scalars override, `null` nullifies, `undefined` is a no-op.
64
+
65
+ ```typescript
66
+ function deepMerge(base: unknown, override: unknown): unknown
67
+ ```
68
+
69
+ ---
70
+
71
+ ### Zod schemas
72
+
73
+ | Schema | Validates |
74
+ |--------|-----------|
75
+ | `TaskOptionsSchema` | `Record<string, unknown>` |
76
+ | `TaskDefinitionSchema` | Task definition object |
77
+ | `FlowStepSchema` | Single flow step (task xor flow) |
78
+ | `FlowDefinitionSchema` | Flow with description and steps |
79
+ | `EngineConfigSchema` | Top-level config with `tasks` and `flows` |
80
+
81
+ ---
82
+
83
+ ### Config types
84
+
85
+ ```typescript
86
+ type TaskOptions = Record<string, unknown>;
87
+
88
+ type TaskDefinition = {
89
+ class_path: string;
90
+ description?: string;
91
+ group?: string;
92
+ options: TaskOptions; // defaults to {}
93
+ };
94
+
95
+ type FlowStep = {
96
+ task?: string;
97
+ flow?: string;
98
+ options?: TaskOptions;
99
+ };
100
+
101
+ type FlowDefinition = {
102
+ description: string;
103
+ steps: Record<string, FlowStep>;
104
+ };
105
+
106
+ type EngineConfig = {
107
+ tasks: Record<string, TaskDefinition>;
108
+ flows: Record<string, FlowDefinition>;
109
+ };
110
+ ```
111
+
112
+ ---
113
+
114
+ ## Task
115
+
116
+ *Import from `@db-lyon/flowkit` or `@db-lyon/flowkit/task`*
117
+
118
+ ### `BaseTask<TOpts>`
119
+
120
+ Abstract base class for all tasks.
121
+
122
+ ```typescript
123
+ abstract class BaseTask<TOpts = Record<string, unknown>> {
124
+ protected ctx: TaskContext;
125
+ protected options: TOpts;
126
+ protected logger: Logger;
127
+
128
+ constructor(ctx: TaskContext, options: TOpts);
129
+
130
+ abstract get taskName(): string;
131
+ abstract execute(): Promise<TaskResult>;
132
+ protected validate(): void;
133
+ async run(): Promise<TaskResult>;
134
+ }
135
+ ```
136
+
137
+ | Method | Description |
138
+ |--------|-------------|
139
+ | `taskName` | (getter) Human-readable name for logging |
140
+ | `execute()` | Perform the task's work. Return a `TaskResult`. |
141
+ | `validate()` | Optional. Called before `execute()`. Throw to abort. |
142
+ | `run()` | Lifecycle wrapper: validate → execute → catch errors → add duration. Called by the flow runner. |
143
+
144
+ ---
145
+
146
+ ### `TaskContext`
147
+
148
+ ```typescript
149
+ interface TaskContext {
150
+ logger?: Logger;
151
+ [key: string]: unknown;
152
+ }
153
+ ```
154
+
155
+ Shared context passed to every task. Add any properties you need (database connections, API clients, etc.).
156
+
157
+ ---
158
+
159
+ ### `TaskResult`
160
+
161
+ ```typescript
162
+ interface TaskResult {
163
+ success: boolean;
164
+ data?: Record<string, unknown>;
165
+ error?: Error;
166
+ duration?: number; // milliseconds, set by run()
167
+ }
168
+ ```
169
+
170
+ ---
171
+
172
+ ### `ShellTask`
173
+
174
+ Built-in task that executes shell commands via `execSync`.
175
+
176
+ ```typescript
177
+ class ShellTask extends BaseTask<ShellTaskOptions> {
178
+ get taskName(): string; // "shell:{command}"
179
+ protected validate(): void; // requires command
180
+ async execute(): Promise<TaskResult>;
181
+ }
182
+ ```
183
+
184
+ **`ShellTaskOptions`**
185
+
186
+ | Field | Type | Default | Description |
187
+ |-------|------|---------|-------------|
188
+ | `command` | `string` | (required) | Shell command to execute |
189
+ | `cwd` | `string` | `undefined` | Working directory |
190
+ | `timeout` | `number` | `300000` | Timeout in milliseconds (5 min) |
191
+
192
+ **Success result:** `data.output` contains trimmed stdout.
193
+
194
+ **Failure result:** `data.exitCode`, `data.stderr`, `data.stdout`.
195
+
196
+ ---
197
+
198
+ ### `TaskRegistry`
199
+
200
+ Registry that maps names and class paths to task constructors.
201
+
202
+ ```typescript
203
+ class TaskRegistry {
204
+ register(name: string, ctor: TaskConstructor): this;
205
+ registerClassPath(classPath: string, ctor: TaskConstructor): this;
206
+ registerAll(entries: Record<string, TaskConstructor>): this;
207
+ registerClassPaths(entries: Record<string, TaskConstructor>): this;
208
+ async resolve(classPathOrName: string): Promise<TaskConstructor>;
209
+ async create(
210
+ classPathOrName: string,
211
+ ctx: TaskContext,
212
+ options: Record<string, unknown>,
213
+ ): Promise<BaseTask>;
214
+ listRegistered(): string[];
215
+ }
216
+ ```
217
+
218
+ | Method | Description |
219
+ |--------|-------------|
220
+ | `register(name, ctor)` | Register by short name |
221
+ | `registerClassPath(path, ctor)` | Register by dotted class path |
222
+ | `registerAll(entries)` | Bulk register by short name |
223
+ | `registerClassPaths(entries)` | Bulk register by class path |
224
+ | `resolve(nameOrPath)` | Look up a constructor. Falls back to dynamic filesystem import. |
225
+ | `create(nameOrPath, ctx, opts)` | Resolve + instantiate in one call |
226
+ | `listRegistered()` | Return all registered names and class paths |
227
+
228
+ **`TaskConstructor`**
229
+
230
+ ```typescript
231
+ type TaskConstructor = new (
232
+ ctx: TaskContext,
233
+ options: Record<string, unknown>,
234
+ ) => BaseTask;
235
+ ```
236
+
237
+ ---
238
+
239
+ ## Flow
240
+
241
+ *Import from `@db-lyon/flowkit` or `@db-lyon/flowkit/flow`*
242
+
243
+ ### `FlowRunner`
244
+
245
+ Orchestration engine that executes flows.
246
+
247
+ ```typescript
248
+ class FlowRunner {
249
+ constructor(config: FlowRunnerConfig);
250
+ async run(options: FlowRunOptions): Promise<FlowRunResult>;
251
+ resolveExecutionPlan(
252
+ flow: FlowDefinition,
253
+ skipSet: Set<string>,
254
+ ): PlanStep[];
255
+ }
256
+ ```
257
+
258
+ ---
259
+
260
+ ### `FlowRunnerConfig`
261
+
262
+ ```typescript
263
+ interface FlowRunnerConfig {
264
+ tasks: Record<string, TaskDefinition>;
265
+ flows: Record<string, FlowDefinition>;
266
+ registry: TaskRegistry;
267
+ context: TaskContext;
268
+ hooks?: FlowRunnerHooks;
269
+ logger?: Logger;
270
+ }
271
+ ```
272
+
273
+ ---
274
+
275
+ ### `FlowRunOptions`
276
+
277
+ ```typescript
278
+ interface FlowRunOptions {
279
+ flowName: string; // name of the flow to execute
280
+ skip?: string[]; // task names or step numbers to skip
281
+ plan?: boolean; // return plan without executing
282
+ }
283
+ ```
284
+
285
+ ---
286
+
287
+ ### `FlowRunResult`
288
+
289
+ ```typescript
290
+ interface FlowRunResult {
291
+ success: boolean;
292
+ steps: FlowStepResult[];
293
+ duration: number; // total milliseconds
294
+ error?: Error; // first error that caused failure
295
+ }
296
+ ```
297
+
298
+ ---
299
+
300
+ ### `FlowStepResult`
301
+
302
+ ```typescript
303
+ interface FlowStepResult {
304
+ stepNumber: number;
305
+ type: 'task' | 'flow';
306
+ name: string;
307
+ result?: TaskResult;
308
+ skipped: boolean;
309
+ duration: number; // milliseconds
310
+ }
311
+ ```
312
+
313
+ ---
314
+
315
+ ### `PlanStep`
316
+
317
+ Represents a step in the execution plan (returned by plan mode or passed to hooks).
318
+
319
+ ```typescript
320
+ interface PlanStep {
321
+ stepNumber: number;
322
+ type: 'task' | 'flow';
323
+ name: string;
324
+ skipped: boolean;
325
+ options?: Record<string, unknown>;
326
+ }
327
+ ```
328
+
329
+ ---
330
+
331
+ ### `FlowRunnerHooks`
332
+
333
+ ```typescript
334
+ interface FlowRunnerHooks {
335
+ beforeRun?(flowName: string, plan: PlanStep[]): Promise<void>;
336
+ afterRun?(result: FlowRunResult): Promise<void>;
337
+ beforeStep?(step: PlanStep): Promise<void>;
338
+ afterStep?(step: PlanStep, result: FlowStepResult): Promise<void>;
339
+ onStepError?(
340
+ step: PlanStep,
341
+ error: Error,
342
+ completed: FlowStepResult[],
343
+ ): Promise<void>;
344
+ }
345
+ ```
346
+
347
+ | Hook | Fires | Scope |
348
+ |------|-------|-------|
349
+ | `beforeRun` | Once before execution starts | Top-level flow only |
350
+ | `afterRun` | Once after execution completes | Top-level flow only |
351
+ | `beforeStep` | Before each step executes | All steps (including nested) |
352
+ | `afterStep` | After each step completes | All steps (including nested) |
353
+ | `onStepError` | When a step fails | All steps (including nested) |
354
+
355
+ ---
356
+
357
+ ## DAG
358
+
359
+ *Import from `@db-lyon/flowkit` or `@db-lyon/flowkit/dag`*
360
+
361
+ ### `topologicalSort(nodes)`
362
+
363
+ Sort a directed acyclic graph in dependency order (dependencies first).
364
+
365
+ ```typescript
366
+ function topologicalSort<T>(nodes: DagNode<T>[]): DagNode<T>[]
367
+ ```
368
+
369
+ Throws `CircularDependencyError` if the graph has cycles. Throws `MissingDependencyError` if a node references a dependency that doesn't exist.
370
+
371
+ ---
372
+
373
+ ### `DagNode<T>`
374
+
375
+ ```typescript
376
+ interface DagNode<T = unknown> {
377
+ id: string;
378
+ dependencies: string[];
379
+ data: T;
380
+ }
381
+ ```
382
+
383
+ ---
384
+
385
+ ### `CircularDependencyError`
386
+
387
+ ```typescript
388
+ class CircularDependencyError extends Error {
389
+ cycle: string[]; // e.g., ['a', 'b', 'c', 'a']
390
+ }
391
+ ```
392
+
393
+ ---
394
+
395
+ ### `MissingDependencyError`
396
+
397
+ ```typescript
398
+ class MissingDependencyError extends Error {
399
+ nodeId: string; // the node that has the bad dependency
400
+ missingDep: string; // the dependency that doesn't exist
401
+ }
402
+ ```
403
+
404
+ ---
405
+
406
+ ## Logger
407
+
408
+ *Import from `@db-lyon/flowkit`*
409
+
410
+ ### `Logger` interface
411
+
412
+ ```typescript
413
+ interface Logger {
414
+ debug(...args: unknown[]): void;
415
+ info(...args: unknown[]): void;
416
+ warn(...args: unknown[]): void;
417
+ error(...args: unknown[]): void;
418
+ child(bindings: Record<string, unknown>): Logger;
419
+ }
420
+ ```
421
+
422
+ Compatible with pino, winston, and similar structured loggers.
423
+
424
+ ### `noopLogger`
425
+
426
+ A silent logger that discards all output. Used as the default when no logger is provided.
427
+
428
+ ```typescript
429
+ const noopLogger: Logger;
430
+ ```