@oomol-lab/open-flow 0.1.0-beta.61 → 0.1.0-beta.63

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 (55) hide show
  1. package/dist/browser/{createResourceDialog-D71fO68i.js → createResourceDialog-BAJXbzNH.js} +20 -7
  2. package/dist/browser/flow-authoring.js +8 -7
  3. package/dist/browser/flow-change-schema.d.ts +1 -0
  4. package/dist/browser/flow-change.d.ts +1 -0
  5. package/dist/browser/flow-change.js +8 -7
  6. package/dist/browser/{flowChanges-DSA0FxxN.js → flowChanges-DpZOQuJE.js} +3001 -2588
  7. package/dist/browser/{flowRunInputEditorStore-Dsxyfwae.js → flowRunInputEditorStore-B2Rw4VsT.js} +1 -1
  8. package/dist/browser/{flowWorkspace-0sUJ5JhQ.js → flowWorkspace-B7a5NNA_.js} +217 -83
  9. package/dist/browser/{icons-DVJvrj1H.js → icons-Db2Jb2iX.js} +2907 -2887
  10. package/dist/browser/preview.css +5 -6
  11. package/dist/browser/preview.js +889 -541
  12. package/dist/browser/{typeScriptSession-fXPMFGjW.js → typeScriptSession-D0bjYDeg.js} +1 -1
  13. package/dist/browser/ui.css +4 -5
  14. package/dist/browser/ui.js +2 -2
  15. package/dist/browser/{value-DL_poNiC.js → value-BADHeZ9I.js} +12 -1
  16. package/dist/browser/workbench-contract.d.ts +10 -0
  17. package/dist/browser/workbench.css +9 -26
  18. package/dist/browser/workbench.d.ts +5 -3
  19. package/dist/browser/workbench.js +272 -178
  20. package/dist/browser/{workbenchSelect-cr4-mKq3.js → workbenchSelect-C-jf6NIM.js} +1 -1
  21. package/dist/command/index.js +45 -44
  22. package/dist/common/authoring.d.ts +1 -1
  23. package/dist/common/authoringSchema.d.ts +1 -0
  24. package/dist/common/connector-action.d.ts +1 -0
  25. package/dist/common/connector-action.js +15 -12
  26. package/dist/common/control-api-conformance.js +1371 -1207
  27. package/dist/common/control-api-errors.d.ts +0 -4
  28. package/dist/common/control-api.d.ts +18 -11
  29. package/dist/common/control-api.js +2053 -2274
  30. package/dist/common/control-requests.d.ts +6 -0
  31. package/dist/common/control-requests.js +64 -33
  32. package/dist/common/decision.js +8 -7
  33. package/dist/common/flow-connectionUsage.d.ts +1 -0
  34. package/dist/common/flow-encoding.d.ts +1 -0
  35. package/dist/common/flow-encoding.js +202 -10
  36. package/dist/common/flow-semantics.js +64 -46
  37. package/dist/common/flow-workflowFile.d.ts +23 -0
  38. package/dist/common/integration-trigger.js +8 -7
  39. package/dist/common/liveDetails.d.ts +138 -0
  40. package/dist/common/localization.d.ts +1 -0
  41. package/dist/common/localization.js +12 -1
  42. package/dist/common/mcp.d.ts +55 -26
  43. package/dist/common/mcp.js +377 -245
  44. package/dist/common/openapi.js +8 -7
  45. package/dist/common/poll-trigger.js +8 -7
  46. package/dist/common/runtime-contract.js +1 -1
  47. package/dist/common/scheduler.d.ts +22 -2
  48. package/dist/common/scheduler.js +354 -83
  49. package/dist/common/trigger-config.d.ts +2 -0
  50. package/dist/common/webhook-trigger.js +8 -7
  51. package/dist/index.d.ts +2 -2
  52. package/package.json +1 -1
  53. package/skills/open-flow/SKILL.md +6 -3
  54. package/skills/open-flow/references/flow-authoring.md +48 -24
  55. package/dist/common/publicationResources.d.ts +0 -29
