@almadar/runtime 6.73.0 → 6.75.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,6 +1,6 @@
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, B as BindingContext, g as EffectContext, S as ServiceCallContext, E as EffectHandlers } from './types-CWaIuEQn.js';
3
- import { EventPayload, EventId, EntityRow, UserContext, ServiceParams, EntityAccessPolicies, Orbital, ServiceCallResult, TraitConfig, DeclaredTraitConfig, Entity, OrbitalSchema, Trait, PatternConfig, ResolvedPatternProps, SExpr, BusEventSource, RawUserClaims, OrbitalDefinition, TraitTick } from '@almadar/core';
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, B as BindingContext, g as EffectContext, S as ServiceCallContext, E as EffectHandlers } from './types-BO4tbEPp.js';
3
+ import { EventPayload, EventId, EntityRow, UserContext, ServiceParams, EntityAccessPolicies, Orbital, ServiceCallResult, TraitConfig, DeclaredTraitConfig, Entity, OrbitalSchema, Trait, PatternConfig, ResolvedPatternProps, BusEventSource, RawUserClaims, OrbitalDefinition, TraitTick } from '@almadar/core';
4
4
 
5
5
  /**
6
6
  * EventBus - Platform-Agnostic Pub/Sub Implementation
@@ -538,7 +538,7 @@ interface CreateServerEffectHandlersOptions {
538
538
  * transition, call this factory again.
539
539
  *
540
540
  * Intentionally does NOT implement:
541
- * - `renderUI` / `notify` / `navigate` — these are client-side, provided
541
+ * - `renderUI` / `navigate` — these are client-side, provided
542
542
  * by `createClientEffectHandlers`. A mock runtime merges both handler
543
543
  * sets.
544
544
  * - `os/watch-*` observers — these are a no-op outside the server.
@@ -1030,19 +1030,19 @@ declare function parseNamespacedEvent(eventName: string): {
1030
1030
 
1031
1031
  /**
1032
1032
  * Client-side effect tuple shipped in `OrbitalEventResponse.clientEffects`.
1033
- * Restricted to the three effect kinds the client knows how to apply to the
1034
- * UI: render-ui (slot mutation), navigate (route change), notify (toast).
1033
+ * Restricted to the effect kinds the client knows how to apply to the
1034
+ * UI: render-ui (slot mutation, including the `toast` slot that carries
1035
+ * what used to be the separate notify effect) and navigate (route change).
1035
1036
  * Server-only effects (persist, set, fetch, ...) execute on the server and
1036
1037
  * surface their results via `effectResults` and `emittedEvents`, not here.
1037
1038
  *
1038
1039
  * Shape note: the wire form is broader than `RenderUIEffect` /
1039
- * `NavigateEffect` / `NotifyEffect` from `@almadar/core/types/effect.ts` in
1040
- * two places — the runtime appends an interpolated `props` object plus an
1041
- * optional `priority` slot to render-ui (slot 4 + 5), and `navigate` /
1042
- * `notify` may surface their optional argument as `undefined` rather than
1043
- * absent. The local union spells those variants out explicitly so consumers
1044
- * (ServerBridge.tsx parser, debugger inspector) get accurate completions
1045
- * instead of `unknown[]`.
1040
+ * `NavigateEffect` from `@almadar/core/types/effect.ts` in two places — the
1041
+ * runtime appends an interpolated `props` object plus an optional `priority`
1042
+ * slot to render-ui (slot 4 + 5), and `navigate`'s optional argument may
1043
+ * surface as `undefined` rather than absent. The local union spells those
1044
+ * variants out explicitly so consumers (ServerBridge.tsx parser, debugger
1045
+ * inspector) get accurate completions instead of `unknown[]`.
1046
1046
  *
1047
1047
  * `slot` is a plain `string` in this wire shape (not `UISlot`'s literal
1048
1048
  * union) because the runtime forwards the raw string from the trait's
@@ -1054,10 +1054,7 @@ type ClientNavigateTuple = ['navigate', string] | ['navigate', string, Record<st
1054
1054
  crumb?: string;
1055
1055
  }];
1056
1056
  type ClientNavigateBackTuple = ['navigate-back'];
1057
- type ClientNotifyTuple = ['notify', string, string | SExpr | undefined] | ['notify', string, string | SExpr | undefined, {
1058
- type?: string;
1059
- }];
1060
- type ClientEffectTuple = ClientRenderUITuple | ClientNavigateTuple | ClientNavigateBackTuple | ClientNotifyTuple;
1057
+ type ClientEffectTuple = ClientRenderUITuple | ClientNavigateTuple | ClientNavigateBackTuple;
1061
1058
 
1062
1059
  /** @deprecated Use OrbitalSchema from @almadar/core */
1063
1060
  type RuntimeOrbitalSchema = OrbitalSchema;
@@ -1174,7 +1171,7 @@ interface OrbitalEventResponse {
1174
1171
  payload?: EventPayload;
1175
1172
  source?: BusEventSource;
1176
1173
  }>;
1177
- /** Client-side effects to execute (render-ui, navigate, notify) */
1174
+ /** Client-side effects to execute (render-ui, navigate) */
1178
1175
  clientEffects?: ClientEffectTuple[];
1179
1176
  /**
1180
1177
  * Same effects as `clientEffects`, paired with the producing trait name.
@@ -1638,6 +1635,12 @@ declare class OrbitalServerRuntime {
1638
1635
  * entity, its auxiliary entities, then other registered orbitals' primary
1639
1636
  * entities (cross-orbital binds like a membership rail in the chat page). */
1640
1637
  private isSharedEntity;
1638
+ /** Names of an entity's `@intrinsic` fields — trait-owned view state
1639
+ * (`ChatMessage.activeChannel`, `ChannelMember.pendingChannelId`, …) that
1640
+ * is NEVER a persisted column. Resolves the entity by name the same way
1641
+ * `isSharedEntity` does: the orbital's own entity, its auxiliary
1642
+ * entities, then other registered orbitals' primary entities. */
1643
+ private intrinsicFieldNames;
1641
1644
  /**
1642
1645
  * Process an event for an orbital
1643
1646
  *
@@ -1763,4 +1766,4 @@ declare class OrbitalServerRuntime {
1763
1766
  */
1764
1767
  declare function createOrbitalServerRuntime(config?: OrbitalServerRuntimeConfig): OrbitalServerRuntime;
1765
1768
 
