@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.
package/dist/avl/index.js CHANGED
@@ -4446,6 +4446,16 @@ function useUISlotManager() {
4446
4446
  },
4447
4447
  []
4448
4448
  );
4449
+ const updateTraitContent = useCallback(
4450
+ (traitName, content) => {
4451
+ const id = generateId();
4452
+ const fullContent = { ...content, id, sourceTrait: traitName };
4453
+ indexTraitRender(traitName, fullContent);
4454
+ notifyTraitSubscribers(traitName, fullContent);
4455
+ return id;
4456
+ },
4457
+ [indexTraitRender, notifyTraitSubscribers]
4458
+ );
4449
4459
  return {
4450
4460
  slots,
4451
4461
  render,
@@ -4457,7 +4467,8 @@ function useUISlotManager() {
4457
4467
  hasContent,
4458
4468
  getContent,
4459
4469
  getTraitContent,
4460
- subscribeTrait
4470
+ subscribeTrait,
4471
+ updateTraitContent
4461
4472
  };
4462
4473
  }
4463
4474
  var DEFAULT_SOURCE_KEY, MULTI_SOURCE_STACK_TRAIT, ALL_SLOTS, DEFAULT_SLOTS, DEFAULT_SOURCES, idCounter;
@@ -51496,6 +51507,76 @@ function useResolvedSchema(schema, pageName) {
51496
51507
  return result;
51497
51508
  }
51498
51509
 
51510
+ // runtime/embedded-traits.ts
51511
+ var TRAIT_BINDING_PREFIX = "@trait.";
51512
+ function collectTraitRefsFromValue(value, into) {
51513
+ if (value === null || value === void 0) return;
51514
+ if (typeof value === "string") {
51515
+ if (value.startsWith(TRAIT_BINDING_PREFIX)) {
51516
+ const rest = value.slice(TRAIT_BINDING_PREFIX.length);
51517
+ const dot = rest.indexOf(".");
51518
+ const traitName = dot === -1 ? rest : rest.slice(0, dot);
51519
+ if (traitName.length > 0) into.add(traitName);
51520
+ }
51521
+ return;
51522
+ }
51523
+ if (Array.isArray(value)) {
51524
+ for (const item of value) collectTraitRefsFromValue(item, into);
51525
+ return;
51526
+ }
51527
+ if (typeof value === "object") {
51528
+ for (const v of Object.values(value)) {
51529
+ collectTraitRefsFromValue(v, into);
51530
+ }
51531
+ }
51532
+ }
51533
+ function collectTraitRefsFromEffects(effects, into) {
51534
+ if (!effects) return;
51535
+ for (const effect of effects) {
51536
+ if (!Array.isArray(effect)) continue;
51537
+ if (effect[0] === "render-ui" && effect.length >= 3) {
51538
+ collectTraitRefsFromValue(effect[2], into);
51539
+ continue;
51540
+ }
51541
+ for (let i = 1; i < effect.length; i++) {
51542
+ const arg = effect[i];
51543
+ if (Array.isArray(arg)) collectTraitRefsFromEffects([arg], into);
51544
+ else collectTraitRefsFromValue(arg, into);
51545
+ }
51546
+ }
51547
+ }
51548
+ function collectEmbeddedTraits(schema) {
51549
+ const out = /* @__PURE__ */ new Set();
51550
+ if (!schema?.orbitals) return out;
51551
+ for (const orbital of schema.orbitals) {
51552
+ if (!orbital || typeof orbital !== "object") continue;
51553
+ const traits2 = orbital.traits;
51554
+ if (!Array.isArray(traits2)) continue;
51555
+ for (const trait of traits2) {
51556
+ if (!trait || typeof trait !== "object") continue;
51557
+ const resolved = trait._resolved;
51558
+ const target = resolved && typeof resolved === "object" ? resolved : trait;
51559
+ const stateMachine = target.stateMachine;
51560
+ const transitions = stateMachine?.transitions;
51561
+ if (!Array.isArray(transitions)) continue;
51562
+ for (const t of transitions) {
51563
+ if (!t || typeof t !== "object") continue;
51564
+ const effects = t.effects;
51565
+ collectTraitRefsFromEffects(effects, out);
51566
+ }
51567
+ const initialEffects = target.initialEffects;
51568
+ collectTraitRefsFromEffects(initialEffects, out);
51569
+ const ticks2 = target.ticks;
51570
+ if (Array.isArray(ticks2)) {
51571
+ for (const tick of ticks2) {
51572
+ collectTraitRefsFromEffects(tick?.effects, out);
51573
+ }
51574
+ }
51575
+ }
51576
+ }
51577
+ return out;
51578
+ }
51579
+
51499
51580
  // hooks/index.ts
