@almadar/ui 2.27.4 → 2.28.0

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.
@@ -33573,6 +33573,119 @@ function EventDispatcherTab({ traits: traits2, schema }) {
33573
33573
  ] });
33574
33574
  }
33575
33575
  EventDispatcherTab.displayName = "EventDispatcherTab";
33576
+ function ServerResponseRow({ sr }) {
33577
+ const entityEntries = Object.entries(sr.dataEntities);
33578
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-4 pl-2 border-l border-purple-700/50 py-0.5 text-[10px] font-mono", children: [
33579
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
33580
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: sr.success ? "text-green-400" : "text-red-400", children: [
33581
+ sr.success ? "\u2713" : "\u2717",
33582
+ " server"
33583
+ ] }),
33584
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-purple-300", children: sr.orbitalName }),
33585
+ sr.clientEffects > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-1 rounded bg-purple-900/50 text-purple-300", children: [
33586
+ sr.clientEffects,
33587
+ " clientEffect",
33588
+ sr.clientEffects !== 1 ? "s" : ""
33589
+ ] }),
33590
+ sr.emittedEvents.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-1 rounded bg-blue-900/50 text-blue-300", children: [
33591
+ "emit: ",
33592
+ sr.emittedEvents.join(", ")
33593
+ ] }),
33594
+ sr.error && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-1 rounded bg-red-900/50 text-red-400 truncate max-w-[300px]", children: sr.error })
33595
+ ] }),
33596
+ entityEntries.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1 mt-0.5", children: entityEntries.map(([name, count]) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-1 rounded bg-gray-800 text-gray-300", children: [
33597
+ name,
33598
+ ": ",
33599
+ count,
33600
+ " row",
33601
+ count !== 1 ? "s" : ""
33602
+ ] }, name)) })
33603
+ ] });
33604
+ }
33605
+ function TransitionRow({ trace }) {
33606
+ const isServerEntry = !!trace.serverResponse && trace.traitName.startsWith("server:");
33607
+ const hasFailedEffects = trace.effects.some((e) => e.status === "failed");
33608
+ if (isServerEntry && trace.serverResponse) {
33609
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-0.5 border-b border-gray-800 last:border-0", children: [
33610
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 text-xs font-mono", children: [
33611
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-1.5 w-1.5 h-1.5 rounded-full flex-shrink-0 bg-purple-500" }),
33612
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "warning", size: "sm", className: "flex-shrink-0", children: trace.event }),
33613
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-purple-400 flex-shrink-0", children: "server response" })
33614
+ ] }),
33615
+ /* @__PURE__ */ jsxRuntime.jsx(ServerResponseRow, { sr: trace.serverResponse })
33616
+ ] });
33617
+ }
33618
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-0.5 border-b border-gray-800 last:border-0", children: [
33619
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 text-xs font-mono", children: [
33620
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
33621
+ "mt-1.5 w-1.5 h-1.5 rounded-full flex-shrink-0",
33622
+ hasFailedEffects ? "bg-red-500" : "bg-green-500"
33623
+ ) }),
33624
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "info", size: "sm", className: "flex-shrink-0", children: trace.event }),
33625
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-300 flex-shrink-0", children: trace.traitName }),
33626
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-400 flex-shrink-0", children: [
33627
+ trace.from,
33628
+ " ",
33629
+ "\u2192",
33630
+ " ",
33631
+ trace.to
33632
+ ] })
33633
+ ] }),
33634
+ trace.effects.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1 ml-6 mt-0.5", children: trace.effects.map((eff, i) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn(
33635
+ "px-1 rounded text-[10px]",
33636
+ eff.status === "executed" ? "bg-green-900/50 text-green-400" : eff.status === "failed" ? "bg-red-900/50 text-red-400" : "bg-yellow-900/50 text-yellow-400"
33637
+ ), children: [
33638
+ eff.status === "executed" ? "\u2713" : eff.status === "failed" ? "\u2717" : "-",
33639
+ " ",
33640
+ eff.type,
33641
+ eff.args.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-500 ml-0.5", children: JSON.stringify(eff.args).slice(0, 40) })
33642
+ ] }, i)) }),
33643
+ trace.serverResponse && /* @__PURE__ */ jsxRuntime.jsx(ServerResponseRow, { sr: trace.serverResponse })
33644
+ ] });
33645
+ }
33646
+ function VerifyModePanel({
33647
+ className,
33648
+ failedChecks,
33649
+ transitions,
33650
+ traitStates,
33651
+ serverCount,
33652
+ localCount
33653
+ }) {
33654
+ const scrollRef = React91__namespace.useRef(null);
33655
+ const prevCountRef = React91__namespace.useRef(0);
33656
+ React91__namespace.useEffect(() => {
33657
+ if (transitions.length > prevCountRef.current && scrollRef.current) {
33658
+ scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
33659
+ }
33660
+ prevCountRef.current = transitions.length;
33661
+ }, [transitions.length]);
33662
+ return /* @__PURE__ */ jsxRuntime.jsxs(
33663
+ "div",
33664
+ {
33665
+ className: cn(
33666
+ "runtime-debugger runtime-debugger--verify",
33667
+ "fixed bottom-0 left-0 right-0 z-[9999] h-[35vh] flex flex-col bg-gray-900 text-white border-t-2 border-cyan-500",
33668
+ className
33669
+ ),
33670
+ "data-testid": "debugger-verify",
33671
+ children: [
33672
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-1.5 flex items-center gap-3 text-xs font-mono border-b border-gray-700 flex-shrink-0", children: [
33673
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: failedChecks > 0 ? "danger" : "success", size: "sm", children: failedChecks > 0 ? `${failedChecks} fail` : "OK" }),
33674
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-400", children: [
33675
+ localCount,
33676
+ " local"
33677
+ ] }),
33678
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-purple-400", children: [
33679
+ serverCount,
33680
+ " server"
33681
+ ] }),
33682
+ traitStates && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-cyan-400 truncate max-w-[400px]", children: traitStates })
33683
+ ] }),
33684
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: scrollRef, className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 py-1", children: transitions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-500 text-xs font-mono py-2 text-center", children: "Waiting for transitions..." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0.5", children: transitions.map((trace) => /* @__PURE__ */ jsxRuntime.jsx(TransitionRow, { trace }, trace.id)) }) }) })
33685
+ ]
33686
+ }
33687
+ );
33688
+ }
33576
33689
  function RuntimeDebugger({
33577
33690
  position = "bottom-right",
33578
33691
  defaultCollapsed = true,
@@ -33722,51 +33835,17 @@ function RuntimeDebugger({
33722
33835
  }
33723
33836
  if (mode === "verify") {
33724
33837
  const traitStates = debugData.traits.map((t) => `${t.name}:${t.currentState}`).join(" | ");
33725
- return /* @__PURE__ */ jsxRuntime.jsxs(
33726
- "div",
33838
+ const serverEntries = verification.transitions.filter((t) => t.serverResponse);
33839
+ const localEntries = verification.transitions.filter((t) => !t.serverResponse);
33840
+ return /* @__PURE__ */ jsxRuntime.jsx(
33841
+ VerifyModePanel,
33727
33842
  {
33728
- className: cn(
33729
- "runtime-debugger runtime-debugger--verify",
33730
- "fixed bottom-0 left-0 right-0 z-[9999] h-[35vh] flex flex-col bg-gray-900 text-white border-t-2 border-cyan-500",
33731
- className
33732
- ),
33733
- "data-testid": "debugger-verify",
33734
- children: [
33735
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-1.5 flex items-center gap-3 text-xs font-mono border-b border-gray-700 flex-shrink-0", children: [
33736
- /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: failedChecks > 0 ? "danger" : "success", size: "sm", children: failedChecks > 0 ? `${failedChecks} fail` : "OK" }),
33737
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-400", children: [
33738
- verification.transitions.length,
33739
- " transitions"
33740
- ] }),
33741
- traitStates && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-cyan-400 truncate max-w-[400px]", children: traitStates })
33742
- ] }),
33743
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 py-1", children: verification.transitions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-500 text-xs font-mono py-2 text-center", children: "Waiting for transitions..." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0.5", children: verification.transitions.map((trace) => {
33744
- const hasFailedEffects = trace.effects.some((e) => e.status === "failed");
33745
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 text-xs font-mono py-0.5 border-b border-gray-800 last:border-0", children: [
33746
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
33747
- "mt-1.5 w-1.5 h-1.5 rounded-full flex-shrink-0",
33748
- hasFailedEffects ? "bg-red-500" : "bg-green-500"
33749
- ) }),
33750
- /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "info", size: "sm", className: "flex-shrink-0", children: trace.event }),
33751
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-400 flex-shrink-0", children: [
33752
- trace.from,
33753
- " ",
33754
- "\u2192",
33755
- " ",
33756
- trace.to
33757
- ] }),
33758
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-wrap gap-1 ml-1", children: trace.effects.map((eff, i) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn(
33759
- "px-1 rounded text-[10px]",
33760
- eff.status === "executed" ? "bg-green-900/50 text-green-400" : eff.status === "failed" ? "bg-red-900/50 text-red-400" : "bg-yellow-900/50 text-yellow-400"
33761
- ), children: [
33762
- eff.status === "executed" ? "\u2713" : eff.status === "failed" ? "\u2717" : "-",
33763
- " ",
33764
- eff.type,
33765
- eff.args.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-500 ml-0.5", children: JSON.stringify(eff.args).slice(0, 30) })
33766
- ] }, i)) })
33767
- ] }, trace.id);
33768
- }) }) }) })
33769
- ]
33843
+ className,
33844
+ failedChecks,
33845
+ transitions: verification.transitions,
33846
+ traitStates,
33847
+ serverCount: serverEntries.length,
33848
+ localCount: localEntries.length
33770
33849
  }
