@oomol-lab/open-flow 0.1.0-beta.50 → 0.1.0-beta.52

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 (44) hide show
  1. package/dist/browser/{createResourceDialog-CSltk-qY.js → createResourceDialog-BsaBMf7_.js} +2 -1
  2. package/dist/browser/flow-authoring-node.d.ts +3 -1
  3. package/dist/browser/flow-authoring.js +82 -3
  4. package/dist/browser/flow-change-schema.d.ts +1 -1
  5. package/dist/browser/flow-change.d.ts +15 -2
  6. package/dist/browser/flow-change.js +81 -3
  7. package/dist/browser/{flowChanges-DbYrpHnS.js → flowChanges-DtraMpva.js} +3858 -1921
  8. package/dist/browser/{flowWorkspace-CjwpbVBR.js → flowWorkspace-DLgti4Lk.js} +1353 -513
  9. package/dist/browser/{workbenchSelect-oVujN2z6.js → icons-0s-Q_3lp.js} +92 -35
  10. package/dist/browser/licenses.md +204 -0
  11. package/dist/browser/preview.css +302 -179
  12. package/dist/browser/preview.js +4829 -2198
  13. package/dist/browser/theme.css +2 -0
  14. package/dist/browser/ui-hostNavigationActions.d.ts +13 -0
  15. package/dist/browser/ui-hostTooltip.d.ts +8 -0
  16. package/dist/browser/ui-logo.d.ts +5 -0
  17. package/dist/browser/ui.css +102 -8
  18. package/dist/browser/ui.d.ts +3 -0
  19. package/dist/browser/ui.js +176 -11
  20. package/dist/browser/workbench-contract.d.ts +5 -11
  21. package/dist/browser/workbench.css +366 -200
  22. package/dist/browser/workbench.d.ts +1 -1
  23. package/dist/browser/workbench.js +1154 -379
  24. package/dist/browser/workbenchSelect-BqUPacsr.js +31 -0
  25. package/dist/common/authoringExamples.d.ts +4 -2
  26. package/dist/common/control-api-conformance.js +129 -11
  27. package/dist/common/control-api.d.ts +38 -5
  28. package/dist/common/control-api.js +198 -12
  29. package/dist/common/control-requests.d.ts +4 -0
  30. package/dist/common/control-requests.js +1320 -67
  31. package/dist/common/flow-encoding.js +64 -5
  32. package/dist/common/flow-semantics.js +823 -316
  33. package/dist/common/integration-trigger.js +39 -1
  34. package/dist/common/mcp.js +129 -11
  35. package/dist/common/openapi.d.ts +53 -0
  36. package/dist/common/openapi.js +10390 -0
  37. package/dist/common/poll-trigger.js +39 -1
  38. package/dist/common/provider-triggers.js +39 -1
  39. package/dist/common/run-events.js +26 -1
  40. package/dist/common/scheduler.d.ts +4 -1
  41. package/dist/common/scheduler.js +122 -6
  42. package/dist/common/trigger-contract.d.ts +2 -0
  43. package/dist/common/webhook-trigger.js +39 -1
  44. package/package.json +5 -1
@@ -1,7 +1,7 @@
1
- import { $t as EmptyTitle, An as connectorActionMetadata, At as flowDependencies, Bn as IconThemeContext, Ct as resetInputValues, Dt as setTriggerConnection, Et as setInputSources, F as deriveAddNodeOptions, Fn as string, Ft as PopoverContent, G as resourceValue, Gt as InputGroup, H as Resource, In as providerIconAppearance, Jt as Empty, K as designerGraph, Kt as InputGroupAddon, L as feishuResourceKind, Ln as ApiError, Mn as invalidResponse, Mt as followWorkbenchLink, Nn as jsonValue, Nt as Switch, Ot as updateTriggerConfig, P as addNodeIntent, Pn as record, Pt as Popover, Qt as EmptyMedia, R as supportsFeishuChatFilter, Rn as controlErrorCode, Rt as PopoverTitle, St as repairNodeNames, Tn as isJsonObject, Tt as setConnectorConnection, V as scopedValue, W as resourceData, X as providerIcon, Xt as EmptyDescription, Yt as EmptyContent, Zt as EmptyHeader, _ as updateTaskAdditionalInputs, _n as WorkbenchClient, _t as setComment, a as deleteSelection, at as Latest, b as updateWebhook, bt as setNodePositions, c as setInputVariable, d as updateNodeIcon, dt as actionWithConnections, en as EventSourcesPage, f as updateNodeName, ft as connectionCatalog, g as updateTask, gn as errorNotice, gt as restoreCanvasPresentation, h as updateSubflow, ht as removeComments, i as createResource, it as revisionView, jn as inputValue, jt as IdTooltip, kn as connection, kt as updateTriggerSchedule, l as updateCondition, m as updateResolution, mt as commentIds, o as nameCreatedNodes, ot as deriveInspectorDiagnostics, p as updateNodeSettings, pt as canvasPresentationChange, qt as InputGroupInput, r as applyFlowChanges, rn as createI18n, s as setInputValue, st as diagnosticItems, t as addNode, tt as RunStore, u as updateNodeDescription, v as updateTaskPorts, vn as randomId, vt as setFlowViewport, wn as triggerOutputDefinitions, wt as setCodeActions, xn as decodeTriggerCatalog, xt as targetPresentation, y as updateValue, yn as allConnectorConnectionsQuery, yt as setNodeContentHidden, z as combineSources, zt as PopoverTrigger } from "./flowChanges-DbYrpHnS.js";
1
+ import { $t as InputGroup, At as flowDependencies, Bn as inputValue, Bt as followWorkbenchLink, Ct as resetInputValues, Dn as allConnectorConnectionsQuery, Dt as setTriggerConnection, En as randomId, Et as setInputSources, F as deriveAddNodeOptions, G as resourceValue, Gn as providerIconAppearance, H as CacheResource, Hn as jsonValue, Ht as Popover, K as designerGraph, Kn as ApiError, Kt as PopoverTitle, L as feishuResourceKind, Mn as sampleErrorOutputs, Nn as triggerOutputDefinitions, Ot as updateTriggerConfig, P as addNodeIntent, Pn as isJsonObject, R as supportsFeishuChatFilter, Rn as connection, St as repairNodeNames, Tn as WorkbenchClient, Tt as setConnectorConnection, Un as record, Ut as PopoverContent, V as scopedValue, Vn as invalidResponse, Vt as Switch, W as resourceData, Wn as string, X as providerIcon, Yn as IconThemeContext, _ as updateTaskAdditionalInputs, _t as setComment, a as deleteSelection, an as EmptyHeader, at as Latest, b as updateWebhook, bt as setNodePositions, c as setInputVariable, cn as EventSourcesPage, d as updateNodeIcon, dn as createI18n, dt as actionWithConnections, en as InputGroupAddon, f as updateNodeName, ft as connectionCatalog, g as updateTask, gt as restoreCanvasPresentation, h as updateSubflow, ht as removeComments, i as createResource, in as EmptyDescription, it as revisionView, kn as decodeTriggerCatalog, kt as updateTriggerSchedule, l as updateCondition, m as updateResolution, mt as commentIds, nn as Empty, o as nameCreatedNodes, on as EmptyMedia, ot as deriveInspectorDiagnostics, p as updateNodeSettings, pt as canvasPresentationChange, qn as controlErrorCode, qt as PopoverTrigger, r as applyFlowChanges, rn as EmptyContent, s as setInputValue, sn as EmptyTitle, st as diagnosticItems, t as addNode, tn as InputGroupInput, tt as RunStore, u as updateNodeDescription, v as updateTaskPorts, vt as setFlowViewport, wn as errorNotice, wt as setCodeActions, xt as targetPresentation, y as updateValue, yt as setNodeContentHidden, z as combineSources, zn as connectorActionMetadata, zt as IdTooltip } from "./flowChanges-DtraMpva.js";
2
2
  import { a as derive, i as compute, l as val } from "./dist-bO8nvHFH.js";
3
3
  import { a as useVal, i as useTranslate, r as useLang, t as I18nProvider } from "./main-BPABKzwN.js";
4
- import { D as FlowChangeError, E as FieldLabel, Fr as Button, L as mapConditionSources, Lr as cn, Mn as Input, N as portsByHandle, O as applyFlowChanges$1, P as resourceNameIssue, R as nodeInputMappings, S as Field, T as FieldGroup, a as DialogContent, c as DialogHeader, d as Tooltip, f as TooltipContent, i as DialogClose, l as DialogTitle, m as TooltipTrigger, n as Icon, o as DialogDescription, q as dequal$1, r as Dialog, s as DialogFooter, t as WorkbenchSelect, w as FieldError, x as Spinner } from "./workbenchSelect-oVujN2z6.js";
4
+ import { C as FieldError, D as applyFlowChanges$1, E as FlowChangeError, I as mapConditionSources, Ir as cn, K as dequal$1, L as nodeInputMappings, N as resourceNameIssue, Pr as Button, T as FieldLabel, a as DialogDescription, b as Spinner, c as DialogTitle, d as TooltipContent, i as DialogContent, jn as Input, n as Dialog, o as DialogFooter, p as TooltipTrigger, r as DialogClose, s as DialogHeader, t as Icon, u as Tooltip, w as FieldGroup, x as Field } from "./icons-0s-Q_3lp.js";
5
5
  import { a as toPlainObject } from "./dist-BDBTOgS5.js";
6
6
  import { c as isUiLanguage, d as uiLanguages, l as resolveUiLanguage, u as uiLanguageNames } from "./value-DL_poNiC.js";
7
7
  import { Suspense, lazy, useEffect, useRef, useState } from "react";
@@ -68,6 +68,9 @@ var NavigationStore = class {
68
68
  this.#store = store;
69
69
  this.#view.set(location.view);
70
70
  }
71
+ get runId() {
72
+ return this.#location.view == "runs" ? this.#location.runId : void 0;
73
+ }
71
74
  get runSource() {
72
75
  return this.#location.view == "runs" ? this.#location.runSource : void 0;
73
76
  }
@@ -155,15 +158,19 @@ var NavigationStore = class {
155
158
  #sync;
156
159
  #write(view, replace, options = this.#location) {
157
160
  const flowId = this.#store.workspace.$.flowId.value;
158
- const { runSource } = options;
161
+ const { runSource, runId } = options;
159
162
  const location = {
160
163
  flowId,
161
164
  view: flowId == null ? "design" : view,
162
- ...flowId != null && view == "runs" && runSource != null ? { runSource } : {}
165
+ ...flowId != null && view == "runs" && runSource != null ? { runSource } : {},
166
+ ...flowId != null && view == "runs" && runId != null ? { runId } : {}
163
167
  };
164
168
  if (this.#ready.value && this.#view.value == "runs" && location.view == "runs") {
165
169
  const filter = this.#store.runs.$.filter.value;
166
- if (filter.source != location.runSource) this.#store.runs.applyFilter({
170
+ if (filter.source != location.runSource || filter.runId != location.runId) this.#store.runs.applyFilter(location.runId != filter.runId ? {
171
+ source: location.runSource,
172
+ runId: location.runId
173
+ } : {
167
174
  ...filter,
168
175
  source: location.runSource
169
176
  });
@@ -176,7 +183,7 @@ var NavigationStore = class {
176
183
  }
177
184
  };
178
185
  function sameLocation(left, right) {
179
- return left.flowId == right.flowId && left.view == right.view && left.runSource == right.runSource;
186
+ return left.flowId == right.flowId && left.view == right.view && left.runSource == right.runSource && left.runId == right.runId;
180
187
  }
181
188
  //#endregion
182
189
  //#region src/ui/browser/skeleton.tsx
@@ -189,34 +196,11 @@ function Skeleton({ className, ...props }) {
189
196
  }
190
197
  //#endregion
191
198
  //#region src/workbench/browser/runtime/shell/resourceBrowser.tsx
192
- var CreateResourceDialog = lazy(() => import("./createResourceDialog-CSltk-qY.js"));
193
- var languageOptions = uiLanguages.map((language) => ({
194
- label: uiLanguageNames[language],
195
- value: language
196
- }));
199
+ var CreateResourceDialog = lazy(() => import("./createResourceDialog-BsaBMf7_.js"));
197
200
  var flowIdTooltipAlignOffset = 44;
198
201
  var renamePopoverAlignOffset = -12;
199
202
  var renamePopoverVerticalShift = 8;
200
203
  var rowControlSelector = "a, button, input, select, textarea, [data-slot=\"tooltip-trigger\"]";
201
- function LanguageSelect({ language, onLanguageChange }) {
202
- const t = useTranslate();
203
- const [portalRoot, setPortalRoot] = useState(null);
204
- if (onLanguageChange == null) return null;
205
- return /* @__PURE__ */ jsxs("div", {
206
- className: "resource-language",
207
- ref: setPortalRoot,
208
- children: [/* @__PURE__ */ jsx("span", {
209
- className: "sr-only",
210
- children: t("language.label")
211
- }), /* @__PURE__ */ jsx(WorkbenchSelect, {
212
- ariaLabel: t("language.label"),
213
- onValueChange: (value) => onLanguageChange(value),
214
- options: languageOptions,
215
- portalRoot,
216
- value: language
217
- })]
218
- });
219
- }
220
204
  function compactFlowId(flowId) {
221
205
  return flowId.length <= 20 ? flowId : `${flowId.slice(0, 10)}…${flowId.slice(-6)}`;
222
206
  }