51500
51581
  init_useEventBus();
51501
51582
  init_useUISlots();
@@ -52154,6 +52235,38 @@ init_EntitySchemaContext();
52154
52235
  init_useEventBus();
52155
52236
  init_logger();
52156
52237
  var xOrbitalLog2 = createLogger("almadar:runtime:cross-orbital");
52238
+ function createHttpTransport(serverUrl) {
52239
+ return {
52240
+ register: async (schema) => {
52241
+ try {
52242
+ const res = await fetch(`${serverUrl}/register`, {
52243
+ method: "POST",
52244
+ headers: { "Content-Type": "application/json" },
52245
+ body: JSON.stringify({ schema })
52246
+ });
52247
+ const result = await res.json();
52248
+ return !!result.success;
52249
+ } catch (err) {
52250
+ console.error("[ServerBridge] Registration failed:", err);
52251
+ return false;
52252
+ }
52253
+ },
52254
+ unregister: async () => {
52255
+ try {
52256
+ await fetch(`${serverUrl}/unregister`, { method: "DELETE" });
52257
+ } catch {
52258
+ }
52259
+ },
52260
+ sendEvent: async (orbitalName, event, payload) => {
52261
+ const res = await fetch(`${serverUrl}/${orbitalName}/events`, {
52262
+ method: "POST",
52263
+ headers: { "Content-Type": "application/json" },
52264
+ body: JSON.stringify({ event, payload })
52265
+ });
52266
+ return res.json();
52267
+ }
52268
+ };
52269
+ }
52157
52270
  var ServerBridgeContext = createContext(null);
