@almadar/runtime 6.44.0 → 6.45.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.
@@ -1,5 +1,5 @@
1
1
  import { Router } from 'express';
2
- import { I as IEventBus, R as RuntimeEvent, a as EventListener, U as Unsubscribe, T as TraitDefinition, b as RuntimeConfig, c as TransitionObserver, d as TraitState, C as ConfigContext, e as TransitionResult, f as EvaluationContextExtensions, E as EffectHandlers } from './types-p_L8-Sk4.js';
2
+ import { I as IEventBus, R as RuntimeEvent, a as EventListener, U as Unsubscribe, T as TraitDefinition, b as RuntimeConfig, c as TransitionObserver, d as TraitState, C as ConfigContext, e as TransitionResult, f as EvaluationContextExtensions, E as EffectHandlers } from './types-CL03tjGU.js';
3
3
  import { EventPayload, EventId, EntityRow, UserContext, Orbital, ServiceCallResult, TraitConfig, DeclaredTraitConfig, Entity, OrbitalSchema, Trait, PatternConfig, ResolvedPatternProps, SExpr, BusEventSource, RawUserClaims, OrbitalDefinition, TraitTick } from '@almadar/core';
4
4
 
5
5
  /**
@@ -937,6 +937,13 @@ interface RegisteredOrbital {
937
937
  * `state.fields`. The trait's `@entity` binding is a three-layer merge:
938
938
  * declared entity field defaults < persistence entityData < this map.
939
939
  * Mutated only by the `set` effect handler.
940
+ *
941
+ * For a `[shared]` linked entity the map is keyed `$shared::<entityName>`
942
+ * instead of the trait name — ONE frame across every bound trait, the
943
+ * server half of the client hook's `sharedKeyByTraitName` groups. Without
944
+ * it a writer trait's `(set @entity.X …)` was invisible to a sibling's
945
+ * effect interpolation (the chat thread's refetch filter read "" while the
946
+ * composer held the open channel).
940
947
  */
941
948
  traitFieldStates: Map<string, EntityRow>;
942
949
  }
