@oomol-lab/open-flow 0.1.0-beta.80 → 0.1.0-beta.82

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 (52) hide show
  1. package/README.md +35 -0
  2. package/dist/browser/{FlowCanvas-CrsiDHK8.js → FlowCanvas-Dew2fmoT.js} +55 -274
  3. package/dist/browser/{createResourceDialog-CS3u9ga9.js → createResourceDialog-bdOJa5Zk.js} +2 -1
  4. package/dist/browser/{exportPng-BOPfjeEi.js → exportPng-Cjdb6COo.js} +2 -2
  5. package/dist/browser/{flowChanges-pFjPHU5k.js → flowChanges-URBEd4DI.js} +2719 -78
  6. package/dist/browser/{flowWorkspace-CRlqc403.js → flowWorkspace-BlXx-yAn.js} +445 -2699
  7. package/dist/browser/{markdownContent-CAG_CQfH.js → markdownContent-D8G_oNOe.js} +18 -41
  8. package/dist/browser/{markdownContent-frwDfQQU.js → markdownContent-IS8xXDoc.js} +18 -40
  9. package/dist/browser/preview.css +88 -80
  10. package/dist/browser/preview.js +291 -188
  11. package/dist/browser/ui.css +8 -0
  12. package/dist/browser/{dist-CHwj9BhV.js → videoLink-NAWDmBtf.js} +35 -1
  13. package/dist/browser/workbench-contract.d.ts +6 -0
  14. package/dist/browser/workbench.css +259 -251
  15. package/dist/browser/workbench.d.ts +2 -0
  16. package/dist/browser/workbench.js +311 -143
  17. package/dist/browser/{ContentIcon-CMn0c-kl.js → wrapLayout-DZvW9dBs.js} +4397 -4152
  18. package/dist/command/index.js +43 -41
  19. package/dist/common/authoring.d.ts +1 -1
  20. package/dist/common/control-api-conformance.js +306 -2
  21. package/dist/common/control-api.d.ts +20 -0
  22. package/dist/common/control-api.js +306 -4
  23. package/dist/common/control-requests.d.ts +3 -5
  24. package/dist/common/control-requests.js +24 -10
  25. package/dist/common/flow-authoring.js +19 -3
  26. package/dist/common/flow-encoding.d.ts +1 -0
  27. package/dist/common/flow-encoding.js +167 -1
  28. package/dist/common/flow-semantics.js +44 -7
  29. package/dist/common/flow-workflowBundle.d.ts +27 -0
  30. package/dist/common/flow-workflowFile.d.ts +2 -0
  31. package/dist/common/flow-workflowReferences.d.ts +4 -0
  32. package/dist/common/mcp.d.ts +2 -0
  33. package/dist/common/mcp.js +312 -4
  34. package/dist/render/browser/licenses.md +4047 -0
  35. package/dist/render/browser/runtime.css +14877 -0
  36. package/dist/render/browser/runtime.js +266765 -0
  37. package/dist/render/common/png.d.ts +24 -0
  38. package/dist/render/node/index.d.ts +11 -0
  39. package/dist/render/node/index.js +9491 -0
  40. package/dist/render/node/licenses.md +75 -0
  41. package/package.json +12 -2
  42. package/src/connector/common/actionContract.ts +26 -0
  43. package/src/control/common/api.ts +50 -0
  44. package/src/control/common/flowDecoders.ts +2 -0
  45. package/src/control/common/mcp.ts +4 -4
  46. package/src/control/common/requests.ts +12 -1
  47. package/src/flow/common/edgeChanges.ts +9 -6
  48. package/src/flow/common/encoding.ts +1 -0
  49. package/src/flow/common/semantics.ts +11 -8
  50. package/src/flow/common/workflowBundle.ts +117 -0
  51. package/src/flow/common/workflowFile.ts +4 -0
  52. package/src/flow/common/workflowReferences.ts +20 -0
@@ -8617,6 +8617,31 @@ function isSchemaKeyword(value) {
8617
8617
  return schemaKeywords.has(value);
8618
8618
  }
8619
8619
  //#endregion