52158
52271
  function useServerBridge() {
52159
52272
  const ctx = useContext(ServerBridgeContext);
@@ -52166,40 +52279,34 @@ function useServerBridge() {
52166
52279
  function ServerBridgeProvider({
52167
52280
  schema,
52168
52281
  serverUrl,
52282
+ transport: customTransport,
52169
52283
  children
52170
52284
  }) {
52285
+ if (!serverUrl && !customTransport) {
52286
+ throw new Error("ServerBridgeProvider requires either serverUrl or transport");
52287
+ }
52288
+ if (serverUrl && customTransport) {
52289
+ throw new Error("ServerBridgeProvider accepts serverUrl OR transport, not both");
52290
+ }
52171
52291
  const eventBus = useEventBus();
52172
52292
  const [connected, setConnected] = useState(false);
52173
- const registerSchema = useCallback(async () => {
52174
- try {
52175
- const res = await fetch(`${serverUrl}/register`, {
52176
- method: "POST",
52177
- headers: { "Content-Type": "application/json" },
52178
- body: JSON.stringify({ schema })
52179
- });
52180
- const result = await res.json();
52181
- return !!result.success;
52182
- } catch (err) {
52183
- console.error("[ServerBridge] Registration failed:", err);
52184
- return false;
52185
- }
52186
- }, [schema, serverUrl]);
52187
- const unregisterSchema = useCallback(async () => {
52188
- try {
52189
- await fetch(`${serverUrl}/unregister`, { method: "DELETE" });
52190
- } catch {
52191
- }
52192
- }, [serverUrl]);
52293
+ const transport = useMemo(
52294
+ () => customTransport ?? createHttpTransport(serverUrl),
52295
+ [serverUrl, customTransport]
52296
+ );
52297
+ const registerSchema = useCallback(
52298
+ async () => transport.register(schema),
52299
+ [schema, transport]
52300
+ );
52301
+ const unregisterSchema = useCallback(
52302
+ async () => transport.unregister(),
52303
+ [transport]
52304
+ );
52193
52305
  const sendEvent = useCallback(async (orbitalName, event, payload) => {
52194
52306
  const emptyMeta = { success: false, clientEffects: 0, dataEntities: {}, emittedEvents: [] };
52195
52307
  if (!connected) return { effects: [], meta: emptyMeta };
52196
52308
  try {
52197
- const res = await fetch(`${serverUrl}/${orbitalName}/events`, {
52198
- method: "POST",
52199
- headers: { "Content-Type": "application/json" },
52200
- body: JSON.stringify({ event, payload })
52201
- });
52202
- const result = await res.json();
52309
+ const result = await transport.sendEvent(orbitalName, event, payload);
52203
52310
  const effects = [];
52204
52311
  const responseData = result.data || {};
52205
52312
  const dataEntities = {};
@@ -52257,7 +52364,7 @@ function ServerBridgeProvider({
52257
52364
  console.error("[ServerBridge] Event send failed:", err);
52258
52365
  return { effects: [], meta: { ...emptyMeta, error: err instanceof Error ? err.message : String(err) } };
52259
52366
  }
52260
- }, [connected, serverUrl, eventBus]);
52367
+ }, [connected, transport, eventBus]);
52261
52368
  useEffect(() => {
52262
52369
  if (!schema) return;
52263
52370
  let cancelled = false;
@@ -52444,32 +52551,49 @@ function SlotBridge() {
52444
52551
  }, [slots, render, clear]);
52445
52552
  return null;
52446
52553
  }
52447
- function applyServerEffects(effects, uiSlots, onNavigate) {
52554
+ function applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits) {
52448
52555
  for (const eff of effects) {
52449
52556
  if (eff.type === "render-ui" && eff.slot && eff.pattern) {
52450
52557
  const patternRecord = eff.pattern;
52451
52558
  const { type: patternType, children, ...inlineProps } = patternRecord;
52452
52559
  const normalizedChildren = Array.isArray(children) ? children.map((c) => normalizeChild(c)) : children;
52453
- xOrbitalLog3.info("slot-write", {
52454
- slot: eff.slot,
52455
- sourceTrait: eff.traitName ?? "server",
52456
- patternType: typeof patternType === "string" ? patternType : void 0
52457
- });
52458
- uiSlots.render({
52459
- target: eff.slot,
52460
- pattern: patternType,
52461
- props: {
52462
- ...inlineProps,
52463
- ...normalizedChildren !== void 0 ? { children: normalizedChildren } : {}
52464
- },
52465
- sourceTrait: eff.traitName ?? "server"
52466
- });
52560
+ const sourceTrait = eff.traitName ?? "server";
52561
+ const isEmbedded = embeddedTraits?.has(sourceTrait) ?? false;
52562
+ const props = {
52563
+ ...inlineProps,
52564
+ ...normalizedChildren !== void 0 ? { children: normalizedChildren } : {}
52565
+ };
52566
+ if (isEmbedded) {
52567
+ xOrbitalLog3.info("slot:embed-routed", {
52568
+ sourceTrait,
52569
+ slot: eff.slot,
52570
+ patternType: typeof patternType === "string" ? patternType : void 0
52571
+ });
52572
+ uiSlots.updateTraitContent(sourceTrait, {
52573
+ pattern: patternType,
52574
+ props,
52575
+ priority: 0,
52576
+ animation: "fade"
52577
+ });
52578
+ } else {
52579
+ xOrbitalLog3.info("slot-write", {
52580
+ slot: eff.slot,
52581
+ sourceTrait,
52582
+ patternType: typeof patternType === "string" ? patternType : void 0
52583
+ });
52584
+ uiSlots.render({
52585
+ target: eff.slot,
52586
+ pattern: patternType,
52587
+ props,
52588
+ sourceTrait
52589
+ });
52590
+ }
52467
52591
  } else if (eff.type === "navigate" && eff.route && onNavigate) {
52468
52592
  onNavigate(eff.route, eff.params);
52469
52593
  }
52470
52594
  }
52471
52595
  }
52472
- function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFallback, persistence, traitConfigsByName, orbitalsByTrait }) {
52596
+ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFallback, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits }) {
52473
52597
  const slotsActions = useSlotsActions();
52474
52598
  const bridge = useServerBridge();
52475
52599
  const uiSlots = useUISlots();
@@ -52485,9 +52609,9 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFa
52485
52609
  for (const name of targets) {
52486
52610
  const { effects, meta } = await bridge.sendEvent(name, event, payload);
52487
52611
  recordServerResponse(name, event, meta);
52488
- applyServerEffects(effects, uiSlots, onNavigate);
52612
+ applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits);
52489
52613
  }
