@objectstack/service-automation 7.8.0 → 8.0.0
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/dist/index.cjs +59 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +667 -8
- package/dist/index.d.ts +667 -8
- package/dist/index.js +59 -17
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -181,7 +181,7 @@ var AutomationEngine = class {
|
|
|
181
181
|
description: `Deprecated alias of '${canonicalType}' (ADR-0018 M3). Author new flows with '${canonicalType}'.`,
|
|
182
182
|
category: meta?.category ?? "io",
|
|
183
183
|
source: "builtin",
|
|
184
|
-
paradigms: meta?.paradigms ?? ["flow", "
|
|
184
|
+
paradigms: meta?.paradigms ?? ["flow", "approval"],
|
|
185
185
|
supportsRetry: true,
|
|
186
186
|
needsOutbox: meta?.needsOutbox ?? false,
|
|
187
187
|
deprecated: true,
|
|
@@ -1023,6 +1023,9 @@ ${failures.join("\n")}`
|
|
|
1023
1023
|
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1024
1024
|
durationMs: Date.now() - stepStart
|
|
1025
1025
|
});
|
|
1026
|
+
if (result.childSteps?.length) {
|
|
1027
|
+
steps.push(...result.childSteps);
|
|
1028
|
+
}
|
|
1026
1029
|
if (result.output) {
|
|
1027
1030
|
for (const [key, value] of Object.entries(result.output)) {
|
|
1028
1031
|
variables.set(`${node.id}.${key}`, value);
|
|
@@ -1087,14 +1090,19 @@ ${failures.join("\n")}`
|
|
|
1087
1090
|
* nodes/edges, so the main DAG traversal (`traverseNext`) is never aware of
|
|
1088
1091
|
* scope markers — keeping the shared traversal untouched.
|
|
1089
1092
|
*
|
|
1090
|
-
*
|
|
1091
|
-
*
|
|
1093
|
+
* #1479: the executed body steps are **returned** (tagged with `grouping`)
|
|
1094
|
+
* so the calling container node can fold them into the parent run log via
|
|
1095
|
+
* `NodeExecutionResult.childSteps`. Tagging only fills fields left undefined,
|
|
1096
|
+
* so when regions nest, each step keeps its **innermost** container's
|
|
1097
|
+
* `parentNodeId` / `iteration` / `regionKind`. On failure the region throws
|
|
1098
|
+
* as before (preserving `try_catch` retry semantics); a failed attempt's
|
|
1099
|
+
* partial steps are not surfaced.
|
|
1092
1100
|
*
|
|
1093
1101
|
* Durable pause (`suspend`) inside a region is not supported in this
|
|
1094
1102
|
* iteration — it is converted into a clear error (mirrors the `subflow`
|
|
1095
1103
|
* nested-pause guard).
|
|
1096
1104
|
*/
|
|
1097
|
-
async runRegion(region, variables, context) {
|
|
1105
|
+
async runRegion(region, variables, context, grouping) {
|
|
1098
1106
|
const entryId = (0, import_automation.findRegionEntry)(region);
|
|
1099
1107
|
const entry = region.nodes.find((n) => n.id === entryId);
|
|
1100
1108
|
if (!entry) {
|
|
@@ -1112,6 +1120,16 @@ ${failures.join("\n")}`
|
|
|
1112
1120
|
}
|
|
1113
1121
|
throw err;
|
|
1114
1122
|
}
|
|
1123
|
+
if (grouping) {
|
|
1124
|
+
for (const step of regionSteps) {
|
|
1125
|
+
if (step.parentNodeId === void 0) {
|
|
1126
|
+
step.parentNodeId = grouping.parentNodeId;
|
|
1127
|
+
if (grouping.iteration !== void 0) step.iteration = grouping.iteration;
|
|
1128
|
+
if (grouping.regionKind !== void 0) step.regionKind = grouping.regionKind;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
return regionSteps;
|
|
1115
1133
|
}
|
|
1116
1134
|
/**
|
|
1117
1135
|
* Execute a promise with timeout using Promise.race.
|
|
@@ -1796,13 +1814,19 @@ function registerLoopNode(engine, ctx) {
|
|
|
1796
1814
|
};
|
|
1797
1815
|
}
|
|
1798
1816
|
let iterations = 0;
|
|
1817
|
+
const childSteps = [];
|
|
1799
1818
|
for (let i = 0; i < collection.length; i++) {
|
|
1800
1819
|
variables.set(iteratorVariable, collection[i]);
|
|
1801
1820
|
if (indexVariable) variables.set(indexVariable, i);
|
|
1802
|
-
await engine.runRegion(body, variables, context ?? {}
|
|
1821
|
+
const iterSteps = await engine.runRegion(body, variables, context ?? {}, {
|
|
1822
|
+
parentNodeId: node.id,
|
|
1823
|
+
iteration: i,
|
|
1824
|
+
regionKind: "loop-body"
|
|
1825
|
+
});
|
|
1826
|
+
childSteps.push(...iterSteps);
|
|
1803
1827
|
iterations++;
|
|
1804
1828
|
}
|
|
1805
|
-
return { success: true, output: { iterations } };
|
|
1829
|
+
return { success: true, output: { iterations }, childSteps };
|
|
1806
1830
|
}
|
|
1807
1831
|
});
|
|
1808
1832
|
ctx.logger.info("[Loop Node] 1 built-in node executor registered");
|
|
@@ -1850,15 +1874,22 @@ function registerParallelNode(engine, ctx) {
|
|
|
1850
1874
|
error: `parallel '${node.id}': config.branches must declare at least 2 branch regions`
|
|
1851
1875
|
};
|
|
1852
1876
|
}
|
|
1877
|
+
let branchSteps;
|
|
1853
1878
|
try {
|
|
1854
|
-
await Promise.all(
|
|
1855
|
-
branches.map(
|
|
1879
|
+
branchSteps = await Promise.all(
|
|
1880
|
+
branches.map(
|
|
1881
|
+
(branch, i) => engine.runRegion(branch, variables, context ?? {}, {
|
|
1882
|
+
parentNodeId: node.id,
|
|
1883
|
+
iteration: i,
|
|
1884
|
+
regionKind: "parallel-branch"
|
|
1885
|
+
})
|
|
1886
|
+
)
|
|
1856
1887
|
);
|
|
1857
1888
|
} catch (err) {
|
|
1858
1889
|
const message = err instanceof Error ? err.message : String(err);
|
|
1859
1890
|
return { success: false, error: `parallel '${node.id}': branch failed \u2014 ${message}` };
|
|
1860
1891
|
}
|
|
1861
|
-
return { success: true, output: { branches: branches.length } };
|
|
1892
|
+
return { success: true, output: { branches: branches.length }, childSteps: branchSteps.flat() };
|
|
1862
1893
|
}
|
|
1863
1894
|
});
|
|
1864
1895
|
ctx.logger.info("[Parallel Node] 1 built-in node executor registered");
|
|
@@ -1929,8 +1960,11 @@ function registerTryCatchNode(engine, ctx) {
|
|
|
1929
1960
|
if (delay > 0) await new Promise((r) => setTimeout(r, delay));
|
|
1930
1961
|
}
|
|
1931
1962
|
try {
|
|
1932
|
-
await engine.runRegion(tryRegion, variables, ctxOrEmpty
|
|
1933
|
-
|
|
1963
|
+
const trySteps = await engine.runRegion(tryRegion, variables, ctxOrEmpty, {
|
|
1964
|
+
parentNodeId: node.id,
|
|
1965
|
+
regionKind: "try"
|
|
1966
|
+
});
|
|
1967
|
+
return { success: true, output: { attempts: attempt + 1, caught: false }, childSteps: trySteps };
|
|
1934
1968
|
} catch (err) {
|
|
1935
1969
|
lastError = err instanceof Error ? err.message : String(err);
|
|
1936
1970
|
}
|
|
@@ -1938,8 +1972,15 @@ function registerTryCatchNode(engine, ctx) {
|
|
|
1938
1972
|
if (catchRegion != null) {
|
|
1939
1973
|
variables.set(errorVariable, { nodeId: node.id, message: lastError });
|
|
1940
1974
|
try {
|
|
1941
|
-
await engine.runRegion(catchRegion, variables, ctxOrEmpty
|
|
1942
|
-
|
|
1975
|
+
const catchSteps = await engine.runRegion(catchRegion, variables, ctxOrEmpty, {
|
|
1976
|
+
parentNodeId: node.id,
|
|
1977
|
+
regionKind: "catch"
|
|
1978
|
+
});
|
|
1979
|
+
return {
|
|
1980
|
+
success: true,
|
|
1981
|
+
output: { attempts: maxRetries + 1, caught: true, error: lastError },
|
|
1982
|
+
childSteps: catchSteps
|
|
1983
|
+
};
|
|
1943
1984
|
} catch (catchErr) {
|
|
1944
1985
|
const catchMsg = catchErr instanceof Error ? catchErr.message : String(catchErr);
|
|
1945
1986
|
return { success: false, error: `try_catch '${node.id}': catch region failed \u2014 ${catchMsg}` };
|
|
@@ -2197,7 +2238,7 @@ function registerHttpNodes(engine, ctx) {
|
|
|
2197
2238
|
// and the messaging HTTP outbox is wired).
|
|
2198
2239
|
needsOutbox: true,
|
|
2199
2240
|
supportsRetry: true,
|
|
2200
|
-
paradigms: ["flow", "
|
|
2241
|
+
paradigms: ["flow", "approval"],
|
|
2201
2242
|
configSchema: {
|
|
2202
2243
|
type: "object",
|
|
2203
2244
|
required: ["url"],
|
|
@@ -2307,8 +2348,9 @@ function registerConnectorNodes(engine, ctx) {
|
|
|
2307
2348
|
category: "io",
|
|
2308
2349
|
source: "builtin",
|
|
2309
2350
|
supportsRetry: true,
|
|
2310
|
-
// Present in
|
|
2311
|
-
|
|
2351
|
+
// Present in both authoring paradigms (ADR-0018 §registry table;
|
|
2352
|
+
// workflow_rule retired per ADR-0019).
|
|
2353
|
+
paradigms: ["flow", "approval"],
|
|
2312
2354
|
// Config contract — drives the Studio property form and flow validation.
|
|
2313
2355
|
configSchema: {
|
|
2314
2356
|
type: "object",
|
|
@@ -2383,7 +2425,7 @@ function registerNotifyNode(engine, ctx) {
|
|
|
2383
2425
|
// Delivery is outbox-backed inside the messaging service (ADR-0030
|
|
2384
2426
|
// emit → sys_notification_delivery), so it inherits retry/dead-letter.
|
|
2385
2427
|
needsOutbox: true,
|
|
2386
|
-
paradigms: ["flow", "
|
|
2428
|
+
paradigms: ["flow", "approval"]
|
|
2387
2429
|
}),
|
|
2388
2430
|
async execute(node, variables, context) {
|
|
2389
2431
|
const cfg = node.config ?? {};
|