@@ -1341,6 +1348,19 @@ declare class OrbitalServerRuntime {
1341
1348
  setDefaultUser(user: UserContext | undefined): void;
1342
1349
  /** The viewer a dev host is currently presenting the app as. */
1343
1350
  getDefaultUser(): UserContext | undefined;
1351
+ /**
1352
+ * `traitFieldStates` key for one trait: its own name, or — when its linked
1353
+ * entity is `[shared]` — `$shared::<entityName>` so every trait bound to
1354
+ * that entity reads/writes ONE frame. The server twin of the client hook's
1355
+ * `sharedKeyByTraitName` (useTraitStateMachine): without it, a sibling
1356
+ * trait's effect interpolation (a fetch filter reading
1357
+ * `@entity.activeChannel`) never saw the writer's `(set …)`.
1358
+ */
1359
+ private sharedFieldKey;
1360
+ /** Resolve an entity name to its declared `shared` flag: the orbital's own
1361
+ * entity, its auxiliary entities, then other registered orbitals' primary
1362
+ * entities (cross-orbital binds like a membership rail in the chat page). */
1363
+ private isSharedEntity;
1344
1364
  /**
1345
1365
  * Process an event for an orbital
1346
1366
  *
@@ -1,4 +1,4 @@
1
1
  import 'express';
2
- export { F as ClientEffectTuple, G as ClientNavigateTuple, H as ClientNotifyTuple, J as ClientRenderUITuple, K as EffectResult, e as InMemoryPersistence, M as LiveBroadcastItem, N as LoaderConfig, O as OrbitalEventRequest, f as OrbitalEventResponse, Q as OrbitalServerRuntime, g as OrbitalServerRuntimeConfig, P as PersistenceAdapter, R as RegisteredOrbital, l as RuntimeOrbital, m as RuntimeOrbitalSchema, n as RuntimeTrait, T as RuntimeTraitTick, p as collectDeclaredConfigDefaults, V as createOrbitalServerRuntime } from './OrbitalServerRuntime-Dz0oubQ_.js';
3
- import './types-p_L8-Sk4.js';
2
+ export { F as ClientEffectTuple, G as ClientNavigateTuple, H as ClientNotifyTuple, J as ClientRenderUITuple, K as EffectResult, e as InMemoryPersistence, M as LiveBroadcastItem, N as LoaderConfig, O as OrbitalEventRequest, f as OrbitalEventResponse, Q as OrbitalServerRuntime, g as OrbitalServerRuntimeConfig, P as PersistenceAdapter, R as RegisteredOrbital, l as RuntimeOrbital, m as RuntimeOrbitalSchema, n as RuntimeTrait, T as RuntimeTraitTick, p as collectDeclaredConfigDefaults, V as createOrbitalServerRuntime } from './OrbitalServerRuntime-A2h0EikK.js';
3
+ import './types-CL03tjGU.js';
4
4
  import '@almadar/core';
@@ -1,5 +1,5 @@
1
- import { createTickScheduler, EventBus, createUnifiedLoader, MockPersistenceAdapter, InMemoryPersistence, preprocessSchema, normalizeCallSiteConfigToValues, StateMachineManager, parseDurationString, createContextFromBindings, validateEventPayload, formatPayloadValidationError, collectDeclaredConfigDefaults, resolveCallSitePayloadCaptures, collectDeclaredEntityDefaults, EffectExecutor } from './chunk-EJHMWSUS.js';
2
- export { InMemoryPersistence, collectDeclaredConfigDefaults } from './chunk-EJHMWSUS.js';
1
+ import { createTickScheduler, EventBus, createUnifiedLoader, MockPersistenceAdapter, InMemoryPersistence, preprocessSchema, normalizeCallSiteConfigToValues, StateMachineManager, parseDurationString, createContextFromBindings, validateEventPayload, formatPayloadValidationError, collectDeclaredConfigDefaults, resolveCallSitePayloadCaptures, collectDeclaredEntityDefaults, EffectExecutor } from './chunk-FIBEYLME.js';
2
+ export { InMemoryPersistence, collectDeclaredConfigDefaults } from './chunk-FIBEYLME.js';
3
3
  import { isValidCronExpression } from './chunk-OU3ITB5S.js';
4
4
  import './chunk-T4VDAB4C.js';
5
5
  import './chunk-SCRAHWOC.js';
@@ -7,7 +7,7 @@ import './chunk-MLKGABMK.js';
7
7
  import { createLogger } from '@almadar/logger';
8
8
  import * as nodeModule from 'module';
9
9
  import { evaluateListenPayloadExpr, evaluateGuard, evaluate } from '@almadar/evaluator';
10
- import { DEFAULT_VIEWER, buildResolvedTraitConfigs, isInlineTrait, isEntityCall, applyListenPayloadMapping, normalizeUserContext } from '@almadar/core';
10
+ import { DEFAULT_VIEWER, buildResolvedTraitConfigs, isInlineTrait, isEntityCall, applyListenPayloadMapping, normalizeUserContext, isRuntimeEntity } from '@almadar/core';
11
11
  import { ownerFieldsFromSchema, identityEntityName } from '@almadar/core/mock';
12
12
 
13
13
  // src/identity/routing.ts
@@ -650,6 +650,16 @@ var OrbitalServerRuntime = class {
650
650
  const routeKey = eventRouteKey(bareEvent, listener.eventId);
651
651
  const cleanup = this.eventBus.on(routeKey, async (event) => {
652
652
  if (!matcher(event.source)) return;
653
+ if (event.source?.originClientId !== void 0) {
654
+ if (this.config.debug) {
655
+ xOrbitalLog.debug("listen:skip-client-origin", {
656
+ receiverTrait: trait.name,
657
+ event: listener.event,
658
+ originClientId: event.source.originClientId
659
+ });
660
+ }
661
+ return;
662
+ }
653
663
  if (this.config.debug) {
654
664
  xOrbitalLog.debug("listen:received", () => ({
655
665
  receiverOrbital: orbitalName,
@@ -915,6 +925,34 @@ var OrbitalServerRuntime = class {
915
925
  // ==========================================================================
916
926
  // Event Processing
917
927
  // ==========================================================================
928
+ /**
929
+ * `traitFieldStates` key for one trait: its own name, or — when its linked
930
+ * entity is `[shared]` — `$shared::<entityName>` so every trait bound to
931
+ * that entity reads/writes ONE frame. The server twin of the client hook's
932
+ * `sharedKeyByTraitName` (useTraitStateMachine): without it, a sibling
933
+ * trait's effect interpolation (a fetch filter reading
934
+ * `@entity.activeChannel`) never saw the writer's `(set …)`.
935
+ */
936
+ sharedFieldKey(registered, traitName) {
937
+ const trait = registered.traits.find((t) => t.name === traitName);
938
+ const linked = trait?.linkedEntity ?? registered.entity.name;
939
+ return this.isSharedEntity(registered, linked) ? `$shared::${linked}` : traitName;
940
+ }
941
+ /** Resolve an entity name to its declared `shared` flag: the orbital's own
942
+ * entity, its auxiliary entities, then other registered orbitals' primary
943
+ * entities (cross-orbital binds like a membership rail in the chat page). */
944
+ isSharedEntity(registered, entityName) {
945
+ if (registered.entity.name === entityName) return registered.entity.shared === true;
946
+ for (const aux of registered.schema.auxiliaryEntities ?? []) {
947
+ if (typeof aux === "object" && !isEntityCall(aux) && aux.name === entityName) {
948
+ return aux.shared === true;
949
+ }
950
+ }
951
+ for (const other of this.orbitals.values()) {
952
+ if (other.entity.name === entityName) return other.entity.shared === true;
953
+ }
954
+ return false;
955
+ }
918
956
  /**
919
957
  * Process an event for an orbital
920
958
  *
@@ -1010,9 +1048,10 @@ var OrbitalServerRuntime = class {
1010
1048
  }
1011
1049
  }
1012
1050
  const entityByTrait = {};
1013
- for (const [name, fields] of registered.traitFieldStates) {
1051
+ for (const trait of registered.traits) {
1052
+ const fields = registered.traitFieldStates.get(this.sharedFieldKey(registered, trait.name));
1014
1053
  if (fields && Object.keys(fields).length > 0) {
1015
- entityByTrait[name] = fields;
1054
+ entityByTrait[trait.name] = fields;
1016
1055
  }
1017
1056
  }
1018
1057
  const results = registered.manager.sendEvent(
@@ -1127,6 +1166,9 @@ var OrbitalServerRuntime = class {
1127
1166
  if (stamp.eventId === void 0 && emitContract?.eventId !== void 0) {
1128
1167
  stamp.eventId = emitContract.eventId;
1129
1168
  }
1169
+ if (originClientId !== void 0 && stamp.originClientId === void 0) {
1170
+ stamp.originClientId = originClientId;
1171
+ }
1130
1172
  this.eventBus.emit(event, eventPayload, stamp, eventRouteKey(event, stamp.eventId));
1131
1173
  const emittedItem = { event, payload: eventPayload, source: stamp };
1132
1174
  emittedEvents.push(emittedItem);
@@ -1155,10 +1197,11 @@ var OrbitalServerRuntime = class {
1155
1197
  }
1156
1198
  },
1157
1199
  set: async (targetId, field, value) => {
1158
- let fieldState = registered.traitFieldStates.get(traitName);
1200
+ const fieldKey = this.sharedFieldKey(registered, traitName);
1201
+ let fieldState = registered.traitFieldStates.get(fieldKey);
1159
1202
  if (!fieldState) {
1160
1203
  fieldState = {};
1161
- registered.traitFieldStates.set(traitName, fieldState);
1204
+ registered.traitFieldStates.set(fieldKey, fieldState);
1162
1205
  }
1163
1206
  fieldState[field] = value;
1164
1207
  effectResults.push({
@@ -1531,7 +1574,10 @@ var OrbitalServerRuntime = class {
1531
1574
  bindings: bindingsRef ?? {},
1532
1575
  context: contextRef ?? { traitName, orbitalName: registered.schema.name, state: "unknown", transition: "unknown" },
1533
1576
  debug: this.config.debug,
1534
- contextExtensions: this.config.contextExtensions
1577
+ contextExtensions: this.config.contextExtensions,
1578
+ // Same render-time marker boundary as the outer executor
1579
+ // (including the [shared]-defers-regardless-of-persistence rule).
1580
+ deferRenderBindings: registered.entity === void 0 || isRuntimeEntity(registered.entity) || registered.entity.shared === true
1535
1581
  });
1536
1582
  for (const innerEffect of atomicEffects) {
1537
1583
  if (atomicFailed) break;
@@ -1619,7 +1665,7 @@ var OrbitalServerRuntime = class {
1619
1665
  };
1620
1666
  }
1621
1667
  const entityFieldDefaults = collectDeclaredEntityDefaults(registered.entity);
1622
- const traitFieldState = registered.traitFieldStates.get(traitName);
1668
+ const traitFieldState = registered.traitFieldStates.get(this.sharedFieldKey(registered, traitName));
1623
1669
  if (entityFieldDefaults || traitFieldState) {
1624
1670
  bindings.entity = {
1625
1671
  ...entityFieldDefaults ?? {},
@@ -1644,7 +1690,19 @@ var OrbitalServerRuntime = class {
1644
1690
  bindings,
1645
1691
  context,
1646
1692
  debug: this.config.debug,
1647
- contextExtensions: this.config.contextExtensions
1693
+ contextExtensions: this.config.contextExtensions,
1694
+ // Carry `@entity`-dependent render-ui leaves as render-time markers
1695
+ // for runtime-only (and unlinked) entities: the client's local state
1696
+ // machines execute the same `(set)` writes, so the renderer resolves
1697
+ // markers against its live store — otherwise these SSE-pushed eager
1698
+ // props clobber the client's live marker frames on every event.
1699
+ // Persistent NON-shared entities stay eager: their `@entity` merges
1700
+ // persistence rows the client does not hold. A `[shared]` entity is
1701
+ // deferred REGARDLESS of persistence — its trait frame's scalars are
1702
+ // client-held by contract (one live frame across bound traits), and
1703
+ // the eager clobber pinned the chat composer's controlled input to
1704
+ // the server's flush-time "" on every keystroke round-trip.
1705
+ deferRenderBindings: registered.entity === void 0 || isRuntimeEntity(registered.entity) || registered.entity.shared === true
1648
1706
  });
1649
1707
  await executor.executeAll(effects);
1650
1708
  }
@@ -1,4 +1,4 @@
1
- import { I as IEventBus } from './types-p_L8-Sk4.js';
1
+ import { I as IEventBus } from './types-CL03tjGU.js';
2
2
  import { EventPayload } from '@almadar/core';
3
3
 
4
4
  /**
@@ -5,7 +5,7 @@ import { createLogger, setNamespaceLevel } from '@almadar/logger';
5
5
  import { createMinimalContext, resolveBinding, evaluate, evaluateGuard, SExpressionEvaluator } from '@almadar/evaluator';
6
6
  export { createMinimalContext } from '@almadar/evaluator';
7
7
  import { isKnownStdOperator } from '@almadar/std/registry';
8
- import { OrbitalSchemaSchema, isInlineTrait, isEntityCall, isEntityReference, parseEntityRef, parseImportedTraitRef, isPageReference, isPageReferenceString, isPageReferenceObject, parsePageRef, isReferenceConfigType, configRefEventKnob, normalizeCallSiteConfigToValues, resolveConfigRefEventName } from '@almadar/core';
8
+ import { containsEntityBinding, containsPayloadBinding, RENDER_BINDING_MARKER, OrbitalSchemaSchema, isInlineTrait, isEntityCall, isEntityReference, parseEntityRef, parseImportedTraitRef, isPageReference, isPageReferenceString, isPageReferenceObject, parsePageRef, isReferenceConfigType, configRefEventKnob, normalizeCallSiteConfigToValues, resolveConfigRefEventName } from '@almadar/core';
9
9
  export { normalizeCallSiteConfigToValues } from '@almadar/core';
10
10
  import { sampleRowCount, sampleRow } from '@almadar/core/mock';
11
11
 
@@ -291,6 +291,7 @@ function isValidDurationString(interval) {
291
291
  }
292
292
  var bindLog = createLogger("almadar:runtime:bindings");
293
293
  setNamespaceLevel("almadar:runtime:bindings", "WARN");
294
+ var deferLog = createLogger("almadar:runtime:defer");
294
295
  var renderLog = createLogger("almadar:runtime:render-ui");
295
296
  var CLIENT_ONLY_BINDING_ROOTS = /* @__PURE__ */ new Set(["trait"]);
296
297
  var CALLSITE_PAYLOAD_PREFIX = "@callsitePayload.";
@@ -396,6 +397,45 @@ function interpolateValue(value, ctx) {
396
397
  }
397
398
  return value;
398
399
  }