52490
- }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate]);
52614
+ }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, embeddedTraits]);
52491
52615
  const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, traitConfigsByName, orbitalsByTrait } : { navigate: onNavigate, persistence, traitConfigsByName, orbitalsByTrait };
52492
52616
  const { sendEvent } = useTraitStateMachine(traits2, slotsActions, opts);
52493
52617
  const initSentRef = useRef(false);
@@ -52527,13 +52651,13 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFa
52527
52651
  effects: effectTraces,
52528
52652
  timestamp: Date.now()
52529
52653
  });
52530
- applyServerEffects(effects, uiSlots, onNavigate);
52654
+ applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits);
52531
52655
  }
52532
52656
  })();
52533
- }, [bridge.connected, orbitalNames, bridge.sendEvent, uiSlots, onNavigate]);
52657
+ }, [bridge.connected, orbitalNames, bridge.sendEvent, uiSlots, onNavigate, embeddedTraits]);
52534
52658
  return null;
52535
52659
  }
52536
- function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate, onLocalFallback, persistence }) {
52660
+ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavigate, onLocalFallback, persistence }) {
52537
52661
  const { traits: traits2, allEntities, ir } = useResolvedSchema(schema, pageName);
52538
52662
  const allPageTraits = useMemo(() => {
52539
52663
  if (pageName && traits2.length > 0) return traits2;
@@ -52636,6 +52760,9 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate, onLoc
52636
52760
  }
52637
52761
  return map;
52638
52762
  }, [schema]);
52763
+ const embeddedTraits = useMemo(() => {
52764
+ return collectEmbeddedTraits(schema);
52765
+ }, [schema]);
52639
52766
  const inner = /* @__PURE__ */ jsx(VerificationProvider, { enabled: true, children: /* @__PURE__ */ jsx(SlotsProvider, { children: /* @__PURE__ */ jsxs(
52640
52767
  EntitySchemaProvider,
52641
52768
  {
@@ -52647,9 +52774,10 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate, onLoc
52647
52774
  TraitInitializer,
52648
52775
  {
52649
52776
  traits: allPageTraits,
52650
- orbitalNames: serverUrl ? pageOrbitalNames : void 0,
52777
+ orbitalNames: serverUrl || transport ? pageOrbitalNames : void 0,
52651
52778
  traitConfigsByName,
52652
52779
  orbitalsByTrait,
52780
+ embeddedTraits,
52653
52781
  onNavigate,
52654
52782
  onLocalFallback,
52655
52783
  persistence
@@ -52660,8 +52788,8 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate, onLoc
52660
52788
  ]
52661
52789
  }
52662
52790
  ) }) });
52663
- if (serverUrl) {
52664
- return /* @__PURE__ */ jsx(ServerBridgeProvider, { schema, serverUrl, children: inner });
52791
+ if (serverUrl || transport) {
52792
+ return /* @__PURE__ */ jsx(ServerBridgeProvider, { schema, serverUrl, transport, children: inner });
52665
52793
  }
52666
52794
  return inner;
52667
52795
  }