@@ -1,9 +1,9 @@
1
- import { $ as RunStore, $n as setInputSources, B as CacheResource, Bn as providerIconAppearance, Bt as EmptyHeader, Ct as Popover, F as feishuResourceKind, Fn as allConnectorConnectionsQuery, Ft as InputGroupAddon, Gt as DropdownMenuContent, H as resourceData, Ht as EmptyTitle, I as supportsFeishuChatFilter, It as InputGroupInput, J as providerIcon, L as combineSources, Ln as decodeTriggerCatalog, Lt as Empty, M as addNodeIntent, Mn as errorNotice, N as deriveAddNodeOptions, Nn as WorkbenchClient, Ot as PopoverTitle, Pn as randomId, Pt as InputGroup, Qn as setConnectorConnection, Rn as connection, Rt as EmptyContent, St as followWorkbenchLink, U as resourceValue, Ut as DropdownMenu, Vt as EmptyMedia, W as designerGraph, Xn as resetInputValues, Yn as repairNodeNames, Zn as setCodeActions, Zt as DropdownMenuSeparator, _ as updateValue, _r as ApiError, _t as setComment, a as nameCreatedNodes, at as deriveInspectorDiagnostics, bt as setNodePositions, c as updateCondition, cr as triggerOutputDefinitions, d as updateNodeName, dt as connectionCatalog, er as setTriggerConnection, f as updateNodeSettings, fr as inputValue, ft as canvasPresentationChange, g as updateTaskPorts, gn as EventSourcesPage, gr as string, gt as restoreCanvasPresentation, h as updateTaskAdditionalInputs, hn as Badge, hr as record, ht as removeComments, i as deleteSelection, ir as replaceSource, it as Latest, l as updateNodeDescription, lr as isJsonObject, m as updateTask, mr as jsonValue, mt as flowPresentation, nr as updateTriggerSchedule, nt as revisionView, o as setInputValue, ot as diagnosticItems, p as updateResolution, pr as invalidResponse, pt as commentIds, qt as DropdownMenuItem, r as applyFlowChanges, rr as imports, rt as flowResourceReferences, s as setInputVariable, sr as sampleErrorOutputs, t as addNode, tn as DropdownMenuTrigger, tr as updateTriggerConfig, u as updateNodeIcon, ut as actionWithConnections, v as updateWebhook, vr as controlErrorCode, vt as setFlowViewport, wt as PopoverContent, xr as IconThemeContext, xt as IdTooltip, yn as createI18n, yt as setNodeContentHidden, z as scopedValue, zn as connectorActionMetadata, zt as EmptyDescription } from "./flowChanges-DSA0FxxN.js";
1
+ import { $n as connection, $t as DropdownMenu, At as WorkflowExportMenuItem, B as CacheResource, Ct as resetInputValues, Dt as setTriggerConnection, En as EventSourcesPage, Et as setInputSources, F as feishuResourceKind, G as designerGraph, Gn as allConnectorConnectionsQuery, Gt as InputGroupAddon, H as resourceData, Hn as errorNotice, I as supportsFeishuChatFilter, Jt as EmptyContent, Kt as InputGroupInput, L as combineSources, M as addNodeIntent, Mt as followWorkbenchLink, N as deriveAddNodeOptions, Nt as Popover, Ot as updateTriggerConfig, Pt as PopoverContent, Qn as isJsonObject, Qt as EmptyTitle, Rt as PopoverTitle, Sr as controlErrorCode, St as repairNodeNames, Tn as Badge, Tr as IconThemeContext, Tt as setConnectorConnection, U as resourceValue, Un as WorkbenchClient, W as connectorActionPorts, Wn as randomId, Wt as InputGroup, Xn as sampleErrorOutputs, Xt as EmptyHeader, Y as providerIcon, Yt as EmptyDescription, Zn as triggerOutputDefinitions, Zt as EmptyMedia, _ as updateValue, _r as invalidResponse, _t as restoreCanvasPresentation, a as nameCreatedNodes, at as Latest, br as string, bt as setNodeContentHidden, c as updateCondition, d as updateNodeName, dn as DropdownMenuTrigger, dt as actionWithConnections, er as connectorActionMetadata, et as RunStore, f as updateNodeSettings, ft as connectionCatalog, g as updateTaskPorts, gr as inputValue, gt as removeComments, h as updateTaskAdditionalInputs, ht as flowPresentation, i as deleteSelection, ir as workflowNameFromFile, it as flowResourceReferences, jt as IdTooltip, kn as createI18n, kt as updateTriggerSchedule, l as updateNodeDescription, m as updateTask, mt as commentIds, nr as parseWorkflowFile, o as setInputValue, ot as deriveInspectorDiagnostics, p as updateResolution, pt as canvasPresentationChange, qn as decodeTriggerCatalog, qt as Empty, r as applyFlowChanges, rn as DropdownMenuItem, rr as workflowFileName, rt as revisionView, s as setInputVariable, sn as DropdownMenuSeparator, sr as providerIconAppearance, st as diagnosticItems, t as addNode, tn as DropdownMenuContent, tr as encodeWorkflowFile, u as updateNodeIcon, v as updateWebhook, vr as jsonValue, vt as setComment, wt as setCodeActions, xr as ApiError, xt as setNodePositions, yr as record, yt as setFlowViewport, z as scopedValue } from "./flowChanges-DpZOQuJE.js";
2
2
  import { a as derive, i as compute, l as val } from "./dist-bO8nvHFH.js";
3
- import { a as toPlainObject, c as useLang, l as useTranslate, o as I18nProvider, u as useVal } from "./dist-BFmpkX4P.js";
4
- import { E as FieldLabel, J as nodeInputMappings, L as FlowChangeError, R as applyFlowChanges$1, S as Field, T as FieldGroup, W as resourceNameIssue, a as DialogDescription, bi as cn, c as DialogTitle, d as TooltipContent, i as DialogContent, n as Dialog, o as DialogFooter, or as Input, p as TooltipTrigger, q as mapConditionSources, r as DialogClose, s as DialogHeader, t as Icon, u as Tooltip, vi as Button, w as FieldError, x as Spinner, yt as dequal$1 } from "./icons-DVJvrj1H.js";
5
- import { c as isUiLanguage, d as uiLanguages, l as resolveUiLanguage, u as uiLanguageNames } from "./value-DL_poNiC.js";
6
- import { Suspense, lazy, useEffect, useRef, useState } from "react";
3
+ import { c as useLang, l as useTranslate, o as I18nProvider, u as useVal } from "./dist-BFmpkX4P.js";
4
+ import { B as FlowChangeError, Ci as cn, E as FieldLabel, Q as nodeInputMappings, S as Field, T as FieldGroup, V as applyFlowChanges$1, Z as mapConditionSources, a as DialogDescription, at as dequal$1, c as DialogTitle, d as TooltipContent, i as DialogContent, lr as Input, n as Dialog, o as DialogFooter, p as TooltipTrigger, q as resourceNameIssue, r as DialogClose, s as DialogHeader, t as Icon, u as Tooltip, w as FieldError, x as Spinner, xi as Button } from "./icons-Db2Jb2iX.js";
5
+ import { c as importedWorkflowName, d as uiLanguageNames, f as uiLanguages, l as isUiLanguage, u as resolveUiLanguage } from "./value-BADHeZ9I.js";
6
+ import { Suspense, forwardRef, lazy, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
8
  import * as Cause from "effect/Cause";
9
9
  import * as Effect from "effect/Effect";
@@ -95,11 +95,17 @@ var NavigationStore = class {
95
95
  this.#syncing = false;
96
96
  this.#write(view, false, { runSource });
97
97
  }
98
+ async importFlow(file, name, key, importer) {
99
+ return await this.#openNewFlow(() => this.#store.importFlow(file, name, key, importer));
100
+ }
98
101
  async createFlow(name, create) {
102
+ return await this.#openNewFlow(() => this.#store.createFlow(name, create));
103
+ }
104
+ async #openNewFlow(create) {
99
105
  const change = ++this.#change;
100
106
  this.#syncing = true;
101
107
  try {
102
- const created = await this.#store.createFlow(name, create);
108
+ const created = await create();
103
109
  if (created && change == this.#change) this.#write("design", false);
104
110
  return created;
105
111
  } finally {
@@ -184,7 +190,7 @@ function Skeleton({ className, ...props }) {
184
190
  }
185
191
  //#endregion
186
192
  //#region src/workbench/browser/runtime/shell/resourceBrowser.tsx
187
- var CreateResourceDialog = lazy(() => import("./createResourceDialog-D71fO68i.js"));
193
+ var CreateResourceDialog = lazy(() => import("./createResourceDialog-BAJXbzNH.js"));
188
194
  var flowIdTooltipAlignOffset = 44;
189
195
  var renamePopoverAlignOffset = -12;
190
196
  var renamePopoverVerticalShift = 8;
@@ -531,6 +537,10 @@ function FlowItem({ showTeam, badge, busy, flow, href, onSelect, store }) {
531
537
  }), t(flow.live.enabled ? "resource.stop" : "resource.start")]
532
538
  }),
