@burdenoff/fluidgrids-fe-sdk 2026.1111.13 → 2026.1111.15

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 (43) hide show
  1. package/README.md +41 -0
  2. package/dist/{ExecutionDetailPage-CDkJeeu2.js → ExecutionDetailPage-DO38vZ_F.js} +4 -4
  3. package/dist/{FluidGridsProvider-CDZjKmfD.js → FluidGridsProvider-B9RR_CI_.js} +237 -325
  4. package/dist/{HistoryPage-DnVGN_72.js → HistoryPage-CA42pU85.js} +1 -1
  5. package/dist/{InsightsPage-CGRpZtGu.js → InsightsPage-CBoN_Mj9.js} +2 -2
  6. package/dist/{ManagedAiPolicyAuthority-DbJBledZ.js → ManagedAiPolicyAuthority-CKihmbJE.js} +2 -2
  7. package/dist/{MissingNodesInstallModal-Ca4f--lw.js → MissingNodesInstallModal-Dm0nMBXM.js} +1 -1
  8. package/dist/{TemplateConfigurationModal-ChQsXf0-.js → TemplateConfigurationModal-Bs_V-E4u.js} +1 -1
  9. package/dist/{TemplateDetailPanel-C0YiVdub.js → TemplateDetailPanel-MlT39VLG.js} +1 -1
  10. package/dist/{TemplatesPage-QXtq6mI3.js → TemplatesPage-CHVpWBuw.js} +5 -4
  11. package/dist/{WorkflowSearchRedirect-B4nHALJg.js → WorkflowSearchRedirect-3gyHcYY2.js} +38 -51
  12. package/dist/{WorkflowShareDialog-ByTSWwwR.js → WorkflowShareDialog-0Ai1HED-.js} +2 -1
  13. package/dist/{WorkflowsList-B9F2e8M6.js → WorkflowsList-CJ3KmMHX.js} +5 -4
  14. package/dist/agent-tools.d.ts +3 -0
  15. package/dist/agent-tools.js +5 -0
  16. package/dist/{agentTools-C0g2OWvI.js → agentTools-B1IK1JEO.js} +2 -2
  17. package/dist/{canvasNoteTools-BUWY18XK.js → canvasNoteTools-eewVHVuy.js} +3 -2
  18. package/dist/executions.js +1 -1
  19. package/dist/{flow-builder-BvCQAGDR.js → flow-builder-C_3sY3pZ.js} +54 -209
  20. package/dist/fluidgridsEvents-CNdcrUNN.js +310 -0
  21. package/dist/history.js +1 -1
  22. package/dist/index-CHeY7_A1.d.ts +105 -0
  23. package/dist/{index-CLqh2u28.d.ts → index-DRf25-D3.d.ts} +7 -105
  24. package/dist/index.d.ts +3 -2
  25. package/dist/index.js +21 -946
  26. package/dist/marksStore-DGCXjTmZ.js +151 -0
  27. package/dist/{node-detail-view-CPD_NSZc.js → node-detail-view-CAws5qjg.js} +3 -3
  28. package/dist/observability.d.ts +1 -1
  29. package/dist/observability.js +1 -1
  30. package/dist/{quick-config-panel-DHkYGaCL.js → quick-config-panel-DOzNkSVV.js} +2 -2
  31. package/dist/settings.js +1 -1
  32. package/dist/templates.js +1 -1
  33. package/dist/uiMarkTools-nlmzsHQM.js +937 -0
  34. package/dist/{useExecutions-BqoD7XWi.js → useExecutions-DkS0FTfw.js} +2 -1
  35. package/dist/{useObservability-Cs-5_NHh.js → useObservability-BkxhHZsX.js} +2 -1
  36. package/dist/{useRunHistory-CEL-CIz-.js → useRunHistory-DHehG09Z.js} +1 -1
  37. package/dist/{useWorkflows-Bwpvfdgv.js → useWorkflows-DyhtoVwp.js} +25 -5
  38. package/dist/workflow-builder.js +2 -2
  39. package/dist/workflow-route.d.ts +33 -0
  40. package/dist/workflow-route.js +4 -0
  41. package/dist/workflowRouteData-BkfVOc-O.js +169 -0
  42. package/dist/workflows-list.js +1 -1
  43. package/package.json +9 -1
@@ -2,6 +2,7 @@
2
2
  import { At as NodeManifestsDocument, Bi as describeOperationError, Di as createFluidGridsClient, Dr as WorkflowDefinitionDocument, En as SaveWorkflowDraftDocument, Jn as TriggerWorkflowDocument, Jr as WorkflowRunDocument, Li as emitFluidGridsEvent, Mi as setFluidGridsClient, Ni as waitForFluidGridsClient, Oi as getFluidGridsClient, Pi as createFluidGridsTokenRefreshLink, Qi as validateTrustedOrigin, R as CreateWorkflowVersionDocument, Ri as emitOperationErrorEvent, Ui as throwIfResultError, Wi as createLiveTokenReader, Xi as resetFluidGridsExecutionState, Yi as resetFluidGridsConfig, Zi as setFluidGridsConfig, at as EventRegistrationsDocument, j as CreateWorkflowDefinitionDocument, ji as resetFluidGridsClient, jt as NodePaletteEntriesDocument, ki as getFluidGridsClientSafe, oa as __exportAll, ot as ExecuteStepDocument, qi as getFluidGridsConfig, st as ExecutionDetailDocument, t as fetchAllNodeEndpointConfigs, vn as RunFromNodeDocument, zi as emitRunCompletedOnce } from "./node-endpoint-configs-DHFGA5MQ.js";
3
3
  import { A as nodeAccent, C as nodeAdaptersOf, D as NodeCard, E as resolveOutputHandles, H as useFlowStore, I as partitionStickyNotes, L as resolveStickyColor, N as DEFAULT_STICKY_COLOR, O as NodeCardBody, P as STICKY_COLORS, R as stickySurfaceStyle, T as resolveInputHandles, V as STICKY_NOTE_TYPE, W as isNodeTrigger, _ as LogicNodeCard, b as alignPlainOutputEdges, i as WAIT_FOR_SIGNAL_NODE_TYPE, j as NodeTypeIcon, k as NodeCardHeader, l as interfaceFields, m as readSignalName, n as synchronizeOperationUpdate, p as readCodeWorkflowState, r as CODE_WORKFLOW_NODE_TYPE, t as resolveOperationName, u as interfaceHandlers, v as InputHandles, w as outputHandlesSpacerHeight, x as hasNodeManifest, y as OutputHandles } from "./node-operation-selection--oy-yEq_.js";
