@gravito/flux 3.0.1 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +298 -0
  2. package/bin/flux.js +25 -1
  3. package/dev/viewer/app.js +4 -4
  4. package/dist/bun.cjs +2 -2
  5. package/dist/bun.cjs.map +1 -1
  6. package/dist/bun.d.cts +65 -26
  7. package/dist/bun.d.ts +65 -26
  8. package/dist/bun.js +1 -1
  9. package/dist/chunk-4DXCQ6CL.js +3486 -0
  10. package/dist/chunk-4DXCQ6CL.js.map +1 -0
  11. package/dist/chunk-6AZNHVEO.cjs +316 -0
  12. package/dist/chunk-6AZNHVEO.cjs.map +1 -0
  13. package/dist/{chunk-ZAMVC732.js → chunk-NAIVO7RR.js} +64 -15
  14. package/dist/chunk-NAIVO7RR.js.map +1 -0
  15. package/dist/chunk-WAPZDXSX.cjs +3486 -0
  16. package/dist/chunk-WAPZDXSX.cjs.map +1 -0
  17. package/dist/chunk-WGDTB6OC.js +316 -0
  18. package/dist/chunk-WGDTB6OC.js.map +1 -0
  19. package/dist/{chunk-SJSPR4ZU.cjs → chunk-YXBEYVGY.cjs} +66 -17
  20. package/dist/chunk-YXBEYVGY.cjs.map +1 -0
  21. package/dist/cli/flux-visualize.cjs +108 -0
  22. package/dist/cli/flux-visualize.cjs.map +1 -0
  23. package/dist/cli/flux-visualize.d.cts +1 -0
  24. package/dist/cli/flux-visualize.d.ts +1 -0
  25. package/dist/cli/flux-visualize.js +108 -0
  26. package/dist/cli/flux-visualize.js.map +1 -0
  27. package/dist/index.cjs +97 -9
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +369 -13
  30. package/dist/index.d.ts +369 -13
  31. package/dist/index.js +96 -8
  32. package/dist/index.js.map +1 -1
  33. package/dist/index.node.cjs +11 -3
  34. package/dist/index.node.cjs.map +1 -1
  35. package/dist/index.node.d.cts +1110 -247
  36. package/dist/index.node.d.ts +1110 -247
  37. package/dist/index.node.js +10 -2
  38. package/dist/types-CRz5XdLd.d.cts +433 -0
  39. package/dist/types-CRz5XdLd.d.ts +433 -0
  40. package/package.json +17 -6
  41. package/dist/chunk-3JGQYHUN.js +0 -1006
  42. package/dist/chunk-3JGQYHUN.js.map +0 -1
  43. package/dist/chunk-5OXXH442.cjs +0 -1006
  44. package/dist/chunk-5OXXH442.cjs.map +0 -1
  45. package/dist/chunk-SJSPR4ZU.cjs.map +0 -1
  46. package/dist/chunk-ZAMVC732.js.map +0 -1
  47. package/dist/types-CZwYGpou.d.cts +0 -353
  48. package/dist/types-CZwYGpou.d.ts +0 -353
@@ -1,314 +1,399 @@
1
- import { j as WorkflowContext, F as FluxWaitResult, W as WorkflowDefinition, k as WorkflowDescriptor, a as FluxConfig, c as FluxResult, m as WorkflowState, o as WorkflowStorage, l as WorkflowFilter, f as FluxTraceSink, d as FluxTraceEvent, n as WorkflowStatus, S as StepDefinition, h as StepExecution, i as StepResult, b as FluxLogger } from './types-CZwYGpou.cjs';
2
- export { e as FluxTraceEventType, g as StepDescriptor } from './types-CZwYGpou.cjs';
1
+ import { l as WorkflowContext, q as StepHandlerResult, W as WorkflowDefinition, m as WorkflowDescriptor, a as WorkflowState, o as WorkflowStatus, h as LockProvider, L as Lock, S as StepDefinition, j as StepExecution, k as StepResult, c as FluxLogger, p as WorkflowStorage, n as WorkflowFilter, g as FluxTraceSink, e as FluxTraceEvent, b as FluxConfig, d as FluxResult, C as CronScheduleOptions } from './types-CRz5XdLd.cjs';
2
+ export { f as FluxTraceEventType, M as MemoryLockProvider, i as StepDescriptor } from './types-CRz5XdLd.cjs';
3
3
  import { GravitoOrbit, PlanetCore } from '@gravito/core';
4
4
 
5
5
  /**
6
- * @fileoverview Workflow Builder - Fluent API for defining workflows
7
- *
8
- * Type-safe, chainable workflow definition.
9
- *
10
- * @module @gravito/flux/builder
11
- */
12
-
13
- /**
14
- * Options for configuring a single step in a workflow.
15
- * @public
6
+ * Configuration options for a workflow step.
7
+ * Allows fine-tuning of execution behavior such as retries, timeouts, and conditional logic.
16
8
  */
