@oomol-lab/open-flow 0.1.0-beta.89 → 0.1.0-beta.90

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 (33) hide show
  1. package/README.md +29 -0
  2. package/dist/browser/{FlowCanvas-SqPUBqze.js → FlowCanvas-C4iuvVKB.js} +2 -2
  3. package/dist/browser/{exportPng-CLZKdNzR.js → exportPng-DMsB9ku_.js} +4 -4
  4. package/dist/browser/{flowChanges-CnOOPJJR.js → flowChanges-SKYJBr6X.js} +12 -11
  5. package/dist/browser/{flowWorkspace-d9Ef-aRK.js → flowWorkspace-4UHRaHcz.js} +10 -7
  6. package/dist/browser/{markdownContent-D0BBrFcF.js → markdownContent-B75ojl0E.js} +1 -1
  7. package/dist/browser/preview.css +14 -5
  8. package/dist/browser/preview.d.ts +4 -1
  9. package/dist/browser/preview.js +397 -95
  10. package/dist/browser/workbench-contract.d.ts +3 -0
  11. package/dist/browser/workbench.css +14 -5
  12. package/dist/browser/workbench.js +12 -9
  13. package/dist/browser/{wrapLayout-BB_qwy3k.js → wrapLayout-DU5HG1qH.js} +371 -71
  14. package/dist/command/index.js +13 -13
  15. package/dist/common/cache.d.ts +7 -0
  16. package/dist/common/catalogCache.d.ts +3 -7
  17. package/dist/common/control-api-conformance.js +10 -9
  18. package/dist/common/control-api.d.ts +3 -1
  19. package/dist/common/control-api.js +10 -9
  20. package/dist/common/mcp.js +10 -9
  21. package/dist/common/provider-icons.d.ts +35 -0
  22. package/dist/common/provider-icons.js +134 -0
  23. package/dist/render/browser/runtime.css +14 -5
  24. package/dist/render/browser/runtime.js +667 -365
  25. package/dist/render/common/png.d.ts +7 -0
  26. package/dist/render/node/index.d.ts +10 -2
  27. package/dist/render/node/index.js +1284 -37
  28. package/dist/render/node/licenses.md +24 -0
  29. package/package.json +5 -1
  30. package/src/base/common/cache.ts +8 -0
  31. package/src/connector/common/providerIconCache.ts +191 -0
  32. package/src/control/common/api.ts +10 -3
  33. package/src/control/common/catalogCache.ts +19 -11
@@ -1,9 +1,9 @@
1
- import { A as DropdownMenuItem, C as IconifyProvider, E as DropdownMenu, O as DropdownMenuContent, P as DropdownMenuSeparator, R as DropdownMenuTrigger, c as PopoverContent, f as PopoverTitle, p as PopoverTrigger, pt as IconThemeContext, s as Popover, v as ContentIcon } from "./wrapLayout-BB_qwy3k.js";
1
+ import { A as DropdownMenuItem, C as IconifyProvider, E as DropdownMenu, O as DropdownMenuContent, P as DropdownMenuSeparator, R as DropdownMenuTrigger, c as PopoverContent, f as PopoverTitle, ht as IconThemeContext, p as PopoverTrigger, pt as ProviderIconCacheContext, s as Popover, v as ContentIcon } from "./wrapLayout-DU5HG1qH.js";
2
2
  import { a as derive, i as compute, l as val } from "./dist-bO8nvHFH.js";
3
3
  import { c as useLang, l as useTranslate, o as I18nProvider, u as useVal } from "./dist-BFmpkX4P.js";
4
4
  import { Cr as cn, i as TooltipTrigger, n as TooltipContent, t as Tooltip, xr as Button } from "./tooltip-BZ6tpqnr.js";
5
5
  import { Bt as schemaObject, C as upgradeManualTrigger, Dt as connectorProxyTask, M as mapConditionSources, N as nodeInputMappings, Rt as matchesSchema, S as resourceNameIssue, Yt as dequal, _ as applyFlowChanges, a as DialogFooter, bt as connectorProxyConfigSchema, d as Field, g as FlowChangeError, h as FieldLabel, hn as Input, i as DialogDescription, l as Icon, m as FieldGroup, o as DialogHeader, p as FieldError, r as DialogContent, s as DialogTitle, t as Dialog, u as Spinner, v as isTriggerNode, w as upgradeRevisionContent } from "./dialog-Bi-MVTGj.js";
