@fluidgrids/workflows 2026.1028.2 → 2026.1029.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/README.md +72 -10
- package/dist/{activation-DnhG7SmF.d.ts → activation-BnVQMv9y.d.ts} +1 -1
- package/dist/{activation-BBh1p82z.d.cts → activation-CESehfYi.d.cts} +1 -1
- package/dist/{chunk-XHXIDVEC.js → chunk-25BKWR2O.js} +1 -1
- package/dist/{chunk-UK3WM7YZ.cjs → chunk-2B37XAFQ.cjs} +44 -8
- package/dist/{chunk-DJYMDLV5.js → chunk-2DDULZFM.js} +93 -1
- package/dist/{chunk-623FVQSN.cjs → chunk-3FIDHONL.cjs} +104 -0
- package/dist/chunk-6QPOJZT6.cjs +1180 -0
- package/dist/chunk-7ILGCUI6.js +154 -0
- package/dist/chunk-A2OHX3UQ.js +1156 -0
- package/dist/{chunk-VOKMAAJP.js → chunk-A36CCOWS.js} +188 -19
- package/dist/{chunk-FMSW2HDF.cjs → chunk-ELL2RBML.cjs} +0 -14
- package/dist/{chunk-JD2VQIDZ.cjs → chunk-EWYADREB.cjs} +2 -2
- package/dist/{chunk-HWJZVOG7.js → chunk-FQSJI5NV.js} +1 -1
- package/dist/{chunk-ABFZWYHT.js → chunk-FWBRQWRX.js} +156 -48
- package/dist/{chunk-PZCVF76Q.cjs → chunk-I47EENR4.cjs} +209 -40
- package/dist/chunk-J3PYFGKA.cjs +166 -0
- package/dist/{chunk-C5OLWZ42.js → chunk-KXJDRQ6G.js} +1 -13
- package/dist/chunk-M272AHEX.js +25 -0
- package/dist/{chunk-VRHHBPT6.js → chunk-MJ5TGYVG.js} +333 -65
- package/dist/{chunk-SAOBPYYJ.cjs → chunk-NXFBVDOI.cjs} +3 -3
- package/dist/{chunk-XKJA7KX3.js → chunk-OIX4O6UR.js} +38 -2
- package/dist/{chunk-FEW3JBYA.cjs → chunk-OKX3FYIM.cjs} +3 -3
- package/dist/{chunk-M4BBAERY.cjs → chunk-OMY3CKUZ.cjs} +404 -136
- package/dist/chunk-PWIUEWC3.js +81 -0
- package/dist/chunk-Q4MWQNJK.cjs +28 -0
- package/dist/{chunk-P6TA5EZT.cjs → chunk-RUQIMTN5.cjs} +171 -57
- package/dist/{chunk-IISBRUWJ.js → chunk-WXXNCHUY.js} +1 -1
- package/dist/chunk-YHBVMOMK.cjs +87 -0
- package/dist/codegen/index.d.cts +2 -2
- package/dist/codegen/index.d.ts +2 -2
- package/dist/collect-BTHjQaSp.d.ts +86 -0
- package/dist/collect-CSyOg5XC.d.cts +86 -0
- package/dist/{file-BOoHZgoQ.d.cts → file-cgL9l9l8.d.cts} +765 -14
- package/dist/{file-yuPCFU5b.d.ts → file-olQudcx5.d.ts} +765 -14
- package/dist/history/index.cjs +198 -86
- package/dist/history/index.d.cts +49 -10
- package/dist/history/index.d.ts +49 -10
- package/dist/history/index.js +49 -4
- package/dist/index.cjs +64 -51
- package/dist/index.d.cts +9 -53
- package/dist/index.d.ts +9 -53
- package/dist/index.js +5 -4
- package/dist/ir/index.cjs +24 -3
- package/dist/ir/index.d.cts +43 -4
- package/dist/ir/index.d.ts +43 -4
- package/dist/ir/index.js +24 -3
- package/dist/{lower-BzmUz0sq.d.cts → lower-3S6PsqjJ.d.cts} +40 -6
- package/dist/{lower-_-iT4HYs.d.ts → lower-DmZpQ8hJ.d.ts} +40 -6
- package/dist/{manifest-C8N6HDYl.d.ts → manifest-BJjrQt77.d.ts} +1 -1
- package/dist/{manifest-0OLw0i7k.d.cts → manifest-gRI2Q5Fj.d.cts} +1 -1
- package/dist/node-evaluator-SOADN23V.js +14 -0
- package/dist/node-evaluator-YGDEXK4U.cjs +24 -0
- package/dist/quickjs/index.cjs +25 -24
- package/dist/quickjs/index.d.cts +6 -6
- package/dist/quickjs/index.d.ts +6 -6
- package/dist/quickjs/index.js +8 -7
- package/dist/roundtrip/index.cjs +245 -43
- package/dist/roundtrip/index.d.cts +86 -9
- package/dist/roundtrip/index.d.ts +86 -9
- package/dist/roundtrip/index.js +172 -8
- package/dist/runtime/index.cjs +21 -20
- package/dist/runtime/index.d.cts +49 -7
- package/dist/runtime/index.d.ts +49 -7
- package/dist/runtime/index.js +8 -7
- package/dist/testing/index.cjs +514 -74
- package/dist/testing/index.d.cts +127 -10
- package/dist/testing/index.d.ts +127 -10
- package/dist/testing/index.js +480 -42
- package/dist/{types-BGoPzgcl.d.ts → types-Bb2wRnJ5.d.cts} +20 -1
- package/dist/{types-BGoPzgcl.d.cts → types-Bb2wRnJ5.d.ts} +20 -1
- package/dist/{types-DV-HX_Gt.d.ts → types-CQKOhPTa.d.cts} +122 -14
- package/dist/{types-CpBBjaGX.d.cts → types-CnIOinoz.d.ts} +122 -14
- package/dist/{workflow-Bpr3vnA_.d.ts → workflow-8uRU9rhL.d.ts} +2 -2
- package/dist/{workflow-FXUkpIBc.d.cts → workflow-CZOXUlQ5.d.cts} +2 -2
- package/dist/{workflow-C2a05WUJ.d.ts → workflow-DWTPHFbt.d.ts} +124 -12
- package/dist/{workflow-J-yYixny.d.cts → workflow-O6e64ZcG.d.cts} +124 -12
- package/fixtures/histories/auto-upgrade-patched.history.json +276 -0
- package/fixtures/histories/benign-failure.history.json +146 -0
- package/fixtures/histories/cancel-activity-try-cancel.history.json +150 -0
- package/fixtures/histories/child-cancel-wait-requested.history.json +217 -0
- package/fixtures/histories/child-options-roundtrip.history.json +192 -0
- package/fixtures/histories/continue-as-new-last-result.history.json +86 -0
- package/fixtures/histories/continue-as-new-options.history.json +99 -0
- package/fixtures/histories/continue-as-new-r1-long-task-queue.history.json +78 -0
- package/fixtures/histories/continue-as-new-r1-retry-options.history.json +83 -0
- package/fixtures/histories/execution-timeout-chain.history.json +98 -0
- package/fixtures/histories/external-cancel-resolved.history.json +123 -0
- package/fixtures/histories/external-cancel-unknown-target.history.json +127 -0
- package/fixtures/histories/failure-error-types-fails-run.history.json +144 -0
- package/fixtures/histories/handler-drain-warn.history.json +222 -0
- package/fixtures/histories/heartbeat-details-on-retry.history.json +145 -0
- package/fixtures/histories/local-activity-abandoned-at-completion.history.json +73 -0
- package/fixtures/histories/local-activity-cancelled-in-scope.history.json +118 -0
- package/fixtures/histories/local-activity-completed.history.json +157 -0
- package/fixtures/histories/local-activity-failed.history.json +93 -0
- package/fixtures/histories/local-activity-retry-in-task.history.json +88 -0
- package/fixtures/histories/run-retry-last-failure.history.json +90 -0
- package/fixtures/histories/run-timeout.history.json +159 -0
- package/fixtures/histories/schedule-to-start-timeout.history.json +132 -0
- package/fixtures/histories/start-delay-signal-ends-delay.history.json +155 -0
- package/fixtures/histories/typeerror-task-retry-100.history.json +137 -0
- package/package.json +1 -1
- package/schema/history-file.schema.json +283 -2
- package/schema/ir-v2.schema.json +45 -0
- package/schema/run-event.schema.json +264 -2
- package/schema/workflow-command.schema.json +178 -1
- package/schema/workflow-task.schema.json +392 -4
- package/dist/assemble-BLqQ8lSu.d.cts +0 -39
- package/dist/assemble-DWgaXHd-.d.ts +0 -39
- package/dist/chunk-2J6TF7YI.cjs +0 -86
- package/dist/chunk-BO6OVILK.js +0 -79
- package/dist/chunk-DHTLALBL.cjs +0 -80
- package/dist/chunk-I5LR3D2K.js +0 -869
- package/dist/chunk-N23SKIG4.js +0 -73
- package/dist/chunk-QQ6ULXHI.cjs +0 -885
- package/dist/node-evaluator-4MSDKWOG.cjs +0 -22
- package/dist/node-evaluator-SX4LEYQC.js +0 -12
package/dist/chunk-I5LR3D2K.js
DELETED
|
@@ -1,869 +0,0 @@
|
|
|
1
|
-
import { COLLECTION_FORMAT } from './chunk-XKJA7KX3.js';
|
|
2
|
-
import { internalNodes, parseLayoutSidecar, assembleRecording, RECORDING_FORMAT, RECORDING_FORMAT_VERSION, defineWorkflow, op } from './chunk-HWJZVOG7.js';
|
|
3
|
-
import { sourceHash, buildIdOf, CODE_WORKFLOW_NODE_TYPE } from './chunk-BD7ZPG53.js';
|
|
4
|
-
import { isRecord } from './chunk-PMCM2OH4.js';
|
|
5
|
-
import { SDK_VERSION } from './chunk-N23SKIG4.js';
|
|
6
|
-
import { isActivityNodeTypeAllowed } from './chunk-BO6OVILK.js';
|
|
7
|
-
import { Worker } from 'worker_threads';
|
|
8
|
-
|
|
9
|
-
// src/roundtrip/lower-types.ts
|
|
10
|
-
var LowerError = class extends Error {
|
|
11
|
-
constructor(message, reason, diagnostics = []) {
|
|
12
|
-
super(message);
|
|
13
|
-
this.reason = reason;
|
|
14
|
-
this.name = "LowerError";
|
|
15
|
-
this.diagnostics = diagnostics;
|
|
16
|
-
}
|
|
17
|
-
reason;
|
|
18
|
-
/** The compiler messages, when bundling failed; empty otherwise. */
|
|
19
|
-
diagnostics;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
// src/generated/runtime-source.ts
|
|
23
|
-
var RUNTIME_SOURCE = 'function isRecord(value) {\n return typeof value === "object" && value !== null && !Array.isArray(value);\n}\nfunction setOwn(target, key, value) {\n Object.defineProperty(target, key, {\n value,\n enumerable: true,\n writable: true,\n configurable: true\n });\n}\nfunction ownValue(record, key) {\n return Object.hasOwn(record, key) ? record[key] : void 0;\n}\nfunction cloneJson(value) {\n return structuredCloneJson(value);\n}\nfunction structuredCloneJson(value) {\n if (Array.isArray(value)) return value.map(structuredCloneJson);\n if (isRecord(value)) {\n const out = {};\n for (const [key, child] of Object.entries(value)) {\n if (child !== void 0) setOwn(out, key, structuredCloneJson(child));\n }\n return out;\n }\n return value;\n}\n\nfunction op(nodeType, version, operation) {\n return {\n kind: "operation",\n nodeType,\n ...version !== void 0 ? { version } : {},\n ...operation !== void 0 ? { operation } : {}\n };\n}\nfunction trigger(nodeType, version, operation) {\n return { ...op(nodeType, version, operation), role: "trigger" };\n}\nfunction isOperation(value) {\n return typeof value === "object" && value !== null && value.kind === "operation" && typeof value.nodeType === "string";\n}\nvar triggers = {\n api: trigger("internal:api"),\n manual: trigger("internal:api"),\n schedule: trigger("internal:schedule"),\n webhook: trigger("internal:webhook"),\n form: trigger("internal:form"),\n errorTrigger: trigger("internal:error-trigger"),\n workflowCall: trigger("internal:workflow-call"),\n rssFeed: trigger("internal:rss-feed"),\n httpPoll: trigger("internal:http-poll"),\n databasePoll: trigger("internal:database-poll"),\n emailImap: trigger("internal:email-imap"),\n fileUpload: trigger("internal:file-upload"),\n recordChange: trigger("internal:record-change"),\n stateChange: trigger("internal:state-change")\n};\nvar internalNodes = {\n merge: op("internal:merge"),\n if: op("internal:if"),\n switch: op("internal:switch"),\n loop: op("internal:loop"),\n set: op("internal:set"),\n filter: op("internal:filter"),\n aggregate: op("internal:aggregate"),\n wait: op("internal:wait"),\n noop: op("internal:noop"),\n code: op("internal:code"),\n http: op("internal:http"),\n transform: op("internal:transform"),\n validate: op("internal:validate"),\n log: op("internal:log"),\n error: op("internal:error"),\n subworkflow: op("internal:subworkflow"),\n compareDatasets: op("internal:compare-datasets"),\n splitOut: op("internal:split-out"),\n limit: op("internal:limit"),\n dedupe: op("internal:dedupe"),\n sort: op("internal:sort"),\n dataTable: op("internal:datatable"),\n respondToWebhook: op("internal:respond-to-webhook"),\n sendAndWait: op("internal:send-and-wait"),\n codeWorkflow: op("internal:code-workflow"),\n waitForSignal: op("internal:wait-for-signal")\n};\nvar nodes = {\n internal: internalNodes,\n /**\n * Any node type, including ones the registry snapshot does not know. Typed\n * as JSON in and out.\n */\n custom(nodeType, operation, version) {\n return op(nodeType, version, operation);\n }\n};\n\nvar DURABLE_MARKER = "fluidgrids.durable-workflow";\nvar KEY = /^[a-z0-9][a-z0-9_-]{0,127}$/;\nfunction workflow(name, optionsOrFn, maybeFn) {\n if (typeof name !== "string" || !KEY.test(name))\n throw new TypeError(\n `workflow() needs a key of lowercase letters, digits, "-" and "_" (got "${String(name)}")`\n );\n const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;\n const options = typeof optionsOrFn === "function" ? {} : optionsOrFn ?? {};\n if (typeof fn !== "function") throw new TypeError(`workflow("${name}") needs a function`);\n return Object.freeze({ __fluidgrids: DURABLE_MARKER, name, options, fn });\n}\nfunction isDurableWorkflow(value) {\n return typeof value === "object" && value !== null && value.__fluidgrids === DURABLE_MARKER && typeof value.fn === "function";\n}\nfunction isJsonValue(value, depth = 0) {\n if (depth > 64) return false;\n if (value === null || typeof value === "string" || typeof value === "boolean") return true;\n if (typeof value === "number") return Number.isFinite(value);\n if (Array.isArray(value)) return value.every((item) => isJsonValue(item, depth + 1));\n if (typeof value === "object") {\n if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)\n return false;\n return Object.values(value).every((item) => isJsonValue(item, depth + 1));\n }\n return false;\n}\nfunction jsonSchemaOf(schema) {\n if (schema === void 0) return void 0;\n const method = schema.toJSONSchema;\n if (typeof method === "function") {\n const produced = method.call(schema);\n return isJsonValue(produced) && typeof produced === "object" && !Array.isArray(produced) && produced !== null ? produced : void 0;\n }\n return isJsonValue(schema) && !Array.isArray(schema) && schema !== null && typeof schema === "object" ? schema : void 0;\n}\nfunction interfaceOf(definition) {\n const out = {};\n const input = jsonSchemaOf(definition.options.input);\n const output = jsonSchemaOf(definition.options.output);\n if (input) out.input = input;\n if (output) out.output = output;\n const signals = definition.options.signals ?? [];\n if (signals.length > 0) {\n out.signals = {};\n for (const signal of signals) {\n const entry = {};\n const payload = jsonSchemaOf(signal.schema);\n if (payload) entry.payload = payload;\n if (signal.description !== void 0) entry.description = signal.description;\n out.signals[signal.name] = entry;\n }\n }\n const queries = definition.options.queries ?? [];\n if (queries.length > 0) {\n out.queries = {};\n for (const query of queries)\n out.queries[query.name] = query.description !== void 0 ? { description: query.description } : {};\n }\n const updates = definition.options.updates ?? [];\n if (updates.length > 0) {\n out.updates = {};\n for (const update of updates)\n out.updates[update.name] = update.description !== void 0 ? { description: update.description } : {};\n }\n return out;\n}\n\nvar IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\nfunction segmentFromKey(key) {\n return /^(0|[1-9][0-9]{0,8})$/.test(key) ? { kind: "index", index: Number(key) } : { kind: "key", key };\n}\nfunction formatPath(path) {\n return path.map((segment) => {\n if (segment.kind === "index") return `[${segment.index}]`;\n return IDENTIFIER.test(segment.key) ? `.${segment.key}` : `[${JSON.stringify(segment.key)}]`;\n }).join("");\n}\nfunction formatRefExpression(ref) {\n const path = formatPath(ref.path);\n switch (ref.root.kind) {\n case "node":\n return `$node[${JSON.stringify(ref.root.nodeId)}].item${path}`;\n case "json":\n return `$json${path}`;\n case "vars":\n return `$vars${path}`;\n case "now":\n return `$now${path}`;\n case "execution":\n return `$execution${path}`;\n }\n}\nfunction formatRefTemplate(ref) {\n return `{{ ${formatRefExpression(ref)} }}`;\n}\n\nvar REF_MODEL = /* @__PURE__ */ Symbol.for("fluidgrids.workflows.ref");\nvar PREDICATE = /* @__PURE__ */ Symbol.for("fluidgrids.workflows.predicate");\nvar PREDICATE_OPERATORS = {\n eq: { operator: "==", unary: false },\n neq: { operator: "!=", unary: false },\n gt: { operator: ">", unary: false },\n gte: { operator: ">=", unary: false },\n lt: { operator: "<", unary: false },\n lte: { operator: "<=", unary: false },\n contains: { operator: "contains", unary: false },\n notContains: { operator: "notContains", unary: false },\n startsWith: { operator: "startsWith", unary: false },\n endsWith: { operator: "endsWith", unary: false },\n matches: { operator: "regex", unary: false },\n hasProperty: { operator: "hasProperty", unary: false },\n isEmpty: { operator: "isEmpty", unary: true },\n isNotEmpty: { operator: "isNotEmpty", unary: true },\n isNull: { operator: "isNull", unary: true },\n isNotNull: { operator: "isNotNull", unary: true },\n isTrue: { operator: "isTrue", unary: true },\n isFalse: { operator: "isFalse", unary: true }\n};\nvar BuilderError = class extends Error {\n constructor(message) {\n super(message);\n this.name = "BuilderError";\n }\n};\nfunction isRuleValue(value) {\n return value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);\n}\nfunction conditionField(ref) {\n const segments = ref.path.map((segment) => {\n const text = segment.kind === "index" ? String(segment.index) : segment.key;\n if (text === "" || text.includes(".")) {\n throw new BuilderError(\n `A condition cannot address the key "${text}" (condition fields are dot-separated); use a raw condition tree`\n );\n }\n return text;\n });\n switch (ref.root.kind) {\n case "node":\n if (ref.root.nodeId.includes(".")) {\n throw new BuilderError(\n `A condition cannot address node "${ref.root.nodeId}"; its id contains a dot`\n );\n }\n return ["WorkflowState", ref.root.nodeId, ...segments].join(".");\n case "json":\n return ["output", ...segments].join(".");\n default:\n throw new BuilderError(\n `A condition can compare node outputs and $json only, not $${ref.root.kind}; use an expression`\n );\n }\n}\nfunction makePredicate(target, operator, args, unary) {\n const rule = { type: "rule", field: conditionField(target), operator };\n if (!unary) {\n if (args.length < 1 || !isRuleValue(args[0])) {\n throw new BuilderError(\n `The "${operator}" comparison needs a string, number, boolean or null value`\n );\n }\n rule.value = args[0];\n } else if (args.length > 0) {\n throw new BuilderError(`The "${operator}" comparison takes no value`);\n }\n return { [PREDICATE]: rule };\n}\nfunction callOnRef(model, args) {\n const last = model.path[model.path.length - 1];\n if (last?.kind !== "key") {\n throw new BuilderError("A reference is not a function; call a comparison such as .gte(500)");\n }\n const parent = { root: model.root, path: model.path.slice(0, -1) };\n if (last.key === "is") {\n const [operator, ...rest] = args;\n if (typeof operator !== "string" || operator === "") {\n throw new BuilderError(".is(operator, value) needs an operator name");\n }\n return makePredicate(parent, operator, rest, rest.length === 0);\n }\n const known = PREDICATE_OPERATORS[last.key];\n if (!known) {\n throw new BuilderError(`"${last.key}" is not a comparison; references are data, not functions`);\n }\n return makePredicate(parent, known.operator, args, known.unary);\n}\nfunction makeRef(root, path = []) {\n const model = { root, path };\n const render = () => formatRefTemplate(model);\n const target = function fluidgridsRef() {\n return void 0;\n };\n const handler = {\n get(_target, property) {\n if (property === REF_MODEL) return model;\n if (property === Symbol.toPrimitive) return render;\n if (typeof property === "symbol") return void 0;\n if (property === "then") return void 0;\n if (property === "toJSON" || property === "toString" || property === "valueOf") return render;\n return makeRef(root, [...path, segmentFromKey(property)]);\n },\n apply(_target, _thisArg, args) {\n return callOnRef(model, args);\n },\n has(_target, property) {\n return property === REF_MODEL;\n },\n set() {\n throw new BuilderError("References are read-only");\n }\n };\n return new Proxy(target, handler);\n}\nfunction refModelOf(value) {\n if ((typeof value === "function" || typeof value === "object") && value !== null && REF_MODEL in value) {\n const model = value[REF_MODEL];\n return model;\n }\n return void 0;\n}\nfunction isPredicate(value) {\n return typeof value === "object" && value !== null && PREDICATE in value;\n}\nfunction predicateTree(predicate) {\n return predicate[PREDICATE];\n}\nfunction group(combinator, predicates) {\n if (predicates.length === 0)\n throw new BuilderError(`${combinator.toLowerCase()}() needs at least one condition`);\n for (const predicate of predicates) {\n if (!isPredicate(predicate))\n throw new BuilderError(`${combinator.toLowerCase()}() takes conditions only`);\n }\n return { [PREDICATE]: { type: "group", combinator, children: predicates.map(predicateTree) } };\n}\nfunction and(...predicates) {\n return group("AND", predicates);\n}\nfunction or(...predicates) {\n return group("OR", predicates);\n}\nfunction conditionTreeOf(predicate) {\n const tree = predicateTree(predicate);\n return tree.type === "group" ? tree : { type: "group", combinator: "AND", children: [tree] };\n}\nfunction expr(strings, ...values) {\n let out = strings[0] ?? "";\n values.forEach((value, index) => {\n const model = refModelOf(value);\n if (model) out += formatRefTemplate(model);\n else if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {\n out += String(value);\n } else {\n throw new BuilderError("expr`\u2026` interpolates references, strings, numbers and booleans only");\n }\n out += strings[index + 1] ?? "";\n });\n return out;\n}\n\nvar RECORDING_FORMAT = "fluidgrids.tier1-recording";\nvar RECORDING_FORMAT_VERSION = 1;\nvar WORKFLOW_MARKER = "fluidgrids.tier1-workflow";\nfunction edge(from, options = {}) {\n return { kind: "edge", from, ...options };\n}\nfunction isTier1Workflow(value) {\n return isRecord(value) && value["__fluidgrids"] === WORKFLOW_MARKER && isRecord(value["recording"]);\n}\nfunction deepMerge(base, extra, path) {\n for (const [key, value] of Object.entries(extra)) {\n const existing = ownValue(base, key);\n if (isRecord(existing) && isRecord(value)) {\n deepMerge(existing, value, `${path}.${key}`);\n } else if (existing !== void 0) {\n throw new BuilderError(\n `extra sets ${path}.${key}, which the builder already wrote; use the typed option`\n );\n } else {\n setOwn(base, key, lowerValue(value, `${path}.${key}`));\n }\n }\n}\nfunction lowerValue(value, path) {\n const model = refModelOf(value);\n if (model) return formatRefTemplate(model);\n if (value === null || typeof value === "string" || typeof value === "boolean") return value;\n if (typeof value === "number") {\n if (!Number.isFinite(value)) throw new BuilderError(`${path} is not a finite number`);\n return value;\n }\n if (Array.isArray(value))\n return value.map((item, index) => lowerValue(item, `${path}[${index}]`));\n if (isPredicate(value)) {\n throw new BuilderError(`${path} is a condition; conditions belong in wf.if({ condition })`);\n }\n if (isRecord(value)) {\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) {\n throw new BuilderError(`${path} is not a plain object`);\n }\n const out = {};\n for (const [key, child] of Object.entries(value)) {\n if (child === void 0) continue;\n setOwn(out, key, lowerValue(child, `${path}.${key}`));\n }\n return out;\n }\n throw new BuilderError(`${path} cannot be stored in a workflow definition (${typeof value})`);\n}\nfunction lowerObject(value, path) {\n const lowered = lowerValue(value, path);\n if (!isRecord(lowered)) throw new BuilderError(`${path} must be an object`);\n return lowered;\n}\nfunction slugify(text) {\n const slug = text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 50);\n return /^[a-z]/.test(slug) ? slug : `node-${slug || "x"}`;\n}\nfunction handleRef(nodeId, handle) {\n return { kind: "handle", nodeId, handle };\n}\nfunction nodeRef(id) {\n return {\n kind: "node",\n id,\n // An untyped reference serves every output type; the static type comes from the operation.\n output: makeRef({ kind: "node", nodeId: id }),\n handle: (name) => handleRef(id, name)\n };\n}\nfunction isNodeRef(value) {\n return isRecord(value) && value["kind"] === "node" && typeof value["id"] === "string";\n}\nfunction isHandleRef(value) {\n return isRecord(value) && value["kind"] === "handle" && typeof value["nodeId"] === "string";\n}\nfunction isEdgeSpec(value) {\n return isRecord(value) && value["kind"] === "edge" && "from" in value;\n}\nfunction sourceOf(from) {\n if (typeof from === "string") return { source: from };\n if (isHandleRef(from)) return { source: from.nodeId, sourceHandle: from.handle };\n if (isNodeRef(from)) return { source: from.id };\n throw new BuilderError("after takes node references, handles, node ids or edge(\u2026) entries");\n}\nfunction defaultEdgeId(source, target, sourceHandle, targetHandle) {\n return ["e", source, target, sourceHandle, targetHandle].filter((part) => Boolean(part)).join("-");\n}\nvar LIMIT_UNITS = {\n s: "seconds",\n m: "minutes",\n h: "hours",\n d: "days",\n w: "weeks"\n};\nfunction limitWait(limit) {\n if (typeof limit === "string") {\n const match = /^([1-9][0-9]*)([smhdw])$/.exec(limit);\n const unit = match?.[2] !== void 0 ? LIMIT_UNITS[match[2]] : void 0;\n if (!match?.[1] || !unit)\n throw new BuilderError(`limit "${limit}" must look like 30s, 15m, 2h, 3d or 1w`);\n return { amount: Number(match[1]), unit };\n }\n return { amount: limit.amount, unit: limit.unit };\n}\nvar WorkflowBuilder = class {\n constructor(autoIds) {\n this.autoIds = autoIds;\n }\n autoIds;\n /** `$json`: the current item\'s JSON. */\n json = makeRef({ kind: "json" });\n /** `$vars`: workflow variables. */\n vars = makeRef({ kind: "vars" });\n /** `$now`. */\n now = makeRef({ kind: "now" });\n /** `$execution`: run metadata. */\n execution = makeRef({ kind: "execution" });\n nodes = [];\n edges = [];\n notes = [];\n ids = /* @__PURE__ */ new Set();\n /** Ids given explicitly; a second edge with the same explicit id is an error. */\n edgeIds = /* @__PURE__ */ new Set();\n /** Edges whose id is the default, as indices into `edges`, with the unsuffixed default id. */\n defaultIds = [];\n edgeOrder;\n durableRefs = [];\n /** A reference to a node by id, for nodes declared later in the source. */\n ref(id) {\n return nodeRef(id);\n }\n /** A trigger node. */\n trigger(operation, options = {}) {\n return this.add(operation, options, {});\n }\n /** A store or internal node. */\n step(operation, options = {}) {\n return this.add(operation, options, {});\n }\n /** `internal:if`. */\n if(options) {\n const { condition, ...rest } = options;\n const sugar = {};\n if (condition !== void 0) {\n if (typeof condition === "string") sugar["condition"] = condition;\n else if (isPredicate(condition)) sugar["conditionTree"] = conditionTreeOf(condition);\n else\n throw new BuilderError(\n "condition takes a comparison such as x.output.total.gte(500), and(), or() or a string"\n );\n }\n const ref = this.add(internalNodes.if, rest, sugar);\n return { ...ref, true: ref.handle("true"), false: ref.handle("false") };\n }\n /** `internal:switch`. */\n switch(options) {\n const { value, cases, ...rest } = options;\n const sugar = {};\n if (value !== void 0) sugar["switchValue"] = value;\n if (cases !== void 0) sugar["cases"] = cases;\n const ref = this.add(internalNodes.switch, rest, sugar);\n return { ...ref, case: (handle) => ref.handle(handle), default: ref.handle("default") };\n }\n /**\n * `internal:loop`. With a body callback, the nodes the callback declares\n * after `batch` form the loop body and the builder adds the return edge from\n * the node the callback returns.\n */\n loop(options, body) {\n const { items, batchSize, ...rest } = options;\n const sugar = {};\n if (items !== void 0) sugar["sourceArray"] = items;\n if (batchSize !== void 0) sugar["batchSize"] = batchSize;\n const ref = this.add(internalNodes.loop, rest, sugar);\n const loopRef = { ...ref, body: ref.handle("loop"), done: ref.handle("done") };\n if (body) {\n const last = body(loopRef.body);\n if (last !== void 0) this.connect(last, ref.id, {});\n }\n return loopRef;\n }\n /** `internal:merge`. */\n merge(options) {\n const { inputs, mode, ...rest } = options;\n const sugar = {};\n if (mode !== void 0) sugar["mode"] = mode;\n if (inputs !== void 0 && rest.after !== void 0) {\n throw new BuilderError("merge takes inputs or after, not both");\n }\n const after = inputs?.map(\n (input, index) => edge(input, { targetHandle: `input-${index + 1}` })\n );\n return this.add(internalNodes.merge, after ? { ...rest, after } : rest, sugar);\n }\n /** `internal:wait`. */\n wait(options) {\n return this.add(internalNodes.wait, options, {});\n }\n /** `internal:wait-for-signal` (IR v2). */\n waitForSignal(options) {\n const { name, limit, until, consume, ...rest } = options;\n if (limit !== void 0 && until !== void 0)\n throw new BuilderError("wf.waitForSignal takes limit or until, not both");\n if (consume !== void 0 && consume !== "first" && consume !== "all")\n throw new BuilderError(`consume must be "first" or "all" (got "${String(consume)}")`);\n const sugar = {};\n if (name !== void 0) sugar["signalName"] = name;\n if (consume !== void 0) sugar["consume"] = consume;\n if (limit !== void 0) sugar["limitWait"] = limitWait(limit);\n if (until !== void 0) {\n const deadline = until instanceof Date ? until.toISOString() : until;\n if (typeof deadline !== "string" || Number.isNaN(Date.parse(deadline)))\n throw new BuilderError(`until "${String(until)}" is not an ISO 8601 date-time`);\n sugar["limitWaitUntil"] = deadline;\n }\n const ref = this.add(internalNodes.waitForSignal, rest, sugar);\n return { ...ref, received: ref.handle("received"), timedOut: ref.handle("timedOut") };\n }\n /** `internal:send-and-wait`. */\n sendAndWait(options) {\n const ref = this.add(internalNodes.sendAndWait, options, {});\n return {\n ...ref,\n approved: ref.handle("approved"),\n declined: ref.handle("declined"),\n timedOut: ref.handle("timedOut")\n };\n }\n /** `internal:subworkflow`. */\n subworkflow(options) {\n const { key, targetVersion, input, ...rest } = options;\n const sugar = {};\n if (key !== void 0) sugar["workflowKey"] = key;\n if (targetVersion !== void 0) sugar["version"] = targetVersion;\n if (input !== void 0) sugar["inputMapping"] = input;\n return this.add(internalNodes.subworkflow, rest, sugar);\n }\n /**\n * `internal:code-workflow`: run a tier-2 function of this project as a\n * durable child run. `fn` is a `workflow()` value (its export name is\n * resolved when the bundle is collected) or an export name.\n */\n codeWorkflow(fn, options = {}) {\n const {\n input,\n taskQueue,\n waitForCompletion,\n timeoutSeconds,\n failOnError,\n parentClosePolicy,\n ...rest\n } = options;\n let workflowFn;\n let definition;\n if (typeof fn === "string" && fn !== "") workflowFn = fn;\n else if (isDurableWorkflow(fn)) {\n definition = fn;\n workflowFn = fn.name;\n } else throw new BuilderError("wf.codeWorkflow needs a workflow() function or its export name");\n if (parentClosePolicy !== void 0 && !["TERMINATE", "ABANDON", "REQUEST_CANCEL"].includes(parentClosePolicy))\n throw new BuilderError(`parentClosePolicy "${String(parentClosePolicy)}" is not a policy`);\n const sugar = { workflowFn };\n if (input !== void 0) sugar["inputMapping"] = input;\n if (taskQueue !== void 0) sugar["taskQueue"] = taskQueue;\n if (waitForCompletion !== void 0) sugar["waitForCompletion"] = waitForCompletion;\n if (timeoutSeconds !== void 0) sugar["timeout"] = timeoutSeconds;\n if (failOnError !== void 0) sugar["failOnError"] = failOnError;\n if (parentClosePolicy !== void 0) sugar["parentClosePolicy"] = parentClosePolicy;\n const ref = this.add(internalNodes.codeWorkflow, rest, sugar);\n if (definition) this.durableRefs.push({ nodeId: ref.id, definition });\n return ref;\n }\n /** The `wf.codeWorkflow` calls that named a function. */\n durableReferences() {\n return [...this.durableRefs];\n }\n /** `internal:validate`. */\n validate(options) {\n const ref = this.add(internalNodes.validate, options, {});\n return { ...ref, valid: ref.handle("valid"), invalid: ref.handle("invalid") };\n }\n /** `internal:compare-datasets`. */\n compareDatasets(options) {\n const ref = this.add(internalNodes.compareDatasets, options, {});\n return {\n ...ref,\n inAOnly: ref.handle("inAOnly"),\n inBOnly: ref.handle("inBOnly"),\n same: ref.handle("same"),\n different: ref.handle("different")\n };\n }\n /** `internal:set`. */\n set(options) {\n return this.add(internalNodes.set, options, {});\n }\n /** `internal:filter`. */\n filter(options) {\n return this.add(internalNodes.filter, options, {});\n }\n /** `internal:aggregate`. */\n aggregate(options) {\n return this.add(internalNodes.aggregate, options, {});\n }\n /** `internal:split-out`. */\n splitOut(options) {\n return this.add(internalNodes.splitOut, options, {});\n }\n /** `internal:limit`. */\n limit(options) {\n return this.add(internalNodes.limit, options, {});\n }\n /** `internal:dedupe`. */\n dedupe(options) {\n return this.add(internalNodes.dedupe, options, {});\n }\n /** `internal:sort`. */\n sort(options) {\n return this.add(internalNodes.sort, options, {});\n }\n /** `internal:datatable`. */\n dataTable(options) {\n return this.add(internalNodes.dataTable, options, {});\n }\n /** `internal:http`. */\n http(options) {\n return this.add(internalNodes.http, options, {});\n }\n /** `internal:code`. The code is a string (`args.code`), so it round-trips byte for byte. */\n code(options) {\n return this.add(internalNodes.code, options, {});\n }\n /** `internal:transform`. */\n transform(options) {\n return this.add(internalNodes.transform, options, {});\n }\n /** `internal:log`. */\n log(options) {\n return this.add(internalNodes.log, options, {});\n }\n /** `internal:respond-to-webhook`. */\n respondToWebhook(options) {\n return this.add(internalNodes.respondToWebhook, options, {});\n }\n /** `internal:error` (stop and error). */\n stopAndError(options) {\n return this.add(internalNodes.error, options, {});\n }\n /** `internal:noop`. */\n noop(options) {\n return this.add(internalNodes.noop, options, {});\n }\n /** A sticky note on the canvas. */\n note(content, options) {\n if (typeof content !== "string") throw new BuilderError("A note takes Markdown text");\n this.claimId(options.id, "sticky note");\n const near = options.near === void 0 ? void 0 : typeof options.near === "string" ? options.near : options.near.id;\n this.notes.push({\n note: {\n id: options.id,\n type: "sticky-note",\n width: 260,\n height: 170,\n zIndex: -1,\n data: { content, color: options.color ?? "yellow" }\n },\n ...near !== void 0 ? { near } : {}\n });\n }\n /** An edge added outside `after`, for example a loop\'s return edge. */\n connect(from, to, options = {}) {\n const target = typeof to === "string" ? to : to.id;\n this.addEdge(edge(from, options), target);\n }\n /**\n * Put `data.edges` in this exact order. Each entry names one edge, by id or,\n * for an edge without an id, by its position in declaration order; every edge\n * appears once. The lifter emits this when a stored definition\'s edge order\n * differs from the order the code declares its edges in.\n */\n edgeOrderIs(order) {\n if (this.edgeOrder) throw new BuilderError("edgeOrderIs() may be called once");\n this.edgeOrder = [...order];\n }\n /** The recording, once the callback has returned. */\n finish(key, document) {\n this.assignDefaultEdgeIds();\n return {\n format: RECORDING_FORMAT,\n formatVersion: RECORDING_FORMAT_VERSION,\n key,\n document,\n nodes: this.nodes,\n edges: this.edges,\n ...this.edgeOrder ? { edgeOrder: this.edgeOrder } : {},\n notes: this.notes\n };\n }\n claimId(id, what) {\n if (typeof id !== "string" || id === "") throw new BuilderError(`A ${what} needs an id`);\n if (this.ids.has(id)) throw new BuilderError(`Duplicate id "${id}"`);\n this.ids.add(id);\n }\n resolveId(options, operation) {\n if (options.id !== void 0) return options.id;\n if (!this.autoIds) {\n throw new BuilderError(`Every node needs an id (a ${operation.nodeType} node has none)`);\n }\n const base = slugify(options.label ?? operation.nodeType.split(/[:/]/).pop() ?? "node");\n let candidate = base;\n for (let suffix = 2; this.ids.has(candidate); suffix++) candidate = `${base}-${suffix}`;\n return candidate;\n }\n /**\n * Give every edge declared without an id its default id. Explicit ids are\n * claimed first, so a default never takes an id the code names; a default that\n * is taken gets `-2`, `-3`, \u2026 in declaration order. The result depends only on\n * the builder calls.\n */\n assignDefaultEdgeIds() {\n const taken = new Set(this.edgeIds);\n for (const { index, base } of this.defaultIds) {\n let id = base;\n for (let suffix = 2; taken.has(id); suffix++) id = `${base}-${suffix}`;\n taken.add(id);\n const built = this.edges[index];\n if (built) built.id = id;\n }\n this.defaultIds.length = 0;\n }\n addEdge(spec, target) {\n const { source, sourceHandle } = sourceOf(spec.from);\n const explicit = typeof spec.id === "string" ? spec.id : void 0;\n if (spec.id !== void 0 && spec.id !== false && explicit === void 0)\n throw new BuilderError("An edge id must be a string or false");\n if (explicit !== void 0) {\n if (this.edgeIds.has(explicit)) throw new BuilderError(`Duplicate edge id "${explicit}"`);\n this.edgeIds.add(explicit);\n }\n const base = spec.id === void 0 ? defaultEdgeId(source, target, sourceHandle, spec.targetHandle) : void 0;\n const id = explicit ?? base;\n if (base !== void 0) this.defaultIds.push({ index: this.edges.length, base });\n const built = id !== void 0 ? { id, source, target } : { source, target };\n if (sourceHandle !== void 0) built["sourceHandle"] = sourceHandle;\n if (spec.targetHandle !== void 0) built["targetHandle"] = spec.targetHandle;\n if (spec.type !== false) built["type"] = spec.type ?? "deletable";\n if (spec.label !== void 0) built["label"] = spec.label;\n const where = `edge ${id ?? `${source}->${target}`}`;\n if (spec.data !== void 0) built["data"] = lowerObject(spec.data, `${where} data`);\n if (spec.mapping !== void 0)\n built["mapping"] = lowerObject(spec.mapping, `${where} mapping`);\n if (spec.extra !== void 0)\n deepMerge(built, lowerObject(spec.extra, `${where} extra`), where);\n this.edges.push(built);\n }\n add(operation, options, sugar) {\n if (!isOperation(operation)) {\n throw new BuilderError(\n "The first argument must be a node operation (nodes.*, triggers.* or a generated client)"\n );\n }\n if (typeof options !== "object" || options === null || Array.isArray(options)) {\n throw new BuilderError("Node options must be an object");\n }\n const id = this.resolveId(options, operation);\n this.claimId(id, "node");\n const where = `node ${id}`;\n const node = { id, type: operation.nodeType };\n if (options.label !== void 0) node["label"] = options.label;\n const operationName = options.operation === false ? void 0 : options.operation ?? operation.operation;\n if (operationName !== void 0) node["operation_name"] = operationName;\n const version = options.version === false ? void 0 : options.version ?? operation.version;\n if (version !== void 0) node["version"] = version;\n const args = {};\n const explicitArgs = options.args === void 0 ? void 0 : lowerObject(options.args, `${where} args`);\n const sugarArgs = lowerObject(sugar, `${where} args`);\n if (explicitArgs || Object.keys(sugarArgs).length > 0) {\n for (const key of Object.keys(sugarArgs)) {\n if (explicitArgs && Object.hasOwn(explicitArgs, key)) {\n throw new BuilderError(`${where}: "${key}" is set twice (by an option and in args)`);\n }\n }\n args["state"] = { ...explicitArgs, ...sugarArgs };\n }\n if (options.connection !== void 0 && options.connections !== void 0) {\n throw new BuilderError(`${where}: use connection (names) or connections (ids), not both`);\n }\n const connectionNames = options.connection === void 0 ? void 0 : typeof options.connection === "string" ? [options.connection] : [...options.connection];\n if (connectionNames?.some((name) => typeof name !== "string" || name === "")) {\n throw new BuilderError(`${where}: connection names must be non-empty strings`);\n }\n if (options.connections !== void 0)\n args["connections"] = lowerValue(options.connections, `${where} connections`);\n if (options.credentials !== void 0)\n args["credentials"] = lowerValue(options.credentials, `${where} credentials`);\n if (options.context !== void 0)\n args["context"] = lowerObject(options.context, `${where} context`);\n if (Object.keys(args).length > 0 || connectionNames) node["args"] = args;\n const hasSugar = options.retry !== void 0 || options.timeout !== void 0 || options.onError !== void 0;\n if (options.errorConfig !== void 0 && hasSugar) {\n throw new BuilderError(`${where}: use errorConfig or retry / timeout / onError, not both`);\n }\n if (options.errorConfig !== void 0) {\n node["errorConfig"] = lowerObject(options.errorConfig, `${where} errorConfig`);\n } else if (hasSugar) {\n const errorConfig = {};\n if (typeof options.onError === "string") errorConfig["onError"] = options.onError;\n else if (options.onError !== void 0) {\n errorConfig["onError"] = "branch";\n errorConfig["errorBranchId"] = options.onError.branch;\n }\n if (options.retry !== void 0)\n errorConfig["retryConfig"] = lowerObject(options.retry, `${where} retry`);\n if (options.timeout !== void 0)\n errorConfig["timeout"] = lowerObject(options.timeout, `${where} timeout`);\n node["errorConfig"] = errorConfig;\n }\n if (options.executionSettings !== void 0) {\n const settings = lowerObject(options.executionSettings, `${where} executionSettings`);\n node["executionSettings"] = settings;\n if (settings["runOn"] !== void 0)\n node["data"] = { executionSettings: { runOn: settings["runOn"] } };\n }\n if (options.disabled !== void 0) node["disabled"] = options.disabled;\n if (options.extra !== void 0)\n deepMerge(node, lowerObject(options.extra, `${where} extra`), where);\n this.nodes.push({\n // Built field by field above from lowered JSON.\n node,\n ...connectionNames ? { connectionNames } : {}\n });\n const after = options.after === void 0 ? [] : Array.isArray(options.after) ? options.after : [options.after];\n for (const entry of after) {\n this.addEdge(isEdgeSpec(entry) ? entry : edge(entry), id);\n }\n return nodeRef(id);\n }\n};\nfunction defineWorkflow(options, build) {\n if (typeof options !== "object" || options === null || typeof options.key !== "string" || options.key === "") {\n throw new BuilderError("defineWorkflow needs a key");\n }\n const builder = new WorkflowBuilder(options.autoIds === true);\n build(builder);\n const document = { key: options.key };\n if (options.name !== void 0) document["name"] = options.name;\n if (options.description !== void 0) document["description"] = options.description;\n if (options.interface !== void 0)\n document["interface"] = lowerObject(options.interface, "interface");\n if (options.code !== void 0) document["code"] = lowerObject(options.code, "code");\n if (options.config !== void 0) document["config"] = lowerObject(options.config, "config");\n if (options.meta !== void 0) document["meta"] = lowerObject(options.meta, "meta");\n if (options.tags !== void 0) document["tags"] = lowerValue(options.tags, "tags");\n if (options.extra !== void 0)\n deepMerge(document, lowerObject(options.extra, "extra"), "workflow");\n const recording = builder.finish(options.key, document);\n const durableRefs = builder.durableReferences();\n return {\n __fluidgrids: WORKFLOW_MARKER,\n key: options.key,\n recording,\n ...durableRefs.length > 0 ? { durableRefs } : {}\n };\n}\n\nvar LAYOUT_COLUMN_WIDTH = 300;\nvar LAYOUT_ROW_HEIGHT = 170;\nfunction autoLayout(nodeIds, edges) {\n const depth = /* @__PURE__ */ new Map();\n const roots = nodeIds.filter((id) => !edges.some((edge2) => edge2.target === id));\n const queue = [...roots];\n for (const id of queue) depth.set(id, 0);\n const guardLimit = nodeIds.length * nodeIds.length + 1;\n for (let guard = 0; queue.length > 0 && guard < guardLimit; guard++) {\n const current = queue.shift();\n if (current === void 0) break;\n const currentDepth = depth.get(current) ?? 0;\n for (const edge2 of edges) {\n if (edge2.source !== current) continue;\n const next = currentDepth + 1;\n if (next > (depth.get(edge2.target) ?? -1) && next < nodeIds.length) {\n depth.set(edge2.target, next);\n queue.push(edge2.target);\n }\n }\n }\n const maxDepth = Math.max(0, ...depth.values());\n const columns = /* @__PURE__ */ new Map();\n for (const id of nodeIds) {\n const column = depth.get(id) ?? maxDepth + 1;\n columns.set(column, [...columns.get(column) ?? [], id]);\n }\n const positions = /* @__PURE__ */ new Map();\n for (const [column, ids] of columns) {\n ids.forEach((id, row) => {\n positions.set(id, {\n x: column * LAYOUT_COLUMN_WIDTH,\n // `+ 0` turns the -0 Math.round can return into 0, so JSON never sees -0.\n y: Math.round((row - (ids.length - 1) / 2) * LAYOUT_ROW_HEIGHT) + 0\n });\n });\n }\n return positions;\n}\n\nvar SDK_VERSION = "2026.1028.2";\n\nvar LAYOUT_FORMAT = "fluidgrids.layout";\nvar LAYOUT_FORMAT_VERSION = 1;\nvar UnresolvedConnectionsError = class extends Error {\n constructor(names) {\n super(`Create these connections in the workspace first: ${names.join(", ")}`);\n this.names = names;\n this.name = "UnresolvedConnectionsError";\n }\n names;\n};\nfunction resolveConnection(resolver, name) {\n if (!resolver) return void 0;\n if (typeof resolver === "function") return resolver(name);\n return Object.hasOwn(resolver, name) ? resolver[name] : void 0;\n}\nfunction parseLayoutSidecar(value) {\n if (!isRecord(value) || value["format"] !== LAYOUT_FORMAT || value["formatVersion"] !== LAYOUT_FORMAT_VERSION) {\n throw new BuilderError(\n `A layout file must have format "${LAYOUT_FORMAT}" and formatVersion ${LAYOUT_FORMAT_VERSION}`\n );\n }\n const positions = value["positions"];\n if (!isRecord(positions)) throw new BuilderError("A layout file needs a positions object");\n const parsed = {};\n for (const [id, position] of Object.entries(positions)) {\n if (!isRecord(position) || typeof position["x"] !== "number" || typeof position["y"] !== "number") {\n throw new BuilderError(`The layout position of "${id}" must be { x, y }`);\n }\n setOwn(parsed, id, { x: position["x"], y: position["y"] });\n }\n const sidecar = {\n format: LAYOUT_FORMAT,\n formatVersion: LAYOUT_FORMAT_VERSION,\n positions: parsed\n };\n if (value["stickyNotes"] !== void 0) {\n if (!Array.isArray(value["stickyNotes"]) || !value["stickyNotes"].every(isRecord)) {\n throw new BuilderError("stickyNotes in a layout file must be an array of objects");\n }\n sidecar.stickyNotes = cloneJson(value["stickyNotes"]);\n }\n if (value["metaLayout"] !== void 0) {\n if (!isRecord(value["metaLayout"]))\n throw new BuilderError("metaLayout in a layout file must be an object");\n sidecar.metaLayout = cloneJson(value["metaLayout"]);\n }\n return sidecar;\n}\nfunction orderEdges(edges, order) {\n if (!order) return edges;\n const indexById = /* @__PURE__ */ new Map();\n edges.forEach((item, index) => {\n if (typeof item.id === "string") indexById.set(item.id, index);\n });\n const indices = order.map(\n (entry) => typeof entry === "number" ? entry : indexById.get(entry) ?? -1\n );\n const valid = indices.length === edges.length && new Set(indices).size === indices.length && indices.every((index) => Number.isInteger(index) && index >= 0 && index < edges.length);\n if (!valid)\n throw new BuilderError(\n "edgeOrderIs() must name every edge exactly once, by id or declaration position"\n );\n return indices.map((index) => edges[index]);\n}\nfunction assembleRecording(recording, options = {}) {\n const missing = /* @__PURE__ */ new Set();\n const nodes2 = recording.nodes.map((recorded) => {\n const node = cloneJson(recorded.node);\n if (recorded.connectionNames) {\n const refs = [];\n for (const name of recorded.connectionNames) {\n const ref = resolveConnection(options.connections, name);\n if (ref) refs.push({ connectionId: ref.connectionId, adapter: ref.adapter });\n else missing.add(name);\n }\n const args = isRecord(node["args"]) ? node["args"] : {};\n args["connections"] = refs;\n node["args"] = args;\n }\n return node;\n });\n if (missing.size > 0) throw new UnresolvedConnectionsError([...missing].sort());\n const edges = orderEdges(cloneJson(recording.edges), recording.edgeOrder);\n const ids = nodes2.map((node) => String(node["id"]));\n const positions = options.layout?.positions ?? {};\n const needsAuto = ids.some((id) => !Object.hasOwn(positions, id));\n const auto = needsAuto ? autoLayout(ids, edges) : /* @__PURE__ */ new Map();\n for (const node of nodes2) {\n const id = String(node["id"]);\n const position = Object.hasOwn(positions, id) ? positions[id] : auto.get(id);\n if (position) node["position"] = { x: position.x, y: position.y };\n }\n const stickyNotes = options.layout?.stickyNotes !== void 0 || recording.notes.length > 0 ? [...options.layout?.stickyNotes ? cloneJson(options.layout.stickyNotes) : []] : void 0;\n for (const recorded of recording.notes) {\n const anchor = recorded.near !== void 0 ? nodes2.find((node) => node["id"] === recorded.near) : void 0;\n const anchorPosition = isRecord(anchor?.["position"]) ? anchor["position"] : { x: 0, y: 0 };\n const x = typeof anchorPosition["x"] === "number" ? anchorPosition["x"] : 0;\n const y = typeof anchorPosition["y"] === "number" ? anchorPosition["y"] : 0;\n stickyNotes?.push({ ...cloneJson(recorded.note), position: { x, y: y - 220 } });\n }\n const document = cloneJson(recording.document);\n const extraData = isRecord(document["data"]) ? document["data"] : {};\n for (const key of ["nodes", "edges", "stickyNotes"]) {\n if (Object.hasOwn(extraData, key))\n throw new BuilderError(`extra.data.${key} is written by the builder`);\n }\n delete document["data"];\n const authoring = options.authoring ?? {\n mode: "canvas",\n generator: "sdk-ts",\n generatorVersion: SDK_VERSION\n };\n const out = { schemaVersion: 2 };\n for (const key of ["key", "name", "description", "interface", "code"]) {\n if (document[key] !== void 0) out[key] = document[key];\n }\n out["authoring"] = authoring;\n out["data"] = {\n ...extraData,\n nodes: nodes2,\n edges,\n ...stickyNotes !== void 0 ? { stickyNotes } : {}\n };\n for (const key of ["config"]) if (document[key] !== void 0) out[key] = document[key];\n if (options.pinnedData !== void 0) out["pinnedData"] = cloneJson(options.pinnedData);\n if (options.layout?.metaLayout !== void 0) {\n const meta = isRecord(document["meta"]) ? document["meta"] : {};\n if (meta["layout"] !== void 0)\n throw new BuilderError("meta.layout comes from the layout file; do not set it in code");\n meta["layout"] = cloneJson(options.layout.metaLayout);\n document["meta"] = meta;\n }\n for (const [key, value] of Object.entries(document)) {\n if (!Object.hasOwn(out, key) && value !== void 0) setOwn(out, key, value);\n }\n return out;\n}\nfunction toIR(workflow2, options = {}) {\n if (!isTier1Workflow(workflow2))\n throw new BuilderError("toIR takes the value defineWorkflow returned");\n return assembleRecording(workflow2.recording, options);\n}\n\nvar COLLECTION_FORMAT = "fluidgrids.tier1-collection";\nfunction triggerOf(spec, where) {\n if (spec === void 0) return void 0;\n const operation = isOperation(spec) ? spec : isRecord(spec) ? spec.operation : void 0;\n if (!isOperation(operation))\n throw new BuilderError(`${where}: trigger must be a trigger operation`);\n const out = { nodeType: operation.nodeType };\n if (operation.version !== void 0) out.version = operation.version;\n if (operation.operation !== void 0) out.operation = operation.operation;\n if (!isOperation(spec)) {\n if (spec.args !== void 0) out.args = spec.args;\n if (spec.id !== void 0) out.id = spec.id;\n }\n return out;\n}\nfunction collectWorkflowExports(modules) {\n const exportNames = /* @__PURE__ */ new Map();\n const durable = [];\n for (const [module, namespace] of modules) {\n for (const exportName of Object.keys(namespace).sort()) {\n const value = namespace[exportName];\n if (!isDurableWorkflow(value) || exportNames.has(value)) continue;\n exportNames.set(value, exportName);\n const options = value.options;\n const entry = {\n module,\n exportName,\n name: value.name,\n taskQueue: options.taskQueue ?? "managed",\n interface: interfaceOf(value)\n };\n if (options.title !== void 0) entry.title = options.title;\n if (options.description !== void 0) entry.description = options.description;\n if (options.standalone !== void 0) entry.standalone = options.standalone;\n const trigger2 = triggerOf(options.trigger, `workflow("${value.name}")`);\n if (trigger2) entry.trigger = trigger2;\n durable.push(entry);\n }\n }\n const workflows = [];\n for (const [module, namespace] of modules) {\n for (const exportName of Object.keys(namespace).sort()) {\n const value = namespace[exportName];\n if (!isTier1Workflow(value)) continue;\n for (const ref of value.durableRefs ?? []) {\n const resolved = exportNames.get(ref.definition);\n if (resolved === void 0)\n throw new BuilderError(\n `${value.key}: wf.codeWorkflow node "${ref.nodeId}" uses workflow("${ref.definition.name}"), which no module exports`\n );\n const recorded = value.recording.nodes.find((entry) => entry.node.id === ref.nodeId);\n const state = recorded?.node.args?.state;\n if (isRecord(state)) setOwn(state, "workflowFn", resolved);\n }\n workflows.push({ module, exportName, recording: value.recording });\n }\n }\n const collection = {\n format: COLLECTION_FORMAT,\n workflows,\n ...durable.length > 0 ? { durable } : {}\n };\n return JSON.stringify(collection);\n}\n\nfunction checkName(name, what) {\n if (typeof name !== "string" || name === "" || name.startsWith("__"))\n throw new TypeError(`${what} needs a name that does not start with "__"`);\n}\nfunction defineSignal(name, options = {}) {\n checkName(name, "defineSignal");\n return {\n kind: "signal",\n name,\n ...options.description !== void 0 ? { description: options.description } : {},\n ...options.schema !== void 0 ? { schema: options.schema } : {}\n };\n}\nfunction defineQuery(name, options = {}) {\n checkName(name, "defineQuery");\n return {\n kind: "query",\n name,\n ...options.description !== void 0 ? { description: options.description } : {}\n };\n}\nfunction defineUpdate(name, options = {}) {\n checkName(name, "defineUpdate");\n return {\n kind: "update",\n name,\n ...options.description !== void 0 ? { description: options.description } : {}\n };\n}\nfunction signalName(signal) {\n return typeof signal === "string" ? signal : signal.name;\n}\n\nvar ERROR_TYPE_VALUES = /* @__PURE__ */ new Set([\n "TIMEOUT",\n "TRANSIENT",\n "DEPENDENCY",\n "AUTHORIZATION",\n "VALIDATION",\n "PERMANENT",\n "UNKNOWN"\n]);\nfunction isErrorType(value) {\n return typeof value === "string" && ERROR_TYPE_VALUES.has(value);\n}\nvar WorkflowFailure = class extends Error {\n /** The shared error type the engine classifies this failure as. */\n errorType;\n constructor(message, errorType, options = {}) {\n super(message);\n this.name = "WorkflowFailure";\n this.errorType = errorType;\n if (options.cause !== void 0)\n Object.defineProperty(this, "cause", {\n value: options.cause,\n enumerable: false,\n writable: true,\n configurable: true\n });\n }\n};\nvar ApplicationError = class extends WorkflowFailure {\n type;\n nonRetryable;\n details;\n nextRetryDelayMs;\n category;\n constructor(message, options = {}) {\n super(\n message,\n options.errorType ?? (isErrorType(options.type) ? options.type : "UNKNOWN"),\n options.cause !== void 0 ? { cause: options.cause } : {}\n );\n this.name = "ApplicationError";\n this.type = options.type;\n this.nonRetryable = options.nonRetryable === true;\n this.details = options.details;\n this.nextRetryDelayMs = options.nextRetryDelay;\n this.category = options.category;\n }\n};\nvar ActivityFailure = class extends WorkflowFailure {\n constructor(message, activityId, nodeType, operation, cause) {\n super(message, cause instanceof WorkflowFailure ? cause.errorType : "UNKNOWN", { cause });\n this.activityId = activityId;\n this.nodeType = nodeType;\n this.operation = operation;\n this.name = "ActivityFailure";\n }\n activityId;\n nodeType;\n operation;\n};\nvar ChildRunFailure = class extends WorkflowFailure {\n constructor(message, childId, childRunId, cause) {\n super(message, cause instanceof WorkflowFailure ? cause.errorType : "UNKNOWN", { cause });\n this.childId = childId;\n this.childRunId = childRunId;\n this.name = "ChildRunFailure";\n }\n childId;\n childRunId;\n};\nvar TerminatedFailure = class extends WorkflowFailure {\n constructor(message = "Terminated") {\n super(message, "PERMANENT");\n this.name = "TerminatedFailure";\n }\n};\nvar ServerFailure = class extends WorkflowFailure {\n constructor(message, nonRetryable = false, errorType = "DEPENDENCY") {\n super(message, errorType);\n this.nonRetryable = nonRetryable;\n this.name = "ServerFailure";\n }\n nonRetryable;\n};\nvar CancelledFailure = class extends WorkflowFailure {\n constructor(message = "Cancelled") {\n super(message, "PERMANENT");\n this.name = "CancelledFailure";\n }\n};\nvar TimeoutFailure = class extends WorkflowFailure {\n constructor(message, timeoutType) {\n super(message, "TIMEOUT");\n this.timeoutType = timeoutType;\n this.name = "TimeoutFailure";\n }\n timeoutType;\n};\nvar DeterminismViolation = class extends Error {\n constructor(message) {\n super(message);\n this.name = "DeterminismViolation";\n }\n};\nvar HistoryLimitExceeded = class extends Error {\n constructor(message) {\n super(message);\n this.name = "HistoryLimitExceeded";\n }\n};\nvar PhaseCFeatureError = class extends Error {\n code = "durable.phaseC";\n constructor(feature) {\n super(\n `${feature} is not available yet (Phase C); durable functions in this release cannot use it`\n );\n this.name = "PhaseCFeatureError";\n }\n};\nfunction isCancellation(error) {\n let current = error;\n for (let depth = 0; depth < 16 && current instanceof Error; depth++) {\n if (current instanceof CancelledFailure || current.name === "CancelledFailure") return true;\n if (!(current instanceof ActivityFailure || current instanceof ChildRunFailure)) return false;\n current = current.cause;\n }\n return false;\n}\nfunction isRunFailure(error) {\n return error instanceof WorkflowFailure;\n}\nfunction stackOf(error) {\n return typeof error.stack === "string" && error.stack !== "" ? error.stack : void 0;\n}\nfunction errorToFailure(error, source = "sdk-ts", depth = 0) {\n if (!(error instanceof Error)) return { errorType: "UNKNOWN", message: String(error), source };\n const failure = {\n errorType: error instanceof WorkflowFailure ? error.errorType : "UNKNOWN",\n message: error.message,\n type: error instanceof ApplicationError && error.type !== void 0 ? error.type : error.name,\n source\n };\n const stack = stackOf(error);\n if (stack !== void 0) failure.stackTrace = stack;\n if (error instanceof ApplicationError) {\n if (error.nonRetryable) failure.nonRetryable = true;\n if (error.details !== void 0) failure.details = error.details;\n if (error.nextRetryDelayMs !== void 0) failure.nextRetryDelayMs = error.nextRetryDelayMs;\n if (error.category !== void 0) failure.category = error.category;\n }\n if (error instanceof TimeoutFailure) failure.timeoutType = error.timeoutType;\n if (error instanceof ServerFailure && error.nonRetryable) failure.nonRetryable = true;\n const cause = error.cause;\n if (cause !== void 0 && depth < 16) failure.cause = errorToFailure(cause, source, depth + 1);\n return failure;\n}\nfunction failureToError(failure, depth = 0) {\n const cause = failure.cause && depth < 16 ? failureToError(failure.cause, depth + 1) : void 0;\n let error;\n switch (failure.type) {\n case "CancelledFailure":\n error = new CancelledFailure(failure.message);\n break;\n case "TerminatedFailure":\n error = new TerminatedFailure(failure.message);\n break;\n case "TimeoutFailure":\n error = new TimeoutFailure(failure.message, failure.timeoutType ?? "UNKNOWN");\n break;\n case "ServerFailure":\n error = new ServerFailure(failure.message, failure.nonRetryable === true, failure.errorType);\n break;\n default:\n if (failure.timeoutType !== void 0 && failure.errorType === "TIMEOUT" && !failure.type)\n error = new TimeoutFailure(failure.message, failure.timeoutType);\n else\n error = new ApplicationError(failure.message, {\n errorType: failure.errorType,\n ...failure.type !== void 0 ? { type: failure.type } : {},\n ...failure.nonRetryable !== void 0 ? { nonRetryable: failure.nonRetryable } : {},\n ...failure.details !== void 0 ? { details: failure.details } : {},\n ...failure.nextRetryDelayMs !== void 0 ? { nextRetryDelay: failure.nextRetryDelayMs } : {},\n ...failure.category !== void 0 ? { category: failure.category } : {},\n ...cause !== void 0 ? { cause } : {}\n });\n }\n if (cause !== void 0 && !(error instanceof ApplicationError))\n Object.defineProperty(error, "cause", {\n value: cause,\n enumerable: false,\n writable: true,\n configurable: true\n });\n if (failure.stackTrace !== void 0) error.stack = failure.stackTrace;\n return error;\n}\n\nvar SHORT = /^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d|w)$/;\nvar ISO = /^P(?:(\\d+(?:\\.\\d+)?)W)?(?:(\\d+(?:\\.\\d+)?)D)?(?:T(?:(\\d+(?:\\.\\d+)?)H)?(?:(\\d+(?:\\.\\d+)?)M)?(?:(\\d+(?:\\.\\d+)?)S)?)?$/;\nvar SECOND_MS = 1e3;\nvar MINUTE_MS = 60 * SECOND_MS;\nvar HOUR_MS = 60 * MINUTE_MS;\nvar DAY_MS = 24 * HOUR_MS;\nvar WEEK_MS = 7 * DAY_MS;\nvar UNIT_MS = {\n ms: 1,\n s: SECOND_MS,\n m: MINUTE_MS,\n h: HOUR_MS,\n d: DAY_MS,\n w: WEEK_MS\n};\nfunction durationMs(value, numberUnit) {\n if (typeof value === "number") {\n if (!Number.isFinite(value) || value < 0) return void 0;\n return numberUnit === "s" ? value * 1e3 : value;\n }\n if (typeof value !== "string") return void 0;\n const text = value.trim();\n const short = SHORT.exec(text);\n if (short?.[1] !== void 0 && short[2] !== void 0) {\n const unit = UNIT_MS[short[2]];\n return unit === void 0 ? void 0 : Number(short[1]) * unit;\n }\n const iso = ISO.exec(text);\n if (iso && text !== "P" && text !== "PT") {\n const [, weeks, days, hours, minutes, seconds] = iso;\n const parts = [weeks, days, hours, minutes, seconds];\n if (parts.every((part) => part === void 0)) return void 0;\n return Number(weeks ?? 0) * WEEK_MS + Number(days ?? 0) * DAY_MS + Number(hours ?? 0) * HOUR_MS + Number(minutes ?? 0) * MINUTE_MS + Number(seconds ?? 0) * SECOND_MS;\n }\n return void 0;\n}\n\nfunction toMs(value, what = "duration") {\n const ms = durationMs(value, "ms");\n if (ms === void 0) throw new TypeError(`${what} "${String(value)}" is not a duration`);\n return Math.round(ms);\n}\nfunction optionalMs(value, what) {\n return value === void 0 ? void 0 : toMs(value, what);\n}\n\nvar HISTORY_PROTOCOL = 1;\nvar DEFAULT_HISTORY_LIMIT = { events: 1e4, bytes: 16 * 1024 * 1024 };\nvar CONTINUE_AS_NEW_SUGGESTED_RATIO = 0.8;\nvar HISTORY_LIMIT_EXCEEDED_RATIO = 0.95;\nvar BUILT_IN_QUERIES = [\n "__stack_trace",\n "__enhanced_stack_trace",\n "__metadata"\n];\nvar COMMAND_EVENT_TYPES = {\n SCHEDULE_ACTIVITY: "ACTIVITY_SCHEDULED",\n REQUEST_CANCEL_ACTIVITY: "ACTIVITY_CANCEL_REQUESTED",\n START_TIMER: "TIMER_STARTED",\n CANCEL_TIMER: "TIMER_CANCELLED",\n START_CHILD_RUN: "CHILD_RUN_INITIATED",\n SIGNAL_RUN: "EXTERNAL_RUN_SIGNALED",\n RECORD_SIDE_EFFECT: "SIDE_EFFECT_RECORDED",\n RECORD_MARKER: "MARKER_RECORDED",\n COMPLETE_WORKFLOW: "WORKFLOW_COMPLETED",\n FAIL_WORKFLOW: "WORKFLOW_FAILED",\n CANCEL_WORKFLOW: "WORKFLOW_CANCELLED",\n UPSERT_CONTEXT: "CONTEXT_UPSERTED",\n RECORD_LOCAL_ACTIVITY: "LOCAL_ACTIVITY_COMPLETED",\n CONTINUE_AS_NEW: "WORKFLOW_CONTINUED_AS_NEW",\n REQUEST_CANCEL_EXTERNAL_RUN: "EXTERNAL_RUN_CANCEL_REQUESTED",\n UPSERT_SEARCH_ATTRIBUTES: "SEARCH_ATTRIBUTES_UPSERTED",\n ACCEPT_UPDATE: "UPDATE_ACCEPTED",\n REJECT_UPDATE: null,\n COMPLETE_UPDATE: "UPDATE_COMPLETED"\n};\nvar COMMAND_EVENTS = /* @__PURE__ */ new Set([\n "ACTIVITY_SCHEDULED",\n "ACTIVITY_CANCEL_REQUESTED",\n "TIMER_STARTED",\n "TIMER_CANCELLED",\n "CHILD_RUN_INITIATED",\n "EXTERNAL_RUN_SIGNALED",\n "SIDE_EFFECT_RECORDED",\n "MARKER_RECORDED",\n "WORKFLOW_COMPLETED",\n "WORKFLOW_FAILED",\n "WORKFLOW_CANCELLED",\n "CONTEXT_UPSERTED",\n "LOCAL_ACTIVITY_COMPLETED",\n "LOCAL_ACTIVITY_FAILED",\n "WORKFLOW_CONTINUED_AS_NEW",\n "EXTERNAL_RUN_CANCEL_REQUESTED",\n "SEARCH_ATTRIBUTES_UPSERTED",\n "UPDATE_ACCEPTED",\n "UPDATE_COMPLETED"\n]);\nvar INPUT_EVENTS = /* @__PURE__ */ new Set([\n "WORKFLOW_STARTED",\n "ACTIVITY_COMPLETED",\n "ACTIVITY_FAILED",\n "ACTIVITY_TIMED_OUT",\n "ACTIVITY_CANCELLED",\n "TIMER_FIRED",\n "SIGNAL_RECEIVED",\n "UPDATE_ADMITTED",\n "CHILD_RUN_STARTED",\n "CHILD_RUN_COMPLETED",\n "CHILD_RUN_FAILED",\n "CHILD_RUN_CANCELLED",\n "CHILD_RUN_TERMINATED",\n "CHILD_RUN_TIMED_OUT",\n "EXTERNAL_RUN_CANCEL_RESOLVED",\n "WORKFLOW_CANCEL_REQUESTED"\n]);\nfunction isInputEvent(event) {\n if (event.type === "EXTERNAL_RUN_SIGNALED") return event.payload["resolved"] === true;\n return INPUT_EVENTS.has(event.type);\n}\nfunction isCommandEvent(event) {\n if (event.type === "EXTERNAL_RUN_SIGNALED") return event.payload["resolved"] !== true;\n return COMMAND_EVENTS.has(event.type);\n}\n\nvar ACTIVITY_INTERNAL_ALLOWLIST = /* @__PURE__ */ new Set([\n "internal:http",\n "internal:datatable",\n "internal:set",\n "internal:code"\n]);\nvar LEGACY_SHORT_NAMES = /* @__PURE__ */ new Set([\n "if",\n "switch",\n "loop",\n "merge",\n "set",\n "filter",\n "aggregate",\n "wait",\n "noop",\n "code",\n "http",\n "transform",\n "validate",\n "log",\n "error",\n "subworkflow",\n "end",\n "trigger",\n "webhook",\n "schedule",\n "manual",\n "api"\n]);\nfunction canonicalType(nodeType) {\n const lower = nodeType.trim().toLowerCase();\n return LEGACY_SHORT_NAMES.has(lower) ? `internal:${lower}` : lower;\n}\nfunction isActivityNodeTypeAllowed(nodeType) {\n if (typeof nodeType !== "string" || nodeType.trim() === "") return false;\n const type = canonicalType(nodeType);\n if (!type.startsWith("internal:")) return true;\n return ACTIVITY_INTERNAL_ALLOWLIST.has(type);\n}\n\nvar DEFAULT_ACTIVITY_RETRY = Object.freeze({\n retryDelay: 1e3,\n backoffMultiplier: 2,\n maxDelay: 1e5\n});\nfunction explicitRetryPolicy(policy) {\n const retryDelay = policy?.retryDelay ?? DEFAULT_ACTIVITY_RETRY.retryDelay;\n const out = {\n retryDelay,\n backoffMultiplier: policy?.backoffMultiplier ?? DEFAULT_ACTIVITY_RETRY.backoffMultiplier ?? 2,\n maxDelay: policy?.maxDelay ?? (policy?.retryDelay === void 0 ? 1e5 : Math.max(retryDelay, retryDelay * 100))\n };\n if (policy?.maxRetries !== void 0) out.maxRetries = policy.maxRetries;\n if (policy?.retryOnErrorTypes !== void 0)\n out.retryOnErrorTypes = [...policy.retryOnErrorTypes];\n if (policy?.nonRetryableErrorTypes !== void 0)\n out.nonRetryableErrorTypes = [...policy.nonRetryableErrorTypes];\n return out;\n}\n\nfunction timeOf(event) {\n const startedAt = event.payload["startedAt"];\n const text = typeof startedAt === "string" ? startedAt : event.createdAt;\n const ms = Date.parse(text);\n return Number.isFinite(ms) ? ms : 0;\n}\nfunction cutoffOf(event) {\n const leased = event.payload["historyLength"];\n return typeof leased === "number" && leased < event.seq ? leased : event.seq;\n}\nfunction walk(history) {\n const activations = [];\n let pending = [];\n let started;\n let afterStarted = [];\n let last;\n for (const event of history) {\n switch (event.type) {\n case "WORKFLOW_TASK_STARTED":\n if (started) pending.push(...afterStarted);\n started = event;\n afterStarted = [];\n continue;\n case "WORKFLOW_TASK_FAILED":\n case "WORKFLOW_TASK_TIMED_OUT":\n if (started) pending.push(...afterStarted);\n started = void 0;\n afterStarted = [];\n continue;\n case "WORKFLOW_TASK_COMPLETED": {\n const taskId = typeof event.payload["taskId"] === "string" ? event.payload["taskId"] : "";\n const boundary = started !== void 0 && started.payload["taskId"] === event.payload["taskId"] ? started : event;\n const cutoff = boundary === event ? event.seq : cutoffOf(boundary);\n const seen = pending.filter((input) => input.seq <= cutoff);\n const later = pending.filter((input) => input.seq > cutoff);\n last = {\n inputs: seen,\n recorded: [],\n timeMs: timeOf(boundary),\n taskId,\n historyLength: cutoff\n };\n activations.push(last);\n pending = [...later, ...afterStarted];\n started = void 0;\n afterStarted = [];\n continue;\n }\n default:\n break;\n }\n if (isInputEvent(event)) {\n if (started) afterStarted.push(event);\n else pending.push(event);\n } else if (isCommandEvent(event) && last?.recorded) {\n last.recorded.push(event);\n }\n }\n return { activations, pending, started, afterStarted };\n}\nfunction splitActivations(history, nowMs, includeOpen) {\n const { activations, pending, started } = walk(history);\n if (includeOpen) {\n const cutoff = started ? cutoffOf(started) : history.length;\n const inputs = pending.filter((input) => input.seq <= cutoff);\n activations.push({ inputs, recorded: void 0, timeMs: nowMs, historyLength: cutoff });\n }\n return activations;\n}\n\nfunction utf8Bytes(text) {\n let bytes = 0;\n for (let index = 0; index < text.length; index++) {\n const unit = text.charCodeAt(index);\n if (unit < 128) bytes += 1;\n else if (unit < 2048) bytes += 2;\n else if (unit >= 55296 && unit <= 56319 && index + 1 < text.length) {\n const next = text.charCodeAt(index + 1);\n if (next >= 56320 && next <= 57343) {\n bytes += 4;\n index++;\n } else bytes += 3;\n } else bytes += 3;\n }\n return bytes;\n}\n\nvar CHILD_DEFAULT_PARENT_CLOSE_POLICY = Object.freeze({ child: "TERMINATE", startChild: "ABANDON" });\nvar CHILD_DEFAULT_CANCELLATION_TYPE = "WAIT_CANCELLATION_COMPLETED";\n\nvar CommandIds = class {\n counters = { a: 0, t: 0, c: 0, s: 0, x: 0, m: 0 };\n /** The next id of a kind: `a1`, `a2`, ... */\n next(kind) {\n this.counters[kind] += 1;\n return `${kind}${this.counters[kind]}`;\n }\n};\nfunction patchMarkerId(patchId) {\n return `patch:${patchId}`;\n}\nfunction isPatchMarkerId(markerId) {\n return markerId.startsWith("patch:");\n}\n\nfunction field(event, key) {\n return event.payload[key];\n}\nfunction describeCommand(command) {\n switch (command.type) {\n case "SCHEDULE_ACTIVITY":\n return `SCHEDULE_ACTIVITY ${command.activityId} (${command.nodeType} ${command.operation})`;\n case "REQUEST_CANCEL_ACTIVITY":\n return `REQUEST_CANCEL_ACTIVITY ${command.activityId}`;\n case "START_TIMER":\n case "CANCEL_TIMER":\n return `${command.type} ${command.timerId}`;\n case "START_CHILD_RUN":\n return `START_CHILD_RUN ${command.childId} (${command.workflowKey ?? command.workflowFn ?? ""})`;\n case "SIGNAL_RUN":\n return `SIGNAL_RUN ${command.externalId} (${command.name})`;\n case "REQUEST_CANCEL_EXTERNAL_RUN":\n return `REQUEST_CANCEL_EXTERNAL_RUN ${command.externalId}`;\n case "RECORD_SIDE_EFFECT":\n return `RECORD_SIDE_EFFECT ${command.sideEffectId}`;\n case "RECORD_MARKER":\n return `RECORD_MARKER ${command.markerId}`;\n case "RECORD_LOCAL_ACTIVITY":\n return `RECORD_LOCAL_ACTIVITY ${command.localActivityId}`;\n default:\n return command.type;\n }\n}\nfunction describeEvent(event) {\n const id = field(event, "activityId") ?? field(event, "timerId") ?? field(event, "childId") ?? field(event, "externalId") ?? field(event, "sideEffectId") ?? field(event, "markerId") ?? field(event, "localActivityId");\n return `${event.type}${typeof id === "string" ? ` ${id}` : ""} (seq ${event.seq})`;\n}\nfunction mismatch(command, event) {\n const expected = COMMAND_EVENT_TYPES[command.type];\n const typeOk = command.type === "RECORD_LOCAL_ACTIVITY" ? event.type === "LOCAL_ACTIVITY_COMPLETED" || event.type === "LOCAL_ACTIVITY_FAILED" : event.type === expected;\n const differ = () => `the code issued ${describeCommand(command)} where the history has ${describeEvent(event)}`;\n if (!typeOk) return differ();\n switch (command.type) {\n case "SCHEDULE_ACTIVITY":\n return field(event, "activityId") === command.activityId && field(event, "nodeType") === command.nodeType && field(event, "operation") === command.operation ? void 0 : differ();\n case "REQUEST_CANCEL_ACTIVITY":\n return field(event, "activityId") === command.activityId ? void 0 : differ();\n case "START_TIMER":\n case "CANCEL_TIMER":\n return field(event, "timerId") === command.timerId ? void 0 : differ();\n case "START_CHILD_RUN":\n return field(event, "childId") === command.childId && (field(event, "workflowKey") ?? null) === (command.workflowKey ?? null) && (field(event, "workflowFn") ?? null) === (command.workflowFn ?? null) ? void 0 : differ();\n case "SIGNAL_RUN":\n return field(event, "externalId") === command.externalId && field(event, "name") === command.name ? void 0 : differ();\n case "REQUEST_CANCEL_EXTERNAL_RUN":\n return field(event, "externalId") === command.externalId ? void 0 : differ();\n case "RECORD_SIDE_EFFECT":\n return field(event, "sideEffectId") === command.sideEffectId ? void 0 : differ();\n case "RECORD_MARKER":\n return field(event, "markerId") === command.markerId ? void 0 : differ();\n case "RECORD_LOCAL_ACTIVITY":\n return field(event, "localActivityId") === command.localActivityId ? void 0 : differ();\n default:\n return void 0;\n }\n}\nfunction isSkippablePatch(event) {\n const markerId = field(event, "markerId");\n return event.type === "MARKER_RECORDED" && typeof markerId === "string" && isPatchMarkerId(markerId);\n}\nfunction matchActivation(commands, recorded) {\n let position = 0;\n for (const command of commands) {\n let event = recorded[position];\n while (event !== void 0 && isSkippablePatch(event) && !(command.type === "RECORD_MARKER" && command.markerId === field(event, "markerId"))) {\n position += 1;\n event = recorded[position];\n }\n if (event === void 0)\n return {\n message: `the code issued ${describeCommand(command)}, which the history does not have`\n };\n const reason = mismatch(command, event);\n if (reason !== void 0) return { message: reason, seq: event.seq };\n position += 1;\n }\n for (; position < recorded.length; position++) {\n const event = recorded[position];\n if (event !== void 0 && !isSkippablePatch(event))\n return {\n message: `the history has ${describeEvent(event)}, which the code did not issue`,\n seq: event.seq\n };\n }\n return void 0;\n}\n\nvar SHIM_VIOLATION = "DeterminismViolation";\nvar SHIM_HOOK = "__fluidgridsShims";\nvar TASK_PRELUDE = `(() => {\n const NAME = ${JSON.stringify(SHIM_VIOLATION)};\n const fail = (what) => {\n const error = new Error(what + " is not allowed in workflow code: use ctx.now(), ctx.random(), ctx.sleep() or an activity.");\n error.name = NAME;\n throw error;\n };\n let hooks = null;\n const now = (what) => (hooks !== null ? hooks.now() : fail(what + " outside a workflow task"));\n const lock = (target, key, value) =>\n Object.defineProperty(target, key, { value, writable: false, enumerable: false, configurable: false });\n const RealDate = Date;\n // ---- Built-ins that differ between hosts and engines --------------------\n // Local time is UTC whatever the host\'s TZ, locale formatting is fixed\n // (en-US shapes, no ICU), Intl is absent and garbage collection cannot be\n // observed, so QuickJS and vm on any host run workflow code the same way.\n const proto = RealDate.prototype;\n const hostOffset = proto.getTimezoneOffset;\n const realParse = RealDate.parse;\n const isInvalid = (date) => Number.isNaN(proto.getTime.call(date));\n for (const unit of ["FullYear", "Month", "Date", "Day", "Hours", "Minutes", "Seconds", "Milliseconds"]) {\n lock(proto, "get" + unit, proto["getUTC" + unit]);\n if (unit !== "Day") lock(proto, "set" + unit, proto["setUTC" + unit]);\n }\n lock(proto, "getTimezoneOffset", function getTimezoneOffset() { return isInvalid(this) ? NaN : 0; });\n if (typeof proto.getYear === "function")\n lock(proto, "getYear", function getYear() { return isInvalid(this) ? NaN : this.getUTCFullYear() - 1900; });\n if (typeof proto.setYear === "function")\n lock(proto, "setYear", function setYear(value) {\n const year = Number(value);\n if (Number.isNaN(year)) return this.setTime(NaN);\n const whole = Math.trunc(year);\n const base = new RealDate(isInvalid(this) ? 0 : this.getTime());\n base.setUTCFullYear(whole >= 0 && whole <= 99 ? 1900 + whole : whole);\n return this.setTime(base.getTime());\n });\n const DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];\n const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];\n const pad = (value, width) => String(value).padStart(width, "0");\n const yearText = (year) => (year < 0 ? "-" + pad(-year, 6) : pad(year, 4));\n const dateText = (d) =>\n DAYS[d.getUTCDay()] + " " + MONTHS[d.getUTCMonth()] + " " + pad(d.getUTCDate(), 2) + " " + yearText(d.getUTCFullYear());\n const timeText = (d) =>\n pad(d.getUTCHours(), 2) + ":" + pad(d.getUTCMinutes(), 2) + ":" + pad(d.getUTCSeconds(), 2) + " GMT+0000 (Coordinated Universal Time)";\n const localeDate = (d) => d.getUTCMonth() + 1 + "/" + d.getUTCDate() + "/" + d.getUTCFullYear();\n const localeTime = (d) => {\n const hours = d.getUTCHours();\n return ((hours + 11) % 12) + 1 + ":" + pad(d.getUTCMinutes(), 2) + ":" + pad(d.getUTCSeconds(), 2) + (hours < 12 ? " AM" : " PM");\n };\n const formatter = (format) => function () { return isInvalid(this) ? "Invalid Date" : format(this); };\n lock(proto, "toString", formatter((d) => dateText(d) + " " + timeText(d)));\n lock(proto, "toDateString", formatter(dateText));\n lock(proto, "toTimeString", formatter(timeText));\n lock(proto, "toLocaleString", formatter((d) => localeDate(d) + ", " + localeTime(d)));\n lock(proto, "toLocaleDateString", formatter(localeDate));\n lock(proto, "toLocaleTimeString", formatter(localeTime));\n // A date-time without an offset is local time to the host\'s parser; read it as UTC.\n const DATE_ONLY = /^[+-]?\\\\d{4,6}(?:-\\\\d{2}(?:-\\\\d{2})?)?$/;\n const ZONE_AFTER_TIME = /\\\\d:\\\\d{2}(?::\\\\d{2}(?:[.,]\\\\d+)?)?\\\\s*(?:[AP]M\\\\s*)?(?:Z|[+-]\\\\d{2}(?::?\\\\d{2})?|[ECMP][SD]T)\\\\s*(?:\\\\([^)]*\\\\))?\\\\s*$/i;\n const NAMED_ZONE = /\\\\b(?:GMT|UTC|UT)\\\\b(?:\\\\s*[+-]\\\\d{2}:?\\\\d{2})?\\\\s*(?:\\\\([^)]*\\\\))?\\\\s*$/i;\n const parse = function parse(value) {\n const text = String(value);\n const time = realParse(text);\n if (Number.isNaN(time)) return time;\n const trimmed = text.trim();\n if (DATE_ONLY.test(trimmed) || ZONE_AFTER_TIME.test(trimmed) || NAMED_ZONE.test(trimmed)) return time;\n return time - hostOffset.call(new RealDate(time)) * 60000;\n };\n const toTimeValue = (value) => {\n if (value instanceof RealDate) return value.getTime();\n let primitive = value;\n if (typeof value === "object" && value !== null) {\n primitive = value.valueOf();\n if (typeof primitive === "object" && primitive !== null) primitive = String(value);\n }\n return typeof primitive === "string" ? parse(primitive) : primitive;\n };\n // ---- Number, string and array locale methods ----------------------------\n const group = (digits) => digits.replace(/\\\\B(?=(\\\\d{3})+(?!\\\\d))/g, ",");\n lock(Number.prototype, "toLocaleString", function toLocaleString() {\n const x = Number.prototype.valueOf.call(this);\n if (Number.isNaN(x)) return "NaN";\n const sign = x < 0 || Object.is(x, -0) ? "-" : "";\n const abs = Math.abs(x);\n if (abs === Infinity) return sign + "\\\\u221e";\n const fixed = abs < 1e21 ? abs.toFixed(3) : BigInt(abs).toString() + ".000";\n const [whole, fraction] = fixed.split(".");\n const kept = fraction.replace(/0+$/, "");\n return sign + group(whole) + (kept === "" ? "" : "." + kept);\n });\n if (typeof BigInt === "function")\n lock(BigInt.prototype, "toLocaleString", function toLocaleString() {\n const text = BigInt.prototype.toString.call(this);\n return text.startsWith("-") ? "-" + group(text.slice(1)) : group(text);\n });\n lock(String.prototype, "localeCompare", function localeCompare(that) {\n const a = String(this);\n const b = String(that);\n return a < b ? -1 : a > b ? 1 : 0;\n });\n lock(String.prototype, "toLocaleUpperCase", function toLocaleUpperCase() { return String(this).toUpperCase(); });\n lock(String.prototype, "toLocaleLowerCase", function toLocaleLowerCase() { return String(this).toLowerCase(); });\n const listLocale = function toLocaleString() {\n return Array.prototype.map.call(this, (item) => (item === null || item === undefined ? "" : item.toLocaleString())).join(",");\n };\n lock(Array.prototype, "toLocaleString", listLocale);\n lock(Object.getPrototypeOf(Uint8Array.prototype), "toLocaleString", listLocale);\n // ---- Absent or refused ---------------------------------------------------\n if (!Reflect.deleteProperty(globalThis, "Intl")) lock(globalThis, "Intl", undefined);\n for (const name of ["WeakRef", "FinalizationRegistry"]) {\n lock(globalThis, name, function () { return fail(name + " (garbage collection is not deterministic)"); });\n }\n const LockedDate = function Date(...args) {\n if (new.target === undefined) return new RealDate(now("Date()")).toString();\n if (args.length === 0) return Reflect.construct(RealDate, [now("new Date()")], new.target);\n if (args.length === 1) return Reflect.construct(RealDate, [toTimeValue(args[0])], new.target);\n return Reflect.construct(RealDate, [RealDate.UTC(...args)], new.target);\n };\n lock(LockedDate, "prototype", RealDate.prototype);\n lock(RealDate.prototype, "constructor", LockedDate);\n lock(LockedDate, "now", function now_() { return now("Date.now()"); });\n lock(LockedDate, "parse", parse);\n lock(LockedDate, "UTC", RealDate.UTC);\n lock(globalThis, "Date", LockedDate);\n lock(Math, "random", function random() {\n return hooks !== null ? hooks.random() : fail("Math.random() outside a workflow task");\n });\n const crypto = globalThis.crypto;\n if (crypto !== null && typeof crypto === "object") {\n if (typeof crypto.getRandomValues === "function")\n lock(crypto, "getRandomValues", function getRandomValues(array) {\n if (hooks === null) return fail("crypto.getRandomValues() outside a workflow task");\n for (let i = 0; i < array.length; i++) array[i] = Math.floor(hooks.random() * 256);\n return array;\n });\n if (typeof crypto.randomUUID === "function")\n lock(crypto, "randomUUID", function randomUUID() { return fail("crypto.randomUUID(): use ctx.uuid()"); });\n }\n for (const name of ["setTimeout", "setInterval", "setImmediate", "clearTimeout", "clearInterval", "clearImmediate"]) {\n lock(globalThis, name, function () { return fail(name + "(): use ctx.sleep()"); });\n }\n for (const name of ["fetch", "XMLHttpRequest", "WebSocket", "EventSource"]) {\n lock(globalThis, name, function () { return fail(name + ": do I/O in an activity (ctx.run)"); });\n }\n Object.defineProperty(globalThis, ${JSON.stringify(SHIM_HOOK)}, {\n value: Object.freeze({\n attach(next) { hooks = next; },\n detach() { hooks = null; },\n }),\n writable: false,\n enumerable: false,\n configurable: true,\n });\n})();\n`;\nfunction isShimControl(value) {\n return typeof value === "object" && value !== null && typeof value.attach === "function" && typeof value.detach === "function";\n}\nfunction takeShimControl() {\n const holder = globalThis;\n const control = holder[SHIM_HOOK];\n if (!isShimControl(control)) return void 0;\n delete holder[SHIM_HOOK];\n return control;\n}\nfunction seedOf(text) {\n let hash = 2166136261;\n for (let index = 0; index < text.length; index++) {\n hash ^= text.charCodeAt(index);\n hash = Math.imul(hash, 16777619) >>> 0;\n }\n return hash >>> 0;\n}\nfunction createRandom(seed) {\n let state = seed >>> 0;\n return () => {\n state = state + 1831565813 >>> 0;\n let t = state;\n t = Math.imul(t ^ t >>> 15, t | 1);\n t ^= t + Math.imul(t ^ t >>> 7, t | 61);\n return ((t ^ t >>> 14) >>> 0) / 4294967296;\n };\n}\nfunction uuidFrom(random) {\n const hex = [];\n for (let index = 0; index < 16; index++) {\n let byte = Math.floor(random() * 256) & 255;\n if (index === 6) byte = byte & 15 | 64;\n if (index === 8) byte = byte & 63 | 128;\n hex.push(byte.toString(16).padStart(2, "0"));\n }\n const text = hex.join("");\n return `${text.slice(0, 8)}-${text.slice(8, 12)}-${text.slice(12, 16)}-${text.slice(16, 20)}-${text.slice(20)}`;\n}\n\nvar RUNTIME_FRAME = /fluidgrids-runtime|\\/runtime\\/(scheduler|index)\\.|WorkflowExecution|RuntimeContext/;\nfunction captureStack() {\n const stack = new Error("stack").stack ?? "";\n return stack.split("\\n").slice(1).filter((line) => line.trim() !== "" && !RUNTIME_FRAME.test(line)).join("\\n");\n}\nvar V8_FRAME = /^\\s*at (?:(.*?) \\()?(.*?):(\\d+):(\\d+)\\)?$/;\nvar QUICKJS_FRAME = /^\\s*at (?:(.*?) )?\\(?(.*?)(?::(\\d+))?(?::(\\d+))?\\)?$/;\nfunction parseStack(stack) {\n const locations = [];\n for (const line of stack.split("\\n")) {\n if (line.trim() === "") continue;\n const match = V8_FRAME.exec(line) ?? QUICKJS_FRAME.exec(line);\n if (!match) continue;\n const location = {};\n if (match[1]) location.functionName = match[1];\n if (match[2]) location.filePath = match[2];\n if (match[3]) location.line = Number(match[3]);\n if (match[4]) location.column = Number(match[4]);\n locations.push(location);\n }\n return locations;\n}\n\nvar SDK_NAME = "@fluidgrids/workflows";\nvar ContinueAsNewRequest = class {\n constructor(input, options) {\n this.input = input;\n this.options = options;\n }\n input;\n options;\n};\nvar TaskFailure = class {\n constructor(cause, message, stackTrace, seq, errorType) {\n this.cause = cause;\n this.message = message;\n this.stackTrace = stackTrace;\n this.seq = seq;\n this.errorType = errorType;\n }\n cause;\n message;\n stackTrace;\n seq;\n errorType;\n};\nvar Scope = class {\n constructor(parent, nonCancellable) {\n this.parent = parent;\n this.nonCancellable = nonCancellable;\n this.cancelRequested = new Promise((_resolve, reject) => {\n this.rejectRequested = reject;\n });\n this.cancelRequested.catch(() => void 0);\n if (parent && !nonCancellable) {\n parent.children.add(this);\n if (parent.consideredCancelled) this.cancel();\n }\n }\n parent;\n nonCancellable;\n consideredCancelled = false;\n cancelRequested;\n rejectRequested = () => void 0;\n handlers = /* @__PURE__ */ new Set();\n children = /* @__PURE__ */ new Set();\n /** Register a reaction to cancellation; returns its removal. */\n onCancel(handler) {\n if (this.consideredCancelled) {\n handler();\n return () => void 0;\n }\n this.handlers.add(handler);\n return () => this.handlers.delete(handler);\n }\n /**\n * Cancel the scope and its children. Every handler and child runs even when\n * one throws; the first error is rethrown once the fan-out is complete.\n */\n cancel() {\n if (this.consideredCancelled) return;\n this.consideredCancelled = true;\n this.rejectRequested(new CancelledFailure("Cancellation requested"));\n const errors = [];\n const handlers = [...this.handlers];\n this.handlers.clear();\n for (const handler of handlers) {\n try {\n handler();\n } catch (error) {\n errors.push(error);\n }\n }\n for (const child of [...this.children]) {\n try {\n child.cancel();\n } catch (error) {\n errors.push(error);\n }\n }\n if (errors.length > 0) throw errors[0];\n }\n detach() {\n this.parent?.children.delete(this);\n }\n};\nfunction toJson(value, what) {\n if (value === void 0) return null;\n if (typeof value === "function" || typeof value === "symbol")\n throw new TypeError(`${what} is not JSON: it is a ${typeof value}`);\n let text;\n try {\n text = JSON.stringify(value);\n } catch (error) {\n if (!(error instanceof TypeError)) throw error;\n throw new TypeError(`${what} is not JSON: ${error.message}`);\n }\n if (text === void 0) return null;\n const parsed = JSON.parse(text);\n return parsed;\n}\nfunction randomnessSeedOf(request) {\n const started = request.history[0];\n const seed = started?.type === "WORKFLOW_STARTED" ? started.payload["randomnessSeed"] : void 0;\n return typeof seed === "string" ? seed : request.info.runId;\n}\nfunction errorName(error) {\n return error instanceof Error ? error.name : "";\n}\nfunction messageOf(error) {\n return error instanceof Error ? error.message : String(error);\n}\nfunction stackTextOf(error) {\n return error instanceof Error && typeof error.stack === "string" ? error.stack : void 0;\n}\nvar WorkflowExecution = class {\n request;\n definition;\n exportNames;\n sdkVersion;\n activations;\n index = -1;\n activationOpen = false;\n replaying = false;\n clock = 0;\n random;\n ids = new CommandIds();\n commands = [];\n newCommands = [];\n logs = [];\n failure;\n closed = false;\n captureStacks;\n /** History length and inline bytes the current activation reports (see `Activation.historyLength`). */\n historyLength = 0;\n historyBytes = 0;\n /** `bytesUpTo[n]`: UTF-8 bytes of the payloads of events 1..n. */\n bytesUpTo;\n limitEvents;\n limitBytes;\n root = new Scope(void 0, false);\n /**\n * Scopes whose function is running synchronously right now, innermost\n * last. The outer `ctx` uses the innermost one, else the root: a scope is\n * ambient only during the synchronous part of its function, never across\n * an await, so concurrent branches never see each other\'s scopes.\n */\n syncScopes = [];\n /** A scope that is never cancelled, for waits that ignore cancellation. */\n detachedScope = new Scope(void 0, true);\n cancelRequested = false;\n activities = /* @__PURE__ */ new Map();\n timers = /* @__PURE__ */ new Map();\n children = /* @__PURE__ */ new Map();\n externals = /* @__PURE__ */ new Map();\n issued = /* @__PURE__ */ new Set();\n recordedSideEffects = /* @__PURE__ */ new Map();\n recordedMarkers = /* @__PURE__ */ new Set();\n patches = /* @__PURE__ */ new Map();\n signalBuffers = /* @__PURE__ */ new Map();\n signalOrder = [];\n signalHandlers = /* @__PURE__ */ new Map();\n signalWaiters = /* @__PURE__ */ new Map();\n defaultSignalHandler;\n runningHandlers = 0;\n conditions = [];\n currentDetails;\n context;\n info;\n constructor(input) {\n this.request = input.request;\n this.definition = input.definition;\n this.exportNames = input.exportNames;\n this.sdkVersion = input.sdkVersion;\n const history = input.request.history;\n this.bytesUpTo = [0];\n let bytes = 0;\n for (const event of history) {\n bytes += utf8Bytes(JSON.stringify(event.payload));\n this.bytesUpTo.push(bytes);\n }\n this.historyLength = history.length;\n this.historyBytes = bytes;\n const limit = input.request.info.historyLimit ?? DEFAULT_HISTORY_LIMIT;\n this.limitEvents = limit.events;\n this.limitBytes = limit.bytes;\n this.captureStacks = input.request.kind === "query";\n this.random = createRandom(seedOf(randomnessSeedOf(input.request)));\n for (const event of history) {\n if (event.type === "SIDE_EFFECT_RECORDED") {\n const id = event.payload["sideEffectId"];\n if (typeof id === "string")\n this.recordedSideEffects.set(id, event.payload["value"] ?? null);\n } else if (event.type === "MARKER_RECORDED") {\n const id = event.payload["markerId"];\n if (typeof id === "string") this.recordedMarkers.add(id);\n }\n }\n this.activations = splitActivations(\n history,\n input.request.nowMs,\n input.request.kind !== "query"\n );\n const execution = this;\n this.info = {\n ...input.request.info,\n workflowFn: input.request.workflowFn,\n get historyLength() {\n return execution.historyLength;\n },\n get historyBytes() {\n return execution.historyBytes;\n },\n get continueAsNewSuggested() {\n return execution.continueAsNewSuggested();\n },\n get isReplaying() {\n return execution.replaying;\n }\n };\n this.context = this.contextFor(void 0);\n }\n continueAsNewSuggested() {\n return this.historyLength >= this.limitEvents * CONTINUE_AS_NEW_SUGGESTED_RATIO || this.historyBytes >= this.limitBytes * CONTINUE_AS_NEW_SUGGESTED_RATIO;\n }\n /** The workflow clock. */\n now() {\n return this.clock;\n }\n /** The next deterministic random number. */\n nextRandom() {\n return this.random();\n }\n /** Begin or finish an activation; `done` when there is nothing left to do. */\n step() {\n if (this.failure) return "done";\n if (this.activationOpen) {\n if (this.checkConditions()) return "more";\n this.finishActivation();\n if (this.failure) return "done";\n }\n const next = this.activations[this.index + 1];\n if (!next) return "done";\n this.index += 1;\n this.beginActivation(next);\n return this.failure ? "done" : "more";\n }\n /** The task\'s result. Call after `step()` returned `done` and jobs were drained. */\n complete() {\n if (!this.failure && this.activationOpen) {\n this.checkConditions();\n this.finishActivation();\n }\n const result = {\n protocol: HISTORY_PROTOCOL,\n outcome: this.failure ? "failed" : "commands",\n commands: this.failure ? [] : this.newCommands,\n logs: this.logs\n };\n if (this.failure) {\n result.failure = { cause: this.failure.cause, message: this.failure.message };\n if (this.failure.stackTrace !== void 0)\n result.failure.stackTrace = this.failure.stackTrace;\n if (this.failure.seq !== void 0) result.failure.seq = this.failure.seq;\n if (this.failure.errorType !== void 0) result.failure.errorType = this.failure.errorType;\n }\n if (this.request.kind === "query") result.queryResults = this.answerQueries();\n return result;\n }\n /** Fail the task (the runtime\'s own failures and code errors). */\n failTask(cause, message, stackTrace, seq, errorType) {\n if (!this.failure) this.failure = new TaskFailure(cause, message, stackTrace, seq, errorType);\n }\n beginActivation(activation) {\n this.activationOpen = true;\n this.replaying = activation.recorded !== void 0;\n this.clock = activation.timeMs;\n this.historyLength = activation.historyLength;\n this.historyBytes = this.bytesUpTo[Math.min(activation.historyLength, this.bytesUpTo.length - 1)] ?? 0;\n this.commands = [];\n for (const event of activation.inputs) {\n if (this.failure) return;\n this.deliver(event);\n }\n }\n finishActivation() {\n this.activationOpen = false;\n const activation = this.activations[this.index];\n if (!activation) return;\n if (activation.recorded) {\n const found = matchActivation(this.commands, activation.recorded);\n if (found)\n this.failTask(\n "NON_DETERMINISM",\n `Replay of workflow task ${activation.taskId ?? this.index + 1} diverged: ${found.message}`,\n void 0,\n found.seq\n );\n } else {\n this.newCommands = this.commands;\n }\n this.commands = [];\n }\n // ---- inputs ---------------------------------------------------------------\n deliver(event) {\n const p = event.payload;\n const id = (key) => typeof p[key] === "string" ? p[key] : "";\n switch (event.type) {\n case "WORKFLOW_STARTED":\n this.startFunction(p["input"] ?? null);\n return;\n case "ACTIVITY_COMPLETED":\n case "ACTIVITY_FAILED":\n case "ACTIVITY_TIMED_OUT":\n case "ACTIVITY_CANCELLED":\n this.settleActivity(event, id("activityId"));\n return;\n case "TIMER_FIRED": {\n const timerId = id("timerId");\n this.expectIssued(`timer:${timerId}`, event);\n const pending = this.timers.get(timerId);\n if (pending) {\n this.timers.delete(timerId);\n pending.release?.();\n pending.resolve(void 0);\n }\n return;\n }\n case "SIGNAL_RECEIVED":\n this.dispatchSignal(id("name"), p["payload"] ?? null);\n return;\n case "CHILD_RUN_STARTED":\n case "CHILD_RUN_COMPLETED":\n case "CHILD_RUN_FAILED":\n case "CHILD_RUN_CANCELLED":\n case "CHILD_RUN_TERMINATED":\n case "CHILD_RUN_TIMED_OUT":\n this.settleChild(event, id("childId"));\n return;\n case "EXTERNAL_RUN_SIGNALED":\n case "EXTERNAL_RUN_CANCEL_RESOLVED": {\n const externalId = id("externalId");\n this.expectIssued(`external:${externalId}`, event);\n const pending = this.externals.get(externalId);\n if (!pending) return;\n this.externals.delete(externalId);\n if (p["ok"] === true) pending.resolve(void 0);\n else {\n const failure = p["failure"];\n pending.reject(\n typeof failure === "object" && failure !== null && !Array.isArray(failure) ? failureToError(failure) : new ServerFailure(`${pending.description} was not delivered`)\n );\n }\n return;\n }\n case "WORKFLOW_CANCEL_REQUESTED":\n this.cancelRequested = true;\n this.root.cancel();\n return;\n default:\n return;\n }\n }\n expectIssued(key, event) {\n if (!this.issued.has(key))\n this.failTask(\n "NON_DETERMINISM",\n `The history has ${event.type} (seq ${event.seq}) for ${key}, which the code never issued`,\n void 0,\n event.seq\n );\n }\n settleActivity(event, activityId) {\n this.expectIssued(`activity:${activityId}`, event);\n const pending = this.activities.get(activityId);\n if (!pending) return;\n this.activities.delete(activityId);\n pending.release?.();\n const p = event.payload;\n const failure = typeof p["failure"] === "object" && p["failure"] !== null && !Array.isArray(p["failure"]) ? p["failure"] : void 0;\n const wrap = (cause) => new ActivityFailure(\n `Activity ${activityId} (${pending.nodeType} ${pending.operation}) failed: ${cause.message}`,\n activityId,\n pending.nodeType,\n pending.operation,\n cause\n );\n switch (event.type) {\n case "ACTIVITY_COMPLETED":\n pending.resolve(p["result"] ?? null);\n return;\n case "ACTIVITY_FAILED":\n pending.reject(\n wrap(\n failure ? failureToError(failure) : new ApplicationError("Activity failed", { errorType: "UNKNOWN" })\n )\n );\n return;\n case "ACTIVITY_TIMED_OUT": {\n const timeoutType = typeof p["timeoutType"] === "string" ? p["timeoutType"] : "UNKNOWN";\n pending.reject(\n wrap(new TimeoutFailure(`Activity timed out (${timeoutType})`, timeoutType))\n );\n return;\n }\n default:\n pending.reject(wrap(new CancelledFailure("Activity cancelled")));\n }\n }\n settleChild(event, childId) {\n this.expectIssued(`child:${childId}`, event);\n const child = this.children.get(childId);\n if (!child) return;\n const p = event.payload;\n if (typeof p["childRunId"] === "string") child.runId = p["childRunId"];\n if (event.type === "CHILD_RUN_STARTED") {\n const started2 = child.started;\n child.started = void 0;\n started2?.resolve(child.runId);\n return;\n }\n let outcome;\n const failureValue = p["failure"];\n const failure = typeof failureValue === "object" && failureValue !== null && !Array.isArray(failureValue) ? failureValue : void 0;\n const wrap = (cause) => new ChildRunFailure(\n `Child run ${childId} ${event.type.slice("CHILD_RUN_".length).toLowerCase().replace("_", " ")}: ${cause.message}`,\n childId,\n child.runId,\n cause\n );\n switch (event.type) {\n case "CHILD_RUN_COMPLETED":\n outcome = { ok: true, value: p["result"] ?? null };\n break;\n case "CHILD_RUN_FAILED":\n outcome = {\n ok: false,\n error: wrap(\n failure ? failureToError(failure) : new ApplicationError("Child failed", { errorType: "UNKNOWN" })\n )\n };\n break;\n case "CHILD_RUN_CANCELLED":\n outcome = { ok: false, error: wrap(new CancelledFailure("Child run cancelled")) };\n break;\n case "CHILD_RUN_TERMINATED":\n outcome = {\n ok: false,\n error: wrap(\n new TerminatedFailure(typeof p["reason"] === "string" ? p["reason"] : "Terminated")\n )\n };\n break;\n default: {\n const timeoutType = typeof p["timeoutType"] === "string" ? p["timeoutType"] : "WORKFLOW_RUN";\n outcome = {\n ok: false,\n error: wrap(new TimeoutFailure(`Child run timed out (${timeoutType})`, timeoutType))\n };\n }\n }\n child.settled = true;\n child.outcome = outcome;\n const started = child.started;\n child.started = void 0;\n if (started) {\n if (outcome.ok) started.resolve(child.runId);\n else started.reject(outcome.error);\n }\n const result = child.result;\n child.result = void 0;\n if (result) {\n result.release?.();\n if (outcome.ok) result.resolve(outcome.value);\n else result.reject(outcome.error);\n }\n }\n dispatchSignal(name, payload) {\n const handler = this.signalHandlers.get(name);\n if (handler) {\n this.runHandler(() => handler(payload));\n return;\n }\n const waiters = this.signalWaiters.get(name);\n const waiter = waiters?.shift();\n if (waiter) {\n waiter.release?.();\n waiter.resolve(payload);\n return;\n }\n if (this.defaultSignalHandler) {\n const fallback = this.defaultSignalHandler;\n this.runHandler(() => fallback(name, payload));\n return;\n }\n const buffer = this.signalBuffers.get(name) ?? [];\n buffer.push(payload);\n this.signalBuffers.set(name, buffer);\n this.signalOrder.push({ name, payload });\n }\n takeBuffered(name) {\n const buffer = this.signalBuffers.get(name);\n if (!buffer || buffer.length === 0) return void 0;\n const payload = buffer.shift();\n const position = this.signalOrder.findIndex((entry) => entry.name === name);\n if (position >= 0) this.signalOrder.splice(position, 1);\n return payload;\n }\n runHandler(call) {\n let result;\n try {\n result = call();\n } catch (error) {\n this.onWorkflowError(error);\n return;\n }\n if (result instanceof Promise) {\n this.runningHandlers += 1;\n result.then(\n () => {\n this.runningHandlers -= 1;\n },\n (error) => {\n this.runningHandlers -= 1;\n this.onWorkflowError(error);\n }\n );\n }\n }\n // ---- the workflow function ------------------------------------------------\n startFunction(input) {\n let promise;\n try {\n promise = Promise.resolve(this.definition.fn(this.context, input));\n } catch (error) {\n promise = Promise.reject(error);\n }\n promise.then(\n (value) => this.onReturn(value),\n (error) => this.onWorkflowError(error)\n );\n }\n onReturn(value) {\n if (this.closed || this.failure) return;\n let output;\n try {\n output = toJson(value, "The workflow output");\n } catch (error) {\n if (error instanceof TypeError)\n this.failTask("WORKFLOW_CODE_ERROR", messageOf(error), stackTextOf(error));\n else this.onWorkflowError(error);\n return;\n }\n this.pushTerminal({ type: "COMPLETE_WORKFLOW", output });\n }\n isFailureType(error) {\n const listed = this.definition.options.failureErrorTypes ?? [];\n return listed.some((type) => error instanceof type);\n }\n /** What an error thrown out of workflow code does (11 \xA72.25, \xA72.37). */\n onWorkflowError(error) {\n if (this.closed || this.failure) return;\n if (error instanceof ContinueAsNewRequest) {\n this.pushTerminal({ type: "CONTINUE_AS_NEW", input: error.input, options: error.options });\n return;\n }\n const name = errorName(error);\n if (error instanceof DeterminismViolation || name === "DeterminismViolation") {\n this.failTask("NON_DETERMINISM", messageOf(error), stackTextOf(error), void 0, name);\n return;\n }\n if (error instanceof HistoryLimitExceeded) {\n this.failTask("HISTORY_LIMIT", messageOf(error), stackTextOf(error));\n return;\n }\n if (name === "InternalError" && /out of memory/i.test(messageOf(error))) {\n this.failTask("ISOLATE_MEMORY", messageOf(error), stackTextOf(error), void 0, name);\n return;\n }\n if (error instanceof PhaseCFeatureError) {\n this.failTask("UNSUPPORTED_COMMAND", messageOf(error), stackTextOf(error));\n return;\n }\n if (this.cancelRequested && isCancellation(error)) {\n this.pushTerminal({ type: "CANCEL_WORKFLOW" });\n return;\n }\n if (isRunFailure(error) || this.isFailureType(error)) {\n this.pushTerminal({ type: "FAIL_WORKFLOW", failure: errorToFailure(error) });\n return;\n }\n this.failTask(\n "WORKFLOW_CODE_ERROR",\n `${name || "Error"}: ${messageOf(error)}`,\n stackTextOf(error),\n void 0,\n name || void 0\n );\n }\n // ---- commands -------------------------------------------------------------\n currentScope() {\n return this.syncScopes[this.syncScopes.length - 1] ?? this.root;\n }\n /**\n * Throw `HistoryLimitExceeded` from 95 % of the cap. It runs on replay too:\n * the history length is the activation\'s cutoff and the command count is\n * the activation\'s own, so replay sees what the first execution saw.\n */\n checkLimit() {\n const events = this.historyLength + this.commands.length;\n if (events >= this.limitEvents * HISTORY_LIMIT_EXCEEDED_RATIO || this.historyBytes >= this.limitBytes * HISTORY_LIMIT_EXCEEDED_RATIO)\n throw new HistoryLimitExceeded(\n `The history has ${events} events and ${this.historyBytes} bytes, past 95 % of its limit (${this.limitEvents} events, ${this.limitBytes} bytes); continue as new`\n );\n }\n /** Issue a command; false when the run is already closed (the command is dropped). */\n push(command) {\n if (this.closed || this.failure) return false;\n this.checkLimit();\n this.commands.push(command);\n return true;\n }\n pushTerminal(command) {\n if (this.closed || this.failure) return;\n this.commands.push(command);\n this.closed = true;\n }\n stack() {\n return this.captureStacks ? captureStack() : void 0;\n }\n never() {\n return new Promise(() => void 0);\n }\n scheduleActivity(scope, operation, options) {\n if (typeof operation !== "object" || operation === null || typeof operation.nodeType !== "string")\n throw new TypeError("ctx.run needs a node operation (from nodes.* or the generated clients)");\n if (operation.role === "trigger" || !isActivityNodeTypeAllowed(operation.nodeType))\n throw new ApplicationError(\n `${operation.nodeType} cannot run as a durable activity: only store and registry nodes and internal:http, internal:datatable, internal:set and internal:code can`,\n { type: "durable.activityTypeNotAllowed", errorType: "VALIDATION", nonRetryable: true }\n );\n const activityId = this.ids.next("a");\n const operationName = options.operation ?? operation.operation ?? "execute";\n const nodeVersion = options.nodeVersion ?? operation.version;\n const cancellationType = options.cancellationType ?? "WAIT_CANCELLATION_COMPLETED";\n const command = {\n type: "SCHEDULE_ACTIVITY",\n activityId,\n kind: "node",\n nodeType: operation.nodeType,\n operation: operationName,\n args: toJson(options.args, `The args of ${operation.nodeType}`),\n retry: explicitRetryPolicy(options.retry)\n };\n if (nodeVersion !== void 0) command.nodeVersion = nodeVersion;\n if (options.connection !== void 0) command.connection = options.connection;\n const startToClose = optionalMs(options.startToCloseTimeout, "startToCloseTimeout");\n const scheduleToClose = optionalMs(options.scheduleToCloseTimeout, "scheduleToCloseTimeout");\n const scheduleToStart = optionalMs(options.scheduleToStartTimeout, "scheduleToStartTimeout");\n const heartbeat = optionalMs(options.heartbeatTimeout, "heartbeatTimeout");\n if (startToClose !== void 0) command.startToCloseTimeout = startToClose;\n if (scheduleToClose !== void 0) command.scheduleToCloseTimeout = scheduleToClose;\n if (scheduleToStart !== void 0) command.scheduleToStartTimeout = scheduleToStart;\n if (heartbeat !== void 0) command.heartbeatTimeout = heartbeat;\n if (options.cancellationType !== void 0) command.cancellationType = options.cancellationType;\n if (options.priority !== void 0) command.priority = options.priority;\n if (options.summary !== void 0) command.summary = options.summary;\n if (options.runOn !== void 0) command.runOn = options.runOn;\n if (options.headers !== void 0) command.headers = { ...options.headers };\n if (scope.consideredCancelled)\n return Promise.reject(new CancelledFailure("Scope is cancelled"));\n if (!this.push(command)) return this.never();\n this.issued.add(`activity:${activityId}`);\n return new Promise((resolve, reject) => {\n const entry = {\n resolve,\n reject,\n description: `activity ${activityId} (${operation.nodeType} ${operationName})`,\n nodeType: operation.nodeType,\n operation: operationName,\n cancellationType\n };\n const stack = this.stack();\n if (stack !== void 0) entry.stack = stack;\n entry.release = scope.onCancel(() => {\n if (!this.activities.has(activityId)) return;\n const cancelled = new ActivityFailure(\n `Activity ${activityId} cancelled`,\n activityId,\n entry.nodeType,\n entry.operation,\n new CancelledFailure("Activity cancelled")\n );\n if (cancellationType !== "ABANDON")\n this.push({ type: "REQUEST_CANCEL_ACTIVITY", activityId });\n if (cancellationType !== "WAIT_CANCELLATION_COMPLETED") {\n this.activities.delete(activityId);\n reject(cancelled);\n }\n });\n this.activities.set(activityId, entry);\n });\n }\n startTimer(scope, durationMs2, summary) {\n return this.timer(scope, durationMs2, summary).promise;\n }\n /** Start a durable timer; `timerId` is undefined when no timer was needed or issued. */\n timer(scope, durationMs2, summary) {\n if (durationMs2 <= 0) return { promise: Promise.resolve() };\n if (scope.consideredCancelled)\n return { promise: Promise.reject(new CancelledFailure("Scope is cancelled")) };\n const timerId = this.ids.next("t");\n const command = {\n type: "START_TIMER",\n timerId,\n durationMs: Math.max(1, Math.round(durationMs2))\n };\n if (summary !== void 0) command.summary = summary;\n if (!this.push(command)) return { promise: this.never() };\n this.issued.add(`timer:${timerId}`);\n const promise = new Promise((resolve, reject) => {\n const entry = {\n resolve,\n reject,\n description: `timer ${timerId} (${durationMs2} ms)`\n };\n const stack = this.stack();\n if (stack !== void 0) entry.stack = stack;\n entry.release = scope.onCancel(() => {\n if (!this.timers.has(timerId)) return;\n this.timers.delete(timerId);\n this.push({ type: "CANCEL_TIMER", timerId });\n reject(new CancelledFailure("Timer cancelled"));\n });\n this.timers.set(timerId, entry);\n });\n return { promise, timerId };\n }\n /** Cancel a pending timer the runtime started for itself (condition and scope timeouts). */\n cancelOwnTimer(timerId) {\n if (timerId === void 0) return;\n const pending = this.timers.get(timerId);\n if (!pending) return;\n this.timers.delete(timerId);\n pending.release?.();\n this.push({ type: "CANCEL_TIMER", timerId });\n }\n condition(scope, predicate, timeout) {\n if (predicate()) return Promise.resolve(true);\n if (scope.consideredCancelled)\n return Promise.reject(new CancelledFailure("Scope is cancelled"));\n return new Promise((resolve, reject) => {\n const condition = { predicate, resolve, reject };\n const stack = this.stack();\n if (stack !== void 0) condition.stack = stack;\n this.conditions.push(condition);\n if (timeout !== void 0) {\n const timer = this.timer(scope, toMs(timeout, "condition timeout"), void 0);\n if (timer.timerId !== void 0) condition.timerId = timer.timerId;\n timer.promise.then(\n () => {\n if (!this.conditions.includes(condition)) return;\n this.conditions = this.conditions.filter((entry) => entry !== condition);\n condition.release?.();\n resolve(false);\n },\n () => void 0\n );\n }\n condition.release = scope.onCancel(() => {\n if (!this.conditions.includes(condition)) return;\n this.conditions = this.conditions.filter((entry) => entry !== condition);\n this.cancelOwnTimer(condition.timerId);\n reject(new CancelledFailure("Condition cancelled"));\n });\n });\n }\n /** Resolve conditions whose predicate now holds; true when any did. */\n checkConditions() {\n let fired = false;\n for (const condition of [...this.conditions]) {\n let holds = false;\n try {\n holds = condition.predicate();\n } catch (error) {\n this.conditions = this.conditions.filter((entry) => entry !== condition);\n condition.release?.();\n condition.reject(error);\n fired = true;\n continue;\n }\n if (!holds) continue;\n this.conditions = this.conditions.filter((entry) => entry !== condition);\n condition.release?.();\n this.cancelOwnTimer(condition.timerId);\n condition.resolve(true);\n fired = true;\n }\n return fired;\n }\n signalReceived(scope, signal) {\n const name = signalName(signal);\n const buffered = this.takeBuffered(name);\n if (buffered !== void 0) return Promise.resolve(buffered);\n return new Promise((resolve, reject) => {\n const entry = {\n resolve,\n reject,\n description: `signal ${name}`\n };\n const stack = this.stack();\n if (stack !== void 0) entry.stack = stack;\n const waiters = this.signalWaiters.get(name) ?? [];\n waiters.push(entry);\n this.signalWaiters.set(name, waiters);\n entry.release = scope.onCancel(() => {\n const list = this.signalWaiters.get(name) ?? [];\n const position = list.indexOf(entry);\n if (position < 0) return;\n list.splice(position, 1);\n reject(new CancelledFailure("Signal wait cancelled"));\n });\n });\n }\n onSignal(signal, handler) {\n const name = signalName(signal);\n this.signalHandlers.set(name, handler);\n let payload = this.takeBuffered(name);\n while (payload !== void 0) {\n const value = payload;\n this.runHandler(() => handler(value));\n payload = this.takeBuffered(name);\n }\n }\n setDefaultSignalHandler(handler) {\n this.defaultSignalHandler = handler;\n const buffered = [...this.signalOrder];\n for (const entry of buffered) {\n if (this.signalHandlers.has(entry.name)) continue;\n const payload = this.takeBuffered(entry.name);\n if (payload !== void 0) this.runHandler(() => handler(entry.name, payload));\n }\n }\n childTarget(target) {\n if (typeof target === "string") {\n if (target === "") throw new TypeError("ctx.child needs a workflow key or function");\n return { workflowKey: target };\n }\n if (isDurableWorkflow(target)) {\n const exportName = this.exportNames.get(target);\n if (exportName === void 0)\n throw new TypeError(\n `workflow("${target.name}") is not exported by any module of this bundle; export it to start it as a child (in the test environment, pass it in \\`workflows\\`)`\n );\n return { workflowFn: exportName };\n }\n throw new TypeError("ctx.child needs a workflow key or a workflow() function");\n }\n childCommand(childId, target, options, defaultPolicy) {\n const opts = { parentClosePolicy: options.parentClosePolicy ?? defaultPolicy };\n if (options.cancellationType !== void 0) opts["cancellationType"] = options.cancellationType;\n if (options.taskQueue !== void 0) opts["taskQueue"] = options.taskQueue;\n if (options.workflowId !== void 0) opts["workflowId"] = options.workflowId;\n if (options.priority !== void 0) opts["priority"] = options.priority;\n if (options.summary !== void 0) opts["summary"] = options.summary;\n if (options.details !== void 0) opts["details"] = options.details;\n if (options.context !== void 0)\n opts["context"] = toJson(options.context, "The child context");\n const durations = [\n ["startDelay", "startDelay"],\n ["executionTimeout", "executionTimeout"],\n ["runTimeout", "runTimeout"],\n ["workflowTaskTimeout", "workflowTaskTimeout"]\n ];\n for (const [key, name] of durations) {\n const value = options[key];\n if (value !== void 0 && (typeof value === "number" || typeof value === "string"))\n opts[name] = toMs(value, name);\n }\n const command = {\n type: "START_CHILD_RUN",\n childId,\n ...this.childTarget(target),\n input: toJson(options.input, "The child input"),\n options: {\n parentClosePolicy: opts["parentClosePolicy"] === "ABANDON" ? "ABANDON" : opts["parentClosePolicy"] === "REQUEST_CANCEL" ? "REQUEST_CANCEL" : "TERMINATE",\n ...opts\n }\n };\n if (options.version !== void 0) command.version = options.version;\n if (options.headers !== void 0) command.headers = { ...options.headers };\n return command;\n }\n startChildRun(scope, target, options, defaultPolicy) {\n if (scope.consideredCancelled) return void 0;\n const childId = this.ids.next("c");\n const command = this.childCommand(childId, target, options, defaultPolicy);\n if (!this.push(command)) return void 0;\n this.issued.add(`child:${childId}`);\n const child = { childId, settled: false, scope };\n if (options.cancellationType !== void 0) child.cancellationType = options.cancellationType;\n this.children.set(childId, child);\n return child;\n }\n /** What cancelling the scope of a child\'s awaitable does (see `ChildOptions.cancellationType`). */\n onChildCancel(child, entry) {\n return () => {\n if (child.settled) return;\n const type = child.cancellationType ?? CHILD_DEFAULT_CANCELLATION_TYPE;\n const error = new ChildRunFailure(\n `Child run ${child.childId} cancelled`,\n child.childId,\n child.runId,\n new CancelledFailure("Child run cancelled")\n );\n if (type === "ABANDON") {\n child.result = void 0;\n entry.reject(error);\n return;\n }\n const externalId = this.ids.next("x");\n if (this.push({\n type: "REQUEST_CANCEL_EXTERNAL_RUN",\n externalId,\n target: { childId: child.childId }\n })) {\n this.issued.add(`external:${externalId}`);\n if (type === "WAIT_CANCELLATION_REQUESTED") {\n this.externals.set(externalId, {\n resolve: () => {\n child.result = void 0;\n entry.reject(error);\n },\n reject: () => {\n child.result = void 0;\n entry.reject(error);\n },\n description: `cancel of child ${child.childId}`\n });\n } else {\n this.externals.set(externalId, {\n resolve: () => void 0,\n reject: () => void 0,\n description: `cancel of child ${child.childId}`\n });\n }\n }\n if (type === "TRY_CANCEL") {\n child.result = void 0;\n entry.reject(error);\n }\n };\n }\n child(scope, target, options) {\n const child = this.startChildRun(\n scope,\n target,\n options,\n CHILD_DEFAULT_PARENT_CLOSE_POLICY.child\n );\n if (!child)\n return scope.consideredCancelled ? Promise.reject(new CancelledFailure("Scope is cancelled")) : this.never();\n return this.childResult(child);\n }\n childResult(child) {\n if (child.settled && child.outcome) {\n const outcome = child.outcome;\n return outcome.ok ? Promise.resolve(outcome.value) : Promise.reject(outcome.error);\n }\n return new Promise((resolve, reject) => {\n const entry = {\n resolve,\n reject,\n description: `child run ${child.childId}`\n };\n const stack = this.stack();\n if (stack !== void 0) entry.stack = stack;\n entry.release = child.scope.onCancel(this.onChildCancel(child, entry));\n child.result = entry;\n });\n }\n startChild(scope, target, options) {\n const child = this.startChildRun(\n scope,\n target,\n options,\n CHILD_DEFAULT_PARENT_CLOSE_POLICY.startChild\n );\n if (!child)\n return scope.consideredCancelled ? Promise.reject(new CancelledFailure("Scope is cancelled")) : this.never();\n return new Promise((resolve, reject) => {\n const entry = {\n resolve,\n reject,\n description: `start of child run ${child.childId}`\n };\n const stack = this.stack();\n if (stack !== void 0) entry.stack = stack;\n child.started = entry;\n }).then((runId) => {\n const handle = {\n childId: child.childId,\n runId: runId ?? child.runId ?? "",\n result: () => this.childResult(child),\n signal: (signal, payload) => this.signalExternal({ childId: child.childId }, signalName(signal), payload),\n cancel: () => this.cancelExternal({ childId: child.childId })\n };\n return handle;\n });\n }\n signalExternal(target, name, payload) {\n const externalId = this.ids.next("x");\n const command = {\n type: "SIGNAL_RUN",\n externalId,\n target,\n name,\n payload: toJson(payload, `The payload of signal ${name}`)\n };\n if (!this.push(command)) return this.never();\n this.issued.add(`external:${externalId}`);\n return new Promise((resolve, reject) => {\n const entry = {\n resolve,\n reject,\n description: `signal ${name}`\n };\n const stack = this.stack();\n if (stack !== void 0) entry.stack = stack;\n this.externals.set(externalId, entry);\n });\n }\n cancelExternal(target) {\n const externalId = this.ids.next("x");\n if (!this.push({ type: "REQUEST_CANCEL_EXTERNAL_RUN", externalId, target }))\n return this.never();\n this.issued.add(`external:${externalId}`);\n return new Promise((resolve, reject) => {\n const entry = {\n resolve,\n reject,\n description: `cancel request ${externalId}`\n };\n const stack = this.stack();\n if (stack !== void 0) entry.stack = stack;\n this.externals.set(externalId, entry);\n });\n }\n sideEffect(fn) {\n const sideEffectId = this.ids.next("s");\n let value;\n if (this.replaying && this.recordedSideEffects.has(sideEffectId)) {\n value = this.recordedSideEffects.get(sideEffectId) ?? null;\n } else {\n value = toJson(fn(), "The side effect value");\n }\n this.push({ type: "RECORD_SIDE_EFFECT", sideEffectId, value });\n return toJson(value, "The side effect value");\n }\n patched(patchId, deprecated) {\n if (typeof patchId !== "string" || patchId === "") throw new TypeError("A patch needs an id");\n const known = this.patches.get(patchId);\n if (known !== void 0) return known;\n const markerId = patchMarkerId(patchId);\n let result;\n if (this.replaying) {\n result = this.recordedMarkers.has(markerId);\n if (result)\n this.push({\n type: "RECORD_MARKER",\n markerId,\n data: { patchId, ...deprecated ? { deprecated: true } : {} }\n });\n } else {\n result = true;\n if (!this.recordedMarkers.has(markerId)) {\n this.push({\n type: "RECORD_MARKER",\n markerId,\n data: { patchId, ...deprecated ? { deprecated: true } : {} }\n });\n this.recordedMarkers.add(markerId);\n }\n }\n this.patches.set(patchId, result);\n return result;\n }\n setCurrentDetails(markdown) {\n if (typeof markdown !== "string") throw new TypeError("setCurrentDetails takes Markdown text");\n this.currentDetails = markdown;\n this.push({\n type: "RECORD_MARKER",\n markerId: this.ids.next("m"),\n data: { currentDetails: markdown }\n });\n }\n upsertContext(entries) {\n this.push({\n type: "UPSERT_CONTEXT",\n entries: toJson(entries, "The context entries")\n });\n }\n /** The request a `ctx.continueAsNew` call throws; the run ends with `CONTINUE_AS_NEW`. */\n continueAsNew(input, options) {\n const opts = {};\n if (options.taskQueue !== void 0) opts["taskQueue"] = options.taskQueue;\n if (options.retry !== void 0)\n opts["retry"] = toJson(explicitRetryPolicy(options.retry), "retry");\n if (options.workflowTaskTimeout !== void 0)\n opts["workflowTaskTimeout"] = toMs(options.workflowTaskTimeout, "workflowTaskTimeout");\n if (options.context !== void 0) opts["context"] = toJson(options.context, "context");\n if (options.versioningBehavior !== void 0)\n opts["versioningBehavior"] = options.versioningBehavior;\n return new ContinueAsNewRequest(toJson(input, "The continue-as-new input"), opts);\n }\n async cancellationScope(parent, fn, options) {\n const scope = new Scope(parent, options.nonCancellable === true);\n let timerId;\n if (options.timeout !== void 0) {\n const timer = this.timer(parent, toMs(options.timeout, "scope timeout"), void 0);\n timerId = timer.timerId;\n timer.promise.then(\n () => scope.cancel(),\n () => void 0\n );\n }\n this.syncScopes.push(scope);\n let promise;\n try {\n promise = Promise.resolve(fn(this.contextFor(scope)));\n } catch (error) {\n promise = Promise.reject(error);\n } finally {\n this.syncScopes.pop();\n }\n try {\n return await promise;\n } finally {\n scope.detach();\n if (timerId !== void 0 && this.timers.has(timerId)) this.cancelOwnTimer(timerId);\n }\n }\n /** Waits for the signal handlers regardless of cancellation, as Temporal does. */\n allHandlersFinished() {\n return this.condition(this.detachedScope, () => this.runningHandlers === 0, void 0).then(\n () => void 0\n );\n }\n // ---- queries --------------------------------------------------------------\n pendingStacks() {\n const out = [];\n const add = (entry, fallback) => {\n if (!entry) return;\n out.push({ description: entry.description ?? fallback, stack: entry.stack ?? "" });\n };\n for (const entry of this.activities.values()) add(entry, "activity");\n for (const entry of this.timers.values()) add(entry, "timer");\n for (const child of this.children.values()) {\n add(child.started, "child start");\n add(child.result, "child result");\n }\n for (const entry of this.externals.values()) add(entry, "external");\n for (const list of this.signalWaiters.values()) for (const entry of list) add(entry, "signal");\n for (const condition of this.conditions)\n add(\n {\n description: "condition",\n ...condition.stack !== void 0 ? { stack: condition.stack } : {}\n },\n "condition"\n );\n return out;\n }\n answerQueries() {\n return (this.request.queries ?? []).map((query) => {\n if (!BUILT_IN_QUERIES.includes(query.name))\n return {\n queryId: query.queryId,\n error: `Unknown query ${String(query.name)}; custom queries are Phase C`\n };\n if (this.failure)\n return { queryId: query.queryId, error: `The replay failed: ${this.failure.message}` };\n if (query.name === "__stack_trace")\n return {\n queryId: query.queryId,\n value: this.pendingStacks().map((entry) => `${entry.description}\n${entry.stack}`).join("\\n\\n")\n };\n if (query.name === "__enhanced_stack_trace")\n return {\n queryId: query.queryId,\n value: {\n sdk: { name: SDK_NAME, version: this.sdkVersion },\n stacks: this.pendingStacks().map((entry) => ({\n description: entry.description,\n locations: parseStack(entry.stack).map((location) => {\n const out = {};\n if (location.filePath !== void 0) out["filePath"] = location.filePath;\n if (location.line !== void 0) out["line"] = location.line;\n if (location.column !== void 0) out["column"] = location.column;\n if (location.functionName !== void 0)\n out["functionName"] = location.functionName;\n return out;\n })\n }))\n }\n };\n const options = this.definition.options;\n const describe = (items) => (items ?? []).map((item) => ({ name: item.name, description: item.description ?? null }));\n return {\n queryId: query.queryId,\n value: {\n definition: {\n name: this.definition.name,\n signals: describe(options.signals),\n queries: describe(options.queries),\n updates: describe(options.updates)\n },\n currentDetails: this.currentDetails ?? null\n }\n };\n });\n }\n // ---- the context ----------------------------------------------------------\n contextFor(bound) {\n const scope = () => bound ?? this.currentScope();\n const log = (level) => (message, data) => {\n if (this.replaying) return;\n const line = { level, message: String(message) };\n if (data !== void 0) line.data = toJson(data, "The log data");\n this.logs.push(line);\n };\n const logger = {\n debug: log("debug"),\n info: log("info"),\n warn: log("warn"),\n error: log("error")\n };\n const scopeFn = ((fn, options = {}) => this.cancellationScope(scope(), fn, options));\n scopeFn.current = () => scope();\n const phaseC = (feature) => () => {\n throw new PhaseCFeatureError(feature);\n };\n const context = {\n info: this.info,\n log: logger,\n run: (operation, options) => this.scheduleActivity(scope(), operation, options),\n sleep: (duration, options = {}) => this.startTimer(scope(), toMs(duration, "sleep duration"), options.summary),\n condition: (predicate, timeout) => this.condition(scope(), predicate, timeout),\n signalReceived: (signal) => this.signalReceived(scope(), signal),\n onSignal: (signal, handler) => this.onSignal(signal, handler),\n setDefaultSignalHandler: (handler) => this.setDefaultSignalHandler(handler),\n child: (target, options = {}) => this.child(scope(), target, options),\n startChild: (target, options = {}) => this.startChild(scope(), target, options),\n signalRun: (runId, signal, payload) => this.signalExternal({ runId }, signalName(signal), payload),\n signalParent: (signal, payload) => this.signalExternal({ parent: true }, signalName(signal), payload),\n getRunHandle: (runId) => ({\n runId,\n signal: (signal, payload) => this.signalExternal({ runId }, signalName(signal), payload),\n cancel: () => this.cancelExternal({ runId })\n }),\n cancelRun: (runId) => this.cancelExternal({ runId }),\n now: () => this.clock,\n random: () => this.random(),\n uuid: () => uuidFrom(this.random),\n sideEffect: (fn) => this.sideEffect(fn),\n patched: (patchId) => this.patched(patchId, false),\n deprecatePatch: (patchId) => {\n this.patched(patchId, true);\n },\n setCurrentDetails: (markdown) => this.setCurrentDetails(markdown),\n upsertContext: (entries) => this.upsertContext(entries),\n continueAsNew: (input, options = {}) => {\n try {\n return Promise.reject(this.continueAsNew(input, options));\n } catch (error) {\n return Promise.reject(error);\n }\n },\n cancellationScope: scopeFn,\n nonCancellable: (fn) => this.cancellationScope(scope(), fn, { nonCancellable: true }),\n onCancel: (fn) => {\n scope().onCancel(() => {\n try {\n fn();\n } catch (error) {\n this.onWorkflowError(error);\n }\n });\n },\n isCancellation: (error) => isCancellation(error),\n saga: () => {\n const compensations = [];\n return {\n add: (compensation) => {\n compensations.push(compensation);\n },\n // Each compensation runs in its own non-cancellable scope, so it\n // still runs after a cancel request; it gets that scope\'s `ctx`.\n compensate: async () => {\n const pending = [...compensations].reverse();\n compensations.length = 0;\n for (const compensation of pending)\n await this.cancellationScope(\n scope(),\n async (scoped) => {\n await compensation(scoped);\n },\n { nonCancellable: true }\n );\n }\n };\n },\n allHandlersFinished: () => this.allHandlersFinished(),\n activity: phaseC("ctx.activity (user activities)"),\n localActivity: phaseC(\n "ctx.localActivity (local activities)"\n ),\n handleQuery: phaseC("ctx.handleQuery (custom queries)"),\n handleUpdate: phaseC("ctx.handleUpdate (updates)"),\n upsertSearchAttributes: phaseC("ctx.upsertSearchAttributes (search attributes)")\n };\n return Object.freeze(context);\n }\n};\n\nvar RUNTIME_GLOBAL = "__fluidgridsRuntime";\nfunction buildWorkflowRegistry(modules) {\n const byName = /* @__PURE__ */ new Map();\n const exportNames = /* @__PURE__ */ new Map();\n const ambiguous = /* @__PURE__ */ new Set();\n for (const [, namespace] of modules) {\n for (const exportName of Object.keys(namespace).sort()) {\n const value = namespace[exportName];\n if (!isDurableWorkflow(value)) continue;\n const existing = byName.get(exportName);\n if (existing && existing !== value) ambiguous.add(exportName);\n byName.set(exportName, value);\n if (!exportNames.has(value)) exportNames.set(value, exportName);\n }\n }\n return { byName, exportNames, ambiguous };\n}\nfunction failedResult(cause, message) {\n return {\n protocol: HISTORY_PROTOCOL,\n outcome: "failed",\n commands: [],\n failure: { cause, message },\n logs: []\n };\n}\nfunction isObject(value) {\n return typeof value === "object" && value !== null && !Array.isArray(value);\n}\nfunction checkRequest(value) {\n if (!isObject(value)) return "the request is not an object";\n if (typeof value["workflowFn"] !== "string" || value["workflowFn"] === "")\n return "workflowFn is missing";\n if (value["kind"] !== "task" && value["kind"] !== "query" && value["kind"] !== "verify")\n return "kind must be task, query or verify";\n const info = value["info"];\n if (!isObject(info) || typeof info["runId"] !== "string") return "info.runId is missing";\n if (!Array.isArray(value["history"])) return "history must be an array";\n for (const [index, event] of value["history"].entries()) {\n if (!isObject(event) || typeof event["type"] !== "string" || typeof event["seq"] !== "number" || !isObject(event["payload"]) || typeof event["createdAt"] !== "string")\n return `history[${index}] is not an event`;\n }\n if (typeof value["nowMs"] !== "number" || !Number.isFinite(value["nowMs"]))\n return "nowMs must be a number";\n return value;\n}\nfunction createWorkflowRuntime(registry, shims = void 0) {\n let execution;\n let early;\n const internalFailure = (error) => {\n const message = error instanceof Error ? error.message : String(error);\n const stack = error instanceof Error ? error.stack : void 0;\n if (error instanceof HistoryLimitExceeded) execution?.failTask("HISTORY_LIMIT", message, stack);\n else if (error instanceof DeterminismViolation || error instanceof Error && error.name === "DeterminismViolation")\n execution?.failTask("NON_DETERMINISM", message, stack);\n else execution?.failTask("INTERNAL", message, stack);\n };\n return Object.freeze({\n protocol: HISTORY_PROTOCOL,\n sdkVersion: SDK_VERSION,\n start(requestJson) {\n shims?.detach();\n execution = void 0;\n early = void 0;\n let parsed;\n try {\n parsed = JSON.parse(requestJson);\n } catch (error) {\n early = failedResult(\n "INVALID_REQUEST",\n `The request is not JSON: ${error instanceof Error ? error.message : String(error)}`\n );\n return;\n }\n if (isObject(parsed) && parsed["protocol"] !== HISTORY_PROTOCOL) {\n early = failedResult(\n "PROTOCOL_MISMATCH",\n `This bundle speaks runtime protocol ${HISTORY_PROTOCOL}; the request uses ${String(parsed["protocol"])}`\n );\n return;\n }\n const request = checkRequest(parsed);\n if (typeof request === "string") {\n early = failedResult("INVALID_REQUEST", `Invalid workflow task request: ${request}`);\n return;\n }\n if (registry.ambiguous.has(request.workflowFn)) {\n early = failedResult(\n "INVALID_REQUEST",\n `More than one module exports a workflow named "${request.workflowFn}"`\n );\n return;\n }\n const definition = registry.byName.get(request.workflowFn);\n if (!definition) {\n early = failedResult(\n "INVALID_REQUEST",\n `The bundle exports no workflow named "${request.workflowFn}"`\n );\n return;\n }\n try {\n const created = new WorkflowExecution({\n definition,\n exportNames: registry.exportNames,\n request,\n sdkVersion: SDK_VERSION\n });\n execution = created;\n shims?.attach({ now: () => created.now(), random: () => created.nextRandom() });\n } catch (error) {\n early = failedResult("INTERNAL", error instanceof Error ? error.message : String(error));\n }\n },\n step() {\n if (!execution) return "done";\n try {\n return execution.step();\n } catch (error) {\n internalFailure(error);\n return "done";\n }\n },\n complete() {\n try {\n if (early || !execution)\n return JSON.stringify(early ?? failedResult("INVALID_REQUEST", "start() was not called"));\n try {\n return JSON.stringify(execution.complete());\n } catch (error) {\n internalFailure(error);\n return JSON.stringify(execution.complete());\n }\n } finally {\n shims?.detach();\n execution = void 0;\n early = void 0;\n }\n }\n });\n}\nfunction installWorkflowRuntime(modules) {\n const holder = globalThis;\n if (holder[RUNTIME_GLOBAL] !== void 0) return;\n const runtime = createWorkflowRuntime(buildWorkflowRegistry(modules), takeShimControl());\n Object.defineProperty(globalThis, RUNTIME_GLOBAL, {\n value: runtime,\n writable: false,\n enumerable: false,\n configurable: false\n });\n}\nexport {\n ActivityFailure,\n ApplicationError,\n BuilderError,\n COLLECTION_FORMAT,\n CancelledFailure,\n ChildRunFailure,\n DURABLE_MARKER,\n DeterminismViolation,\n HistoryLimitExceeded,\n LAYOUT_FORMAT,\n LAYOUT_FORMAT_VERSION,\n PREDICATE_OPERATORS,\n PhaseCFeatureError,\n RECORDING_FORMAT,\n RECORDING_FORMAT_VERSION,\n SDK_VERSION,\n ServerFailure,\n TerminatedFailure,\n TimeoutFailure,\n UnresolvedConnectionsError,\n WorkflowBuilder,\n WorkflowFailure,\n and,\n assembleRecording,\n collectWorkflowExports,\n defaultEdgeId,\n defineQuery,\n defineSignal,\n defineUpdate,\n defineWorkflow,\n edge,\n errorToFailure,\n expr,\n failureToError,\n installWorkflowRuntime,\n interfaceOf,\n internalNodes,\n isCancellation,\n isDurableWorkflow,\n isOperation,\n isTier1Workflow,\n jsonSchemaOf,\n nodes,\n op,\n or,\n parseLayoutSidecar,\n toIR,\n toMs,\n trigger,\n triggers,\n workflow\n};\n';
|
|
24
|
-
|
|
25
|
-
// src/roundtrip/bundle.ts
|
|
26
|
-
var PROJECT_NS = "fluidgrids-project";
|
|
27
|
-
var SDK_NS = "fluidgrids-sdk";
|
|
28
|
-
var ENTRY_NS = "fluidgrids-entry";
|
|
29
|
-
var DEPS_NS = "fluidgrids-deps";
|
|
30
|
-
var ENTRY_PATH = "__entry__.js";
|
|
31
|
-
var DEFAULT_MAX_SOURCE = 1024 * 1024;
|
|
32
|
-
var DEFAULT_MAX_BUNDLE = 1536 * 1024;
|
|
33
|
-
var DEFAULT_MAX_BUNDLE_WITH_DEPS = 4 * 1024 * 1024;
|
|
34
|
-
var NODE_BUILTINS = /* @__PURE__ */ new Set([
|
|
35
|
-
"assert",
|
|
36
|
-
"async_hooks",
|
|
37
|
-
"buffer",
|
|
38
|
-
"child_process",
|
|
39
|
-
"cluster",
|
|
40
|
-
"console",
|
|
41
|
-
"constants",
|
|
42
|
-
"crypto",
|
|
43
|
-
"dgram",
|
|
44
|
-
"diagnostics_channel",
|
|
45
|
-
"dns",
|
|
46
|
-
"domain",
|
|
47
|
-
"events",
|
|
48
|
-
"fs",
|
|
49
|
-
"http",
|
|
50
|
-
"http2",
|
|
51
|
-
"https",
|
|
52
|
-
"inspector",
|
|
53
|
-
"module",
|
|
54
|
-
"net",
|
|
55
|
-
"os",
|
|
56
|
-
"path",
|
|
57
|
-
"perf_hooks",
|
|
58
|
-
"process",
|
|
59
|
-
"punycode",
|
|
60
|
-
"querystring",
|
|
61
|
-
"readline",
|
|
62
|
-
"repl",
|
|
63
|
-
"sqlite",
|
|
64
|
-
"stream",
|
|
65
|
-
"string_decoder",
|
|
66
|
-
"sys",
|
|
67
|
-
"test",
|
|
68
|
-
"timers",
|
|
69
|
-
"tls",
|
|
70
|
-
"trace_events",
|
|
71
|
-
"tty",
|
|
72
|
-
"url",
|
|
73
|
-
"util",
|
|
74
|
-
"v8",
|
|
75
|
-
"vm",
|
|
76
|
-
"wasi",
|
|
77
|
-
"worker_threads",
|
|
78
|
-
"zlib"
|
|
79
|
-
]);
|
|
80
|
-
function utf8Length(text) {
|
|
81
|
-
let bytes = 0;
|
|
82
|
-
for (let index = 0; index < text.length; index++) {
|
|
83
|
-
const unit = text.charCodeAt(index);
|
|
84
|
-
if (unit < 128) bytes += 1;
|
|
85
|
-
else if (unit < 2048) bytes += 2;
|
|
86
|
-
else if (unit >= 55296 && unit <= 56319 && index + 1 < text.length) {
|
|
87
|
-
const next = text.charCodeAt(index + 1);
|
|
88
|
-
if (next >= 56320 && next <= 57343) {
|
|
89
|
-
bytes += 4;
|
|
90
|
-
index++;
|
|
91
|
-
} else bytes += 3;
|
|
92
|
-
} else bytes += 3;
|
|
93
|
-
}
|
|
94
|
-
return bytes;
|
|
95
|
-
}
|
|
96
|
-
function normalizePath(path) {
|
|
97
|
-
const parts = [];
|
|
98
|
-
for (const part of path.split("/")) {
|
|
99
|
-
if (part === "" || part === ".") continue;
|
|
100
|
-
if (part === "..") {
|
|
101
|
-
if (parts.length === 0) throw new LowerError(`"${path}" leaves the project`);
|
|
102
|
-
parts.pop();
|
|
103
|
-
} else parts.push(part);
|
|
104
|
-
}
|
|
105
|
-
return parts.join("/");
|
|
106
|
-
}
|
|
107
|
-
function dirname(path) {
|
|
108
|
-
const index = path.lastIndexOf("/");
|
|
109
|
-
return index === -1 ? "" : path.slice(0, index);
|
|
110
|
-
}
|
|
111
|
-
function resolveIn(has, importer, specifier, extensions) {
|
|
112
|
-
const base = normalizePath(`${dirname(importer)}/${specifier}`);
|
|
113
|
-
const candidates = [
|
|
114
|
-
base,
|
|
115
|
-
...extensions.map((ext) => `${base}${ext}`),
|
|
116
|
-
...extensions.map((ext) => `${base}/index${ext}`)
|
|
117
|
-
];
|
|
118
|
-
if (/\.(m?js)$/.test(base)) candidates.push(base.replace(/\.(m?js)$/, ".ts"));
|
|
119
|
-
return candidates.find(has);
|
|
120
|
-
}
|
|
121
|
-
function defaultEntries(paths) {
|
|
122
|
-
return paths.filter((path) => path.endsWith(".ts") && !path.endsWith(".d.ts") && !path.endsWith(".test.ts")).filter(
|
|
123
|
-
(path) => !path.startsWith(".fluidgrids/") && !path.startsWith("node_modules/") && !path.startsWith("tests/")
|
|
124
|
-
).sort();
|
|
125
|
-
}
|
|
126
|
-
function entrySource(entries) {
|
|
127
|
-
const imports = entries.map(
|
|
128
|
-
(path, index) => `import * as m${index} from ${JSON.stringify(`./${path}`)};`
|
|
129
|
-
);
|
|
130
|
-
const list = entries.map((path, index) => `[${JSON.stringify(path)}, m${index}]`).join(", ");
|
|
131
|
-
return `import { collectWorkflowExports, installWorkflowRuntime } from "@fluidgrids/workflows";
|
|
132
|
-
${imports.join("\n")}
|
|
133
|
-
const modules = [${list}];
|
|
134
|
-
installWorkflowRuntime(modules);
|
|
135
|
-
export const __fluidgrids = collectWorkflowExports(modules);
|
|
136
|
-
`;
|
|
137
|
-
}
|
|
138
|
-
function splitSpecifier(specifier) {
|
|
139
|
-
const parts = specifier.split("/");
|
|
140
|
-
const nameParts = specifier.startsWith("@") ? parts.slice(0, 2) : parts.slice(0, 1);
|
|
141
|
-
const rest = parts.slice(nameParts.length).join("/");
|
|
142
|
-
return { name: nameParts.join("/"), subpath: rest === "" ? "." : `./${rest}` };
|
|
143
|
-
}
|
|
144
|
-
var ESM_CONDITIONS = ["import", "module", "browser", "default"];
|
|
145
|
-
function pickExport(target) {
|
|
146
|
-
if (typeof target === "string") return target;
|
|
147
|
-
if (Array.isArray(target)) {
|
|
148
|
-
for (const item of target) {
|
|
149
|
-
const found = pickExport(item);
|
|
150
|
-
if (found !== void 0) return found;
|
|
151
|
-
}
|
|
152
|
-
return void 0;
|
|
153
|
-
}
|
|
154
|
-
if (typeof target === "object" && target !== null) {
|
|
155
|
-
const record = target;
|
|
156
|
-
for (const condition of ESM_CONDITIONS) {
|
|
157
|
-
if (condition in record) {
|
|
158
|
-
const found = pickExport(record[condition]);
|
|
159
|
-
if (found !== void 0) return found;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
return void 0;
|
|
164
|
-
}
|
|
165
|
-
function packageJsonOf(name, pkg) {
|
|
166
|
-
const text = pkg.files["package.json"];
|
|
167
|
-
if (text === void 0)
|
|
168
|
-
throw new LowerError(`The vendored package "${name}" has no package.json`);
|
|
169
|
-
try {
|
|
170
|
-
const parsed = JSON.parse(text);
|
|
171
|
-
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed))
|
|
172
|
-
return parsed;
|
|
173
|
-
} catch {
|
|
174
|
-
}
|
|
175
|
-
throw new LowerError(`The package.json of "${name}" is not valid JSON`);
|
|
176
|
-
}
|
|
177
|
-
function resolvePackageEntry(name, pkg, subpath) {
|
|
178
|
-
const manifest = packageJsonOf(name, pkg);
|
|
179
|
-
const has = (path2) => Object.hasOwn(pkg.files, path2);
|
|
180
|
-
let target;
|
|
181
|
-
const exportsField = manifest["exports"];
|
|
182
|
-
if (exportsField !== void 0) {
|
|
183
|
-
const map = typeof exportsField === "string" || Array.isArray(exportsField) || typeof exportsField === "object" && exportsField !== null && !Object.keys(exportsField).some((key) => key.startsWith(".")) ? { ".": exportsField } : exportsField;
|
|
184
|
-
target = pickExport(map[subpath]);
|
|
185
|
-
if (target === void 0) {
|
|
186
|
-
for (const [pattern, value] of Object.entries(map)) {
|
|
187
|
-
if (!pattern.includes("*")) continue;
|
|
188
|
-
const [prefix, suffix] = pattern.split("*");
|
|
189
|
-
if (subpath.startsWith(prefix) && subpath.endsWith(suffix)) {
|
|
190
|
-
const middle = subpath.slice(prefix.length, subpath.length - suffix.length);
|
|
191
|
-
target = pickExport(value)?.replace("*", middle);
|
|
192
|
-
break;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
if (target === void 0)
|
|
197
|
-
throw new LowerError(`"${name}" does not export "${subpath}" for ES modules`);
|
|
198
|
-
} else if (subpath === ".") {
|
|
199
|
-
const moduleField = manifest["module"];
|
|
200
|
-
const mainField = manifest["main"];
|
|
201
|
-
if (typeof moduleField === "string") target = moduleField;
|
|
202
|
-
else if (manifest["type"] === "module" && typeof mainField === "string") target = mainField;
|
|
203
|
-
else if (manifest["type"] === "module") target = "index.js";
|
|
204
|
-
else
|
|
205
|
-
throw new LowerError(
|
|
206
|
-
`"${name}" is a CommonJS package (no "exports", "module" or "type": "module"); workflow bundles take pure ES modules only`
|
|
207
|
-
);
|
|
208
|
-
} else {
|
|
209
|
-
target = subpath;
|
|
210
|
-
}
|
|
211
|
-
const path = normalizePath(target);
|
|
212
|
-
const found = resolveIn(has, "", path, ["", ".js", ".mjs"]) ?? (has(path) ? path : void 0);
|
|
213
|
-
if (found === void 0)
|
|
214
|
-
throw new LowerError(`"${name}" exports "${target}", which is not in its files`);
|
|
215
|
-
return found;
|
|
216
|
-
}
|
|
217
|
-
var CJS_MARKERS = /(^|[^.\w$])(module\.exports|exports\.[A-Za-z_$][\w$]*\s*=|require\s*\()/m;
|
|
218
|
-
function checkPackage(name, pkg) {
|
|
219
|
-
const native = Object.keys(pkg.files).find(
|
|
220
|
-
(path) => path.endsWith(".node") || path.endsWith("binding.gyp")
|
|
221
|
-
);
|
|
222
|
-
if (native !== void 0)
|
|
223
|
-
throw new LowerError(
|
|
224
|
-
`"${name}" contains a native addon (${native}); workflow bundles take pure JavaScript only`
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
function isBuiltin(specifier) {
|
|
228
|
-
if (specifier.startsWith("node:")) return specifier;
|
|
229
|
-
const { name } = splitSpecifier(specifier);
|
|
230
|
-
return NODE_BUILTINS.has(name) ? specifier : void 0;
|
|
231
|
-
}
|
|
232
|
-
function bundleSourceHash(files, deps = {}) {
|
|
233
|
-
const all = [...files].map(([path, content]) => ({ path, content }));
|
|
234
|
-
for (const name of Object.keys(deps).sort()) {
|
|
235
|
-
const pkg = deps[name];
|
|
236
|
-
if (!pkg) continue;
|
|
237
|
-
for (const path of Object.keys(pkg.files).sort())
|
|
238
|
-
all.push({ path: `node_modules/${name}/${path}`, content: pkg.files[path] ?? "" });
|
|
239
|
-
}
|
|
240
|
-
return sourceHash(all);
|
|
241
|
-
}
|
|
242
|
-
var MAX_LISTED_DIAGNOSTICS = 10;
|
|
243
|
-
function displayFile(file) {
|
|
244
|
-
const colon = file.indexOf(":");
|
|
245
|
-
if (colon === -1) return file;
|
|
246
|
-
const namespace = file.slice(0, colon);
|
|
247
|
-
const path = file.slice(colon + 1);
|
|
248
|
-
if (namespace === PROJECT_NS) return path;
|
|
249
|
-
if (namespace === DEPS_NS) return `node_modules/${path}`;
|
|
250
|
-
if (namespace === SDK_NS) return "@fluidgrids/workflows";
|
|
251
|
-
if (namespace === ENTRY_NS) return ENTRY_PATH;
|
|
252
|
-
return file;
|
|
253
|
-
}
|
|
254
|
-
function asRecord(value) {
|
|
255
|
-
return typeof value === "object" && value !== null ? value : void 0;
|
|
256
|
-
}
|
|
257
|
-
function buildDiagnostics(error) {
|
|
258
|
-
const errors = asRecord(error)?.["errors"];
|
|
259
|
-
if (!Array.isArray(errors)) return [];
|
|
260
|
-
return errors.map((item) => {
|
|
261
|
-
const record = asRecord(item);
|
|
262
|
-
const text = typeof record?.["text"] === "string" ? record["text"] : "build error";
|
|
263
|
-
const location = asRecord(record?.["location"]);
|
|
264
|
-
const file = location?.["file"];
|
|
265
|
-
const line = location?.["line"];
|
|
266
|
-
const column = location?.["column"];
|
|
267
|
-
const lineText = location?.["lineText"];
|
|
268
|
-
if (typeof file !== "string" || typeof line !== "number" || typeof column !== "number")
|
|
269
|
-
return { text };
|
|
270
|
-
return {
|
|
271
|
-
text,
|
|
272
|
-
location: {
|
|
273
|
-
file: displayFile(file),
|
|
274
|
-
line,
|
|
275
|
-
column,
|
|
276
|
-
lineText: typeof lineText === "string" ? lineText : ""
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
function formatDiagnostics(diagnostics) {
|
|
282
|
-
const listed = diagnostics.slice(0, MAX_LISTED_DIAGNOSTICS).map(
|
|
283
|
-
({ text, location }) => location ? `${location.file}:${location.line}:${location.column}: ${text}` : text
|
|
284
|
-
);
|
|
285
|
-
const more = diagnostics.length - listed.length;
|
|
286
|
-
if (more > 0) listed.push(`and ${more} more error${more === 1 ? "" : "s"}`);
|
|
287
|
-
return listed.join("; ");
|
|
288
|
-
}
|
|
289
|
-
function bundlingError(error) {
|
|
290
|
-
const diagnostics = buildDiagnostics(error);
|
|
291
|
-
const text = diagnostics.length > 0 ? formatDiagnostics(diagnostics) : error instanceof Error ? error.message : String(error);
|
|
292
|
-
return new LowerError(`Bundling failed: ${text}`, void 0, diagnostics);
|
|
293
|
-
}
|
|
294
|
-
async function buildBundle(files, options = {}) {
|
|
295
|
-
const maxSource = options.maxSourceBytes ?? DEFAULT_MAX_SOURCE;
|
|
296
|
-
let sourceBytes = 0;
|
|
297
|
-
for (const content of files.values()) sourceBytes += utf8Length(content);
|
|
298
|
-
if (sourceBytes > maxSource)
|
|
299
|
-
throw new LowerError(
|
|
300
|
-
`The workflow sources are ${sourceBytes} bytes; the limit is ${maxSource}`,
|
|
301
|
-
"too-large"
|
|
302
|
-
);
|
|
303
|
-
const entries = options.entries ? options.entries.map(normalizePath) : defaultEntries([...files.keys()]);
|
|
304
|
-
if (entries.length === 0) throw new LowerError("No workflow modules to bundle");
|
|
305
|
-
for (const entry of entries)
|
|
306
|
-
if (!files.has(entry)) throw new LowerError(`Entry ${entry} is not in the project files`);
|
|
307
|
-
const deps = options.deps ?? {};
|
|
308
|
-
for (const [name, pkg] of Object.entries(deps)) checkPackage(name, pkg);
|
|
309
|
-
const esbuild = options.esbuild ?? await import('esbuild');
|
|
310
|
-
const result = await esbuild.build({
|
|
311
|
-
entryPoints: [ENTRY_PATH],
|
|
312
|
-
bundle: true,
|
|
313
|
-
write: false,
|
|
314
|
-
format: "esm",
|
|
315
|
-
platform: "neutral",
|
|
316
|
-
target: "es2023",
|
|
317
|
-
charset: "utf8",
|
|
318
|
-
legalComments: "none",
|
|
319
|
-
logLevel: "silent",
|
|
320
|
-
plugins: [
|
|
321
|
-
{
|
|
322
|
-
name: "fluidgrids-project",
|
|
323
|
-
setup(build) {
|
|
324
|
-
build.onResolve({ filter: /.*/ }, (args) => {
|
|
325
|
-
try {
|
|
326
|
-
if (args.kind === "entry-point") return { path: ENTRY_PATH, namespace: ENTRY_NS };
|
|
327
|
-
if (args.path === "@fluidgrids/workflows")
|
|
328
|
-
return { path: "workflows.mjs", namespace: SDK_NS };
|
|
329
|
-
const relative = args.path.startsWith("./") || args.path.startsWith("../");
|
|
330
|
-
if (relative && args.namespace === DEPS_NS) {
|
|
331
|
-
const slash = args.importer.startsWith("@") ? args.importer.indexOf("/", args.importer.indexOf("/") + 1) : args.importer.indexOf("/");
|
|
332
|
-
const pkgName = args.importer.slice(0, slash);
|
|
333
|
-
const inner = args.importer.slice(slash + 1);
|
|
334
|
-
const pkg2 = deps[pkgName];
|
|
335
|
-
if (!pkg2) throw new LowerError(`"${pkgName}" is not vendored`);
|
|
336
|
-
const found = resolveIn(
|
|
337
|
-
(path) => Object.hasOwn(pkg2.files, path),
|
|
338
|
-
inner,
|
|
339
|
-
args.path,
|
|
340
|
-
[".js", ".mjs"]
|
|
341
|
-
);
|
|
342
|
-
if (found === void 0)
|
|
343
|
-
throw new LowerError(`Cannot resolve "${args.path}" in "${pkgName}"`);
|
|
344
|
-
return { path: `${pkgName}/${found}`, namespace: DEPS_NS };
|
|
345
|
-
}
|
|
346
|
-
if (relative) {
|
|
347
|
-
const importer = args.namespace === PROJECT_NS ? args.importer : "";
|
|
348
|
-
const found = resolveIn((path) => files.has(path), importer, args.path, [
|
|
349
|
-
".ts",
|
|
350
|
-
".js",
|
|
351
|
-
".mjs",
|
|
352
|
-
".json"
|
|
353
|
-
]);
|
|
354
|
-
if (found === void 0)
|
|
355
|
-
throw new LowerError(
|
|
356
|
-
`Cannot resolve "${args.path}" from ${importer || "the project"}`
|
|
357
|
-
);
|
|
358
|
-
return { path: found, namespace: PROJECT_NS };
|
|
359
|
-
}
|
|
360
|
-
const builtin = isBuiltin(args.path);
|
|
361
|
-
if (builtin !== void 0)
|
|
362
|
-
throw new LowerError(
|
|
363
|
-
`"${builtin}" is a Node built-in; workflow code runs in an isolate without Node APIs (do I/O in an activity)`
|
|
364
|
-
);
|
|
365
|
-
const { name, subpath } = splitSpecifier(args.path);
|
|
366
|
-
const pkg = deps[name];
|
|
367
|
-
if (!pkg)
|
|
368
|
-
throw new LowerError(
|
|
369
|
-
`Workflow code may import project files, "@fluidgrids/workflows" and vendored pure-ESM packages only; "${args.path}" is not vendored`
|
|
370
|
-
);
|
|
371
|
-
return {
|
|
372
|
-
path: `${name}/${resolvePackageEntry(name, pkg, subpath)}`,
|
|
373
|
-
namespace: DEPS_NS
|
|
374
|
-
};
|
|
375
|
-
} catch (error) {
|
|
376
|
-
return {
|
|
377
|
-
errors: [{ text: error instanceof Error ? error.message : String(error) }]
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
build.onLoad({ filter: /.*/, namespace: ENTRY_NS }, () => ({
|
|
382
|
-
contents: entrySource(entries),
|
|
383
|
-
loader: "js"
|
|
384
|
-
}));
|
|
385
|
-
build.onLoad({ filter: /.*/, namespace: SDK_NS }, () => ({
|
|
386
|
-
contents: RUNTIME_SOURCE,
|
|
387
|
-
loader: "js"
|
|
388
|
-
}));
|
|
389
|
-
build.onLoad({ filter: /.*/, namespace: DEPS_NS }, (args) => {
|
|
390
|
-
const slash = args.path.startsWith("@") ? args.path.indexOf("/", args.path.indexOf("/") + 1) : args.path.indexOf("/");
|
|
391
|
-
const pkgName = args.path.slice(0, slash);
|
|
392
|
-
const inner = args.path.slice(slash + 1);
|
|
393
|
-
const contents = deps[pkgName]?.files[inner];
|
|
394
|
-
if (contents === void 0)
|
|
395
|
-
return { errors: [{ text: `${args.path} is not in the vendored files` }] };
|
|
396
|
-
if (inner.endsWith(".cjs") || !inner.endsWith(".json") && CJS_MARKERS.test(contents))
|
|
397
|
-
return {
|
|
398
|
-
errors: [
|
|
399
|
-
{
|
|
400
|
-
text: `"${pkgName}" is CommonJS (${inner}); workflow bundles take pure ES modules only`
|
|
401
|
-
}
|
|
402
|
-
]
|
|
403
|
-
};
|
|
404
|
-
return { contents, loader: inner.endsWith(".json") ? "json" : "js" };
|
|
405
|
-
});
|
|
406
|
-
build.onLoad({ filter: /.*/, namespace: PROJECT_NS }, (args) => {
|
|
407
|
-
const contents = files.get(args.path);
|
|
408
|
-
if (contents === void 0)
|
|
409
|
-
return { errors: [{ text: `${args.path} is not in the project files` }] };
|
|
410
|
-
return {
|
|
411
|
-
contents,
|
|
412
|
-
loader: args.path.endsWith(".json") ? "json" : args.path.endsWith(".js") || args.path.endsWith(".mjs") ? "js" : "ts"
|
|
413
|
-
};
|
|
414
|
-
});
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
]
|
|
418
|
-
}).catch((error) => {
|
|
419
|
-
throw bundlingError(error);
|
|
420
|
-
});
|
|
421
|
-
const output = result.outputFiles?.[0];
|
|
422
|
-
if (!output) throw new LowerError("esbuild produced no bundle");
|
|
423
|
-
const bundle = output.text;
|
|
424
|
-
const maxBundle = options.maxBundleBytes ?? (Object.keys(deps).length > 0 ? DEFAULT_MAX_BUNDLE_WITH_DEPS : DEFAULT_MAX_BUNDLE);
|
|
425
|
-
const bundleBytes = utf8Length(bundle);
|
|
426
|
-
if (bundleBytes > maxBundle)
|
|
427
|
-
throw new LowerError(
|
|
428
|
-
`The workflow bundle is ${bundleBytes} bytes; the limit is ${maxBundle}`,
|
|
429
|
-
"too-large"
|
|
430
|
-
);
|
|
431
|
-
return {
|
|
432
|
-
bundle,
|
|
433
|
-
buildId: buildIdOf(bundle),
|
|
434
|
-
sourceHash: bundleSourceHash(files, deps),
|
|
435
|
-
entries
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// src/roundtrip/isolate.ts
|
|
440
|
-
var DETERMINISM_VIOLATION = "DeterminismViolation";
|
|
441
|
-
`(() => {
|
|
442
|
-
const NAME = ${JSON.stringify(DETERMINISM_VIOLATION)};
|
|
443
|
-
const fail = (what) => {
|
|
444
|
-
const error = new Error(
|
|
445
|
-
what + " is not allowed in workflow code: lowering must give the same IR on every build. Read times and random values at run time instead (for example wf.now)."
|
|
446
|
-
);
|
|
447
|
-
error.name = NAME;
|
|
448
|
-
throw error;
|
|
449
|
-
};
|
|
450
|
-
const lock = (target, key, value) =>
|
|
451
|
-
Object.defineProperty(target, key, { value, writable: false, enumerable: false, configurable: false });
|
|
452
|
-
const RealDate = Date;
|
|
453
|
-
const LockedDate = function Date(...args) {
|
|
454
|
-
if (new.target === undefined) return fail("Date()");
|
|
455
|
-
if (args.length === 0) return fail("new Date()");
|
|
456
|
-
return Reflect.construct(RealDate, args, new.target);
|
|
457
|
-
};
|
|
458
|
-
lock(LockedDate, "prototype", RealDate.prototype);
|
|
459
|
-
lock(RealDate.prototype, "constructor", LockedDate);
|
|
460
|
-
lock(LockedDate, "now", function now() { return fail("Date.now()"); });
|
|
461
|
-
lock(LockedDate, "parse", RealDate.parse);
|
|
462
|
-
lock(LockedDate, "UTC", RealDate.UTC);
|
|
463
|
-
lock(globalThis, "Date", LockedDate);
|
|
464
|
-
lock(Math, "random", function random() { return fail("Math.random()"); });
|
|
465
|
-
const crypto = globalThis.crypto;
|
|
466
|
-
if (crypto !== null && typeof crypto === "object") {
|
|
467
|
-
for (const name of ["getRandomValues", "randomUUID"]) {
|
|
468
|
-
if (typeof crypto[name] === "function") lock(crypto, name, function () { return fail("crypto." + name + "()"); });
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
const DateTimeFormat = typeof Intl === "object" && Intl !== null ? Intl.DateTimeFormat : undefined;
|
|
472
|
-
if (typeof DateTimeFormat === "function") {
|
|
473
|
-
const proto = DateTimeFormat.prototype;
|
|
474
|
-
const format = Object.getOwnPropertyDescriptor(proto, "format");
|
|
475
|
-
if (format && typeof format.get === "function") {
|
|
476
|
-
const get = format.get;
|
|
477
|
-
Object.defineProperty(proto, "format", {
|
|
478
|
-
get() {
|
|
479
|
-
const bound = get.call(this);
|
|
480
|
-
return (date) => (date === undefined ? fail("Intl.DateTimeFormat format()") : bound(date));
|
|
481
|
-
},
|
|
482
|
-
enumerable: false,
|
|
483
|
-
configurable: false,
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
const formatToParts = proto.formatToParts;
|
|
487
|
-
if (typeof formatToParts === "function") {
|
|
488
|
-
lock(proto, "formatToParts", function (date) {
|
|
489
|
-
return date === undefined ? fail("Intl.DateTimeFormat formatToParts()") : formatToParts.call(this, date);
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
})();
|
|
494
|
-
`;
|
|
495
|
-
var FAILURES = /* @__PURE__ */ new Set([
|
|
496
|
-
"error",
|
|
497
|
-
"timeout",
|
|
498
|
-
"determinism",
|
|
499
|
-
"no-collection",
|
|
500
|
-
"out-of-memory",
|
|
501
|
-
"crashed"
|
|
502
|
-
]);
|
|
503
|
-
function isIsolateOutcome(value) {
|
|
504
|
-
if (!isRecord(value)) return false;
|
|
505
|
-
if (value["ok"] === true) return typeof value["value"] === "string";
|
|
506
|
-
return value["ok"] === false && typeof value["failure"] === "string" && FAILURES.has(value["failure"]) && typeof value["message"] === "string";
|
|
507
|
-
}
|
|
508
|
-
function failure(kind, message) {
|
|
509
|
-
return { ok: false, failure: kind, message };
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
// src/roundtrip/isolate-worker.ts
|
|
513
|
-
var DEFAULT_STARTUP_TIMEOUT_MS = 1e4;
|
|
514
|
-
function runIsolateWorker(options) {
|
|
515
|
-
return new Promise((resolve) => {
|
|
516
|
-
let settled = false;
|
|
517
|
-
let deadline;
|
|
518
|
-
const worker = new Worker(options.source, {
|
|
519
|
-
eval: true,
|
|
520
|
-
workerData: options.workerData,
|
|
521
|
-
...options.resourceLimits ? { resourceLimits: options.resourceLimits } : {}
|
|
522
|
-
});
|
|
523
|
-
const finish = (outcome) => {
|
|
524
|
-
if (settled) return;
|
|
525
|
-
settled = true;
|
|
526
|
-
clearTimeout(startup);
|
|
527
|
-
if (deadline !== void 0) clearTimeout(deadline);
|
|
528
|
-
void worker.terminate();
|
|
529
|
-
resolve(outcome);
|
|
530
|
-
};
|
|
531
|
-
const startup = setTimeout(
|
|
532
|
-
() => finish(failure("timeout", "The evaluation worker did not start in time")),
|
|
533
|
-
options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS
|
|
534
|
-
);
|
|
535
|
-
worker.once("online", () => {
|
|
536
|
-
clearTimeout(startup);
|
|
537
|
-
deadline = setTimeout(
|
|
538
|
-
() => finish(
|
|
539
|
-
failure(
|
|
540
|
-
"timeout",
|
|
541
|
-
`Evaluating the workflow code timed out after ${options.timeoutMs} ms`
|
|
542
|
-
)
|
|
543
|
-
),
|
|
544
|
-
options.timeoutMs
|
|
545
|
-
);
|
|
546
|
-
});
|
|
547
|
-
worker.once("message", (message) => {
|
|
548
|
-
finish(
|
|
549
|
-
isIsolateOutcome(message) ? message : failure("crashed", "The evaluation worker returned an unexpected message")
|
|
550
|
-
);
|
|
551
|
-
});
|
|
552
|
-
worker.once("error", (error) => {
|
|
553
|
-
const outOfMemory = "code" in error && error.code === "ERR_WORKER_OUT_OF_MEMORY";
|
|
554
|
-
finish(
|
|
555
|
-
outOfMemory ? failure("out-of-memory", "Evaluating the workflow code ran out of memory") : failure("crashed", `The evaluation worker failed: ${error.message}`)
|
|
556
|
-
);
|
|
557
|
-
});
|
|
558
|
-
worker.once("exit", (code) => {
|
|
559
|
-
finish(failure("crashed", `The evaluation worker exited (code ${code}) without a result`));
|
|
560
|
-
});
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
// src/roundtrip/lower.ts
|
|
565
|
-
var EVALUATION_GLOBAL = "__fluidgridsBundle";
|
|
566
|
-
var ESBUILD_VERSION = "0.28.2";
|
|
567
|
-
var DeterminismViolationError = class extends LowerError {
|
|
568
|
-
constructor(message) {
|
|
569
|
-
super(message, "determinism");
|
|
570
|
-
this.name = "DeterminismViolation";
|
|
571
|
-
}
|
|
572
|
-
};
|
|
573
|
-
function outcomeToCollection(outcome) {
|
|
574
|
-
if (outcome.ok) return outcome.value;
|
|
575
|
-
switch (outcome.failure) {
|
|
576
|
-
case "determinism":
|
|
577
|
-
throw new DeterminismViolationError(outcome.message);
|
|
578
|
-
case "error":
|
|
579
|
-
throw new LowerError(`Evaluating the workflow code failed: ${outcome.message}`, "error");
|
|
580
|
-
default:
|
|
581
|
-
throw new LowerError(outcome.message, outcome.failure);
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
var DEFAULT_MAX_OUTPUT = 16 * 1024 * 1024;
|
|
585
|
-
async function bundleProject(files, entries, esbuild) {
|
|
586
|
-
return (await buildBundle(files, {
|
|
587
|
-
entries,
|
|
588
|
-
esbuild,
|
|
589
|
-
maxSourceBytes: Infinity,
|
|
590
|
-
maxBundleBytes: Infinity
|
|
591
|
-
})).bundle;
|
|
592
|
-
}
|
|
593
|
-
async function defaultEvaluator() {
|
|
594
|
-
const { createNodeVmEvaluator } = await import('./node-evaluator-SX4LEYQC.js');
|
|
595
|
-
return createNodeVmEvaluator();
|
|
596
|
-
}
|
|
597
|
-
function fail(message) {
|
|
598
|
-
throw new LowerError(`The workflow code returned an invalid recording: ${message}`);
|
|
599
|
-
}
|
|
600
|
-
function isStringArray(value) {
|
|
601
|
-
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
602
|
-
}
|
|
603
|
-
function checkRecording(value) {
|
|
604
|
-
if (!isRecord(value)) fail("not an object");
|
|
605
|
-
if (value["format"] !== RECORDING_FORMAT || value["formatVersion"] !== RECORDING_FORMAT_VERSION) {
|
|
606
|
-
fail("unknown recording format (is the bundle built with this SDK version?)");
|
|
607
|
-
}
|
|
608
|
-
if (typeof value["key"] !== "string" || value["key"] === "") fail("missing key");
|
|
609
|
-
if (!isRecord(value["document"])) fail("missing document");
|
|
610
|
-
if (!Array.isArray(value["nodes"]) || !Array.isArray(value["edges"]) || !Array.isArray(value["notes"])) {
|
|
611
|
-
fail("nodes, edges and notes must be arrays");
|
|
612
|
-
}
|
|
613
|
-
for (const recorded of value["nodes"]) {
|
|
614
|
-
if (!isRecord(recorded) || !isRecord(recorded["node"])) fail("a node entry is not an object");
|
|
615
|
-
const node = recorded["node"];
|
|
616
|
-
if (typeof node["id"] !== "string" || typeof node["type"] !== "string")
|
|
617
|
-
fail("a node has no id or type");
|
|
618
|
-
if (recorded["connectionNames"] !== void 0 && !isStringArray(recorded["connectionNames"])) {
|
|
619
|
-
fail("connectionNames must be strings");
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
for (const edge of value["edges"]) {
|
|
623
|
-
if (!isRecord(edge) || typeof edge["source"] !== "string" || typeof edge["target"] !== "string") {
|
|
624
|
-
fail("an edge has no source or target");
|
|
625
|
-
}
|
|
626
|
-
if (edge["id"] !== void 0 && typeof edge["id"] !== "string")
|
|
627
|
-
fail("an edge id must be a string");
|
|
628
|
-
}
|
|
629
|
-
for (const note of value["notes"]) {
|
|
630
|
-
if (!isRecord(note) || !isRecord(note["note"])) fail("a note entry is not an object");
|
|
631
|
-
if (note["near"] !== void 0 && typeof note["near"] !== "string")
|
|
632
|
-
fail("a note anchor must be a node id");
|
|
633
|
-
}
|
|
634
|
-
const order = value["edgeOrder"];
|
|
635
|
-
if (order !== void 0 && !(Array.isArray(order) && order.every((entry) => typeof entry === "string" || Number.isInteger(entry)))) {
|
|
636
|
-
fail("edgeOrder must list edge ids or positions");
|
|
637
|
-
}
|
|
638
|
-
return value;
|
|
639
|
-
}
|
|
640
|
-
function readJsonFile(files, path) {
|
|
641
|
-
const text = files.get(path);
|
|
642
|
-
if (text === void 0) return void 0;
|
|
643
|
-
try {
|
|
644
|
-
return JSON.parse(text);
|
|
645
|
-
} catch {
|
|
646
|
-
throw new LowerError(`${path} is not valid JSON`);
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
function toFileMap(files) {
|
|
650
|
-
const map = /* @__PURE__ */ new Map();
|
|
651
|
-
const entries = Array.isArray(files) ? files.map((file) => [file.path, file.content]) : Object.entries(files);
|
|
652
|
-
for (const [path, content] of entries) {
|
|
653
|
-
const normalized = normalizePath(path);
|
|
654
|
-
if (map.has(normalized)) throw new LowerError(`${normalized} is given twice`);
|
|
655
|
-
map.set(normalized, content);
|
|
656
|
-
}
|
|
657
|
-
return map;
|
|
658
|
-
}
|
|
659
|
-
var SLUG = /^[a-z][a-z0-9-]{0,62}$/;
|
|
660
|
-
function checkDurable(value) {
|
|
661
|
-
if (value === void 0) return [];
|
|
662
|
-
if (!Array.isArray(value)) fail("durable must be an array");
|
|
663
|
-
return value.map((entry) => {
|
|
664
|
-
if (!isRecord(entry) || typeof entry["module"] !== "string" || typeof entry["exportName"] !== "string" || typeof entry["name"] !== "string" || typeof entry["taskQueue"] !== "string" || !isRecord(entry["interface"]))
|
|
665
|
-
fail("a durable entry is malformed");
|
|
666
|
-
const trigger = entry["trigger"];
|
|
667
|
-
if (trigger !== void 0 && (!isRecord(trigger) || typeof trigger["nodeType"] !== "string"))
|
|
668
|
-
fail("a durable trigger is malformed");
|
|
669
|
-
return entry;
|
|
670
|
-
});
|
|
671
|
-
}
|
|
672
|
-
var PHASE_C_CALLS = /\.\s*(handleQuery|handleUpdate|upsertSearchAttributes|setDefaultQueryHandler|setDefaultUpdateHandler|localActivity)\s*\(/g;
|
|
673
|
-
var USER_ACTIVITY_CALL = /\bctx\s*\.\s*activity\s*\(/g;
|
|
674
|
-
var PHASE_C_EXPORTS = /\bexport\s+(?:const|let|var|function)\s+(interceptors|sinks)\b/g;
|
|
675
|
-
var INTERNAL_RUN = /\.run\(\s*(?:nodes\.internal|internalNodes|n\.internal)\.(\w+)/g;
|
|
676
|
-
function scanDurableSources(files, modules) {
|
|
677
|
-
const issues = [];
|
|
678
|
-
const descriptors = internalNodes;
|
|
679
|
-
for (const module of [...new Set(modules)].sort()) {
|
|
680
|
-
const text = files.get(module);
|
|
681
|
-
if (text === void 0) continue;
|
|
682
|
-
for (const match of text.matchAll(PHASE_C_CALLS))
|
|
683
|
-
issues.push({
|
|
684
|
-
code: "durable.phaseC",
|
|
685
|
-
module,
|
|
686
|
-
message: `${module}: ${match[1] ?? ""}() is not available in durable functions yet`
|
|
687
|
-
});
|
|
688
|
-
const userActivityCalls = text.match(USER_ACTIVITY_CALL)?.length ?? 0;
|
|
689
|
-
for (let call = 0; call < userActivityCalls; call++)
|
|
690
|
-
issues.push({
|
|
691
|
-
code: "durable.phaseC",
|
|
692
|
-
module,
|
|
693
|
-
message: `${module}: ctx.activity() (user activities) is not available yet; use ctx.run with a node`
|
|
694
|
-
});
|
|
695
|
-
for (const match of text.matchAll(PHASE_C_EXPORTS))
|
|
696
|
-
issues.push({
|
|
697
|
-
code: "durable.phaseC",
|
|
698
|
-
module,
|
|
699
|
-
message: `${module}: exported ${match[1] ?? ""} are not available yet`
|
|
700
|
-
});
|
|
701
|
-
for (const match of text.matchAll(INTERNAL_RUN)) {
|
|
702
|
-
const name = match[1] ?? "";
|
|
703
|
-
const nodeType = Object.hasOwn(descriptors, name) ? descriptors[name]?.nodeType : void 0;
|
|
704
|
-
if (nodeType !== void 0 && !isActivityNodeTypeAllowed(nodeType))
|
|
705
|
-
issues.push({
|
|
706
|
-
code: "durable.activityTypeNotAllowed",
|
|
707
|
-
module,
|
|
708
|
-
message: `${module}: ${nodeType} cannot run as a durable activity`
|
|
709
|
-
});
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
return issues;
|
|
713
|
-
}
|
|
714
|
-
function usesCodeWorkflow(recording) {
|
|
715
|
-
return recording.nodes.some((entry) => entry.node.type === CODE_WORKFLOW_NODE_TYPE);
|
|
716
|
-
}
|
|
717
|
-
function standaloneRecording(entry) {
|
|
718
|
-
const trigger = entry.trigger ?? { nodeType: "internal:api" };
|
|
719
|
-
const nodeId = SLUG.test(entry.name) ? entry.name : "code-workflow";
|
|
720
|
-
const triggerId = trigger.id ?? (nodeId === "trigger" ? "start" : "trigger");
|
|
721
|
-
const hasInterface = Object.keys(entry.interface).length > 0;
|
|
722
|
-
const built = defineWorkflow(
|
|
723
|
-
{
|
|
724
|
-
key: entry.name,
|
|
725
|
-
...entry.title !== void 0 ? { name: entry.title } : {},
|
|
726
|
-
...entry.description !== void 0 ? { description: entry.description } : {},
|
|
727
|
-
...hasInterface ? { interface: entry.interface } : {}
|
|
728
|
-
},
|
|
729
|
-
(wf) => {
|
|
730
|
-
const start = wf.trigger(op(trigger.nodeType, trigger.version, trigger.operation), {
|
|
731
|
-
id: triggerId,
|
|
732
|
-
...trigger.args !== void 0 ? { args: trigger.args } : {}
|
|
733
|
-
});
|
|
734
|
-
wf.step(internalNodes.codeWorkflow, {
|
|
735
|
-
id: nodeId,
|
|
736
|
-
after: start,
|
|
737
|
-
args: {
|
|
738
|
-
workflowFn: entry.exportName,
|
|
739
|
-
...entry.taskQueue !== "managed" ? { taskQueue: entry.taskQueue } : {}
|
|
740
|
-
}
|
|
741
|
-
});
|
|
742
|
-
}
|
|
743
|
-
);
|
|
744
|
-
return built.recording;
|
|
745
|
-
}
|
|
746
|
-
async function lower(files, options = {}) {
|
|
747
|
-
const fileMap = toFileMap(files);
|
|
748
|
-
const esbuild = options.esbuild ?? await import('esbuild');
|
|
749
|
-
const built = await buildBundle(fileMap, {
|
|
750
|
-
...options.entries ? { entries: options.entries } : {},
|
|
751
|
-
...options.deps ? { deps: options.deps } : {},
|
|
752
|
-
esbuild,
|
|
753
|
-
maxSourceBytes: options.maxSourceBytes ?? 1024 * 1024,
|
|
754
|
-
...options.maxBundleBytes !== void 0 ? { maxBundleBytes: options.maxBundleBytes } : {}
|
|
755
|
-
});
|
|
756
|
-
const bundle = built.bundle;
|
|
757
|
-
const evaluator = options.evaluator ?? await defaultEvaluator();
|
|
758
|
-
const code = evaluator.format === "esm" ? bundle : (await esbuild.transform(bundle, {
|
|
759
|
-
format: "iife",
|
|
760
|
-
globalName: EVALUATION_GLOBAL,
|
|
761
|
-
target: "es2023",
|
|
762
|
-
platform: "neutral",
|
|
763
|
-
charset: "utf8",
|
|
764
|
-
legalComments: "none",
|
|
765
|
-
logLevel: "silent"
|
|
766
|
-
})).code;
|
|
767
|
-
const output = await evaluator.evaluate(code);
|
|
768
|
-
if (typeof output !== "string") throw new LowerError("The evaluation returned no collection");
|
|
769
|
-
if (output.length > (options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT))
|
|
770
|
-
throw new LowerError("The workflow code produced too much output", "too-large");
|
|
771
|
-
let parsed;
|
|
772
|
-
try {
|
|
773
|
-
parsed = JSON.parse(output);
|
|
774
|
-
} catch {
|
|
775
|
-
throw new LowerError("The evaluation returned invalid JSON");
|
|
776
|
-
}
|
|
777
|
-
if (!isRecord(parsed) || parsed["format"] !== COLLECTION_FORMAT || !Array.isArray(parsed["workflows"])) {
|
|
778
|
-
fail("not a workflow collection");
|
|
779
|
-
}
|
|
780
|
-
const hash = built.sourceHash;
|
|
781
|
-
const durable = checkDurable(parsed["durable"]);
|
|
782
|
-
const durableExports = {};
|
|
783
|
-
for (const entry of durable) {
|
|
784
|
-
if (Object.hasOwn(durableExports, entry.exportName))
|
|
785
|
-
throw new LowerError(
|
|
786
|
-
`Two modules export a workflow function named "${entry.exportName}"; export names must be unique in a project`
|
|
787
|
-
);
|
|
788
|
-
durableExports[entry.exportName] = { interface: entry.interface, taskQueue: entry.taskQueue };
|
|
789
|
-
}
|
|
790
|
-
const codeBlock = () => ({
|
|
791
|
-
language: "typescript",
|
|
792
|
-
sdk: `@fluidgrids/workflows@${SDK_VERSION}`,
|
|
793
|
-
buildId: built.buildId,
|
|
794
|
-
determinism: "isolate",
|
|
795
|
-
exports: {
|
|
796
|
-
workflows: JSON.parse(JSON.stringify(durableExports))
|
|
797
|
-
}
|
|
798
|
-
});
|
|
799
|
-
const recordings = [];
|
|
800
|
-
const embedded = /* @__PURE__ */ new Set();
|
|
801
|
-
for (const item of parsed["workflows"]) {
|
|
802
|
-
if (!isRecord(item) || typeof item["module"] !== "string" || typeof item["exportName"] !== "string")
|
|
803
|
-
fail("bad entry");
|
|
804
|
-
const recording = checkRecording(item["recording"]);
|
|
805
|
-
for (const entry of recording.nodes) {
|
|
806
|
-
const state = entry.node.args?.state;
|
|
807
|
-
if (entry.node.type === CODE_WORKFLOW_NODE_TYPE && isRecord(state) && typeof state["workflowFn"] === "string")
|
|
808
|
-
embedded.add(state["workflowFn"]);
|
|
809
|
-
}
|
|
810
|
-
recordings.push({
|
|
811
|
-
module: item["module"],
|
|
812
|
-
exportName: item["exportName"],
|
|
813
|
-
recording,
|
|
814
|
-
mode: durable.length > 0 && usesCodeWorkflow(recording) ? "hybrid" : "canvas"
|
|
815
|
-
});
|
|
816
|
-
}
|
|
817
|
-
for (const entry of durable) {
|
|
818
|
-
const standalone = entry.standalone ?? (entry.trigger !== void 0 || !embedded.has(entry.exportName));
|
|
819
|
-
if (standalone)
|
|
820
|
-
recordings.push({
|
|
821
|
-
module: entry.module,
|
|
822
|
-
exportName: entry.exportName,
|
|
823
|
-
recording: standaloneRecording(entry),
|
|
824
|
-
mode: "code"
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
const seen = /* @__PURE__ */ new Map();
|
|
828
|
-
const workflows = [];
|
|
829
|
-
for (const { module, exportName, recording, mode } of recordings) {
|
|
830
|
-
const where = `${module}#${exportName}`;
|
|
831
|
-
const previous = seen.get(recording.key);
|
|
832
|
-
if (previous)
|
|
833
|
-
throw new LowerError(
|
|
834
|
-
`Workflow key "${recording.key}" is defined twice (${previous} and ${where})`
|
|
835
|
-
);
|
|
836
|
-
seen.set(recording.key, where);
|
|
837
|
-
const layoutValue = readJsonFile(fileMap, `workflows/${recording.key}.layout.json`);
|
|
838
|
-
const pinnedValue = readJsonFile(fileMap, `workflows/${recording.key}.pinned.json`);
|
|
839
|
-
if (pinnedValue !== void 0 && !isRecord(pinnedValue))
|
|
840
|
-
throw new LowerError(`workflows/${recording.key}.pinned.json must be an object`);
|
|
841
|
-
const layout = layoutValue === void 0 ? void 0 : parseLayoutSidecar(layoutValue);
|
|
842
|
-
const definition = assembleRecording(recording, {
|
|
843
|
-
...layout ? { layout } : {},
|
|
844
|
-
...options.connections ? { connections: options.connections } : {},
|
|
845
|
-
...pinnedValue !== void 0 ? { pinnedData: pinnedValue } : {},
|
|
846
|
-
authoring: {
|
|
847
|
-
mode,
|
|
848
|
-
generator: "sdk-ts",
|
|
849
|
-
generatorVersion: SDK_VERSION,
|
|
850
|
-
sourceHash: hash
|
|
851
|
-
}
|
|
852
|
-
});
|
|
853
|
-
if (mode !== "canvas") definition.code = codeBlock();
|
|
854
|
-
workflows.push({ key: recording.key, module, exportName, definition });
|
|
855
|
-
}
|
|
856
|
-
return {
|
|
857
|
-
buildId: built.buildId,
|
|
858
|
-
bundle,
|
|
859
|
-
sourceHash: hash,
|
|
860
|
-
workflows,
|
|
861
|
-
durableExports,
|
|
862
|
-
issues: scanDurableSources(
|
|
863
|
-
fileMap,
|
|
864
|
-
durable.map((entry) => entry.module)
|
|
865
|
-
)
|
|
866
|
-
};
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
export { DeterminismViolationError, ESBUILD_VERSION, EVALUATION_GLOBAL, LowerError, NODE_BUILTINS, buildBundle, bundleProject, bundleSourceHash, defaultEntries, lower, outcomeToCollection, resolvePackageEntry, runIsolateWorker, scanDurableSources, splitSpecifier };
|