@almadar/ui 6.18.0 → 6.20.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.
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
  import React__default, { ReactNode } from 'react';
3
3
  import { ResolvedEntity, EventPayload, EntityRow, OrbitalSchema, BusEventSource, SExpr, ResolvedTrait, ResolvedTraitBinding, TraitConfig } from '@almadar/core';
4
4
  import { AnyPatternConfig } from '@almadar/core/patterns';
5
- import { ServerEffectResult } from '@almadar/runtime';
5
+ import { ServerEffectResult, TransitionResult } from '@almadar/runtime';
6
6
 
7
7
  /**
8
8
  * EntitySchemaContext
@@ -162,7 +162,14 @@ interface SendEventResult {
162
162
  }
163
163
  interface ServerBridgeContextValue {
164
164
  connected: boolean;
165
- sendEvent: (orbitalName: string, event: string, payload?: EventPayload, tick?: string, sourceTrait?: string, locallyEmitted?: readonly string[]) => Promise<SendEventResult>;
165
+ sendEvent: (orbitalName: string, event: string, payload?: EventPayload, tick?: string, sourceTrait?: string, locallyEmitted?: readonly string[],
166
+ /** Part G: traits the client's own local dispatch already executed for this event. */
167
+ results?: ReadonlyArray<{
168
+ traitName: string;
169
+ result: TransitionResult;
170
+ }>,
171
+ /** Part G: the client's own current entity snapshot per trait. */
172
+ entityByTrait?: Readonly<Record<string, EntityRow>>) => Promise<SendEventResult>;
166
173
  }
167
174
  /**
168
175
  * Transport adapter for ServerBridgeProvider. Decouples the bridge's
@@ -190,7 +197,10 @@ interface ServerBridgeTransport {
190
197
  * tick-originated latest-state broadcast: the server coalesces these
191
198
  * newest-per-key and relays them to other tabs at snapshot rate.
192
199
  */
193
- sendEvent: (orbitalName: string, event: string, payload?: EventPayload, clientId?: string, tick?: string, sourceTrait?: string) => Promise<OrbitalEventResponse>;
200
+ sendEvent: (orbitalName: string, event: string, payload?: EventPayload, clientId?: string, tick?: string, sourceTrait?: string, results?: ReadonlyArray<{
201
+ traitName: string;
202
+ result: TransitionResult;
203
+ }>, entityByTrait?: Readonly<Record<string, EntityRow>>) => Promise<OrbitalEventResponse>;
194
204
  }
195
205
  /**
196
206
  * Supplies the bearer token the hosting server authenticates with. Resolved
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
  import React__default, { ReactNode } from 'react';
3
3
  import { ResolvedEntity, EventPayload, EntityRow, OrbitalSchema, BusEventSource, SExpr, ResolvedTrait, ResolvedTraitBinding, TraitConfig } from '@almadar/core';
4
4
  import { AnyPatternConfig } from '@almadar/core/patterns';
5
- import { ServerEffectResult } from '@almadar/runtime';
5
+ import { ServerEffectResult, TransitionResult } from '@almadar/runtime';
6
6
 
7
7
  /**
8
8
  * EntitySchemaContext
@@ -162,7 +162,14 @@ interface SendEventResult {
162
162
  }
163
163
  interface ServerBridgeContextValue {
164
164
  connected: boolean;
165
- sendEvent: (orbitalName: string, event: string, payload?: EventPayload, tick?: string, sourceTrait?: string, locallyEmitted?: readonly string[]) => Promise<SendEventResult>;
165
+ sendEvent: (orbitalName: string, event: string, payload?: EventPayload, tick?: string, sourceTrait?: string, locallyEmitted?: readonly string[],
166
+ /** Part G: traits the client's own local dispatch already executed for this event. */
167
+ results?: ReadonlyArray<{
168
+ traitName: string;
169
+ result: TransitionResult;
170
+ }>,
171
+ /** Part G: the client's own current entity snapshot per trait. */
172
+ entityByTrait?: Readonly<Record<string, EntityRow>>) => Promise<SendEventResult>;
166
173
  }
