@almadar/runtime 6.38.0 → 6.39.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, E as EffectHandlers } from './types-Ca9e3aCT.js';
3
- import { EventPayload, EventId, EntityRow, Orbital, ServiceCallResult, TraitConfig, DeclaredTraitConfig, Entity, OrbitalSchema, Trait, PatternConfig, ResolvedPatternProps, SExpr, BusEventSource, 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, E as EffectHandlers } from './types-p_L8-Sk4.js';
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
  /**
6
6
  * EventBus - Platform-Agnostic Pub/Sub Implementation
@@ -137,6 +137,14 @@ interface ProcessEventOptions {
137
137
  * trait's `RegisteredOrbital.configByTrait`).
138
138
  */
139
139
  config?: ConfigContext;
140
+ /**
141
+ * Authenticated viewer for `@user.X` resolution inside guard expressions.
142
+ * The validator admits `@user` in guard context alongside `@config`; this
143
+ * is the runtime side of that contract. Without it a role gate
144
+ * (`when ["=", @user.role, "admin"]`) can never pass, because the guard's
145
+ * EvaluationContext has no user to compare against.
146
+ */
147
+ user?: UserContext;
140
148
  /**
141
149
  * Guard evaluation error handling mode. (RCG-02)
142
150
  * - "permissive": Guard errors allow the transition (default, backwards-compatible)
@@ -308,7 +316,7 @@ declare class StateMachineManager {
308
316
  *
309
317
  * @returns Array of transition results (one per trait that had a matching transition)
310
318
  */
