@walkeros/explorer 1.0.0 → 1.0.2

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.
package/dist/index.mjs CHANGED
@@ -1735,12 +1735,20 @@ function DestinationInitDemo({
1735
1735
  }
1736
1736
 
1737
1737
  // src/components/demos/PromotionPlayground.tsx
1738
- import { useState as useState13, useCallback as useCallback10 } from "react";
1738
+ import {
1739
+ useState as useState12,
1740
+ useEffect as useEffect9,
1741
+ useRef as useRef6,
1742
+ useCallback as useCallback10,
1743
+ useMemo as useMemo3
1744
+ } from "react";
1745
+ import { startFlow as startFlow3 } from "@walkeros/collector";
1739
1746
 
1740
1747
  // src/components/molecules/preview.tsx
1741
1748
  import { useState as useState10, useEffect as useEffect8, useRef as useRef5, useCallback as useCallback9 } from "react";
1742
- import { sourceBrowser } from "@walkeros/web-source-browser";
1743
- import { startFlow as startFlow3 } from "@walkeros/collector";
1749
+ import {
1750
+ sourceBrowser
1751
+ } from "@walkeros/web-source-browser";
1744
1752
 
1745
1753
  // src/components/atoms/preview-footer.tsx
1746
1754
  import { jsx as jsx10 } from "react/jsx-runtime";
@@ -1772,17 +1780,17 @@ import { jsx as jsx11 } from "react/jsx-runtime";
1772
1780
  function Preview({
1773
1781
  html,
1774
1782
  css = "",
1775
- onEvent,
1783
+ elb,
1776
1784
  label = "Preview"
1777
1785
  }) {
1778
1786
  const [highlights, setHighlights] = useState10(/* @__PURE__ */ new Set());
1779
1787
  const iframeRef = useRef5(null);
1780
1788
  const updateTimeoutRef = useRef5(void 0);
1781
- const onEventRef = useRef5(onEvent);
1782
- const collectorRef = useRef5(null);
1789
+ const elbRef = useRef5(elb);
1790
+ const sourceRef = useRef5(null);
1783
1791
  useEffect8(() => {
1784
- onEventRef.current = onEvent;
1785
- }, [onEvent]);
1792
+ elbRef.current = elb;
1793
+ }, [elb]);
1786
1794
  const toggleHighlight = (type) => {
1787
1795
  setHighlights((prev) => {
1788
1796
  const next = new Set(prev);
@@ -1889,58 +1897,65 @@ function Preview({
1889
1897
  `);
1890
1898
  doc.close();
1891
1899
  autoMarkProperties(doc);
1892
- if (onEventRef.current && iframe.contentWindow && iframe.contentDocument) {
1900
+ if (elbRef.current && iframe.contentWindow && iframe.contentDocument) {
1893
1901
  setTimeout(async () => {
1894
- if (collectorRef.current) {
1902
+ if (sourceRef.current) {
1895
1903
  try {
1896
- for (const source of Object.values(
1897
- collectorRef.current.sources
1898
- )) {
1899
- await source.destroy?.();
1900
- }
1901
- } catch (e) {
1904
+ await sourceRef.current.destroy?.();
1905
+ } catch {
1902
1906
  }
1903
1907
  }
1904
1908
  try {
1905
- if (!iframe.contentWindow || !iframe.contentDocument) return;
1906
- const { collector, elb } = await startFlow3({
1907
- sources: {
1908
- browser: {
1909
- code: sourceBrowser,
1910
- config: {
1911
- settings: {
1912
- pageview: true,
1913
- session: false,
1914
- prefix: "data-elb",
1915
- elb: "elb",
1916
- elbLayer: "elbLayer"
1917
- }
1918
- },
1919
- env: {
1920
- window: iframe.contentWindow,
1921
- document: iframe.contentDocument
1922
- },
1923
- primary: true
1924
- }
1909
+ if (!iframe.contentWindow || !iframe.contentDocument || !elbRef.current) {
1910
+ return;
1911
+ }
1912
+ const createNoopLogger = () => ({
1913
+ error: () => {
1925
1914
  },
1926
- destinations: {
1927
- // Capture events and forward to onEvent callback
1928
- preview: {
1929
- code: {
1930
- type: "preview",
1931
- config: {},
1932
- push: async (event) => {
1933
- if (onEventRef.current) {
1934
- onEventRef.current(event);
1935
- }
1936
- }
1937
- }
1915
+ info: () => {
1916
+ },
1917
+ debug: () => {
1918
+ },
1919
+ throw: (msg) => {
1920
+ throw msg instanceof Error ? msg : new Error(msg);
1921
+ },
1922
+ scope: () => createNoopLogger()
1923
+ });
1924
+ const noopLogger = createNoopLogger();
1925
+ const noopPush = async () => ({
1926
+ ok: true,
1927
+ destination: {}
1928
+ });
1929
+ const source = await sourceBrowser({
1930
+ id: "preview",
1931
+ collector: {},
1932
+ // Not used when elb is provided directly
1933
+ logger: noopLogger,
1934
+ setIngest: async () => {
1935
+ },
1936
+ config: {
1937
+ settings: {
1938
+ pageview: false,
1939
+ session: false,
1940
+ prefix: "data-elb",
1941
+ elb: "elb",
1942
+ elbLayer: "elbLayer",
1943
+ // Use body as scope - trigger.ts compares `scope !== document` against
1944
+ // main page's document, so iframe.contentDocument fails the Element cast
1945
+ scope: iframe.contentDocument.body
1938
1946
  }
1939
1947
  },
1940
- run: false
1948
+ env: {
1949
+ elb: elbRef.current,
1950
+ push: noopPush,
1951
+ command: async () => ({ ok: true, destination: {} }),
1952
+ logger: noopLogger,
1953
+ window: iframe.contentWindow,
1954
+ document: iframe.contentDocument
1955
+ }
1941
1956
  });
1942
- collectorRef.current = collector;
1943
- } catch (error) {
1957
+ sourceRef.current = source;
1958
+ } catch {
1944
1959
  }
1945
1960
  }, 50);
1946
1961
  }
@@ -1949,13 +1964,11 @@ function Preview({
1949
1964
  if (updateTimeoutRef.current) {
1950
1965
  clearTimeout(updateTimeoutRef.current);
1951
1966
  }
1952
- if (collectorRef.current) {
1953
- for (const source of Object.values(collectorRef.current.sources)) {
1954
- source.destroy?.();
1955
- }
1967
+ if (sourceRef.current) {
1968
+ sourceRef.current.destroy?.();
1956
1969
  }
1957
1970
  };
1958
- }, [html, css, highlights, autoMarkProperties]);
1971
+ }, [html, css, highlights, autoMarkProperties, elb]);
1959
1972
  return /* @__PURE__ */ jsx11(
1960
1973
  Box,
1961
1974
  {
@@ -2101,60 +2114,6 @@ function BrowserBox({
2101
2114
  );
2102
2115
  }
2103
2116
 
2104
- // src/components/organisms/collector-box.tsx
2105
- import { useState as useState12, useEffect as useEffect9 } from "react";
2106
- import { startFlow as startFlow4 } from "@walkeros/collector";
2107
- import { jsx as jsx15 } from "react/jsx-runtime";
2108
- function CollectorBox({
2109
- event,
2110
- mapping,
2111
- destination,
2112
- label = "Result",
2113
- wordWrap = false
2114
- }) {
2115
- const [output, setOutput] = useState12(
2116
- "// Click elements in the preview to see function call"
2117
- );
2118
- useEffect9(() => {
2119
- (async () => {
2120
- try {
2121
- const eventObj = JSON.parse(event);
2122
- const mappingObj = JSON.parse(mapping);
2123
- const { collector } = await startFlow4({
2124
- destinations: {
2125
- demo: {
2126
- code: destination,
2127
- config: {
2128
- mapping: mappingObj
2129
- },
2130
- env: {
2131
- elb: setOutput
2132
- }
2133
- }
2134
- }
2135
- });
2136
- await collector.push(eventObj);
2137
- } catch (error) {
2138
- if (error instanceof Error) {
2139
- setOutput(`// Error: ${error.message}`);
2140
- } else {
2141
- setOutput(`// Error: ${String(error)}`);
2142
- }
2143
- }
2144
- })();
2145
- }, [event, mapping, destination]);
2146
- return /* @__PURE__ */ jsx15(
2147
- CodeBox,
2148
- {
2149
- code: output,
2150
- language: "javascript",
2151
- disabled: true,
2152
- label,
2153
- wordWrap
2154
- }
2155
- );
2156
- }
2157
-
2158
2117
  // src/helpers/destinations.ts
