@almadar/ui 4.6.14 → 4.7.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.
@@ -1116,13 +1116,23 @@ function SlotsProvider({ children }) {
1116
1116
  const setSlotPatterns = React115.useCallback((slot, patterns, source) => {
1117
1117
  const sourceKey = source?.trait ?? DEFAULT_SOURCE_KEY;
1118
1118
  const entityProp = patterns[0]?.pattern && typeof patterns[0].pattern === "object" ? patterns[0].pattern.entity : void 0;
1119
+ const firstPatternType = patterns[0]?.pattern && typeof patterns[0].pattern === "object" ? patterns[0].pattern.type : void 0;
1119
1120
  slotLog.debug("setSlotPatterns", {
1120
1121
  slot,
1121
1122
  sourceKey,
1122
1123
  patternCount: patterns.length,
1123
- firstPatternType: patterns[0]?.pattern && typeof patterns[0].pattern === "object" ? patterns[0].pattern.type : void 0,
1124
+ firstPatternType,
1124
1125
  entityRefId: refId(entityProp)
1125
1126
  });
1127
+ if (source?.trait) {
1128
+ xOrbitalLog.info("slot-set", {
1129
+ slot,
1130
+ sourceTrait: source.trait,
1131
+ patternCount: patterns.length,
1132
+ firstPatternType,
1133
+ state: source.state
1134
+ });
1135
+ }
1126
1136
  setSlots((prev) => {
1127
1137
  const prevSlot = prev[slot] ?? {};
1128
1138
  return {
@@ -1144,6 +1154,7 @@ function SlotsProvider({ children }) {
1144
1154
  });
1145
1155
  }, []);
1146
1156
  const clearSlotForSource = React115.useCallback((slot, sourceTrait) => {
1157
+ xOrbitalLog.info("slot-clear-source", { slot, sourceTrait });
1147
1158
  setSlots((prev) => {
1148
1159
  const existing = prev[slot];
1149
1160
  if (!existing || !(sourceTrait in existing)) return prev;
@@ -1184,11 +1195,12 @@ function useSlotsActions() {
1184
1195
  }
1185
1196
  return actions;
1186
1197
  }
1187
- var slotLog, refIds, nextRefId, DEFAULT_SOURCE_KEY, SlotsStateContext, SlotsActionsContext;
1198
+ var slotLog, xOrbitalLog, refIds, nextRefId, DEFAULT_SOURCE_KEY, SlotsStateContext, SlotsActionsContext;
1188
1199
  var init_SlotsContext = __esm({
1189
1200
  "runtime/ui/SlotsContext.tsx"() {
1190
1201
  init_logger();
1191
1202
  slotLog = createLogger("almadar:ui:slot-render");
1203
+ xOrbitalLog = createLogger("almadar:runtime:cross-orbital");
1192
1204
  refIds = /* @__PURE__ */ new WeakMap();
1193
1205
  nextRefId = 1;
1194
1206
  DEFAULT_SOURCE_KEY = "__default__";
@@ -8182,7 +8194,7 @@ var init_MapView = __esm({
8182
8194
  shadowSize: [41, 41]
8183
8195
  });
8184
8196
  L.Marker.prototype.options.icon = defaultIcon;
8185
- const { useEffect: useEffect68, useRef: useRef65, useCallback: useCallback110, useState: useState103 } = React115__namespace.default;
8197
+ const { useEffect: useEffect68, useRef: useRef65, useCallback: useCallback110, useState: useState102 } = React115__namespace.default;
8186
8198
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
8187
8199
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
8188
8200
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -8226,7 +8238,7 @@ var init_MapView = __esm({
8226
8238
  showAttribution = true
8227
8239
  }) {
8228
8240
  const eventBus = useEventBus2();
8229
- const [clickedPosition, setClickedPosition] = useState103(null);
8241
+ const [clickedPosition, setClickedPosition] = useState102(null);
8230
8242
  const handleMapClick = useCallback110((lat, lng) => {
8231
8243
  if (showClickedPin) {
8232
8244
  setClickedPosition({ lat, lng });
@@ -38179,6 +38191,7 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
38179
38191
  const eventBus = useEventBus();
38180
38192
  const { entities } = useEntitySchema();
38181
38193
  const traitConfigsByName = options?.traitConfigsByName;
38194
+ const orbitalsByTrait = options?.orbitalsByTrait;
38182
38195
  const manager = React115.useMemo(() => {
38183
38196
  const traitDefs = traitBindings.map(toTraitDefinition);
38184
38197
  const m = new runtime.StateMachineManager(traitDefs);
@@ -38627,7 +38640,10 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
38627
38640
  if (!LIFECYCLE_EVENTS.has(normalizedEvent)) {
38628
38641
  for (const { traitName, result } of results) {
38629
38642
  if (!result.executed) continue;
38630
- eventBus.emit(normalizedEvent, payload, {
38643
+ const orbitalName = orbitalsByTrait?.[traitName];
38644
+ if (!orbitalName) continue;
38645
+ eventBus.emit(`UI:${orbitalName}.${traitName}.${normalizedEvent}`, payload, {
38646
+ orbital: orbitalName,
38631
38647
  trait: traitName,
38632
38648
  fromBridge: true
38633
38649
  });
@@ -38638,7 +38654,13 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
38638
38654
  }
38639
38655
  const onEventProcessed = optionsRef.current?.onEventProcessed;
38640
38656
  if (onEventProcessed) {
38641
- await onEventProcessed(normalizedEvent, payload);
38657
+ const dispatchedOrbitals = /* @__PURE__ */ new Set();
38658
+ for (const { traitName, result } of results) {
38659
+ if (!result.executed) continue;
38660
+ const orbital = orbitalsByTrait?.[traitName];
38661
+ if (orbital) dispatchedOrbitals.add(orbital);
38662
+ }
38663
+ await onEventProcessed(normalizedEvent, payload, dispatchedOrbitals);
38642
38664
  }
38643
38665
  }, [entities, eventBus]);
38644
38666
  const drainEventQueue = React115.useCallback(async () => {
@@ -38682,26 +38704,34 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
38682
38704
  }
38683
38705
  console.log("[TraitStateMachine] Subscribing to events:", Array.from(allEvents));
38684
38706
  const unsubscribes = [];
38685
- for (const eventKey of allEvents) {
38686
- if (eventKey === "INIT" || eventKey === "LOAD" || eventKey === "$MOUNT") {
38687
- continue;
38707
+ for (const binding of traitBindings) {
38708
+ const traitName = binding.trait.name;
38709
+ const orbitalName = orbitalsByTrait?.[traitName];
38710
+ if (!orbitalName) continue;
38711
+ for (const transition of binding.trait.transitions) {
38712
+ const eventKey = transition.event;
38713
+ if (eventKey === "INIT" || eventKey === "LOAD" || eventKey === "$MOUNT") {
38714
+ continue;
38715
+ }
38716
+ const unsub = eventBus.on(`UI:${orbitalName}.${traitName}.${eventKey}`, (event) => {
38717
+ if (event.source && event.source.fromBridge) {
38718
+ return;
38719
+ }
38720
+ enqueueAndDrain(eventKey, event.payload);
38721
+ });
38722
+ unsubscribes.push(unsub);
38688
38723
  }
38689
- const unsub = eventBus.on(`UI:${eventKey}`, (event) => {
38690
- console.log("[TraitStateMachine] Received event:", `UI:${eventKey}`, event);
38691
- enqueueAndDrain(eventKey, event.payload);
38692
- });
38693
- unsubscribes.push(unsub);
38694
38724
  }
38695
38725
  for (const binding of traitBindings) {
38726
+ const ownOrbital = orbitalsByTrait?.[binding.trait.name];
38696
38727
  const listens = binding.trait.listens ?? [];
38697
38728
  for (const listen of listens) {
38698
- const expectedTrait = listen.source?.trait;
38699
- const unsub = eventBus.on(listen.event, (event) => {
38700
- if (expectedTrait) {
38701
- const emitTrait = event.source?.trait;
38702
- if (emitTrait !== expectedTrait) return;
38703
- }
38704
- console.log("[TraitStateMachine] listens", binding.trait.name, listen.event, "\u2192", listen.triggers, "from", event.source?.trait);
38729
+ const sourceTrait = listen.source?.trait;
38730
+ if (!sourceTrait) continue;
38731
+ const sourceOrbital = listen.source?.orbital ?? ownOrbital;
38732
+ if (!sourceOrbital) continue;
38733
+ const busKey = `UI:${sourceOrbital}.${sourceTrait}.${listen.event}`;
38734
+ const unsub = eventBus.on(busKey, (event) => {
38705
38735
  enqueueAndDrain(listen.triggers, event.payload);
38706
38736
  });
38707
38737
  unsubscribes.push(unsub);
@@ -38848,6 +38878,8 @@ init_EntitySchemaContext();
38848
38878
 
38849
38879
  // runtime/ServerBridge.tsx
38850
38880
  init_useEventBus();
38881
+ init_logger();
38882
+ var xOrbitalLog2 = createLogger("almadar:runtime:cross-orbital");
38851
38883
  var ServerBridgeContext = React115.createContext(null);
38852
38884
  function useServerBridge() {
38853
38885
  const ctx = React115.useContext(ServerBridgeContext);
@@ -38925,8 +38957,22 @@ function ServerBridgeProvider({
38925
38957
  }
38926
38958
  if (result.emittedEvents) {
38927
38959
  for (const emitted of result.emittedEvents) {
38928
- eventBus.emit(`UI:${emitted.event}`, emitted.payload);
38929
- eventBus.emit(emitted.event, emitted.payload);
38960
+ const evTrait = emitted.source?.trait;
38961
+ if (!evTrait) {
38962
+ xOrbitalLog2.warn("emit:dropped-no-source", {
38963
+ event: emitted.event,
38964
+ dispatchOrbital: orbitalName
38965
+ });
38966
+ continue;
38967
+ }
38968
+ const key = emitted.source?.orbital ? `UI:${emitted.source.orbital}.${evTrait}.${emitted.event}` : `UI:${evTrait}.${emitted.event}`;
38969
+ xOrbitalLog2.info("emit:rebroadcast", {
38970
+ busKey: key,
38971
+ sourceOrbital: emitted.source?.orbital,
38972
+ sourceTrait: evTrait,
38973
+ dispatchOrbital: orbitalName
38974
+ });
38975
+ eventBus.emit(key, emitted.payload);
38930
38976
  }
38931
38977
  }
38932
38978
  } else if (result.error) {
@@ -39047,6 +39093,10 @@ function prepareSchemaForPreview(input) {
39047
39093
  const schema = adjustSchemaForMockData(parsed, mockData);
39048
39094
  return { schema, mockData };
39049
39095
  }
39096
+
39097
+ // runtime/OrbPreview.tsx
39098
+ init_logger();
39099
+ var xOrbitalLog3 = createLogger("almadar:runtime:cross-orbital");
39050
39100
  function normalizeChild(child) {
39051
39101
  if (typeof child === "string") return child;
39052
39102
  if (child === null || typeof child !== "object" || Array.isArray(child)) {
@@ -39126,6 +39176,11 @@ function applyServerEffects(effects, uiSlots, onNavigate) {
39126
39176
  const patternRecord = eff.pattern;
39127
39177
  const { type: patternType, children, ...inlineProps } = patternRecord;
39128
39178
  const normalizedChildren = Array.isArray(children) ? children.map((c) => normalizeChild(c)) : children;
39179
+ xOrbitalLog3.info("slot-write", {
39180
+ slot: eff.slot,
39181
+ sourceTrait: eff.traitName ?? "server",
39182
+ patternType: typeof patternType === "string" ? patternType : void 0
39183
+ });
39129
39184
  uiSlots.render({
39130
39185
  target: eff.slot,
39131
39186
  pattern: patternType,
@@ -39140,19 +39195,26 @@ function applyServerEffects(effects, uiSlots, onNavigate) {
39140
39195
  }
39141
39196
  }
39142
39197
  }
39143
- function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFallback, persistence, traitConfigsByName }) {
39198
+ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFallback, persistence, traitConfigsByName, orbitalsByTrait }) {
39144
39199
  const slotsActions = useSlotsActions();
39145
39200
  const bridge = useServerBridge();
39146
39201
  const uiSlots = context.useUISlots();
39147
- const onEventProcessed = React115.useCallback(async (event, payload) => {
39202
+ const onEventProcessed = React115.useCallback(async (event, payload, dispatchedOrbitals) => {
39148
39203
  if (!bridge.connected || !orbitalNames?.length) return;
39149
- for (const name of orbitalNames) {
39204
+ const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
39205
+ xOrbitalLog3.info("TraitInitializer:fanout", {
39206
+ event,
39207
+ sentTo: targets,
39208
+ skipped: orbitalNames.filter((n) => !targets.includes(n)),
39209
+ dispatchedOrbitalsSize: dispatchedOrbitals?.size ?? 0
39210
+ });
39211
+ for (const name of targets) {
39150
39212
  const { effects, meta } = await bridge.sendEvent(name, event, payload);
39151
39213
  recordServerResponse(name, event, meta);
39152
39214
  applyServerEffects(effects, uiSlots, onNavigate);
39153
39215
  }
39154
39216
  }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate]);
39155
- const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, traitConfigsByName } : { navigate: onNavigate, persistence, traitConfigsByName };
39217
+ const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, traitConfigsByName, orbitalsByTrait } : { navigate: onNavigate, persistence, traitConfigsByName, orbitalsByTrait };
39156
39218
  const { sendEvent } = useTraitStateMachine(traits2, slotsActions, opts);
39157
39219
  const initSentRef = React115.useRef(false);
39158
39220
  React115.useEffect(() => {
@@ -39202,27 +39264,68 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate, onLoc
39202
39264
  const allPageTraits = React115.useMemo(() => {
39203
39265
  if (pageName && traits2.length > 0) return traits2;
39204
39266
  if (!ir?.pages || ir.pages.size <= 1) return traits2;
39205
- const combined = [];
39267
+ const firstPage = ir.pages.values().next().value;
39268
+ if (!firstPage) return traits2;
39269
+ const firstPageTraits = [];
39206
39270
  const seen = /* @__PURE__ */ new Set();
39207
- for (const page of ir.pages.values()) {
39208
- for (const t of page.traits) {
39209
- const binding = t;
39210
- const traitObj = binding.trait;
39211
- const name = traitObj?.name ?? binding.name ?? "";
39212
- if (name && !seen.has(name)) {
39213
- seen.add(name);
39214
- combined.push(t);
39215
- }
39271
+ for (const binding of firstPage.traits) {
39272
+ const name = binding.trait.name;
39273
+ if (name && !seen.has(name)) {
39274
+ seen.add(name);
39275
+ firstPageTraits.push(binding);
39216
39276
  }
39217
39277
  }
39218
- return combined.length > 0 ? combined : traits2;
39278
+ return firstPageTraits.length > 0 ? firstPageTraits : traits2;
39219
39279
  }, [ir, traits2, pageName]);
39220
- const orbitalNames = React115.useMemo(() => {
39280
+ React115.useMemo(() => {
39221
39281
  const parsed = schema;
39222
39282
  const orbitals = parsed?.orbitals;
39223
39283
  if (!orbitals) return [];
39224
39284
  return orbitals.filter((o) => typeof o.name === "string").map((o) => o.name);
39225
39285
  }, [schema]);
39286
+ const orbitalsByTrait = React115.useMemo(() => {
39287
+ const map = {};
39288
+ const parsed = schema;
39289
+ if (!parsed?.orbitals) return map;
39290
+ for (const orb of parsed.orbitals) {
39291
+ for (const traitRef of orb.traits) {
39292
+ let traitName;
39293
+ if (typeof traitRef === "string") {
39294
+ const parts = traitRef.split(".");
39295
+ traitName = parts[parts.length - 1];
39296
+ } else if ("ref" in traitRef && typeof traitRef.ref === "string") {
39297
+ const parts = traitRef.ref.split(".");
39298
+ traitName = traitRef.name ?? parts[parts.length - 1];
39299
+ } else if ("name" in traitRef && typeof traitRef.name === "string") {
39300
+ traitName = traitRef.name;
39301
+ }
39302
+ if (traitName) map[traitName] = orb.name;
39303
+ }
39304
+ }
39305
+ return map;
39306
+ }, [schema]);
39307
+ const pageOrbitalNames = React115.useMemo(() => {
39308
+ const set = /* @__PURE__ */ new Set();
39309
+ for (const binding of allPageTraits) {
39310
+ const orb = orbitalsByTrait[binding.trait.name];
39311
+ if (orb) set.add(orb);
39312
+ }
39313
+ return Array.from(set);
39314
+ }, [allPageTraits, orbitalsByTrait]);
39315
+ React115.useEffect(() => {
39316
+ const traitNames = allPageTraits.map((b) => b.trait.name);
39317
+ const orbitalsByTraitForPage = {};
39318
+ for (const name of traitNames) {
39319
+ const orb = orbitalsByTrait[name];
39320
+ if (orb) orbitalsByTraitForPage[name] = orb;
39321
+ }
39322
+ xOrbitalLog3.info("SchemaRunner:mount", {
39323
+ pageName,
39324
+ traitNames,
39325
+ orbitalsByTraitForPage,
39326
+ pageOrbitalNames: pageOrbitalNames.join(",")
39327
+ });
39328
+ }, [pageName, allPageTraits, orbitalsByTrait, pageOrbitalNames]);
39226
39329
  const traitConfigsByName = React115.useMemo(() => {
39227
39330
  const map = {};
39228
39331
  const parsed = schema;
@@ -39263,8 +39366,9 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate, onLoc
39263
39366
  TraitInitializer,
39264
39367
  {
39265
39368
  traits: allPageTraits,
39266
- orbitalNames: serverUrl ? orbitalNames : void 0,
39369
+ orbitalNames: serverUrl ? pageOrbitalNames : void 0,
39267
39370
  traitConfigsByName,
39371
+ orbitalsByTrait,
39268
39372
  onNavigate,
39269
39373
  onLocalFallback,
39270
39374
  persistence
@@ -39286,7 +39390,8 @@ function OrbPreview({
39286
39390
  autoMock = false,
39287
39391
  height = "400px",
39288
39392
  className,
39289
- serverUrl
39393
+ serverUrl,
39394
+ initialPagePath
39290
39395
  }) {
39291
39396
  const [localFallback, setLocalFallback] = React115.useState(false);
39292
39397
  const eventBus = useEventBus();
@@ -39332,7 +39437,17 @@ function OrbPreview({
39332
39437
  return [];
39333
39438
  }
39334
39439
  }, [parsedSchema]);
39335
- const [currentPage, setCurrentPage] = React115.useState(void 0);
39440
+ const initialPageName = React115.useMemo(() => {
39441
+ if (!initialPagePath) return void 0;
39442
+ const match = pages.find(({ page }) => page.path === initialPagePath);
39443
+ return match?.page.name;
39444
+ }, [pages, initialPagePath]);
39445
+ const [currentPage, setCurrentPage] = React115.useState(initialPageName);
39446
+ React115.useEffect(() => {
39447
+ if (initialPageName && initialPageName !== currentPage) {
39448
+ setCurrentPage(initialPageName);
39449
+ }
39450
+ }, [initialPageName, currentPage]);
39336
39451
  const handleNavigate = React115.useCallback((path) => {
39337
39452
  const match = pages.find(({ page }) => page.path === path);
39338
39453
  if (match) {