17
- interface StepOptions<TInput = any, TData = any> {
18
- /** Maximum number of automatic retries on failure (default: 0) */
9
+ interface StepOptions<TInput = unknown, TData = Record<string, any>> {
10
+ /** Maximum number of retry attempts on failure. */
19
11
  retries?: number;
20
- /** Maximum execution time in milliseconds before timeout error */
12
+ /** Execution time limit in milliseconds. */
21
13
  timeout?: number;
22
- /** Predicate to determine if the step should be executed or skipped */
14
+ /** Predicate to determine if the step should execute based on current context. */
23
15
  when?: (ctx: WorkflowContext<TInput, TData>) => boolean;
24
- /** Logic to undo the effects of this step if a later step fails */
16
+ /** Logic to execute for rolling back changes if a subsequent step fails. */
17
+ compensate?: (ctx: WorkflowContext<TInput, TData>) => Promise<void> | void;
18
+ }
19
+ interface ParallelStepConfig<TInput = unknown, TData = Record<string, any>> {
20
+ name: string;
21
+ handler: (ctx: WorkflowContext<TInput, TData>) => StepHandlerResult;
22
+ options?: StepOptions<TInput, TData>;
23
+ /** Shorthand for options.compensate - rollback logic if subsequent steps fail */
25
24
  compensate?: (ctx: WorkflowContext<TInput, TData>) => Promise<void> | void;
25
+ /** Shorthand for options.retries */
26
+ retries?: number;
27
+ /** Shorthand for options.timeout */
28
+ timeout?: number;
29
+ /** Shorthand for options.when */
30
+ when?: (ctx: WorkflowContext<TInput, TData>) => boolean;
26
31
  }
27
32
  /**
28
- * WorkflowBuilder provides a fluent, type-safe API for defining sequential logic.
33
+ * A fluent API for defining workflows in a type-safe manner.
34
+ * The builder pattern ensures that workflows are constructed with all necessary components
35
+ * before being passed to the execution engine.
29
36
  *
30
37
  * @example
31
38
  * ```typescript
32
- * const myFlow = createWorkflow('process-order')
33
- * .input<{ orderId: string }>()
34
- * .step('validate', async (ctx) => { ... })
35
- * .step('charge', async (ctx) => { ... }, { compensate: async (ctx) => { ... } })
36
- * .commit('ship', async (ctx) => { ... });
39
+ * const flow = new WorkflowBuilder('order-process')
40
+ * .input<{ id: string }>()
41
+ * .step('validate', (ctx) => { ... })
42
+ * .build();
37
43
  * ```
38
- * @public
39
44
  */
40
- declare class WorkflowBuilder<TInput = unknown, TData = Record<string, unknown>> {
41
- drum: any;
45
+ declare class WorkflowBuilder<TInput = unknown, TData = Record<string, any>> {
42
46
  private _name;
47
+ private _version?;
43
48
  private _steps;
44
49
  private _validateInput?;
50
+ private _parallelGroupCounter;
51
+ /**
52
+ * Initializes a new workflow builder with a unique name.
53
+ * @param name - The identifier for this workflow definition.
54
+ */
45
55
  constructor(name: string);
46
56
  /**
47
- * Define input type
48
- *
49
- * This method is used for TypeScript type inference.
57
+ * Defines the expected input type for the workflow.
58
+ * This is a type-only operation that enables compile-time safety for subsequent steps.
59
+ * @returns A builder instance with the specified input type.
50
60
  */
51
61
  input<T>(): WorkflowBuilder<T, TData>;
52
62
  /**
53
- * Define workflow data (state) type
54
- *
55
- * This method is used for TypeScript type inference.
63
+ * Defines the structure of the shared data object used across steps.
64
+ * @returns A builder instance with the specified data type.
56
65
  */
57
- data<T>(): WorkflowBuilder<TInput, T>;
66
+ data<T extends Record<string, any>>(): WorkflowBuilder<TInput, T>;
58
67
  /**
59
- * Add input validator
68
+ * Sets the semantic version of this workflow definition.
69
+ * @param v - A semantic version string (e.g., "1.0.0", "2.1.0").
70
+ * @returns The builder instance for chaining.
71
+ */
72
+ version(v: string): this;
73
+ /**
74
+ * Attaches a runtime validator for the workflow input.
75
+ * @param validator - A type guard function to verify input integrity.
76
+ * @returns The builder instance for chaining.
60
77
  */
61
78
  validate(validator: (input: unknown) => input is TInput): this;
62
79
  /**
63
- * Add a step to the workflow
80
+ * Adds a standard processing step to the workflow.
81
+ * Standard steps are subject to compensation if the workflow fails later.
82
+ *
83
+ * @param name - Unique name for the step.
84
+ * @param handler - The business logic to execute.
85
+ * @param options - Optional execution configuration.
86
+ * @returns The builder instance for chaining.
87
+ */
88
+ step(name: string, handler: (ctx: WorkflowContext<TInput, TData>) => StepHandlerResult, options?: StepOptions<TInput, TData>): this;
89
+ /**
90
+ * Adds multiple steps that execute in parallel.
91
+ * All steps in a parallel group will run concurrently and must all succeed before proceeding.
92
+ *
93
+ * @param steps - Array of step configurations to execute in parallel.
94
+ * @returns The builder instance for chaining.
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * workflow.stepParallel([
99
+ * { name: 'fetch-user', handler: async (ctx) => { ctx.data.user = await getUser() } },
100
+ * { name: 'fetch-orders', handler: async (ctx) => { ctx.data.orders = await getOrders() } },
101
+ * { name: 'fetch-profile', handler: async (ctx) => { ctx.data.profile = await getProfile() } }
102
+ * ])
103
+ * ```
64
104
  */
65
- step(name: string, handler: (ctx: WorkflowContext<TInput, TData>) => void | Promise<void | undefined | FluxWaitResult> | undefined | FluxWaitResult, options?: StepOptions<TInput, TData>): this;
105
+ stepParallel(steps: ParallelStepConfig<TInput, TData>[]): this;
66
106
  /**
67
- * Add a commit step (always executes, even on replay)
107
+ * Adds a "commit" step that represents a permanent side-effect.
108
+ * Commit steps are intended for operations that should not be rolled back
109
+ * or re-executed during certain replay scenarios.
68
110
  *
69
- * Commit steps are for side effects that should not be skipped,
70
- * such as database writes or external API calls.
111
+ * @param name - Unique name for the step.
112
+ * @param handler - The side-effect logic to execute.
113
+ * @param options - Optional execution configuration (compensation is not allowed).
114
+ * @returns The builder instance for chaining.
71
115
  */
72
116
  commit(name: string, handler: (ctx: WorkflowContext<TInput, TData>) => Promise<void> | void, options?: Omit<StepOptions<TInput, TData>, 'compensate'>): this;
73
117
  /**
74
- * Build the workflow definition
118
+ * Finalizes the workflow definition.
119
+ * @returns A complete workflow blueprint ready for execution.
120
+ * @throws Error if the workflow has no steps defined.
75
121
  */
76
122
  build(): WorkflowDefinition<TInput, TData>;
77
123
  /**
78
- * Describe workflow (serializable metadata)
124
+ * Generates a structural description of the workflow for introspection.
125
+ * @returns A descriptor containing step metadata.
79
126
  */
80
127
  describe(): WorkflowDescriptor;
81
- /**
82
- * Get workflow name
83
- */
128
+ /** The name of the workflow being built. */
84
129
  get name(): string;
85
- /**
86
- * Get step count
87
- */
130
+ /** The number of steps currently defined in the workflow. */
88
131
  get stepCount(): number;
89
132
  }
90
133
  /**
91
- * Create a new workflow builder
134
+ * Factory function to initiate a new workflow definition.
92
135
  *
93
- * @param name - Unique workflow name
94
- * @returns WorkflowBuilder instance
136
+ * @param name - The unique name for the workflow.
137
+ * @returns A new WorkflowBuilder instance.
95
138
  *
96
139
  * @example
97
140
  * ```typescript
98
- * const uploadFlow = createWorkflow('image-upload')
99
- * .input<{ file: Buffer }>()
100
- * .step('resize', async (ctx) => {
101
- * ctx.data.resized = await sharp(ctx.input.file).resize(200).toBuffer()
102
- * })
103
- * .commit('save', async (ctx) => {
104
- * await storage.put(ctx.data.resized)
105
- * })
141
+ * const flow = createWorkflow('my-flow')
142
+ * .step('hello', () => console.log('world'))
143
+ * .build();
106
144
  * ```
107
145
  */
108
146
  declare function createWorkflow(name: string): WorkflowBuilder;
109
147
 
110
148
  /**
111
- * @fileoverview Flux Engine - Main workflow execution engine
149
+ * Orchestrates the lifecycle and state transformations of a workflow context.
112
150
  *
113
- * Orchestrates workflow execution with storage and event handling.
114
- *
115
- * @module @gravito/flux
116
- */
117
-
118
- /**
119
- * FluxEngine is the primary execution orchestrator for workflows.
120
- * It manages context lifecycle, persistence via storage adapters,
121
- * step execution with retries, and transactional rollbacks (compensation).
151
+ * The ContextManager is responsible for initializing new contexts, restoring them from
152
+ * persisted states, and performing immutable updates during execution.
122
153
  *
123
154
  * @example
124
155
  * ```typescript
125
- * const engine = new FluxEngine({
126
- * storage: new BunSQLiteStorage(),
127
- * logger: new FluxConsoleLogger()
128
- * });
129
- *
130
- * const workflow = createWorkflow('onboard-user')
131
- * .step('create-account', async (ctx) => { ... })
132
- * .step('send-email', async (ctx) => { ... });
133
- *
134
- * const result = await engine.execute(workflow, { email: 'user@example.com' });
135
- * if (result.status === 'completed') {
136
- * console.log('User onboarded successfully');
137
- * }
156
+ * const manager = new ContextManager();
157
+ * const ctx = manager.create('order-flow', { id: '123' }, 5);
138
158
  * ```
139
- * @public
140
159
  */
141
- declare class FluxEngine {
142
- private storage;
143
- private executor;
144
- private contextManager;
145
- private config;
146
- constructor(config?: FluxConfig);
160
+ declare class ContextManager {
147
161
  /**
148
- * Execute a workflow with input data
162
+ * Initializes a fresh workflow context with a pending status and empty history.
149
163
  *
150
- * @param workflow - Workflow builder or definition
151
- * @param input - Input data for the workflow
152
- * @returns Execution result
153
- */
154
- execute<TInput, TData = any>(workflow: WorkflowBuilder<TInput, TData> | WorkflowDefinition<TInput, TData>, input: TInput): Promise<FluxResult<TData>>;
155
- /**
156
- * Resume a paused or failed workflow
164
+ * @param name - The human-readable identifier for the workflow type.
165
+ * @param input - The initial data required to start the workflow.
166
+ * @param stepCount - Total number of steps defined in the workflow for history pre-allocation.
167
+ * @returns A new WorkflowContext instance.
157
168
  *
158
- * @param workflowId - Workflow instance ID
159
- * @returns Execution result or null if not found
160
- */
161
- resume<TInput, TData = any>(workflow: WorkflowBuilder<TInput, TData> | WorkflowDefinition<TInput, TData>, workflowId: string, options?: {
162
- fromStep?: number | string;
163
- }): Promise<FluxResult<TData> | null>;
164
- /**
165
- * Send a signal to a suspended workflow
166
- */
167
- signal<TInput, TData = any>(workflow: WorkflowBuilder<TInput, TData> | WorkflowDefinition<TInput, TData>, workflowId: string, signalName: string, payload?: any): Promise<FluxResult<TData>>;
168
- /**
169
- * Retry a specific step (replays from that step onward)
169
+ * @example
170
+ * ```typescript
171
+ * const ctx = manager.create('signup', { email: 'user@example.com' }, 3);
172
+ * ```
170
173
  */
171
- retryStep<TInput, TData = any>(workflow: WorkflowBuilder<TInput, TData> | WorkflowDefinition<TInput, TData>, workflowId: string, stepName: string): Promise<FluxResult<TData> | null>;
174
+ create<TInput, TData extends Record<string, any> = Record<string, any>>(name: string, input: TInput, stepCount: number): WorkflowContext<TInput, TData>;
172
175
  /**
173
- * Get workflow state by ID
174
- */
175
- get<TInput = any, TData = any>(workflowId: string): Promise<WorkflowState<TInput, TData> | null>;
176
- /**
177
- * Save workflow state manually (e.g., for external updates)
176
+ * Reconstructs a workflow context from a previously persisted state.
177
+ *
178
+ * Used for resuming suspended workflows or replaying failed ones from a specific point.
179
+ *
180
+ * @param state - The persisted state object.
181
+ * @returns A hydrated WorkflowContext ready for execution.
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * const state = await storage.load(id);
186
+ * const ctx = manager.restore(state);
187
+ * ```
178
188
  */
179
- saveState<TInput, TData>(state: WorkflowState<TInput, TData>): Promise<void>;
189
+ restore<TInput, TData extends Record<string, any> = Record<string, any>>(state: WorkflowState<TInput, TData>): WorkflowContext<TInput, TData>;
180
190
  /**
181
- * List workflows
191
+ * Converts a runtime context into a serializable state for persistence.
192
+ *
193
+ * Captures the current progress, data, and execution history.
194
+ *
195
+ * @param ctx - The active workflow context.
196
+ * @returns A serializable WorkflowState object.
197
+ *
198
+ * @example
199
+ * ```typescript
200
+ * const state = manager.toState(ctx);
201
+ * await storage.save(state);
202
+ * ```
182
203
  */
183
- list(filter?: Parameters<WorkflowStorage['list']>[0]): Promise<WorkflowState<any, any>[]>;
204
+ toState<TInput, TData extends Record<string, any>>(ctx: WorkflowContext<TInput, TData>): WorkflowState<TInput, TData>;
184
205
  /**
185
- * Initialize engine (init storage)
206
+ * Updates the overall status of the workflow.
207
+ *
208
+ * @param ctx - The current context.
209
+ * @param status - The new status to apply.
210
+ * @returns A new context instance with the updated status.
211
+ *
212
+ * @example
213
+ * ```typescript
214
+ * const runningCtx = manager.updateStatus(ctx, 'running');
215
+ * ```
186
216
  */
187
- init(): Promise<void>;
217
+ updateStatus<TInput, TData extends Record<string, any>>(ctx: WorkflowContext<TInput, TData>, status: WorkflowStatus): WorkflowContext<TInput, TData>;
188
218
  /**
189
- * Shutdown engine (cleanup)
219
+ * Increments the current step pointer.
220
+ *
221
+ * @param ctx - The current context.
222
+ * @returns A new context instance pointing to the next step.
223
+ *
224
+ * @example
225
+ * ```typescript
226
+ * const nextStepCtx = manager.advanceStep(ctx);
227
+ * console.log(nextStepCtx.currentStep); // ctx.currentStep + 1
228
+ * ```
190
229
  */
191
- close(): Promise<void>;
192
- private resolveDefinition;
193
- private resolveStartIndex;
194
- private resetHistoryFrom;
230
+ advanceStep<TInput, TData extends Record<string, any>>(ctx: WorkflowContext<TInput, TData>): WorkflowContext<TInput, TData>;
195
231
  /**
196
- * Rollback workflow by executing compensation handlers in reverse order
232
+ * Assigns a name to a specific step in the execution history.
233
+ *
234
+ * Useful for tracking which step is currently being executed or has been completed.
235
+ *
236
+ * @param ctx - The current context.
237
+ * @param index - The index of the step in the history array.
238
+ * @param name - The name to assign to the step.
239
+ * @returns A new context instance with the updated history.
240
+ *
241
+ * @example
242
+ * ```typescript
243
+ * const namedCtx = manager.setStepName(ctx, 0, 'validate-user');
244
+ * console.log(namedCtx.history[0].name); // 'validate-user'
245
+ * ```
197
246
  */
198
- private rollback;
199
- private runFrom;
200
- private emitTrace;
247
+ setStepName<TInput, TData extends Record<string, any>>(ctx: WorkflowContext<TInput, TData>, index: number, name: string): WorkflowContext<TInput, TData>;
201
248
  }
202
249
 
203
250
  /**
204
- * @fileoverview In-memory storage adapter
251
+ * @fileoverview Redis-based Lock Provider for distributed workflow execution
205
252
  *
206
- * Simple storage for development and testing.
253
+ * Provides a Redis-backed distributed locking mechanism for coordinating
254
+ * workflow execution across multiple nodes in a cluster.
207
255
  *
208
- * @module @gravito/flux/storage
256
+ * @module @gravito/flux/core
209
257
  */
210
258
 
211
259
  /**
212
- * Memory Storage
213
- *
214
- * In-memory storage adapter for development and testing.
215
- * Data is not persisted across restarts.
260
+ * Minimal Redis client interface for compatibility with ioredis/redis libraries.
261
+ * Consumers should provide a client that implements these methods.
216
262
  */
217
- declare class MemoryStorage implements WorkflowStorage {
218
- private store;
219
- save(state: WorkflowState): Promise<void>;
220
- load(id: string): Promise<WorkflowState | null>;
221
- list(filter?: WorkflowFilter): Promise<WorkflowState[]>;
222
- delete(id: string): Promise<void>;
223
- init(): Promise<void>;
224
- close(): Promise<void>;
263
+ interface RedisClient {
225
264
  /**
226
- * Get store size (for testing)
265
+ * SET command with optional NX and PX options.
266
+ * @param key - The key to set
267
+ * @param value - The value to set
268
+ * @param options - SET options (NX for only-if-not-exists, PX for expiry in ms)
269
+ * @returns 'OK' if set, null if key exists (with NX)
227
270
  */
228
- size(): number;
271
+ set(key: string, value: string, options?: {
272
+ NX?: boolean;
273
+ PX?: number;
274
+ }): Promise<'OK' | null>;
275
+ /**
276
+ * GET command to retrieve a value.
277
+ * @param key - The key to get
278
+ * @returns The value or null if not found
279
+ */
280
+ get(key: string): Promise<string | null>;
281
+ /**
282
+ * DEL command to delete a key.
283
+ * @param key - The key to delete
284
+ * @returns Number of keys deleted
285
+ */
286
+ del(key: string): Promise<number>;
287
+ /**
288
+ * EVAL command to execute Lua scripts atomically.
289
+ * @param script - The Lua script
290
+ * @param keys - Array of keys
291
+ * @param args - Array of arguments
292
+ * @returns Script result
293
+ */
294
+ eval(script: string, keys: string[], args: (string | number)[]): Promise<unknown>;
229
295
  }
230
-
231
296
  /**
232
- * @fileoverview JSON file trace sink (NDJSON)
233
- *
234
- * Writes trace events to a newline-delimited JSON file.
297
+ * Configuration options for RedisLockProvider.
235
298
  */
236
-
237
- /**
238
- * Options for configuring the `JsonFileTraceSink`.
239
- *
240
- * @public
241
- * @since 3.0.0
242
- */
243
- interface JsonFileTraceSinkOptions {
244
- /** Absolute path where the trace file should be stored. */
245
- path: string;
246
- /** Whether to reset (clear) the file on initialization. @default true */
247
- reset?: boolean;
299
+ interface RedisLockProviderOptions {
300
+ /** Redis client instance (must implement RedisClient interface) */
301
+ client: RedisClient;
302
+ /** Prefix for all lock keys (default: 'flux:lock:') */
303
+ keyPrefix?: string;
304
+ /** Default TTL for locks in milliseconds (default: 30000) */
305
+ defaultTtl?: number;
306
+ /** Delay between retry attempts in milliseconds (default: 100) */
307
+ retryDelay?: number;
308
+ /** Maximum number of retry attempts (default: 0, no retries) */
309
+ maxRetries?: number;
248
310
  }
249
311
  /**
250
- * A trace sink that writes events to a newline-delimited JSON (NDJSON) file.
312
+ * Redis-based implementation of LockProvider for distributed locking.
251
313
  *
252
- * This sink is ideal for local development and debugging as it produces
253
- * a human-readable and easily machine-parsable log of workflow events.
314
+ * Uses Redis SET NX PX for atomic lock acquisition and Lua scripts
315
+ * for safe release and refresh operations.
254
316
  *
255
317
  * @example
256
318
  * ```typescript
257
- * const sink = new JsonFileTraceSink({
258
- * path: './traces/workflow.jsonl',
259
- * reset: true
260
- * });
261
- * ```
319
+ * import Redis from 'ioredis'
320
+ * import { RedisLockProvider } from '@gravito/flux'
262
321
  *
263
- * @public
264
- * @since 3.0.0
265
- */
266
- declare class JsonFileTraceSink implements FluxTraceSink {
267
- private path;
268
- private ready;
269
- constructor(options: JsonFileTraceSinkOptions);
270
- private init;
271
- emit(event: FluxTraceEvent): Promise<void>;
272
- }
273
-
274
- /**
275
- * @fileoverview Context Manager for workflow execution
276
- *
277
- * Manages workflow context lifecycle and state snapshots.
278
- *
279
- * @module @gravito/flux/core
280
- */
281
-
282
- /**
283
- * Context Manager
322
+ * const redis = new Redis()
323
+ * const lockProvider = new RedisLockProvider({
324
+ * client: redis,
325
+ * keyPrefix: 'myapp:locks:',
326
+ * defaultTtl: 30000,
327
+ * })
284
328
  *
285
- * Creates and manages workflow execution contexts.
329
+ * const lock = await lockProvider.acquire('workflow-123', 'node-1', 30000)
330
+ * if (lock) {
331
+ * try {
332
+ * // Do work with the lock
333
+ * } finally {
334
+ * await lock.release()
335
+ * }
336
+ * }
337
+ * ```
286
338
  */
287
- declare class ContextManager {
339
+ declare class RedisLockProvider implements LockProvider {
340
+ private readonly client;
341
+ private readonly keyPrefix;
342
+ private readonly defaultTtl;
343
+ private readonly retryDelay;
344
+ private readonly maxRetries;
345
+ constructor(options: RedisLockProviderOptions);
288
346
  /**
289
- * Create a new workflow context
347
+ * Attempts to acquire a lock for a specific resource.
348
+ *
349
+ * Uses Redis SET with NX (only if not exists) and PX (expire in ms)
350
+ * for atomic lock acquisition. Supports retry with configurable delay.
351
+ *
352
+ * @param resourceId - The unique ID of the resource to lock
353
+ * @param owner - The identifier of the node/process requesting the lock
354
+ * @param ttl - Time-to-live for the lock in milliseconds
355
+ * @returns A Lock object if successful, otherwise null
290
356
  */
291
- create<TInput, TData = any>(name: string, input: TInput, stepCount: number): WorkflowContext<TInput, TData>;
357
+ acquire(resourceId: string, owner: string, ttl: number): Promise<Lock | null>;
292
358
  /**
293
- * Restore context from saved state
359
+ * Refreshes an existing lock to extend its lifetime.
360
+ *
361
+ * Uses a Lua script to atomically check ownership and extend TTL.
362
+ *
363
+ * @param resourceId - The ID of the resource
364
+ * @param owner - The current owner of the lock
365
+ * @param ttl - The new time-to-live from the current moment
366
+ * @returns True if the lock was successfully refreshed
367
+ */
368
+ refresh(resourceId: string, owner: string, ttl: number): Promise<boolean>;
369
+ /**
370
+ * Forcefully releases a lock, regardless of the owner.
371
+ *
372
+ * @param resourceId - The ID of the resource to unlock
294
373
  */
295
- restore<TInput, TData = any>(state: WorkflowState<TInput, TData>): WorkflowContext<TInput, TData>;
374
+ release(resourceId: string): Promise<void>;
296
375
  /**
297
- * Convert context to serializable state
376
+ * Safely releases a lock only if owned by the specified owner.
377
+ *
378
+ * Uses a Lua script to atomically check ownership and delete.
379
+ *
380
+ * @param resourceId - The ID of the resource to unlock
381
+ * @param owner - The owner that should release the lock
382
+ * @returns True if the lock was released, false if not owned
298
383
  */
299
- toState<TInput, TData>(ctx: WorkflowContext<TInput, TData>): WorkflowState<TInput, TData>;
384
+ releaseIfOwned(resourceId: string, owner: string): Promise<boolean>;
300
385
  /**
301
- * Update context status (returns new context for immutability)
386
+ * Generates the Redis key for a resource.
302
387
  */
303
- updateStatus<TInput, TData>(ctx: WorkflowContext<TInput, TData>, status: WorkflowStatus): WorkflowContext<TInput, TData>;
388
+ private getKey;
304
389
  /**
305
- * Advance to next step
390
+ * Creates a Lock object with a release method.
306
391
  */
307
- advanceStep<TInput, TData>(ctx: WorkflowContext<TInput, TData>): WorkflowContext<TInput, TData>;
392
+ private createLock;
308
393
  /**
309
- * Update step name in history
394
+ * Sleeps for the specified duration.
310
395
  */
311
- setStepName<TInput, TData>(ctx: WorkflowContext<TInput, TData>, index: number, name: string): void;
396
+ private sleep;
312
397
  }
313
398
 
314
399
  /**
@@ -320,36 +405,93 @@ declare class ContextManager {
320
405
  */
321
406
 
322
407
  /**
323
- * State Machine for workflow status management
408
+ * Manages the lifecycle states of a workflow instance.
409
+ *
410
+ * The StateMachine enforces transition rules and notifies listeners of state changes.
411
+ * It is designed to be the single source of truth for a workflow's current progress.
324
412
  *
325
- * Provides validated state transitions using EventTarget for events.
413
+ * @example
414
+ * ```typescript
415
+ * const sm = new StateMachine();
416
+ * sm.addEventListener('transition', (e) => console.log(e.detail));
417
+ * sm.transition('running');
418
+ * ```
326
419
  */
327
420
  declare class StateMachine extends EventTarget {
328
421
  private _status;
329
422
  /**
330
- * Current status
423
+ * The current operational status of the workflow.
331
424
  */
332
425
  get status(): WorkflowStatus;
333
426
  /**
334
- * Check if transition to target status is allowed
427
+ * Evaluates if a transition to the specified status is valid from the current state.
428
+ *
429
+ * @param to - The target status to check.
430
+ * @returns True if the transition is permitted by the transition map.
431
+ *
432
+ * @example
433
+ * ```typescript
434
+ * if (sm.canTransition('completed')) {
435
+ * sm.transition('completed');
436
+ * }
437
+ * ```
335
438
  */
336
439
  canTransition(to: WorkflowStatus): boolean;
337
440
  /**
338
- * Transition to a new status
441
+ * Moves the workflow to a new status if the transition is valid.
442
+ *
443
+ * @param to - The target status.
444
+ * @throws {Error} If the transition is illegal according to the defined rules.
339
445
  *
340
- * @throws {Error} If transition is not allowed
446
+ * @example
447
+ * ```typescript
448
+ * try {
449
+ * sm.transition('completed');
450
+ * } catch (e) {
451
+ * // Handle invalid transition
452
+ * }
453
+ * ```
341
454
  */
342
455
  transition(to: WorkflowStatus): void;
343
456
  /**
344
- * Force set status (for replay/restore)
457
+ * Overrides the current status without validation.
458
+ *
459
+ * This should only be used during workflow restoration from persisted storage
460
+ * or when replaying history where the state is already known to be valid.
461
+ *
462
+ * @param status - The status to force set.
463
+ *
464
+ * @example
465
+ * ```typescript
466
+ * // Restore state from database
467
+ * sm.forceStatus(storedState.status);
468
+ * ```
345
469
  */
346
470
  forceStatus(status: WorkflowStatus): void;
347
471
  /**
348
- * Check if workflow is in terminal state
472
+ * Determines if the workflow has reached a state where no further execution is possible.
473
+ *
474
+ * @returns True if the status is 'completed', 'failed', or 'rolled_back'.
475
+ *
476
+ * @example
477
+ * ```typescript
478
+ * if (sm.isTerminal()) {
479
+ * console.log('Workflow finished');
480
+ * }
481
+ * ```
349
482
  */
350
483
  isTerminal(): boolean;
351
484
  /**
352
- * Check if workflow can be executed
485
+ * Checks if the workflow is in a state that allows for execution or resumption.
486
+ *
487
+ * @returns True if the workflow can be started or resumed.
488
+ *
489
+ * @example
490
+ * ```typescript
491
+ * if (sm.canExecute()) {
492
+ * await engine.run();
493
+ * }
494
+ * ```
353
495
  */
354
496
  canExecute(): boolean;
355
497
  }
@@ -363,29 +505,81 @@ declare class StateMachine extends EventTarget {
363
505
  */
364
506
 
365
507
  /**
366
- * Step Executor
508
+ * Handles the isolated execution of a single workflow step.
367
509
  *
368
- * Executes individual workflow steps with retry and timeout support.
510
+ * The StepExecutor manages the operational aspects of step execution, including
511
+ * condition checking, retry logic with exponential backoff, and timeout enforcement.
512
+ *
513
+ * @example
514
+ * ```typescript
515
+ * const executor = new StepExecutor({ defaultRetries: 3 });
516
+ * const { result } = await executor.execute(stepDef, ctx, executionRecord);
517
+ * ```
369
518
  */
370
519
  declare class StepExecutor {
371
520
  private defaultRetries;
372
521
  private defaultTimeout;
373
522
  private onRetry?;
523
+ /**
524
+ * Creates a new StepExecutor with global defaults.
525
+ *
526
+ * @param options - Configuration for default behavior and lifecycle hooks.
527
+ */
374
528
  constructor(options?: {
375
529
  defaultRetries?: number;
376
530
  defaultTimeout?: number;
377
531
  onRetry?: (step: StepDefinition<any, any>, ctx: WorkflowContext<any, any>, error: Error, attempt: number, maxRetries: number) => void | Promise<void>;
378
532
  });
379
533
  /**
380
- * Execute a step with retry and timeout
534
+ * Executes a step definition against a workflow context.
535
+ *
536
+ * This method performs the following sequence:
537
+ * 1. Evaluates the `when` condition (if present).
538
+ * 2. Initiates the execution loop with retries.
539
+ * 3. Enforces timeouts for each attempt.
540
+ * 4. Handles suspension signals (`flux_wait`).
541
+ * 5. Updates the execution history record.
542
+ *
543
+ * @param step - The definition of the step to execute.
544
+ * @param ctx - The current workflow context.
545
+ * @param execution - The current execution record for this step.
546
+ * @returns The result of the execution and the updated execution record.
547
+ *
548
+ * @throws {Error} If the step handler throws an unrecoverable error or times out.
549
+ *
550
+ * @example
551
+ * ```typescript
552
+ * const { result, execution } = await executor.execute(
553
+ * stepDefinition,
554
+ * currentContext,
555
+ * currentExecution
556
+ * );
557
+ *
558
+ * if (!result.success) {
559
+ * console.error(result.error);
560
+ * }
561
+ * ```
381
562
  */
382
- execute<TInput, TData>(step: StepDefinition<TInput, TData>, ctx: WorkflowContext<TInput, TData>, execution: StepExecution): Promise<StepResult>;
563
+ execute<TInput, TData extends Record<string, any>>(step: StepDefinition<TInput, TData>, ctx: WorkflowContext<TInput, TData>, execution: StepExecution): Promise<{
564
+ result: StepResult;
565
+ execution: StepExecution;
566
+ }>;
383
567
  /**
384
- * Execute handler with timeout
568
+ * Wraps the step handler in a timeout race.
569
+ *
570
+ * @param handler - The user-defined step handler.
571
+ * @param ctx - The workflow context.
572
+ * @param timeout - Maximum time allowed for execution in milliseconds.
573
+ * @returns The handler result or a suspension signal.
574
+ * @throws {Error} If the timeout is reached before the handler completes.
575
+ * @private
385
576
  */
386
577
  private executeWithTimeout;
387
578
  /**
388
- * Sleep helper
579
+ * Pauses execution for a specified duration.
580
+ *
581
+ * @param ms - Milliseconds to sleep.
582
+ * @private
389
583
  */
390
584
  private sleep;
391
585
  }
@@ -399,73 +593,123 @@ declare class StepExecutor {
399
593
  */
400
594
 
401
595
  /**
402
- * Console Logger
596
+ * Console Logger implementation for FluxEngine.
403
597
  *
404
- * Default logger that outputs to console.
598
+ * Provides a standard way to output workflow execution logs to the system console
599
+ * with a configurable prefix for easy filtering.
405
600
  *
406
601
  * @example
407
602
  * ```typescript
408
- * const engine = new FluxEngine({
409
- * logger: new FluxConsoleLogger()
410
- * })
603
+ * const logger = new FluxConsoleLogger('[OrderFlow]');
604
+ * logger.info('Workflow started', { orderId: '123' });
411
605
  * ```
412
606
  */
413
607
  declare class FluxConsoleLogger implements FluxLogger {
414
608
  private prefix;
609
+ /**
610
+ * Creates a new console logger instance.
611
+ *
612
+ * @param prefix - String prepended to every log message for identification.
613
+ */
415
614
  constructor(prefix?: string);
615
+ /**
616
+ * Logs fine-grained informational events that are most useful to debug an application.
617
+ *
618
+ * @param message - The primary log message.
619
+ * @param args - Additional metadata or objects to include in the log output.
620
+ */
416
621
  debug(message: string, ...args: unknown[]): void;
622
+ /**
623
+ * Logs informational messages that highlight the progress of the application at coarse-grained level.
624
+ *
625
+ * @param message - The primary log message.
626
+ * @param args - Additional metadata or objects to include in the log output.
627
+ */
417
628
  info(message: string, ...args: unknown[]): void;
629
+ /**
630
+ * Logs potentially harmful situations that should be noted but don't stop execution.
631
+ *
632
+ * @param message - The primary log message.
633
+ * @param args - Additional metadata or objects to include in the log output.
634
+ */
418
635
  warn(message: string, ...args: unknown[]): void;
636
+ /**
637
+ * Logs error events that might still allow the application to continue running.
638
+ *
639
+ * @param message - The primary log message.
640
+ * @param args - Additional metadata or objects to include in the log output.
641
+ */
419
642
  error(message: string, ...args: unknown[]): void;
420
643
  }
421
644
  /**
422
- * Silent Logger
645
+ * Silent Logger implementation that discards all log entries.
646
+ *
647
+ * Useful for production environments where logging is handled externally,
648
+ * or for unit tests where console output should be suppressed.
423
649
  *
424
- * Logger that outputs nothing (for testing or production).
650
+ * @example
651
+ * ```typescript
652
+ * const engine = new FluxEngine({
653
+ * logger: new FluxSilentLogger()
654
+ * });
655
+ * ```
425
656
  */
426
657
  declare class FluxSilentLogger implements FluxLogger {
658
+ /** Discards debug logs. */
427
659
  debug(): void;
660
+ /** Discards info logs. */
428
661
  info(): void;
662
+ /** Discards warning logs. */
429
663
  warn(): void;
664
+ /** Discards error logs. */
430
665
  error(): void;
431
666
  }
432
667
 
433
668
  /**
434
- * OrbitFlux configuration options
669
+ * Configuration options for the OrbitFlux extension.
670
+ *
671
+ * Defines how the workflow engine should be initialized and integrated into the Gravito core.
435
672
  */
436
673
  interface OrbitFluxOptions {
437
674
  /**
438
- * Storage driver: 'memory' | 'sqlite' | custom WorkflowStorage
439
- * @default 'memory'
675
+ * Specifies the storage driver to use for persisting workflow states.
676
+ *
677
+ * - 'memory': Volatile in-memory storage (default).
678
+ * - 'sqlite': Persistent SQLite storage (Bun only).
679
+ * - WorkflowStorage: A custom implementation of the storage interface.
440
680
  */
441
681
  storage?: 'memory' | 'sqlite' | WorkflowStorage;
442
682
  /**
443
- * SQLite database path (only used if storage is 'sqlite')
444
- * @default ':memory:'
683
+ * The file system path for the SQLite database.
684
+ *
685
+ * Only applicable when `storage` is set to 'sqlite'.
445
686
  */
446
687
  dbPath?: string;
447
688
  /**
448
- * Service name in core.services
449
- * @default 'flux'
689
+ * The key under which the FluxEngine will be registered in the core service container.
450
690
  */
451
691
  exposeAs?: string;
452
692
  /**
453
- * Custom logger
693
+ * A custom logger implementation for the workflow engine.
694
+ *
695
+ * If not provided, the engine will use a wrapper around the core logger.
454
696
  */
455
697
  logger?: FluxLogger;
456
698
  /**
457
- * Default retry count for steps
458
- * @default 3
699
+ * The default number of times a workflow step should be retried upon failure.
459
700
  */
460
701
  defaultRetries?: number;
461
702
  /**
462
- * Default timeout for steps (ms)
463
- * @default 30000
703
+ * The default timeout in milliseconds for workflow steps.
464
704
  */
465
705
  defaultTimeout?: number;
466
706
  }
467
707
  /**
468
- * OrbitFlux - Gravito Workflow Integration
708
+ * OrbitFlux integrates the Flux workflow engine into the Gravito Galaxy Architecture.
709
+ *
710
+ * It acts as an "Orbit" (infrastructure extension) that provides a managed `FluxEngine`
711
+ * instance to the core application and other satellites. It also bridges engine events
712
+ * to the core hook system.
469
713
  *
470
714
  * @example
471
715
  * ```typescript
@@ -473,33 +717,652 @@ interface OrbitFluxOptions {
473
717
  *
474
718
  * const core = await PlanetCore.boot({
475
719
  * orbits: [
476
- * new OrbitFlux({ storage: 'sqlite', dbPath: './data/workflows.db' })
720
+ * new OrbitFlux({
721
+ * storage: 'sqlite',
722
+ * dbPath: './data/workflows.db'
723
+ * })
477
724
  * ]
478
725
  * })
479
726
  *
480
- * // Access via container
727
+ * // Access the engine from the container
481
728
  * const flux = core.container.make<FluxEngine>('flux')
482
- * await flux.execute(myWorkflow, input)
483
729
  * ```
484
730
  */
485
731
  declare class OrbitFlux implements GravitoOrbit {
486
732
  private options;
487
733
  private engine?;
734
+ /**
735
+ * Initializes a new OrbitFlux instance with the given options.
736
+ *
737
+ * @param options - Configuration for the workflow engine integration.
738
+ */
488
739
  constructor(options?: OrbitFluxOptions);
489
740
  /**
490
- * Create OrbitFlux with configuration
741
+ * Static factory method to create and configure an OrbitFlux instance.
742
+ *
743
+ * @param options - Configuration for the workflow engine integration.
744
+ * @returns A configured OrbitFlux instance.
491
745
  */
492
746
  static configure(options?: OrbitFluxOptions): OrbitFlux;
493
747
  /**
494
- * Install into PlanetCore
748
+ * Installs the Flux workflow engine into the Gravito core.
749
+ *
750
+ * This method resolves the storage adapter, initializes it, configures the engine
751
+ * with core-integrated logging and hooks, and registers the engine in the IoC container.
495
752
  *
496
- * @param core - The PlanetCore instance
753
+ * @param core - The PlanetCore instance being booted.
754
+ * @throws {Error} If storage initialization fails or engine registration conflicts occur.
497
755
  */
498
756
  install(core: PlanetCore): Promise<void>;
499
757
  /**
500
- * Get the FluxEngine instance
758
+ * Retrieves the managed FluxEngine instance.
759
+ *
760
+ * @returns The FluxEngine instance, or undefined if the orbit has not been installed.
501
761
  */
502
762
  getEngine(): FluxEngine | undefined;
763
+ /**
764
+ * Performs cleanup operations when the core is shutting down.
765
+ *
766
+ * Closes the underlying workflow engine and its storage connections.
767
+ *
768
+ * @throws {Error} If the engine fails to close cleanly.
769
+ */
770
+ cleanup(): Promise<void>;
771
+ }
772
+
773
+ /**
774
+ * @fileoverview In-memory storage adapter
775
+ *
776
+ * Simple storage for development and testing.
777
+ *
778
+ * @module @gravito/flux/storage
779
+ */
780
+
781
+ /**
782
+ * MemoryStorage provides a volatile, in-memory storage backend for Flux workflows.
783
+ *
784
+ * It is primarily intended for development, testing, and ephemeral workloads where persistence
785
+ * across process restarts is not required.
786
+ *
787
+ * @example
788
+ * ```typescript
789
+ * const storage = new MemoryStorage();
790
+ * await storage.save(workflowState);
791
+ * const state = await storage.load('workflow-id');
792
+ * ```
793
+ */
794
+ declare class MemoryStorage implements WorkflowStorage {
795
+ private store;
796
+ /**
797
+ * Stores a workflow state in the internal Map.
798
+ *
799
+ * Automatically updates the `updatedAt` timestamp to reflect the current time.
800
+ *
801
+ * @param state - The workflow state to persist.
802
+ * @throws {Error} If the state object is invalid or cannot be stored.
803
+ */
804
+ save(state: WorkflowState): Promise<void>;
805
+ /**
806
+ * Retrieves a workflow state by its ID from the internal Map.
807
+ *
808
+ * @param id - The unique identifier of the workflow.
809
+ * @returns The workflow state if found, otherwise null.
810
+ */
811
+ load(id: string): Promise<WorkflowState | null>;
812
+ /**
813
+ * Filters and returns workflow states stored in memory.
814
+ *
815
+ * Supports filtering by name and status, and provides basic pagination.
816
+ * Results are sorted by creation date in descending order.
817
+ *
818
+ * @param filter - Criteria for filtering and paginating results.
819
+ * @returns An array of matching workflow states.
820
+ */
821
+ list(filter?: WorkflowFilter): Promise<WorkflowState[]>;
822
+ /**
823
+ * Removes a workflow state from the internal Map.
824
+ *
825
+ * @param id - The unique identifier of the workflow to delete.
826
+ */
827
+ delete(id: string): Promise<void>;
828
+ /**
829
+ * Initializes the memory storage.
830
+ *
831
+ * This is a no-op for MemoryStorage but satisfies the WorkflowStorage interface.
832
+ */
833
+ init(): Promise<void>;
834
+ /**
835
+ * Clears all stored workflow states and resets the storage.
836
+ */
837
+ close(): Promise<void>;
838
+ /**
839
+ * Returns the total number of workflow states currently stored in memory.
840
+ *
841
+ * Useful for assertions in test environments.
842
+ *
843
+ * @returns The number of entries in the store.
844
+ */
845
+ size(): number;
846
+ }
847
+
848
+ /**
849
+ * Configuration options for the PostgreSQL storage adapter.
850
+ *
851
+ * Defines connection parameters and database schema settings.
852
+ */
853
+ interface PostgreSQLStorageOptions {
854
+ /** Connection string URL (e.g. "postgres://user:pass@host:5432/db"). */
855
+ connectionString?: string;
856
+ /** Database host address. */
857
+ host?: string;
858
+ /** Database port number. @default 5432 */
859
+ port?: number;
860
+ /** Database name. @default "postgres" */
861
+ database?: string;
862
+ /** Database user. */
863
+ user?: string;
864
+ /** Database password. */
865
+ password?: string;
866
+ /** Name of the table to store workflows. @default "flux_workflows" */
867
+ tableName?: string;
868
+ /** SSL configuration for secure connections. */
869
+ ssl?: boolean | {
870
+ rejectUnauthorized?: boolean;
871
+ };
872
+ }
873
+ /**
874
+ * PostgreSQL storage adapter for Flux workflows.
875
+ *
876
+ * Provides persistent, reliable storage using a PostgreSQL database.
877
+ * Supports JSONB for efficient storage of workflow state and history.
878
+ *
879
+ * @example
880
+ * ```typescript
881
+ * const storage = new PostgreSQLStorage({
882
+ * connectionString: process.env.DATABASE_URL,
883
+ * tableName: 'my_workflows'
884
+ * });
885
+ * await storage.init();
886
+ * ```
887
+ */
888
+ declare class PostgreSQLStorage implements WorkflowStorage {
889
+ private pool;
890
+ private tableName;
891
+ private initialized;
892
+ private options;
893
+ /**
894
+ * Creates a new PostgreSQL storage instance.
895
+ *
896
+ * @param options - Connection and configuration options.
897
+ */
898
+ constructor(options?: PostgreSQLStorageOptions);
899
+ /**
900
+ * Initializes the database connection pool and schema.
901
+ *
902
+ * Creates the workflow table and indexes if they do not exist.
903
+ * This method is idempotent.
904
+ *
905
+ * @throws {Error} If connection fails or schema creation fails.
906
+ */
907
+ init(): Promise<void>;
908
+ /**
909
+ * Persists the current state of a workflow.
910
+ *
911
+ * Uses upsert (INSERT ... ON CONFLICT) to save or update the workflow state.
912
+ *
913
+ * @param state - The workflow state to save.
914
+ * @throws {Error} If the database operation fails.
915
+ */
916
+ save(state: WorkflowState): Promise<void>;
917
+ /**
918
+ * Loads a workflow state by its ID.
919
+ *
920
+ * @param id - The unique identifier of the workflow.
921
+ * @returns The workflow state, or null if not found.
922
+ * @throws {Error} If the database query fails.
923
+ */
924
+ load(id: string): Promise<WorkflowState | null>;
925
+ /**
926
+ * Lists workflows matching the given filter.
927
+ *
928
+ * @param filter - Criteria to filter the results.
929
+ * @returns A list of matching workflow states.
930
+ * @throws {Error} If the database query fails.
931
+ */
932
+ list(filter?: WorkflowFilter): Promise<WorkflowState[]>;
933
+ /**
934
+ * Deletes a workflow state by its ID.
935
+ *
936
+ * @param id - The unique identifier of the workflow to delete.
937
+ * @throws {Error} If the database operation fails.
938
+ */
939
+ delete(id: string): Promise<void>;
940
+ /**
941
+ * Closes the database connection pool.
942
+ *
943
+ * Should be called when shutting down the application.
944
+ */
945
+ close(): Promise<void>;
946
+ /**
947
+ * Converts a database row to a WorkflowState object.
948
+ *
949
+ * @param row - The raw database row.
950
+ * @returns The parsed workflow state.
951
+ */
952
+ private rowToState;
953
+ /**
954
+ * Returns the underlying pg.Pool instance.
955
+ *
956
+ * Useful for testing or advanced database operations.
957
+ *
958
+ * @returns The PostgreSQL connection pool.
959
+ */
960
+ getPool(): any;
961
+ /**
962
+ * Optimizes the database table by reclaiming storage and updating statistics.
963
+ *
964
+ * Runs VACUUM ANALYZE on the workflow table.
965
+ *
966
+ * @throws {Error} If the maintenance operation fails.
967
+ */
968
+ vacuum(): Promise<void>;
969
+ }
970
+
971
+ /**
972
+ * @fileoverview JSON file trace sink (NDJSON)
973
+ *
974
+ * Writes trace events to a newline-delimited JSON file.
975
+ */
976
+
977
+ /**
978
+ * Options for configuring the `JsonFileTraceSink`.
979
+ *
980
+ * @public
981
+ */
982
+ interface JsonFileTraceSinkOptions {
983
+ /** Absolute path where the trace file should be stored. */
984
+ path: string;
985
+ /** Whether to reset (clear) the file on initialization. @default true */
986
+ reset?: boolean;
987
+ }
988
+ /**
989
+ * A trace sink that writes events to a newline-delimited JSON (NDJSON) file.
990
+ *
991
+ * This sink is ideal for local development and debugging as it produces
992
+ * a human-readable and easily machine-parsable log of workflow events.
993
+ *
994
+ * @example
995
+ * ```typescript
996
+ * const sink = new JsonFileTraceSink({
997
+ * path: './traces/workflow.jsonl',
998
+ * reset: true
999
+ * });
1000
+ * ```
1001
+ *
1002
+ * @public
1003
+ */
1004
+ declare class JsonFileTraceSink implements FluxTraceSink {
1005
+ private path;
1006
+ private ready;
1007
+ /**
1008
+ * Creates a new JSON file trace sink.
1009
+ *
1010
+ * @param options - Configuration options for the sink.
1011
+ */
1012
+ constructor(options: JsonFileTraceSinkOptions);
1013
+ /**
1014
+ * Ensures the target directory exists and optionally resets the file.
1015
+ *
1016
+ * @param reset - Whether to truncate the file if it already exists.
1017
+ * @throws {Error} If directory creation or file writing fails.
1018
+ */
1019
+ private init;
1020
+ /**
1021
+ * Appends a trace event to the file in NDJSON format.
1022
+ *
1023
+ * Waits for initialization to complete before writing.
1024
+ *
1025
+ * @param event - The trace event to record.
1026
+ * @throws {Error} If writing to the file fails.
1027
+ *
1028
+ * @example
1029
+ * ```typescript
1030
+ * await sink.emit({
1031
+ * type: 'step_start',
1032
+ * workflowId: 'wf-1',
1033
+ * timestamp: Date.now(),
1034
+ * data: { step: 'validate' }
1035
+ * });
1036
+ * ```
1037
+ */
1038
+ emit(event: FluxTraceEvent): Promise<void>;
1039
+ }
1040
+
1041
+ /**
1042
+ * Callback for handling recovery needed events.
1043
+ */
1044
+ type RecoveryCallback<TInput = unknown, TData = Record<string, any>> = (ctx: WorkflowContext<TInput, TData>, stepName: string, error: Error) => Promise<void> | void;
1045
+ /**
1046
+ * Recovery action types for manual intervention.
1047
+ */
1048
+ type RecoveryAction = {
1049
+ type: 'retry';
1050
+ maxAttempts?: number;
1051
+ } | {
1052
+ type: 'skip';
1053
+ } | {
1054
+ type: 'manual';
1055
+ handler: () => Promise<void>;
1056
+ } | {
1057
+ type: 'abort';
1058
+ };
1059
+ /**
1060
+ * Manages recovery from failed compensation actions through human intervention.
1061
+ *
1062
+ * When automatic retry fails, this manager allows workflows to wait for
1063
+ * manual recovery actions before proceeding with rollback.
1064
+ *
1065
+ * @example
1066
+ * ```typescript
1067
+ * const manager = new RecoveryManager();
1068
+ *
1069
+ * manager.onRecoveryNeeded(async (ctx, stepName, error) => {
1070
+ * await notificationService.alert(
1071
+ * 'CRITICAL: Manual recovery needed',
1072
+ * { workflow: ctx.id, step: stepName, error: error.message }
1073
+ * );
1074
+ * });
1075
+ *
1076
+ * manager.registerAction('refund-payment', {
1077
+ * type: 'manual',
1078
+ * handler: async () => {
1079
+ * await finance.manualRefund(ctx.data.transactionId);
1080
+ * }
1081
+ * });
1082
+ * ```
1083
+ */
1084
+ declare class RecoveryManager<TInput = unknown, TData = Record<string, any>> {
1085
+ private recoveryCallbacks;
1086
+ private actions;
1087
+ private pendingRecoveries;
1088
+ /**
1089
+ * Registers a callback to be invoked when recovery is needed.
1090
+ *
1091
+ * @param callback - Function to call when a recovery event occurs.
1092
+ *
1093
+ * @example
1094
+ * ```typescript
1095
+ * manager.onRecoveryNeeded(async (ctx, stepName, error) => {
1096
+ * await slack.send(`#alerts`, `Workflow ${ctx.id} needs recovery at ${stepName}`);
1097
+ * });
1098
+ * ```
1099
+ */
1100
+ onRecoveryNeeded(callback: RecoveryCallback<TInput, TData>): void;
1101
+ /**
1102
+ * Emits a recovery needed event.
1103
+ *
1104
+ * @param ctx - The workflow context.
1105
+ * @param stepName - The step that failed compensation.
1106
+ * @param error - The error that occurred.
1107
+ */
1108
+ notifyRecoveryNeeded(ctx: WorkflowContext<TInput, TData>, stepName: string, error: Error): Promise<void>;
1109
+ /**
1110
+ * Registers a recovery action for a specific step.
1111
+ *
1112
+ * @param stepName - The step name to associate the action with.
1113
+ * @param action - The recovery action to perform.
1114
+ *
1115
+ * @example
1116
+ * ```typescript
1117
+ * manager.registerAction('book-flight', {
1118
+ * type: 'retry',
1119
+ * maxAttempts: 5
1120
+ * });
1121
+ *
1122
+ * manager.registerAction('charge-card', {
1123
+ * type: 'manual',
1124
+ * handler: async () => {
1125
+ * await accountingSystem.manualRefund(transactionId);
1126
+ * }
1127
+ * });
1128
+ * ```
1129
+ */
1130
+ registerAction(stepName: string, action: RecoveryAction): void;
1131
+ /**
1132
+ * Gets the registered recovery action for a step.
1133
+ *
1134
+ * @param stepName - The step name.
1135
+ * @returns The recovery action if registered, otherwise undefined.
1136
+ */
1137
+ getAction(stepName: string): RecoveryAction | undefined;
1138
+ /**
1139
+ * Checks if a workflow has a pending recovery.
1140
+ *
1141
+ * @param workflowId - The workflow ID.
1142
+ * @returns True if recovery is pending.
1143
+ */
1144
+ hasPendingRecovery(workflowId: string): boolean;
1145
+ /**
1146
+ * Gets the pending recovery details for a workflow.
1147
+ *
1148
+ * @param workflowId - The workflow ID.
1149
+ * @returns The pending recovery details if any.
1150
+ */
1151
+ getPendingRecovery(workflowId: string): {
1152
+ stepName: string;
1153
+ error: Error;
1154
+ } | undefined;
1155
+ /**
1156
+ * Marks a recovery as resolved.
1157
+ *
1158
+ * @param workflowId - The workflow ID.
1159
+ */
1160
+ resolveRecovery(workflowId: string): void;
1161
+ /**
1162
+ * Executes the registered recovery action for a step.
1163
+ *
1164
+ * @param stepName - The step name.
1165
+ * @returns The recovery action result.
1166
+ *
1167
+ * @example
1168
+ * ```typescript
1169
+ * const action = manager.getAction('failed-step');
1170
+ * if (action && action.type === 'manual') {
1171
+ * await manager.executeRecovery('failed-step');
1172
+ * }
1173
+ * ```
1174
+ */
1175
+ executeRecovery(stepName: string): Promise<void>;
1176
+ /**
1177
+ * Clears all registered actions.
1178
+ */
1179
+ clearActions(): void;
1180
+ /**
1181
+ * Clears all recovery callbacks.
1182
+ */
1183
+ clearCallbacks(): void;
1184
+ /**
1185
+ * Gets all pending recoveries.
1186
+ *
1187
+ * @returns A map of workflow IDs to pending recovery details.
1188
+ */
1189
+ getAllPendingRecoveries(): Map<string, {
1190
+ stepName: string;
1191
+ error: Error;
1192
+ }>;
1193
+ /**
1194
+ * Clears all pending recoveries.
1195
+ */
1196
+ clearPendingRecoveries(): void;
1197
+ /**
1198
+ * Gets the count of registered callbacks.
1199
+ * @internal For testing purposes.
1200
+ */
1201
+ getCallbackCount(): number;
1202
+ }
1203
+
1204
+ /**
1205
+ * The core execution engine for Flux workflows.
1206
+ *
1207
+ * FluxEngine manages the lifecycle of workflow execution, including persistence,
1208
+ * state transitions, retries, and compensation (rollback) logic. It acts as the
1209
+ * primary entry point for interacting with the workflow system.
1210
+ *
1211
+ * @example
1212
+ * ```typescript
1213
+ * const engine = new FluxEngine({
1214
+ * storage: new MemoryStorage(),
1215
+ * defaultRetries: 3
1216
+ * });
1217
+ * await engine.init();
1218
+ * const result = await engine.execute(myWorkflow, { userId: '123' });
1219
+ * ```
1220
+ */
1221
+ declare class FluxEngine {
1222
+ private storage;
1223
+ private contextManager;
1224
+ private traceEmitter;
1225
+ private executor;
1226
+ private rollbackManager;
1227
+ private cronTrigger;
1228
+ private dataOptimizer?;
1229
+ constructor(config?: FluxConfig);
1230
+ private config;
1231
+ execute<TInput, TData extends Record<string, any> = Record<string, any>>(workflow: WorkflowBuilder<TInput, TData> | WorkflowDefinition<TInput, TData>, input: TInput): Promise<FluxResult<TData>>;
1232
+ executeBatch<TInput, TData extends Record<string, any> = Record<string, any>>(workflow: WorkflowBuilder<TInput, TData> | WorkflowDefinition<TInput, TData>, inputs: TInput[], options?: BatchExecutionOptions): Promise<BatchResult<TData>>;
1233
+ private executeWithLock;
1234
+ resume<TInput, TData extends Record<string, any> = Record<string, any>>(workflow: WorkflowBuilder<TInput, TData> | WorkflowDefinition<TInput, TData>, workflowId: string, options?: {
1235
+ fromStep?: number | string;
1236
+ }): Promise<FluxResult<TData> | null>;
1237
+ signal<TInput, TData extends Record<string, any> = Record<string, any>>(workflow: WorkflowBuilder<TInput, TData> | WorkflowDefinition<TInput, TData>, workflowId: string, signalName: string, payload?: any): Promise<FluxResult<TData>>;
1238
+ retryStep<TInput, TData extends Record<string, any> = Record<string, any>>(workflow: WorkflowBuilder<TInput, TData> | WorkflowDefinition<TInput, TData>, workflowId: string, stepName: string): Promise<FluxResult<TData> | null>;
1239
+ /**
1240
+ * Retrieves the current state of a workflow instance from storage.
1241
+ *
1242
+ * @param workflowId - The unique identifier of the workflow.
1243
+ * @returns A promise resolving to the workflow state or null if not found.
1244
+ */
1245
+ get<TInput = any, TData = any>(workflowId: string): Promise<WorkflowState<TInput, TData> | null>;
1246
+ saveState<TInput, TData extends Record<string, any>>(state: WorkflowState<TInput, TData>): Promise<void>;
1247
+ list(filter?: Parameters<WorkflowStorage['list']>[0]): Promise<WorkflowState<unknown, Record<string, any>>[]>;
1248
+ schedule<TInput, TData extends Record<string, any>>(cron: string, workflow: WorkflowBuilder<TInput, TData> | WorkflowDefinition<TInput, TData>, input: TInput, id?: string): string;
1249
+ unschedule(id: string): void;
1250
+ /**
1251
+ * Lists all active workflow schedules.
1252
+ */
1253
+ listSchedules(): CronScheduleOptions[];
1254
+ /**
1255
+ * Gets the recovery manager for handling manual intervention.
1256
+ */
1257
+ getRecoveryManager(): RecoveryManager<unknown, Record<string, any>>;
1258
+ /**
1259
+ * Gets the lock provider used for cluster mode.
1260
+ */
1261
+ getLockProvider(): LockProvider | undefined;
1262
+ /**
1263
+ * Initializes the engine and its underlying storage, and starts the scheduler.
1264
+ */
1265
+ init(): Promise<void>;
1266
+ /**
1267
+ * Closes the engine and releases storage resources.
1268
+ */
1269
+ close(): Promise<void>;
1270
+ private persist;
1271
+ }
1272
+
1273
+ /**
1274
+ * Options for batch execution of workflows.
1275
+ */
1276
+ interface BatchExecutionOptions {
1277
+ /** Maximum concurrent workflow executions. @default 10 */
1278
+ concurrency?: number;
1279
+ /** Whether to continue on individual workflow failures. @default true */
1280
+ continueOnError?: boolean;
1281
+ /** Callback for progress updates */
1282
+ onProgress?: (completed: number, total: number, result: BatchItemResult) => void;
1283
+ /** Abort signal for cancellation */
1284
+ signal?: AbortSignal;
1285
+ }
1286
+ /**
1287
+ * Result of a single item in a batch execution.
1288
+ */
1289
+ interface BatchItemResult<TData = any> {
1290
+ /** Index in the batch */
1291
+ index: number;
1292
+ /** Input provided to this workflow */
1293
+ input: unknown;
1294
+ /** Execution result (null if failed before execution) */
1295
+ result: FluxResult<TData> | null;
1296
+ /** Error if failed */
1297
+ error?: Error;
1298
+ /** Whether this item succeeded */
1299
+ success: boolean;
1300
+ }
1301
+ /**
1302
+ * Result of a batch execution containing all individual results.
1303
+ */
1304
+ interface BatchResult<TData = any> {
1305
+ /** Total items in batch */
1306
+ total: number;
1307
+ /** Number of successful executions */
1308
+ succeeded: number;
1309
+ /** Number of failed executions */
1310
+ failed: number;
1311
+ /** Results for each item in order */
1312
+ results: BatchItemResult<TData>[];
1313
+ /** Total execution time in milliseconds */
1314
+ duration: number;
1315
+ }
1316
+ /**
1317
+ * Executes workflows in batches with controlled concurrency.
1318
+ *
1319
+ * BatchExecutor provides efficient parallel execution of multiple workflow instances
1320
+ * while respecting concurrency limits, handling errors gracefully, and supporting
1321
+ * cancellation via AbortSignal.
1322
+ *
1323
+ * @example
1324
+ * ```typescript
1325
+ * const engine = new FluxEngine()
1326
+ * const executor = new BatchExecutor(engine)
1327
+ *
1328
+ * const results = await executor.execute(
1329
+ * myWorkflow,
1330
+ * [{ id: 1 }, { id: 2 }, { id: 3 }],
1331
+ * {
1332
+ * concurrency: 5,
1333
+ * onProgress: (completed, total) => console.log(`${completed}/${total}`)
1334
+ * }
1335
+ * )
1336
+ *
1337
+ * console.log(`Succeeded: ${results.succeeded}, Failed: ${results.failed}`)
1338
+ * ```
1339
+ */
1340
+ declare class BatchExecutor {
1341
+ private engine;
1342
+ constructor(engine: FluxEngine);
1343
+ /**
1344
+ * Execute a workflow for multiple inputs with controlled concurrency.
1345
+ *
1346
+ * @param workflow - The workflow definition or builder to execute.
1347
+ * @param inputs - Array of inputs, one per workflow execution.
1348
+ * @param options - Execution options (concurrency, error handling, etc.).
1349
+ * @returns Batch result containing all individual execution results.
1350
+ */
1351
+ execute<TInput, TData extends Record<string, any> = Record<string, any>>(workflow: WorkflowBuilder<TInput, TData> | WorkflowDefinition<TInput, TData>, inputs: TInput[], options?: BatchExecutionOptions): Promise<BatchResult<TData>>;
1352
+ /**
1353
+ * Execute different workflows in a single batch.
1354
+ *
1355
+ * Unlike `execute()`, this method allows each item in the batch to use a different
1356
+ * workflow definition, enabling heterogeneous batch processing.
1357
+ *
1358
+ * @param items - Array of workflow/input pairs to execute.
1359
+ * @param options - Execution options (concurrency, error handling, etc.).
1360
+ * @returns Batch result containing all individual execution results.
1361
+ */
1362
+ executeMany<TData = any>(items: Array<{
1363
+ workflow: WorkflowDefinition<any, any>;
1364
+ input: any;
1365
+ }>, options?: BatchExecutionOptions): Promise<BatchResult<TData>>;
503
1366
  }
504
1367
 
505
- export { ContextManager, FluxConfig, FluxConsoleLogger, FluxEngine, FluxLogger, FluxResult, FluxSilentLogger, FluxTraceEvent, FluxTraceSink, JsonFileTraceSink, MemoryStorage, OrbitFlux, type OrbitFluxOptions, StateMachine, StepDefinition, StepExecution, StepExecutor, StepResult, WorkflowBuilder, WorkflowContext, WorkflowDefinition, WorkflowDescriptor, WorkflowFilter, WorkflowState, WorkflowStatus, WorkflowStorage, createWorkflow };
1368
+ export { type BatchExecutionOptions, BatchExecutor, type BatchItemResult, type BatchResult, ContextManager, FluxConfig, FluxConsoleLogger, FluxEngine, FluxLogger, FluxResult, FluxSilentLogger, FluxTraceEvent, FluxTraceSink, JsonFileTraceSink, Lock, LockProvider, MemoryStorage, OrbitFlux, type OrbitFluxOptions, PostgreSQLStorage, type PostgreSQLStorageOptions, type RedisClient, RedisLockProvider, type RedisLockProviderOptions, StateMachine, StepDefinition, StepExecution, StepExecutor, StepResult, WorkflowBuilder, WorkflowContext, WorkflowDefinition, WorkflowDescriptor, WorkflowFilter, WorkflowState, WorkflowStatus, WorkflowStorage, createWorkflow };