@almadar/ui 5.158.0 → 5.159.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.
package/dist/avl/index.js CHANGED
@@ -13,7 +13,7 @@ import { Loader2, X, Code, FileText, WrapText, Check, Copy, Lightbulb, CheckCirc
13
13
  import { createPortal } from 'react-dom';
14
14
  import { UISlotProvider, useUISlots, useTheme } from '@almadar/ui/context';
15
15
  import { evaluateGuard, evaluateListenPayloadExpr, evaluate, createMinimalContext, executeEffects } from '@almadar/evaluator';
16
- import { prepareSchemaForPreview, collectTraitRefsFromResolvedTrait, buildOrbitalsByTrait, collectEmbeddedTraits, wrapCallbackForEvent, pushPerfEntry, perfStart, perfEnd } from '@almadar/runtime/ui';
16
+ import { prepareSchemaForPreview, collectTraitRefsFromResolvedTrait, buildOrbitalsByTrait, collectEmbeddedTraits, perfStart, perfEnd, perfGauge, perfTimeAsync, wrapCallbackForEvent, pushPerfEntry } from '@almadar/runtime/ui';
17
17
  import { Link, Outlet, useLocation } from 'react-router-dom';
18
18
  import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism-light.js';
19
19
  import dark from 'react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus.js';
@@ -4588,7 +4588,16 @@ function isPlainObject(value) {
4588
4588
  if (typeof value === "function") return false;
4589
4589
  return true;
4590
4590
  }
4591
+ function isEvaluatorResolvedData(value) {
4592
+ return evaluatorResolvedData.has(value);
4593
+ }
4594
+ function brandResolved(value) {
4595
+ if (value !== null && typeof value === "object" && !React94__default.isValidElement(value) && !(value instanceof Date)) {
4596
+ resolvedMarkerFree.add(value);
4597
+ }
4598
+ }
4591
4599
  function subtreeHasMarker(value) {
4600
+ if (resolvedMarkerFree.has(value)) return false;
4592
4601
  const cached = markerPresenceCache.get(value);
4593
4602
  if (cached !== void 0) return cached;
4594
4603
  let found = false;
@@ -4610,10 +4619,23 @@ function subtreeHasMarker(value) {
4610
4619
  }
4611
4620
  function walkValue(value, scopeTrait, entity, config, state) {
4612
4621
  if (isRenderBindingMarker(value)) {
4613
- return { resolved: resolveMarkerExpression(value.expression, entity, config, state), changed: true };
4622
+ const cached = markerResolutionCache.get(value);
4623
+ if (cached !== void 0 && cached.entity === entity && cached.config === config && cached.state === state) {
4624
+ return { resolved: cached.resolved, changed: false };
4625
+ }
4626
+ const resolved = resolveMarkerExpression(value.expression, entity, config, state);
4627
+ markerResolutionCache.set(value, { entity, config, state, resolved });
4628
+ if (resolved !== null && typeof resolved === "object" && !React94__default.isValidElement(resolved) && !(resolved instanceof Date)) {
4629
+ resolvedMarkerFree.add(resolved);
4630
+ evaluatorResolvedData.add(resolved);
4631
+ }
4632
+ return { resolved, changed: true };
4614
4633
  }
4615
4634
  if (Array.isArray(value)) {
4616
- if (!subtreeHasMarker(value)) return { resolved: value, changed: false };
4635
+ if (!subtreeHasMarker(value)) {
4636
+ brandResolved(value);
4637
+ return { resolved: value, changed: false };
4638
+ }
4617
4639
  const out = [];
4618
4640
  let changed = false;
4619
4641
  for (const item of value) {
@@ -4628,10 +4650,14 @@ function walkValue(value, scopeTrait, entity, config, state) {
4628
4650
  out.push(resolved);
4629
4651
  if (itemChanged) changed = true;
4630
4652
  }
4653
+ brandResolved(out);
4631
4654
  return changed ? { resolved: out, changed: true } : { resolved: value, changed: false };
4632
4655
  }
4633
4656
  if (isPlainObject(value)) {
4634
- if (!subtreeHasMarker(value)) return { resolved: value, changed: false };
4657
+ if (!subtreeHasMarker(value)) {
4658
+ brandResolved(value);
4659
+ return { resolved: value, changed: false };
4660
+ }
4635
4661
  const sourceTrait = value._sourceTrait;
4636
4662
  if (typeof sourceTrait === "string" && sourceTrait !== scopeTrait) {
4637
4663
  return { resolved: value, changed: false };
@@ -4643,11 +4669,13 @@ function walkValue(value, scopeTrait, entity, config, state) {
4643
4669
  out[key] = resolved;
4644
4670
  if (itemChanged) changed = true;
4645
4671
  }
4672
+ brandResolved(out);
4646
4673
  return changed ? { resolved: out, changed: true } : { resolved: value, changed: false };
4647
4674
  }
4648
4675
  return { resolved: value, changed: false };
4649
4676
  }
4650
4677
  function resolveRenderBindingMarkers(props, scopeTrait, entity, config, state) {
4678
+ if (resolvedMarkerFree.has(props)) return props;
4651
4679
  const out = {};
4652
4680
  let changed = false;
4653
4681
  for (const [key, value] of Object.entries(props)) {
@@ -4655,13 +4683,17 @@ function resolveRenderBindingMarkers(props, scopeTrait, entity, config, state) {
4655
4683
  out[key] = resolved;
4656
4684
  if (propChanged) changed = true;
4657
4685
  }
4686
+ brandResolved(out);
4658
4687
  return changed ? out : props;
4659
4688
  }
4660
- var markerPresenceCache;
4689
+ var markerPresenceCache, markerResolutionCache, resolvedMarkerFree, evaluatorResolvedData;
4661
4690
  var init_resolve_render_bindings = __esm({
4662
4691
  "lib/resolve-render-bindings.ts"() {
4663
4692
  "use client";
4664
4693
  markerPresenceCache = /* @__PURE__ */ new WeakMap();
4694
+ markerResolutionCache = /* @__PURE__ */ new WeakMap();
4695
+ resolvedMarkerFree = /* @__PURE__ */ new WeakSet();
4696
+ evaluatorResolvedData = /* @__PURE__ */ new WeakSet();
4665
4697
  }
4666
4698
  });
4667
4699
  function getCurrentIconFamily() {
@@ -15266,6 +15298,19 @@ var init_molecules = __esm({
15266
15298
  init_puzzleObject();
15267
15299
  }
15268
15300
  });
15301
+ var profilerOnRender;
15302
+ var init_perf = __esm({
15303
+ "lib/perf.ts"() {
15304
+ profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
15305
+ pushPerfEntry({
15306
+ name: `profiler:${id}:${phase}`,
15307
+ durationMs: actualDuration,
15308
+ ts: commitTime,
15309
+ detail: { baseDuration }
15310
+ });
15311
+ };
15312
+ }
15313
+ });
15269
15314
  function themeBodyFont(el) {
15270
15315
  if (typeof getComputedStyle !== "function") return "system-ui, sans-serif";
15271
15316
  const v = getComputedStyle(el).getPropertyValue("--font-family-body").trim();
@@ -15614,6 +15659,7 @@ var init_LearningCanvas = __esm({
15614
15659
  "components/learning/atoms/LearningCanvas.tsx"() {
15615
15660
  "use client";
15616
15661
  init_cn();
15662
+ init_perf();
15617
15663
  init_useEventBus();
15618
15664
  DASH_PATTERNS = { dashed: [6, 4], dotted: [2, 3] };
15619
15665
  TRACE_SERIES_COLORS = ["#2563eb", "#dc2626", "#16a34a", "#f59e0b"];
@@ -15657,6 +15703,7 @@ var init_LearningCanvas = __esm({
15657
15703
  return [...shapes, ...traceOut, ...readoutOut];
15658
15704
  }, [shapes, traces, readouts, width, height]);
15659
15705
  const draw = useCallback(() => {
15706
+ const _perfT = perfStart("learningcanvas:paint");
15660
15707
  const canvas = canvasRef.current;
15661
15708
  if (!canvas) return;
15662
15709
  const ctx = canvas.getContext("2d");
@@ -15678,6 +15725,7 @@ var init_LearningCanvas = __esm({
15678
15725
  for (const shape of derivedShapes) {
15679
15726
  if (shape.type === "text") drawShape(ctx, shape, width, height, derivedShapes);
15680
15727
  }
15728
+ perfEnd("learningcanvas:paint", _perfT);
15681
15729
  }, [width, height, backgroundColor, derivedShapes]);
15682
15730
  useEffect(() => {
15683
15731
  draw();
@@ -32872,6 +32920,7 @@ var init_MathCanvas = __esm({
32872
32920
  "components/learning/molecules/MathCanvas.tsx"() {
32873
32921
  "use client";
32874
32922
  init_useEventBus();
32923
+ init_perf();
32875
32924
  init_atoms();
32876
32925
  init_Stack();
32877
32926
  init_LearningCanvas();
@@ -32937,6 +32986,7 @@ var init_MathCanvas = __esm({
32937
32986
  };
32938
32987
  }, [stableKeyMap, stableKeyUpMap, eventBus]);
32939
32988
  const derivedShapes = useMemo(() => {
32989
+ const _perfT = perfStart("mathcanvas:derive");
32940
32990
  const out = [];
32941
32991
  const margin = 24;
32942
32992
  const plotW = width - margin * 2;
@@ -33180,6 +33230,7 @@ var init_MathCanvas = __esm({
33180
33230
  }
33181
33231
  }
33182
33232
  out.push(...shapes);
33233
+ perfEnd("mathcanvas:derive", _perfT);
33183
33234
  return out;
33184
33235
  }, [
33185
33236
  width,
@@ -39533,7 +39584,7 @@ var init_RichBlockEditor = __esm({
39533
39584
  {
39534
39585
  variant: "bordered",
39535
39586
  padding: "none",
39536
- className: cn("flex flex-col", className),
39587
+ className: cn("flex flex-col text-card-foreground", className),
39537
39588
  children: [
39538
39589
  enableBlocks && showToolbar && !readOnly && /* @__PURE__ */ jsx(
39539
39590
  Box,
@@ -44352,6 +44403,7 @@ var init_DetailPanel = __esm({
44352
44403
  "use client";
44353
44404
  init_atoms();
44354
44405
  init_Box();
44406
+ init_Input();
44355
44407
  init_Stack();
44356
44408
  init_SimpleGrid();
44357
44409
  init_Menu();
@@ -44367,6 +44419,7 @@ var init_DetailPanel = __esm({
44367
44419
  ReactMarkdown2 = lazy(() => import('react-markdown'));
44368
44420
  DetailPanel = ({
44369
44421
  title: propTitle,
44422
+ onTitleCommit,
44370
44423
  subtitle,
44371
44424
  status,
44372
44425
  avatar,
@@ -44388,6 +44441,7 @@ var init_DetailPanel = __esm({
44388
44441
  }) => {
44389
44442
  const eventBus = useEventBus();
44390
44443
  const { t } = useTranslate();
44444
+ const [titleDraft, setTitleDraft] = React94__default.useState(null);
44391
44445
  const isFieldDefArray = (arr) => {
44392
44446
  if (!arr || arr.length === 0) return false;
44393
44447
  const first = arr[0];
@@ -44608,6 +44662,50 @@ var init_DetailPanel = __esm({
44608
44662
  }),
44609
44663
  status && /* @__PURE__ */ jsx(Badge, { variant: status.variant ?? "default", children: status.label })
44610
44664
  ] });
44665
+ const commitTitle = () => {
44666
+ if (!onTitleCommit) return;
44667
+ const next = (titleDraft ?? "").trim();
44668
+ setTitleDraft(null);
44669
+ if (!next || next === title) return;
44670
+ onTitleCommit(next, normalizedData?.id !== void 0 ? String(normalizedData.id) : "");
44671
+ };
44672
+ const titleNode = onTitleCommit && titleDraft !== null ? /* @__PURE__ */ jsx(
44673
+ Input,
44674
+ {
44675
+ value: titleDraft,
44676
+ autoFocus: true,
44677
+ "aria-label": t("common.title"),
44678
+ className: "h-auto py-1 text-3xl font-bold tracking-tight",
44679
+ onChange: (e) => setTitleDraft(e.target.value),
44680
+ onBlur: commitTitle,
44681
+ onKeyDown: (e) => {
44682
+ if (e.key === "Enter") {
44683
+ e.preventDefault();
44684
+ commitTitle();
44685
+ } else if (e.key === "Escape") {
44686
+ e.preventDefault();
44687
+ setTitleDraft(null);
44688
+ }
44689
+ },
44690
+ "data-testid": "detail-title-input"
44691
+ }
44692
+ ) : onTitleCommit ? /* @__PURE__ */ jsx(
44693
+ Box,
44694
+ {
44695
+ role: "button",
44696
+ tabIndex: 0,
44697
+ className: "cursor-text rounded px-1 -mx-1 transition-colors hover:bg-muted/40",
44698
+ onClick: () => setTitleDraft(title ?? ""),
44699
+ onKeyDown: (e) => {
44700
+ if (e.key === "Enter" || e.key === " ") {
44701
+ e.preventDefault();
44702
+ setTitleDraft(title ?? "");
44703
+ }
44704
+ },
44705
+ "data-testid": "detail-title-editable",
44706
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" })
44707
+ }
44708
+ ) : /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" });
44611
44709
  const content = /* @__PURE__ */ jsx(Card, { variant: "elevated", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", className: "p-6", children: [
44612
44710
  /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "start", gap: "md", children: [
44613
44711
  /* @__PURE__ */ jsxs(HStack, { align: "start", gap: "sm", className: "min-w-0", children: [
@@ -44627,7 +44725,7 @@ var init_DetailPanel = __esm({
44627
44725
  avatar,
44628
44726
  /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "min-w-0", children: [
44629
44727
  /* @__PURE__ */ jsxs(HStack, { align: "center", gap: "sm", wrap: true, children: [
44630
- /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" }),
44728
+ titleNode,
44631
44729
  statusBadges
44632
44730
  ] }),
44633
44731
  subtitle && /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: subtitle })
@@ -45188,7 +45286,7 @@ var init_Form = __esm({
45188
45286
  });
45189
45287
  debug(
45190
45288
  "forms",
45191
- `Calculation triggered: ${calc.variableName} = ${value}`
45289
+ `Calculation triggered: ${calc.variableName} = ${String(value)}`
45192
45290
  );
45193
45291
  }
45194
45292
  });
@@ -51687,6 +51785,7 @@ function isPlainConfigObject(value) {
51687
51785
  return proto === Object.prototype || proto === null;
51688
51786
  }
51689
51787
  function subtreeHasTraitRef(value) {
51788
+ if (isEvaluatorResolvedData(value)) return false;
51690
51789
  const cached = traitRefPresenceCache.get(value);
51691
51790
  if (cached !== void 0) return cached;
51692
51791
  let found = false;
@@ -51759,6 +51858,10 @@ function renderPatternProps(props, onDismiss, propsSchema) {
51759
51858
  };
51760
51859
  rendered[key] = /* @__PURE__ */ jsx(SlotContentRenderer, { content: childContent, onDismiss });
51761
51860
  } else if (Array.isArray(value)) {
51861
+ if (!isEvaluatorResolvedData(value) && value.some((el) => isPatternConfig(el))) ; else if (!subtreeHasTraitRef(value)) {
51862
+ rendered[key] = value;
51863
+ continue;
51864
+ }
51762
51865
  const isDataArray = propsSchema?.[key]?.items?.types?.includes("object") ?? false;
51763
51866
  rendered[key] = value.map((item, i) => {
51764
51867
  const el = item;
@@ -55785,6 +55888,7 @@ function enqueueEvent(queue, entry) {
55785
55888
  }
55786
55889
 
55787
55890
  // hooks/useTraitStateMachine.ts
55891
+ init_perf();
55788
55892
  init_traitRegistry();
55789
55893
  init_verificationRegistry();
55790
55894
  var crossTraitLog = createLogger("almadar:ui:cross-trait");
@@ -56471,6 +56575,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
56471
56575
  }, [eventBus]);
56472
56576
  useEffect(() => {
56473
56577
  const scheduler = createTickScheduler();
56578
+ const timedTick = (key, fn) => () => perfTimeAsync(key, fn);
56474
56579
  const pureWriterTickKeys = /* @__PURE__ */ new Set();
56475
56580
  for (const group of sharedGroups.values()) {
56476
56581
  const ticksByInterval = /* @__PURE__ */ new Map();
@@ -56487,12 +56592,12 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
56487
56592
  }
56488
56593
  for (const entries of ticksByInterval.values()) {
56489
56594
  const interval = entries[0].tick.interval;
56490
- const onDue = () => {
56595
+ const onDue = timedTick(`tick:shared:${group.storeKey}@${String(interval)}`, () => {
56491
56596
  const writers = entries.map(
56492
56597
  ({ binding, tick }) => createSharedEntityWriter(binding, tick, traitStatesRef, emitFromSharedWriter)
56493
56598
  );
56494
56599
  runTickFrame(group.storeKey, writers, sharedEntityStore);
56495
- };
56600
+ });
56496
56601
  if (interval === "frame") {
56497
56602
  scheduler.add(0, onDue);
56498
56603
  } else if (typeof interval === "number") {
@@ -56510,14 +56615,15 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
56510
56615
  if (sharedKey !== void 0 && pureWriterTickKeys.has(`${binding.trait.name}::${tick.name}`)) {
56511
56616
  continue;
56512
56617
  }
56618
+ const tickKey = `tick:${binding.trait.name}::${tick.name}`;
56513
56619
  if (tick.interval === "frame") {
56514
- scheduler.add(0, () => runTickEffects(tick, binding));
56620
+ scheduler.add(0, timedTick(tickKey, () => runTickEffects(tick, binding)));
56515
56621
  } else if (typeof tick.interval === "number") {
56516
- scheduler.add(tick.interval, () => runTickEffects(tick, binding));
56622
+ scheduler.add(tick.interval, timedTick(tickKey, () => runTickEffects(tick, binding)));
56517
56623
  } else if (isValidCronExpression(tick.interval)) {
56518
- scheduler.addCron(tick.interval, () => runTickEffects(tick, binding));
56624
+ scheduler.addCron(tick.interval, timedTick(tickKey, () => runTickEffects(tick, binding)));
56519
56625
  } else {
56520
- scheduler.add(parseDurationString(tick.interval), () => runTickEffects(tick, binding));
56626
+ scheduler.add(parseDurationString(tick.interval), timedTick(tickKey, () => runTickEffects(tick, binding)));
56521
56627
  }
56522
56628
  }
56523
56629
  }
@@ -56525,6 +56631,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
56525
56631
  }, [traitBindings, runTickEffects, sharedGroups, sharedEntityStore, emitFromSharedWriter]);
56526
56632
  const processEventQueued = useCallback(async (eventKey, payload, targetTrait, tick, sourceTrait) => {
56527
56633
  const normalizedEvent = normalizeEventKey(eventKey);
56634
+ const _perfT0 = perfStart("processEvent:total");
56528
56635
  const bindings = traitBindingsRef.current;
56529
56636
  const currentManager = managerRef.current;
56530
56637
  crossTraitLog.debug("processEvent:enter", () => ({
@@ -56548,6 +56655,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
56548
56655
  entityByTrait[name] = { ...sharedEntityStore.getSnapshot(sharedKey) };
56549
56656
  }
56550
56657
  }
56658
+ const _perfT1 = perfStart("processEvent:guardMatch");
56551
56659
  const results = currentManager.sendEvent(
56552
56660
  normalizedEvent,
56553
56661
  payload,
@@ -56556,6 +56664,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
56556
56664
  void 0,
56557
56665
  targetTrait
56558
56666
  );
56667
+ perfEnd("processEvent:guardMatch", _perfT1);
56559
56668
  crossTraitLog.debug("processEvent:results", {
56560
56669
  event: normalizedEvent,
56561
56670
  executedCount: results.length,
@@ -56605,6 +56714,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
56605
56714
  transition: `${result.previousState} -> ${result.newState}`,
56606
56715
  effects: JSON.stringify(result.effects)
56607
56716
  }));
56717
+ const _perfT2 = perfStart("processEvent:executeAll");
56608
56718
  const emittedDuringExec = await executeTransitionEffects({
56609
56719
  binding,
56610
56720
  // upstream gap: /runtime TransitionResult.effects is unknown[] — they are SExpr at runtime (see Almadar_UI_Gaps.md)
@@ -56616,6 +56726,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
56616
56726
  syncOnly: false,
56617
56727
  log: stateLog
56618
56728
  });
56729
+ perfEnd("processEvent:executeAll", _perfT2);
56619
56730
  emittedByTrait.set(traitName, emittedDuringExec);
56620
56731
  for (const emittedKey of emittedDuringExec) {
56621
56732
  bridgeEchoPendingRef.current.set(
@@ -56712,27 +56823,31 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
56712
56823
  if (orbital) dispatchedOrbitals.add(orbital);
56713
56824
  }
56714
56825
  const relayPayload = targetTrait !== void 0 ? { ...payload ?? {}, _targetTrait: targetTrait } : payload;
56715
- if (tick !== void 0) {
56716
- void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait);
56717
- } else {
56718
- await onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals);
56719
- }
56826
+ void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait);
56720
56827
  }
56828
+ perfEnd("processEvent:total", _perfT0);
56829
+ perfEnd(`event:${normalizedEvent}`, _perfT0);
56721
56830
  }, [entities, eventBus, sharedEntityStore]);
56722
56831
  const drainEventQueue = useCallback(async () => {
56723
56832
  if (processingRef.current) return;
56724
56833
  processingRef.current = true;
56834
+ const _perfT = perfStart("drain:pass");
56835
+ let _perfN = 0;
56725
56836
  try {
56726
56837
  while (eventQueueRef.current.length > 0) {
56727
56838
  const entry = eventQueueRef.current.shift();
56839
+ _perfN++;
56728
56840
  await processEventQueued(entry.eventKey, entry.payload, entry.targetTrait, entry.tick, entry.sourceTrait);
56729
56841
  }
56730
56842
  } finally {
56731
56843
  processingRef.current = false;
56844
+ perfEnd("drain:pass", _perfT);
56845
+ perfGauge("drain:passEntries", _perfN);
56732
56846
  }
56733
56847
  }, [processEventQueued]);
56734
56848
  const enqueueAndDrain = useCallback((eventKey, payload, targetTrait, tick, sourceTrait) => {
56735
56849
  enqueueEvent(eventQueueRef.current, { eventKey, payload, targetTrait, tick, sourceTrait });
56850
+ perfGauge("queue:depthAtEnqueue", eventQueueRef.current.length);
56736
56851
  void drainEventQueue();
56737
56852
  }, [drainEventQueue]);
56738
56853
  useCallback((eventKey, payload) => {
@@ -57031,7 +57146,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
57031
57146
  [serverActiveTraits]
57032
57147
  );
57033
57148
  const uiSlots = useUISlots();
57034
- const onEventProcessed = useCallback(async (event, payload, dispatchedOrbitals, tick, sourceTrait) => {
57149
+ const onEventProcessed = useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait) => {
57035
57150
  if (!bridge.connected || !orbitalNames?.length) return;
57036
57151
  const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
57037
57152
  xOrbitalLog.debug("TraitInitializer:fanout", () => ({
@@ -57045,9 +57160,10 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
57045
57160
  void bridge.sendEvent(name, event, withActiveTraits(payload), tick, sourceTrait);
57046
57161
  continue;
57047
57162
  }
57048
- const { effects, meta } = await bridge.sendEvent(name, event, withActiveTraits(payload));
57049
- recordServerResponse(name, event, meta);
57050
- applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
57163
+ void bridge.sendEvent(name, event, withActiveTraits(payload)).then(({ effects, meta }) => {
57164
+ recordServerResponse(name, event, meta);
57165
+ applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
57166
+ });
57051
57167
  }
57052
57168
  }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, onNavigateBack, embeddedTraits, activeTraitNames, withActiveTraits]);
57053
57169
  const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, navigateBack: onNavigateBack, traitConfigsByName, orbitalsByTrait, embeddedTraits, initPayload: routeParams } : { navigate: onNavigate, navigateBack: onNavigateBack, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits, initPayload: routeParams };
@@ -57365,14 +57481,15 @@ function OrbPreview({
57365
57481
  return pattern.replace(/:([A-Za-z0-9_]+)/g, (whole, key) => routeParams[key] ?? whole);
57366
57482
  }, [currentPagePath, routeParams]);
57367
57483
  const navStackRef = useRef(null);
57368
- const handleNavigate = useCallback((path) => {
57484
+ const handleNavigate = useCallback((path, navState) => {
57369
57485
  const hit = matchPathAmong(pages, path, (entry) => entry.page.path);
57370
57486
  const match = hit?.candidate;
57371
- const params = hit?.params ?? {};
57487
+ const params = { ...hit?.params ?? {}, ...navState ?? {} };
57372
57488
  navLog.debug("handleNavigate", () => ({
57373
57489
  path,
57374
57490
  matched: match?.page.name ?? null,
57375
57491
  params,
57492
+ navState: navState ? JSON.stringify(navState) : void 0,
57376
57493
  availablePaths: pages.map((p) => p.page.path)
57377
57494
  }));
57378
57495
  if (match?.page.name) {
@@ -57387,9 +57504,9 @@ function OrbPreview({
57387
57504
  }
57388
57505
  }, [pages]);
57389
57506
  const handleNavigateEffect = useCallback(
57390
- (path, _params, crumb) => {
57507
+ (path, params, crumb) => {
57391
57508
  navStackRef.current?.beginNavigate(path, crumb);
57392
- handleNavigate(path);
57509
+ handleNavigate(path, params);
57393
57510
  },
57394
57511
  [handleNavigate]
57395
57512
  );
@@ -59706,14 +59823,7 @@ TraitCardNode.displayName = "TraitCardNode";
59706
59823
 
59707
59824
  // components/avl/organisms/FlowCanvas.tsx
59708
59825
  init_useEventBus();
59709
- var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
59710
- pushPerfEntry({
59711
- name: `profiler:${id}:${phase}`,
59712
- durationMs: actualDuration,
59713
- ts: commitTime,
59714
- detail: { baseDuration }
59715
- });
59716
- };
59826
+ init_perf();
59717
59827
  var flowCanvasLog = createLogger("almadar:ui:flow-canvas");
59718
59828
  var NODE_TYPES = {
59719
59829
  preview: OrbPreviewNode,