33771
33850
  );
33772
33851
  }
@@ -33543,6 +33543,119 @@ function EventDispatcherTab({ traits: traits2, schema }) {
33543
33543
  ] });
33544
33544
  }
33545
33545
  EventDispatcherTab.displayName = "EventDispatcherTab";
33546
+ function ServerResponseRow({ sr }) {
33547
+ const entityEntries = Object.entries(sr.dataEntities);
33548
+ return /* @__PURE__ */ jsxs("div", { className: "ml-4 pl-2 border-l border-purple-700/50 py-0.5 text-[10px] font-mono", children: [
33549
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
33550
+ /* @__PURE__ */ jsxs("span", { className: sr.success ? "text-green-400" : "text-red-400", children: [
33551
+ sr.success ? "\u2713" : "\u2717",
33552
+ " server"
33553
+ ] }),
33554
+ /* @__PURE__ */ jsx("span", { className: "text-purple-300", children: sr.orbitalName }),
33555
+ sr.clientEffects > 0 && /* @__PURE__ */ jsxs("span", { className: "px-1 rounded bg-purple-900/50 text-purple-300", children: [
33556
+ sr.clientEffects,
33557
+ " clientEffect",
33558
+ sr.clientEffects !== 1 ? "s" : ""
33559
+ ] }),
33560
+ sr.emittedEvents.length > 0 && /* @__PURE__ */ jsxs("span", { className: "px-1 rounded bg-blue-900/50 text-blue-300", children: [
33561
+ "emit: ",
33562
+ sr.emittedEvents.join(", ")
33563
+ ] }),
33564
+ sr.error && /* @__PURE__ */ jsx("span", { className: "px-1 rounded bg-red-900/50 text-red-400 truncate max-w-[300px]", children: sr.error })
33565
+ ] }),
33566
+ entityEntries.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 mt-0.5", children: entityEntries.map(([name, count]) => /* @__PURE__ */ jsxs("span", { className: "px-1 rounded bg-gray-800 text-gray-300", children: [
33567
+ name,
33568
+ ": ",
33569
+ count,
33570
+ " row",
33571
+ count !== 1 ? "s" : ""
33572
+ ] }, name)) })
33573
+ ] });
33574
+ }
33575
+ function TransitionRow({ trace }) {
33576
+ const isServerEntry = !!trace.serverResponse && trace.traitName.startsWith("server:");
33577
+ const hasFailedEffects = trace.effects.some((e) => e.status === "failed");
33578
+ if (isServerEntry && trace.serverResponse) {
33579
+ return /* @__PURE__ */ jsxs("div", { className: "py-0.5 border-b border-gray-800 last:border-0", children: [
33580
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-xs font-mono", children: [
33581
+ /* @__PURE__ */ jsx("span", { className: "mt-1.5 w-1.5 h-1.5 rounded-full flex-shrink-0 bg-purple-500" }),
33582
+ /* @__PURE__ */ jsx(Badge, { variant: "warning", size: "sm", className: "flex-shrink-0", children: trace.event }),
33583
+ /* @__PURE__ */ jsx("span", { className: "text-purple-400 flex-shrink-0", children: "server response" })
33584
+ ] }),
33585
+ /* @__PURE__ */ jsx(ServerResponseRow, { sr: trace.serverResponse })
33586
+ ] });
33587
+ }
33588
+ return /* @__PURE__ */ jsxs("div", { className: "py-0.5 border-b border-gray-800 last:border-0", children: [
33589
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-xs font-mono", children: [
33590
+ /* @__PURE__ */ jsx("span", { className: cn(
33591
+ "mt-1.5 w-1.5 h-1.5 rounded-full flex-shrink-0",
33592
+ hasFailedEffects ? "bg-red-500" : "bg-green-500"
33593
+ ) }),
33594
+ /* @__PURE__ */ jsx(Badge, { variant: "info", size: "sm", className: "flex-shrink-0", children: trace.event }),
33595
+ /* @__PURE__ */ jsx("span", { className: "text-gray-300 flex-shrink-0", children: trace.traitName }),
33596
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-400 flex-shrink-0", children: [
33597
+ trace.from,
33598
+ " ",
33599
+ "\u2192",
33600
+ " ",
33601
+ trace.to
33602
+ ] })
33603
+ ] }),
33604
+ trace.effects.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 ml-6 mt-0.5", children: trace.effects.map((eff, i) => /* @__PURE__ */ jsxs("span", { className: cn(
33605
+ "px-1 rounded text-[10px]",
33606
+ eff.status === "executed" ? "bg-green-900/50 text-green-400" : eff.status === "failed" ? "bg-red-900/50 text-red-400" : "bg-yellow-900/50 text-yellow-400"
33607
+ ), children: [
33608
+ eff.status === "executed" ? "\u2713" : eff.status === "failed" ? "\u2717" : "-",
33609
+ " ",
33610
+ eff.type,
33611
+ eff.args.length > 0 && /* @__PURE__ */ jsx("span", { className: "text-gray-500 ml-0.5", children: JSON.stringify(eff.args).slice(0, 40) })
33612
+ ] }, i)) }),
33613
+ trace.serverResponse && /* @__PURE__ */ jsx(ServerResponseRow, { sr: trace.serverResponse })
33614
+ ] });
33615
+ }
33616
+ function VerifyModePanel({
33617
+ className,
33618
+ failedChecks,
33619
+ transitions,
33620
+ traitStates,
33621
+ serverCount,
33622
+ localCount
33623
+ }) {
33624
+ const scrollRef = React91.useRef(null);
33625
+ const prevCountRef = React91.useRef(0);
33626
+ React91.useEffect(() => {
33627
+ if (transitions.length > prevCountRef.current && scrollRef.current) {
33628
+ scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
33629
+ }
33630
+ prevCountRef.current = transitions.length;
33631
+ }, [transitions.length]);
33632
+ return /* @__PURE__ */ jsxs(
33633
+ "div",
33634
+ {
33635
+ className: cn(
33636
+ "runtime-debugger runtime-debugger--verify",
33637
+ "fixed bottom-0 left-0 right-0 z-[9999] h-[35vh] flex flex-col bg-gray-900 text-white border-t-2 border-cyan-500",
33638
+ className
33639
+ ),
33640
+ "data-testid": "debugger-verify",
33641
+ children: [
33642
+ /* @__PURE__ */ jsxs("div", { className: "px-3 py-1.5 flex items-center gap-3 text-xs font-mono border-b border-gray-700 flex-shrink-0", children: [
33643
+ /* @__PURE__ */ jsx(Badge, { variant: failedChecks > 0 ? "danger" : "success", size: "sm", children: failedChecks > 0 ? `${failedChecks} fail` : "OK" }),
33644
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-400", children: [
33645
+ localCount,
33646
+ " local"
33647
+ ] }),
33648
+ /* @__PURE__ */ jsxs("span", { className: "text-purple-400", children: [
33649
+ serverCount,
33650
+ " server"
33651
+ ] }),
33652
+ traitStates && /* @__PURE__ */ jsx("span", { className: "text-cyan-400 truncate max-w-[400px]", children: traitStates })
33653
+ ] }),
33654
+ /* @__PURE__ */ jsx("div", { ref: scrollRef, className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx("div", { className: "px-2 py-1", children: transitions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-gray-500 text-xs font-mono py-2 text-center", children: "Waiting for transitions..." }) : /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: transitions.map((trace) => /* @__PURE__ */ jsx(TransitionRow, { trace }, trace.id)) }) }) })
33655
+ ]
33656
+ }
33657
+ );
33658
+ }
33546
33659
  function RuntimeDebugger({
33547
33660
  position = "bottom-right",
33548
33661
  defaultCollapsed = true,
@@ -33692,51 +33805,17 @@ function RuntimeDebugger({
33692
33805
  }
33693
33806
  if (mode === "verify") {
33694
33807
  const traitStates = debugData.traits.map((t) => `${t.name}:${t.currentState}`).join(" | ");
33695
- return /* @__PURE__ */ jsxs(
33696
- "div",
33808
+ const serverEntries = verification.transitions.filter((t) => t.serverResponse);
33809
+ const localEntries = verification.transitions.filter((t) => !t.serverResponse);
33810
+ return /* @__PURE__ */ jsx(
33811
+ VerifyModePanel,
33697
33812
  {
33698
- className: cn(
33699
- "runtime-debugger runtime-debugger--verify",
33700
- "fixed bottom-0 left-0 right-0 z-[9999] h-[35vh] flex flex-col bg-gray-900 text-white border-t-2 border-cyan-500",
33701
- className
33702
- ),
33703
- "data-testid": "debugger-verify",
33704
- children: [
33705
- /* @__PURE__ */ jsxs("div", { className: "px-3 py-1.5 flex items-center gap-3 text-xs font-mono border-b border-gray-700 flex-shrink-0", children: [
33706
- /* @__PURE__ */ jsx(Badge, { variant: failedChecks > 0 ? "danger" : "success", size: "sm", children: failedChecks > 0 ? `${failedChecks} fail` : "OK" }),
33707
- /* @__PURE__ */ jsxs("span", { className: "text-gray-400", children: [
33708
- verification.transitions.length,
33709
- " transitions"
33710
- ] }),
33711
- traitStates && /* @__PURE__ */ jsx("span", { className: "text-cyan-400 truncate max-w-[400px]", children: traitStates })
33712
- ] }),
33713
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx("div", { className: "px-2 py-1", children: verification.transitions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-gray-500 text-xs font-mono py-2 text-center", children: "Waiting for transitions..." }) : /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: verification.transitions.map((trace) => {
33714
- const hasFailedEffects = trace.effects.some((e) => e.status === "failed");
33715
- return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-xs font-mono py-0.5 border-b border-gray-800 last:border-0", children: [
33716
- /* @__PURE__ */ jsx("span", { className: cn(
33717
- "mt-1.5 w-1.5 h-1.5 rounded-full flex-shrink-0",
33718
- hasFailedEffects ? "bg-red-500" : "bg-green-500"
33719
- ) }),
33720
- /* @__PURE__ */ jsx(Badge, { variant: "info", size: "sm", className: "flex-shrink-0", children: trace.event }),
33721
- /* @__PURE__ */ jsxs("span", { className: "text-gray-400 flex-shrink-0", children: [
33722
- trace.from,
33723
- " ",
33724
- "\u2192",
33725
- " ",
33726
- trace.to
33727
- ] }),
33728
- /* @__PURE__ */ jsx("span", { className: "flex flex-wrap gap-1 ml-1", children: trace.effects.map((eff, i) => /* @__PURE__ */ jsxs("span", { className: cn(
33729
- "px-1 rounded text-[10px]",
33730
- eff.status === "executed" ? "bg-green-900/50 text-green-400" : eff.status === "failed" ? "bg-red-900/50 text-red-400" : "bg-yellow-900/50 text-yellow-400"
33731
- ), children: [
33732
- eff.status === "executed" ? "\u2713" : eff.status === "failed" ? "\u2717" : "-",
33733
- " ",
33734
- eff.type,
33735
- eff.args.length > 0 && /* @__PURE__ */ jsx("span", { className: "text-gray-500 ml-0.5", children: JSON.stringify(eff.args).slice(0, 30) })
33736
- ] }, i)) })
33737
- ] }, trace.id);
33738
- }) }) }) })
33739
- ]
33813
+ className,
33814
+ failedChecks,
33815
+ transitions: verification.transitions,
33816
+ traitStates,
33817
+ serverCount: serverEntries.length,
33818
+ localCount: localEntries.length
33740
33819
  }
