@gravito/flux 3.0.2 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -9
- package/dist/bun.cjs +2 -2
- package/dist/bun.cjs.map +1 -1
- package/dist/bun.d.cts +1 -1
- package/dist/bun.d.ts +1 -1
- package/dist/bun.js +1 -1
- package/dist/chunk-6AZNHVEO.cjs.map +1 -1
- package/dist/{chunk-WAPZDXSX.cjs → chunk-DN7SIQ34.cjs} +147 -47
- package/dist/chunk-DN7SIQ34.cjs.map +1 -0
- package/dist/{chunk-NAIVO7RR.js → chunk-EZGSU6AW.js} +10 -2
- package/dist/chunk-EZGSU6AW.js.map +1 -0
- package/dist/{chunk-4DXCQ6CL.js → chunk-M2ZRQRF4.js} +112 -12
- package/dist/chunk-M2ZRQRF4.js.map +1 -0
- package/dist/{chunk-YXBEYVGY.cjs → chunk-ZE2RDS47.cjs} +10 -2
- package/dist/chunk-ZE2RDS47.cjs.map +1 -0
- package/dist/cli/flux-visualize.cjs.map +1 -1
- package/dist/index.cjs +5 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.node.cjs +3 -3
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.d.cts +37 -6
- package/dist/index.node.d.ts +37 -6
- package/dist/index.node.js +2 -2
- package/dist/{types-CRz5XdLd.d.cts → types-CGIEQPFv.d.cts} +10 -0
- package/dist/{types-CRz5XdLd.d.ts → types-CGIEQPFv.d.ts} +10 -0
- package/package.json +5 -3
- package/dist/chunk-4DXCQ6CL.js.map +0 -1
- package/dist/chunk-NAIVO7RR.js.map +0 -1
- package/dist/chunk-WAPZDXSX.cjs.map +0 -1
- package/dist/chunk-YXBEYVGY.cjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BunSQLiteStorage
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-EZGSU6AW.js";
|
|
4
4
|
|
|
5
5
|
// src/errors.ts
|
|
6
6
|
var FluxErrorCode = /* @__PURE__ */ ((FluxErrorCode2) => {
|
|
@@ -1544,7 +1544,11 @@ function resetHistoryFrom(ctx, startIndex) {
|
|
|
1544
1544
|
entry.status = "pending";
|
|
1545
1545
|
entry.startedAt = void 0;
|
|
1546
1546
|
entry.completedAt = void 0;
|
|
1547
|
+
entry.suspendedAt = void 0;
|
|
1548
|
+
entry.compensatedAt = void 0;
|
|
1549
|
+
entry.waitingFor = void 0;
|
|
1547
1550
|
entry.duration = void 0;
|
|
1551
|
+
entry.output = void 0;
|
|
1548
1552
|
entry.error = void 0;
|
|
1549
1553
|
entry.retries = 0;
|
|
1550
1554
|
}
|
|
@@ -1954,6 +1958,7 @@ var RollbackManager = class {
|
|
|
1954
1958
|
error: originalError.message
|
|
1955
1959
|
});
|
|
1956
1960
|
let compensatedCount = 0;
|
|
1961
|
+
let skippedCount = 0;
|
|
1957
1962
|
for (let i = failedAtIndex - 1; i >= 0; i--) {
|
|
1958
1963
|
const step = definition.steps[i];
|
|
1959
1964
|
let execution = currentCtx.history[i];
|
|
@@ -1988,11 +1993,36 @@ var RollbackManager = class {
|
|
|
1988
1993
|
} catch (err) {
|
|
1989
1994
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
1990
1995
|
const action = this.recoveryManager.getAction(step.name);
|
|
1996
|
+
if (action?.type === "retry") {
|
|
1997
|
+
const retryResult = await new CompensationRetryPolicy({
|
|
1998
|
+
...this.retryPolicy.getConfig(),
|
|
1999
|
+
maxAttempts: action.maxAttempts ?? this.retryPolicy.getConfig().maxAttempts
|
|
2000
|
+
}).execute(async () => {
|
|
2001
|
+
await step.compensate?.(currentCtx);
|
|
2002
|
+
});
|
|
2003
|
+
if (retryResult.success) {
|
|
2004
|
+
execution = { ...execution, status: "compensated", compensatedAt: /* @__PURE__ */ new Date() };
|
|
2005
|
+
currentCtx = updateWorkflowContext(currentCtx, {
|
|
2006
|
+
history: currentCtx.history.map((h, idx) => idx === i ? execution : h)
|
|
2007
|
+
});
|
|
2008
|
+
compensatedCount++;
|
|
2009
|
+
await this.traceEmitter.stepCompensate(currentCtx, step.name, i);
|
|
2010
|
+
currentCtx = await this.persist(currentCtx);
|
|
2011
|
+
continue;
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
1991
2014
|
if (action?.type === "skip") {
|
|
2015
|
+
execution = { ...execution, status: "completed", error: error.message };
|
|
2016
|
+
currentCtx = updateWorkflowContext(currentCtx, {
|
|
2017
|
+
history: currentCtx.history.map((h, idx) => idx === i ? execution : h)
|
|
2018
|
+
});
|
|
2019
|
+
currentCtx = await this.persist(currentCtx);
|
|
2020
|
+
skippedCount++;
|
|
1992
2021
|
continue;
|
|
1993
2022
|
}
|
|
1994
2023
|
if (action?.type === "abort") {
|
|
1995
2024
|
currentCtx = updateWorkflowContext(currentCtx, { status: "compensation_failed" });
|
|
2025
|
+
currentCtx = await this.persist(currentCtx);
|
|
1996
2026
|
await this.traceEmitter.emit({
|
|
1997
2027
|
type: "workflow:error",
|
|
1998
2028
|
timestamp: Date.now(),
|
|
@@ -2005,6 +2035,7 @@ var RollbackManager = class {
|
|
|
2005
2035
|
}
|
|
2006
2036
|
await this.recoveryManager.notifyRecoveryNeeded(currentCtx, step.name, error);
|
|
2007
2037
|
currentCtx = updateWorkflowContext(currentCtx, { status: "compensation_failed" });
|
|
2038
|
+
currentCtx = await this.persist(currentCtx);
|
|
2008
2039
|
await this.traceEmitter.emit({
|
|
2009
2040
|
type: "workflow:error",
|
|
2010
2041
|
timestamp: Date.now(),
|
|
@@ -2017,7 +2048,7 @@ var RollbackManager = class {
|
|
|
2017
2048
|
}
|
|
2018
2049
|
currentCtx = await this.persist(currentCtx);
|
|
2019
2050
|
}
|
|
2020
|
-
if (compensatedCount > 0) {
|
|
2051
|
+
if (compensatedCount > 0 || skippedCount > 0) {
|
|
2021
2052
|
currentCtx = updateWorkflowContext(currentCtx, { status: "rolled_back" });
|
|
2022
2053
|
await this.traceEmitter.emit({
|
|
2023
2054
|
type: "workflow:rollback_complete",
|
|
@@ -2712,7 +2743,14 @@ var FluxEngine = class {
|
|
|
2712
2743
|
}
|
|
2713
2744
|
ctx = updateWorkflowContext(ctx, {
|
|
2714
2745
|
history: ctx.history.map(
|
|
2715
|
-
(h, i) => i === idx ? {
|
|
2746
|
+
(h, i) => i === idx ? {
|
|
2747
|
+
...h,
|
|
2748
|
+
status: "completed",
|
|
2749
|
+
completedAt: /* @__PURE__ */ new Date(),
|
|
2750
|
+
suspendedAt: void 0,
|
|
2751
|
+
waitingFor: void 0,
|
|
2752
|
+
output: payload
|
|
2753
|
+
} : h
|
|
2716
2754
|
)
|
|
2717
2755
|
});
|
|
2718
2756
|
await this.traceEmitter.emit({
|
|
@@ -2831,7 +2869,7 @@ var PostgreSQLStorage = class {
|
|
|
2831
2869
|
*/
|
|
2832
2870
|
constructor(options = {}) {
|
|
2833
2871
|
this.options = options;
|
|
2834
|
-
this.tableName = options.tableName ?? "flux_workflows";
|
|
2872
|
+
this.tableName = validateSqlIdentifier(options.tableName ?? "flux_workflows", "tableName");
|
|
2835
2873
|
}
|
|
2836
2874
|
/**
|
|
2837
2875
|
* Initializes the database connection pool and schema.
|
|
@@ -3056,20 +3094,34 @@ var PostgreSQLStorage = class {
|
|
|
3056
3094
|
await this.pool.query("VACUUM ANALYZE");
|
|
3057
3095
|
}
|
|
3058
3096
|
};
|
|
3097
|
+
function validateSqlIdentifier(value, field) {
|
|
3098
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
|
|
3099
|
+
throw new Error(
|
|
3100
|
+
`Invalid ${field}: "${value}". Only letters, numbers, and underscores are allowed.`
|
|
3101
|
+
);
|
|
3102
|
+
}
|
|
3103
|
+
return value;
|
|
3104
|
+
}
|
|
3059
3105
|
|
|
3060
3106
|
// src/trace/JsonFileTraceSink.ts
|
|
3061
|
-
import {
|
|
3107
|
+
import { mkdir } from "fs/promises";
|
|
3062
3108
|
import { dirname } from "path";
|
|
3109
|
+
import { getDefaultRuntimeAdapter } from "@gravito/core";
|
|
3063
3110
|
var JsonFileTraceSink = class {
|
|
3064
3111
|
path;
|
|
3065
3112
|
ready;
|
|
3113
|
+
fileSink = null;
|
|
3114
|
+
buffer = [];
|
|
3115
|
+
bufferSize;
|
|
3116
|
+
adapter = getDefaultRuntimeAdapter();
|
|
3066
3117
|
/**
|
|
3067
|
-
* Creates a new JSON file trace sink.
|
|
3118
|
+
* Creates a new JSON file trace sink with buffering support.
|
|
3068
3119
|
*
|
|
3069
3120
|
* @param options - Configuration options for the sink.
|
|
3070
3121
|
*/
|
|
3071
3122
|
constructor(options) {
|
|
3072
3123
|
this.path = options.path;
|
|
3124
|
+
this.bufferSize = options.bufferSize ?? 50;
|
|
3073
3125
|
this.ready = this.init(options.reset ?? true);
|
|
3074
3126
|
}
|
|
3075
3127
|
/**
|
|
@@ -3080,14 +3132,22 @@ var JsonFileTraceSink = class {
|
|
|
3080
3132
|
*/
|
|
3081
3133
|
async init(reset) {
|
|
3082
3134
|
await mkdir(dirname(this.path), { recursive: true });
|
|
3083
|
-
if (
|
|
3084
|
-
await
|
|
3135
|
+
if (this.adapter.createFileSink) {
|
|
3136
|
+
this.fileSink = await this.adapter.createFileSink?.(this.path);
|
|
3137
|
+
}
|
|
3138
|
+
if (reset && !this.fileSink) {
|
|
3139
|
+
if (this.adapter.writeFile) {
|
|
3140
|
+
await this.adapter.writeFile(this.path, "");
|
|
3141
|
+
}
|
|
3142
|
+
} else if (reset && this.fileSink) {
|
|
3143
|
+
this.fileSink.write("");
|
|
3085
3144
|
}
|
|
3086
3145
|
}
|
|
3087
3146
|
/**
|
|
3088
3147
|
* Appends a trace event to the file in NDJSON format.
|
|
3089
3148
|
*
|
|
3090
|
-
*
|
|
3149
|
+
* Events are buffered and written in batches using FileSink
|
|
3150
|
+
* for improved I/O efficiency. Waits for initialization to complete before writing.
|
|
3091
3151
|
*
|
|
3092
3152
|
* @param event - The trace event to record.
|
|
3093
3153
|
* @throws {Error} If writing to the file fails.
|
|
@@ -3104,8 +3164,48 @@ var JsonFileTraceSink = class {
|
|
|
3104
3164
|
*/
|
|
3105
3165
|
async emit(event) {
|
|
3106
3166
|
await this.ready;
|
|
3107
|
-
|
|
3108
|
-
|
|
3167
|
+
const eventLine = `${JSON.stringify(event)}
|
|
3168
|
+
`;
|
|
3169
|
+
if (this.fileSink) {
|
|
3170
|
+
this.buffer.push(eventLine);
|
|
3171
|
+
if (this.buffer.length >= this.bufferSize) {
|
|
3172
|
+
await this.flushBuffer();
|
|
3173
|
+
}
|
|
3174
|
+
} else {
|
|
3175
|
+
if (this.adapter.appendFile) {
|
|
3176
|
+
await this.adapter.appendFile(this.path, eventLine);
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
/**
|
|
3181
|
+
* Flushes buffered events to disk.
|
|
3182
|
+
*
|
|
3183
|
+
* This is called automatically when the buffer reaches the configured size.
|
|
3184
|
+
* Can also be called manually to ensure all events are written.
|
|
3185
|
+
*
|
|
3186
|
+
* @throws {Error} If flushing fails.
|
|
3187
|
+
*/
|
|
3188
|
+
async flushBuffer() {
|
|
3189
|
+
if (!this.fileSink || this.buffer.length === 0) {
|
|
3190
|
+
return;
|
|
3191
|
+
}
|
|
3192
|
+
const content = this.buffer.join("");
|
|
3193
|
+
this.fileSink.write(content);
|
|
3194
|
+
this.buffer = [];
|
|
3195
|
+
await this.fileSink.flush();
|
|
3196
|
+
}
|
|
3197
|
+
/**
|
|
3198
|
+
* Closes the sink and flushes any remaining buffered events.
|
|
3199
|
+
*
|
|
3200
|
+
* Should be called before process exit to ensure all events are persisted.
|
|
3201
|
+
*
|
|
3202
|
+
* @throws {Error} If closing or flushing fails.
|
|
3203
|
+
*/
|
|
3204
|
+
async close() {
|
|
3205
|
+
await this.flushBuffer();
|
|
3206
|
+
if (this.fileSink) {
|
|
3207
|
+
await this.fileSink.end();
|
|
3208
|
+
}
|
|
3109
3209
|
}
|
|
3110
3210
|
};
|
|
3111
3211
|
|
|
@@ -3483,4 +3583,4 @@ export {
|
|
|
3483
3583
|
FluxSilentLogger,
|
|
3484
3584
|
OrbitFlux
|
|
3485
3585
|
};
|
|
3486
|
-
//# sourceMappingURL=chunk-
|
|
3586
|
+
//# sourceMappingURL=chunk-M2ZRQRF4.js.map
|