8620
+ //#region src/flow/common/workflowReferences.ts
8621
+ /** Workflow declarations share discovery across authoring, admission and resource indexing. */
8622
+ function nodeWorkflowReferences(node) {
8623
+ if (node.kind != "task") return [];
8624
+ if ("moduleId" in node.task) return (node.task.capabilities ?? []).flatMap((item, index) => item.kind == "workflow" ? [{
8625
+ target: item,
8626
+ path: `task/capabilities/${index}`,
8627
+ tool: item.name
8628
+ }] : []);
8629
+ if (node.task.executor.kind == "workflow") return [{
8630
+ target: {
8631
+ ...node.task.executor,
8632
+ inputs: node.task.inputs.filter((port) => "handle" in port),
8633
+ outputs: node.task.outputs.filter((port) => "handle" in port)
8634
+ },
8635
+ path: "task/executor"
8636
+ }];
8637
+ if (node.task.executor.kind == "agent") return node.task.executor.tools.flatMap((item, index) => item.kind == "workflow" ? [{
8638
+ target: item,
8639
+ path: `task/executor/tools/${index}`,
8640
+ tool: item.name
8641
+ }] : []);
8642
+ return [];
8643
+ }
8644
+ //#endregion
8620
8645
  //#region src/workflow/common/workflow.ts