311
- sendEvent(eventKey: string, payload?: EventPayload, entityData?: EntityRow, entityByTrait?: Record<string, EntityRow>, eventId?: EventId, targetTrait?: string): Array<{
319
+ sendEvent(eventKey: string, payload?: EventPayload, entityData?: EntityRow, entityByTrait?: Record<string, EntityRow>, eventId?: EventId, targetTrait?: string, user?: UserContext): Array<{
312
320
  traitName: string;
313
321
  result: TransitionResult;
314
322
  }>;
@@ -319,7 +327,7 @@ declare class StateMachineManager {
319
327
  * trait to process them sequentially (actor-model guarantee: one event
320
328
  * at a time per trait, effects fully awaited before the next event).
321
329
  */
322
- enqueueEvent(eventKey: string, payload?: EventPayload, entityData?: EntityRow, entityByTrait?: Record<string, EntityRow>, eventId?: EventId): void;
330
+ enqueueEvent(eventKey: string, payload?: EventPayload, entityData?: EntityRow, entityByTrait?: Record<string, EntityRow>, eventId?: EventId, user?: UserContext): void;
323
331
  /**
324
332
  * Drain a single (trait, entity) pair's event queue, processing
325
333
  * events sequentially. Pass `entityId` to drain a specific entity
@@ -952,13 +960,8 @@ interface OrbitalEventRequest {
952
960
  * initializer (R-SCOPED-LISTEN-INIT-RENAME-FREEZE re-fire cascade).
953
961
  */
954
962
  targetTrait?: string;
955
- /** User context for @user bindings (from Firebase auth) */
956
- user?: {
957
- uid: string;
958
- email?: string;
959
- displayName?: string;
960
- [key: string]: unknown;
961
- };
963
+ /** Provider claims for `@user` bindings, normalized by `normalizeUserContext`. */
964
+ user?: RawUserClaims;
962
965
  /** Per-tab client identity (UUID) — excludes this request's origin from live-broadcast delivery. */
963
966
  clientId?: string;
964
967
  }
@@ -1101,6 +1104,28 @@ interface OrbitalServerRuntimeConfig {
1101
1104
  * @almadar-io/rabit injects these at runtime; tests can inject mocks.
1102
1105
  */
1103
1106
  substrateServices?: SubstrateServices;
1107
+ /**
1108
+ * Viewer identity used when a request carries no authenticated user — the
1109
+ * persona a preview or verification run is looking at the app AS.
1110
+ *
1111
+ * `@user.id` / `@user.role` are what an app's ownership scoping and role
1112
+ * gates resolve against, so with no user every predicate takes its negative
1113
+ * branch and every owner filter matches nothing. A host that has real auth
1114
+ * leaves this unset and the request's own user always wins; a dev host
1115
+ * (playground, runtime-verify) sets it to make both branches reachable.
1116
+ *
1117
+ * Never a fallback for production auth: an authenticated request is not
1118
+ * overridden, and a host that sets this is declaring itself a dev host.
1119
+ */
1120
+ defaultUser?: UserContext;
1121
+ /**
1122
+ * Seeded columns that hold a user id, as `Entity.field` pairs (e.g.
1123
+ * `RosterEntry.memberId`). In mock mode the `defaultUser` is assigned to
1124
+ * every other seeded row of each named column, so a scoped view has real
1125
+ * rows and a second persona sees the complement. Explicit by design — the
1126
+ * seeder never guesses an owner column from its name.
1127
+ */
1128
+ mockOwnerFields?: string[];
1104
1129
  }
1105
1130
 
1106
1131
  declare class OrbitalServerRuntime {
@@ -1299,6 +1324,15 @@ declare class OrbitalServerRuntime {
1299
1324
  * every OTHER connected client; a fresh call replaces the previous sink.
1300
1325
  */
1301
1326
  setLiveBroadcastSink(sink: (item: LiveBroadcastItem) => void): void;
1327
+ /**
1328
+ * Switch the viewer a dev host presents the app as — see
1329
+ * `OrbitalServerRuntimeConfig.defaultUser`. Pass `undefined` for an
1330
+ * unauthenticated viewer. Takes effect on the next event; an authenticated
1331
+ * request still overrides it.
1332
+ */
1333
+ setDefaultUser(user: UserContext | undefined): void;
1334
+ /** The viewer a dev host is currently presenting the app as. */
1335
+ getDefaultUser(): UserContext | undefined;
1302
1336
  /**
1303
1337
  * Process an event for an orbital
1304
1338
  *
@@ -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-CrzdKD7O.js';
3
- import './types-Ca9e3aCT.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-C3TtYP6I.js';
3
+ import './types-p_L8-Sk4.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-RF7P73CR.js';
2
- export { InMemoryPersistence, collectDeclaredConfigDefaults } from './chunk-RF7P73CR.js';
1
+ import { createTickScheduler, EventBus, createUnifiedLoader, MockPersistenceAdapter, InMemoryPersistence, preprocessSchema, normalizeCallSiteConfigToValues, StateMachineManager, parseDurationString, createContextFromBindings, validateEventPayload, formatPayloadValidationError, collectDeclaredConfigDefaults, resolveCallSitePayloadCaptures, collectDeclaredEntityDefaults, EffectExecutor } from './chunk-WC5HVSMY.js';
2
+ export { InMemoryPersistence, collectDeclaredConfigDefaults } from './chunk-WC5HVSMY.js';
3
3
  import { isValidCronExpression } from './chunk-OU3ITB5S.js';
4
4
  import './chunk-OQJIK6PZ.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 { buildResolvedTraitConfigs, isInlineTrait, isEntityCall, applyListenPayloadMapping } from '@almadar/core';
10
+ import { buildResolvedTraitConfigs, isInlineTrait, isEntityCall, applyListenPayloadMapping, normalizeUserContext } from '@almadar/core';
11
11
 
12
12
  // src/identity/routing.ts
13
13
  function eventRouteKey(eventName, eventId) {
@@ -131,7 +131,12 @@ var OrbitalServerRuntime = class {
131
131
  this.persistence = new MockPersistenceAdapter({
132
132
  seed: config.mockSeed,
133
133
  defaultSeedCount: config.mockSeedCount ?? 6,
134
- debug: config.debug
134
+ debug: config.debug,
135
+ // Let the dev viewer own some seeded rows, so ownership-scoped views
136
+ // ("only mine") have data instead of being indistinguishable from a
137
+ // broken filter. Columns are declared, never inferred by name.
138
+ ownerId: config.defaultUser?.id,
139
+ ownerFields: config.mockOwnerFields
135
140
  });
136
141
  if (config.debug) {
137
142
  persistLog.debug("mock:init", { adapter: "MockPersistenceAdapter" });
@@ -726,7 +731,9 @@ var OrbitalServerRuntime = class {
726
731
  const ctx = createContextFromBindings({
727
732
  entity,
728
733
  payload: {},
729
- state: registered.manager.getState(traitName)?.currentState || "unknown"
734
+ state: registered.manager.getState(traitName)?.currentState || "unknown",
735
+ // A tick has no request user; only a dev host's ambient persona.
736
+ user: this.config.defaultUser
730
737
  }, false, this.config.contextExtensions);
731
738
  const guardPasses = evaluateGuard(
732
739
  tick.guard,
@@ -765,7 +772,8 @@ var OrbitalServerRuntime = class {
765
772
  emittedEvents,
766
773
  fetchedData,
767
774
  clientEffects,
768
- tickEffectResults
775
+ tickEffectResults,
776
+ this.config.defaultUser
769
777
  );
770
778
  if (this.config.debug) {
771
779
  effectLog.debug("tick:effects-executed", () => ({
@@ -848,6 +856,19 @@ var OrbitalServerRuntime = class {
848
856
  setLiveBroadcastSink(sink) {
849
857
  this.liveBroadcastSink = sink;
850
858
  }
859
+ /**
860
+ * Switch the viewer a dev host presents the app as — see
861
+ * `OrbitalServerRuntimeConfig.defaultUser`. Pass `undefined` for an
862
+ * unauthenticated viewer. Takes effect on the next event; an authenticated
863
+ * request still overrides it.
864
+ */
865
+ setDefaultUser(user) {
866
+ this.config.defaultUser = user;
867
+ }
868
+ /** The viewer a dev host is currently presenting the app as. */
869
+ getDefaultUser() {
870
+ return this.config.defaultUser;
871
+ }
851
872
  // ==========================================================================
852
873
  // Event Processing
853
874
  // ==========================================================================
@@ -903,7 +924,8 @@ var OrbitalServerRuntime = class {
903
924
  request.payload?.["_activeTraits"] ?? null
904
925
  )
905
926
  }));