@@ -234,6 +218,56 @@ function formatUpdatedAt(updatedAt, locale) {
234
218
  function clickedRowControl(event) {
235
219
  return event.target instanceof Element && event.target.closest(rowControlSelector) != null;
236
220
  }
221
+ function FlowDeletionImpact({ listeners, failed, onRetry }) {
222
+ const t = useTranslate();
223
+ if (failed) return /* @__PURE__ */ jsxs("div", {
224
+ className: "space-y-2",
225
+ children: [/* @__PURE__ */ jsx("p", {
226
+ role: "alert",
227
+ className: "text-sm text-destructive",
228
+ children: t("sidebar.listenersFailed")
229
+ }), /* @__PURE__ */ jsx(Button, {
230
+ variant: "outline",
231
+ size: "sm",
232
+ onClick: onRetry,
233
+ children: t("errorWorkflow.retry")
234
+ })]
235
+ });
236
+ if (listeners == null) return /* @__PURE__ */ jsx("p", {
237
+ role: "status",
238
+ className: "text-sm text-muted-foreground",
239
+ children: t("sidebar.listenersLoading")
240
+ });
241
+ if (listeners.length == 0) return null;
242
+ return /* @__PURE__ */ jsxs("div", {
243
+ className: "min-w-0 space-y-3 text-sm",
244
+ children: [
245
+ /* @__PURE__ */ jsx("p", { children: t("sidebar.listenersTitle") }),
246
+ /* @__PURE__ */ jsx("ul", {
247
+ className: "m-0 max-h-48 list-none space-y-2 overflow-y-auto p-0",
248
+ children: listeners.map((listener) => /* @__PURE__ */ jsxs("li", {
249
+ className: "break-words",
250
+ children: [
251
+ /* @__PURE__ */ jsx("span", {
252
+ className: "font-medium",
253
+ children: listener.flowName
254
+ }),
255
+ " / ",
256
+ listener.nodeName,
257
+ !listener.enabled && /* @__PURE__ */ jsx("span", {
258
+ className: "ml-2 text-muted-foreground",
259
+ children: t("sidebar.listenerDisabled")
260
+ })
261
+ ]
262
+ }, `${listener.flowId}/${listener.nodeId}`))
263
+ }),
264
+ /* @__PURE__ */ jsx("p", {
265
+ className: "text-muted-foreground",
266
+ children: t("sidebar.listenersImpact")
267
+ })
268
+ ]
269
+ });
270
+ }
237
271
  function FlowItem({ badge, busy, flow, href, onSelect, store }) {
238
272
  const [root, setRoot] = useState(null);
239
273
  const renameAnchor = useRef(null);
@@ -244,6 +278,26 @@ function FlowItem({ badge, busy, flow, href, onSelect, store }) {
244
278
  const t = useTranslate();
245
279
  const [mode, setMode] = useState("idle");
246
280
  const [name, setName] = useState(flow.name);
281
+ const [listeners, setListeners] = useState();
282
+ const [listenersFailed, setListenersFailed] = useState(false);
283
+ const [listenersRetry, setListenersRetry] = useState(0);
284
+ useEffect(() => {
285
+ if (mode != "delete") return;
286
+ const controller = new AbortController();
287
+ setListeners(void 0);
288
+ setListenersFailed(false);
289
+ store.workspace.getErrorListeners(flow.flowId, controller.signal).then((value) => {
290
+ if (!controller.signal.aborted) setListeners(value);
291
+ }, () => {
292
+ if (!controller.signal.aborted) setListenersFailed(true);
293
+ });
294
+ return () => controller.abort();
295
+ }, [
296
+ mode,
297
+ flow.flowId,
298
+ store,
299
+ listenersRetry
300
+ ]);
247
301
  const [pending, setPending] = useState();
248
302
  const changed = flow.live != null && flow.live.revisionId != flow.draftRevisionId;
249
303
  const publicationStatus = flow.status == "retiring" ? "resource.retiring" : flow.live == null ? "resource.notPublished" : changed ? "resource.unpublishedChanges" : "resource.isPublished";
@@ -427,12 +481,19 @@ function FlowItem({ badge, busy, flow, href, onSelect, store }) {
427
481
  "aria-hidden": "true",
428
482
  className: cn("status-dot", publicationTone)
429
483
  }),
430
- t(publicationStatus),
431
- flow.live != null && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
432
- "aria-hidden": "true",
433
- className: "resource-status-separator",
434
- children: "·"
435
- }), /* @__PURE__ */ jsx("span", { children: t(flow.live.enabled ? "resource.enabled" : "resource.disabled") })] })
484
+ /* @__PURE__ */ jsx("span", { children: t(publicationStatus) }),
485
+ flow.live != null && /* @__PURE__ */ jsxs("span", {
486
+ className: "resource-enabled-status",
487
+ "aria-busy": pending == "enabled",
488
+ children: [/* @__PURE__ */ jsx("span", { children: t(flow.live.enabled ? "resource.enabled" : "resource.disabled") }), /* @__PURE__ */ jsx(Switch, {
489
+ "aria-label": t("resource.enableFlow", { name: flow.name }),
490
+ checked: flow.live.enabled,
491
+ disabled: flow.status != "active" || busy != null || pending != null,
492
+ onCheckedChange: (enabled) => void update(enabled),
493
+ size: "sm",
494
+ title: t("resource.enabledHint")
495
+ })]
496
+ })
436
497
  ]
437
498
  })
438
499
  ]
@@ -442,14 +503,6 @@ function FlowItem({ badge, busy, flow, href, onSelect, store }) {
442
503
  "aria-busy": pending != null,
443
504
  onClick: openFromRow,
444
505
  children: [
445
- flow.live != null && /* @__PURE__ */ jsx(Switch, {
446
- "aria-label": t("resource.enableFlow", { name: flow.name }),
447
- checked: flow.live.enabled,
448
- disabled: flow.status != "active" || busy != null || pending != null,
449
- onCheckedChange: (enabled) => void update(enabled),
450
- size: "sm",
451
- title: t("resource.enabledHint")
452
- }),
453
506
  flow.status == "active" && /* @__PURE__ */ jsx(Button, {
454
507
  onClick: () => onSelect(flow),
455
508
  size: "sm",
@@ -496,18 +549,26 @@ function FlowItem({ badge, busy, flow, href, onSelect, store }) {
496
549
  initialFocus: cancelDelete,
497
550
  finalFocus: deleteButton,
498
551
  showCloseButton: false,
499
- children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: t("sidebar.deleteFlowConfirm", { name: flow.name }) }), /* @__PURE__ */ jsx(DialogDescription, { children: t("resource.deleteDescription") })] }), /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(DialogClose, {
500
- render: /* @__PURE__ */ jsx(Button, {
501
- ref: cancelDelete,
502
- variant: "outline"
552
+ children: [
553
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: t("sidebar.deleteFlowConfirm", { name: flow.name }) }), /* @__PURE__ */ jsx(DialogDescription, { children: t("resource.deleteDescription") })] }),
554
+ /* @__PURE__ */ jsx(FlowDeletionImpact, {
555
+ listeners,
556
+ failed: listenersFailed,
557
+ onRetry: () => setListenersRetry((value) => value + 1)
503
558
  }),
504
- children: t("common.cancel")
505
- }), /* @__PURE__ */ jsx(Button, {
506
- disabled: busy != null,
507
- onClick: () => void remove(),
508
- variant: "destructive",
509
- children: t(busy == "flow" ? "common.deleting" : "common.delete")
510
- })] })]
559
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(DialogClose, {
560
+ render: /* @__PURE__ */ jsx(Button, {
561
+ ref: cancelDelete,
562
+ variant: "outline"
563
+ }),
564
+ children: t("common.cancel")
565
+ }), /* @__PURE__ */ jsx(Button, {
566
+ disabled: busy != null || listeners == null && !listenersFailed,
567
+ onClick: () => void remove(),
568
+ variant: "destructive",
569
+ children: t(busy == "flow" ? "common.deleting" : "common.delete")
570
+ })] })
571
+ ]
511
572
  })
512
573
  })
513
574
  ]
@@ -534,7 +595,7 @@ function FlowSkeleton() {
534
595
  })]
535
596
  });
536
597
  }