167
174
  /**
168
175
  * Transport adapter for ServerBridgeProvider. Decouples the bridge's
@@ -190,7 +197,10 @@ interface ServerBridgeTransport {
190
197
  * tick-originated latest-state broadcast: the server coalesces these
191
198
  * newest-per-key and relays them to other tabs at snapshot rate.
192
199
  */
193
- sendEvent: (orbitalName: string, event: string, payload?: EventPayload, clientId?: string, tick?: string, sourceTrait?: string) => Promise<OrbitalEventResponse>;
200
+ sendEvent: (orbitalName: string, event: string, payload?: EventPayload, clientId?: string, tick?: string, sourceTrait?: string, results?: ReadonlyArray<{
201
+ traitName: string;
202
+ result: TransitionResult;
203
+ }>, entityByTrait?: Readonly<Record<string, EntityRow>>) => Promise<OrbitalEventResponse>;
194
204
  }
195
205
  /**
196
206
  * Supplies the bearer token the hosting server authenticates with. Resolved
@@ -60208,7 +60208,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
60208
60208
  }
60209
60209
  const relayPayload = targetTrait !== void 0 ? { ...payload ?? {}, _targetTrait: targetTrait } : payload;
60210
60210
  const locallyEmitted = Array.from(emittedByTrait.values()).flat();
60211
- void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted);
60211
+ void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted, results, entityByTrait);
60212
60212
  }
60213
60213
  ui.perfEnd("processEvent:total", _perfT0);
60214
60214
  ui.perfEnd(`event:${normalizedEvent}`, _perfT0);
@@ -60543,7 +60543,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60543
60543
  [serverActiveTraits]
60544
60544
  );
60545
60545
  const uiSlots = context.useUISlots();
60546
- const onEventProcessed = React96.useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted) => {
60546
+ const onEventProcessed = React96.useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted, results, entityByTrait) => {
60547
60547
  if (!bridge.connected || !orbitalNames?.length) return;
60548
60548
  const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
60549
60549
  xOrbitalLog.debug("TraitInitializer:fanout", () => ({
@@ -60557,7 +60557,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60557
60557
  void bridge.sendEvent(name, event, withActiveTraits(payload), tick, sourceTrait);
60558
60558
  continue;
60559
60559
  }
60560
- void bridge.sendEvent(name, event, withActiveTraits(payload), void 0, void 0, locallyEmitted).then(({ effects, meta }) => {
60560
+ void bridge.sendEvent(name, event, withActiveTraits(payload), void 0, void 0, locallyEmitted, results, entityByTrait).then(({ effects, meta }) => {
60561
60561
  recordServerResponse(name, event, { ...meta, effectResults: effectResultsToTraces(meta.effectResults) });
60562
60562
  applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
60563
60563
  });
package/dist/avl/index.js CHANGED
@@ -60132,7 +60132,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
60132
60132
  }
60133
60133
  const relayPayload = targetTrait !== void 0 ? { ...payload ?? {}, _targetTrait: targetTrait } : payload;
60134
60134
  const locallyEmitted = Array.from(emittedByTrait.values()).flat();
60135
- void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted);
60135
+ void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted, results, entityByTrait);
60136
60136
  }
60137
60137
  perfEnd("processEvent:total", _perfT0);
60138
60138
  perfEnd(`event:${normalizedEvent}`, _perfT0);
@@ -60467,7 +60467,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60467
60467
  [serverActiveTraits]
60468
60468
  );
60469
60469
  const uiSlots = useUISlots();
60470
- const onEventProcessed = useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted) => {
60470
+ const onEventProcessed = useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted, results, entityByTrait) => {
60471
60471
  if (!bridge.connected || !orbitalNames?.length) return;
60472
60472
  const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
60473
60473
  xOrbitalLog.debug("TraitInitializer:fanout", () => ({
@@ -60481,7 +60481,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60481
60481
  void bridge.sendEvent(name, event, withActiveTraits(payload), tick, sourceTrait);
60482
60482
  continue;
60483
60483
  }
60484
- void bridge.sendEvent(name, event, withActiveTraits(payload), void 0, void 0, locallyEmitted).then(({ effects, meta }) => {
60484
+ void bridge.sendEvent(name, event, withActiveTraits(payload), void 0, void 0, locallyEmitted, results, entityByTrait).then(({ effects, meta }) => {
60485
60485
  recordServerResponse(name, event, { ...meta, effectResults: effectResultsToTraces(meta.effectResults) });
60486
60486
  applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
60487
60487
  });
@@ -54627,8 +54627,28 @@ function createHttpTransport(serverUrl, getAccessToken) {
54627
54627
  } catch {
54628
54628
  }
54629
54629
  },
54630
- sendEvent: async (orbitalName, event, payload, clientId, tick, sourceTrait) => {
54631
- const body = { event, payload, clientId, tick, sourceTrait };
54630
+ sendEvent: async (orbitalName, event, payload, clientId, tick, sourceTrait, results, entityByTrait) => {
54631
+ const traits2 = results?.map((r) => ({ trait: r.traitName, from: r.result.previousState }));
54632
+ const body = {
54633
+ event,
54634
+ payload,
54635
+ clientId,
54636
+ tick,
54637
+ sourceTrait,
54638
+ // `results === undefined` (as opposed to an explicit, possibly-empty
54639
+ // array) distinguishes two genuinely different cases a stateless
54640
+ // server must tell apart: the mount-time INIT dispatch (OrbPreview's
54641
+ // "Server INIT when bridge connects" effect) calls this WITHOUT ever
54642
+ // running a local dispatch first — by design, the server is
54643
+ // authoritative for that one case — so there is no local `traits`
54644
+ // list to send at all; a command-class dispatch (via
54645
+ // `onEventProcessed`) always supplies `results`, even as `[]` when
54646
+ // local dispatch genuinely matched nothing. Collapsing both to "omit
54647
+ // `traits`" would make the mount-time case indistinguishable from
54648
+ // "do nothing" and break every organism's INIT on the stateless path.
54649
+ ...results !== void 0 ? { traits: traits2 ?? [] } : {},
54650
+ ...entityByTrait ? { entityByTrait } : {}
54651
+ };
54632
54652
  const res = await fetch(`${serverUrl}/${orbitalName}/events`, {
54633
54653
  method: "POST",
54634
54654
  headers: await authHeaders(getAccessToken),
@@ -54689,7 +54709,7 @@ function ServerBridgeProvider({
54689
54709
  disposedRef.current = true;
54690
54710
  };
54691
54711
  }, []);
54692
- const sendEvent = React89.useCallback(async (orbitalName, event, payload, tick, sourceTrait, locallyEmitted) => {
54712
+ const sendEvent = React89.useCallback(async (orbitalName, event, payload, tick, sourceTrait, locallyEmitted, results, entityByTrait) => {
54693
54713
  const emptyMeta = { success: false, transitioned: false, clientEffects: 0, dataEntities: {}, emittedEvents: [] };
54694
54714
  if (!connected) return { effects: [], meta: emptyMeta };
54695
54715
  if (tick !== void 0) {
@@ -54699,7 +54719,7 @@ function ServerBridgeProvider({
54699
54719
  return commandPump.enqueue(async () => {
54700
54720
  if (disposedRef.current) return { effects: [], meta: emptyMeta };
54701
54721
  try {
54702
- const result = await transport.sendEvent(orbitalName, event, payload, getTabClientId(), tick, sourceTrait);
54722
+ const result = await transport.sendEvent(orbitalName, event, payload, getTabClientId(), tick, sourceTrait, results, entityByTrait);
54703
54723
  const effects = [];
54704
54724
  const responseData = result.data || {};
54705
54725
  const dataEntities = {};
@@ -6,7 +6,7 @@ export { a as CurrentPagePathContext, b as CurrentPagePathProvider, c as Current
6
6
  import { b as UserData } from '../UserContext-D566nfWA.cjs';
7
7
  export { U as UserContext, a as UserContextValue, c as UserProvider, d as UserProviderProps, u as useHasPermission, e as useHasRole, f as useUser, g as useUserForEvaluation } from '../UserContext-D566nfWA.cjs';
8
8
  import { E as EventBusContextType } from '../event-bus-types-Bl78kokd.cjs';
9
- export { A as AccessTokenProvider, E as EntityBindingContext, a as EntityBindingSource, b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, S as SendEventResult, e as ServerBridgeContextValue, f as ServerBridgeProvider, g as ServerBridgeProviderProps, h as ServerBridgeTransport, i as ServerClientEffect, j as ServerResponseMeta, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, u as useEntityBindingSnapshot, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-Dglbi9ks.cjs';
9
+ export { A as AccessTokenProvider, E as EntityBindingContext, a as EntityBindingSource, b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, S as SendEventResult, e as ServerBridgeContextValue, f as ServerBridgeProvider, g as ServerBridgeProviderProps, h as ServerBridgeTransport, i as ServerClientEffect, j as ServerResponseMeta, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, u as useEntityBindingSnapshot, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-DoK8Xq71.cjs';
10
10
  import { i as UseOfflineExecutorResult, U as UseOfflineExecutorOptions } from '../offline-executor-DdV2o0Zu.cjs';
11
11
  export { N as NavigationContextValue, c as NavigationProvider, d as NavigationProviderProps, e as NavigationState, j as comparePathSpecificity, l as extractRouteParams, m as findPageByName, n as findPageByPath, o as getAllPages, p as getDefaultPage, q as matchPath, r as matchPathAmong, s as pathMatches, u as useActivePage, t as useInitPayload, v as useNavigateTo, w as useNavigation, x as useNavigationId, y as useNavigationState } from '../offline-executor-DdV2o0Zu.cjs';
12
12
  import '../verificationRegistry-DTrKDRoa.cjs';
@@ -6,7 +6,7 @@ export { a as CurrentPagePathContext, b as CurrentPagePathProvider, c as Current
6
6
  import { b as UserData } from '../UserContext-D566nfWA.js';
7
7
  export { U as UserContext, a as UserContextValue, c as UserProvider, d as UserProviderProps, u as useHasPermission, e as useHasRole, f as useUser, g as useUserForEvaluation } from '../UserContext-D566nfWA.js';
8
8
  import { E as EventBusContextType } from '../event-bus-types-Bl78kokd.js';
9
- export { A as AccessTokenProvider, E as EntityBindingContext, a as EntityBindingSource, b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, S as SendEventResult, e as ServerBridgeContextValue, f as ServerBridgeProvider, g as ServerBridgeProviderProps, h as ServerBridgeTransport, i as ServerClientEffect, j as ServerResponseMeta, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, u as useEntityBindingSnapshot, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-Dglbi9ks.js';
9
+ export { A as AccessTokenProvider, E as EntityBindingContext, a as EntityBindingSource, b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, S as SendEventResult, e as ServerBridgeContextValue, f as ServerBridgeProvider, g as ServerBridgeProviderProps, h as ServerBridgeTransport, i as ServerClientEffect, j as ServerResponseMeta, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, u as useEntityBindingSnapshot, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-DoK8Xq71.js';
10
10
  import { i as UseOfflineExecutorResult, U as UseOfflineExecutorOptions } from '../offline-executor-DdV2o0Zu.js';
11
11
  export { N as NavigationContextValue, c as NavigationProvider, d as NavigationProviderProps, e as NavigationState, j as comparePathSpecificity, l as extractRouteParams, m as findPageByName, n as findPageByPath, o as getAllPages, p as getDefaultPage, q as matchPath, r as matchPathAmong, s as pathMatches, u as useActivePage, t as useInitPayload, v as useNavigateTo, w as useNavigation, x as useNavigationId, y as useNavigationState } from '../offline-executor-DdV2o0Zu.js';
12
12
  import '../verificationRegistry-Cwa52VyK.js';
@@ -54553,8 +54553,28 @@ function createHttpTransport(serverUrl, getAccessToken) {
54553
54553
  } catch {
54554
54554
  }
54555
54555
  },
54556
- sendEvent: async (orbitalName, event, payload, clientId, tick, sourceTrait) => {
54557
- const body = { event, payload, clientId, tick, sourceTrait };
54556
+ sendEvent: async (orbitalName, event, payload, clientId, tick, sourceTrait, results, entityByTrait) => {
54557
+ const traits2 = results?.map((r) => ({ trait: r.traitName, from: r.result.previousState }));
54558
+ const body = {
54559
+ event,
54560
+ payload,
54561
+ clientId,
54562
+ tick,
54563
+ sourceTrait,
54564
+ // `results === undefined` (as opposed to an explicit, possibly-empty
54565
+ // array) distinguishes two genuinely different cases a stateless
54566
+ // server must tell apart: the mount-time INIT dispatch (OrbPreview's
54567
+ // "Server INIT when bridge connects" effect) calls this WITHOUT ever
54568
+ // running a local dispatch first — by design, the server is
54569
+ // authoritative for that one case — so there is no local `traits`
54570
+ // list to send at all; a command-class dispatch (via
54571
+ // `onEventProcessed`) always supplies `results`, even as `[]` when
54572
+ // local dispatch genuinely matched nothing. Collapsing both to "omit
54573
+ // `traits`" would make the mount-time case indistinguishable from
54574
+ // "do nothing" and break every organism's INIT on the stateless path.
54575
+ ...results !== void 0 ? { traits: traits2 ?? [] } : {},
54576
+ ...entityByTrait ? { entityByTrait } : {}
54577
+ };
54558
54578
  const res = await fetch(`${serverUrl}/${orbitalName}/events`, {
54559
54579
  method: "POST",
54560
54580
  headers: await authHeaders(getAccessToken),
@@ -54615,7 +54635,7 @@ function ServerBridgeProvider({
54615
54635
  disposedRef.current = true;
54616
54636
  };
54617
54637
  }, []);
54618
- const sendEvent = useCallback(async (orbitalName, event, payload, tick, sourceTrait, locallyEmitted) => {
54638
+ const sendEvent = useCallback(async (orbitalName, event, payload, tick, sourceTrait, locallyEmitted, results, entityByTrait) => {
54619
54639
  const emptyMeta = { success: false, transitioned: false, clientEffects: 0, dataEntities: {}, emittedEvents: [] };
54620
54640
  if (!connected) return { effects: [], meta: emptyMeta };
54621
54641
  if (tick !== void 0) {
@@ -54625,7 +54645,7 @@ function ServerBridgeProvider({
54625
54645
  return commandPump.enqueue(async () => {
54626
54646
  if (disposedRef.current) return { effects: [], meta: emptyMeta };
54627
54647
  try {
54628
- const result = await transport.sendEvent(orbitalName, event, payload, getTabClientId(), tick, sourceTrait);
54648
+ const result = await transport.sendEvent(orbitalName, event, payload, getTabClientId(), tick, sourceTrait, results, entityByTrait);
54629
54649
  const effects = [];
54630
54650
  const responseData = result.data || {};
54631
54651
  const dataEntities = {};
@@ -54332,7 +54332,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
54332
54332
  }
54333
54333
  const relayPayload = targetTrait !== void 0 ? { ...payload ?? {}, _targetTrait: targetTrait } : payload;
54334
54334
  const locallyEmitted = Array.from(emittedByTrait.values()).flat();
54335
- void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted);
54335
+ void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted, results, entityByTrait);
54336
54336
  }
54337
54337
  ui.perfEnd("processEvent:total", _perfT0);
54338
54338
  ui.perfEnd(`event:${normalizedEvent}`, _perfT0);
@@ -54770,7 +54770,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
54770
54770
  [serverActiveTraits]
54771
54771
  );
54772
54772
  const uiSlots = context.useUISlots();
54773
- const onEventProcessed = React87.useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted) => {
54773
+ const onEventProcessed = React87.useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted, results, entityByTrait) => {
54774
54774
  if (!bridge.connected || !orbitalNames?.length) return;
54775
54775
  const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
54776
54776
  xOrbitalLog.debug("TraitInitializer:fanout", () => ({
@@ -54784,7 +54784,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
54784
54784
  void bridge.sendEvent(name, event, withActiveTraits(payload), tick, sourceTrait);
54785
54785
  continue;
54786
54786
  }
54787
- void bridge.sendEvent(name, event, withActiveTraits(payload), void 0, void 0, locallyEmitted).then(({ effects, meta }) => {
54787
+ void bridge.sendEvent(name, event, withActiveTraits(payload), void 0, void 0, locallyEmitted, results, entityByTrait).then(({ effects, meta }) => {
54788
54788
  recordServerResponse(name, event, { ...meta, effectResults: effectResultsToTraces(meta.effectResults) });
54789
54789
  applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
54790
54790
  });
@@ -1,12 +1,12 @@
1
1
  import * as _almadar_core from '@almadar/core';
2
- import { EventPayload, ServiceParams, ResolvedTraitBinding, ResolvedPage, ResolvedEntity, ResolvedTrait, ResolvedIR, OrbitalSchema, PatternConfig, ResolvedPatternProps, EventSource, SExpr, BusEventSource, EntityRow, EntityData } from '@almadar/core';
2
+ import { EventPayload, EntityRow, ServiceParams, ResolvedTraitBinding, ResolvedPage, ResolvedEntity, ResolvedTrait, ResolvedIR, OrbitalSchema, PatternConfig, ResolvedPatternProps, EventSource, SExpr, BusEventSource, EntityData } from '@almadar/core';
3
3
  export { ResolvedEntity, ResolvedIR, ResolvedPage, ResolvedTrait, ResolvedTraitBinding } from '@almadar/core';
4
4
  import * as _almadar_runtime from '@almadar/runtime';
5
- import { TraitState, EffectHandlers } from '@almadar/runtime';
5
+ import { TraitState, TransitionResult, EffectHandlers } from '@almadar/runtime';
6
6
  import { K as KeyCaptureTable } from '../useKeyboardRouter-CVn8lfiX.cjs';
7
7
  import { c as useUISlots } from '../UISlotContext-BlRDbHDy.cjs';
8
- import { a as EntityBindingSource, h as ServerBridgeTransport, A as AccessTokenProvider } from '../EntityBindingContext-Dglbi9ks.cjs';
9
- export { b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, e as ServerBridgeContextValue, f as ServerBridgeProvider, i as ServerClientEffect, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-Dglbi9ks.cjs';
8
+ import { a as EntityBindingSource, h as ServerBridgeTransport, A as AccessTokenProvider } from '../EntityBindingContext-DoK8Xq71.cjs';
9
+ export { b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, e as ServerBridgeContextValue, f as ServerBridgeProvider, i as ServerClientEffect, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-DoK8Xq71.cjs';
10
10
  import '../verificationRegistry-DTrKDRoa.cjs';
11
11
  export { PERF_NAMESPACE, PerfEntry, PreparedPreviewSchema, adjustSchemaForMockData, buildMockData, clearPerf, perfEnd, perfStart, perfTime, prepareSchemaForPreview, wrapCallbackForEvent } from '@almadar/runtime/ui';
12
12
  import React__default, { ReactNode } from 'react';
@@ -54,7 +54,27 @@ interface UseTraitStateMachineOptions {
54
54
  */