@@ -52672,8 +52800,12 @@ function OrbPreview({
52672
52800
  height = "400px",
52673
52801
  className,
52674
52802
  serverUrl,
52803
+ transport,
52675
52804
  initialPagePath
52676
52805
  }) {
52806
+ if (serverUrl && transport) {
52807
+ throw new Error("OrbPreview accepts serverUrl OR transport, not both");
52808
+ }
52677
52809
  const [localFallback, setLocalFallback] = useState(false);
52678
52810
  const eventBus = useEventBus();
52679
52811
  const handleLocalFallback = useCallback(() => {
@@ -52695,21 +52827,21 @@ function OrbPreview({
52695
52827
  } else {
52696
52828
  parsed = schema;
52697
52829
  }
52698
- if (autoMock && !serverUrl) {
52830
+ if (autoMock && !serverUrl && !transport) {
52699
52831
  const prepared = prepareSchemaForPreview(parsed);
52700
52832
  return { ok: true, schema: prepared.schema, mockData: prepared.mockData };
52701
52833
  }
52702
52834
  return { ok: true, schema: parsed, mockData: mockData ?? {} };
52703
- }, [schema, autoMock, serverUrl, mockData]);
52835
+ }, [schema, autoMock, serverUrl, transport, mockData]);
52704
52836
  const parsedSchema = parseResult.ok ? parseResult.schema : null;
52705
52837
  const effectiveMockData = parseResult.ok ? parseResult.mockData : {};
52706
52838
  const persistence = useMemo(() => {
52707
- if (!parsedSchema || serverUrl) return void 0;
52839
+ if (!parsedSchema || serverUrl || transport) return void 0;
52708
52840
  if (!autoMock) return void 0;
52709
52841
  const adapter = new InMemoryPersistence();
52710
52842
  adapter.seed(effectiveMockData);
52711
52843
  return adapter;
52712
- }, [parsedSchema, serverUrl, autoMock, effectiveMockData]);
52844
+ }, [parsedSchema, serverUrl, transport, autoMock, effectiveMockData]);
52713
52845
  const pages = useMemo(() => {
52714
52846
  if (!parsedSchema) return [];
52715
52847
  try {
@@ -52771,6 +52903,7 @@ function OrbPreview({
52771
52903
  {
52772
52904
  schema: parsedSchema,
52773
52905
  serverUrl,
52906
+ transport,
52774
52907
  mockData: effectiveMockData,
52775
52908
  pageName: currentPage,
52776
52909
  onNavigate: handleNavigate,
@@ -41153,6 +41153,16 @@ function useUISlotManager() {
41153
41153
  },
41154
41154
  []
41155
41155
  );
41156
+ const updateTraitContent = React111.useCallback(
41157
+ (traitName, content) => {
41158
+ const id = generateId();
41159
+ const fullContent = { ...content, id, sourceTrait: traitName };
41160
+ indexTraitRender(traitName, fullContent);
41161
+ notifyTraitSubscribers(traitName, fullContent);
41162
+ return id;
41163
+ },
41164
+ [indexTraitRender, notifyTraitSubscribers]
41165
+ );
41156
41166
  return {
41157
41167
  slots,
41158
41168
  render,
@@ -41164,7 +41174,8 @@ function useUISlotManager() {
41164
41174
  hasContent,
41165
41175
  getContent,
41166
41176
  getTraitContent,
41167
- subscribeTrait
41177
+ subscribeTrait,
41178
+ updateTraitContent
41168
41179
  };
41169
41180
  }
41170
41181
 
@@ -41108,6 +41108,16 @@ function useUISlotManager() {
41108
41108
  },
41109
41109
  []
41110
41110
  );
41111
+ const updateTraitContent = useCallback(
41112
+ (traitName, content) => {
41113
+ const id = generateId();
41114
+ const fullContent = { ...content, id, sourceTrait: traitName };
41115
+ indexTraitRender(traitName, fullContent);
41116
+ notifyTraitSubscribers(traitName, fullContent);
41117
+ return id;
41118
+ },
41119
+ [indexTraitRender, notifyTraitSubscribers]
41120
+ );
41111
41121
  return {
41112
41122
  slots,
41113
41123
  render,
@@ -41119,7 +41129,8 @@ function useUISlotManager() {
41119
41129
  hasContent,
41120
41130
  getContent,
41121
41131
  getTraitContent,
41122
- subscribeTrait
41132
+ subscribeTrait,
41133
+ updateTraitContent
41123
41134
  };
41124
41135
  }
41125
41136
 
@@ -305,6 +305,16 @@ function useUISlotManager() {
305
305
  },
306
306
  []
307
307
  );
308
+ const updateTraitContent = react.useCallback(
309
+ (traitName, content) => {
310
+ const id = generateId();
311
+ const fullContent = { ...content, id, sourceTrait: traitName };
312
+ indexTraitRender(traitName, fullContent);
313
+ notifyTraitSubscribers(traitName, fullContent);
314
+ return id;
315
+ },
316
+ [indexTraitRender, notifyTraitSubscribers]
317
+ );
308
318
  return {
309
319
  slots,
310
320
  render,
@@ -316,7 +326,8 @@ function useUISlotManager() {
316
326
  hasContent,
317
327
  getContent,
318
328
  getTraitContent,
319
- subscribeTrait
329
+ subscribeTrait,
330
+ updateTraitContent
320
331
  };
321
332
  }
322
333
  var UISlotContext = react.createContext(null);
@@ -303,6 +303,16 @@ function useUISlotManager() {
303
303
  },
304
304
  []
305
305
  );
306
+ const updateTraitContent = useCallback(
307
+ (traitName, content) => {
308
+ const id = generateId();
309
+ const fullContent = { ...content, id, sourceTrait: traitName };
310
+ indexTraitRender(traitName, fullContent);
311
+ notifyTraitSubscribers(traitName, fullContent);
312
+ return id;
313
+ },
314
+ [indexTraitRender, notifyTraitSubscribers]
315
+ );
306
316
  return {
307
317
  slots,
308
318
  render,
@@ -314,7 +324,8 @@ function useUISlotManager() {
314
324
  hasContent,
315
325
  getContent,
316
326
  getTraitContent,
317
- subscribeTrait
327
+ subscribeTrait,
328
+ updateTraitContent
318
329
  };
319
330
  }
320
331
  var UISlotContext = createContext(null);
@@ -1348,6 +1348,16 @@ function useUISlotManager() {
1348
1348
  },
1349
1349
  []
1350
1350
  );
1351
+ const updateTraitContent = react.useCallback(
1352
+ (traitName, content) => {
1353
+ const id = generateId();
1354
+ const fullContent = { ...content, id, sourceTrait: traitName };
1355
+ indexTraitRender(traitName, fullContent);
1356
+ notifyTraitSubscribers(traitName, fullContent);
1357
+ return id;
1358
+ },
1359
+ [indexTraitRender, notifyTraitSubscribers]
1360
+ );
1351
1361
  return {
1352
1362
  slots,
1353
1363
  render,
@@ -1359,7 +1369,8 @@ function useUISlotManager() {
1359
1369
  hasContent,
1360
1370
  getContent,
1361
1371
  getTraitContent,
1362
- subscribeTrait
1372
+ subscribeTrait,
1373
+ updateTraitContent
1363
1374
  };
1364
1375
  }
1365
1376
  var UI_PREFIX = "UI:";
@@ -1346,6 +1346,16 @@ function useUISlotManager() {
1346
1346
  },
1347
1347
  []
1348
1348
  );