2159
2118
  function createGtagDestination() {
2160
2119
  return {
@@ -2191,7 +2150,7 @@ function createPlausibleDestination() {
2191
2150
  }
2192
2151
 
2193
2152
  // src/components/demos/PromotionPlayground.tsx
2194
- import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
2153
+ import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
2195
2154
  var defaultHtml = `<div
2196
2155
  data-elb="product"
2197
2156
  data-elbaction="load:view"
@@ -2448,25 +2407,94 @@ function PromotionPlayground({
2448
2407
  labelEvents = "Events",
2449
2408
  labelMapping = "Mapping",
2450
2409
  labelResult = "Result",
2451
- destination = createGtagDestination()
2410
+ destination: destinationProp
2452
2411
  }) {
2453
- const [html, setHtml] = useState13(initialHtml);
2454
- const [css, setCss] = useState13(initialCss);
2455
- const [js, setJs] = useState13(initialJs);
2456
- const [mappingInput, setMappingInput] = useState13(initialMapping);
2457
- const [capturedEvent, setCapturedEvent] = useState13(
2458
- null
2412
+ const destination = useMemo3(
2413
+ () => destinationProp ?? createGtagDestination(),
2414
+ [destinationProp]
2459
2415
  );
2460
- const [eventInput, setEventInput] = useState13(
2416
+ const [html, setHtml] = useState12(initialHtml);
2417
+ const [css, setCss] = useState12(initialCss);
2418
+ const [js, setJs] = useState12(initialJs);
2419
+ const [mappingInput, setMappingInput] = useState12(initialMapping);
2420
+ const [eventJson, setEventJson] = useState12(
2461
2421
  "// Click elements in the preview to see events"
2462
2422
  );
2463
- const handleEvent = useCallback10((event) => {
2464
- setCapturedEvent(event);
2465
- setEventInput(JSON.stringify(event, null, 2));
2423
+ const [outputString, setOutputString] = useState12(
2424
+ "// Click elements in the preview to see function call"
2425
+ );
2426
+ const collectorRef = useRef6(null);
2427
+ const elbRef = useRef6(null);
2428
+ const lastEventRef = useRef6(null);
2429
+ const [isReady, setIsReady] = useState12(false);
2430
+ useEffect9(() => {
2431
+ let mounted = true;
2432
+ const init = async () => {
2433
+ try {
2434
+ const parsedMapping = JSON.parse(initialMapping);
2435
+ const { collector, elb } = await startFlow3({
2436
+ destinations: {
2437
+ // Capture raw events for display in Events column
2438
+ rawCapture: {
2439
+ code: {
2440
+ type: "rawCapture",
2441
+ config: {},
2442
+ push: async (event) => {
2443
+ if (!mounted) return;
2444
+ lastEventRef.current = event;
2445
+ setEventJson(JSON.stringify(event, null, 2));
2446
+ }
2447
+ }
2448
+ },
2449
+ // Transform and display formatted output in Result column
2450
+ gtag: {
2451
+ code: destination,
2452
+ config: {
2453
+ mapping: parsedMapping
2454
+ },
2455
+ env: {
2456
+ elb: (output) => {
2457
+ if (!mounted) return;
2458
+ setOutputString(output);
2459
+ }
2460
+ }
2461
+ }
2462
+ },
2463
+ consent: { functional: true, marketing: true },
2464
+ user: { session: "playground" }
2465
+ });
2466
+ if (!mounted) return;
2467
+ collectorRef.current = collector;
2468
+ elbRef.current = elb;
2469
+ setIsReady(true);
2470
+ } catch {
2471
+ }
2472
+ };
2473
+ init();
2474
+ return () => {
2475
+ mounted = false;
2476
+ if (collectorRef.current) {
2477
+ }
2478
+ };
2479
+ }, [initialMapping, destination]);
2480
+ const handleMappingChange = useCallback10((newMapping) => {
2481
+ setMappingInput(newMapping);
2482
+ const timeoutId = setTimeout(() => {
2483
+ try {
2484
+ const parsed = JSON.parse(newMapping);
2485
+ if (collectorRef.current?.destinations?.gtag?.config) {
2486
+ collectorRef.current.destinations.gtag.config.mapping = parsed;
2487
+ }
2488
+ if (lastEventRef.current && collectorRef.current) {
2489
+ collectorRef.current.push(lastEventRef.current);
2490
+ }
2491
+ } catch {
2492
+ }
2493
+ }, 500);
2494
+ return () => clearTimeout(timeoutId);
2466
2495
  }, []);
2467
- const eventDisplay = eventInput;
2468
2496
  return /* @__PURE__ */ jsxs9(Grid, { columns: 5, rowHeight: 600, children: [
2469
- /* @__PURE__ */ jsx16(
2497
+ /* @__PURE__ */ jsx15(
2470
2498
  BrowserBox,
2471
2499
  {
2472
2500
  label: labelCode,
@@ -2482,42 +2510,42 @@ function PromotionPlayground({
2482
2510
  wordWrap: true
2483
2511
  }
2484
2512
  ),
2485
- /* @__PURE__ */ jsx16(
2513
+ /* @__PURE__ */ jsx15(
2486
2514
  Preview,
2487
2515
  {
2488
2516
  label: labelPreview,
2489
2517
  html,
2490
2518
  css,
2491
- onEvent: handleEvent
2519
+ elb: isReady ? elbRef.current ?? void 0 : void 0
2492
2520
  }
2493
2521
  ),
2494
- /* @__PURE__ */ jsx16(
2522
+ /* @__PURE__ */ jsx15(
2495
2523
  CodeBox,
2496
2524
  {
2497
2525
  label: labelEvents,
2498
- code: eventDisplay,
2499
- onChange: setEventInput,
2526
+ code: eventJson,
2527
+ onChange: setEventJson,
2500
2528
  language: "json",
2501
2529
  wordWrap: true
2502
2530
  }
2503
2531
  ),
2504
- /* @__PURE__ */ jsx16(
2532
+ /* @__PURE__ */ jsx15(
2505
2533
  CodeBox,
2506
2534
  {
2507
2535
  label: labelMapping,
2508
2536
  code: mappingInput,
2509
- onChange: setMappingInput,
2537
+ onChange: handleMappingChange,
2510
2538
  language: "json",
2511
2539
  wordWrap: true
2512
2540
  }
2513
2541
  ),
2514
- /* @__PURE__ */ jsx16(
2515
- CollectorBox,
2542
+ /* @__PURE__ */ jsx15(
2543
+ CodeBox,
2516
2544
  {
2517
- event: eventInput,
2518
- mapping: mappingInput,
2519
- destination,
2520
2545
  label: labelResult,
2546
+ code: outputString,
2547
+ language: "javascript",
2548
+ disabled: true,
2521
2549
  wordWrap: true
2522
2550
  }
2523
2551
  )
@@ -2525,7 +2553,7 @@ function PromotionPlayground({
2525
2553
  }
2526
2554
 
2527
2555
  // src/components/organisms/live-code.tsx
2528
- import { useState as useState14, useEffect as useEffect10, useCallback as useCallback11 } from "react";
2556
+ import { useState as useState13, useEffect as useEffect10, useCallback as useCallback11 } from "react";
2529
2557
  import { debounce, isString, tryCatchAsync as tryCatchAsync3 } from "@walkeros/core";
2530
2558
 
2531
2559
  // src/utils/format-code.ts
@@ -2587,7 +2615,7 @@ async function formatCode(code, language) {
2587
2615
  }
2588
2616
 
2589
2617
  // src/components/organisms/live-code.tsx
2590
- import { jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
2618
+ import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
2591
2619
  function formatValue(value, options = {}) {
2592
2620
  if (value === void 0) return "";
2593
2621
  const str = isString(value) ? value.trim() : JSON.stringify(value, null, 2);
@@ -2612,9 +2640,9 @@ function LiveCode({
2612
2640
  format: format3 = true,
2613
2641
  rowHeight
2614
2642
  }) {
2615
- const [input, setInput] = useState14(formatValue(initInput));
2616
- const [config, setConfig] = useState14(formatValue(initConfig));
2617
- const [output, setOutput] = useState14([formatValue(initOutput)]);
2643
+ const [input, setInput] = useState13(formatValue(initInput));
2644
+ const [config, setConfig] = useState13(formatValue(initConfig));
2645
+ const [output, setOutput] = useState13([formatValue(initOutput)]);
2618
2646
  useEffect10(() => {
2619
2647
  if (format3 && initInput) {
2620
2648
  const rawInput = formatValue(initInput);
@@ -2652,7 +2680,7 @@ function LiveCode({
2652
2680
  updateOutput(input, config, options || {});
2653
2681
  }, [input, config, options, updateOutput]);
2654
2682
  return /* @__PURE__ */ jsxs10(Grid, { columns: 3, className, rowHeight, children: [
2655
- /* @__PURE__ */ jsx17(
2683
+ /* @__PURE__ */ jsx16(
2656
2684
  CodeBox,
2657
2685
  {
2658
2686
  label: labelInput,
@@ -2663,7 +2691,7 @@ function LiveCode({
2663
2691
  showFormat: !disableInput && language === "json"
2664
2692
  }
2665
2693
  ),
2666
- config && /* @__PURE__ */ jsx17(
2694
+ config && /* @__PURE__ */ jsx16(
2667
2695
  CodeBox,
2668
2696
  {
2669
2697
  label: labelConfig,
@@ -2674,7 +2702,7 @@ function LiveCode({
2674
2702
  showFormat: !disableConfig && language === "json"
2675
2703
  }
2676
2704
  ),
2677
- /* @__PURE__ */ jsx17(
2705
+ /* @__PURE__ */ jsx16(
2678
2706
  CodeBox,
2679
2707
  {
2680
2708
  label: labelOutput,
@@ -2686,14 +2714,68 @@ function LiveCode({
2686
2714
  ] });
2687
2715
  }
2688
2716
 
2717
+ // src/components/organisms/collector-box.tsx
2718
+ import { useState as useState14, useEffect as useEffect11 } from "react";
2719
+ import { startFlow as startFlow4 } from "@walkeros/collector";
2720
+ import { jsx as jsx17 } from "react/jsx-runtime";
2721
+ function CollectorBox({
2722
+ event,
2723
+ mapping,
2724
+ destination,
2725
+ label = "Result",
2726
+ wordWrap = false
2727
+ }) {
2728
+ const [output, setOutput] = useState14(
2729
+ "// Click elements in the preview to see function call"
2730
+ );
2731
+ useEffect11(() => {
2732
+ (async () => {
2733
+ try {
2734
+ const eventObj = JSON.parse(event);
2735
+ const mappingObj = JSON.parse(mapping);
2736
+ const { collector } = await startFlow4({
2737
+ destinations: {
2738
+ demo: {
2739
+ code: destination,
2740
+ config: {
2741
+ mapping: mappingObj
2742
+ },
2743
+ env: {
2744
+ elb: setOutput
2745
+ }
2746
+ }
2747
+ }
2748
+ });
2749
+ await collector.push(eventObj);
2750
+ } catch (error) {
2751
+ if (error instanceof Error) {
2752
+ setOutput(`// Error: ${error.message}`);
2753
+ } else {
2754
+ setOutput(`// Error: ${String(error)}`);
2755
+ }
2756
+ }
2757
+ })();
2758
+ }, [event, mapping, destination]);
2759
+ return /* @__PURE__ */ jsx17(
2760
+ CodeBox,
2761
+ {
2762
+ code: output,
2763
+ language: "javascript",
2764
+ disabled: true,
2765
+ label,
2766
+ wordWrap
2767
+ }
2768
+ );
2769
+ }
2770
+
2689
2771
  // src/components/organisms/config-editor/config-editor-box.tsx