537
- function FlowBrowser({ catalogWidth, createFlowDisabled, createFlowField, flowBadges, hrefForFlow, language, onCreateFlow, onLanguageChange, onSelectFlow, store }) {
598
+ function FlowBrowser({ catalogWidth, createFlowDisabled, createFlowField, flowBadges, hrefForFlow, onCreateFlow, onSelectFlow, store }) {
538
599
  const t = useTranslate();
539
600
  const busy = useVal(store.workspace.$.busy);
540
601
  const loadFailed = useVal(store.workspace.$.flowLoadFailed);
@@ -581,107 +642,105 @@ function FlowBrowser({ catalogWidth, createFlowDisabled, createFlowField, flowBa
581
642
  }), !loading && /* @__PURE__ */ jsx("span", { children: t("resource.flowCount", { count: total ?? flows.length }) })]
582
643
  }), /* @__PURE__ */ jsxs("div", {
583
644
  className: "resource-list-actions",
584
- children: [
585
- /* @__PURE__ */ jsx(LanguageSelect, {
586
- language,
587
- onLanguageChange
588
- }),
589
- /* @__PURE__ */ jsxs(InputGroup, {
590
- className: "w-full sm:w-56",
591
- children: [/* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(Icon, {
592
- name: "search",
593
- size: 17
594
- }) }), /* @__PURE__ */ jsx(InputGroupInput, {
595
- autoComplete: "off",
596
- "aria-label": t("resource.searchByName"),
597
- name: "flow-search",
598
- onChange: (event) => setFilter(event.target.value),
599
- placeholder: t("resource.searchByName"),
600
- value: filter
601
- })]
602
- }),
603
- /* @__PURE__ */ jsxs(Button, {
604
- className: "pr-3",
605
- disabled: busy != null,
606
- onClick: () => setCreating(true),
607
- children: [/* @__PURE__ */ jsx(Icon, {
608
- "data-icon": "inline-start",
609
- name: "plus"
610
- }), t("resource.newFlow")]
611
- })
612
- ]
613
- })]
614
- }),
615
- /* @__PURE__ */ jsxs("div", {
616
- "aria-hidden": "true",
617
- className: "resource-list-columns-shell",
618
- children: [/* @__PURE__ */ jsxs("div", {
619
- className: "resource-list-columns flow-columns",
620
- children: [
621
- /* @__PURE__ */ jsx("span", { children: t("resource.name") }),
622
- /* @__PURE__ */ jsx("span", {
623
- className: "resource-flow-id-heading",
624
- children: t("resource.flowId")
625
- }),
626
- /* @__PURE__ */ jsx("span", {
627
- className: "resource-updated-heading",
628
- children: t("resource.updated")
629
- }),
630
- /* @__PURE__ */ jsx("span", { children: t("resource.status") })
631
- ]
632
- }), /* @__PURE__ */ jsx("span", {
633
- className: "resource-actions-heading",
634
- children: t("resource.actions")
635
- })]
636
- }),
637
- /* @__PURE__ */ jsx("div", {
638
- className: "resource-list",
639
- children: loading ? Array.from({ length: 5 }, (_, index) => /* @__PURE__ */ jsx(FlowSkeleton, {}, index)) : loadFailed ? /* @__PURE__ */ jsxs(Empty, {
640
- className: "min-h-64",
641
- role: "alert",
642
- children: [/* @__PURE__ */ jsxs(EmptyHeader, { children: [
643
- /* @__PURE__ */ jsx(EmptyMedia, {
644
- variant: "icon",
645
- children: /* @__PURE__ */ jsx(Icon, {
646
- name: "alert",
647
- size: 20
648
- })
649
- }),
650
- /* @__PURE__ */ jsx(EmptyTitle, { children: t("resource.flowsLoadFailed") }),
651
- /* @__PURE__ */ jsx(EmptyDescription, { children: t("resource.flowsLoadFailedDescription") })
652
- ] }), /* @__PURE__ */ jsx(EmptyContent, { children: /* @__PURE__ */ jsx(Button, {
653
- onClick: () => void store.retryFlows(),
654
- variant: "outline",
655
- children: t("empty.retry")
656
- }) })]
657
- }) : visible.length == 0 ? /* @__PURE__ */ jsxs(Empty, {
658
- className: "min-h-64",
659
- children: [/* @__PURE__ */ jsxs(EmptyHeader, { children: [
660
- /* @__PURE__ */ jsx(EmptyMedia, {
661
- variant: "icon",
662
- children: /* @__PURE__ */ jsx(Icon, {
663
- name: "flow",
664
- size: 20
665
- })
666
- }),
667
- /* @__PURE__ */ jsx(EmptyTitle, { children: t(normalized.length == 0 ? "resource.noFlows" : "resource.noMatchingFlows") }),
668
- /* @__PURE__ */ jsx(EmptyDescription, { children: t(normalized.length == 0 ? "resource.noFlowsDescription" : "resource.noMatchingDescription") })
669
- ] }), normalized.length == 0 && /* @__PURE__ */ jsx(EmptyContent, { children: /* @__PURE__ */ jsxs(Button, {
645
+ children: [/* @__PURE__ */ jsxs(InputGroup, {
646
+ className: "w-full sm:w-56",
647
+ children: [/* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(Icon, {
648
+ name: "search",
649
+ size: 17
650
+ }) }), /* @__PURE__ */ jsx(InputGroupInput, {
651
+ autoComplete: "off",
652
+ "aria-label": t("resource.searchByName"),
653
+ name: "flow-search",
654
+ onChange: (event) => setFilter(event.target.value),
655
+ placeholder: t("resource.searchByName"),
656
+ value: filter
657
+ })]
658
+ }), /* @__PURE__ */ jsxs(Button, {
659
+ className: "pr-3",
660
+ disabled: busy != null,
670
661
  onClick: () => setCreating(true),
671
- variant: "outline",
672
662
  children: [/* @__PURE__ */ jsx(Icon, {
673
663
  "data-icon": "inline-start",
674
664
  name: "plus"
675
665
  }), t("resource.newFlow")]
676
- }) })]
677
- }) : visible.map((flow) => /* @__PURE__ */ jsx(FlowItem, {
678
- badge: flowBadges?.[flow.flowId],
679
- busy,
680
- flow,
681
- href: hrefForFlow(flow),
682
- onSelect: onSelectFlow,
683
- store
684
- }, flow.flowId))
666
+ })]
667
+ })]
668
+ }),
669
+ /* @__PURE__ */ jsx("div", {
670
+ className: "resource-table-scroll",
671
+ children: /* @__PURE__ */ jsxs("div", {
672
+ className: "resource-table",
673
+ children: [/* @__PURE__ */ jsxs("div", {
674
+ "aria-hidden": "true",
675
+ className: "resource-list-columns-shell",
676
+ children: [/* @__PURE__ */ jsxs("div", {
677
+ className: "resource-list-columns flow-columns",
678
+ children: [
679
+ /* @__PURE__ */ jsx("span", { children: t("resource.name") }),
680
+ /* @__PURE__ */ jsx("span", {
681
+ className: "resource-flow-id-heading",
682
+ children: t("resource.flowId")
683
+ }),
684
+ /* @__PURE__ */ jsx("span", {
685
+ className: "resource-updated-heading",
686
+ children: t("resource.updated")
687
+ }),
688
+ /* @__PURE__ */ jsx("span", { children: t("resource.status") })
689
+ ]
690
+ }), /* @__PURE__ */ jsx("span", {
691
+ className: "resource-actions-heading",
692
+ children: t("resource.actions")
693
+ })]
694
+ }), /* @__PURE__ */ jsx("div", {
695
+ className: "resource-list",
696
+ children: loading ? Array.from({ length: 5 }, (_, index) => /* @__PURE__ */ jsx(FlowSkeleton, {}, index)) : loadFailed ? /* @__PURE__ */ jsxs(Empty, {
697
+ className: "min-h-64",
698
+ role: "alert",
699
+ children: [/* @__PURE__ */ jsxs(EmptyHeader, { children: [
700
+ /* @__PURE__ */ jsx(EmptyMedia, {
701
+ variant: "icon",
702
+ children: /* @__PURE__ */ jsx(Icon, {
703
+ name: "alert",
704
+ size: 20
705
+ })
706
+ }),
707
+ /* @__PURE__ */ jsx(EmptyTitle, { children: t("resource.flowsLoadFailed") }),
708
+ /* @__PURE__ */ jsx(EmptyDescription, { children: t("resource.flowsLoadFailedDescription") })
709
+ ] }), /* @__PURE__ */ jsx(EmptyContent, { children: /* @__PURE__ */ jsx(Button, {
710
+ onClick: () => void store.retryFlows(),
711
+ variant: "outline",
712
+ children: t("empty.retry")
713
+ }) })]
714
+ }) : visible.length == 0 ? /* @__PURE__ */ jsxs(Empty, {
715
+ className: "min-h-64",
716
+ children: [/* @__PURE__ */ jsxs(EmptyHeader, { children: [
717
+ /* @__PURE__ */ jsx(EmptyMedia, {
718
+ variant: "icon",
719
+ children: /* @__PURE__ */ jsx(Icon, {
720
+ name: "flow",
721
+ size: 20
722
+ })
723
+ }),
724
+ /* @__PURE__ */ jsx(EmptyTitle, { children: t(normalized.length == 0 ? "resource.noFlows" : "resource.noMatchingFlows") }),
725
+ /* @__PURE__ */ jsx(EmptyDescription, { children: t(normalized.length == 0 ? "resource.noFlowsDescription" : "resource.noMatchingDescription") })
726
+ ] }), normalized.length == 0 && /* @__PURE__ */ jsx(EmptyContent, { children: /* @__PURE__ */ jsxs(Button, {
727
+ onClick: () => setCreating(true),
728
+ variant: "outline",
729
+ children: [/* @__PURE__ */ jsx(Icon, {
730
+ "data-icon": "inline-start",
731
+ name: "plus"
732
+ }), t("resource.newFlow")]
733
+ }) })]
734
+ }) : visible.map((flow) => /* @__PURE__ */ jsx(FlowItem, {
735
+ badge: flowBadges?.[flow.flowId],
736
+ busy,
737
+ flow,
738
+ href: hrefForFlow(flow),
739
+ onSelect: onSelectFlow,
740
+ store
741
+ }, flow.flowId))
742
+ })]
743
+ })
685
744
  }),
686
745
  nextCursor != null && /* @__PURE__ */ jsx("div", {
687
746
  className: "resource-list-footer",
@@ -1421,87 +1480,34 @@ var PublicationStore = class {
1421
1480
  //#endregion
1422
1481
  //#region src/workbench/browser/runtime/runs/runRequestStore.ts
1423
1482
  var initialState$5 = { starting: false };
1424
- function inputPorts$1(node) {
1425
- switch (node.kind) {
1426
- case "condition": return {};
1427
- case "subflow": return portsByHandle(node.definition?.inputs ?? []);
1428
- case "task": return portsByHandle(node.definition?.inputs ?? []);
1429
- case "value": return {};
1430
- case "approval":
1431
- case "wait": return portsByHandle(node.node.inputDefinitions);
1432
- }
1433
- }
1434
- function nodeTitle(node) {
1435
- if (node.node.name != null) return node.node.name;
1436
- if (node.kind == "task" || node.kind == "subflow") return node.definition?.name ?? node.id;
1437
- return node.id;
1438
- }
1439
- function inputSpecs(draft, triggerId) {
1440
- const revision = revisionView(draft);
1441
- const graph = revision.graph({ kind: "flow" });
1442
- if (graph == null) return [];
1443
- const reachable = /* @__PURE__ */ new Set([triggerId]);
1444
- const pending = [triggerId];
1445
- while (pending.length > 0) {
1446
- const source = pending.pop();
1447
- for (const edge of graph.edges) {
1448
- if (edge.source != source || reachable.has(edge.target)) continue;
1449
- reachable.add(edge.target);
1450
- pending.push(edge.target);
1451
- }
1452
- }
1453
- return Object.entries(graph.nodes).filter(([id]) => reachable.has(id)).toSorted(([left], [right]) => left.localeCompare(right)).flatMap(([nodeId, node]) => {
1454
- const resolved = revision.resolveNode(nodeId, node);
1455
- if (resolved.kind == "trigger") {
1456
- if (resolved.trigger.kind == "manual" || resolved.trigger.kind == "cron") return [];
1457
- return [{
1458
- definitions: triggerOutputDefinitions(resolved.trigger),
1459
- nodeId,
1460
- title: resolved.trigger.name
1461
- }];
1462
- }
1463
- const definitions = Object.entries(inputPorts$1(resolved)).filter(([handle, port]) => resolved.node.inputs[handle] == null && !Object.hasOwn(port, "value")).toSorted(([left], [right]) => left.localeCompare(right)).map(([handle, port]) => Object.assign({
1464
- handle,
1465
- jsonSchema: port.jsonSchema,
1466
- nullable: port.nullable
1467
- }, port.description == null ? {} : { description: port.description }));
1468
- return definitions.length == 0 ? [] : [{
1469
- definitions,
1470
- nodeId,
1471
- title: nodeTitle(resolved)
1472
- }];
1473
- });
1483
+ function inputSpec(draft, triggerId) {
1484
+ const trigger = revisionView(draft).graph({ kind: "flow" })?.nodes[triggerId];
1485
+ if (trigger == null || "inputs" in trigger || trigger.kind == "manual" || trigger.kind == "cron") return void 0;
1486
+ const definitions = triggerOutputDefinitions(trigger);
1487
+ return definitions.length === 0 ? void 0 : {
1488
+ definitions,
1489
+ samples: trigger.kind == "error" ? sampleErrorOutputs : void 0
1490
+ };
1474
1491
  }
1475
- function inputSignature(specs) {
1476
- return JSON.stringify(specs.map((group) => [group.nodeId, group.definitions.map((definition) => [
1492
+ function inputSignature(spec) {
1493
+ return JSON.stringify(spec?.definitions.map((definition) => [
1477
1494
  definition.handle,
1478
1495
  definition.jsonSchema,
1479
1496
  definition.nullable
1480
- ])]));
1497
+ ]) ?? []);
1481
1498
  }
1482
- async function inputGroups(specs, language, values) {
1499
+ async function inputEditor(spec, language, values) {
1500
+ if (spec == null) return void 0;
1483
1501
  const { FlowRunInputEditorStore } = await import("./flowRunInputEditorStore-Dsxyfwae.js").then((n) => n.t);
1484
- return specs.map((group) => {
1485
- const editor = new FlowRunInputEditorStore(group.definitions, language);
1486
- if (values?.[group.nodeId] != null) editor.replaceValues(values[group.nodeId]);
1487
- return {
1488
- editor,
1489
- nodeId: group.nodeId,
1490
- title: group.title
1491
- };
1492
- });
1493
- }
1494
- function groupValues(groups) {
1495
- return Object.fromEntries(groups.map((group) => [group.nodeId, group.editor.values()]));
1502
+ const editor = new FlowRunInputEditorStore(spec.definitions, language);
1503
+ const initial = values ?? spec.samples;
1504
+ if (initial != null) editor.replaceValues(initial);
1505
+ return editor;
1496
1506
  }
1497
1507
  function testOutputs(revision, triggerId) {
1498
- return (revisionView(revision).graph({ kind: "flow" })?.nodes[triggerId])?.kind === "cron" ? { scheduledAt: (/* @__PURE__ */ new Date()).toISOString() } : {};
1499
- }
1500
- function runValues(groups, triggerId, revision) {
1501
- return {
1502
- inputs: Object.fromEntries(groups.filter((group) => group.nodeId != triggerId).map((group) => [group.nodeId, group.editor.values()])),
1503
- outputs: groups.find((group) => group.nodeId == triggerId)?.editor.values() ?? testOutputs(revision, triggerId)
1504
- };
1508
+ const node = revisionView(revision).graph({ kind: "flow" })?.nodes[triggerId];
1509
+ if (node?.kind == "error") return sampleErrorOutputs;
1510
+ return node?.kind === "cron" ? { scheduledAt: (/* @__PURE__ */ new Date()).toISOString() } : {};
1505
1511
  }
1506
1512
  var RunRequestStore = class {
1507
1513
  #prepareDraft;
@@ -1567,10 +1573,10 @@ var RunRequestStore = class {
1567
1573
  }
1568
1574
  }
1569
1575
  inputStatus(flowId, draft, triggerId) {
1570
- const specs = inputSpecs(draft, triggerId);
1571
- if (specs.length == 0) return "none";
1576
+ const spec = inputSpec(draft, triggerId);
1577
+ if (spec == null) return "none";
1572
1578
  const saved = this.#savedInputs.get(this.#inputKey(flowId, triggerId));
1573
- return saved?.valid == true && saved.signature == inputSignature(specs) ? "ready" : "missing";
1579
+ return saved?.valid == true && saved.signature == inputSignature(spec) ? "ready" : "missing";
1574
1580
  }
1575
1581
  async requestLive(flow) {
1576
1582
  const current = this.#requests.begin();
@@ -1605,11 +1611,11 @@ var RunRequestStore = class {
1605
1611
  return false;
1606
1612
  }
1607
1613
  this.#rememberInputs(request);
1608
- const { inputs, outputs } = runValues(request.groups, request.triggerId, request.revision);
1614
+ const outputs = request.editor?.values() ?? testOutputs(request.revision, request.triggerId);
1609
1615
  const started = await this.#start(request.source, request.flow, request.revisionId, {
1610
1616
  nodeId: request.triggerId,
1611
1617
  outputs
1612
- }, inputs, request.publicationId);
1618
+ }, request.publicationId);
1613
1619
  if (started && this.#state.value.inputRequest === request) this.dismissInputs();
1614
1620
  return started;
1615
1621
  }
@@ -1620,18 +1626,18 @@ var RunRequestStore = class {
1620
1626
  this.#rememberInputs(request);
1621
1627
  this.#set({ starting: true });
1622
1628
  try {
1623
- const specs = inputSpecs(request.revision, triggerId);
1629
+ const spec = inputSpec(request.revision, triggerId);
1624
1630
  const saved = this.#savedInputs.get(this.#inputKey(request.flow.flowId, triggerId));
1625
- const groups = await inputGroups(specs, this.#i18n.lang$, saved?.values);
1631
+ const editor = await inputEditor(spec, this.#i18n.lang$, saved?.values);
1626
1632
  if (!current() || this.#state.value.inputRequest !== request) {
1627
- for (const group of groups) group.editor.dispose();
1633
+ editor?.dispose();
1628
1634
  return;
1629
1635
  }
1630
- const valid = compute((get) => groups.every((group) => get(group.editor.valid$)));
1636
+ const valid = compute((get) => editor == null || get(editor.valid$));
1631
1637
  this.#set({ inputRequest: {
1632
1638
  ...request,
1633
1639
  attempted: false,
1634
- groups,
1640
+ editor,
1635
1641
  triggerId,
1636
1642
  valid
1637
1643
  } });
@@ -1673,32 +1679,32 @@ var RunRequestStore = class {
1673
1679
  });
1674
1680
  return "unavailable";
1675
1681
  }
1676
- const specs = only == null ? [] : inputSpecs(revision, only.nodeId);
1677
- const signature = inputSignature(specs);
1682
+ const spec = only == null ? void 0 : inputSpec(revision, only.nodeId);
1683
+ const signature = inputSignature(spec);
1678
1684
  const saved = only == null ? void 0 : this.#savedInputs.get(this.#inputKey(flow.flowId, only.nodeId));
1679
- const groups = only == null ? [] : await inputGroups(specs, this.#i18n.lang$, saved?.values);
1685
+ const editor = await inputEditor(spec, this.#i18n.lang$, saved?.values);
1680
1686
  if (!current()) {
1681
- for (const group of groups) group.editor.dispose();
1687
+ editor?.dispose();
1682
1688
  return "unavailable";
1683
1689
  }
1684
- if (!edit && only != null && groups.length == 0) return await this.#start(source, flow, revisionId, {
1690
+ if (!edit && only != null && editor == null) return await this.#start(source, flow, revisionId, {
1685
1691
  nodeId: only.nodeId,
1686
1692
  outputs: testOutputs(revision, only.nodeId)
1687
- }, {}, publicationId) ? "started" : "unavailable";
1688
- if (!edit && only != null && saved?.valid == true && saved.signature == signature && groups.every((group) => group.editor.valid$.value)) {
1689
- const values = runValues(groups, only.nodeId, revision);
1690
- for (const group of groups) group.editor.dispose();
1693
+ }, publicationId) ? "started" : "unavailable";
1694
+ if (!edit && only != null && saved?.valid == true && saved.signature == signature && editor != null && editor.valid$.value) {
1695
+ const outputs = editor.values();
1696
+ editor?.dispose();
1691
1697
  return await this.#start(source, flow, revisionId, {
1692
1698
  nodeId: only.nodeId,
1693
- outputs: values.outputs
1694
- }, values.inputs, publicationId) ? "started" : "unavailable";
1699
+ outputs
1700
+ }, publicationId) ? "started" : "unavailable";
1695
1701
  }