55
55
  tick?: string, sourceTrait?: string,
56
56
  /** Every event name this dispatch's local effect execution emitted, one entry per emit (multiplicity matters — see `stampLocallyDeliveredEchoes`). */
57
- locallyEmitted?: readonly string[]) => void | Promise<void>;
57
+ locallyEmitted?: readonly string[],
58
+ /**
59
+ * Every trait whose LOCAL dispatch actually executed a transition
60
+ * for this event (Part G, stateless dual-execution) — always a
61
+ * subset of successfully-transitioned traits, never filtered
62
+ * further here. A stateless server consults this instead of
63
+ * rediscovering "which traits match this event" against its own
64
+ * shared state.
65
+ */
66
+ results?: ReadonlyArray<{
67
+ traitName: string;
68
+ result: TransitionResult;
69
+ }>,
70
+ /**
71
+ * The client's own current entity snapshot per trait (built the
72
+ * same way as the `entityByTrait` already passed to
73
+ * `currentManager.sendEvent` above) — the input a stateless server
74
+ * needs for `[runtime]`-persistence entities, which have nowhere
75
+ * else to live.
76
+ */
77
+ entityByTrait?: Readonly<Record<string, EntityRow>>) => void | Promise<void>;
58
78
  /** Router navigate function for navigate effects. `crumb` labels the
59
79
  * target page's navigation-stack entry (from the effect's options). */
