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