1696
- const valid = compute((get) => only != null && groups.every((group) => get(group.editor.valid$)));
1702
+ const valid = compute((get) => only != null && (editor == null || get(editor.valid$)));
1697
1703
  this.#set({
1698
1704
  inputRequest: {
1699
1705
  attempted: false,
1700
1706
  flow,
1701
- groups,
1707
+ editor,
1702
1708
  revision,
1703
1709
  triggers,
1704
1710
  triggerId: only?.nodeId,
@@ -1712,7 +1718,7 @@ var RunRequestStore = class {
1712
1718
  });
1713
1719
  return "input";
1714
1720
  }
1715
- async #start(source, flow, revisionId, trigger, inputs = {}, publicationId) {
1721
+ async #start(source, flow, revisionId, trigger, publicationId) {
1716
1722
  if (source == "live" && publicationId == null) return false;
1717
1723
  const alive = this.#lifetime.capture();
1718
1724
  const current = this.#runs.prepareStart();
@@ -1731,7 +1737,6 @@ var RunRequestStore = class {
1731
1737
  revisionId
1732
1738
  } : { publicationId };
1733
1739
  const signature = JSON.stringify({
1734
- inputs,
1735
1740
  trigger,
1736
1741
  source,
1737
1742
  ...target
@@ -1743,11 +1748,11 @@ var RunRequestStore = class {
1743
1748
  this.#attempt = attempt;
1744
1749
  const run = source == "draft" ? await this.#client.createDraftRun(flow.flowId, revisionId, {
1745
1750
  idempotencyKey: attempt.key,
1746
- inputs,
1751
+ inputs: {},
1747
1752
  trigger
1748
1753
  }) : await this.#client.createLiveRun(publicationId, {
1749
1754
  idempotencyKey: attempt.key,
1750
- inputs,
1755
+ inputs: {},
1751
1756
  trigger
1752
1757
  });
1753
1758
  if (!alive() || !current()) return false;
@@ -1766,17 +1771,17 @@ var RunRequestStore = class {
1766
1771
  #disposeInputRequest(request = this.#state.value.inputRequest) {
1767
1772
  if (request == null) return;
1768
1773
  request.valid.dispose();
1769
- for (const group of request.groups) group.editor.dispose();
1774
+ request.editor?.dispose();
1770
1775
  }
1771
1776
  #inputKey(flowId, triggerId) {
1772
1777
  return `${flowId}\u0000${triggerId}`;
1773
1778
  }
1774
1779
  #rememberInputs(request) {
1775
- if (request?.triggerId == null || request.groups.length == 0) return;
1780
+ if (request?.triggerId == null || request.editor == null) return;
1776
1781
  this.#savedInputs.set(this.#inputKey(request.flow.flowId, request.triggerId), {
1777
- signature: inputSignature(inputSpecs(request.revision, request.triggerId)),
1782
+ signature: inputSignature(inputSpec(request.revision, request.triggerId)),
1778
1783
  valid: request.valid.value,
1779
- values: groupValues(request.groups)
1784
+ values: request.editor.values()
1780
1785
  });
1781
1786
  }
1782
1787
  #set(patch) {
@@ -1871,47 +1876,590 @@ function createStore(dbName, storeName) {
1871
1876
  };
1872
1877
  return (txMode, callback) => getDB().then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName)));
1873
1878
  }