1349
+ const updateTraitContent = useCallback(
1350
+ (traitName, content) => {
1351
+ const id = generateId();
1352
+ const fullContent = { ...content, id, sourceTrait: traitName };
1353
+ indexTraitRender(traitName, fullContent);
1354
+ notifyTraitSubscribers(traitName, fullContent);
1355
+ return id;
1356
+ },
1357
+ [indexTraitRender, notifyTraitSubscribers]
1358
+ );
1349
1359
  return {
1350
1360
  slots,
1351
1361
  render,
@@ -1357,7 +1367,8 @@ function useUISlotManager() {
1357
1367
  hasContent,
1358
1368
  getContent,
1359
1369
  getTraitContent,
1360
- subscribeTrait
1370
+ subscribeTrait,
1371
+ updateTraitContent
1361
1372
  };
1362
1373
  }
1363
1374
  var UI_PREFIX = "UI:";
@@ -119,6 +119,20 @@ export interface UISlotManager {
119
119
  * the trait they embed actually changes — not on every slot update.
120
120
  */
121
121
  subscribeTrait: (traitName: string, callback: TraitChangeCallback) => () => void;
122
+ /**
123
+ * Update only the per-trait sidecar without writing to any slot.
124
+ *
125
+ * Used for embed-aware slot routing: when a trait is referenced via
126
+ * `@trait.X` by a sibling layout's render-ui, its render output should
127
+ * not stack into the same slot the layout writes — the layout owns the
128
+ * slot and embeds the trait's frame via `<TraitFrame>`. This method
129
+ * keeps the per-trait sidecar (`traitIndexRef`) up-to-date so
130
+ * `<TraitFrame>` re-renders, while leaving `slots[target]` untouched.
131
+ *
132
+ * Mirrors what the compiled-path codegen does structurally — atoms
133
+ * inlined as JSX inside the layout's pattern, not writing slots.
134
+ */
135
+ updateTraitContent: (traitName: string, content: Omit<SlotContent, 'id' | 'sourceTrait'>) => string;
122
136
  }
