@oomol-lab/open-flow 0.1.0-beta.65 → 0.1.0-beta.66

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/{createResourceDialog-BAJXbzNH.js → createResourceDialog-C-Si_cYs.js} +2 -2
  2. package/dist/browser/flow-authoring-node.d.ts +12 -3
  3. package/dist/browser/flow-authoring.js +114 -19
  4. package/dist/browser/flow-change-schema.d.ts +3 -1
  5. package/dist/browser/flow-change.d.ts +15 -3
  6. package/dist/browser/flow-change.js +111 -16
  7. package/dist/browser/{flowChanges-DkvG5uDq.js → flowChanges-T4_R5p1f.js} +2654 -1858
  8. package/dist/browser/{flowRunInputEditorStore-B2Rw4VsT.js → flowRunInputEditorStore-DJqmR6Qh.js} +3 -2
  9. package/dist/browser/{flowWorkspace-BEp-lxqF.js → flowWorkspace-C0J5C0oM.js} +700 -224
  10. package/dist/browser/{icons-Db2Jb2iX.js → icons-BD3m0RQq.js} +4484 -4370
  11. package/dist/browser/preview.css +152 -64
  12. package/dist/browser/preview.js +4460 -3412
  13. package/dist/browser/ui.css +85 -3
  14. package/dist/browser/ui.js +8 -5
  15. package/dist/browser/workbench.css +152 -64
  16. package/dist/browser/workbench.js +146 -57
  17. package/dist/browser/{workbenchSelect-C-jf6NIM.js → workbenchSelect-B-PFpF_Q.js} +1 -1
  18. package/dist/command/index.js +49 -49
  19. package/dist/common/authoring.d.ts +7 -5
  20. package/dist/common/authoringExamples.d.ts +3 -3
  21. package/dist/common/authoringFields.d.ts +20 -0
  22. package/dist/common/authoringSchema.d.ts +404 -15
  23. package/dist/common/control-api-conformance.js +384 -137
  24. package/dist/common/control-api.d.ts +63 -7
  25. package/dist/common/control-api.js +3562 -3428
  26. package/dist/common/control-requests.d.ts +10 -3
  27. package/dist/common/control-requests.js +418 -43
  28. package/dist/common/decision.js +28 -3
  29. package/dist/common/flow-encoding.d.ts +4 -2
  30. package/dist/common/flow-encoding.js +144 -10
  31. package/dist/common/flow-graph.d.ts +1 -1
  32. package/dist/common/flow-semantics.d.ts +12 -2
  33. package/dist/common/flow-semantics.js +146 -33
  34. package/dist/common/integration-trigger.js +28 -3
  35. package/dist/common/liveDetails.d.ts +26 -11
  36. package/dist/common/mcp.d.ts +6 -3
  37. package/dist/common/mcp.js +203 -84
  38. package/dist/common/openapi.js +28 -3
  39. package/dist/common/poll-trigger.js +28 -3
  40. package/dist/common/run-events.d.ts +2 -0
  41. package/dist/common/run-events.js +9 -3
  42. package/dist/common/scheduler.d.ts +10 -1
  43. package/dist/common/scheduler.js +167 -45
  44. package/dist/common/trigger-contract.d.ts +2 -0
  45. package/dist/common/webhook-trigger.js +28 -3
  46. package/dist/common/workflow.d.ts +93 -0
  47. package/dist/common/workflow.js +10491 -0
  48. package/package.json +5 -1
  49. package/skills/open-flow/references/flow-authoring.md +26 -16
@@ -22,6 +22,15 @@ function dequal(foo, bar) {
22
22
  return foo !== foo && bar !== bar;
23
23
  }
24
24
  //#endregion
25
+ //#region src/openapi/common/authBindings.ts
26
+ /** Never allow credentials to enter a Revision as literal node inputs. */
27
+ function assertOpenApiAuthBindings(document) {
28
+ for (const node of Object.values(document.graph.nodes)) {
29
+ if (node.kind != "task" || !("executor" in node.task) || node.task.executor.kind != "openapi") continue;
30
+ for (const [handle, mapping] of Object.entries(node.inputs)) if (handle.startsWith("auth.") && mapping.kind == "value") throw new TypeError("OpenAPI authentication accepts deployment variables and upstream outputs only.");
31
+ }
32
+ }
33
+ //#endregion
25
34
  //#region ../../node_modules/.bun/zod@4.6.5/node_modules/zod/v4/core/util.js
26
35
  function getEnumValues(entries) {
27
36
  const numericValues = Object.values(entries).filter((v) => typeof v === "number");
@@ -5691,50 +5700,6 @@ function preprocess(fn, schema) {
5691
5700
  });
5692
5701
  }
5693
5702
  //#endregion
5694
- //#region src/flow/common/webhookMethod.ts
5695
- var webhookMethods = [
5696
- "GET",
5697
- "POST",
5698
- "PUT",
5699
- "PATCH",
5700
- "DELETE"
5701
- ];
5702
- function webhookSupportsBody(method) {
5703
- return method !== "GET";
5704
- }
5705
- //#endregion
5706
- //#region src/openapi/common/authBindings.ts
5707
- /** Never allow credentials to enter a Revision as literal node inputs. */
5708
- function assertOpenApiAuthBindings(document) {
5709
- for (const node of Object.values(document.graph.nodes)) {
5710
- if (node.kind != "task" || !("executor" in node.task) || node.task.executor.kind != "openapi") continue;
5711
- for (const [handle, mapping] of Object.entries(node.inputs)) if (handle.startsWith("auth.") && mapping.kind == "value") throw new TypeError("OpenAPI authentication accepts deployment variables and upstream outputs only.");
5712
- }
5713
- }
5714
- //#endregion
5715
- //#region src/flow/common/change.ts
5716
- var schemaKeywords = /* @__PURE__ */ new Set([
5717
- "const",
5718
- "enum",
5719
- "exclusiveMaximum",
5720
- "exclusiveMinimum",
5721
- "maximum",
5722
- "maxItems",
5723
- "maxLength",
5724
- "maxProperties",
5725
- "minimum",
5726
- "minItems",
5727
- "minLength",
5728
- "minProperties",
5729
- "multipleOf",
5730
- "pattern",
5731
- "required",
5732
- "type"
5733
- ]);
5734
- function isSchemaKeyword(value) {
5735
- return schemaKeywords.has(value);
5736
- }
5737
- //#endregion
5738
5703
  //#region src/json-schema-subset/utils.ts
5739
5704
  var nextId = 0;
5740
5705
  function createId() {
@@ -8601,6 +8566,18 @@ var triggerScheduleSchema = array(union([object({
8601
8566
  ]),
8602
8567
  value: number()
8603
8568
  })]));
8569
+ //#endregion
8570
+ //#region src/flow/common/webhookMethod.ts
8571
+ var webhookMethods = [
8572
+ "GET",
8573
+ "POST",
8574
+ "PUT",
8575
+ "PATCH",
8576
+ "DELETE"
8577
+ ];
8578
+ function webhookSupportsBody(method) {
8579
+ return method !== "GET";
8580
+ }
8604
8581
  var text = string$1();
8605
8582
  var json$3 = json$4();
8606
8583
  var strings$1 = array(text);
@@ -8610,6 +8587,7 @@ var port$1 = object({
8610
8587
  nullable: boolean(),
8611
8588
  handle: text
8612
8589
  });
8590
+ var workflowInputDefs = array(port$1.strict());
8613
8591
  var input = port$1.extend({ value: json$3.optional() });
8614
8592
  var group = object({
8615
8593
  collapsed: boolean().optional(),
@@ -8767,6 +8745,11 @@ var managedFields = object({
8767
8745
  messageHandle: text,
8768
8746
  inputs: record$3(text, agentValue)
8769
8747
  }).optional()
8748
+ }),
8749
+ strictObject({
8750
+ kind: literal("workflow"),
8751
+ flowId: text,
8752
+ revisionId: text
8770
8753
  })
8771
8754
  ])
8772
8755
  });