6
- import { $ as resourceValue, $n as allConnectorConnectionsQuery, $t as WorkflowExportDialog, At as actionWithConnections, Bn as EmptyMedia, Br as ApiError, Bt as setNodeContentHidden, C as updateValue, Ct as flowResourceReferences, Et as diagnosticItems, Fn as InputGroupInput, Ft as removeComments, Gt as setCodeActions, Hn as Badge, Ht as setVerticalNodeWidth, In as Empty, It as restoreCanvasPresentation, J as scopedValue, Jt as setServiceConnections, K as combineSources, Kn as createI18n, Kt as setConnectorConnection, Ln as EmptyContent, Lt as setCanvasLayout, Mn as followWorkbenchLink, Mt as canvasPresentationChange, Nn as InputGroup, Nt as commentIds, Pn as InputGroupAddon, Pr as workflowCandidate, Pt as flowPresentation, Q as resourceData, Qn as randomId, Qt as WorkflowBundleSummary, Rn as EmptyDescription, Rr as invalidResponse, Rt as setComment, S as updateTriggerConfig, St as revisionView, Tt as deriveInspectorDiagnostics, U as addNodeIntent, Un as EventSourcesPage, Ut as repairNodeNames, Vn as EmptyTitle, Vr as controlErrorCode, Vt as setNodePositions, W as deriveAddNodeOptions, Wt as resetInputValues, X as CacheResource, Xn as WorkbenchClient, Xt as updateTriggerSchedule, Y as connectorActionPresentation, Yn as errorNotice, Yt as updateStartInputDefs, Zn as normalizeFlowQuery, Zt as dequal$1, _ as updateRequestParameters, _r as workflowBundleFromPreview, a as nameCreatedNodes, an as FlowTagChips, at as getActionsCache, b as updateTaskAdditionalInputs, br as workflowNameFromFile, c as setInputVariable, cr as normalizeTriggerOutputs, ct as getProvidersCache, d as updateCondition, en as WorkflowExportMenuItem, et as action, f as updateNodeDescription, fr as isJsonValue, ft as designerGraph, g as updateOutputPorts, gr as parseWorkflowImportFile, h as updateNodeSettings, hr as encodeWorkflowBundle, i as deleteSelection, in as FlowSettingsDialog, jn as useFlowQuery, jt as connectionCatalog, l as setTriggerConnection, lr as sampleErrorOutputs, lt as createPersistentCache, m as updateNodeName, mr as connectorActionMetadata, nn as IdTooltip, nt as proxyResponse, o as selectWebhookResponse, on as TagPicker, p as updateNodeIcon, pr as connection, qt as setInputSources, r as applyFlowChanges$1, rt as validateAction, s as setInputValue, st as getConnectionsCache, t as addNode, tn as useWorkflowExportAction, tr as decodeTriggerCatalog, tt as provider, u as setTriggerEventSource, ur as triggerOutputDefinitions, ut as createSessionCache, v as updateResolution, vr as encodeWorkflowFile, vt as providerIcon, w as updateWebhook, wt as Latest, x as updateTaskPorts, y as updateTask, yr as workflowFileName, yt as RunStore, zn as EmptyHeader, zr as record, zt as setFlowViewport } from "./flowChanges-CnOOPJJR.js";
6
+ import { $ as resourceValue, $n as allConnectorConnectionsQuery, $t as WorkflowExportDialog, At as actionWithConnections, Bn as EmptyMedia, Br as ApiError, Bt as setNodeContentHidden, C as updateValue, Ct as flowResourceReferences, Et as diagnosticItems, Fn as InputGroupInput, Ft as removeComments, Gt as setCodeActions, Hn as Badge, Ht as setVerticalNodeWidth, In as Empty, It as restoreCanvasPresentation, J as scopedValue, Jt as setServiceConnections, K as combineSources, Kn as createI18n, Kt as setConnectorConnection, Ln as EmptyContent, Lt as setCanvasLayout, Mn as followWorkbenchLink, Mt as canvasPresentationChange, Nn as InputGroup, Nt as commentIds, Pn as InputGroupAddon, Pr as workflowCandidate, Pt as flowPresentation, Q as resourceData, Qn as randomId, Qt as WorkflowBundleSummary, Rn as EmptyDescription, Rr as invalidResponse, Rt as setComment, S as updateTriggerConfig, St as revisionView, Tt as deriveInspectorDiagnostics, U as addNodeIntent, Un as EventSourcesPage, Ut as repairNodeNames, Vn as EmptyTitle, Vr as controlErrorCode, Vt as setNodePositions, W as deriveAddNodeOptions, Wt as resetInputValues, X as CacheResource, Xn as WorkbenchClient, Xt as updateTriggerSchedule, Y as connectorActionPresentation, Yn as errorNotice, Yt as updateStartInputDefs, Zn as normalizeFlowQuery, Zt as dequal$1, _ as updateRequestParameters, _r as workflowBundleFromPreview, a as nameCreatedNodes, an as FlowTagChips, at as getActionsCache, b as updateTaskAdditionalInputs, br as workflowNameFromFile, c as setInputVariable, cr as normalizeTriggerOutputs, ct as getProvidersCache, d as updateCondition, en as WorkflowExportMenuItem, et as action, f as updateNodeDescription, fr as isJsonValue, ft as designerGraph, g as updateOutputPorts, gr as parseWorkflowImportFile, h as updateNodeSettings, hr as encodeWorkflowBundle, i as deleteSelection, in as FlowSettingsDialog, jn as useFlowQuery, jt as connectionCatalog, l as setTriggerConnection, lr as sampleErrorOutputs, lt as createPersistentCache, m as updateNodeName, mr as connectorActionMetadata, nn as IdTooltip, nt as proxyResponse, o as selectWebhookResponse, on as TagPicker, p as updateNodeIcon, pr as connection, qt as setInputSources, r as applyFlowChanges$1, rt as validateAction, s as setInputValue, st as getConnectionsCache, t as addNode, tn as useWorkflowExportAction, tr as decodeTriggerCatalog, tt as provider, u as setTriggerEventSource, ur as triggerOutputDefinitions, ut as createSessionCache, v as updateResolution, vr as encodeWorkflowFile, vt as providerIcon, w as updateWebhook, wt as Latest, x as updateTaskPorts, y as updateTask, yr as workflowFileName, yt as RunStore, zn as EmptyHeader, zr as record, zt as setFlowViewport } from "./flowChanges-SKYJBr6X.js";
7
7
  import { a as uiLanguages, i as uiLanguageNames, n as isUiLanguage, r as resolveUiLanguage, t as importedWorkflowName } from "./languages-gYzoQqCi.js";
8
8
  import { i as objectValue, n as isJsonValue$1, s as valueType, t as initialValue } from "./value-BbFQZZ_V.js";