400
+ function deferEntityBindings(value, ctx, configHops = 0) {
401
+ if (typeof value === "string") {
402
+ if (containsEntityBinding(value) && !containsPayloadBinding(value)) {
403
+ return { [RENDER_BINDING_MARKER]: true, expression: value };
404
+ }
405
+ if (value.startsWith("@config.") && !value.includes(" ") && configHops < 8) {
406
+ const hop = ctx.config?.[value.slice("@config.".length)];
407
+ deferLog.debug("defer:config-hop", () => ({
408
+ forward: value,
409
+ hopType: typeof hop,
410
+ hopPreview: typeof hop === "string" ? hop : Array.isArray(hop) ? "array" : hop === void 0 ? "undefined" : "object"
411
+ }));
412
+ if (hop !== void 0 && hop !== value) {
413
+ return deferEntityBindings(hop, ctx, configHops + 1);
414
+ }
415
+ }
416
+ return interpolateValue(value, ctx);
417
+ }
418
+ if (Array.isArray(value)) {
419
+ if (value.length === 3 && value[0] === "fn" && typeof value[1] === "string") {
420
+ return value;
421
+ }
422
+ if (isSExpression(value)) {
423
+ if (containsEntityBinding(value) && !containsPayloadBinding(value)) {
424
+ return { [RENDER_BINDING_MARKER]: true, expression: value };
425
+ }
426
+ return interpolateValue(value, ctx);
427
+ }
428
+ return value.map((item) => deferEntityBindings(item, ctx));
429
+ }
430
+ if (value !== null && typeof value === "object") {
431
+ const out = {};
432
+ for (const [key, item] of Object.entries(value)) {
433
+ out[key] = deferEntityBindings(item, ctx);
434
+ }
435
+ return out;
436
+ }
437
+ return value;
438
+ }
399
439
  var inFlightConfigRecursions = /* @__PURE__ */ new Set();