1766
- export { isElectron as A, isNamespacedEvent as B, type CreateServerEffectHandlersOptions as C, isNode as D, type EntitySharingMap as E, normalizeEventKey as F, parseNamespacedEvent as G, preprocessSchema as H, type ImportChainLike as I, processEvent as J, type ClientEffectTuple as K, type LoadResult as L, type ClientNavigateBackTuple as M, type ClientNavigateTuple as N, type OrbitalEventRequest as O, type PersistenceAdapter as P, type ClientNotifyTuple as Q, type RegisteredOrbital as R, type SchemaLoader as S, type ClientRenderUITuple as T, type UnifiedLoaderOptions as U, type LiveBroadcastItem as V, type LoaderConfig as W, OrbitalServerRuntime as X, type RuntimeTraitTick as Y, createOrbitalServerRuntime as Z, type LoadedSchema as a, type LoadedOrbital as b, EventBus as c, type EventNamespaceMap as d, InMemoryPersistence as e, LIFECYCLE_EVENTS as f, type OrbitalEventResponse as g, type OrbitalServerRuntimeConfig as h, type PreprocessOptions as i, type PreprocessResult as j, type PreprocessedSchema as k, type ProcessEventOptions as l, type RuntimeOrbital as m, type RuntimeOrbitalSchema as n, type RuntimeTrait as o, type ServerEffectResult as p, StateMachineManager as q, collectDeclaredConfigDefaults as r, collectDeclaredEntityDefaults as s, createInitialTraitState as t, createServerEffectHandlers as u, findInitialState as v, findTransition as w, getIsolatedCollectionName as x, getNamespacedEvent as y, isBrowser as z };
1769
+ export { isElectron as A, isNamespacedEvent as B, type CreateServerEffectHandlersOptions as C, isNode as D, type EntitySharingMap as E, normalizeEventKey as F, parseNamespacedEvent as G, preprocessSchema as H, type ImportChainLike as I, processEvent as J, type ClientEffectTuple as K, type LoadResult as L, type ClientNavigateBackTuple as M, type ClientNavigateTuple as N, type OrbitalEventRequest as O, type PersistenceAdapter as P, type ClientRenderUITuple as Q, type RegisteredOrbital as R, type SchemaLoader as S, type LiveBroadcastItem as T, type UnifiedLoaderOptions as U, type LoaderConfig as V, OrbitalServerRuntime as W, type RuntimeTraitTick as X, createOrbitalServerRuntime as Y, type LoadedSchema as a, type LoadedOrbital as b, EventBus as c, type EventNamespaceMap as d, InMemoryPersistence as e, LIFECYCLE_EVENTS as f, type OrbitalEventResponse as g, type OrbitalServerRuntimeConfig as h, type PreprocessOptions as i, type PreprocessResult as j, type PreprocessedSchema as k, type ProcessEventOptions as l, type RuntimeOrbital as m, type RuntimeOrbitalSchema as n, type RuntimeTrait as o, type ServerEffectResult as p, StateMachineManager as q, collectDeclaredConfigDefaults as r, collectDeclaredEntityDefaults as s, createInitialTraitState as t, createServerEffectHandlers as u, findInitialState as v, findTransition as w, getIsolatedCollectionName as x, getNamespacedEvent as y, isBrowser as z };
@@ -1,4 +1,4 @@
1
1
  import 'express';
2
- export { K as ClientEffectTuple, M as ClientNavigateBackTuple, N as ClientNavigateTuple, Q as ClientNotifyTuple, T as ClientRenderUITuple, e as InMemoryPersistence, V as LiveBroadcastItem, W as LoaderConfig, O as OrbitalEventRequest, g as OrbitalEventResponse, X as OrbitalServerRuntime, h as OrbitalServerRuntimeConfig, P as PersistenceAdapter, R as RegisteredOrbital, m as RuntimeOrbital, n as RuntimeOrbitalSchema, o as RuntimeTrait, Y as RuntimeTraitTick, r as collectDeclaredConfigDefaults, Z as createOrbitalServerRuntime } from './OrbitalServerRuntime-BiEntWd-.js';
3
- import './types-CWaIuEQn.js';
2
+ export { K as ClientEffectTuple, M as ClientNavigateBackTuple, N as ClientNavigateTuple, Q as ClientRenderUITuple, e as InMemoryPersistence, T as LiveBroadcastItem, V as LoaderConfig, O as OrbitalEventRequest, g as OrbitalEventResponse, W as OrbitalServerRuntime, h as OrbitalServerRuntimeConfig, P as PersistenceAdapter, R as RegisteredOrbital, m as RuntimeOrbital, n as RuntimeOrbitalSchema, o as RuntimeTrait, X as RuntimeTraitTick, r as collectDeclaredConfigDefaults, Y as createOrbitalServerRuntime } from './OrbitalServerRuntime-Buvz7dd7.js';
3
+ import './types-BO4tbEPp.js';
4
4
  import '@almadar/core';
@@ -1,5 +1,5 @@
1
- import { createTickScheduler, EventBus, createUnifiedLoader, MockPersistenceAdapter, InMemoryPersistence, preprocessSchema, normalizeCallSiteConfigToValues, StateMachineManager, parseDurationString, validateEventPayload, formatPayloadValidationError, collectDeclaredConfigDefaults, collectDeclaredEntityDefaults, EffectExecutor, LIFECYCLE_EVENTS } from './chunk-H7HQQVQJ.js';
2
- export { InMemoryPersistence, collectDeclaredConfigDefaults } from './chunk-H7HQQVQJ.js';
1
+ import { createTickScheduler, EventBus, createUnifiedLoader, MockPersistenceAdapter, InMemoryPersistence, preprocessSchema, normalizeCallSiteConfigToValues, StateMachineManager, parseDurationString, validateEventPayload, formatPayloadValidationError, collectDeclaredConfigDefaults, collectDeclaredEntityDefaults, EffectExecutor, LIFECYCLE_EVENTS } from './chunk-CEYC3Z2O.js';
2
+ export { InMemoryPersistence, collectDeclaredConfigDefaults } from './chunk-CEYC3Z2O.js';
3
3
  import { isValidCronExpression } from './chunk-OU3ITB5S.js';
4
4
  import { createContextFromBindings, checkMutationAccess, applyRowAccess, accessDeniedMessage } from './chunk-ZWAOJT6R.js';
5
5
  import './chunk-T4VDAB4C.js';
@@ -8,7 +8,7 @@ import './chunk-MLKGABMK.js';
8
8
  import { createLogger } from '@almadar/logger';
9
9
  import * as nodeModule from 'module';
10
10
  import { evaluateListenPayloadExpr, evaluateGuard, evaluate } from '@almadar/evaluator';
11
- import { DEFAULT_VIEWER, buildResolvedTraitConfigs, collectCallsiteCaptureChildren, isInlineTrait, isEntityCall, applyListenPayloadMapping, personaFromIdentityRow, normalizeUserContext, isRuntimeEntity, isPageReference } from '@almadar/core';
11
+ import { DEFAULT_VIEWER, buildResolvedTraitConfigs, collectCallsiteCaptureChildren, isInlineTrait, isEntityCall, applyListenPayloadMapping, personaFromIdentityRow, normalizeUserContext, isRuntimeEntity, omitFrameFields, isPageReference } from '@almadar/core';
12
12
  import { ownerFieldsFromSchema, identityEntityName, entityAccessPoliciesByStoreKey, entityAccessPolicies } from '@almadar/core/mock';