533
539
  /* @__PURE__ */ jsx(DropdownMenuSeparator, { className: "mx-2 bg-border/50" }),
540
+ /* @__PURE__ */ jsx(WorkflowExportMenuItem, {
541
+ disabled: flow.status != "active" || busy != null,
542
+ onClick: () => void store.workspace.exportFlow(flow.flowId)
543
+ }),
534
544
  /* @__PURE__ */ jsxs(DropdownMenuItem, {
535
545
  disabled: flow.status != "active",
536
546
  onClick: () => onSelect(flow, "publications"),
@@ -622,7 +632,7 @@ function FlowSkeleton({ showTeam }) {
622
632
  })]
623
633
  });
624
634
  }
625
- function FlowBrowser({ catalogWidth, createFlowDisabled, createFlowField, flowBadges, hrefForFlow, initializing = false, onCreateFlow, onSelectFlow, store }) {
635
+ var FlowBrowser = forwardRef(function FlowBrowser({ catalogWidth, createFlowDisabled, createFlowField, flowBadges, hrefForFlow, initializing = false, onCreateFlow, onImportFlow, onSelectFlow, store, language }, ref) {
626
636
  const t = useTranslate();
627
637
  const busy = useVal(store.workspace.$.busy);
628
638
  const loadFailed = useVal(store.workspace.$.flowLoadFailed);
@@ -634,17 +644,54 @@ function FlowBrowser({ catalogWidth, createFlowDisabled, createFlowField, flowBa
634
644
  const refreshing = useVal(store.workspace.$.flowRefreshing);
635
645
  const flows = useVal(store.workspace.$.flows);
636
646
  const total = useVal(store.workspace.$.flowTotal);
637
- const [creating, setCreating] = useState(false);
647
+ const [creation$] = useState(() => val(void 0));
648
+ const creation = useVal(creation$);
649
+ const [importError, setImportError] = useState(false);
650
+ const fileInput = useRef(null);
638
651
  const [filter, setFilter] = useState("");
639
652
  const [name, setName] = useState("");
640
653
  const showTeam = flows.some((flow) => (flowBadges?.[flow.flowId]?.trim().length ?? 0) > 0);
641
654
  const normalized = filter.trim().toLocaleLowerCase();
642
655
  const visible = flows.filter((flow) => flow.name.toLocaleLowerCase().includes(normalized));
656
+ const command = useRef();
657
+ useImperativeHandle(ref, () => ({ openImport: (input) => command.current?.(input) ?? "unavailable" }), []);
658
+ useLayoutEffect(() => {
659
+ command.current = openImport;
660
+ return () => {
661
+ command.current = void 0;
662
+ };
663
+ });
664
+ function openImport(input) {
665
+ if (initializing || store.workspace.$.busy.value != null || creation$.value != null || onImportFlow == null) return "unavailable";
666
+ setImportError(false);
667
+ let file;
668
+ try {
669
+ file = parseWorkflowFile(input.text);
670
+ } catch {
671
+ setImportError(true);
672
+ return "invalid-file";
673
+ }
674
+ setName(file.name ?? (input.fileName == null ? importedWorkflowName(language) : workflowNameFromFile(input.fileName)));
675
+ creation$.set({
676
+ kind: "import",
677
+ file,
678
+ key: randomId(),
679
+ ...input.sourceUrl == null ? {} : { sourceUrl: input.sourceUrl }
680
+ });
681
+ return "opened";
682
+ }
683
+ function openCreate() {
684
+ if (creation$.value != null) return;
685
+ setName("");
686
+ creation$.set({ kind: "create" });
687
+ }
643
688
  async function create(event) {
644
689
  event.preventDefault();
690
+ const request = creation$.value;
645
691
  const nextName = name.trim();
646
- if (resourceNameIssue(nextName) != null || !await onCreateFlow(nextName)) return;
647
- setCreating(false);
692
+ if (request == null || resourceNameIssue(nextName) != null) return;
693
+ if (!(request.kind == "create" ? await onCreateFlow(nextName) : await onImportFlow?.(request.file, nextName, request.key)) || command.current == null || creation$.value !== request) return;
694
+ creation$.set(void 0);
648
695
  setName("");
649
696
  }
650
697
  return /* @__PURE__ */ jsx("main", {
@@ -675,30 +722,61 @@ function FlowBrowser({ catalogWidth, createFlowDisabled, createFlowField, flowBa
675
722
  }), !loading && /* @__PURE__ */ jsx("span", { children: t("resource.flowCount", { count: total ?? flows.length }) })]
676
723
  }), /* @__PURE__ */ jsxs("div", {
677
724
  className: "resource-list-actions",
678
- children: [/* @__PURE__ */ jsxs(InputGroup, {
679
- className: "w-full sm:w-56",
680
- children: [/* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(Icon, {
681
- name: "search",
682
- size: 17
683
- }) }), /* @__PURE__ */ jsx(InputGroupInput, {
684
- autoComplete: "off",
685
- "aria-label": t("resource.searchByName"),
686
- name: "flow-search",
687
- onChange: (event) => setFilter(event.target.value),
688
- placeholder: t("resource.searchByName"),
689
- value: filter
690
- })]
691
- }), /* @__PURE__ */ jsxs(Button, {
692
- className: "pr-3",
693
- disabled: initializing || busy != null,
694
- onClick: () => setCreating(true),
695
- children: [/* @__PURE__ */ jsx(Icon, {
696
- "data-icon": "inline-start",
697
- name: "plus"
698
- }), t("resource.newFlow")]
699
- })]
725
+ children: [
726
+ /* @__PURE__ */ jsxs(InputGroup, {
727
+ className: "w-full sm:w-56",
728
+ children: [/* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(Icon, {
729
+ name: "search",
730
+ size: 17
731
+ }) }), /* @__PURE__ */ jsx(InputGroupInput, {
732
+ autoComplete: "off",
733
+ "aria-label": t("resource.searchByName"),
734
+ name: "flow-search",
735
+ onChange: (event) => setFilter(event.target.value),
736
+ placeholder: t("resource.searchByName"),
737
+ value: filter
738
+ })]
739
+ }),
740
+ onImportFlow != null && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Input, {
741
+ ref: fileInput,
742
+ className: "hidden",
743
+ type: "file",
744
+ accept: ".openflow.json,.json,application/json",
745
+ "aria-label": t("resource.importFlow"),
746
+ onChange: (event) => {
747
+ const file = event.target.files?.[0];
748
+ event.target.value = "";
749
+ if (file == null) return;
750
+ setImportError(false);
751
+ file.text().then((text) => {
752
+ command.current?.({
753
+ text,
754
+ fileName: file.name
755
+ });
756
+ }).catch(() => setImportError(true));
757
+ }
758
+ }), /* @__PURE__ */ jsx(Button, {
759
+ variant: "outline",
760
+ disabled: initializing || busy != null || createFlowDisabled,
761
+ onClick: () => fileInput.current?.click(),
762
+ children: t("resource.importFlow")
763
+ })] }),
764
+ /* @__PURE__ */ jsxs(Button, {
765
+ className: "pr-3",
766
+ disabled: initializing || busy != null,
767
+ onClick: openCreate,
768
+ children: [/* @__PURE__ */ jsx(Icon, {
769
+ "data-icon": "inline-start",
770
+ name: "plus"
771
+ }), t("resource.newFlow")]
772
+ })
773
+ ]
700
774
  })]