906
- const { event, eventId, payload, entityId, user, clientId } = request;
927
+ const { event, eventId, payload, entityId, user: requestUser, clientId } = request;
928
+ const viewer = normalizeUserContext(requestUser) ?? this.config.defaultUser;
907
929
  const targetTrait = request.targetTrait ?? payload?.["_targetTrait"];
908
930
  const validationFailures = [];
909
931
  for (const trait of registered.traits) {
@@ -956,7 +978,8 @@ var OrbitalServerRuntime = class {
956
978
  entityData,
957
979
  entityByTrait,
958
980
  eventId,
959
- targetTrait
981
+ targetTrait,
982
+ viewer
960
983
  );
961
984
  const filteredResults = activeTraits && activeTraits.length > 0 ? results.filter(({ traitName }) => activeTraits.includes(traitName)) : results;
962
985
  if (this.config.debug && activeTraits) {
@@ -979,7 +1002,7 @@ var OrbitalServerRuntime = class {
979
1002
  fetchedData,
980
1003
  clientEffects,
981
1004
  effectResults,
982
- user,
1005
+ viewer,
983
1006
  clientEffectsByTrait,
984
1007
  onPush,
985
1008
  clientId
@@ -1313,7 +1336,7 @@ var OrbitalServerRuntime = class {
1313
1336
  const predicate = options.filter;
1314
1337
  entities = entities.filter((entity) => {
1315
1338
  const ctx = createContextFromBindings(
1316
- { entity, payload: bindingsRef?.payload, current: entity },
1339
+ { entity, payload: bindingsRef?.payload, current: entity, user: bindingsRef?.user },
1317
1340
  false
1318
1341
  );
1319
1342
  try {
@@ -1531,7 +1554,6 @@ var OrbitalServerRuntime = class {
1531
1554
  payload,
1532
1555
  state: state?.currentState || "unknown",
1533
1556
  user
1534
- // @user bindings from Firebase auth
1535
1557
  };
1536
1558
  const traitDef = registered.traits.find((t) => t.name === traitName);
1537
1559
  const declaredDefaults = collectDeclaredConfigDefaults(traitDef);
@@ -1,4 +1,4 @@
1
- import { I as IEventBus } from './types-Ca9e3aCT.js';
1
+ import { I as IEventBus } from './types-p_L8-Sk4.js';
2
2
  import { EventPayload } from '@almadar/core';
3
3
 
4
4
  /**
@@ -523,6 +523,9 @@ function createContextFromBindings(bindings, strictBindings, contextExtensions)
523
523
  if (bindings.config) {
524
524
  ctx.config = bindings.config;
525
525
  }
526
+ if (bindings.user) {
527
+ ctx.user = bindings.user;
528
+ }
526
529
  if (bindings.locals) {
527
530
  ctx.locals = bindings.locals;
528
531
  }
@@ -579,6 +582,7 @@ function processEvent(options) {
579
582
  payload,
580
583
  entityData,
581
584
  config,
585
+ user,
582
586
  guardMode = "permissive",
583
587
  strictBindings = false,
584
588
  contextExtensions
@@ -619,7 +623,8 @@ function processEvent(options) {
619
623
  // list as of v3.12.0). createContextFromBindings already
620
624
  // propagates `bindings.config` to ctx.config when present —
621
625
  // we just need to pass it through here.
622
- config
626
+ config,
627
+ user
623
628
  }, strictBindings, contextExtensions);
624
629
  try {
625
630
  const guardPasses = evaluateGuard(
@@ -956,7 +961,7 @@ var StateMachineManager = class {
956
961
  *
957
962
  * @returns Array of transition results (one per trait that had a matching transition)
958
963
  */
959
- sendEvent(eventKey, payload, entityData, entityByTrait, eventId, targetTrait) {
964
+ sendEvent(eventKey, payload, entityData, entityByTrait, eventId, targetTrait, user) {
960
965
  const results = [];
961
966
  const scope = scopeOf(entityData);
962
967
  for (const [traitName, trait] of this.traits) {
@@ -973,6 +978,7 @@ var StateMachineManager = class {
973
978
  payload,
974
979
  entityData: perTraitEntity,
975
980
  config: this.traitConfigs.get(traitName),
981
+ user,
976
982
  guardMode: this.config.guardMode,
977
983
  strictBindings: this.config.strictBindings,
978
984
  contextExtensions: this.config.contextExtensions
@@ -1011,12 +1017,12 @@ var StateMachineManager = class {
1011
1017
  * trait to process them sequentially (actor-model guarantee: one event
1012
1018
  * at a time per trait, effects fully awaited before the next event).
1013
1019
  */
1014
- enqueueEvent(eventKey, payload, entityData, entityByTrait, eventId) {
1020
+ enqueueEvent(eventKey, payload, entityData, entityByTrait, eventId, user) {
1015
1021
  const scope = scopeOf(entityData);
1016
1022
  for (const [traitName] of this.traits) {
1017
1023
  const key = compositeKey(traitName, scope);
1018
1024
  const queue = this.queues.get(key) ?? [];
1019
- queue.push({ eventKey, eventId, payload, entityData, entityByTrait });
1025
+ queue.push({ eventKey, eventId, payload, entityData, entityByTrait, user });
1020
1026
  this.queues.set(key, queue);
1021
1027
  }
1022
1028
  }
@@ -1045,6 +1051,7 @@ var StateMachineManager = class {
1045
1051
  payload: entry.payload,
1046
1052
  entityData: perTraitEntity,
1047
1053
  config: this.traitConfigs.get(traitName),
1054
+ user: entry.user,
1048
1055
  guardMode: this.config.guardMode,
1049
1056
  strictBindings: this.config.strictBindings,
1050
1057
  contextExtensions: this.config.contextExtensions
@@ -2459,9 +2466,14 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
2459
2466
  if (this.config.debug) {
2460
2467
  mockLog.debug("seeding", { count, entity: entityName });
2461
2468
  }
2469
+ const ownerCols = (this.config.ownerFields ?? []).map((pair) => pair.split(".")).filter(([ent]) => ent?.toLowerCase() === normalized).map(([, field]) => field).filter((field) => Boolean(field));
2470
+ const ownerId = this.config.ownerId;
2462
2471
  const generated = [];
2463
2472
  for (let i = 0; i < count; i++) {
2464
2473
  const item = this.generateMockItem(normalized, entityName, fields, i + 1);
2474
+ if (ownerId && ownerCols.length > 0 && i % 2 === 0) {
2475
+ for (const col of ownerCols) item[col] = ownerId;
2476
+ }
2465
2477
  store.set(item.id, item);
2466
2478
  generated.push({
2467
2479
  id: item.id,
@@ -1,4 +1,4 @@
1
- import { E as EffectHandlers } from './types-Ca9e3aCT.js';
1
+ import { E as EffectHandlers } from './types-p_L8-Sk4.js';
2
2
  import { EventPayload } from '@almadar/core';
3
3
 
4
4
  /**
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
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-Ca9e3aCT.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-Ca9e3aCT.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-CrzdKD7O.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-CrzdKD7O.js';
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-C3TtYP6I.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-C3TtYP6I.js';
5
5
  import { EvaluationContext, SExpressionEvaluator } from '@almadar/evaluator';
6
6
  export { EvaluationContext, createMinimalContext } from '@almadar/evaluator';
7
7
  import { TraitConfigObject, EventPayload, PatternConfig, EntityId, EntityField, EntityRow, ServiceParams, PayloadField, OrbitalDefinition, OrbitalSchema } from '@almadar/core';
@@ -553,6 +553,21 @@ interface MockPersistenceConfig {
553
553
  defaultSeedCount?: number;
554
554
  /** Enable debug logging */
555
555
  debug?: boolean;
556
+ /**
557
+ * Make the signed-in viewer own some of the seeded rows.
558
+ *
559
+ * An ownership-scoped view (`only my bookings`, `my prescriptions`) filters
560
+ * rows by `@user.id`. Faker-seeded owner columns hold random ids, so such a
561
+ * view is ALWAYS empty in mock mode and cannot be told apart from a broken
562
+ * filter — the exact ambiguity that cost this campaign a debugging cycle.
563
+ *
564
+ * `ownerFields` names the columns that hold a user id, as `Entity.field`
565
+ * pairs — declared explicitly, never inferred from a field's name. Every
566
+ * other seeded row is assigned `ownerId`, so a scoped view has real data AND
567
+ * the scoping stays observable (a second persona sees the complement).
568
+ */
569
+ ownerId?: string;
570
+ ownerFields?: string[];
556
571
  }
557
572
  /**
558
573
  * In-memory mock data store with CRUD operations and seeded mock generation.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { EffectExecutor, createContextFromBindings } from './chunk-RF7P73CR.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-RF7P73CR.js';
1
+ import { EffectExecutor, createContextFromBindings } from './chunk-WC5HVSMY.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-WC5HVSMY.js';
3
3
  export { cronMatches, cronMinuteKey, isValidCronExpression, parseCron, parseCronField } from './chunk-OU3ITB5S.js';
4
4
  import './chunk-OQJIK6PZ.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-O5VGKPTG.js';
@@ -1,5 +1,5 @@
1
1
  import * as _almadar_core from '@almadar/core';
2
- import { TraitId, EventId, SExpr, TraitEventListener, AgentContext, LlmContext, WorkspaceContext, SessionContext, MemoryContext, TraceContext, IntegrationContext, TraitConfig, EventPayload, BusEvent, EntityRow, FieldValue, ServiceParams, FetchResult, PatternConfig, ResolvedPatternProps, Orbital, ServiceCallResult, BusEventSource, BusEventListener, Unsubscribe as Unsubscribe$1 } from '@almadar/core';
2
+ import { TraitId, EventId, SExpr, TraitEventListener, AgentContext, LlmContext, WorkspaceContext, SessionContext, MemoryContext, TraceContext, IntegrationContext, TraitConfig, EventPayload, BusEvent, EntityRow, FieldValue, ServiceParams, FetchResult, PatternConfig, ResolvedPatternProps, Orbital, ServiceCallResult, BusEventSource, BusEventListener, Unsubscribe as Unsubscribe$1, UserContext } from '@almadar/core';
3
3
 
4
4
  /** Alias for ResolvedPatternProps to avoid breaking internal consumers */
5
5
  type PatternProps = ResolvedPatternProps;
@@ -305,6 +305,8 @@ interface BindingContext {
305
305
  state?: string;
306
306
  /** Trait-level state/config */
307
307
  config?: ConfigContext;
308
+ /** Authenticated viewer behind `@user.x` — ownership (`@user.id`) and role gates. */
309
+ user?: UserContext;
308
310
  /**
309
311
  * Local variables introduced by a `let` form, keyed by bare name and
310
312
  * referenced via `@<name>` (the canonical evaluator convention — same as
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/runtime",
3
- "version": "6.38.0",
3
+ "version": "6.39.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.35.0",
56
- "@almadar/evaluator": "^2.36.0",
55
+ "@almadar/core": "^10.36.0",
56
+ "@almadar/evaluator": "^2.37.0",
57
57
  "@almadar/logger": "^1.10.0",
58
- "@almadar/server": "^2.27.0",
59
- "@almadar/std": "^16.145.0"
58
+ "@almadar/server": "^2.28.0",
59
+ "@almadar/std": "^16.146.0"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "express": "^5.0.0"