@pumped-fn/core-next 0.5.81 → 0.5.82
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/CHANGELOG.md +38 -0
- package/dist/index.cjs +299 -75
- package/dist/index.d.cts +55 -8
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +55 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +299 -75
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# @pumped-fn/core-next
|
|
2
2
|
|
|
3
|
+
## 0.5.82
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 40be7e4: Fix unhandled promise rejections in Promised wrapper
|
|
8
|
+
- 596bf02: Add flow execution tracking and extension authoring improvements
|
|
9
|
+
|
|
10
|
+
**Flow Execution Tracking:**
|
|
11
|
+
|
|
12
|
+
- FlowExecution return type with id, status, abort, ctx access
|
|
13
|
+
- Cancellation via AbortController with ctx.signal and ctx.throwIfAborted()
|
|
14
|
+
- Timeout support at scope.exec() and ctx.exec() levels
|
|
15
|
+
- Status tracking with observable status changes
|
|
16
|
+
- Execution registry with auto-cleanup
|
|
17
|
+
|
|
18
|
+
**Extension Authoring:**
|
|
19
|
+
|
|
20
|
+
- Extension authoring documentation and examples
|
|
21
|
+
- Scope capabilities and lifecycle documentation
|
|
22
|
+
- Real-world patterns for extensions
|
|
23
|
+
|
|
24
|
+
**API Changes:**
|
|
25
|
+
|
|
26
|
+
- scope.exec() now uses named parameters: `scope.exec({ flow, input, ...options })`
|
|
27
|
+
- scope.exec() returns FlowExecution<T> (thenable, backward compatible)
|
|
28
|
+
|
|
29
|
+
**Migration:**
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// Before
|
|
33
|
+
await scope.exec(myFlow, input);
|
|
34
|
+
await scope.exec(myFlow, input, { tags: [tag1] });
|
|
35
|
+
|
|
36
|
+
// After
|
|
37
|
+
await scope.exec({ flow: myFlow, input });
|
|
38
|
+
await scope.exec({ flow: myFlow, input, tags: [tag1] });
|
|
39
|
+
```
|
|
40
|
+
|
|
3
41
|
## 0.5.81
|
|
4
42
|
|
|
5
43
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -372,6 +372,7 @@ var Promised = class Promised {
|
|
|
372
372
|
constructor(promise, executionDataPromise) {
|
|
373
373
|
this.promise = promise instanceof Promised ? promise.promise : promise;
|
|
374
374
|
this.executionDataPromise = executionDataPromise;
|
|
375
|
+
this.promise.catch(() => {});
|
|
375
376
|
}
|
|
376
377
|
static create(promise, executionDataPromise) {
|
|
377
378
|
return new Promised(promise, executionDataPromise);
|
|
@@ -738,12 +739,20 @@ var FlowContext = class FlowContext {
|
|
|
738
739
|
scope;
|
|
739
740
|
reversedExtensions;
|
|
740
741
|
tags;
|
|
741
|
-
|
|
742
|
+
abortController;
|
|
743
|
+
constructor(scope, extensions, tags, parent, abortController) {
|
|
742
744
|
this.extensions = extensions;
|
|
743
745
|
this.parent = parent;
|
|
744
746
|
this.scope = scope;
|
|
745
747
|
this.reversedExtensions = [...extensions].reverse();
|
|
746
748
|
this.tags = tags;
|
|
749
|
+
this.abortController = abortController || new AbortController();
|
|
750
|
+
}
|
|
751
|
+
get signal() {
|
|
752
|
+
return this.abortController.signal;
|
|
753
|
+
}
|
|
754
|
+
throwIfAborted() {
|
|
755
|
+
if (this.signal.aborted) throw new Error("Flow execution cancelled");
|
|
747
756
|
}
|
|
748
757
|
resolve(executor) {
|
|
749
758
|
return this.scope.resolve(executor);
|
|
@@ -792,45 +801,133 @@ var FlowContext = class FlowContext {
|
|
|
792
801
|
this.contextData.set(key, value);
|
|
793
802
|
return value;
|
|
794
803
|
}
|
|
795
|
-
|
|
796
|
-
if (
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
804
|
+
exec(keyOrFlowOrConfig, flowOrInput, inputOrUndefined) {
|
|
805
|
+
if (typeof keyOrFlowOrConfig === "object" && keyOrFlowOrConfig !== null && !("factory" in keyOrFlowOrConfig)) {
|
|
806
|
+
const config = keyOrFlowOrConfig;
|
|
807
|
+
this.throwIfAborted();
|
|
808
|
+
const childAbort = new AbortController();
|
|
809
|
+
let timeoutId;
|
|
810
|
+
if (config.timeout) timeoutId = setTimeout(() => {
|
|
811
|
+
if (!childAbort.signal.aborted) childAbort.abort(/* @__PURE__ */ new Error(`Operation timeout after ${config.timeout}ms`));
|
|
812
|
+
}, config.timeout);
|
|
813
|
+
if (this.signal.aborted) {
|
|
814
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
815
|
+
childAbort.abort(this.signal.reason);
|
|
816
|
+
} else this.signal.addEventListener("abort", () => {
|
|
817
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
818
|
+
childAbort.abort(this.signal.reason);
|
|
819
|
+
}, { once: true });
|
|
820
|
+
if ("flow" in config) {
|
|
821
|
+
const flow$2 = config.flow;
|
|
822
|
+
const input$1 = config.input;
|
|
823
|
+
if (config.key) {
|
|
824
|
+
if (!this.journal) this.journal = /* @__PURE__ */ new Map();
|
|
825
|
+
const journalKey = `${this.find(flowMeta.flowName) || "unknown"}:${this.get(flowMeta.depth)}:${config.key}`;
|
|
826
|
+
const promise$1 = (async () => {
|
|
827
|
+
const journal = this.journal;
|
|
828
|
+
if (journal.has(journalKey)) {
|
|
829
|
+
const entry = journal.get(journalKey);
|
|
830
|
+
if (isErrorEntry(entry)) throw entry.error;
|
|
831
|
+
return entry;
|
|
832
|
+
}
|
|
833
|
+
this.throwIfAborted();
|
|
834
|
+
const handler = await this.scope.resolve(flow$2);
|
|
835
|
+
const definition = flowDefinitionMeta.readFrom(flow$2);
|
|
836
|
+
if (definition) {
|
|
837
|
+
const validated = validate(definition.input, input$1);
|
|
838
|
+
const childContext = new FlowContext(this.scope, this.extensions, config.tags, this, childAbort);
|
|
839
|
+
childContext.initializeExecutionContext(definition.name, false);
|
|
840
|
+
try {
|
|
841
|
+
const result = await handler(childContext, validated);
|
|
842
|
+
validate(definition.output, result);
|
|
843
|
+
journal.set(journalKey, result);
|
|
844
|
+
return result;
|
|
845
|
+
} catch (error) {
|
|
846
|
+
journal.set(journalKey, {
|
|
847
|
+
__error: true,
|
|
848
|
+
error
|
|
849
|
+
});
|
|
850
|
+
throw error;
|
|
851
|
+
} finally {
|
|
852
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
853
|
+
}
|
|
854
|
+
} else throw new Error("Flow definition not found");
|
|
855
|
+
})();
|
|
856
|
+
return Promised.create(promise$1);
|
|
857
|
+
} else return this.scope.resolve(flow$2).map(async (handler) => {
|
|
858
|
+
this.throwIfAborted();
|
|
859
|
+
const definition = flowDefinitionMeta.readFrom(flow$2);
|
|
860
|
+
if (definition) {
|
|
861
|
+
const validated = validate(definition.input, input$1);
|
|
862
|
+
const childContext = new FlowContext(this.scope, this.extensions, config.tags, this, childAbort);
|
|
863
|
+
childContext.initializeExecutionContext(definition.name, false);
|
|
864
|
+
try {
|
|
865
|
+
const result = await handler(childContext, validated);
|
|
866
|
+
validate(definition.output, result);
|
|
867
|
+
return result;
|
|
868
|
+
} finally {
|
|
869
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
870
|
+
}
|
|
871
|
+
} else throw new Error("Flow definition not found");
|
|
819
872
|
});
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
key
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
873
|
+
} else if ("fn" in config) {
|
|
874
|
+
const fn = config.fn;
|
|
875
|
+
const params = "params" in config ? config.params || [] : [];
|
|
876
|
+
if (config.key) {
|
|
877
|
+
if (!this.journal) this.journal = /* @__PURE__ */ new Map();
|
|
878
|
+
const flowName = this.find(flowMeta.flowName) || "unknown";
|
|
879
|
+
const depth = this.get(flowMeta.depth);
|
|
880
|
+
const journalKey = `${flowName}:${depth}:${config.key}`;
|
|
881
|
+
const promise$1 = (async () => {
|
|
882
|
+
const journal = this.journal;
|
|
883
|
+
const isReplay = journal.has(journalKey);
|
|
884
|
+
const executeCore = () => {
|
|
885
|
+
if (isReplay) {
|
|
886
|
+
const entry = journal.get(journalKey);
|
|
887
|
+
if (isErrorEntry(entry)) throw entry.error;
|
|
888
|
+
return Promised.create(Promise.resolve(entry));
|
|
889
|
+
}
|
|
890
|
+
return Promised.try(async () => {
|
|
891
|
+
const result = await fn(...params);
|
|
892
|
+
journal.set(journalKey, result);
|
|
893
|
+
return result;
|
|
894
|
+
}).catch((error) => {
|
|
895
|
+
journal.set(journalKey, {
|
|
896
|
+
__error: true,
|
|
897
|
+
error
|
|
898
|
+
});
|
|
899
|
+
throw error;
|
|
900
|
+
});
|
|
901
|
+
};
|
|
902
|
+
const executor = this.wrapWithExtensions(executeCore, {
|
|
903
|
+
kind: "journal",
|
|
904
|
+
key: config.key,
|
|
905
|
+
flowName,
|
|
906
|
+
depth,
|
|
907
|
+
isReplay,
|
|
908
|
+
context: this,
|
|
909
|
+
params: params.length > 0 ? params : void 0
|
|
910
|
+
});
|
|
911
|
+
try {
|
|
912
|
+
return await executor();
|
|
913
|
+
} finally {
|
|
914
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
915
|
+
}
|
|
916
|
+
})();
|
|
917
|
+
return Promised.create(promise$1);
|
|
918
|
+
} else {
|
|
919
|
+
this.throwIfAborted();
|
|
920
|
+
return Promised.try(async () => {
|
|
921
|
+
try {
|
|
922
|
+
return await fn(...params);
|
|
923
|
+
} finally {
|
|
924
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
925
|
+
}
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
} else throw new Error("Invalid config: must have either 'flow' or 'fn'");
|
|
929
|
+
}
|
|
930
|
+
const keyOrFlow = keyOrFlowOrConfig;
|
|
834
931
|
if (typeof keyOrFlow === "string") {
|
|
835
932
|
if (!this.journal) this.journal = /* @__PURE__ */ new Map();
|
|
836
933
|
const key = keyOrFlow;
|
|
@@ -999,11 +1096,29 @@ var FlowContext = class FlowContext {
|
|
|
999
1096
|
};
|
|
1000
1097
|
function execute(flow$1, input, options) {
|
|
1001
1098
|
if (options && "scope" in options) {
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1099
|
+
const execution$1 = options.scope.exec({
|
|
1100
|
+
flow: flow$1,
|
|
1101
|
+
input,
|
|
1102
|
+
tags: options.executionTags
|
|
1005
1103
|
});
|
|
1006
|
-
|
|
1104
|
+
if (options.details === true) return Promised.create(execution$1.result.then(async (r) => {
|
|
1105
|
+
const ctx = await execution$1.result.ctx();
|
|
1106
|
+
if (!ctx) throw new Error("Execution context not available");
|
|
1107
|
+
return {
|
|
1108
|
+
success: true,
|
|
1109
|
+
result: r,
|
|
1110
|
+
ctx
|
|
1111
|
+
};
|
|
1112
|
+
}).catch(async (error) => {
|
|
1113
|
+
const ctx = await execution$1.result.ctx();
|
|
1114
|
+
if (!ctx) throw new Error("Execution context not available");
|
|
1115
|
+
return {
|
|
1116
|
+
success: false,
|
|
1117
|
+
error,
|
|
1118
|
+
ctx
|
|
1119
|
+
};
|
|
1120
|
+
}));
|
|
1121
|
+
return execution$1.result;
|
|
1007
1122
|
}
|
|
1008
1123
|
const scope = options ? createScope({
|
|
1009
1124
|
initialValues: options.initialValues,
|
|
@@ -1011,15 +1126,31 @@ function execute(flow$1, input, options) {
|
|
|
1011
1126
|
extensions: options.extensions,
|
|
1012
1127
|
tags: options.scopeTags
|
|
1013
1128
|
}) : createScope();
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1129
|
+
const execution = scope.exec({
|
|
1130
|
+
flow: flow$1,
|
|
1131
|
+
input,
|
|
1132
|
+
tags: options?.executionTags
|
|
1133
|
+
});
|
|
1134
|
+
if (options?.details === true) return Promised.create(execution.result.then(async (r) => {
|
|
1135
|
+
await scope.dispose();
|
|
1136
|
+
const ctx = await execution.result.ctx();
|
|
1137
|
+
if (!ctx) throw new Error("Execution context not available");
|
|
1138
|
+
return {
|
|
1139
|
+
success: true,
|
|
1140
|
+
result: r,
|
|
1141
|
+
ctx
|
|
1142
|
+
};
|
|
1143
|
+
}).catch(async (error) => {
|
|
1144
|
+
await scope.dispose();
|
|
1145
|
+
const ctx = await execution.result.ctx();
|
|
1146
|
+
if (!ctx) throw new Error("Execution context not available");
|
|
1147
|
+
return {
|
|
1148
|
+
success: false,
|
|
1149
|
+
error,
|
|
1150
|
+
ctx
|
|
1151
|
+
};
|
|
1152
|
+
}));
|
|
1153
|
+
return Promised.create(execution.result.then((r) => scope.dispose().then(() => r)), execution.result.ctx());
|
|
1023
1154
|
}
|
|
1024
1155
|
function flowImpl(first, second, third) {
|
|
1025
1156
|
if (typeof first === "function") {
|
|
@@ -1071,6 +1202,78 @@ function flowImpl(first, second, third) {
|
|
|
1071
1202
|
}
|
|
1072
1203
|
const flow = Object.assign(flowImpl, { execute });
|
|
1073
1204
|
|
|
1205
|
+
//#endregion
|
|
1206
|
+
//#region src/flow-execution.ts
|
|
1207
|
+
var FlowExecutionImpl = class {
|
|
1208
|
+
result;
|
|
1209
|
+
id;
|
|
1210
|
+
flowName;
|
|
1211
|
+
abort;
|
|
1212
|
+
_status = "pending";
|
|
1213
|
+
statusCallbacks = /* @__PURE__ */ new Set();
|
|
1214
|
+
callbackErrors = [];
|
|
1215
|
+
_ctx;
|
|
1216
|
+
statusTracking;
|
|
1217
|
+
statusTrackingActive = false;
|
|
1218
|
+
constructor(config) {
|
|
1219
|
+
this.id = config.id;
|
|
1220
|
+
this.flowName = config.flowName;
|
|
1221
|
+
this.abort = config.abort;
|
|
1222
|
+
this._ctx = config.ctx;
|
|
1223
|
+
this.result = config.result;
|
|
1224
|
+
this.statusTracking = config.statusTracking ?? null;
|
|
1225
|
+
}
|
|
1226
|
+
get status() {
|
|
1227
|
+
this["~ensureStatusTracking"]();
|
|
1228
|
+
return this._status;
|
|
1229
|
+
}
|
|
1230
|
+
get ctx() {
|
|
1231
|
+
return this._ctx ?? void 0;
|
|
1232
|
+
}
|
|
1233
|
+
get statusCallbackErrors() {
|
|
1234
|
+
return this.callbackErrors;
|
|
1235
|
+
}
|
|
1236
|
+
"~setStatus"(newStatus) {
|
|
1237
|
+
if (this._status === newStatus) return;
|
|
1238
|
+
this._status = newStatus;
|
|
1239
|
+
for (const callback of this.statusCallbacks) Promise.resolve(callback(newStatus, this)).catch((err) => {
|
|
1240
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1241
|
+
this.callbackErrors.push(error);
|
|
1242
|
+
console.error("Error in status change callback:", err);
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
"~setCtx"(ctx) {
|
|
1246
|
+
this._ctx = ctx;
|
|
1247
|
+
}
|
|
1248
|
+
"~ensureStatusTracking"() {
|
|
1249
|
+
if (this.statusTrackingActive || !this.statusTracking) return;
|
|
1250
|
+
this.statusTrackingActive = true;
|
|
1251
|
+
const { promise, timeoutId, abortController } = this.statusTracking;
|
|
1252
|
+
promise.then(async () => {
|
|
1253
|
+
const ctx = await promise.ctx().catch(() => void 0);
|
|
1254
|
+
if (ctx) this["~setCtx"](ctx);
|
|
1255
|
+
this["~setStatus"]("completed");
|
|
1256
|
+
}).catch(async () => {
|
|
1257
|
+
const ctx = await promise.ctx().catch(() => void 0);
|
|
1258
|
+
if (ctx) this["~setCtx"](ctx);
|
|
1259
|
+
if (abortController.signal.aborted) this["~setStatus"]("cancelled");
|
|
1260
|
+
else this["~setStatus"]("failed");
|
|
1261
|
+
}).finally(() => {
|
|
1262
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
onStatusChange(callback) {
|
|
1266
|
+
this["~ensureStatusTracking"]();
|
|
1267
|
+
this.statusCallbacks.add(callback);
|
|
1268
|
+
return () => {
|
|
1269
|
+
this.statusCallbacks.delete(callback);
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
then(onfulfilled, onrejected) {
|
|
1273
|
+
return this.result.then(onfulfilled, onrejected);
|
|
1274
|
+
}
|
|
1275
|
+
};
|
|
1276
|
+
|
|
1074
1277
|
//#endregion
|
|
1075
1278
|
//#region src/scope.ts
|
|
1076
1279
|
var AccessorImpl = class {
|
|
@@ -1279,6 +1482,7 @@ function getExecutor(e) {
|
|
|
1279
1482
|
var BaseScope = class {
|
|
1280
1483
|
disposed = false;
|
|
1281
1484
|
cache = /* @__PURE__ */ new Map();
|
|
1485
|
+
executions = /* @__PURE__ */ new Map();
|
|
1282
1486
|
onEvents = {
|
|
1283
1487
|
change: /* @__PURE__ */ new Set(),
|
|
1284
1488
|
release: /* @__PURE__ */ new Set(),
|
|
@@ -1570,6 +1774,7 @@ var BaseScope = class {
|
|
|
1570
1774
|
this.onEvents.change.clear();
|
|
1571
1775
|
this.onEvents.release.clear();
|
|
1572
1776
|
this.onEvents.error.clear();
|
|
1777
|
+
this.executions.clear();
|
|
1573
1778
|
})());
|
|
1574
1779
|
}
|
|
1575
1780
|
onUpdate(e, cb) {
|
|
@@ -1647,37 +1852,56 @@ var BaseScope = class {
|
|
|
1647
1852
|
use(extension$1) {
|
|
1648
1853
|
return this.useExtension(extension$1);
|
|
1649
1854
|
}
|
|
1650
|
-
exec(
|
|
1855
|
+
exec(config) {
|
|
1651
1856
|
this["~ensureNotDisposed"]();
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
}));
|
|
1857
|
+
const executionId = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : `exec-${Date.now()}-${Math.random()}`;
|
|
1858
|
+
const abortController = new AbortController();
|
|
1859
|
+
let timeoutId;
|
|
1860
|
+
if (config.timeout) timeoutId = setTimeout(() => {
|
|
1861
|
+
if (!abortController.signal.aborted) abortController.abort(/* @__PURE__ */ new Error(`Flow execution timeout after ${config.timeout}ms`));
|
|
1862
|
+
}, config.timeout);
|
|
1863
|
+
let flowPromise;
|
|
1864
|
+
let flowName;
|
|
1865
|
+
if ("flow" in config) {
|
|
1866
|
+
flowPromise = this["~executeFlow"](config.flow, config.input, config.tags, abortController);
|
|
1867
|
+
flowName = flowDefinitionMeta.readFrom(config.flow)?.name;
|
|
1868
|
+
} else {
|
|
1869
|
+
flowPromise = Promised.create((async () => {
|
|
1870
|
+
const deps = await this["~resolveDependencies"](config.dependencies, { [executorSymbol]: "main" });
|
|
1871
|
+
if ("input" in config) return config.fn(deps, config.input);
|
|
1872
|
+
else return config.fn(deps);
|
|
1873
|
+
})());
|
|
1874
|
+
flowName = void 0;
|
|
1671
1875
|
}
|
|
1672
|
-
|
|
1876
|
+
const execution = new FlowExecutionImpl({
|
|
1877
|
+
id: executionId,
|
|
1878
|
+
flowName,
|
|
1879
|
+
abort: abortController,
|
|
1880
|
+
result: flowPromise,
|
|
1881
|
+
ctx: null,
|
|
1882
|
+
statusTracking: {
|
|
1883
|
+
promise: flowPromise,
|
|
1884
|
+
timeoutId: timeoutId ?? null,
|
|
1885
|
+
abortController
|
|
1886
|
+
}
|
|
1887
|
+
});
|
|
1888
|
+
this.executions.set(executionId, {
|
|
1889
|
+
execution,
|
|
1890
|
+
startTime: Date.now()
|
|
1891
|
+
});
|
|
1892
|
+
flowPromise.finally(() => {
|
|
1893
|
+
this.executions.delete(executionId);
|
|
1894
|
+
});
|
|
1895
|
+
execution["~setStatus"]("running");
|
|
1896
|
+
return execution;
|
|
1673
1897
|
}
|
|
1674
|
-
"~executeFlow"(flow$1, input, executionTags) {
|
|
1898
|
+
"~executeFlow"(flow$1, input, executionTags, abortController) {
|
|
1675
1899
|
let resolveSnapshot;
|
|
1676
1900
|
const snapshotPromise = new Promise((resolve) => {
|
|
1677
1901
|
resolveSnapshot = resolve;
|
|
1678
1902
|
});
|
|
1679
1903
|
const promise = (async () => {
|
|
1680
|
-
const context = new FlowContext(this, this.extensions, executionTags);
|
|
1904
|
+
const context = new FlowContext(this, this.extensions, executionTags, void 0, abortController);
|
|
1681
1905
|
try {
|
|
1682
1906
|
const executeCore = () => {
|
|
1683
1907
|
return this.resolve(flow$1).map(async (handler) => {
|
package/dist/index.d.cts
CHANGED
|
@@ -229,14 +229,25 @@ declare namespace Core {
|
|
|
229
229
|
onError<T>(executor: Executor<T>, callback: ErrorCallback<T>): Cleanup;
|
|
230
230
|
onError(callback: GlobalErrorCallback): Cleanup;
|
|
231
231
|
useExtension(extension: Extension.Extension): Cleanup;
|
|
232
|
-
exec<S, I
|
|
232
|
+
exec<S, I>(config: {
|
|
233
|
+
flow: Executor<Flow.Handler<S, I>>;
|
|
234
|
+
input?: I;
|
|
235
|
+
timeout?: number;
|
|
233
236
|
tags?: Tag.Tagged[];
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
+
}): Flow.FlowExecution<S>;
|
|
238
|
+
exec<S, D extends DependencyLike>(config: {
|
|
239
|
+
dependencies: D;
|
|
240
|
+
fn: (deps: InferOutput<D>) => S | Promise<S>;
|
|
241
|
+
timeout?: number;
|
|
237
242
|
tags?: Tag.Tagged[];
|
|
238
|
-
|
|
239
|
-
|
|
243
|
+
}): Flow.FlowExecution<S>;
|
|
244
|
+
exec<S, I, D extends DependencyLike>(config: {
|
|
245
|
+
dependencies: D;
|
|
246
|
+
fn: (deps: InferOutput<D>, input: I) => S | Promise<S>;
|
|
247
|
+
input: I;
|
|
248
|
+
timeout?: number;
|
|
249
|
+
tags?: Tag.Tagged[];
|
|
250
|
+
}): Flow.FlowExecution<S>;
|
|
240
251
|
}
|
|
241
252
|
}
|
|
242
253
|
declare class FlowError extends Error {
|
|
@@ -306,14 +317,38 @@ declare namespace Flow {
|
|
|
306
317
|
type C = {
|
|
307
318
|
readonly scope: Core.Scope;
|
|
308
319
|
readonly tags: Tag.Tagged[] | undefined;
|
|
320
|
+
readonly signal: AbortSignal;
|
|
321
|
+
throwIfAborted(): void;
|
|
309
322
|
get<T>(accessor: Tag.Tag<T, false> | Tag.Tag<T, true>): T;
|
|
310
323
|
find<T>(accessor: Tag.Tag<T, false>): T | undefined;
|
|
311
324
|
find<T>(accessor: Tag.Tag<T, true>): T;
|
|
312
325
|
set<T>(accessor: Tag.Tag<T, false> | Tag.Tag<T, true>, value: T): void;
|
|
313
|
-
run<T>(key: string, fn: () => Promised<T> | T): Promised<T>;
|
|
314
|
-
run<T, P extends readonly unknown[]>(key: string, fn: (...args: P) => Promised<T> | T, ...params: P): Promised<T>;
|
|
315
326
|
exec<F extends UFlow>(flow: F, input: InferInput<F>): Promised<InferOutput<F>>;
|
|
316
327
|
exec<F extends UFlow>(key: string, flow: F, input: InferInput<F>): Promised<InferOutput<F>>;
|
|
328
|
+
exec<F extends UFlow>(config: {
|
|
329
|
+
flow: F;
|
|
330
|
+
input: InferInput<F>;
|
|
331
|
+
key?: string;
|
|
332
|
+
timeout?: number;
|
|
333
|
+
retry?: number;
|
|
334
|
+
tags?: Tag.Tagged[];
|
|
335
|
+
}): Promised<InferOutput<F>>;
|
|
336
|
+
exec<T>(config: {
|
|
337
|
+
fn: () => T | Promise<T>;
|
|
338
|
+
params?: never;
|
|
339
|
+
key?: string;
|
|
340
|
+
timeout?: number;
|
|
341
|
+
retry?: number;
|
|
342
|
+
tags?: Tag.Tagged[];
|
|
343
|
+
}): Promised<T>;
|
|
344
|
+
exec<Fn extends (...args: any[]) => any>(config: {
|
|
345
|
+
fn: Fn;
|
|
346
|
+
params: Parameters<Fn>;
|
|
347
|
+
key?: string;
|
|
348
|
+
timeout?: number;
|
|
349
|
+
retry?: number;
|
|
350
|
+
tags?: Tag.Tagged[];
|
|
351
|
+
}): Promised<ReturnType<Fn>>;
|
|
317
352
|
parallel<T extends readonly Promised<any>[]>(promises: [...T]): Promised<ParallelResult<{ [K in keyof T]: T[K] extends Promised<infer R> ? R : never }>>;
|
|
318
353
|
parallelSettled<T extends readonly Promised<any>[]>(promises: [...T]): Promised<ParallelSettledResult<{ [K in keyof T]: T[K] extends Promised<infer R> ? R : never }>>;
|
|
319
354
|
};
|
|
@@ -334,6 +369,18 @@ declare namespace Flow {
|
|
|
334
369
|
error: unknown;
|
|
335
370
|
ctx: ExecutionData;
|
|
336
371
|
};
|
|
372
|
+
type ExecutionStatus = "pending" | "running" | "completed" | "failed" | "cancelled";
|
|
373
|
+
interface FlowExecution<T> {
|
|
374
|
+
readonly result: Promised<T>;
|
|
375
|
+
readonly id: string;
|
|
376
|
+
readonly flowName: string | undefined;
|
|
377
|
+
readonly status: ExecutionStatus;
|
|
378
|
+
readonly ctx: ExecutionData | undefined;
|
|
379
|
+
readonly abort: AbortController;
|
|
380
|
+
readonly statusCallbackErrors: readonly Error[];
|
|
381
|
+
onStatusChange(callback: (status: ExecutionStatus, execution: FlowExecution<T>) => void | Promise<void>): Core.Cleanup;
|
|
382
|
+
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null | undefined): PromiseLike<TResult1 | TResult2>;
|
|
383
|
+
}
|
|
337
384
|
}
|
|
338
385
|
declare namespace Extension {
|
|
339
386
|
type Operation = {
|