@@ -8875,6 +8858,12 @@ var base = {
8875
8858
  timeoutMs: number().optional()
8876
8859
  };
8877
8860
  var node = union([
8861
+ strictObject({
8862
+ ...base,
8863
+ kind: literal("outputs"),
8864
+ outputDefs: array(port$1.strict()),
8865
+ outputMappings: inputs
8866
+ }).omit({ inputs: true }),
8878
8867
  object({
8879
8868
  ...base,
8880
8869
  inputs: record$3(text, never()),
@@ -8907,6 +8896,11 @@ var node = union([
8907
8896
  ...trigger,
8908
8897
  kind: literal("manual")
8909
8898
  }),
8899
+ strictObject({
8900
+ ...trigger,
8901
+ kind: literal("start"),
8902
+ inputDefs: workflowInputDefs
8903
+ }),
8910
8904
  strictObject({
8911
8905
  ...trigger,
8912
8906
  kind: literal("error"),
@@ -8986,7 +8980,7 @@ var module = object({
8986
8980
  imports: strings$1,
8987
8981
  source: text
8988
8982
  });
8989
- var document = preprocess(rejectRetiredDefinitions, object({
8983
+ var document = preprocess(normalizeDocument, object({
8990
8984
  bindings: record$3(text, binding$1),
8991
8985
  graph
8992
8986
  }));
@@ -8995,7 +8989,9 @@ var revision = object({
8995
8989
  literal(2),
8996
8990
  literal(4),
8997
8991
  literal(5),
8998
- literal(6)
8992
+ literal(6),
8993
+ literal(7),
8994
+ literal(8)
8999
8995
  ]),
9000
8996
  document,
9001
8997
  modules: record$3(text, module)
@@ -9004,13 +9000,19 @@ revision.extend({
9004
9000
  kind: literal("open-flow-flow-revision"),
9005
9001
  version: literal(1)
9006
9002
  });
9007
- function rejectRetiredDefinitions(value) {
9003
+ function normalizeDocument(value) {
9008
9004
  const candidate = record$2(value);
9009
9005
  if (candidate.tasks !== void 0 && (candidate.tasks === null || typeof candidate.tasks !== "object" || Array.isArray(candidate.tasks) || Object.keys(candidate.tasks).length > 0)) throw new TypeError("Independent Task definitions are no longer supported.");
9010
9006
  if (Object.values(record$2(record$2(candidate.graph).nodes)).some((candidateNode) => Object.hasOwn(record$2(candidateNode), "taskId"))) throw new TypeError("Task references are no longer supported.");
9011
9007
  const subflows = candidate.subflows;
9012
9008
  if (subflows !== void 0 && (subflows === null || typeof subflows !== "object" || Array.isArray(subflows) || Object.keys(subflows).length > 0)) throw new TypeError("Subflows are no longer supported.");
9013
9009
  if (Object.values(record$2(record$2(candidate.graph).nodes)).some((candidateNode) => record$2(candidateNode).kind === "subflow")) throw new TypeError("Subflow nodes are no longer supported.");
9010
+ if ([
9011
+ "inputDefs",
9012
+ "outputDefs",
9013
+ "outputMappings"
9014
+ ].some((field) => Object.hasOwn(candidate, field))) throw new TypeError("Workflow interface configuration must belong to Start and Outputs nodes.");
9015
+ if (Object.values(record$2(record$2(candidate.graph).nodes)).some((candidateNode) => record$2(candidateNode).kind == "start" && Object.hasOwn(record$2(candidateNode), "parameters"))) throw new TypeError("Legacy Start.parameters is unsupported; configure node.inputDefs.");
9014
9016
  return value;
9015
9017
  }
9016
9018
  function record$2(value) {
@@ -9176,10 +9178,100 @@ array(union([...new Map(Object.entries(shapes).map(([kind, shape]) => [kind, sha
9176
9178
  ...shape
9177
9179
  })])).values()])).min(1);
9178
9180
  function checkModelVersion(content) {
9181
+ if (content.modelVersion < 8 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "outputs")) throw new TypeError("Workflow outputs require Flow model version 8.");
9182
+ if (content.modelVersion < 7 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "start")) throw new TypeError("Start Triggers require Flow model version 7.");
9179
9183
  if (content.modelVersion < 6 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "task" && "executor" in candidateNode.task)) throw new TypeError("Node-owned managed Tasks require Flow model version 6.");
9180
9184
  if (content.modelVersion < 5 && Object.values(content.document.graph.nodes).some((itemNode) => itemNode.kind == "error")) throw new TypeError("Error workflows require Flow model version 5.");
9181
9185
  }
9182
9186
  //#endregion
9187
+ //#region src/flow/common/change.ts
9188
+ var schemaKeywords = /* @__PURE__ */ new Set([
9189
+ "const",
9190
+ "enum",
9191
+ "exclusiveMaximum",
9192
+ "exclusiveMinimum",
9193
+ "maximum",
9194
+ "maxItems",
9195
+ "maxLength",
9196
+ "maxProperties",
9197
+ "minimum",
9198
+ "minItems",
9199
+ "minLength",
9200
+ "minProperties",
9201
+ "multipleOf",
9202
+ "pattern",
9203
+ "required",
9204
+ "type"
9205
+ ]);
9206
+ function isSchemaKeyword(value) {
9207
+ return schemaKeywords.has(value);
9208
+ }
9209
+ /** Lossless upgrade of readable content. Historical content and its encoding stay unchanged. */
9210
+ function upgradeRevisionContent(content) {
9211
+ const upgraded = upgradeDecodedRevisionContent(decodeRevisionContent(content));
9212
+ return dequal(content, upgraded) ? content : upgraded;
9213
+ }
9214
+ function upgradeDecodedRevisionContent(content) {
9215
+ const graph = content.document.graph;
9216
+ const hasManual = Object.values(graph.nodes).some((node) => node.kind == "manual");
9217
+ if (!hasManual && content.modelVersion == 8) return content;
9218
+ return {
9219
+ ...content,
9220
+ modelVersion: 8,
9221
+ document: {
9222
+ ...content.document,
9223
+ graph: hasManual ? {
9224
+ ...graph,
9225
+ nodes: Object.fromEntries(Object.entries(graph.nodes).map(([id, node]) => [id, upgradeManualTrigger(node)]))
9226
+ } : graph
9227
+ }
9228
+ };
9229
+ }
9230
+ function upgradeManualTrigger(node) {
9231
+ return node.kind == "manual" ? {
9232
+ ...node,
9233
+ kind: "start",
9234
+ inputDefs: []
9235
+ } : node;
9236
+ }
9237
+ //#endregion
9238
+ //#region src/workflow/common/workflow.ts
9239
+ var portSchema = object({
9240
+ handle: string$1().min(1),
9241
+ jsonSchema: json$4(),
9242
+ nullable: boolean(),
9243
+ description: string$1().optional()
9244
+ });
9245
+ strictObject({
9246
+ inputs: array(portSchema).nullable(),
9247
+ outputs: array(portSchema).nullable()
9248
+ });
9249
+ var workflowContractSchema = object({
9250
+ version: literal(1),
9251
+ flowId: string$1().min(1),
9252
+ name: string$1(),
9253
+ revisionId: string$1().min(1),
9254
+ publicationId: string$1().min(1),
9255
+ inputs: array(portSchema),
9256
+ outputs: array(portSchema).nullable()
9257
+ });
9258
+ var workflowReferencesSchema = object({
9259
+ version: literal(1),
9260
+ direction: _enum(["incoming", "outgoing"]),
9261
+ total: int().nonnegative(),
9262
+ nextOffset: int().nonnegative().optional(),
9263
+ references: array(object({
9264
+ flowId: string$1(),
9265
+ name: string$1().nullable(),
9266
+ available: boolean(),
9267
+ draft: boolean(),
9268
+ live: object({
9269
+ publicationId: string$1(),
9270
+ enabled: boolean()
9271
+ }).nullable()
9272
+ }))
9273
+ });
9274
+ //#endregion
9183
9275
  //#region src/control/common/authoringLlm.ts
9184
9276
  var authoringLlmConfiguration = strictObject({
9185
9277
  mode: _enum(["chat", "json"]),
@@ -9212,7 +9304,9 @@ var id$1 = string$1().min(1);
9212
9304
  var json$2 = json$4();
9213
9305
  var patch = record$3(id$1, json$2);
9214
9306
  var type = _enum([
9215
- "manual",
9307
+ "start",
9308
+ "outputs",
9309
+ "workflow",
9216
9310
  "webhook",
9217
9311
  "cron",
9218
9312
  "error",
@@ -9284,6 +9378,12 @@ var field = strictObject({
9284
9378
  description: string$1().optional()
9285
9379
  });
9286
9380
  var inputFields = record$3(id$1, field.extend({ default: json$2.optional() })).describe("Optional business input constraints by name. A binding to a new Code, Agent, LLM, Wait or Approval input automatically declares an input accepting any JSON. Existing constraints are preserved. Omitted schema accepts any JSON; omitted nullable is true. Use default for inherited values; input.set supplies data.");
9381
+ var flowInputFields = record$3(id$1, field).describe("Workflow input definitions by name. Omitted schema accepts any JSON; omitted nullable is true. No defaults. Supply call values as trigger.outputs.");
9382
+ var flowOutputFields = flowInputFields.describe("Workflow output definitions by name. Omitted schema accepts any JSON; omitted nullable is true. No defaults. Set values on the Outputs node with input.set or node.add.inputs.");
9383
+ var flowInputFieldsView = record$3(id$1, field.extend({
9384
+ schema: json$2,
9385
+ nullable: boolean()
9386
+ }));
9287
9387
  var outputFields = record$3(id$1, field).describe("Code return fields by name. Omitted schema accepts any JSON; omitted nullable is true.");
9288
9388
  var expression = strictObject({
9289
9389
  left: operand,
@@ -9297,7 +9397,9 @@ var when = union([
9297
9397
  strictObject({ any: array(union([expression, all])) })
9298
9398
  ]);
9299
9399
  var authoringConfigurations = {
9300
- manual: strictObject({}),
9400
+ workflow: strictObject({ flowId: id$1 }),
9401
+ start: strictObject({ inputDefs: flowInputFields.default({}) }),
9402
+ outputs: strictObject({ outputDefs: flowOutputFields.default({}) }),
9301
9403
  error: strictObject({ sourceFlowIds: array(id$1).optional() }),
9302
9404
  webhook: authoringDefinitionSchemas.webhook.omit({ bodyFields: true }).extend({ body: inputFields }).strict(),
9303
9405
  cron: strictObject({ schedule: authoringDefinitionSchemas.schedule }),
@@ -9368,6 +9470,10 @@ var authoringEditSchema = discriminatedUnion("op", [
9368
9470
  set: updates.optional(),
9369
9471
  clear: array(array(id$1).min(1)).optional()
9370
9472
  }),
9473
+ strictObject({
9474
+ op: literal("node.refresh"),
9475
+ node: referenceSchema
9476
+ }),
9371
9477
  strictObject({
9372
9478
  op: literal("node.remove"),
9373
9479
  node: referenceSchema
@@ -9478,7 +9584,7 @@ var authoringSearchResponse = object({
9478
9584
  revision: id$1,
9479
9585
  data: object({
9480
9586
  matches: array(object({
9481
- node: id$1,
9587
+ node: id$1.optional(),
9482
9588
  field: id$1,
9483
9589
  line: int().optional(),
9484
9590
  excerpt: string$1()
@@ -9566,6 +9672,10 @@ function record$1(value) {
9566
9672
  function string(value) {
9567
9673
  return typeof value == "string" && value.length > 0 ? value : invalidResponse("Expected a non-empty string.");
9568
9674
  }
9675
+ function requiredFields(value, keys) {
9676
+ const missing = keys.filter((key) => !Object.hasOwn(value, key));
9677
+ if (missing.length > 0) invalidResponse(`Missing fields: ${missing.join(", ")}.`);
9678
+ }
9569
9679
  function exact(value, keys) {
9570
9680
  const actual = Object.keys(value);
9571
9681
  if (actual.length != keys.length || actual.some((key) => !keys.includes(key))) {
@@ -9633,7 +9743,7 @@ function publishOperation(value) {
9633
9743
  if (source.version != 1) return invalidResponse();
9634
9744
  switch (status) {
9635
9745
  case "pending":
9636
- exact(source, [
9746
+ requiredFields(source, [
9637
9747
  "createdAt",
9638
9748
  "flowId",
9639
9749
  "operationId",
@@ -9647,7 +9757,7 @@ function publishOperation(value) {
9647
9757
  status
9648
9758
  };
9649
9759
  case "succeeded":
9650
- exact(source, [
9760
+ requiredFields(source, [
9651
9761
  "createdAt",
9652
9762
  "flowId",
9653
9763
  "operationId",
@@ -9663,7 +9773,7 @@ function publishOperation(value) {
9663
9773
  status
9664
9774
  };
9665
9775
  case "failed": {
9666
- exact(source, [
9776
+ requiredFields(source, [
9667
9777
  "createdAt",
9668
9778
  "flowId",
9669
9779
  "issue",
@@ -9675,7 +9785,7 @@ function publishOperation(value) {
9675
9785
  ]);
9676
9786
  const issue = record$1(source.issue);
9677
9787
  const nodeId = issue.nodeId;
9678
- exact(issue, [
9788
+ requiredFields(issue, [
9679
9789
  "code",
9680
9790
  "message",
9681
9791
  ...nodeId == null ? [] : ["nodeId"]
@@ -9916,43 +10026,48 @@ var metadata = {
9916
10026
  var binding = unknown().transform(triggerBinding);
9917
10027
  var provider = {
9918
10028
  provider: string$1().min(1),
9919
- inputs: record$3(string$1(), discriminatedUnion("kind", [strictObject({
10029
+ inputs: record$3(string$1(), discriminatedUnion("kind", [object({
9920
10030
  kind: literal("value"),
9921
10031
  value: json$4()
9922
- }), strictObject({ kind: literal("unset") })]))
10032
+ }), object({ kind: literal("unset") })]))
9923
10033
  };
9924
10034
  var entrySchema = discriminatedUnion("type", [
9925
- strictObject({
10035
+ object({
10036
+ ...metadata,
10037
+ type: literal("start"),
10038
+ config: authoringConfigurations.start
10039
+ }),
10040
+ object({
9926
10041
  ...metadata,
9927
10042
  type: literal("manual"),
9928
- config: authoringConfigurations.manual
10043
+ config: object({})
9929
10044
  }),
9930
- strictObject({
10045
+ object({
9931
10046
  ...metadata,
9932
10047
  type: literal("webhook"),
9933
10048
  config: authoringConfigurations.webhook,
9934
10049
  binding
9935
10050
  }),
9936
- strictObject({
10051
+ object({
9937
10052
  ...metadata,
9938
10053
  type: literal("cron"),
9939
10054
  config: authoringConfigurations.cron,
9940
10055
  binding
9941
10056
  }),
9942
- strictObject({
10057
+ object({
9943
10058
  ...metadata,
9944
10059
  type: literal("error"),
9945
10060
  config: authoringConfigurations.error,
9946
10061
  binding
9947
10062
  }),
9948
- strictObject({
10063
+ object({
9949
10064
  ...metadata,
9950
10065
  ...provider,
9951
10066
  type: literal("poll"),
9952
10067
  config: authoringConfigurations.poll,
9953
10068
  binding
9954
10069
  }),
9955
- strictObject({
10070
+ object({
9956
10071
  ...metadata,
9957
10072
  ...provider,
9958
10073
  type: literal("integration"),
@@ -9965,9 +10080,10 @@ function decodeLiveDetails(value) {
9965
10080
  const flowId = string(source.flowId);
9966
10081
  if (source.version != 1 || !Array.isArray(source.entries)) return invalidResponse();
9967
10082
  if (source.publication === null) {
9968
- if (source.status != "not-published" || source.entries.length != 0 || Object.hasOwn(source, "enabled")) return invalidResponse();
10083
+ if (source.inputDefs !== null || source.status != "not-published" || source.entries.length != 0 || Object.hasOwn(source, "enabled")) return invalidResponse();
9969
10084
  return {
9970
10085
  flowId,
10086
+ inputDefs: null,
9971
10087
  publication: null,
9972
10088
  status: "not-published",
9973
10089
  entries: [],
@@ -9979,8 +10095,11 @@ function decodeLiveDetails(value) {
9979
10095
  if (current.flowId != flowId || typeof source.enabled != "boolean") return invalidResponse();
9980
10096
  if (status != "runnable" && status != "suspended") return invalidResponse();
9981
10097
  if (!source.enabled && source.status == "runnable") return invalidResponse();
10098
+ const inputDefs = flowInputFieldsView.safeParse(source.inputDefs);
10099
+ if (!inputDefs.success) return invalidResponse();
9982
10100
  return {
9983
10101
  flowId,
10102
+ inputDefs: inputDefs.data,
9984
10103
  publication: current,
9985
10104
  status,
9986
10105
  enabled: source.enabled,
@@ -9996,7 +10115,7 @@ function decodeEntries(values, current) {
9996
10115
  for (const entry of parsed.data) {
9997
10116
  if (ids.has(entry.nodeId)) return invalidResponse();
9998
10117
  ids.add(entry.nodeId);
9999
- if (entry.type != "manual" && (entry.binding.flowId != current.flowId || entry.binding.triggerNodeId != entry.nodeId || entry.binding.kind != entry.type || entry.binding.currentPublicationId != current.publicationId || entry.binding.currentRevisionId != current.revisionId)) return invalidResponse();
10118
+ if (entry.type != "start" && entry.type != "manual" && (entry.binding.flowId != current.flowId || entry.binding.triggerNodeId != entry.nodeId || entry.binding.kind != entry.type || entry.binding.currentPublicationId != current.publicationId || entry.binding.currentRevisionId != current.revisionId)) return invalidResponse();
10000
10119
  if (entry.type == "webhook" && (!entry.binding.endpointUrl || !webhookSupportsBody(entry.config.method) && Object.keys(entry.config.body).length > 0)) return invalidResponse();
10001
10120
  }
10002
10121
  return parsed.data;
@@ -10309,7 +10428,7 @@ function connectorAccessCandidatesBatch(value, providerIds) {
10309
10428
  }
10310
10429
  function connection(value) {
10311
10430
  const source = record$1(value);
10312
- exact(source, [
10431
+ requiredFields(source, [
10313
10432
  ...Object.hasOwn(source, "providerAccountId") ? ["providerAccountId"] : [],
10314
10433
  ...Object.hasOwn(source, "alias") ? ["alias"] : [],
10315
10434
  ...Object.hasOwn(source, "builtInAccount") ? ["builtInAccount"] : [],
@@ -10338,7 +10457,7 @@ function port(value, input = false) {
10338
10457
  const source = record$1(value);
10339
10458
  const description = source.description;
10340
10459
  const hasValue = input && Object.hasOwn(source, "value");
10341
- exact(source, [
10460
+ requiredFields(source, [
10342
10461
  "jsonSchema",
10343
10462
  "nullable",
10344
10463
  ...description == null ? [] : ["description"],
@@ -10363,7 +10482,7 @@ function connectorActionMetadata(value) {
10363
10482
  const source = record$1(value);
10364
10483
  const homepageUrl = source.homepageUrl;
10365
10484
  const icon = source.icon;
10366
- exact(source, [
10485
+ requiredFields(source, [
10367
10486
  "actionId",
10368
10487
  ...Object.hasOwn(source, "operationType") ? ["operationType"] : [],
10369
10488
  ...Object.hasOwn(source, "inputSchema") ? ["inputSchema"] : [],
@@ -10414,7 +10533,7 @@ function connectorProvider(value) {
10414
10533
  const homepageUrl = source.homepageUrl;
10415
10534
  const icon = source.icon;
10416
10535
  if (source.noSetup !== void 0 && typeof source.noSetup != "boolean") return invalidResponse();
10417
- exact(source, [
10536
+ requiredFields(source, [
10418
10537
  ...Object.hasOwn(source, "noSetup") ? ["noSetup"] : [],
10419
10538
  "serviceId",
10420
10539
  "serviceName",
@@ -10438,7 +10557,7 @@ function connectorProvider(value) {
10438
10557
  var id = string$1().min(1).max(256);
10439
10558
  var eventType = string$1().regex(/^[a-z][a-z0-9_.]{0,127}$/);
10440
10559
  var name = string$1().trim().min(1).max(128);
10441
- var eventSourceSchema = strictObject({
10560
+ var eventSourceSchema = object({
10442
10561
  version: literal(1),
10443
10562
  sourceId: id,
10444
10563
  revision: int().positive(),
@@ -10456,7 +10575,7 @@ var eventSourceSchema = strictObject({
10456
10575
  verifiedAt: string$1().nullable(),
10457
10576
  lastReceivedAt: string$1().nullable(),
10458
10577
  updatedAt: string$1(),
10459
- consumers: array(strictObject({
10578
+ consumers: array(object({
10460
10579
  flowId: id,
10461
10580
  flowName: string$1(),
10462
10581
  triggerNodeId: id
@@ -10466,7 +10585,7 @@ function decodeEventSource(value) {
10466
10585
  return eventSourceSchema.parse(value);
10467
10586
  }
10468
10587
  function decodeEventSources(value) {
10469
- return strictObject({
10588
+ return object({
10470
10589
  version: literal(1),
10471
10590
  sources: array(eventSourceSchema),
10472
10591
  teamId: id.nullable().optional()
@@ -10488,7 +10607,7 @@ function isUiLanguage(value) {
10488
10607
  //#region src/control/common/triggerCatalog.ts
10489
10608
  function decodeTriggerCatalog(value) {
10490
10609
  const source = record$1(value);
10491
- exact(source, [
10610
+ requiredFields(source, [
10492
10611
  "version",
10493
10612
  "locale",
10494
10613
  "definitions",
@@ -10502,7 +10621,7 @@ function decodeTriggerCatalog(value) {
10502
10621
  const display = Object.fromEntries(definitions.map((definition) => {
10503
10622
  const { key } = definition;
10504
10623
  const copy = record$1(entries[key]);
10505
- exact(copy, [
10624
+ requiredFields(copy, [
10506
10625
  "configInputs",
10507
10626
  "configInputLabels",
10508
10627
  "displayName",
@@ -10546,7 +10665,7 @@ strictObject({
10546
10665
  //#endregion
10547
10666
  //#region src/control/common/results.ts
10548
10667
  var json$1 = json$4();
10549
- var entry = strictObject({
10668
+ var entry = object({
10550
10669
  pointer: string$1(),
10551
10670
  type: _enum([
10552
10671
  "object",
@@ -10565,25 +10684,25 @@ var page = entry.extend({
10565
10684
  nextOffset: number().int().positive().optional(),
10566
10685
  entries: array(entry).optional()
10567
10686
  });
10568
- var result = strictObject({
10687
+ var result = object({
10569
10688
  resultId: string$1().min(1),
10570
10689
  callId: string$1().min(1),
10571
10690
  toolId: string$1().min(1),
10572
- source: discriminatedUnion("kind", [strictObject({
10691
+ source: discriminatedUnion("kind", [object({
10573
10692
  kind: literal("connector"),
10574
10693
  action: string$1().min(1)
10575
- }), strictObject({ kind: literal("code") })]),
10694
+ }), object({ kind: literal("code") })]),
10576
10695
  bytes: number().int().nonnegative(),
10577
10696
  digest: string$1().regex(/^[a-f0-9]{64}$/),
10578
10697
  createdAt: string$1().datetime()
10579
10698
  });
10580
- var listSchema = strictObject({
10699
+ var listSchema = object({
10581
10700
  version: literal(1),
10582
10701
  runId: string$1(),
10583
10702
  results: array(result),
10584
10703
  nextAfter: string$1().optional()
10585
10704
  });
10586
- var readSchema = strictObject({
10705
+ var readSchema = object({
10587
10706
  version: literal(1),
10588
10707
  runId: string$1(),
10589
10708
  result,
@@ -10660,7 +10779,7 @@ function connectorProvidersQuery(flowId, locale) {
10660
10779
  path: `/v1/connector/providers${parameters ? `?${parameters}` : ""}`,
10661
10780
  decode: (value) => {
10662
10781
  const source = record$1(value);
10663
- exact(source, ["providers", "version"]);
10782
+ requiredFields(source, ["providers", "version"]);
10664
10783
  if (source.version != 1 || !Array.isArray(source.providers)) return invalidResponse();
10665
10784
  return source.providers.map(connectorProvider);
10666
10785
  }
@@ -10675,7 +10794,7 @@ function connectorActionQuery(actionId, flowId, locale) {
10675
10794
  path: `/v1/connector/actions/${encodeURIComponent(actionId)}${parameters ? `?${parameters}` : ""}`,
10676
10795
  decode: (value) => {
10677
10796
  const source = record$1(value);
10678
- exact(source, ["action", "version"]);
10797
+ requiredFields(source, ["action", "version"]);
10679
10798
  if (source.version != 1) return invalidResponse();
10680
10799
  return connectorAction(source.action);
10681
10800
  }
@@ -10686,7 +10805,7 @@ function allConnectorConnectionsQuery(flowId) {
10686
10805
  path: `/v1/connector/connections${scope(flowId)}`,
10687
10806
  decode: (value) => {
10688
10807
  const source = record$1(value);
10689
- exact(source, ["connections", "version"]);
10808
+ requiredFields(source, ["connections", "version"]);
10690
10809
  if (source.version != 1 || !Array.isArray(source.connections)) return invalidResponse();
10691
10810
  return source.connections.map(connection);
10692
10811
  }
@@ -10697,7 +10816,7 @@ function connectorConnectionsQuery(serviceId, flowId) {
10697
10816
  path: `/v1/connector/connections/${encodeURIComponent(serviceId)}${scope(flowId)}`,
10698
10817
  decode: (value) => {
10699
10818
  const source = record$1(value);
10700
- exact(source, [
10819
+ requiredFields(source, [
10701
10820
  "connections",
10702
10821
  "serviceId",
10703
10822
  "version"
@@ -10722,6 +10841,7 @@ function resourceReferences(input) {
10722
10841
  if (accessRevision < 0) return invalidResponse();
10723
10842
  return {
10724
10843
  draft: draft == null ? null : {
10844
+ ...draft.calledFlowIds === void 0 ? {} : { calledFlowIds: strings(draft.calledFlowIds) },
10725
10845
  variableNames: strings(draft.variableNames),
10726
10846
  errorSourceFlowIds: strings(draft.errorSourceFlowIds),
10727
10847
  connections: draft.connections.map((value) => {
@@ -10752,10 +10872,11 @@ function flow(value) {
10752
10872
  if (source.version != 1) return invalidResponse();
10753
10873
  if (status != "active" && status != "retiring") return invalidResponse();
10754
10874
  const target = source.live == null ? void 0 : record$1(source.live);
10755
- if (target != null && typeof target.enabled != "boolean") return invalidResponse();
10875
+ if (target != null && (typeof target.enabled != "boolean" || typeof target.hasStart != "boolean")) return invalidResponse();
10756
10876
  return {
10757
10877
  ...target == null ? {} : { live: {
10758
10878
  enabled: target.enabled,
10879
+ hasStart: target.hasStart,
10759
10880
  publicationId: string(target.publicationId),
10760
10881
  revisionId: string(target.revisionId)
10761
10882
  } },
@@ -10786,7 +10907,7 @@ function flowPage(value) {
10786
10907
  }
10787
10908
  function variable(value) {
10788
10909
  const source = record$1(value);
10789
- exact(source, [
10910
+ requiredFields(source, [
10790
10911
  "name",
10791
10912
  "updatedAt",
10792
10913
  "value",
@@ -10806,6 +10927,15 @@ function variable(value) {
10806
10927
  version: 1
10807
10928
  };
10808
10929
  }
10930
+ function variableListItem(value) {
10931
+ const { referenceCount, ...fields } = record$1(value);
10932
+ const count = integer(referenceCount);
10933
+ if (count < 0) return invalidResponse();
10934
+ return {
10935
+ ...variable(fields),
10936
+ referenceCount: count
10937
+ };
10938
+ }
10809
10939
  function errorListener(value) {
10810
10940
  const source = record$1(value);
10811
10941
  if (typeof source.enabled != "boolean") return invalidResponse();
@@ -10819,17 +10949,13 @@ function errorListener(value) {
10819
10949
  }
10820
10950
  function variableReferences(input) {
10821
10951
  const source = record$1(input);
10822
- exact(source, [
10823
- "version",
10824
- "references",
10825
- "unknown"
10826
- ]);
10827
- if (source.version != 1 || !Array.isArray(source.references) || !Array.isArray(source.unknown)) return invalidResponse();
10952
+ requiredFields(source, ["version", "references"]);
10953
+ if (source.version != 1 || !Array.isArray(source.references)) return invalidResponse();
10828
10954
  return {
10829
10955
  version: 1,
10830
10956
  references: source.references.map((value) => {
10831
10957
  const item = record$1(value);
10832
- exact(item, [
10958
+ requiredFields(item, [
10833
10959
  "flowId",
10834
10960
  "flowName",
10835
10961
  "draft",
@@ -10838,7 +10964,7 @@ function variableReferences(input) {
10838
10964
  if (typeof item.draft != "boolean") return invalidResponse();
10839
10965
  const live = item.live === null ? null : record$1(item.live);
10840
10966
  if (live != null) {
10841
- exact(live, ["publicationId", "enabled"]);
10967
+ requiredFields(live, ["publicationId", "enabled"]);
10842
10968
  if (typeof live.enabled != "boolean") return invalidResponse();
10843
10969
  }
10844
10970
  return {
@@ -10850,20 +10976,6 @@ function variableReferences(input) {
10850
10976
  enabled: live.enabled
10851
10977
  }
10852
10978
  };
10853
- }),
10854
- unknown: source.unknown.map((value) => {
10855
- const item = record$1(value);
10856
- exact(item, [
10857
- "flowId",
10858
- "flowName",
10859
- "scope"
10860
- ]);
10861
- if (item.scope !== "draft" && item.scope !== "live") return invalidResponse();
10862
- return {
10863
- flowId: string(item.flowId),
10864
- flowName: string(item.flowName),
10865
- scope: item.scope
10866
- };
10867
10979
  })
10868
10980
  };
10869
10981
  }
@@ -10961,7 +11073,7 @@ function run(value) {
10961
11073
  }
10962
11074
  function runWaiting(value) {
10963
11075
  const source = record$1(value);
10964
- exact(source, [
11076
+ requiredFields(source, [
10965
11077
  "actions",
10966
11078
  "expiresAt",
10967
11079
  "nodeId",
@@ -10980,6 +11092,15 @@ function runWaiting(value) {
10980
11092
  waitingSince: string(source.waitingSince)
10981
11093
  };
10982
11094
  }
11095
+ function workflowIdentity(value) {
11096
+ const ref = record$1(value);
11097
+ return {
11098
+ flowId: string(ref.flowId),
11099
+ runId: string(ref.runId),
11100
+ nodeId: string(ref.nodeId),
11101
+ executionId: string(ref.executionId)
11102
+ };
11103
+ }
10983
11104
  function runDetails(value) {
10984
11105
  const source = record$1(value);
10985
11106
  const summary = run(source);
@@ -10987,20 +11108,24 @@ function runDetails(value) {
10987
11108
  if (eventsExpiresAt != null && typeof eventsExpiresAt != "string") return invalidResponse();
10988
11109
  if (source.waiting !== void 0 || !Array.isArray(source.waits)) return invalidResponse();
10989
11110
  const waits = source.waits.map(runWaiting);
10990
- if (new Set(waits.map((wait) => wait.waitId)).size != waits.length || summary.status == "waiting" && waits.length == 0 || [
11111
+ if (new Set(waits.map((wait) => wait.waitId)).size != waits.length || summary.status == "waiting" && waits.length == 0 && (!Array.isArray(source.calls) || source.calls.length == 0) || [
10991
11112
  "completed",
10992
11113
  "failed",
10993
11114
  "canceled",
10994
11115
  "indeterminate"
10995
11116
  ].includes(summary.status) && waits.length > 0) return invalidResponse();
10996
- if (source.occurrenceId === void 0 != (source.triggerNodeId === void 0)) return invalidResponse();
11117
+ if (source.occurrenceId !== void 0 && source.triggerNodeId === void 0) return invalidResponse();
10997
11118
  const state = {
10998
11119
  status: summary.status,
10999
11120
  waits
11000
11121
  };
11122
+ if (source.calls !== void 0 && !Array.isArray(source.calls)) return invalidResponse();
11001
11123
  const details = {
11002
11124
  ...summary,
11003
11125
  ...errorHandling(source),
11126
+ ...source.triggerNodeId === void 0 ? {} : { triggerNodeId: string(source.triggerNodeId) },
11127
+ ...source.caller === void 0 ? {} : { caller: workflowIdentity(source.caller) },
11128
+ ...source.calls === void 0 ? {} : { calls: source.calls.map((item) => Object.assign(workflowIdentity(item), { status: record$1(item).status === null ? null : runStatus(record$1(item).status) })) },
11004
11129
  closureDigest: string(source.closureDigest),
11005
11130
  engineContract: string(source.engineContract),
11006
11131
  engineDigest: string(source.engineDigest),
@@ -11051,7 +11176,7 @@ function runCancellation(value) {
11051
11176
  }
11052
11177
  function waitResolution(value) {
11053
11178
  const source = record$1(value);
11054
- exact(source, [
11179
+ requiredFields(source, [
11055
11180
  "action",
11056
11181
  "comment",
11057
11182
  "resolutionAccepted",
@@ -11268,7 +11393,7 @@ function decodeRunEvent(value) {
11268
11393
  switch (kind) {
11269
11394
  case "node.started": {
11270
11395
  const nodeKind = payload.nodeKind;
11271
- if (nodeKind !== void 0 && nodeKind !== "approval" && nodeKind !== "condition" && nodeKind !== "connector" && nodeKind !== "javascript" && nodeKind !== "decision" && nodeKind !== "openapi" && nodeKind !== "llm" && nodeKind !== "agent" && nodeKind !== "value" && nodeKind !== "wait") return invalidResponse();
11396
+ if (nodeKind !== void 0 && nodeKind !== "approval" && nodeKind !== "condition" && nodeKind !== "connector" && nodeKind !== "javascript" && nodeKind !== "decision" && nodeKind !== "openapi" && nodeKind !== "llm" && nodeKind !== "agent" && nodeKind !== "value" && nodeKind !== "outputs" && nodeKind !== "workflow" && nodeKind !== "wait") return invalidResponse();
11272
11397
  return {
11273
11398
  ...base,
11274
11399
  kind,
@@ -11395,14 +11520,14 @@ var ControlClient = class {
11395
11520
  if (options.limit != null) parameters.set("limit", String(options.limit));
11396
11521
  if (options.includeTotal != null) parameters.set("includeTotal", String(options.includeTotal));
11397
11522
  const query = parameters.size == 0 ? "" : `?${parameters}`;
11398
- return flowPage(await this.request(`/v1/flows${query}`));
11523
+ return flowPage(await this.request(`/v1/flows${query}`, options.signal == null ? void 0 : { signal: options.signal }));
11399
11524
  }
11400
11525
  async listEventSources(flowId, signal) {
11401
11526
  return decodeEventSources(await this.request("/v1/event-sources" + (flowId == null ? "" : `?flowId=${segment(flowId)}`), { signal }));
11402
11527
  }
11403
11528
  async listEventSourceConnections(teamId, signal) {
11404
11529
  const source = record$1(await this.request(`/v1/event-sources/connections${teamId == null ? "" : `?teamId=${segment(teamId)}`}`, { signal }));
11405
- exact(source, ["version", "connections"]);
11530
+ requiredFields(source, ["version", "connections"]);
11406
11531
  if (source.version != 1 || !Array.isArray(source.connections)) return invalidResponse();
11407
11532
  return source.connections.map(connection);
11408
11533
  }
@@ -11429,13 +11554,24 @@ var ControlClient = class {
11429
11554
  }
11430
11555
  async listVariables() {
11431
11556
  const source = record$1(await this.request("/v1/variables"));
11432
- exact(source, ["variables", "version"]);
11557
+ requiredFields(source, ["variables", "version"]);
11433
11558
  if (source.version != 1 || !Array.isArray(source.variables)) return invalidResponse();
11434
11559
  return {
11435
- variables: source.variables.map(variable),
11560
+ variables: source.variables.map(variableListItem),
11436
11561
  version: 1
11437
11562
  };
11438
11563
  }
11564
+ async getFlowReferences(flowId, options = {}) {
11565
+ const query = new URLSearchParams({
11566
+ direction: options.direction ?? "incoming",
11567
+ offset: String(options.offset ?? 0),
11568
+ limit: String(options.limit ?? 50)
11569
+ });
11570
+ return workflowReferencesSchema.parse(await this.request(`/v1/flows/${segment(flowId)}/references?${query}`, { signal: options.signal }));
11571
+ }
11572
+ async getWorkflowContract(flowId, signal) {
11573
+ return workflowContractSchema.parse(await this.request(`/v1/flows/${segment(flowId)}/call-contract`, { signal }));
11574
+ }
11439
11575
  async getVariableReferences(name, signal) {
11440
11576
  return variableReferences(await this.request(`/v1/variables/${segment(name)}/references`, { signal }));
11441
11577
  }
@@ -11450,7 +11586,7 @@ var ControlClient = class {
11450
11586
  }
11451
11587
  async deleteVariable(name) {
11452
11588
  const source = record$1(await this.request(`/v1/variables/${segment(name)}`, { method: "DELETE" }));
11453
- exact(source, ["version"]);
11589
+ requiredFields(source, ["version"]);
11454
11590
  if (source.version != 1) return invalidResponse();
11455
11591
  }
11456
11592
  async exportFlow(flowId) {
@@ -11492,7 +11628,7 @@ var ControlClient = class {
11492
11628
  command
11493
11629
  })
11494
11630
  }));
11495
- exact(source, [
11631
+ requiredFields(source, [
11496
11632
  "version",
11497
11633
  "flowId",
11498
11634
  "broadcast"
@@ -11632,11 +11768,11 @@ var ControlClient = class {
11632
11768
  }
11633
11769
  async listTriggerConfigOptions(flowId, nodeId, field, signal) {
11634
11770
  const source = record$1(await this.request(`/v1/flows/${segment(flowId)}/triggers/${segment(nodeId)}/options/${segment(field)}`, { signal }));
11635
- exact(source, ["options", "version"]);
11771
+ requiredFields(source, ["options", "version"]);
11636
11772
  if (source.version != 1 || !Array.isArray(source.options) || source.options.length > 1e3) return invalidResponse();
11637
11773
  return source.options.map((value) => {
11638
11774
  const item = record$1(value);
11639
- exact(item, [
11775
+ requiredFields(item, [
11640
11776
  "value",
11641
11777
  "label",
11642
11778
  ...item.color == null ? [] : ["color"]
@@ -11655,7 +11791,7 @@ var ControlClient = class {
11655
11791
  }
11656
11792
  async listConnectorTeams(signal) {
11657
11793
  const source = record$1(await this.request("/v1/connector/teams", { signal }));
11658
- exact(source, [
11794
+ requiredFields(source, [
11659
11795
  "enabled",
11660
11796
  "teams",
11661
11797
  "version"
@@ -11665,7 +11801,7 @@ var ControlClient = class {
11665
11801
  enabled: source.enabled,
11666
11802
  teams: source.teams.map((value) => {
11667
11803
  const team = record$1(value);
11668
- exact(team, [
11804
+ requiredFields(team, [
11669
11805
  "id",
11670
11806
  "name",
11671
11807
  "systemCreated"
@@ -11778,7 +11914,7 @@ var ControlClient = class {
11778
11914
  body: JSON.stringify({ version: 1 }),
11779
11915
  method: "POST"
11780
11916
  }));
11781
- exact(source, ["url", "version"]);
11917
+ requiredFields(source, ["url", "version"]);
11782
11918
  if (source.version != 1) return invalidResponse();
11783
11919
  try {
11784
11920
  const url = new URL(string(source.url));
@@ -11840,6 +11976,16 @@ var ControlClient = class {
11840
11976
  method: "POST"
11841
11977
  }));
11842
11978
  }
11979
+ async upgradeDraft(flowId, expectedRevisionId, options = {}) {
11980
+ return draftChange(await this.request(`/v1/flows/${segment(flowId)}/draft/upgrade`, {
11981
+ body: JSON.stringify({
11982
+ expectedRevisionId,
11983
+ version: 1
11984
+ }),
11985
+ headers: { "idempotency-key": options.idempotencyKey ?? operationKey("upgrade") },
11986
+ method: "POST"
11987
+ }));
11988
+ }
11843
11989
  async checkFlow(flowId, revisionId) {
11844
11990
  return flowCheck(await this.request(`/v1/flows/${segment(flowId)}/revisions/${segment(revisionId)}/check`, {
11845
11991
  body: JSON.stringify({
@@ -11982,7 +12128,7 @@ var ControlClient = class {
11982
12128
  const suffix = query == "" ? "" : `?${query}`;
11983
12129
  return this.connectorRequest(`/v1/connector/actions${suffix}`, "actions", signal, (value) => {
11984
12130
  const source = record$1(value);
11985
- exact(source, ["actions", "version"]);
12131
+ requiredFields(source, ["actions", "version"]);
11986
12132
  if (source.version != 1 || !Array.isArray(source.actions)) return invalidResponse();
11987
12133
  return source.actions.map(connectorAction);
11988
12134
  });
@@ -12119,15 +12265,16 @@ function addValueNode(harness, flowId, revisionId, nodeId = "marker", changeId)
12119
12265
  nodeId
12120
12266
  }], changeId);
12121
12267
  }
12122
- async function addManualTrigger(harness, flowId, revisionId) {
12268
+ async function addStartTrigger(harness, flowId, revisionId) {
12123
12269
  return changedRevisionId(await json(await changeRequest(harness, flowId, revisionId, [{
12124
12270
  kind: "graph.node.create",
12125
12271
  node: {
12126
- kind: "manual",
12272
+ inputDefs: [],
12273
+ kind: "start",
12127
12274
  name: "Start"
12128
12275
  },
12129
12276
  nodeId: "start"
12130
- }]), 200, "Add manual trigger"), "Manual trigger Revision");
12277
+ }]), 200, "Add Start node"), "Start Revision");
12131
12278
  }
12132
12279
  function changedRevisionId(change, message) {
12133
12280
  return requiredString(record(change.revision, `${message} revision`).revisionId, `${message} revisionId`);
@@ -12216,7 +12363,10 @@ var controlApiConformanceCases = [
12216
12363
  const idempotencyKey = crypto.randomUUID();
12217
12364
  const created = await api.importFlow(file, { idempotencyKey });
12218
12365
  equal(dequal(await api.importFlow(file, { idempotencyKey }), created), true, "Import retry must return the same Flow.");
12219
- equal(dequal(await api.exportFlow(created.flowId), file), true, "Export must retain the graph and Presentation.");
12366
+ equal(dequal(await api.exportFlow(created.flowId), {
12367
+ ...file,
12368
+ content: upgradeRevisionContent(file.content)
12369
+ }), true, "Export must upgrade legacy Manual nodes and retain the graph and Presentation.");
12220
12370
  const editor = await api.getEditor(created.flowId);
12221
12371
  equal(editor.live.publication == null, true, "Import must not publish.");
12222
12372
  equal(editor.draft.parentRevisionId == null, true, "Import must create an initial Revision.");
@@ -12323,12 +12473,107 @@ var controlApiConformanceCases = [
12323
12473
  equal((await api.checkAuthoring(flow.flowId, changed.revision)).revisionId, changed.revision, "Fixed check identity");
12324
12474
  }
12325
12475
  },
12476
+ {
12477
+ name: "authors Start parameters and admits their shared call contract",
12478
+ async verify(harness) {
12479
+ const api = client(harness), flow = await api.createFlow("Start parameters");
12480
+ equal((await api.authoringSchema(flow.flowId, { type: "start" })).type, "start", "Start discovery");
12481
+ const created = await api.editAuthoring(flow.flowId, {
12482
+ baseRevision: flow.draftRevisionId,
12483
+ requestId: "start-parameters-create",
12484
+ edits: [{
12485
+ op: "node.add",
12486
+ as: "start",
12487
+ type: "start",
12488
+ name: "Start",
12489
+ config: { inputDefs: {
12490
+ message: {
12491
+ schema: { type: "string" },
12492
+ nullable: false,
12493
+ description: "Original"
12494
+ },
12495
+ note: {
12496
+ schema: { type: "string" },
12497
+ nullable: true
12498
+ }
12499
+ } }
12500
+ }]
12501
+ });
12502
+ const nodeId = created.nodes.start;
12503
+ const changed = await api.editAuthoring(flow.flowId, {
12504
+ baseRevision: created.revision,
12505
+ requestId: "start-parameters-update",
12506
+ edits: [{
12507
+ op: "node.update",
12508
+ node: nodeId,
12509
+ set: { config: { inputDefs: { message: { description: "Call message" } } } }
12510
+ }]
12511
+ });
12512
+ equal(((await api.readAuthoring(flow.flowId, { nodes: [nodeId] })).data.nodes?.[0]?.config)?.inputDefs, {
12513
+ message: {
12514
+ schema: { type: "string" },
12515
+ nullable: false,
12516
+ description: "Call message"
12517
+ },
12518
+ note: {
12519
+ schema: { type: "string" },
12520
+ nullable: true
12521
+ }
12522
+ }, "Local parameter update preserves the contract");
12523
+ const runPath = `/v1/flows/${flow.flowId}/revisions/${changed.revision}/runs`;
12524
+ const run = (outputs, key) => request(harness, runPath, {
12525
+ method: "POST",
12526
+ headers: { "idempotency-key": key },
12527
+ body: JSON.stringify({
12528
+ engineContract,
12529
+ inputs: {},
12530
+ trigger: {
12531
+ nodeId,
12532
+ outputs
12533
+ },
12534
+ version: 2
12535
+ })
12536
+ });
12537
+ for (const [index, outputs] of [
12538
+ {},
12539
+ { message: 0 },
12540
+ {
12541
+ message: "Hello",
12542
+ extra: true
12543
+ }
12544
+ ].entries()) await error(await run(outputs, `start-invalid-${index}`), 400, "run.invalid", "Reject invalid Start parameters");
12545
+ const admitted = await json(await run({ message: "Hello" }, "start-call"), 202, "Admit omitted nullable parameter");
12546
+ equal(await json(await run({ message: "Hello" }, "start-call"), 200, "Replay Start call"), admitted, "Stable Start admission");
12547
+ await error(await run({
12548
+ message: "Hello",
12549
+ note: null
12550
+ }, "start-call"), 409, "run.conflict", "Preserve original request identity before normalization");
12551
+ await json(await run({
12552
+ message: "Hello",
12553
+ note: null
12554
+ }, "start-explicit-null"), 202, "Admit explicit null");
12555
+ equal(((await api.readAuthoring(flow.flowId, {
12556
+ revision: created.revision,
12557
+ nodes: [nodeId]
12558
+ })).data.nodes?.[0]?.config)?.inputDefs, {
12559
+ message: {
12560
+ schema: { type: "string" },
12561
+ nullable: false,
12562
+ description: "Original"
12563
+ },
12564
+ note: {
12565
+ schema: { type: "string" },
12566
+ nullable: true
12567
+ }
12568
+ }, "Fixed Start read preserves old configuration");
12569
+ }
12570
+ },
12326
12571
  {
12327
12572
  name: "admits simultaneous retries as one Run and preserves its Trigger identity",
12328
12573
  async verify(harness) {
12329
12574
  const flow = await createFlow(harness, "Concurrent Run", "concurrent-run-flow");
12330
12575
  const flowId = requiredString(flow.flowId, "Flow ID");
12331
- const revisionId = await addManualTrigger(harness, flowId, requiredString(flow.draftRevisionId, "Revision ID"));
12576
+ const revisionId = await addStartTrigger(harness, flowId, requiredString(flow.draftRevisionId, "Revision ID"));
12332
12577
  const submit = (payload = {}) => request(harness, `/v1/flows/${flowId}/revisions/${revisionId}/runs`, {
12333
12578
  method: "POST",
12334
12579
  headers: { "idempotency-key": "concurrent-run" },
@@ -12458,6 +12703,7 @@ var controlApiConformanceCases = [
12458
12703
  equal(created.name, "Control flow", "Created Flow name");
12459
12704
  equal(created.status, "active", "Created Flow status");
12460
12705
  equal(record(created.resourceReferences, "Flow resource references").draft, {
12706
+ calledFlowIds: [],
12461
12707
  variableNames: [],
12462
12708
  connections: [],
12463
12709
  errorSourceFlowIds: []
@@ -12629,7 +12875,7 @@ var controlApiConformanceCases = [
12629
12875
  async verify(harness) {
12630
12876
  const flow = await createFlow(harness, "Partial Draft", "partial-draft");
12631
12877
  const flowId = requiredString(flow.flowId, "Partial Flow identity");
12632
- const revisionId = changedRevisionId(await json(await changeRequest(harness, flowId, await addManualTrigger(harness, flowId, requiredString(flow.draftRevisionId, "Partial Draft identity")), [
12878
+ const revisionId = changedRevisionId(await json(await changeRequest(harness, flowId, await addStartTrigger(harness, flowId, requiredString(flow.draftRevisionId, "Partial Draft identity")), [
12633
12879
  {
12634
12880
  kind: "graph.node.create",
12635
12881
  nodeId: "other",
@@ -12699,7 +12945,7 @@ var controlApiConformanceCases = [
12699
12945
  async verify(harness) {
12700
12946
  const flow = await createFlow(harness, "Run flow", "run-flow");
12701
12947
  const flowId = requiredString(flow.flowId, "Run Flow flowId");
12702
- const draftRevisionId = await addManualTrigger(harness, flowId, requiredString(flow.draftRevisionId, "Run Flow revisionId"));
12948
+ const draftRevisionId = await addStartTrigger(harness, flowId, requiredString(flow.draftRevisionId, "Run Flow revisionId"));
12703
12949
  equal((await json(await request(harness, `/v1/flows/${flowId}/revisions/${draftRevisionId}/check`, {
12704
12950
  body: JSON.stringify({
12705
12951
  engineContract,
@@ -12823,7 +13069,7 @@ var controlApiConformanceCases = [
12823
13069
  async verify(harness) {
12824
13070
  const flow = await createFlow(harness, "Wait flow", "wait-flow");
12825
13071
  const flowId = requiredString(flow.flowId, "Wait Flow flowId");
12826
- const runPath = `/v1/flows/${flowId}/revisions/${changedRevisionId(await json(await changeRequest(harness, flowId, await addManualTrigger(harness, flowId, requiredString(flow.draftRevisionId, "Wait Flow revisionId")), [{
13072
+ const runPath = `/v1/flows/${flowId}/revisions/${changedRevisionId(await json(await changeRequest(harness, flowId, await addStartTrigger(harness, flowId, requiredString(flow.draftRevisionId, "Wait Flow revisionId")), [{
12827
13073
  kind: "graph.node.create",
12828
13074
  node: {
12829
13075
  inputDefinitions: [{
@@ -12995,7 +13241,7 @@ var publicationControlApiConformanceCases = [
12995
13241
  async verify(harness) {
12996
13242
  const flow = await createFlow(harness, "Enabled flow", "enabled-flow");
12997
13243
  const flowId = requiredString(flow.flowId, "Flow id");
12998
- const revisionId = await addManualTrigger(harness, flowId, requiredString(flow.draftRevisionId, "Draft id"));
13244
+ const revisionId = await addStartTrigger(harness, flowId, requiredString(flow.draftRevisionId, "Draft id"));
12999
13245
  const change = (enabled, expectedPublicationId) => request(harness, `/v1/flows/${flowId}/enabled`, {
13000
13246
  method: "PUT",
13001
13247
  body: JSON.stringify({
@@ -13009,6 +13255,7 @@ var publicationControlApiConformanceCases = [
13009
13255
  const disabled = await json(await change(false, publicationId), 200, "Disable");
13010
13256
  equal(disabled.live, {
13011
13257
  enabled: false,
13258
+ hasStart: true,
13012
13259
  publicationId,
13013
13260
  revisionId
13014
13261
  }, "Disabled summary");
@@ -13040,7 +13287,7 @@ var publicationControlApiConformanceCases = [
13040
13287
  async verify(harness) {
13041
13288
  const flow = await createFlow(harness, "Publication flow", "publication-flow");
13042
13289
  const flowId = requiredString(flow.flowId, "Publication Flow flowId");
13043
- const draftRevisionId = await addManualTrigger(harness, flowId, requiredString(flow.draftRevisionId, "Publication Flow revisionId"));
13290
+ const draftRevisionId = await addStartTrigger(harness, flowId, requiredString(flow.draftRevisionId, "Publication Flow revisionId"));
13044
13291
  equal((await json(await request(harness, `/v1/flows/${flowId}/live`), 200, "Read Live")).status, "not-published", "Initial Live status");
13045
13292
  const publish = () => publishRequest(harness, flowId, draftRevisionId, null, "publication-first");
13046
13293
  const completed = await completePublish(harness, await publish(), 202, "Publish Flow");
@@ -13073,7 +13320,7 @@ var publicationControlApiConformanceCases = [
13073
13320
  async verify(harness) {
13074
13321
  const flow = await createFlow(harness, "Rollback flow", "rollback-flow");
13075
13322
  const flowId = requiredString(flow.flowId, "Rollback Flow flowId");
13076
- const firstRevisionId = await addManualTrigger(harness, flowId, requiredString(flow.draftRevisionId, "Rollback Flow revisionId"));
13323
+ const firstRevisionId = await addStartTrigger(harness, flowId, requiredString(flow.draftRevisionId, "Rollback Flow revisionId"));
13077
13324
  const layoutApi = client(harness);
13078
13325
  const initialLayout = await layoutApi.getPresentation(flowId);
13079
13326
  const publishedLayout = await json(await request(harness, `/v1/flows/${flowId}/presentation`, {
@@ -13434,7 +13681,7 @@ function selectableConnectorAccessControlApiConformanceCases(fixture) {
13434
13681
  equal(record(binding, "Selected Connector access binding").connectionDisplayName, fixture.connectionDisplayName, "Selected Provider access binding connection display name");
13435
13682
  equal(record(binding, "Selected Connector access binding").permissionGroupName, fixture.permissionGroupName, "Selected Provider access binding permission group name");
13436
13683
  const selectedDigest = requiredString(selected.sharedAccessDigest, "Selected Connector access digest");
13437
- const revisionId = await addManualTrigger(harness, flowId, requiredString(created.draftRevisionId, "Draft Revision ID"));
13684
+ const revisionId = await addStartTrigger(harness, flowId, requiredString(created.draftRevisionId, "Draft Revision ID"));
13438
13685
  equal((await json(await request(harness, `/v1/flows/${flowId}/revisions/${revisionId}/runs`, {
13439
13686
  body: JSON.stringify({
13440
13687
  engineContract,