@octaviaflow/core 3.1.0-beta.65 → 3.1.0-beta.68

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 (145) hide show
  1. package/dist/chunk-5AKA6EJB.js +3003 -0
  2. package/dist/chunk-5AKA6EJB.js.map +1 -0
  3. package/dist/chunk-JMSZOWT2.js +2616 -0
  4. package/dist/chunk-JMSZOWT2.js.map +1 -0
  5. package/dist/chunk-KZP2MNBO.js +2516 -0
  6. package/dist/chunk-KZP2MNBO.js.map +1 -0
  7. package/dist/chunk-S4LE4BFQ.js +5934 -0
  8. package/dist/chunk-S4LE4BFQ.js.map +1 -0
  9. package/dist/chunk-X7YETDK7.js +107 -0
  10. package/dist/chunk-X7YETDK7.js.map +1 -0
  11. package/dist/components/AgentCard/AgentCard.d.ts +5 -0
  12. package/dist/components/AgentCard/AgentCard.d.ts.map +1 -1
  13. package/dist/components/Catalog/Catalog.d.ts +116 -0
  14. package/dist/components/Catalog/Catalog.d.ts.map +1 -0
  15. package/dist/components/Catalog/index.d.ts +2 -0
  16. package/dist/components/Catalog/index.d.ts.map +1 -0
  17. package/dist/components/ExecutionConsole/ExecutionConsole.d.ts.map +1 -1
  18. package/dist/components/FlowMinimap/FlowMinimap.d.ts.map +1 -1
  19. package/dist/components/FlowToolbar/FlowToolbar.d.ts +27 -0
  20. package/dist/components/FlowToolbar/FlowToolbar.d.ts.map +1 -1
  21. package/dist/components/FlowToolbar/index.d.ts +1 -1
  22. package/dist/components/FlowToolbar/index.d.ts.map +1 -1
  23. package/dist/components/ItemDetail/ItemDetail.d.ts +57 -0
  24. package/dist/components/ItemDetail/ItemDetail.d.ts.map +1 -0
  25. package/dist/components/ItemDetail/index.d.ts +2 -0
  26. package/dist/components/ItemDetail/index.d.ts.map +1 -0
  27. package/dist/components/MessageBlockBuilder/BlockFieldsEditor.d.ts +18 -0
  28. package/dist/components/MessageBlockBuilder/BlockFieldsEditor.d.ts.map +1 -0
  29. package/dist/components/MessageBlockBuilder/MessageBlockBuilder.d.ts +6 -0
  30. package/dist/components/MessageBlockBuilder/MessageBlockBuilder.d.ts.map +1 -0
  31. package/dist/components/MessageBlockBuilder/MessagePreview.d.ts +9 -0
  32. package/dist/components/MessageBlockBuilder/MessagePreview.d.ts.map +1 -0
  33. package/dist/components/MessageBlockBuilder/TokenPanel.d.ts +17 -0
  34. package/dist/components/MessageBlockBuilder/TokenPanel.d.ts.map +1 -0
  35. package/dist/components/MessageBlockBuilder/glyphs.d.ts +18 -0
  36. package/dist/components/MessageBlockBuilder/glyphs.d.ts.map +1 -0
  37. package/dist/components/MessageBlockBuilder/index.d.ts +4 -0
  38. package/dist/components/MessageBlockBuilder/index.d.ts.map +1 -0
  39. package/dist/components/MessageBlockBuilder/internal.d.ts +33 -0
  40. package/dist/components/MessageBlockBuilder/internal.d.ts.map +1 -0
  41. package/dist/components/MessageBlockBuilder/platforms/googleChat.d.ts +7 -0
  42. package/dist/components/MessageBlockBuilder/platforms/googleChat.d.ts.map +1 -0
  43. package/dist/components/MessageBlockBuilder/platforms/index.d.ts +7 -0
  44. package/dist/components/MessageBlockBuilder/platforms/index.d.ts.map +1 -0
  45. package/dist/components/MessageBlockBuilder/platforms/slack.d.ts +7 -0
  46. package/dist/components/MessageBlockBuilder/platforms/slack.d.ts.map +1 -0
  47. package/dist/components/MessageBlockBuilder/platforms/teams.d.ts +7 -0
  48. package/dist/components/MessageBlockBuilder/platforms/teams.d.ts.map +1 -0
  49. package/dist/components/MessageBlockBuilder/types.d.ts +183 -0
  50. package/dist/components/MessageBlockBuilder/types.d.ts.map +1 -0
  51. package/dist/components/PlanCard/PlanCard.d.ts +35 -0
  52. package/dist/components/PlanCard/PlanCard.d.ts.map +1 -0
  53. package/dist/components/PlanCard/index.d.ts +2 -0
  54. package/dist/components/PlanCard/index.d.ts.map +1 -0
  55. package/dist/components/PlanPicker/PlanPicker.d.ts +16 -0
  56. package/dist/components/PlanPicker/PlanPicker.d.ts.map +1 -0
  57. package/dist/components/PlanPicker/context.d.ts +8 -0
  58. package/dist/components/PlanPicker/context.d.ts.map +1 -0
  59. package/dist/components/PlanPicker/index.d.ts +2 -0
  60. package/dist/components/PlanPicker/index.d.ts.map +1 -0
  61. package/dist/components/PricingCard/index.d.ts +1 -1
  62. package/dist/components/PricingCard/index.d.ts.map +1 -1
  63. package/dist/components/TemplateCard/TemplateCard.d.ts +27 -0
  64. package/dist/components/TemplateCard/TemplateCard.d.ts.map +1 -1
  65. package/dist/components/UsageMeter/UsageMeter.d.ts +41 -0
  66. package/dist/components/UsageMeter/UsageMeter.d.ts.map +1 -0
  67. package/dist/components/UsageMeter/index.d.ts +2 -0
  68. package/dist/components/UsageMeter/index.d.ts.map +1 -0
  69. package/dist/components/WorkflowShowcase/ShowcaseScene.d.ts +20 -0
  70. package/dist/components/WorkflowShowcase/ShowcaseScene.d.ts.map +1 -0
  71. package/dist/components/WorkflowShowcase/ShowcaseSignup.d.ts +14 -0
  72. package/dist/components/WorkflowShowcase/ShowcaseSignup.d.ts.map +1 -0
  73. package/dist/components/WorkflowShowcase/WorkflowShowcase.d.ts +48 -0
  74. package/dist/components/WorkflowShowcase/WorkflowShowcase.d.ts.map +1 -0
  75. package/dist/components/WorkflowShowcase/index.d.ts +3 -0
  76. package/dist/components/WorkflowShowcase/index.d.ts.map +1 -0
  77. package/dist/components/WorkflowShowcase/showcaseEngine.d.ts +102 -0
  78. package/dist/components/WorkflowShowcase/showcaseEngine.d.ts.map +1 -0
  79. package/dist/index.cjs +16261 -11888
  80. package/dist/index.cjs.map +1 -1
  81. package/dist/index.d.ts +8 -2
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +19366 -20520
  84. package/dist/index.js.map +1 -1
  85. package/dist/marketing/components/AssistantTranscript/AssistantTranscript.d.ts +15 -0
  86. package/dist/marketing/components/AssistantTranscript/AssistantTranscript.d.ts.map +1 -0
  87. package/dist/marketing/components/CtaBanner/CtaBanner.d.ts +16 -0
  88. package/dist/marketing/components/CtaBanner/CtaBanner.d.ts.map +1 -0
  89. package/dist/marketing/components/FeatureGrid/FeatureGrid.d.ts +15 -0
  90. package/dist/marketing/components/FeatureGrid/FeatureGrid.d.ts.map +1 -0
  91. package/dist/marketing/components/IntegrationsWall/IntegrationsWall.d.ts +19 -0
  92. package/dist/marketing/components/IntegrationsWall/IntegrationsWall.d.ts.map +1 -0
  93. package/dist/marketing/components/LiveConsole/LiveConsole.d.ts +21 -0
  94. package/dist/marketing/components/LiveConsole/LiveConsole.d.ts.map +1 -0
  95. package/dist/marketing/components/MarketingFooter/MarketingFooter.d.ts +25 -0
  96. package/dist/marketing/components/MarketingFooter/MarketingFooter.d.ts.map +1 -0
  97. package/dist/marketing/components/MarketingHero/MarketingHero.d.ts +11 -0
  98. package/dist/marketing/components/MarketingHero/MarketingHero.d.ts.map +1 -0
  99. package/dist/marketing/components/MarketingNav/MarketingNav.d.ts +17 -0
  100. package/dist/marketing/components/MarketingNav/MarketingNav.d.ts.map +1 -0
  101. package/dist/marketing/components/MarketingSection/MarketingSection.d.ts +15 -0
  102. package/dist/marketing/components/MarketingSection/MarketingSection.d.ts.map +1 -0
  103. package/dist/marketing/components/StatBand/StatBand.d.ts +16 -0
  104. package/dist/marketing/components/StatBand/StatBand.d.ts.map +1 -0
  105. package/dist/marketing/components/WorkflowShowcase/ShowcaseScene.d.ts +20 -0
  106. package/dist/marketing/components/WorkflowShowcase/ShowcaseScene.d.ts.map +1 -0
  107. package/dist/marketing/components/WorkflowShowcase/ShowcaseSignup.d.ts +14 -0
  108. package/dist/marketing/components/WorkflowShowcase/ShowcaseSignup.d.ts.map +1 -0
  109. package/dist/marketing/components/WorkflowShowcase/WorkflowShowcase.d.ts +48 -0
  110. package/dist/marketing/components/WorkflowShowcase/WorkflowShowcase.d.ts.map +1 -0
  111. package/dist/marketing/components/WorkflowShowcase/index.d.ts +3 -0
  112. package/dist/marketing/components/WorkflowShowcase/index.d.ts.map +1 -0
  113. package/dist/marketing/components/WorkflowShowcase/showcaseEngine.d.ts +102 -0
  114. package/dist/marketing/components/WorkflowShowcase/showcaseEngine.d.ts.map +1 -0
  115. package/dist/marketing/glyphs.d.ts +20 -0
  116. package/dist/marketing/glyphs.d.ts.map +1 -0
  117. package/dist/marketing/index.d.ts +13 -0
  118. package/dist/marketing/index.d.ts.map +1 -0
  119. package/dist/marketing.cjs +3985 -0
  120. package/dist/marketing.cjs.map +1 -0
  121. package/dist/marketing.js +1669 -0
  122. package/dist/marketing.js.map +1 -0
  123. package/dist/styles.css +1 -1
  124. package/dist/workflow/components/FlowCanvas/FlowCanvas.d.ts +3 -3
  125. package/dist/workflow/components/FlowCanvas/FlowCanvas.d.ts.map +1 -1
  126. package/dist/workflow/components/FlowNode/FlowNode.d.ts.map +1 -1
  127. package/dist/workflow/components/Handle/Handle.d.ts.map +1 -1
  128. package/dist/workflow/components/HttpActionPanel/HttpActionPanel.d.ts +29 -0
  129. package/dist/workflow/components/HttpActionPanel/HttpActionPanel.d.ts.map +1 -0
  130. package/dist/workflow/components/HttpActionPanel/httpActionTypes.d.ts +135 -0
  131. package/dist/workflow/components/HttpActionPanel/httpActionTypes.d.ts.map +1 -0
  132. package/dist/workflow/components/NodeResizer/NodeResizer.d.ts.map +1 -1
  133. package/dist/workflow/index.d.ts +2 -0
  134. package/dist/workflow/index.d.ts.map +1 -1
  135. package/dist/workflow/layout/dagre.d.ts.map +1 -1
  136. package/dist/workflow/layout/elk.d.ts.map +1 -1
  137. package/dist/workflow/layout/types.d.ts +1 -1
  138. package/dist/workflow/layout/types.d.ts.map +1 -1
  139. package/dist/workflow/utils/parenting.d.ts +26 -6
  140. package/dist/workflow/utils/parenting.d.ts.map +1 -1
  141. package/dist/workflow.cjs +7118 -411
  142. package/dist/workflow.cjs.map +1 -1
  143. package/dist/workflow.js +1598 -68
  144. package/dist/workflow.js.map +1 -1
  145. package/package.json +6 -1
