@almadar/ui 4.10.7 → 4.12.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.
@@ -4492,6 +4492,16 @@ function useUISlotManager() {
4492
4492
  },
4493
4493
  []
4494
4494
  );
4495
+ const updateTraitContent = React128.useCallback(
4496
+ (traitName, content) => {
4497
+ const id = generateId();
4498
+ const fullContent = { ...content, id, sourceTrait: traitName };
4499
+ indexTraitRender(traitName, fullContent);
4500
+ notifyTraitSubscribers(traitName, fullContent);
4501
+ return id;
4502
+ },
4503
+ [indexTraitRender, notifyTraitSubscribers]
4504
+ );
4495
4505
  return {
4496
4506
  slots,
4497
4507
  render,
@@ -4503,7 +4513,8 @@ function useUISlotManager() {
4503
4513
  hasContent,
4504
4514
  getContent,
4505
4515
  getTraitContent,
4506
- subscribeTrait
4516
+ subscribeTrait,
4517
+ updateTraitContent
4507
4518
  };
4508
4519
  }
4509
4520
  var DEFAULT_SOURCE_KEY, MULTI_SOURCE_STACK_TRAIT, ALL_SLOTS, DEFAULT_SLOTS, DEFAULT_SOURCES, idCounter;
@@ -51542,6 +51553,76 @@ function useResolvedSchema(schema, pageName) {
51542
51553
  return result;
51543
51554
  }
51544
51555
 
51556
+ // runtime/embedded-traits.ts
51557
+ var TRAIT_BINDING_PREFIX = "@trait.";
51558
+ function collectTraitRefsFromValue(value, into) {
51559
+ if (value === null || value === void 0) return;
51560
+ if (typeof value === "string") {
51561
+ if (value.startsWith(TRAIT_BINDING_PREFIX)) {
51562
+ const rest = value.slice(TRAIT_BINDING_PREFIX.length);
51563
+ const dot = rest.indexOf(".");
51564
+ const traitName = dot === -1 ? rest : rest.slice(0, dot);
51565
+ if (traitName.length > 0) into.add(traitName);
51566
+ }
51567
+ return;
51568
+ }
51569
+ if (Array.isArray(value)) {
51570
+ for (const item of value) collectTraitRefsFromValue(item, into);
51571
+ return;
51572
+ }
51573
+ if (typeof value === "object") {
51574
+ for (const v of Object.values(value)) {
51575
+ collectTraitRefsFromValue(v, into);
51576
+ }
51577
+ }
51578
+ }
51579
+ function collectTraitRefsFromEffects(effects, into) {
51580
+ if (!effects) return;
51581
+ for (const effect of effects) {
51582
+ if (!Array.isArray(effect)) continue;
51583
+ if (effect[0] === "render-ui" && effect.length >= 3) {
51584
+ collectTraitRefsFromValue(effect[2], into);
51585
+ continue;
51586
+ }
51587
+ for (let i = 1; i < effect.length; i++) {
51588
+ const arg = effect[i];
51589
+ if (Array.isArray(arg)) collectTraitRefsFromEffects([arg], into);
51590
+ else collectTraitRefsFromValue(arg, into);
51591
+ }
51592
+ }
51593
+ }
51594
+ function collectEmbeddedTraits(schema) {
51595
+ const out = /* @__PURE__ */ new Set();
51596
+ if (!schema?.orbitals) return out;
51597
+ for (const orbital of schema.orbitals) {
51598
+ if (!orbital || typeof orbital !== "object") continue;
51599
+ const traits2 = orbital.traits;
51600
+ if (!Array.isArray(traits2)) continue;
51601
+ for (const trait of traits2) {
51602
+ if (!trait || typeof trait !== "object") continue;
51603
+ const resolved = trait._resolved;
51604
+ const target = resolved && typeof resolved === "object" ? resolved : trait;
51605
+ const stateMachine = target.stateMachine;
51606
+ const transitions = stateMachine?.transitions;
51607
+ if (!Array.isArray(transitions)) continue;
51608
+ for (const t of transitions) {
51609
+ if (!t || typeof t !== "object") continue;
51610
+ const effects = t.effects;
51611
+ collectTraitRefsFromEffects(effects, out);
51612
+ }
51613
+ const initialEffects = target.initialEffects;
51614
+ collectTraitRefsFromEffects(initialEffects, out);
51615
+ const ticks2 = target.ticks;
51616
+ if (Array.isArray(ticks2)) {
51617
+ for (const tick of ticks2) {
51618
+ collectTraitRefsFromEffects(tick?.effects, out);
51619
+ }
51620
+ }
51621
+ }
51622
+ }
51623
+ return out;
51624
+ }
51625
+
51545
51626
  // hooks/index.ts