4
4
  import { n as FluidGridsTranslationProvider, r as useTr, t as ENGLISH_FALLBACK_TRANSLATOR } from "./TranslationBridge-Da-TPgQm.js";
5
+ import { _ as errorCodesOf, g as collectExtensions, i as emitRunStarted, m as RUNS_QUOTA_NAME, n as emitRunFailed, p as QUOTA_EXHAUSTED_CODE, r as emitRunLimitHit, s as emitWorkflowCreated, v as findQuotaRefusal } from "./fluidgridsEvents-CNdcrUNN.js";
5
6
  import { createContext, memo, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
6
7
  import { useNavigate, useParams } from "react-router";
7
8
  import { ApolloProvider } from "@apollo/client/react";
@@ -1379,314 +1380,6 @@ function NodeInfoButtonWithModal({ metadata }) {
1379
1380
  })] });
1380
1381
  }
1381
1382
 
1382
- // src/billing/quota.ts
1383
- /**
1384
- * Plan-quota refusals for the FluidGrids SDK.
1385
- *
1386
- * wspace-workflow-svc meters two quotas with `@usage`, and the gateway refuses
1387
- * a call past either one with `429 QUOTA_EXHAUSTED`:
1388
- *
1389
- * - `fluidgrids.runs.monthly` — every mutation that starts a run:
1390
- * `triggerWorkflow`, `runFromNode`, `replayWorkflowRun`, `retryWorkflowRuns`
1391
- * and `listenForWebhookTestEvent`.
1392
- * - `fluidgrids.workflows.count` — the mutations that create a workflow
1393
- * (save, duplicate, template import). Those keep their local
1394
- * `QuotaExhaustedDialog`.
1395
- * - `fluidgrids.nodes.count` — node additions are counted by workflow save;
1396
- * the same save dialog handles its refusal.
1397
- *
1398
- * A run refusal opens the shell's shared upgrade prompt — see
1399
- * `openRunQuotaUpgradePrompt` in `./upgradePrompt`. This module is the pure
1400
- * detection half, so it imports nothing from `@burdenoff/fe-libs`.
1401
- *
1402
- * ★★ Why this does not just call fe-libs `isQuotaExhaustedError`. That helper
1403
- * reads the Apollo 3 shapes (`graphQLErrors`, `networkError.result.errors`, a
1404
- * code in the message). Under Apollo 4 — what every host runs — the refusal
1405
- * never takes those shapes:
1406
- *
1407
- * - the gateway answers `429`, and Apollo 4's HTTP link turns any non-2xx
1408
- * `application/json` response into a `ServerError` whose GraphQL body is
1409
- * only in `bodyText` (message: "Response not successful: Received status
1410
- * code 429");
1411
- * - a 2xx GraphQL error arrives as `CombinedGraphQLErrors`, whose list is
1412
- * `.errors`, not `.graphQLErrors`;
1413
- * - `throwIfResultError` wraps either one in a plain `Error`, keeping the
1414
- * original as `cause`.
1415
- *
1416
- * None of those match, so the refusal read as an ordinary failure. This walker
1417
- * reads all of them, and the Apollo 3 shapes too.
1418
- */
1419
- /** The monthly run allowance every run-starting mutation is metered against. */
1420
- const RUNS_QUOTA_NAME = "fluidgrids.runs.monthly";
1421
- /** The workflow-count allowance save / duplicate / template import consume. */
1422
- const WORKFLOWS_QUOTA_NAME = "fluidgrids.workflows.count";
1423
- /**
1424
- * Where an upgrade CTA sends the user: the plan picker, not the billing
1425
- * overview. Matches the shared `UpgradePromptModal` default and the shell nav.
1426
- */
1427
- const BILLING_PLANS_PATH = "/billing/plans";
1428
- const QUOTA_EXHAUSTED_CODE = "QUOTA_EXHAUSTED";
1429
- const QUOTA_NOT_PROVISIONED_CODE = "QUOTA_NOT_PROVISIONED";
1430
- function asRecord$3(value) {
1431
- return typeof value === "object" && value !== null ? value : null;
1432
- }
1433
- /** The `extensions` of each entry of an `errors`-like list. */
1434
- function extensionsOfList(list) {
1435
- if (!Array.isArray(list)) return [];
1436
- const found = [];
1437
- for (const entry of list) {
1438
- const extensions = asRecord$3(asRecord$3(entry)?.extensions);
1439
- if (extensions) found.push(extensions);
1440
- }
1441
- return found;
1442
- }
1443
- /** The GraphQL `errors[].extensions` inside a raw response body, if it is JSON. */
1444
- function extensionsOfBody(bodyText) {
1445
- if (typeof bodyText !== "string" || !bodyText.includes("errors")) return [];
1446
- try {
1447
- return extensionsOfList(asRecord$3(JSON.parse(bodyText))?.errors);
1448
- } catch {
1449
- return [];
1450
- }
1451
- }
1452
- /** Bounds the `cause` walk; real chains are one or two links long. */
1453
- const MAX_CAUSE_DEPTH = 5;
1454
- /**
1455
- * Every `extensions` object reachable on a thrown value, across the Apollo 3
1456
- * and Apollo 4 shapes and the `cause` chain `throwIfResultError` adds.
1457
- */
1458
- function collectExtensions(error) {
1459
- const found = [];
1460
- const seen = /* @__PURE__ */ new Set();
1461
- let current = error;
1462
- for (let depth = 0; depth < MAX_CAUSE_DEPTH; depth += 1) {
1463
- const host = asRecord$3(current);
1464
- if (!host || seen.has(host)) break;
1465
- seen.add(host);
1466
- const direct = asRecord$3(host.extensions);
1467
- if (direct) found.push(direct);
1468
- found.push(...extensionsOfList(host.errors));
1469
- found.push(...extensionsOfList(host.graphQLErrors));
1470
- const networkError = asRecord$3(host.networkError);
1471
- found.push(...extensionsOfList(asRecord$3(networkError?.result)?.errors));
1472
- found.push(...extensionsOfBody(networkError?.bodyText));
1473
- found.push(...extensionsOfList(asRecord$3(host.result)?.errors));
1474
- found.push(...extensionsOfBody(host.bodyText));
1475
- current = host.cause;
1476
- }
1477
- return found;
1478
- }
1479
- /** Every GraphQL `extensions.code` carried by `error` or its causes. */
1480
- function errorCodesOf(error) {
1481
- return collectExtensions(error).map((ext) => ext.code).filter((code) => typeof code === "string");
1482
- }
1483
- function stringField(extensions, key) {
1484
- const value = extensions[key];
1485
- return typeof value === "string" && value.length > 0 ? value : null;
1486
- }
1487
- /**
1488
- * The refusal kind one GraphQL `extensions` object reports, or null.
1489
- *
1490
- * The gateway sets both `code` and `quotaBlock` on a quota refusal
1491
- * (`sendQuotaExhausted` in wspace-public-gateway); either is enough here, so
1492
- * a refusal relayed with only one of them (a proxy, an older gateway build)
1493
- * still reads as one.
1494
- */
1495
- function refusalKindOf(extensions) {
1496
- if (extensions.code === "QUOTA_NOT_PROVISIONED" || extensions.quotaBlock === "not-provisioned") return "not-provisioned";
1497
- if (extensions.code === "QUOTA_EXHAUSTED" || extensions.quotaBlock === "exhausted") return "exhausted";
1498
- return null;
1499
- }
1500
- /**
1501
- * The quota refusal carried by `error`, or null when it is not one.
1502
- *
1503
- * Keyed on `extensions.code` (or the gateway's `extensions.quotaBlock`), never
1504
- * on the HTTP status or the message: both refusals are 429s, and only those
1505
- * fields tell "used up" from "never granted". `not-provisioned` wins when both
1506
- * appear.
1507
- */
1508
- function findQuotaRefusal(error) {
1509
- const all = collectExtensions(error);
1510
- const notProvisioned = all.find((ext) => refusalKindOf(ext) === "not-provisioned");
1511
- if (notProvisioned) return {
1512
- kind: "not-provisioned",
1513
- quotaName: stringField(notProvisioned, "quotaName"),
1514
- limitLeft: null
1515
- };
1516
- const exhausted = all.find((ext) => refusalKindOf(ext) === "exhausted");
1517
- if (exhausted) {
1518
- const limitLeft = exhausted.limitLeft;
1519
- return {
1520
- kind: "exhausted",
1521
- quotaName: stringField(exhausted, "quotaName"),
1522
- limitLeft: typeof limitLeft === "number" ? limitLeft : null
1523
- };
1524
- }
1525
- return null;
1526
- }
1527
- /** True when `error` is an exhausted (not merely unprovisioned) plan quota. */
1528
- function isQuotaExhaustedFailure(error) {
1529
- return findQuotaRefusal(error)?.kind === "exhausted";
1530
- }
1531
-
1532
- // src/analytics/fluidgridsEvents.ts
1533
- /** `component` stamped on every event so devtools/OTel can tell the emitter. */
1534
- const FLUIDGRIDS_ANALYTICS_COMPONENT = "fluidgrids-fe-sdk";
1535
- /** Upper bound for a slug-like dimension; anything longer is not a slug. */
1536
- const MAX_DIMENSION_LENGTH = 64;
1537
- const SLUG_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_./:-]*$/;
1538
- /**
1539
- * Keep a dimension only when it is a short slug (`integration/slack`,
1540
- * `trigger_webhook`, `marketing`). Anything else — spaces, free text, a very
1541
- * long value — is dropped rather than risk sending user data.
1542
- */
1543
- function toDimension(value) {
1544
- if (typeof value !== "string") return void 0;
1545
- const trimmed = value.trim();
1546
- if (!trimmed || trimmed.length > MAX_DIMENSION_LENGTH) return void 0;
1547
- return SLUG_PATTERN.test(trimmed) ? trimmed : void 0;
1548
- }
1549
- /** Non-empty string id, or undefined. */
1550
- function idOrUndefined(value) {
1551
- return typeof value === "string" && value.length > 0 ? value : void 0;
1552
- }
1553
- /** A finite, non-negative integer count, or undefined. */
1554
- function countOrUndefined(value) {
1555
- return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.round(value) : void 0;
1556
- }
1557
- function emit(bus, name, payload) {
1558
- if (!bus) return;
1559
- const clean = Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== void 0));
1560
- try {
1561
- bus.emit(name, clean, { component: FLUIDGRIDS_ANALYTICS_COMPONENT });
1562
- } catch (error) {
1563
- console.warn(`[fluidgrids analytics] failed to emit ${name}`, error);
1564
- }
1565
- }
1566
- function asRecord$2(value) {
1567
- return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
1568
- }
1569
- /**
1570
- * The executable node list of a workflow definition, wherever it sits: the
1571
- * flow store's `{ nodes }`, a saved `definitionJson` (`{ data: { nodes } }`) or
1572
- * a raw list.
1573
- */
1574
- function nodesOf(definition) {
1575
- if (Array.isArray(definition)) return definition;
1576
- const record = asRecord$2(definition);
1577
- if (!record) return [];
1578
- if (Array.isArray(record.nodes)) return record.nodes;
1579
- const data = asRecord$2(record.data);
1580
- if (data && Array.isArray(data.nodes)) return data.nodes;
1581
- return [];
1582
- }
1583
- function isTriggerNode(node) {
1584
- if ((typeof node.type === "string" ? node.type.toLowerCase() : "").includes("trigger")) return true;
1585
- const data = asRecord$2(node.data);
1586
- return data?.isTrigger === true || data?.category === "trigger";
1587
- }
1588
- /** Node-type slug of the workflow's trigger node, when it has one. */
1589
- function triggerTypeOf(definition) {
1590
- const trigger = nodesOf(definition).find(isTriggerNode);
1591
- return trigger ? toDimension(trigger.type) : void 0;
1592
- }
1593
- /** Number of executable nodes on the canvas. */
1594
- function nodeCountOf(definition) {
1595
- const nodes = nodesOf(definition);
1596
- return nodes.length > 0 ? nodes.length : void 0;
1597
- }
1598
- /** `fluidgrids.workflow.created` — a new workflow exists in the workspace. */
1599
- function emitWorkflowCreated(bus, fact) {
1600
- emit(bus, "fluidgrids.workflow.created", {
1601
- workspaceId: idOrUndefined(fact.workspaceId),
1602
- workflowId: idOrUndefined(fact.workflowId),
1603
- source: fact.source,
1604
- triggerType: triggerTypeOf(fact.definition),
1605
- nodeCount: nodeCountOf(fact.definition)
1606
- });
1607
- }
1608
- /** `fluidgrids.workflow.published` — a version was activated. */
1609
- function emitWorkflowPublished(bus, fact) {
1610
- emit(bus, "fluidgrids.workflow.published", {
1611
- workspaceId: idOrUndefined(fact.workspaceId),
1612
- workflowId: idOrUndefined(fact.workflowId),
1613
- triggerType: triggerTypeOf(fact.definition),
1614
- nodeCount: nodeCountOf(fact.definition)
1615
- });
1616
- }
1617
- /** `fluidgrids.workflow.run_started` — the backend accepted a run. */
1618
- function emitRunStarted(bus, fact) {
1619
- emit(bus, "fluidgrids.workflow.run_started", {
1620
- workspaceId: idOrUndefined(fact.workspaceId),
1621
- workflowId: idOrUndefined(fact.workflowId),
1622
- executionId: idOrUndefined(fact.executionId),
1623
- trigger: fact.trigger
1624
- });
1625
- }
1626
- /**
1627
- * `fluidgrids.workflow.run_failed` — a run this user started ended FAILED.
1628
- * `errorCode` is the run's machine error classification (`TIMEOUT`,
1629
- * `VALIDATION`, …), never its message.
1630
- */
1631
- function emitRunFailed(bus, fact) {
1632
- emit(bus, "fluidgrids.workflow.run_failed", {
1633
- workspaceId: idOrUndefined(fact.workspaceId),
1634
- workflowId: idOrUndefined(fact.workflowId),
1635
- executionId: idOrUndefined(fact.executionId),
1636
- trigger: fact.trigger,
1637
- errorCode: toDimension(fact.errorCode),
1638
- durationMs: countOrUndefined(fact.durationMs)
1639
- });
1640
- }
1641
- /** `fluidgrids.template.used` — a store template became a workflow. */
1642
- function emitTemplateUsed(bus, fact) {
1643
- emit(bus, "fluidgrids.template.used", {
1644
- workspaceId: idOrUndefined(fact.workspaceId),
1645
- templateId: idOrUndefined(fact.templateId),
1646
- category: toDimension(fact.category)
1647
- });
1648
- }
1649
- /** `fluidgrids.node.installed` — a store node was installed. */
1650
- function emitNodeInstalled(bus, fact) {
1651
- emit(bus, "fluidgrids.node.installed", {
1652
- workspaceId: idOrUndefined(fact.workspaceId),
1653
- nodeType: toDimension(fact.nodeType),
1654
- source: fact.source
1655
- });
1656
- }
1657
- /** `fluidgrids.quota.workflow_limit_hit` — a create was refused at the limit. */
1658
- function emitWorkflowLimitHit(bus, fact) {
1659
- emit(bus, "fluidgrids.quota.workflow_limit_hit", {
1660
- workspaceId: idOrUndefined(fact.workspaceId),
1661
- quotaKey: WORKFLOWS_QUOTA_NAME,
1662
- surface: fact.surface
1663
- });
1664
- }
1665
- /** `fluidgrids.quota.run_limit_hit` — a run was refused at the monthly limit. */
1666
- function emitRunLimitHit(bus, fact) {
1667
- emit(bus, "fluidgrids.quota.run_limit_hit", {
1668
- workspaceId: idOrUndefined(fact.workspaceId),
1669
- quotaKey: toDimension(fact.quotaKey) ?? "fluidgrids.runs.monthly",
1670
- surface: fact.surface
1671
- });
1672
- }
1673
- /** `fluidgrids.billing.upgrade_clicked` — a FluidGrids upgrade CTA was clicked. */
1674
- function emitUpgradeClicked(bus, fact) {
1675
- emit(bus, "fluidgrids.billing.upgrade_clicked", {
1676
- workspaceId: idOrUndefined(fact.workspaceId),
1677
- surface: fact.surface,
1678
- quotaKey: toDimension(fact.quotaKey)
1679
- });
1680
- }
1681
- /**
1682
- * Map a run's backend mode/trigger to the analytics trigger dimension. The
1683
- * builder's debug paths are always `TEST`; anything else a person started by
1684
- * hand is `manual`.
1685
- */
1686
- function runTriggerFromMode(mode) {
1687
- return typeof mode === "string" && mode.toUpperCase() === "TEST" ? "test" : "manual";
1688
- }
1689
-
1690
1383
  // src/billing/upgradePrompt.ts
