@fluidgrids/workflows 0.0.0-stage → 2026.1027.1
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/LICENSE +9 -0
- package/README.md +208 -2
- package/dist/assemble-CrpUyd_3.d.ts +587 -0
- package/dist/assemble-DEf3znGD.d.cts +587 -0
- package/dist/chunk-3M34AUIY.cjs +27 -0
- package/dist/chunk-5AW745OG.js +25 -0
- package/dist/chunk-5LUIDMF4.js +42 -0
- package/dist/chunk-6AIAC2FP.cjs +185 -0
- package/dist/chunk-6BEW4QD6.js +95 -0
- package/dist/chunk-6U446SKY.js +263 -0
- package/dist/chunk-7YR7DI7B.cjs +274 -0
- package/dist/chunk-CSYBNN3V.cjs +252 -0
- package/dist/chunk-E3APHA6O.cjs +199 -0
- package/dist/chunk-EEAIM35V.js +748 -0
- package/dist/chunk-G4UEPUGO.cjs +46 -0
- package/dist/chunk-IHKXLG6I.js +246 -0
- package/dist/chunk-MBBKGD7K.js +440 -0
- package/dist/chunk-OSPTJCDI.cjs +102 -0
- package/dist/chunk-TQF7MYEN.cjs +771 -0
- package/dist/chunk-TWOYB4Y7.cjs +76 -0
- package/dist/chunk-UB2BHU2M.js +174 -0
- package/dist/chunk-UJNHTS6D.js +181 -0
- package/dist/chunk-UWQWD7BP.cjs +931 -0
- package/dist/chunk-W32BSO3M.js +74 -0
- package/dist/chunk-XBIID5DY.js +893 -0
- package/dist/chunk-Y7NWR3WH.cjs +450 -0
- package/dist/codegen/index.cjs +18 -0
- package/dist/codegen/index.d.cts +15 -0
- package/dist/codegen/index.d.ts +15 -0
- package/dist/codegen/index.js +5 -0
- package/dist/expressions-DhHaqyar.d.cts +62 -0
- package/dist/expressions-DhHaqyar.d.ts +62 -0
- package/dist/hash-CZkTXPCX.d.cts +15 -0
- package/dist/hash-CZkTXPCX.d.ts +15 -0
- package/dist/index.cjs +117 -0
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +4 -0
- package/dist/ir/index.cjs +1246 -0
- package/dist/ir/index.d.cts +838 -0
- package/dist/ir/index.d.ts +838 -0
- package/dist/ir/index.js +1122 -0
- package/dist/lower-CXggJTIo.d.ts +67 -0
- package/dist/lower-DAzvsJCo.d.cts +67 -0
- package/dist/manifest-Bp9ZJlav.d.ts +60 -0
- package/dist/manifest-Duf-gHdO.d.cts +60 -0
- package/dist/node-evaluator-CH3XCJND.cjs +17 -0
- package/dist/node-evaluator-TULXA3WE.js +8 -0
- package/dist/quickjs/index.cjs +46 -0
- package/dist/quickjs/index.d.cts +18 -0
- package/dist/quickjs/index.d.ts +18 -0
- package/dist/quickjs/index.js +44 -0
- package/dist/roundtrip/index.cjs +1448 -0
- package/dist/roundtrip/index.d.cts +290 -0
- package/dist/roundtrip/index.d.ts +290 -0
- package/dist/roundtrip/index.js +1397 -0
- package/dist/types-Dr2Fn1Ax.d.cts +225 -0
- package/dist/types-Dr2Fn1Ax.d.ts +225 -0
- package/package.json +143 -4
- package/schema/ir-v2.schema.json +655 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// src/ir/layout.ts
|
|
2
|
+
var LAYOUT_COLUMN_WIDTH = 300;
|
|
3
|
+
var LAYOUT_ROW_HEIGHT = 170;
|
|
4
|
+
function autoLayout(nodeIds, edges) {
|
|
5
|
+
const depth = /* @__PURE__ */ new Map();
|
|
6
|
+
const roots = nodeIds.filter((id) => !edges.some((edge) => edge.target === id));
|
|
7
|
+
const queue = [...roots];
|
|
8
|
+
for (const id of queue) depth.set(id, 0);
|
|
9
|
+
const guardLimit = nodeIds.length * nodeIds.length + 1;
|
|
10
|
+
for (let guard = 0; queue.length > 0 && guard < guardLimit; guard++) {
|
|
11
|
+
const current = queue.shift();
|
|
12
|
+
if (current === void 0) break;
|
|
13
|
+
const currentDepth = depth.get(current) ?? 0;
|
|
14
|
+
for (const edge of edges) {
|
|
15
|
+
if (edge.source !== current) continue;
|
|
16
|
+
const next = currentDepth + 1;
|
|
17
|
+
if (next > (depth.get(edge.target) ?? -1) && next < nodeIds.length) {
|
|
18
|
+
depth.set(edge.target, next);
|
|
19
|
+
queue.push(edge.target);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const maxDepth = Math.max(0, ...depth.values());
|
|
24
|
+
const columns = /* @__PURE__ */ new Map();
|
|
25
|
+
for (const id of nodeIds) {
|
|
26
|
+
const column = depth.get(id) ?? maxDepth + 1;
|
|
27
|
+
columns.set(column, [...columns.get(column) ?? [], id]);
|
|
28
|
+
}
|
|
29
|
+
const positions = /* @__PURE__ */ new Map();
|
|
30
|
+
for (const [column, ids] of columns) {
|
|
31
|
+
ids.forEach((id, row) => {
|
|
32
|
+
positions.set(id, {
|
|
33
|
+
x: column * LAYOUT_COLUMN_WIDTH,
|
|
34
|
+
// `+ 0` turns the -0 Math.round can return into 0, so JSON never sees -0.
|
|
35
|
+
y: Math.round((row - (ids.length - 1) / 2) * LAYOUT_ROW_HEIGHT) + 0
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return positions;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { LAYOUT_COLUMN_WIDTH, LAYOUT_ROW_HEIGHT, autoLayout };
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkE3APHA6O_cjs = require('./chunk-E3APHA6O.cjs');
|
|
4
|
+
|
|
5
|
+
// src/builder/refs.ts
|
|
6
|
+
var REF_MODEL = /* @__PURE__ */ Symbol.for("fluidgrids.workflows.ref");
|
|
7
|
+
var PREDICATE = /* @__PURE__ */ Symbol.for("fluidgrids.workflows.predicate");
|
|
8
|
+
var PREDICATE_OPERATORS = {
|
|
9
|
+
eq: { operator: "==", unary: false },
|
|
10
|
+
neq: { operator: "!=", unary: false },
|
|
11
|
+
gt: { operator: ">", unary: false },
|
|
12
|
+
gte: { operator: ">=", unary: false },
|
|
13
|
+
lt: { operator: "<", unary: false },
|
|
14
|
+
lte: { operator: "<=", unary: false },
|
|
15
|
+
contains: { operator: "contains", unary: false },
|
|
16
|
+
notContains: { operator: "notContains", unary: false },
|
|
17
|
+
startsWith: { operator: "startsWith", unary: false },
|
|
18
|
+
endsWith: { operator: "endsWith", unary: false },
|
|
19
|
+
matches: { operator: "regex", unary: false },
|
|
20
|
+
hasProperty: { operator: "hasProperty", unary: false },
|
|
21
|
+
isEmpty: { operator: "isEmpty", unary: true },
|
|
22
|
+
isNotEmpty: { operator: "isNotEmpty", unary: true },
|
|
23
|
+
isNull: { operator: "isNull", unary: true },
|
|
24
|
+
isNotNull: { operator: "isNotNull", unary: true },
|
|
25
|
+
isTrue: { operator: "isTrue", unary: true },
|
|
26
|
+
isFalse: { operator: "isFalse", unary: true }
|
|
27
|
+
};
|
|
28
|
+
var RESERVED_REF_KEYS = /* @__PURE__ */ new Set([
|
|
29
|
+
"then",
|
|
30
|
+
"toJSON",
|
|
31
|
+
"toString",
|
|
32
|
+
"valueOf"
|
|
33
|
+
]);
|
|
34
|
+
var BuilderError = class extends Error {
|
|
35
|
+
constructor(message) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "BuilderError";
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
function isRuleValue(value) {
|
|
41
|
+
return value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
|
|
42
|
+
}
|
|
43
|
+
function conditionField(ref) {
|
|
44
|
+
const segments = ref.path.map((segment) => {
|
|
45
|
+
const text = segment.kind === "index" ? String(segment.index) : segment.key;
|
|
46
|
+
if (text === "" || text.includes(".")) {
|
|
47
|
+
throw new BuilderError(
|
|
48
|
+
`A condition cannot address the key "${text}" (condition fields are dot-separated); use a raw condition tree`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return text;
|
|
52
|
+
});
|
|
53
|
+
switch (ref.root.kind) {
|
|
54
|
+
case "node":
|
|
55
|
+
if (ref.root.nodeId.includes(".")) {
|
|
56
|
+
throw new BuilderError(
|
|
57
|
+
`A condition cannot address node "${ref.root.nodeId}"; its id contains a dot`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
return ["WorkflowState", ref.root.nodeId, ...segments].join(".");
|
|
61
|
+
case "json":
|
|
62
|
+
return ["output", ...segments].join(".");
|
|
63
|
+
default:
|
|
64
|
+
throw new BuilderError(
|
|
65
|
+
`A condition can compare node outputs and $json only, not $${ref.root.kind}; use an expression`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function makePredicate(target, operator, args, unary) {
|
|
70
|
+
const rule = { type: "rule", field: conditionField(target), operator };
|
|
71
|
+
if (!unary) {
|
|
72
|
+
if (args.length < 1 || !isRuleValue(args[0])) {
|
|
73
|
+
throw new BuilderError(
|
|
74
|
+
`The "${operator}" comparison needs a string, number, boolean or null value`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
rule.value = args[0];
|
|
78
|
+
} else if (args.length > 0) {
|
|
79
|
+
throw new BuilderError(`The "${operator}" comparison takes no value`);
|
|
80
|
+
}
|
|
81
|
+
return { [PREDICATE]: rule };
|
|
82
|
+
}
|
|
83
|
+
function callOnRef(model, args) {
|
|
84
|
+
const last = model.path[model.path.length - 1];
|
|
85
|
+
if (last?.kind !== "key") {
|
|
86
|
+
throw new BuilderError("A reference is not a function; call a comparison such as .gte(500)");
|
|
87
|
+
}
|
|
88
|
+
const parent = { root: model.root, path: model.path.slice(0, -1) };
|
|
89
|
+
if (last.key === "is") {
|
|
90
|
+
const [operator, ...rest] = args;
|
|
91
|
+
if (typeof operator !== "string" || operator === "") {
|
|
92
|
+
throw new BuilderError(".is(operator, value) needs an operator name");
|
|
93
|
+
}
|
|
94
|
+
return makePredicate(parent, operator, rest, rest.length === 0);
|
|
95
|
+
}
|
|
96
|
+
const known = PREDICATE_OPERATORS[last.key];
|
|
97
|
+
if (!known) {
|
|
98
|
+
throw new BuilderError(`"${last.key}" is not a comparison; references are data, not functions`);
|
|
99
|
+
}
|
|
100
|
+
return makePredicate(parent, known.operator, args, known.unary);
|
|
101
|
+
}
|
|
102
|
+
function makeRef(root, path = []) {
|
|
103
|
+
const model = { root, path };
|
|
104
|
+
const render = () => chunkE3APHA6O_cjs.formatRefTemplate(model);
|
|
105
|
+
const target = function fluidgridsRef() {
|
|
106
|
+
return void 0;
|
|
107
|
+
};
|
|
108
|
+
const handler = {
|
|
109
|
+
get(_target, property) {
|
|
110
|
+
if (property === REF_MODEL) return model;
|
|
111
|
+
if (property === Symbol.toPrimitive) return render;
|
|
112
|
+
if (typeof property === "symbol") return void 0;
|
|
113
|
+
if (property === "then") return void 0;
|
|
114
|
+
if (property === "toJSON" || property === "toString" || property === "valueOf") return render;
|
|
115
|
+
return makeRef(root, [...path, chunkE3APHA6O_cjs.segmentFromKey(property)]);
|
|
116
|
+
},
|
|
117
|
+
apply(_target, _thisArg, args) {
|
|
118
|
+
return callOnRef(model, args);
|
|
119
|
+
},
|
|
120
|
+
has(_target, property) {
|
|
121
|
+
return property === REF_MODEL;
|
|
122
|
+
},
|
|
123
|
+
set() {
|
|
124
|
+
throw new BuilderError("References are read-only");
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
return new Proxy(target, handler);
|
|
128
|
+
}
|
|
129
|
+
function refModelOf(value) {
|
|
130
|
+
if ((typeof value === "function" || typeof value === "object") && value !== null && REF_MODEL in value) {
|
|
131
|
+
const model = value[REF_MODEL];
|
|
132
|
+
return model;
|
|
133
|
+
}
|
|
134
|
+
return void 0;
|
|
135
|
+
}
|
|
136
|
+
function isPredicate(value) {
|
|
137
|
+
return typeof value === "object" && value !== null && PREDICATE in value;
|
|
138
|
+
}
|
|
139
|
+
function predicateTree(predicate) {
|
|
140
|
+
return predicate[PREDICATE];
|
|
141
|
+
}
|
|
142
|
+
function group(combinator, predicates) {
|
|
143
|
+
if (predicates.length === 0)
|
|
144
|
+
throw new BuilderError(`${combinator.toLowerCase()}() needs at least one condition`);
|
|
145
|
+
for (const predicate of predicates) {
|
|
146
|
+
if (!isPredicate(predicate))
|
|
147
|
+
throw new BuilderError(`${combinator.toLowerCase()}() takes conditions only`);
|
|
148
|
+
}
|
|
149
|
+
return { [PREDICATE]: { type: "group", combinator, children: predicates.map(predicateTree) } };
|
|
150
|
+
}
|
|
151
|
+
function and(...predicates) {
|
|
152
|
+
return group("AND", predicates);
|
|
153
|
+
}
|
|
154
|
+
function or(...predicates) {
|
|
155
|
+
return group("OR", predicates);
|
|
156
|
+
}
|
|
157
|
+
function conditionTreeOf(predicate) {
|
|
158
|
+
const tree = predicateTree(predicate);
|
|
159
|
+
return tree.type === "group" ? tree : { type: "group", combinator: "AND", children: [tree] };
|
|
160
|
+
}
|
|
161
|
+
function expr(strings, ...values) {
|
|
162
|
+
let out = strings[0] ?? "";
|
|
163
|
+
values.forEach((value, index) => {
|
|
164
|
+
const model = refModelOf(value);
|
|
165
|
+
if (model) out += chunkE3APHA6O_cjs.formatRefTemplate(model);
|
|
166
|
+
else if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
167
|
+
out += String(value);
|
|
168
|
+
} else {
|
|
169
|
+
throw new BuilderError("expr`\u2026` interpolates references, strings, numbers and booleans only");
|
|
170
|
+
}
|
|
171
|
+
out += strings[index + 1] ?? "";
|
|
172
|
+
});
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
exports.BuilderError = BuilderError;
|
|
177
|
+
exports.PREDICATE_OPERATORS = PREDICATE_OPERATORS;
|
|
178
|
+
exports.RESERVED_REF_KEYS = RESERVED_REF_KEYS;
|
|
179
|
+
exports.and = and;
|
|
180
|
+
exports.conditionTreeOf = conditionTreeOf;
|
|
181
|
+
exports.expr = expr;
|
|
182
|
+
exports.isPredicate = isPredicate;
|
|
183
|
+
exports.makeRef = makeRef;
|
|
184
|
+
exports.or = or;
|
|
185
|
+
exports.refModelOf = refModelOf;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { isRecord, setOwn } from './chunk-UJNHTS6D.js';
|
|
2
|
+
|
|
3
|
+
// src/ir/manifest.ts
|
|
4
|
+
function operationsOf(manifest) {
|
|
5
|
+
const operations = Array.isArray(manifest.operations) ? manifest.operations : manifest.operations.operations;
|
|
6
|
+
return Array.isArray(operations) ? operations.filter((operation) => isRecord(operation) && typeof operation.name === "string") : [];
|
|
7
|
+
}
|
|
8
|
+
function isTriggerOperation(operation) {
|
|
9
|
+
if (typeof operation.role === "string") return operation.role.toLowerCase() === "trigger";
|
|
10
|
+
return operation.type === "trigger" || operation.type === "subscription";
|
|
11
|
+
}
|
|
12
|
+
function fieldOf(value) {
|
|
13
|
+
if (typeof value === "string") return { type: value };
|
|
14
|
+
return isRecord(value) ? value : {};
|
|
15
|
+
}
|
|
16
|
+
function fieldSchema(value) {
|
|
17
|
+
const field = fieldOf(value);
|
|
18
|
+
const description = typeof field.description === "string" ? { description: field.description } : {};
|
|
19
|
+
const choices = Array.isArray(field.enum) ? field.enum : Array.isArray(field.options) ? field.options : void 0;
|
|
20
|
+
if (choices && choices.every((choice) => typeof choice === "string")) {
|
|
21
|
+
return { enum: choices, ...description };
|
|
22
|
+
}
|
|
23
|
+
if (field.format === "binary") {
|
|
24
|
+
return {
|
|
25
|
+
type: "object",
|
|
26
|
+
description: field.description ?? "File reference",
|
|
27
|
+
properties: { fileId: { type: "string" } }
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
switch (field.type) {
|
|
31
|
+
case "string":
|
|
32
|
+
case "code":
|
|
33
|
+
case "workflow":
|
|
34
|
+
case "time":
|
|
35
|
+
return { type: "string", ...description };
|
|
36
|
+
case "date":
|
|
37
|
+
case "datetime":
|
|
38
|
+
return { type: "string", format: "date-time", ...description };
|
|
39
|
+
case "integer":
|
|
40
|
+
return { type: "integer", ...description };
|
|
41
|
+
case "number":
|
|
42
|
+
return { type: "number", ...description };
|
|
43
|
+
case "boolean":
|
|
44
|
+
return { type: "boolean", ...description };
|
|
45
|
+
case "array": {
|
|
46
|
+
const items = field.items !== void 0 ? { items: fieldSchema(field.items) } : {};
|
|
47
|
+
return { type: "array", ...items, ...description };
|
|
48
|
+
}
|
|
49
|
+
case "object": {
|
|
50
|
+
if (isRecord(field.properties)) {
|
|
51
|
+
const properties = {};
|
|
52
|
+
for (const [name, child] of Object.entries(field.properties))
|
|
53
|
+
setOwn(properties, name, fieldSchema(child));
|
|
54
|
+
return { type: "object", properties, ...description };
|
|
55
|
+
}
|
|
56
|
+
return { type: "object", ...description };
|
|
57
|
+
}
|
|
58
|
+
default:
|
|
59
|
+
return { ...description };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function fieldsSchema(fields) {
|
|
63
|
+
const properties = {};
|
|
64
|
+
const required = [];
|
|
65
|
+
for (const [name, field] of Object.entries(fields ?? {})) {
|
|
66
|
+
setOwn(properties, name, fieldSchema(field));
|
|
67
|
+
if (fieldOf(field).required === true) required.push(name);
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
type: "object",
|
|
71
|
+
properties,
|
|
72
|
+
...required.length > 0 ? { required } : {}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function findManifest(manifests, nodeType) {
|
|
76
|
+
const candidates = manifests.filter((manifest) => manifest.nodeType === nodeType);
|
|
77
|
+
return candidates.sort((a, b) => compareVersions(b.nodeVersion, a.nodeVersion))[0];
|
|
78
|
+
}
|
|
79
|
+
function compareVersions(left, right) {
|
|
80
|
+
const a = (left ?? "").split(".");
|
|
81
|
+
const b = (right ?? "").split(".");
|
|
82
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
83
|
+
const x = a[i] ?? "";
|
|
84
|
+
const y = b[i] ?? "";
|
|
85
|
+
const nx = Number(x);
|
|
86
|
+
const ny = Number(y);
|
|
87
|
+
if (x !== y) {
|
|
88
|
+
if (Number.isFinite(nx) && Number.isFinite(ny) && x !== "" && y !== "") return nx - ny;
|
|
89
|
+
return x < y ? -1 : 1;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export { compareVersions, fieldSchema, fieldsSchema, findManifest, isTriggerOperation, operationsOf };
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { autoLayout } from './chunk-5LUIDMF4.js';
|
|
2
|
+
import { sha256Tagged, canonicalJson } from './chunk-IHKXLG6I.js';
|
|
3
|
+
import { isRecord, cloneJson, deepEqual, setOwn } from './chunk-UJNHTS6D.js';
|
|
4
|
+
|
|
5
|
+
// src/ir/node-types.ts
|
|
6
|
+
var EXECUTOR_INTERNAL_TYPES = /* @__PURE__ */ new Set([
|
|
7
|
+
"internal:if",
|
|
8
|
+
"internal:switch",
|
|
9
|
+
"internal:loop",
|
|
10
|
+
"internal:merge",
|
|
11
|
+
"internal:set",
|
|
12
|
+
"internal:filter",
|
|
13
|
+
"internal:aggregate",
|
|
14
|
+
"internal:wait",
|
|
15
|
+
"internal:noop",
|
|
16
|
+
"internal:code",
|
|
17
|
+
"internal:http",
|
|
18
|
+
"internal:transform",
|
|
19
|
+
"internal:validate",
|
|
20
|
+
"internal:log",
|
|
21
|
+
"internal:error",
|
|
22
|
+
"internal:subworkflow",
|
|
23
|
+
"internal:compare-datasets",
|
|
24
|
+
"internal:split-out",
|
|
25
|
+
"internal:limit",
|
|
26
|
+
"internal:dedupe",
|
|
27
|
+
"internal:sort",
|
|
28
|
+
"internal:datatable",
|
|
29
|
+
"internal:respond-to-webhook",
|
|
30
|
+
"internal:send-and-wait",
|
|
31
|
+
"if",
|
|
32
|
+
"switch",
|
|
33
|
+
"loop",
|
|
34
|
+
"merge",
|
|
35
|
+
"set",
|
|
36
|
+
"filter",
|
|
37
|
+
"aggregate",
|
|
38
|
+
"wait",
|
|
39
|
+
"noop",
|
|
40
|
+
"code",
|
|
41
|
+
"http",
|
|
42
|
+
"transform",
|
|
43
|
+
"validate",
|
|
44
|
+
"log",
|
|
45
|
+
"error",
|
|
46
|
+
"subworkflow"
|
|
47
|
+
]);
|
|
48
|
+
var CODE_WORKFLOW_NODE_TYPE = "internal:code-workflow";
|
|
49
|
+
var WAIT_FOR_SIGNAL_NODE_TYPE = "internal:wait-for-signal";
|
|
50
|
+
var V2_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
51
|
+
CODE_WORKFLOW_NODE_TYPE,
|
|
52
|
+
WAIT_FOR_SIGNAL_NODE_TYPE
|
|
53
|
+
]);
|
|
54
|
+
var INTERNAL_TRIGGER_TYPES = /* @__PURE__ */ new Set([
|
|
55
|
+
"internal:api",
|
|
56
|
+
"internal:schedule",
|
|
57
|
+
"internal:webhook",
|
|
58
|
+
"internal:form",
|
|
59
|
+
"internal:error-trigger",
|
|
60
|
+
"internal:workflow-call",
|
|
61
|
+
"internal:rss-feed",
|
|
62
|
+
"internal:http-poll",
|
|
63
|
+
"internal:database-poll",
|
|
64
|
+
"internal:email-imap",
|
|
65
|
+
"internal:file-upload",
|
|
66
|
+
"internal:record-change",
|
|
67
|
+
"internal:state-change"
|
|
68
|
+
]);
|
|
69
|
+
function usesMergedParameters(type) {
|
|
70
|
+
const lower = type.toLowerCase();
|
|
71
|
+
return EXECUTOR_INTERNAL_TYPES.has(lower) || V2_NODE_TYPES.has(lower);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/ir/normalize.ts
|
|
75
|
+
function isNonEmptyString(value) {
|
|
76
|
+
return typeof value === "string" && value !== "";
|
|
77
|
+
}
|
|
78
|
+
function firstTruthy(...values) {
|
|
79
|
+
for (const value of values) if (value) return value;
|
|
80
|
+
return void 0;
|
|
81
|
+
}
|
|
82
|
+
function readPosition(value) {
|
|
83
|
+
if (!isRecord(value)) return void 0;
|
|
84
|
+
const { x, y } = value;
|
|
85
|
+
return typeof x === "number" && typeof y === "number" && Number.isFinite(x) && Number.isFinite(y) ? { x, y } : void 0;
|
|
86
|
+
}
|
|
87
|
+
function removeIfEmpty(parent, key) {
|
|
88
|
+
const value = parent[key];
|
|
89
|
+
if (isRecord(value) && Object.keys(value).length === 0) delete parent[key];
|
|
90
|
+
}
|
|
91
|
+
function normalizeLabel(node, data) {
|
|
92
|
+
if (node["label"] === void 0 && typeof data["label"] === "string")
|
|
93
|
+
node["label"] = data["label"];
|
|
94
|
+
if (data["label"] !== void 0 && deepEqual(data["label"], node["label"])) delete data["label"];
|
|
95
|
+
}
|
|
96
|
+
function normalizeOperation(node, data) {
|
|
97
|
+
if (!isNonEmptyString(node["operation_name"]) && isNonEmptyString(data["operation_name"])) {
|
|
98
|
+
node["operation_name"] = data["operation_name"];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function normalizeVersion(node, data, merged) {
|
|
102
|
+
if (merged) return;
|
|
103
|
+
const effective = firstTruthy(data["version"], node["version"]);
|
|
104
|
+
if (typeof effective === "string") node["version"] = effective;
|
|
105
|
+
if (data["nodeVersion"] !== void 0 && deepEqual(data["nodeVersion"], node["version"])) {
|
|
106
|
+
delete data["nodeVersion"];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function normalizeExternalState(node, data) {
|
|
110
|
+
const args = isRecord(node["args"]) ? node["args"] : void 0;
|
|
111
|
+
const dataArgs = isRecord(data["args"]) ? data["args"] : void 0;
|
|
112
|
+
const effective = firstTruthy(args?.["state"], dataArgs?.["state"]);
|
|
113
|
+
if (effective !== void 0 && args?.["state"] === void 0) {
|
|
114
|
+
const nextArgs = args ?? {};
|
|
115
|
+
nextArgs["state"] = effective;
|
|
116
|
+
node["args"] = nextArgs;
|
|
117
|
+
}
|
|
118
|
+
const rootState = isRecord(node["args"]) ? node["args"]["state"] : void 0;
|
|
119
|
+
if (dataArgs && dataArgs["state"] !== void 0 && deepEqual(dataArgs["state"], rootState)) {
|
|
120
|
+
delete dataArgs["state"];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function normalizeMergedState(node, data) {
|
|
124
|
+
const args = isRecord(node["args"]) ? node["args"] : {};
|
|
125
|
+
const dataArgs = isRecord(data["args"]) ? data["args"] : void 0;
|
|
126
|
+
const config = isRecord(node["config"]) ? node["config"] : void 0;
|
|
127
|
+
const dataState = isRecord(dataArgs?.["state"]) ? dataArgs["state"] : void 0;
|
|
128
|
+
const rootState = isRecord(args["state"]) ? args["state"] : void 0;
|
|
129
|
+
if (config === void 0 && dataState === void 0) return;
|
|
130
|
+
args["state"] = { ...config, ...dataState, ...rootState };
|
|
131
|
+
node["args"] = args;
|
|
132
|
+
if (config !== void 0) delete node["config"];
|
|
133
|
+
if (dataArgs && dataState !== void 0) delete dataArgs["state"];
|
|
134
|
+
}
|
|
135
|
+
function normalizeConnections(node, data) {
|
|
136
|
+
const dataArgs = isRecord(data["args"]) ? data["args"] : void 0;
|
|
137
|
+
if (!dataArgs) return;
|
|
138
|
+
for (const key of ["connections", "credentials"]) {
|
|
139
|
+
const args = isRecord(node["args"]) ? node["args"] : void 0;
|
|
140
|
+
if (!args?.[key] && dataArgs[key]) {
|
|
141
|
+
const nextArgs = args ?? {};
|
|
142
|
+
nextArgs[key] = dataArgs[key];
|
|
143
|
+
node["args"] = nextArgs;
|
|
144
|
+
}
|
|
145
|
+
const rootValue = isRecord(node["args"]) ? node["args"][key] : void 0;
|
|
146
|
+
if (dataArgs[key] !== void 0 && deepEqual(dataArgs[key], rootValue)) delete dataArgs[key];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function normalizeContext(node, data) {
|
|
150
|
+
const dataArgs = isRecord(data["args"]) ? data["args"] : void 0;
|
|
151
|
+
const args = isRecord(node["args"]) ? node["args"] : void 0;
|
|
152
|
+
if (!dataArgs || dataArgs["context"] === void 0) return;
|
|
153
|
+
if (args && deepEqual(dataArgs["context"], args["context"])) delete dataArgs["context"];
|
|
154
|
+
}
|
|
155
|
+
function normalizeErrorConfig(node, data) {
|
|
156
|
+
const dataArgs = isRecord(data["args"]) ? data["args"] : void 0;
|
|
157
|
+
const dataState = isRecord(dataArgs?.["state"]) ? dataArgs["state"] : void 0;
|
|
158
|
+
const effective = node["errorConfig"] ?? data["errorConfig"] ?? dataState?.["errorConfig"];
|
|
159
|
+
if (effective !== void 0 && effective !== null) node["errorConfig"] = effective;
|
|
160
|
+
else if (node["errorConfig"] === null) delete node["errorConfig"];
|
|
161
|
+
if (data["errorConfig"] !== void 0 && deepEqual(data["errorConfig"], node["errorConfig"])) {
|
|
162
|
+
delete data["errorConfig"];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function normalizeExecutionSettings(node, data) {
|
|
166
|
+
const root = isRecord(node["executionSettings"]) ? node["executionSettings"] : void 0;
|
|
167
|
+
const mirror = isRecord(data["executionSettings"]) ? data["executionSettings"] : void 0;
|
|
168
|
+
if (!root && !mirror) return;
|
|
169
|
+
const merged = { ...root };
|
|
170
|
+
for (const [key, value] of Object.entries(mirror ?? {}))
|
|
171
|
+
if (!Object.hasOwn(merged, key)) setOwn(merged, key, value);
|
|
172
|
+
if (root?.["executeOnce"] === true || mirror?.["executeOnce"] === true)
|
|
173
|
+
merged["executeOnce"] = true;
|
|
174
|
+
if (mirror && Object.hasOwn(mirror, "runOn")) {
|
|
175
|
+
merged["runOn"] = mirror["runOn"];
|
|
176
|
+
data["executionSettings"] = { runOn: mirror["runOn"] };
|
|
177
|
+
} else {
|
|
178
|
+
if (mirror) delete data["executionSettings"];
|
|
179
|
+
}
|
|
180
|
+
node["executionSettings"] = merged;
|
|
181
|
+
}
|
|
182
|
+
function normalizeDisabled(node, data) {
|
|
183
|
+
if (node["disabled"] === true || data["disabled"] === true) node["disabled"] = true;
|
|
184
|
+
delete data["disabled"];
|
|
185
|
+
}
|
|
186
|
+
function normalizeNode(raw) {
|
|
187
|
+
if (!isRecord(raw)) return raw;
|
|
188
|
+
const node = cloneJson(raw);
|
|
189
|
+
const type = typeof node["type"] === "string" ? node["type"] : "";
|
|
190
|
+
const merged = usesMergedParameters(type);
|
|
191
|
+
const data = isRecord(node["data"]) ? node["data"] : {};
|
|
192
|
+
normalizeLabel(node, data);
|
|
193
|
+
normalizeOperation(node, data);
|
|
194
|
+
normalizeVersion(node, data, merged);
|
|
195
|
+
normalizeErrorConfig(node, data);
|
|
196
|
+
if (merged) normalizeMergedState(node, data);
|
|
197
|
+
else normalizeExternalState(node, data);
|
|
198
|
+
normalizeConnections(node, data);
|
|
199
|
+
normalizeContext(node, data);
|
|
200
|
+
normalizeExecutionSettings(node, data);
|
|
201
|
+
normalizeDisabled(node, data);
|
|
202
|
+
if (isRecord(data["args"])) removeIfEmpty(data, "args");
|
|
203
|
+
if (Object.keys(data).length === 0) delete node["data"];
|
|
204
|
+
else node["data"] = data;
|
|
205
|
+
return node;
|
|
206
|
+
}
|
|
207
|
+
function normalizeDefinition(definition) {
|
|
208
|
+
if (!isRecord(definition) || !isRecord(definition["data"])) return definition;
|
|
209
|
+
const doc = cloneJson(definition);
|
|
210
|
+
const data = doc["data"];
|
|
211
|
+
const rawNodes = Array.isArray(data["nodes"]) ? data["nodes"] : [];
|
|
212
|
+
const nodes = rawNodes.map(normalizeNode);
|
|
213
|
+
data["nodes"] = nodes;
|
|
214
|
+
const edges = Array.isArray(data["edges"]) ? data["edges"].filter(isRecord) : [];
|
|
215
|
+
const ids = nodes.flatMap(
|
|
216
|
+
(node) => isRecord(node) && typeof node["id"] === "string" ? [node["id"]] : []
|
|
217
|
+
);
|
|
218
|
+
const missing = nodes.some(
|
|
219
|
+
(node) => isRecord(node) && readPosition(node["position"]) === void 0
|
|
220
|
+
);
|
|
221
|
+
if (missing) {
|
|
222
|
+
const meta = isRecord(doc["meta"]) ? doc["meta"] : void 0;
|
|
223
|
+
const metaLayout = isRecord(meta?.["layout"]) ? meta["layout"] : void 0;
|
|
224
|
+
const computed = autoLayout(
|
|
225
|
+
ids,
|
|
226
|
+
edges.flatMap(
|
|
227
|
+
(edge) => typeof edge["source"] === "string" && typeof edge["target"] === "string" ? [{ source: edge["source"], target: edge["target"] }] : []
|
|
228
|
+
)
|
|
229
|
+
);
|
|
230
|
+
for (const node of nodes) {
|
|
231
|
+
if (!isRecord(node) || typeof node["id"] !== "string") continue;
|
|
232
|
+
if (readPosition(node["position"]) !== void 0) continue;
|
|
233
|
+
const fromMeta = readPosition(metaLayout?.[node["id"]]);
|
|
234
|
+
const position = fromMeta ?? computed.get(node["id"]);
|
|
235
|
+
if (position) node["position"] = { x: position.x, y: position.y };
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
doc["schemaVersion"] = 2;
|
|
239
|
+
return doc;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/ir/hash.ts
|
|
243
|
+
function hashedProjection(definition) {
|
|
244
|
+
const normalized = normalizeDefinition(definition);
|
|
245
|
+
if (!isRecord(normalized)) return normalized;
|
|
246
|
+
const copy = { ...normalized };
|
|
247
|
+
delete copy["authoring"];
|
|
248
|
+
return copy;
|
|
249
|
+
}
|
|
250
|
+
function irHash(definition) {
|
|
251
|
+
return sha256Tagged(canonicalJson(hashedProjection(definition)));
|
|
252
|
+
}
|
|
253
|
+
function sourceHash(files) {
|
|
254
|
+
const entries = [...files].sort(
|
|
255
|
+
(a, b) => a.path === b.path ? a.content < b.content ? -1 : a.content > b.content ? 1 : 0 : a.path < b.path ? -1 : 1
|
|
256
|
+
).map((file) => [file.path, file.content]);
|
|
257
|
+
return sha256Tagged(canonicalJson(entries));
|
|
258
|
+
}
|
|
259
|
+
function buildIdOf(bundle) {
|
|
260
|
+
return sha256Tagged(bundle);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export { CODE_WORKFLOW_NODE_TYPE, INTERNAL_TRIGGER_TYPES, V2_NODE_TYPES, WAIT_FOR_SIGNAL_NODE_TYPE, buildIdOf, hashedProjection, irHash, normalizeDefinition, sourceHash, usesMergedParameters };
|