60
80
  navigate?: (path: string, params?: Record<string, string>, crumb?: string) => void;
@@ -1,12 +1,12 @@
1
1
  import * as _almadar_core from '@almadar/core';
2
- import { EventPayload, ServiceParams, ResolvedTraitBinding, ResolvedPage, ResolvedEntity, ResolvedTrait, ResolvedIR, OrbitalSchema, PatternConfig, ResolvedPatternProps, EventSource, SExpr, BusEventSource, EntityRow, EntityData } from '@almadar/core';
2
+ import { EventPayload, EntityRow, ServiceParams, ResolvedTraitBinding, ResolvedPage, ResolvedEntity, ResolvedTrait, ResolvedIR, OrbitalSchema, PatternConfig, ResolvedPatternProps, EventSource, SExpr, BusEventSource, EntityData } from '@almadar/core';
3
3
  export { ResolvedEntity, ResolvedIR, ResolvedPage, ResolvedTrait, ResolvedTraitBinding } from '@almadar/core';
4
4
  import * as _almadar_runtime from '@almadar/runtime';
5
- import { TraitState, EffectHandlers } from '@almadar/runtime';
5
+ import { TraitState, TransitionResult, EffectHandlers } from '@almadar/runtime';
6
6
  import { K as KeyCaptureTable } from '../useKeyboardRouter-B1pIi9jo.js';