1691
1384
  /**
1692
1385
  * The shared upgrade prompt for the monthly run allowance.
@@ -10145,6 +9838,181 @@ const OrganizationPrivateNodesDocument = {
10145
9838
  "end": 432
10146
9839
  }
10147
9840
  };
9841
+ const StoreNodeProductsByTypeDocument = {
9842
+ "kind": "Document",
9843
+ "definitions": [{
9844
+ "kind": "OperationDefinition",
9845
+ "operation": "query",
9846
+ "name": {
9847
+ "kind": "Name",
9848
+ "value": "StoreNodeProductsByType"
9849
+ },
9850
+ "variableDefinitions": [{
9851
+ "kind": "VariableDefinition",
9852
+ "variable": {
9853
+ "kind": "Variable",
9854
+ "name": {
9855
+ "kind": "Name",
9856
+ "value": "nodeTypes"
9857
+ }
9858
+ },
9859
+ "type": {
9860
+ "kind": "NonNullType",
9861
+ "type": {
9862
+ "kind": "ListType",
9863
+ "type": {
9864
+ "kind": "NonNullType",
9865
+ "type": {
9866
+ "kind": "NamedType",
9867
+ "name": {
9868
+ "kind": "Name",
9869
+ "value": "String"
9870
+ }
9871
+ }
9872
+ }
9873
+ }
9874
+ },
9875
+ "directives": []
9876
+ }, {
9877
+ "kind": "VariableDefinition",
9878
+ "variable": {
9879
+ "kind": "Variable",
9880
+ "name": {
9881
+ "kind": "Name",
9882
+ "value": "compatibleWith"
9883
+ }
9884
+ },
9885
+ "type": {
9886
+ "kind": "NamedType",
9887
+ "name": {
9888
+ "kind": "Name",
9889
+ "value": "String"
9890
+ }
9891
+ },
9892
+ "directives": []
9893
+ }],
9894
+ "directives": [],
9895
+ "selectionSet": {
9896
+ "kind": "SelectionSet",
9897
+ "selections": [{
9898
+ "kind": "Field",
9899
+ "name": {
9900
+ "kind": "Name",
9901
+ "value": "storeNodeProductsByType"
9902
+ },
9903
+ "arguments": [{
9904
+ "kind": "Argument",
9905
+ "name": {
9906
+ "kind": "Name",
9907
+ "value": "nodeTypes"
9908
+ },
9909
+ "value": {
9910
+ "kind": "Variable",
9911
+ "name": {
9912
+ "kind": "Name",
9913
+ "value": "nodeTypes"
9914
+ }
9915
+ }
9916
+ }, {
9917
+ "kind": "Argument",
9918
+ "name": {
9919
+ "kind": "Name",
9920
+ "value": "compatibleWith"
9921
+ },
9922
+ "value": {
9923
+ "kind": "Variable",
9924
+ "name": {
9925
+ "kind": "Name",
9926
+ "value": "compatibleWith"
9927
+ }
9928
+ }
9929
+ }],
9930
+ "directives": [],
9931
+ "selectionSet": {
9932
+ "kind": "SelectionSet",
9933
+ "selections": [
9934
+ {
9935
+ "kind": "Field",
9936
+ "name": {
9937
+ "kind": "Name",
9938
+ "value": "id"
9939
+ },
9940
+ "arguments": [],
9941
+ "directives": []
9942
+ },
9943
+ {
9944
+ "kind": "Field",
9945
+ "name": {
9946
+ "kind": "Name",
9947
+ "value": "productId"
9948
+ },
9949
+ "arguments": [],
9950
+ "directives": []
9951
+ },
9952
+ {
9953
+ "kind": "Field",
9954
+ "name": {
9955
+ "kind": "Name",
9956
+ "value": "name"
9957
+ },
9958
+ "arguments": [],
9959
+ "directives": []
9960
+ },
9961
+ {
9962
+ "kind": "Field",
9963
+ "name": {
9964
+ "kind": "Name",
9965
+ "value": "manifest"
9966
+ },
9967
+ "arguments": [],
9968
+ "directives": []
9969
+ },
9970
+ {
9971
+ "kind": "Field",
9972
+ "name": {
9973
+ "kind": "Name",
9974
+ "value": "manifestVersion"
9975
+ },
9976
+ "arguments": [],
9977
+ "directives": []
9978
+ },
9979
+ {
9980
+ "kind": "Field",
9981
+ "name": {
9982
+ "kind": "Name",
9983
+ "value": "pricingModel"
9984
+ },
9985
+ "arguments": [],
9986
+ "directives": []
9987
+ },
9988
+ {
9989
+ "kind": "Field",
9990
+ "name": {
9991
+ "kind": "Name",
9992
+ "value": "downloads"
9993
+ },
9994
+ "arguments": [],
9995
+ "directives": []
9996
+ },
9997
+ {
9998
+ "kind": "Field",
9999
+ "name": {
10000
+ "kind": "Name",
10001
+ "value": "publishedAt"
10002
+ },
10003
+ "arguments": [],
10004
+ "directives": []
10005
+ }
10006
+ ]
10007
+ }
10008
+ }]
10009
+ }
10010
+ }],
10011
+ "loc": {
10012
+ "start": 0,
10013
+ "end": 290
10014
+ }
10015
+ };
10148
10016
 
10149
10017
  // src/graphql/global-operations.ts
10150
10018
  var global_operations_exports = /* @__PURE__ */ __exportAll({ InstallWorkflowNodeDocument: () => InstallWorkflowNodeDocument });