33741
33820
  );
33742
33821
  }
@@ -513,6 +513,36 @@ function getTransitions() {
513
513
  function getTransitionsForTrait(traitName) {
514
514
  return getState().transitions.filter((t) => t.traitName === traitName);
515
515
  }
516
+ function recordServerResponse(orbitalName, event, response) {
517
+ const serverResponse = {
518
+ ...response,
519
+ orbitalName,
520
+ timestamp: Date.now()
521
+ };
522
+ const entry = {
523
+ id: `srv-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
524
+ traitName: `server:${orbitalName}`,
525
+ from: "server",
526
+ to: "server",
527
+ event,
528
+ effects: [],
529
+ serverResponse,
530
+ timestamp: Date.now()
531
+ };
532
+ getState().transitions.push(entry);
533
+ if (getState().transitions.length > MAX_TRANSITIONS) {
534
+ getState().transitions.shift();
535
+ }
536
+ if (!response.success && response.error) {
537
+ registerCheck(
538
+ `server-error-${entry.id}`,
539
+ `Server error for ${orbitalName}:${event}`,
540
+ "fail",
541
+ response.error
542
+ );
543
+ }
544
+ notifyListeners5();
545
+ }
516
546
  function updateBridgeHealth(health) {
517
547
  getState().bridgeHealth = { ...health };
518
548
  const checkId = "server-bridge";
@@ -1482,6 +1512,7 @@ exports.onDebugToggle = onDebugToggle;
1482
1512
  exports.parseContentSegments = parseContentSegments;
1483
1513
  exports.parseMarkdownWithCodeBlocks = parseMarkdownWithCodeBlocks;
1484
1514
  exports.recordGuardEvaluation = recordGuardEvaluation;
1515
+ exports.recordServerResponse = recordServerResponse;
1485
1516
  exports.recordTransition = recordTransition;
1486
1517
  exports.registerCheck = registerCheck;
1487
1518
  exports.registerTick = registerTick;
package/dist/lib/index.js CHANGED
@@ -511,6 +511,36 @@ function getTransitions() {
511
511
  function getTransitionsForTrait(traitName) {
512
512
  return getState().transitions.filter((t) => t.traitName === traitName);
513
513
  }
514
+ function recordServerResponse(orbitalName, event, response) {
515
+ const serverResponse = {
516
+ ...response,
517
+ orbitalName,
518
+ timestamp: Date.now()
519
+ };
520
+ const entry = {
521
+ id: `srv-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
522
+ traitName: `server:${orbitalName}`,
523
+ from: "server",
524
+ to: "server",
525
+ event,
526
+ effects: [],
527
+ serverResponse,
528
+ timestamp: Date.now()
529
+ };
530
+ getState().transitions.push(entry);
531
+ if (getState().transitions.length > MAX_TRANSITIONS) {
532
+ getState().transitions.shift();
533
+ }
534
+ if (!response.success && response.error) {
535
+ registerCheck(
536
+ `server-error-${entry.id}`,
537
+ `Server error for ${orbitalName}:${event}`,
538
+ "fail",
539
+ response.error
540
+ );
541
+ }
542
+ notifyListeners5();
543
+ }
514
544
  function updateBridgeHealth(health) {
515
545
  getState().bridgeHealth = { ...health };
516
546
  const checkId = "server-bridge";
@@ -1416,4 +1446,4 @@ function parseContentSegments(content) {
1416
1446
  return segments;
1417
1447
  }
1418
1448
 
1419
- export { ApiError, DEFAULT_CONFIG, apiClient, bindCanvasCapture, bindEventBus, bindTraitStateGetter, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, clearVerification, cn, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, extractOutputsFromTransitions, extractStateMachine, formatGuard, formatNestedFieldLabel, getAllChecks, getAllTicks, getAllTraits, getBridgeHealth, getDebugEvents, getEffectSummary, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getSnapshot, getSummary, getTick, getTrait, getTransitions, getTransitionsForTrait, initDebugShortcut, isDebugEnabled, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, parseContentSegments, parseMarkdownWithCodeBlocks, recordGuardEvaluation, recordTransition, registerCheck, registerTick, registerTrait, renderStateMachineToDomData, renderStateMachineToSvg, setDebugEnabled, setEntityProvider, setTickActive, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, subscribeToVerification, toggleDebug, unregisterTick, unregisterTrait, updateAssetStatus, updateBridgeHealth, updateCheck, updateGuardResult, updateTickExecution, updateTraitState, waitForTransition };
1449
+ export { ApiError, DEFAULT_CONFIG, apiClient, bindCanvasCapture, bindEventBus, bindTraitStateGetter, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, clearVerification, cn, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, extractOutputsFromTransitions, extractStateMachine, formatGuard, formatNestedFieldLabel, getAllChecks, getAllTicks, getAllTraits, getBridgeHealth, getDebugEvents, getEffectSummary, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getSnapshot, getSummary, getTick, getTrait, getTransitions, getTransitionsForTrait, initDebugShortcut, isDebugEnabled, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, parseContentSegments, parseMarkdownWithCodeBlocks, recordGuardEvaluation, recordServerResponse, recordTransition, registerCheck, registerTick, registerTrait, renderStateMachineToDomData, renderStateMachineToSvg, setDebugEnabled, setEntityProvider, setTickActive, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, subscribeToVerification, toggleDebug, unregisterTick, unregisterTrait, updateAssetStatus, updateBridgeHealth, updateCheck, updateGuardResult, updateTickExecution, updateTraitState, waitForTransition };
@@ -25,6 +25,16 @@ export interface EffectTrace {
25
25
  error?: string;
26
26
  durationMs?: number;
27
27
  }
28
+ /** Captures what the server returned for a given event */
29
+ export interface ServerResponseTrace {
30
+ orbitalName: string;
31
+ success: boolean;
32
+ clientEffects: number;
33
+ dataEntities: Record<string, number>;
34
+ emittedEvents: string[];
35
+ error?: string;
36
+ timestamp: number;
37
+ }
28
38
  export interface TransitionTrace {
29
39
  id: string;
30
40
  traitName: string;
@@ -34,6 +44,8 @@ export interface TransitionTrace {
34
44
  guardExpression?: string;
35
45
  guardResult?: boolean;
36
46
  effects: EffectTrace[];
47
+ /** Server response data when event was forwarded to server bridge */
48
+ serverResponse?: ServerResponseTrace;
37
49
  timestamp: number;
38
50
  }
39
51
  export interface BridgeHealth {
@@ -63,6 +75,12 @@ export declare function getAllChecks(): VerificationCheck[];
63
75
  export declare function recordTransition(trace: Omit<TransitionTrace, "id">): void;
64
76
  export declare function getTransitions(): TransitionTrace[];
65
77
  export declare function getTransitionsForTrait(traitName: string): TransitionTrace[];
78
+ /**
79
+ * Record a server response as a timeline entry.
80
+ * Creates a synthetic transition entry with type "server-response" to show
81
+ * what the server returned (clientEffects, data counts, emitted events).
82
+ */
83
+ export declare function recordServerResponse(orbitalName: string, event: string, response: Omit<ServerResponseTrace, "orbitalName" | "timestamp">): void;
66
84
  export declare function updateBridgeHealth(health: BridgeHealth): void;
67
85
  export declare function getBridgeHealth(): BridgeHealth | null;
68
86
  export declare function getSummary(): VerificationSummary;
@@ -7,9 +7,21 @@ export interface ServerClientEffect {
7
7
  params?: Record<string, unknown>;
8
8
  message?: string;
9
9
  }
10
+ /** Metadata about what the server returned, for debugger logging */
11
+ export interface ServerResponseMeta {
12
+ success: boolean;
13
+ clientEffects: number;
14
+ dataEntities: Record<string, number>;
15
+ emittedEvents: string[];
16
+ error?: string;
17
+ }
18
+ export interface SendEventResult {
19
+ effects: ServerClientEffect[];
20
+ meta: ServerResponseMeta;
21
+ }
10
22
  export interface ServerBridgeContextValue {
11
23
  connected: boolean;
12
- sendEvent: (orbitalName: string, event: string, payload?: Record<string, unknown>) => Promise<ServerClientEffect[]>;
24
+ sendEvent: (orbitalName: string, event: string, payload?: Record<string, unknown>) => Promise<SendEventResult>;
13
25
  }
14
26
  /**
15
27
  * Access the server bridge. Returns a no-op stub when outside the provider.
@@ -851,6 +851,36 @@ function recordTransition(trace) {
851
851
  function getTransitions() {
852
852
  return [...getState().transitions];
853
853
  }
854
+ function recordServerResponse(orbitalName, event, response) {
855
+ const serverResponse = {
856
+ ...response,
857
+ orbitalName,
858
+ timestamp: Date.now()
859
+ };
860
+ const entry = {
861
+ id: `srv-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
862
+ traitName: `server:${orbitalName}`,
863
+ from: "server",
864
+ to: "server",
865
+ event,
866
+ effects: [],
867
+ serverResponse,
868
+ timestamp: Date.now()
869
+ };
870
+ getState().transitions.push(entry);
871
+ if (getState().transitions.length > MAX_TRANSITIONS) {
872
+ getState().transitions.shift();
873
+ }
874
+ if (!response.success && response.error) {
875
+ registerCheck(
876
+ `server-error-${entry.id}`,
877
+ `Server error for ${orbitalName}:${event}`,
878
+ "fail",
879
+ response.error
880
+ );
881
+ }
882
+ notifyListeners2();
883
+ }
854
884
  function getBridgeHealth() {
855
885
  const bh = getState().bridgeHealth;
856
886
  return bh ? { ...bh } : null;
@@ -27934,6 +27964,119 @@ function EventDispatcherTab({ traits: traits2, schema }) {
27934
27964
  ] });
27935
27965
  }
27936
27966
  EventDispatcherTab.displayName = "EventDispatcherTab";
27967
+ function ServerResponseRow({ sr }) {
27968
+ const entityEntries = Object.entries(sr.dataEntities);
27969
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-4 pl-2 border-l border-purple-700/50 py-0.5 text-[10px] font-mono", children: [
27970
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
27971
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: sr.success ? "text-green-400" : "text-red-400", children: [
27972
+ sr.success ? "\u2713" : "\u2717",
27973
+ " server"
27974
+ ] }),
27975
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-purple-300", children: sr.orbitalName }),
27976
+ sr.clientEffects > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-1 rounded bg-purple-900/50 text-purple-300", children: [
27977
+ sr.clientEffects,
27978
+ " clientEffect",
27979
+ sr.clientEffects !== 1 ? "s" : ""
27980
+ ] }),
27981
+ sr.emittedEvents.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-1 rounded bg-blue-900/50 text-blue-300", children: [
27982
+ "emit: ",
27983
+ sr.emittedEvents.join(", ")
27984
+ ] }),
27985
+ sr.error && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-1 rounded bg-red-900/50 text-red-400 truncate max-w-[300px]", children: sr.error })
27986
+ ] }),
27987
+ entityEntries.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1 mt-0.5", children: entityEntries.map(([name, count]) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-1 rounded bg-gray-800 text-gray-300", children: [
27988
+ name,
27989
+ ": ",
27990
+ count,
27991
+ " row",
27992
+ count !== 1 ? "s" : ""
27993
+ ] }, name)) })
27994
+ ] });
27995
+ }
27996
+ function TransitionRow({ trace }) {
27997
+ const isServerEntry = !!trace.serverResponse && trace.traitName.startsWith("server:");
27998
+ const hasFailedEffects = trace.effects.some((e) => e.status === "failed");
27999
+ if (isServerEntry && trace.serverResponse) {
28000
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-0.5 border-b border-gray-800 last:border-0", children: [
28001
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 text-xs font-mono", children: [
28002
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-1.5 w-1.5 h-1.5 rounded-full flex-shrink-0 bg-purple-500" }),
28003
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "warning", size: "sm", className: "flex-shrink-0", children: trace.event }),
28004
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-purple-400 flex-shrink-0", children: "server response" })
28005
+ ] }),
28006
+ /* @__PURE__ */ jsxRuntime.jsx(ServerResponseRow, { sr: trace.serverResponse })
28007
+ ] });
28008
+ }
28009
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-0.5 border-b border-gray-800 last:border-0", children: [
28010
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 text-xs font-mono", children: [
28011
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
28012
+ "mt-1.5 w-1.5 h-1.5 rounded-full flex-shrink-0",
28013
+ hasFailedEffects ? "bg-red-500" : "bg-green-500"
28014
+ ) }),
28015
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "info", size: "sm", className: "flex-shrink-0", children: trace.event }),
28016
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-300 flex-shrink-0", children: trace.traitName }),
28017
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-400 flex-shrink-0", children: [
28018
+ trace.from,
28019
+ " ",
28020
+ "\u2192",
28021
+ " ",
28022
+ trace.to
28023
+ ] })
28024
+ ] }),
28025
+ trace.effects.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1 ml-6 mt-0.5", children: trace.effects.map((eff, i) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn(
28026
+ "px-1 rounded text-[10px]",
28027
+ eff.status === "executed" ? "bg-green-900/50 text-green-400" : eff.status === "failed" ? "bg-red-900/50 text-red-400" : "bg-yellow-900/50 text-yellow-400"
28028
+ ), children: [
28029
+ eff.status === "executed" ? "\u2713" : eff.status === "failed" ? "\u2717" : "-",
28030
+ " ",
28031
+ eff.type,
28032
+ eff.args.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-500 ml-0.5", children: JSON.stringify(eff.args).slice(0, 40) })
28033
+ ] }, i)) }),
28034
+ trace.serverResponse && /* @__PURE__ */ jsxRuntime.jsx(ServerResponseRow, { sr: trace.serverResponse })
28035
+ ] });
28036
+ }
28037
+ function VerifyModePanel({
28038
+ className,
28039
+ failedChecks,
28040
+ transitions,
28041
+ traitStates,
28042
+ serverCount,
28043
+ localCount
28044
+ }) {
28045
+ const scrollRef = React117__namespace.useRef(null);
28046
+ const prevCountRef = React117__namespace.useRef(0);
28047
+ React117__namespace.useEffect(() => {
28048
+ if (transitions.length > prevCountRef.current && scrollRef.current) {
28049
+ scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
28050
+ }
28051
+ prevCountRef.current = transitions.length;
28052
+ }, [transitions.length]);
28053
+ return /* @__PURE__ */ jsxRuntime.jsxs(
28054
+ "div",
28055
+ {
28056
+ className: cn(
28057
+ "runtime-debugger runtime-debugger--verify",
28058
+ "fixed bottom-0 left-0 right-0 z-[9999] h-[35vh] flex flex-col bg-gray-900 text-white border-t-2 border-cyan-500",
28059
+ className
28060
+ ),
28061
+ "data-testid": "debugger-verify",
28062
+ children: [
28063
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-1.5 flex items-center gap-3 text-xs font-mono border-b border-gray-700 flex-shrink-0", children: [
28064
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: failedChecks > 0 ? "danger" : "success", size: "sm", children: failedChecks > 0 ? `${failedChecks} fail` : "OK" }),
28065
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-400", children: [
28066
+ localCount,
28067
+ " local"
28068
+ ] }),
28069
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-purple-400", children: [
28070
+ serverCount,
28071
+ " server"
28072
+ ] }),
28073
+ traitStates && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-cyan-400 truncate max-w-[400px]", children: traitStates })
28074
+ ] }),
28075
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: scrollRef, className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 py-1", children: transitions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-500 text-xs font-mono py-2 text-center", children: "Waiting for transitions..." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0.5", children: transitions.map((trace) => /* @__PURE__ */ jsxRuntime.jsx(TransitionRow, { trace }, trace.id)) }) }) })
28076
+ ]
28077
+ }
28078
+ );
28079
+ }
27937
28080
  function RuntimeDebugger({
27938
28081
  position = "bottom-right",
27939
28082
  defaultCollapsed = true,
@@ -28083,51 +28226,17 @@ function RuntimeDebugger({
28083
28226
  }
28084
28227
  if (mode === "verify") {
28085
28228
  const traitStates = debugData.traits.map((t) => `${t.name}:${t.currentState}`).join(" | ");
28086
- return /* @__PURE__ */ jsxRuntime.jsxs(
28087
- "div",
28229
+ const serverEntries = verification.transitions.filter((t) => t.serverResponse);
28230
+ const localEntries = verification.transitions.filter((t) => !t.serverResponse);
28231
+ return /* @__PURE__ */ jsxRuntime.jsx(
28232
+ VerifyModePanel,
28088
28233
  {
28089
- className: cn(
28090
- "runtime-debugger runtime-debugger--verify",
28091
- "fixed bottom-0 left-0 right-0 z-[9999] h-[35vh] flex flex-col bg-gray-900 text-white border-t-2 border-cyan-500",
28092
- className
28093
- ),
28094
- "data-testid": "debugger-verify",
28095
- children: [
28096
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-1.5 flex items-center gap-3 text-xs font-mono border-b border-gray-700 flex-shrink-0", children: [
28097
- /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: failedChecks > 0 ? "danger" : "success", size: "sm", children: failedChecks > 0 ? `${failedChecks} fail` : "OK" }),
28098
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-400", children: [
28099
- verification.transitions.length,
28100
- " transitions"
28101
- ] }),
28102
- traitStates && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-cyan-400 truncate max-w-[400px]", children: traitStates })
28103
- ] }),
28104
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 py-1", children: verification.transitions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-500 text-xs font-mono py-2 text-center", children: "Waiting for transitions..." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0.5", children: verification.transitions.map((trace) => {
28105
- const hasFailedEffects = trace.effects.some((e) => e.status === "failed");
28106
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 text-xs font-mono py-0.5 border-b border-gray-800 last:border-0", children: [
28107
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
28108
- "mt-1.5 w-1.5 h-1.5 rounded-full flex-shrink-0",
28109
- hasFailedEffects ? "bg-red-500" : "bg-green-500"
28110
- ) }),
28111
- /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "info", size: "sm", className: "flex-shrink-0", children: trace.event }),
28112
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-400 flex-shrink-0", children: [
28113
- trace.from,
28114
- " ",
28115
- "\u2192",
28116
- " ",
28117
- trace.to
28118
- ] }),
28119
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-wrap gap-1 ml-1", children: trace.effects.map((eff, i) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn(
28120
- "px-1 rounded text-[10px]",
28121
- eff.status === "executed" ? "bg-green-900/50 text-green-400" : eff.status === "failed" ? "bg-red-900/50 text-red-400" : "bg-yellow-900/50 text-yellow-400"
28122
- ), children: [
28123
- eff.status === "executed" ? "\u2713" : eff.status === "failed" ? "\u2717" : "-",
28124
- " ",
28125
- eff.type,
28126
- eff.args.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-500 ml-0.5", children: JSON.stringify(eff.args).slice(0, 30) })
28127
- ] }, i)) })
28128
- ] }, trace.id);
28129
- }) }) }) })
28130
- ]
28234
+ className,
28235
+ failedChecks,
28236
+ transitions: verification.transitions,
28237
+ traitStates,
28238
+ serverCount: serverEntries.length,
28239
+ localCount: localEntries.length
28131
28240
  }