7
7
  import { c as useUISlots } from '../UISlotContext-CB89mv7N.js';
8
- import { a as EntityBindingSource, h as ServerBridgeTransport, A as AccessTokenProvider } from '../EntityBindingContext-Dglbi9ks.js';
9
- export { b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, e as ServerBridgeContextValue, f as ServerBridgeProvider, i as ServerClientEffect, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-Dglbi9ks.js';
8
+ import { a as EntityBindingSource, h as ServerBridgeTransport, A as AccessTokenProvider } from '../EntityBindingContext-DoK8Xq71.js';
9
+ export { b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, e as ServerBridgeContextValue, f as ServerBridgeProvider, i as ServerClientEffect, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-DoK8Xq71.js';
10
10
  import '../verificationRegistry-Cwa52VyK.js';
11
11
  export { PERF_NAMESPACE, PerfEntry, PreparedPreviewSchema, adjustSchemaForMockData, buildMockData, clearPerf, perfEnd, perfStart, perfTime, prepareSchemaForPreview, wrapCallbackForEvent } from '@almadar/runtime/ui';
12
12
  import React__default, { ReactNode } from 'react';
@@ -54,7 +54,27 @@ interface UseTraitStateMachineOptions {
54
54
  */
55
55
  tick?: string, sourceTrait?: string,
56
56
  /** Every event name this dispatch's local effect execution emitted, one entry per emit (multiplicity matters — see `stampLocallyDeliveredEchoes`). */
57
- locallyEmitted?: readonly string[]) => void | Promise<void>;
57
+ locallyEmitted?: readonly string[],
58
+ /**
59
+ * Every trait whose LOCAL dispatch actually executed a transition
60
+ * for this event (Part G, stateless dual-execution) — always a
61
+ * subset of successfully-transitioned traits, never filtered
62
+ * further here. A stateless server consults this instead of
63
+ * rediscovering "which traits match this event" against its own
64
+ * shared state.
65
+ */
66
+ results?: ReadonlyArray<{
67
+ traitName: string;
68
+ result: TransitionResult;
69
+ }>,
70
+ /**
71
+ * The client's own current entity snapshot per trait (built the
72
+ * same way as the `entityByTrait` already passed to
73
+ * `currentManager.sendEvent` above) — the input a stateless server
74
+ * needs for `[runtime]`-persistence entities, which have nowhere
75
+ * else to live.
76
+ */
77
+ entityByTrait?: Readonly<Record<string, EntityRow>>) => void | Promise<void>;
58
78
  /** Router navigate function for navigate effects. `crumb` labels the
59
79
  * target page's navigation-stack entry (from the effect's options). */
60
80
  navigate?: (path: string, params?: Record<string, string>, crumb?: string) => void;
@@ -54258,7 +54258,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
54258
54258
  }
