@oomol-lab/open-flow 0.1.0-beta.69 → 0.1.0-beta.70

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.
Files changed (49) hide show
  1. package/dist/browser/{ContentIcon-CsECY5id.js → ContentIcon-CUQHjQIw.js} +16 -8
  2. package/dist/browser/{FlowCanvas-C5X22xQ7.js → FlowCanvas-CqtUDPGj.js} +11 -26
  3. package/dist/browser/{createResourceDialog-Di5BBrQv.js → createResourceDialog-BAHYW9yu.js} +3 -3
  4. package/dist/browser/{dialog-Bjo-r9B0.js → dialog-DcGOzUP2.js} +162 -12
  5. package/dist/browser/{exportSvg-Cj6Spxx-.js → exportSvg-Dv5Qgrq7.js} +2 -2
  6. package/dist/browser/flow-authoring.js +95 -12
  7. package/dist/browser/flow-change-schema.d.ts +24 -1
  8. package/dist/browser/flow-change.d.ts +33 -4
  9. package/dist/browser/flow-change.js +96 -13
  10. package/dist/browser/{flowChanges-Dp-rcEJ6.js → flowChanges-CYyehKer.js} +2593 -2254
  11. package/dist/browser/{flowWorkspace-CB1QACku.js → flowWorkspace-qYUZPJHR.js} +1114 -392
  12. package/dist/browser/preview.css +225 -221
  13. package/dist/browser/preview.js +3781 -2655
  14. package/dist/browser/{tooltip-CJjYs_2I.js → tooltip-wZJRB9oP.js} +28 -1
  15. package/dist/browser/ui.css +8 -20
  16. package/dist/browser/workbench.css +225 -221
  17. package/dist/browser/workbench.js +31 -10
  18. package/dist/browser/{workbenchSelect-C3hxUcYm.js → workbenchSelect-D8_vP2p5.js} +2 -2
  19. package/dist/command/index.js +45 -45
  20. package/dist/common/authoring.d.ts +3 -3
  21. package/dist/common/authoringExamples.d.ts +3 -2
  22. package/dist/common/authoringSchema.d.ts +37 -374
  23. package/dist/common/control-api-conformance.js +151 -55
  24. package/dist/common/control-api.d.ts +12 -78
  25. package/dist/common/control-api.js +162 -39
  26. package/dist/common/control-requests.d.ts +3 -3
  27. package/dist/common/control-requests.js +221 -35
  28. package/dist/common/decision.js +85 -7
  29. package/dist/common/engine-contract.d.ts +4 -2
  30. package/dist/common/flow-encoding.js +110 -14
  31. package/dist/common/flow-graph.d.ts +3 -0
  32. package/dist/common/flow-semantics.js +273 -14
  33. package/dist/common/integration-trigger.js +85 -7
  34. package/dist/common/liveDetails.d.ts +15 -0
  35. package/dist/common/mcp.d.ts +3 -3
  36. package/dist/common/mcp.js +134 -38
  37. package/dist/common/openapi.js +85 -7
  38. package/dist/common/poll-trigger.js +85 -7
  39. package/dist/common/run-events.d.ts +2 -0
  40. package/dist/common/run-events.js +59 -2
  41. package/dist/common/runtime-contract.js +14 -4
  42. package/dist/common/scheduler.d.ts +6 -2
  43. package/dist/common/scheduler.js +178 -11
  44. package/dist/common/webhook-response.d.ts +43 -0
  45. package/dist/common/webhook-trigger.d.ts +12 -0
  46. package/dist/common/webhook-trigger.js +236 -9
  47. package/dist/common/workflow.js +85 -7
  48. package/package.json +1 -1
  49. package/skills/open-flow/references/flow-authoring.md +15 -10