28132
28241
  );
28133
28242
  }
@@ -32486,7 +32595,8 @@ var ServerBridgeContext = React117.createContext(null);
32486
32595
  function useServerBridge() {
32487
32596
  const ctx = React117.useContext(ServerBridgeContext);
32488
32597
  if (!ctx) {
32489
- return { connected: false, sendEvent: async () => [] };
32598
+ const emptyMeta = { success: false, clientEffects: 0, dataEntities: {}, emittedEvents: [] };
32599
+ return { connected: false, sendEvent: async () => ({ effects: [], meta: emptyMeta }) };
32490
32600
  }
32491
32601
  return ctx;
32492
32602
  }
@@ -32518,7 +32628,8 @@ function ServerBridgeProvider({
32518
32628
  }
32519
32629
  }, [serverUrl]);
32520
32630
  const sendEvent = React117.useCallback(async (orbitalName, event, payload) => {
32521
- if (!connected) return [];
32631
+ const emptyMeta = { success: false, clientEffects: 0, dataEntities: {}, emittedEvents: [] };
32632
+ if (!connected) return { effects: [], meta: emptyMeta };
32522
32633
  try {
32523
32634
  const res = await fetch(`${serverUrl}/${orbitalName}/events`, {
32524
32635
  method: "POST",
@@ -32527,8 +32638,19 @@ function ServerBridgeProvider({
32527
32638
  });
32528
32639
  const result = await res.json();
32529
32640
  const effects = [];
32641
+ const responseData = result.data || {};
32642
+ const dataEntities = {};
32643
+ for (const [entityName, records] of Object.entries(responseData)) {
32644
+ dataEntities[entityName] = Array.isArray(records) ? records.length : 0;
32645
+ }
32646
+ const meta = {
32647
+ success: !!result.success,
32648
+ clientEffects: result.clientEffects?.length ?? 0,
32649
+ dataEntities,
32650
+ emittedEvents: result.emittedEvents?.map((e) => e.event) ?? [],
32651
+ error: result.error
32652
+ };
32530
32653
  if (result.success) {
32531
- const responseData = result.data || {};
32532
32654
  if (result.clientEffects) {
32533
32655
  for (const effect of result.clientEffects) {
32534
32656
  const arr = effect;
@@ -32554,10 +32676,10 @@ function ServerBridgeProvider({
32554
32676
  } else if (result.error) {
32555
32677
  console.error("[ServerBridge] Event error:", result.error);
32556
32678
  }
32557
- return effects;
32679
+ return { effects, meta };
32558
32680
  } catch (err) {
32559
32681
  console.error("[ServerBridge] Event send failed:", err);
32560
- return [];
32682
+ return { effects: [], meta: { ...emptyMeta, error: err instanceof Error ? err.message : String(err) } };
32561
32683
  }
32562
32684
  }, [connected, serverUrl, eventBus]);
32563
32685
  React117.useEffect(() => {
@@ -32618,7 +32740,8 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate }) {
32618
32740
  const onEventProcessed = React117.useCallback(async (event, payload) => {
32619
32741
  if (!bridge.connected || !orbitalNames?.length) return;
32620
32742
  for (const name of orbitalNames) {
32621
- const effects = await bridge.sendEvent(name, event, payload);
32743
+ const { effects, meta } = await bridge.sendEvent(name, event, payload);
32744
+ recordServerResponse(name, event, meta);
32622
32745
  for (const eff of effects) {
32623
32746
  if (eff.type === "render-ui" && eff.slot && eff.pattern) {
32624
32747
  slotsActions.setSlotPatterns(
@@ -32652,7 +32775,8 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate }) {
32652
32775
  initSentRef.current = true;
32653
32776
  (async () => {
32654
32777
  for (const name of orbitalNames) {
32655
- const effects = await bridge.sendEvent(name, "INIT", {});
32778
+ const { effects, meta } = await bridge.sendEvent(name, "INIT", {});
32779
+ recordServerResponse(name, "INIT", meta);
32656
32780
  const effectTraces = [
32657
32781
  { type: "fetch", args: [], status: "executed" },
32658
32782
  ...effects.map((eff) => ({
@@ -32686,6 +32810,7 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate }) {
32686
32810
  function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate }) {
32687
32811
  const { traits: traits2, allEntities, ir } = useResolvedSchema(schema, pageName);
32688
32812
  const allPageTraits = React117.useMemo(() => {
32813
+ if (pageName && traits2.length > 0) return traits2;
32689
32814
  if (!ir?.pages || ir.pages.size <= 1) return traits2;
32690
32815
  const combined = [];
32691
32816
  const seen = /* @__PURE__ */ new Set();
@@ -32701,7 +32826,7 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate }) {
32701
32826
  }
32702
32827
  }
32703
32828
  return combined.length > 0 ? combined : traits2;
32704
- }, [ir, traits2]);
32829
+ }, [ir, traits2, pageName]);
32705
32830
  const orbitalNames = React117.useMemo(() => {
32706
32831
  const parsed = schema;
32707
32832
  const orbitals = parsed?.orbitals;
@@ -821,6 +821,36 @@ function recordTransition(trace) {
821
821
  function getTransitions() {
822
822
  return [...getState().transitions];
823
823
  }
824
+ function recordServerResponse(orbitalName, event, response) {
825
+ const serverResponse = {
826
+ ...response,
827
+ orbitalName,
828
+ timestamp: Date.now()
829
+ };
830
+ const entry = {
831
+ id: `srv-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
832
+ traitName: `server:${orbitalName}`,
833
+ from: "server",
834
+ to: "server",
835
+ event,
836
+ effects: [],
837
+ serverResponse,
838
+ timestamp: Date.now()
839
+ };
840
+ getState().transitions.push(entry);
841
+ if (getState().transitions.length > MAX_TRANSITIONS) {
842
+ getState().transitions.shift();
843
+ }
844
+ if (!response.success && response.error) {
845
+ registerCheck(
846
+ `server-error-${entry.id}`,
847
+ `Server error for ${orbitalName}:${event}`,
848
+ "fail",
849
+ response.error
850
+ );
851
+ }
852
+ notifyListeners2();
853
+ }
824
854
  function getBridgeHealth() {
825
855
  const bh = getState().bridgeHealth;
826
856
  return bh ? { ...bh } : null;
@@ -27904,6 +27934,119 @@ function EventDispatcherTab({ traits: traits2, schema }) {
27904
27934
  ] });
27905
27935
  }
27906
27936
  EventDispatcherTab.displayName = "EventDispatcherTab";
27937
+ function ServerResponseRow({ sr }) {
27938
+ const entityEntries = Object.entries(sr.dataEntities);
27939
+ return /* @__PURE__ */ jsxs("div", { className: "ml-4 pl-2 border-l border-purple-700/50 py-0.5 text-[10px] font-mono", children: [
27940
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
27941
+ /* @__PURE__ */ jsxs("span", { className: sr.success ? "text-green-400" : "text-red-400", children: [
27942
+ sr.success ? "\u2713" : "\u2717",
27943
+ " server"
27944
+ ] }),
27945
+ /* @__PURE__ */ jsx("span", { className: "text-purple-300", children: sr.orbitalName }),
27946
+ sr.clientEffects > 0 && /* @__PURE__ */ jsxs("span", { className: "px-1 rounded bg-purple-900/50 text-purple-300", children: [
27947
+ sr.clientEffects,
27948
+ " clientEffect",
27949
+ sr.clientEffects !== 1 ? "s" : ""
27950
+ ] }),
27951
+ sr.emittedEvents.length > 0 && /* @__PURE__ */ jsxs("span", { className: "px-1 rounded bg-blue-900/50 text-blue-300", children: [
27952
+ "emit: ",
27953
+ sr.emittedEvents.join(", ")
27954
+ ] }),
27955
+ sr.error && /* @__PURE__ */ jsx("span", { className: "px-1 rounded bg-red-900/50 text-red-400 truncate max-w-[300px]", children: sr.error })
27956
+ ] }),
27957
+ entityEntries.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 mt-0.5", children: entityEntries.map(([name, count]) => /* @__PURE__ */ jsxs("span", { className: "px-1 rounded bg-gray-800 text-gray-300", children: [
27958
+ name,
27959
+ ": ",
27960
+ count,
27961
+ " row",
27962
+ count !== 1 ? "s" : ""
27963
+ ] }, name)) })
27964
+ ] });
27965
+ }
27966
+ function TransitionRow({ trace }) {
27967
+ const isServerEntry = !!trace.serverResponse && trace.traitName.startsWith("server:");
27968
+ const hasFailedEffects = trace.effects.some((e) => e.status === "failed");
27969
+ if (isServerEntry && trace.serverResponse) {
27970
+ return /* @__PURE__ */ jsxs("div", { className: "py-0.5 border-b border-gray-800 last:border-0", children: [
27971
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-xs font-mono", children: [
27972
+ /* @__PURE__ */ jsx("span", { className: "mt-1.5 w-1.5 h-1.5 rounded-full flex-shrink-0 bg-purple-500" }),
27973
+ /* @__PURE__ */ jsx(Badge, { variant: "warning", size: "sm", className: "flex-shrink-0", children: trace.event }),
27974
+ /* @__PURE__ */ jsx("span", { className: "text-purple-400 flex-shrink-0", children: "server response" })
27975
+ ] }),
27976
+ /* @__PURE__ */ jsx(ServerResponseRow, { sr: trace.serverResponse })
27977
+ ] });
27978
+ }
27979
+ return /* @__PURE__ */ jsxs("div", { className: "py-0.5 border-b border-gray-800 last:border-0", children: [
27980
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-xs font-mono", children: [
27981
+ /* @__PURE__ */ jsx("span", { className: cn(
27982
+ "mt-1.5 w-1.5 h-1.5 rounded-full flex-shrink-0",
27983
+ hasFailedEffects ? "bg-red-500" : "bg-green-500"
27984
+ ) }),
27985
+ /* @__PURE__ */ jsx(Badge, { variant: "info", size: "sm", className: "flex-shrink-0", children: trace.event }),
27986
+ /* @__PURE__ */ jsx("span", { className: "text-gray-300 flex-shrink-0", children: trace.traitName }),
27987
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-400 flex-shrink-0", children: [
27988
+ trace.from,
27989
+ " ",
27990
+ "\u2192",
27991
+ " ",
27992
+ trace.to
27993
+ ] })
27994
+ ] }),
27995
+ trace.effects.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 ml-6 mt-0.5", children: trace.effects.map((eff, i) => /* @__PURE__ */ jsxs("span", { className: cn(
27996
+ "px-1 rounded text-[10px]",
27997
+ eff.status === "executed" ? "bg-green-900/50 text-green-400" : eff.status === "failed" ? "bg-red-900/50 text-red-400" : "bg-yellow-900/50 text-yellow-400"
27998
+ ), children: [
27999
+ eff.status === "executed" ? "\u2713" : eff.status === "failed" ? "\u2717" : "-",
28000
+ " ",
28001
+ eff.type,
28002
+ eff.args.length > 0 && /* @__PURE__ */ jsx("span", { className: "text-gray-500 ml-0.5", children: JSON.stringify(eff.args).slice(0, 40) })
28003
+ ] }, i)) }),
28004
+ trace.serverResponse && /* @__PURE__ */ jsx(ServerResponseRow, { sr: trace.serverResponse })
28005
+ ] });
28006
+ }
28007
+ function VerifyModePanel({
28008
+ className,
28009
+ failedChecks,
28010
+ transitions,
28011
+ traitStates,
28012
+ serverCount,
28013
+ localCount
28014
+ }) {
28015
+ const scrollRef = React117.useRef(null);
28016
+ const prevCountRef = React117.useRef(0);
28017
+ React117.useEffect(() => {
28018
+ if (transitions.length > prevCountRef.current && scrollRef.current) {
28019
+ scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
28020
+ }
28021
+ prevCountRef.current = transitions.length;
28022
+ }, [transitions.length]);
28023
+ return /* @__PURE__ */ jsxs(
28024
+ "div",
28025
+ {
28026
+ className: cn(
28027
+ "runtime-debugger runtime-debugger--verify",
28028
+ "fixed bottom-0 left-0 right-0 z-[9999] h-[35vh] flex flex-col bg-gray-900 text-white border-t-2 border-cyan-500",
28029
+ className
28030
+ ),
28031
+ "data-testid": "debugger-verify",
28032
+ children: [
28033
+ /* @__PURE__ */ jsxs("div", { className: "px-3 py-1.5 flex items-center gap-3 text-xs font-mono border-b border-gray-700 flex-shrink-0", children: [
28034
+ /* @__PURE__ */ jsx(Badge, { variant: failedChecks > 0 ? "danger" : "success", size: "sm", children: failedChecks > 0 ? `${failedChecks} fail` : "OK" }),
28035
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-400", children: [
28036
+ localCount,
28037
+ " local"
28038
+ ] }),
28039
+ /* @__PURE__ */ jsxs("span", { className: "text-purple-400", children: [
28040
+ serverCount,
28041
+ " server"
28042
+ ] }),
28043
+ traitStates && /* @__PURE__ */ jsx("span", { className: "text-cyan-400 truncate max-w-[400px]", children: traitStates })
28044
+ ] }),
28045
+ /* @__PURE__ */ jsx("div", { ref: scrollRef, className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx("div", { className: "px-2 py-1", children: transitions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-gray-500 text-xs font-mono py-2 text-center", children: "Waiting for transitions..." }) : /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: transitions.map((trace) => /* @__PURE__ */ jsx(TransitionRow, { trace }, trace.id)) }) }) })
28046
+ ]
28047
+ }
28048
+ );
28049
+ }
27907
28050
  function RuntimeDebugger({
27908
28051
  position = "bottom-right",
27909
28052
  defaultCollapsed = true,
@@ -28053,51 +28196,17 @@ function RuntimeDebugger({
28053
28196
  }
28054
28197
  if (mode === "verify") {
28055
28198
  const traitStates = debugData.traits.map((t) => `${t.name}:${t.currentState}`).join(" | ");
28056
- return /* @__PURE__ */ jsxs(
28057
- "div",
28199
+ const serverEntries = verification.transitions.filter((t) => t.serverResponse);
28200
+ const localEntries = verification.transitions.filter((t) => !t.serverResponse);
28201
+ return /* @__PURE__ */ jsx(
28202
+ VerifyModePanel,
28058
28203
  {
28059
- className: cn(
28060
- "runtime-debugger runtime-debugger--verify",
28061
- "fixed bottom-0 left-0 right-0 z-[9999] h-[35vh] flex flex-col bg-gray-900 text-white border-t-2 border-cyan-500",
28062
- className
28063
- ),
28064
- "data-testid": "debugger-verify",
28065
- children: [
28066
- /* @__PURE__ */ jsxs("div", { className: "px-3 py-1.5 flex items-center gap-3 text-xs font-mono border-b border-gray-700 flex-shrink-0", children: [
28067
- /* @__PURE__ */ jsx(Badge, { variant: failedChecks > 0 ? "danger" : "success", size: "sm", children: failedChecks > 0 ? `${failedChecks} fail` : "OK" }),
28068
- /* @__PURE__ */ jsxs("span", { className: "text-gray-400", children: [
28069
- verification.transitions.length,
28070
- " transitions"
28071
- ] }),
28072
- traitStates && /* @__PURE__ */ jsx("span", { className: "text-cyan-400 truncate max-w-[400px]", children: traitStates })
28073
- ] }),
28074
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx("div", { className: "px-2 py-1", children: verification.transitions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-gray-500 text-xs font-mono py-2 text-center", children: "Waiting for transitions..." }) : /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: verification.transitions.map((trace) => {
28075
- const hasFailedEffects = trace.effects.some((e) => e.status === "failed");
28076
- return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-xs font-mono py-0.5 border-b border-gray-800 last:border-0", children: [
28077
- /* @__PURE__ */ jsx("span", { className: cn(
28078
- "mt-1.5 w-1.5 h-1.5 rounded-full flex-shrink-0",
28079
- hasFailedEffects ? "bg-red-500" : "bg-green-500"
28080
- ) }),
28081
- /* @__PURE__ */ jsx(Badge, { variant: "info", size: "sm", className: "flex-shrink-0", children: trace.event }),
28082
- /* @__PURE__ */ jsxs("span", { className: "text-gray-400 flex-shrink-0", children: [
28083
- trace.from,
28084
- " ",
28085
- "\u2192",
28086
- " ",
28087
- trace.to
28088
- ] }),
28089
- /* @__PURE__ */ jsx("span", { className: "flex flex-wrap gap-1 ml-1", children: trace.effects.map((eff, i) => /* @__PURE__ */ jsxs("span", { className: cn(
28090
- "px-1 rounded text-[10px]",
28091
- eff.status === "executed" ? "bg-green-900/50 text-green-400" : eff.status === "failed" ? "bg-red-900/50 text-red-400" : "bg-yellow-900/50 text-yellow-400"
28092
- ), children: [
28093
- eff.status === "executed" ? "\u2713" : eff.status === "failed" ? "\u2717" : "-",
28094
- " ",
28095
- eff.type,
28096
- eff.args.length > 0 && /* @__PURE__ */ jsx("span", { className: "text-gray-500 ml-0.5", children: JSON.stringify(eff.args).slice(0, 30) })
28097
- ] }, i)) })
28098
- ] }, trace.id);
28099
- }) }) }) })
28100
- ]
28204
+ className,
28205
+ failedChecks,
28206
+ transitions: verification.transitions,
28207
+ traitStates,
28208
+ serverCount: serverEntries.length,
28209
+ localCount: localEntries.length
28101
28210
  }
28102
28211
  );
28103
28212
  }
@@ -32456,7 +32565,8 @@ var ServerBridgeContext = createContext(null);
32456
32565
  function useServerBridge() {
32457
32566
  const ctx = useContext(ServerBridgeContext);
32458
32567
  if (!ctx) {
32459
- return { connected: false, sendEvent: async () => [] };
32568
+ const emptyMeta = { success: false, clientEffects: 0, dataEntities: {}, emittedEvents: [] };
32569
+ return { connected: false, sendEvent: async () => ({ effects: [], meta: emptyMeta }) };
32460
32570
  }
32461
32571
  return ctx;
32462
32572
  }
@@ -32488,7 +32598,8 @@ function ServerBridgeProvider({
32488
32598
  }
32489
32599
  }, [serverUrl]);
32490
32600
  const sendEvent = useCallback(async (orbitalName, event, payload) => {
32491
- if (!connected) return [];
32601
+ const emptyMeta = { success: false, clientEffects: 0, dataEntities: {}, emittedEvents: [] };
32602
+ if (!connected) return { effects: [], meta: emptyMeta };
32492
32603
  try {
32493
32604
  const res = await fetch(`${serverUrl}/${orbitalName}/events`, {
32494
32605
  method: "POST",
@@ -32497,8 +32608,19 @@ function ServerBridgeProvider({
32497
32608
  });
32498
32609
  const result = await res.json();
32499
32610
  const effects = [];
32611
+ const responseData = result.data || {};
32612
+ const dataEntities = {};
32613
+ for (const [entityName, records] of Object.entries(responseData)) {
32614
+ dataEntities[entityName] = Array.isArray(records) ? records.length : 0;
32615
+ }
32616
+ const meta = {
32617
+ success: !!result.success,
32618
+ clientEffects: result.clientEffects?.length ?? 0,
32619
+ dataEntities,
32620
+ emittedEvents: result.emittedEvents?.map((e) => e.event) ?? [],
32621
+ error: result.error
32622
+ };
32500
32623
  if (result.success) {
32501
- const responseData = result.data || {};
32502
32624
  if (result.clientEffects) {
32503
32625
  for (const effect of result.clientEffects) {
32504
32626
  const arr = effect;
@@ -32524,10 +32646,10 @@ function ServerBridgeProvider({
32524
32646
  } else if (result.error) {
32525
32647
  console.error("[ServerBridge] Event error:", result.error);
32526
32648
  }
32527
- return effects;
32649
+ return { effects, meta };
32528
32650
  } catch (err) {
32529
32651
  console.error("[ServerBridge] Event send failed:", err);
32530
- return [];
32652
+ return { effects: [], meta: { ...emptyMeta, error: err instanceof Error ? err.message : String(err) } };
32531
32653
  }
32532
32654
  }, [connected, serverUrl, eventBus]);
32533
32655
  useEffect(() => {
@@ -32588,7 +32710,8 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate }) {
32588
32710
  const onEventProcessed = useCallback(async (event, payload) => {
32589
32711
  if (!bridge.connected || !orbitalNames?.length) return;
32590
32712
  for (const name of orbitalNames) {
32591
- const effects = await bridge.sendEvent(name, event, payload);
32713
+ const { effects, meta } = await bridge.sendEvent(name, event, payload);
32714
+ recordServerResponse(name, event, meta);
32592
32715
  for (const eff of effects) {
32593
32716
  if (eff.type === "render-ui" && eff.slot && eff.pattern) {
32594
32717
  slotsActions.setSlotPatterns(
@@ -32622,7 +32745,8 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate }) {
32622
32745
  initSentRef.current = true;
32623
32746
  (async () => {
32624
32747
  for (const name of orbitalNames) {
32625
- const effects = await bridge.sendEvent(name, "INIT", {});
32748
+ const { effects, meta } = await bridge.sendEvent(name, "INIT", {});
32749
+ recordServerResponse(name, "INIT", meta);
32626
32750
  const effectTraces = [
32627
32751
  { type: "fetch", args: [], status: "executed" },
32628
32752
  ...effects.map((eff) => ({
@@ -32656,6 +32780,7 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate }) {
32656
32780
  function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate }) {
32657
32781
  const { traits: traits2, allEntities, ir } = useResolvedSchema(schema, pageName);
32658
32782
  const allPageTraits = useMemo(() => {
32783
+ if (pageName && traits2.length > 0) return traits2;
32659
32784
  if (!ir?.pages || ir.pages.size <= 1) return traits2;
32660
32785
  const combined = [];
32661
32786
  const seen = /* @__PURE__ */ new Set();
@@ -32671,7 +32796,7 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate }) {
32671
32796
  }
32672
32797
  }
32673
32798
  return combined.length > 0 ? combined : traits2;
32674
- }, [ir, traits2]);
32799
+ }, [ir, traits2, pageName]);
32675
32800
  const orbitalNames = useMemo(() => {
32676
32801
  const parsed = schema;
32677
32802
  const orbitals = parsed?.orbitals;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "2.27.4",
3
+ "version": "2.28.0",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "main": "./dist/components/index.js",