13
13
  import { getPatternFieldsContract } from '@almadar/core/patterns';
14
14
 
@@ -1266,6 +1266,24 @@ var OrbitalServerRuntime = class {
1266
1266
  }
1267
1267
  return false;
1268
1268
  }
1269
+ /** Names of an entity's `@intrinsic` fields — trait-owned view state
1270
+ * (`ChatMessage.activeChannel`, `ChannelMember.pendingChannelId`, …) that
1271
+ * is NEVER a persisted column. Resolves the entity by name the same way
1272
+ * `isSharedEntity` does: the orbital's own entity, its auxiliary
1273
+ * entities, then other registered orbitals' primary entities. */
1274
+ intrinsicFieldNames(registered, entityName) {
1275
+ const namesOf = (entity) => entity.fields.filter((field) => field.intrinsic === true && typeof field.name === "string").map((field) => field.name);
1276
+ if (registered.entity.name === entityName) return namesOf(registered.entity);
1277
+ for (const aux of registered.schema.auxiliaryEntities ?? []) {
1278
+ if (typeof aux === "object" && !isEntityCall(aux) && aux.name === entityName) {
1279
+ return namesOf(aux);
1280
+ }
1281
+ }
1282
+ for (const other of this.orbitals.values()) {
1283
+ if (other.entity.name === entityName) return namesOf(other.entity);
1284
+ }
1285
+ return [];
1286
+ }
1269
1287
  /**
1270
1288
  * Process an event for an orbital
1271
1289
  *
@@ -1321,8 +1339,14 @@ var OrbitalServerRuntime = class {
1321
1339
  const { event, eventId, payload, entityId, user: requestUser, clientId } = request;
1322
1340
  const viewer = normalizeUserContext(requestUser) ?? this.config.defaultUser;
1323
1341
  const targetTrait = request.targetTrait ?? payload?.["_targetTrait"];
1342
+ const activeTraits = payload?._activeTraits;
1343
+ const dispatchTargetTraits = registered.traits.filter((trait) => {
1344
+ if (targetTrait !== void 0) return trait.name === targetTrait;
1345
+ if (activeTraits && activeTraits.length > 0 && !activeTraits.includes(trait.name)) return false;
1346
+ return registered.manager.canHandleEvent(trait.name, event, entityId, eventId);
1347
+ });
1324
1348
  const validationFailures = [];
1325
- for (const trait of registered.traits) {
1349
+ for (const trait of dispatchTargetTraits) {
1326
1350
  const eventSchema = trait.stateMachine?.events?.find((e) => e.key === event);
1327
1351
  if (eventSchema?.payloadSchema && eventSchema.payloadSchema.length > 0) {
1328
1352
  validationFailures.push(
@@ -1344,7 +1368,6 @@ var OrbitalServerRuntime = class {
1344
1368
  const clientEffects = [];
1345
1369
  const clientEffectsByTrait = [];
1346
1370
  const effectResults = [];
1347
- const activeTraits = payload?._activeTraits;
1348
1371
  const cleanPayload = payload ? { ...payload } : void 0;
1349
1372
  if (cleanPayload) {
1350
1373
  delete cleanPayload._activeTraits;
@@ -1577,7 +1600,8 @@ var OrbitalServerRuntime = class {
1577
1600
  try {
1578
1601
  switch (opAction) {
1579
1602
  case "create": {
1580
- const createData = opRest[0] || {};
1603
+ const createIntrinsicFields = this.intrinsicFieldNames(registered, opEntityType);
1604
+ const createData = createIntrinsicFields.length > 0 ? omitFrameFields(opRest[0] || {}, createIntrinsicFields) : opRest[0] || {};
1581
1605
  const { id: newId } = await this.persistence.create(opEntityType, createData);
1582
1606
  batchResults.push({ ...createData, action: "create", entityType: opEntityType, id: newId });
1583
1607
  completed.push({ action: "create", entityType: opEntityType, id: newId });
@@ -1585,7 +1609,8 @@ var OrbitalServerRuntime = class {
1585
1609
  }
1586
1610
  case "update": {
1587
1611
  const updateId = opRest[0];
1588
- const updateData = opRest[1] || {};
1612
+ const updateIntrinsicFields = this.intrinsicFieldNames(registered, opEntityType);
1613
+ const updateData = updateIntrinsicFields.length > 0 ? omitFrameFields(opRest[1] || {}, updateIntrinsicFields) : opRest[1] || {};
1589
1614
  await this.persistence.update(opEntityType, updateId, updateData);
1590
1615
  const updated = await this.persistence.getById(opEntityType, updateId);
1591
1616
  batchResults.push({ ...updated || updateData, action: "update", entityType: opEntityType, id: updateId });
@@ -1625,6 +1650,10 @@ var OrbitalServerRuntime = class {
1625
1650
  return;
1626
1651
  }
1627
1652
  const type = targetEntityType || entityType;
1653
+ if ((action === "create" || action === "update") && data !== void 0) {
1654
+ const intrinsicFields = this.intrinsicFieldNames(registered, type);
1655
+ if (intrinsicFields.length > 0) data = omitFrameFields(data, intrinsicFields);
1656
+ }
1628
1657
  let resultData;
1629
1658
  const sizeBefore = (await this.persistence.list(type)).length;
1630
1659
  let deniedReason;
@@ -1952,7 +1981,8 @@ var OrbitalServerRuntime = class {
1952
1981
  contextExtensions: this.config.contextExtensions,
1953
1982
  // Same render-time marker boundary as the outer executor
1954
1983
  // (including the [shared]-defers-regardless-of-persistence rule).
1955
- deferRenderBindings: registered.entity === void 0 || isRuntimeEntity(registered.entity) || registered.entity.shared === true
1984
+ deferRenderBindings: registered.entity === void 0 || isRuntimeEntity(registered.entity) || registered.entity.shared === true,
1985
+ resolveIntrinsicFields: (type) => this.intrinsicFieldNames(registered, type)
1956
1986
  });
1957
1987
  for (const innerEffect of atomicEffects) {
1958
1988
  if (atomicFailed) break;
@@ -2003,12 +2033,6 @@ var OrbitalServerRuntime = class {
2003
2033
  navigateBack: () => {
2004
2034
  pushClientEffect(["navigate-back"]);
2005
2035
  },
2006
- notify: (message, type) => {
2007
- if (this.config.debug) {
2008
- effectLog.info("notify", { type, message });
2009
- }
2010
- pushClientEffect(["notify", message, { type }]);
2011
- },
2012
2036
  log: (message, level) => {
2013
2037
  if (level === "error") {
2014
2038
  dynamicLog.error(message);
@@ -2117,7 +2141,8 @@ var OrbitalServerRuntime = class {
2117
2141
  // client-held by contract (one live frame across bound traits), and
2118
2142
  // the eager clobber pinned the chat composer's controlled input to
2119
2143
  // the server's flush-time "" on every keystroke round-trip.
2120
- deferRenderBindings: registered.entity === void 0 || isRuntimeEntity(registered.entity) || registered.entity.shared === true
2144
+ deferRenderBindings: registered.entity === void 0 || isRuntimeEntity(registered.entity) || registered.entity.shared === true,
2145
+ resolveIntrinsicFields: (type) => this.intrinsicFieldNames(registered, type)
2121
2146
  });
2122
2147
  await executor.executeAll(effects);
2123
2148
  }
@@ -1,4 +1,4 @@
1
- import { I as IEventBus } from './types-CWaIuEQn.js';
1
+ import { I as IEventBus } from './types-BO4tbEPp.js';
2
2
  import { EventPayload } from '@almadar/core';
3
3
 
4
4
  /**
@@ -4,9 +4,9 @@ import { seedRandom, randomArrayElement, randomInt, shuffleArray, randomPastDate
4
4
  import { collectTraitRefsFromValue, collectTraitRefsFromEffects } from './chunk-SCRAHWOC.js';
5
5
  import { createLogger, setNamespaceLevel } from '@almadar/logger';
6
6
  import { evaluateGuard, SExpressionEvaluator } from '@almadar/evaluator';
7
- import { OrbitalSchemaSchema, isInlineTrait, isEntityCall, isEntityReference, parseEntityRef, parseImportedTraitRef, isPageReference, isPageReferenceString, isPageReferenceObject, parsePageRef, parseOrbitalRef, overrideDeclaredKnobs, asTraitId, asEntityId, asPageId, asOrbitalId, deriveId, isReferenceConfigType, configRefEventKnob, normalizeCallSiteConfigToValues, resolveConfigRefEventName, isCallSiteConfigDeclaration, asEventId, ledgerRename, idPrefix, eventListPropsOf } from '@almadar/core';
7
+ import { omitFrameFields, OrbitalSchemaSchema, isInlineTrait, isEntityCall, isEntityReference, parseEntityRef, parseImportedTraitRef, isPageReference, isPageReferenceString, isPageReferenceObject, parsePageRef, parseOrbitalRef, overrideDeclaredKnobs, asTraitId, asEntityId, asPageId, asOrbitalId, deriveId, isReferenceConfigType, configRefEventKnob, normalizeCallSiteConfigToValues, resolveConfigRefEventName, isCallSiteConfigDeclaration, asEventId, ledgerRename, idPrefix, eventListPropsOf } from '@almadar/core';
8
8
  export { normalizeCallSiteConfigToValues } from '@almadar/core';
9
- import { sampleRowCount, sampleRow, identityEntitiesOf, roleVocabularyOf } from '@almadar/core/mock';
9
+ import { sampleRowCount, linkSelfRelationField, sampleRow, identityEntitiesOf, roleVocabularyOf } from '@almadar/core/mock';
10
10
 
11
11
  var log = createLogger("almadar:runtime:eventbus");
12
12
  var EventBus = class {
@@ -922,14 +922,13 @@ var StateMachineManager = class {
922
922
 
923
923
  // src/types.ts
924
924
  var HANDLER_MANIFEST = {
925
- client: ["render-ui", "render", "navigate", "navigate-back", "notify", "emit", "set", "log", "ref", "deref", "watch", "send-server", "browser/open-file-picker", "browser/clipboard-read", "browser/clipboard-write", "browser/geolocation-current"],
925
+ client: ["render-ui", "render", "navigate", "navigate-back", "emit", "set", "log", "ref", "deref", "watch", "send-server", "browser/open-file-picker", "browser/clipboard-read", "browser/clipboard-write", "browser/geolocation-current"],
926
926
  server: ["persist", "fetch", "fetch-stream", "call-service", "emit", "set", "spawn", "despawn", "log", "ref", "deref", "swap!", "atomic", "os/watch-files", "os/watch-process", "os/watch-port", "os/watch-http", "os/watch-cron", "os/watch-signal", "os/watch-env", "os/debounce"],
927
927
  test: [
928
928
  "render-ui",
929
929
  "render",
930
930
  "navigate",
931
931
  "navigate-back",
932
- "notify",
933
932
  "emit",
934
933
  "set",
935
934
  "persist",
@@ -989,6 +988,7 @@ var EffectExecutor = class _EffectExecutor {
989
988
  contextExtensions;
990
989
  evaluator;
991
990
  deferRenderBindings;
991
+ resolveIntrinsicFields;
992
992
  constructor(options) {
993
993
  this.handlers = options.handlers;
994
994
  this.bindings = options.bindings;
@@ -998,6 +998,22 @@ var EffectExecutor = class _EffectExecutor {
998
998
  this.contextExtensions = options.contextExtensions;
999
999
  this.evaluator = options.evaluator;
1000
1000
  this.deferRenderBindings = options.deferRenderBindings ?? false;
1001
+ this.resolveIntrinsicFields = options.resolveIntrinsicFields;
1002
+ }
1003
+ /**
1004
+ * `@intrinsic` fields are NEVER a persisted column — strips them from
1005
+ * `data` before a `persist create`/`persist update` write, regardless of
1006
+ * what expression produced `data` (bare `@entity`, an explicit literal
1007
+ * that names one, an `object/merge` result, …). Deterministic on the
1008
+ * entity's declared schema, not on how the value was constructed. A
1009
+ * no-op when no schema was supplied (`resolveIntrinsicFields` absent,
1010
+ * e.g. a browser/offline-preview handler set) or the entity declares no
1011
+ * intrinsic fields.
1012
+ */
1013
+ stripFrameFields(entityType, data) {
1014
+ if (data === void 0 || !this.resolveIntrinsicFields) return data;
1015
+ const intrinsicFields = this.resolveIntrinsicFields(entityType);
1016
+ return intrinsicFields.length > 0 ? omitFrameFields(data, intrinsicFields) : data;
1001
1017
  }
