@almadar/runtime 6.43.0 → 6.44.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.
@@ -1199,6 +1199,14 @@ declare class OrbitalServerRuntime {
1199
1199
  * std registry on disk.
1200
1200
  */
1201
1201
  register(schema: OrbitalSchema): Promise<void>;
1202
+ /**
1203
+ * Teach the mock seeder which columns hold the viewer's id, derived from the
1204
+ * schema's `[identity]` entity. No-op for a program that declares none, so
1205
+ * unmigrated apps seed exactly as before. Mirrors
1206
+ * `orbital-core/src/runtime/seed.rs::owner_fields_from_schema` — a feature
1207
+ * that lives on only one execution path is not a feature.
1208
+ */
1209
+ private applyIdentityOwnerFields;
1202
1210
  /**
1203
1211
  * Register an OrbitalSchema synchronously (for backward compatibility).
1204
1212
  * Note: This version doesn't wait for instance seeding to complete.
@@ -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-f0EZSw4f.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-Dz0oubQ_.js';
3
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-2SM626PK.js';
2
- export { InMemoryPersistence, collectDeclaredConfigDefaults } from './chunk-2SM626PK.js';
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';
3
3
  import { isValidCronExpression } from './chunk-OU3ITB5S.js';
4
4
  import './chunk-T4VDAB4C.js';
5
5
  import './chunk-SCRAHWOC.js';
@@ -7,7 +7,8 @@ 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, normalizeUserContext } from '@almadar/core';
10
+ import { DEFAULT_VIEWER, buildResolvedTraitConfigs, isInlineTrait, isEntityCall, applyListenPayloadMapping, normalizeUserContext } from '@almadar/core';
11
+ import { ownerFieldsFromSchema, identityEntityName } from '@almadar/core/mock';
11
12
 
12
13
  // src/identity/routing.ts
13
14
  function eventRouteKey(eventName, eventId) {
@@ -115,7 +116,12 @@ var OrbitalServerRuntime = class {
115
116
  // Default to mock mode for preview
116
117
  autoPreprocess: false,
117
118
  namespaceEvents: true,
118
- ...config
119
+ ...config,
120
+ // `@user` is never Null. A host that named no viewer (no ALMADAR_PERSONA,
121
+ // no auth yet) otherwise renders every `viewerName: @user.name` blank, so
122
+ // the app cannot say who you are. DEFAULT_VIEWER carries an empty `role`,
123
+ // so no `@user.role` guard changes outcome — see its doc in @almadar/core.
124
+ defaultUser: config.defaultUser ?? DEFAULT_VIEWER
119
125
  };
120
126
  this.eventBus = new EventBus();
121
127
  if (config.loaderConfig?.loader) {
@@ -135,7 +141,9 @@ var OrbitalServerRuntime = class {
135
141
  // Let the dev viewer own some seeded rows, so ownership-scoped views
136
142
  // ("only mine") have data instead of being indistinguishable from a
137
143
  // broken filter. Columns are declared, never inferred by name.
138
- ownerId: config.defaultUser?.id,
144
+ // `this.config`, not `config` — the DEFAULT_VIEWER fallback is applied
145
+ // there, and reading the raw param leaves every seeded row unowned.
146
+ ownerId: this.config.defaultUser?.id,
139
147
  ownerFields: config.mockOwnerFields
140
148
  });
141
149
  if (config.debug) {
@@ -293,6 +301,7 @@ var OrbitalServerRuntime = class {
293
301
  registerLog.warn("register:no-loader", { name: schema.name });
294
302
  }
295
303
  }
304
+ this.applyIdentityOwnerFields(schema);
296
305
  for (const orbital of schema.orbitals) {
297
306
  await this.registerOrbitalAsync(orbital);
298
307
  }
@@ -301,6 +310,23 @@ var OrbitalServerRuntime = class {
301
310
  this.resolvedSchema = schema;
302
311
  this.resolvedTraitConfigs = buildResolvedTraitConfigs(schema);
303
312
  }
313
+ /**
314
+ * Teach the mock seeder which columns hold the viewer's id, derived from the
315
+ * schema's `[identity]` entity. No-op for a program that declares none, so
316
+ * unmigrated apps seed exactly as before. Mirrors
317
+ * `orbital-core/src/runtime/seed.rs::owner_fields_from_schema` — a feature
318
+ * that lives on only one execution path is not a feature.
319
+ */
320
+ applyIdentityOwnerFields(schema) {
321
+ if (!(this.persistence instanceof MockPersistenceAdapter)) return;
322
+ const derived = ownerFieldsFromSchema(schema);
323
+ if (derived.length === 0) return;
324
+ this.persistence.addOwnerFields(derived);
325
+ persistLog.debug("mock:identity-owner-fields", {
326
+ identity: identityEntityName(schema),
327
+ columns: derived
328
+ });
329
+ }
304
330
  /**
305
331
  * Register an OrbitalSchema synchronously (for backward compatibility).
306
332
  * Note: This version doesn't wait for instance seeding to complete.
@@ -310,6 +336,7 @@ var OrbitalServerRuntime = class {
310
336
  if (this.config.debug) {
311
337
  registerLog.debug("register:schema-sync", { name: schema.name });
312
338
  }
339
+ this.applyIdentityOwnerFields(schema);
313
340
  for (const orbital of schema.orbitals) {
314
341
  this.registerOrbital(orbital);
315
342
  }
@@ -317,6 +344,7 @@ var OrbitalServerRuntime = class {
317
344
  this.setupTicks();
318
345
  this.resolvedSchema = schema;
319
346
  this.resolvedTraitConfigs = buildResolvedTraitConfigs(schema);
347
+ this.applyIdentityOwnerFields(schema);
320
348
  }
321
349
  /**
322
350
  * Returns the schema that this runtime is currently executing, post-
@@ -2346,6 +2346,22 @@ var MockPersistenceAdapter = class {
2346
2346
  seedRandom(this.config.seed);
2347
2347
  mockLog.debug("mock:adapter:init", { seed: this.config.seed });
2348
2348
  }
2349
+ /**
2350
+ * Add owner columns discovered after construction.
2351
+ *
2352
+ * The adapter is built before any schema is registered, so schema-DERIVED
2353
+ * owner columns (relation fields pointing at the `[identity]` entity) can
2354
+ * only arrive later.
2355
+ *
2356
+ * ⚠️ Seeding is EAGER — `registerEntity()` seeds immediately — so callers must
2357
+ * supply these columns BEFORE registering any orbital. Calling this afterwards
2358
+ * silently stamps nothing.
2359
+ */
2360
+ addOwnerFields(fields) {
2361
+ if (fields.length === 0) return;
2362
+ const merged = /* @__PURE__ */ new Set([...this.config.ownerFields ?? [], ...fields]);
2363
+ this.config.ownerFields = [...merged];
2364
+ }
2349
2365
  /** Re-anchor the PRNG to the configured seed. Called before every
2350
2366
  * re-seed loop so identical reseed sequences produce identical rows
2351
2367
  * (timestamps + generated fields). Without this, the first
@@ -2422,6 +2438,9 @@ var MockPersistenceAdapter = class {
2422
2438
  if (relationFields.length === 0) continue;
2423
2439
  for (const row of store.values()) {
2424
2440
  for (const field of relationFields) {
2441
+ if (this.config.ownerId !== void 0 && row[field.name] === this.config.ownerId) {
2442
+ continue;
2443
+ }
2425
2444
  const targetNormalized = (field.relation.entityId && this.storeNameById.get(field.relation.entityId)) ?? field.relation.entity.toLowerCase();
2426
2445
  const targetStore = this.stores.get(targetNormalized);
2427
2446
  if (!targetStore || targetStore.size === 0) continue;
@@ -3642,6 +3661,96 @@ function renameEntityInEffect(effect, rename, props) {
3642
3661
  }
3643
3662
  return effect;
3644
3663
  }
3664
+ var TRAIT_EMBED_PREFIX = "@trait.";
3665
+ function renameTraitEmbedsInValue(node, subs) {
3666
+ if (node === null || node === void 0) return node;
3667
+ if (typeof node === "string") {
3668
+ if (!node.startsWith(TRAIT_EMBED_PREFIX)) return node;
3669
+ const rest = node.slice(TRAIT_EMBED_PREFIX.length);
3670
+ const dot = rest.search(/[.[]/);
3671
+ const name = dot === -1 ? rest : rest.slice(0, dot);
3672
+ const suffix = dot === -1 ? "" : rest.slice(dot);
3673
+ const to = subs.get(name);
3674
+ return to === void 0 ? node : `${TRAIT_EMBED_PREFIX}${to}${suffix}`;
3675
+ }
3676
+ if (Array.isArray(node)) return node.map((item) => renameTraitEmbedsInValue(item, subs));
3677
+ if (typeof node !== "object") return node;
3678
+ const next = {};
3679
+ for (const [key, value] of Object.entries(node)) {
3680
+ next[key] = renameTraitEmbedsInValue(value, subs);
3681
+ }
3682
+ return next;
3683
+ }
3684
+ function renameTraitEmbeds(trait, subs) {
3685
+ if (subs.size === 0) return trait;
3686
+ const sm = trait.stateMachine;
3687
+ const next = { ...trait };
3688
+ if (sm) {
3689
+ next.stateMachine = {
3690
+ ...sm,
3691
+ transitions: (sm.transitions ?? []).map(
3692
+ (t) => t.effects ? { ...t, effects: renameTraitEmbedsInValue(t.effects, subs) } : t
3693
+ )
3694
+ };
3695
+ }
3696
+ if (trait.ticks) {
3697
+ next.ticks = trait.ticks.map(
3698
+ (tick) => tick.effects ? { ...tick, effects: renameTraitEmbedsInValue(tick.effects, subs) } : tick
3699
+ );
3700
+ }
3701
+ if (trait.config) {
3702
+ const nextConfig = {};
3703
+ for (const [key, field] of Object.entries(trait.config)) {
3704
+ nextConfig[key] = field.default === void 0 ? field : {
3705
+ ...field,
3706
+ default: renameTraitEmbedsInValue(
3707
+ field.default,
3708
+ subs
3709
+ )
3710
+ };
3711
+ }
3712
+ next.config = nextConfig;
3713
+ }
3714
+ return next;
3715
+ }
3716
+ function findTraitEntryInOrbital(orbital, localName) {
3717
+ for (const traitRef of orbital.traits ?? []) {
3718
+ if (typeof traitRef === "string") continue;
3719
+ if ("stateMachine" in traitRef) {
3720
+ if (traitRef.name === localName) return traitRef;
3721
+ continue;
3722
+ }
3723
+ if (!("ref" in traitRef)) continue;
3724
+ const refObj = traitRef;
3725
+ const declared = refObj.name ?? parseImportedTraitRef(refObj.ref)?.traitName;
3726
+ if (declared === localName) return traitRef;
3727
+ }
3728
+ return null;
3729
+ }
3730
+ function traitEmbedNamesOf(trait) {
3731
+ const found = /* @__PURE__ */ new Set();
3732
+ const walk = (node) => {
3733
+ if (node === null || node === void 0) return;
3734
+ if (typeof node === "string") {
3735
+ if (!node.startsWith(TRAIT_EMBED_PREFIX)) return;
3736
+ const rest = node.slice(TRAIT_EMBED_PREFIX.length);
3737
+ const dot = rest.search(/[.[]/);
3738
+ const name = dot === -1 ? rest : rest.slice(0, dot);
3739
+ if (name.length > 0) found.add(name);
3740
+ return;
3741
+ }
3742
+ if (Array.isArray(node)) {
3743
+ for (const item of node) walk(item);
3744
+ return;
3745
+ }
3746
+ if (typeof node !== "object") return;
3747
+ for (const value of Object.values(node)) walk(value);
3748
+ };
3749
+ for (const t of trait.stateMachine?.transitions ?? []) walk(t.effects);
3750
+ for (const tick of trait.ticks ?? []) walk(tick.effects);
3751
+ for (const field of Object.values(trait.config ?? {})) walk(field.default);
3752
+ return [...found];
3753
+ }
3645
3754
  function applyLinkedEntityRename(trait, linkedEntity) {
3646
3755
  const atomLinked = trait.linkedEntity;
3647
3756
  if (!linkedEntity || !atomLinked || linkedEntity === atomLinked) return trait;
@@ -3813,6 +3922,8 @@ var ReferenceResolver = class {
3813
3922
  localTraits;
3814
3923
  /** id-keyed mirror of `localTraits`, populated wherever the trait carries an `id`. */
3815
3924
  localTraitsById = /* @__PURE__ */ new Map();
3925
+ /** Import scope of each loaded source orbital, keyed by its source path. */
3926
+ sourceImportsCache = /* @__PURE__ */ new Map();
3816
3927
  loaderInitialized = false;
3817
3928
  constructor(options) {
3818
3929
  this.options = options;
@@ -3869,6 +3980,10 @@ var ReferenceResolver = class {
3869
3980
  if (!entityResult.success || !traitsResult.success || !pagesResult.success) {
3870
3981
  return { success: false, errors: ["Internal error: unexpected failure state"] };
3871
3982
  }
3983
+ const pullErrors = await this.pullSiblingTraits(traitsResult.data, imports, importChain);
3984
+ if (pullErrors.length > 0) {
3985
+ return { success: false, errors: pullErrors };
3986
+ }
3872
3987
  for (const resolvedTrait of traitsResult.data) {
3873
3988
  resolvedTrait.trait = resolveEntityTokensById(resolvedTrait.trait, imports.idIndex);
3874
3989
  resolvedTrait.trait = resolveConfigRefsById(resolvedTrait.trait, imports.idIndex);
@@ -4042,6 +4157,191 @@ var ReferenceResolver = class {
4042
4157
  }
4043
4158
  return { success: true, data: resolved, warnings: [] };
4044
4159
  }
4160
+ /**
4161
+ * The import scope of an already-loaded orbital, memoised per source path.
4162
+ * A sibling that is itself a ref names its target through the SOURCE atom's
4163
+ * aliases, so it can only be resolved against those.
4164
+ */
4165
+ async importsOfSource(imported, chain) {
4166
+ const key = imported.sourcePath ?? `${imported.alias}:${imported.from}`;
4167
+ const cached = this.sourceImportsCache.get(key);
4168
+ if (cached) return cached;
4169
+ const result = await this.resolveImports(
4170
+ imported.orbital.uses ?? [],
4171
+ imported.sourcePath,
4172
+ chain
4173
+ );
4174
+ if (!result.success) return null;
4175
+ result.data.idIndex = buildIdIndex(imported.orbital, result.data.orbitals);
4176
+ this.sourceImportsCache.set(key, result.data);
4177
+ return result.data;
4178
+ }
4179
+ /**
4180
+ * Sibling-trait auto-pull — the JS twin of the compiler's
4181
+ * `phases/inline/trait.rs` pass, appending to `resolved` in place.
4182
+ *
4183
+ * An atom's main trait embeds its own sub-views as `@trait.<Sibling>` string
4184
+ * literals (`std-browse`'s `bodyContent: {children: [@trait.DataGrid1]}`).
4185
+ * A consumer that imports only the main trait never instantiates those
4186
+ * siblings, so the token dangles: no state machine, no fetch, an empty list
4187
+ * where the grid should be. The compiled path materialises them; without this
4188
+ * pass the interpreted path did not, so a raw `.orb` handed straight to
4189
+ * `OrbitalServerRuntime` rendered a different app than the same `.orb` run
4190
+ * through `orbital resolve`.
4191
+ *
4192
+ * Pulls are keyed per EMBEDDER (`owner` = the top-level consumer trait that
4193
+ * started the chain), not per atom. Two rebinds of one atom in one orbital
4194
+ * (`ChannelRail -> Channel` and `ChatThread -> ChatMessage`, both std-browse)
4195
+ * carry different entity rebinds and different hosts to listen to, so one
4196
+ * shared copy can only ever serve one of them. The first owner keeps the
4197
+ * source name; later owners pull under `<Owner><Sibling>` — unique by
4198
+ * construction, since owner names are unique within the orbital.
4199
+ */
4200
+ async pullSiblingTraits(resolved, imports, chain) {
4201
+ const work = [];
4202
+ const ownerSubs = /* @__PURE__ */ new Map();
4203
+ const subsFor = (owner) => {
4204
+ let m = ownerSubs.get(owner);
4205
+ if (!m) {
4206
+ m = /* @__PURE__ */ new Map();
4207
+ ownerSubs.set(owner, m);
4208
+ }
4209
+ return m;
4210
+ };
4211
+ for (const rt of resolved) {
4212
+ if (rt.source.type !== "imported" || !rt.trait.name) continue;
4213
+ const owner = rt.trait.name;
4214
+ subsFor(owner).set(rt.source.traitName, owner);
4215
+ for (const sibling of traitEmbedNamesOf(rt.trait)) {
4216
+ work.push({ alias: rt.source.alias, sibling, linkedEntity: rt.linkedEntity, parent: owner, owner });
4217
+ }
4218
+ }
4219
+ if (work.length === 0) return [];
4220
+ const errors = [];
4221
+ const consumerDeclared = new Set(resolved.map((r) => r.trait.name).filter(Boolean));
4222
+ const seen = new Set(consumerDeclared);
4223
+ const visited = /* @__PURE__ */ new Set();
4224
+ const pulledAs = /* @__PURE__ */ new Map();
4225
+ const ownerOf = /* @__PURE__ */ new Map();
4226
+ const parentRewrites = /* @__PURE__ */ new Map();
4227
+ const pulled = [];
4228
+ const noteRewrite = (parent, from, to) => {
4229
+ let m = parentRewrites.get(parent);
4230
+ if (!m) {
4231
+ m = /* @__PURE__ */ new Map();
4232
+ parentRewrites.set(parent, m);
4233
+ }
4234
+ m.set(from, to);
4235
+ };
4236
+ for (let item = work.pop(); item !== void 0; item = work.pop()) {
4237
+ const { alias, sibling, linkedEntity, parent, owner } = item;
4238
+ const pullKey = `${alias}\0${sibling}\0${owner}`;
4239
+ const existing = pulledAs.get(pullKey);
4240
+ if (existing !== void 0) {
4241
+ if (existing !== sibling) noteRewrite(parent, sibling, existing);
4242
+ continue;
4243
+ }
4244
+ let finalName = sibling;
4245
+ if (seen.has(sibling)) {
4246
+ if (consumerDeclared.has(sibling)) continue;
4247
+ finalName = `${owner}${sibling}`;
4248
+ if (seen.has(finalName)) continue;
4249
+ }
4250
+ if (visited.has(pullKey)) continue;
4251
+ visited.add(pullKey);
4252
+ const imported = imports.orbitals.get(alias);
4253
+ if (!imported) continue;
4254
+ const atomEntry = findTraitEntryInOrbital(imported.orbital, sibling);
4255
+ if (!atomEntry) continue;
4256
+ let atomTrait;
4257
+ if ("stateMachine" in atomEntry) {
4258
+ const { trait: cfgResolved, errors: cfgErrors } = resolveConfigRefEmitNames(
4259
+ atomEntry
4260
+ );
4261
+ if (cfgErrors.length > 0) {
4262
+ errors.push(...cfgErrors);
4263
+ continue;
4264
+ }
4265
+ atomTrait = cfgResolved;
4266
+ } else {
4267
+ const srcImports = await this.importsOfSource(imported, chain);
4268
+ if (!srcImports) continue;
4269
+ const refObj = atomEntry;
4270
+ const nested = this.resolveTraitRefString(
4271
+ refObj.ref,
4272
+ srcImports,
4273
+ refObj.config,
4274
+ refObj.linkedEntity,
4275
+ refObj.name ?? sibling,
4276
+ refObj.events,
4277
+ refObj.listens,
4278
+ refObj.refId
4279
+ );
4280
+ if (!nested.success) {
4281
+ errors.push(...nested.errors);
4282
+ continue;
4283
+ }
4284
+ atomTrait = nested.data.trait;
4285
+ }
4286
+ let copy = applyLinkedEntityRename(atomTrait, linkedEntity);
4287
+ if (finalName !== sibling) {
4288
+ copy = { ...copy, name: finalName };
4289
+ noteRewrite(parent, sibling, finalName);
4290
+ }
4291
+ for (const next of traitEmbedNamesOf(copy)) {
4292
+ work.push({ alias, sibling: next, linkedEntity, parent: finalName, owner });
4293
+ }
4294
+ pulledAs.set(pullKey, finalName);
4295
+ subsFor(owner).set(sibling, finalName);
4296
+ ownerOf.set(finalName, owner);
4297
+ seen.add(finalName);
4298
+ pulled.push({
4299
+ trait: copy,
4300
+ source: { type: "imported", alias, traitName: sibling },
4301
+ ...linkedEntity !== void 0 ? { linkedEntity } : {}
4302
+ });
4303
+ }
4304
+ if (pulled.length === 0 && parentRewrites.size === 0) return errors;
4305
+ const applyRewrites = (rt) => {
4306
+ const subs = rt.trait.name ? parentRewrites.get(rt.trait.name) : void 0;
4307
+ if (subs) rt.trait = renameTraitEmbeds(rt.trait, subs);
4308
+ };
4309
+ for (const rt of resolved) applyRewrites(rt);
4310
+ for (const rt of pulled) applyRewrites(rt);
4311
+ const idByName = /* @__PURE__ */ new Map();
4312
+ for (const rt of [...resolved, ...pulled]) {
4313
+ if (rt.trait.name) idByName.set(rt.trait.name, rt.trait.id);
4314
+ }
4315
+ for (const rt of pulled) {
4316
+ const listens = rt.trait.listens;
4317
+ const owner = rt.trait.name ? ownerOf.get(rt.trait.name) : void 0;
4318
+ const subs = owner ? ownerSubs.get(owner) : void 0;
4319
+ if (!listens || listens.length === 0 || !subs) continue;
4320
+ let changed = false;
4321
+ const nextListens = listens.map((listen) => {
4322
+ const source = listen.source;
4323
+ if (!source || source.kind !== "trait") return listen;
4324
+ const target = subs.get(source.trait);
4325
+ if (target === void 0 || target === source.trait) return listen;
4326
+ changed = true;
4327
+ const traitId = idByName.get(target);
4328
+ return {
4329
+ ...listen,
4330
+ source: { kind: "trait", trait: target, ...traitId ? { traitId } : {} }
4331
+ };
4332
+ });
4333
+ if (changed) rt.trait = { ...rt.trait, listens: nextListens };
4334
+ }
4335
+ refResolverLog.info("sibling-pull", {
4336
+ pulled: pulled.map((p) => ({
4337
+ trait: p.trait.name,
4338
+ owner: p.trait.name ? ownerOf.get(p.trait.name) : void 0,
4339
+ linkedEntity: p.linkedEntity ?? p.trait.linkedEntity
4340
+ }))
4341
+ });
4342
+ resolved.push(...pulled);
4343
+ return errors;
4344
+ }
4045
4345
  /**
4046
4346
  * Resolve a single trait reference.
4047
4347
  */
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
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
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-f0EZSw4f.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-f0EZSw4f.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';
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, EntityPersistence, ServiceParams, PayloadField, OrbitalDefinition, OrbitalSchema } from '@almadar/core';
@@ -585,6 +585,18 @@ declare class MockPersistenceAdapter implements PersistenceAdapter {
585
585
  private storeNameById;
586
586
  private config;
587
587
  constructor(config?: MockPersistenceConfig);
588
+ /**
589
+ * Add owner columns discovered after construction.
590
+ *
591
+ * The adapter is built before any schema is registered, so schema-DERIVED
592
+ * owner columns (relation fields pointing at the `[identity]` entity) can
593
+ * only arrive later.
594
+ *
595
+ * ⚠️ Seeding is EAGER — `registerEntity()` seeds immediately — so callers must
596
+ * supply these columns BEFORE registering any orbital. Calling this afterwards
597
+ * silently stamps nothing.
598
+ */
599
+ addOwnerFields(fields: readonly string[]): void;
588
600
  /** Re-anchor the PRNG to the configured seed. Called before every
589
601
  * re-seed loop so identical reseed sequences produce identical rows
590
602
  * (timestamps + generated fields). Without this, the first
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { EffectExecutor, createContextFromBindings } from './chunk-2SM626PK.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-2SM626PK.js';
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';
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';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/runtime",
3
- "version": "6.43.0",
3
+ "version": "6.44.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.40.0",
55
+ "@almadar/core": "^10.42.0",
56
56
  "@almadar/evaluator": "^2.37.0",
57
57
  "@almadar/logger": "^1.10.0",
58
58
  "@almadar/server": "^2.29.0",
59
- "@almadar/std": "^16.151.0"
59
+ "@almadar/std": "^16.152.0"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "express": "^5.0.0"