8621
8646
  var portSchema = object({
8622
8647
  handle: string$1().min(1),
@@ -10547,7 +10572,7 @@ var entrySchema = discriminatedUnion("type", [
10547
10572
  /** Project only the selected published definition and its current bindings. */
10548
10573
  function liveEntries(content, current, bindings) {
10549
10574
  const byNode = new Map(bindings.filter((item) => item.flowId == current.flowId && item.currentPublicationId == current.publicationId && item.currentRevisionId == current.revisionId).map((item) => [item.triggerNodeId, item]));
10550
- return decodeEntries(Object.entries(content.document.graph.nodes).toSorted(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).flatMap(([nodeId, node]) => {
10575
+ return decodeEntries$1(Object.entries(content.document.graph.nodes).toSorted(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).flatMap(([nodeId, node]) => {
10551
10576
  if (node.kind != "start" && node.kind != "manual" && node.kind != "webhook" && node.kind != "cron" && node.kind != "error" && node.kind != "poll" && node.kind != "integration") return [];
10552
10577
  const config = triggerConfiguration(node);
10553
10578
  return [{
@@ -10595,12 +10620,12 @@ function decodeLiveDetails(value) {
10595
10620
  publication: current,
10596
10621
  status,
10597
10622
  enabled: source.enabled,
10598
- entries: decodeEntries(source.entries, current),
10623
+ entries: decodeEntries$1(source.entries, current),
10599
10624
  version: 1
10600
10625
  };
10601
10626
  }
10602
10627
  /** Both producers and consumers enforce the same published-entry invariants. */
10603
- function decodeEntries(values, current) {
10628
+ function decodeEntries$1(values, current) {
10604
10629
  const parsed = array(entrySchema).safeParse(values);
10605
10630
  if (!parsed.success) return invalidResponse();
10606
10631
  const ids = /* @__PURE__ */ new Set();
@@ -10670,17 +10695,134 @@ function conditionInputPorts(node) {
10670
10695
  nullable: operand.kind === "value" ? operand.value === null : true
10671
10696
  }]));
10672
10697
  }
10698
+ function clearConditionBinding(operand) {
10699
+ return operand.kind == "source" && operand.source.kind == "binding" ? { kind: "value" } : operand;
10700
+ }
10701
+ function clearConditionBindings(node) {
10702
+ return {
10703
+ ...node,
10704
+ cases: node.cases.map((item) => ({
10705
+ ...item,
10706
+ groups: item.groups.map((group) => ({
10707
+ ...group,
10708
+ expressions: group.expressions.map((expression) => ({
10709
+ ...expression,
10710
+ left: clearConditionBinding(expression.left),
10711
+ ...expression.right == null ? {} : { right: clearConditionBinding(expression.right) }
10712
+ }))
10713
+ }))
10714
+ }))
10715
+ };
10716
+ }
10673
10717
  //#endregion
10674
10718
  //#region src/flow/common/model.ts
10675
10719
  function portsByHandle(ports) {
10676
10720
  return Object.fromEntries(ports.flatMap((port) => "handle" in port ? [[port.handle, port]] : []));
10677
10721
  }
10678
10722
  //#endregion
10723
+ //#region src/trigger/common/config.ts
10724
+ /** Deployment-bound selections owned by the Trigger configuration contract. */
10725
+ function clearTriggerExternalConfig(key, config) {
10726
+ const fields = key == "jira.on_issue_event" || key == "intercom.on_conversation_event" || key == "sentry.on_issue_alert" || key == "zoom.on_recording_ready" || key == "fireflies.on_meeting_ready" ? ["sourceId", "eventTypes"] : key == "slackbot.on_event" ? [
10727
+ "sourceId",
10728
+ "eventTypes",
10729
+ "channelIds"
10730
+ ] : key == "feishu_app_bot.on_event" ? [
10731
+ "sourceId",
10732
+ "eventTypes",
10733
+ "resource",
10734
+ "chatIds"
10735
+ ] : key == "linear.on_issue_changed" ? ["teamId", "stateIds"] : [];
10736
+ return {
10737
+ ...config,
10738
+ ...Object.fromEntries(fields.map((field) => [field, { kind: "unset" }]))
10739
+ };
10740
+ }
10741
+ //#endregion
10742
+ //#region src/flow/common/connectionUsage.ts
10743
+ function clearNodeConnections(graph, connectionId) {
10744
+ return {
10745
+ ...graph,
10746
+ nodes: Object.fromEntries(Object.entries(graph.nodes).map(([id, node]) => {
10747
+ if ((node.kind == "poll" || node.kind == "integration") && (connectionId == null || node.connectionId == connectionId)) {
10748
+ const { connectionId: _, ...remaining } = node;
10749
+ return [id, remaining];
10750
+ }
10751
+ if (node.kind != "task") return [id, node];
10752
+ if ("executor" in node.task) {
10753
+ const executor = node.task.executor;
10754
+ const clear = (value) => {
10755
+ if (value.connectionId === "") return value;
10756
+ if (connectionId != null && value.connectionId != connectionId) return value;
10757
+ const { connectionId: _, ...rest } = value;
10758
+ return rest;
10759
+ };
10760
+ if (executor.kind == "connector") return [id, {
10761
+ ...node,
10762
+ task: {
10763
+ ...node.task,
10764
+ executor: clear(executor)
10765
+ }
10766
+ }];
10767
+ if (executor.kind == "agent") return [id, {
10768
+ ...node,
10769
+ task: {
10770
+ ...node.task,
10771
+ executor: {
10772
+ ...executor,
10773
+ tools: executor.tools.map(clear),
10774
+ ...executor.notification == null ? {} : { notification: clear(executor.notification) }
10775
+ }
10776
+ }
10777
+ }];
10778
+ return [id, node];
10779
+ }
10780
+ const capabilities = node.task.capabilities?.map((capability) => {
10781
+ if (capability.kind == "workflow" || capability.kind == "http") return capability;
10782
+ if (!("mode" in capability)) {
10783
+ if ("action" in capability) {
10784
+ const { connectionId: selected, ...rest } = capability;
10785
+ return {
10786
+ ...rest,
10787
+ connections: capability.connections.filter((item) => connectionId != null && item.connectionId != connectionId),
10788
+ ...selected != null && connectionId != null && selected != connectionId ? { connectionId: selected } : {}
10789
+ };
10790
+ }
10791
+ return {
10792
+ ...capability,
10793
+ ...connectionId == null && (capability.connectionHints?.length ?? 0) > 0 ? { actionHints: [.../* @__PURE__ */ new Set([...capability.actionHints ?? [], ...capability.connectionHints.map((hint) => hint.action)])] } : {},
10794
+ ...capability.connectionHints == null ? {} : { connectionHints: capability.connectionHints.filter((item) => connectionId != null && item.connectionId != connectionId) }
10795
+ };
10796
+ }
10797
+ if (capability.mode != "independent") return capability;
10798
+ return {
10799
+ ...capability,
10800
+ actions: capability.actions.map((action) => {
10801
+ if (action.connectionId === "") return action;
10802
+ if (connectionId != null && action.connectionId != connectionId) return action;
10803
+ const { connectionId: _, ...remaining } = action;
10804
+ return remaining;
10805
+ })
10806
+ };
10807
+ });
10808
+ return [id, capabilities == null ? node : {
10809
+ ...node,
10810
+ task: {
10811
+ ...node.task,
10812
+ capabilities
10813
+ }
10814
+ }];
10815
+ }))
10816
+ };
10817
+ }
10818
+ //#endregion
10679
10819
  //#region src/flow/common/workflowFile.ts
10680
10820
  var envelope = strictObject({
10681
10821
  kind: literal("open-flow-workflow"),
10682
10822
  version: literal(1),
10683
10823
  name: string$1().optional(),
10824
+ icon: string$1().optional(),
10825
+ description: string$1().optional(),
10684
10826
  content: unknown(),
10685
10827
  presentation: record$2(string$1(), json$3()).optional()
10686
10828
  });
@@ -10693,6 +10835,126 @@ function decodeWorkflowFile(value) {
10693
10835
  content: decodeRevisionContent(file.content)
10694
10836
  };
10695
10837
  }
10838
+ function cleanInput(input) {
10839
+ if (input.kind != "sources" || !input.sources.some((source) => source.kind == "binding")) return input;
10840
+ const sources = input.sources.filter((source) => source.kind != "binding");
10841
+ return sources.length == 0 ? { kind: "unset" } : {
10842
+ kind: "sources",
10843
+ sources
10844
+ };
10845
+ }
10846
+ /** Clear only owned structured references, never strings in code or business values. */
10847
+ function cleanWorkflowFile(value) {
10848
+ const file = decodeWorkflowFile(value);
10849
+ const original = file.content.document.graph;
10850
+ const graph = clearNodeConnections(original);
10851
+ const nodes = Object.fromEntries(Object.entries(graph.nodes).map(([id, source]) => {
10852
+ let node = source;
10853
+ if ("inputs" in node) node = {
10854
+ ...node,
10855
+ inputs: Object.fromEntries(Object.entries(node.inputs).map(([key, input]) => [key, cleanInput(input)]))
10856
+ };
10857
+ if (node.kind == "outputs") node = {
10858
+ ...node,
10859
+ outputMappings: Object.fromEntries(Object.entries(node.outputMappings).map(([key, input]) => [key, cleanInput(input)]))
10860
+ };
10861
+ if (node.kind == "condition") node = clearConditionBindings(node);
10862
+ if (node.kind == "error" && node.sourceFlowIds != null) node = {
10863
+ ...node,
10864
+ sourceFlowIds: []
10865
+ };
10866
+ if (node.kind == "poll" || node.kind == "integration") node = {
10867
+ ...node,
10868
+ config: clearTriggerExternalConfig(node.definition.key, node.config)
10869
+ };
10870
+ return [id, node];
10871
+ }));
10872
+ return {
10873
+ file: {
10874
+ ...file,
10875
+ content: {
10876
+ ...file.content,
10877
+ document: {
10878
+ ...file.content.document,
10879
+ bindings: {},
10880
+ graph: {
10881
+ ...graph,
10882
+ nodes
10883
+ }
10884
+ }
10885
+ }
10886
+ },
10887
+ summary: {
10888
+ changedNodeIds: Object.keys(nodes).filter((id) => !dequal(nodes[id], original.nodes[id])),
10889
+ removedBindings: Object.keys(file.content.document.bindings).length
10890
+ }
10891
+ };
10892
+ }
10893
+ //#endregion
10894
+ //#region src/flow/common/workflowBundle.ts
10895
+ var entries = array(strictObject({
10896
+ flowId: string$1().min(1),
10897
+ file: unknown()
10898
+ })).min(1);
10899
+ var bundleSchema = strictObject({
10900
+ kind: literal("open-flow-workflow-bundle"),
10901
+ version: literal(1),
10902
+ entryFlowId: string$1().min(1),
10903
+ workflows: entries
10904
+ });
10905
+ var previewSchema = strictObject({
10906
+ version: literal(1),
10907
+ entryFlowId: string$1().min(1),
10908
+ workflows: entries,
10909
+ unavailableFlowIds: array(string$1().min(1))
10910
+ });
10911
+ function decodeEntries(value, entryFlowId, unavailableFlowIds = []) {
10912
+ const workflows = value.map(({ flowId, file }) => ({
10913
+ flowId,
10914
+ file: decodeWorkflowFile(file)
10915
+ }));
10916
+ const ids = new Set(workflows.map(({ flowId }) => flowId));
10917
+ if (ids.size != workflows.length || !ids.has(entryFlowId)) throw new TypeError("Workflow identities must be unique and include the entry workflow.");
10918
+ const unavailable = new Set(unavailableFlowIds);
10919
+ if (unavailable.size != unavailableFlowIds.length || unavailableFlowIds.some((id) => ids.has(id))) throw new TypeError("Invalid unavailable workflow identities.");
10920
+ for (const { file } of workflows) for (const node of Object.values(file.content.document.graph.nodes)) for (const { target } of nodeWorkflowReferences(node)) if (target.flowId && !ids.has(target.flowId) && !unavailable.has(target.flowId)) throw new TypeError("A referenced workflow is missing from the bundle.");
10921
+ return workflows;
10922
+ }
10923
+ function decodeWorkflowBundle(value) {
10924
+ checkJsonDepth(value, -4);
10925
+ const bundle = bundleSchema.parse(value);
10926
+ return {
10927
+ ...bundle,
10928
+ workflows: decodeEntries(bundle.workflows, bundle.entryFlowId)
10929
+ };
10930
+ }
10931
+ function decodeWorkflowExportPreview(value) {
10932
+ checkJsonDepth(value, -4);
10933
+ const preview = previewSchema.parse(value);
10934
+ return {
10935
+ ...preview,
10936
+ workflows: decodeEntries(preview.workflows, preview.entryFlowId, preview.unavailableFlowIds)
10937
+ };
10938
+ }
10939
+ function cleanWorkflowBundle(value) {
10940
+ const bundle = decodeWorkflowBundle(value);
10941
+ return {
10942
+ ...bundle,
10943
+ workflows: bundle.workflows.map(({ flowId, file }) => ({
10944
+ flowId,
10945
+ file: cleanWorkflowFile(file).file
10946
+ }))
10947
+ };
10948
+ }
10949
+ function workflowBundleFromPreview(preview) {
10950
+ if (preview.unavailableFlowIds.length) throw new TypeError("Some referenced workflows are unavailable.");
10951
+ return cleanWorkflowBundle({
10952
+ kind: "open-flow-workflow-bundle",
10953
+ version: 1,
10954
+ entryFlowId: preview.entryFlowId,
10955
+ workflows: preview.workflows
10956
+ });
10957
+ }
10696
10958
  //#endregion
10697
10959
  //#region src/flow/common/encoding.ts
10698
10960
  var encoder$1 = new TextEncoder();
@@ -11996,6 +12258,8 @@ function flow(value) {
11996
12258
  resourceReferences: resourceReferences(source.resourceReferences),
11997
12259
  flowId: string(source.flowId),
11998
12260
  name: string(source.name),
12261
+ ...source.icon === void 0 ? {} : { icon: string(source.icon) },
12262
+ ...source.description === void 0 ? {} : { description: string(source.description) },
11999
12263
  status,
12000
12264
  updatedAt: string(source.updatedAt),
12001
12265
  version: 1
@@ -12482,6 +12746,18 @@ function decodeTagListItem(value) {
12482
12746
  }
12483
12747
  //#endregion
12484
12748
  //#region src/control/common/api.ts
12749
+ function decodeWorkflowBundleImportResult(value) {
12750
+ const source = record(value);
12751
+ if (source.version != 1 || !Array.isArray(source.flows) || source.flows.length == 0) return invalidResponse();
12752
+ const entry = flow(source.flow);
12753
+ const flows = source.flows.map(flow);
12754
+ if (new Set(flows.map((item) => item.flowId)).size != flows.length || !flows.some((item) => item.flowId == entry.flowId)) return invalidResponse();
12755
+ return {
12756
+ version: 1,
12757
+ flow: entry,
12758
+ flows
12759
+ };
12760
+ }
12485
12761
  function isRunTerminalEvent(event) {
12486
12762
  return event?.kind == "run.completed" || event?.kind == "run.failed" || event?.kind == "run.canceled" || event?.kind == "run.indeterminate";
12487
12763
  }
@@ -12799,6 +13075,32 @@ var ControlClient = class {
12799
13075
  return invalidResponse();
12800
13076
  }
12801
13077
  }
13078
+ async getFlowExportPreview(flowId) {
13079
+ const value = await this.request(`/v1/flows/${segment(flowId)}/export-preview`);
13080
+ try {
13081
+ return decodeWorkflowExportPreview(value);
13082
+ } catch {
13083
+ return invalidResponse();
13084
+ }
13085
+ }
13086
+ async exportFlowBundle(flowId) {
13087
+ const preview = await this.getFlowExportPreview(flowId);
13088
+ if (preview.unavailableFlowIds.length) throw new ApiError(400, "flow.invalid", "Some referenced workflows are unavailable.");
13089
+ return workflowBundleFromPreview(preview);
13090
+ }
13091
+ async importFlowBundle(file, options = {}) {
13092
+ return decodeWorkflowBundleImportResult(await this.request("/v1/flows/import-bundle", {
13093
+ method: "POST",
13094
+ headers: { "Idempotency-Key": options.idempotencyKey ?? `flow-${randomId()}` },
13095
+ body: JSON.stringify({
13096
+ file,
13097
+ name: options.name,
13098
+ teamId: options.teamId,
13099
+ tagIds: options.tagIds,
13100
+ version: 1
13101
+ })
13102
+ }));
13103
+ }
12802
13104
  async importFlow(file, options = {}) {
12803
13105
  return flow(await this.request("/v1/flows/import", {
12804
13106
  method: "POST",
@@ -13455,4 +13757,4 @@ var ControlClient = class {
13455
13757
  }
13456
13758
  };
13457
13759
  //#endregion
13458
- export { ApiError, ControlClient, actionSummary, controlErrorCode, controlErrorMetadata, connectorAccess as decodeConnectorAccess, connectorAccessSnapshot as decodeConnectorAccessSnapshot, decodeEventSource, decodeEventSources, decodeResultList, decodeResultRead, decodeRunEvent, decodeTriggerCatalog, flowInputDefinitions, flowInspection, inspectFlowDraft, isRunTerminalEvent, liveEntries, nodeDetails, normalizeFlowQuery, parseProviderAccessSource, parseResultQuery, providerAccessBindingId, providerIconAppearance, readResult, searchTriggerKeys };
13760
+ export { ApiError, ControlClient, actionSummary, controlErrorCode, controlErrorMetadata, connectorAccess as decodeConnectorAccess, connectorAccessSnapshot as decodeConnectorAccessSnapshot, decodeEventSource, decodeEventSources, decodeResultList, decodeResultRead, decodeRunEvent, decodeTriggerCatalog, decodeWorkflowBundleImportResult, flowInputDefinitions, flowInspection, inspectFlowDraft, isRunTerminalEvent, liveEntries, nodeDetails, normalizeFlowQuery, parseProviderAccessSource, parseResultQuery, providerAccessBindingId, providerIconAppearance, readResult, searchTriggerKeys };
@@ -224,12 +224,10 @@ export declare const controlRequests: {
224
224
  version: 1;
225
225
  };
226
226
  updateFlow: (value: unknown) => {
227
- name: string;
228
- tagIds?: string[] | undefined;
229
- version: 1;
230
- } | {
231
227
  name?: string | undefined;
232
- tagIds: string[];
228
+ icon?: string | null | undefined;
229
+ description?: string | null | undefined;
230
+ tagIds?: string[] | undefined;
233
231
  version: 1;
234
232
  };
235
233
  renameFlow: (value: unknown) => {
@@ -15393,6 +15393,21 @@ function applyFlowChanges(content, operations) {
15393
15393
  });
15394
15394
  }
15395
15395
  //#endregion
15396
+ //#region src/connector/common/actionContract.ts
15397
+ /** These rules also apply to existing Revision snapshots without a catalog lookup. */
15398
+ var connectorActionContracts = { "leina.send_notification": {
15399
+ inputConstraints: [{
15400
+ handle: "leinaId",
15401
+ jsonSchema: {
15402
+ type: "string",
15403
+ pattern: "\\S"
15404
+ },
15405
+ code: "leina.robot-required",
15406
+ message: "Select a Leina robot or bind its identifier to an input source."
15407
+ }],
15408
+ pendingMessageInput: "message"
15409
+ } };
15410
+ //#endregion
15396
15411
  //#region src/flow/common/edgeChanges.ts
15397
15412
  function connect(content, edge) {
15398
15413
  const selected = content.document.graph;
@@ -15403,11 +15418,12 @@ function connect(content, edge) {
15403
15418
  }];
15404
15419
  const source = selected.nodes[edge.source];
15405
15420
  const target = selected.nodes[edge.target];
15406
- if (edge.sourceHandle == "pending" && (source?.kind == "approval" || source?.kind == "wait") && target?.kind == "task" && "executor" in target.task && target.task.executor.kind == "connector" && target.task.executor.action == "leina.send_notification" && (target.inputs.message == null || target.inputs.message.kind == "unset")) changes.push({
15421
+ const messageInput = target?.kind == "task" && "executor" in target.task && target.task.executor.kind == "connector" ? connectorActionContracts[target.task.executor.action]?.pendingMessageInput : void 0;
15422
+ if (edge.sourceHandle == "pending" && (source?.kind == "approval" || source?.kind == "wait") && target?.kind == "task" && messageInput != null && (target.inputs[messageInput] == null || target.inputs[messageInput]?.kind == "unset")) changes.push({
15407
15423
  kind: "graph.node.input.set",
15408
15424
  nodeId: edge.target,
15409
- handle: "message",
15410
- before: target.inputs.message,
15425
+ handle: messageInput,
15426
+ before: target.inputs[messageInput],
15411
15427
  value: {
15412
15428
  kind: "sources",
15413
15429
  sources: [{
@@ -17932,15 +17948,13 @@ var schemas = {
17932
17948
  tagIds,
17933
17949
  version
17934
17950
  }),
17935
- updateFlow: union([strictObject({
17936
- name: flowName,
17937
- tagIds: tagIds.optional(),
17938
- version
17939
- }), strictObject({
17951
+ updateFlow: strictObject({
17940
17952
  name: flowName.optional(),
17941
- tagIds,
17953
+ icon: string().nullable().optional(),
17954
+ description: string().nullable().optional(),
17955
+ tagIds: tagIds.optional(),
17942
17956
  version
17943
- })]),
17957
+ }).refine((value) => value.name !== void 0 || value.icon !== void 0 || value.description !== void 0 || value.tagIds !== void 0, "Flow settings are empty."),
17944
17958
  renameFlow: strictObject({
17945
17959
  name: flowName,
17946
17960
  version
@@ -57,6 +57,21 @@ function dequal(foo, bar) {
57
57
  return foo !== foo && bar !== bar;
58
58
  }
59
59
  //#endregion
60
+ //#region src/connector/common/actionContract.ts
61
+ /** These rules also apply to existing Revision snapshots without a catalog lookup. */
62
+ var connectorActionContracts = { "leina.send_notification": {
63
+ inputConstraints: [{
64
+ handle: "leinaId",
65
+ jsonSchema: {
66
+ type: "string",
67
+ pattern: "\\S"
68
+ },
69
+ code: "leina.robot-required",
70
+ message: "Select a Leina robot or bind its identifier to an input source."
71
+ }],
72
+ pendingMessageInput: "message"
73
+ } };
74
+ //#endregion
60
75
  //#region src/flow/common/edgeChanges.ts
61
76
  function connect(content, edge) {
62
77
  const selected = content.document.graph;
@@ -67,11 +82,12 @@ function connect(content, edge) {
67
82
  }];
68
83
  const source = selected.nodes[edge.source];
69
84
  const target = selected.nodes[edge.target];
70
- if (edge.sourceHandle == "pending" && (source?.kind == "approval" || source?.kind == "wait") && target?.kind == "task" && "executor" in target.task && target.task.executor.kind == "connector" && target.task.executor.action == "leina.send_notification" && (target.inputs.message == null || target.inputs.message.kind == "unset")) changes.push({
85
+ const messageInput = target?.kind == "task" && "executor" in target.task && target.task.executor.kind == "connector" ? connectorActionContracts[target.task.executor.action]?.pendingMessageInput : void 0;
86
+ if (edge.sourceHandle == "pending" && (source?.kind == "approval" || source?.kind == "wait") && target?.kind == "task" && messageInput != null && (target.inputs[messageInput] == null || target.inputs[messageInput]?.kind == "unset")) changes.push({
71
87
  kind: "graph.node.input.set",
72
88
  nodeId: edge.target,
73
- handle: "message",
74
- before: target.inputs.message,
89
+ handle: messageInput,
90
+ before: target.inputs[messageInput],
75
91
  value: {
76
92
  kind: "sources",
77
93
  sources: [{
@@ -1,5 +1,6 @@
1
1
  import type { CodeModule, FlowDocument, Graph, Group, InputMapping, InputPort, JsonValue, ManagedTaskDefinition, Port, RevisionContent, TriggerNode } from '@oomol-lab/open-flow/flow-change';
2
2
  export * from './flow-workflowFile.js';
3
+ export * from './flow-workflowBundle.js';
3
4
  export { maxJsonDepth } from './flow-json.js';
4
5
  export { decodeFlowDocument, decodeRevisionContent, upgradeWorkflowInterfaceDocument } from './flow-change-schema.js';
5
6
  export { upgradeRevisionContent } from '@oomol-lab/open-flow/flow-change';