1002
1018
  _evaluator;
1003
1019
  getEvaluator() {
@@ -1063,7 +1079,6 @@ var EffectExecutor = class _EffectExecutor {
1063
1079
  "render": this.handlers.renderUI,
1064
1080
  "navigate": this.handlers.navigate,
1065
1081
  "navigate-back": this.handlers.navigateBack,
1066
- "notify": this.handlers.notify,
1067
1082
  "log": this.handlers.log,
1068
1083
  "ref": this.handlers.ref,
1069
1084
  "deref": this.handlers.deref,
@@ -1413,7 +1428,19 @@ var EffectExecutor = class _EffectExecutor {
1413
1428
  }
1414
1429
  try {
1415
1430
  if (action === "batch") {
1416
- const operations = args[1];
1431
+ const operations = args[1].map((op) => {
1432
+ if (!Array.isArray(op) || op.length < 2) return op;
1433
+ const [opAction, opEntityType, ...opRest] = op;
1434
+ if (opAction === "create") {
1435
+ const stripped = this.stripFrameFields(opEntityType, opRest[0]);
1436
+ return [opAction, opEntityType, stripped, ...opRest.slice(1)];
1437
+ }
1438
+ if (opAction === "update") {
1439
+ const stripped = this.stripFrameFields(opEntityType, opRest[1]);
1440
+ return [opAction, opEntityType, opRest[0], stripped, ...opRest.slice(2)];
1441
+ }
1442
+ return op;
1443
+ });
1417
1444
  const batchSummary = await this.handlers.persist("batch", "", {
1418
1445
  operations
1419
1446
  });
@@ -1432,7 +1459,7 @@ var EffectExecutor = class _EffectExecutor {
1432
1459
  persistLog.debug("persist:emit-fired", { action, eventName: emitCfg?.success });
1433
1460
  } else {
1434
1461
  const entityType = args[1];
1435
- const data = args[2];
1462
+ const data = action === "create" || action === "update" ? this.stripFrameFields(entityType, args[2]) : args[2];
1436
1463
  const persisted = await this.handlers.persist(action, entityType, data);
1437
1464
  if (persisted === void 0) {
1438
1465
  const attemptedId = typeof data === "string" ? data : data && typeof data === "object" ? data.id : void 0;
@@ -1697,15 +1724,7 @@ var EffectExecutor = class _EffectExecutor {
1697
1724
  break;
1698
1725
  }
1699
1726
  case "notify": {
1700
- if (this.handlers.notify) {
1701
- const message = args[0];
1702
- const type = args[1] || "info";
1703
- this.handlers.notify(message, type);
1704
- } else {
1705
- const category = typeof args[1] === "string" ? args[1] : "info";
1706
- const message = typeof args[0] === "string" ? args[0] : JSON.stringify(args[0] ?? null);
1707
- effectLog.info("notify", { category, message });
1708
- }
1727
+ this.logUnsupported("notify");
1709
1728
  break;
1710
1729
  }
1711
1730
  // === Compound Effects ===
@@ -2476,14 +2495,18 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
2476
2495
  * of nested-tree atoms (e.g. std-thread-comments-linear with ThreadPost.
2477
2496
  * replies → [ThreadPost]) render empty reply cards.
2478
2497
  *
2479
- * Cross-entity relations pick random IDs from the target store. A
2480
- * SELF-referential `one`-cardinality relation (a parent column like
2481
- * `Tag.parentId : Tag`) is linked deterministically instead: row 0 stays a
2482
- * root (`""`) and row *i* parents to row ⌊(i−1)/2⌋ — a proper forest with
2483
- * real roots and no cycles, so tree views and `parentId = ""` root fetches
2484
- * render sensibly. Self-referential `many` relations keep the 2–4 random
2485
- * sibling IDs (excluding self). The runtime caps recursion at depth=2 in
2486
- * `populateRelations`, so deep chains render two levels then stop.
2498
+ * Cross-entity relations pick random IDs from the target store. EVERY
2499
+ * self-referential relation, any cardinality, is linked deterministically
2500
+ * instead via `@almadar/core/mock`'s `linkSelfRelationField`: row 0 stays a
2501
+ * root (never referenced), row *i* parents to row ⌊(i−1)/2⌋ — one shared
2502
+ * forest, real roots, no cycles. `one`/`many-to-one` self-relations (a
2503
+ * parent column like `Tag.parentId : Tag`) store the scalar parent id;
2504
+ * `many`/`one-to-many`/`many-to-many` self-relations (a children list like
2505
+ * `ChatMessage.replies : [ChatMessage]`) store the forest's children-id
2506
+ * list — no more random cross-linking, so the root row is never referenced
2507
+ * and stays deletable under `onDelete: restrict`. The runtime caps
2508
+ * recursion at depth=2 in `populateRelations`, so deep chains render two
2509
+ * levels then stop.
2487
2510
  *
2488
2511
  * Entities sharing a collection are linked once per STORE, over the union
2489
2512
  * of their declared relation fields (first declarer of a field name wins).
@@ -2525,13 +2548,12 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
2525
2548
  if (!targetStore || targetStore.size === 0) continue;
2526
2549
  const sameStore = targetStore === store;
2527
2550
  const cardinality = field.relation.cardinality ?? "many";
2528
- if (sameStore && (cardinality === "one" || cardinality === "many-to-one")) {
2529
- rows.forEach((row, i) => {
2530
- if (this.config.ownerId !== void 0 && row[field.name] === this.config.ownerId || stampedCellKeys.has(stampedCellKey(storeKey, row["id"], field.name))) {
2531
- return;
2532
- }
2533
- row[field.name] = i === 0 ? "" : rows[Math.floor((i - 1) / 2)]["id"];
2534
- });
2551
+ if (sameStore) {
2552
+ linkSelfRelationField(
2553
+ rows,
2554
+ { name: field.name, cardinality },
2555
+ (row, i) => this.config.ownerId !== void 0 && row[field.name] === this.config.ownerId || stampedCellKeys.has(stampedCellKey(storeKey, row["id"], field.name))
2556
+ );
2535
2557
  continue;
2536
2558
  }
2537
2559
  for (const row of rows) {
@@ -2539,11 +2561,7 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
2539
2561
  if (this.config.ownerId !== void 0 && row[field.name] === this.config.ownerId || stampedCellKeys.has(stampedCellKey(storeKey, selfId, field.name))) {
2540
2562
  continue;
2541
2563
  }
2542
- let eligible = [];
2543
- for (const id of targetStore.keys()) {
2544
- if (sameStore && id === selfId) continue;
2545
- eligible.push(id);
2546
- }
2564
+ let eligible = [...targetStore.keys()];
2547
2565
  if (isOwnerColumn && this.ownerCandidateGate) {
2548
2566
  const gate = this.ownerCandidateGate;
2549
2567
  eligible = eligible.filter(
@@ -4326,10 +4344,18 @@ function traitEmbedNamesOf(trait) {
4326
4344
  for (const field of Object.values(trait.config ?? {})) walk(field.default);
4327
4345
  return [...found].sort();
4328
4346
  }
4329
- function resolveForwardedSiblingConfigFrom(trait, parentChain, orbitalConfig, schemaConfig) {
4347
+ function resolveForwardedSiblingConfigFrom(trait, parentChain, orbitalConfig, schemaConfig, schemaOnlyKeys) {
4330
4348
  const declared = trait.config;
4331
4349
  if (!declared) return trait;
4332
- const next = resolveConfigForwards(declared, parentChain, orbitalConfig, void 0, void 0, schemaConfig);
4350
+ const next = resolveConfigForwards(
4351
+ declared,
4352
+ parentChain,
4353
+ orbitalConfig,
4354
+ void 0,
4355
+ void 0,
4356
+ schemaConfig,
4357
+ schemaOnlyKeys
4358
+ );
4333
4359
  return next ? { ...trait, config: next } : trait;
4334
4360
  }
4335
4361
  function callSiteRungValue(rungConfig, knob) {
@@ -4338,8 +4364,9 @@ function callSiteRungValue(rungConfig, knob) {
4338
4364
  return isCallSiteConfigDeclaration(entry) ? entry.default : entry;
4339
4365
  }
4340
4366
  function walkConfigForwardChain(forward, parentChain, orbitalConfig, upstreamOrbitalConfig, upstreamSchemaConfig, schemaConfig) {
4367
+ const unresolved = { value: void 0, reachedSchemaConfigOnly: false };
4341
4368
  let knob = forward.slice("@config.".length);
4342
- if (knob.length === 0 || knob.includes(".")) return void 0;
4369
+ if (knob.length === 0 || knob.includes(".")) return unresolved;
4343
4370
  let value;
4344
4371
  let currentForward = forward;
4345
4372
  for (const rungConfig of parentChain) {
@@ -4358,16 +4385,17 @@ function walkConfigForwardChain(forward, parentChain, orbitalConfig, upstreamOrb
4358
4385
  if (value === void 0 || value === currentForward) value = orbitalConfig?.[knob]?.default;
4359
4386
  if (value === void 0 || value === currentForward) value = upstreamOrbitalConfig?.[knob]?.default;
4360
4387
  if (value === void 0 || value === currentForward) value = upstreamSchemaConfig?.[knob]?.default;
4361
- if (value === void 0 || value === currentForward) value = schemaConfig?.[knob]?.default;
4362
- if (value === void 0 || value === currentForward) return void 0;
4363
- return value;
4388
+ const reachesSchemaConfigRung = value === void 0 || value === currentForward;
4389
+ if (reachesSchemaConfigRung) value = schemaConfig?.[knob]?.default;
4390
+ if (value === void 0 || value === currentForward) return unresolved;
4391
+ return { value, reachedSchemaConfigOnly: reachesSchemaConfigRung };
4364
4392
  }
4365
- function resolveConfigForwards(declared, parentChain, orbitalConfig, upstreamOrbitalConfig, upstreamSchemaConfig, schemaConfig) {
4393
+ function resolveConfigForwards(declared, parentChain, orbitalConfig, upstreamOrbitalConfig, upstreamSchemaConfig, schemaConfig, schemaOnlyKeys) {
4366
4394
  let next;
4367
4395
  for (const [key, field] of Object.entries(declared)) {
4368
4396
  const forward = field.default;
4369
4397
  if (typeof forward !== "string" || !forward.startsWith("@config.")) continue;
4370
- const value = walkConfigForwardChain(
4398
+ const { value, reachedSchemaConfigOnly } = walkConfigForwardChain(
4371
4399
  forward,
4372
4400
  parentChain,
4373
4401
  orbitalConfig,
@@ -4376,6 +4404,7 @@ function resolveConfigForwards(declared, parentChain, orbitalConfig, upstreamOrb
4376
4404
  schemaConfig
4377
4405
  );
4378
4406
  if (value === void 0) continue;
4407
+ if (reachedSchemaConfigOnly) schemaOnlyKeys?.add(key);
4379
4408
  next ??= { ...declared };
4380
4409
  next[key] = { ...field, default: value, forwardedFrom: forward };
4381
4410
  }
@@ -4386,7 +4415,7 @@ function resolveCallSiteConfigForwards(config, parentChain, orbitalConfig, schem
4386
4415
  for (const [key, entry] of Object.entries(config)) {
4387
4416
  const forward = isCallSiteConfigDeclaration(entry) ? entry.default : entry;
4388
4417
  if (typeof forward !== "string" || !forward.startsWith("@config.")) continue;
4389
- const value = walkConfigForwardChain(forward, parentChain, orbitalConfig, void 0, void 0, schemaConfig);
4418
+ const { value } = walkConfigForwardChain(forward, parentChain, orbitalConfig, void 0, void 0, schemaConfig);
4390
4419
  if (value === void 0) continue;
4391
4420
  next ??= { ...config };
4392
4421
  next[key] = isCallSiteConfigDeclaration(entry) ? { ...entry, default: value, forwardedFrom: forward } : value;
@@ -5584,11 +5613,11 @@ function rewriteConfigPagePaths(node, pathMap) {
5584
5613
  }
5585
5614
  return node;
5586
5615
  }
5587
- function rewriteTraitConfigPagePaths(trait, pathMap) {
5616
+ function rewriteTraitConfigPagePaths(trait, pathMap, schemaOnlyKeys) {
5588
5617
  if (pathMap.size === 0 || !trait.config) return trait;
5589
5618
  const nextConfig = {};
5590
5619
  for (const [key, field] of Object.entries(trait.config)) {
5591
- nextConfig[key] = field.default === void 0 ? field : { ...field, default: rewriteConfigPagePaths(field.default, pathMap) };
5620
+ nextConfig[key] = field.default === void 0 || schemaOnlyKeys.has(key) ? field : { ...field, default: rewriteConfigPagePaths(field.default, pathMap) };
5592
5621
  }
5593
5622
  return { ...trait, config: nextConfig };
5594
5623
  }
@@ -7479,17 +7508,30 @@ var ReferenceResolver = class _ReferenceResolver {
7479
7508
  if (pathMap.size > 0) {
7480
7509
  next = rewriteTraitNavigateTargets(next, pathMap);
7481
7510
  }
7511
+ const schemaOnlyKeys = /* @__PURE__ */ new Set();
7482
7512
  for (const embedderName of embeddersOf.get(trait.name) ?? []) {
7483
7513
  const embedderConfig = parentConfigs.get(embedderName);
7484
- next = resolveForwardedSiblingConfigFrom(next, embedderConfig ? [embedderConfig] : []);
7514
+ next = resolveForwardedSiblingConfigFrom(
7515
+ next,
7516
+ embedderConfig ? [embedderConfig] : [],
7517
+ void 0,
7518
+ void 0,
7519
+ schemaOnlyKeys
7520
+ );
7485
7521
  }
7486
- next = resolveForwardedSiblingConfigFrom(next, transitiveEmbedderChain(trait.name));
7487
- next = resolveForwardedSiblingConfigFrom(next, [], foldedConfig, importedSchemaConfig);
7522
+ next = resolveForwardedSiblingConfigFrom(
7523
+ next,
7524
+ transitiveEmbedderChain(trait.name),
7525
+ void 0,
7526
+ void 0,
7527
+ schemaOnlyKeys
7528
+ );
7529
+ next = resolveForwardedSiblingConfigFrom(next, [], foldedConfig, importedSchemaConfig, schemaOnlyKeys);
7488
7530
  if (fieldSubs.size > 0 && next.config) {
7489
7531
  next = { ...next, config: rewriteEntityFieldsInConfig(next.config, fieldSubs) };
7490
7532
  }
7491
7533
  if (pathMap.size > 0) {
7492
- next = rewriteTraitConfigPagePaths(next, pathMap);
7534
+ next = rewriteTraitConfigPagePaths(next, pathMap, schemaOnlyKeys);
7493
7535
  }
7494
7536
  next = applyEventRenames(next, ref.events, keptFinalNames);
7495
7537
  return next;
@@ -1,4 +1,4 @@
1
- import { E as EffectHandlers } from './types-CWaIuEQn.js';
1
+ import { E as EffectHandlers } from './types-BO4tbEPp.js';
2
2
  import { EventPayload } from '@almadar/core';
3
3
 
4
4
  /**
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { h as RuntimePatternValue, B as BindingContext, f as EvaluationContextExtensions, P as PatternProps, E as EffectHandlers, g as EffectContext, i as ExecutionEnvironment, j as EffectResult, T as TraitDefinition } from './types-CWaIuEQn.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-CWaIuEQn.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-BiEntWd-.js';
4
- export { C as CreateServerEffectHandlersOptions, E as EntitySharingMap, c as EventBus, d as EventNamespaceMap, e as InMemoryPersistence, f as LIFECYCLE_EVENTS, O as OrbitalEventRequest, g as OrbitalEventResponse, h as OrbitalServerRuntimeConfig, i as PreprocessOptions, j as PreprocessResult, k as PreprocessedSchema, l as ProcessEventOptions, R as RegisteredOrbital, m as RuntimeOrbital, n as RuntimeOrbitalSchema, o as RuntimeTrait, p as ServerEffectResult, q as StateMachineManager, r as collectDeclaredConfigDefaults, s as collectDeclaredEntityDefaults, t as createInitialTraitState, u as createServerEffectHandlers, v as findInitialState, w as findTransition, x as getIsolatedCollectionName, y as getNamespacedEvent, z as isBrowser, A as isElectron, B as isNamespacedEvent, D as isNode, F as normalizeEventKey, G as parseNamespacedEvent, H as preprocessSchema, J as processEvent } from './OrbitalServerRuntime-BiEntWd-.js';
1
+ import { h as RuntimePatternValue, B as BindingContext, f as EvaluationContextExtensions, P as PatternProps, E as EffectHandlers, g as EffectContext, i as ExecutionEnvironment, j as EffectResult, T as TraitDefinition } from './types-BO4tbEPp.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-BO4tbEPp.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-Buvz7dd7.js';
4
+ export { C as CreateServerEffectHandlersOptions, E as EntitySharingMap, c as EventBus, d as EventNamespaceMap, e as InMemoryPersistence, f as LIFECYCLE_EVENTS, O as OrbitalEventRequest, g as OrbitalEventResponse, h as OrbitalServerRuntimeConfig, i as PreprocessOptions, j as PreprocessResult, k as PreprocessedSchema, l as ProcessEventOptions, R as RegisteredOrbital, m as RuntimeOrbital, n as RuntimeOrbitalSchema, o as RuntimeTrait, p as ServerEffectResult, q as StateMachineManager, r as collectDeclaredConfigDefaults, s as collectDeclaredEntityDefaults, t as createInitialTraitState, u as createServerEffectHandlers, v as findInitialState, w as findTransition, x as getIsolatedCollectionName, y as getNamespacedEvent, z as isBrowser, A as isElectron, B as isNamespacedEvent, D as isNode, F as normalizeEventKey, G as parseNamespacedEvent, H as preprocessSchema, J as processEvent } from './OrbitalServerRuntime-Buvz7dd7.js';
5
5
  import { EvaluationContext, SExpressionEvaluator } from '@almadar/evaluator';
6
6
  export { EvaluationContext, createMinimalContext } from '@almadar/evaluator';
7
7
  import { RenderBindingMarker, SExpr, RuntimeValue, EventPayload, PatternConfig, EntityId, EntityField, EntityRow, EntityPersistence, PayloadField, OrbitalDefinition, OrbitalSchema } from '@almadar/core';
@@ -353,6 +353,16 @@ interface EffectExecutorOptions {
353
353
  * SSE-pushed props stay concrete.
354
354
  */
355
355
  deferRenderBindings?: boolean;
356
+ /**
357
+ * Names of an entity's `@intrinsic` fields — trait-owned view state
358
+ * (never a persisted column) — keyed by entity type. Supplied only by a
359
+ * caller holding the registered schema (`OrbitalServerRuntime`); the
360
+ * `persist` case uses it to strip those keys from a bare `@entity`
361
+ * binding before the write reaches the store. Absent means "no schema
362
+ * available" (e.g. a browser/offline-preview handler set), in which case
363
+ * persist writes verbatim exactly as before.
364
+ */
365
+ resolveIntrinsicFields?: (entityType: string) => readonly string[];
356
366
  }
357
367
  /**
358
368
  * EffectExecutor - Routes effects to handlers.
@@ -389,7 +399,19 @@ declare class EffectExecutor {
389
399
  private contextExtensions?;
390
400
  private evaluator?;
391
401
  private deferRenderBindings;
402
+ private resolveIntrinsicFields?;
392
403
  constructor(options: EffectExecutorOptions);
404
+ /**
405
+ * `@intrinsic` fields are NEVER a persisted column — strips them from
406
+ * `data` before a `persist create`/`persist update` write, regardless of
407
+ * what expression produced `data` (bare `@entity`, an explicit literal
408
+ * that names one, an `object/merge` result, …). Deterministic on the
409
+ * entity's declared schema, not on how the value was constructed. A
410
+ * no-op when no schema was supplied (`resolveIntrinsicFields` absent,
411
+ * e.g. a browser/offline-preview handler set) or the entity declares no
412
+ * intrinsic fields.
413
+ */
414
+ private stripFrameFields;
393
415
  private _evaluator?;
394
416
  private getEvaluator;
395
417
  /**
@@ -521,8 +543,6 @@ interface CreateClientEffectHandlersOptions {
521
543
  }, crumb?: string) => void;
522
544
  /** Navigate-back function: pop the orbital-scoped navigation stack. */
523
545
  navigateBack?: () => void;
524
- /** Notify function for notification effects */
525
- notify?: (message: string, type: 'success' | 'error' | 'warning' | 'info') => void;
526
546
  /**
527
547
  * Send-server handler for `send-server` effects.
528
548
  * When omitted, defaults to a lazy WebSocket transport connecting to the
@@ -542,7 +562,7 @@ interface CreateClientEffectHandlersOptions {
542
562
  /**
543
563
  * Create client-side effect handlers for trait state machine execution.
544
564
  *
545
- * Client handles: emit, renderUI, navigate, notify, sendServer
565
+ * Client handles: emit, renderUI, navigate, sendServer
546
566
  * Server handles: persist, set, callService (logged as warnings on client)
547
567
  *
548
568
  * @example
@@ -554,7 +574,6 @@ interface CreateClientEffectHandlersOptions {
554
574
  * clearSlot: (slot) => pendingSlots.set(slot, []),
555
575
  * },
556
576
  * navigate: (path) => router.push(path),
557
- * notify: (msg, type) => toast[type](msg),
558
577
  * });
559
578
  * ```
560
579
  */
@@ -747,14 +766,18 @@ declare class MockPersistenceAdapter implements PersistenceAdapter {
747
766
  * of nested-tree atoms (e.g. std-thread-comments-linear with ThreadPost.
748
767
  * replies → [ThreadPost]) render empty reply cards.
749
768
  *
750
- * Cross-entity relations pick random IDs from the target store. A
751
- * SELF-referential `one`-cardinality relation (a parent column like
752
- * `Tag.parentId : Tag`) is linked deterministically instead: row 0 stays a
753
- * root (`""`) and row *i* parents to row ⌊(i−1)/2⌋ — a proper forest with
754
- * real roots and no cycles, so tree views and `parentId = ""` root fetches
755
- * render sensibly. Self-referential `many` relations keep the 2–4 random
756
- * sibling IDs (excluding self). The runtime caps recursion at depth=2 in
757
- * `populateRelations`, so deep chains render two levels then stop.
769
+ * Cross-entity relations pick random IDs from the target store. EVERY
770
+ * self-referential relation, any cardinality, is linked deterministically
771
+ * instead via `@almadar/core/mock`'s `linkSelfRelationField`: row 0 stays a
772
+ * root (never referenced), row *i* parents to row ⌊(i−1)/2⌋ — one shared
773
+ * forest, real roots, no cycles. `one`/`many-to-one` self-relations (a
774
+ * parent column like `Tag.parentId : Tag`) store the scalar parent id;
775
+ * `many`/`one-to-many`/`many-to-many` self-relations (a children list like
776
+ * `ChatMessage.replies : [ChatMessage]`) store the forest's children-id
777
+ * list — no more random cross-linking, so the root row is never referenced
778
+ * and stays deletable under `onDelete: restrict`. The runtime caps
779
+ * recursion at depth=2 in `populateRelations`, so deep chains render two
780
+ * levels then stop.
758
781
  *
759
782
  * Entities sharing a collection are linked once per STORE, over the union
760
783
  * of their declared relation fields (first declarer of a field name wins).
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { EffectExecutor } from './chunk-H7HQQVQJ.js';
2
- export { EffectExecutor, EventBus, HANDLER_MANIFEST, InMemoryPersistence, LIFECYCLE_EVENTS, MockPersistenceAdapter, StateMachineManager, TickScheduler, buildEmitsFromTraits, collectDeclaredConfigDefaults, collectDeclaredEntityDefaults, createInitialTraitState, createMockPersistence, createTestExecutor, createTickScheduler, createUnifiedLoader, findInitialState, findTransition, formatPayloadValidationError, getIsolatedCollectionName, getNamespacedEvent, isBrowser, isElectron, isNamespacedEvent, isNode, isValidDurationString, normalizeCallSiteConfigToValues, normalizeEventKey, parseDurationString, parseNamespacedEvent, preprocessSchema, processEvent, validateEventPayload, validatePayloadShapes } from './chunk-H7HQQVQJ.js';
1
+ import { EffectExecutor } from './chunk-CEYC3Z2O.js';
2
+ export { EffectExecutor, EventBus, HANDLER_MANIFEST, InMemoryPersistence, LIFECYCLE_EVENTS, MockPersistenceAdapter, StateMachineManager, TickScheduler, buildEmitsFromTraits, collectDeclaredConfigDefaults, collectDeclaredEntityDefaults, createInitialTraitState, createMockPersistence, createTestExecutor, createTickScheduler, createUnifiedLoader, findInitialState, findTransition, formatPayloadValidationError, getIsolatedCollectionName, getNamespacedEvent, isBrowser, isElectron, isNamespacedEvent, isNode, isValidDurationString, normalizeCallSiteConfigToValues, normalizeEventKey, parseDurationString, parseNamespacedEvent, preprocessSchema, processEvent, validateEventPayload, validatePayloadShapes } from './chunk-CEYC3Z2O.js';
3
3
  export { cronMatches, cronMinuteKey, isValidCronExpression, parseCron, parseCronField } from './chunk-OU3ITB5S.js';
4
4
  import { createContextFromBindings, applyRowAccess, checkMutationAccess, accessDeniedMessage } from './chunk-ZWAOJT6R.js';
5
5
  export { applyRowAccess, checkMutationAccess, containsBindings, createContextFromBindings, createMinimalContext, deferEntityBindings, extractBindings, interpolateProps, interpolateValue } from './chunk-ZWAOJT6R.js';
@@ -68,7 +68,7 @@ function sendServerEvent(orbital, event, payload) {
68
68
  }
69
69
  }
70
70
  function createClientEffectHandlers(options) {
71
- const { eventBus, slotSetter, navigate, navigateBack, notify, sendServer, orbitalName = "" } = options;
71
+ const { eventBus, slotSetter, navigate, navigateBack, sendServer, orbitalName = "" } = options;
72
72
  return {
73
73
  emit: (event, payload) => {
74
74
  const prefixedEvent = event.startsWith("UI:") ? event : `UI:${event}`;
@@ -101,9 +101,6 @@ function createClientEffectHandlers(options) {
101
101
  navigateBack: navigateBack ?? (() => {
102
102
  log.warn("navigate-back-no-handler");
103
103
  }),
104
- notify: notify ?? ((msg, type) => {
105
- log.debug("notify", { type: type ?? null, message: msg });
106
- }),
107
104
  sendServer: sendServer ?? ((event, payload) => {
108
105
  sendServerEvent(orbitalName, event, payload);
109
106
  }),
@@ -240,8 +240,6 @@ interface EffectHandlers {
240
240
  /** Pop the orbital-scoped navigation stack and return to the previous
241
241
  * entry (client only). */
242
242
  navigateBack?: () => void;
243
- /** Show a notification (client: toast, server: log) */
244
- notify?: (message: string, type: 'success' | 'error' | 'warning' | 'info') => void;
245
243
  /** Log a message */
246
244
  log?: (message: string, level?: 'log' | 'warn' | 'error', data?: unknown) => void;
247
245
  /** Ref: declarative data subscription (server: same as fetch) */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/runtime",
3
- "version": "6.73.0",
3
+ "version": "6.75.0",
4
4
  "description": "Interpreted runtime for Almadar orbital applications (OrbitalServerRuntime)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -57,11 +57,11 @@
57
57
  "access": "public"
58
58
  },
59
59
  "dependencies": {
60
- "@almadar/core": "^10.88.0",
60
+ "@almadar/core": "^10.90.0",
61
61
  "@almadar/evaluator": "^2.45.0",
62
62
  "@almadar/logger": "^1.12.0",
63
- "@almadar/server": "^2.40.0",
64
- "@almadar/std": "^16.209.0"
63
+ "@almadar/server": "^2.41.0",
64
+ "@almadar/std": "^16.211.0"
65
65
  },
66
66
  "peerDependencies": {
67
67
  "express": "^5.0.0"