package/dist/workflow.js CHANGED
@@ -1,9 +1,15 @@
1
1
  import {
2
+ Accordion,
2
3
  ActionNode,
4
+ Badge,
5
+ Banner,
6
+ CodeEditor,
7
+ Combobox,
3
8
  ConditionNode,
4
9
  DEFAULT_NODE_HEIGHT,
5
10
  DEFAULT_NODE_KINDS,
6
11
  DEFAULT_NODE_WIDTH,
12
+ Disclosure,
7
13
  ErrorNode,
8
14
  FlowCanvas,
9
15
  FlowEdge,
@@ -12,10 +18,18 @@ import {
12
18
  GroupNode,
13
19
  Handle,
14
20
  HttpRequestNode,
21
+ JsonViewer,
22
+ KeyValueEditor,
15
23
  NodeResizer,
24
+ NumberInput,
16
25
  OutputNode,
17
26
  ParallelNode,
27
+ PasswordInput,
28
+ SegmentedControl,
29
+ Spinner,
18
30
  StickyNode,
31
+ Switch,
32
+ Tabs,
19
33
  TriggerNode,
20
34
  WaitNode,
21
35
  WebhookNode,
@@ -50,7 +64,12 @@ import {
50
64
  useSelection,
51
65
  useViewport,
52
66
  useViewportOrNull
53
- } from "./chunk-KOE4VS4I.js";
67
+ } from "./chunk-S4LE4BFQ.js";
68
+ import {
69
+ Button,
70
+ Input,
71
+ Select
72
+ } from "./chunk-KZP2MNBO.js";
54
73
  import {
55
74
  cn
56
75
  } from "./chunk-ZAUUGK2Y.js";
@@ -244,7 +263,7 @@ function createDagreEngine(dagre, defaults = {}) {
244
263
  }
245
264
  for (const e of edges) {
246
265
  if (e.hidden) continue;
247
- g.setEdge(e.source, e.target, { id: e.id });
266
+ g.setEdge(e.source, e.target, { id: e.id }, e.id);
248
267
  }
249
268
  lib.layout(g);
250
269
  const result = [];
@@ -302,6 +321,13 @@ function createElkEngine(elk, defaults = {}) {
302
321
  const engineOptions = Object.fromEntries(
303
322
  Object.entries(options?.engine ?? {}).map(([k, v]) => [k, String(v)])
304
323
  );
324
+ const baseLayeredOptions = {
325
+ "elk.algorithm": algorithm,
326
+ "elk.direction": ELK_DIRECTION[direction],
327
+ "elk.spacing.nodeNode": String(nodeSpacing),
328
+ "elk.layered.spacing.nodeNodeBetweenLayers": String(rankSpacing),
329
+ "elk.layered.considerModelOrder.strategy": "NODES_AND_EDGES"
330
+ };
305
331
  const buildChildren = (parentId) => {
306
332
  const list = childrenByParent.get(parentId) ?? [];
307
333
  return list.map((n) => ({
@@ -310,10 +336,7 @@ function createElkEngine(elk, defaults = {}) {
310
336
  height: n.height ?? DEFAULT_NODE_HEIGHT,
311
337
  children: childrenByParent.has(n.id) ? buildChildren(n.id) : void 0,
312
338
  layoutOptions: childrenByParent.has(n.id) ? {
313
- "elk.algorithm": algorithm,
314
- "elk.direction": ELK_DIRECTION[direction],
315
- "elk.spacing.nodeNode": String(nodeSpacing),
316
- "elk.layered.spacing.nodeNodeBetweenLayers": String(rankSpacing),
339
+ ...baseLayeredOptions,
317
340
  ...engineOptions
318
341
  } : void 0
319
342
  }));
@@ -326,13 +349,8 @@ function createElkEngine(elk, defaults = {}) {
326
349
  const graph = {
327
350
  id: "root",
328
351
  layoutOptions: {
329
- "elk.algorithm": algorithm,
330
- "elk.direction": ELK_DIRECTION[direction],
331
- "elk.spacing.nodeNode": String(nodeSpacing),
332
- "elk.layered.spacing.nodeNodeBetweenLayers": String(rankSpacing),
333
- ...Object.fromEntries(
334
- Object.entries(options?.engine ?? {}).map(([k, v]) => [k, String(v)])
335
- )
352
+ ...baseLayeredOptions,
353
+ ...engineOptions
336
354
  },
337
355
  children: buildChildren(void 0),
338
356
  edges: elkEdges
@@ -621,11 +639,1510 @@ function ConfigPanel({
621
639
  );
622
640
  }
623
641
 
642
+ // src/workflow/components/HttpActionPanel/HttpActionPanel.tsx
643
+ import {
644
+ CheckmarkIcon,
645
+ CodeIcon,
646
+ CopyIcon,
647
+ DataViewAltIcon,
648
+ GlobeIcon,
649
+ ListIcon,
650
+ LockedIcon,
651
+ PlayIcon,
652
+ RenewIcon,
653
+ TagIcon
654
+ } from "@octaviaflow/icons";
655
+ import { useCallback as useCallback4, useId, useMemo as useMemo2, useRef as useRef4, useState as useState4 } from "react";
656
+
657
+ // src/workflow/components/HttpActionPanel/httpActionTypes.ts
658
+ var HTTP_METHODS = [
659
+ "GET",
660
+ "POST",
661
+ "PUT",
662
+ "PATCH",
663
+ "DELETE",
664
+ "HEAD",
665
+ "OPTIONS"
666
+ ];
667
+ var HTTP_ACTION_DEFAULTS = {
668
+ apiType: "rest",
669
+ method: "GET",
670
+ url: "",
671
+ queryParams: [],
672
+ headers: [],
673
+ bodyType: "json",
674
+ formData: [],
675
+ graphqlQuery: "",
676
+ graphqlVariables: {},
677
+ auth: { type: "none" },
678
+ timeout: 3e4,
679
+ failOnError: true,
680
+ followRedirects: true,
681
+ retry: {
682
+ maxAttempts: 1,
683
+ retryOn: [429, 500, 502, 503, 504],
684
+ initialDelayMs: 1e3,
685
+ backoffFactor: 2,
686
+ maxDelayMs: 3e4
687
+ },
688
+ pagination: { type: "none" },
689
+ extract: {},
690
+ responseType: "json",
691
+ expectedContentTypes: []
692
+ };
693
+ function normalizeKeyValues(raw) {
694
+ if (Array.isArray(raw)) {
695
+ return raw.map((r) => ({
696
+ key: String(r.key ?? ""),
697
+ value: String(r.value ?? ""),
698
+ description: r.description,
699
+ enabled: r.enabled !== false
700
+ }));
701
+ }
702
+ if (raw && typeof raw === "object") {
703
+ return Object.entries(raw).map(([key, value]) => ({
704
+ key,
705
+ value: String(value),
706
+ enabled: true
707
+ }));
708
+ }
709
+ return [];
710
+ }
711
+ function normalizeAuth(raw) {
712
+ const r = raw ?? {};
713
+ const rawType = r.type ?? "none";
714
+ const type = rawType === "oauth2" ? "bearer" : rawType;
715
+ return {
716
+ type: ["none", "basic", "bearer", "apikey"].includes(type) ? type : "none",
717
+ username: r.username ?? "",
718
+ password: r.password ?? "",
719
+ token: r.token ?? r.accessToken ?? "",
720
+ apiKeyName: r.apiKeyName ?? "X-API-Key",
721
+ apiKeyValue: r.apiKeyValue ?? "",
722
+ apiKeyLocation: r.apiKeyLocation === "query" ? "query" : "header"
723
+ };
724
+ }
725
+ function effectiveUrl(baseUrl, url) {
726
+ const base = (baseUrl ?? "").trim();
727
+ if (!base) return url;
728
+ return `${base.replace(/\/$/, "")}/${url.replace(/^\//, "")}`;
729
+ }
730
+ function serializeKeyValues(rows) {
731
+ return rows.filter((r) => r.key || r.value).map((r) => ({
732
+ key: r.key,
733
+ value: r.value,
734
+ enabled: r.enabled !== false,
735
+ ...r.description ? { description: r.description } : {}
736
+ }));
737
+ }
738
+ function validateHttpConfig(config) {
739
+ const errors = [];
740
+ const apiType = config.apiType ?? "rest";
741
+ if (apiType === "rest" && !config.method) errors.push("Method is required");
742
+ if (apiType === "graphql" && !String(config.graphqlQuery ?? "").trim()) {
743
+ errors.push("GraphQL query is required");
744
+ }
745
+ const hasConnection = Boolean(config.connectionId);
746
+ if (!config.url && !hasConnection) {
747
+ errors.push("URL is required");
748
+ } else if (config.url && !hasConnection && !config.baseUrl && !config.url.includes("{{")) {
749
+ try {
750
+ new URL(config.url);
751
+ } catch {
752
+ errors.push("Invalid URL format");
753
+ }
754
+ }
755
+ if (typeof config.timeout === "number" && config.timeout < 1e3) {
756
+ errors.push("Timeout must be at least 1000ms");
757
+ }
758
+ return { valid: errors.length === 0, errors };
759
+ }
760
+ function countGraphqlVariables(query) {
761
+ return new Set(query.match(/\$[A-Za-z_][A-Za-z0-9_]*/g) ?? []).size;
762
+ }
763
+ function shellTokens(input) {
764
+ const tokens = [];
765
+ const flat = input.replace(/\\\r?\n/g, " ");
766
+ const re = /'([^']*)'|"((?:[^"\\]|\\.)*)"|(\S+)/g;
767
+ let m = re.exec(flat);
768
+ while (m !== null) {
769
+ if (m[1] !== void 0) tokens.push(m[1]);
770
+ else if (m[2] !== void 0) tokens.push(m[2].replace(/\\(["\\])/g, "$1"));
771
+ else tokens.push(m[3]);
772
+ m = re.exec(flat);
773
+ }
774
+ return tokens;
775
+ }
776
+ function parseCurl(input) {
777
+ const tokens = shellTokens(input.trim());
778
+ if (!tokens.length || !/^curl$/i.test(tokens[0])) return null;
779
+ let method;
780
+ let url = "";
781
+ const headers = [];
782
+ const formData = [];
783
+ let bodyRaw;
784
+ let basicUser;
785
+ let followRedirects;
786
+ for (let i = 1; i < tokens.length; i++) {
787
+ const t = tokens[i];
788
+ const next = () => tokens[++i] ?? "";
789
+ if (t === "-X" || t === "--request") {
790
+ const m = next().toUpperCase();
791
+ if (HTTP_METHODS.includes(m)) method = m;
792
+ } else if (t === "-H" || t === "--header") {
793
+ const raw = next();
794
+ const idx = raw.indexOf(":");
795
+ if (idx > 0) {
796
+ headers.push({
797
+ key: raw.slice(0, idx).trim(),
798
+ value: raw.slice(idx + 1).trim(),
799
+ enabled: true
800
+ });
801
+ }
802
+ } else if (t === "-d" || t === "--data" || t === "--data-raw" || t === "--data-binary" || t === "--data-urlencode") {
803
+ bodyRaw = next();
804
+ } else if (t === "-F" || t === "--form") {
805
+ const raw = next();
806
+ const idx = raw.indexOf("=");
807
+ if (idx > 0) {
808
+ formData.push({ key: raw.slice(0, idx), value: raw.slice(idx + 1), enabled: true });
809
+ }
810
+ } else if (t === "-u" || t === "--user") {
811
+ basicUser = next();
812
+ } else if (t === "--url") {
813
+ url = next();
814
+ } else if (t === "-L" || t === "--location") {
815
+ followRedirects = true;
816
+ } else if (t.startsWith("-")) {
817
+ if ([
818
+ "-o",
819
+ "--output",
820
+ "-A",
821
+ "--user-agent",
822
+ "-e",
823
+ "--referer",
824
+ "-b",
825
+ "--cookie",
826
+ "--connect-timeout",
827
+ "-m",
828
+ "--max-time"
829
+ ].includes(t)) {
830
+ next();
831
+ }
832
+ } else if (!url) {
833
+ url = t;
834
+ }
835
+ }
836
+ if (!url) return null;
837
+ const patch = { url, apiType: "rest" };
838
+ const qIdx = url.indexOf("?");
839
+ if (qIdx >= 0) {
840
+ const query = url.slice(qIdx + 1);
841
+ patch.url = url.slice(0, qIdx);
842
+ patch.queryParams = query.split("&").filter(Boolean).map((pair) => {
843
+ const eq = pair.indexOf("=");
844
+ const rawKey = eq >= 0 ? pair.slice(0, eq) : pair;
845
+ const rawValue = eq >= 0 ? pair.slice(eq + 1) : "";
846
+ const decode = (s) => {
847
+ try {
848
+ return decodeURIComponent(s.replace(/\+/g, "%20"));
849
+ } catch {
850
+ return s;
851
+ }
852
+ };
853
+ return { key: decode(rawKey), value: decode(rawValue), enabled: true };
854
+ });
855
+ }
856
+ const authHeaderIdx = headers.findIndex((h) => h.key.toLowerCase() === "authorization");
857
+ if (authHeaderIdx >= 0 && /^bearer\s+/i.test(headers[authHeaderIdx].value)) {
858
+ patch.auth = {
859
+ type: "bearer",
860
+ token: headers[authHeaderIdx].value.replace(/^bearer\s+/i, "")
861
+ };
862
+ headers.splice(authHeaderIdx, 1);
863
+ } else if (basicUser) {
864
+ const sep = basicUser.indexOf(":");
865
+ patch.auth = {
866
+ type: "basic",
867
+ username: sep >= 0 ? basicUser.slice(0, sep) : basicUser,
868
+ password: sep >= 0 ? basicUser.slice(sep + 1) : ""
869
+ };
870
+ }
871
+ if (headers.length) patch.headers = headers;
872
+ if (followRedirects !== void 0) patch.followRedirects = followRedirects;
873
+ if (formData.length) {
874
+ patch.bodyType = "form-data";
875
+ patch.formData = formData;
876
+ patch.method = method ?? "POST";
877
+ } else if (bodyRaw !== void 0) {
878
+ try {
879
+ patch.body = JSON.parse(bodyRaw);
880
+ patch.bodyType = "json";
881
+ } catch {
882
+ patch.body = bodyRaw;
883
+ patch.bodyType = "raw";
884
+ }
885
+ patch.method = method ?? "POST";
886
+ } else {
887
+ patch.method = method ?? "GET";
888
+ patch.bodyType = "none";
889
+ }
890
+ return patch;
891
+ }
892
+ function shellQuote(value) {
893
+ return `'${value.replace(/'/g, `'\\''`)}'`;
894
+ }
895
+ function buildCurl(config) {
896
+ const parts = ["curl"];
897
+ const method = config.apiType === "graphql" ? "POST" : config.method ?? "GET";
898
+ if (method !== "GET") parts.push(`-X ${method}`);
899
+ let url = effectiveUrl(config.baseUrl, config.url);
900
+ const params = normalizeKeyValues(config.queryParams).filter((p) => p.enabled !== false && p.key);
901
+ if (params.length) {
902
+ const qs = params.map((p) => `${encodeURIComponent(p.key)}=${encodeURIComponent(p.value)}`).join("&");
903
+ url += (url.includes("?") ? "&" : "?") + qs;
904
+ }
905
+ parts.push(shellQuote(url));
906
+ for (const h of normalizeKeyValues(config.headers).filter((h2) => h2.enabled !== false && h2.key)) {
907
+ parts.push(`-H ${shellQuote(`${h.key}: ${h.value}`)}`);
908
+ }
909
+ const auth = config.auth;
910
+ if (auth?.type === "bearer" && auth.token) {
911
+ parts.push(`-H ${shellQuote(`Authorization: Bearer ${auth.token}`)}`);
912
+ } else if (auth?.type === "basic" && auth.username) {
913
+ parts.push(`-u ${shellQuote(`${auth.username}:${auth.password ?? ""}`)}`);
914
+ } else if (auth?.type === "apikey" && auth.apiKeyName && auth.apiKeyValue) {
915
+ if ((auth.apiKeyLocation ?? "header") === "header") {
916
+ parts.push(`-H ${shellQuote(`${auth.apiKeyName}: ${auth.apiKeyValue}`)}`);
917
+ }
918
+ }
919
+ if (config.apiType === "graphql") {
920
+ const payload = JSON.stringify({
921
+ query: config.graphqlQuery ?? "",
922
+ variables: typeof config.graphqlVariables === "string" ? config.graphqlVariables : config.graphqlVariables ?? {}
923
+ });
924
+ parts.push(`-H ${shellQuote("Content-Type: application/json")}`);
925
+ parts.push(`-d ${shellQuote(payload)}`);
926
+ } else if (config.bodyType === "form-data") {
927
+ for (const f of normalizeKeyValues(config.formData).filter(
928
+ (f2) => f2.enabled !== false && f2.key
929
+ )) {
930
+ parts.push(`-F ${shellQuote(`${f.key}=${f.value}`)}`);
931
+ }
932
+ } else if (config.bodyType && config.bodyType !== "none" && config.body != null) {
933
+ const raw = typeof config.body === "string" ? config.body : JSON.stringify(config.body);
934
+ if (raw) {
935
+ if (config.bodyType === "json") {
936
+ parts.push(`-H ${shellQuote("Content-Type: application/json")}`);
937
+ }
938
+ parts.push(`-d ${shellQuote(raw)}`);
939
+ }
940
+ }
941
+ if (config.followRedirects !== false) parts.push("-L");
942
+ return parts.join(" ");
943
+ }
944
+ function inferJsonSchema(value, depth = 0) {
945
+ if (value === null || value === void 0) return { type: "null" };
946
+ if (Array.isArray(value)) {
947
+ if (!value.length || depth > 6) return { type: "array" };
948
+ return { type: "array", items: inferJsonSchema(value[0], depth + 1) };
949
+ }
950
+ if (typeof value === "object") {
951
+ if (depth > 6) return { type: "object" };
952
+ const properties = {};
953
+ for (const [k, v] of Object.entries(value)) {
954
+ properties[k] = inferJsonSchema(v, depth + 1);
955
+ }
956
+ return { type: "object", properties };
957
+ }
958
+ return { type: typeof value };
959
+ }
960
+ function countSchemaPaths(schema, depth = 0) {
961
+ if (!schema || typeof schema !== "object" || depth > 8) return 0;
962
+ const s = schema;
963
+ let count = 0;
964
+ if (s.type === "object" && s.properties) {
965
+ for (const child of Object.values(s.properties)) {
966
+ count += 1 + countSchemaPaths(child, depth + 1);
967
+ }
968
+ } else if (s.type === "array" && s.items) {
969
+ count += countSchemaPaths(s.items, depth + 1);
970
+ }
971
+ return count;
972
+ }
973
+ function statusTone(status) {
974
+ if (status < 300) return "success";
975
+ if (status < 400) return "info";
976
+ if (status < 500) return "warning";
977
+ return "error";
978
+ }
979
+ function formatBytes(size) {
980
+ return size < 1024 ? `${size} B` : `${(size / 1024).toFixed(1)} KB`;
981
+ }
982
+
983
+ // src/workflow/components/HttpActionPanel/HttpActionPanel.tsx
984
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
985
+ function toPairs(rows) {
986
+ return rows.map((r) => ({
987
+ key: r.key,
988
+ value: r.value,
989
+ enabled: r.enabled !== false,
990
+ description: r.description
991
+ }));
992
+ }
993
+ function textOf(raw) {
994
+ if (typeof raw === "string") return raw;
995
+ if (raw == null) return "";
996
+ try {
997
+ return JSON.stringify(raw, null, 2);
998
+ } catch {
999
+ return "";
1000
+ }
1001
+ }
1002
+ function HttpActionPanel({
1003
+ value,
1004
+ onChange,
1005
+ disabled = false,
1006
+ connections,
1007
+ connectionsLoading = false,
1008
+ onSendPreview,
1009
+ className
1010
+ }) {
1011
+ const uid = useId();
1012
+ const cfgRef = useRef4({
1013
+ ...HTTP_ACTION_DEFAULTS,
1014
+ ...value,
1015
+ queryParams: normalizeKeyValues(value?.queryParams),
1016
+ headers: normalizeKeyValues(value?.headers),
1017
+ formData: normalizeKeyValues(value?.formData),
1018
+ auth: normalizeAuth(value?.auth),
1019
+ retry: {
1020
+ ...HTTP_ACTION_DEFAULTS.retry,
1021
+ ...value?.retry
1022
+ },
1023
+ pagination: {
1024
+ ...HTTP_ACTION_DEFAULTS.pagination,
1025
+ ...value?.pagination
1026
+ }
1027
+ });
1028
+ const [, force] = useState4(0);
1029
+ const emit = useCallback4(
1030
+ (patch) => {
1031
+ cfgRef.current = { ...cfgRef.current, ...patch };
1032
+ force((n) => n + 1);
1033
+ onChange?.(cfgRef.current);
1034
+ },
1035
+ [onChange]
1036
+ );
1037
+ const cfg = cfgRef.current;
1038
+ const connectionId = cfg.connectionId ?? "";
1039
+ const selectedConnection = connections?.find((c) => c.id === connectionId) ?? null;
1040
+ const endpoints = selectedConnection?.endpoints ?? [];
1041
+ const method = cfg.method ?? "GET";
1042
+ const url = cfg.url ?? "";
1043
+ const baseUrl = cfg.baseUrl ?? "";
1044
+ const fullUrl = connectionId ? url : effectiveUrl(baseUrl, url);
1045
+ const queryParams = normalizeKeyValues(cfg.queryParams);
1046
+ const headers = normalizeKeyValues(cfg.headers);
1047
+ const formData = normalizeKeyValues(cfg.formData);
1048
+ const auth = normalizeAuth(cfg.auth);
1049
+ const retry = cfg.retry ?? HTTP_ACTION_DEFAULTS.retry;
1050
+ const pagination = cfg.pagination ?? { type: "none" };
1051
+ const responseType = cfg.responseType ?? "json";
1052
+ const [bodyText, setBodyText] = useState4(() => textOf(cfg.body));
1053
+ const [bodyError, setBodyError] = useState4();
1054
+ const [gqlVarsText, setGqlVarsText] = useState4(() => textOf(cfg.graphqlVariables));
1055
+ const [gqlVarsError, setGqlVarsError] = useState4();
1056
+ const [retryOnText, setRetryOnText] = useState4(() => (retry?.retryOn ?? []).join(", "));
1057
+ const [expectedCtText, setExpectedCtText] = useState4(
1058
+ () => (cfg.expectedContentTypes ?? []).join(", ")
1059
+ );
1060
+ const [urlError, setUrlError] = useState4();
1061
+ const [extractRows, setExtractRows] = useState4(
1062
+ () => Object.entries(cfg.extract ?? {}).map(([key, v]) => ({ key, value: v, enabled: true }))
1063
+ );
1064
+ const [curlOpen, setCurlOpen] = useState4(false);
1065
+ const [curlText, setCurlText] = useState4("");
1066
+ const [curlError, setCurlError] = useState4();
1067
+ const [copiedCurl, setCopiedCurl] = useState4(false);
1068
+ const [copiedResult, setCopiedResult] = useState4(false);
1069
+ const applyCurl = () => {
1070
+ const patch = parseCurl(curlText);
1071
+ if (!patch) {
1072
+ setCurlError(
1073
+ "That doesn't look like a cURL command \u2014 it should start with `curl` and include a URL."
1074
+ );
1075
+ return;
1076
+ }
1077
+ setCurlError(void 0);
1078
+ setCurlText("");
1079
+ setCurlOpen(false);
1080
+ setBodyText(textOf(patch.body));
1081
+ setBodyError(void 0);
1082
+ emit({ ...patch, connectionId: void 0, baseUrl: void 0 });
1083
+ };
1084
+ const copyCurl = async () => {
1085
+ try {
1086
+ await navigator.clipboard?.writeText(buildCurl(cfg));
1087
+ setCopiedCurl(true);
1088
+ setTimeout(() => setCopiedCurl(false), 1600);
1089
+ } catch {
1090
+ }
1091
+ };
1092
+ const copyResult = async () => {
1093
+ if (preview.phase !== "success") return;
1094
+ const r = preview.response;
1095
+ const bundle = {
1096
+ request: {
1097
+ method: cfg.apiType === "graphql" ? "POST" : method,
1098
+ url: connectionId ? `${selectedConnection?.name ?? connectionId} \xB7 ${url}` : fullUrl
1099
+ },
1100
+ response: {
1101
+ status: r.status,
1102
+ statusText: r.statusText,
1103
+ ok: r.ok,
1104
+ durationMs: r.duration,
1105
+ sizeBytes: r.size,
1106
+ headers: r.headers,
1107
+ body: r.body
1108
+ }
1109
+ };
1110
+ try {
1111
+ await navigator.clipboard?.writeText(JSON.stringify(bundle, null, 2));
1112
+ setCopiedResult(true);
1113
+ setTimeout(() => setCopiedResult(false), 1600);
1114
+ } catch {
1115
+ }
1116
+ };
1117
+ const validateUrl = (nextUrl, nextBase, hasConnection) => {
1118
+ if (!nextUrl && !nextBase && !hasConnection) {
1119
+ setUrlError("URL is required");
1120
+ return;
1121
+ }
1122
+ if (!nextUrl || hasConnection || nextBase || nextUrl.includes("{{")) {
1123
+ setUrlError(void 0);
1124
+ return;
1125
+ }
1126
+ try {
1127
+ new URL(nextUrl);
1128
+ setUrlError(void 0);
1129
+ } catch {
1130
+ setUrlError("URL does not look valid");
1131
+ }
1132
+ };
1133
+ const bodyMode = cfg.apiType === "graphql" ? "graphql" : cfg.bodyType ?? "json";
1134
+ const gqlVarCount = useMemo2(
1135
+ () => countGraphqlVariables(cfg.graphqlQuery ?? ""),
1136
+ [cfg.graphqlQuery]
1137
+ );
1138
+ const handleBodyMode = (next) => {
1139
+ if (next === "graphql") {
1140
+ emit(method === "GET" ? { apiType: "graphql", method: "POST" } : { apiType: "graphql" });
1141
+ return;
1142
+ }
1143
+ emit({ apiType: "rest", bodyType: next });
1144
+ };
1145
+ const [preview, setPreview] = useState4({ phase: "idle" });
1146
+ const [schemaInfo, setSchemaInfo] = useState4(
1147
+ null
1148
+ );
1149
+ const lastSchemaKey = useRef4("");
1150
+ const inferAndEmitSchema = useCallback4(
1151
+ (response, forceRefresh = false) => {
1152
+ if (responseType === "binary") return;
1153
+ const snapshot = {
1154
+ status: response.status,
1155
+ statusText: response.statusText,
1156
+ ok: response.ok,
1157
+ headers: response.headers,
1158
+ body: response.body,
1159
+ duration: response.duration,
1160
+ attempts: 1,
1161
+ extracted: {}
1162
+ };
1163
+ const inferred = inferJsonSchema(snapshot);
1164
+ const key = JSON.stringify(inferred);
1165
+ if (!forceRefresh && key === lastSchemaKey.current) return;
1166
+ lastSchemaKey.current = key;
1167
+ emit({ _outputSchema: inferred });
1168
+ const bodySchema = inferred.properties?.body;
1169
+ const topKeys = Object.keys(bodySchema?.properties ?? inferred.properties ?? {});
1170
+ setSchemaInfo({ pathCount: countSchemaPaths(inferred), topKeys });
1171
+ },
1172
+ [emit, responseType]
1173
+ );
1174
+ const sendPreview = async () => {
1175
+ if (!onSendPreview) return;
1176
+ setPreview({ phase: "loading" });
1177
+ try {
1178
+ const response = await onSendPreview({
1179
+ method: cfg.apiType === "graphql" ? "POST" : method,
1180
+ url: connectionId ? url : fullUrl,
1181
+ connectionId: connectionId || void 0,
1182
+ headers,
1183
+ queryParams,
1184
+ bodyType: cfg.bodyType ?? "json",
1185
+ body: bodyText,
1186
+ formData,
1187
+ graphqlQuery: cfg.apiType === "graphql" ? cfg.graphqlQuery ?? "" : void 0,
1188
+ graphqlVariables: cfg.apiType === "graphql" ? gqlVarsText : void 0,
1189
+ auth,
1190
+ timeout: cfg.timeout ?? 3e4
1191
+ });
1192
+ setPreview({ phase: "success", response });
1193
+ inferAndEmitSchema(response);
1194
+ } catch (err) {
1195
+ setPreview({
1196
+ phase: "error",
1197
+ message: err instanceof Error ? err.message : "Request failed"
1198
+ });
1199
+ }
1200
+ };
1201
+ const previewUrlOk = Boolean(fullUrl) && !fullUrl.includes("{{");
1202
+ const canSend = Boolean(onSendPreview) && previewUrlOk && preview.phase !== "loading" && !disabled;
1203
+ const paramCount = queryParams.filter((r) => r.enabled !== false && r.key).length;
1204
+ const headerCount = headers.filter((r) => r.enabled !== false && r.key).length;
1205
+ const extractCount = extractRows.filter((r) => r.key).length;
1206
+ const advancedSummary = [];
1207
+ if ((cfg.timeout ?? 3e4) !== 3e4) advancedSummary.push(`${(cfg.timeout ?? 0) / 1e3}s`);
1208
+ if ((retry?.maxAttempts ?? 1) > 1) advancedSummary.push(`retry \xD7${retry?.maxAttempts}`);
1209
+ if (pagination.type !== "none") advancedSummary.push(pagination.type.replace("_", " "));
1210
+ if (extractCount > 0) advancedSummary.push(`${extractCount} extracted`);
1211
+ const kvTab = (rows, key, desc, keyPlaceholder) => /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__tab", children: [
1212
+ /* @__PURE__ */ jsx2("p", { className: "ods-http-panel__desc", children: desc }),
1213
+ /* @__PURE__ */ jsx2(
1214
+ KeyValueEditor,
1215
+ {
1216
+ pairs: toPairs(rows),
1217
+ onChange: (pairs) => emit({ [key]: serializeKeyValues(pairs) }),
1218
+ rowToggle: true,
1219
+ showDescription: true,
1220
+ keyPlaceholder,
1221
+ valuePlaceholder: "value or {{var}}",
1222
+ emptyLabel: "No entries yet \u2014 click Add to begin.",
1223
+ addLabel: "Add",
1224
+ size: "sm",
1225
+ disabled
1226
+ }
1227
+ )
1228
+ ] });
1229
+ const paramsTab = kvTab(
1230
+ queryParams,
1231
+ "queryParams",
1232
+ /* @__PURE__ */ jsxs2(Fragment2, { children: [
1233
+ "Query parameters appended to the URL. Supports ",
1234
+ /* @__PURE__ */ jsx2("code", { children: "{{variable}}" }),
1235
+ " interpolation."
1236
+ ] }),
1237
+ "param name"
1238
+ );
1239
+ const headersTab = kvTab(
1240
+ headers,
1241
+ "headers",
1242
+ /* @__PURE__ */ jsxs2(Fragment2, { children: [
1243
+ "Request headers. Auth headers are injected automatically from the Auth tab. Supports",
1244
+ " ",
1245
+ /* @__PURE__ */ jsx2("code", { children: "{{variable}}" }),
1246
+ " interpolation."
1247
+ ] }),
1248
+ "Header-Name"
1249
+ );
1250
+ const bodyTab = /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__tab", children: [
1251
+ /* @__PURE__ */ jsx2(
1252
+ SegmentedControl,
1253
+ {
1254
+ size: "sm",
1255
+ "aria-label": "Body type",
1256
+ options: [
1257
+ { value: "none", label: "None" },
1258
+ { value: "json", label: "JSON" },
1259
+ { value: "graphql", label: "GraphQL" },
1260
+ { value: "raw", label: "Raw" },
1261
+ { value: "form-data", label: "Form" },
1262
+ { value: "xml", label: "XML" }
1263
+ ],
1264
+ value: bodyMode,
1265
+ onChange: handleBodyMode
1266
+ }
1267
+ ),
1268
+ bodyMode === "none" && /* @__PURE__ */ jsx2("p", { className: "ods-http-panel__empty", children: "No request body will be sent." }),
1269
+ (bodyMode === "json" || bodyMode === "raw" || bodyMode === "xml") && /* @__PURE__ */ jsxs2(Fragment2, { children: [
1270
+ /* @__PURE__ */ jsx2(
1271
+ CodeEditor,
1272
+ {
1273
+ value: bodyText,
1274
+ language: bodyMode === "json" ? "json" : "plain",
1275
+ onChange: (next) => {
1276
+ setBodyText(next);
1277
+ if (bodyMode === "json" && next.trim()) {
1278
+ try {
1279
+ emit({ body: JSON.parse(next) });
1280
+ setBodyError(void 0);
1281
+ } catch {
1282
+ setBodyError("Invalid JSON");
1283
+ emit({ body: next });
1284
+ }
1285
+ } else {
1286
+ setBodyError(void 0);
1287
+ emit({ body: next || void 0 });
1288
+ }
1289
+ },
1290
+ readOnly: disabled,
1291
+ minHeight: 180,
1292
+ ariaLabel: "Request body"
1293
+ }
1294
+ ),
1295
+ bodyError && /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__error", children: [
1296
+ "\u26A0 ",
1297
+ bodyError
1298
+ ] }),
1299
+ /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__desc", children: [
1300
+ "Supports ",
1301
+ /* @__PURE__ */ jsx2("code", { children: "{{variable}}" }),
1302
+ " interpolation."
1303
+ ] })
1304
+ ] }),
1305
+ bodyMode === "graphql" && /* @__PURE__ */ jsxs2(Fragment2, { children: [
1306
+ /* @__PURE__ */ jsx2(
1307
+ CodeEditor,
1308
+ {
1309
+ value: cfg.graphqlQuery ?? "",
1310
+ language: "plain",
1311
+ onChange: (next) => emit({ graphqlQuery: next }),
1312
+ readOnly: disabled,
1313
+ minHeight: 160,
1314
+ placeholder: "query ($id: ID!) {\n node(id: $id) { id }\n}",
1315
+ ariaLabel: "GraphQL query"
1316
+ }
1317
+ ),
1318
+ /* @__PURE__ */ jsxs2(
1319
+ Disclosure,
1320
+ {
1321
+ size: "sm",
1322
+ title: "Variables",
1323
+ defaultOpen: Boolean(gqlVarsText.trim()) || gqlVarCount > 0,
1324
+ trailing: gqlVarCount > 0 ? /* @__PURE__ */ jsx2(Badge, { size: "sm", variant: "neutral", children: gqlVarCount }) : void 0,
1325
+ children: [
1326
+ /* @__PURE__ */ jsx2(
1327
+ CodeEditor,
1328
+ {
1329
+ value: gqlVarsText,
1330
+ language: "json",
1331
+ onChange: (next) => {
1332
+ setGqlVarsText(next);
1333
+ if (!next.trim()) {
1334
+ setGqlVarsError(void 0);
1335
+ emit({ graphqlVariables: {} });
1336
+ return;
1337
+ }
1338
+ try {
1339
+ emit({ graphqlVariables: JSON.parse(next) });
1340
+ setGqlVarsError(void 0);
1341
+ } catch {
1342
+ setGqlVarsError("Invalid JSON");
1343
+ }
1344
+ },
1345
+ readOnly: disabled,
1346
+ minHeight: 100,
1347
+ ariaLabel: "GraphQL variables (JSON)"
1348
+ }
1349
+ ),
1350
+ gqlVarsError && /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__error", children: [
1351
+ "\u26A0 ",
1352
+ gqlVarsError
1353
+ ] })
1354
+ ]
1355
+ }
1356
+ )
1357
+ ] }),
1358
+ bodyMode === "form-data" && /* @__PURE__ */ jsxs2(Fragment2, { children: [
1359
+ /* @__PURE__ */ jsx2("p", { className: "ods-http-panel__desc", children: "Multipart form fields. Content-Type is set automatically with the boundary." }),
1360
+ /* @__PURE__ */ jsx2(
1361
+ KeyValueEditor,
1362
+ {
1363
+ pairs: toPairs(formData),
1364
+ onChange: (pairs) => emit({ formData: serializeKeyValues(pairs), bodyType: "form-data" }),
1365
+ rowToggle: true,
1366
+ keyPlaceholder: "field name",
1367
+ valuePlaceholder: "value or {{var}}",
1368
+ emptyLabel: "No fields yet \u2014 click Add to begin.",
1369
+ addLabel: "Add",
1370
+ size: "sm",
1371
+ disabled
1372
+ }
1373
+ )
1374
+ ] })
1375
+ ] });
1376
+ const authTab = /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__tab", children: [
1377
+ connectionId ? /* @__PURE__ */ jsxs2(Banner, { variant: "success", appearance: "subtle", size: "sm", children: [
1378
+ "Authentication is inherited from ",
1379
+ /* @__PURE__ */ jsx2("strong", { children: selectedConnection?.name }),
1380
+ " and refreshed automatically. Choose a type below only to override it for this step."
1381
+ ] }) : /* @__PURE__ */ jsx2(Banner, { variant: "info", appearance: "subtle", size: "sm", children: "For OAuth 2.0 APIs that need a login screen, create an API connection and select it as the Source \u2014 the token is obtained once and refreshed automatically. Inline auth here is for non-interactive credentials only." }),
1382
+ /* @__PURE__ */ jsx2(
1383
+ Select,
1384
+ {
1385
+ id: `${uid}-auth-type`,
1386
+ label: connectionId ? "Override authentication" : "Authentication",
1387
+ value: auth.type,
1388
+ onChange: (next) => emit({ auth: { ...auth, type: next } }),
1389
+ disabled,
1390
+ options: [
1391
+ { value: "none", label: connectionId ? "Inherit from connection" : "No auth" },
1392
+ { value: "basic", label: "Basic auth (username + password)" },
1393
+ { value: "bearer", label: "Bearer token" },
1394
+ { value: "apikey", label: "API key" }
1395
+ ]
1396
+ }
1397
+ ),
1398
+ auth.type === "basic" && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__grid", children: [
1399
+ /* @__PURE__ */ jsx2(
1400
+ Input,
1401
+ {
1402
+ id: `${uid}-auth-user`,
1403
+ label: "Username",
1404
+ value: auth.username ?? "",
1405
+ placeholder: "username or {{var}}",
1406
+ onChange: (e) => emit({ auth: { ...auth, username: e.target.value } }),
1407
+ disabled
1408
+ }
1409
+ ),
1410
+ /* @__PURE__ */ jsx2(
1411
+ PasswordInput,
1412
+ {
1413
+ id: `${uid}-auth-pass`,
1414
+ label: "Password",
1415
+ value: auth.password ?? "",
1416
+ placeholder: "password or {{var}}",
1417
+ onChange: (next) => emit({ auth: { ...auth, password: next } }),
1418
+ disabled
1419
+ }
1420
+ )
1421
+ ] }),
1422
+ auth.type === "bearer" && /* @__PURE__ */ jsx2(
1423
+ PasswordInput,
1424
+ {
1425
+ id: `${uid}-auth-token`,
1426
+ label: "Token",
1427
+ value: auth.token ?? "",
1428
+ placeholder: "your-token or {{step.token}}",
1429
+ onChange: (next) => emit({ auth: { ...auth, token: next } }),
1430
+ disabled
1431
+ }
1432
+ ),
1433
+ auth.type === "apikey" && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__grid", children: [
1434
+ /* @__PURE__ */ jsx2(
1435
+ Input,
1436
+ {
1437
+ id: `${uid}-auth-keyname`,
1438
+ label: "Key name",
1439
+ value: auth.apiKeyName ?? "",
1440
+ placeholder: "X-API-Key",
1441
+ onChange: (e) => emit({ auth: { ...auth, apiKeyName: e.target.value } }),
1442
+ disabled
1443
+ }
1444
+ ),
1445
+ /* @__PURE__ */ jsx2(
1446
+ PasswordInput,
1447
+ {
1448
+ id: `${uid}-auth-keyval`,
1449
+ label: "Key value",
1450
+ value: auth.apiKeyValue ?? "",
1451
+ placeholder: "your-api-key or {{var}}",
1452
+ onChange: (next) => emit({ auth: { ...auth, apiKeyValue: next } }),
1453
+ disabled
1454
+ }
1455
+ ),
1456
+ /* @__PURE__ */ jsx2(
1457
+ Select,
1458
+ {
1459
+ id: `${uid}-auth-keyloc`,
1460
+ label: "Send in",
1461
+ value: auth.apiKeyLocation ?? "header",
1462
+ onChange: (next) => emit({ auth: { ...auth, apiKeyLocation: next } }),
1463
+ disabled,
1464
+ options: [
1465
+ { value: "header", label: "Request header" },
1466
+ { value: "query", label: "Query parameter" }
1467
+ ]
1468
+ }
1469
+ )
1470
+ ] }),
1471
+ auth.type === "none" && /* @__PURE__ */ jsx2("p", { className: "ods-http-panel__empty", children: connectionId ? "This step uses the connection's authentication." : "No authentication will be added to this request." })
1472
+ ] });
1473
+ const responseTab = /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__tab", children: [
1474
+ /* @__PURE__ */ jsx2(
1475
+ SegmentedControl,
1476
+ {
1477
+ size: "sm",
1478
+ "aria-label": "Response type",
1479
+ options: [
1480
+ { value: "json", label: "JSON" },
1481
+ { value: "text", label: "Text" },
1482
+ { value: "binary", label: "Binary" }
1483
+ ],
1484
+ value: responseType,
1485
+ onChange: (next) => emit({ responseType: next })
1486
+ }
1487
+ ),
1488
+ /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__desc", children: [
1489
+ responseType === "json" && "Tries to parse the response body as JSON; falls back to raw text on parse failure.",
1490
+ responseType === "text" && "Returns the raw response body as a string. No JSON parsing.",
1491
+ responseType === "binary" && /* @__PURE__ */ jsxs2(Fragment2, { children: [
1492
+ "Returns the response as bytes with ",
1493
+ /* @__PURE__ */ jsx2("code", { children: "fileName" }),
1494
+ ", ",
1495
+ /* @__PURE__ */ jsx2("code", { children: "contentType" }),
1496
+ " and",
1497
+ " ",
1498
+ /* @__PURE__ */ jsx2("code", { children: "size" }),
1499
+ " on the step output \u2014 for downloads feeding file actions. Pagination is not compatible with binary responses."
1500
+ ] })
1501
+ ] }),
1502
+ /* @__PURE__ */ jsx2(
1503
+ Input,
1504
+ {
1505
+ id: `${uid}-expected-ct`,
1506
+ label: "Expected content-types (optional)",
1507
+ value: expectedCtText,
1508
+ placeholder: "application/pdf, application/json",
1509
+ helperText: "Comma-separated. A warning is logged when the response Content-Type matches none of these.",
1510
+ onChange: (e) => {
1511
+ setExpectedCtText(e.target.value);
1512
+ const parts = e.target.value.split(",").map((s) => s.trim()).filter(Boolean);
1513
+ emit({ expectedContentTypes: parts.length ? parts : void 0 });
1514
+ },
1515
+ disabled
1516
+ }
1517
+ ),
1518
+ /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__schema", children: [
1519
+ /* @__PURE__ */ jsx2("span", { className: "ods-http-panel__schema-label", children: "Data stream schema" }),
1520
+ schemaInfo ? /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__desc", children: [
1521
+ /* @__PURE__ */ jsxs2(Badge, { size: "sm", variant: "success", children: [
1522
+ schemaInfo.pathCount,
1523
+ " paths"
1524
+ ] }),
1525
+ " ",
1526
+ "Inferred from the last test send. Top-level keys:",
1527
+ " ",
1528
+ /* @__PURE__ */ jsx2("code", { children: schemaInfo.topKeys.join(", ") }),
1529
+ ". Downstream binding (Field Mapper, Transform, ForEach) sees this shape immediately; Save persists it."
1530
+ ] }) : /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__desc", children: [
1531
+ "No schema yet \u2014 hit ",
1532
+ /* @__PURE__ */ jsx2("strong", { children: "Send" }),
1533
+ " in the request bar. On success the response shape is inferred so downstream steps bind against real field names."
1534
+ ] }),
1535
+ /* @__PURE__ */ jsx2(
1536
+ Button,
1537
+ {
1538
+ variant: "ghost",
1539
+ size: "sm",
1540
+ disabled: preview.phase !== "success" || responseType === "binary" || disabled,
1541
+ onClick: () => {
1542
+ if (preview.phase === "success") inferAndEmitSchema(preview.response, true);
1543
+ },
1544
+ children: "Refresh schema from last send"
1545
+ }
1546
+ )
1547
+ ] })
1548
+ ] });
1549
+ const tabItems = [
1550
+ {
1551
+ value: "params",
1552
+ label: paramCount ? `Params \xB7 ${paramCount}` : "Params",
1553
+ icon: /* @__PURE__ */ jsx2(ListIcon, { size: "sm" }),
1554
+ children: paramsTab
1555
+ },
1556
+ {
1557
+ value: "headers",
1558
+ label: headerCount ? `Headers \xB7 ${headerCount}` : "Headers",
1559
+ icon: /* @__PURE__ */ jsx2(TagIcon, { size: "sm" }),
1560
+ children: headersTab
1561
+ },
1562
+ {
1563
+ value: "body",
1564
+ label: bodyMode === "none" ? "Body" : `Body \xB7 ${bodyMode === "form-data" ? "form" : bodyMode}`,
1565
+ icon: /* @__PURE__ */ jsx2(CodeIcon, { size: "sm" }),
1566
+ children: bodyTab
1567
+ },
1568
+ {
1569
+ value: "auth",
1570
+ label: auth.type === "none" ? "Auth" : `Auth \xB7 ${auth.type}`,
1571
+ icon: /* @__PURE__ */ jsx2(LockedIcon, { size: "sm" }),
1572
+ children: authTab
1573
+ },
1574
+ {
1575
+ value: "response",
1576
+ label: responseType === "json" ? "Response" : `Response \xB7 ${responseType}`,
1577
+ icon: /* @__PURE__ */ jsx2(DataViewAltIcon, { size: "sm" }),
1578
+ children: responseTab
1579
+ }
1580
+ ];
1581
+ return /* @__PURE__ */ jsxs2("div", { className: cn("ods-http-panel", className), children: [
1582
+ connections && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__source", children: [
1583
+ /* @__PURE__ */ jsx2(
1584
+ Select,
1585
+ {
1586
+ id: `${uid}-connection`,
1587
+ label: "Source",
1588
+ placeholder: connectionsLoading ? "Loading\u2026" : "No connection (manual config)",
1589
+ options: connections.map((c) => ({ value: c.id, label: c.name, icon: c.icon })),
1590
+ value: connectionId,
1591
+ onChange: (next) => emit({ connectionId: next || void 0 }),
1592
+ disabled: disabled || connectionsLoading,
1593
+ helperText: connectionId ? `Base URL and auth are inherited from "${selectedConnection?.name}" at runtime.` : "Select a saved API connection to inherit base URL and auth, or configure manually."
1594
+ }
1595
+ ),
1596
+ connectionId && endpoints.length > 0 && /* @__PURE__ */ jsx2(
1597
+ Combobox,
1598
+ {
1599
+ ariaLabel: "Endpoint",
1600
+ placeholder: `Search ${endpoints.length} discovered endpoints\u2026`,
1601
+ value: url,
1602
+ creatable: true,
1603
+ options: endpoints.map((e) => ({
1604
+ value: e.path,
1605
+ label: `${e.method} ${e.path}`,
1606
+ description: e.summary
1607
+ })),
1608
+ onChange: (nextPath) => {
1609
+ const match = endpoints.find((e) => e.path === nextPath);
1610
+ validateUrl(nextPath, baseUrl, true);
1611
+ emit(
1612
+ match && HTTP_METHODS.includes(match.method.toUpperCase()) ? { url: nextPath, method: match.method.toUpperCase() } : { url: nextPath }
1613
+ );
1614
+ }
1615
+ }
1616
+ )
1617
+ ] }),
1618
+ /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__bar", children: [
1619
+ /* @__PURE__ */ jsx2(
1620
+ Select,
1621
+ {
1622
+ id: `${uid}-method`,
1623
+ "aria-label": "HTTP method",
1624
+ className: cn(
1625
+ "ods-http-panel__method",
1626
+ `ods-http-panel__method--${method.toLowerCase()}`
1627
+ ),
1628
+ value: method,
1629
+ onChange: (next) => emit({ method: next }),
1630
+ disabled,
1631
+ options: HTTP_METHODS.map((m) => ({ value: m, label: m }))
1632
+ }
1633
+ ),
1634
+ /* @__PURE__ */ jsx2(
1635
+ Input,
1636
+ {
1637
+ id: `${uid}-url`,
1638
+ "aria-label": connectionId ? "Path" : "URL",
1639
+ "data-fx-droppable": "true",
1640
+ className: "ods-http-panel__url",
1641
+ value: url,
1642
+ placeholder: connectionId ? "/v1/users" : "https://api.example.com/v1/users or {{var}}",
1643
+ error: Boolean(urlError),
1644
+ errorMessage: urlError,
1645
+ onChange: (e) => {
1646
+ validateUrl(e.target.value, baseUrl, Boolean(connectionId));
1647
+ emit({ url: e.target.value });
1648
+ },
1649
+ disabled
1650
+ }
1651
+ ),
1652
+ onSendPreview && /* @__PURE__ */ jsx2(
1653
+ Button,
1654
+ {
1655
+ variant: "primary",
1656
+ size: "md",
1657
+ leftIcon: preview.phase === "loading" ? void 0 : /* @__PURE__ */ jsx2(PlayIcon, { size: "sm" }),
1658
+ onClick: sendPreview,
1659
+ disabled: !canSend,
1660
+ children: preview.phase === "loading" ? "Sending\u2026" : "Send"
1661
+ }
1662
+ )
1663
+ ] }),
1664
+ !connectionId && baseUrl && /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__effective", children: [
1665
+ /* @__PURE__ */ jsx2("span", { children: "Effective URL:" }),
1666
+ " ",
1667
+ /* @__PURE__ */ jsx2("code", { children: fullUrl || "\u2014" })
1668
+ ] }),
1669
+ fullUrl.includes("{{") && /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__desc", children: [
1670
+ "\u26A0 URL contains ",
1671
+ /* @__PURE__ */ jsx2("code", { children: "{{variables}}" }),
1672
+ " \u2014 they resolve at run time; testing needs literal values."
1673
+ ] }),
1674
+ /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__tools", children: [
1675
+ /* @__PURE__ */ jsxs2("span", { className: "ods-http-panel__hint", children: [
1676
+ "Use ",
1677
+ /* @__PURE__ */ jsx2("code", { children: "{{stepName.fieldPath}}" }),
1678
+ " to insert data from upstream steps."
1679
+ ] }),
1680
+ /* @__PURE__ */ jsxs2("span", { className: "ods-http-panel__tools-actions", children: [
1681
+ /* @__PURE__ */ jsx2(Button, { variant: "ghost", size: "sm", onClick: () => setCurlOpen((o) => !o), children: "Import cURL" }),
1682
+ /* @__PURE__ */ jsx2(
1683
+ Button,
1684
+ {
1685
+ variant: "ghost",
1686
+ size: "sm",
1687
+ className: cn(copiedCurl && "ods-http-panel__copy-done"),
1688
+ leftIcon: copiedCurl ? /* @__PURE__ */ jsx2(CheckmarkIcon, { size: "sm" }) : /* @__PURE__ */ jsx2(CopyIcon, { size: "sm" }),
1689
+ onClick: copyCurl,
1690
+ children: copiedCurl ? "Copied" : "Copy as cURL"
1691
+ }
1692
+ )
1693
+ ] })
1694
+ ] }),
1695
+ curlOpen && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__curl", children: [
1696
+ /* @__PURE__ */ jsx2(
1697
+ CodeEditor,
1698
+ {
1699
+ value: curlText,
1700
+ language: "plain",
1701
+ onChange: setCurlText,
1702
+ minHeight: 90,
1703
+ showLineNumbers: false,
1704
+ placeholder: "curl -X POST 'https://api.example.com/v1/users' -H 'Authorization: Bearer \u2026' -d '{\u2026}'",
1705
+ ariaLabel: "cURL command"
1706
+ }
1707
+ ),
1708
+ curlError && /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__error", children: [
1709
+ "\u26A0 ",
1710
+ curlError
1711
+ ] }),
1712
+ /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__curl-actions", children: [
1713
+ /* @__PURE__ */ jsx2(Button, { variant: "secondary", size: "sm", onClick: () => setCurlOpen(false), children: "Cancel" }),
1714
+ /* @__PURE__ */ jsx2(Button, { variant: "primary", size: "sm", onClick: applyCurl, disabled: !curlText.trim(), children: "Apply to request" })
1715
+ ] })
1716
+ ] }),
1717
+ /* @__PURE__ */ jsx2(Tabs, { items: tabItems, defaultValue: "params", className: "ods-http-panel__tabs" }),
1718
+ /* @__PURE__ */ jsxs2(
1719
+ Disclosure,
1720
+ {
1721
+ size: "sm",
1722
+ icon: /* @__PURE__ */ jsx2(GlobeIcon, { size: "sm" }),
1723
+ title: "Advanced options",
1724
+ description: "Base URL, timeout, retries, pagination, response extraction",
1725
+ trailing: advancedSummary.length ? /* @__PURE__ */ jsx2(Badge, { size: "sm", variant: "info", children: advancedSummary.join(" \xB7 ") }) : void 0,
1726
+ children: [
1727
+ /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__grid", children: [
1728
+ !connectionId && /* @__PURE__ */ jsx2(
1729
+ Input,
1730
+ {
1731
+ id: `${uid}-base-url`,
1732
+ label: "Base URL (optional)",
1733
+ value: baseUrl,
1734
+ placeholder: "https://api.example.com",
1735
+ helperText: "Combined with the request path to form the full URL.",
1736
+ onChange: (e) => {
1737
+ validateUrl(url, e.target.value, Boolean(connectionId));
1738
+ emit({ baseUrl: e.target.value || void 0 });
1739
+ },
1740
+ disabled
1741
+ }
1742
+ ),
1743
+ /* @__PURE__ */ jsx2(
1744
+ NumberInput,
1745
+ {
1746
+ label: "Timeout (ms)",
1747
+ helperText: "Minimum 1000 ms",
1748
+ value: cfg.timeout ?? 3e4,
1749
+ min: 1e3,
1750
+ step: 1e3,
1751
+ onChange: (next) => {
1752
+ if (!Number.isNaN(next) && next >= 1e3) emit({ timeout: next });
1753
+ },
1754
+ disabled
1755
+ }
1756
+ ),
1757
+ /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__switches", children: [
1758
+ /* @__PURE__ */ jsx2(
1759
+ Switch,
1760
+ {
1761
+ id: `${uid}-fail`,
1762
+ label: "Fail on non-2xx",
1763
+ checked: cfg.failOnError !== false,
1764
+ onChange: (next) => emit({ failOnError: next }),
1765
+ disabled,
1766
+ size: "sm"
1767
+ }
1768
+ ),
1769
+ /* @__PURE__ */ jsx2(
1770
+ Switch,
1771
+ {
1772
+ id: `${uid}-redirects`,
1773
+ label: "Follow redirects",
1774
+ checked: cfg.followRedirects !== false,
1775
+ onChange: (next) => emit({ followRedirects: next }),
1776
+ disabled,
1777
+ size: "sm"
1778
+ }
1779
+ )
1780
+ ] })
1781
+ ] }),
1782
+ /* @__PURE__ */ jsx2(
1783
+ Disclosure,
1784
+ {
1785
+ size: "sm",
1786
+ title: "Retry",
1787
+ trailing: (retry?.maxAttempts ?? 1) > 1 ? /* @__PURE__ */ jsxs2(Badge, { size: "sm", variant: "info", children: [
1788
+ retry?.maxAttempts,
1789
+ " attempts"
1790
+ ] }) : void 0,
1791
+ children: /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__grid", children: [
1792
+ /* @__PURE__ */ jsx2(
1793
+ NumberInput,
1794
+ {
1795
+ label: "Max attempts",
1796
+ helperText: "1 = no retry",
1797
+ value: retry?.maxAttempts ?? 1,
1798
+ min: 1,
1799
+ max: 10,
1800
+ onChange: (next) => {
1801
+ if (!Number.isNaN(next) && next >= 1 && retry) {
1802
+ emit({ retry: { ...retry, maxAttempts: next } });
1803
+ }
1804
+ },
1805
+ disabled
1806
+ }
1807
+ ),
1808
+ /* @__PURE__ */ jsx2(
1809
+ Input,
1810
+ {
1811
+ id: `${uid}-retry-on`,
1812
+ label: "Retry on (status codes)",
1813
+ value: retryOnText,
1814
+ placeholder: "429, 500, 502, 503, 504",
1815
+ helperText: "Comma-separated HTTP status codes",
1816
+ onChange: (e) => {
1817
+ setRetryOnText(e.target.value);
1818
+ const codes = e.target.value.split(",").map((s) => Number.parseInt(s.trim(), 10)).filter((n) => !Number.isNaN(n));
1819
+ if (retry) emit({ retry: { ...retry, retryOn: codes } });
1820
+ },
1821
+ disabled
1822
+ }
1823
+ ),
1824
+ /* @__PURE__ */ jsx2(
1825
+ NumberInput,
1826
+ {
1827
+ label: "Initial delay (ms)",
1828
+ value: retry?.initialDelayMs ?? 1e3,
1829
+ min: 100,
1830
+ step: 100,
1831
+ onChange: (next) => {
1832
+ if (!Number.isNaN(next) && retry)
1833
+ emit({ retry: { ...retry, initialDelayMs: next } });
1834
+ },
1835
+ disabled
1836
+ }
1837
+ ),
1838
+ /* @__PURE__ */ jsx2(
1839
+ NumberInput,
1840
+ {
1841
+ label: "Backoff factor",
1842
+ helperText: "Delay multiplies by this each retry",
1843
+ value: retry?.backoffFactor ?? 2,
1844
+ min: 1,
1845
+ step: 0.5,
1846
+ onChange: (next) => {
1847
+ if (!Number.isNaN(next) && retry)
1848
+ emit({ retry: { ...retry, backoffFactor: next } });
1849
+ },
1850
+ disabled
1851
+ }
1852
+ ),
1853
+ /* @__PURE__ */ jsx2(
1854
+ NumberInput,
1855
+ {
1856
+ label: "Max delay (ms)",
1857
+ value: retry?.maxDelayMs ?? 3e4,
1858
+ min: 1e3,
1859
+ step: 1e3,
1860
+ onChange: (next) => {
1861
+ if (!Number.isNaN(next) && retry) emit({ retry: { ...retry, maxDelayMs: next } });
1862
+ },
1863
+ disabled
1864
+ }
1865
+ )
1866
+ ] })
1867
+ }
1868
+ ),
1869
+ /* @__PURE__ */ jsxs2(
1870
+ Disclosure,
1871
+ {
1872
+ size: "sm",
1873
+ title: "Pagination",
1874
+ trailing: pagination.type !== "none" ? /* @__PURE__ */ jsx2(Badge, { size: "sm", variant: "success", children: pagination.type.replace("_", " ") }) : void 0,
1875
+ children: [
1876
+ /* @__PURE__ */ jsx2(
1877
+ Select,
1878
+ {
1879
+ id: `${uid}-pag-type`,
1880
+ label: "Strategy",
1881
+ value: pagination.type,
1882
+ onChange: (next) => emit({
1883
+ pagination: { ...pagination, type: next }
1884
+ }),
1885
+ disabled,
1886
+ options: [
1887
+ { value: "none", label: "None (single request)" },
1888
+ { value: "offset", label: "Offset / page number" },
1889
+ { value: "cursor", label: "Cursor-based" },
1890
+ { value: "link_header", label: 'Link header (rel="next")' },
1891
+ { value: "next_url", label: "Next URL in response body" }
1892
+ ]
1893
+ }
1894
+ ),
1895
+ pagination.type !== "none" && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__grid", children: [
1896
+ /* @__PURE__ */ jsx2(
1897
+ NumberInput,
1898
+ {
1899
+ label: "Max pages",
1900
+ helperText: "Safety cap against infinite loops",
1901
+ value: pagination.maxPages ?? 20,
1902
+ min: 1,
1903
+ onChange: (next) => {
1904
+ if (!Number.isNaN(next)) emit({ pagination: { ...pagination, maxPages: next } });
1905
+ },
1906
+ disabled
1907
+ }
1908
+ ),
1909
+ /* @__PURE__ */ jsx2(
1910
+ Input,
1911
+ {
1912
+ id: `${uid}-pag-merge`,
1913
+ label: "Merge key (dot path)",
1914
+ value: pagination.mergeKey ?? "",
1915
+ placeholder: "data.items",
1916
+ helperText: "Array to merge across pages",
1917
+ onChange: (e) => emit({ pagination: { ...pagination, mergeKey: e.target.value } }),
1918
+ disabled
1919
+ }
1920
+ ),
1921
+ (pagination.type === "offset" || pagination.type === "cursor") && /* @__PURE__ */ jsxs2(Fragment2, { children: [
1922
+ /* @__PURE__ */ jsx2(
1923
+ Input,
1924
+ {
1925
+ id: `${uid}-pag-limitp`,
1926
+ label: "Limit param",
1927
+ value: pagination.limitParam ?? "limit",
1928
+ onChange: (e) => emit({ pagination: { ...pagination, limitParam: e.target.value } }),
1929
+ disabled
1930
+ }
1931
+ ),
1932
+ /* @__PURE__ */ jsx2(
1933
+ NumberInput,
1934
+ {
1935
+ label: "Page size",
1936
+ value: pagination.limitValue ?? 100,
1937
+ min: 1,
1938
+ onChange: (next) => {
1939
+ if (!Number.isNaN(next)) {
1940
+ emit({ pagination: { ...pagination, limitValue: next } });
1941
+ }
1942
+ },
1943
+ disabled
1944
+ }
1945
+ )
1946
+ ] }),
1947
+ pagination.type === "offset" && /* @__PURE__ */ jsx2(
1948
+ Input,
1949
+ {
1950
+ id: `${uid}-pag-offset`,
1951
+ label: "Offset param",
1952
+ value: pagination.offsetParam ?? "offset",
1953
+ onChange: (e) => emit({ pagination: { ...pagination, offsetParam: e.target.value } }),
1954
+ disabled
1955
+ }
1956
+ ),
1957
+ pagination.type === "cursor" && /* @__PURE__ */ jsxs2(Fragment2, { children: [
1958
+ /* @__PURE__ */ jsx2(
1959
+ Input,
1960
+ {
1961
+ id: `${uid}-pag-cres`,
1962
+ label: "Cursor in response (dot path)",
1963
+ value: pagination.cursorResponsePath ?? "",
1964
+ placeholder: "meta.next_cursor",
1965
+ onChange: (e) => emit({ pagination: { ...pagination, cursorResponsePath: e.target.value } }),
1966
+ disabled
1967
+ }
1968
+ ),
1969
+ /* @__PURE__ */ jsx2(
1970
+ Input,
1971
+ {
1972
+ id: `${uid}-pag-creq`,
1973
+ label: "Cursor request param",
1974
+ value: pagination.cursorRequestParam ?? "cursor",
1975
+ onChange: (e) => emit({ pagination: { ...pagination, cursorRequestParam: e.target.value } }),
1976
+ disabled
1977
+ }
1978
+ )
1979
+ ] }),
1980
+ pagination.type === "next_url" && /* @__PURE__ */ jsx2(
1981
+ Input,
1982
+ {
1983
+ id: `${uid}-pag-next`,
1984
+ label: "Next URL in response (dot path)",
1985
+ value: pagination.nextUrlResponsePath ?? "",
1986
+ placeholder: "links.next",
1987
+ onChange: (e) => emit({ pagination: { ...pagination, nextUrlResponsePath: e.target.value } }),
1988
+ disabled
1989
+ }
1990
+ )
1991
+ ] })
1992
+ ]
1993
+ }
1994
+ ),
1995
+ /* @__PURE__ */ jsxs2(
1996
+ Disclosure,
1997
+ {
1998
+ size: "sm",
1999
+ title: "Response field extraction",
2000
+ trailing: extractCount > 0 ? /* @__PURE__ */ jsxs2(Badge, { size: "sm", variant: "info", children: [
2001
+ extractCount,
2002
+ " field",
2003
+ extractCount === 1 ? "" : "s"
2004
+ ] }) : void 0,
2005
+ children: [
2006
+ /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__desc", children: [
2007
+ "Extract fields from the response with dot paths \u2014 available downstream as",
2008
+ " ",
2009
+ /* @__PURE__ */ jsx2("code", { children: "{{extracted.keyName}}" }),
2010
+ "."
2011
+ ] }),
2012
+ /* @__PURE__ */ jsx2(
2013
+ KeyValueEditor,
2014
+ {
2015
+ pairs: extractRows.map((r) => ({ key: r.key, value: r.value })),
2016
+ onChange: (pairs) => {
2017
+ const rows = pairs.map((p) => ({ key: p.key, value: p.value, enabled: true }));
2018
+ setExtractRows(rows);
2019
+ const extract = {};
2020
+ for (const r of rows) if (r.key && r.value) extract[r.key] = r.value;
2021
+ emit({ extract: Object.keys(extract).length ? extract : void 0 });
2022
+ },
2023
+ keyPlaceholder: "outputKey",
2024
+ valuePlaceholder: "data.user.id",
2025
+ emptyLabel: "No extractions yet \u2014 click Add to begin.",
2026
+ addLabel: "Add",
2027
+ size: "sm",
2028
+ disabled
2029
+ }
2030
+ )
2031
+ ]
2032
+ }
2033
+ )
2034
+ ]
2035
+ }
2036
+ ),
2037
+ preview.phase !== "idle" && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__console", children: [
2038
+ /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__console-head", children: [
2039
+ /* @__PURE__ */ jsx2(
2040
+ "code",
2041
+ {
2042
+ className: cn(
2043
+ "ods-http-panel__console-method",
2044
+ `ods-http-panel__method--${method.toLowerCase()}`
2045
+ ),
2046
+ children: cfg.apiType === "graphql" ? "POST" : method
2047
+ }
2048
+ ),
2049
+ /* @__PURE__ */ jsx2("code", { className: "ods-http-panel__console-url", children: connectionId ? `${selectedConnection?.name ?? connectionId} \xB7 ${url || "\u2014"}` : fullUrl || "\u2014" }),
2050
+ preview.phase === "success" && /* @__PURE__ */ jsx2(
2051
+ Button,
2052
+ {
2053
+ variant: "ghost",
2054
+ size: "sm",
2055
+ className: cn(copiedResult && "ods-http-panel__copy-done"),
2056
+ leftIcon: copiedResult ? /* @__PURE__ */ jsx2(CheckmarkIcon, { size: "sm" }) : /* @__PURE__ */ jsx2(CopyIcon, { size: "sm" }),
2057
+ onClick: copyResult,
2058
+ children: copiedResult ? "Copied" : "Copy result"
2059
+ }
2060
+ ),
2061
+ /* @__PURE__ */ jsx2(
2062
+ Button,
2063
+ {
2064
+ variant: "ghost",
2065
+ size: "sm",
2066
+ leftIcon: /* @__PURE__ */ jsx2(RenewIcon, { size: "sm" }),
2067
+ onClick: () => {
2068
+ setPreview({ phase: "idle" });
2069
+ },
2070
+ disabled: preview.phase === "loading",
2071
+ children: "Clear"
2072
+ }
2073
+ )
2074
+ ] }),
2075
+ preview.phase === "loading" && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__console-loading", children: [
2076
+ /* @__PURE__ */ jsx2(Spinner, { size: "sm" }),
2077
+ /* @__PURE__ */ jsx2("span", { children: "Sending request\u2026" })
2078
+ ] }),
2079
+ preview.phase === "error" && /* @__PURE__ */ jsxs2(Banner, { variant: "error", appearance: "subtle", size: "sm", children: [
2080
+ /* @__PURE__ */ jsx2("strong", { children: "Request failed." }),
2081
+ " ",
2082
+ preview.message
2083
+ ] }),
2084
+ preview.phase === "success" && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__console-result", children: [
2085
+ /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__console-status", children: [
2086
+ /* @__PURE__ */ jsxs2(Badge, { size: "sm", variant: statusTone(preview.response.status), children: [
2087
+ preview.response.status,
2088
+ " ",
2089
+ preview.response.statusText
2090
+ ] }),
2091
+ /* @__PURE__ */ jsxs2("span", { className: "ods-http-panel__meta", children: [
2092
+ preview.response.duration,
2093
+ "ms"
2094
+ ] }),
2095
+ /* @__PURE__ */ jsx2("span", { className: "ods-http-panel__meta", children: formatBytes(preview.response.size) })
2096
+ ] }),
2097
+ /* @__PURE__ */ jsx2(
2098
+ Accordion,
2099
+ {
2100
+ size: "sm",
2101
+ mode: "multiple",
2102
+ defaultValue: ["res-body"],
2103
+ items: [
2104
+ {
2105
+ id: "res-headers",
2106
+ label: "Response headers",
2107
+ trailing: /* @__PURE__ */ jsx2(Badge, { size: "sm", variant: "neutral", children: Object.keys(preview.response.headers).length }),
2108
+ content: /* @__PURE__ */ jsx2("div", { className: "ods-http-panel__res-headers", children: Object.entries(preview.response.headers).map(([k, v]) => /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__res-header", children: [
2109
+ /* @__PURE__ */ jsx2("span", { className: "ods-http-panel__res-header-key", children: k }),
2110
+ /* @__PURE__ */ jsx2("span", { className: "ods-http-panel__res-header-val", children: v })
2111
+ ] }, k)) })
2112
+ },
2113
+ {
2114
+ id: "res-body",
2115
+ label: "Response body",
2116
+ trailing: !preview.response.ok ? /* @__PURE__ */ jsx2(Badge, { size: "sm", variant: "error", children: "Error" }) : null,
2117
+ content: (
2118
+ // Size guard: the tree view renders recursively (no
2119
+ // virtualization) — very large bodies fall back to text.
2120
+ preview.response.body !== null && typeof preview.response.body === "object" && preview.response.size <= 15e5 ? /* @__PURE__ */ jsx2(
2121
+ JsonViewer,
2122
+ {
2123
+ data: preview.response.body,
2124
+ mode: "view",
2125
+ maxHeight: 320,
2126
+ copyable: true
2127
+ }
2128
+ ) : /* @__PURE__ */ jsx2("pre", { className: "ods-http-panel__res-body", children: typeof preview.response.body === "object" ? JSON.stringify(preview.response.body, null, 2) : String(
2129
+ preview.response.bodyRaw ?? preview.response.body ?? "(empty body)"
2130
+ ) })
2131
+ )
2132
+ }
2133
+ ]
2134
+ }
2135
+ )
2136
+ ] })
2137
+ ] })
2138
+ ] });
2139
+ }
2140
+
624
2141
  // src/workflow/components/FxPanel/FxPanel.tsx
625
2142
  import {
626
- useMemo as useMemo2,
627
- useRef as useRef4,
628
- useState as useState4
2143
+ useMemo as useMemo3,
2144
+ useRef as useRef5,
2145
+ useState as useState5
629
2146
  } from "react";
630
2147
  import {
631
2148
  ChevronDownIcon,
@@ -638,7 +2155,7 @@ import {
638
2155
  SearchIcon,
639
2156
  ValueVariableIcon
640
2157
  } from "@octaviaflow/icons";
641
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
2158
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
642
2159
  var KIND_ICON = {
643
2160
  function: FunctionMathIcon,
644
2161
  variable: ValueVariableIcon
@@ -697,18 +2214,18 @@ function FxPanel({
697
2214
  className,
698
2215
  style
699
2216
  }) {
700
- const [internalSearch, setInternalSearch] = useState4(defaultSearch);
2217
+ const [internalSearch, setInternalSearch] = useState5(defaultSearch);
701
2218
  const search = controlledSearch ?? internalSearch;
702
2219
  const query = search.trim().toLowerCase();
703
2220
  const setSearch = (next) => {
704
2221
  if (controlledSearch === void 0) setInternalSearch(next);
705
2222
  onSearchChange?.(next);
706
2223
  };
707
- const visibleCategories = useMemo2(
2224
+ const visibleCategories = useMemo3(
708
2225
  () => categories.filter((c) => c.items.length > 0),
709
2226
  [categories]
710
2227
  );
711
- const [internalCat, setInternalCat] = useState4(
2228
+ const [internalCat, setInternalCat] = useState5(
712
2229
  defaultExpandedCategory !== void 0 ? defaultExpandedCategory : visibleCategories[0]?.id ?? null
713
2230
  );
714
2231
  const openCategoryId = controlledExpanded ?? internalCat;
@@ -716,7 +2233,7 @@ function FxPanel({
716
2233
  if (controlledExpanded === void 0) setInternalCat(id);
717
2234
  onExpandedCategoryChange?.(id);
718
2235
  };
719
- const [expandedItems, setExpandedItems] = useState4(() => {
2236
+ const [expandedItems, setExpandedItems] = useState5(() => {
720
2237
  const ids = /* @__PURE__ */ new Set();
721
2238
  for (const cat of categories) {
722
2239
  for (const item of cat.items) {
@@ -745,9 +2262,9 @@ function FxPanel({
745
2262
  return next;
746
2263
  });
747
2264
  };
748
- const [draggingId, setDraggingId] = useState4(null);
749
- const [focusedId, setFocusedId] = useState4(null);
750
- const hits = useMemo2(() => {
2265
+ const [draggingId, setDraggingId] = useState5(null);
2266
+ const [focusedId, setFocusedId] = useState5(null);
2267
+ const hits = useMemo3(() => {
751
2268
  if (!query) return null;
752
2269
  const all = [];
753
2270
  for (const cat of visibleCategories) {
@@ -771,7 +2288,7 @@ function FxPanel({
771
2288
  e.dataTransfer.effectAllowed = "copy";
772
2289
  }
773
2290
  };
774
- const listRef = useRef4(null);
2291
+ const listRef = useRef5(null);
775
2292
  const focusRow = (id) => {
776
2293
  setFocusedId(id);
777
2294
  requestAnimationFrame(() => {
@@ -829,7 +2346,7 @@ function FxPanel({
829
2346
  break;
830
2347
  }
831
2348
  };
832
- const searchRows = useMemo2(
2349
+ const searchRows = useMemo3(
833
2350
  () => hits ? hits.map(({ hit }) => ({
834
2351
  item: hit.item,
835
2352
  depth: 0,
@@ -843,7 +2360,7 @@ function FxPanel({
843
2360
  const mono = category.kind === "function";
844
2361
  const draggable = !!item.insertValue;
845
2362
  const isFocused = focusedId === item.id;
846
- return /* @__PURE__ */ jsxs2(
2363
+ return /* @__PURE__ */ jsxs3(
847
2364
  "div",
848
2365
  {
849
2366
  "data-fx-row": item.id,
@@ -868,12 +2385,12 @@ function FxPanel({
868
2385
  },
869
2386
  title: item.insertValue,
870
2387
  children: [
871
- Array.from({ length: depth }, (_, i) => /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__indent", "aria-hidden": "true" }, i)),
872
- hasChildren ? /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__twisty", "aria-hidden": "true", children: expanded ? /* @__PURE__ */ jsx2(ChevronDownIcon, { size: "sm" }) : /* @__PURE__ */ jsx2(ChevronRightIcon, { size: "sm" }) }) : /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__grip", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(DraggableIcon, { size: "sm" }) }),
873
- /* @__PURE__ */ jsxs2("span", { className: "ods-flow-fx-panel__row-main", children: [
874
- /* @__PURE__ */ jsxs2("span", { className: "ods-flow-fx-panel__row-line", children: [
875
- mono ? /* @__PURE__ */ jsx2("code", { className: "ods-flow-fx-panel__row-label ods-flow-fx-panel__row-label--mono", children: item.label }) : /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__row-label", children: item.label }),
876
- item.valueType && /* @__PURE__ */ jsx2(
2388
+ Array.from({ length: depth }, (_, i) => /* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-panel__indent", "aria-hidden": "true" }, i)),
2389
+ hasChildren ? /* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-panel__twisty", "aria-hidden": "true", children: expanded ? /* @__PURE__ */ jsx3(ChevronDownIcon, { size: "sm" }) : /* @__PURE__ */ jsx3(ChevronRightIcon, { size: "sm" }) }) : /* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-panel__grip", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(DraggableIcon, { size: "sm" }) }),
2390
+ /* @__PURE__ */ jsxs3("span", { className: "ods-flow-fx-panel__row-main", children: [
2391
+ /* @__PURE__ */ jsxs3("span", { className: "ods-flow-fx-panel__row-line", children: [
2392
+ mono ? /* @__PURE__ */ jsx3("code", { className: "ods-flow-fx-panel__row-label ods-flow-fx-panel__row-label--mono", children: item.label }) : /* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-panel__row-label", children: item.label }),
2393
+ item.valueType && /* @__PURE__ */ jsx3(
877
2394
  "span",
878
2395
  {
879
2396
  className: cn(
@@ -884,8 +2401,8 @@ function FxPanel({
884
2401
  }
885
2402
  )
886
2403
  ] }),
887
- (item.description || crumb) && /* @__PURE__ */ jsxs2("span", { className: "ods-flow-fx-panel__row-sub", children: [
888
- crumb && /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__crumb", children: crumb }),
2404
+ (item.description || crumb) && /* @__PURE__ */ jsxs3("span", { className: "ods-flow-fx-panel__row-sub", children: [
2405
+ crumb && /* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-panel__crumb", children: crumb }),
889
2406
  item.description
890
2407
  ] })
891
2408
  ] })
@@ -894,29 +2411,29 @@ function FxPanel({
894
2411
  item.id
895
2412
  );
896
2413
  };
897
- return /* @__PURE__ */ jsxs2(
2414
+ return /* @__PURE__ */ jsxs3(
898
2415
  "aside",
899
2416
  {
900
2417
  className: cn("ods-flow-fx-panel", className),
901
2418
  style: { width, ...style },
902
2419
  "aria-label": typeof title === "string" ? title : "Data References",
903
2420
  children: [
904
- /* @__PURE__ */ jsxs2("header", { className: "ods-flow-fx-panel__header", children: [
905
- /* @__PURE__ */ jsx2("h3", { className: "ods-flow-fx-panel__title", children: title }),
906
- onClose && /* @__PURE__ */ jsx2(
2421
+ /* @__PURE__ */ jsxs3("header", { className: "ods-flow-fx-panel__header", children: [
2422
+ /* @__PURE__ */ jsx3("h3", { className: "ods-flow-fx-panel__title", children: title }),
2423
+ onClose && /* @__PURE__ */ jsx3(
907
2424
  "button",
908
2425
  {
909
2426
  type: "button",
910
2427
  className: "ods-flow-fx-panel__close",
911
2428
  onClick: onClose,
912
2429
  "aria-label": "Close data references",
913
- children: /* @__PURE__ */ jsx2(CloseIcon, { size: "sm" })
2430
+ children: /* @__PURE__ */ jsx3(CloseIcon, { size: "sm" })
914
2431
  }
915
2432
  )
916
2433
  ] }),
917
- /* @__PURE__ */ jsxs2("div", { className: "ods-flow-fx-panel__search", children: [
918
- /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__search-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(SearchIcon, { size: "sm" }) }),
919
- /* @__PURE__ */ jsx2(
2434
+ /* @__PURE__ */ jsxs3("div", { className: "ods-flow-fx-panel__search", children: [
2435
+ /* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-panel__search-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(SearchIcon, { size: "sm" }) }),
2436
+ /* @__PURE__ */ jsx3(
920
2437
  "input",
921
2438
  {
922
2439
  type: "text",
@@ -927,21 +2444,21 @@ function FxPanel({
927
2444
  onChange: (e) => setSearch(e.target.value)
928
2445
  }
929
2446
  ),
930
- search && /* @__PURE__ */ jsx2(
2447
+ search && /* @__PURE__ */ jsx3(
931
2448
  "button",
932
2449
  {
933
2450
  type: "button",
934
2451
  className: "ods-flow-fx-panel__search-clear",
935
2452
  onClick: () => setSearch(""),
936
2453
  "aria-label": "Clear search",
937
- children: /* @__PURE__ */ jsx2(CloseIcon, { size: "sm" })
2454
+ children: /* @__PURE__ */ jsx3(CloseIcon, { size: "sm" })
938
2455
  }
939
2456
  )
940
2457
  ] }),
941
- hint && !query && /* @__PURE__ */ jsx2("p", { className: "ods-flow-fx-panel__hint", children: hint }),
942
- /* @__PURE__ */ jsxs2("div", { className: "ods-flow-fx-panel__list", ref: listRef, role: "tree", children: [
943
- query && hits && (hits.length > 0 ? /* @__PURE__ */ jsxs2("div", { className: "ods-flow-fx-panel__results", children: [
944
- /* @__PURE__ */ jsxs2("div", { className: "ods-flow-fx-panel__results-count", children: [
2458
+ hint && !query && /* @__PURE__ */ jsx3("p", { className: "ods-flow-fx-panel__hint", children: hint }),
2459
+ /* @__PURE__ */ jsxs3("div", { className: "ods-flow-fx-panel__list", ref: listRef, role: "tree", children: [
2460
+ query && hits && (hits.length > 0 ? /* @__PURE__ */ jsxs3("div", { className: "ods-flow-fx-panel__results", children: [
2461
+ /* @__PURE__ */ jsxs3("div", { className: "ods-flow-fx-panel__results-count", children: [
945
2462
  hits.length,
946
2463
  " ",
947
2464
  hits.length === 1 ? "match" : "matches"
@@ -954,7 +2471,7 @@ function FxPanel({
954
2471
  hit.ancestors.length ? hit.ancestors.join(" / ") : category.label
955
2472
  )
956
2473
  )
957
- ] }) : /* @__PURE__ */ jsx2("div", { className: "ods-flow-fx-panel__empty", children: emptyLabel })),
2474
+ ] }) : /* @__PURE__ */ jsx3("div", { className: "ods-flow-fx-panel__empty", children: emptyLabel })),
958
2475
  !query && visibleCategories.map((cat) => {
959
2476
  const isOpen = openCategoryId === cat.id;
960
2477
  const kind = cat.kind ?? "function";
@@ -965,8 +2482,8 @@ function FxPanel({
965
2482
  const rows = [];
966
2483
  if (isOpen) flattenTree(cat.items, 0, expandedItems, rows);
967
2484
  const allExpanded = hasTree && [...branchIds].every((id) => expandedItems.has(id));
968
- return /* @__PURE__ */ jsxs2("div", { className: "ods-flow-fx-panel__category", children: [
969
- /* @__PURE__ */ jsxs2(
2485
+ return /* @__PURE__ */ jsxs3("div", { className: "ods-flow-fx-panel__category", children: [
2486
+ /* @__PURE__ */ jsxs3(
970
2487
  "div",
971
2488
  {
972
2489
  className: cn(
@@ -974,7 +2491,7 @@ function FxPanel({
974
2491
  isOpen && "ods-flow-fx-panel__cat-header--open"
975
2492
  ),
976
2493
  children: [
977
- /* @__PURE__ */ jsxs2(
2494
+ /* @__PURE__ */ jsxs3(
978
2495
  "button",
979
2496
  {
980
2497
  type: "button",
@@ -982,7 +2499,7 @@ function FxPanel({
982
2499
  "aria-expanded": isOpen,
983
2500
  onClick: () => setOpenCategory(isOpen ? null : cat.id),
984
2501
  children: [
985
- /* @__PURE__ */ jsx2(
2502
+ /* @__PURE__ */ jsx3(
986
2503
  ChevronRightIcon,
987
2504
  {
988
2505
  size: "sm",
@@ -992,7 +2509,7 @@ function FxPanel({
992
2509
  )
993
2510
  }
994
2511
  ),
995
- /* @__PURE__ */ jsxs2(
2512
+ /* @__PURE__ */ jsxs3(
996
2513
  "span",
997
2514
  {
998
2515
  className: cn(
@@ -1000,7 +2517,7 @@ function FxPanel({
1000
2517
  `ods-flow-fx-panel__badge--${kind}`
1001
2518
  ),
1002
2519
  children: [
1003
- /* @__PURE__ */ jsx2(
2520
+ /* @__PURE__ */ jsx3(
1004
2521
  KindIcon,
1005
2522
  {
1006
2523
  size: "sm",
@@ -1011,11 +2528,11 @@ function FxPanel({
1011
2528
  ]
1012
2529
  }
1013
2530
  ),
1014
- /* @__PURE__ */ jsx2("span", { className: "ods-flow-fx-panel__count", children: countLeaves(cat.items) })
2531
+ /* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-panel__count", children: countLeaves(cat.items) })
1015
2532
  ]
1016
2533
  }
1017
2534
  ),
1018
- isOpen && hasTree && /* @__PURE__ */ jsx2(
2535
+ isOpen && hasTree && /* @__PURE__ */ jsx3(
1019
2536
  "button",
1020
2537
  {
1021
2538
  type: "button",
@@ -1023,13 +2540,13 @@ function FxPanel({
1023
2540
  "aria-label": allExpanded ? "Collapse all" : "Expand all",
1024
2541
  title: allExpanded ? "Collapse all" : "Expand all",
1025
2542
  onClick: () => setCategoryExpansion(cat, !allExpanded),
1026
- children: allExpanded ? /* @__PURE__ */ jsx2(CollapseAllIcon, { size: "sm" }) : /* @__PURE__ */ jsx2(ExpandAllIcon, { size: "sm" })
2543
+ children: allExpanded ? /* @__PURE__ */ jsx3(CollapseAllIcon, { size: "sm" }) : /* @__PURE__ */ jsx3(ExpandAllIcon, { size: "sm" })
1027
2544
  }
1028
2545
  )
1029
2546
  ]
1030
2547
  }
1031
2548
  ),
1032
- isOpen && /* @__PURE__ */ jsx2(
2549
+ isOpen && /* @__PURE__ */ jsx3(
1033
2550
  "div",
1034
2551
  {
1035
2552
  className: "ods-flow-fx-panel__rows",
@@ -1048,7 +2565,7 @@ function FxPanel({
1048
2565
 
1049
2566
  // src/workflow/components/FxPanel/DataRefButton.tsx
1050
2567
  import { DataReferenceIcon } from "@octaviaflow/icons";
1051
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
2568
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1052
2569
  function DataRefButton({
1053
2570
  active = false,
1054
2571
  label = "Data ref",
@@ -1056,7 +2573,7 @@ function DataRefButton({
1056
2573
  type = "button",
1057
2574
  ...rest
1058
2575
  }) {
1059
- return /* @__PURE__ */ jsxs3(
2576
+ return /* @__PURE__ */ jsxs4(
1060
2577
  "button",
1061
2578
  {
1062
2579
  ...rest,
@@ -1070,21 +2587,21 @@ function DataRefButton({
1070
2587
  "aria-pressed": active,
1071
2588
  title: active ? "Hide data references" : "Show data references",
1072
2589
  children: [
1073
- /* @__PURE__ */ jsx3(
2590
+ /* @__PURE__ */ jsx4(
1074
2591
  DataReferenceIcon,
1075
2592
  {
1076
2593
  size: "sm",
1077
2594
  className: "ods-flow-dataref-button__icon"
1078
2595
  }
1079
2596
  ),
1080
- label != null && /* @__PURE__ */ jsx3("span", { className: "ods-flow-dataref-button__label", children: label })
2597
+ label != null && /* @__PURE__ */ jsx4("span", { className: "ods-flow-dataref-button__label", children: label })
1081
2598
  ]
1082
2599
  }
1083
2600
  );
1084
2601
  }
1085
2602
 
1086
2603
  // src/workflow/components/NodeToolbar/NodeToolbar.tsx
1087
- import { jsx as jsx4 } from "react/jsx-runtime";
2604
+ import { jsx as jsx5 } from "react/jsx-runtime";
1088
2605
  function NodeToolbar({
1089
2606
  isVisible,
1090
2607
  position = "top",
@@ -1099,7 +2616,7 @@ function NodeToolbar({
1099
2616
  const show = isVisible ?? node.selected;
1100
2617
  if (!show) return null;
1101
2618
  const inverseScale = 1 / viewport.zoom;
1102
- return /* @__PURE__ */ jsx4(
2619
+ return /* @__PURE__ */ jsx5(
1103
2620
  "div",
1104
2621
  {
1105
2622
  className: cn("ods-node-toolbar", `ods-node-toolbar--${position}`, className),
@@ -1111,7 +2628,7 @@ function NodeToolbar({
1111
2628
  onPointerDown: (e) => e.stopPropagation(),
1112
2629
  onMouseDown: (e) => e.stopPropagation(),
1113
2630
  onClick: (e) => e.stopPropagation(),
1114
- children: /* @__PURE__ */ jsx4(
2631
+ children: /* @__PURE__ */ jsx5(
1115
2632
  "div",
1116
2633
  {
1117
2634
  className: "ods-node-toolbar__inner",
@@ -1267,7 +2784,10 @@ export {
1267
2784
  ForEachNode,
1268
2785
  FxPanel,
1269
2786
  GroupNode,
2787
+ HTTP_ACTION_DEFAULTS,
2788
+ HTTP_METHODS,
1270
2789
  Handle,
2790
+ HttpActionPanel,
1271
2791
  HttpRequestNode,
1272
2792
  NodeResizer,
1273
2793
  NodeToolbar,
@@ -1281,19 +2801,28 @@ export {
1281
2801
  applyNodeChanges,
1282
2802
  bezierPath2 as bezierPath,
1283
2803
  bezierPath as bezierPathFn,
2804
+ buildCurl,
1284
2805
  buildEdgePath,
1285
2806
  buildNodeKindRegistry,
1286
2807
  change,
1287
2808
  clampToParentExtent,
1288
2809
  collapseFor,
2810
+ countGraphqlVariables,
2811
+ countSchemaPaths,
1289
2812
  createDagreEngine,
1290
2813
  createElkEngine,
1291
2814
  descendantsOf,
2815
+ effectiveUrl,
1292
2816
  findAncestor,
1293
2817
  findContainingGroup,
1294
2818
  flowToScreen,
1295
2819
  handleCentre,
2820
+ inferJsonSchema,
2821
+ normalizeAuth,
2822
+ normalizeKeyValues,
2823
+ parseCurl,
1296
2824
  screenToFlow,
2825
+ serializeKeyValues,
1297
2826
  smoothStepPath,
1298
2827
  stepPath,
1299
2828
  straightPath,
@@ -1313,6 +2842,7 @@ export {
1313
2842
  useNodes,
1314
2843
  useSelection,
1315
2844
  useViewport,
1316
- useViewportOrNull
2845
+ useViewportOrNull,
2846
+ validateHttpConfig
1317
2847
  };
1318
2848
  //# sourceMappingURL=workflow.js.map