9
9
  import { Suspense, forwardRef, lazy, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
@@ -7047,7 +7047,7 @@ var WorkbenchStore = class {
7047
7047
  async downloadPng(result) {
7048
7048
  const title = this.workspace.$.flow.value?.name ?? this.workspace.$.flowId.value ?? "Workflow";
7049
7049
  try {
7050
- const { downloadPng } = await import("./exportPng-CLZKdNzR.js");
7050
+ const { downloadPng } = await import("./exportPng-DMsB9ku_.js");
7051
7051
  downloadPng(result, title);
7052
7052
  if (!this.#disposed) this.#notice.set({
7053
7053
  kind: "success",
@@ -7314,7 +7314,7 @@ var WorkbenchStore = class {
7314
7314
  };
7315
7315
  //#endregion
7316
7316
  //#region src/workbench/browser/runtime/openFlowWorkbench.tsx
7317
- var FlowWorkspace = lazy(() => import("./flowWorkspace-d9Ef-aRK.js"));
7317
+ var FlowWorkspace = lazy(() => import("./flowWorkspace-4UHRaHcz.js"));
7318
7318
  function OpenFlowSessionGate({ action, description, error, onSubmit, onTokenChange, pending = false, title, token, tokenLabel }) {
7319
7319
  const hasToken = token != null && tokenLabel != null && onTokenChange != null;
7320
7320
  const tokenValue = token ?? "";
@@ -7551,11 +7551,14 @@ var Session = forwardRef(function Session({ catalogWidth, createFlow, importFlow
7551
7551
  });
7552
7552
  });
7553
7553
  var OpenFlowWorkbench = forwardRef(function OpenFlowWorkbench({ sessionKey, ...props }, ref) {
7554
- return /* @__PURE__ */ jsx(Session, {
7555
- ref,
7556
- sessionKey,
7557
- ...props
7558
- }, `${sessionKey}:${props.host.connectorOwnerId ?? ""}`);
7554
+ return /* @__PURE__ */ jsx(ProviderIconCacheContext.Provider, {
7555
+ value: props.host.iconCache,
7556
+ children: /* @__PURE__ */ jsx(Session, {
7557
+ ref,
7558
+ sessionKey,
7559
+ ...props
7560
+ }, `${sessionKey}:${props.host.connectorOwnerId ?? ""}`)
7561
+ });
7559
7562
  });
7560
7563
  //#endregion
7561
7564
  export { EventSourcesPage, OpenFlowSessionGate, OpenFlowWorkbench, isUiLanguage as isWorkbenchLanguage, resolveUiLanguage as resolveWorkbenchLanguage, uiLanguageNames as workbenchLanguageNames, uiLanguages as workbenchLanguages };
@@ -1,7 +1,8 @@
1
1
  import { a as derive, l as val, r as combine } from "./dist-bO8nvHFH.js";
2
+ import { u as useVal } from "./dist-BFmpkX4P.js";
2
3
  import { $ as useToolbarRootContext, $t as fastComponent, An as isMac, Ar as warn, At as useImplicitActiveTrigger, B as ARROW_LEFT, Bn as transitionStatusMapping, Br as useStableCallback, Bt as useFloatingNodeId, Cr as cn, Ct as useHoverFloatingInteraction, Dn as getTarget, Dr as EMPTY_ARRAY$1, Dt as createInitialPopupStoreState, En as contains, Er as useRenderElement, Fn as createLucideIcon, Fr as formatErrorMessage, Ft as useDismiss, G as HORIZONTAL_KEYS, Gr as isHTMLElement$1, Gt as CLICK_TRIGGER_IDENTIFIER, H as ARROW_UP, Hn as useOnMount, Hr as getParentNode, Ht as useFloatingTree, I as useCompositeListItem, In as useTransitionStatus, Ir as mergeProps, It as useClick, Jn as closePress, Jt as FocusGuard, K as HORIZONTAL_KEYS_WITH_EXTRA_KEYS, Kn as cancelOpen, Kr as isLastTraversableNode, Kt as DROPDOWN_COLLISION_AVOIDANCE, L as ALL_KEYS, Ln as useOpenChangeComplete, Lr as useIsoLayoutEffect, Lt as FloatingFocusManager, Mn as ownerDocument, Mr as useButton, Mt as useTriggerDataForwarding, Nr as CompositeRootContext, Nt as useTriggerRegistration, Or as EMPTY_OBJECT, Ot as popupStoreSelectors, P as Separator, Pn as Check, Pr as useCompositeRootContext, Q as scrollIntoViewIfNeeded, R as ARROW_DOWN, Rn as useAnimationsFinished, Rr as SafeReact, Rt as FloatingNode, St as useHoverReferenceInteraction, Tr as clsx, Tt as useSyncedFloatingRootContext, U as COMPOSITE_KEYS, Un as useValueChanged, Ut as FloatingTreeStore, V as ARROW_RIGHT, Vr as useRefWithInit, Vt as useFloatingParentNodeId, Wn as createChangeEventDetails, Wt as FloatingPortal, X as VERTICAL_KEYS_WITH_EXTRA_KEYS, Xn as focusOut, Xt as ReactStore, Y as VERTICAL_KEYS, Z as isNativeInput, Zn as imperativeAction, _n as getMaxListIndex, _r as fieldValidityMapping, _t as safePolygon, an as useOnFirstRender, ar as siblingOpen, at as useAnchorPositioning, bn as isListIndexDisabled, br as useControlled, bt as useListNavigation, cn as getNextTabbable, ct as CompositeList, dn as isOutsideEvent, dr as useFormContext, en as fastComponentRef, et as useAnchoredPopupScrollLock, fn as createGridCellMap, fr as useRegisterFieldControl, ft as popupStateMapping, gn as getGridNavigatedIndex, hn as getGridCellIndices, hr as useId$1, ht as useOpenInteractionType, it as InternalBackdrop, jr as useMergedRefs, jt as useOpenStateTransitions, kr as NOOP, kt as PopupTriggerMap, ln as getTabbableAfterElement, lt as inertValue, mn as getGridCellIndexOfCorner, mr as useBaseUiId, mt as triggerOpenStateMapping, nt as usePositioner, on as Timeout, ot as adaptiveOrigin, pn as findNonDisabledListIndex, pr as useFieldRootContext, pt as pressableTriggerOpenStateMapping, q as MODIFIER_KEYS, qt as POPUP_COLLISION_AVOIDANCE, rn as createSelector, rr as none, rt as getDisabledMountTransitionStyles, sn as useTimeout, sr as triggerHover, st as useDirection, tr as itemPress, un as getTabbableBeforeElement, ur as useLabelableContext, ut as getPseudoElementBounds, vn as getMinListIndex, vr as visuallyHidden, vt as useTypeahead, wt as useFocus, xr as Button, xt as useInteractions, yn as isIndexOutOfListBounds, yr as visuallyHiddenInput, yt as useRole, z as ARROW_KEYS, zt as FloatingTree } from "./tooltip-BZ6tpqnr.js";
3
4
  import * as React from "react";
4
- import reactExports, { createContext, forwardRef, memo, useCallback, useContext, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
5
+ import reactExports, { createContext, forwardRef, memo, useCallback, useContext, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState } from "react";
5
6
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
7
  import * as ReactDOM from "react-dom";
7
8
  import { flushSync } from "react-dom";
@@ -9,6 +10,299 @@ import { flushSync } from "react-dom";
9
10
  /** Resource selection only; visual styling remains owned by theme.css. */
10
11
  var IconThemeContext = createContext("light");
11
12
  //#endregion
13
+ //#region src/connector/common/providerIconCache.ts
14
+ var defaultMaxAgeMs = 864e5;
15
+ var dataUrl = (entry) => `data:${entry.contentType};base64,${entry.body}`;
16
+ function decodeRecord(value) {
17
+ if (value == null || typeof value !== "object") return;
18
+ const v = value;
19
+ if (v.formatVersion !== 1 || typeof v.sourceUrl !== "string" || !(v.spriteVersion === null || typeof v.spriteVersion === "string") || typeof v.contentType !== "string" || !/^image\/[\w.+-]+$/i.test(v.contentType) || typeof v.body !== "string" || !v.body || v.body.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(v.body) || !(v.etag === null || typeof v.etag === "string") || !Number.isFinite(v.validatedAt) || v.validatedAt < 0 || !(v.maxAgeMs === null || Number.isFinite(v.maxAgeMs) && v.maxAgeMs >= 0)) return;
20
+ return v;
21
+ }
22
+ function encodeBytes(bytes) {
23
+ let text = "";
24
+ for (let index = 0; index < bytes.length; index += 8192) text += String.fromCharCode(...bytes.subarray(index, index + 8192));
25
+ return btoa(text);
26
+ }
27
+ function freshness(response, immutable, previous) {
28
+ const control = response.headers.get("cache-control") ?? "";
29
+ if (/\bno-cache\b/i.test(control)) return 0;
30
+ if (immutable) return null;
31
+ const maxAge = /(?:^|,)\s*max-age\s*=\s*"?(\d+)/i.exec(control);
32
+ if (maxAge) return Math.max(0, Number(maxAge[1]) * 1e3 - (Number(response.headers.get("age")) || 0) * 1e3);
33
+ const expires = Date.parse(response.headers.get("expires") ?? "");
34
+ if (Number.isFinite(expires)) return Math.max(0, expires - Date.parse(response.headers.get("date") ?? (/* @__PURE__ */ new Date()).toUTCString()));
35
+ return previous?.maxAgeMs ?? defaultMaxAgeMs;
36
+ }
37
+ /** Complete image responses in bounded, identity-checked slots; no catalog entities live here. */
38
+ var ProviderIconCache = class {
39
+ #memory = /* @__PURE__ */ new Map();
40
+ #pending = /* @__PURE__ */ new Map();
41
+ #targets = /* @__PURE__ */ new Map();
42
+ #writes = /* @__PURE__ */ new Map();
43
+ constructor(options) {
44
+ this.options = options;
45
+ if (!options.scope.trim()) throw new TypeError("Provider icon cache scope must be nonempty.");
46
+ }
47
+ get(request, options = {}) {
48
+ if (request.url.startsWith("data:image/")) return Promise.resolve(request.url);
49
+ let protocol;
50
+ try {
51
+ protocol = new URL(request.url).protocol;
52
+ } catch (error) {
53
+ return Promise.reject(error);
54
+ }
55
+ if (!["http:", "https:"].includes(protocol)) return Promise.reject(/* @__PURE__ */ new TypeError("Unsupported Provider icon URL."));
56
+ const slot = JSON.stringify([
57
+ "open-flow:provider-icons",
58
+ 1,
59
+ this.options.scope,
60
+ request.kind,
61
+ request.kind === "sprite" ? request.theme : request.providerId
62
+ ]);
63
+ const version = request.kind === "sprite" ? request.version : null;
64
+ const identity = JSON.stringify([request.url, version]);
65
+ const offline = options.allowNetwork === false || this.options.mode === "offline";
66
+ const key = JSON.stringify([
67
+ slot,
68
+ identity,
69
+ offline
70
+ ]);
71
+ const pending = this.#pending.get(key);
72
+ if (pending) return pending;
73
+ if (!offline) this.#targets.set(slot, identity);
74
+ const promise = this.#load(slot, identity, request.url, version, offline).finally(() => this.#pending.delete(key));
75
+ this.#pending.set(key, promise);
76
+ return promise;
77
+ }
78
+ async #read(slot, url, version) {
79
+ const memory = this.#memory.get(slot);
80
+ if (this.#memory.has(slot) && (!memory || memory.sourceUrl === url && memory.spriteVersion === version)) return memory;
81
+ if (!this.options.delegate) return this.#memory.get(slot);
82
+ try {
83
+ const stored = await this.options.delegate.get(slot);
84
+ if (stored === void 0) return this.#memory.get(slot);
85
+ const entry = decodeRecord(stored);
86
+ if (entry) {
87
+ this.#memory.set(slot, entry);
88
+ return entry;
89
+ }
90
+ this.#memory.delete(slot);
91
+ await this.options.delegate.delete(slot);
92
+ } catch {
93
+ return this.#memory.get(slot);
94
+ }
95
+ }
96
+ async #store(slot, identity, entry) {
97
+ const operation = (this.#writes.get(slot) ?? Promise.resolve()).then(async () => {
98
+ if (this.#targets.get(slot) !== identity) return;
99
+ this.#memory.set(slot, entry);
100
+ if (!this.options.delegate) return;
101
+ try {
102
+ if (entry) await this.options.delegate.set(slot, { ...entry });
103
+ else await this.options.delegate.delete(slot);
104
+ } catch {}
105
+ });
106
+ this.#writes.set(slot, operation);
107
+ try {
108
+ await operation;
109
+ } finally {
110
+ if (this.#writes.get(slot) === operation) this.#writes.delete(slot);
111
+ }
112
+ }
113
+ async #load(slot, identity, url, version, offline) {
114
+ const stored = await this.#read(slot, url, version);
115
+ const cached = stored?.sourceUrl === url && stored.spriteVersion === version ? stored : void 0;
116
+ const age = cached == null ? Infinity : Date.now() - cached.validatedAt;
117
+ if (cached && (offline || this.options.mode !== "refresh" && age >= 0 && (cached.maxAgeMs === null || age < cached.maxAgeMs))) return dataUrl(cached);
118
+ if (offline) throw new Error(`Provider icon is not cached: ${url}`);
119
+ const response = await (this.options.fetch ?? globalThis.fetch)(url, {
120
+ credentials: "omit",
121
+ referrerPolicy: "no-referrer",
122
+ signal: AbortSignal.timeout(15e3),
123
+ headers: cached?.etag ? { "if-none-match": cached.etag } : {}
124
+ });
125
+ if (response.status !== 304 && !response.ok) throw new Error(`Could not load Provider icon: ${response.status}`);
126
+ if (response.status === 304 && !cached) throw new Error("Provider icon returned 304 without a cached image.");
127
+ const contentType = response.status === 304 ? cached.contentType : response.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
128
+ if (!contentType || !/^image\/[\w.+-]+$/i.test(contentType)) throw new Error("Provider icon response is not an image.");
129
+ const body = response.status === 304 ? cached.body : encodeBytes(new Uint8Array(await response.arrayBuffer()));
130
+ if (!body) throw new Error("Provider icon response is empty.");
131
+ const entry = {
132
+ formatVersion: 1,
133
+ sourceUrl: url,
134
+ spriteVersion: version,
135
+ contentType,
136
+ body,
137
+ etag: response.headers.get("etag") ?? (response.status === 304 ? cached.etag : null),
138
+ validatedAt: Date.now(),
139
+ maxAgeMs: freshness(response, version !== null, response.status === 304 ? cached : void 0)
140
+ };
141
+ await this.#store(slot, identity, /\bno-store\b/i.test(response.headers.get("cache-control") ?? "") ? void 0 : entry);
142
+ return dataUrl(entry);
143
+ }
144
+ };
145
+ //#endregion
146
+ //#region src/ui/browser/icons/providerIconResource.ts
147
+ var ProviderIconCacheContext = createContext(void 0);
148
+ /** IDB holds the same opaque JSON records as a host's disk delegate. */
149
+ function indexedDbIconDelegate() {
150
+ let database;
151
+ function open() {
152
+ database ??= new Promise((resolve, reject) => {
153
+ const request = indexedDB.open("open-flow-provider-icons", 1);
154
+ request.addEventListener("upgradeneeded", () => request.result.createObjectStore("icons"), { once: true });
155
+ request.addEventListener("error", () => reject(request.error), { once: true });
156
+ request.addEventListener("blocked", () => reject(/* @__PURE__ */ new Error("Provider icon cache is blocked.")), { once: true });
157
+ request.addEventListener("success", () => {
158
+ const db = request.result;
159
+ db.addEventListener("versionchange", () => {
160
+ db.close();
161
+ database = void 0;
162
+ }, { once: true });
163
+ resolve(db);
164
+ }, { once: true });
165
+ }).catch((error) => {
166
+ database = void 0;
167
+ throw error;
168
+ });
169
+ return database;
170
+ }
171
+ async function transaction(mode, operation) {
172
+ const db = await open();
173
+ return new Promise((resolve, reject) => {
174
+ const tx = db.transaction("icons", mode);
175
+ const request = operation(tx.objectStore("icons"));
176
+ tx.addEventListener("complete", () => resolve(request.result), { once: true });
177
+ tx.addEventListener("abort", () => reject(tx.error ?? request.error), { once: true });
178
+ tx.addEventListener("error", () => reject(tx.error ?? request.error), { once: true });
179
+ });
180
+ }
181
+ return {
182
+ get: (key) => transaction("readonly", (store) => store.get(key)),
183
+ set: async (key, value) => {
184
+ await transaction("readwrite", (store) => store.put(value, key));
185
+ },
186
+ delete: async (key) => {
187
+ await transaction("readwrite", (store) => store.delete(key));
188
+ }
189
+ };
190
+ }
191
+ var browserCache;
192
+ function defaultBrowserIconCache() {
193
+ return browserCache ??= new ProviderIconCache({
194
+ scope: "browser",
195
+ delegate: indexedDbIconDelegate()
196
+ });
197
+ }
198
+ function useProviderIconCache() {
199
+ return useContext(ProviderIconCacheContext) ?? defaultBrowserIconCache();
200
+ }
201
+ var loading = { status: "loading" };
202
+ function createIconResource(cache, request, ready) {
203
+ const state = val(ready ?? loading);
204
+ let pending;
205
+ return {
206
+ state,
207
+ refresh() {
208
+ if (pending) return pending;
209
+ const previous = state.value.status === "loaded" ? state.value : void 0;
210
+ if (previous) state.set({
211
+ ...previous,
212
+ refreshing: true
213
+ });
214
+ else if (state.value.status === "failed") state.set(loading);
215
+ pending = (async () => {
216
+ let image;
217
+ try {
218
+ const url = await cache.get(request);
219
+ if (previous?.url === url) {
220
+ state.set({
221
+ ...previous,
222
+ refreshing: false
223
+ });
224
+ return;
225
+ }
226
+ image = new Image();
227
+ image.src = url;
228
+ await image.decode();
229
+ state.set({
230
+ status: "loaded",
231
+ url,
232
+ image
233
+ });
234
+ } catch {
235
+ if (image) image.src = "";
236
+ state.set(previous ? {
237
+ ...previous,
238
+ refreshing: false
239
+ } : { status: "failed" });
240
+ }
241
+ })().finally(() => {
242
+ pending = void 0;
243
+ });
244
+ return pending;
245
+ }
246
+ };
247
+ }
248
+ var resources = /* @__PURE__ */ new WeakMap();
249
+ /** Components read ready state synchronously; only the shared owner fetches and decodes. */
250
+ function useProviderIconResource(request, crop) {
251
+ const cache = useProviderIconCache();
252
+ const slot = JSON.stringify([request.kind, request.kind === "sprite" ? request.theme : request.providerId]);
253
+ const identity = JSON.stringify([
254
+ slot,
255
+ request.url,
256
+ request.kind === "sprite" ? request.version : null
257
+ ]);
258
+ const previous = useRef();
259
+ const resource = useMemo(() => {
260
+ let slots = resources.get(cache);
261
+ if (!slots) {
262
+ slots = /* @__PURE__ */ new Map();
263
+ resources.set(cache, slots);
264
+ }
265
+ let current = slots.get(slot);
266
+ if (current?.identity !== identity) {
267
+ const value = previous.current?.identity === identity ? previous.current.resource.state.value : void 0;
268
+ current = {
269
+ identity,
270
+ resource: createIconResource(cache, request, value?.status === "loaded" ? value : void 0)
271
+ };
272
+ slots.set(slot, current);
273
+ }
274
+ previous.current = current;
275
+ return current.resource;
276
+ }, [cache, identity]);
277
+ const state = useVal(resource.state);
278
+ useEffect(() => {
279
+ resource.refresh();
280
+ }, [resource]);
281
+ return useMemo(() => {
282
+ if (state.status !== "loaded" || !crop) return state;
283
+ const canvas = document.createElement("canvas");
284
+ try {
285
+ canvas.width = canvas.height = crop.size;
286
+ const context = canvas.getContext("2d");
287
+ if (!context) throw new Error("Could not crop the Provider icon.");
288
+ context.drawImage(state.image, crop.x, crop.y, crop.size, crop.size, 0, 0, crop.size, crop.size);
289
+ return {
290
+ ...state,
291
+ url: canvas.toDataURL("image/png")
292
+ };
293
+ } catch {
294
+ return { status: "failed" };
295
+ } finally {
296
+ canvas.width = canvas.height = 0;
297
+ }
298
+ }, [
299
+ state,
300
+ crop?.x,
301
+ crop?.y,
302
+ crop?.size
303
+ ]);
304
+ }
305
+ //#endregion
12
306
  //#region ../../node_modules/.bun/@base-ui+react@1.4.1+fa6c2f29eeb10566/node_modules/@base-ui/react/esm/checkbox/root/CheckboxRootDataAttributes.js
13
307
  var CheckboxRootDataAttributes = /*#__PURE__*/ function(CheckboxRootDataAttributes) {
14
308
  /**
@@ -7632,9 +7926,10 @@ function DropdownMenuSeparator({ className, ...props }) {
7632
7926
  });
7633
7927
  }
7634
7928
  var ContentIcon_module_default = {
7635
- img: "ContentIcon_img_4e5d2",
7636
- initials: "ContentIcon_initials_4e5d2",
7637
- sprite: "ContentIcon_sprite_4e5d2"
7929
+ img: "ContentIcon_img_e2c99",
7930
+ pending: "ContentIcon_pending_e2c99",
7931
+ initials: "ContentIcon_initials_e2c99",
7932
+ sprite: "ContentIcon_sprite_e2c99"
7638
7933
  };
7639
7934
  var IconifyIcon_module_default = {
7640
7935
  icon: "IconifyIcon_icon_e957a",
@@ -7901,60 +8196,8 @@ function generateSvgDataUri(width, height, rawIcon, color) {
7901
8196
  return `data:image/svg+xml;utf8,${encodeSvgForCss(svg)}`;
7902
8197
  }
7903
8198
  //#endregion
7904
- //#region src/ui/browser/icons/spriteResource.ts
7905
- function createResource(url) {
7906
- let status = "loading";
7907
- let started = false;
7908
- const listeners = /* @__PURE__ */ new Set();
7909
- return {
7910
- getSnapshot: () => status,
7911
- subscribe(listener) {
7912
- listeners.add(listener);
7913
- if (!started) {
7914
- started = true;
7915
- const finish = (next) => {
7916
- status = next;
7917
- for (const notify of listeners) notify();
7918
- };
7919
- if (typeof Image == "undefined") finish("failed");
7920
- else {
7921
- const image = new Image();
7922
- const settle = (next) => {
7923
- image.removeEventListener("load", loaded);
7924
- image.removeEventListener("error", failed);
7925
- finish(next);
7926
- };
7927
- const loaded = () => settle("loaded");
7928
- const failed = () => settle("failed");
7929
- image.addEventListener("load", loaded, { once: true });
7930
- image.addEventListener("error", failed, { once: true });
7931
- image.referrerPolicy = "no-referrer";
7932
- image.src = url;
7933
- }
7934
- }
7935
- return () => {
7936
- listeners.delete(listener);
7937
- };
7938
- }
7939
- };
7940
- }
7941
- var resources = /* @__PURE__ */ new Map();
7942
- function spriteResource(url) {
7943
- let resource = resources.get(url);
7944
- if (!resource) {
7945
- resource = createResource(url);
7946
- resources.set(url, resource);
7947
- }
7948
- return resource;
7949
- }
7950
- var serverSnapshot = () => "loading";
7951
- function useSpriteStatus(url) {
7952
- const resource = spriteResource(url);
7953
- return useSyncExternalStore(resource.subscribe, resource.getSnapshot, serverSnapshot);
7954
- }
7955
- //#endregion
7956
8199
  //#region src/ui/browser/icons/ContentIcon.tsx
7957
- /** Standalone image capture uses individual, cross-origin-readable images instead of sprites. */
8200
+ /** Standalone image capture crops sprites and uses cross-origin-readable images. */
7958
8201
  var IconImageCrossOriginContext = createContext(void 0);
7959
8202
  /** A bundled, theme-aware placeholder that does not load a remote icon. */
7960
8203
  var placeholderIcon = "data:application/vnd.open-flow.placeholder-icon,";
@@ -7966,18 +8209,19 @@ var ContentIcon = ({ src, className, fallback = null, loading = "lazy", decoding
7966
8209
  const result = useMemo(() => parseIconifyIcon(source), [source]);
7967
8210
  const [error, setError] = useState();
7968
8211
  const onError = () => setError(source);
7969
- if (sprite) return crossOrigin ? /* @__PURE__ */ jsx(ContentIcon, {
8212
+ if (sprite) return /* @__PURE__ */ jsx(SpriteIcon, {
7970
8213
  className,
7971
8214
  fallback,
7972
8215
  loading,
7973
8216
  decoding,
7974
- src: sprite.fallback
7975
- }) : /* @__PURE__ */ jsx(SpriteIcon, {
8217
+ sprite
8218
+ });
8219
+ if (image?.providerId) return /* @__PURE__ */ jsx(ProviderImage, {
7976
8220
  className,
7977
8221
  fallback,
7978
8222
  loading,
7979
8223
  decoding,
7980
- sprite
8224
+ image
7981
8225
  });
7982
8226
  if (source === "data:application/vnd.open-flow.placeholder-icon,") return /* @__PURE__ */ jsx("i", {
7983
8227
  "aria-hidden": "true",
@@ -8020,10 +8264,11 @@ var ContentIcon = ({ src, className, fallback = null, loading = "lazy", decoding
8020
8264
  };
8021
8265
  var initialsIconPrefix = "data:application/vnd.open-flow.initials,";
8022
8266
  var imageIconPrefix = "data:application/vnd.open-flow.image-icon+json,";
8023
- function imageIcon(source, fallback) {
8267
+ function imageIcon(source, fallback, providerId) {
8024
8268
  return `${imageIconPrefix}${encodeURIComponent(JSON.stringify({
8025
8269
  fallback,
8026
- source
8270
+ source,
8271
+ ...providerId == null ? {} : { providerId }
8027
8272
  }))}`;
8028
8273
  }
8029
8274
  function parseImageIcon(src) {
@@ -8032,7 +8277,8 @@ function parseImageIcon(src) {
8032
8277
  const value = JSON.parse(decodeURIComponent(src.slice(47)));
8033
8278
  if (typeof value.fallback == "string" && typeof value.source == "string") return {
8034
8279
  fallback: value.fallback,
8035
- source: value.source
8280
+ source: value.source,
8281
+ ...typeof value.providerId === "string" ? { providerId: value.providerId } : {}
8036
8282
  };
8037
8283
  } catch {
8038
8284
  return;
@@ -8072,19 +8318,39 @@ function parseSpriteIcon(src) {
8072
8318
  }
8073
8319
  function SpriteIcon({ sprite, ...props }) {
8074
8320
  const theme = useContext(IconThemeContext);
8321
+ const capture = useContext(IconImageCrossOriginContext) != null;
8075
8322
  const { iconSprite: m, iconSpritePosition: p } = sprite;
8076
- const url = theme == "dark" ? m.darkUrl : m.lightUrl;
8077
- const status = useSpriteStatus(url);
8078
- if (status == "failed") return /* @__PURE__ */ jsx(ContentIcon, {
8323
+ const resource = useProviderIconResource({
8324
+ kind: "sprite",
8325
+ theme,
8326
+ url: theme == "dark" ? m.darkUrl : m.lightUrl,
8327
+ version: m.version
8328
+ }, capture ? {
8329
+ x: p.x,
8330
+ y: p.y,
8331
+ size: m.iconSize
8332
+ } : void 0);
8333
+ if (resource.status == "failed") return /* @__PURE__ */ jsx(ContentIcon, {
8079
8334
  ...props,
8080
8335
  src: sprite.fallback
8081
8336
  });
8337
+ if (resource.status === "loading") return /* @__PURE__ */ jsx(PendingIcon, {
8338
+ className: props.className,
8339
+ fallback: props.fallback
8340
+ });
8341
+ if (capture) return /* @__PURE__ */ jsx("img", {
8342
+ alt: "",
8343
+ className: clsx(ContentIcon_module_default.img, props.className),
8344
+ "data-render-pending": resource.refreshing || void 0,
8345
+ src: resource.url,
8346
+ decoding: "sync"
8347
+ });
8082
8348
  return /* @__PURE__ */ jsx("span", {
8083
8349
  "aria-hidden": "true",
8084
- "data-render-pending": status == "loading" || void 0,
8350
+ "data-render-pending": resource.refreshing || void 0,
8085
8351
  className: clsx(ContentIcon_module_default.sprite, props.className),
8086
- children: status == "loaded" && /* @__PURE__ */ jsx("span", { style: {
8087
- backgroundImage: `url(${JSON.stringify(url)})`,
8352
+ children: /* @__PURE__ */ jsx("span", { style: {
8353
+ backgroundImage: `url(${JSON.stringify(resource.url)})`,
8088
8354
  width: `${m.width / m.iconSize * 100}%`,
8089
8355
  height: `${m.height / m.iconSize * 100}%`,
8090
8356
  left: `${-p.x / m.iconSize * 100}%`,
@@ -8092,6 +8358,40 @@ function SpriteIcon({ sprite, ...props }) {
8092
8358
  } })
8093
8359
  });
8094
8360
  }
8361
+ function ProviderImage({ image, ...props }) {
8362
+ const resource = useProviderIconResource({
8363
+ kind: "image",
8364
+ providerId: image.providerId,
8365
+ url: image.source
8366
+ });
8367
+ if (resource.status === "failed") return /* @__PURE__ */ jsx(ContentIcon, {
8368
+ ...props,
8369
+ src: image.fallback
8370
+ });
8371
+ if (resource.status === "loading") return /* @__PURE__ */ jsx(PendingIcon, {
8372
+ className: props.className,
8373
+ fallback: props.fallback
8374
+ });
8375
+ return /* @__PURE__ */ jsx("img", {
8376
+ alt: "",
8377
+ className: clsx(ContentIcon_module_default.img, props.className),
8378
+ "data-render-pending": resource.refreshing || void 0,
8379
+ src: resource.url,
8380
+ loading: props.loading,
8381
+ decoding: props.decoding
8382
+ });
8383
+ }
8384
+ function PendingIcon({ className, fallback }) {
8385
+ return /* @__PURE__ */ jsx("span", {
8386
+ "aria-hidden": "true",
8387
+ className: clsx(ContentIcon_module_default.pending, className),
8388
+ "data-render-pending": true,
8389
+ children: fallback ?? /* @__PURE__ */ jsx(ContentIcon, {
8390
+ src: "data:application/vnd.open-flow.placeholder-icon,",
8391
+ className
8392
+ })
8393
+ });
8394
+ }
8095
8395
  //#endregion
8096
8396
  //#region ../../node_modules/.bun/@base-ui+react@1.4.1+fa6c2f29eeb10566/node_modules/@base-ui/react/esm/popover/root/PopoverRootContext.js
8097
8397
  var PopoverRootContext = /*#__PURE__*/ React.createContext(void 0);
@@ -12219,4 +12519,4 @@ function wrapLayout(nodes, availableWidth) {
12219
12519
  return positions;
12220
12520
  }
12221
12521
  //#endregion
12222
- export { waitBranchDescription as $, DropdownMenuItem as A, CompositeItem as B, IconifyProvider as C, DropdownMenuCheckboxItem as D, DropdownMenu as E, DropdownMenuSub as F, MenuPopup as G, MenuRoot as H, DropdownMenuSubContent as I, ContextMenuRootContext as J, MenuItem as K, DropdownMenuSubTrigger as L, DropdownMenuRadioGroup as M, DropdownMenuRadioItem as N, DropdownMenuContent as O, DropdownMenuSeparator as P, uiLocales as Q, DropdownMenuTrigger as R, spriteIcon as S, useIconifyData as T, MenuPositioner as U, useCompositeItem as V, MenuPortal as W, MenuRootContext as X, useContextMenuRootContext as Y, useMenuRootContext as Z, Z as _, CompositeRoot as a, ja_default$1 as at, imageIcon as b, PopoverContent as c, I18n as ct, PopoverPanelContent as d, useAriaLabelledBy as dt, waitBranchLocales as et, PopoverTitle as f, useFieldItemContext as ft, VirtualScrollArea as g, ScrollArea as h, Textarea as i, ko_default$1 as it, DropdownMenuLabel as j, DropdownMenuGroup as k, PopoverDescription as l, providerIconAppearance as lt, NativeScrollArea as m, wrapLayout as n, zh_CN_default$1 as nt, ACTIVE_COMPOSITE_ITEM as o, fr_default$1 as ot, PopoverTrigger as p, IconThemeContext as pt, MenuGroup as q, canvasDirection as r, ru_default$1 as rt, Popover as s, en_default$1 as st, layoutAxes as t, zh_TW_default$1 as tt, PopoverHeader as u, Checkbox as ut, ContentIcon as v, useIconifyCollectionLoader as w, placeholderIcon as x, IconImageCrossOriginContext as y, findRootOwnerId as z };
12522
+ export { waitBranchDescription as $, DropdownMenuItem as A, CompositeItem as B, IconifyProvider as C, DropdownMenuCheckboxItem as D, DropdownMenu as E, DropdownMenuSub as F, MenuPopup as G, MenuRoot as H, DropdownMenuSubContent as I, ContextMenuRootContext as J, MenuItem as K, DropdownMenuSubTrigger as L, DropdownMenuRadioGroup as M, DropdownMenuRadioItem as N, DropdownMenuContent as O, DropdownMenuSeparator as P, uiLocales as Q, DropdownMenuTrigger as R, spriteIcon as S, useIconifyData as T, MenuPositioner as U, useCompositeItem as V, MenuPortal as W, MenuRootContext as X, useContextMenuRootContext as Y, useMenuRootContext as Z, Z as _, CompositeRoot as a, ja_default$1 as at, imageIcon as b, PopoverContent as c, I18n as ct, PopoverPanelContent as d, useAriaLabelledBy as dt, waitBranchLocales as et, PopoverTitle as f, useFieldItemContext as ft, VirtualScrollArea as g, ScrollArea as h, IconThemeContext as ht, Textarea as i, ko_default$1 as it, DropdownMenuLabel as j, DropdownMenuGroup as k, PopoverDescription as l, providerIconAppearance as lt, NativeScrollArea as m, useProviderIconCache as mt, wrapLayout as n, zh_CN_default$1 as nt, ACTIVE_COMPOSITE_ITEM as o, fr_default$1 as ot, PopoverTrigger as p, ProviderIconCacheContext as pt, MenuGroup as q, canvasDirection as r, ru_default$1 as rt, Popover as s, en_default$1 as st, layoutAxes as t, zh_TW_default$1 as tt, PopoverHeader as u, Checkbox as ut, ContentIcon as v, useIconifyCollectionLoader as w, placeholderIcon as x, IconImageCrossOriginContext as y, findRootOwnerId as z };