@@ -10364,17 +10232,27 @@ async function initializeNodeConfigs() {
10364
10232
  function isRegistryNodeType(type) {
10365
10233
  return Boolean(type) && type !== "sticky-note" && type !== "default";
10366
10234
  }
10367
- /** Node types being loaded for a canvas, so concurrent callers share one request. */
10235
+ /**
10236
+ * Node types the registry is known not to carry: the manifests that came with a
10237
+ * workflow left them out (BOFF-11754). The registry is not asked about them again
10238
+ * until it is reloaded; the workspace's installed store nodes may still provide
10239
+ * them.
10240
+ */
10241
+ const registryLacks = /* @__PURE__ */ new Set();
10242
+ /** Registry loads in flight, by node type, so concurrent callers share one request. */
10368
10243
  const nodeTypeLoads = /* @__PURE__ */ new Map();
10369
- async function loadNodeTypes(types) {
10244
+ /** The distinct registry node types of `types` that are not registered yet. */
10245
+ function unregisteredTypes(types) {
10246
+ if (isInitialized) return [];
10247
+ return [...new Set(types)].filter((type) => isRegistryNodeType(type) && !hasNodeConfig(type));
10248
+ }
10249
+ async function loadRegistryNodeTypes(types) {
10370
10250
  try {
10371
10251
  const client = await waitForFluidGridsClient(15e3, 150);
10372
10252
  if (client) {
10373
10253
  const manifests = await loadNodeManifests(client, types.map((nodeType) => ({ nodeType })));
10374
10254
  for (const manifest of manifests) addNodeConfig(toNodeConfig(manifest, manifest.publishType));
10375
10255
  }
10376
- const missing = new Set(types.filter((type) => !hasNodeConfig(type)));
10377
- if (missing.size > 0) await loadInstalledStoreNodes(missing);
10378
10256
  } catch (error) {
10379
10257
  const message = error instanceof Error ? error.message : "Unknown error";
10380
10258
  console.error("[Workflows] Could not load node types:", message);
@@ -10382,16 +10260,12 @@ async function loadNodeTypes(types) {
10382
10260
  rebuildNodeArrays();
10383
10261
  }
10384
10262
  /**
10385
- * Make sure the given node types are registered, without loading the rest of the
10386
- * palette: what a canvas needs before it is drawn. Types already registered cost
10387
- * nothing; the rest are fetched with one batched request, and a type the registry
10388
- * does not carry is looked up among the workspace's installed store nodes. Types
10389
- * that resolve nowhere stay unregistered (the canvas draws them with the fallback
10390
- * card). Never rejects.
10263
+ * Register the given node types from the node registry: one batched
10264
+ * `nodeManifests` request for the ones not registered yet. Types the registry is
10265
+ * known to lack (see `registerNodeManifests`) are not asked about. Never rejects.
10391
10266
  */
10392
- function ensureNodeTypesLoaded(types) {
10393
- if (isInitialized) return Promise.resolve();
10394
- const wanted = [...new Set(types)].filter((type) => isRegistryNodeType(type) && !hasNodeConfig(type));
10267
+ function ensureRegistryNodeTypesLoaded(types) {
10268
+ const wanted = unregisteredTypes(types).filter((type) => !registryLacks.has(type));
10395
10269
  if (wanted.length === 0) return Promise.resolve();
10396
10270
  const pending = /* @__PURE__ */ new Set();
10397
10271
  const fresh = [];
@@ -10401,7 +10275,7 @@ function ensureNodeTypesLoaded(types) {
10401
10275
  else fresh.push(type);
10402
10276
  }
10403
10277
  if (fresh.length > 0) {
10404
- const load = loadNodeTypes(fresh).finally(() => {
10278
+ const load = loadRegistryNodeTypes(fresh).finally(() => {
10405
10279
  for (const type of fresh) if (nodeTypeLoads.get(type) === load) nodeTypeLoads.delete(type);
10406
10280
  });
10407
10281
  for (const type of fresh) nodeTypeLoads.set(type, load);
@@ -10410,12 +10284,46 @@ function ensureNodeTypesLoaded(types) {
10410
10284
  return Promise.all(pending).then(() => void 0);
10411
10285
  }
10412
10286
  /**
10287
+ * Register the given node types from the workspace's installed store nodes, for
10288
+ * the ones not registered yet. Concurrent callers share one installations
10289
+ * request. Never rejects.
10290
+ */
10291
+ async function ensureInstalledNodeTypesLoaded(types) {
10292
+ const wanted = unregisteredTypes(types);
10293
+ if (wanted.length === 0) return;
10294
+ try {
10295
+ await loadInstalledStoreNodes(new Set(wanted));
10296
+ } catch (error) {
10297
+ const message = error instanceof Error ? error.message : "Unknown error";
10298
+ console.error("[Workflows] Could not load installed node types:", message);
10299
+ }
10300
+ rebuildNodeArrays();
10301
+ }
10302
+ /**
10303
+ * Make sure the given node types are registered, without loading the rest of the
10304
+ * palette: what a canvas needs before it is drawn. Types already registered cost
10305
+ * nothing; the rest are fetched with one batched request, and a type the registry
10306
+ * does not carry is looked up among the workspace's installed store nodes. Types
10307
+ * that resolve nowhere stay unregistered (the canvas draws them with the fallback
10308
+ * card). Never rejects.
10309
+ */
10310
+ async function ensureNodeTypesLoaded(types) {
10311
+ const wanted = [...types];
10312
+ await ensureRegistryNodeTypesLoaded(wanted);
10313
+ await ensureInstalledNodeTypesLoaded(wanted);
10314
+ }
10315
+ /**
10413
10316
  * Register manifests that arrived with a workflow (`WorkflowDefinition.nodeManifests`)
10414
10317
  * and keep them in the session cache, so the canvas needs no further request.
10318
+ *
10319
+ * `lookedUp` names the node types those manifests answer for (the workflow's own
10320
+ * node types): one the response left out is a type the registry does not carry,
10321
+ * and it is not asked about again (BOFF-11754).
10415
10322
  */
10416
- function registerNodeManifests(values) {
10323
+ function registerNodeManifests(values, lookedUp = []) {
10417
10324
  let added = false;
10418
10325
  for (const manifest of rememberNodeManifests(values)) if (addNodeConfig(toNodeConfig(manifest, manifest.publishType))) added = true;
10326
+ for (const type of lookedUp) if (isRegistryNodeType(type) && !hasNodeConfig(type)) registryLacks.add(type);
10419
10327
  if (added) rebuildNodeArrays();
10420
10328
  }
10421
10329
  /** Register the client-side node components every canvas needs. */
@@ -10434,6 +10342,7 @@ function resetNodeRegistry() {
10434
10342
  isInitialized = false;
10435
10343
  initPromise = null;
10436
10344
  nodeTypeLoads.clear();
10345
+ registryLacks.clear();
10437
10346
  registerBaseNodeTypes();
10438
10347
  }
10439
10348
  /**
@@ -10448,7 +10357,10 @@ function resetNodeRegistry() {
10448
10357
  * anything.
10449
10358
  */
10450
10359
  async function refetchStoreNodes() {
10451
- if (NODE_CONFIGS.length === 0 && !initPromise && nodeTypeLoads.size === 0) return;
10360
+ if (NODE_CONFIGS.length === 0 && !initPromise && nodeTypeLoads.size === 0 && !installationsRequest) {
10361
+ registryLacks.clear();
10362
+ return;
10363
+ }
10452
10364
  try {
10453
10365
  resetNodeRegistry();
10454
10366
  await initializeNodeConfigs();
@@ -10827,4 +10739,4 @@ function useFluidGridsContext() {
10827
10739
  return context;
10828
10740
  }
10829
10741
 
10830
- export { resolveLoadOptionsSpec as $, useWorkflowTestsEnabled as $n, useNodeExecution as $t, UninstallWorkflowNodeDocument as A, clearCodeWorkflowDefinitionCache as An, bannerOf as At, coerceNumber as B, FLUIDGRIDS_FLAGS as Bn, forgetSessionForReload as Bt, InstallOrganizationPrivateNodeDocument as C, RUNS_QUOTA_NAME as Cn, classifyCreateRefusal as Ct, OrganizationPrivateNodesDocument as D, isQuotaExhaustedFailure as Dn, useSaveStatusStore as Dt, MyWorkflowTemplateSubmissionsDocument as E, findQuotaRefusal as En, saveIndicatorOf as Et, useInsertNode as F, durableInterfaceOf as Fn, phaseAfterTakeOver as Ft, paramsFromOperation as G, useContinuousOptimisationEnabled as Gn, AUTOSAVE_DEBOUNCE_MS as Gt, nodeSubtitle as H, PHASE_C_FLAGS_OFF as Hn, sessionBeforeReload as Ht, MissingParametersDialog as I, parseRawSignalPayload as In, releasesOnClose as It, resolveUiSpec as J, useFluidGridsFlag as Jn, codeBuildIdOf as Jt, selectedOperationOf as K, useDurableFunctionNodesEnabled as Kn, AUTOSAVE_RETRY_DELAYS_MS as Kt, useRunGuard as L, payloadFromCardValues as Ln, shouldReleaseForIdle as Lt, getNodeMetadata as M, useCodeWorkflowInterface as Mn, leaseCallQueue as Mt, buildOperationSeed as N, canSignalRun as Nn, leaseCallSequence as Nt, SubmitWorkflowTemplateDocument as O, useCanvasEdges as On, useEditLeaseLocked as Ot, createConfiguredNode as P, declaredSignals as Pn, phaseAfterAcquire as Pt, optionListValues as Q, useSelfHostedWorkersEnabled as Qn, workflowFingerprint as Qt, workflowParameterIssues as R, runSignalTargets as Rn, tickAction as Rt, GetNodeInstallableVersionsDocument as S, BILLING_PLANS_PATH as Sn, builderPathOf as St, InstallWorkflowNodeDocument as T, collectExtensions as Tn, refusalOfQuota as Tt, nodeTitle as U, resolveFluidGridsFlagsSettled as Un, rememberOwnStatusChange as Ut, fixedParameterState as V, FLUIDGRIDS_FLAG_DEFAULTS as Vn, rememberSessionForReload as Vt, optionText as W, resolvePhaseCFlags as Wn, rememberRevision as Wt, isStringOptionList as X, usePaletteGates as Xn, inAppLeaveTarget as Xt, stripSubmitActions as Y, useFluidGridsFlagsSettled as Yn, findSaveConflict as Yt, optionListText as Z, usePhaseCFlags as Zn, saveFailureActionOf as Zt, global_operations_exports as _, emitWorkflowCreated as _n, watchLeavingLosesChanges as _t, NODES_METADATA as a, structuredParameterType as an, getNodeDetail as ar, latestNodeLog as at, CreateStoreOrderDocument as b, nodesOf as bn, useSaveWorkflow as bt, ensureNodeConfigsLoaded as c, isParamVisible as cn, useBuilderReadOnly as cr, useGuardedNavigate as ct, onNodeTypesUpdate as d, emitNodeInstalled as dn, global_client_exports as dr, departingSave as dt, formatElapsedMs as en, connectionsForAdapter as er, ConditionTreeBuilder as et, refetchStoreNodes as f, emitRunFailed as fn, resetGlobalStoreClient as fr, editStateFor as ft, scheduleNodePaletteLoad as g, emitUpgradeClicked as gn, touchesSavedFields as gt, registryNodeData as h, emitTemplateUsed as hn, savedEverythingBeforeLeaving as ht, AVAILABLE_NODES as i, parseParameterValue as in, replaceAdapterConnections as ir, parseMappingValue as it, WithdrawWorkflowTemplateSubmissionDocument as j, loadDefinitionJson as jn, isLocked as jt, UninstallOrganizationPrivateNodeDocument as k, useNodeRegistryRevision as kn, useEditLeaseStore as kt, ensureNodeTypesLoaded as l, useFluidGridsAnalytics as ln, createGlobalStoreClient as lr, useManualSave as lt, registerWorkflowNodeTypes as m, emitRunStarted as mn, leavingLosesChanges as mt, FluidGridsProvider as n, runDurationMs as nn, matchesAdapterProvider as nr, casesFromRules as nt, NODE_CONFIGS as o, fieldsFromValue as on, buildStickyNode as or, boundFieldsOf as ot, registerNodeManifests as p, emitRunLimitHit as pn, setGlobalStoreClient as pr, editingLeaseLocked as pt, useNodeConfig as q, useDurableParityEnabled as qn, canAutosave as qt, useFluidGridsContext as r, formatParameterValue as rn, newConnectionProviderKey as rr, FieldTree as rt, NODE_TYPES as s, resolveNodeOperation as sn, BuilderReadOnlyProvider as sr, missingRequiredParameters as st, FluidGridsContext as t, nodeStateDurationMs as tn, isOptionalAdapter as tr, SwitchRulesEditor as tt, isNodeConfigsInitialized as u, openRunQuotaUpgradePrompt as un, getGlobalStoreClient as ur, autosaveAllowedFor as ut, BrowseWorkflowNodesDocument as v, emitWorkflowLimitHit as vn, isFlowComplete as vt, InstallPurchasedNodeDocument as w, WORKFLOWS_QUOTA_NAME as wn, createThenOpen as wt, GetMyNodeInstallationsDocument as x, runTriggerFromMode as xn, blankWorkflowCreateInput as xt, BrowseWorkflowTemplatesDocument as y, emitWorkflowPublished as yn, useFlowValidator as yt, asRecord as z, signalPayloadCard as zn, EDIT_SESSION_ID as zt };
10742
+ export { isStringOptionList as $, setGlobalStoreClient as $n, inAppLeaveTarget as $t, StoreNodeProductsByTypeDocument as A, resolvePhaseCFlags as An, useSaveStatusStore as At, useRunGuard as B, connectionsForAdapter as Bn, shouldReleaseForIdle as Bt, GetMyNodeInstallationsDocument as C, payloadFromCardValues as Cn, useSaveWorkflow as Ct, InstallWorkflowNodeDocument as D, FLUIDGRIDS_FLAG_DEFAULTS as Dn, createThenOpen as Dt, InstallPurchasedNodeDocument as E, FLUIDGRIDS_FLAGS as En, classifyCreateRefusal as Et, getNodeMetadata as F, useFluidGridsFlagsSettled as Fn, leaseCallQueue as Ft, nodeSubtitle as G, getNodeDetail as Gn, sessionBeforeReload as Gt, asRecord as H, matchesAdapterProvider as Hn, EDIT_SESSION_ID as Ht, buildOperationSeed as I, usePaletteGates as In, leaseCallSequence as It, paramsFromOperation as J, useBuilderReadOnly as Jn, AUTOSAVE_DEBOUNCE_MS as Jt, nodeTitle as K, buildStickyNode as Kn, rememberOwnStatusChange as Kt, createConfiguredNode as L, usePhaseCFlags as Ln, phaseAfterAcquire as Lt, UninstallOrganizationPrivateNodeDocument as M, useDurableFunctionNodesEnabled as Mn, useEditLeaseStore as Mt, UninstallWorkflowNodeDocument as N, useDurableParityEnabled as Nn, bannerOf as Nt, MyWorkflowTemplateSubmissionsDocument as O, PHASE_C_FLAGS_OFF as On, refusalOfQuota as Ot, WithdrawWorkflowTemplateSubmissionDocument as P, useFluidGridsFlag as Pn, isLocked as Pt, stripSubmitActions as Q, resetGlobalStoreClient as Qn, findSaveConflict as Qt, useInsertNode as R, useSelfHostedWorkersEnabled as Rn, phaseAfterTakeOver as Rt, CreateStoreOrderDocument as S, parseRawSignalPayload as Sn, useFlowValidator as St, InstallOrganizationPrivateNodeDocument as T, signalPayloadCard as Tn, builderPathOf as Tt, coerceNumber as U, newConnectionProviderKey as Un, forgetSessionForReload as Ut, workflowParameterIssues as V, isOptionalAdapter as Vn, tickAction as Vt, fixedParameterState as W, replaceAdapterConnections as Wn, rememberSessionForReload as Wt, useNodeConfig as X, getGlobalStoreClient as Xn, canAutosave as Xt, selectedOperationOf as Y, createGlobalStoreClient as Yn, AUTOSAVE_RETRY_DELAYS_MS as Yt, resolveUiSpec as Z, global_client_exports as Zn, codeBuildIdOf as Zt, registryNodeData as _, loadDefinitionJson as _n, leavingLosesChanges as _t, NODES_METADATA as a, runDurationMs as an, casesFromRules as at, BrowseWorkflowNodesDocument as b, declaredSignals as bn, watchLeavingLosesChanges as bt, ensureInstalledNodeTypesLoaded as c, structuredParameterType as cn, latestNodeLog as ct, ensureRegistryNodeTypesLoaded as d, isParamVisible as dn, useGuardedNavigate as dt, saveFailureActionOf as en, optionListText as et, isNodeConfigsInitialized as f, useFluidGridsAnalytics as fn, useManualSave as ft, registerWorkflowNodeTypes as g, clearCodeWorkflowDefinitionCache as gn, editingLeaseLocked as gt, registerNodeManifests as h, useNodeRegistryRevision as hn, editStateFor as ht, AVAILABLE_NODES as i, nodeStateDurationMs as in, SwitchRulesEditor as it, SubmitWorkflowTemplateDocument as j, useContinuousOptimisationEnabled as jn, useEditLeaseLocked as jt, OrganizationPrivateNodesDocument as k, resolveFluidGridsFlagsSettled as kn, saveIndicatorOf as kt, ensureNodeConfigsLoaded as l, fieldsFromValue as ln, boundFieldsOf as lt, refetchStoreNodes as m, useCanvasEdges as mn, departingSave as mt, FluidGridsProvider as n, useNodeExecution as nn, resolveLoadOptionsSpec as nt, NODE_CONFIGS as o, formatParameterValue as on, FieldTree as ot, onNodeTypesUpdate as p, openRunQuotaUpgradePrompt as pn, autosaveAllowedFor as pt, optionText as q, BuilderReadOnlyProvider as qn, rememberRevision as qt, useFluidGridsContext as r, formatElapsedMs as rn, ConditionTreeBuilder as rt, NODE_TYPES as s, parseParameterValue as sn, parseMappingValue as st, FluidGridsContext as t, workflowFingerprint as tn, optionListValues as tt, ensureNodeTypesLoaded as u, resolveNodeOperation as un, missingRequiredParameters as ut, scheduleNodePaletteLoad as v, useCodeWorkflowInterface as vn, savedEverythingBeforeLeaving as vt, GetNodeInstallableVersionsDocument as w, runSignalTargets as wn, blankWorkflowCreateInput as wt, BrowseWorkflowTemplatesDocument as x, durableInterfaceOf as xn, isFlowComplete as xt, global_operations_exports as y, canSignalRun as yn, touchesSavedFields as yt, MissingParametersDialog as z, useWorkflowTestsEnabled as zn, releasesOnClose as zt };
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { d as useRestoreWorkflowVersion, h as useWorkflowDefinitions } from "./useWorkflows-Bwpvfdgv.js";
2
+ import { d as useRestoreWorkflowVersion, h as useWorkflowDefinitions } from "./useWorkflows-DyhtoVwp.js";
3
3
  import { i as versionsOfWorkflow, t as VersionDiffDialog } from "./VersionDiffDialog-Dq2xlPFI.js";
4
4
  import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
5
5
  import { qi as getFluidGridsConfig } from "./node-endpoint-configs-DHFGA5MQ.js";