123
137
  declare const DEFAULT_SLOTS: Record<UISlot, SlotContent | null>;
124
138
  /**
@@ -0,0 +1,34 @@
1
+ /**
2
+ * BrowserPlayground — in-browser Almadar runtime mount.
3
+ *
4
+ * Runs `OrbitalServerRuntime` (mock mode) in-process and threads it through
5
+ * `<OrbPreview>` via the `ServerBridgeTransport` adapter. Equivalent to
6
+ * canonical playground-runtime's server-mode mount, but without Express,
7
+ * fork, or HTTP — invokes `runtime.processOrbitalEvent` directly.
8
+ *
9
+ * Same React tree as `runtime-verify` (and apps/builder server-mode) speak,
10
+ * so any `@almadar/runtime` fix flows in through one bump cycle.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <BrowserPlayground schema={schema} mode="mock" height="100%" />
15
+ * ```
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ import React from 'react';
20
+ import type { OrbitalSchema } from '@almadar/core';
21
+ export interface BrowserPlaygroundProps {
22
+ /** OrbitalSchema to render. */
23
+ schema: OrbitalSchema;
24
+ /** Persistence mode for the in-process runtime. Default: 'mock' (Faker-seeded MockPersistenceAdapter). */
25
+ mode?: 'mock';
26
+ /** Initial page path to render (forwarded to OrbPreview). */
27
+ initialPagePath?: string;
28
+ /** Preview container height. Default: '400px'. */
29
+ height?: string;
30
+ /** CSS class for the outer container. */
31
+ className?: string;
32
+ }
33
+ export declare function BrowserPlayground({ schema, mode, initialPagePath, height, className, }: BrowserPlaygroundProps): React.ReactElement;
34
+ export default BrowserPlayground;
@@ -13,6 +13,7 @@
13
13
  */
14
14
  import React from 'react';
15
15
  import type { OrbitalSchema, EntityData } from '@almadar/core';
16
+ import { type ServerBridgeTransport } from './ServerBridge';
16
17
  export interface OrbPreviewProps {
17
18
  /**
18
19
  * The orbital schema. Accepts a JSON string or an `OrbitalSchema` object
@@ -42,6 +43,12 @@ export interface OrbPreviewProps {
42
43
  className?: string;
43
44
  /** Server URL for dual execution (e.g. "/api/orbitals"). When set, events are forwarded to the server. */
44
45
  serverUrl?: string;
46
+ /**
47
+ * Custom transport for in-process execution. Mutually exclusive with
48
+ * `serverUrl`. Used by `<BrowserPlayground>` to invoke
49
+ * `OrbitalServerRuntime.processOrbitalEvent` directly without HTTP.
50
+ */
51
+ transport?: ServerBridgeTransport;
45
52
  /**
46
53
  * Initial page path to render (e.g. `/deals`). Resolves against the
47
54
  * schema's `pages[]` to seed `currentPage` so the right orbital's traits
@@ -64,7 +71,7 @@ export interface OrbPreviewProps {
64
71
  * <OrbPreview schema={schema} serverUrl="/api/orbitals" />
65
72
  * ```
66
73
  */
67
- export declare function OrbPreview({ schema, mockData, autoMock, height, className, serverUrl, initialPagePath, }: OrbPreviewProps): React.ReactElement;
74
+ export declare function OrbPreview({ schema, mockData, autoMock, height, className, serverUrl, transport, initialPagePath, }: OrbPreviewProps): React.ReactElement;
68
75
  export declare namespace OrbPreview {
69
76
  var displayName: string;
70
77
  }