701
775
  }),
776
+ importError && /* @__PURE__ */ jsx("p", {
777
+ role: "alert",
778
+ children: t("resource.importInvalid")
779
+ }),
702
780
  /* @__PURE__ */ jsx("div", {
703
781
  className: "resource-table-scroll",
704
782
  children: /* @__PURE__ */ jsxs("div", {
@@ -762,7 +840,7 @@ function FlowBrowser({ catalogWidth, createFlowDisabled, createFlowField, flowBa
762
840
  /* @__PURE__ */ jsx(EmptyTitle, { children: t(normalized.length == 0 ? "resource.noFlows" : "resource.noMatchingFlows") }),
763
841
  /* @__PURE__ */ jsx(EmptyDescription, { children: t(normalized.length == 0 ? "resource.noFlowsDescription" : "resource.noMatchingDescription") })
764
842
  ] }), normalized.length == 0 && /* @__PURE__ */ jsx(EmptyContent, { children: /* @__PURE__ */ jsxs(Button, {
765
- onClick: () => setCreating(true),
843
+ onClick: openCreate,
766
844
  variant: "outline",
767
845
  children: [/* @__PURE__ */ jsx(Icon, {
768
846
  "data-icon": "inline-start",
@@ -792,7 +870,7 @@ function FlowBrowser({ catalogWidth, createFlowDisabled, createFlowField, flowBa
792
870
  })
793
871
  ]
794
872
  }),
795
- creating && /* @__PURE__ */ jsx(Suspense, {
873
+ creation != null && /* @__PURE__ */ jsx(Suspense, {
796
874
  fallback: null,
797
875
  children: /* @__PURE__ */ jsx(CreateResourceDialog, {
798
876
  disabled: createFlowDisabled,
@@ -802,16 +880,23 @@ function FlowBrowser({ catalogWidth, createFlowDisabled, createFlowField, flowBa
802
880
  label: t("resource.flowName"),
803
881
  name,
804
882
  onNameChange: setName,
805
- onOpenChange: setCreating,
883
+ onOpenChange: (open) => {
884
+ if (!open) {
885
+ creation$.set(void 0);
886
+ setName("");
887
+ }
888
+ },
806
889
  onSubmit: (event) => void create(event),
807
890
  pending: busy == "flow",
808
- title: t("resource.newFlow")
891
+ sourceUrl: creation.kind == "import" ? creation.sourceUrl : void 0,
892
+ submitLabel: creation.kind == "import" ? t("resource.importFlow") : void 0,
893
+ title: t(creation.kind == "create" ? "resource.newFlow" : "resource.importFlow")
809
894
  })
810
895
  })
811
896
  ]
812
897
  })
813
898
  });
814
- }
899
+ });
815
900
  //#endregion
816
901
  //#region ../../node_modules/.bun/dequal@2.0.3/node_modules/dequal/dist/index.mjs
817
902
  var has = Object.prototype.hasOwnProperty;
@@ -925,6 +1010,36 @@ function disconnect(content, edge) {
925
1010
  kind: "graph.edge.disconnect"
926
1011
  }];
927
1012
  }
1013
+ //#endregion
1014
+ //#region src/flow/common/moduleChanges.ts
1015
+ async function imports(source) {
1016
+ try {
1017
+ const { parse } = await import("./lib-Dws05GHj.js").then((n) => n.t);
1018
+ const program = parse(source, {
1019
+ errorRecovery: true,
1020
+ sourceType: "module"
1021
+ }).program;
1022
+ const dependencies = /* @__PURE__ */ new Set();
1023
+ for (const statement of program.body) {
1024
+ if (statement.type != "ImportDeclaration") continue;
1025
+ const match = /^\.\/(.+)\.mjs$/.exec(statement.source.value);
1026
+ if (match?.[1] != null) dependencies.add(match[1]);
1027
+ }
1028
+ return [...dependencies].toSorted();
1029
+ } catch {
1030
+ return [];
1031
+ }
1032
+ }
1033
+ function replaceSource(moduleId, beforeSource, beforeImports, source, moduleImports) {
1034
+ return [{
1035
+ beforeImports,
1036
+ beforeSource,
1037
+ imports: moduleImports,
1038
+ kind: "module.source.replace",
1039
+ moduleId,
1040
+ source
1041
+ }];
1042
+ }
928
1043
  var createAuthoringId = customAlphabet("23456789abcdefghjkmnpqrstuvwxyz", 10);
929
1044
  //#endregion
930
1045
  //#region src/workbench/browser/runtime/editor/triggerDiagnosticPresentation.ts
@@ -945,12 +1060,15 @@ function presentTriggerDiagnostics(items, revision, displays, language, t) {
945
1060
  }
946
1061
  //#endregion
947
1062
  //#region src/workbench/browser/runtime/publications/publicationStore.ts
1063
+ var initialBindings = {
1064
+ status: "idle",
1065
+ bindings: []
1066
+ };
948
1067
  var initialState$6 = {
949
1068
  activities: [],
950
1069
  activitiesLoadFailed: false,
951
1070
  activitiesLoading: false,
952
1071
  activitiesLoadingMore: false,
953
- bindings: [],
954
1072
  detailLoading: false,
955
1073
  loaded: false,
956
1074
  loadFailed: false,
@@ -971,6 +1089,8 @@ var PublicationStore = class {
971
1089
  #client;
972
1090
  #identity;
973
1091
  #i18n;
1092
+ #bindings = val(initialBindings);
1093
+ #bindingLoads = new Latest();
974
1094
  #loads = new Latest();
975
1095
  #operation = new Latest();
976
1096
  #preferences;
@@ -994,7 +1114,7 @@ var PublicationStore = class {
994
1114
  activitiesLoading: derive(this.#state, (state) => state.activitiesLoading),
995
1115
  activitiesLoadingMore: derive(this.#state, (state) => state.activitiesLoadingMore),
996
1116
  activitiesNextCursor: derive(this.#state, (state) => state.activitiesNextCursor),
997
- bindings: derive(this.#state, (state) => state.bindings),
1117
+ bindings: this.#bindings,
998
1118
  detail: derive(this.#state, (state) => state.detail),
999
1119
  detailLoading: derive(this.#state, (state) => state.detailLoading),
1000
1120
  live: derive(this.#state, (state) => state.live),
@@ -1015,6 +1135,7 @@ var PublicationStore = class {
1015
1135
  };
1016
1136
  }
1017
1137
  dispose() {
1138
+ this.#bindingLoads.invalidate();
1018
1139
  this.#loads.invalidate();
1019
1140
  this.#operation.invalidate();
1020
1141
  this.#stopObservation();
@@ -1024,6 +1145,8 @@ var PublicationStore = class {
1024
1145
  this.#state.dispose();
1025
1146
  }
1026
1147
  reset() {
1148
+ this.#bindingLoads.invalidate();
1149
+ this.#bindings.set(initialBindings);
1027
1150
  this.#loads.invalidate();
1028
1151
  this.#operation.invalidate();
1029
1152
  this.#stopObservation();
@@ -1055,11 +1178,11 @@ var PublicationStore = class {
1055
1178
  });
1056
1179
  try {
1057
1180
  const operation = warm ? state.operation : await this.#storedOperation(target);
1058
- const [live, page, bindings] = await this.#read(target);
1181
+ if (!current()) return;
1182
+ const [live, page] = await this.#read(target);
1059
1183
  if (!current()) return;
1060
1184
  this.#workspace.updateLive(live);
1061
1185
  this.#set({
1062
- bindings,
1063
1186
  live,
1064
1187
  loaded: true,
1065
1188
  loading: false,
@@ -1086,6 +1209,36 @@ var PublicationStore = class {
1086
1209
  this.#setNotice(errorNotice(error, this.#i18n.t));
1087
1210
  }
1088
1211
  }
1212
+ async loadBindings(flowId) {
1213
+ try {
1214
+ await this.#readBindings(flowId);
1215
+ } catch {}
1216
+ }
1217
+ async #readBindings(flowId, signal) {
1218
+ const previous = this.#bindings.value;
1219
+ const current = this.#bindingLoads.begin();
1220
+ this.#bindings.set({
1221
+ flowId,
1222
+ status: "loading",
1223
+ bindings: previous.flowId === flowId ? previous.bindings : []
1224
+ });
1225
+ try {
1226
+ const bindings = await this.#client.listFlowTriggerBindings(flowId, signal);
1227
+ if (!current()) return;
1228
+ this.#bindings.set({
1229
+ flowId,
1230
+ status: "loaded",
1231
+ bindings
1232
+ });
1233
+ } catch (error) {
1234
+ if (!current()) return;
1235
+ this.#bindings.set({
1236
+ ...this.#bindings.value,
1237
+ status: "failed"
1238
+ });
1239
+ throw error;
1240
+ }
1241
+ }
1089
1242
  async loadMore() {
1090
1243
  const { loadingMore, nextCursor, target } = this.#state.value;
1091
1244
  if (loadingMore || nextCursor == null || target == null) return;
@@ -1307,14 +1460,13 @@ var PublicationStore = class {
1307
1460
  }
1308
1461
  async #refresh(target, signal) {
1309
1462
  const current = this.#loads.begin();
1310
- const [live, page, bindings] = await this.#read(target, signal).catch((error) => {
1463
+ const [live, page] = await this.#read(target, signal).catch((error) => {
1311
1464
  if (current() && sameTarget(this.#state.value.target, target)) this.#set({ refreshing: false });
1312
1465
  throw error;
1313
1466
  });
1314
1467
  signal?.throwIfAborted();
1315
1468
  if (current()) this.#workspace.updateLive(live);
1316
1469
  if (current() && sameTarget(this.#state.value.target, target)) this.#set({
1317
- bindings,
1318
1470
  live,
1319
1471
  loaded: true,
1320
1472
  loadFailed: false,
@@ -1341,7 +1493,7 @@ var PublicationStore = class {
1341
1493
  includeTotal: true,
1342
1494
  limit: pageLimit$1
1343
1495
  }, signal),
1344
- this.#client.listFlowTriggerBindings(target.flowId, signal)
1496
+ this.#readBindings(target.flowId, signal)
1345
1497
  ]);
1346
1498
  }
1347
1499
  async #storedOperation(target) {
@@ -1475,7 +1627,7 @@ function inputSignature(spec) {
1475
1627
  }
1476
1628
  async function inputEditor(spec, language, values) {
1477
1629
  if (spec == null) return void 0;
1478
- const { FlowRunInputEditorStore } = await import("./flowRunInputEditorStore-Dsxyfwae.js").then((n) => n.t);
1630
+ const { FlowRunInputEditorStore } = await import("./flowRunInputEditorStore-B2Rw4VsT.js").then((n) => n.t);
1479
1631
  const editor = new FlowRunInputEditorStore(spec.definitions, language);
1480
1632
  const initial = values ?? spec.samples;
1481
1633
  if (initial != null) editor.replaceValues(initial);
@@ -2439,116 +2591,6 @@ function getConnectionsCache(options) {
2439
2591
  return getSingleton(singletonKey(oomolNamespaces.connections, options, [query.ownerId], options.sessionId), () => createConnectionsCacheInternal(options, validated));
2440
2592
  }
2441
2593
  //#endregion
2442
- //#region src/connector/common/actionSchema.ts
2443
- function connectorActionPorts(inputSchema, outputSchema) {
2444
- const inputs = inputPorts(inputSchema);
2445
- return {
2446
- inputs,
2447
- initialInputs: inputs.flatMap((input) => input.value === void 0 ? [] : [{
2448
- handle: input.handle,
2449
- value: input.value
2450
- }]),
2451
- outputs: outputPorts(outputSchema)
2452
- };
2453
- }
2454
- function inputPorts(schema) {
2455
- const root = toPlainObject(schema);
2456
- if (root == null || root.type != "object" && root.properties == null) throw new Error("Connector action inputSchema must be an object schema.");
2457
- const properties = toPlainObject(root.properties);
2458
- if (properties == null) return [];
2459
- const required = stringSet(root.required);
2460
- return Object.entries(properties).map(([handle, propertySchema]) => {
2461
- const nullable = !required.has(handle) || schemaAllowsNull(propertySchema, root);
2462
- return {
2463
- description: schemaDescription(root, propertySchema),
2464
- handle,
2465
- json_schema: propertySchemaWithDefinitions(root, propertySchema),
2466
- nullable,
2467
- value: schemaDefault(root, propertySchema, nullable)
2468
- };
2469
- });
2470
- }
2471
- function outputPorts(schema) {
2472
- const root = toPlainObject(schema);
2473
- const properties = toPlainObject(root?.properties);
2474
- if (root != null && (root.type == "object" || properties != null)) {
2475
- if (properties == null) return [];
2476
- const required = stringSet(root.required);
2477
- return Object.entries(properties).map(([handle, propertySchema]) => ({
2478
- description: schemaDescription(root, propertySchema),
2479
- handle,
2480
- json_schema: propertySchemaWithDefinitions(root, propertySchema),
2481
- nullable: !required.has(handle) || schemaAllowsNull(propertySchema, root)
2482
- }));
2483
- } else return [{
2484
- description: schemaDescription(root, schema),
2485
- handle: "output",
2486
- json_schema: schema,
2487
- nullable: schemaAllowsNull(schema)
2488
- }];
2489
- }
2490
- function propertySchemaWithDefinitions(root, schema) {
2491
- const property = toPlainObject(schema);
2492
- if (property == null) return schema;
2493
- const result = Object.assign({}, property);
2494
- if (result.$defs == null && root.$defs != null) result.$defs = root.$defs;
2495
- if (result.definitions == null && root.definitions != null) result.definitions = root.definitions;
2496
- return result;
2497
- }
2498
- function schemaDescription(root, schema) {
2499
- for (const object of referencedSchemas(root, schema)) if (typeof object.description == "string") return object.description;
2500
- }
2501
- function schemaDefault(root, schema, nullable) {
2502
- for (const object of referencedSchemas(root, schema)) if (Object.hasOwn(object, "default")) return object.default;
2503
- return nullable ? null : void 0;
2504
- }
2505
- function stringSet(value) {
2506
- if (!Array.isArray(value)) return /* @__PURE__ */ new Set();
2507
- return new Set(value.filter((item) => typeof item == "string"));
2508
- }
2509
- function schemaAllowsNull(schema, root = schema, references = /* @__PURE__ */ new Set()) {
2510
- const object = toPlainObject(schema);
2511
- if (object == null) return false;
2512
- if (Object.hasOwn(object, "type")) return object.type == "null" || Array.isArray(object.type) && object.type.includes("null");
2513
- if (Object.hasOwn(object, "enum")) return Array.isArray(object.enum) && object.enum.includes(null);
2514
- for (const key of ["anyOf", "oneOf"]) if (Object.hasOwn(object, key)) return Array.isArray(object[key]) && object[key].some((item) => schemaAllowsNull(item, root, references));
2515
- const reference = typeof object.$ref == "string" ? object.$ref : void 0;
2516
- if (reference == null || references.has(reference)) return false;
2517
- const target = resolveLocalReference(root, reference);
2518
- if (target === void 0) return false;
2519
- const nextReferences = new Set(references);
2520
- nextReferences.add(reference);
2521
- return schemaAllowsNull(target, root, nextReferences);
2522
- }
2523
- function referencedSchemas(root, schema) {
2524
- const result = [];
2525
- const references = /* @__PURE__ */ new Set();
2526
- let current = schema;
2527
- while (true) {
2528
- const object = toPlainObject(current);
2529
- if (object == null) return result;
2530
- result.push(object);
2531
- const reference = typeof object.$ref == "string" ? object.$ref : void 0;
2532
- if (reference == null || references.has(reference)) return result;
2533
- const target = resolveLocalReference(root, reference);
2534
- if (target === void 0) return result;
2535
- references.add(reference);
2536
- current = target;
2537
- }
2538
- }
2539
- function resolveLocalReference(root, reference) {
2540
- if (reference == "#") return root;
2541
- if (!reference.startsWith("#/")) return void 0;
2542
- let current = root;
2543
- for (const encodedToken of reference.slice(2).split("/")) {
2544
- const object = toPlainObject(current);
2545
- const token = encodedToken.replaceAll("~1", "/").replaceAll("~0", "~");
2546
- if (object == null || !Object.hasOwn(object, token)) return void 0;
2547
- current = object[token];
2548
- }
2549
- return current;
2550
- }
2551
- //#endregion
2552
2594
  //#region src/workbench/browser/runtime/stores/proxyCatalog.ts
2553
2595
  /** Validate the fields we consume without discarding upstream representation fields. */
2554
2596
  function proxyResponse(value, validate) {
@@ -4836,12 +4878,6 @@ var FlowCatalog = class {
4836
4878
  this.#pending.delete(flow.flowId);
4837
4879
  }
4838
4880
  }
4839
- async create(name) {
4840
- const flow = await this.#client.createFlow(name);
4841
- if (this.#disposed) return;
4842
- this.insert(flow);
4843
- return flow;
4844
- }
4845
4881
  include(flow) {
4846
4882
  const index = this.#state.value.flows.findIndex((candidate) => candidate.flowId == flow.flowId);
4847
4883
  if (index < 0) {
@@ -5025,6 +5061,7 @@ var PresentationChanges = class {
5025
5061
  #changes = Promise.resolve();
5026
5062
  #committed;
5027
5063
  #disposed = false;
5064
+ #failed = false;
5028
5065
  #pending = [];
5029
5066
  constructor(client, setNotice, setPresentation, i18n) {
5030
5067
  this.#client = client;
@@ -5033,6 +5070,7 @@ var PresentationChanges = class {
5033
5070
  this.#i18n = i18n;
5034
5071
  }
5035
5072
  reset(presentation) {
5073
+ this.#failed = false;
5036
5074
  this.#committed = presentation;
5037
5075
  this.#pending = [];
5038
5076
  }
@@ -5040,8 +5078,16 @@ var PresentationChanges = class {
5040
5078
  this.#disposed = true;
5041
5079
  this.#pending = [];
5042
5080
  }
5081
+ async flush() {
5082
+ await this.settled();
5083
+ return !this.#failed && !this.#disposed;
5084
+ }
5043
5085
  async settled() {
5044
- await this.#changes;
5086
+ let pending;
5087
+ do {
5088
+ pending = this.#changes;
5089
+ await pending;
5090
+ } while (pending !== this.#changes);
5045
5091
  }
5046
5092
  async change(flowId, presentation, current, update) {
5047
5093
  if (this.#disposed || this.#committed == null) return false;
@@ -5074,6 +5120,7 @@ var PresentationChanges = class {
5074
5120
  success = true;
5075
5121
  } catch (error) {
5076
5122
  if (this.#disposed || !current()) return;
5123
+ this.#failed = true;
5077
5124
  if (error instanceof ApiError && error.code == "flow.presentation-conflict") try {
5078
5125
  const latest = await this.#client.getPresentation(flowId);
5079
5126
  if (this.#disposed || !current()) return;
@@ -5488,14 +5535,49 @@ var WorkspaceStore = class {
5488
5535
  });
5489
5536
  return true;
5490
5537
  }
5491
- async createFlow(name, create) {
5538
+ async exportFlow(flowId) {
5539
+ const current = this.#draftSession.capture();
5540
+ const selected = this.#model.value.flowId == flowId;
5541
+ if (selected && (!await this.saveDraft() || !await this.#presentationChanges.flush() || !current())) {
5542
+ this.#setNotice({
5543
+ kind: "error",
5544
+ message: this.#i18n.t("notice.exportSaveFailed")
5545
+ });
5546
+ return;
5547
+ }
5548
+ this.#set({ busy: "flow" });
5549
+ try {
5550
+ const file = await this.#client.exportFlow(flowId);
5551
+ if (this.#disposed || selected && !current()) return;
5552
+ const url = URL.createObjectURL(new Blob([encodeWorkflowFile(file)], { type: "application/json;charset=utf-8" }));
5553
+ const link = document.createElement("a");
5554
+ link.href = url;
5555
+ link.download = workflowFileName(file.name ?? "workflow");
5556
+ link.click();
5557
+ setTimeout(() => URL.revokeObjectURL(url), 0);
5558
+ } catch (error) {
5559
+ if (!this.#disposed) this.#setNotice(errorNotice(error, this.#i18n.t));
5560
+ } finally {
5561
+ this.#set({ busy: void 0 });
5562
+ }
5563
+ }
5564
+ createFlow(name, create) {
5565
+ return this.#createFlow(async () => create == null ? this.#client.createFlow(name) : this.#client.getFlow(await create(name)));
5566
+ }
5567
+ importFlow(file, name, key, importer) {
5568
+ return this.#createFlow(async () => importer == null ? this.#client.importFlow(file, {
5569
+ name,
5570
+ idempotencyKey: key
5571
+ }) : this.#client.getFlow(await importer(file, name, key)));
5572
+ }
5573
+ async #createFlow(create) {
5492
5574
  if (!await this.saveModuleEditor()) return;
5493
5575
  this.#set({ busy: "flow" });
5494
5576
  try {
5495
- if (create == null) return await this.#flows.create(name);
5496
- const flow = await this.#client.getFlow(await create(name));
5497
- this.#flows.insert(flow);
5498
- return flow;
5577
+ const created = await create();
5578
+ if (this.#disposed) return;
5579
+ this.#flows.insert(created);
5580
+ return created;
5499
5581
  } catch (error) {
5500
5582
  if (!this.#disposed) this.#setNotice(errorNotice(error, this.#i18n.t));
5501
5583
  } finally {
@@ -6540,13 +6622,18 @@ var WorkbenchStore = class {
6540
6622
  this.#openingCreatedFlow = false;
6541
6623
  }
6542
6624
  }
6625
+ async importFlow(file, name, key, importer) {
6626
+ return await this.#openNewFlow(await this.workspace.importFlow(file, name, key, importer), "notice.flowImported");
6627
+ }
6543
6628
  async createFlow(name, create) {
6544
- const flow = await this.workspace.createFlow(name, create);
6545
- if (this.#disposed || flow == null) return false;
6546
- await this.selectFlow(flow.flowId);
6629
+ return await this.#openNewFlow(await this.workspace.createFlow(name, create), "notice.created");
6630
+ }
6631
+ async #openNewFlow(created, notice) {
6632
+ if (this.#disposed || created == null) return false;
6633
+ await this.selectFlow(created.flowId);
6547
6634
  if (!this.#disposed) this.#notice.set({
6548
6635
  kind: "success",
6549
- message: this.#i18n.t("notice.created", { name: flow.name })
6636
+ message: this.#i18n.t(notice, { name: created.name })
6550
6637
  });
6551
6638
  return true;
6552
6639
  }
@@ -6726,7 +6813,7 @@ var WorkbenchStore = class {
6726
6813
  };
6727
6814
  //#endregion
6728
6815
  //#region src/workbench/browser/runtime/openFlowWorkbench.tsx
6729
- var FlowWorkspace = lazy(() => import("./flowWorkspace-0sUJ5JhQ.js"));
6816
+ var FlowWorkspace = lazy(() => import("./flowWorkspace-B7a5NNA_.js"));
6730
6817
  function OpenFlowSessionGate({ action, description, error, onSubmit, onTokenChange, pending = false, title, token, tokenLabel }) {
6731
6818
  const hasToken = token != null && tokenLabel != null && onTokenChange != null;
6732
6819
  const tokenValue = token ?? "";
@@ -6832,11 +6919,12 @@ function FlowNameBridge({ store, onChange }) {
6832
6919
  useEffect(() => () => onChange(void 0), [onChange]);
6833
6920
  return null;
6834
6921
  }
6835
- function Workbench({ catalogWidth, createFlow, createFlowDisabled, createFlowField, flowBadges, connectionHref, hrefFor, initializing, language, navigation, onConfigureConnector, onManageConnectorAccess, onLanguageChange, store, theme }) {
6922
+ function Workbench({ importRef, catalogWidth, createFlow, importFlow, createFlowDisabled, createFlowField, flowBadges, connectionHref, hrefFor, initializing, language, navigation, onConfigureConnector, onManageConnectorAccess, onLanguageChange, store, theme }) {
6836
6923
  const flowId = useVal(store.workspace.$.flowId);
6837
6924
  return /* @__PURE__ */ jsx("div", {
6838
6925
  className: "app-shell",
6839
6926
  children: flowId == null ? /* @__PURE__ */ jsx(FlowBrowser, {
6927
+ ref: importRef,
6840
6928
  catalogWidth,
6841
6929
  createFlowDisabled,
6842
6930
  createFlowField,
@@ -6848,6 +6936,7 @@ function Workbench({ catalogWidth, createFlow, createFlowDisabled, createFlowFie
6848
6936
  initializing,
6849
6937
  language,
6850
6938
  onCreateFlow: (name) => navigation.createFlow(name, createFlow),
6939
+ onImportFlow: (file, name, key) => navigation.importFlow(file, name, key, importFlow),
6851
6940
  onLanguageChange,
6852
6941
  onSelectFlow: (flow, view) => void navigation.selectFlow(flow, view),
6853
6942
  store
@@ -6868,7 +6957,9 @@ function Workbench({ catalogWidth, createFlow, createFlowDisabled, createFlowFie
6868
6957
  })
6869
6958
  });
6870
6959
  }
6871
- function Session({ catalogWidth, createFlow, createFlowDisabled, createFlowField, flowBadges, connectionHref, host, hrefFor, language, location, onConfigureConnector, onManageConnectorAccess, onLanguageChange, onNavigate, onFlowNameChange, preferences, sessionKey, theme, variables = true }) {
6960
+ var Session = forwardRef(function Session({ catalogWidth, createFlow, importFlow, createFlowDisabled, createFlowField, flowBadges, connectionHref, host, hrefFor, language, location, onConfigureConnector, onManageConnectorAccess, onLanguageChange, onNavigate, onFlowNameChange, preferences, sessionKey, theme, variables = true }, ref) {
6961
+ const importRef = useRef(null);
6962
+ useImperativeHandle(ref, () => ({ openImport: (input) => importRef.current?.openImport(input) ?? "unavailable" }), []);
6872
6963
  const navigate = useRef(onNavigate);
6873
6964
  navigate.current = onNavigate;
6874
6965
  const [{ i18n, navigation, store }] = useState(() => {
@@ -6932,8 +7023,10 @@ function Session({ catalogWidth, createFlow, createFlowDisabled, createFlowField
6932
7023
  onChange: onFlowNameChange
6933
7024
  }),
6934
7025
  started || location.flowId == null ? /* @__PURE__ */ jsx(Workbench, {
7026
+ importRef: location.flowId == null ? importRef : void 0,
6935
7027
  catalogWidth,
6936
7028
  createFlow,
7029
+ importFlow,
6937
7030
  createFlowDisabled,
6938
7031
  createFlowField,
6939
7032
  flowBadges,
@@ -6955,12 +7048,13 @@ function Session({ catalogWidth, createFlow, createFlowDisabled, createFlowField
6955
7048
  })
6956
7049
  })
6957
7050
  });
6958
- }
6959
- function OpenFlowWorkbench({ sessionKey, ...props }) {
7051
+ });
7052
+ var OpenFlowWorkbench = forwardRef(function OpenFlowWorkbench({ sessionKey, ...props }, ref) {
6960
7053
  return /* @__PURE__ */ jsx(Session, {
7054
+ ref,
6961
7055
  sessionKey,
6962
7056
  ...props
6963
7057
  }, `${sessionKey}:${props.host.connectorOwnerId ?? ""}`);
6964
- }
7058
+ });
6965
7059
  //#endregion
6966
7060
  export { EventSourcesPage, OpenFlowSessionGate, OpenFlowWorkbench, isUiLanguage as isWorkbenchLanguage, resolveUiLanguage as resolveWorkbenchLanguage, uiLanguageNames as workbenchLanguageNames, uiLanguages as workbenchLanguages };