400
440
  function interpolateString(value, ctx) {
401
441
  if (value.startsWith("@") && isPureBinding(value)) {
@@ -1178,6 +1218,18 @@ function resolveArgs(args, bindings, strictBindings, contextExtensions) {
1178
1218
  const ctx = createContextFromBindings(bindings, strictBindings, contextExtensions);
1179
1219
  return args.map((arg) => interpolateValue(arg, ctx));
1180
1220
  }
1221
+ function interpolateFilterTraitRefs(value, ctx) {
1222
+ if (typeof value === "string") {
1223
+ return value === "@entity" || value.startsWith("@entity.") ? interpolateValue(value, ctx) : value;
1224
+ }
1225
+ if (Array.isArray(value)) {
1226
+ if (value.length >= 2 && value[0] === "object/get" && value[1] === "@entity") {
1227
+ return value;
1228
+ }
1229
+ return value.map((v) => interpolateFilterTraitRefs(v, ctx));
1230
+ }
1231
+ return value;
1232
+ }
1181
1233
  var EffectExecutor = class _EffectExecutor {
1182
1234
  handlers;
1183
1235
  bindings;
@@ -1186,6 +1238,7 @@ var EffectExecutor = class _EffectExecutor {
1186
1238
  strictBindings;
1187
1239
  contextExtensions;
1188
1240
  evaluator;
1241
+ deferRenderBindings;
1189
1242
  constructor(options) {
1190
1243
  this.handlers = options.handlers;
1191
1244
  this.bindings = options.bindings;
@@ -1194,6 +1247,7 @@ var EffectExecutor = class _EffectExecutor {
1194
1247
  this.strictBindings = options.strictBindings ?? false;
1195
1248
  this.contextExtensions = options.contextExtensions;
1196
1249
  this.evaluator = options.evaluator;
1250
+ this.deferRenderBindings = options.deferRenderBindings ?? false;
1197
1251
  }
1198
1252
  _evaluator;
1199
1253
  getEvaluator() {
@@ -1293,9 +1347,15 @@ var EffectExecutor = class _EffectExecutor {
1293
1347
  const isCompound = operator === "do" || operator === "when" || operator === "let" || operator === "if";
1294
1348
  const isSetPathForm = operator === "set" && args.length >= 2 && typeof args[0] === "string" && args[0].startsWith("@entity.");
1295
1349
  const isFetchLike = (operator === "fetch" || operator === "ref" || operator === "deref" || operator === "os/watch-collection" || operator === "os/watch") && args.length >= 2 && args[1] !== null && typeof args[1] === "object" && !Array.isArray(args[1]);
1350
+ const isDeferringRenderUI = (operator === "render-ui" || operator === "render") && this.deferRenderBindings;
1296
1351
  let resolvedArgs;
1297
1352
  if (isCompound) {
1298
1353
  resolvedArgs = args;
1354
+ } else if (isDeferringRenderUI) {
1355
+ const ctx = createContextFromBindings(this.bindings, this.strictBindings, this.contextExtensions);
1356
+ resolvedArgs = args.map(
1357
+ (arg, index) => index === 0 ? interpolateValue(arg, ctx) : deferEntityBindings(arg, ctx)
1358
+ );
1299
1359
  } else if (isSetPathForm) {
1300
1360
  const ctx = createContextFromBindings(this.bindings, this.strictBindings, this.contextExtensions);
1301
1361
  const resolvedRest = [];
@@ -1316,7 +1376,7 @@ var EffectExecutor = class _EffectExecutor {
1316
1376
  const opts = args[1];
1317
1377
  const resolvedOpts = {
1318
1378
  ...opts.id !== void 0 && { id: interpolateValue(opts.id, ctx) },
1319
- ...opts.filter !== void 0 && { filter: opts.filter },
1379
+ ...opts.filter !== void 0 && { filter: interpolateFilterTraitRefs(opts.filter, ctx) },
1320
1380
  ...opts.limit !== void 0 && { limit: interpolateValue(opts.limit, ctx) },
1321
1381
  ...opts.offset !== void 0 && { offset: interpolateValue(opts.offset, ctx) },
1322
1382
  ...opts.include !== void 0 && { include: interpolateValue(opts.include, ctx) },
@@ -1868,7 +1928,8 @@ var EffectExecutor = class _EffectExecutor {
1868
1928
  context: this.context,
1869
1929
  debug: this.debug,
1870
1930
  strictBindings: this.strictBindings,
1871
- contextExtensions: this.contextExtensions
1931
+ contextExtensions: this.contextExtensions,
1932
+ deferRenderBindings: this.deferRenderBindings
1872
1933
  });
1873
1934
  await bodyExecutor.execute(body);
1874
1935
  break;
@@ -4882,4 +4943,4 @@ var InMemoryPersistence = class {
4882
4943
  }
4883
4944
  };
4884
4945
 
4885
- export { CALLSITE_PAYLOAD_PREFIX, EffectExecutor, EventBus, HANDLER_MANIFEST, InMemoryPersistence, MockPersistenceAdapter, StateMachineManager, TickScheduler, buildEmitsFromTraits, collectDeclaredConfigDefaults, collectDeclaredEntityDefaults, containsBindings, createContextFromBindings, createInitialTraitState, createMockPersistence, createTestExecutor, createTickScheduler, createUnifiedLoader, extractBindings, findInitialState, findTransition, formatPayloadValidationError, getIsolatedCollectionName, getNamespacedEvent, interpolateProps, interpolateValue, isBrowser, isElectron, isNamespacedEvent, isNode, isValidDurationString, normalizeEventKey, parseDurationString, parseNamespacedEvent, preprocessSchema, processEvent, resolveCallSitePayloadCaptures, validateEventPayload, validatePayloadShapes };
4946
+ export { CALLSITE_PAYLOAD_PREFIX, EffectExecutor, EventBus, HANDLER_MANIFEST, InMemoryPersistence, MockPersistenceAdapter, StateMachineManager, TickScheduler, buildEmitsFromTraits, collectDeclaredConfigDefaults, collectDeclaredEntityDefaults, containsBindings, createContextFromBindings, createInitialTraitState, createMockPersistence, createTestExecutor, createTickScheduler, createUnifiedLoader, deferEntityBindings, extractBindings, findInitialState, findTransition, formatPayloadValidationError, getIsolatedCollectionName, getNamespacedEvent, interpolateProps, interpolateValue, isBrowser, isElectron, isNamespacedEvent, isNode, isValidDurationString, normalizeEventKey, parseDurationString, parseNamespacedEvent, preprocessSchema, processEvent, resolveCallSitePayloadCaptures, validateEventPayload, validatePayloadShapes };
@@ -1,4 +1,4 @@
1
- import { E as EffectHandlers } from './types-p_L8-Sk4.js';
1
+ import { E as EffectHandlers } from './types-CL03tjGU.js';
2
2
  import { EventPayload } from '@almadar/core';
3
3
 
4
4
  /**
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { B as BindingContext, f as EvaluationContextExtensions, P as PatternProps, E as EffectHandlers, g as EffectContext, h as ExecutionEnvironment, i as EffectResult, T as TraitDefinition } from './types-p_L8-Sk4.js';
2
- export { j as BrowserFileMeta, k as BrowserFilePickerOptions, l as BrowserGeolocationOptions, m as BrowserGeolocationPosition, C as ConfigContext, n as Effect, a as EventListener, H as HANDLER_MANIFEST, I as IEventBus, b as RuntimeConfig, R as RuntimeEvent, d as TraitState, c as TransitionObserver, e as TransitionResult, U as Unsubscribe } from './types-p_L8-Sk4.js';
3
- import { U as UnifiedLoaderOptions, S as SchemaLoader, I as ImportChainLike, L as LoadResult, a as LoadedSchema, b as LoadedOrbital, P as PersistenceAdapter } from './OrbitalServerRuntime-Dz0oubQ_.js';
4
- export { E as EntitySharingMap, c as EventBus, d as EventNamespaceMap, e as InMemoryPersistence, O as OrbitalEventRequest, f as OrbitalEventResponse, g as OrbitalServerRuntimeConfig, h as PreprocessOptions, i as PreprocessResult, j as PreprocessedSchema, k as ProcessEventOptions, R as RegisteredOrbital, l as RuntimeOrbital, m as RuntimeOrbitalSchema, n as RuntimeTrait, o as StateMachineManager, p as collectDeclaredConfigDefaults, q as collectDeclaredEntityDefaults, r as createInitialTraitState, s as findInitialState, t as findTransition, u as getIsolatedCollectionName, v as getNamespacedEvent, w as isBrowser, x as isElectron, y as isNamespacedEvent, z as isNode, A as normalizeEventKey, B as parseNamespacedEvent, C as preprocessSchema, D as processEvent } from './OrbitalServerRuntime-Dz0oubQ_.js';
1
+ import { g as RuntimePatternValue, B as BindingContext, f as EvaluationContextExtensions, P as PatternProps, E as EffectHandlers, h as EffectContext, i as ExecutionEnvironment, j as EffectResult, T as TraitDefinition } from './types-CL03tjGU.js';
2
+ export { k as BrowserFileMeta, l as BrowserFilePickerOptions, m as BrowserGeolocationOptions, n as BrowserGeolocationPosition, C as ConfigContext, o as Effect, a as EventListener, H as HANDLER_MANIFEST, I as IEventBus, b as RuntimeConfig, R as RuntimeEvent, d as TraitState, c as TransitionObserver, e as TransitionResult, U as Unsubscribe } from './types-CL03tjGU.js';
3
+ import { U as UnifiedLoaderOptions, S as SchemaLoader, I as ImportChainLike, L as LoadResult, a as LoadedSchema, b as LoadedOrbital, P as PersistenceAdapter } from './OrbitalServerRuntime-A2h0EikK.js';
4
+ export { E as EntitySharingMap, c as EventBus, d as EventNamespaceMap, e as InMemoryPersistence, O as OrbitalEventRequest, f as OrbitalEventResponse, g as OrbitalServerRuntimeConfig, h as PreprocessOptions, i as PreprocessResult, j as PreprocessedSchema, k as ProcessEventOptions, R as RegisteredOrbital, l as RuntimeOrbital, m as RuntimeOrbitalSchema, n as RuntimeTrait, o as StateMachineManager, p as collectDeclaredConfigDefaults, q as collectDeclaredEntityDefaults, r as createInitialTraitState, s as findInitialState, t as findTransition, u as getIsolatedCollectionName, v as getNamespacedEvent, w as isBrowser, x as isElectron, y as isNamespacedEvent, z as isNode, A as normalizeEventKey, B as parseNamespacedEvent, C as preprocessSchema, D as processEvent } from './OrbitalServerRuntime-A2h0EikK.js';
5
5
  import { EvaluationContext, SExpressionEvaluator } from '@almadar/evaluator';
6
6
  export { EvaluationContext, createMinimalContext } from '@almadar/evaluator';
7
- import { TraitConfigObject, EventPayload, PatternConfig, EntityId, EntityField, EntityRow, EntityPersistence, ServiceParams, PayloadField, OrbitalDefinition, OrbitalSchema } from '@almadar/core';
7
+ import { RenderBindingMarker, SExpr, TraitConfigObject, EventPayload, PatternConfig, EntityId, EntityField, EntityRow, EntityPersistence, ServiceParams, PayloadField, OrbitalDefinition, OrbitalSchema } from '@almadar/core';
8
8
  export { EntityField, normalizeCallSiteConfigToValues } from '@almadar/core';
9
9
  export { ServerBridgeConfig, ServerBridgeState } from './ServerBridge.js';
10
10
  export { OsHandlerContext, OsHandlerResult } from './createOsHandlers.js';
@@ -284,6 +284,28 @@ declare function interpolateProps(props: PatternProps, ctx: EvaluationContext):
284
284
  * Interpolate a single value.
285
285
  */
286
286
  declare function interpolateValue(value: unknown, ctx: EvaluationContext): unknown;
287
+ /**
288
+ * Value a deferred render-ui prop tree can carry: interpolated runtime
289
+ * values, raw pass-through S-expressions (`fn` lambdas), render-time
290
+ * binding markers, and nested arrays/records of the same. No `unknown`
291
+ * escape hatch.
292
+ */
293
+ type DeferredPatternValue = RuntimePatternValue | RenderBindingMarker | SExpr | Date | readonly DeferredPatternValue[] | {
294
+ readonly [prop: string]: DeferredPatternValue;
295
+ };
296
+ /**
297
+ * Carry `@entity`-dependent prop leaves into slot content as
298
+ * `RenderBindingMarker`s instead of resolving them at flush time — the
299
+ * renderer (`@almadar/ui`'s SlotContentRenderer) evaluates each marker
300
+ * against the live entity store on every React render, the same model the
301
+ * compiled shell uses. Everything else resolves eagerly through the same
302
+ * `interpolateValue` path the non-deferring executor uses:
303
+ * - payload-referencing leaves stay eager (`@payload` is event-scoped and
304
+ * does not exist at render time);
305
+ * - `fn` render lambdas pass through raw (they are already render-time);
306
+ * - literal arrays (children lists) and plain objects recurse per item.
307
+ */
308
+ declare function deferEntityBindings(value: SExpr, ctx: EvaluationContext, configHops?: number): DeferredPatternValue;
287
309
  /**
288
310
  * Check if a value contains any binding references.
289
311
  */
@@ -328,6 +350,14 @@ interface EffectExecutorOptions {
328
350
  contextExtensions?: EvaluationContextExtensions;
329
351
  /** Evaluator for resolving nested S-expression values in `set` (e.g., substrate operators) */
330
352
  evaluator?: SExpressionEvaluator;
353
+ /**
354
+ * When true, render-ui args keep `@entity`-dependent prop leaves as
355
+ * `RenderBindingMarker`s for render-time evaluation instead of resolving
356
+ * them eagerly at flush time. Set by the client-side interpreter
357
+ * (`useTraitStateMachine`); server-side executors resolve eagerly so
358
+ * SSE-pushed props stay concrete.
359
+ */
360
+ deferRenderBindings?: boolean;
331
361
  }
332
362
  /**
333
363
  * EffectExecutor - Routes effects to handlers.
@@ -363,6 +393,7 @@ declare class EffectExecutor {
363
393
  private strictBindings;
364
394
  private contextExtensions?;
365
395
  private evaluator?;
396
+ private deferRenderBindings;
366
397
  constructor(options: EffectExecutorOptions);
367
398
  private _evaluator?;
368
399
  private getEvaluator;
@@ -1045,4 +1076,4 @@ declare namespace index {
1045
1076
  export { type index_ComposeBehaviorsInput as ComposeBehaviorsInput, type index_ComposeBehaviorsResult as ComposeBehaviorsResult, type index_EventWiringEntry as EventWiringEntry, type index_LayoutStrategy as LayoutStrategy, type index_PipeStep as PipeStep, index_applyEventWiring as applyEventWiring, index_composeBehaviors as composeBehaviors, index_detectLayoutStrategy as detectLayoutStrategy, index_pipeBehaviors as pipeBehaviors };
1046
1077
  }
1047
1078
 
1048
- export { BindingContext, CALLSITE_PAYLOAD_PREFIX, type ClientEventBus, type ComposeBehaviorsInput, type ComposeBehaviorsResult, type CreateClientEffectHandlersOptions, type CreateServerEffectHandlersOptions, type CronFields, EffectContext, EffectExecutor, type EffectExecutorOptions, EffectHandlers, EffectResult, type EntitySchema, type EventWiringEntry, ExecutionEnvironment, ImportChainLike, type LayoutStrategy, LoadResult, LoadedOrbital, LoadedSchema, MockPersistenceAdapter, type MockPersistenceConfig, type PayloadMismatch, type PayloadValidationFailure, PersistenceAdapter, type PipeStep, SchemaLoader, type ServerEffectResult, type SlotSetter, type TickHandle, TickScheduler, TraitDefinition, UnifiedLoaderOptions, applyEventWiring, buildEmitsFromTraits, composeBehaviors, index as composition, containsBindings, createClientEffectHandlers, createContextFromBindings, createMockPersistence, createServerEffectHandlers, createTestExecutor, createTickScheduler, createUnifiedLoader, cronMatches, cronMinuteKey, detectLayoutStrategy, extractBindings, formatPayloadValidationError, interpolateProps, interpolateValue, isValidCronExpression, isValidDurationString, parseCron, parseCronField, parseDurationString, pipeBehaviors, resolveCallSitePayloadCaptures, validateEventPayload, validatePayloadShapes };
1079
+ export { BindingContext, CALLSITE_PAYLOAD_PREFIX, type ClientEventBus, type ComposeBehaviorsInput, type ComposeBehaviorsResult, type CreateClientEffectHandlersOptions, type CreateServerEffectHandlersOptions, type CronFields, type DeferredPatternValue, EffectContext, EffectExecutor, type EffectExecutorOptions, EffectHandlers, EffectResult, type EntitySchema, type EventWiringEntry, ExecutionEnvironment, ImportChainLike, type LayoutStrategy, LoadResult, LoadedOrbital, LoadedSchema, MockPersistenceAdapter, type MockPersistenceConfig, type PayloadMismatch, type PayloadValidationFailure, PersistenceAdapter, type PipeStep, SchemaLoader, type ServerEffectResult, type SlotSetter, type TickHandle, TickScheduler, TraitDefinition, UnifiedLoaderOptions, applyEventWiring, buildEmitsFromTraits, composeBehaviors, index as composition, containsBindings, createClientEffectHandlers, createContextFromBindings, createMockPersistence, createServerEffectHandlers, createTestExecutor, createTickScheduler, createUnifiedLoader, cronMatches, cronMinuteKey, deferEntityBindings, detectLayoutStrategy, extractBindings, formatPayloadValidationError, interpolateProps, interpolateValue, isValidCronExpression, isValidDurationString, parseCron, parseCronField, parseDurationString, pipeBehaviors, resolveCallSitePayloadCaptures, validateEventPayload, validatePayloadShapes };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { EffectExecutor, createContextFromBindings } from './chunk-EJHMWSUS.js';
2
- export { CALLSITE_PAYLOAD_PREFIX, EffectExecutor, EventBus, HANDLER_MANIFEST, InMemoryPersistence, MockPersistenceAdapter, StateMachineManager, TickScheduler, buildEmitsFromTraits, collectDeclaredConfigDefaults, collectDeclaredEntityDefaults, containsBindings, createContextFromBindings, createInitialTraitState, createMinimalContext, createMockPersistence, createTestExecutor, createTickScheduler, createUnifiedLoader, extractBindings, findInitialState, findTransition, formatPayloadValidationError, getIsolatedCollectionName, getNamespacedEvent, interpolateProps, interpolateValue, isBrowser, isElectron, isNamespacedEvent, isNode, isValidDurationString, normalizeCallSiteConfigToValues, normalizeEventKey, parseDurationString, parseNamespacedEvent, preprocessSchema, processEvent, resolveCallSitePayloadCaptures, validateEventPayload, validatePayloadShapes } from './chunk-EJHMWSUS.js';
1
+ import { EffectExecutor, createContextFromBindings } from './chunk-FIBEYLME.js';
2
+ export { CALLSITE_PAYLOAD_PREFIX, EffectExecutor, EventBus, HANDLER_MANIFEST, InMemoryPersistence, MockPersistenceAdapter, StateMachineManager, TickScheduler, buildEmitsFromTraits, collectDeclaredConfigDefaults, collectDeclaredEntityDefaults, containsBindings, createContextFromBindings, createInitialTraitState, createMinimalContext, createMockPersistence, createTestExecutor, createTickScheduler, createUnifiedLoader, deferEntityBindings, extractBindings, findInitialState, findTransition, formatPayloadValidationError, getIsolatedCollectionName, getNamespacedEvent, interpolateProps, interpolateValue, isBrowser, isElectron, isNamespacedEvent, isNode, isValidDurationString, normalizeCallSiteConfigToValues, normalizeEventKey, parseDurationString, parseNamespacedEvent, preprocessSchema, processEvent, resolveCallSitePayloadCaptures, validateEventPayload, validatePayloadShapes } from './chunk-FIBEYLME.js';
3
3
  export { cronMatches, cronMinuteKey, isValidCronExpression, parseCron, parseCronField } from './chunk-OU3ITB5S.js';
4
4
  import './chunk-T4VDAB4C.js';
5
5
  export { PERF_NAMESPACE, RendererContractViolationError, adjustSchemaForMockData, aggregateSlotContent, assertIsMultiSourceSlotManager, assertIsSlotManager, bindEventBus, bindTraitStateGetter, buildMockData, buildOrbitalsByTrait, clearPerf, createSlotSetter, ensureVerificationApi, getOrbitalVerification, perfEnd, perfStart, perfStore, perfTime, prepareSchemaForPreview, pushPerfEntry, validateSlotContent, wrapCallbackForEvent } from './chunk-FOFLEZRJ.js';
@@ -3,6 +3,25 @@ import { TraitId, EventId, SExpr, TraitEventListener, AgentContext, LlmContext,
3
3
 
4
4
  /** Alias for ResolvedPatternProps to avoid breaking internal consumers */
5
5
  type PatternProps = ResolvedPatternProps;
6
+ /**
7
+ * Value a render-ui pattern prop can carry AFTER interpolation. Mirrors
8
+ * `FieldValue` but extends with `RuntimeRenderPattern` so nested pattern
9
+ * configs (children, slot props that are themselves render-ui nodes)
10
+ * round-trip without an `unknown` escape hatch.
11
+ */
12
+ type RuntimePatternValue = string | number | boolean | null | undefined | EntityRow | EntityRow[] | readonly RuntimePatternValue[] | RuntimeRenderPattern;
13
+ /**
14
+ * Shape of a render-ui pattern AFTER interpolation, as the runtime hands
15
+ * it to `EffectHandlers.renderUI`. Different from `ResolvedPatternProps`
16
+ * (`@almadar/core`) because the post-interpolation pattern carries
17
+ * resolved EntityRow values (e.g. `{ entity: <row> }` from `@payload.row`)
18
+ * not just primitives. Used by render-ui observability helpers to narrow
19
+ * safely without `unknown` casts.
20
+ */
21
+ interface RuntimeRenderPattern {
22
+ readonly [prop: string]: RuntimePatternValue;
23
+ }
24
+
6
25
  type ConfigContext = TraitConfig;
7
26
  /**
8
27
  * Event structure for cross-trait communication.
@@ -432,7 +451,7 @@ interface TransitionObserver {
432
451
  guardResult?: boolean;
433
452
  effects: Array<{
434
453
  type: string;
435
- args: unknown[];
454
+ args: SExpr[];
436
455
  status: "executed" | "failed" | "skipped";
437
456
  error?: string;
438
457
  durationMs?: number;
@@ -444,4 +463,4 @@ interface TransitionObserver {
444
463
  */
445
464
  declare const HANDLER_MANIFEST: Record<ExecutionEnvironment, string[]>;
446
465
 
447
- export { type BindingContext as B, type ConfigContext as C, type EffectHandlers as E, HANDLER_MANIFEST as H, type IEventBus as I, type PatternProps as P, type RuntimeEvent as R, type TraitDefinition as T, type Unsubscribe as U, type EventListener as a, type RuntimeConfig as b, type TransitionObserver as c, type TraitState as d, type TransitionResult as e, type EvaluationContextExtensions as f, type EffectContext as g, type ExecutionEnvironment as h, type EffectResult as i, type BrowserFileMeta as j, type BrowserFilePickerOptions as k, type BrowserGeolocationOptions as l, type BrowserGeolocationPosition as m, type Effect as n };
466
+ export { type BindingContext as B, type ConfigContext as C, type EffectHandlers as E, HANDLER_MANIFEST as H, type IEventBus as I, type PatternProps as P, type RuntimeEvent as R, type TraitDefinition as T, type Unsubscribe as U, type EventListener as a, type RuntimeConfig as b, type TransitionObserver as c, type TraitState as d, type TransitionResult as e, type EvaluationContextExtensions as f, type RuntimePatternValue as g, type EffectContext as h, type ExecutionEnvironment as i, type EffectResult as j, type BrowserFileMeta as k, type BrowserFilePickerOptions as l, type BrowserGeolocationOptions as m, type BrowserGeolocationPosition as n, type Effect as o };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/runtime",
3
- "version": "6.44.0",
3
+ "version": "6.45.0",
4
4
  "description": "Interpreted runtime for Almadar orbital applications (OrbitalServerRuntime)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -52,11 +52,11 @@
52
52
  "access": "public"
53
53
  },
54
54
  "dependencies": {
55
- "@almadar/core": "^10.42.0",
56
- "@almadar/evaluator": "^2.37.0",
55
+ "@almadar/core": "^10.43.0",
56
+ "@almadar/evaluator": "^2.38.0",
57
57
  "@almadar/logger": "^1.10.0",
58
58
  "@almadar/server": "^2.29.0",
59
- "@almadar/std": "^16.152.0"
59
+ "@almadar/std": "^16.153.0"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "express": "^5.0.0"