@@ -1930,7 +1930,7 @@ function timeSource(args) {
1930
1930
  function time(args) {
1931
1931
  return new RegExp(`^${timeSource(args)}$`);
1932
1932
  }
1933
- function datetime(args) {
1933
+ function datetime$1(args) {
1934
1934
  const opts = ["Z"];
1935
1935
  if (args.offset) opts.push(`([+-](?:[01]\\d|2[0-3]):[0-5]\\d)`);
1936
1936
  const qualified = `${timeSource({
@@ -2581,7 +2581,7 @@ var $ZodKSUID = /*@__PURE__*/ $constructor("$ZodKSUID", (inst, def) => {
2581
2581
  $ZodStringFormat.init(inst, def);
2582
2582
  });
2583
2583
  var $ZodISODateTime = /*@__PURE__*/ $constructor("$ZodISODateTime", (inst, def) => {
2584
- def.pattern ?? (def.pattern = datetime(def));
2584
+ def.pattern ?? (def.pattern = datetime$1(def));
2585
2585
  $ZodStringFormat.init(inst, def);
2586
2586
  });
2587
2587
  var $ZodISODate = /*@__PURE__*/ $constructor("$ZodISODate", (inst, def) => {
@@ -6577,6 +6577,11 @@ function preprocess(fn, schema) {
6577
6577
  out: schema
6578
6578
  });
6579
6579
  }
6580
+ //#endregion
6581
+ //#region ../../node_modules/.bun/zod@4.6.5/node_modules/zod/v4/classic/iso.js
6582
+ function datetime(params) {
6583
+ return /* @__PURE__ */ _isoDateTime(ZodISODateTime, params);
6584
+ }
6580
6585
  function checkJsonDepth(value, depth = 0) {
6581
6586
  if (depth > 64) throw new TypeError("Value exceeds the maximum JSON depth.");
6582
6587
  if (value != null && typeof value == "object") for (const child of Object.values(value)) checkJsonDepth(child, depth + 1);
@@ -6621,6 +6626,33 @@ var triggerScheduleSchema = array(union([object$1({
6621
6626
  value: number()
6622
6627
  })]));
6623
6628
  //#endregion
6629
+ //#region src/localization/common/timeZone.ts
6630
+ /** Validate a named timezone using the same runtime data used for date conversion. */
6631
+ function isTimeZone(value) {
6632
+ try {
6633
+ Intl.DateTimeFormat("en", { timeZone: value });
6634
+ return true;
6635
+ } catch {
6636
+ return false;
6637
+ }
6638
+ }
6639
+ //#endregion
6640
+ //#region src/flow/common/wait.ts
6641
+ /** Drafts retain incomplete values; semantic validation gates publication and execution. */
6642
+ var waitAutoContinueDraftSchema = discriminatedUnion("kind", [strictObject({
6643
+ kind: literal("after"),
6644
+ durationMs: number().nullable()
6645
+ }), strictObject({
6646
+ kind: literal("at"),
6647
+ at: string(),
6648
+ timezone: string().optional()
6649
+ })]);
6650
+ /** Static business configuration; the deployment owns the allowed wait lifetime. */
6651
+ var waitAutoContinueSchema = discriminatedUnion("kind", [waitAutoContinueDraftSchema.options[0].extend({ durationMs: number().int().positive().max(Number.MAX_SAFE_INTEGER) }), waitAutoContinueDraftSchema.options[1].extend({
6652
+ at: datetime({ offset: true }),
6653
+ timezone: string().refine(isTimeZone, "Select a valid IANA timezone.").optional()
6654
+ })]);
6655
+ //#endregion
6624
6656
  //#region src/flow/common/webhookMethod.ts
6625
6657
  var webhookMethods = [
6626
6658
  "GET",
@@ -6632,6 +6664,98 @@ var webhookMethods = [
6632
6664
  function webhookSupportsBody(method) {
6633
6665
  return method !== "GET";
6634
6666
  }
6667
+ //#endregion
6668
+ //#region src/flow/common/webhookResponse.ts
6669
+ var webhookResponseTimeout = {
6670
+ defaultMs: 3e4,
6671
+ minMs: 1e3,
6672
+ maxMs: 6e4
6673
+ };
6674
+ var webhookStatusCodePort = {
6675
+ jsonSchema: { type: "number" },
6676
+ nullable: true
6677
+ };
6678
+ function webhookResponseAllowsBody(status) {
6679
+ return status !== 204 && status !== 205 && status !== 304;
6680
+ }
6681
+ var webhookHeaderValuePort = {
6682
+ jsonSchema: { type: [
6683
+ "string",
6684
+ "number",
6685
+ "boolean"
6686
+ ] },
6687
+ nullable: true
6688
+ };
6689
+ var webhookHeadersPort = {
6690
+ jsonSchema: {
6691
+ type: "object",
6692
+ additionalProperties: { type: [
6693
+ "string",
6694
+ "number",
6695
+ "boolean"
6696
+ ] }
6697
+ },
6698
+ nullable: true
6699
+ };
6700
+ function workflowOutputsPort(outputs) {
6701
+ return {
6702
+ jsonSchema: {
6703
+ type: "object",
6704
+ properties: Object.fromEntries(outputs.map((port) => [port.handle, port.jsonSchema])),
6705
+ additionalProperties: false,
6706
+ required: outputs.map((port) => port.handle)
6707
+ },
6708
+ nullable: false
6709
+ };
6710
+ }
6711
+ /** Header names are case-insensitive; never silently combine duplicate business fields. */
6712
+ function webhookHeaderNameIssue(name, names) {
6713
+ if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name)) return "invalid";
6714
+ if (names.some((candidate) => candidate.toLowerCase() === name.toLowerCase())) return "duplicate";
6715
+ }
6716
+ /** Fixed inputs belong to the node, not author-supplied definitions. */
6717
+ var webhookResponseInputs = [
6718
+ {
6719
+ handle: "body",
6720
+ jsonSchema: {},
6721
+ nullable: true,
6722
+ value: ""
6723
+ },
6724
+ {
6725
+ handle: "statusCode",
6726
+ jsonSchema: { type: "number" },
6727
+ nullable: false,
6728
+ value: 200
6729
+ },
6730
+ {
6731
+ handle: "headers",
6732
+ jsonSchema: webhookHeadersPort.jsonSchema,
6733
+ nullable: false,
6734
+ value: {}
6735
+ }
6736
+ ];
6737
+ function validWebhookStatus(value) {
6738
+ return typeof value === "number" && Number.isInteger(value) && value >= 200 && value <= 599 && webhookResponseAllowsBody(value);
6739
+ }
6740
+ /** Portable validation also runs in the isolated engine, which has no HTTP globals. */
6741
+ function webhookHeaderValues(source) {
6742
+ if (source == null || typeof source !== "object" || Array.isArray(source)) return;
6743
+ const headers = {};
6744
+ const names = [];
6745
+ for (const [name, value] of Object.entries(source)) {
6746
+ if (webhookHeaderNameIssue(name, names) != null) return;
6747
+ if (typeof value !== "string" && typeof value !== "boolean" && !(typeof value === "number" && Number.isFinite(value))) return;
6748
+ const text = String(value);
6749
+ if ([...text].some((character) => character.charCodeAt(0) > 255 || /[\0\r\n]/.test(character))) return;
6750
+ names.push(name);
6751
+ Object.defineProperty(headers, name, {
6752
+ value: text,
6753
+ enumerable: true,
6754
+ configurable: true
6755
+ });
6756
+ }
6757
+ return headers;
6758
+ }
6635
6759
  var text = string();
6636
6760
  var actionConnection = text.describe("Account selection: omit while unconfigured; use an account ID to select it; use \"\" to explicitly defer configuration. Deferred Actions fail if called; deferred Agent tools are excluded from the callable tool set. Not supported by Triggers.");
6637
6761
  var json = json$1();
@@ -6859,9 +6983,24 @@ var webhookOptions = object$1({
6859
6983
  allowedMethods: never().optional(),
6860
6984
  allowedOrigins: strings.optional(),
6861
6985
  noResponseBody: never().optional(),
6986
+ responseBody: discriminatedUnion("kind", [strictObject({
6987
+ kind: literal("workflow-outputs"),
6988
+ output: text.optional(),
6989
+ timeoutMs: number().int().min(webhookResponseTimeout.minMs).max(webhookResponseTimeout.maxMs).optional()
6990
+ }), strictObject({
6991
+ kind: literal("webhook-response"),
6992
+ nodeId: text.optional(),
6993
+ timeoutMs: number().int().min(webhookResponseTimeout.minMs).max(webhookResponseTimeout.maxMs).optional()
6994
+ })]).optional(),
6862
6995
  responseData: text.optional(),
6863
6996
  responseHeaders: record$1(text, text).optional(),
6864
- responseStatusCode: number().int().min(200).max(599).optional()
6997
+ responseHeadersSource: strictObject({
6998
+ kind: literal("workflow-outputs"),
6999
+ output: text.optional()
7000
+ }).optional(),
7001
+ responseHeaderOutputs: record$1(text, text).optional(),
7002
+ responseStatusCode: number().int().min(200).max(599).optional(),
7003
+ responseStatusCodeOutput: text.optional()
6865
7004
  });
6866
7005
  var webhook = {
6867
7006
  bodyFields: array(input),
@@ -6916,6 +7055,12 @@ var base = {
6916
7055
  onError: _enum(["stop", "error"]).optional()
6917
7056
  };
6918
7057
  var node = union([
7058
+ strictObject({
7059
+ ...base,
7060
+ kind: literal("webhook-response"),
7061
+ retry: never().optional(),
7062
+ onError: never().optional()
7063
+ }),
6919
7064
  strictObject({
6920
7065
  ...base,
6921
7066
  kind: literal("outputs"),
@@ -6948,7 +7093,8 @@ var node = union([
6948
7093
  strictObject({
6949
7094
  ...base,
6950
7095
  kind: literal("wait"),
6951
- ...wait
7096
+ ...wait,
7097
+ autoContinue: waitAutoContinueDraftSchema.optional()
6952
7098
  }).omit({ timeoutMs: true }),
6953
7099
  object$1({
6954
7100
  ...trigger,
@@ -7035,7 +7181,8 @@ object$1({
7035
7181
  literal(6),
7036
7182
  literal(7),
7037
7183
  literal(8),
7038
- literal(9)
7184
+ literal(9),
7185
+ literal(10)
7039
7186
  ]),
7040
7187
  document,
7041
7188
  modules: record$1(text, module)
@@ -7160,8 +7307,14 @@ var shapes = {
7160
7307
  },
7161
7308
  "graph.node.resolution.set": {
7162
7309
  ...at,
7163
- before: object$1(wait),
7164
- value: object$1(wait)
7310
+ before: strictObject({
7311
+ ...wait,
7312
+ autoContinue: waitAutoContinueDraftSchema.optional()
7313
+ }),
7314
+ value: strictObject({
7315
+ ...wait,
7316
+ autoContinue: waitAutoContinueDraftSchema.optional()
7317
+ })
7165
7318
  },
7166
7319
  "graph.node.webhook.set": {
7167
7320
  ...at,
@@ -11434,9 +11587,11 @@ function normalizeTriggerOutputs(trigger, outputs) {
11434
11587
  }
11435
11588
  //#endregion
11436
11589
  //#region src/execution/common/engineContract.ts
11437
- var currentEngineContract = "open-flow-engine/v6";
11438
- var nodejsEngineContract = "open-flow-engine/v6/nodejs-compat-v1";
11590
+ var currentEngineContract = "open-flow-engine/v7";
11591
+ var nodejsEngineContract = "open-flow-engine/v7/nodejs-compat-v1";
11439
11592
  var currentContract = {
11593
+ waitAutoContinue: true,
11594
+ webhookResponses: true,
11440
11595
  platformExports: /* @__PURE__ */ new Set(["engineContract", "identity"]),
11441
11596
  platformModule: "open-flow:platform",
11442
11597
  platformSource: `export const engineContract = ${JSON.stringify(currentEngineContract)}
@@ -11476,8 +11631,16 @@ export function identity(value) { return value }
11476
11631
  `
11477
11632
  };
11478
11633
  function findEngineContract(contract) {
11479
- if (contract == "open-flow-engine/v6") return currentContract;
11480
- if (contract == "open-flow-engine/v6/nodejs-compat-v1") return nodejsContract;
11634
+ if (contract == "open-flow-engine/v7") return currentContract;
11635
+ if (contract == "open-flow-engine/v7/nodejs-compat-v1") return nodejsContract;
11636
+ if (contract == "open-flow-engine/v6" || contract == "open-flow-engine/v6/nodejs-compat-v1") return {
11637
+ ...contract == "open-flow-engine/v6" ? currentContract : nodejsContract,
11638
+ waitAutoContinue: false,
11639
+ webhookResponses: false,
11640
+ platformSource: `export const engineContract = ${JSON.stringify(contract)}
11641
+ export function identity(value) { return value }
11642
+ `
11643
+ };
11481
11644
  }
11482
11645
  //#endregion
11483
11646
  //#region src/flow/common/agent.ts
@@ -11841,6 +12004,10 @@ function canonicalNode(value) {
11841
12004
  } }
11842
12005
  };
11843
12006
  switch (value.kind) {
12007
+ case "webhook-response": return {
12008
+ ...common,
12009
+ kind: value.kind
12010
+ };
11844
12011
  case "outputs": return {
11845
12012
  ...common,
11846
12013
  kind: value.kind,
@@ -11882,7 +12049,8 @@ function canonicalNode(value) {
11882
12049
  ...common,
11883
12050
  inputDefinitions: canonicalPorts(value.inputDefinitions),
11884
12051
  kind: value.kind,
11885
- prompt: value.prompt
12052
+ prompt: value.prompt,
12053
+ ...value.kind == "wait" && value.autoContinue != null ? { autoContinue: { ...value.autoContinue } } : {}
11886
12054
  };
11887
12055
  }
11888
12056
  }
@@ -11994,9 +12162,20 @@ function canonicalTriggerDefinition(snapshot) {
11994
12162
  function canonicalWebhookOptions(value) {
11995
12163
  return {
11996
12164
  ...value.allowedOrigins == null ? {} : { allowedOrigins: value.allowedOrigins },
12165
+ ...value.responseBody == null ? {} : { responseBody: {
12166
+ kind: value.responseBody.kind,
12167
+ ...value.responseBody.kind === "workflow-outputs" ? value.responseBody.output == null ? {} : { output: value.responseBody.output } : value.responseBody.nodeId == null ? {} : { nodeId: value.responseBody.nodeId },
12168
+ ...value.responseBody.timeoutMs == null ? {} : { timeoutMs: value.responseBody.timeoutMs }
12169
+ } },
11997
12170
  ...value.responseData == null ? {} : { responseData: value.responseData },
11998
12171
  ...value.responseHeaders == null ? {} : { responseHeaders: value.responseHeaders },
11999
- ...value.responseStatusCode == null ? {} : { responseStatusCode: value.responseStatusCode }
12172
+ ...value.responseHeadersSource == null ? {} : { responseHeadersSource: {
12173
+ kind: value.responseHeadersSource.kind,
12174
+ ...value.responseHeadersSource.output == null ? {} : { output: value.responseHeadersSource.output }
12175
+ } },
12176
+ ...value.responseHeaderOutputs == null ? {} : { responseHeaderOutputs: value.responseHeaderOutputs },
12177
+ ...value.responseStatusCode == null ? {} : { responseStatusCode: value.responseStatusCode },
12178
+ ...value.responseStatusCodeOutput == null ? {} : { responseStatusCodeOutput: value.responseStatusCodeOutput }
12000
12179
  };
12001
12180
  }
12002
12181
  function canonicalTriggerSchedule(value) {
@@ -12112,6 +12291,68 @@ function graphDiagnostic(code, message, path, values, mismatch) {
12112
12291
  ...values == null ? {} : { values }
12113
12292
  };
12114
12293
  }
12294
+ /** Execution reachability is independent of data bindings and selected runtime branches. */
12295
+ function executionReachableNodes(graph, source) {
12296
+ const reachable = /* @__PURE__ */ new Set([source]);
12297
+ for (const id of reachable) for (const edge of graph.edges) if (edge.source === id) reachable.add(edge.target);
12298
+ return reachable;
12299
+ }
12300
+ function webhookResponseDiagnostics(graph, triggerId, path = `/document/graph/nodes/${triggerId}`) {
12301
+ const trigger = graph.nodes[triggerId];
12302
+ if (trigger?.kind != "webhook") return [];
12303
+ const options = trigger.options ?? {};
12304
+ const response = options.responseBody;
12305
+ const statusOutput = options.responseStatusCodeOutput;
12306
+ const statusPath = `${path}/options/responseStatusCodeOutput`;
12307
+ const diagnostics = [];
12308
+ const headersSource = options.responseHeadersSource;
12309
+ const headerOutputs = options.responseHeaderOutputs;
12310
+ const headersPath = `${path}/options/${headersSource == null ? "responseHeaderOutputs" : "responseHeadersSource"}`;
12311
+ if (response?.kind !== "workflow-outputs") {
12312
+ if (statusOutput != null) diagnostics.push(graphDiagnostic("trigger.webhook-response-status-source", "Choose workflow outputs as the response source to use a status output.", statusPath));
12313
+ if (headersSource != null || headerOutputs != null) diagnostics.push(graphDiagnostic("trigger.webhook-response-headers-source", "Choose workflow outputs as the response source to use dynamic headers.", headersPath));
12314
+ if (response?.kind === "webhook-response") {
12315
+ const location = `${path}/options/responseBody/nodeId`;
12316
+ const { nodeId } = response;
12317
+ if (nodeId == null || graph.nodes[nodeId]?.kind !== "webhook-response") diagnostics.push(graphDiagnostic("trigger.webhook-response-node-missing", "Select a Webhook Response node.", location));
12318
+ else if (!executionReachableNodes(graph, triggerId).has(nodeId)) diagnostics.push(graphDiagnostic("trigger.webhook-response-node-unreachable", "Connect this Webhook to the selected Webhook Response node.", location));
12319
+ }
12320
+ return diagnostics;
12321
+ }
12322
+ if (headersSource == null) for (const [headers, location] of [[options.responseHeaders, `${path}/options/responseHeaders`], [headerOutputs, headersPath]]) {
12323
+ const names = [];
12324
+ for (const name of Object.keys(headers ?? {})) {
12325
+ if (webhookHeaderNameIssue(name, names) != null) diagnostics.push(graphDiagnostic("trigger.webhook-response-header-name", "Use valid, unique HTTP header names.", location));
12326
+ names.push(name);
12327
+ }
12328
+ }
12329
+ const responsePath = `${path}/options/responseBody`;
12330
+ const outputs = Object.entries(graph.nodes).filter(([, node]) => node.kind == "outputs");
12331
+ if (outputs.length == 0) diagnostics.push(graphDiagnostic("trigger.webhook-response-outputs-missing", "Add a workflow Outputs node for the HTTP response.", responsePath));
12332
+ else if (outputs.length == 1) {
12333
+ const output = outputs[0];
12334
+ if (!executionReachableNodes(graph, triggerId).has(output[0])) diagnostics.push(graphDiagnostic("trigger.webhook-response-unreachable", "Connect this Webhook to the workflow Outputs node.", responsePath));
12335
+ const field = response.output;
12336
+ if (field != null && output[1].kind == "outputs" && !output[1].outputDefs.some((port) => port.handle == field)) diagnostics.push(graphDiagnostic("trigger.webhook-response-output-missing", `Workflow output "${field}" does not exist.`, `${responsePath}/output`, { output: field }));
12337
+ if (statusOutput != null && output[1].kind == "outputs") {
12338
+ const port = output[1].outputDefs.find((candidate) => candidate.handle == statusOutput);
12339
+ if (port == null) diagnostics.push(graphDiagnostic("trigger.webhook-response-status-output-missing", `Workflow status output "${statusOutput}" does not exist.`, statusPath, { output: statusOutput }));
12340
+ else if (!portsAssignable(port, webhookStatusCodePort)) diagnostics.push(graphDiagnostic("trigger.webhook-response-status-output-type", "Choose a numeric workflow output for the response status code.", statusPath));
12341
+ }
12342
+ if (output[1].kind == "outputs") {
12343
+ const fields = output[1].outputDefs;
12344
+ const checkHeaderSource = (headerField, target, location) => {
12345
+ const port = headerField == null ? workflowOutputsPort(fields) : fields.find((candidate) => candidate.handle == headerField);
12346
+ if (port == null) diagnostics.push(graphDiagnostic("trigger.webhook-response-header-output-missing", `Workflow output "${headerField}" does not exist.`, location, { output: headerField }));
12347
+ else if (!portsAssignable(port, target)) diagnostics.push(graphDiagnostic("trigger.webhook-response-header-output-type", "Choose a compatible workflow output for the response headers.", location));
12348
+ };
12349
+ if (headersSource != null) checkHeaderSource(headersSource.output, webhookHeadersPort, headersPath);
12350
+ else for (const [name, headerField] of Object.entries(headerOutputs ?? {})) checkHeaderSource(headerField, webhookHeaderValuePort, `${headersPath}/${name.replaceAll("~", "~0").replaceAll("/", "~1")}`);
12351
+ }
12352
+ }
12353
+ if (statusOutput == null && !webhookResponseAllowsBody(options.responseStatusCode ?? 200)) diagnostics.push(graphDiagnostic("trigger.webhook-response-status-invalid", "Choose a response status code that permits a body.", `${path}/options/responseStatusCode`));
12354
+ return diagnostics;
12355
+ }
12115
12356
  function validateTrigger(triggerId, trigger, path, diagnostics) {
12116
12357
  if (trigger.kind == "start") return;
12117
12358
  const outputs = triggerOutputDefinitions(trigger);
@@ -12142,6 +12383,7 @@ function validateTrigger(triggerId, trigger, path, diagnostics) {
12142
12383
  }
12143
12384
  function nodeInputPorts(node) {
12144
12385
  switch (node.kind) {
12386
+ case "webhook-response": return portsByHandle(webhookResponseInputs);
12145
12387
  case "outputs": return portsByHandle(node.outputDefs);
12146
12388
  case "condition": return conditionInputPorts(node);
12147
12389
  case "value": return {};
@@ -12188,7 +12430,8 @@ function resolutionOutputPorts(node) {
12188
12430
  pattern: "\\S"
12189
12431
  },
12190
12432
  ...Object.fromEntries(actions.map((action) => [`${action}Url`, { type: "string" }])),
12191
- expiresAt: { type: "string" }
12433
+ expiresAt: { type: "string" },
12434
+ ...node.kind == "wait" && node.autoContinue != null ? { autoContinueAt: { type: "string" } } : {}
12192
12435
  }),
12193
12436
  ...Object.fromEntries(actions.map((action) => [action, objectPort({
12194
12437
  inputs,
@@ -12200,6 +12443,7 @@ function resolutionOutputPorts(node) {
12200
12443
  }
12201
12444
  function nodeOutputPorts(node) {
12202
12445
  switch (node.kind) {
12446
+ case "webhook-response":
12203
12447
  case "outputs":
12204
12448
  case "condition": return {};
12205
12449
  case "value": return portsByHandle(node.values);
@@ -12406,6 +12650,10 @@ function validateResolution(nodeId, node, path, diagnostics) {
12406
12650
  "name",
12407
12651
  "prompt"
12408
12652
  ]);
12653
+ if (node.kind == "wait") {
12654
+ fields.add("autoContinue");
12655
+ if (node.autoContinue != null && !waitAutoContinueSchema.safeParse(node.autoContinue).success) diagnostics.push(graphDiagnostic("wait.auto-continue-invalid", "Enter a positive integer duration or a timestamp with an explicit timezone.", `${path}/autoContinue`));
12656
+ }
12409
12657
  const label = node.kind == "wait" ? "Wait" : "Approval";
12410
12658
  const unsupported = Object.keys(node).filter((field) => !fields.has(field));
12411
12659
  if (unsupported.length > 0) diagnostics.push(graphDiagnostic(`${node.kind}.field-unsupported`, `${label} node "${nodeId}" contains unsupported fields: ${unsupported.join(", ")}.`, path, {
@@ -12421,6 +12669,15 @@ function validateGraph(graph, document, path, diagnostics) {
12421
12669
  const errorTriggers = Object.entries(graph.nodes).filter(([, node]) => node.kind == "error");
12422
12670
  if (errorTriggers.length > 1) for (const [nodeId] of errorTriggers) diagnostics.push(graphDiagnostic("graph.error-trigger-duplicate", "A graph can contain only one Flow Error node.", `${path}/nodes/${nodeId}`));
12423
12671
  const outputNodes = Object.entries(graph.nodes).filter(([, node]) => node.kind == "outputs");
12672
+ for (const [nodeId, node] of Object.entries(graph.nodes)) {
12673
+ if (node.kind == "webhook") diagnostics.push(...webhookResponseDiagnostics(graph, nodeId, `${path}/nodes/${nodeId}`));
12674
+ if (node.kind === "webhook-response") {
12675
+ const status = node.inputs.statusCode;
12676
+ if (status?.kind === "value" && !validWebhookStatus(status.value)) diagnostics.push(graphDiagnostic("webhook.response-status-invalid", "Use an integer status from 200 to 599, excluding 204, 205 and 304.", `${path}/nodes/${nodeId}/inputs/statusCode`));
12677
+ const headers = node.inputs.headers;
12678
+ if (headers?.kind === "value" && (webhookHeaderValues(headers.value) == null || Object.values(headers.value).some((value) => typeof value !== "string"))) diagnostics.push(graphDiagnostic("webhook.response-headers-invalid", "Use valid, unique HTTP header names and single-line text values.", `${path}/nodes/${nodeId}/inputs/headers`));
12679
+ }
12680
+ }
12424
12681
  if (outputNodes.length > 1) for (const [nodeId] of outputNodes) diagnostics.push(graphDiagnostic("graph.outputs-duplicate", "A graph can contain only one Outputs node.", `${path}/nodes/${nodeId}`));
12425
12682
  const startTriggers = Object.entries(graph.nodes).filter(([, node]) => node.kind == "manual" || node.kind == "start");
12426
12683
  if (startTriggers.length > 1) for (const [nodeId] of startTriggers) diagnostics.push(graphDiagnostic("graph.start-trigger-duplicate", "A graph can contain only one Start Trigger.", `${path}/nodes/${nodeId}`));
@@ -24482,6 +24739,8 @@ async function prepareFlow(revision, engineContract, triggerId) {
24482
24739
  };
24483
24740
  revision = runRevision(revision, triggerId);
24484
24741
  }
24742
+ if (!engine.webhookResponses && Object.values(revision.document.graph.nodes).some((node) => node.kind === "webhook-response" || node.kind === "webhook" && node.options?.responseBody?.kind === "webhook-response")) return { kind: "engine-unsupported" };
24743
+ if (!engine.waitAutoContinue && Object.values(revision.document.graph.nodes).some((node) => node.kind == "wait" && node.autoContinue != null)) return { kind: "engine-unsupported" };
24485
24744
  const validation = await validateFlow(revision, engine);
24486
24745
  if (!validation.valid) return {
24487
24746
  kind: "flow-invalid",
@@ -1930,7 +1930,7 @@ function timeSource(args) {
1930
1930
  function time(args) {
1931
1931
  return new RegExp(`^${timeSource(args)}$`);
1932
1932
  }
1933
- function datetime(args) {
1933
+ function datetime$1(args) {
1934
1934
  const opts = ["Z"];
1935
1935
  if (args.offset) opts.push(`([+-](?:[01]\\d|2[0-3]):[0-5]\\d)`);
1936
1936
  const qualified = `${timeSource({
@@ -2581,7 +2581,7 @@ var $ZodKSUID = /*@__PURE__*/ $constructor("$ZodKSUID", (inst, def) => {
2581
2581
  $ZodStringFormat.init(inst, def);
2582
2582
  });
2583
2583
  var $ZodISODateTime = /*@__PURE__*/ $constructor("$ZodISODateTime", (inst, def) => {
2584
- def.pattern ?? (def.pattern = datetime(def));
2584
+ def.pattern ?? (def.pattern = datetime$1(def));
2585
2585
  $ZodStringFormat.init(inst, def);
2586
2586
  });
2587
2587
  var $ZodISODate = /*@__PURE__*/ $constructor("$ZodISODate", (inst, def) => {
@@ -6578,6 +6578,11 @@ function preprocess(fn, schema) {
6578
6578
  });
6579
6579
  }
6580
6580
  //#endregion
6581
+ //#region ../../node_modules/.bun/zod@4.6.5/node_modules/zod/v4/classic/iso.js
6582
+ function datetime(params) {
6583
+ return /* @__PURE__ */ _isoDateTime(ZodISODateTime, params);
6584
+ }
6585
+ //#endregion
6581
6586
  //#region src/decision/common/decision.ts
6582
6587
  var decisionLimits = {
6583
6588
  choice: 255,
@@ -6697,6 +6702,32 @@ var triggerScheduleSchema = array(union([object({
6697
6702
  value: number()
6698
6703
  })]));
6699
6704
  //#endregion
6705
+ //#region src/localization/common/timeZone.ts
6706
+ /** Validate a named timezone using the same runtime data used for date conversion. */
6707
+ function isTimeZone(value) {
6708
+ try {
6709
+ Intl.DateTimeFormat("en", { timeZone: value });
6710
+ return true;
6711
+ } catch {
6712
+ return false;
6713
+ }
6714
+ }
6715
+ //#endregion
6716
+ //#region src/flow/common/wait.ts
6717
+ /** Drafts retain incomplete values; semantic validation gates publication and execution. */
6718
+ var waitAutoContinueDraftSchema = discriminatedUnion("kind", [strictObject({
6719
+ kind: literal("after"),
6720
+ durationMs: number().nullable()
6721
+ }), strictObject({
6722
+ kind: literal("at"),
6723
+ at: string(),
6724
+ timezone: string().optional()
6725
+ })]);
6726
+ discriminatedUnion("kind", [waitAutoContinueDraftSchema.options[0].extend({ durationMs: number().int().positive().max(Number.MAX_SAFE_INTEGER) }), waitAutoContinueDraftSchema.options[1].extend({
6727
+ at: datetime({ offset: true }),
6728
+ timezone: string().refine(isTimeZone, "Select a valid IANA timezone.").optional()
6729
+ })]);
6730
+ //#endregion
6700
6731
  //#region src/flow/common/webhookMethod.ts
6701
6732
  var webhookMethods = [
6702
6733
  "GET",
@@ -6705,6 +6736,24 @@ var webhookMethods = [
6705
6736
  "PATCH",
6706
6737
  "DELETE"
6707
6738
  ];
6739
+ //#endregion
6740
+ //#region src/flow/common/webhookResponse.ts
6741
+ var webhookResponseTimeout = {
6742
+ defaultMs: 3e4,
6743
+ minMs: 1e3,
6744
+ maxMs: 6e4
6745
+ };
6746
+ ({
6747
+ jsonSchema: {
6748
+ type: "object",
6749
+ additionalProperties: { type: [
6750
+ "string",
6751
+ "number",
6752
+ "boolean"
6753
+ ] }
6754
+ },
6755
+ nullable: true
6756
+ }).jsonSchema;
6708
6757
  var text = string();
6709
6758
  var actionConnection = text.describe("Account selection: omit while unconfigured; use an account ID to select it; use \"\" to explicitly defer configuration. Deferred Actions fail if called; deferred Agent tools are excluded from the callable tool set. Not supported by Triggers.");
6710
6759
  var json = json$1();
@@ -6932,9 +6981,24 @@ var webhookOptions = object({
6932
6981
  allowedMethods: never().optional(),
6933
6982
  allowedOrigins: strings.optional(),
6934
6983
  noResponseBody: never().optional(),
6984
+ responseBody: discriminatedUnion("kind", [strictObject({
6985
+ kind: literal("workflow-outputs"),
6986
+ output: text.optional(),
6987
+ timeoutMs: number().int().min(webhookResponseTimeout.minMs).max(webhookResponseTimeout.maxMs).optional()
6988
+ }), strictObject({
6989
+ kind: literal("webhook-response"),
6990
+ nodeId: text.optional(),
6991
+ timeoutMs: number().int().min(webhookResponseTimeout.minMs).max(webhookResponseTimeout.maxMs).optional()
6992
+ })]).optional(),
6935
6993
  responseData: text.optional(),
6936
6994
  responseHeaders: record$2(text, text).optional(),
6937
- responseStatusCode: number().int().min(200).max(599).optional()
6995
+ responseHeadersSource: strictObject({
6996
+ kind: literal("workflow-outputs"),
6997
+ output: text.optional()
6998
+ }).optional(),
6999
+ responseHeaderOutputs: record$2(text, text).optional(),
7000
+ responseStatusCode: number().int().min(200).max(599).optional(),
7001
+ responseStatusCodeOutput: text.optional()
6938
7002
  });
6939
7003
  var webhook = {
6940
7004
  bodyFields: array(input),
@@ -6989,6 +7053,12 @@ var base = {
6989
7053
  onError: _enum(["stop", "error"]).optional()
6990
7054
  };
6991
7055
  var node = union([
7056
+ strictObject({
7057
+ ...base,
7058
+ kind: literal("webhook-response"),
7059
+ retry: never().optional(),
7060
+ onError: never().optional()
7061
+ }),
6992
7062
  strictObject({
6993
7063
  ...base,
6994
7064
  kind: literal("outputs"),
@@ -7021,7 +7091,8 @@ var node = union([
7021
7091
  strictObject({
7022
7092
  ...base,
7023
7093
  kind: literal("wait"),
7024
- ...wait
7094
+ ...wait,
7095
+ autoContinue: waitAutoContinueDraftSchema.optional()
7025
7096
  }).omit({ timeoutMs: true }),
7026
7097
  object({
7027
7098
  ...trigger,
@@ -7108,7 +7179,8 @@ object({
7108
7179
  literal(6),
7109
7180
  literal(7),
7110
7181
  literal(8),
7111
- literal(9)
7182
+ literal(9),
7183
+ literal(10)
7112
7184
  ]),
7113
7185
  document,
7114
7186
  modules: record$2(text, module)
@@ -7233,8 +7305,14 @@ var shapes = {
7233
7305
  },
7234
7306
  "graph.node.resolution.set": {
7235
7307
  ...at,
7236
- before: object(wait),
7237
- value: object(wait)
7308
+ before: strictObject({
7309
+ ...wait,
7310
+ autoContinue: waitAutoContinueDraftSchema.optional()
7311
+ }),
7312
+ value: strictObject({
7313
+ ...wait,
7314
+ autoContinue: waitAutoContinueDraftSchema.optional()
7315
+ })
7238
7316
  },
7239
7317
  "graph.node.webhook.set": {
7240
7318
  ...at,
@@ -37,9 +37,24 @@ declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
37
37
  allowedMethods: z.ZodOptional<z.ZodNever>;
38
38
  allowedOrigins: z.ZodOptional<z.ZodArray<z.ZodString>>;
39
39
  noResponseBody: z.ZodOptional<z.ZodNever>;
40
+ responseBody: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
41
+ kind: z.ZodLiteral<"workflow-outputs">;
42
+ output: z.ZodOptional<z.ZodString>;
43
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
44
+ }, z.core.$strict>, z.ZodObject<{
45
+ kind: z.ZodLiteral<"webhook-response">;
46
+ nodeId: z.ZodOptional<z.ZodString>;
47
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
48
+ }, z.core.$strict>], "kind">>;
40
49
  responseData: z.ZodOptional<z.ZodString>;
41
50
  responseHeaders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
51
+ responseHeadersSource: z.ZodOptional<z.ZodObject<{
52
+ kind: z.ZodLiteral<"workflow-outputs">;
53
+ output: z.ZodOptional<z.ZodString>;
54
+ }, z.core.$strict>>;
55
+ responseHeaderOutputs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
42
56
  responseStatusCode: z.ZodOptional<z.ZodNumber>;
57
+ responseStatusCodeOutput: z.ZodOptional<z.ZodString>;
43
58
  }, z.core.$strip>>;
44
59
  body: z.ZodRecord<z.ZodString, z.ZodObject<{
45
60
  schema: z.ZodOptional<z.ZodJSONSchema>;
@@ -161,7 +161,7 @@ export declare const mcpTools: {
161
161
  value: {
162
162
  revision?: string | undefined;
163
163
  query: string;
164
- type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "start" | "value" | "wait" | "webhook" | "workflow" | undefined;
164
+ type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "start" | "value" | "wait" | "webhook" | "webhook-response" | "workflow" | undefined;
165
165
  offset: number;
166
166
  limit: number;
167
167
  flowId: string;
@@ -193,7 +193,7 @@ export declare const mcpTools: {
193
193
  };
194
194
  validate(value: unknown): {
195
195
  value: {
196
- type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "start" | "value" | "wait" | "webhook" | "workflow" | undefined;
196
+ type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "start" | "value" | "wait" | "webhook" | "webhook-response" | "workflow" | undefined;
197
197
  action?: string | undefined;
198
198
  flowId?: string | undefined;
199
199
  };
@@ -321,7 +321,7 @@ export declare const mcpTools: {
321
321
  edits: ({
322
322
  op: "node.add";
323
323
  as: string;
324
- type: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "start" | "value" | "wait" | "webhook" | "workflow";
324
+ type: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "start" | "value" | "wait" | "webhook" | "webhook-response" | "workflow";
325
325
  name: string;
326
326
  onError?: "error" | "stop" | undefined;
327
327
  retry?: {