2690
- import { useState as useState36, useMemo as useMemo5, useCallback as useCallback18 } from "react";
2772
+ import { useState as useState36, useMemo as useMemo6, useCallback as useCallback18 } from "react";
2691
2773
 
2692
2774
  // src/components/organisms/config-editor/config-editor-tabs.tsx
2693
- import { useEffect as useEffect23, useState as useState35, useMemo as useMemo4 } from "react";
2775
+ import { useEffect as useEffect24, useState as useState35, useMemo as useMemo5 } from "react";
2694
2776
 
2695
2777
  // src/hooks/useMappingState.ts
2696
- import { useState as useState15, useCallback as useCallback12, useRef as useRef6 } from "react";
2778
+ import { useState as useState15, useCallback as useCallback12, useRef as useRef7 } from "react";
2697
2779
 
2698
2780
  // src/utils/mapping-path.ts
2699
2781
  function getValueAtPath(obj, path) {
@@ -2778,7 +2860,7 @@ function getParentPath(path) {
2778
2860
  // src/hooks/useMappingState.ts
2779
2861
  function useMappingState(initialMapping, onChange) {
2780
2862
  const [config, setConfig] = useState15(initialMapping);
2781
- const isCallingOnChange = useRef6(false);
2863
+ const isCallingOnChange = useRef7(false);
2782
2864
  const updateConfig = useCallback12(
2783
2865
  (newConfig) => {
2784
2866
  setConfig(newConfig);
@@ -3609,7 +3691,7 @@ function MappingBreadcrumb({
3609
3691
  }
3610
3692
 
3611
3693
  // src/components/atoms/mapping-confirm-button.tsx
3612
- import { useState as useState18, useEffect as useEffect11, useRef as useRef7 } from "react";
3694
+ import { useState as useState18, useEffect as useEffect12, useRef as useRef8 } from "react";
3613
3695
  import { jsx as jsx19 } from "react/jsx-runtime";
3614
3696
  var TrashIcon = () => /* @__PURE__ */ jsx19(
3615
3697
  "svg",
@@ -3636,8 +3718,8 @@ function MappingConfirmButton({
3636
3718
  className = ""
3637
3719
  }) {
3638
3720
  const [isConfirming, setIsConfirming] = useState18(false);
3639
- const buttonRef = useRef7(null);
3640
- useEffect11(() => {
3721
+ const buttonRef = useRef8(null);
3722
+ useEffect12(() => {
3641
3723
  if (!isConfirming) return;
3642
3724
  const handleClickOutside = (e) => {
3643
3725
  if (buttonRef.current && !buttonRef.current.contains(e.target)) {
@@ -3782,7 +3864,7 @@ function MappingNavigationHeader({
3782
3864
  }
3783
3865
 
3784
3866
  // src/components/molecules/config-tree-sidebar.tsx
3785
- import { useState as useState19, useRef as useRef8, useEffect as useEffect12 } from "react";
3867
+ import { useState as useState19, useRef as useRef9, useEffect as useEffect13 } from "react";
3786
3868
 
3787
3869
  // src/components/atoms/mapping-input.tsx
3788
3870
  import { jsx as jsx21 } from "react/jsx-runtime";
@@ -3905,14 +3987,14 @@ function ConfigTreeNodeComponent({
3905
3987
  const [isAddingAction, setIsAddingAction] = useState19(false);
3906
3988
  const [newActionName, setNewActionName] = useState19("");
3907
3989
  const [actionExists, setActionExists] = useState19(false);
3908
- const inputRef = useRef8(null);
3990
+ const inputRef = useRef9(null);
3909
3991
  const isEntityNode = node.type === "entity" && node.path.length === 2 && node.path[0] === "mapping";
3910
- useEffect12(() => {
3992
+ useEffect13(() => {
3911
3993
  if (isAddingAction && inputRef.current) {
3912
3994
  inputRef.current.focus();
3913
3995
  }
3914
3996
  }, [isAddingAction]);
3915
- useEffect12(() => {
3997
+ useEffect13(() => {
3916
3998
  if (isEntityNode && newActionName) {
3917
3999
  const exists = node.children?.some((child) => child.label === newActionName) ?? false;
3918
4000
  setActionExists(exists);
@@ -4079,13 +4161,13 @@ function ConfigTreeSidebar({
4079
4161
  const [isAddingEntity, setIsAddingEntity] = useState19(false);
4080
4162
  const [newEntityName, setNewEntityName] = useState19("");
4081
4163
  const [entityExists, setEntityExists] = useState19(false);
4082
- const entityInputRef = useRef8(null);
4083
- useEffect12(() => {
4164
+ const entityInputRef = useRef9(null);
4165
+ useEffect13(() => {
4084
4166
  if (isAddingEntity && entityInputRef.current) {
4085
4167
  entityInputRef.current.focus();
4086
4168
  }
4087
4169
  }, [isAddingEntity]);
4088
- useEffect12(() => {
4170
+ useEffect13(() => {
4089
4171
  if (newEntityName) {
4090
4172
  const mappingNode = tree.find((node) => node.key === "mapping");
4091
4173
  const exists = mappingNode?.children?.some((child) => child.label === newEntityName) ?? false;
@@ -4226,7 +4308,7 @@ function ConfigTreeSidebar({
4226
4308
  }
4227
4309
 
4228
4310
  // src/components/molecules/mapping-entity-pane.tsx
4229
- import { useState as useState20, useEffect as useEffect13 } from "react";
4311
+ import { useState as useState20, useEffect as useEffect14 } from "react";
4230
4312
 
4231
4313
  // src/components/atoms/pane-header.tsx
4232
4314
  import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
@@ -4332,7 +4414,7 @@ function MappingEntityPane({
4332
4414
  const entity = path[0];
4333
4415
  const entityConfig = mappingState.actions.getValue([entity]);
4334
4416
  const actions = entityConfig && typeof entityConfig === "object" ? Object.keys(entityConfig).sort() : [];
4335
- useEffect13(() => {
4417
+ useEffect14(() => {
4336
4418
  if (newActionName) {
4337
4419
  const exists = actions.includes(newActionName);
4338
4420
  setActionExists(exists);
@@ -5324,7 +5406,7 @@ function MappingKeyPaneView({
5324
5406
  }
5325
5407
 
5326
5408
  // src/components/molecules/mapping-function-pane-base.tsx
5327
- import { useState as useState22, useEffect as useEffect14 } from "react";
5409
+ import { useState as useState22, useEffect as useEffect15 } from "react";
5328
5410
 
5329
5411
  // src/utils/code-normalizer.ts
5330
5412
  function normalizeCode(code) {
@@ -5347,7 +5429,7 @@ function MappingFunctionPaneBase({
5347
5429
  const value = mappingState.actions.getValue(path);
5348
5430
  const initialCode = typeof value === "string" ? value : defaultCode;
5349
5431
  const [code, setCode] = useState22(initialCode);
5350
- useEffect14(() => {
5432
+ useEffect15(() => {
5351
5433
  const currentValue = mappingState.actions.getValue(path);
5352
5434
  const newCode = typeof currentValue === "string" ? currentValue : defaultCode;
5353
5435
  setCode(newCode);
@@ -5991,7 +6073,7 @@ function MappingBatchPaneView({
5991
6073
  }
5992
6074
 
5993
6075
  // src/components/molecules/mapping-consent-pane-view.tsx
5994
- import { useState as useState23, useMemo as useMemo3 } from "react";
6076
+ import { useState as useState23, useMemo as useMemo4 } from "react";
5995
6077
 
5996
6078
  // src/components/atoms/consent-state-tile.tsx
5997
6079
  import { jsx as jsx40, jsxs as jsxs30 } from "react/jsx-runtime";
@@ -6112,7 +6194,7 @@ function MappingConsentPaneView({
6112
6194
  const [newStateName, setNewStateName] = useState23("");
6113
6195
  const value = mappingState.actions.getValue(path);
6114
6196
  const currentConsent = value && typeof value === "object" ? value : {};
6115
- const discoveredStates = useMemo3(
6197
+ const discoveredStates = useMemo4(
6116
6198
  () => scanMappingForConsentStates(mappingState.config),
6117
6199
  [mappingState.config]
6118
6200
  );
@@ -6151,7 +6233,7 @@ function MappingConsentPaneView({
6151
6233
  setNewStateName("");
6152
6234
  }
6153
6235
  };
6154
- const { title, description } = useMemo3(
6236
+ const { title, description } = useMemo4(
6155
6237
  () => getPathDescription(path, mappingState.config),
6156
6238
  [path, mappingState.config]
6157
6239
  );
@@ -6577,7 +6659,7 @@ function MappingBooleanWidget(props) {
6577
6659
  }
6578
6660
 
6579
6661
  // src/components/atoms/mapping-consent.tsx
6580
- import { useState as useState26, useEffect as useEffect15 } from "react";
6662
+ import { useState as useState26, useEffect as useEffect16 } from "react";
6581
6663
 
6582
6664
  // src/components/atoms/mapping-collapsible.tsx
6583
6665
  import { useState as useState25 } from "react";
@@ -6899,7 +6981,7 @@ function MappingConsentWidget(props) {
6899
6981
  const title = schema?.title || "Consent";
6900
6982
  const description = schema?.description;
6901
6983
  const [isExpanded, setIsExpanded] = useState26(hasConsent);
6902
- useEffect15(() => {
6984
+ useEffect16(() => {
6903
6985
  setIsExpanded(hasConsent);
6904
6986
  }, [hasConsent]);
6905
6987
  const handleAddConsent = () => {
@@ -6981,7 +7063,7 @@ function MappingConsentWidget(props) {
6981
7063
  }
6982
7064
 
6983
7065
  // src/components/atoms/mapping-value.tsx
6984
- import React15, { useState as useState27, useEffect as useEffect16 } from "react";
7066
+ import React15, { useState as useState27, useEffect as useEffect17 } from "react";
6985
7067
 
6986
7068
  // src/components/atoms/field-header.tsx
6987
7069
  import { Fragment as Fragment8, jsx as jsx51, jsxs as jsxs41 } from "react/jsx-runtime";
@@ -7061,7 +7143,7 @@ function MappingValueWidget(props) {
7061
7143
  const [selectedType, setSelectedType] = useState27(getCurrentType);
7062
7144
  const userSelectedTypeRef = React15.useRef(false);
7063
7145
  const prevValueRef = React15.useRef(value);
7064
- useEffect16(() => {
7146
+ useEffect17(() => {
7065
7147
  const prevType = typeof prevValueRef.current;
7066
7148
  const currentType = typeof value;
7067
7149
  const isMajorTypeChange = prevType !== currentType || value === void 0 && prevValueRef.current !== void 0 || value !== void 0 && prevValueRef.current === void 0;
@@ -7908,7 +7990,7 @@ function MappingValidateField(props) {
7908
7990
  }
7909
7991
 
7910
7992
  // src/components/atoms/mapping-data.tsx
7911
- import { useState as useState29, useEffect as useEffect17, useRef as useRef9, useCallback as useCallback15 } from "react";
7993
+ import { useState as useState29, useEffect as useEffect18, useRef as useRef10, useCallback as useCallback15 } from "react";
7912
7994
 
7913
7995
  // src/schemas/value-config-schema.ts
7914
7996
  var valueConfigSchema = {
@@ -8150,8 +8232,8 @@ function MappingDataWidget(props) {
8150
8232
  const description = schema?.description;
8151
8233
  const [showForm, setShowForm] = useState29(hasData);
8152
8234
  const [isExpanded, setIsExpanded] = useState29(hasData);
8153
- const prevValueRef = useRef9(value);
8154
- useEffect17(() => {
8235
+ const prevValueRef = useRef10(value);
8236
+ useEffect18(() => {
8155
8237
  const newHasData = value && typeof value === "object" && Object.keys(value).length > 0;
8156
8238
  setShowForm(!!newHasData);
8157
8239
  setIsExpanded(!!newHasData);
@@ -8234,7 +8316,7 @@ function MappingDataField(props) {
8234
8316
  }
8235
8317
 
8236
8318
  // src/components/atoms/mapping-settings.tsx
8237
- import { useState as useState30, useEffect as useEffect18, useRef as useRef10, useCallback as useCallback16 } from "react";
8319
+ import { useState as useState30, useEffect as useEffect19, useRef as useRef11, useCallback as useCallback16 } from "react";
8238
8320
  import { jsx as jsx67, jsxs as jsxs51 } from "react/jsx-runtime";
8239
8321
  function MappingSettingsWidget(props) {
8240
8322
  const {
@@ -8256,8 +8338,8 @@ function MappingSettingsWidget(props) {
8256
8338
  const hasSchema = destinationSchema && destinationSchema.properties && Object.keys(destinationSchema.properties).length > 0;
8257
8339
  const [showForm, setShowForm] = useState30(hasSettings);
8258
8340
  const [isExpanded, setIsExpanded] = useState30(hasSettings);
8259
- const prevValueRef = useRef10(value);
8260
- useEffect18(() => {
8341
+ const prevValueRef = useRef11(value);
8342
+ useEffect19(() => {
8261
8343
  const newHasSettings = value && typeof value === "object" && Object.keys(value).length > 0;
8262
8344
  setShowForm(!!newHasSettings);
8263
8345
  setIsExpanded(!!newHasSettings);
@@ -8415,7 +8497,7 @@ function MappingObjectExplorerField(props) {
8415
8497
  }
8416
8498
 
8417
8499
  // src/components/molecules/mapping-map-field.tsx
8418
- import { useState as useState31, useEffect as useEffect19, useRef as useRef11 } from "react";
8500
+ import { useState as useState31, useEffect as useEffect20, useRef as useRef12 } from "react";
8419
8501
 
8420
8502
  // src/components/atoms/mapping-map-entry.tsx
8421
8503
  import { jsx as jsx70, jsxs as jsxs52 } from "react/jsx-runtime";
@@ -8545,15 +8627,15 @@ function MappingMapField(props) {
8545
8627
  );
8546
8628
  const hasEntries = entries.length > 0;
8547
8629
  const [isExpanded, setIsExpanded] = useState31(hasEntries);
8548
- const prevFormDataRef = useRef11(formData);
8549
- useEffect19(() => {
8630
+ const prevFormDataRef = useRef12(formData);
8631
+ useEffect20(() => {
8550
8632
  if (prevFormDataRef.current === formData) {
8551
8633
  return;
8552
8634
  }
8553
8635
  prevFormDataRef.current = formData;
8554
8636
  setEntries(objectToEntries(formData));
8555
8637
  }, [formData]);
8556
- useEffect19(() => {
8638
+ useEffect20(() => {
8557
8639
  setIsExpanded(hasEntries);
8558
8640
  }, [hasEntries]);
8559
8641
  const duplicateKeys = /* @__PURE__ */ new Set();
@@ -8640,7 +8722,7 @@ function MappingMapField(props) {
8640
8722
  }
8641
8723
 
8642
8724
  // src/components/molecules/mapping-set-field.tsx
8643
- import { useState as useState32, useEffect as useEffect20, useRef as useRef12 } from "react";
8725
+ import { useState as useState32, useEffect as useEffect21, useRef as useRef13 } from "react";
8644
8726
 
8645
8727
  // src/components/atoms/mapping-set-entry.tsx
8646
8728
  import { jsx as jsx72, jsxs as jsxs54 } from "react/jsx-runtime";
@@ -8774,8 +8856,8 @@ function MappingSetField(props) {
8774
8856
  );
8775
8857
  const hasEntries = entries.length > 0;
8776
8858
  const [isExpanded, setIsExpanded] = useState32(hasEntries);
8777
- const prevFormDataRef = useRef12(formData);
8778
- useEffect20(() => {
8859
+ const prevFormDataRef = useRef13(formData);
8860
+ useEffect21(() => {
8779
8861
  if (prevFormDataRef.current === formData) {
8780
8862
  return;
8781
8863
  }
@@ -8798,7 +8880,7 @@ function MappingSetField(props) {
8798
8880
  });
8799
8881
  setEntries(newEntries);
8800
8882
  }, [formData]);
8801
- useEffect20(() => {
8883
+ useEffect21(() => {
8802
8884
  setIsExpanded(hasEntries);
8803
8885
  }, [hasEntries]);
8804
8886
  const handleEntriesChange = (newEntries) => {
@@ -8921,7 +9003,7 @@ function MappingSetField(props) {
8921
9003
  }
8922
9004
 
8923
9005
  // src/components/molecules/mapping-loop-field.tsx
8924
- import { useState as useState33, useEffect as useEffect21, useRef as useRef13 } from "react";
9006
+ import { useState as useState33, useEffect as useEffect22, useRef as useRef14 } from "react";
8925
9007
  import { jsx as jsx74, jsxs as jsxs56 } from "react/jsx-runtime";
8926
9008
  function MappingLoopField(props) {
8927
9009
  const { formData, onChange, schema, disabled, readonly } = props;
@@ -8946,8 +9028,8 @@ function MappingLoopField(props) {
8946
9028
  );
8947
9029
  const [transform, setTransform] = useState33(() => parseFormData(formData)[1]);
8948
9030
  const [isExpanded, setIsExpanded] = useState33(false);
8949
- const prevFormDataRef = useRef13(formData);
8950
- useEffect21(() => {
9031
+ const prevFormDataRef = useRef14(formData);
9032
+ useEffect22(() => {
8951
9033
  if (prevFormDataRef.current === formData) {
8952
9034
  return;
8953
9035
  }
@@ -9321,7 +9403,7 @@ function MappingMapPaneViewRJSF({
9321
9403
  }
9322
9404
 
9323
9405
  // src/components/atoms/mapping-enum-select.tsx
9324
- import { useState as useState34, useRef as useRef14, useEffect as useEffect22 } from "react";
9406
+ import { useState as useState34, useRef as useRef15, useEffect as useEffect23 } from "react";
9325
9407
  import { jsx as jsx78, jsxs as jsxs58 } from "react/jsx-runtime";
9326
9408
  function MappingEnumSelect({
9327
9409
  value,
@@ -9335,19 +9417,19 @@ function MappingEnumSelect({
9335
9417
  const [highlightedIndex, setHighlightedIndex] = useState34(0);
9336
9418
  const [inputValue, setInputValue] = useState34(String(value || ""));
9337
9419
  const [hasTyped, setHasTyped] = useState34(false);
9338
- const containerRef = useRef14(null);
9339
- const inputRef = useRef14(null);
9340
- const dropdownRef = useRef14(null);
9341
- useEffect22(() => {
9420
+ const containerRef = useRef15(null);
9421
+ const inputRef = useRef15(null);
9422
+ const dropdownRef = useRef15(null);
9423
+ useEffect23(() => {
9342
9424
  setInputValue(String(value || ""));
9343
9425
  setHasTyped(false);
9344
9426
  }, [value]);
9345
- useEffect22(() => {
9427
+ useEffect23(() => {
9346
9428
  if (isOpen) {
9347
9429
  setHighlightedIndex(0);
9348
9430
  }
9349
9431
  }, [isOpen]);
9350
- useEffect22(() => {
9432
+ useEffect23(() => {
9351
9433
  const handleClickOutside = (event) => {
9352
9434
  if (containerRef.current && !containerRef.current.contains(event.target)) {
9353
9435
  setIsOpen(false);
@@ -9361,7 +9443,7 @@ function MappingEnumSelect({
9361
9443
  return () => document.removeEventListener("mousedown", handleClickOutside);
9362
9444
  }
9363
9445
  }, [isOpen, hasTyped, inputValue, onChange, type]);
9364
- useEffect22(() => {
9446
+ useEffect23(() => {
9365
9447
  if (isOpen && dropdownRef.current && dropdownRef.current.children[highlightedIndex]) {
9366
9448
  const highlighted = dropdownRef.current.children[highlightedIndex];
9367
9449
  if (highlighted) {
@@ -10326,18 +10408,18 @@ function ConfigEditorTabs({
10326
10408
  });
10327
10409
  const treeState = useTreeState(initialNavigationState?.expandedPaths || [[]]);
10328
10410
  const [codeViewActive, setCodeViewActive] = useState35(false);
10329
- const configTree = useMemo4(
10411
+ const configTree = useMemo5(
10330
10412
  () => buildTree(config, structure, schemas, sections),
10331
10413
  [config, structure, schemas, sections]
10332
10414
  );
10333
- const validationErrors = useMemo4(
10415
+ const validationErrors = useMemo5(
10334
10416
  () => validateConfig(config, schemas),
10335
10417
  [config, schemas]
10336
10418
  );
10337
10419
  const activeTab = navigation.openTabs.find(
10338
10420
  (tab) => tab.id === navigation.activeTabId
10339
10421
  );
10340
- const currentCode = useMemo4(() => {
10422
+ const currentCode = useMemo5(() => {
10341
10423
  if (!activeTab || activeTab.path.length === 0) {
10342
10424
  return JSON.stringify(config, null, 2);
10343
10425
  }
@@ -10365,7 +10447,7 @@ function ConfigEditorTabs({
10365
10447
  } catch (e) {
10366
10448
  }
10367
10449
  };
10368
- useEffect23(() => {
10450
+ useEffect24(() => {
10369
10451
  if (navigation.navigationHistory.length === 0) {
10370
10452
  navigation.switchToTab("");
10371
10453
  if (initialNavigationState && initialNavigationState.currentPath.length > 0) {
@@ -10376,7 +10458,7 @@ function ConfigEditorTabs({
10376
10458
  }
10377
10459
  }
10378
10460
  }, []);
10379
- useEffect23(() => {
10461
+ useEffect24(() => {
10380
10462
  if (onNavigationStateChange && activeTab) {
10381
10463
  onNavigationStateChange({
10382
10464
  currentPath: activeTab.path,
@@ -10387,7 +10469,7 @@ function ConfigEditorTabs({
10387
10469
  });
10388
10470
  }
10389
10471
  }, [activeTab, treeState.expandedPaths, onNavigationStateChange]);
10390
- useEffect23(() => {
10472
+ useEffect24(() => {
10391
10473
  if (activeTab && activeTab.path.length > 0) {
10392
10474
  for (let i = 1; i <= activeTab.path.length; i++) {
10393
10475
  const pathToExpand = activeTab.path.slice(0, i);
@@ -10532,8 +10614,8 @@ function ConfigEditorBox({
10532
10614
  }) {
10533
10615
  const [activeTab, setActiveTab] = useState36(initialTab);
10534
10616
  const [persistedNavigationState, setPersistedNavigationState] = useState36(initialNavigationState || null);
10535
- const configJson = useMemo5(() => JSON.stringify(config, null, 2), [config]);
10536
- const buttons = useMemo5(
10617
+ const configJson = useMemo6(() => JSON.stringify(config, null, 2), [config]);
10618
+ const buttons = useMemo6(
10537
10619
  () => [
10538
10620
  {
10539
10621
  label: "Visual",
@@ -10607,7 +10689,7 @@ function ConfigEditor(props) {
10607
10689
  }
10608
10690
 
10609
10691
  // node_modules/@iconify/react/dist/iconify.js
10610
- import { createElement, forwardRef, useState as useState37, useEffect as useEffect24 } from "react";
10692
+ import { createElement, forwardRef, useState as useState37, useEffect as useEffect25 } from "react";
10611
10693
  function getIconsTree(data, names) {
10612
10694
  const icons = data.icons;
10613
10695
  const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
@@ -11971,11 +12053,11 @@ function IconComponent(props) {
11971
12053
  }
11972
12054
  }
11973
12055
  }
11974
- useEffect24(() => {
12056
+ useEffect25(() => {
11975
12057
  setMounted(true);
11976
12058
  return cleanup;
11977
12059
  }, []);
11978
- useEffect24(() => {
12060
+ useEffect25(() => {
11979
12061
  if (mounted) {
11980
12062
  updateState();
11981
12063
  }
@@ -15077,7 +15159,7 @@ function FlowSectionBox({ section }) {
15077
15159
  }
15078
15160
 
15079
15161
  // src/components/molecules/code-snippet.tsx
15080
- import { useState as useState38, useEffect as useEffect25 } from "react";
15162
+ import { useState as useState38, useEffect as useEffect26 } from "react";
15081
15163
  import { jsx as jsx89 } from "react/jsx-runtime";
15082
15164
  function CodeSnippet(props) {
15083
15165
  const {
@@ -15093,7 +15175,7 @@ function CodeSnippet(props) {
15093
15175
  } = props;
15094
15176
  const snippetClassName = `elb-code-snippet ${className || ""}`.trim();
15095
15177
  const [formattedCode, setFormattedCode] = useState38(code);
15096
- useEffect25(() => {
15178
+ useEffect26(() => {
15097
15179
  if (format3 && code) {
15098
15180
  formatCode(code, language).then(setFormattedCode);
15099
15181
  } else {
@@ -15117,7 +15199,7 @@ function CodeSnippet(props) {
15117
15199
  }
15118
15200
 
15119
15201
  // src/components/molecules/flow-map/FlowMap.tsx
15120
- import React23, { useEffect as useEffect26, useRef as useRef15 } from "react";
15202
+ import React23, { useEffect as useEffect27, useRef as useRef16 } from "react";
15121
15203
  import rough from "roughjs";
15122
15204
  import { Fragment as Fragment11, jsx as jsx90, jsxs as jsxs67 } from "react/jsx-runtime";
15123
15205
  function RoughRect({
@@ -15128,8 +15210,8 @@ function RoughRect({
15128
15210
  fill,
15129
15211
  stroke
15130
15212
  }) {
15131
- const ref = useRef15(null);
15132
- useEffect26(() => {
15213
+ const ref = useRef16(null);
15214
+ useEffect27(() => {
15133
15215
  if (!ref.current) return;
15134
15216
  const svg = ref.current.ownerSVGElement;
15135
15217
  if (!svg) return;
@@ -15168,8 +15250,8 @@ function RoughCircle({
15168
15250
  fill,
15169
15251
  stroke
15170
15252
  }) {
15171
- const ref = useRef15(null);
15172
- useEffect26(() => {
15253
+ const ref = useRef16(null);
15254
+ useEffect27(() => {
15173
15255
  if (!ref.current) return;
15174
15256
  const svg = ref.current.ownerSVGElement;
15175
15257
  if (!svg) return;
@@ -15226,8 +15308,8 @@ function RoughArrow({
15226
15308
  arrowSize = 8,
15227
15309
  centerY
15228
15310
  }) {
15229
- const ref = useRef15(null);
15230
- useEffect26(() => {
15311
+ const ref = useRef16(null);
15312
+ useEffect27(() => {
15231
15313
  if (!ref.current) return;
15232
15314
  const svg = ref.current.ownerSVGElement;
15233
15315
  if (!svg) return;
@@ -15563,7 +15645,7 @@ function FlowMap({
15563
15645
  return aIdx - bIdx;
15564
15646
  }
15565
15647
  );
15566
- const containerRef = useRef15(null);
15648
+ const containerRef = useRef16(null);
15567
15649
  const hasDescription = stageBefore?.description || sourceEntries.some(([, s]) => s.description) || preTransformerList.some((p) => p.config.description) || collector?.description || postTransformerList.some((p) => p.config.description) || destinationEntries.some(([, d]) => d.description) || stageAfter?.description || destinationEntries.some(([, d]) => d.after?.description);
15568
15650
  const hasLink = stageBefore?.link !== false || sourceEntries.some(([, s]) => s.link !== false) || preTransformerList.some((p) => p.config.link !== false) || collector?.link !== false || postTransformerList.some((p) => p.config.link !== false) || destinationEntries.some(([, d]) => d.link !== false) || stageAfter?.link !== false || destinationEntries.some(([, d]) => d.after?.link !== false);
15569
15651
  const stageMarkerPositions = [
@@ -15739,6 +15821,14 @@ function FlowMap({
15739
15821
  if (directDests.length === 1 && !hasChainOutput) {
15740
15822
  const destPos = stages[`destination-${directDests[0]}`];
15741
15823
  y = destPos ? destPos.y : stackedCenterY - boxHeight / 2;
15824
+ } else if (directDests.length > 1 && !hasChainOutput) {
15825
+ const destYPositions = directDests.map((d) => stages[`destination-${d}`]?.y).filter((pos2) => pos2 !== void 0);
15826
+ if (destYPositions.length > 0) {
15827
+ const avgY = destYPositions.reduce((sum, pos2) => sum + pos2, 0) / destYPositions.length;
15828
+ y = avgY;
15829
+ } else {
15830
+ y = stackedCenterY - boxHeight / 2;
15831
+ }
15742
15832
  } else {
15743
15833
  y = stackedCenterY - boxHeight / 2;
15744
15834
  }
@@ -15894,9 +15984,6 @@ function FlowMap({
15894
15984
  if (destConfig.before && postTransformers?.[destConfig.before]) {
15895
15985
  return stages[`post-${destConfig.before}`];
15896
15986
  }
15897
- if (postTransformerList.length > 0) {
15898
- return stages[`post-${postTransformerList[postTransformerList.length - 1].name}`];
15899
- }
15900
15987
  return collectorPos;
15901
15988
  };
15902
15989
  return /* @__PURE__ */ jsxs67(Fragment11, { children: [