51546
51627
  init_useEventBus();
51547
51628
  init_useUISlots();
@@ -52200,6 +52281,38 @@ init_EntitySchemaContext();
52200
52281
  init_useEventBus();
52201
52282
  init_logger();
52202
52283
  var xOrbitalLog2 = createLogger("almadar:runtime:cross-orbital");
52284
+ function createHttpTransport(serverUrl) {
52285
+ return {
52286
+ register: async (schema) => {
52287
+ try {
52288
+ const res = await fetch(`${serverUrl}/register`, {
52289
+ method: "POST",
52290
+ headers: { "Content-Type": "application/json" },
52291
+ body: JSON.stringify({ schema })
52292
+ });
52293
+ const result = await res.json();
52294
+ return !!result.success;
52295
+ } catch (err) {
52296
+ console.error("[ServerBridge] Registration failed:", err);
52297
+ return false;
52298
+ }
52299
+ },
52300
+ unregister: async () => {
52301
+ try {
52302
+ await fetch(`${serverUrl}/unregister`, { method: "DELETE" });
52303
+ } catch {
52304
+ }
52305
+ },
52306
+ sendEvent: async (orbitalName, event, payload) => {
52307
+ const res = await fetch(`${serverUrl}/${orbitalName}/events`, {
52308
+ method: "POST",
52309
+ headers: { "Content-Type": "application/json" },
52310
+ body: JSON.stringify({ event, payload })
52311
+ });
52312
+ return res.json();
52313
+ }
52314
+ };
52315
+ }
52203
52316
  var ServerBridgeContext = React128.createContext(null);