1874
- var defaultGetStoreFunc;
1875
- function defaultGetStore() {
1876
- if (!defaultGetStoreFunc) defaultGetStoreFunc = createStore("keyval-store", "keyval");
1877
- return defaultGetStoreFunc;
1878
- }
1879
- /**
1880
- * Get a value by its key.
1881
- *
1882
- * @param key
1883
- * @param customStore Method to get a custom store. Use with caution (see the docs).
1884
- */
1885
- function get(key, customStore = defaultGetStore()) {
1886
- return customStore("readonly", (store) => promisifyRequest(store.get(key)));
1879
+ //#endregion
1880
+ //#region ../../node_modules/.bun/@oomol-lab+resource-cache@0.1.4/node_modules/@oomol-lab/resource-cache/dist/src-bwD0r9NQ.mjs
1881
+ function abortError() {
1882
+ return new DOMException("Cache operation aborted", "AbortError");
1887
1883
  }
1888
- /**
1889
- * Set a value with a key.
1890
- *
1891
- * @param key
1892
- * @param value
1893
- * @param customStore Method to get a custom store. Use with caution (see the docs).
1894
- */
1895
- function set(key, value, customStore = defaultGetStore()) {
1896
- return customStore("readwrite", (store) => {
1897
- store.put(value, key);
1898
- return promisifyRequest(store.transaction);
1884
+ function wait(promise, lifetime, caller) {
1885
+ const signals = caller ? [lifetime, caller] : [lifetime];
1886
+ return new Promise((resolve, reject) => {
1887
+ const cleanup = () => {
1888
+ for (const signal of signals) signal.removeEventListener("abort", abort);
1889
+ };
1890
+ const abort = () => {
1891
+ cleanup();
1892
+ reject(abortError());
1893
+ };
1894
+ for (const signal of signals) signal.addEventListener("abort", abort, { once: true });
1895
+ promise.then((value) => {
1896
+ cleanup();
1897
+ resolve(value);
1898
+ }, (error) => {
1899
+ cleanup();
1900
+ reject(error);
1901
+ });
1899
1902
  });
1900
1903
  }
1904
+ /** @internal */
1905
+ function validateOptions(options) {
1906
+ if (typeof options.namespace !== "string" || !options.namespace.trim()) throw new TypeError("namespace must be nonempty");
1907
+ if (!Number.isSafeInteger(options.schemaVersion) || options.schemaVersion <= 0) throw new TypeError("schemaVersion must be a positive safe integer");
1908
+ if (!Number.isFinite(options.maxAge) || options.maxAge < 0) throw new TypeError("maxAge must be finite and nonnegative");
1909
+ for (const name of [
1910
+ "key",
1911
+ "decode",
1912
+ "load"
1913
+ ]) if (typeof options[name] !== "function") throw new TypeError(`${name} must be a function`);
1914
+ }
1915
+ /** @internal */
1916
+ function createCache(options, backend, session) {
1917
+ const states = /* @__PURE__ */ new Map();
1918
+ let disposed = false;
1919
+ let scopeBlocked = false;
1920
+ let disposal;
1921
+ let io = Promise.resolve();
1922
+ function storage(action) {
1923
+ const result = io.then(action);
1924
+ io = result.catch(() => {});
1925
+ return result;
1926
+ }
1927
+ function checkOpen() {
1928
+ if (disposed) throw new Error("Cache is disposed");
1929
+ }
1930
+ function identity(query) {
1931
+ checkOpen();
1932
+ const key = options.key(query);
1933
+ if (typeof key !== "string") throw new TypeError("key must return a string");
1934
+ return key;
1935
+ }
1936
+ function stateFor(key) {
1937
+ let state = states.get(key);
1938
+ if (!state) {
1939
+ state = {
1940
+ controller: new AbortController(),
1941
+ blocked: scopeBlocked
1942
+ };
1943
+ states.set(key, state);
1944
+ }
1945
+ return state;
1946
+ }
1947
+ function checkState(state) {
1948
+ if (state.controller.signal.aborted) throw abortError();
1949
+ }
1950
+ function fresh(entry) {
1951
+ const now = Date.now();
1952
+ return !entry.invalidated && entry.validatedAt <= now && now - entry.validatedAt < options.maxAge;
1953
+ }
1954
+ function restore(value, previous) {
1955
+ return {
1956
+ ...value.meta,
1957
+ data: value.body ? options.decode(value.body.data) : previous.data
1958
+ };
1959
+ }
1960
+ async function read(key, state) {
1961
+ if (state.entry && fresh(state.entry)) return state.entry;
1962
+ const entry = await storage(async () => {
1963
+ checkState(state);
1964
+ if (state.blocked) return state.entry;
1965
+ try {
1966
+ const value = await backend.read(key, state.entry?.version);
1967
+ return value ? restore(value, state.entry) : state.entry;
1968
+ } catch {
1969
+ return state.entry;
1970
+ }
1971
+ });
1972
+ checkState(state);
1973
+ state.entry = entry;
1974
+ return entry;
1975
+ }
1976
+ function schedule(key, query, state, force) {
1977
+ const job = {
1978
+ started: false,
1979
+ force
1980
+ };
1981
+ job.promise = (async () => {
1982
+ const previous = await read(key, state);
1983
+ checkState(state);
1984
+ if (!job.force && previous && fresh(previous)) return previous.data;
1985
+ job.started = true;
1986
+ const result = await options.load(query, {
1987
+ etag: previous?.etag ?? null,
1988
+ signal: state.controller.signal
1989
+ });
1990
+ checkState(state);
1991
+ let entry;
1992
+ if (result.modified) entry = {
1993
+ data: result.data,
1994
+ etag: result.etag,
1995
+ version: crypto.getRandomValues(/* @__PURE__ */ new Uint32Array(4)).join("-"),
1996
+ validatedAt: Date.now(),
1997
+ invalidated: false
1998
+ };
1999
+ else {
2000
+ if (!previous) throw new Error("Load protocol error: unmodified response without cached data");
2001
+ entry = {
2002
+ ...previous,
2003
+ etag: result.etag === void 0 ? previous.etag : result.etag,
2004
+ validatedAt: Date.now(),
2005
+ invalidated: false
2006
+ };
2007
+ }
2008
+ await storage(async () => {
2009
+ checkState(state);
2010
+ try {
2011
+ if (await backend.write(key, entry, result.modified)) state.blocked = false;
2012
+ } catch {
2013
+ state.blocked = true;
2014
+ }
2015
+ checkState(state);
2016
+ state.entry = entry;
2017
+ });
2018
+ checkState(state);
2019
+ return entry.data;
2020
+ })();
2021
+ state.job = job;
2022
+ const release = () => {
2023
+ state.job = void 0;
2024
+ };
2025
+ job.promise.then(release, release);
2026
+ return job;
2027
+ }
2028
+ function refresh(key, query, state, force) {
2029
+ const active = state.job;
2030
+ if (!active) return schedule(key, query, state, force).promise;
2031
+ if (!force) return active.promise;
2032
+ if (!active.started) {
2033
+ active.force = true;
2034
+ return active.promise;
2035
+ }
2036
+ if (!state.queued) {
2037
+ const start = () => {
2038
+ checkState(state);
2039
+ state.queued = void 0;
2040
+ return schedule(key, query, state, true).promise;
2041
+ };
2042
+ state.queued = active.promise.then(start, start);
2043
+ }
2044
+ return state.queued;
2045
+ }
2046
+ function reset(key, keep) {
2047
+ const old = states.get(key);
2048
+ const state = {
2049
+ controller: new AbortController(),
2050
+ blocked: true
2051
+ };
2052
+ if (keep && old?.entry) state.entry = {
2053
+ ...old.entry,
2054
+ invalidated: true
2055
+ };
2056
+ states.set(key, state);
2057
+ return {
2058
+ state,
2059
+ cancel: () => old?.controller.abort()
2060
+ };
2061
+ }
2062
+ function resetAll() {
2063
+ const old = [...states.values()];
2064
+ states.clear();
2065
+ const barrier = {};
2066
+ scopeBlocked = barrier;
2067
+ return {
2068
+ barrier,
2069
+ cancel() {
2070
+ for (const state of old) state.controller.abort();
2071
+ }
2072
+ };
2073
+ }
2074
+ return {
2075
+ async get(query, getOptions = {}) {
2076
+ const key = identity(query);
2077
+ if (getOptions.signal?.aborted) throw abortError();
2078
+ const state = stateFor(key);
2079
+ if (!getOptions.revalidate && state.entry && fresh(state.entry)) return state.entry.data;
2080
+ return wait(refresh(key, query, state, getOptions.revalidate === true), state.controller.signal, getOptions.signal);
2081
+ },
2082
+ async peek(query) {
2083
+ const key = identity(query);
2084
+ const state = stateFor(key);
2085
+ const entry = await wait(read(key, state), state.controller.signal);
2086
+ return entry ? {
2087
+ data: entry.data,
2088
+ etag: entry.etag,
2089
+ validatedAt: entry.validatedAt,
2090
+ fresh: fresh(entry)
2091
+ } : void 0;
2092
+ },
2093
+ async invalidate(query) {
2094
+ const key = identity(query);
2095
+ const canRestore = !(states.get(key)?.blocked ?? scopeBlocked);
2096
+ const { state, cancel } = reset(key, true);
2097
+ const cleanup = storage(async () => {
2098
+ const value = await backend.invalidate(key);
2099
+ if (canRestore) state.blocked = false;
2100
+ if (canRestore && !state.controller.signal.aborted && !state.entry && value) try {
2101
+ state.entry = restore(value);
2102
+ } catch {}
2103
+ });
2104
+ cancel();
2105
+ await cleanup;
2106
+ },
2107
+ async remove(query) {
2108
+ const key = identity(query);
2109
+ const { state, cancel } = reset(key, false);
2110
+ const cleanup = storage(async () => {
2111
+ await backend.remove(key);
2112
+ state.blocked = false;
2113
+ });
2114
+ cancel();
2115
+ await cleanup;
2116
+ },
2117
+ async clear() {
2118
+ checkOpen();
2119
+ const { barrier, cancel } = resetAll();
2120
+ const cleanup = storage(async () => {
2121
+ await backend.clear(false);
2122
+ if (scopeBlocked === barrier) scopeBlocked = false;
2123
+ for (const state of states.values()) if (state.blocked === barrier) state.blocked = false;
2124
+ });
2125
+ cancel();
2126
+ await cleanup;
2127
+ },
2128
+ dispose() {
2129
+ if (!disposal) {
2130
+ disposed = true;
2131
+ const { cancel } = resetAll();
2132
+ disposal = storage(async () => {
2133
+ if (session) await backend.clear(true);
2134
+ });
2135
+ disposal = disposal.catch((error) => {
2136
+ disposal = void 0;
2137
+ throw error;
2138
+ });
2139
+ cancel();
2140
+ }
2141
+ return disposal;
2142
+ }
2143
+ };
2144
+ }
2145
+ function object(value) {
2146
+ return typeof value === "object" && value !== null;
2147
+ }
2148
+ function metadata(value) {
2149
+ if (!object(value) || typeof value.version !== "string" || !value.version || !(value.etag === null || typeof value.etag === "string") || typeof value.invalidated !== "boolean") return void 0;
2150
+ const validTime = typeof value.validatedAt === "number" && Number.isFinite(value.validatedAt) && value.validatedAt >= 0;
2151
+ return {
2152
+ version: value.version,
2153
+ etag: value.etag,
2154
+ validatedAt: validTime ? value.validatedAt : 0,
2155
+ invalidated: !validTime || value.invalidated === true
2156
+ };
2157
+ }
2158
+ function stored(meta, body) {
2159
+ if (!object(body) || body.version !== meta.version || !Object.hasOwn(body, "data")) return void 0;
2160
+ return {
2161
+ meta,
2162
+ body: { data: body.data }
2163
+ };
2164
+ }
2165
+ var storagePrefix = "@oomol-lab/resource-cache:";
2166
+ /** Delimit identity fields without ambiguous string concatenation. @internal */
2167
+ function scope(namespace) {
2168
+ return storagePrefix + JSON.stringify(namespace);
2169
+ }
2170
+ /** @internal */
2171
+ function sessionScope(namespace, sessionId) {
2172
+ return storagePrefix + JSON.stringify([namespace, sessionId]);
2173
+ }
2174
+ /** @internal */
2175
+ function persistentStorage(namespace, schemaVersion) {
2176
+ const useStore = createStore("@oomol-lab/resource-cache", "records");
2177
+ const prefix = `${scope(namespace)}:${schemaVersion}:`;
2178
+ const identity = (key, part) => prefix + JSON.stringify([key, part]);
2179
+ function transaction(mode, work) {
2180
+ return useStore(mode, (store) => new Promise((resolve, reject) => {
2181
+ const tx = store.transaction;
2182
+ let value;
2183
+ let failure;
2184
+ tx.oncomplete = () => resolve(value);
2185
+ tx.onabort = () => reject(failure ?? tx.error);
2186
+ const guard = (fn) => {
2187
+ try {
2188
+ fn();
2189
+ } catch (error) {
2190
+ failure = error;
2191
+ tx.abort();
2192
+ }
2193
+ };
2194
+ const read = (request, fn) => {
2195
+ request.onsuccess = () => guard(() => fn(request.result));
2196
+ };
2197
+ guard(() => work(store, read, (result) => {
2198
+ value = result;
2199
+ }));
2200
+ }));
2201
+ }
2202
+ return {
2203
+ read(key, version) {
2204
+ return transaction("readonly", (store, read, result) => {
2205
+ read(store.get(identity(key, "meta")), (raw) => {
2206
+ const meta = metadata(raw);
2207
+ if (!meta) return;
2208
+ if (meta.version === version) {
2209
+ result({ meta });
2210
+ return;
2211
+ }
2212
+ read(store.get(identity(key, "body")), (body) => result(stored(meta, body)));
2213
+ });
2214
+ });
2215
+ },
2216
+ write(key, entry, modified) {
2217
+ return transaction("readwrite", (store, read, result) => {
2218
+ const { data, ...meta } = entry;
2219
+ if (modified) {
2220
+ store.put(meta, identity(key, "meta"));
2221
+ store.put({
2222
+ version: meta.version,
2223
+ data
2224
+ }, identity(key, "body"));
2225
+ result(true);
2226
+ } else read(store.get(identity(key, "meta")), (raw) => {
2227
+ const matches = metadata(raw)?.version === meta.version;
2228
+ if (matches) store.put(meta, identity(key, "meta"));
2229
+ result(matches);
2230
+ });
2231
+ });
2232
+ },
2233
+ invalidate(key) {
2234
+ return transaction("readwrite", (store, read, result) => {
2235
+ read(store.get(identity(key, "meta")), (raw) => {
2236
+ const meta = metadata(raw);
2237
+ if (!meta) return;
2238
+ meta.invalidated = true;
2239
+ store.put(meta, identity(key, "meta"));
2240
+ read(store.get(identity(key, "body")), (body) => result(stored(meta, body)));
2241
+ });
2242
+ });
2243
+ },
2244
+ remove(key) {
2245
+ return transaction("readwrite", (store) => {
2246
+ store.delete(identity(key, "meta"));
2247
+ store.delete(identity(key, "body"));
2248
+ });
2249
+ },
2250
+ clear() {
2251
+ return transaction("readwrite", (store, read) => {
2252
+ read(store.getAllKeys(), (keys) => {
2253
+ for (const key of keys) if (typeof key === "string" && key.startsWith(prefix)) store.delete(key);
2254
+ });
2255
+ });
2256
+ }
2257
+ };
2258
+ }
2259
+ /** @internal */
2260
+ function sessionStorageBackend(namespace, schemaVersion, sessionId) {
2261
+ const base = `${sessionScope(namespace, sessionId)}:`;
2262
+ const prefix = `${base}${schemaVersion}:`;
2263
+ const identity = (key) => prefix + JSON.stringify(key);
2264
+ const record = (key) => {
2265
+ const text = globalThis.sessionStorage.getItem(identity(key));
2266
+ if (text === null) return void 0;
2267
+ const raw = JSON.parse(text);
2268
+ const meta = metadata(raw);
2269
+ return meta ? stored(meta, raw) : void 0;
2270
+ };
2271
+ return {
2272
+ async read(key, version) {
2273
+ const value = record(key);
2274
+ if (value && value.meta.version === version) return { meta: value.meta };
2275
+ return value;
2276
+ },
2277
+ async write(key, entry, modified) {
2278
+ if (modified) {
2279
+ globalThis.sessionStorage.setItem(identity(key), JSON.stringify(entry));
2280
+ return true;
2281
+ } else {
2282
+ const value = record(key);
2283
+ if (value?.meta.version === entry.version) {
2284
+ const { data: _data, ...meta } = entry;
2285
+ globalThis.sessionStorage.setItem(identity(key), JSON.stringify({
2286
+ ...meta,
2287
+ data: value.body.data
2288
+ }));
2289
+ return true;
2290
+ }
2291
+ return false;
2292
+ }
2293
+ },
2294
+ async invalidate(key) {
2295
+ const value = record(key);
2296
+ if (value) {
2297
+ value.meta.invalidated = true;
2298
+ globalThis.sessionStorage.setItem(identity(key), JSON.stringify({
2299
+ ...value.meta,
2300
+ ...value.body
2301
+ }));
2302
+ }
2303
+ return value;
2304
+ },
2305
+ async remove(key) {
2306
+ globalThis.sessionStorage.removeItem(identity(key));
2307
+ },
2308
+ async clear(allVersions) {
2309
+ const storage = globalThis.sessionStorage;
2310
+ const matches = [];
2311
+ for (let i = 0; i < storage.length; i++) {
2312
+ const key = storage.key(i);
2313
+ if (key.startsWith(allVersions ? base : prefix)) matches.push(key);
2314
+ }
2315
+ for (const key of matches) storage.removeItem(key);
2316
+ }
2317
+ };
2318
+ }
2319
+ /** Create an IndexedDB cache. Storage failures preserve successful network results. */
2320
+ function createPersistentCache(options) {
2321
+ validateOptions(options);
2322
+ return createCache({ ...options }, persistentStorage(options.namespace, options.schemaVersion), false);
2323
+ }
2324
+ /** Create a login-scoped sessionStorage cache. Data must survive JSON serialization and decoding. */
2325
+ function createSessionCache(options) {
2326
+ validateOptions(options);
2327
+ if (typeof options.sessionId !== "string" || !options.sessionId.trim()) throw new TypeError("sessionId must be nonempty");
2328
+ return createCache({ ...options }, sessionStorageBackend(options.namespace, options.schemaVersion, options.sessionId), true);
2329
+ }
1901
2330
  //#endregion
1902
- //#region src/workbench/browser/runtime/stores/catalogStorage.ts
1903
- var responses = createStore("open-flow-cache", "responses");
1904
- var indexedStorage = {
1905
- get: (key) => get(key, responses),
1906
- set: (key, value) => set(key, value, responses)
2331
+ //#region ../../node_modules/.bun/@oomol-lab+resource-cache@0.1.4/node_modules/@oomol-lab/resource-cache/dist/oomol.mjs
2332
+ /** Namespaces reserved for the OOMOL response factories. */
2333
+ var oomolNamespaces = {
2334
+ providers: "oomol:providers",
2335
+ actions: "oomol:actions",
2336
+ appCatalog: "oomol:app-catalog",
2337
+ connections: "oomol:connections"
1907
2338
  };
1908
- function catalogPersistence(options, kind, query) {
1909
- if (options == null) return void 0;
1910
- const storage = options.storage ?? indexedStorage;
2339
+ /** Join identity fields without nesting JSON in the storage key. */
2340
+ function readableKey(...parts) {
2341
+ return parts.map((part) => encodeURIComponent(String(part)).replaceAll("%3A", ":")).join("/");
2342
+ }
2343
+ var singletonRegistrySymbol = Symbol.for("oomol-lab.resource-cache.oomol-singletons");
2344
+ var singletonCaches = Reflect.get(globalThis, singletonRegistrySymbol) ?? (() => {
2345
+ const registry = /* @__PURE__ */ new Map();
2346
+ Reflect.set(globalThis, singletonRegistrySymbol, registry);
2347
+ return registry;
2348
+ })();
2349
+ function createOomolCache(resource, options, query) {
2350
+ const environment = validateOomolOptions(options);
2351
+ const { load } = options;
2352
+ const key = readableKey(query.locale);
2353
+ return createPersistentCache({
2354
+ namespace: readableKey(resource, environment),
2355
+ schemaVersion: options.schemaVersion,
2356
+ maxAge: options.maxAge,
2357
+ key: () => key,
2358
+ decode: options.decode,
2359
+ load: (_query, validation) => load({ ...query }, validation)
2360
+ });
2361
+ }
2362
+ function createConnectionsCacheInternal(options, validated) {
2363
+ const { environment, ownerId } = validated;
2364
+ const { load } = options;
2365
+ const key = readableKey(ownerId);
2366
+ return createSessionCache({
2367
+ namespace: readableKey(oomolNamespaces.connections, environment),
2368
+ schemaVersion: options.schemaVersion,
2369
+ maxAge: options.maxAge,
2370
+ sessionId: options.sessionId,
2371
+ key: () => key,
2372
+ decode: options.decode,
2373
+ load: (_query, validation) => load({ ownerId }, validation)
2374
+ });
2375
+ }
2376
+ function validateOomolOptions(options) {
2377
+ const environment = normalizeEnvironment(options.environment);
2378
+ if (typeof options.locale !== "string" || !options.locale.trim()) throw new TypeError("locale must be nonempty");
2379
+ if (typeof options.load !== "function") throw new TypeError("load must be a function");
2380
+ return environment;
2381
+ }
2382
+ function normalizeEnvironment(value) {
2383
+ const environment = value === void 0 ? "production" : value;
2384
+ if (typeof environment !== "string" || !environment.trim()) throw new TypeError("environment must be nonempty");
2385
+ return environment;
2386
+ }
2387
+ function normalizeOwnerId(value) {
2388
+ if (typeof value !== "string" || !value.trim()) throw new TypeError("ownerId must be nonempty");
2389
+ return value;
2390
+ }
2391
+ function validateConnectionsOptions(options) {
2392
+ const environment = normalizeEnvironment(options.environment);
2393
+ if (typeof options.sessionId !== "string" || !options.sessionId.trim()) throw new TypeError("sessionId must be nonempty");
2394
+ const ownerId = normalizeOwnerId(options.ownerId);
2395
+ if (typeof options.load !== "function") throw new TypeError("load must be a function");
1911
2396
  return {
1912
- key: `${kind}:v1:${query}`,
1913
- storage
2397
+ environment,
2398
+ ownerId
2399
+ };
2400
+ }
2401
+ /** Create an IndexedDB cache for the account-independent GET /v1/providers response, keyed by environment and locale. */
2402
+ function createProvidersCacheInternal(options) {
2403
+ return createOomolCache(oomolNamespaces.providers, options, { locale: options.locale });
2404
+ }
2405
+ /** Create an IndexedDB cache for account-independent GET /v1/actions?service=…, keyed by environment, locale and service. */
2406
+ function createActionsCacheInternal(options) {
2407
+ const environment = validateOomolOptions(options);
2408
+ const { locale, load } = options;
2409
+ return createPersistentCache({
2410
+ namespace: readableKey(oomolNamespaces.actions, environment),
2411
+ schemaVersion: options.schemaVersion,
2412
+ maxAge: options.maxAge,
2413
+ key: (service) => {
2414
+ if (typeof service !== "string" || !service.trim()) throw new TypeError("service must be nonempty");
2415
+ return readableKey(locale, service);
2416
+ },
2417
+ decode: options.decode,
2418
+ load: (service, validation) => load({
2419
+ locale,
2420
+ service
2421
+ }, validation)
2422
+ });
2423
+ }
2424
+ function singletonKey(resource, options, query, sessionId) {
2425
+ const environment = normalizeEnvironment(options.environment);
2426
+ return sessionId === void 0 ? readableKey(resource, environment, options.schemaVersion, ...query) : readableKey(resource, environment, options.schemaVersion, sessionId, ...query);
2427
+ }
2428
+ function getSingleton(key, create) {
2429
+ const existing = singletonCaches.get(key);
2430
+ if (existing) return existing;
2431
+ const cache = create();
2432
+ let disposal;
2433
+ const singleton = {
2434
+ ...cache,
2435
+ dispose() {
2436
+ if (!disposal) disposal = cache.dispose().then(() => {
2437
+ singletonCaches.delete(key);
2438
+ }, (error) => {
2439
+ disposal = void 0;
2440
+ throw error;
2441
+ });
2442
+ return disposal;
2443
+ }
1914
2444
  };
2445
+ singletonCaches.set(key, singleton);
2446
+ return singleton;
2447
+ }
2448
+ /** Return the shared Providers cache for one environment, locale and schema version. */
2449
+ function getProvidersCache(options) {
2450
+ const query = { locale: options.locale };
2451
+ return getSingleton(singletonKey(oomolNamespaces.providers, options, [query.locale]), () => createProvidersCacheInternal(options));
2452
+ }
2453
+ /** Return the shared Actions cache for one environment, locale and schema version. */
2454
+ function getActionsCache(options) {
2455
+ const query = { locale: options.locale };
2456
+ return getSingleton(singletonKey(oomolNamespaces.actions, options, [query.locale]), () => createActionsCacheInternal(options));
2457
+ }
2458
+ /** Return the shared sessionStorage cache for one login session and owner scope. */
2459
+ function getConnectionsCache(options) {
2460
+ const validated = validateConnectionsOptions(options);
2461
+ const query = { ownerId: validated.ownerId };
2462
+ return getSingleton(singletonKey(oomolNamespaces.connections, options, [query.ownerId], options.sessionId), () => createConnectionsCacheInternal(options, validated));
1915
2463
  }
1916
2464
  //#endregion
1917
2465
  //#region src/connector/common/actionSchema.ts
@@ -2086,46 +2634,178 @@ function action(source, providers) {
2086
2634
  }
2087
2635
  //#endregion
2088
2636
  //#region src/workbench/browser/runtime/stores/catalogStores.ts
2089
- function actionsResponse(value) {
2637
+ var catalogMaxAge = {
2638
+ providers: 3e5,
2639
+ actions: 3e4,
2640
+ connections: 3e4
2641
+ };
2642
+ var identity = (...parts) => JSON.stringify(parts);
2643
+ function proxyCatalogPath(kind, flowId, locale, service) {
2644
+ return `/v1/connector/proxy/${kind}?${new URLSearchParams({
2645
+ ...flowId == null ? {} : { flowId },
2646
+ ...service == null ? {} : { service },
2647
+ locale
2648
+ })}`;
2649
+ }
2650
+ function mapCache(cache, toValue, toSnapshot, query) {
2651
+ return {
2652
+ get: async (value, options) => toValue(await cache.get(query(value), options)),
2653
+ peek: async (value) => {
2654
+ const snapshot = await cache.peek(query(value));
2655
+ return snapshot == null ? void 0 : {
2656
+ ...snapshot,
2657
+ data: toSnapshot(snapshot.data)
2658
+ };
2659
+ },
2660
+ invalidate: (value) => cache.invalidate(query(value)),
2661
+ remove: (value) => cache.remove(query(value)),
2662
+ clear: () => cache.clear(),
2663
+ dispose: () => cache.dispose()
2664
+ };
2665
+ }
2666
+ function providerCacheValue(value) {
2667
+ return proxyResponse(value);
2668
+ }
2669
+ function actionCacheValue(value) {
2670
+ return proxyResponse(value);
2671
+ }
2672
+ function connectionsCacheValue(value) {
2090
2673
  const source = record(value);
2091
- if (source.version != 1 || !Array.isArray(source.actions)) return invalidResponse();
2092
- return source.actions.map(connectorActionMetadata);
2674
+ if (source.success === true && Array.isArray(source.data)) return source;
2675
+ if (source.version == 1 && Array.isArray(source.connections)) return {
2676
+ success: true,
2677
+ message: "",
2678
+ data: source.connections,
2679
+ meta: { summary: {
2680
+ providerCount: 0,
2681
+ connectableProviderCount: 0,
2682
+ connectedProviderCount: 0,
2683
+ activeConnectedProviderCount: 0,
2684
+ connectedAppCount: source.connections.length,
2685
+ activeConnectedAppCount: source.connections.length,
2686
+ filteredAppCount: source.connections.length
2687
+ } }
2688
+ };
2689
+ return invalidResponse();
2093
2690
  }
2094
- var identity = (...parts) => JSON.stringify(parts);
2095
- /** Each entry owns one complete upstream response, never a merged entity catalog. */
2691
+ function connectionsAsProxy(value) {
2692
+ return value.data.map(connection);
2693
+ }
2694
+ /** Shared cache construction for one Workbench session. */
2695
+ var CacheFactory = class {
2696
+ #caches = /* @__PURE__ */ new Set();
2697
+ #entries = /* @__PURE__ */ new Map();
2698
+ #disposed = false;
2699
+ constructor(scope) {
2700
+ this.scope = scope;
2701
+ }
2702
+ cache(key, create, owned = true) {
2703
+ let entry = this.#entries.get(key);
2704
+ if (entry == null) {
2705
+ entry = create().then((cache) => {
2706
+ if (owned) {
2707
+ if (this.#disposed) cache.dispose();
2708
+ else this.#caches.add(cache);
2709
+ }
2710
+ return cache;
2711
+ });
2712
+ this.#entries.set(key, entry);
2713
+ }
2714
+ return entry;
2715
+ }
2716
+ async dispose() {
2717
+ this.#disposed = true;
2718
+ await Promise.all([...this.#caches].map((cache) => cache.dispose()));
2719
+ this.#caches.clear();
2720
+ this.#entries.clear();
2721
+ }
2722
+ get environment() {
2723
+ return this.scope.environment ?? "production";
2724
+ }
2725
+ get sessionId() {
2726
+ return this.scope.sessionId;
2727
+ }
2728
+ get connectorOwnerId() {
2729
+ return this.scope.connectorOwnerId;
2730
+ }
2731
+ };
2732
+ /** Each entry owns one complete upstream response; views are derived below. */
2096
2733
  var ProxyStore = class {
2097
- constructor(client, kind, options) {
2734
+ #factory;
2735
+ constructor(client, kind, scope) {
2098
2736
  this.client = client;
2099
2737
  this.kind = kind;
2100
- this.options = options;
2101
2738
  this.entries = /* @__PURE__ */ new Map();
2739
+ this.#factory = new CacheFactory(scope);
2102
2740
  }
2103
- get(flowId, locale, service, force = false) {
2104
- const params = new URLSearchParams({
2105
- ...flowId == null ? {} : { flowId },
2106
- ...service == null ? {} : { service },
2107
- ...locale == null ? {} : { locale }
2108
- });
2109
- const path = `/v1/connector/proxy/${this.kind}${params.size ? `?${params}` : ""}`;
2741
+ get(flowId, locale = "en", service, force = false) {
2742
+ const path = proxyCatalogPath(this.kind, flowId, locale, service);
2110
2743
  let entry = this.entries.get(path);
2111
2744
  if (entry == null) {
2112
- const decode = (value) => proxyResponse(value, this.kind == "providers" ? provider : void 0);
2113
- const cacheParams = new URLSearchParams(params);
2114
- cacheParams.delete("flowId");
2115
- const persistence = catalogPersistence(this.options, this.kind, cacheParams.toString());
2116
- entry = new Resource((etag, signal) => this.client.readProxyCatalog({
2117
- path,
2118
- decode
2119
- }, etag, signal), this.kind == "providers" ? 3e5 : 3e4, persistence == null ? void 0 : {
2120
- ...persistence,
2121
- decode
2122
- });
2745
+ entry = new CacheResource(() => this.#cache(flowId, locale, service, path), void 0, false, catalogMaxAge[this.kind]);
2123
2746
  this.entries.set(path, entry);
2124
2747
  }
2125
2748
  return entry.get(force);
2126
2749
  }
2750
+ async #cache(flowId, locale, service, path) {
2751
+ const ownerId = this.#factory.connectorOwnerId;
2752
+ const key = JSON.stringify([
2753
+ this.kind,
2754
+ flowId ?? null,
2755
+ locale,
2756
+ service ?? null,
2757
+ ownerId ?? null
2758
+ ]);
2759
+ return this.#factory.cache(key, async () => {
2760
+ if (ownerId != null) {
2761
+ if (this.kind == "providers") return mapCache(getProvidersCache({
2762
+ environment: this.#factory.environment,
2763
+ locale,
2764
+ schemaVersion: 1,
2765
+ maxAge: catalogMaxAge.providers,
2766
+ decode: providerCacheValue,
2767
+ load: async (_query, validation) => {
2768
+ return await this.client.readProxyCatalog({
2769
+ path,
2770
+ decode: providerCacheValue
2771
+ }, validation.etag, validation.signal);
2772
+ }
2773
+ }), (value) => value, (value) => value, () => void 0);
2774
+ return mapCache(getActionsCache({
2775
+ environment: this.#factory.environment,
2776
+ locale,
2777
+ schemaVersion: 1,
2778
+ maxAge: catalogMaxAge.actions,
2779
+ decode: actionCacheValue,
2780
+ load: async ({ service: requestedService }, validation) => {
2781
+ return await this.client.readProxyCatalog({
2782
+ path: proxyCatalogPath("actions", flowId, locale, requestedService),
2783
+ decode: actionCacheValue
2784
+ }, validation.etag, validation.signal);
2785
+ }
2786
+ }), (value) => value, (value) => value, () => service ?? "");
2787
+ }
2788
+ return createSessionCache({
2789
+ namespace: JSON.stringify([
2790
+ "open-flow:connector-proxy",
2791
+ this.#factory.environment,
2792
+ this.kind,
2793
+ flowId ?? null
2794
+ ]),
2795
+ schemaVersion: 1,
2796
+ sessionId: this.#factory.sessionId,
2797
+ maxAge: this.kind == "providers" ? catalogMaxAge.providers : catalogMaxAge.actions,
2798
+ key: () => JSON.stringify([locale, service ?? null]),
2799
+ decode: proxyResponse,
2800
+ load: async (_query, validation) => this.client.readProxyCatalog({
2801
+ path,
2802
+ decode: proxyResponse
2803
+ }, validation.etag, validation.signal)
2804
+ });
2805
+ }, ownerId == null);
2806
+ }
2127
2807
  retryFailed() {
2128
- for (const entry of this.entries.values()) if (entry.state.value.error != null) entry.refresh();
2808
+ for (const entry of this.entries.values()) if (entry.state.value.error != null) entry.refresh(true);
2129
2809
  }
2130
2810
  refreshFlow(flowId) {
2131
2811
  for (const [path, entry] of this.entries) if (new URL(path, "https://open-flow.invalid").searchParams.get("flowId") == flowId) entry.refresh(true);
@@ -2133,6 +2813,7 @@ var ProxyStore = class {
2133
2813
  dispose() {
2134
2814
  for (const entry of this.entries.values()) entry.dispose();
2135
2815
  this.entries.clear();
2816
+ this.#factory.dispose();
2136
2817
  }
2137
2818
  };
2138
2819
  var Views = class {
@@ -2183,8 +2864,8 @@ var Views = class {
2183
2864
  };
2184
2865
  var ProviderStore = class {
2185
2866
  #views = new Views();
2186
- constructor(client, options) {
2187
- this.raw = new ProxyStore(client, "providers", options);
2867
+ constructor(client, scope) {
2868
+ this.raw = new ProxyStore(client, "providers", scope);
2188
2869
  }
2189
2870
  get(flowId, locale = "en", force = false) {
2190
2871
  return this.#views.get(identity(flowId, locale), [this.raw.get(flowId, locale, void 0, force)], (response) => response.data.map((item) => provider(item, response.meta?.iconSprite)));
@@ -2201,33 +2882,17 @@ var ProviderStore = class {
2201
2882
  }
2202
2883
  };
2203
2884
  var ConnectionStore = class {
2204
- #storage = {
2205
- get: async (key) => {
2206
- const raw = (this.options?.storage ?? window.sessionStorage).getItem(key);
2207
- return raw == null ? void 0 : JSON.parse(raw);
2208
- },
2209
- set: async (key, value) => {
2210
- (this.options?.storage ?? window.sessionStorage).setItem(key, JSON.stringify(value));
2211
- }
2212
- };
2213
2885
  #entries = /* @__PURE__ */ new Map();
2214
2886
  #views = /* @__PURE__ */ new Map();
2215
- constructor(client, options) {
2887
+ #factory;
2888
+ constructor(client, scope) {
2216
2889
  this.client = client;
2217
- this.options = options;
2890
+ this.#factory = new CacheFactory(scope);
2218
2891
  }
2219
2892
  get(serviceId, flowId, force = false) {
2220
2893
  let entry = this.#entries.get(flowId);
2221
2894
  if (entry == null) {
2222
- const query = allConnectorConnectionsQuery(flowId);
2223
- entry = new Resource((etag, signal) => this.client.readCatalog(query, etag, signal), 3e4, this.options == null ? void 0 : {
2224
- key: `open-flow:connections:v1:${query.path}`,
2225
- storage: this.#storage,
2226
- decode: (value) => {
2227
- if (!Array.isArray(value)) return invalidResponse();
2228
- return value.map(connection);
2229
- }
2230
- });
2895
+ entry = new CacheResource(() => this.#cache(flowId), void 0, false, catalogMaxAge.connections);
2231
2896
  this.#entries.set(flowId, entry);
2232
2897
  }
2233
2898
  const source = entry.get(force);
@@ -2243,8 +2908,54 @@ var ConnectionStore = class {
2243
2908
  }
2244
2909
  return view;
2245
2910
  }
2911
+ async #cache(flowId) {
2912
+ const query = allConnectorConnectionsQuery(flowId);
2913
+ const ownerId = this.#factory.connectorOwnerId;
2914
+ const key = JSON.stringify([
2915
+ "connections",
2916
+ flowId ?? null,
2917
+ ownerId ?? null
2918
+ ]);
2919
+ return this.#factory.cache(key, async () => {
2920
+ if (ownerId != null) return mapCache(getConnectionsCache({
2921
+ environment: this.#factory.environment,
2922
+ sessionId: this.#factory.sessionId,
2923
+ ownerId,
2924
+ schemaVersion: 1,
2925
+ maxAge: catalogMaxAge.connections,
2926
+ decode: connectionsCacheValue,
2927
+ load: async (_query, validation) => {
2928
+ const result = await this.client.readCatalog(query, validation.etag, validation.signal);
2929
+ return result.modified ? {
2930
+ modified: true,
2931
+ data: connectionsCacheValue({
2932
+ version: 1,
2933
+ connections: result.data
2934
+ }),
2935
+ etag: result.etag
2936
+ } : result;
2937
+ }
2938
+ }), connectionsAsProxy, connectionsAsProxy, () => void 0);
2939
+ return createSessionCache({
2940
+ namespace: JSON.stringify([
2941
+ "open-flow:connections",
2942
+ this.#factory.environment,
2943
+ flowId ?? null
2944
+ ]),
2945
+ schemaVersion: 1,
2946
+ sessionId: this.#factory.sessionId,
2947
+ maxAge: catalogMaxAge.connections,
2948
+ key: () => "all",
2949
+ decode: (value) => {
2950
+ if (!Array.isArray(value)) return invalidResponse();
2951
+ return value.map(connection);
2952
+ },
2953
+ load: async (_query, validation) => this.client.readCatalog(query, validation.etag, validation.signal)
2954
+ });
2955
+ }, ownerId == null);
2956
+ }
2246
2957
  retryFailed() {
2247
- for (const entry of this.#entries.values()) if (entry.state.value.error != null) entry.refresh();
2958
+ for (const entry of this.#entries.values()) if (entry.state.value.error != null) entry.refresh(true);
2248
2959
  }
2249
2960
  refreshFlow(flowId) {
2250
2961
  this.#entries.get(flowId)?.refresh(true);
@@ -2254,6 +2965,7 @@ var ConnectionStore = class {
2254
2965
  this.#views.clear();
2255
2966
  for (const entry of this.#entries.values()) entry.dispose();
2256
2967
  this.#entries.clear();
2968
+ this.#factory.dispose();
2257
2969
  }
2258
2970
  };
2259
2971
  var ActionStore = class {
@@ -2262,10 +2974,10 @@ var ActionStore = class {
2262
2974
  #details = /* @__PURE__ */ new Map();
2263
2975
  #searches = /* @__PURE__ */ new Set();
2264
2976
  #searchSessions = /* @__PURE__ */ new WeakMap();
2265
- constructor(client, providers, options) {
2977
+ constructor(client, providers, scope) {
2266
2978
  this.client = client;
2267
2979
  this.providers = providers;
2268
- this.#raw = new ProxyStore(client, "actions", options);
2980
+ this.#raw = new ProxyStore(client, "actions", scope);
2269
2981
  }
2270
2982
  get(serviceId, flowId, locale = "en", force = false) {
2271
2983
  return this.#views.get(identity(flowId, serviceId, locale), [this.#raw.get(flowId, locale, serviceId, force), this.providers.raw.get(flowId, locale)], (actions, providers) => actions.data.flatMap((item) => {
@@ -2309,7 +3021,6 @@ var ActionStore = class {
2309
3021
  q: query.trim(),
2310
3022
  locale
2311
3023
  });
2312
- const key = params.toString();
2313
3024
  let entries = this.#searchSessions.get(signal);
2314
3025
  if (entries == null) {
2315
3026
  entries = /* @__PURE__ */ new Map();
@@ -2324,21 +3035,38 @@ var ActionStore = class {
2324
3035
  this.#searchSessions.delete(signal);
2325
3036
  }, { once: true });
2326
3037
  }
3038
+ const key = params.toString();
2327
3039
  const cached = entries.get(key);
2328
3040
  if (cached != null) {
2329
- cached.refresh();
3041
+ cached.refresh(true);
2330
3042
  return cached;
2331
3043
  }
2332
- const resource = new Resource((_etag, requestSignal) => this.client.readCatalog({
2333
- path: `/v1/connector/action-metadata?${params}`,
2334
- decode: actionsResponse
2335
- }, null, requestSignal), 3e4);
2336
- if (signal.aborted) resource.dispose();
3044
+ const cache = createSessionCache({
3045
+ namespace: JSON.stringify(["open-flow:action-search", crypto.randomUUID()]),
3046
+ schemaVersion: 1,
3047
+ sessionId: "search",
3048
+ maxAge: 0,
3049
+ key: () => "result",
3050
+ decode: (value) => {
3051
+ if (!Array.isArray(value)) return invalidResponse();
3052
+ return value.map(connectorActionMetadata);
3053
+ },
3054
+ load: async (_query, validation) => this.client.readCatalog({
3055
+ path: `/v1/connector/action-metadata?${params}`,
3056
+ decode: (value) => {
3057
+ const source = record(value);
3058
+ if (source.version != 1 || !Array.isArray(source.actions)) return invalidResponse();
3059
+ return source.actions.map(connectorActionMetadata);
3060
+ }
3061
+ }, validation.etag, validation.signal)
3062
+ });
3063
+ const result = new CacheResource(async () => cache, void 0, true, 0);
3064
+ if (signal.aborted) result.dispose();
2337
3065
  else {
2338
- entries.set(key, resource);
2339
- this.#searches.add(resource);
3066
+ entries.set(key, result);
3067
+ this.#searches.add(result);
2340
3068
  }
2341
- return resource;
3069
+ return result;
2342
3070
  }
2343
3071
  retryFailed() {
2344
3072
  this.#raw.retryFailed();
@@ -2356,10 +3084,10 @@ var ActionStore = class {
2356
3084
  }
2357
3085
  };
2358
3086
  var CatalogStores = class {
2359
- constructor(client, options, connections) {
2360
- this.providers = new ProviderStore(client, options);
2361
- this.actions = new ActionStore(client, this.providers, options);
2362
- this.connections = new ConnectionStore(client, connections);
3087
+ constructor(client, scope = { sessionId: crypto.randomUUID() }) {
3088
+ this.providers = new ProviderStore(client, scope);
3089
+ this.actions = new ActionStore(client, this.providers, scope);
3090
+ this.connections = new ConnectionStore(client, scope);
2363
3091
  }
2364
3092
  dispose() {
2365
3093
  this.actions.dispose();
@@ -2739,8 +3467,9 @@ var ConnectorStore = class {
2739
3467
  };
2740
3468
  this.provideAddNodeOptionChoices = (optionId, signal) => {
2741
3469
  const service = optionId.slice(19);
2742
- const source = this.data.actions.get(service, void 0, this.#language);
2743
- const providers = this.data.providers.get(void 0, this.#language);
3470
+ const flowId = this.#workspace.$.flowId.value;
3471
+ const source = this.data.actions.get(service, flowId, this.#language);
3472
+ const providers = this.data.providers.get(flowId, this.#language);
2744
3473
  return scopedValue(signal, (get) => {
2745
3474
  const state = get(source);
2746
3475
  const provider = get(providers).data?.find((item) => item.serviceId == service);
@@ -2871,12 +3600,22 @@ var ConnectorStore = class {
2871
3600
  this.#actionIds.set([]);
2872
3601
  this.#services.set([]);
2873
3602
  }
3603
+ retryAction(actionId) {
3604
+ const flowId = this.#workspace.$.flowId.value;
3605
+ if (flowId == null || this.#disposed) return;
3606
+ const actionState = this.data.actions.detail(actionId, flowId, this.#language, true);
3607
+ if (this.data.providers.get(flowId, this.#language).value.error != null) this.data.providers.get(flowId, this.#language, true);
3608
+ if (actionState.value.data?.authenticated !== false) this.data.connections.refreshFlow(flowId);
3609
+ }
2874
3610
  async resolveAction(actionId) {
2875
3611
  const flowId = this.#workspace.$.flowId.value;
2876
3612
  if (flowId == null || this.#disposed) throw new Error("Connector Action cannot be resolved without an active Flow.");
3613
+ const actionState = this.data.actions.detail(actionId, flowId, this.#language);
3614
+ await Promise.resolve();
3615
+ const action = await resourceValue(actionState, void 0, true);
3616
+ const connectionState = action.authenticated ? this.data.connections.get(action.serviceId, flowId) : void 0;
2877
3617
  await Promise.resolve();
2878
- const action = await resourceValue(this.data.actions.detail(actionId, flowId, this.#language), void 0, true);
2879
- const connections = action.authenticated ? await resourceValue(this.data.connections.get(action.serviceId, flowId), void 0, true) : [];
3618
+ const connections = connectionState == null ? [] : await resourceValue(connectionState, void 0, true);
2880
3619
  this.#remember(this.#actionIds, [actionId]);
2881
3620
  if (action.authenticated) this.#remember(this.#services, [action.serviceId]);
2882
3621
  return {
@@ -3053,9 +3792,9 @@ var ConnectorStore = class {
3053
3792
  var TriggerCatalogStore = class {
3054
3793
  #language;
3055
3794
  #entries;
3056
- constructor(client, language, host) {
3795
+ constructor(client, language, environment = "production") {
3057
3796
  this.client = client;
3058
- this.host = host;
3797
+ this.environment = environment;
3059
3798
  this.#entries = /* @__PURE__ */ new Map();
3060
3799
  this.retry = () => {
3061
3800
  this.get(true);
@@ -3071,14 +3810,18 @@ var TriggerCatalogStore = class {
3071
3810
  if (data.locale != locale) throw new Error("Unexpected Trigger catalog language.");
3072
3811
  return data;
3073
3812
  };
3074
- const persistence = catalogPersistence(this.host.catalogCache, "triggers", locale);
3075
- entry = new Resource((etag, signal) => this.client.readCatalog({
3076
- path: `/v1/trigger-keys/catalog?locale=${encodeURIComponent(locale)}`,
3077
- decode
3078
- }, etag, signal), 3e5, persistence == null ? void 0 : {
3079
- ...persistence,
3080
- decode
3813
+ const cache = createPersistentCache({
3814
+ namespace: JSON.stringify(["open-flow:trigger-catalog", this.environment]),
3815
+ schemaVersion: 1,
3816
+ maxAge: 3e5,
3817
+ key: () => locale,
3818
+ decode,
3819
+ load: async (_query, validation) => this.client.readCatalog({
3820
+ path: `/v1/trigger-keys/catalog?locale=${encodeURIComponent(locale)}`,
3821
+ decode
3822
+ }, validation.etag, validation.signal)
3081
3823
  });
3824
+ entry = new CacheResource(async () => cache, void 0, true, 3e5);
3082
3825
  this.#entries.set(locale, entry);
3083
3826
  }
3084
3827
  return entry;
@@ -3157,7 +3900,7 @@ var TriggerStore = class {
3157
3900
  this.#disposed = false;
3158
3901
  this.browseAddNodeOptions = (signal) => this.#options("", signal);
3159
3902
  this.provideAddNodeOptions = (searchTerm, signal) => this.#options(searchTerm, signal);
3160
- this.catalog = new TriggerCatalogStore(client, resolveUiLanguage([i18n.lang]), host);
3903
+ this.catalog = new TriggerCatalogStore(client, resolveUiLanguage([i18n.lang]), host.cacheEnvironment);
3161
3904
  this.#client = client;
3162
3905
  this.#host = host;
3163
3906
  this.#i18n = i18n;
@@ -3172,7 +3915,7 @@ var TriggerStore = class {
3172
3915
  if (trigger.kind != "poll" && trigger.kind != "integration") return { authorizationPending: false };
3173
3916
  const connections = current == null ? void 0 : get(workspace.catalogs.connections.get(current.provider, get(workspace.$.flowId))).data;
3174
3917
  const catalog = connections == null ? void 0 : connectionCatalog(connections);
3175
- const connectionError = current == null ? void 0 : get(workspace.catalogs.connections.get(current.provider, get(workspace.$.flowId))).error;
3918
+ const connectionError = current == null ? void 0 : state.connectionError?.provider == current.provider ? new Error(state.connectionError.message) : get(workspace.catalogs.connections.get(current.provider, get(workspace.$.flowId))).error;
3176
3919
  return {
3177
3920
  activeConnections: catalog?.active,
3178
3921
  authorizationPending: state.authorizationProvider == current?.provider,
@@ -3440,6 +4183,13 @@ function inverseFlowChanges(content, operations) {
3440
4183
  });
3441
4184
  break;
3442
4185
  }
4186
+ case "graph.trigger.sources.set":
4187
+ restore.push({
4188
+ ...operation,
4189
+ before: operation.value,
4190
+ value: operation.before
4191
+ });
4192
+ break;
3443
4193
  case "binding.target.set":
3444
4194
  restore.push({
3445
4195
  ...operation,
@@ -3531,6 +4281,7 @@ function inverseFlowChanges(content, operations) {
3531
4281
  value: operation.before
3532
4282
  });
3533
4283
  break;
4284
+ case "task.openapi.set":
3534
4285
  case "task.agent.set":
3535
4286
  restore.push({
3536
4287
  ...operation,
@@ -3595,8 +4346,9 @@ function pasteNodes(revision, target, clipboard, identity) {
3595
4346
  nodeIds: [],
3596
4347
  sourceIds: []
3597
4348
  };
4349
+ const hasErrorTrigger = Object.values(revision.graph(target)?.nodes ?? {}).some((node) => node.kind === "error");
3598
4350
  const hasManualTrigger = Object.values(revision.graph(target)?.nodes ?? {}).some((node) => node.kind === "manual");
3599
- const entries = Object.entries(clipboard.nodes).filter(([, node]) => (target.kind == "flow" || "inputs" in node) && (node.kind !== "manual" || !hasManualTrigger) && (node.kind != "task" || node.task == null || clipboard.modules[node.task.moduleId] != null));
4351
+ const entries = Object.entries(clipboard.nodes).filter(([, node]) => (target.kind == "flow" || "inputs" in node) && (node.kind !== "manual" || !hasManualTrigger) && (node.kind !== "error" || !hasErrorTrigger) && (node.kind != "task" || node.task == null || clipboard.modules[node.task.moduleId] != null));
3600
4352
  const sourceIds = entries.map(([sourceId]) => sourceId);
3601
4353
  const ids = new Map(sourceIds.map((sourceId) => [sourceId, identity()]));
3602
4354
  const operations = [];
@@ -4848,6 +5600,9 @@ var WorkspaceStore = class {
4848
5600
  this.#set({ busy: void 0 });
4849
5601
  }
4850
5602
  }
5603
+ getErrorListeners(flowId, signal) {
5604
+ return this.#client.getErrorListeners(flowId, signal);
5605
+ }
4851
5606
  async deleteFlow(flowId) {
4852
5607
  if (!await this.saveModuleEditor()) return false;
4853
5608
  const flow = this.#flows.flow(flowId);
@@ -5048,6 +5803,16 @@ var WorkspaceStore = class {
5048
5803
  this.copySelectedNodes();
5049
5804
  await this.pasteNodes(positions, offset);
5050
5805
  }
5806
+ async saveErrorSources(nodeId, value) {
5807
+ const node = this.$.revision.value?.graph({ kind: "flow" })?.nodes[nodeId];
5808
+ if (node?.kind != "error" || dequal$1(node.sourceFlowIds ?? [], value)) return false;
5809
+ return await this.#editDraft([{
5810
+ kind: "graph.trigger.sources.set",
5811
+ nodeId,
5812
+ before: node.sourceFlowIds,
5813
+ value: value.length == 0 ? void 0 : value
5814
+ }]) != null;
5815
+ }
5051
5816
  async saveNodeSettings(nodeId, settings) {
5052
5817
  const revision = this.$.revision.value;
5053
5818
  const target = this.#model.value.target;
@@ -5157,6 +5922,9 @@ var WorkspaceStore = class {
5157
5922
  position
5158
5923
  }));
5159
5924
  }
5925
+ loadOpenApiDocument(url, signal) {
5926
+ return this.#client.loadOpenApiDocument(url, signal);
5927
+ }
5160
5928
  async saveTaskSettings(nodeId, settings) {
5161
5929
  const revision = this.$.revision.value;
5162
5930
  const target = this.#model.value.target;
@@ -5706,7 +6474,7 @@ var WorkbenchStore = class {
5706
6474
  #openingCreatedFlow;
5707
6475
  #stopAccessReaction;
5708
6476
  #accessLoading;
5709
- constructor(client, preferences, identity = randomId, i18n = createI18n(), host = blockedExternalPages, variables = true) {
6477
+ constructor(client, preferences, identity = randomId, i18n = createI18n(), host = blockedExternalPages, variables = true, cacheSessionId = crypto.randomUUID()) {
5710
6478
  this.#externalRuns = new Latest();
5711
6479
  this.#notice = val();
5712
6480
  this.#variableNames = val([]);
@@ -5740,7 +6508,11 @@ var WorkbenchStore = class {
5740
6508
  this.workspace = new WorkspaceStore(client, setNotice, createAuthoringId, i18n, (event) => {
5741
6509
  if (event.kind == "run.created") this.#followExternalRun(client, event);
5742
6510
  else this.runs.changed(event.runId);
5743
- }, new CatalogStores(client, host.catalogCache, host.connectionCache), (flowId) => void this.#openCreatedFlow(flowId), (flowId) => {
6511
+ }, new CatalogStores(client, {
6512
+ sessionId: cacheSessionId,
6513
+ environment: host.cacheEnvironment,
6514
+ connectorOwnerId: host.connectorOwnerId
6515
+ }), (flowId) => void this.#openCreatedFlow(flowId), (flowId) => {
5744
6516
  this.connectorAccess.changed(flowId);
5745
6517
  this.workspace.catalogs.refreshFlow(flowId);
5746
6518
  });
@@ -6118,7 +6890,7 @@ var WorkbenchStore = class {
6118
6890
  };
6119
6891
  //#endregion
6120
6892
  //#region src/workbench/browser/runtime/openFlowWorkbench.tsx
6121
- var FlowWorkspace = lazy(() => import("./flowWorkspace-CjwpbVBR.js"));
6893
+ var FlowWorkspace = lazy(() => import("./flowWorkspace-DLgti4Lk.js"));
6122
6894
  function OpenFlowSessionGate({ action, description, error, onSubmit, onTokenChange, pending = false, title, token, tokenLabel }) {
6123
6895
  const hasToken = token != null && tokenLabel != null && onTokenChange != null;
6124
6896
  const tokenValue = token ?? "";
@@ -6253,17 +7025,17 @@ function Workbench({ catalogWidth, createFlow, createFlowDisabled, createFlowFie
6253
7025
  })
6254
7026
  });
6255
7027
  }
6256
- function Session({ catalogWidth, createFlow, createFlowDisabled, createFlowField, flowBadges, connectionHref, host, hrefFor, language, location, onConfigureConnector, onManageConnectorAccess, onLanguageChange, onNavigate, preferences, theme, variables = true }) {
7028
+ function Session({ catalogWidth, createFlow, createFlowDisabled, createFlowField, flowBadges, connectionHref, host, hrefFor, language, location, onConfigureConnector, onManageConnectorAccess, onLanguageChange, onNavigate, preferences, sessionKey, theme, variables = true }) {
6257
7029
  const navigate = useRef(onNavigate);
6258
7030
  navigate.current = onNavigate;
6259
7031
  const [{ i18n, navigation, store }] = useState(() => {
6260
7032
  const workbenchI18n = createI18n(language);
6261
7033
  const workbenchStore = new WorkbenchStore(new WorkbenchClient((input, init) => host.request(input, init), (flowId, listener) => host.subscribeFlow(flowId, listener), (listener) => host.subscribeFlowCatalog(listener)), preferences, randomId, workbenchI18n, {
6262
7034
  openExternalPage: (resolveUrl) => host.openExternalPage(resolveUrl),
6263
- catalogCache: host.catalogCache,
6264
- connectionCache: host.connectionCache,
7035
+ cacheEnvironment: host.cacheEnvironment,
7036
+ connectorOwnerId: host.connectorOwnerId,
6265
7037
  resolveActor: actorResolver(host, globalThis.location?.origin)
6266
- }, variables);
7038
+ }, variables, sessionKey);
6267
7039
  return {
6268
7040
  i18n: workbenchI18n,
6269
7041
  navigation: new NavigationStore(workbenchStore, location, (nextLocation, options) => navigate.current(nextLocation, options)),
@@ -6334,7 +7106,10 @@ function Session({ catalogWidth, createFlow, createFlowDisabled, createFlowField
6334
7106
  });
6335
7107
  }
6336
7108
  function OpenFlowWorkbench({ sessionKey, ...props }) {
6337
- return /* @__PURE__ */ jsx(Session, { ...props }, sessionKey);
7109
+ return /* @__PURE__ */ jsx(Session, {
7110
+ sessionKey,
7111
+ ...props
7112
+ }, `${sessionKey}:${props.host.connectorOwnerId ?? ""}`);
6338
7113
  }
6339
7114
  //#endregion
6340
7115
  export { EventSourcesPage, OpenFlowSessionGate, OpenFlowWorkbench, isUiLanguage as isWorkbenchLanguage, resolveUiLanguage as resolveWorkbenchLanguage, uiLanguageNames as workbenchLanguageNames, uiLanguages as workbenchLanguages };