@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,1006 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3;
2
-
3
- var _chunkSJSPR4ZUcjs = require('./chunk-SJSPR4ZU.cjs');
4
-
5
- // src/builder/WorkflowBuilder.ts
6
- var WorkflowBuilder = (_class = class {
7
- __init() {this.drum = null}
8
- // No!
9
-
10
- __init2() {this._steps = []}
11
-
12
- constructor(name) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);
13
- this._name = name;
14
- }
15
- /**
16
- * Define input type
17
- *
18
- * This method is used for TypeScript type inference.
19
- */
20
- input() {
21
- return this;
22
- }
23
- /**
24
- * Define workflow data (state) type
25
- *
26
- * This method is used for TypeScript type inference.
27
- */
28
- data() {
29
- return this;
30
- }
31
- /**
32
- * Add input validator
33
- */
34
- validate(validator) {
35
- this._validateInput = validator;
36
- return this;
37
- }
38
- /**
39
- * Add a step to the workflow
40
- */
41
- step(name, handler, options) {
42
- this._steps.push({
43
- name,
44
- handler,
45
- retries: _optionalChain([options, 'optionalAccess', _2 => _2.retries]),
46
- timeout: _optionalChain([options, 'optionalAccess', _3 => _3.timeout]),
47
- when: _optionalChain([options, 'optionalAccess', _4 => _4.when]),
48
- compensate: _optionalChain([options, 'optionalAccess', _5 => _5.compensate]),
49
- commit: false
50
- });
51
- return this;
52
- }
53
- /**
54
- * Add a commit step (always executes, even on replay)
55
- *
56
- * Commit steps are for side effects that should not be skipped,
57
- * such as database writes or external API calls.
58
- */
59
- commit(name, handler, options) {
60
- this._steps.push({
61
- name,
62
- handler,
63
- retries: _optionalChain([options, 'optionalAccess', _6 => _6.retries]),
64
- timeout: _optionalChain([options, 'optionalAccess', _7 => _7.timeout]),
65
- when: _optionalChain([options, 'optionalAccess', _8 => _8.when]),
66
- commit: true
67
- });
68
- return this;
69
- }
70
- /**
71
- * Build the workflow definition
72
- */
73
- build() {
74
- if (this._steps.length === 0) {
75
- throw new Error(`Workflow "${this._name}" has no steps`);
76
- }
77
- return {
78
- name: this._name,
79
- steps: [...this._steps],
80
- validateInput: this._validateInput
81
- };
82
- }
83
- /**
84
- * Describe workflow (serializable metadata)
85
- */
86
- describe() {
87
- const steps = this._steps.map((step) => ({
88
- name: step.name,
89
- commit: Boolean(step.commit),
90
- retries: step.retries,
91
- timeout: step.timeout,
92
- hasCondition: Boolean(step.when)
93
- }));
94
- return {
95
- name: this._name,
96
- steps
97
- };
98
- }
99
- /**
100
- * Get workflow name
101
- */
102
- get name() {
103
- return this._name;
104
- }
105
- /**
106
- * Get step count
107
- */
108
- get stepCount() {
109
- return this._steps.length;
110
- }
111
- }, _class);
112
- function createWorkflow(name) {
113
- return new WorkflowBuilder(name);
114
- }
115
-
116
- // src/core/ContextManager.ts
117
- function generateId() {
118
- return crypto.randomUUID();
119
- }
120
- var ContextManager = class {
121
- /**
122
- * Create a new workflow context
123
- */
124
- create(name, input, stepCount) {
125
- const history = Array.from({ length: stepCount }, (_, _i) => ({
126
- name: "",
127
- status: "pending",
128
- retries: 0
129
- }));
130
- return {
131
- id: generateId(),
132
- name,
133
- input,
134
- data: {},
135
- status: "pending",
136
- currentStep: 0,
137
- history
138
- };
139
- }
140
- /**
141
- * Restore context from saved state
142
- */
143
- restore(state) {
144
- return {
145
- id: state.id,
146
- name: state.name,
147
- input: state.input,
148
- data: { ...state.data },
149
- status: state.status,
150
- currentStep: state.currentStep,
151
- history: state.history.map((h) => ({ ...h }))
152
- };
153
- }
154
- /**
155
- * Convert context to serializable state
156
- */
157
- toState(ctx) {
158
- return {
159
- id: ctx.id,
160
- name: ctx.name,
161
- status: ctx.status,
162
- input: ctx.input,
163
- data: { ...ctx.data },
164
- currentStep: ctx.currentStep,
165
- history: ctx.history.map((h) => ({ ...h })),
166
- createdAt: /* @__PURE__ */ new Date(),
167
- updatedAt: /* @__PURE__ */ new Date()
168
- };
169
- }
170
- /**
171
- * Update context status (returns new context for immutability)
172
- */
173
- updateStatus(ctx, status) {
174
- return {
175
- ...ctx,
176
- status
177
- };
178
- }
179
- /**
180
- * Advance to next step
181
- */
182
- advanceStep(ctx) {
183
- return {
184
- ...ctx,
185
- currentStep: ctx.currentStep + 1
186
- };
187
- }
188
- /**
189
- * Update step name in history
190
- */
191
- setStepName(ctx, index, name) {
192
- if (ctx.history[index]) {
193
- ctx.history[index].name = name;
194
- }
195
- }
196
- };
197
-
198
- // src/core/StateMachine.ts
199
- var TRANSITIONS = {
200
- pending: ["running", "failed"],
201
- running: ["paused", "completed", "failed", "suspended", "rolling_back"],
202
- paused: ["running", "failed"],
203
- suspended: ["running", "failed"],
204
- rolling_back: ["rolled_back", "failed"],
205
- rolled_back: ["pending"],
206
- // allow retry from scratch
207
- completed: [],
208
- // terminal state
209
- failed: ["pending"]
210
- // allow retry
211
- };
212
- var StateMachine = (_class2 = class extends EventTarget {constructor(...args2) { super(...args2); _class2.prototype.__init3.call(this); }
213
- __init3() {this._status = "pending"}
214
- /**
215
- * Current status
216
- */
217
- get status() {
218
- return this._status;
219
- }
220
- /**
221
- * Check if transition to target status is allowed
222
- */
223
- canTransition(to) {
224
- return TRANSITIONS[this._status].includes(to);
225
- }
226
- /**
227
- * Transition to a new status
228
- *
229
- * @throws {Error} If transition is not allowed
230
- */
231
- transition(to) {
232
- if (!this.canTransition(to)) {
233
- throw new Error(`Invalid state transition: ${this._status} \u2192 ${to}`);
234
- }
235
- const from = this._status;
236
- this._status = to;
237
- this.dispatchEvent(
238
- new CustomEvent("transition", {
239
- detail: { from, to }
240
- })
241
- );
242
- }
243
- /**
244
- * Force set status (for replay/restore)
245
- */
246
- forceStatus(status) {
247
- this._status = status;
248
- }
249
- /**
250
- * Check if workflow is in terminal state
251
- */
252
- isTerminal() {
253
- return this._status === "completed" || this._status === "failed" || this._status === "rolled_back";
254
- }
255
- /**
256
- * Check if workflow can be executed
257
- */
258
- canExecute() {
259
- return this._status === "pending" || this._status === "paused";
260
- }
261
- }, _class2);
262
-
263
- // src/core/StepExecutor.ts
264
- var StepExecutor = class {
265
-
266
-
267
-
268
- constructor(options = {}) {
269
- this.defaultRetries = _nullishCoalesce(options.defaultRetries, () => ( 3));
270
- this.defaultTimeout = _nullishCoalesce(options.defaultTimeout, () => ( 3e4));
271
- this.onRetry = options.onRetry;
272
- }
273
- /**
274
- * Execute a step with retry and timeout
275
- */
276
- async execute(step, ctx, execution) {
277
- const maxRetries = _nullishCoalesce(step.retries, () => ( this.defaultRetries));
278
- const timeout = _nullishCoalesce(step.timeout, () => ( this.defaultTimeout));
279
- const startTime = Date.now();
280
- if (step.when && !step.when(ctx)) {
281
- execution.status = "skipped";
282
- return {
283
- success: true,
284
- duration: 0
285
- };
286
- }
287
- execution.status = "running";
288
- execution.startedAt = /* @__PURE__ */ new Date();
289
- let lastError;
290
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
291
- execution.retries = attempt;
292
- try {
293
- const result = await this.executeWithTimeout(step.handler, ctx, timeout);
294
- if (result && typeof result === "object" && "__kind" in result && result.__kind === "flux_wait") {
295
- execution.status = "suspended";
296
- execution.waitingFor = result.signal;
297
- execution.suspendedAt = /* @__PURE__ */ new Date();
298
- execution.duration = Date.now() - startTime;
299
- return {
300
- success: true,
301
- suspended: true,
302
- waitingFor: result.signal,
303
- duration: execution.duration
304
- };
305
- }
306
- execution.status = "completed";
307
- execution.completedAt = /* @__PURE__ */ new Date();
308
- execution.duration = Date.now() - startTime;
309
- return {
310
- success: true,
311
- duration: execution.duration
312
- };
313
- } catch (error) {
314
- lastError = error instanceof Error ? error : new Error(String(error));
315
- if (attempt < maxRetries) {
316
- await _optionalChain([this, 'access', _9 => _9.onRetry, 'optionalCall', _10 => _10(step, ctx, lastError, attempt + 1, maxRetries)]);
317
- await this.sleep(Math.min(1e3 * 2 ** attempt, 1e4));
318
- }
319
- }
320
- }
321
- execution.status = "failed";
322
- execution.completedAt = /* @__PURE__ */ new Date();
323
- execution.duration = Date.now() - startTime;
324
- execution.error = _optionalChain([lastError, 'optionalAccess', _11 => _11.message]);
325
- return {
326
- success: false,
327
- error: lastError,
328
- duration: execution.duration
329
- };
330
- }
331
- /**
332
- * Execute handler with timeout
333
- */
334
- async executeWithTimeout(handler, ctx, timeout) {
335
- let timer = null;
336
- try {
337
- const timeoutPromise = new Promise((_, reject) => {
338
- timer = setTimeout(() => reject(new Error("Step timeout")), timeout);
339
- });
340
- return await Promise.race([Promise.resolve(handler(ctx)), timeoutPromise]);
341
- } finally {
342
- if (timer) {
343
- clearTimeout(timer);
344
- }
345
- }
346
- }
347
- /**
348
- * Sleep helper
349
- */
350
- sleep(ms) {
351
- return new Promise((resolve) => setTimeout(resolve, ms));
352
- }
353
- };
354
-
355
- // src/storage/MemoryStorage.ts
356
- var MemoryStorage = (_class3 = class {constructor() { _class3.prototype.__init4.call(this); }
357
- __init4() {this.store = /* @__PURE__ */ new Map()}
358
- async save(state) {
359
- this.store.set(state.id, {
360
- ...state,
361
- updatedAt: /* @__PURE__ */ new Date()
362
- });
363
- }
364
- async load(id) {
365
- return _nullishCoalesce(this.store.get(id), () => ( null));
366
- }
367
- async list(filter) {
368
- let results = Array.from(this.store.values());
369
- if (_optionalChain([filter, 'optionalAccess', _12 => _12.name])) {
370
- results = results.filter((s) => s.name === filter.name);
371
- }
372
- if (_optionalChain([filter, 'optionalAccess', _13 => _13.status])) {
373
- const statuses = Array.isArray(filter.status) ? filter.status : [filter.status];
374
- results = results.filter((s) => statuses.includes(s.status));
375
- }
376
- results.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
377
- if (_optionalChain([filter, 'optionalAccess', _14 => _14.offset])) {
378
- results = results.slice(filter.offset);
379
- }
380
- if (_optionalChain([filter, 'optionalAccess', _15 => _15.limit])) {
381
- results = results.slice(0, filter.limit);
382
- }
383
- return results;
384
- }
385
- async delete(id) {
386
- this.store.delete(id);
387
- }
388
- async init() {
389
- }
390
- async close() {
391
- this.store.clear();
392
- }
393
- /**
394
- * Get store size (for testing)
395
- */
396
- size() {
397
- return this.store.size;
398
- }
399
- }, _class3);
400
-
401
- // src/engine/FluxEngine.ts
402
- var FluxEngine = class {
403
-
404
-
405
-
406
-
407
- constructor(config = {}) {
408
- this.config = config;
409
- this.storage = _nullishCoalesce(config.storage, () => ( new MemoryStorage()));
410
- this.executor = new StepExecutor({
411
- defaultRetries: config.defaultRetries,
412
- defaultTimeout: config.defaultTimeout,
413
- onRetry: async (step, ctx, error, attempt, maxRetries) => {
414
- await this.emitTrace({
415
- type: "step:retry",
416
- timestamp: Date.now(),
417
- workflowId: ctx.id,
418
- workflowName: ctx.name,
419
- stepName: step.name,
420
- stepIndex: ctx.currentStep,
421
- commit: Boolean(step.commit),
422
- retries: attempt,
423
- maxRetries,
424
- error: error.message,
425
- status: "running"
426
- });
427
- }
428
- });
429
- this.contextManager = new ContextManager();
430
- }
431
- /**
432
- * Execute a workflow with input data
433
- *
434
- * @param workflow - Workflow builder or definition
435
- * @param input - Input data for the workflow
436
- * @returns Execution result
437
- */
438
- async execute(workflow, input) {
439
- const startTime = Date.now();
440
- const definition = this.resolveDefinition(workflow);
441
- if (definition.validateInput && !definition.validateInput(input)) {
442
- throw new Error(`Invalid input for workflow "${definition.name}"`);
443
- }
444
- const ctx = this.contextManager.create(
445
- definition.name,
446
- input,
447
- definition.steps.length
448
- );
449
- const stateMachine = new StateMachine();
450
- await this.storage.save(this.contextManager.toState(ctx));
451
- return this.runFrom(definition, ctx, stateMachine, startTime, 0);
452
- }
453
- /**
454
- * Resume a paused or failed workflow
455
- *
456
- * @param workflowId - Workflow instance ID
457
- * @returns Execution result or null if not found
458
- */
459
- async resume(workflow, workflowId, options) {
460
- const definition = this.resolveDefinition(workflow);
461
- const state = await this.storage.load(workflowId);
462
- if (!state) {
463
- return null;
464
- }
465
- if (state.name !== definition.name) {
466
- throw new Error(`Workflow name mismatch: ${state.name} !== ${definition.name}`);
467
- }
468
- if (state.history.length !== definition.steps.length) {
469
- throw new Error("Workflow definition changed; resume is not safe");
470
- }
471
- const ctx = this.contextManager.restore(state);
472
- const stateMachine = new StateMachine();
473
- stateMachine.forceStatus("pending");
474
- const startIndex = this.resolveStartIndex(definition, _optionalChain([options, 'optionalAccess', _16 => _16.fromStep]), ctx.currentStep);
475
- this.resetHistoryFrom(ctx, startIndex);
476
- Object.assign(ctx, { status: "pending", currentStep: startIndex });
477
- await this.storage.save(this.contextManager.toState(ctx));
478
- return this.runFrom(definition, ctx, stateMachine, Date.now(), startIndex, {
479
- resume: true,
480
- fromStep: startIndex
481
- });
482
- }
483
- /**
484
- * Send a signal to a suspended workflow
485
- */
486
- async signal(workflow, workflowId, signalName, payload) {
487
- const definition = this.resolveDefinition(workflow);
488
- const state = await this.storage.load(workflowId);
489
- if (!state) {
490
- throw new Error("Workflow not found");
491
- }
492
- if (state.status !== "suspended") {
493
- throw new Error(`Workflow is not suspended (status: ${state.status})`);
494
- }
495
- const ctx = this.contextManager.restore(state);
496
- const currentStep = ctx.history[ctx.currentStep];
497
- if (!currentStep || currentStep.status !== "suspended") {
498
- throw new Error("Workflow state invalid: no suspended step found");
499
- }
500
- if (currentStep.waitingFor !== signalName) {
501
- throw new Error(
502
- `Workflow waiting for signal "${currentStep.waitingFor}", received "${signalName}"`
503
- );
504
- }
505
- currentStep.status = "completed";
506
- currentStep.completedAt = /* @__PURE__ */ new Date();
507
- currentStep.output = payload;
508
- const stateMachine = new StateMachine();
509
- stateMachine.forceStatus("suspended");
510
- await this.emitTrace({
511
- type: "signal:received",
512
- timestamp: Date.now(),
513
- workflowId: ctx.id,
514
- workflowName: ctx.name,
515
- status: "suspended",
516
- input: payload
517
- });
518
- const nextStepIndex = ctx.currentStep + 1;
519
- return this.runFrom(definition, ctx, stateMachine, Date.now(), nextStepIndex, {
520
- resume: true,
521
- fromStep: nextStepIndex
522
- });
523
- }
524
- /**
525
- * Retry a specific step (replays from that step onward)
526
- */
527
- async retryStep(workflow, workflowId, stepName) {
528
- const definition = this.resolveDefinition(workflow);
529
- const state = await this.storage.load(workflowId);
530
- if (!state) {
531
- return null;
532
- }
533
- if (state.name !== definition.name) {
534
- throw new Error(`Workflow name mismatch: ${state.name} !== ${definition.name}`);
535
- }
536
- if (state.history.length !== definition.steps.length) {
537
- throw new Error("Workflow definition changed; retry is not safe");
538
- }
539
- const ctx = this.contextManager.restore(state);
540
- const stateMachine = new StateMachine();
541
- stateMachine.forceStatus("pending");
542
- const startIndex = this.resolveStartIndex(definition, stepName, ctx.currentStep);
543
- this.resetHistoryFrom(ctx, startIndex);
544
- Object.assign(ctx, { status: "pending", currentStep: startIndex });
545
- await this.storage.save(this.contextManager.toState(ctx));
546
- return this.runFrom(definition, ctx, stateMachine, Date.now(), startIndex, {
547
- retry: true,
548
- fromStep: startIndex
549
- });
550
- }
551
- /**
552
- * Get workflow state by ID
553
- */
554
- async get(workflowId) {
555
- return this.storage.load(workflowId);
556
- }
557
- /**
558
- * Save workflow state manually (e.g., for external updates)
559
- */
560
- async saveState(state) {
561
- return this.storage.save(state);
562
- }
563
- /**
564
- * List workflows
565
- */
566
- async list(filter) {
567
- return this.storage.list(filter);
568
- }
569
- /**
570
- * Initialize engine (init storage)
571
- */
572
- async init() {
573
- await _optionalChain([this, 'access', _17 => _17.storage, 'access', _18 => _18.init, 'optionalCall', _19 => _19()]);
574
- }
575
- /**
576
- * Shutdown engine (cleanup)
577
- */
578
- async close() {
579
- await _optionalChain([this, 'access', _20 => _20.storage, 'access', _21 => _21.close, 'optionalCall', _22 => _22()]);
580
- }
581
- resolveDefinition(workflow) {
582
- return workflow instanceof WorkflowBuilder ? workflow.build() : workflow;
583
- }
584
- resolveStartIndex(definition, fromStep, fallback) {
585
- if (typeof fromStep === "number") {
586
- if (fromStep < 0 || fromStep >= definition.steps.length) {
587
- throw new Error(`Invalid step index: ${fromStep}`);
588
- }
589
- return fromStep;
590
- }
591
- if (typeof fromStep === "string") {
592
- const index = definition.steps.findIndex((step) => step.name === fromStep);
593
- if (index === -1) {
594
- throw new Error(`Step not found: ${fromStep}`);
595
- }
596
- return index;
597
- }
598
- return Math.max(0, Math.min(fallback, definition.steps.length - 1));
599
- }
600
- resetHistoryFrom(ctx, startIndex) {
601
- for (let i = startIndex; i < ctx.history.length; i++) {
602
- const entry = ctx.history[i];
603
- if (!entry) {
604
- continue;
605
- }
606
- entry.status = "pending";
607
- entry.startedAt = void 0;
608
- entry.completedAt = void 0;
609
- entry.duration = void 0;
610
- entry.error = void 0;
611
- entry.retries = 0;
612
- }
613
- }
614
- /**
615
- * Rollback workflow by executing compensation handlers in reverse order
616
- */
617
- async rollback(definition, ctx, failedAtIndex, originalError) {
618
- Object.assign(ctx, { status: "rolling_back" });
619
- await this.emitTrace({
620
- type: "workflow:rollback_start",
621
- timestamp: Date.now(),
622
- workflowId: ctx.id,
623
- workflowName: ctx.name,
624
- status: "rolling_back",
625
- error: originalError.message
626
- });
627
- let compensatedCount = 0;
628
- for (let i = failedAtIndex - 1; i >= 0; i--) {
629
- const step = definition.steps[i];
630
- const execution = ctx.history[i];
631
- if (!step || !step.compensate || !execution || execution.status !== "completed") {
632
- continue;
633
- }
634
- try {
635
- execution.status = "compensating";
636
- await this.storage.save(this.contextManager.toState(ctx));
637
- await step.compensate(ctx);
638
- execution.status = "compensated";
639
- execution.compensatedAt = /* @__PURE__ */ new Date();
640
- compensatedCount++;
641
- await this.emitTrace({
642
- type: "step:compensate",
643
- timestamp: Date.now(),
644
- workflowId: ctx.id,
645
- workflowName: ctx.name,
646
- stepName: step.name,
647
- stepIndex: i,
648
- status: "compensated"
649
- });
650
- } catch (err) {
651
- const error = err instanceof Error ? err : new Error(String(err));
652
- Object.assign(ctx, { status: "failed" });
653
- await this.emitTrace({
654
- type: "workflow:error",
655
- timestamp: Date.now(),
656
- workflowId: ctx.id,
657
- workflowName: ctx.name,
658
- status: "failed",
659
- error: `Compensation failed at step "${step.name}": ${error.message}`
660
- });
661
- return;
662
- }
663
- await this.storage.save(this.contextManager.toState(ctx));
664
- }
665
- if (compensatedCount > 0) {
666
- Object.assign(ctx, { status: "rolled_back" });
667
- await this.emitTrace({
668
- type: "workflow:rollback_complete",
669
- timestamp: Date.now(),
670
- workflowId: ctx.id,
671
- workflowName: ctx.name,
672
- status: "rolled_back"
673
- });
674
- } else {
675
- Object.assign(ctx, { status: "failed" });
676
- }
677
- }
678
- async runFrom(definition, ctx, stateMachine, startTime, startIndex, meta) {
679
- try {
680
- stateMachine.transition("running");
681
- Object.assign(ctx, { status: "running" });
682
- if (!_optionalChain([meta, 'optionalAccess', _23 => _23.resume])) {
683
- await this.emitTrace({
684
- type: "workflow:start",
685
- timestamp: Date.now(),
686
- workflowId: ctx.id,
687
- workflowName: ctx.name,
688
- status: ctx.status,
689
- input: ctx.input,
690
- meta
691
- });
692
- }
693
- for (let i = startIndex; i < definition.steps.length; i++) {
694
- const step = definition.steps[i];
695
- const execution = ctx.history[i];
696
- this.contextManager.setStepName(ctx, i, step.name);
697
- Object.assign(ctx, { currentStep: i });
698
- _optionalChain([this, 'access', _24 => _24.config, 'access', _25 => _25.on, 'optionalAccess', _26 => _26.stepStart, 'optionalCall', _27 => _27(step.name, ctx)]);
699
- await this.emitTrace({
700
- type: "step:start",
701
- timestamp: Date.now(),
702
- workflowId: ctx.id,
703
- workflowName: ctx.name,
704
- stepName: step.name,
705
- stepIndex: i,
706
- commit: Boolean(step.commit),
707
- retries: execution.retries,
708
- status: execution.status,
709
- meta
710
- });
711
- const result = await this.executor.execute(step, ctx, execution);
712
- if (result.success) {
713
- if (result.suspended) {
714
- stateMachine.transition("suspended");
715
- Object.assign(ctx, { status: "suspended" });
716
- await this.emitTrace({
717
- type: "step:suspend",
718
- timestamp: Date.now(),
719
- workflowId: ctx.id,
720
- workflowName: ctx.name,
721
- stepName: step.name,
722
- stepIndex: i,
723
- meta: { signal: result.waitingFor }
724
- });
725
- await this.storage.save(this.contextManager.toState(ctx));
726
- return {
727
- id: ctx.id,
728
- status: "suspended",
729
- data: ctx.data,
730
- history: ctx.history,
731
- duration: Date.now() - startTime
732
- };
733
- }
734
- _optionalChain([this, 'access', _28 => _28.config, 'access', _29 => _29.on, 'optionalAccess', _30 => _30.stepComplete, 'optionalCall', _31 => _31(step.name, ctx, result)]);
735
- if (execution.status === "skipped") {
736
- await this.emitTrace({
737
- type: "step:skipped",
738
- timestamp: Date.now(),
739
- workflowId: ctx.id,
740
- workflowName: ctx.name,
741
- stepName: step.name,
742
- stepIndex: i,
743
- commit: Boolean(step.commit),
744
- retries: execution.retries,
745
- duration: result.duration,
746
- status: execution.status,
747
- meta
748
- });
749
- } else {
750
- await this.emitTrace({
751
- type: "step:complete",
752
- timestamp: Date.now(),
753
- workflowId: ctx.id,
754
- workflowName: ctx.name,
755
- stepName: step.name,
756
- stepIndex: i,
757
- commit: Boolean(step.commit),
758
- retries: execution.retries,
759
- duration: result.duration,
760
- status: execution.status,
761
- meta
762
- });
763
- }
764
- } else {
765
- _optionalChain([this, 'access', _32 => _32.config, 'access', _33 => _33.on, 'optionalAccess', _34 => _34.stepError, 'optionalCall', _35 => _35(step.name, ctx, result.error)]);
766
- await this.emitTrace({
767
- type: "step:error",
768
- timestamp: Date.now(),
769
- workflowId: ctx.id,
770
- workflowName: ctx.name,
771
- stepName: step.name,
772
- stepIndex: i,
773
- commit: Boolean(step.commit),
774
- retries: execution.retries,
775
- duration: result.duration,
776
- error: _optionalChain([result, 'access', _36 => _36.error, 'optionalAccess', _37 => _37.message]),
777
- status: execution.status,
778
- meta
779
- });
780
- await this.rollback(definition, ctx, i, result.error);
781
- const finalStatus = ctx.status;
782
- stateMachine.forceStatus(finalStatus);
783
- await this.storage.save({
784
- ...this.contextManager.toState(ctx),
785
- error: _optionalChain([result, 'access', _38 => _38.error, 'optionalAccess', _39 => _39.message])
786
- });
787
- return {
788
- id: ctx.id,
789
- status: finalStatus,
790
- data: ctx.data,
791
- history: ctx.history,
792
- duration: Date.now() - startTime,
793
- error: result.error
794
- };
795
- }
796
- await this.storage.save(this.contextManager.toState(ctx));
797
- }
798
- stateMachine.transition("completed");
799
- Object.assign(ctx, { status: "completed" });
800
- await this.storage.save({
801
- ...this.contextManager.toState(ctx),
802
- completedAt: /* @__PURE__ */ new Date()
803
- });
804
- _optionalChain([this, 'access', _40 => _40.config, 'access', _41 => _41.on, 'optionalAccess', _42 => _42.workflowComplete, 'optionalCall', _43 => _43(ctx)]);
805
- await this.emitTrace({
806
- type: "workflow:complete",
807
- timestamp: Date.now(),
808
- workflowId: ctx.id,
809
- workflowName: ctx.name,
810
- status: ctx.status,
811
- duration: Date.now() - startTime,
812
- data: ctx.data,
813
- meta
814
- });
815
- return {
816
- id: ctx.id,
817
- status: "completed",
818
- data: ctx.data,
819
- history: ctx.history,
820
- duration: Date.now() - startTime
821
- };
822
- } catch (error) {
823
- const err = error instanceof Error ? error : new Error(String(error));
824
- _optionalChain([this, 'access', _44 => _44.config, 'access', _45 => _45.on, 'optionalAccess', _46 => _46.workflowError, 'optionalCall', _47 => _47(ctx, err)]);
825
- await this.emitTrace({
826
- type: "workflow:error",
827
- timestamp: Date.now(),
828
- workflowId: ctx.id,
829
- workflowName: ctx.name,
830
- status: "failed",
831
- duration: Date.now() - startTime,
832
- error: err.message,
833
- meta
834
- });
835
- stateMachine.forceStatus("failed");
836
- Object.assign(ctx, { status: "failed" });
837
- await this.storage.save({
838
- ...this.contextManager.toState(ctx),
839
- error: err.message
840
- });
841
- return {
842
- id: ctx.id,
843
- status: "failed",
844
- data: ctx.data,
845
- history: ctx.history,
846
- duration: Date.now() - startTime,
847
- error: err
848
- };
849
- }
850
- }
851
- async emitTrace(event) {
852
- try {
853
- await _optionalChain([this, 'access', _48 => _48.config, 'access', _49 => _49.trace, 'optionalAccess', _50 => _50.emit, 'call', _51 => _51(event)]);
854
- } catch (e) {
855
- }
856
- }
857
- };
858
-
859
- // src/trace/JsonFileTraceSink.ts
860
- var _promises = require('fs/promises');
861
- var _path = require('path');
862
- var JsonFileTraceSink = class {
863
-
864
-
865
- constructor(options) {
866
- this.path = options.path;
867
- this.ready = this.init(_nullishCoalesce(options.reset, () => ( true)));
868
- }
869
- async init(reset) {
870
- await _promises.mkdir.call(void 0, _path.dirname.call(void 0, this.path), { recursive: true });
871
- if (reset) {
872
- await _promises.writeFile.call(void 0, this.path, "", "utf8");
873
- }
874
- }
875
- async emit(event) {
876
- await this.ready;
877
- await _promises.appendFile.call(void 0, this.path, `${JSON.stringify(event)}
878
- `, "utf8");
879
- }
880
- };
881
-
882
- // src/logger/FluxLogger.ts
883
- var FluxConsoleLogger = class {
884
-
885
- constructor(prefix = "[Flux]") {
886
- this.prefix = prefix;
887
- }
888
- debug(message, ...args) {
889
- console.debug(`${this.prefix} ${message}`, ...args);
890
- }
891
- info(message, ...args) {
892
- console.info(`${this.prefix} ${message}`, ...args);
893
- }
894
- warn(message, ...args) {
895
- console.warn(`${this.prefix} ${message}`, ...args);
896
- }
897
- error(message, ...args) {
898
- console.error(`${this.prefix} ${message}`, ...args);
899
- }
900
- };
901
- var FluxSilentLogger = class {
902
- debug() {
903
- }
904
- info() {
905
- }
906
- warn() {
907
- }
908
- error() {
909
- }
910
- };
911
-
912
- // src/orbit/OrbitFlux.ts
913
- var OrbitFlux = class _OrbitFlux {
914
-
915
-
916
- constructor(options = {}) {
917
- this.options = {
918
- storage: "memory",
919
- exposeAs: "flux",
920
- defaultRetries: 3,
921
- defaultTimeout: 3e4,
922
- ...options
923
- };
924
- }
925
- /**
926
- * Create OrbitFlux with configuration
927
- */
928
- static configure(options = {}) {
929
- return new _OrbitFlux(options);
930
- }
931
- /**
932
- * Install into PlanetCore
933
- *
934
- * @param core - The PlanetCore instance
935
- */
936
- async install(core) {
937
- const { storage, dbPath, exposeAs, defaultRetries, defaultTimeout, logger } = this.options;
938
- let storageAdapter;
939
- if (typeof storage === "string") {
940
- switch (storage) {
941
- case "sqlite":
942
- storageAdapter = new (0, _chunkSJSPR4ZUcjs.BunSQLiteStorage)({ path: dbPath });
943
- break;
944
- default:
945
- storageAdapter = new MemoryStorage();
946
- }
947
- } else {
948
- storageAdapter = storage;
949
- }
950
- await _optionalChain([storageAdapter, 'access', _52 => _52.init, 'optionalCall', _53 => _53()]);
951
- const engineConfig = {
952
- storage: storageAdapter,
953
- defaultRetries,
954
- defaultTimeout,
955
- logger: _nullishCoalesce(logger, () => ( {
956
- debug: (msg) => core.logger.debug(`[Flux] ${msg}`),
957
- info: (msg) => core.logger.info(`[Flux] ${msg}`),
958
- warn: (msg) => core.logger.warn(`[Flux] ${msg}`),
959
- error: (msg) => core.logger.error(`[Flux] ${msg}`)
960
- })),
961
- on: {
962
- stepStart: (step) => {
963
- core.hooks.doAction("flux:step:start", { step });
964
- },
965
- stepComplete: (step, ctx, result) => {
966
- core.hooks.doAction("flux:step:complete", { step, ctx, result });
967
- },
968
- stepError: (step, ctx, error) => {
969
- core.hooks.doAction("flux:step:error", { step, ctx, error });
970
- },
971
- workflowComplete: (ctx) => {
972
- core.hooks.doAction("flux:workflow:complete", { ctx });
973
- },
974
- workflowError: (ctx, error) => {
975
- core.hooks.doAction("flux:workflow:error", { ctx, error });
976
- }
977
- }
978
- };
979
- this.engine = new FluxEngine(engineConfig);
980
- core.container.instance(exposeAs, this.engine);
981
- core.logger.info(
982
- `[OrbitFlux] Initialized (Storage: ${typeof storage === "string" ? storage : "custom"})`
983
- );
984
- }
985
- /**
986
- * Get the FluxEngine instance
987
- */
988
- getEngine() {
989
- return this.engine;
990
- }
991
- };
992
-
993
-
994
-
995
-
996
-
997
-
998
-
999
-
1000
-
1001
-
1002
-
1003
-
1004
-
1005
- exports.WorkflowBuilder = WorkflowBuilder; exports.createWorkflow = createWorkflow; exports.ContextManager = ContextManager; exports.StateMachine = StateMachine; exports.StepExecutor = StepExecutor; exports.MemoryStorage = MemoryStorage; exports.FluxEngine = FluxEngine; exports.JsonFileTraceSink = JsonFileTraceSink; exports.FluxConsoleLogger = FluxConsoleLogger; exports.FluxSilentLogger = FluxSilentLogger; exports.OrbitFlux = OrbitFlux;
1006
- //# sourceMappingURL=chunk-5OXXH442.cjs.map