52204
52317
  function useServerBridge() {
52205
52318
  const ctx = React128.useContext(ServerBridgeContext);
@@ -52212,40 +52325,34 @@ function useServerBridge() {
52212
52325
  function ServerBridgeProvider({
52213
52326
  schema,
52214
52327
  serverUrl,
52328
+ transport: customTransport,
52215
52329
  children
52216
52330
  }) {
52331
+ if (!serverUrl && !customTransport) {
52332
+ throw new Error("ServerBridgeProvider requires either serverUrl or transport");
52333
+ }
52334
+ if (serverUrl && customTransport) {
52335
+ throw new Error("ServerBridgeProvider accepts serverUrl OR transport, not both");
52336
+ }
52217
52337
  const eventBus = useEventBus();
52218
52338
  const [connected, setConnected] = React128.useState(false);
52219
- const registerSchema = React128.useCallback(async () => {
52220
- try {
52221
- const res = await fetch(`${serverUrl}/register`, {
52222
- method: "POST",
52223
- headers: { "Content-Type": "application/json" },
52224
- body: JSON.stringify({ schema })
52225
- });
52226
- const result = await res.json();
52227
- return !!result.success;
52228
- } catch (err) {
52229
- console.error("[ServerBridge] Registration failed:", err);
52230
- return false;
52231
- }
52232
- }, [schema, serverUrl]);
52233
- const unregisterSchema = React128.useCallback(async () => {
52234
- try {
52235
- await fetch(`${serverUrl}/unregister`, { method: "DELETE" });
52236
- } catch {
52237
- }
52238
- }, [serverUrl]);
52339
+ const transport = React128.useMemo(
52340
+ () => customTransport ?? createHttpTransport(serverUrl),
52341
+ [serverUrl, customTransport]
52342
+ );
52343
+ const registerSchema = React128.useCallback(
52344
+ async () => transport.register(schema),
52345
+ [schema, transport]
52346
+ );
52347
+ const unregisterSchema = React128.useCallback(
52348
+ async () => transport.unregister(),
52349
+ [transport]
52350
+ );
52239
52351
  const sendEvent = React128.useCallback(async (orbitalName, event, payload) => {
52240
52352
  const emptyMeta = { success: false, clientEffects: 0, dataEntities: {}, emittedEvents: [] };
52241
52353
  if (!connected) return { effects: [], meta: emptyMeta };
52242
52354
  try {
52243
- const res = await fetch(`${serverUrl}/${orbitalName}/events`, {
52244
- method: "POST",
52245
- headers: { "Content-Type": "application/json" },
52246
- body: JSON.stringify({ event, payload })
52247
- });
52248
- const result = await res.json();
52355
+ const result = await transport.sendEvent(orbitalName, event, payload);
52249
52356
  const effects = [];
52250
52357
  const responseData = result.data || {};
52251
52358
  const dataEntities = {};
@@ -52303,7 +52410,7 @@ function ServerBridgeProvider({
52303
52410
  console.error("[ServerBridge] Event send failed:", err);
52304
52411
  return { effects: [], meta: { ...emptyMeta, error: err instanceof Error ? err.message : String(err) } };
52305
52412
  }
52306
- }, [connected, serverUrl, eventBus]);
52413
+ }, [connected, transport, eventBus]);
52307
52414
  React128.useEffect(() => {
52308
52415
  if (!schema) return;
52309
52416
  let cancelled = false;
@@ -52490,32 +52597,49 @@ function SlotBridge() {
52490
52597
  }, [slots, render, clear]);
52491
52598
  return null;
52492
52599
  }
52493
- function applyServerEffects(effects, uiSlots, onNavigate) {
52600
+ function applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits) {
52494
52601
  for (const eff of effects) {
52495
52602
  if (eff.type === "render-ui" && eff.slot && eff.pattern) {
52496
52603
  const patternRecord = eff.pattern;
52497
52604
  const { type: patternType, children, ...inlineProps } = patternRecord;
52498
52605
  const normalizedChildren = Array.isArray(children) ? children.map((c) => normalizeChild(c)) : children;
52499
- xOrbitalLog3.info("slot-write", {
52500
- slot: eff.slot,
52501
- sourceTrait: eff.traitName ?? "server",
52502
- patternType: typeof patternType === "string" ? patternType : void 0
52503
- });
52504
- uiSlots.render({
52505
- target: eff.slot,
52506
- pattern: patternType,
52507
- props: {
52508
- ...inlineProps,
52509
- ...normalizedChildren !== void 0 ? { children: normalizedChildren } : {}
52510
- },
52511
- sourceTrait: eff.traitName ?? "server"
52512
- });
52606
+ const sourceTrait = eff.traitName ?? "server";
52607
+ const isEmbedded = embeddedTraits?.has(sourceTrait) ?? false;
52608
+ const props = {
52609
+ ...inlineProps,
52610
+ ...normalizedChildren !== void 0 ? { children: normalizedChildren } : {}
52611
+ };
52612
+ if (isEmbedded) {
52613
+ xOrbitalLog3.info("slot:embed-routed", {
52614
+ sourceTrait,
52615
+ slot: eff.slot,
52616
+ patternType: typeof patternType === "string" ? patternType : void 0
52617
+ });
52618
+ uiSlots.updateTraitContent(sourceTrait, {
52619
+ pattern: patternType,
52620
+ props,
52621
+ priority: 0,
52622
+ animation: "fade"
52623
+ });
52624
+ } else {
52625
+ xOrbitalLog3.info("slot-write", {
52626
+ slot: eff.slot,
52627
+ sourceTrait,
52628
+ patternType: typeof patternType === "string" ? patternType : void 0
52629
+ });
52630
+ uiSlots.render({
52631
+ target: eff.slot,
52632
+ pattern: patternType,
52633
+ props,
52634
+ sourceTrait
52635
+ });
52636
+ }
52513
52637
  } else if (eff.type === "navigate" && eff.route && onNavigate) {
52514
52638
  onNavigate(eff.route, eff.params);
52515
52639
  }
52516
52640
  }
52517
52641
  }
52518
- function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFallback, persistence, traitConfigsByName, orbitalsByTrait }) {
52642
+ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFallback, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits }) {
52519
52643
  const slotsActions = useSlotsActions();
52520
52644
  const bridge = useServerBridge();
52521
52645
  const uiSlots = useUISlots();
@@ -52531,9 +52655,9 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFa
52531
52655
  for (const name of targets) {
52532
52656
  const { effects, meta } = await bridge.sendEvent(name, event, payload);
52533
52657
  recordServerResponse(name, event, meta);
52534
- applyServerEffects(effects, uiSlots, onNavigate);
52658
+ applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits);
52535
52659
  }
52536
- }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate]);
52660
+ }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, embeddedTraits]);
52537
52661
  const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, traitConfigsByName, orbitalsByTrait } : { navigate: onNavigate, persistence, traitConfigsByName, orbitalsByTrait };
52538
52662
  const { sendEvent } = useTraitStateMachine(traits2, slotsActions, opts);
52539
52663
  const initSentRef = React128.useRef(false);
@@ -52573,13 +52697,13 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFa
52573
52697
  effects: effectTraces,
52574
52698
  timestamp: Date.now()
52575
52699
  });
52576
- applyServerEffects(effects, uiSlots, onNavigate);
52700
+ applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits);
52577
52701
  }
52578
52702
  })();
52579
- }, [bridge.connected, orbitalNames, bridge.sendEvent, uiSlots, onNavigate]);
52703
+ }, [bridge.connected, orbitalNames, bridge.sendEvent, uiSlots, onNavigate, embeddedTraits]);
52580
52704
  return null;
