@objectstack/service-automation 7.9.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.js
CHANGED
|
@@ -145,7 +145,7 @@ var AutomationEngine = class {
|
|
|
145
145
|
description: `Deprecated alias of '${canonicalType}' (ADR-0018 M3). Author new flows with '${canonicalType}'.`,
|
|
146
146
|
category: meta?.category ?? "io",
|
|
147
147
|
source: "builtin",
|
|
148
|
-
paradigms: meta?.paradigms ?? ["flow", "
|
|
148
|
+
paradigms: meta?.paradigms ?? ["flow", "approval"],
|
|
149
149
|
supportsRetry: true,
|
|
150
150
|
needsOutbox: meta?.needsOutbox ?? false,
|
|
151
151
|
deprecated: true,
|
|
@@ -987,6 +987,9 @@ ${failures.join("\n")}`
|
|
|
987
987
|
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
988
988
|
durationMs: Date.now() - stepStart
|
|
989
989
|
});
|
|
990
|
+
if (result.childSteps?.length) {
|
|
991
|
+
steps.push(...result.childSteps);
|
|
992
|
+
}
|
|
990
993
|
if (result.output) {
|
|
991
994
|
for (const [key, value] of Object.entries(result.output)) {
|
|
992
995
|
variables.set(`${node.id}.${key}`, value);
|
|
@@ -1051,14 +1054,19 @@ ${failures.join("\n")}`
|
|
|
1051
1054
|
* nodes/edges, so the main DAG traversal (`traverseNext`) is never aware of
|
|
1052
1055
|
* scope markers — keeping the shared traversal untouched.
|
|
1053
1056
|
*
|
|
1054
|
-
*
|
|
1055
|
-
*
|
|
1057
|
+
* #1479: the executed body steps are **returned** (tagged with `grouping`)
|
|
1058
|
+
* so the calling container node can fold them into the parent run log via
|
|
1059
|
+
* `NodeExecutionResult.childSteps`. Tagging only fills fields left undefined,
|
|
1060
|
+
* so when regions nest, each step keeps its **innermost** container's
|
|
1061
|
+
* `parentNodeId` / `iteration` / `regionKind`. On failure the region throws
|
|
1062
|
+
* as before (preserving `try_catch` retry semantics); a failed attempt's
|
|
1063
|
+
* partial steps are not surfaced.
|
|
1056
1064
|
*
|
|
1057
1065
|
* Durable pause (`suspend`) inside a region is not supported in this
|
|
1058
1066
|
* iteration — it is converted into a clear error (mirrors the `subflow`
|
|
1059
1067
|
* nested-pause guard).
|
|
1060
1068
|
*/
|
|
1061
|
-
async runRegion(region, variables, context) {
|
|
1069
|
+
async runRegion(region, variables, context, grouping) {
|
|
1062
1070
|
const entryId = findRegionEntry(region);
|
|
1063
1071
|
const entry = region.nodes.find((n) => n.id === entryId);
|
|
1064
1072
|
if (!entry) {
|
|
@@ -1076,6 +1084,16 @@ ${failures.join("\n")}`
|
|
|
1076
1084
|
}
|
|
1077
1085
|
throw err;
|
|
1078
1086
|
}
|
|
1087
|
+
if (grouping) {
|
|
1088
|
+
for (const step of regionSteps) {
|
|
1089
|
+
if (step.parentNodeId === void 0) {
|
|
1090
|
+
step.parentNodeId = grouping.parentNodeId;
|
|
1091
|
+
if (grouping.iteration !== void 0) step.iteration = grouping.iteration;
|
|
1092
|
+
if (grouping.regionKind !== void 0) step.regionKind = grouping.regionKind;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
return regionSteps;
|
|
1079
1097
|
}
|
|
1080
1098
|
/**
|
|
1081
1099
|
* Execute a promise with timeout using Promise.race.
|
|
@@ -1760,13 +1778,19 @@ function registerLoopNode(engine, ctx) {
|
|
|
1760
1778
|
};
|
|
1761
1779
|
}
|
|
1762
1780
|
let iterations = 0;
|
|
1781
|
+
const childSteps = [];
|
|
1763
1782
|
for (let i = 0; i < collection.length; i++) {
|
|
1764
1783
|
variables.set(iteratorVariable, collection[i]);
|
|
1765
1784
|
if (indexVariable) variables.set(indexVariable, i);
|
|
1766
|
-
await engine.runRegion(body, variables, context ?? {}
|
|
1785
|
+
const iterSteps = await engine.runRegion(body, variables, context ?? {}, {
|
|
1786
|
+
parentNodeId: node.id,
|
|
1787
|
+
iteration: i,
|
|
1788
|
+
regionKind: "loop-body"
|
|
1789
|
+
});
|
|
1790
|
+
childSteps.push(...iterSteps);
|
|
1767
1791
|
iterations++;
|
|
1768
1792
|
}
|
|
1769
|
-
return { success: true, output: { iterations } };
|
|
1793
|
+
return { success: true, output: { iterations }, childSteps };
|
|
1770
1794
|
}
|
|
1771
1795
|
});
|
|
1772
1796
|
ctx.logger.info("[Loop Node] 1 built-in node executor registered");
|
|
@@ -1814,15 +1838,22 @@ function registerParallelNode(engine, ctx) {
|
|
|
1814
1838
|
error: `parallel '${node.id}': config.branches must declare at least 2 branch regions`
|
|
1815
1839
|
};
|
|
1816
1840
|
}
|
|
1841
|
+
let branchSteps;
|
|
1817
1842
|
try {
|
|
1818
|
-
await Promise.all(
|
|
1819
|
-
branches.map(
|
|
1843
|
+
branchSteps = await Promise.all(
|
|
1844
|
+
branches.map(
|
|
1845
|
+
(branch, i) => engine.runRegion(branch, variables, context ?? {}, {
|
|
1846
|
+
parentNodeId: node.id,
|
|
1847
|
+
iteration: i,
|
|
1848
|
+
regionKind: "parallel-branch"
|
|
1849
|
+
})
|
|
1850
|
+
)
|
|
1820
1851
|
);
|
|
1821
1852
|
} catch (err) {
|
|
1822
1853
|
const message = err instanceof Error ? err.message : String(err);
|
|
1823
1854
|
return { success: false, error: `parallel '${node.id}': branch failed \u2014 ${message}` };
|
|
1824
1855
|
}
|
|
1825
|
-
return { success: true, output: { branches: branches.length } };
|
|
1856
|
+
return { success: true, output: { branches: branches.length }, childSteps: branchSteps.flat() };
|
|
1826
1857
|
}
|
|
1827
1858
|
});
|
|
1828
1859
|
ctx.logger.info("[Parallel Node] 1 built-in node executor registered");
|
|
@@ -1893,8 +1924,11 @@ function registerTryCatchNode(engine, ctx) {
|
|
|
1893
1924
|
if (delay > 0) await new Promise((r) => setTimeout(r, delay));
|
|
1894
1925
|
}
|
|
1895
1926
|
try {
|
|
1896
|
-
await engine.runRegion(tryRegion, variables, ctxOrEmpty
|
|
1897
|
-
|
|
1927
|
+
const trySteps = await engine.runRegion(tryRegion, variables, ctxOrEmpty, {
|
|
1928
|
+
parentNodeId: node.id,
|
|
1929
|
+
regionKind: "try"
|
|
1930
|
+
});
|
|
1931
|
+
return { success: true, output: { attempts: attempt + 1, caught: false }, childSteps: trySteps };
|
|
1898
1932
|
} catch (err) {
|
|
1899
1933
|
lastError = err instanceof Error ? err.message : String(err);
|
|
1900
1934
|
}
|
|
@@ -1902,8 +1936,15 @@ function registerTryCatchNode(engine, ctx) {
|
|
|
1902
1936
|
if (catchRegion != null) {
|
|
1903
1937
|
variables.set(errorVariable, { nodeId: node.id, message: lastError });
|
|
1904
1938
|
try {
|
|
1905
|
-
await engine.runRegion(catchRegion, variables, ctxOrEmpty
|
|
1906
|
-
|
|
1939
|
+
const catchSteps = await engine.runRegion(catchRegion, variables, ctxOrEmpty, {
|
|
1940
|
+
parentNodeId: node.id,
|
|
1941
|
+
regionKind: "catch"
|
|
1942
|
+
});
|
|
1943
|
+
return {
|
|
1944
|
+
success: true,
|
|
1945
|
+
output: { attempts: maxRetries + 1, caught: true, error: lastError },
|
|
1946
|
+
childSteps: catchSteps
|
|
1947
|
+
};
|
|
1907
1948
|
} catch (catchErr) {
|
|
1908
1949
|
const catchMsg = catchErr instanceof Error ? catchErr.message : String(catchErr);
|
|
1909
1950
|
return { success: false, error: `try_catch '${node.id}': catch region failed \u2014 ${catchMsg}` };
|
|
@@ -2161,7 +2202,7 @@ function registerHttpNodes(engine, ctx) {
|
|
|
2161
2202
|
// and the messaging HTTP outbox is wired).
|
|
2162
2203
|
needsOutbox: true,
|
|
2163
2204
|
supportsRetry: true,
|
|
2164
|
-
paradigms: ["flow", "
|
|
2205
|
+
paradigms: ["flow", "approval"],
|
|
2165
2206
|
configSchema: {
|
|
2166
2207
|
type: "object",
|
|
2167
2208
|
required: ["url"],
|
|
@@ -2271,8 +2312,9 @@ function registerConnectorNodes(engine, ctx) {
|
|
|
2271
2312
|
category: "io",
|
|
2272
2313
|
source: "builtin",
|
|
2273
2314
|
supportsRetry: true,
|
|
2274
|
-
// Present in
|
|
2275
|
-
|
|
2315
|
+
// Present in both authoring paradigms (ADR-0018 §registry table;
|
|
2316
|
+
// workflow_rule retired per ADR-0019).
|
|
2317
|
+
paradigms: ["flow", "approval"],
|
|
2276
2318
|
// Config contract — drives the Studio property form and flow validation.
|
|
2277
2319
|
configSchema: {
|
|
2278
2320
|
type: "object",
|
|
@@ -2347,7 +2389,7 @@ function registerNotifyNode(engine, ctx) {
|
|
|
2347
2389
|
// Delivery is outbox-backed inside the messaging service (ADR-0030
|
|
2348
2390
|
// emit → sys_notification_delivery), so it inherits retry/dead-letter.
|
|
2349
2391
|
needsOutbox: true,
|
|
2350
|
-
paradigms: ["flow", "
|
|
2392
|
+
paradigms: ["flow", "approval"]
|
|
2351
2393
|
}),
|
|
2352
2394
|
async execute(node, variables, context) {
|
|
2353
2395
|
const cfg = node.config ?? {};
|