54259
54259
  const relayPayload = targetTrait !== void 0 ? { ...payload ?? {}, _targetTrait: targetTrait } : payload;
54260
54260
  const locallyEmitted = Array.from(emittedByTrait.values()).flat();
54261
- void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted);
54261
+ void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted, results, entityByTrait);
54262
54262
  }
54263
54263
  perfEnd("processEvent:total", _perfT0);
54264
54264
  perfEnd(`event:${normalizedEvent}`, _perfT0);
@@ -54696,7 +54696,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
54696
54696
  [serverActiveTraits]
54697
54697
  );
54698
54698
  const uiSlots = useUISlots();
54699
- const onEventProcessed = useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted) => {
54699
+ const onEventProcessed = useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted, results, entityByTrait) => {
54700
54700
  if (!bridge.connected || !orbitalNames?.length) return;
54701
54701
  const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
54702
54702
  xOrbitalLog.debug("TraitInitializer:fanout", () => ({
@@ -54710,7 +54710,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
54710
54710
  void bridge.sendEvent(name, event, withActiveTraits(payload), tick, sourceTrait);
54711
54711
  continue;
54712
54712
  }
54713
- void bridge.sendEvent(name, event, withActiveTraits(payload), void 0, void 0, locallyEmitted).then(({ effects, meta }) => {
54713
+ void bridge.sendEvent(name, event, withActiveTraits(payload), void 0, void 0, locallyEmitted, results, entityByTrait).then(({ effects, meta }) => {
54714
54714
  recordServerResponse(name, event, { ...meta, effectResults: effectResultsToTraces(meta.effectResults) });
54715
54715
  applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
54716
54716
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "6.18.0",
3
+ "version": "6.20.0",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -121,8 +121,8 @@
121
121
  "@almadar/core": "^10.92.0",
122
122
  "@almadar/evaluator": "^2.45.0",
123
123
  "@almadar/logger": "^1.12.0",
124
- "@almadar/runtime": "^6.78.0",
125
- "@almadar/std": "^16.214.0",
124
+ "@almadar/runtime": "^6.79.0",
125
+ "@almadar/std": "^16.217.0",
126
126
  "@almadar/syntax": "^1.17.0",
127
127
  "@dnd-kit/core": "^6.3.1",
128
128
  "@dnd-kit/sortable": "^10.0.0",
package/themes/index.css CHANGED
@@ -83,6 +83,18 @@
83
83
  border-color: var(--color-border, #e5e7eb);
84
84
  }
85
85
 
86
+ /**
87
+ * currentColor anchor. A nested [data-theme] container re-scopes every
88
+ * var-based color utility, but the raw `color` property inherits straight
89
+ * through from the outer theme — `text-current` icons painted the outer
90
+ * theme's foreground on the inner theme's surface (white-on-white when a
91
+ * behavior pins a light theme inside a dark shell). Re-anchor `color` to
92
+ * the innermost theme's foreground so currentColor always matches.
93
+ */
94
+ [data-theme] {
95
+ color: var(--color-foreground, inherit);
96
+ }
97
+
86
98
  /**
87
99
  * Font inheritance for headings.
88
100
  *