52581
52705
  }
52582
- function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate, onLocalFallback, persistence }) {
52706
+ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavigate, onLocalFallback, persistence }) {
52583
52707
  const { traits: traits2, allEntities, ir } = useResolvedSchema(schema, pageName);
52584
52708
  const allPageTraits = React128.useMemo(() => {
52585
52709
  if (pageName && traits2.length > 0) return traits2;
@@ -52682,6 +52806,9 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate, onLoc
52682
52806
  }
52683
52807
  return map;
52684
52808
  }, [schema]);
52809
+ const embeddedTraits = React128.useMemo(() => {
52810
+ return collectEmbeddedTraits(schema);
52811
+ }, [schema]);
52685
52812
  const inner = /* @__PURE__ */ jsxRuntime.jsx(VerificationProvider, { enabled: true, children: /* @__PURE__ */ jsxRuntime.jsx(SlotsProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(
52686
52813
  EntitySchemaProvider,
52687
52814
  {
@@ -52693,9 +52820,10 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate, onLoc
52693
52820
  TraitInitializer,
52694
52821
  {
52695
52822
  traits: allPageTraits,
52696
- orbitalNames: serverUrl ? pageOrbitalNames : void 0,
52823
+ orbitalNames: serverUrl || transport ? pageOrbitalNames : void 0,
52697
52824
  traitConfigsByName,
52698
52825
  orbitalsByTrait,
52826
+ embeddedTraits,
52699
52827
  onNavigate,
52700
52828
  onLocalFallback,
52701
52829
  persistence
@@ -52706,8 +52834,8 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate, onLoc
52706
52834
  ]
52707
52835
  }
52708
52836
  ) }) });
52709
- if (serverUrl) {
52710
- return /* @__PURE__ */ jsxRuntime.jsx(ServerBridgeProvider, { schema, serverUrl, children: inner });
52837
+ if (serverUrl || transport) {
52838
+ return /* @__PURE__ */ jsxRuntime.jsx(ServerBridgeProvider, { schema, serverUrl, transport, children: inner });
52711
52839
  }
52712
52840
  return inner;
52713
52841
  }
@@ -52718,8 +52846,12 @@ function OrbPreview({
52718
52846
  height = "400px",
52719
52847
  className,
52720
52848
  serverUrl,
52849
+ transport,
52721
52850
  initialPagePath
52722
52851
  }) {
52852
+ if (serverUrl && transport) {
52853
+ throw new Error("OrbPreview accepts serverUrl OR transport, not both");
52854
+ }
52723
52855
  const [localFallback, setLocalFallback] = React128.useState(false);
52724
52856
  const eventBus = useEventBus();
52725
52857
  const handleLocalFallback = React128.useCallback(() => {
@@ -52741,21 +52873,21 @@ function OrbPreview({
52741
52873
  } else {
52742
52874
  parsed = schema;
52743
52875
  }
52744
- if (autoMock && !serverUrl) {
52876
+ if (autoMock && !serverUrl && !transport) {
52745
52877
  const prepared = prepareSchemaForPreview(parsed);
52746
52878
  return { ok: true, schema: prepared.schema, mockData: prepared.mockData };
52747
52879
  }
52748
52880
  return { ok: true, schema: parsed, mockData: mockData ?? {} };
52749
- }, [schema, autoMock, serverUrl, mockData]);
52881
+ }, [schema, autoMock, serverUrl, transport, mockData]);
52750
52882
  const parsedSchema = parseResult.ok ? parseResult.schema : null;
52751
52883
  const effectiveMockData = parseResult.ok ? parseResult.mockData : {};
52752
52884
  const persistence = React128.useMemo(() => {
52753
- if (!parsedSchema || serverUrl) return void 0;
52885
+ if (!parsedSchema || serverUrl || transport) return void 0;
52754
52886
  if (!autoMock) return void 0;
52755
52887
  const adapter = new runtime.InMemoryPersistence();
52756
52888
  adapter.seed(effectiveMockData);
52757
52889
  return adapter;
52758
- }, [parsedSchema, serverUrl, autoMock, effectiveMockData]);
52890
+ }, [parsedSchema, serverUrl, transport, autoMock, effectiveMockData]);
52759
52891
  const pages = React128.useMemo(() => {
52760
52892
  if (!parsedSchema) return [];
52761
52893
  try {
@@ -52817,6 +52949,7 @@ function OrbPreview({
52817
52949
  {
52818
52950
  schema: parsedSchema,
52819
52951
  serverUrl,
52952
+ transport,
52820
52953
  mockData: effectiveMockData,
52821
52954
  pageName: currentPage,
52822
52955
  onNavigate: handleNavigate,