@almadar/runtime 6.71.0 → 6.72.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,12 +1,12 @@
1
1
  import { parseCron, cronMinuteKey, cronMatches } from './chunk-OU3ITB5S.js';
2
- import { createContextFromBindings, interpolateValue, deferEntityBindings } from './chunk-ZJ62H3ES.js';
2
+ import { createContextFromBindings, interpolateValue, deferEntityBindings } from './chunk-ZWAOJT6R.js';
3
3
  import { seedRandom, randomArrayElement, randomInt, shuffleArray, randomPastDate } from './chunk-T4VDAB4C.js';
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, isReferenceConfigType, configRefEventKnob, normalizeCallSiteConfigToValues, resolveConfigRefEventName, eventListPropsOf } from '@almadar/core';
7
+ import { OrbitalSchemaSchema, isInlineTrait, isEntityCall, isEntityReference, parseEntityRef, parseImportedTraitRef, isPageReference, isPageReferenceString, isPageReferenceObject, parsePageRef, parseOrbitalRef, overrideDeclaredKnobs, asTraitId, asEntityId, asPageId, asOrbitalId, deriveId, isReferenceConfigType, configRefEventKnob, normalizeCallSiteConfigToValues, resolveConfigRefEventName, isCallSiteConfigDeclaration, idPrefix, eventListPropsOf } from '@almadar/core';
8
8
  export { normalizeCallSiteConfigToValues } from '@almadar/core';
9
- import { sampleRowCount, sampleRow } from '@almadar/core/mock';
9
+ import { sampleRowCount, sampleRow, identityEntitiesOf, roleVocabularyOf } from '@almadar/core/mock';
10
10
 
11
11
  var log = createLogger("almadar:runtime:eventbus");
12
12
  var EventBus = class {
@@ -324,6 +324,7 @@ function isValidDurationString(interval) {
324
324
  return /^(\d+)(ms|s|m|h)?$/.test(interval);
325
325
  }
326
326
  var smLog = createLogger("almadar:runtime:sm");
327
+ var LIFECYCLE_EVENTS = ["INIT", "LOAD", "$MOUNT"];
327
328
  function findInitialState(trait) {
328
329
  if (!trait.states || trait.states.length === 0) {
329
330
  smLog.warn("trait-has-no-states", { trait: trait.name });
@@ -1197,13 +1198,23 @@ var EffectExecutor = class _EffectExecutor {
1197
1198
  const isCompound = operator === "do" || operator === "when" || operator === "let" || operator === "if";
1198
1199
  const resolvedArgs = isCompound ? rawArgs : resolveArgs(rawArgs, this.bindings, this.strictBindings, this.contextExtensions);
1199
1200
  try {
1200
- await this.dispatch(operator, resolvedArgs);
1201
- results.push({
1202
- type: operator,
1203
- args: resolvedArgs,
1204
- status: "executed",
1205
- durationMs: Date.now() - start
1206
- });
1201
+ const outcome = await this.dispatch(operator, resolvedArgs);
1202
+ if (outcome?.failed) {
1203
+ results.push({
1204
+ type: operator,
1205
+ args: resolvedArgs,
1206
+ status: "failed",
1207
+ error: outcome.error,
1208
+ durationMs: Date.now() - start
1209
+ });
1210
+ } else {
1211
+ results.push({
1212
+ type: operator,
1213
+ args: resolvedArgs,
1214
+ status: "executed",
1215
+ durationMs: Date.now() - start
1216
+ });
1217
+ }
1207
1218
  } catch (error) {
1208
1219
  const errorMessage = error instanceof Error ? error.message : String(error);
1209
1220
  results.push({
@@ -1260,10 +1271,10 @@ var EffectExecutor = class _EffectExecutor {
1260
1271
  this.handlers.emit(eventName, payload, this.sourceStamp(), fromPersistSuccess);
1261
1272
  }
1262
1273
  }
1263
- emitFailure(emit, err) {
1274
+ emitFailure(emit, err, extra) {
1264
1275
  if (!emit?.failure) return;
1265
1276
  const error = err instanceof Error ? err.message : String(err);
1266
- this.handlers.emit(emit.failure, { error }, this.sourceStamp());
1277
+ this.handlers.emit(emit.failure, { ...extra, error }, this.sourceStamp());
1267
1278
  }
1268
1279
  /**
1269
1280
  * Narrow the generic emit config into the `os/watch-*` handler surface
@@ -1310,6 +1321,14 @@ var EffectExecutor = class _EffectExecutor {
1310
1321
  // ==========================================================================
1311
1322
  // Effect Dispatch
1312
1323
  // ==========================================================================
1324
+ /**
1325
+ * Dispatches one effect. Returns `void` for the ordinary case (the
1326
+ * caller only cares whether it threw). A `persist` that resolves
1327
+ * without throwing — the store DENIED the write, signalled by return
1328
+ * value rather than an exception, per the "close the circuit" doctrine
1329
+ * — reports that outcome here so `executeWithResults` can record it as
1330
+ * `status: 'failed'` instead of the default `'executed'`.
1331
+ */
1313
1332
  async dispatch(operator, args) {
1314
1333
  switch (operator) {
1315
1334
  // === Universal Effects ===
@@ -1383,6 +1402,15 @@ var EffectExecutor = class _EffectExecutor {
1383
1402
  success: emitCfg?.success,
1384
1403
  failure: emitCfg?.failure
1385
1404
  });
1405
+ if (this.handlers.persistDelegated === true) {
1406
+ persistLog.debug("persist:delegated", {
1407
+ action,
1408
+ entityType: action === "batch" ? "batch" : args[1],
1409
+ traitName: this.context.traitName,
1410
+ transition: this.context.transition
1411
+ });
1412
+ return;
1413
+ }
1386
1414
  try {
1387
1415
  if (action === "batch") {
1388
1416
  const operations = args[1];
@@ -1406,16 +1434,38 @@ var EffectExecutor = class _EffectExecutor {
1406
1434
  const entityType = args[1];
1407
1435
  const data = args[2];
1408
1436
  const persisted = await this.handlers.persist(action, entityType, data);
1409
- const successPayload = persisted ?? data;
1410
- const dataId = typeof successPayload === "string" ? successPayload : successPayload && typeof successPayload === "object" ? successPayload.id : void 0;
1411
- persistLog.debug("persist:success", {
1412
- action,
1413
- entityType,
1414
- dataId,
1415
- willEmit: emitCfg?.success
1416
- });
1417
- this.emitSuccess(emitCfg, "success", successPayload, true);
1418
- persistLog.debug("persist:emit-fired", { action, eventName: emitCfg?.success });
1437
+ if (persisted === void 0) {
1438
+ const attemptedId = typeof data === "string" ? data : data && typeof data === "object" ? data.id : void 0;
1439
+ persistLog.error("persist:denied", { action, entityType, attemptedId });
1440
+ const deniedError = `persist ${action} ${entityType} was denied or failed`;
1441
+ this.emitFailure(
1442
+ emitCfg,
1443
+ new Error(deniedError),
1444
+ { entityType, id: attemptedId }
1445
+ );
1446
+ return { failed: true, error: deniedError };
1447
+ } else {
1448
+ const dataId = typeof persisted === "string" ? persisted : persisted.id;
1449
+ persistLog.debug("persist:success", {
1450
+ action,
1451
+ entityType,
1452
+ dataId,
1453
+ willEmit: emitCfg?.success
1454
+ });
1455
+ if (action === "create" && this.bindings.entity && typeof dataId === "string") {
1456
+ const boundId = this.bindings.entity.id;
1457
+ const submittedId = data && typeof data === "object" ? data.id : void 0;
1458
+ if (boundId === void 0 || boundId === submittedId) {
1459
+ this.bindings.entity.id = dataId;
1460
+ persistLog.debug("persist:create-bound-id", {
1461
+ entityType,
1462
+ id: dataId
1463
+ });
1464
+ }
1465
+ }
1466
+ this.emitSuccess(emitCfg, "success", persisted, true);
1467
+ persistLog.debug("persist:emit-fired", { action, eventName: emitCfg?.success });
1468
+ }
1419
1469
  }
1420
1470
  } catch (err) {
1421
1471
  persistLog.error("persist:error", {
@@ -1450,8 +1500,16 @@ var EffectExecutor = class _EffectExecutor {
1450
1500
  const emitCfg = this.extractEmitConfig(rawOpt);
1451
1501
  try {
1452
1502
  const result = await this.handlers.fetch(entityType, options);
1453
- const payload = result ? { data: result.rows, totalCount: result.total } : { data: null, totalCount: 0 };
1454
- this.emitSuccess(emitCfg, "success", payload);
1503
+ if (result === null) {
1504
+ if (options?.id !== void 0) {
1505
+ this.emitFailure(emitCfg, new Error(`${entityType} ${options.id} not found`));
1506
+ } else {
1507
+ this.emitSuccess(emitCfg, "success", { data: [], totalCount: 0 });
1508
+ }
1509
+ } else {
1510
+ const payload = { data: result.rows, totalCount: result.total };
1511
+ this.emitSuccess(emitCfg, "success", payload);
1512
+ }
1455
1513
  } catch (err) {
1456
1514
  this.emitFailure(emitCfg, err);
1457
1515
  throw err;
@@ -2642,7 +2700,11 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
2642
2700
  async create(entityType, data) {
2643
2701
  const store = this.getStore(entityType);
2644
2702
  this.assertFileValuesWithinCeiling(entityType, data);
2645
- const id = this.nextId(entityType);
2703
+ const suppliedId = typeof data.id === "string" && data.id.length > 0 ? data.id : void 0;
2704
+ if (suppliedId && store.has(suppliedId)) {
2705
+ throw new Error(`Entity ${entityType} with id ${suppliedId} already exists`);
2706
+ }
2707
+ const id = suppliedId ?? this.nextId(entityType);
2646
2708
  const now = (/* @__PURE__ */ new Date()).toISOString();
2647
2709
  const withDefaults = this.applyFieldDefaults(entityType, data);
2648
2710
  const item = {
@@ -2904,6 +2966,7 @@ var HttpLoader = class {
2904
2966
  data: {
2905
2967
  orbital,
2906
2968
  orbitals: schema.orbitals,
2969
+ ...schema.config ? { schemaConfig: schema.config } : {},
2907
2970
  sourcePath: schemaResult.data.sourcePath,
2908
2971
  importPath
2909
2972
  }
@@ -3113,7 +3176,7 @@ async function getExternalLoaderModule() {
3113
3176
  return null;
3114
3177
  }
3115
3178
  try {
3116
- externalLoaderModule = await import('./external-loader-YUUADLAP.js');
3179
+ externalLoaderModule = await import('./external-loader-CISUEINQ.js');
3117
3180
  return externalLoaderModule;
3118
3181
  } catch {
3119
3182
  return null;
@@ -3287,6 +3350,7 @@ var UnifiedLoader = class {
3287
3350
  data: {
3288
3351
  orbital: found,
3289
3352
  orbitals: schema.orbitals,
3353
+ ...schema.config ? { schemaConfig: schema.config } : {},
3290
3354
  sourcePath: schemaResult.data.sourcePath,
3291
3355
  importPath
3292
3356
  }
@@ -3303,6 +3367,7 @@ var UnifiedLoader = class {
3303
3367
  data: {
3304
3368
  orbital: schema.orbitals[0],
3305
3369
  orbitals: schema.orbitals,
3370
+ ...schema.config ? { schemaConfig: schema.config } : {},
3306
3371
  sourcePath: schemaResult.data.sourcePath,
3307
3372
  importPath
3308
3373
  }
@@ -3637,6 +3702,205 @@ function spliceLambdaTraitRefs(traits, pages) {
3637
3702
  }
3638
3703
  }
3639
3704
 
3705
+ // src/resolver/sentinel-resolution.ts
3706
+ var PRIMITIVE_TYPE_ARG_NAMES = /* @__PURE__ */ new Set([
3707
+ "string",
3708
+ "money",
3709
+ "any",
3710
+ "icon",
3711
+ "component",
3712
+ "email",
3713
+ "url",
3714
+ "phone",
3715
+ "uuid",
3716
+ "image",
3717
+ "node",
3718
+ "json",
3719
+ "render-ui",
3720
+ "relation",
3721
+ "int",
3722
+ "float",
3723
+ "number",
3724
+ "duration",
3725
+ "bool",
3726
+ "boolean",
3727
+ "date",
3728
+ "datetime",
3729
+ "timestamp",
3730
+ "object",
3731
+ "sexpr",
3732
+ "scalar"
3733
+ ]);
3734
+ var BARE_PAYLOAD_CARRIER = "value";
3735
+ function resolveTypeArgValue(value, entitiesByName, typesByName) {
3736
+ if (PRIMITIVE_TYPE_ARG_NAMES.has(value)) {
3737
+ return { kind: "scalar", primitive: value };
3738
+ }
3739
+ const entity = entitiesByName.get(value);
3740
+ if (entity) {
3741
+ return { kind: "entity", entity };
3742
+ }
3743
+ const shape = typesByName[value];
3744
+ if (shape) {
3745
+ return { kind: "struct", shape };
3746
+ }
3747
+ return void 0;
3748
+ }
3749
+ function entityFieldToPayloadField(f) {
3750
+ if (f.type === "object" && f.items) {
3751
+ const valueType = fieldTypeTagOf(f.items);
3752
+ return {
3753
+ name: f.name ?? "",
3754
+ type: `Map<string,${valueType}>`,
3755
+ ...f.required !== void 0 ? { required: f.required } : {}
3756
+ };
3757
+ }
3758
+ let properties;
3759
+ if (f.type === "object" && f.properties) {
3760
+ properties = Object.values(f.properties).map(entityFieldToPayloadField);
3761
+ } else if (f.type === "union" && f.properties) {
3762
+ const ordered = f.values ?? Object.keys(f.properties);
3763
+ properties = ordered.map((k) => f.properties?.[k]).filter((v) => v !== void 0).map(entityFieldToPayloadField);
3764
+ } else if (f.type === "array" && f.items) {
3765
+ properties = entityFieldToPayloadField(f.items).properties;
3766
+ }
3767
+ const isArrayOfStruct = f.type === "array" && properties !== void 0;
3768
+ return {
3769
+ name: f.name ?? "",
3770
+ type: isArrayOfStruct ? "[object]" : fieldTypeTagOf(f),
3771
+ ...f.required !== void 0 ? { required: f.required } : {},
3772
+ ...properties && properties.length > 0 ? { properties } : {}
3773
+ };
3774
+ }
3775
+ function fieldTypeTagOf(f) {
3776
+ return f.type;
3777
+ }
3778
+ function entityFieldsToPayloadFields(entity) {
3779
+ return entity.fields.map(entityFieldToPayloadField);
3780
+ }
3781
+ function flattenBareEntityPayload(fields, entityDef, subs) {
3782
+ if (fields.length !== 1) return false;
3783
+ const field = fields[0];
3784
+ if (field.name !== BARE_PAYLOAD_CARRIER) return false;
3785
+ let entity;
3786
+ if (field.type === "@entity") {
3787
+ entity = entityDef;
3788
+ } else if (field.type === "object" && field.properties) {
3789
+ entity = entityDef;
3790
+ } else if (field.type.startsWith("$")) {
3791
+ const sub = subs.get(field.type.slice(1));
3792
+ entity = sub?.kind === "entity" ? sub.entity : void 0;
3793
+ }
3794
+ if (!entity) return false;
3795
+ fields.length = 0;
3796
+ fields.push(...entityFieldsToPayloadFields(entity));
3797
+ return true;
3798
+ }
3799
+ function resolveSentinelFields(fields, entityDef, subs, declaredNames) {
3800
+ let changed = false;
3801
+ for (const field of fields) {
3802
+ const isSelfRef = field.type === "@entity" || field.type === "[@entity]";
3803
+ if (isSelfRef) {
3804
+ if (entityDef) {
3805
+ const isArray = field.type.startsWith("[");
3806
+ field.type = isArray ? "[object]" : "object";
3807
+ field.properties = entityFieldsToPayloadFields(entityDef);
3808
+ field.entity = entityDef.name;
3809
+ changed = true;
3810
+ }
3811
+ continue;
3812
+ }
3813
+ const isArraySentinel = field.type.startsWith("[$") && field.type.endsWith("]");
3814
+ const isBareSentinel = !isArraySentinel && field.type.startsWith("$");
3815
+ if (isBareSentinel || isArraySentinel) {
3816
+ const paramName = isArraySentinel ? field.type.slice(2, -1) : field.type.slice(1);
3817
+ const sub = subs.get(paramName);
3818
+ if (sub) {
3819
+ switch (sub.kind) {
3820
+ case "scalar":
3821
+ field.type = isArraySentinel ? `[${sub.primitive}]` : sub.primitive;
3822
+ field.properties = void 0;
3823
+ break;
3824
+ case "entity":
3825
+ field.type = isArraySentinel ? "[object]" : "object";
3826
+ field.properties = entityFieldsToPayloadFields(sub.entity);
3827
+ field.entity = sub.entity.name;
3828
+ break;
3829
+ case "struct":
3830
+ field.type = isArraySentinel ? "[object]" : "object";
3831
+ field.properties = [...sub.shape];
3832
+ break;
3833
+ }
3834
+ changed = true;
3835
+ continue;
3836
+ }
3837
+ if (declaredNames.has(paramName)) {
3838
+ continue;
3839
+ }
3840
+ if (entityDef) {
3841
+ field.type = isArraySentinel ? "[object]" : "object";
3842
+ field.properties = entityFieldsToPayloadFields(entityDef);
3843
+ field.entity = entityDef.name;
3844
+ changed = true;
3845
+ }
3846
+ continue;
3847
+ }
3848
+ if (field.properties) {
3849
+ const mutableProps = field.properties;
3850
+ changed = resolveSentinelFields(mutableProps, entityDef, subs, declaredNames) || changed;
3851
+ }
3852
+ }
3853
+ return changed;
3854
+ }
3855
+ function resolveTraitTypeParamSentinels(trait, entityDef, entitiesByName, typesByName, typeArgs) {
3856
+ const declared = trait.typeParams ?? [];
3857
+ const subs = /* @__PURE__ */ new Map();
3858
+ const declaredNames = /* @__PURE__ */ new Set();
3859
+ for (const p of declared) {
3860
+ declaredNames.add(p.name);
3861
+ const argValue = typeArgs?.[p.name];
3862
+ let sub;
3863
+ if (argValue !== void 0) {
3864
+ sub = resolveTypeArgValue(argValue, entitiesByName, typesByName);
3865
+ } else if (p.kind === "Entity" && entityDef) {
3866
+ sub = { kind: "entity", entity: entityDef };
3867
+ } else if (p.default) {
3868
+ sub = resolveTypeArgValue(p.default, entitiesByName, typesByName);
3869
+ }
3870
+ if (sub) subs.set(p.name, sub);
3871
+ }
3872
+ let changed = false;
3873
+ for (const emit of trait.emits ?? []) {
3874
+ if (!emit.payloadSchema) continue;
3875
+ const schema = emit.payloadSchema;
3876
+ if (flattenBareEntityPayload(schema, entityDef, subs)) {
3877
+ changed = true;
3878
+ } else {
3879
+ changed = resolveSentinelFields(schema, entityDef, subs, declaredNames) || changed;
3880
+ }
3881
+ }
3882
+ for (const ev of trait.stateMachine?.events ?? []) {
3883
+ if (!ev.payloadSchema) continue;
3884
+ const schema = ev.payloadSchema;
3885
+ if (flattenBareEntityPayload(schema, entityDef, subs)) {
3886
+ changed = true;
3887
+ } else {
3888
+ changed = resolveSentinelFields(schema, entityDef, subs, declaredNames) || changed;
3889
+ }
3890
+ }
3891
+ return changed;
3892
+ }
3893
+ function resolveOrbitalTypeParamSentinels(traits, primaryEntity, auxiliaryEntities, orbitalTypes) {
3894
+ const entitiesByName = /* @__PURE__ */ new Map();
3895
+ entitiesByName.set(primaryEntity.name, primaryEntity);
3896
+ for (const e of auxiliaryEntities) entitiesByName.set(e.name, e);
3897
+ const typesByName = orbitalTypes ?? {};
3898
+ for (const rt of traits) {
3899
+ const entityDef = rt.trait.linkedEntity ? entitiesByName.get(rt.trait.linkedEntity) : void 0;
3900
+ resolveTraitTypeParamSentinels(rt.trait, entityDef, entitiesByName, typesByName, rt.typeArgs);
3901
+ }
3902
+ }
3903
+
3640
3904
  // src/resolver/reference-resolver.ts
3641
3905
  var refResolverLog = createLogger("almadar:runtime:ref-resolver");
3642
3906
  function indexOrbitalNodes(orbital, idIndex) {
@@ -3910,6 +4174,25 @@ function renameTraitEmbedsInValue(node, subs) {
3910
4174
  }
3911
4175
  return next;
3912
4176
  }
4177
+ function renameEntityNameTokensInValue(node, entitySubs) {
4178
+ if (node === null || node === void 0) return node;
4179
+ if (typeof node === "string") {
4180
+ if (!node.startsWith("@")) return node;
4181
+ const rest = node.slice(1);
4182
+ const dot = rest.search(/[.[]/);
4183
+ const name = dot === -1 ? rest : rest.slice(0, dot);
4184
+ const suffix = dot === -1 ? "" : rest.slice(dot);
4185
+ const to = entitySubs.get(name);
4186
+ return to === void 0 ? node : `@${to}${suffix}`;
4187
+ }
4188
+ if (Array.isArray(node)) return node.map((item) => renameEntityNameTokensInValue(item, entitySubs));
4189
+ if (typeof node !== "object") return node;
4190
+ const next = {};
4191
+ for (const [key, value] of Object.entries(node)) {
4192
+ next[key] = renameEntityNameTokensInValue(value, entitySubs);
4193
+ }
4194
+ return next;
4195
+ }
3913
4196
  function renameTraitEmbeds(trait, subs) {
3914
4197
  if (subs.size === 0) return trait;
3915
4198
  const sm = trait.stateMachine;
@@ -3956,6 +4239,36 @@ function findTraitEntryInOrbital(orbital, localName) {
3956
4239
  }
3957
4240
  return null;
3958
4241
  }
4242
+ function homeOrbitalConfigForTrait(imported, traitName) {
4243
+ for (const o of importedOrbitals(imported)) {
4244
+ if (findTraitEntryInOrbital(o, traitName)) return o.config;
4245
+ }
4246
+ return void 0;
4247
+ }
4248
+ function findPageEntryInOrbital(orbital, localName) {
4249
+ for (const pageRef of orbital.pages ?? []) {
4250
+ if (typeof pageRef === "string") continue;
4251
+ if (!("ref" in pageRef)) {
4252
+ if (pageRef.name === localName) return pageRef;
4253
+ continue;
4254
+ }
4255
+ const refObj = pageRef;
4256
+ if (parsePageRef(refObj.ref)?.pageName === localName) return refObj;
4257
+ }
4258
+ return null;
4259
+ }
4260
+ function toPageTraitRef(traitRef) {
4261
+ if (typeof traitRef === "string") return { ref: traitRef };
4262
+ if ("stateMachine" in traitRef) return { ref: traitRef.name };
4263
+ const refObj = traitRef;
4264
+ return {
4265
+ ref: refObj.name ?? refObj.ref,
4266
+ ...refObj.refId !== void 0 ? { refId: refObj.refId } : {},
4267
+ ...refObj.linkedEntity !== void 0 ? { linkedEntity: refObj.linkedEntity } : {},
4268
+ ...refObj.linkedEntityId !== void 0 ? { linkedEntityId: refObj.linkedEntityId } : {},
4269
+ ...refObj.config !== void 0 ? { config: refObj.config } : {}
4270
+ };
4271
+ }
3959
4272
  function traitEmbedNamesOf(trait) {
3960
4273
  const found = /* @__PURE__ */ new Set();
3961
4274
  const walk = (node) => {
@@ -3975,34 +4288,179 @@ function traitEmbedNamesOf(trait) {
3975
4288
  if (typeof node !== "object") return;
3976
4289
  for (const value of Object.values(node)) walk(value);
3977
4290
  };
3978
- for (const t of trait.stateMachine?.transitions ?? []) walk(t.effects);
3979
- for (const tick of trait.ticks ?? []) walk(tick.effects);
4291
+ for (const t of trait.stateMachine?.transitions ?? []) {
4292
+ walk(t.guard);
4293
+ walk(t.effects);
4294
+ }
4295
+ for (const tick of trait.ticks ?? []) {
4296
+ walk(tick.guard);
4297
+ walk(tick.effects);
4298
+ }
3980
4299
  for (const field of Object.values(trait.config ?? {})) walk(field.default);
3981
- return [...found];
4300
+ return [...found].sort();
3982
4301
  }
3983
- function resolveForwardedSiblingConfig(trait, parent) {
4302
+ function resolveForwardedSiblingConfigFrom(trait, parentChain, orbitalConfig, schemaConfig) {
3984
4303
  const declared = trait.config;
3985
- const parentDeclared = parent?.config;
3986
- if (!declared || !parentDeclared) return trait;
4304
+ if (!declared) return trait;
4305
+ const next = resolveConfigForwards(declared, parentChain, orbitalConfig, void 0, void 0, schemaConfig);
4306
+ return next ? { ...trait, config: next } : trait;
4307
+ }
4308
+ function callSiteRungValue(rungConfig, knob) {
4309
+ const entry = rungConfig[knob];
4310
+ if (entry === void 0) return void 0;
4311
+ return isCallSiteConfigDeclaration(entry) ? entry.default : entry;
4312
+ }
4313
+ function walkConfigForwardChain(forward, parentChain, orbitalConfig, upstreamOrbitalConfig, upstreamSchemaConfig, schemaConfig) {
4314
+ let knob = forward.slice("@config.".length);
4315
+ if (knob.length === 0 || knob.includes(".")) return void 0;
4316
+ let value;
4317
+ let currentForward = forward;
4318
+ for (const rungConfig of parentChain) {
4319
+ const rungValue = callSiteRungValue(rungConfig, knob);
4320
+ if (rungValue === void 0 || rungValue === currentForward) continue;
4321
+ if (typeof rungValue === "string" && rungValue.startsWith("@config.")) {
4322
+ const nextKnob = rungValue.slice("@config.".length);
4323
+ if (nextKnob.length === 0 || nextKnob.includes(".") || nextKnob === knob) continue;
4324
+ knob = nextKnob;
4325
+ currentForward = rungValue;
4326
+ continue;
4327
+ }
4328
+ value = rungValue;
4329
+ break;
4330
+ }
4331
+ if (value === void 0 || value === currentForward) value = orbitalConfig?.[knob]?.default;
4332
+ if (value === void 0 || value === currentForward) value = upstreamOrbitalConfig?.[knob]?.default;
4333
+ if (value === void 0 || value === currentForward) value = upstreamSchemaConfig?.[knob]?.default;
4334
+ if (value === void 0 || value === currentForward) value = schemaConfig?.[knob]?.default;
4335
+ if (value === void 0 || value === currentForward) return void 0;
4336
+ return value;
4337
+ }
4338
+ function resolveConfigForwards(declared, parentChain, orbitalConfig, upstreamOrbitalConfig, upstreamSchemaConfig, schemaConfig) {
3987
4339
  let next;
3988
4340
  for (const [key, field] of Object.entries(declared)) {
3989
4341
  const forward = field.default;
3990
4342
  if (typeof forward !== "string" || !forward.startsWith("@config.")) continue;
3991
- const knob = forward.slice("@config.".length);
3992
- if (knob.length === 0 || knob.includes(".")) continue;
3993
- const value = parentDeclared[knob]?.default;
3994
- if (value === void 0 || value === forward) continue;
4343
+ const value = walkConfigForwardChain(
4344
+ forward,
4345
+ parentChain,
4346
+ orbitalConfig,
4347
+ upstreamOrbitalConfig,
4348
+ upstreamSchemaConfig,
4349
+ schemaConfig
4350
+ );
4351
+ if (value === void 0) continue;
3995
4352
  next ??= { ...declared };
3996
- next[key] = { ...field, default: value };
4353
+ next[key] = { ...field, default: value, forwardedFrom: forward };
3997
4354
  }
3998
- return next ? { ...trait, config: next } : trait;
4355
+ return next;
4356
+ }
4357
+ function resolveCallSiteConfigForwards(config, parentChain, orbitalConfig, schemaConfig) {
4358
+ let next;
4359
+ for (const [key, entry] of Object.entries(config)) {
4360
+ const forward = isCallSiteConfigDeclaration(entry) ? entry.default : entry;
4361
+ if (typeof forward !== "string" || !forward.startsWith("@config.")) continue;
4362
+ const value = walkConfigForwardChain(forward, parentChain, orbitalConfig, void 0, void 0, schemaConfig);
4363
+ if (value === void 0) continue;
4364
+ next ??= { ...config };
4365
+ next[key] = isCallSiteConfigDeclaration(entry) ? { ...entry, default: value, forwardedFrom: forward } : value;
4366
+ }
4367
+ return next;
4368
+ }
4369
+ function traitRefEmbedNamesOf(traitRef) {
4370
+ if (typeof traitRef === "string") return [];
4371
+ return traitEmbedNamesOf(traitRef);
4372
+ }
4373
+ function traitRefLocalName(traitRef) {
4374
+ if (typeof traitRef === "string") {
4375
+ return parseImportedTraitRef(traitRef)?.traitName ?? traitRef;
4376
+ }
4377
+ if ("stateMachine" in traitRef) return traitRef.name;
4378
+ const refObj = traitRef;
4379
+ return refObj.name ?? parseImportedTraitRef(refObj.ref)?.traitName ?? refObj.ref;
4380
+ }
4381
+ function traitRefConfigOf(traitRef) {
4382
+ if (typeof traitRef === "string") return void 0;
4383
+ return traitRef.config;
4384
+ }
4385
+ function buildEmbedGraph(traitRefs) {
4386
+ const out = /* @__PURE__ */ new Map();
4387
+ for (const traitRef of traitRefs) {
4388
+ const referrerName = traitRefLocalName(traitRef);
4389
+ if (!referrerName) continue;
4390
+ for (const child of traitRefEmbedNamesOf(traitRef)) {
4391
+ if (child === referrerName) continue;
4392
+ if (!out.has(child)) out.set(child, referrerName);
4393
+ }
4394
+ }
4395
+ return out;
4396
+ }
4397
+ function embedderChain(localName, traitRefs, graph) {
4398
+ const chain = [];
4399
+ const visited = /* @__PURE__ */ new Set([localName]);
4400
+ let cur = graph.get(localName);
4401
+ let hops = 0;
4402
+ while (cur !== void 0 && !visited.has(cur) && hops < traitRefs.length) {
4403
+ visited.add(cur);
4404
+ hops++;
4405
+ const entry = traitRefs.find((t) => traitRefLocalName(t) === cur);
4406
+ const entryConfig = entry ? traitRefConfigOf(entry) : void 0;
4407
+ if (entryConfig) chain.push(entryConfig);
4408
+ cur = graph.get(cur);
4409
+ }
4410
+ return chain;
4411
+ }
4412
+ function resolveEmbedderConfigForward(config, localName, embedCtx, schemaConfig) {
4413
+ const chain = embedderChain(localName, embedCtx.traitRefs, embedCtx.embedGraph);
4414
+ const next = resolveCallSiteConfigForwards(config, chain, embedCtx.orbitalConfig, schemaConfig);
4415
+ return next ? next : config;
4416
+ }
4417
+ function consumerKnownEntityRebindSubs(trait, entityIds) {
4418
+ const out = /* @__PURE__ */ new Map();
4419
+ const refs = trait.entityRefIds;
4420
+ if (!refs) return out;
4421
+ const idToConsumerName = /* @__PURE__ */ new Map();
4422
+ for (const [name, id] of entityIds) {
4423
+ if (!idToConsumerName.has(id)) idToConsumerName.set(id, name);
4424
+ }
4425
+ for (const [tokenName, entityId] of Object.entries(refs)) {
4426
+ const consumerName = idToConsumerName.get(entityId);
4427
+ if (consumerName !== void 0 && consumerName !== tokenName) {
4428
+ out.set(tokenName, consumerName);
4429
+ }
4430
+ }
4431
+ return out;
4432
+ }
4433
+ function staleEntityRebindSubs(trait, newEntity) {
4434
+ const out = /* @__PURE__ */ new Map();
4435
+ const boundId = trait.linkedEntityId;
4436
+ const refs = trait.entityRefIds;
4437
+ if (boundId && refs) {
4438
+ for (const [tokenName, entityId] of Object.entries(refs)) {
4439
+ if (entityId === boundId) out.set(tokenName, newEntity);
4440
+ }
4441
+ }
4442
+ return out;
3999
4443
  }
4000
- function applyLinkedEntityRename(trait, linkedEntity) {
4444
+ function applyLinkedEntityRename(trait, linkedEntity, entityIds) {
4001
4445
  const atomLinked = trait.linkedEntity;
4002
- if (!linkedEntity || !atomLinked || linkedEntity === atomLinked) return trait;
4003
- const sm = trait.stateMachine;
4004
- if (!sm) return { ...trait, linkedEntity };
4446
+ const entitySubs = consumerKnownEntityRebindSubs(trait, entityIds);
4447
+ if (!linkedEntity || !atomLinked || linkedEntity === atomLinked) {
4448
+ return rewriteEntityRefIds(trait, entitySubs, entityIds);
4449
+ }
4450
+ for (const [from, to] of staleEntityRebindSubs(trait, linkedEntity)) {
4451
+ entitySubs.set(from, to);
4452
+ }
4453
+ entitySubs.set(atomLinked, linkedEntity);
4005
4454
  const rename = (name) => name === atomLinked ? linkedEntity : void 0;
4455
+ const sm = trait.stateMachine;
4456
+ const rebound = {
4457
+ ...trait,
4458
+ linkedEntity,
4459
+ linkedEntityId: entityIds.get(linkedEntity)
4460
+ };
4461
+ if (!sm) {
4462
+ return renamePayloadEntityMarkers(rewriteEntityRefIds(rebound, entitySubs, entityIds), rename);
4463
+ }
4006
4464
  const nextTransitions = (sm.transitions ?? []).map((t) => {
4007
4465
  const nextEffects = t.effects ? renameEntityInEffects(
4008
4466
  t.effects,
@@ -4017,11 +4475,14 @@ function applyLinkedEntityRename(trait, linkedEntity) {
4017
4475
  to: linkedEntity,
4018
4476
  transitionCount: nextTransitions.length
4019
4477
  });
4020
- return {
4021
- ...trait,
4022
- linkedEntity,
4023
- stateMachine: { ...sm, transitions: nextTransitions }
4024
- };
4478
+ return renamePayloadEntityMarkers(
4479
+ rewriteEntityRefIds(
4480
+ { ...rebound, stateMachine: { ...sm, transitions: nextTransitions } },
4481
+ entitySubs,
4482
+ entityIds
4483
+ ),
4484
+ rename
4485
+ );
4025
4486
  }
4026
4487
  function resolveEntityTokensById(trait, idIndex) {
4027
4488
  const map = trait.entityRefIds;
@@ -4170,17 +4631,44 @@ function applyEventRenamesToCallSiteConfig(config, declared, renames) {
4170
4631
  }
4171
4632
  return touched ? next : config;
4172
4633
  }
4634
+ function resolvedKnobValues(before, after, knobs) {
4635
+ const out = /* @__PURE__ */ new Map();
4636
+ if (knobs.length === 0) return out;
4637
+ const knobSet = new Set(knobs);
4638
+ const beforeEmits = before.emits ?? [];
4639
+ const afterEmits = after.emits ?? [];
4640
+ for (let i = 0; i < beforeEmits.length; i++) {
4641
+ const knob = configRefEventKnob(beforeEmits[i].event);
4642
+ if (knob !== void 0 && knobSet.has(knob)) out.set(knob, afterEmits[i].event);
4643
+ }
4644
+ return out;
4645
+ }
4646
+ function foldEventRenameOntoDeclaredKnobs(trait, resolved, eventRenames) {
4647
+ if (!eventRenames || resolved.size === 0 || !trait.config) return trait;
4648
+ let nextConfig;
4649
+ for (const [knob, resolvedValue] of resolved) {
4650
+ const renamed = eventRenames[resolvedValue];
4651
+ if (renamed === void 0 || renamed === resolvedValue) continue;
4652
+ const field = trait.config[knob];
4653
+ if (!field) continue;
4654
+ nextConfig ??= { ...trait.config };
4655
+ nextConfig[knob] = { ...field, default: renamed };
4656
+ }
4657
+ return nextConfig ? { ...trait, config: nextConfig } : trait;
4658
+ }
4173
4659
  function resolveConfigRefEmitNames(trait, callSiteConfig) {
4174
4660
  const emits = trait.emits ?? [];
4175
4661
  const hasRef = emits.some((em) => configRefEventKnob(em.event) !== void 0);
4176
- if (!hasRef) return { trait, errors: [] };
4662
+ if (!hasRef) return { trait, errors: [], resolvedKnobs: [] };
4177
4663
  const effectiveConfig = {
4178
4664
  ...normalizeCallSiteConfigToValues(trait.config) ?? {},
4179
4665
  ...normalizeCallSiteConfigToValues(callSiteConfig) ?? {}
4180
4666
  };
4181
4667
  const errors = [];
4668
+ const resolvedTriples = [];
4182
4669
  const nextEmits = emits.map((em) => {
4183
- if (configRefEventKnob(em.event) === void 0) return em;
4670
+ const knob = configRefEventKnob(em.event);
4671
+ if (knob === void 0) return em;
4184
4672
  const result = resolveConfigRefEventName(em.event, trait.config, effectiveConfig);
4185
4673
  if (!result.ok) {
4186
4674
  errors.push(
@@ -4193,78 +4681,1065 @@ function resolveConfigRefEmitNames(trait, callSiteConfig) {
4193
4681
  ref: em.event,
4194
4682
  resolved: result.value
4195
4683
  });
4684
+ resolvedTriples.push({ knob, from: em.event, to: result.value });
4196
4685
  return { ...em, event: result.value };
4197
4686
  });
4198
- return { trait: { ...trait, emits: nextEmits }, errors };
4687
+ const sm = trait.stateMachine;
4688
+ const nextEvents = resolvedTriples.length > 0 && sm ? sm.events.map((ev) => {
4689
+ const hit = resolvedTriples.find((t) => t.from === ev.key);
4690
+ return hit ? { ...ev, key: hit.to } : ev;
4691
+ }) : sm?.events;
4692
+ return {
4693
+ trait: {
4694
+ ...trait,
4695
+ emits: nextEmits,
4696
+ ...sm && nextEvents !== sm.events ? { stateMachine: { ...sm, events: nextEvents } } : {}
4697
+ },
4698
+ errors,
4699
+ resolvedKnobs: resolvedTriples.map((t) => t.knob)
4700
+ };
4199
4701
  }
4200
- var ReferenceResolver = class {
4201
- loader;
4202
- options;
4203
- localTraits;
4204
- /** id-keyed mirror of `localTraits`, populated wherever the trait carries an `id`. */
4205
- localTraitsById = /* @__PURE__ */ new Map();
4206
- /** Import scope of each loaded source orbital, keyed by its source path. */
4207
- sourceImportsCache = /* @__PURE__ */ new Map();
4208
- loaderInitialized = false;
4209
- constructor(options) {
4210
- this.options = options;
4211
- this.loader = options.loader;
4212
- this.localTraits = options.localTraits ?? /* @__PURE__ */ new Map();
4213
- for (const trait of this.localTraits.values()) {
4214
- if (trait.id) {
4215
- this.localTraitsById.set(trait.id, trait);
4216
- }
4702
+ function foldCallSiteConfigOntoTrait(trait, callSiteConfig) {
4703
+ if (!callSiteConfig) return trait;
4704
+ const declared = trait.config;
4705
+ const overrideValues = {};
4706
+ const overriddenKeys = /* @__PURE__ */ new Set();
4707
+ const newDeclarations = {};
4708
+ for (const [key, entry] of Object.entries(callSiteConfig)) {
4709
+ const isDecl = isCallSiteConfigDeclaration(entry);
4710
+ const value = isDecl ? entry.default : entry;
4711
+ if (declared && key in declared) {
4712
+ if (value !== void 0) {
4713
+ overrideValues[key] = value;
4714
+ overriddenKeys.add(key);
4715
+ }
4716
+ } else if (isDecl) {
4717
+ newDeclarations[key] = entry;
4718
+ }
4719
+ }
4720
+ if (overriddenKeys.size === 0 && Object.keys(newDeclarations).length === 0) {
4721
+ return trait;
4722
+ }
4723
+ let nextConfig = overrideDeclaredKnobs(declared ?? {}, overrideValues);
4724
+ if (overriddenKeys.size > 0) {
4725
+ const patched = { ...nextConfig };
4726
+ for (const key of overriddenKeys) {
4727
+ const field = patched[key];
4728
+ if (!field) continue;
4729
+ const entry = callSiteConfig[key];
4730
+ const entryDecl = isCallSiteConfigDeclaration(entry) ? entry : void 0;
4731
+ patched[key] = {
4732
+ ...field,
4733
+ forwardedFrom: entryDecl?.forwardedFrom,
4734
+ // The atom's OWN `refId` (a reference-config field's declared
4735
+ // default names a SPECIFIC node by id) describes the ATOM's OWN
4736
+ // `default`, not whatever this override just replaced it with —
4737
+ // carrying it forward unchanged left a STALE id bound to the NEW
4738
+ // literal string, so the id-index's "current name" correction
4739
+ // (`resolveConfigRefsById`) silently rewrote the override BACK to
4740
+ // the atom's own default target — found via std-notes'
4741
+ // `NoteGlobalSearch`: `idleContent`'s override says `@trait.
4742
+ // NoteCatalog` but the atom's OWN stale `refId` (still pointing at
4743
+ // `AppSearchIdleHint`, the atom's default) rewrote the sibling-pull
4744
+ // target back to it (rung 2: an override with no id of its own
4745
+ // names no id, so it must clear the atom's). An override that
4746
+ // carries ITS OWN `refId` (an annotated, id-aware override) wins
4747
+ // instead — same precedence a `default` override already has.
4748
+ refId: entryDecl?.refId,
4749
+ ...entryDecl?.label !== void 0 ? { label: entryDecl.label } : {},
4750
+ ...entryDecl?.description !== void 0 ? { description: entryDecl.description } : {},
4751
+ ...entryDecl?.synonyms !== void 0 ? { synonyms: entryDecl.synonyms } : {},
4752
+ ...entryDecl?.tier !== void 0 ? { tier: entryDecl.tier } : {}
4753
+ };
4217
4754
  }
4755
+ nextConfig = patched;
4218
4756
  }
4219
- async ensureLoader() {
4220
- if (this.loader || this.loaderInitialized) return;
4221
- this.loaderInitialized = true;
4222
- try {
4223
- const { ExternalOrbitalLoader } = await import('./external-loader-YUUADLAP.js');
4224
- this.loader = new ExternalOrbitalLoader(this.options);
4225
- } catch {
4226
- }
4757
+ if (Object.keys(newDeclarations).length > 0) {
4758
+ nextConfig = { ...nextConfig, ...newDeclarations };
4227
4759
  }
4228
- /**
4229
- * Resolve all references in an orbital.
4230
- */
4231
- async resolve(orbital, sourcePath, chain) {
4232
- const errors = [];
4233
- const warnings = [];
4234
- const importChain = chain ?? { push: () => null, pop: () => {
4235
- }, clone() {
4236
- return this;
4237
- } };
4238
- const traitsList = orbital.traits ?? [];
4239
- const alreadyResolved = traitsList.length > 0 && traitsList.every((t) => isInlineTrait(t));
4240
- const importsResult = alreadyResolved ? { success: true, data: { orbitals: /* @__PURE__ */ new Map(), idIndex: /* @__PURE__ */ new Map() }} : await this.resolveImports(orbital.uses ?? [], sourcePath, importChain);
4241
- if (!importsResult.success) {
4242
- return { success: false, errors: importsResult.errors };
4243
- }
4244
- const imports = importsResult.data;
4245
- imports.idIndex = buildIdIndex(orbital, imports.orbitals);
4246
- const entityResult = this.resolveEntity(orbital.entity, imports);
4247
- if (!entityResult.success) {
4248
- errors.push(...entityResult.errors);
4249
- }
4250
- const traitsResult = this.resolveTraits(orbital.traits, imports);
4251
- if (!traitsResult.success) {
4252
- errors.push(...traitsResult.errors);
4253
- }
4254
- const pagesResult = this.resolvePages(orbital.pages, imports);
4255
- if (!pagesResult.success) {
4256
- errors.push(...pagesResult.errors);
4760
+ return { ...trait, config: nextConfig };
4761
+ }
4762
+ var ENTITY_FIELD_TOKEN_PREFIX = "@entity.";
4763
+ function rewriteEntityFieldTokensInValue(node, subs) {
4764
+ if (node === null || node === void 0) return node;
4765
+ if (typeof node === "string") {
4766
+ if (!node.startsWith(ENTITY_FIELD_TOKEN_PREFIX)) return node;
4767
+ const rest = node.slice(ENTITY_FIELD_TOKEN_PREFIX.length);
4768
+ const dot = rest.search(/[.[]/);
4769
+ const name = dot === -1 ? rest : rest.slice(0, dot);
4770
+ const suffix = dot === -1 ? "" : rest.slice(dot);
4771
+ const to = subs.get(name);
4772
+ return to === void 0 ? node : `${ENTITY_FIELD_TOKEN_PREFIX}${to}${suffix}`;
4773
+ }
4774
+ if (Array.isArray(node)) return node.map((item) => rewriteEntityFieldTokensInValue(item, subs));
4775
+ if (typeof node !== "object") return node;
4776
+ const next = {};
4777
+ for (const [key, value] of Object.entries(node)) {
4778
+ next[key] = rewriteEntityFieldTokensInValue(value, subs);
4779
+ }
4780
+ return next;
4781
+ }
4782
+ function rewriteEntityFieldsInTrait(trait, fieldSubs) {
4783
+ if (fieldSubs.size === 0) return trait;
4784
+ const rewrite = (v) => rewriteEntityFieldTokensInValue(v, fieldSubs);
4785
+ const next = { ...trait };
4786
+ const sm = trait.stateMachine;
4787
+ if (sm) {
4788
+ next.stateMachine = {
4789
+ ...sm,
4790
+ transitions: (sm.transitions ?? []).map((t) => ({
4791
+ ...t,
4792
+ ...t.guard !== void 0 ? { guard: rewrite(t.guard) } : {},
4793
+ ...t.effects ? { effects: rewrite(t.effects) } : {}
4794
+ }))
4795
+ };
4796
+ }
4797
+ if (trait.ticks) {
4798
+ next.ticks = trait.ticks.map((tick) => ({
4799
+ ...tick,
4800
+ ...tick.guard !== void 0 ? { guard: rewrite(tick.guard) } : {},
4801
+ effects: rewrite(tick.effects)
4802
+ }));
4803
+ }
4804
+ if (trait.listens) {
4805
+ next.listens = trait.listens.map((l) => ({
4806
+ ...l,
4807
+ ...l.guard !== void 0 ? { guard: rewrite(l.guard) } : {},
4808
+ ...l.payloadMapping ? { payloadMapping: rewrite(l.payloadMapping) } : {}
4809
+ }));
4810
+ }
4811
+ if (trait.initialEffects) {
4812
+ next.initialEffects = rewrite(trait.initialEffects);
4813
+ }
4814
+ if (trait.config) {
4815
+ const nextConfig = {};
4816
+ for (const [key, field] of Object.entries(trait.config)) {
4817
+ nextConfig[key] = field.default === void 0 ? field : { ...field, default: rewrite(field.default) };
4257
4818
  }
4258
- if (errors.length > 0) {
4259
- return { success: false, errors };
4819
+ next.config = nextConfig;
4820
+ }
4821
+ return next;
4822
+ }
4823
+ function rewriteEntityFieldsInEntity(entity, fieldSubs) {
4824
+ if (fieldSubs.size === 0) return entity;
4825
+ const rewrite = (v) => rewriteEntityFieldTokensInValue(v, fieldSubs);
4826
+ return {
4827
+ ...entity,
4828
+ fields: entity.fields.map((f) => f.name && fieldSubs.has(f.name) ? { ...f, name: fieldSubs.get(f.name) } : f),
4829
+ ...entity.read_policy !== void 0 ? { read_policy: rewrite(entity.read_policy) } : {},
4830
+ ...entity.create_policy !== void 0 ? { create_policy: rewrite(entity.create_policy) } : {},
4831
+ ...entity.update_policy !== void 0 ? { update_policy: rewrite(entity.update_policy) } : {},
4832
+ ...entity.delete_policy !== void 0 ? { delete_policy: rewrite(entity.delete_policy) } : {}
4833
+ };
4834
+ }
4835
+ var USER_FIELD_PREFIX = "@user.";
4836
+ function directUserField(node) {
4837
+ if (typeof node !== "string" || !node.startsWith(USER_FIELD_PREFIX)) return void 0;
4838
+ const rest = node.slice(USER_FIELD_PREFIX.length);
4839
+ return rest.length > 0 && !/[.[]/.test(rest) ? rest : void 0;
4840
+ }
4841
+ var EQUALITY_OPS = /* @__PURE__ */ new Set(["=", "==", "!=", "!==", "eq", "neq"]);
4842
+ var NEGATED_EQUALITY_OPS = /* @__PURE__ */ new Set(["!=", "!==", "neq"]);
4843
+ function literalHaystackMembers(items) {
4844
+ const isListCall = items[0] === "list";
4845
+ const members = isListCall ? items.slice(1) : items;
4846
+ return members.every((v) => typeof v === "string") ? [...members] : void 0;
4847
+ }
4848
+ function rewriteRoleLiteralsInValue(node, roleFields, roles) {
4849
+ if (node === null || node === void 0) return node;
4850
+ if (Array.isArray(node)) {
4851
+ const head = node[0];
4852
+ if (typeof head === "string" && EQUALITY_OPS.has(head) && node.length === 3) {
4853
+ const [, left, right] = node;
4854
+ const leftField = directUserField(left);
4855
+ const rightField = directUserField(right);
4856
+ const userField = leftField !== void 0 && rightField === void 0 ? leftField : rightField !== void 0 && leftField === void 0 ? rightField : void 0;
4857
+ if (userField !== void 0 && roleFields.has(userField)) {
4858
+ const literalSide = leftField !== void 0 ? right : left;
4859
+ if (typeof literalSide === "string" && literalSide in roles) {
4860
+ const targets = roles[literalSide];
4861
+ if (targets.length === 1) {
4862
+ return leftField !== void 0 ? [head, left, targets[0]] : [head, targets[0], right];
4863
+ }
4864
+ const includesExpr = ["array/includes", [...targets], leftField !== void 0 ? left : right];
4865
+ return NEGATED_EQUALITY_OPS.has(head) ? ["not", includesExpr] : includesExpr;
4866
+ }
4867
+ }
4260
4868
  }
4261
- if (!entityResult.success || !traitsResult.success || !pagesResult.success) {
4262
- return { success: false, errors: ["Internal error: unexpected failure state"] };
4869
+ if (head === "array/includes" && node.length === 3 && Array.isArray(node[1])) {
4870
+ const needleField = directUserField(node[2]);
4871
+ if (needleField !== void 0 && roleFields.has(needleField)) {
4872
+ const members = literalHaystackMembers(node[1]);
4873
+ if (members !== void 0) {
4874
+ const expanded = [];
4875
+ for (const literal of members) {
4876
+ const mapped = roles[literal];
4877
+ if (mapped) {
4878
+ for (const target of mapped) if (!expanded.includes(target)) expanded.push(target);
4879
+ } else if (!expanded.includes(literal)) {
4880
+ expanded.push(literal);
4881
+ }
4882
+ }
4883
+ const isListCall = node[1][0] === "list";
4884
+ return ["array/includes", isListCall ? ["list", ...expanded] : expanded, node[2]];
4885
+ }
4886
+ }
4263
4887
  }
4264
- const pullErrors = await this.pullSiblingTraits(traitsResult.data, imports, importChain);
4265
- if (pullErrors.length > 0) {
4888
+ return node.map((item) => rewriteRoleLiteralsInValue(item, roleFields, roles));
4889
+ }
4890
+ if (typeof node !== "object") return node;
4891
+ const next = {};
4892
+ for (const [key, value] of Object.entries(node)) {
4893
+ next[key] = rewriteRoleLiteralsInValue(value, roleFields, roles);
4894
+ }
4895
+ return next;
4896
+ }
4897
+ function rewriteRoleLiteralsInTrait(trait, roleFields, roles) {
4898
+ if (roleFields.size === 0 || Object.keys(roles).length === 0) return trait;
4899
+ const rewrite = (v) => rewriteRoleLiteralsInValue(v, roleFields, roles);
4900
+ const next = { ...trait };
4901
+ const sm = trait.stateMachine;
4902
+ if (sm) {
4903
+ next.stateMachine = {
4904
+ ...sm,
4905
+ transitions: (sm.transitions ?? []).map((t) => ({
4906
+ ...t,
4907
+ ...t.guard !== void 0 ? { guard: rewrite(t.guard) } : {},
4908
+ ...t.effects ? { effects: rewrite(t.effects) } : {}
4909
+ }))
4910
+ };
4911
+ }
4912
+ if (trait.ticks) {
4913
+ next.ticks = trait.ticks.map((tick) => ({
4914
+ ...tick,
4915
+ ...tick.guard !== void 0 ? { guard: rewrite(tick.guard) } : {},
4916
+ effects: rewrite(tick.effects)
4917
+ }));
4918
+ }
4919
+ if (trait.listens) {
4920
+ next.listens = trait.listens.map((l) => ({
4921
+ ...l,
4922
+ ...l.guard !== void 0 ? { guard: rewrite(l.guard) } : {},
4923
+ ...l.payloadMapping ? { payloadMapping: rewrite(l.payloadMapping) } : {}
4924
+ }));
4925
+ }
4926
+ if (trait.initialEffects) {
4927
+ next.initialEffects = rewrite(trait.initialEffects);
4928
+ }
4929
+ if (trait.config) {
4930
+ const nextConfig = {};
4931
+ for (const [key, field] of Object.entries(trait.config)) {
4932
+ nextConfig[key] = field.default === void 0 ? field : { ...field, default: rewrite(field.default) };
4933
+ }
4934
+ next.config = nextConfig;
4935
+ }
4936
+ if (trait.sourceEntityDefinition) {
4937
+ next.sourceEntityDefinition = rewriteRoleLiteralsInEntity(trait.sourceEntityDefinition, roleFields, roles);
4938
+ }
4939
+ return next;
4940
+ }
4941
+ function rewriteRoleLiteralsInEntity(entity, roleFields, roles) {
4942
+ if (roleFields.size === 0 || Object.keys(roles).length === 0) return entity;
4943
+ const rewrite = (v) => rewriteRoleLiteralsInValue(v, roleFields, roles);
4944
+ return {
4945
+ ...entity,
4946
+ ...entity.read_policy !== void 0 ? { read_policy: rewrite(entity.read_policy) } : {},
4947
+ ...entity.create_policy !== void 0 ? { create_policy: rewrite(entity.create_policy) } : {},
4948
+ ...entity.update_policy !== void 0 ? { update_policy: rewrite(entity.update_policy) } : {},
4949
+ ...entity.delete_policy !== void 0 ? { delete_policy: rewrite(entity.delete_policy) } : {}
4950
+ };
4951
+ }
4952
+ function renameRelationTargetsInField(field, entitySubs, entityIds) {
4953
+ let next = field;
4954
+ if (next.type === "relation") {
4955
+ const to = entitySubs.get(next.relation.entity);
4956
+ if (to !== void 0) {
4957
+ next = { ...next, relation: { ...next.relation, entity: to, entityId: entityIds.get(to) } };
4958
+ }
4959
+ }
4960
+ if ((next.type === "array" || next.type === "object") && next.items) {
4961
+ next = { ...next, items: renameRelationTargetsInField(next.items, entitySubs, entityIds) };
4962
+ }
4963
+ if (next.properties) {
4964
+ const nextProperties = {};
4965
+ for (const [key, value] of Object.entries(next.properties)) {
4966
+ nextProperties[key] = renameRelationTargetsInField(value, entitySubs, entityIds);
4967
+ }
4968
+ next = { ...next, properties: nextProperties };
4969
+ }
4970
+ return next;
4971
+ }
4972
+ function renameEntityRelationTargets(entity, entitySubs, entityIds) {
4973
+ if (entitySubs.size === 0) return entity;
4974
+ return { ...entity, fields: entity.fields.map((f) => renameRelationTargetsInField(f, entitySubs, entityIds)) };
4975
+ }
4976
+ function renameSourceEntityDefinition(trait, subs, entityIds) {
4977
+ const src = trait.sourceEntityDefinition;
4978
+ if (!src || subs.size === 0) return trait;
4979
+ const renamedName = subs.get(src.name) ?? src.name;
4980
+ const nextSrc = renameEntityRelationTargets({ ...src, name: renamedName }, subs, entityIds);
4981
+ return { ...trait, sourceEntityDefinition: nextSrc };
4982
+ }
4983
+ function renamePayloadEntity(fields, rename) {
4984
+ return fields.map((field) => {
4985
+ const renamedEntity = field.entity !== void 0 ? rename(field.entity) : void 0;
4986
+ const renamedProps = field.properties ? renamePayloadEntity(field.properties, rename) : field.properties;
4987
+ return {
4988
+ ...field,
4989
+ ...renamedEntity !== void 0 ? { entity: renamedEntity } : {},
4990
+ ...renamedProps !== void 0 ? { properties: renamedProps } : {}
4991
+ };
4992
+ });
4993
+ }
4994
+ function renamePayloadEntityMarkers(trait, rename) {
4995
+ const sm = trait.stateMachine;
4996
+ const nextEvents = sm?.events ? sm.events.map(
4997
+ (ev) => ev.payloadSchema ? { ...ev, payloadSchema: renamePayloadEntity(ev.payloadSchema, rename) } : ev
4998
+ ) : void 0;
4999
+ const nextEmits = trait.emits ? trait.emits.map(
5000
+ (em) => em.payloadSchema ? { ...em, payloadSchema: renamePayloadEntity(em.payloadSchema, rename) } : em
5001
+ ) : void 0;
5002
+ return {
5003
+ ...trait,
5004
+ ...sm && nextEvents ? { stateMachine: { ...sm, events: nextEvents } } : {},
5005
+ ...nextEmits ? { emits: nextEmits } : {}
5006
+ };
5007
+ }
5008
+ function walkEntityInPayloadMapping(payloadMapping, rename, props) {
5009
+ const next = {};
5010
+ for (const [key, value] of Object.entries(payloadMapping)) {
5011
+ next[key] = renameEntityInEffect(value, rename, props);
5012
+ }
5013
+ return next;
5014
+ }
5015
+ function renameEntitiesInTrait(trait, entitySubs) {
5016
+ if (entitySubs.size === 0) return trait;
5017
+ const rename = (name) => entitySubs.get(name);
5018
+ const withTokens = (value) => renameEntityNameTokensInValue(value, entitySubs);
5019
+ const nextLinked = trait.linkedEntity !== void 0 ? entitySubs.get(trait.linkedEntity) ?? trait.linkedEntity : trait.linkedEntity;
5020
+ const sm = trait.stateMachine;
5021
+ const nextTransitions = sm?.transitions ? sm.transitions.map((t) => ({
5022
+ ...t,
5023
+ ...t.guard !== void 0 ? { guard: withTokens(renameEntityInEffect(t.guard, rename, REBIND_ENTITY_PROPS)) } : {},
5024
+ effects: t.effects ? withTokens(renameEntityInEffects(t.effects, rename, REBIND_ENTITY_PROPS)) : t.effects
5025
+ })) : sm?.transitions;
5026
+ const nextTicks = trait.ticks ? trait.ticks.map((tick) => ({
5027
+ ...tick,
5028
+ ...tick.guard !== void 0 ? { guard: withTokens(renameEntityInEffect(tick.guard, rename, REBIND_ENTITY_PROPS)) } : {},
5029
+ effects: withTokens(renameEntityInEffects(
5030
+ tick.effects,
5031
+ rename,
5032
+ REBIND_ENTITY_PROPS
5033
+ ))
5034
+ })) : trait.ticks;
5035
+ const nextListens = trait.listens ? trait.listens.map((l) => ({
5036
+ ...l,
5037
+ ...l.guard !== void 0 ? { guard: withTokens(renameEntityInEffect(l.guard, rename, REBIND_ENTITY_PROPS)) } : {},
5038
+ ...l.payloadMapping ? { payloadMapping: withTokens(walkEntityInPayloadMapping(l.payloadMapping, rename, REBIND_ENTITY_PROPS)) } : {}
5039
+ })) : trait.listens;
5040
+ const nextInitial = trait.initialEffects ? withTokens(renameEntityInEffects(
5041
+ trait.initialEffects,
5042
+ rename,
5043
+ REBIND_ENTITY_PROPS
5044
+ )) : trait.initialEffects;
5045
+ return renamePayloadEntityMarkers(
5046
+ {
5047
+ ...trait,
5048
+ linkedEntity: nextLinked,
5049
+ ...sm ? { stateMachine: { ...sm, transitions: nextTransitions ?? [] } } : {},
5050
+ ...nextTicks !== void 0 ? { ticks: nextTicks } : {},
5051
+ ...nextListens !== void 0 ? { listens: nextListens } : {},
5052
+ ...nextInitial !== void 0 ? { initialEffects: nextInitial } : {}
5053
+ },
5054
+ rename
5055
+ );
5056
+ }
5057
+ function rewriteEntityRefIds(trait, entitySubs, entityIds) {
5058
+ const refs = trait.entityRefIds;
5059
+ if (!refs) return trait;
5060
+ const out = {};
5061
+ for (const [from, oldId] of Object.entries(refs)) {
5062
+ const name = entitySubs.get(from) ?? from;
5063
+ out[name] = entityIds.get(name) ?? oldId;
5064
+ }
5065
+ return { ...trait, entityRefIds: out };
5066
+ }
5067
+ function applyAliasEntityRenames(trait, subs, entityIds) {
5068
+ if (subs.size === 0) return trait;
5069
+ const rename = (name) => subs.get(name);
5070
+ const withTokens = (value) => renameEntityNameTokensInValue(value, subs);
5071
+ const sm = trait.stateMachine;
5072
+ const nextTransitions = sm?.transitions ? sm.transitions.map((t) => ({
5073
+ ...t,
5074
+ ...t.guard !== void 0 ? { guard: withTokens(renameEntityInEffect(t.guard, rename, REBIND_ENTITY_PROPS)) } : {},
5075
+ effects: t.effects ? withTokens(renameEntityInEffects(t.effects, rename, REBIND_ENTITY_PROPS)) : t.effects
5076
+ })) : sm?.transitions;
5077
+ const nextTicks = trait.ticks ? trait.ticks.map((tick) => ({
5078
+ ...tick,
5079
+ ...tick.guard !== void 0 ? { guard: withTokens(renameEntityInEffect(tick.guard, rename, REBIND_ENTITY_PROPS)) } : {},
5080
+ effects: withTokens(
5081
+ renameEntityInEffects(tick.effects, rename, REBIND_ENTITY_PROPS)
5082
+ )
5083
+ })) : trait.ticks;
5084
+ const next = {
5085
+ ...trait,
5086
+ ...sm ? { stateMachine: { ...sm, transitions: nextTransitions ?? [] } } : {},
5087
+ ...nextTicks !== void 0 ? { ticks: nextTicks } : {}
5088
+ };
5089
+ return rewriteEntityRefIds(next, subs, entityIds);
5090
+ }
5091
+ function collectEntityNamesInTrait(trait, candidates) {
5092
+ const collected = /* @__PURE__ */ new Set();
5093
+ const collect = (name) => {
5094
+ if (candidates.has(name)) collected.add(name);
5095
+ return void 0;
5096
+ };
5097
+ const sm = trait.stateMachine;
5098
+ for (const t of sm?.transitions ?? []) {
5099
+ if (t.guard !== void 0) renameEntityInEffect(t.guard, collect, REBIND_ENTITY_PROPS);
5100
+ if (t.effects) renameEntityInEffects(t.effects, collect, REBIND_ENTITY_PROPS);
5101
+ }
5102
+ for (const tick of trait.ticks ?? []) {
5103
+ if (tick.guard !== void 0) renameEntityInEffect(tick.guard, collect, REBIND_ENTITY_PROPS);
5104
+ renameEntityInEffects(tick.effects, collect, REBIND_ENTITY_PROPS);
5105
+ }
5106
+ for (const l of trait.listens ?? []) {
5107
+ if (l.guard !== void 0) renameEntityInEffect(l.guard, collect, REBIND_ENTITY_PROPS);
5108
+ if (l.payloadMapping) walkEntityInPayloadMapping(l.payloadMapping, collect, REBIND_ENTITY_PROPS);
5109
+ }
5110
+ if (trait.initialEffects) {
5111
+ renameEntityInEffects(trait.initialEffects, collect, REBIND_ENTITY_PROPS);
5112
+ }
5113
+ return collected;
5114
+ }
5115
+ function collectRelationTargets(field, candidates, out) {
5116
+ if (field.type === "relation" && candidates.has(field.relation.entity)) out.add(field.relation.entity);
5117
+ if ((field.type === "array" || field.type === "object") && field.items) {
5118
+ collectRelationTargets(field.items, candidates, out);
5119
+ }
5120
+ if (field.properties) {
5121
+ for (const value of Object.values(field.properties)) collectRelationTargets(value, candidates, out);
5122
+ }
5123
+ }
5124
+ function relationTargetsOfEntity(entity, candidates) {
5125
+ const out = /* @__PURE__ */ new Set();
5126
+ for (const field of entity.fields) collectRelationTargets(field, candidates, out);
5127
+ return out;
5128
+ }
5129
+ function rewriteListenSources(trait, subs, idByName, orbitalRename) {
5130
+ const listens = trait.listens;
5131
+ if (!listens || listens.length === 0) return trait;
5132
+ let changed = false;
5133
+ const nextListens = listens.map((listen) => {
5134
+ const source = listen.source;
5135
+ if (!source) return listen;
5136
+ if (source.kind === "trait") {
5137
+ const target = subs.get(source.trait);
5138
+ if (target === void 0 || target === source.trait) return listen;
5139
+ changed = true;
5140
+ const traitId = idByName.get(target);
5141
+ return {
5142
+ ...listen,
5143
+ source: { kind: "trait", trait: target, ...traitId ? { traitId } : {} }
5144
+ };
5145
+ }
5146
+ if (source.kind === "orbital" && orbitalRename && source.orbital === orbitalRename.from) {
5147
+ const targetTrait = subs.get(source.trait) ?? source.trait;
5148
+ changed = true;
5149
+ const traitId = idByName.get(targetTrait);
5150
+ return {
5151
+ ...listen,
5152
+ source: {
5153
+ kind: "orbital",
5154
+ orbital: orbitalRename.to,
5155
+ trait: targetTrait,
5156
+ ...traitId ? { traitId } : {}
5157
+ }
5158
+ };
5159
+ }
5160
+ return listen;
5161
+ });
5162
+ return changed ? { ...trait, listens: nextListens } : trait;
5163
+ }
5164
+ function isInlineEntity(ref) {
5165
+ return !isEntityReference(ref) && !isEntityCall(ref);
5166
+ }
5167
+ function inlineEntityRefsOf(orbital) {
5168
+ return [orbital.entity, ...orbital.auxiliaryEntities ?? []].filter(isInlineEntity);
5169
+ }
5170
+ function entityByNameForAlias(imports, alias, entityName) {
5171
+ const imported = imports.orbitals.get(alias);
5172
+ if (!imported) return void 0;
5173
+ for (const o of importedOrbitals(imported)) {
5174
+ const found = inlineEntityRefsOf(o).find((e) => e.name === entityName);
5175
+ if (found) return found;
5176
+ }
5177
+ return void 0;
5178
+ }
5179
+ function entityByNameAnyAlias(imports, entityName) {
5180
+ const aliases = Array.from(imports.orbitals.keys()).sort();
5181
+ for (const alias of aliases) {
5182
+ const found = entityByNameForAlias(imports, alias, entityName);
5183
+ if (found) return found;
5184
+ }
5185
+ return void 0;
5186
+ }
5187
+ function ownedTraitEntryFor(imports, alias, traitName) {
5188
+ const imported = imports.orbitals.get(alias);
5189
+ if (!imported) return void 0;
5190
+ const owner = importedOrbitals(imported).find(
5191
+ (o) => findTraitEntryInOrbital(o, traitName) !== null
5192
+ );
5193
+ if (!owner || !isInlineEntity(owner.entity)) return void 0;
5194
+ return { owner, ownerEntity: owner.entity, entry: findTraitEntryInOrbital(owner, traitName) };
5195
+ }
5196
+ function boundTraitOrbitalBinding(imports, alias, traitName) {
5197
+ const imported = imports.orbitals.get(alias);
5198
+ if (imported?.resolvedOrbitals) {
5199
+ for (const ro of imported.resolvedOrbitals) {
5200
+ const entry = findTraitEntryInOrbital(ro.original, traitName);
5201
+ if (!entry) continue;
5202
+ const bound2 = entry.linkedEntity;
5203
+ const resolvedEntities = [ro.entity, ...ro.auxiliaryEntities ?? []];
5204
+ const boundEntity2 = bound2 !== void 0 ? resolvedEntities.find((e) => e.name === bound2) : void 0;
5205
+ const requiredData2 = new Set(
5206
+ ro.traits.find((rt) => rt.trait.name === traitName)?.trait.entityContract?.requires ?? []
5207
+ );
5208
+ return { owner: ro.original, ownerEntity: ro.entity, entity: boundEntity2 ?? ro.entity, requiredData: requiredData2 };
5209
+ }
5210
+ }
5211
+ const owned = ownedTraitEntryFor(imports, alias, traitName);
5212
+ if (!owned) return void 0;
5213
+ const ownerEntities = inlineEntityRefsOf(owned.owner);
5214
+ const bound = owned.entry?.linkedEntity;
5215
+ const boundEntity = bound !== void 0 ? ownerEntities.find((e) => e.name === bound) : void 0;
5216
+ const requiredData = new Set(
5217
+ owned.entry && "stateMachine" in owned.entry ? owned.entry.entityContract?.requires ?? [] : []
5218
+ );
5219
+ return { owner: owned.owner, ownerEntity: owned.ownerEntity, entity: boundEntity ?? owned.ownerEntity, requiredData };
5220
+ }
5221
+ function auxEntitiesFromUnrebindTraitRefs(orbitalTraits, imports) {
5222
+ const out = [];
5223
+ const seen = /* @__PURE__ */ new Set();
5224
+ const push = (e) => {
5225
+ if (!seen.has(e.name)) {
5226
+ seen.add(e.name);
5227
+ out.push(e);
5228
+ }
5229
+ };
5230
+ for (const tr of orbitalTraits) {
5231
+ let ref;
5232
+ let linkedEntity;
5233
+ if (typeof tr === "string") {
5234
+ ref = tr;
5235
+ } else if ("ref" in tr) {
5236
+ ref = tr.ref;
5237
+ linkedEntity = tr.linkedEntity;
5238
+ } else {
5239
+ continue;
5240
+ }
5241
+ const parsed = parseImportedTraitRef(ref);
5242
+ if (!parsed) continue;
5243
+ const binding = boundTraitOrbitalBinding(imports, parsed.alias, parsed.traitName);
5244
+ if (!binding) continue;
5245
+ if (linkedEntity === void 0) {
5246
+ push(binding.entity);
5247
+ }
5248
+ for (const e of inlineEntityRefsOf(binding.owner)) {
5249
+ if (e.name !== binding.ownerEntity.name) push(e);
5250
+ }
5251
+ }
5252
+ return out;
5253
+ }
5254
+ function rewriteSelfRelationTarget(field, oldName, newName, newId) {
5255
+ if (field.type === "relation" && field.relation.entity === oldName) {
5256
+ field.relation = { ...field.relation, entity: newName, entityId: newId };
5257
+ }
5258
+ if (field.type === "array" && field.items) {
5259
+ rewriteSelfRelationTarget(field.items, oldName, newName, newId);
5260
+ }
5261
+ if (field.type === "object" && field.items) {
5262
+ rewriteSelfRelationTarget(field.items, oldName, newName, newId);
5263
+ }
5264
+ if (field.properties) {
5265
+ for (const key of Object.keys(field.properties)) {
5266
+ rewriteSelfRelationTarget(field.properties[key], oldName, newName, newId);
5267
+ }
5268
+ }
5269
+ }
5270
+ function mergeImportedEntityFields(callerEntity, importedEntity, intrinsicOnly, requiredData) {
5271
+ const existingNames = new Set(
5272
+ callerEntity.fields.map((f) => f.name).filter((n) => n !== void 0)
5273
+ );
5274
+ const oldName = importedEntity.name;
5275
+ const newName = callerEntity.name;
5276
+ const newId = callerEntity.id;
5277
+ for (const field of importedEntity.fields) {
5278
+ if (intrinsicOnly && field.intrinsic !== true) continue;
5279
+ if (field.name === void 0) continue;
5280
+ if (requiredData.has(field.name) && field.intrinsic !== true) continue;
5281
+ if (existingNames.has(field.name)) continue;
5282
+ const cloned = structuredClone(field);
5283
+ rewriteSelfRelationTarget(cloned, oldName, newName, newId);
5284
+ callerEntity.fields.push(cloned);
5285
+ }
5286
+ }
5287
+ function mergeImportedEntityFieldsIntoOrbital(orbitalTraits, entity, declaredAuxEntities, imports) {
5288
+ const mergedAliases = /* @__PURE__ */ new Set();
5289
+ const pending = [];
5290
+ for (const tr of orbitalTraits) {
5291
+ let ref;
5292
+ let linkedEntity;
5293
+ if (typeof tr === "string") {
5294
+ ref = tr;
5295
+ } else if ("ref" in tr) {
5296
+ ref = tr.ref;
5297
+ linkedEntity = tr.linkedEntity;
5298
+ } else {
5299
+ continue;
5300
+ }
5301
+ const parsed = parseImportedTraitRef(ref);
5302
+ if (!parsed) continue;
5303
+ const binding = boundTraitOrbitalBinding(imports, parsed.alias, parsed.traitName);
5304
+ if (!binding) continue;
5305
+ const carriesFields = linkedEntity !== void 0 ? true : binding.entity.name === entity.name;
5306
+ if (!carriesFields) continue;
5307
+ const key = `${parsed.alias}\0${parsed.traitName}`;
5308
+ if (mergedAliases.has(key)) continue;
5309
+ mergedAliases.add(key);
5310
+ pending.push({
5311
+ target: linkedEntity,
5312
+ imported: binding.entity,
5313
+ intrinsicOnly: linkedEntity === void 0,
5314
+ requiredData: binding.requiredData
5315
+ });
5316
+ }
5317
+ for (const pm of pending) {
5318
+ const auxTarget = pm.target !== void 0 && pm.target !== entity.name ? declaredAuxEntities.find((e) => e.name === pm.target) : void 0;
5319
+ mergeImportedEntityFields(auxTarget ?? entity, pm.imported, pm.intrinsicOnly, pm.requiredData);
5320
+ }
5321
+ }
5322
+ function consumerEntityIdsOf(orbitals) {
5323
+ const out = /* @__PURE__ */ new Map();
5324
+ for (const orbital of orbitals) {
5325
+ for (const entity of inlineEntityRefsOf(orbital)) {
5326
+ if (entity.id) out.set(entity.name, entity.id);
5327
+ }
5328
+ }
5329
+ return out;
5330
+ }
5331
+ function materializedPrimaryEntity(upstreamEntity, upstreamOrbitalId, ref, localName) {
5332
+ const name = ref.entity ?? `${localName}${upstreamEntity.name}`;
5333
+ const id = asEntityId(
5334
+ deriveMaterializedId(upstreamEntity.id, upstreamOrbitalId, upstreamEntity.name, localName, "entity")
5335
+ );
5336
+ return { name, id };
5337
+ }
5338
+ function applyExtendFields(entity, extend, fieldSubs, consumerEntityIds, localName) {
5339
+ if (!extend || extend.length === 0) return { entity, errors: [] };
5340
+ const errors = [];
5341
+ const taken = new Set(entity.fields.map((f) => f.name).filter((n) => Boolean(n)));
5342
+ for (const target of fieldSubs.values()) taken.add(target);
5343
+ const added = [];
5344
+ for (const field of extend) {
5345
+ const name = field.name;
5346
+ if (!name) continue;
5347
+ if (taken.has(name)) {
5348
+ errors.push(
5349
+ `Orbital "${localName}" declares extend field "${name}" but the upstream primary entity already has a field of that name after "fields {}" renames (ORB_O_EXTEND_FIELD_COLLISION)`
5350
+ );
5351
+ continue;
5352
+ }
5353
+ taken.add(name);
5354
+ if (field.type === "relation" && !field.relation.entityId) {
5355
+ const targetId = consumerEntityIds.get(field.relation.entity);
5356
+ added.push(targetId ? { ...field, relation: { ...field.relation, entityId: targetId } } : field);
5357
+ continue;
5358
+ }
5359
+ added.push(field);
5360
+ }
5361
+ if (added.length === 0) return { entity, errors };
5362
+ return { entity: { ...entity, fields: [...entity.fields, ...added] }, errors };
5363
+ }
5364
+ function deriveMaterializedId(sourceId, upstreamOrbitalId, sourceName, localName, kind) {
5365
+ const parent = sourceId ?? `${idPrefix(kind)}orbital-import-seed:${upstreamOrbitalId ?? "no-orbital-id"}:${sourceName}`;
5366
+ return deriveId(parent, localName);
5367
+ }
5368
+ function navigatePathSegments(path) {
5369
+ return path.split("/").filter((segment) => segment.length > 0);
5370
+ }
5371
+ function navigateParamStrippedPrefix(path) {
5372
+ const segments = navigatePathSegments(path);
5373
+ const last = segments[segments.length - 1];
5374
+ if (last === void 0 || !last.startsWith(":")) return void 0;
5375
+ return `/${segments.slice(0, -1).join("/")}/`;
5376
+ }
5377
+ function rewriteConcatPrefix(literalPrefix, pathMap) {
5378
+ const normalized = literalPrefix.endsWith("/") ? literalPrefix : `${literalPrefix}/`;
5379
+ for (const [upstreamPath, finalPath] of pathMap) {
5380
+ const stripped = navigateParamStrippedPrefix(upstreamPath);
5381
+ if (stripped === void 0 || stripped !== normalized) continue;
5382
+ const finalStripped = navigateParamStrippedPrefix(finalPath);
5383
+ if (finalStripped !== void 0) return finalStripped;
5384
+ }
5385
+ return void 0;
5386
+ }
5387
+ function rewriteNavigateTargets(node, pathMap) {
5388
+ if (node === null || node === void 0) return node;
5389
+ if (Array.isArray(node)) {
5390
+ if (node[0] === "navigate" && node.length >= 2) {
5391
+ const target = node[1];
5392
+ if (typeof target === "string" && pathMap.has(target)) {
5393
+ return [node[0], pathMap.get(target), ...node.slice(2).map((v) => rewriteNavigateTargets(v, pathMap))];
5394
+ }
5395
+ if (Array.isArray(target) && target[0] === "str/concat" && typeof target[1] === "string" && target[1].startsWith("/")) {
5396
+ const rewrittenPrefix = rewriteConcatPrefix(target[1], pathMap);
5397
+ const nextTarget = rewrittenPrefix !== void 0 ? [target[0], rewrittenPrefix, ...target.slice(2)] : target;
5398
+ return [node[0], nextTarget, ...node.slice(2).map((v) => rewriteNavigateTargets(v, pathMap))];
5399
+ }
5400
+ }
5401
+ return node.map((item) => rewriteNavigateTargets(item, pathMap));
5402
+ }
5403
+ if (typeof node !== "object") return node;
5404
+ const next = {};
5405
+ for (const [key, value] of Object.entries(node)) {
5406
+ next[key] = rewriteNavigateTargets(value, pathMap);
5407
+ }
5408
+ return next;
5409
+ }
5410
+ function rewriteTraitNavigateTargets(trait, pathMap) {
5411
+ if (pathMap.size === 0) return trait;
5412
+ const rewrite = (v) => rewriteNavigateTargets(v, pathMap);
5413
+ const next = { ...trait };
5414
+ const sm = trait.stateMachine;
5415
+ if (sm) {
5416
+ next.stateMachine = {
5417
+ ...sm,
5418
+ transitions: (sm.transitions ?? []).map(
5419
+ (t) => t.effects ? { ...t, effects: rewrite(t.effects) } : t
5420
+ )
5421
+ };
5422
+ }
5423
+ if (trait.ticks) {
5424
+ next.ticks = trait.ticks.map((tick) => ({ ...tick, effects: rewrite(tick.effects) }));
5425
+ }
5426
+ if (trait.initialEffects) {
5427
+ next.initialEffects = rewrite(trait.initialEffects);
5428
+ }
5429
+ return next;
5430
+ }
5431
+ function rewriteConfigPagePaths(node, pathMap) {
5432
+ if (typeof node === "string") return pathMap.get(node) ?? node;
5433
+ if (Array.isArray(node)) return node.map((item) => rewriteConfigPagePaths(item, pathMap));
5434
+ if (node !== null && typeof node === "object") {
5435
+ const next = {};
5436
+ for (const [key, value] of Object.entries(node)) {
5437
+ next[key] = rewriteConfigPagePaths(value, pathMap);
5438
+ }
5439
+ return next;
5440
+ }
5441
+ return node;
5442
+ }
5443
+ function rewriteTraitConfigPagePaths(trait, pathMap) {
5444
+ if (pathMap.size === 0 || !trait.config) return trait;
5445
+ const nextConfig = {};
5446
+ for (const [key, field] of Object.entries(trait.config)) {
5447
+ nextConfig[key] = field.default === void 0 ? field : { ...field, default: rewriteConfigPagePaths(field.default, pathMap) };
5448
+ }
5449
+ return { ...trait, config: nextConfig };
5450
+ }
5451
+ function foldUseConfigOverride(declared, override, context) {
5452
+ if (!override) return declared;
5453
+ const values = {};
5454
+ for (const [key, field] of Object.entries(override)) {
5455
+ if (!(key in declared)) {
5456
+ refResolverLog.warn("use-config:unknown-knob", { ...context, key });
5457
+ continue;
5458
+ }
5459
+ if (field.default !== void 0) values[key] = field.default;
5460
+ }
5461
+ return Object.keys(values).length > 0 ? overrideDeclaredKnobs(declared, values) : declared;
5462
+ }
5463
+ function forwardConsumerAppKnobs(folded, consumer) {
5464
+ if (!consumer) return folded;
5465
+ const forwards = {};
5466
+ for (const [key, field] of Object.entries(folded)) {
5467
+ const token = field.default;
5468
+ if (typeof token !== "string" || !token.startsWith("@config.")) continue;
5469
+ const source = token.slice("@config.".length);
5470
+ if (source.includes(".") || !(source in consumer)) continue;
5471
+ if (consumer[source].default === void 0) continue;
5472
+ forwards[key] = source;
5473
+ }
5474
+ if (Object.keys(forwards).length === 0) return folded;
5475
+ const next = { ...folded };
5476
+ for (const [key, source] of Object.entries(forwards)) {
5477
+ next[key] = { ...folded[key], default: consumer[source].default, forwardedFrom: `@config.${source}` };
5478
+ }
5479
+ return next;
5480
+ }
5481
+ var ReferenceResolver = class _ReferenceResolver {
5482
+ loader;
5483
+ options;
5484
+ localTraits;
5485
+ /** id-keyed mirror of `localTraits`, populated wherever the trait carries an `id`. */
5486
+ localTraitsById = /* @__PURE__ */ new Map();
5487
+ /** Import scope of each loaded source orbital, keyed by its source path. */
5488
+ sourceImportsCache = /* @__PURE__ */ new Map();
5489
+ /**
5490
+ * {@link preResolveImportFile}'s cache, keyed by absolute source path —
5491
+ * `null` for a file whose own pre-resolution failed (best-effort, cached
5492
+ * too, so a repeat import doesn't retry a doomed resolve). Distinct from
5493
+ * {@link sourceImportsCache} (raw import SCOPE, no trait resolution) —
5494
+ * this holds the file's fully RESOLVED orbitals.
5495
+ */
5496
+ importFileResolveCache = /* @__PURE__ */ new Map();
5497
+ loaderInitialized = false;
5498
+ /** The schema's declared `config {}` — outermost rung of the forwarded-config chain (§4.5). */
5499
+ schemaConfig;
5500
+ /**
5501
+ * Schema-wide CONSUMER entity NAME → id, growing as each of THIS
5502
+ * schema's own orbitals finishes resolving. JS twin of the compiled
5503
+ * path's `consumer_entity_ids` (`orbital-compiler/src/phases/inline/
5504
+ * mod.rs`), extended the same way: once per orbital, right after it
5505
+ * resolves. Extended ONLY by {@link noteResolvedEntityIds} — called by
5506
+ * the free function {@link resolveSchema} after each of ITS OWN orbitals
5507
+ * finishes — never automatically inside `resolve()` itself, so the
5508
+ * nested `this.resolve()` call {@link materializeOrbitalRef} makes for an
5509
+ * external upstream orbital (a DIFFERENT file, never this consumer
5510
+ * schema) cannot pollute it.
5511
+ */
5512
+ schemaEntityIds = /* @__PURE__ */ new Map();
5513
+ /**
5514
+ * Entity NAME → id visible to the orbital CURRENTLY being resolved:
5515
+ * {@link schemaEntityIds} (every name an EARLIER orbital in this schema
5516
+ * already established) plus the current orbital's own declared primary +
5517
+ * auxiliary entities — JS twin of the compiled path's per-orbital `entity_
5518
+ * ids = consumer_entity_ids.clone(); entity_ids.extend(collect_orbital_
5519
+ * entity_ids(orbital))`, timed the same way (before this orbital's own
5520
+ * trait composition runs). Read by {@link applyLinkedEntityRename}'s call
5521
+ * sites so a call-site `-> Entity` rebind can REFRESH (never merely drop)
5522
+ * the trait's `entityRefIds` side-map when the rebind target's id is
5523
+ * already known — the gap `std-api-gateway` exposed: `RouteOrbital`'s
5524
+ * no-rebind `Audit.traits.AuditCaptureListener` pull establishes
5525
+ * `AuditEntry`'s id; `GatewayUserOrbital`, resolved LATER in the same
5526
+ * schema, rebinds `Browse.traits.BrowseItemBrowse -> AuditEntry` and must
5527
+ * see it. `resolve()` re-sets this fresh at its own entry (no restore
5528
+ * needed once it returns): nothing reads it once `resolve()` has
5529
+ * returned, and no `resolve()` call is ever active while another is on
5530
+ * this instance — the only recursive `this.resolve()` call
5531
+ * (`materializeOrbitalRef`'s upstream re-resolve) runs strictly BEFORE
5532
+ * `resolveSchema`'s own per-orbital loop begins, never nested inside it.
5533
+ */
5534
+ entityIdsInScope = /* @__PURE__ */ new Map();
5535
+ /**
5536
+ * Per-orbital name → the FINAL trait names {@link pullSiblingTraits}
5537
+ * auto-pulled for it (`ResolvedOrbital.name` keyed, set once per `resolve()`
5538
+ * call). JS twin of Rust's `pulled_by_orbital` (`inline/mod.rs`) — read by
5539
+ * {@link uniquifyCrossOrbitalPulledSiblings}, run once by the free
5540
+ * function {@link resolveSchema} AFTER every orbital in the schema has
5541
+ * resolved, because the rename decision (does this pulled name collide
5542
+ * with ANOTHER orbital's own declared trait name?) needs the WHOLE
5543
+ * schema's roster, not just this orbital's — exactly why Rust's own
5544
+ * `uniquify_cross_orbital_pulled_siblings` runs once, after its per-orbital
5545
+ * inline loop, not inside `inline_orbital` itself.
5546
+ */
5547
+ pulledTraitNamesByOrbital = /* @__PURE__ */ new Map();
5548
+ /**
5549
+ * Seed {@link schemaEntityIds} with EVERY orbital's PRIMARY (+ any
5550
+ * already-declared auxiliary) entity name → id, from the RAW pre-resolve
5551
+ * schema — JS twin of the compiled path's `consumer_entity_ids` INITIAL
5552
+ * build (`orbital-compiler/src/phases/inline/mod.rs`, `schema.orbitals
5553
+ * .iter().flat_map(...)`), which scans ALL orbitals' primaries up front,
5554
+ * before ANY of them inlines — not just the ones resolved so far. Without
5555
+ * this, an EARLY-resolved orbital's own `entityRefIds` secondary
5556
+ * references to a LATER orbital's primary entity (`RouteOrbital`'s
5557
+ * `entityRefIds["RateBucket"]`, `RateBucket` being a DIFFERENT, not-yet-
5558
+ * resolved orbital's own primary in `std-api-gateway`) would see nothing
5559
+ * in {@link entityIdsInScope} and {@link consumerKnownEntityRebindSubs}
5560
+ * would never refresh the stale atom-baked id. Called by {@link
5561
+ * resolveSchema} ONCE, before its per-orbital loop begins; {@link
5562
+ * noteResolvedEntityIds} then keeps widening past this seed with each
5563
+ * orbital's post-resolve auxiliary discoveries (Gap #22, sibling pulls),
5564
+ * same as before.
5565
+ */
5566
+ seedSchemaEntityIds(orbitals) {
5567
+ const next = new Map(this.schemaEntityIds);
5568
+ for (const orbital of orbitals) {
5569
+ for (const e of inlineEntityRefsOf(orbital)) {
5570
+ if (e.id) next.set(e.name, e.id);
5571
+ }
5572
+ }
5573
+ this.schemaEntityIds = next;
5574
+ }
5575
+ /**
5576
+ * Extend {@link schemaEntityIds} with a just-resolved orbital's FINAL
5577
+ * entity set — primary + every auxiliary entity resolution carried in
5578
+ * (including a no-rebind sibling pull's own bound entity,
5579
+ * `ResolvedOrbital.auxiliaryEntities`). Mirrors the compiled path's
5580
+ * `consumer_entity_ids.extend(collect_orbital_entity_ids(orbital))`,
5581
+ * called the same way: once per orbital, immediately after it resolves.
5582
+ * Called by {@link resolveSchema}'s own per-orbital loop only.
5583
+ */
5584
+ noteResolvedEntityIds(resolved) {
5585
+ const next = new Map(this.schemaEntityIds);
5586
+ if (resolved.entity.id) next.set(resolved.entity.name, resolved.entity.id);
5587
+ for (const aux of resolved.auxiliaryEntities ?? []) {
5588
+ if (aux.id) next.set(aux.name, aux.id);
5589
+ }
5590
+ this.schemaEntityIds = next;
5591
+ }
5592
+ /**
5593
+ * Make auto-pulled sibling traits app-unique across orbitals — JS twin of
5594
+ * Rust's `uniquify_cross_orbital_pulled_siblings` (`inline/mod.rs`), called
5595
+ * by the free function {@link resolveSchema} once every orbital in the
5596
+ * schema has resolved (mirroring Rust's own post-per-orbital-loop timing:
5597
+ * the rename decision needs the WHOLE schema's trait-name roster, built
5598
+ * fresh here rather than grown incrementally like {@link schemaEntityIds}).
5599
+ * An auto-pulled sibling keeps its source name within its OWN orbital, so a
5600
+ * `@trait.<Sibling>` reference inside that orbital still resolves — but
5601
+ * when TWO orbitals in the same schema each declare (pulled OR explicit) a
5602
+ * trait of the SAME name, that name collides app-wide. Only renames a
5603
+ * PULLED copy (never an explicitly-authored trait ref —
5604
+ * {@link pulledTraitNamesByOrbital} is the eligibility set) whose name is
5605
+ * ALSO declared by at least one OTHER orbital, prefixing it with the
5606
+ * owning orbital's own name; the prefixed name must itself be free
5607
+ * schema-wide or the rename is skipped (matches Rust: a collision on the
5608
+ * PREFIXED name is left for the validator, never silently double-renamed).
5609
+ * Mutates `orbitals`' traits in place, same mutation style as
5610
+ * {@link pullSiblingTraits}.
5611
+ */
5612
+ uniquifyCrossOrbitalPulledSiblings(orbitals) {
5613
+ if (this.pulledTraitNamesByOrbital.size === 0) return;
5614
+ const nameOrbitalCount = /* @__PURE__ */ new Map();
5615
+ for (const orbital of orbitals) {
5616
+ const local = new Set(
5617
+ orbital.traits.map((rt) => rt.trait.name).filter((n) => Boolean(n))
5618
+ );
5619
+ for (const name of local) {
5620
+ nameOrbitalCount.set(name, (nameOrbitalCount.get(name) ?? 0) + 1);
5621
+ }
5622
+ }
5623
+ for (const orbital of orbitals) {
5624
+ const pulledNames = this.pulledTraitNamesByOrbital.get(orbital.name);
5625
+ if (!pulledNames || pulledNames.size === 0) continue;
5626
+ const renames = /* @__PURE__ */ new Map();
5627
+ for (const oldName of pulledNames) {
5628
+ if ((nameOrbitalCount.get(oldName) ?? 0) <= 1) continue;
5629
+ const newName = `${orbital.name}${oldName}`;
5630
+ if (nameOrbitalCount.has(newName)) continue;
5631
+ renames.set(oldName, newName);
5632
+ }
5633
+ if (renames.size === 0) continue;
5634
+ for (const rt of orbital.traits) {
5635
+ if (rt.trait.name && renames.has(rt.trait.name)) {
5636
+ rt.trait = { ...rt.trait, name: renames.get(rt.trait.name) };
5637
+ }
5638
+ }
5639
+ const idByName = /* @__PURE__ */ new Map();
5640
+ for (const rt of orbital.traits) {
5641
+ if (rt.trait.name) idByName.set(rt.trait.name, rt.trait.id);
5642
+ }
5643
+ for (const rt of orbital.traits) {
5644
+ rt.trait = renameTraitEmbeds(rt.trait, renames);
5645
+ rt.trait = rewriteListenSources(rt.trait, renames, idByName);
5646
+ }
5647
+ }
5648
+ }
5649
+ constructor(options) {
5650
+ this.options = options;
5651
+ this.loader = options.loader;
5652
+ this.schemaConfig = options.schemaConfig;
5653
+ this.localTraits = options.localTraits ?? /* @__PURE__ */ new Map();
5654
+ for (const trait of this.localTraits.values()) {
5655
+ if (trait.id) {
5656
+ this.localTraitsById.set(trait.id, trait);
5657
+ }
5658
+ }
5659
+ }
5660
+ async ensureLoader() {
5661
+ if (this.loader || this.loaderInitialized) return;
5662
+ this.loaderInitialized = true;
5663
+ try {
5664
+ const { ExternalOrbitalLoader } = await import('./external-loader-CISUEINQ.js');
5665
+ this.loader = new ExternalOrbitalLoader(this.options);
5666
+ } catch {
5667
+ }
5668
+ }
5669
+ /**
5670
+ * Resolve all references in an orbital.
5671
+ */
5672
+ async resolve(orbital, sourcePath, chain, opts) {
5673
+ const errors = [];
5674
+ const warnings = [];
5675
+ const importChain = chain ?? { push: () => null, pop: () => {
5676
+ }, clone() {
5677
+ return this;
5678
+ } };
5679
+ this.entityIdsInScope = new Map([...this.schemaEntityIds, ...inlineEntityRefsOf(orbital).flatMap((e) => e.id ? [[e.name, e.id]] : [])]);
5680
+ const traitsList = orbital.traits ?? [];
5681
+ const alreadyResolved = traitsList.length > 0 && traitsList.every((t) => isInlineTrait(t));
5682
+ const importsResult = alreadyResolved ? { success: true, data: { orbitals: /* @__PURE__ */ new Map(), idIndex: /* @__PURE__ */ new Map() }} : await this.resolveImports(orbital.uses ?? [], sourcePath, importChain);
5683
+ if (!importsResult.success) {
5684
+ return { success: false, errors: importsResult.errors };
5685
+ }
5686
+ const imports = importsResult.data;
5687
+ imports.idIndex = buildIdIndex(orbital, imports.orbitals);
5688
+ const gap22AuxEntities = auxEntitiesFromUnrebindTraitRefs(orbital.traits ?? [], imports);
5689
+ if (gap22AuxEntities.length > 0) {
5690
+ const next = new Map(this.entityIdsInScope);
5691
+ for (const e of gap22AuxEntities) {
5692
+ if (e.id && !next.has(e.name)) next.set(e.name, e.id);
5693
+ }
5694
+ this.entityIdsInScope = next;
5695
+ }
5696
+ if (isInlineEntity(orbital.entity)) {
5697
+ mergeImportedEntityFieldsIntoOrbital(
5698
+ orbital.traits ?? [],
5699
+ orbital.entity,
5700
+ (orbital.auxiliaryEntities ?? []).filter(isInlineEntity),
5701
+ imports
5702
+ );
5703
+ }
5704
+ const entityResult = this.resolveEntity(orbital.entity, imports);
5705
+ if (!entityResult.success) {
5706
+ errors.push(...entityResult.errors);
5707
+ }
5708
+ const traitsResult = await this.resolveTraits(orbital.traits, imports, importChain, orbital.config);
5709
+ if (!traitsResult.success) {
5710
+ errors.push(...traitsResult.errors);
5711
+ }
5712
+ const pagesResult = await this.resolvePages(orbital.pages, imports, importChain);
5713
+ if (!pagesResult.success) {
5714
+ errors.push(...pagesResult.errors);
5715
+ }
5716
+ if (errors.length > 0) {
5717
+ return { success: false, errors };
5718
+ }
5719
+ if (!entityResult.success || !traitsResult.success || !pagesResult.success) {
5720
+ return { success: false, errors: ["Internal error: unexpected failure state"] };
5721
+ }
5722
+ const { errors: pullErrors, auxEntities: pulledAuxEntities, pulledNames } = await this.pullSiblingTraits(
5723
+ traitsResult.data,
5724
+ imports,
5725
+ importChain,
5726
+ orbital.config
5727
+ );
5728
+ if (pullErrors.length > 0) {
4266
5729
  return { success: false, errors: pullErrors };
4267
5730
  }
5731
+ this.pulledTraitNamesByOrbital.set(orbital.name, pulledNames);
5732
+ const known = /* @__PURE__ */ new Set([entityResult.data.entity.name]);
5733
+ const declaredAux = (orbital.auxiliaryEntities ?? []).filter(isInlineEntity);
5734
+ for (const e of declaredAux) known.add(e.name);
5735
+ const combined = [...declaredAux];
5736
+ for (const e of [...gap22AuxEntities, ...pulledAuxEntities]) {
5737
+ if (!known.has(e.name)) {
5738
+ known.add(e.name);
5739
+ combined.push(e);
5740
+ }
5741
+ }
5742
+ const resolvedAuxEntities = combined.length > 0 ? combined : void 0;
4268
5743
  for (const resolvedTrait of traitsResult.data) {
4269
5744
  resolvedTrait.trait = resolveEntityTokensById(resolvedTrait.trait, imports.idIndex);
4270
5745
  resolvedTrait.trait = resolveConfigRefsById(resolvedTrait.trait, imports.idIndex);
@@ -4277,6 +5752,14 @@ var ReferenceResolver = class {
4277
5752
  }
4278
5753
  throw e;
4279
5754
  }
5755
+ if (!opts?.skipTypeParamSentinels) {
5756
+ resolveOrbitalTypeParamSentinels(
5757
+ traitsResult.data,
5758
+ entityResult.data.entity,
5759
+ resolvedAuxEntities ?? [],
5760
+ orbital.types
5761
+ );
5762
+ }
4280
5763
  return {
4281
5764
  success: true,
4282
5765
  data: {
@@ -4284,6 +5767,7 @@ var ReferenceResolver = class {
4284
5767
  entity: entityResult.data.entity,
4285
5768
  entitySource: entityResult.data.source,
4286
5769
  traits: traitsResult.data,
5770
+ ...resolvedAuxEntities ? { auxiliaryEntities: resolvedAuxEntities } : {},
4287
5771
  pages: pagesResult.data,
4288
5772
  imports,
4289
5773
  original: orbital
@@ -4291,6 +5775,98 @@ var ReferenceResolver = class {
4291
5775
  warnings
4292
5776
  };
4293
5777
  }
5778
+ /**
5779
+ * Pre-resolve one imported FILE's own orbitals to completion — its own
5780
+ * `uses` (recursively, through THIS same method), its own trait refs,
5781
+ * its own sibling pulls, its own entity-ref-id rebinds — BEFORE the
5782
+ * consumer that names this alias ever folds or pulls from it. JS twin
5783
+ * of Rust's per-`uses` recursive `inline_orbital` call (`orbital-
5784
+ * compiler/src/phases/inline/mod.rs:1001-1013`): every `uses` alias's
5785
+ * OWN orbitals are inlined to completion, ahead of `ctx.add_alias_multi`
5786
+ * registering the alias for the consumer's own lookups. Without this, a
5787
+ * sibling-pull collision that is a genuine top-level PEER collision
5788
+ * INSIDE the imported file (`std-approval-request.orb`'s
5789
+ * `InlineBrowseItemBrowse6`/`…10`, both `ref: Dense.traits.
5790
+ * BrowseItemBrowse`, each embedding `@trait.DataGrid1`) never becomes
5791
+ * visible as a peer collision to the CONSUMER's own {@link
5792
+ * pullSiblingTraits} call — it arrives already flattened one level
5793
+ * deeper, sharing one JS-visible owner (see that method's own
5794
+ * drain-order doc for the full trace this ports).
5795
+ *
5796
+ * Cached per absolute `sourcePath` ({@link importFileResolveCache}) —
5797
+ * "a file imported twice resolves once" — so the cache must not bake in
5798
+ * any ONE call site's `uses { config }` override: the child resolver
5799
+ * below is seeded with this FILE's own raw, un-folded `config {}`
5800
+ * (`fileSchemaConfig`), never a folded override. A genuinely
5801
+ * call-site-configured explicit ref (`Alias.traits.X { config: {…} }`)
5802
+ * still resolves through the pre-existing lazy path
5803
+ * ({@link resolveTraitEntry} / {@link resolveTraitRefString}), which
5804
+ * this cache does not touch.
5805
+ *
5806
+ * Runs on a FRESH child `ReferenceResolver`, never `this` — `resolve()`'s
5807
+ * own `entityIdsInScope` / `schemaEntityIds` / `pulledTraitNamesByOrbital`
5808
+ * are single mutable instance state scoped to ONE active `resolve()` call
5809
+ * tree (see {@link entityIdsInScope}'s own doc: "no `resolve()` call is
5810
+ * ever active while another is on this instance"); reusing `this` here
5811
+ * would nest a `resolve()` call inside the CONSUMER's own still-active
5812
+ * `resolve()` → `resolveImports` call and corrupt that state once this
5813
+ * nested call returns. The child reuses `this.loader` (and therefore its
5814
+ * underlying `LoaderCache`) so raw parsing still dedupes exactly as
5815
+ * before. `chain` is threaded through unchanged (not cloned, matching
5816
+ * every other cross-call `chain` hand-off in this file) so genuine `uses`
5817
+ * cycles are still caught by the loader.
5818
+ *
5819
+ * Mirrors {@link resolveSchema}'s own orchestration (flatten orbital
5820
+ * references → collect local traits → seed schema entity ids →
5821
+ * per-orbital `resolve()` → `uniquifyCrossOrbitalPulledSiblings`) rather
5822
+ * than calling that free function directly — it accepts no `chain`
5823
+ * parameter, so a direct call would silently drop cycle protection one
5824
+ * level in.
5825
+ *
5826
+ * Best-effort: returns `null` (never throws) on any failure — a caller
5827
+ * falls back to the pre-existing raw-ref walk, matching this file's
5828
+ * other best-effort pre-passes (e.g. {@link precomputeReferenceFormPrimaryIds}).
5829
+ */
5830
+ async preResolveImportFile(fileOrbitals, sourcePath, fileSchemaConfig, chain) {
5831
+ const cached = this.importFileResolveCache.get(sourcePath);
5832
+ if (cached !== void 0) return cached;
5833
+ let result;
5834
+ try {
5835
+ result = await this.preResolveImportFileUncached(fileOrbitals, sourcePath, fileSchemaConfig, chain);
5836
+ } catch {
5837
+ result = null;
5838
+ }
5839
+ this.importFileResolveCache.set(sourcePath, result);
5840
+ return result;
5841
+ }
5842
+ async preResolveImportFileUncached(fileOrbitals, sourcePath, fileSchemaConfig, chain) {
5843
+ const child = new _ReferenceResolver({
5844
+ ...this.options,
5845
+ loader: this.loader,
5846
+ schemaConfig: fileSchemaConfig
5847
+ });
5848
+ const fileSchema = {
5849
+ name: sourcePath,
5850
+ orbitals: fileOrbitals,
5851
+ ...fileSchemaConfig ? { config: fileSchemaConfig } : {}
5852
+ };
5853
+ const flattenResult = await child.resolveOrbitalImports(fileSchema, { skipTypeParamSentinels: true });
5854
+ if (!flattenResult.success) return null;
5855
+ const orbitals = flattenResult.data;
5856
+ const inlineTraits = orbitals.flatMap(
5857
+ (o) => o.traits.filter((t) => typeof t !== "string" && "stateMachine" in t)
5858
+ );
5859
+ child.addLocalTraits(inlineTraits);
5860
+ child.seedSchemaEntityIds(orbitals);
5861
+ const resolved = [];
5862
+ for (const orbital of orbitals) {
5863
+ const result = await child.resolve(orbital, sourcePath, chain, { skipTypeParamSentinels: true });
5864
+ if (!result.success) return null;
5865
+ resolved.push(result.data);
5866
+ child.noteResolvedEntityIds(result.data);
5867
+ }
5868
+ return resolved;
5869
+ }
4294
5870
  /**
4295
5871
  * Resolve `uses` declarations to loaded orbitals.
4296
5872
  */
@@ -4304,6 +5880,10 @@ var ReferenceResolver = class {
4304
5880
  warnings: ["External loading skipped"]
4305
5881
  };
4306
5882
  }
5883
+ const effectiveChain = chain ?? { push: () => null, pop: () => {
5884
+ }, clone() {
5885
+ return this;
5886
+ } };
4307
5887
  for (const use of uses) {
4308
5888
  if (orbitals.has(use.as)) {
4309
5889
  errors.push(`Duplicate import alias: ${use.as}`);
@@ -4318,18 +5898,32 @@ var ReferenceResolver = class {
4318
5898
  use.from,
4319
5899
  void 0,
4320
5900
  sourcePath,
4321
- chain
5901
+ effectiveChain
4322
5902
  );
4323
5903
  if (!loadResult.success) {
4324
5904
  errors.push(`Failed to load "${use.from}" as "${use.as}": ${loadResult.error}`);
4325
5905
  continue;
4326
5906
  }
5907
+ const fileOrbitals = loadResult.data.orbitals ?? [loadResult.data.orbital];
5908
+ const resolvedOrbitals = await this.preResolveImportFile(
5909
+ fileOrbitals,
5910
+ loadResult.data.sourcePath,
5911
+ loadResult.data.schemaConfig,
5912
+ effectiveChain
5913
+ );
4327
5914
  orbitals.set(use.as, {
4328
5915
  alias: use.as,
4329
5916
  from: use.from,
4330
5917
  orbital: loadResult.data.orbital,
4331
- orbitals: loadResult.data.orbitals ?? [loadResult.data.orbital],
4332
- sourcePath: loadResult.data.sourcePath
5918
+ orbitals: fileOrbitals,
5919
+ sourcePath: loadResult.data.sourcePath,
5920
+ ...resolvedOrbitals ? { resolvedOrbitals } : {},
5921
+ ...loadResult.data.schemaConfig ? {
5922
+ schemaConfig: forwardConsumerAppKnobs(
5923
+ foldUseConfigOverride(loadResult.data.schemaConfig, use.config, use),
5924
+ this.schemaConfig
5925
+ )
5926
+ } : {}
4333
5927
  });
4334
5928
  }
4335
5929
  if (errors.length > 0) {
@@ -4420,14 +6014,79 @@ var ReferenceResolver = class {
4420
6014
  }
4421
6015
  return entityRef;
4422
6016
  }
6017
+ /**
6018
+ * The ATOM's OWN trait `alias.traits.traitName` resolves to — no call-site
6019
+ * overrides applied (`callSiteConfig` omitted) — so its DECLARED
6020
+ * `linkedEntity` can drive {@link buildAliasEntityRenames}. Same lookup
6021
+ * `resolveTraitRefString`'s imported branch performs to find the base
6022
+ * `trait` before any rebind, factored out so the pre-pass and the main
6023
+ * resolve share one lookup rather than two. `null` when the alias or
6024
+ * trait cannot be found — the pre-pass simply skips that entry, same as a
6025
+ * lookup failure anywhere else in this best-effort pass.
6026
+ */
6027
+ async atomOwnTrait(alias, traitName, imports, chain) {
6028
+ const imported = imports.orbitals.get(alias);
6029
+ if (!imported) return null;
6030
+ for (const o of importedOrbitals(imported)) {
6031
+ const entry = findTraitEntryInOrbital(o, traitName);
6032
+ if (!entry) continue;
6033
+ const entryResolved = await this.resolveTraitEntry(imported, entry, traitName, chain, imports);
6034
+ return entryResolved.success ? entryResolved.data.trait : null;
6035
+ }
6036
+ return null;
6037
+ }
6038
+ /**
6039
+ * Alias-scoped cross-trait entity-rebind propagation — JS twin of Rust's
6040
+ * `alias_entity_renames` pre-pass (`inline/trait.rs::inline_traits`). One
6041
+ * explicit pull's `linkedEntity` override (`Button.traits.ButtonRender ->
6042
+ * Route`) establishes a rebind (the atom's OWN declared `linkedEntity` →
6043
+ * the override) that a SIBLING pull from the SAME alias with NO rebind of
6044
+ * its own (`Button.traits.ButtonRender`, no `->`) never sees through
6045
+ * {@link applyLinkedEntityRename} — that call only ever knows ITS OWN
6046
+ * delta. But the no-rebind pull's `entityRefIds` side-map can still carry
6047
+ * a SECONDARY, positional reference to that same atom-local name (a
6048
+ * "self" entry keyed by the atom's own bound entity), which nothing else
6049
+ * rewrites — `std-api-gateway`'s `RouteOrbital.InlineButtonRender3`
6050
+ * (`Button.traits.ButtonRender`, no rebind) recovers `entityRefIds`'
6051
+ * `ButtonItem` key to `Route` only because `InlineButtonRender9` (`Button.
6052
+ * traits.ButtonRender -> Route`) established the rebind earlier in the
6053
+ * SAME orbital's `traits` list. Scanned once per orbital, over every
6054
+ * EXPLICIT `Alias.traits.X -> Y` entry in `traitRefs`: `(alias, atom's
6055
+ * declared linkedEntity) -> override`. First rebind for a given `(alias,
6056
+ * atomLocal)` pair wins (`Map.set` only on a fresh key), matching Rust's
6057
+ * `.or_insert_with`.
6058
+ */
6059
+ async buildAliasEntityRenames(traitRefs, imports, chain) {
6060
+ const out = /* @__PURE__ */ new Map();
6061
+ for (const traitRef of traitRefs) {
6062
+ if (typeof traitRef === "string" || "stateMachine" in traitRef || !("ref" in traitRef)) continue;
6063
+ const refObj = traitRef;
6064
+ if (!refObj.linkedEntity) continue;
6065
+ const parsed = parseImportedTraitRef(refObj.ref);
6066
+ if (!parsed) continue;
6067
+ const atomTrait = await this.atomOwnTrait(parsed.alias, parsed.traitName, imports, chain);
6068
+ const atomLocal = atomTrait?.linkedEntity;
6069
+ if (!atomLocal || atomLocal === refObj.linkedEntity) continue;
6070
+ const forAlias = out.get(parsed.alias) ?? /* @__PURE__ */ new Map();
6071
+ if (!forAlias.has(atomLocal)) forAlias.set(atomLocal, refObj.linkedEntity);
6072
+ out.set(parsed.alias, forAlias);
6073
+ }
6074
+ return out;
6075
+ }
4423
6076
  /**
4424
6077
  * Resolve trait references.
4425
6078
  */
4426
- resolveTraits(traitRefs, imports) {
6079
+ async resolveTraits(traitRefs, imports, chain, orbitalConfig) {
4427
6080
  const errors = [];
4428
6081
  const resolved = [];
6082
+ const embedCtx = {
6083
+ traitRefs,
6084
+ embedGraph: buildEmbedGraph(traitRefs),
6085
+ orbitalConfig
6086
+ };
6087
+ const aliasEntityRenames = await this.buildAliasEntityRenames(traitRefs, imports, chain);
4429
6088
  for (const traitRef of traitRefs) {
4430
- const result = this.resolveTraitRef(traitRef, imports);
6089
+ const result = await this.resolveTraitRef(traitRef, imports, chain, embedCtx, aliasEntityRenames);
4431
6090
  if (!result.success) {
4432
6091
  errors.push(...result.errors);
4433
6092
  } else {
@@ -4458,6 +6117,99 @@ var ReferenceResolver = class {
4458
6117
  this.sourceImportsCache.set(key, result.data);
4459
6118
  return result.data;
4460
6119
  }
6120
+ /**
6121
+ * The concrete base `Trait` a trait entry (found under `localName` in
6122
+ * `imported`) resolves to — an inline entry resolves its own
6123
+ * `@config.<knob>` emit refs against `callSiteConfig` (the ref hop that
6124
+ * led here, e.g. `std-approval-gate`'s `CloseButton = Button.traits.
6125
+ * ButtonRender { config: { action: CLOSE } }` resolving `ButtonRender`
6126
+ * itself); a ref-shaped entry (an atom's sub-view declared `trait X =
6127
+ * Y.traits.Z {…}` INSIDE the source atom, e.g. `std-note`'s
6128
+ * `NoteSubpages = RecordDetail.traits.RecordItemDetail`) recurses through
6129
+ * that source's own import scope via {@link importsOfSource} — the
6130
+ * entry's own declared overrides are its call site. Single owner for
6131
+ * `pullSiblingTraits`' sibling pull and `resolveTraitRefString`'s
6132
+ * imported branch, both of which used to reach `findTraitInOrbital`'s
6133
+ * `stateMachine`-gated lookup (its ref arm did nothing), silently failing
6134
+ * to resolve a nested ref (ledger (i)).
6135
+ *
6136
+ * `callSiteConfig` MUST be threaded by any caller that goes on to fold a
6137
+ * call-site config of its own onto the returned trait
6138
+ * (`resolveTraitRefString`'s ref-imported branch, ledger (o)) — the
6139
+ * `@config.<knob>` emit-name substitution is destructive
6140
+ * (`resolveConfigRefEmitNames` rewrites the marker to a concrete literal
6141
+ * in place), so resolving it here with the WRONG effective config
6142
+ * (the atom's own bare default, absent the override) permanently loses
6143
+ * the override: a second `resolveConfigRefEmitNames` call downstream sees
6144
+ * no more `@config.<knob>` marker to substitute and silently no-ops.
6145
+ * `pullSiblingTraits` (no further fold of its own) omits it, matching its
6146
+ * prior no-callSiteConfig behavior exactly.
6147
+ */
6148
+ async resolveTraitEntry(imported, entry, localName, chain, homeImports, callSiteConfig) {
6149
+ if ("stateMachine" in entry) {
6150
+ const { trait, errors } = resolveConfigRefEmitNames(entry, callSiteConfig);
6151
+ if (errors.length > 0) return { success: false, errors };
6152
+ return {
6153
+ success: true,
6154
+ data: { trait, embedScope: { imports: homeImports, alias: imported.alias } },
6155
+ warnings: []
6156
+ };
6157
+ }
6158
+ const refObj = entry;
6159
+ const srcImports = await this.importsOfSource(imported, chain);
6160
+ if (!srcImports) {
6161
+ return {
6162
+ success: false,
6163
+ errors: [
6164
+ `Trait "${localName}" in imported behavior could not resolve its own import scope to follow ref "${refObj.ref}"`
6165
+ ]
6166
+ };
6167
+ }
6168
+ const nested = await this.resolveTraitRefString(
6169
+ refObj.ref,
6170
+ srcImports,
6171
+ chain,
6172
+ refObj.config,
6173
+ refObj.linkedEntity,
6174
+ refObj.name ?? localName,
6175
+ refObj.events,
6176
+ refObj.listens,
6177
+ refObj.refId,
6178
+ refObj.typeArgs
6179
+ );
6180
+ if (!nested.success) return nested;
6181
+ return {
6182
+ success: true,
6183
+ data: {
6184
+ trait: nested.data.trait,
6185
+ embedScope: nested.data.embedScope ?? { imports: srcImports, alias: imported.alias },
6186
+ ...nested.data.typeArgs !== void 0 ? { typeArgs: nested.data.typeArgs } : {}
6187
+ },
6188
+ warnings: nested.warnings
6189
+ };
6190
+ }
6191
+ /**
6192
+ * The concrete `Page` a page entry (found under `localName` in `imported`)
6193
+ * resolves to — an inline `Page` passes through; a `PageRefObject` (a
6194
+ * re-exported page declared inside the SOURCE orbital's own `pages {}`,
6195
+ * {@link findPageEntryInOrbital}'s ref arm) recurses through that source's
6196
+ * own import scope via {@link importsOfSource} and
6197
+ * {@link resolvePageRefObject} — the page twin of {@link resolveTraitEntry}
6198
+ * (nested refs, ledger (i)).
6199
+ */
6200
+ async resolvePageEntry(imported, entry, chain) {
6201
+ if (!("ref" in entry)) return { success: true, data: { page: entry }, warnings: [] };
6202
+ const srcImports = await this.importsOfSource(imported, chain);
6203
+ if (!srcImports) {
6204
+ return {
6205
+ success: false,
6206
+ errors: [`Page in imported behavior could not resolve its own import scope to follow ref "${entry.ref}"`]
6207
+ };
6208
+ }
6209
+ const nested = await this.resolvePageRefObject(entry, srcImports, chain);
6210
+ if (!nested.success) return nested;
6211
+ return { success: true, data: { page: nested.data.page }, warnings: nested.warnings };
6212
+ }
4461
6213
  /**
4462
6214
  * Sibling-trait auto-pull — the JS twin of the compiler's
4463
6215
  * `phases/inline/trait.rs` pass, appending to `resolved` in place.
@@ -4479,7 +6231,8 @@ var ReferenceResolver = class {
4479
6231
  * source name; later owners pull under `<Owner><Sibling>` — unique by
4480
6232
  * construction, since owner names are unique within the orbital.
4481
6233
  */
4482
- async pullSiblingTraits(resolved, imports, chain) {
6234
+ async pullSiblingTraits(resolved, imports, chain, orbitalConfig) {
6235
+ const auxEntities = [];
4483
6236
  const work = [];
4484
6237
  const ownerSubs = /* @__PURE__ */ new Map();
4485
6238
  const subsFor = (owner) => {
@@ -4495,18 +6248,48 @@ var ReferenceResolver = class {
4495
6248
  const owner = rt.trait.name;
4496
6249
  subsFor(owner).set(rt.source.traitName, owner);
4497
6250
  for (const sibling of traitEmbedNamesOf(rt.trait)) {
4498
- work.push({ alias: rt.source.alias, sibling, linkedEntity: rt.linkedEntity, parent: owner, owner });
6251
+ work.push({
6252
+ alias: rt.source.alias,
6253
+ fallback: rt.embedScope,
6254
+ sibling,
6255
+ linkedEntity: rt.linkedEntity,
6256
+ parent: owner,
6257
+ owner,
6258
+ // Top-level SEED — always starts with the raw-walk-first gate
6259
+ // (see {@link PullItem.preResolvedScope}'s own doc).
6260
+ preResolvedScope: void 0
6261
+ });
4499
6262
  }
4500
6263
  }
4501
- if (work.length === 0) return [];
6264
+ if (work.length === 0) return { errors: [], auxEntities: [], pulledNames: /* @__PURE__ */ new Set() };
4502
6265
  const errors = [];
4503
6266
  const consumerDeclared = new Set(resolved.map((r) => r.trait.name).filter(Boolean));
6267
+ const consumerDeclaredProvenance = /* @__PURE__ */ new Map();
6268
+ for (const rt of resolved) {
6269
+ if (rt.source.type === "imported" && rt.trait.name) {
6270
+ consumerDeclaredProvenance.set(rt.trait.name, { alias: rt.source.alias, traitName: rt.source.traitName });
6271
+ }
6272
+ }
4504
6273
  const seen = new Set(consumerDeclared);
4505
6274
  const visited = /* @__PURE__ */ new Set();
4506
6275
  const pulledAs = /* @__PURE__ */ new Map();
4507
6276
  const ownerOf = /* @__PURE__ */ new Map();
6277
+ const parentOf = /* @__PURE__ */ new Map();
4508
6278
  const parentRewrites = /* @__PURE__ */ new Map();
4509
6279
  const pulled = [];
6280
+ const embedderChain2 = (finalName) => {
6281
+ const chain2 = [];
6282
+ const seenNames = /* @__PURE__ */ new Set();
6283
+ let cur = finalName;
6284
+ while (cur !== void 0 && !seenNames.has(cur)) {
6285
+ seenNames.add(cur);
6286
+ const t = resolved.find((r) => r.trait.name === cur)?.trait ?? pulled.find((r) => r.trait.name === cur)?.trait;
6287
+ if (!t) break;
6288
+ if (t.config) chain2.push(t.config);
6289
+ cur = parentOf.get(cur);
6290
+ }
6291
+ return chain2;
6292
+ };
4510
6293
  const noteRewrite = (parent, from, to) => {
4511
6294
  let m = parentRewrites.get(parent);
4512
6295
  if (!m) {
@@ -4516,8 +6299,8 @@ var ReferenceResolver = class {
4516
6299
  m.set(from, to);
4517
6300
  };
4518
6301
  for (let item = work.pop(); item !== void 0; item = work.pop()) {
4519
- const { alias, sibling, linkedEntity, parent, owner } = item;
4520
- const pullKey = `${alias}\0${sibling}\0${owner}`;
6302
+ const { alias, fallback, sibling, linkedEntity, parent, owner, preResolvedScope } = item;
6303
+ const pullKey = `${alias} ${sibling} ${owner} ${parent}`;
4521
6304
  const existing = pulledAs.get(pullKey);
4522
6305
  if (existing !== void 0) {
4523
6306
  if (existing !== sibling) noteRewrite(parent, sibling, existing);
@@ -4525,73 +6308,122 @@ var ReferenceResolver = class {
4525
6308
  }
4526
6309
  let finalName = sibling;
4527
6310
  if (seen.has(sibling)) {
4528
- if (consumerDeclared.has(sibling)) continue;
4529
- finalName = `${owner}${sibling}`;
6311
+ const provenance = consumerDeclaredProvenance.get(sibling);
6312
+ if (consumerDeclared.has(sibling) && provenance?.alias === alias && provenance.traitName === sibling) {
6313
+ continue;
6314
+ }
6315
+ finalName = `${parent}${sibling}`;
4530
6316
  if (seen.has(finalName)) continue;
4531
6317
  }
4532
6318
  if (visited.has(pullKey)) continue;
4533
6319
  visited.add(pullKey);
4534
- const imported = imports.orbitals.get(alias);
4535
- if (!imported) continue;
4536
- let atomEntry = null;
4537
- for (const o of importedOrbitals(imported)) {
4538
- atomEntry = findTraitEntryInOrbital(o, sibling);
4539
- if (atomEntry) break;
4540
- }
4541
- if (!atomEntry) continue;
6320
+ let searchImports = imports;
6321
+ let searchAlias = alias;
4542
6322
  let atomTrait;
4543
- if ("stateMachine" in atomEntry) {
4544
- const { trait: cfgResolved, errors: cfgErrors } = resolveConfigRefEmitNames(
4545
- atomEntry
4546
- );
4547
- if (cfgErrors.length > 0) {
4548
- errors.push(...cfgErrors);
4549
- continue;
6323
+ let childScope;
6324
+ let foundTypeArgs;
6325
+ let childPreResolvedScope;
6326
+ if (preResolvedScope) {
6327
+ const found = preResolvedScope.traits.find((rt) => rt.trait.name === sibling);
6328
+ if (found) {
6329
+ atomTrait = found.trait;
6330
+ childScope = { imports: searchImports, alias: searchAlias };
6331
+ foundTypeArgs = found.typeArgs;
6332
+ childPreResolvedScope = preResolvedScope;
4550
6333
  }
4551
- atomTrait = cfgResolved;
4552
- } else {
4553
- const srcImports = await this.importsOfSource(imported, chain);
4554
- if (!srcImports) continue;
4555
- const refObj = atomEntry;
4556
- const nested = this.resolveTraitRefString(
4557
- refObj.ref,
4558
- srcImports,
4559
- refObj.config,
4560
- refObj.linkedEntity,
4561
- refObj.name ?? sibling,
4562
- refObj.events,
4563
- refObj.listens,
4564
- refObj.refId
4565
- );
4566
- if (!nested.success) {
4567
- errors.push(...nested.errors);
4568
- continue;
6334
+ }
6335
+ if (!atomTrait) {
6336
+ let imported = imports.orbitals.get(alias);
6337
+ let atomEntry = null;
6338
+ let atomOrbitalIndex = -1;
6339
+ if (imported) {
6340
+ const list = importedOrbitals(imported);
6341
+ for (let i = 0; i < list.length; i++) {
6342
+ atomEntry = findTraitEntryInOrbital(list[i], sibling);
6343
+ if (atomEntry) {
6344
+ atomOrbitalIndex = i;
6345
+ break;
6346
+ }
6347
+ }
6348
+ }
6349
+ if (!atomEntry && fallback) {
6350
+ const fbImported = fallback.imports.orbitals.get(fallback.alias);
6351
+ if (fbImported) {
6352
+ const list = importedOrbitals(fbImported);
6353
+ for (let i = 0; i < list.length; i++) {
6354
+ atomEntry = findTraitEntryInOrbital(list[i], sibling);
6355
+ if (atomEntry) {
6356
+ imported = fbImported;
6357
+ searchImports = fallback.imports;
6358
+ searchAlias = fallback.alias;
6359
+ atomOrbitalIndex = i;
6360
+ break;
6361
+ }
6362
+ }
6363
+ }
6364
+ }
6365
+ if (!imported || !atomEntry) continue;
6366
+ const preResolvedOrbital = imported.resolvedOrbitals?.[atomOrbitalIndex];
6367
+ const preResolved = preResolvedOrbital?.traits.find((rt) => rt.trait.name === sibling);
6368
+ if (preResolved) {
6369
+ atomTrait = preResolved.trait;
6370
+ childScope = { imports: searchImports, alias: searchAlias };
6371
+ foundTypeArgs = preResolved.typeArgs;
6372
+ childPreResolvedScope = preResolvedOrbital;
6373
+ } else {
6374
+ const entryResolved = await this.resolveTraitEntry(imported, atomEntry, sibling, chain, searchImports);
6375
+ if (!entryResolved.success) {
6376
+ errors.push(...entryResolved.errors);
6377
+ continue;
6378
+ }
6379
+ atomTrait = entryResolved.data.trait;
6380
+ childScope = entryResolved.data.embedScope;
6381
+ foundTypeArgs = entryResolved.data.typeArgs;
4569
6382
  }
4570
- atomTrait = nested.data.trait;
4571
6383
  }
4572
- const embedder = resolved.find((r) => r.trait.name === parent)?.trait ?? pulled.find((r) => r.trait.name === parent)?.trait;
4573
- let copy = resolveForwardedSiblingConfig(
4574
- applyLinkedEntityRename(atomTrait, linkedEntity),
4575
- embedder
6384
+ if (!atomTrait || !childScope) continue;
6385
+ const nextFallback = childScope.alias === searchAlias && childScope.imports === searchImports ? void 0 : childScope;
6386
+ let copy = resolveForwardedSiblingConfigFrom(
6387
+ applyLinkedEntityRename(atomTrait, linkedEntity, this.entityIdsInScope),
6388
+ embedderChain2(parent),
6389
+ orbitalConfig,
6390
+ this.schemaConfig
4576
6391
  );
4577
6392
  if (finalName !== sibling) {
4578
6393
  copy = { ...copy, name: finalName };
4579
6394
  noteRewrite(parent, sibling, finalName);
4580
6395
  }
6396
+ const childParent = childPreResolvedScope ? parent : finalName;
4581
6397
  for (const next of traitEmbedNamesOf(copy)) {
4582
- work.push({ alias, sibling: next, linkedEntity, parent: finalName, owner });
6398
+ work.push({
6399
+ alias,
6400
+ fallback: nextFallback,
6401
+ sibling: next,
6402
+ linkedEntity,
6403
+ parent: childParent,
6404
+ owner,
6405
+ preResolvedScope: childPreResolvedScope
6406
+ });
4583
6407
  }
4584
6408
  pulledAs.set(pullKey, finalName);
4585
6409
  subsFor(owner).set(sibling, finalName);
4586
6410
  ownerOf.set(finalName, owner);
6411
+ parentOf.set(finalName, parent);
4587
6412
  seen.add(finalName);
4588
6413
  pulled.push({
4589
6414
  trait: copy,
4590
6415
  source: { type: "imported", alias, traitName: sibling },
4591
- ...linkedEntity !== void 0 ? { linkedEntity } : {}
6416
+ ...linkedEntity !== void 0 ? { linkedEntity } : {},
6417
+ ...foundTypeArgs !== void 0 ? { typeArgs: foundTypeArgs } : {}
4592
6418
  });
6419
+ if (copy.linkedEntity !== void 0) {
6420
+ const aux = entityByNameForAlias(imports, alias, copy.linkedEntity) ?? entityByNameAnyAlias(imports, copy.linkedEntity);
6421
+ if (aux) auxEntities.push(aux);
6422
+ }
6423
+ }
6424
+ if (pulled.length === 0 && parentRewrites.size === 0) {
6425
+ return { errors, auxEntities, pulledNames: /* @__PURE__ */ new Set() };
4593
6426
  }
4594
- if (pulled.length === 0 && parentRewrites.size === 0) return errors;
4595
6427
  const applyRewrites = (rt) => {
4596
6428
  const subs = rt.trait.name ? parentRewrites.get(rt.trait.name) : void 0;
4597
6429
  if (subs) rt.trait = renameTraitEmbeds(rt.trait, subs);
@@ -4603,39 +6435,29 @@ var ReferenceResolver = class {
4603
6435
  if (rt.trait.name) idByName.set(rt.trait.name, rt.trait.id);
4604
6436
  }
4605
6437
  for (const rt of pulled) {
4606
- const listens = rt.trait.listens;
4607
6438
  const owner = rt.trait.name ? ownerOf.get(rt.trait.name) : void 0;
4608
6439
  const subs = owner ? ownerSubs.get(owner) : void 0;
4609
- if (!listens || listens.length === 0 || !subs) continue;
4610
- let changed = false;
4611
- const nextListens = listens.map((listen) => {
4612
- const source = listen.source;
4613
- if (!source || source.kind !== "trait") return listen;
4614
- const target = subs.get(source.trait);
4615
- if (target === void 0 || target === source.trait) return listen;
4616
- changed = true;
4617
- const traitId = idByName.get(target);
4618
- return {
4619
- ...listen,
4620
- source: { kind: "trait", trait: target, ...traitId ? { traitId } : {} }
4621
- };
4622
- });
4623
- if (changed) rt.trait = { ...rt.trait, listens: nextListens };
6440
+ if (!subs) continue;
6441
+ rt.trait = rewriteListenSources(rt.trait, subs, idByName);
4624
6442
  }
4625
6443
  refResolverLog.info("sibling-pull", {
4626
6444
  pulled: pulled.map((p) => ({
4627
6445
  trait: p.trait.name,
4628
6446
  owner: p.trait.name ? ownerOf.get(p.trait.name) : void 0,
6447
+ parent: p.trait.name ? parentOf.get(p.trait.name) : void 0,
4629
6448
  linkedEntity: p.linkedEntity ?? p.trait.linkedEntity
4630
6449
  }))
4631
6450
  });
4632
6451
  resolved.push(...pulled);
4633
- return errors;
6452
+ const pulledNames = new Set(
6453
+ pulled.map((p) => p.trait.name).filter((n) => Boolean(n))
6454
+ );
6455
+ return { errors, auxEntities, pulledNames };
4634
6456
  }
4635
6457
  /**
4636
6458
  * Resolve a single trait reference.
4637
6459
  */
4638
- resolveTraitRef(traitRef, imports) {
6460
+ async resolveTraitRef(traitRef, imports, chain, embedCtx, aliasEntityRenames) {
4639
6461
  if (typeof traitRef !== "string" && "stateMachine" in traitRef) {
4640
6462
  const { trait: resolvedInline, errors } = resolveConfigRefEmitNames(traitRef);
4641
6463
  if (errors.length > 0) {
@@ -4655,16 +6477,33 @@ var ReferenceResolver = class {
4655
6477
  return this.resolveTraitRefString(
4656
6478
  refObj.ref,
4657
6479
  imports,
6480
+ chain,
4658
6481
  refObj.config,
4659
6482
  refObj.linkedEntity,
4660
6483
  refObj.name,
4661
6484
  refObj.events,
4662
6485
  refObj.listens,
4663
- refObj.refId
6486
+ refObj.refId,
6487
+ refObj.typeArgs,
6488
+ embedCtx,
6489
+ aliasEntityRenames
4664
6490
  );
4665
6491
  }
4666
6492
  if (typeof traitRef === "string") {
4667
- return this.resolveTraitRefString(traitRef, imports);
6493
+ return this.resolveTraitRefString(
6494
+ traitRef,
6495
+ imports,
6496
+ chain,
6497
+ void 0,
6498
+ void 0,
6499
+ void 0,
6500
+ void 0,
6501
+ void 0,
6502
+ void 0,
6503
+ void 0,
6504
+ embedCtx,
6505
+ aliasEntityRenames
6506
+ );
4668
6507
  }
4669
6508
  return {
4670
6509
  success: false,
@@ -4674,8 +6513,10 @@ var ReferenceResolver = class {
4674
6513
  /**
4675
6514
  * Resolve a trait reference string.
4676
6515
  */
4677
- resolveTraitRefString(ref, imports, config, linkedEntity, overrideName, eventRenames, listensOverride, refId) {
6516
+ async resolveTraitRefString(ref, imports, chain, config, linkedEntity, overrideName, eventRenames, listensOverride, refId, typeArgs, embedCtx, aliasEntityRenames) {
4678
6517
  const parsed = parseImportedTraitRef(ref);
6518
+ const localName = overrideName ?? (parsed ? parsed.traitName : ref);
6519
+ const resolvedConfig = config && embedCtx ? resolveEmbedderConfigForward(config, localName, embedCtx, this.schemaConfig) : config;
4679
6520
  if (parsed) {
4680
6521
  const imported = imports.orbitals.get(parsed.alias);
4681
6522
  if (!imported) {
@@ -4687,9 +6528,27 @@ var ReferenceResolver = class {
4687
6528
  };
4688
6529
  }
4689
6530
  let trait = null;
4690
- for (const o of importedOrbitals(imported)) {
4691
- trait = this.findTraitInOrbital(o, parsed.traitName, refId, imports.idIndex);
4692
- if (trait) break;
6531
+ let embedScope = { imports, alias: parsed.alias };
6532
+ const idEntry = refId ? imports.idIndex?.get(refId) : void 0;
6533
+ if (idEntry && idEntry.kind === "trait") {
6534
+ trait = idEntry.node;
6535
+ } else {
6536
+ for (const o of importedOrbitals(imported)) {
6537
+ const entry = findTraitEntryInOrbital(o, parsed.traitName);
6538
+ if (!entry) continue;
6539
+ const entryResolved = await this.resolveTraitEntry(
6540
+ imported,
6541
+ entry,
6542
+ parsed.traitName,
6543
+ chain,
6544
+ imports,
6545
+ resolvedConfig
6546
+ );
6547
+ if (!entryResolved.success) return entryResolved;
6548
+ trait = entryResolved.data.trait;
6549
+ embedScope = entryResolved.data.embedScope;
6550
+ break;
6551
+ }
4693
6552
  }
4694
6553
  if (!trait) {
4695
6554
  const available = importedOrbitals(imported).flatMap((o) => this.listTraitsInOrbital(o));
@@ -4700,15 +6559,36 @@ var ReferenceResolver = class {
4700
6559
  ]
4701
6560
  };
4702
6561
  }
6562
+ if (embedCtx && trait.config) {
6563
+ const homeResolvedConfig = resolveConfigForwards(
6564
+ trait.config,
6565
+ embedderChain(localName, embedCtx.traitRefs, embedCtx.embedGraph),
6566
+ embedCtx.orbitalConfig,
6567
+ homeOrbitalConfigForTrait(imported, parsed.traitName),
6568
+ imported.schemaConfig,
6569
+ this.schemaConfig
6570
+ );
6571
+ if (homeResolvedConfig) {
6572
+ trait = { ...trait, config: homeResolvedConfig };
6573
+ }
6574
+ }
4703
6575
  const baseTrait = overrideName ? { ...trait, name: overrideName } : trait;
4704
- const { trait: configResolvedTrait, errors: configRefErrors } = resolveConfigRefEmitNames(baseTrait, config);
6576
+ const { trait: configResolvedTrait, errors: configRefErrors, resolvedKnobs } = resolveConfigRefEmitNames(baseTrait, resolvedConfig);
4705
6577
  if (configRefErrors.length > 0) {
4706
6578
  return { success: false, errors: configRefErrors };
4707
6579
  }
4708
- const reboundTrait = applyLinkedEntityRename(configResolvedTrait, linkedEntity);
4709
- const renamedTrait = applyEventRenames(reboundTrait, eventRenames);
4710
- const renamedConfig = applyEventRenamesToCallSiteConfig(config, reboundTrait.config, eventRenames);
4711
- const finalTrait = listensOverride !== void 0 ? { ...renamedTrait, listens: listensOverride } : renamedTrait;
6580
+ const reboundTrait = applyLinkedEntityRename(configResolvedTrait, linkedEntity, this.entityIdsInScope);
6581
+ const aliasSubs = aliasEntityRenames?.get(parsed.alias);
6582
+ const aliasReboundTrait = aliasSubs ? applyAliasEntityRenames(reboundTrait, aliasSubs, this.entityIdsInScope) : reboundTrait;
6583
+ const renamedTrait = applyEventRenames(aliasReboundTrait, eventRenames);
6584
+ const foldedTrait = foldEventRenameOntoDeclaredKnobs(
6585
+ renamedTrait,
6586
+ resolvedKnobValues(baseTrait, configResolvedTrait, resolvedKnobs),
6587
+ eventRenames
6588
+ );
6589
+ const renamedConfig = applyEventRenamesToCallSiteConfig(resolvedConfig, reboundTrait.config, eventRenames);
6590
+ const configFoldedTrait = foldCallSiteConfigOntoTrait(foldedTrait, renamedConfig);
6591
+ const finalTrait = listensOverride !== void 0 ? { ...configFoldedTrait, listens: listensOverride } : configFoldedTrait;
4712
6592
  if (listensOverride !== void 0) {
4713
6593
  refResolverLog.info("listens-override:imported", {
4714
6594
  trait: finalTrait.name,
@@ -4723,7 +6603,9 @@ var ReferenceResolver = class {
4723
6603
  trait: finalTrait,
4724
6604
  source: { type: "imported", alias: parsed.alias, traitName: parsed.traitName },
4725
6605
  config: renamedConfig,
4726
- linkedEntity
6606
+ linkedEntity,
6607
+ embedScope,
6608
+ ...typeArgs !== void 0 ? { typeArgs } : {}
4727
6609
  },
4728
6610
  warnings: []
4729
6611
  };
@@ -4731,14 +6613,20 @@ var ReferenceResolver = class {
4731
6613
  const localTrait = (refId && this.localTraitsById.get(refId)) ?? this.localTraits.get(ref);
4732
6614
  if (localTrait) {
4733
6615
  const baseLocal = overrideName ? { ...localTrait, name: overrideName } : localTrait;
4734
- const { trait: configResolvedLocal, errors: localConfigRefErrors } = resolveConfigRefEmitNames(baseLocal, config);
6616
+ const { trait: configResolvedLocal, errors: localConfigRefErrors, resolvedKnobs: localResolvedKnobs } = resolveConfigRefEmitNames(baseLocal, resolvedConfig);
4735
6617
  if (localConfigRefErrors.length > 0) {
4736
6618
  return { success: false, errors: localConfigRefErrors };
4737
6619
  }
4738
- const reboundLocal = applyLinkedEntityRename(configResolvedLocal, linkedEntity);
6620
+ const reboundLocal = applyLinkedEntityRename(configResolvedLocal, linkedEntity, this.entityIdsInScope);
4739
6621
  const renamedLocalTrait = applyEventRenames(reboundLocal, eventRenames);
4740
- const renamedLocalConfig = applyEventRenamesToCallSiteConfig(config, reboundLocal.config, eventRenames);
4741
- const finalLocalTrait = listensOverride !== void 0 ? { ...renamedLocalTrait, listens: listensOverride } : renamedLocalTrait;
6622
+ const foldedLocalTrait = foldEventRenameOntoDeclaredKnobs(
6623
+ renamedLocalTrait,
6624
+ resolvedKnobValues(baseLocal, configResolvedLocal, localResolvedKnobs),
6625
+ eventRenames
6626
+ );
6627
+ const renamedLocalConfig = applyEventRenamesToCallSiteConfig(resolvedConfig, reboundLocal.config, eventRenames);
6628
+ const configFoldedLocalTrait = foldCallSiteConfigOntoTrait(foldedLocalTrait, renamedLocalConfig);
6629
+ const finalLocalTrait = listensOverride !== void 0 ? { ...configFoldedLocalTrait, listens: listensOverride } : configFoldedLocalTrait;
4742
6630
  if (listensOverride !== void 0) {
4743
6631
  refResolverLog.info("listens-override:local", {
4744
6632
  trait: finalLocalTrait.name,
@@ -4753,7 +6641,8 @@ var ReferenceResolver = class {
4753
6641
  trait: finalLocalTrait,
4754
6642
  source: { type: "local", name: ref },
4755
6643
  config: renamedLocalConfig,
4756
- linkedEntity
6644
+ linkedEntity,
6645
+ ...typeArgs !== void 0 ? { typeArgs } : {}
4757
6646
  },
4758
6647
  warnings: []
4759
6648
  };
@@ -4765,31 +6654,6 @@ var ReferenceResolver = class {
4765
6654
  ]
4766
6655
  };
4767
6656
  }
4768
- /**
4769
- * Find a trait in an orbital by name. Id-primary: when the calling ref
4770
- * carries a `refId` and the id index has a matching trait entry, return it
4771
- * directly — else fall back to the existing name match unchanged.
4772
- */
4773
- findTraitInOrbital(orbital, traitName, refId, idIndex) {
4774
- if (refId && idIndex) {
4775
- const entry = idIndex.get(refId);
4776
- if (entry && entry.kind === "trait") {
4777
- return entry.node;
4778
- }
4779
- }
4780
- for (const traitRef of orbital.traits) {
4781
- if (typeof traitRef !== "string" && "stateMachine" in traitRef) {
4782
- if (traitRef.name === traitName) {
4783
- return traitRef;
4784
- }
4785
- }
4786
- if (typeof traitRef !== "string" && "ref" in traitRef) {
4787
- const refObj = traitRef;
4788
- if (refObj.ref === traitName || refObj.name === traitName) ;
4789
- }
4790
- }
4791
- return null;
4792
- }
4793
6657
  /**
4794
6658
  * List trait names in an orbital.
4795
6659
  */
@@ -4805,11 +6669,11 @@ var ReferenceResolver = class {
4805
6669
  /**
4806
6670
  * Resolve page references.
4807
6671
  */
4808
- resolvePages(pageRefs, imports) {
6672
+ async resolvePages(pageRefs, imports, chain) {
4809
6673
  const errors = [];
4810
6674
  const resolved = [];
4811
6675
  for (const pageRef of pageRefs) {
4812
- const result = this.resolvePageRef(pageRef, imports);
6676
+ const result = await this.resolvePageRef(pageRef, imports, chain);
4813
6677
  if (!result.success) {
4814
6678
  errors.push(...result.errors);
4815
6679
  } else {
@@ -4824,7 +6688,7 @@ var ReferenceResolver = class {
4824
6688
  /**
4825
6689
  * Resolve a single page reference.
4826
6690
  */
4827
- resolvePageRef(pageRef, imports) {
6691
+ async resolvePageRef(pageRef, imports, chain) {
4828
6692
  if (!isPageReference(pageRef)) {
4829
6693
  return {
4830
6694
  success: true,
@@ -4837,10 +6701,10 @@ var ReferenceResolver = class {
4837
6701
  };
4838
6702
  }
4839
6703
  if (isPageReferenceString(pageRef)) {
4840
- return this.resolvePageRefString(pageRef, imports);
6704
+ return this.resolvePageRefString(pageRef, imports, chain);
4841
6705
  }
4842
6706
  if (isPageReferenceObject(pageRef)) {
4843
- return this.resolvePageRefObject(pageRef, imports);
6707
+ return this.resolvePageRefObject(pageRef, imports, chain);
4844
6708
  }
4845
6709
  return {
4846
6710
  success: false,
@@ -4850,7 +6714,7 @@ var ReferenceResolver = class {
4850
6714
  /**
4851
6715
  * Resolve a page reference string.
4852
6716
  */
4853
- resolvePageRefString(ref, imports, refId) {
6717
+ async resolvePageRefString(ref, imports, chain, refId) {
4854
6718
  const parsed = parsePageRef(ref);
4855
6719
  if (!parsed) {
4856
6720
  return {
@@ -4868,9 +6732,18 @@ var ReferenceResolver = class {
4868
6732
  };
4869
6733
  }
4870
6734
  let page = null;
4871
- for (const o of importedOrbitals(imported)) {
4872
- page = this.findPageInOrbital(o, parsed.pageName, refId, imports.idIndex);
4873
- if (page) break;
6735
+ const idEntry = refId ? imports.idIndex?.get(refId) : void 0;
6736
+ if (idEntry && idEntry.kind === "page") {
6737
+ page = { ...idEntry.node };
6738
+ } else {
6739
+ for (const o of importedOrbitals(imported)) {
6740
+ const entry = findPageEntryInOrbital(o, parsed.pageName);
6741
+ if (!entry) continue;
6742
+ const entryResolved = await this.resolvePageEntry(imported, entry, chain);
6743
+ if (!entryResolved.success) return entryResolved;
6744
+ page = entryResolved.data.page;
6745
+ break;
6746
+ }
4874
6747
  }
4875
6748
  if (!page) {
4876
6749
  const available = importedOrbitals(imported).flatMap((o) => this.listPagesInOrbital(o));
@@ -4892,10 +6765,18 @@ var ReferenceResolver = class {
4892
6765
  };
4893
6766
  }
4894
6767
  /**
4895
- * Resolve a page reference object with optional path override.
6768
+ * Resolve a page reference object, applying every call-site override
6769
+ * `path` (direct assignment), `linkedEntity` (rebind `primaryEntity` and
6770
+ * every page-level trait pointer that named the old entity), and `traits`
6771
+ * (full replacement) — mirroring the compiler's `apply_overrides_to_page`
6772
+ * (`phases/inline/page.rs:21-93`). `Page.traits` is a `PageTraitRef[]`
6773
+ * pointer list (a trait's own body lives in the orbital's `traits {}`, not
6774
+ * on the page), so unlike Rust's `TraitReference` the `linkedEntity` rebind
6775
+ * only ever touches each pointer's OWN `linkedEntity` field — there is no
6776
+ * inline trait body here to walk with `renameEntitiesInTrait`.
4896
6777
  */
4897
- resolvePageRefObject(refObj, imports) {
4898
- const baseResult = this.resolvePageRefString(refObj.ref, imports, refObj.refId);
6778
+ async resolvePageRefObject(refObj, imports, chain) {
6779
+ const baseResult = await this.resolvePageRefString(refObj.ref, imports, chain, refObj.refId);
4899
6780
  if (!baseResult.success) {
4900
6781
  return baseResult;
4901
6782
  }
@@ -4909,36 +6790,25 @@ var ReferenceResolver = class {
4909
6790
  resolved.pathOverridden = true;
4910
6791
  resolved.originalPath = originalPath;
4911
6792
  }
6793
+ if (refObj.linkedEntity) {
6794
+ const oldEntity = resolved.page.primaryEntity;
6795
+ const newEntity = refObj.linkedEntity;
6796
+ const rebindPointers = (pointers) => oldEntity && oldEntity !== newEntity ? pointers?.map((pt) => pt.linkedEntity === oldEntity ? { ...pt, linkedEntity: newEntity } : pt) : pointers;
6797
+ resolved.page = {
6798
+ ...resolved.page,
6799
+ primaryEntity: newEntity,
6800
+ traits: rebindPointers(resolved.page.traits)
6801
+ };
6802
+ }
6803
+ if (refObj.traits) {
6804
+ resolved.page = { ...resolved.page, traits: refObj.traits.map(toPageTraitRef) };
6805
+ }
4912
6806
  return {
4913
6807
  success: true,
4914
6808
  data: resolved,
4915
6809
  warnings: baseResult.warnings
4916
6810
  };
4917
6811
  }
4918
- /**
4919
- * Find a page in an orbital by name. Id-primary: when the calling ref
4920
- * carries a `refId` and the id index has a matching page entry, return it
4921
- * directly — else fall back to the existing name match unchanged.
4922
- */
4923
- findPageInOrbital(orbital, pageName, refId, idIndex) {
4924
- if (refId && idIndex) {
4925
- const entry = idIndex.get(refId);
4926
- if (entry && entry.kind === "page") {
4927
- return { ...entry.node };
4928
- }
4929
- }
4930
- const pages = orbital.pages;
4931
- if (!pages) return null;
4932
- for (const pageRef of pages) {
4933
- if (typeof pageRef !== "string" && !("ref" in pageRef)) {
4934
- const page = pageRef;
4935
- if (page.name === pageName) {
4936
- return { ...page };
4937
- }
4938
- }
4939
- }
4940
- return null;
4941
- }
4942
6812
  /**
4943
6813
  * List page names in an orbital.
4944
6814
  */
@@ -4953,6 +6823,567 @@ var ReferenceResolver = class {
4953
6823
  }
4954
6824
  return names;
4955
6825
  }
6826
+ /**
6827
+ * Flatten every reference-form orbital (`orbital X = Alias.orbitals.Y
6828
+ * { … }`, docs/Almadar_Orbital_Import.md §4) in a schema BEFORE the
6829
+ * ordinary per-orbital {@link resolve} pass runs — the interpreter-path
6830
+ * twin of the (not-yet-landed) compiler's inline-phase flatten. After this
6831
+ * call, no returned `OrbitalDefinition` carries `.reference`.
6832
+ */
6833
+ async resolveOrbitalImports(schema, opts) {
6834
+ const errors = [];
6835
+ const flattened = [];
6836
+ const chain = { push: () => null, pop: () => {
6837
+ }, clone() {
6838
+ return this;
6839
+ } };
6840
+ const visiting = /* @__PURE__ */ new Set();
6841
+ const consumerEntityIds = consumerEntityIdsOf(schema.orbitals);
6842
+ for (const [name, id] of await this.precomputeReferenceFormPrimaryIds(schema, chain)) {
6843
+ if (!consumerEntityIds.has(name)) consumerEntityIds.set(name, id);
6844
+ }
6845
+ const consumerRoster = identityEntitiesOf(schema.orbitals);
6846
+ for (const orbital of schema.orbitals) {
6847
+ if (!orbital.reference) {
6848
+ if (!opts?.skipTypeParamSentinels && isInlineEntity(orbital.entity)) {
6849
+ resolveOrbitalTypeParamSentinels(
6850
+ orbital.traits.filter(isInlineTrait).map((t) => ({ trait: t })),
6851
+ orbital.entity,
6852
+ (orbital.auxiliaryEntities ?? []).filter(isInlineEntity),
6853
+ orbital.types
6854
+ );
6855
+ }
6856
+ flattened.push(orbital);
6857
+ continue;
6858
+ }
6859
+ const result = await this.resolveOrbitalRefChain(orbital, void 0, chain, visiting, consumerEntityIds, consumerRoster);
6860
+ if (!result.success) {
6861
+ errors.push(...result.errors);
6862
+ continue;
6863
+ }
6864
+ flattened.push(result.data);
6865
+ }
6866
+ if (errors.length > 0) return { success: false, errors };
6867
+ return { success: true, data: flattened, warnings: [] };
6868
+ }
6869
+ /**
6870
+ * (B) The materialized primary name → derived id of every REFERENCE-FORM
6871
+ * orbital this schema declares (`orbital X = Alias.orbitals.Y { … }`),
6872
+ * computed order-free — WITHOUT requiring any other orbital in `schema`
6873
+ * to have resolved first, and without recursively flattening the
6874
+ * upstream. Each reference's alias is loaded via the ordinary
6875
+ * `resolveImports` path, which the loader caches by absolute path (see
6876
+ * `ExternalOrbitalLoader`'s `LoaderCache`) — the REAL flatten
6877
+ * (`resolveOrbitalRefChain`) moments later is then a cache hit, no
6878
+ * duplicate work — and its named orbital looked up directly in the
6879
+ * loaded (un-flattened) schema: an upstream's OWN primary entity id/name
6880
+ * never change through resolution (only a CONSUMER-side CLONE gets a
6881
+ * fresh derived id), so this shallow load's entity is exactly what the
6882
+ * real flatten pass would see too. Uses the SAME `materializedPrimaryEntity`
6883
+ * pair `materializeOrbitalRef` computes for itself — one owner. JS twin
6884
+ * of the compiled path's `precompute_reference_form_primary_ids`.
6885
+ *
6886
+ * Best-effort: a reference this pre-pass cannot resolve (unknown alias,
6887
+ * malformed reference string, upstream orbital not found, load failure)
6888
+ * is silently skipped here — the REAL `resolveOrbitalRefChain` call
6889
+ * moments later still surfaces the actual error for it.
6890
+ */
6891
+ async precomputeReferenceFormPrimaryIds(schema, chain) {
6892
+ const out = /* @__PURE__ */ new Map();
6893
+ for (const orbital of schema.orbitals) {
6894
+ const ref = orbital.reference;
6895
+ if (!ref) continue;
6896
+ const parsed = parseOrbitalRef(ref.ref);
6897
+ if (!parsed) continue;
6898
+ const importsResult = await this.resolveImports(orbital.uses ?? [], void 0, chain);
6899
+ if (!importsResult.success) continue;
6900
+ const imported = importsResult.data.orbitals.get(parsed.alias);
6901
+ if (!imported) continue;
6902
+ const upstream = importedOrbitals(imported).find((o) => o.name === parsed.orbitalName);
6903
+ if (!upstream || !isInlineEntity(upstream.entity)) continue;
6904
+ const { name, id } = materializedPrimaryEntity(upstream.entity, upstream.id, ref, orbital.name);
6905
+ out.set(name, id);
6906
+ }
6907
+ return out;
6908
+ }
6909
+ /**
6910
+ * Resolve one reference-form orbital, recursing into the upstream first
6911
+ * when IT is also reference-form ("already fully inlined because inline
6912
+ * recursed into every loaded orbital" — docs/Almadar_Orbital_Import.md §9
6913
+ * step 3 — the JS resolver needs its own cycle guard since it has no
6914
+ * file-level inline-order pass to lean on).
6915
+ */
6916
+ async resolveOrbitalRefChain(orbital, sourcePath, chain, visiting, consumerEntityIds, consumerRoster) {
6917
+ const ref = orbital.reference;
6918
+ if (!ref) return { success: true, data: orbital, warnings: [] };
6919
+ const parsed = parseOrbitalRef(ref.ref);
6920
+ if (!parsed) {
6921
+ return {
6922
+ success: false,
6923
+ errors: [`Invalid orbital reference format: ${ref.ref}. Expected "Alias.orbitals.OrbitalName"`]
6924
+ };
6925
+ }
6926
+ const importsResult = await this.resolveImports(orbital.uses ?? [], sourcePath, chain);
6927
+ if (!importsResult.success) return { success: false, errors: importsResult.errors };
6928
+ const imported = importsResult.data.orbitals.get(parsed.alias);
6929
+ if (!imported) {
6930
+ return {
6931
+ success: false,
6932
+ errors: [
6933
+ `Unknown import alias in orbital reference: ${parsed.alias}. Available aliases: ${Array.from(importsResult.data.orbitals.keys()).join(", ") || "none"}`
6934
+ ]
6935
+ };
6936
+ }
6937
+ const candidates = importedOrbitals(imported);
6938
+ let upstream = candidates.find((o) => o.name === parsed.orbitalName);
6939
+ if (!upstream) {
6940
+ return {
6941
+ success: false,
6942
+ errors: [
6943
+ `Orbital "${parsed.orbitalName}" not found in imported behavior "${parsed.alias}". Available orbitals: ${candidates.map((o) => o.name).join(", ") || "none"}`
6944
+ ]
6945
+ };
6946
+ }
6947
+ const cycleKey = `${imported.sourcePath}::${parsed.orbitalName}`;
6948
+ if (visiting.has(cycleKey)) {
6949
+ return {
6950
+ success: false,
6951
+ errors: [
6952
+ `Circular orbital reference: "${orbital.name}" imports "${parsed.alias}.orbitals.${parsed.orbitalName}" while that orbital is itself being resolved`
6953
+ ]
6954
+ };
6955
+ }
6956
+ visiting.add(cycleKey);
6957
+ if (upstream.reference) {
6958
+ const nested = await this.resolveOrbitalRefChain(
6959
+ upstream,
6960
+ imported.sourcePath,
6961
+ chain,
6962
+ visiting,
6963
+ consumerEntityIds,
6964
+ consumerRoster
6965
+ );
6966
+ if (!nested.success) {
6967
+ visiting.delete(cycleKey);
6968
+ return nested;
6969
+ }
6970
+ upstream = nested.data;
6971
+ }
6972
+ visiting.delete(cycleKey);
6973
+ const materialized = await this.materializeOrbitalRef(
6974
+ upstream,
6975
+ ref,
6976
+ orbital.name,
6977
+ orbital.id,
6978
+ imported.sourcePath,
6979
+ chain,
6980
+ candidates,
6981
+ consumerEntityIds,
6982
+ consumerRoster,
6983
+ imported.schemaConfig
6984
+ );
6985
+ if (!materialized.success) return materialized;
6986
+ const siblingTraits = orbital.traits ?? [];
6987
+ return {
6988
+ success: true,
6989
+ data: {
6990
+ ...materialized.data,
6991
+ ...siblingTraits.length > 0 ? { traits: [...materialized.data.traits, ...siblingTraits] } : {},
6992
+ uses: orbital.uses
6993
+ },
6994
+ warnings: materialized.warnings
6995
+ };
6996
+ }
6997
+ /**
6998
+ * Materialize a reference-form orbital: flatten the (already-inlined)
6999
+ * upstream orbital's whole trait/entity/page closure into the consumer,
7000
+ * unconditionally prefixed by `localName` (docs/Almadar_Orbital_Import.md
7001
+ * §4.3). JS twin of the (not-yet-landed) compiler's
7002
+ * `resolve_orbital_reference`.
7003
+ */
7004
+ async materializeOrbitalRef(upstream, ref, localName, localId, sourcePath, chain, aliasOrbitals, consumerEntityIds, consumerRoster, importedSchemaConfig) {
7005
+ const savedSchemaConfig = this.schemaConfig;
7006
+ this.schemaConfig = importedSchemaConfig;
7007
+ let resolvedUpstream;
7008
+ try {
7009
+ resolvedUpstream = await this.resolve(upstream, sourcePath, chain);
7010
+ } finally {
7011
+ this.schemaConfig = savedSchemaConfig;
7012
+ }
7013
+ if (!resolvedUpstream.success) {
7014
+ return {
7015
+ success: false,
7016
+ errors: resolvedUpstream.errors.map(
7017
+ (e) => `Orbital reference "${localName}" (${ref.ref}): ${e}`
7018
+ )
7019
+ };
7020
+ }
7021
+ const {
7022
+ entity: upstreamEntity,
7023
+ traits: upstreamTraits,
7024
+ pages: upstreamPages,
7025
+ // (C) the RESOLVED aux-entity set — includes whatever sibling-pull
7026
+ // surfaced (`pullSiblingTraits`'s aux-entity carry), never just
7027
+ // `upstream.auxiliaryEntities` (the pre-resolve INPUT, which misses
7028
+ // every un-rebound composed atom's own entity).
7029
+ auxiliaryEntities: upstreamAuxiliaryEntities
7030
+ } = resolvedUpstream.data;
7031
+ const onlySet = ref.only ? new Set(ref.only) : void 0;
7032
+ const omitSet = new Set(ref.omit ?? []);
7033
+ const keptTraits = upstreamTraits.filter(
7034
+ (rt) => onlySet ? onlySet.has(rt.trait.name) : !omitSet.has(rt.trait.name)
7035
+ );
7036
+ const keptNames = new Set(keptTraits.map((rt) => rt.trait.name));
7037
+ const removedNames = new Set(
7038
+ upstreamTraits.map((rt) => rt.trait.name).filter((n) => !keptNames.has(n))
7039
+ );
7040
+ const errors = [];
7041
+ for (const rt of keptTraits) {
7042
+ for (const embed of traitEmbedNamesOf(rt.trait)) {
7043
+ if (removedNames.has(embed)) {
7044
+ errors.push(
7045
+ `Orbital "${localName}" omits trait "${embed}" but surviving trait "${rt.trait.name}" still embeds it via @trait.${embed} (ORB_O_OMIT_EMBEDDED_TRAIT)`
7046
+ );
7047
+ }
7048
+ }
7049
+ }
7050
+ if (errors.length > 0) return { success: false, errors };
7051
+ let auxEntities = upstreamAuxiliaryEntities ?? [];
7052
+ const subs = /* @__PURE__ */ new Map();
7053
+ for (const rt of keptTraits) subs.set(rt.trait.name, `${localName}${rt.trait.name}`);
7054
+ const { name: primaryFinalName, id: primaryId } = materializedPrimaryEntity(
7055
+ upstreamEntity,
7056
+ upstream.id,
7057
+ ref,
7058
+ localName
7059
+ );
7060
+ subs.set(upstreamEntity.name, primaryFinalName);
7061
+ for (const e of auxEntities) subs.set(e.name, `${localName}${e.name}`);
7062
+ const fieldSubs = new Map(Object.entries(ref.fields ?? {}));
7063
+ const closure = /* @__PURE__ */ new Set([upstreamEntity.name, ...auxEntities.map((e) => e.name)]);
7064
+ const upstreamUniverse = /* @__PURE__ */ new Set();
7065
+ const upstreamUniverseEntities = /* @__PURE__ */ new Map();
7066
+ const primaryEntityNames = /* @__PURE__ */ new Set();
7067
+ for (const o of aliasOrbitals) {
7068
+ if (o.name === upstream.name) continue;
7069
+ if (isInlineEntity(o.entity)) primaryEntityNames.add(o.entity.name);
7070
+ for (const entity of inlineEntityRefsOf(o)) {
7071
+ if (!closure.has(entity.name)) {
7072
+ upstreamUniverse.add(entity.name);
7073
+ upstreamUniverseEntities.set(entity.name, entity);
7074
+ }
7075
+ }
7076
+ }
7077
+ const entityIds = /* @__PURE__ */ new Map();
7078
+ if (ref.entities) {
7079
+ for (const [upstreamKey, consumerName] of Object.entries(ref.entities)) {
7080
+ if (!upstreamUniverse.has(upstreamKey)) {
7081
+ errors.push(
7082
+ `Orbital "${localName}" declares entities { ${upstreamKey}: ${consumerName} } but "${upstreamKey}" is not an out-of-orbital entity of upstream alias "${upstream.name}" (ORB_O_ENTITY_UNKNOWN_KEY)`
7083
+ );
7084
+ continue;
7085
+ }
7086
+ const consumerId = consumerEntityIds.get(consumerName);
7087
+ if (consumerId === void 0) {
7088
+ errors.push(
7089
+ `Orbital "${localName}" entities { ${upstreamKey}: ${consumerName} } targets "${consumerName}", which the consumer schema does not declare (ORB_O_ENTITY_TARGET_UNKNOWN)`
7090
+ );
7091
+ continue;
7092
+ }
7093
+ subs.set(upstreamKey, consumerName);
7094
+ entityIds.set(consumerName, consumerId);
7095
+ }
7096
+ if (errors.length > 0) return { success: false, errors };
7097
+ }
7098
+ const referenced = /* @__PURE__ */ new Set();
7099
+ for (const rt of keptTraits) {
7100
+ if (rt.trait.linkedEntity && upstreamUniverse.has(rt.trait.linkedEntity)) {
7101
+ referenced.add(rt.trait.linkedEntity);
7102
+ }
7103
+ for (const name of collectEntityNamesInTrait(rt.trait, upstreamUniverse)) referenced.add(name);
7104
+ if (rt.trait.sourceEntityDefinition) {
7105
+ for (const name of relationTargetsOfEntity(rt.trait.sourceEntityDefinition, upstreamUniverse)) {
7106
+ referenced.add(name);
7107
+ }
7108
+ }
7109
+ }
7110
+ for (const name of relationTargetsOfEntity(upstreamEntity, upstreamUniverse)) referenced.add(name);
7111
+ for (const aux of auxEntities) {
7112
+ for (const name of relationTargetsOfEntity(aux, upstreamUniverse)) referenced.add(name);
7113
+ }
7114
+ for (const rp of upstreamPages) {
7115
+ if (rp.page.primaryEntity && upstreamUniverse.has(rp.page.primaryEntity)) {
7116
+ referenced.add(rp.page.primaryEntity);
7117
+ }
7118
+ for (const tr of rp.page.traits ?? []) {
7119
+ if (tr.linkedEntity && upstreamUniverse.has(tr.linkedEntity)) referenced.add(tr.linkedEntity);
7120
+ }
7121
+ }
7122
+ for (const name of referenced) {
7123
+ if (subs.has(name)) continue;
7124
+ const definition = upstreamUniverseEntities.get(name);
7125
+ const auxOnly = definition !== void 0 && !primaryEntityNames.has(name);
7126
+ if (definition && auxOnly && !definition.identity) {
7127
+ auxEntities = [...auxEntities, definition];
7128
+ subs.set(name, `${localName}${name}`);
7129
+ continue;
7130
+ }
7131
+ errors.push(
7132
+ `Orbital "${localName}" references out-of-orbital entity "${name}" with no "${name}: <consumer entity>" mapping in entities {} (ORB_O_ENTITY_UNMAPPED)`
7133
+ );
7134
+ }
7135
+ if (errors.length > 0) return { success: false, errors };
7136
+ const roleFields = /* @__PURE__ */ new Map();
7137
+ for (const entity of identityEntitiesOf(aliasOrbitals)) {
7138
+ for (const field of entity.fields) {
7139
+ if (!field.name) continue;
7140
+ const vocab = roleVocabularyOf(entity, field.name);
7141
+ if (vocab) roleFields.set(field.name, vocab);
7142
+ }
7143
+ }
7144
+ const consumerRoleFields = /* @__PURE__ */ new Map();
7145
+ for (const entity of consumerRoster) {
7146
+ for (const field of entity.fields) {
7147
+ if (!field.name) continue;
7148
+ const vocab = roleVocabularyOf(entity, field.name);
7149
+ if (!vocab) continue;
7150
+ let values = consumerRoleFields.get(field.name);
7151
+ if (!values) {
7152
+ values = /* @__PURE__ */ new Set();
7153
+ consumerRoleFields.set(field.name, values);
7154
+ }
7155
+ for (const value of vocab) values.add(value);
7156
+ }
7157
+ }
7158
+ for (const [literal, targets] of Object.entries(ref.roles ?? {})) {
7159
+ const matchingFields = [...roleFields.entries()].filter(([, vocab]) => vocab.includes(literal)).map(([field]) => field).sort();
7160
+ if (matchingFields.length === 0) {
7161
+ errors.push(
7162
+ `Orbital "${localName}" declares roles { ${literal}: ... } but upstream alias "${upstream.name}"'s roster declares no role field with literal "${literal}" in its vocabulary (ORB_O_ROLE_UNKNOWN_UPSTREAM)`
7163
+ );
7164
+ continue;
7165
+ }
7166
+ for (const field of matchingFields) {
7167
+ const allowed = consumerRoleFields.get(field);
7168
+ for (const target of targets) {
7169
+ if (allowed?.has(target)) continue;
7170
+ errors.push(
7171
+ `Orbital "${localName}" roles { ${literal}: ${target} } targets "${target}", which is not a member of consumer field "${field}" on the roster (values: ${allowed ? [...allowed].sort().join(", ") : "(none)"}) (ORB_O_ROLE_TARGET_NOT_MEMBER)`
7172
+ );
7173
+ }
7174
+ }
7175
+ }
7176
+ if (errors.length > 0) return { success: false, errors };
7177
+ const declaredConfig = upstream.config;
7178
+ if (ref.config) {
7179
+ for (const key of Object.keys(ref.config)) {
7180
+ if (!declaredConfig || !(key in declaredConfig)) {
7181
+ errors.push(
7182
+ `Orbital "${localName}" overrides config "${key}" but upstream orbital "${upstream.name}" does not declare that knob (ORB_O_CONFIG_UNKNOWN_KEY)`
7183
+ );
7184
+ }
7185
+ }
7186
+ if (errors.length > 0) return { success: false, errors };
7187
+ }
7188
+ const configOverrideValues = {};
7189
+ for (const [key, field] of Object.entries(ref.config ?? {})) {
7190
+ if (field.default !== void 0) configOverrideValues[key] = field.default;
7191
+ }
7192
+ const foldedConfig = declaredConfig ? overrideDeclaredKnobs(declaredConfig, configOverrideValues) : void 0;
7193
+ const idByName = /* @__PURE__ */ new Map();
7194
+ const materializedTraits = keptTraits.map((rt) => {
7195
+ const finalName = subs.get(rt.trait.name);
7196
+ const finalId = asTraitId(deriveMaterializedId(rt.trait.id, upstream.id, rt.trait.name, localName, "trait"));
7197
+ idByName.set(finalName, finalId);
7198
+ return { ...rt.trait, name: finalName, id: finalId };
7199
+ });
7200
+ const embeddersOf = /* @__PURE__ */ new Map();
7201
+ for (const t of materializedTraits) {
7202
+ for (const embed of traitEmbedNamesOf(t)) {
7203
+ const embedFinal = subs.get(embed);
7204
+ if (!embedFinal) continue;
7205
+ let embedders = embeddersOf.get(embedFinal);
7206
+ if (!embedders) {
7207
+ embedders = [];
7208
+ embeddersOf.set(embedFinal, embedders);
7209
+ }
7210
+ embedders.push(t.name);
7211
+ }
7212
+ }
7213
+ const parentConfigs = new Map(
7214
+ materializedTraits.map((t) => [t.name, t.config])
7215
+ );
7216
+ const transitiveEmbedderChain = (name) => {
7217
+ const chain2 = [];
7218
+ const seenNames = /* @__PURE__ */ new Set([name]);
7219
+ let cur = embeddersOf.get(name)?.[0];
7220
+ while (cur !== void 0 && !seenNames.has(cur)) {
7221
+ seenNames.add(cur);
7222
+ const cfg = parentConfigs.get(cur);
7223
+ if (cfg) chain2.push(cfg);
7224
+ cur = embeddersOf.get(cur)?.[0];
7225
+ }
7226
+ return chain2;
7227
+ };
7228
+ entityIds.set(primaryFinalName, primaryId);
7229
+ for (const e of auxEntities) {
7230
+ entityIds.set(
7231
+ subs.get(e.name),
7232
+ asEntityId(deriveMaterializedId(e.id, upstream.id, e.name, localName, "entity"))
7233
+ );
7234
+ }
7235
+ const upstreamPathSet = new Set(upstreamPages.map((rp) => rp.page.path));
7236
+ for (const path of [...Object.keys(ref.pages ?? {}), ...Object.keys(ref.mounts ?? {})]) {
7237
+ if (!upstreamPathSet.has(path)) {
7238
+ errors.push(
7239
+ `Orbital "${localName}" names page path "${path}" but upstream orbital "${upstream.name}" has no page at that path (ORB_O_PAGE_UNKNOWN_PATH)`
7240
+ );
7241
+ }
7242
+ }
7243
+ if (errors.length > 0) return { success: false, errors };
7244
+ const pathMap = new Map(
7245
+ upstreamPages.map((rp) => [rp.page.path, ref.pages?.[rp.page.path] ?? rp.page.path])
7246
+ );
7247
+ const orbitalRename = upstream.name !== localName ? { from: upstream.name, to: localName } : void 0;
7248
+ const finalTraits = materializedTraits.map((trait) => {
7249
+ let next = renameTraitEmbeds(trait, subs);
7250
+ next = renameEntitiesInTrait(next, subs);
7251
+ if (next.linkedEntity !== void 0) {
7252
+ const linkedEntityId = entityIds.get(next.linkedEntity);
7253
+ if (linkedEntityId !== void 0) next = { ...next, linkedEntityId };
7254
+ }
7255
+ next = rewriteEntityRefIds(next, subs, entityIds);
7256
+ next = renameSourceEntityDefinition(next, subs, entityIds);
7257
+ next = rewriteRoleLiteralsInTrait(next, roleFields, ref.roles ?? {});
7258
+ if (fieldSubs.size > 0) next = rewriteEntityFieldsInTrait(next, fieldSubs);
7259
+ next = rewriteListenSources(next, subs, idByName, orbitalRename);
7260
+ if (pathMap.size > 0) {
7261
+ next = rewriteTraitNavigateTargets(next, pathMap);
7262
+ }
7263
+ for (const embedderName of embeddersOf.get(trait.name) ?? []) {
7264
+ const embedderConfig = parentConfigs.get(embedderName);
7265
+ next = resolveForwardedSiblingConfigFrom(next, embedderConfig ? [embedderConfig] : []);
7266
+ }
7267
+ next = resolveForwardedSiblingConfigFrom(next, transitiveEmbedderChain(trait.name));
7268
+ next = resolveForwardedSiblingConfigFrom(next, [], foldedConfig, importedSchemaConfig);
7269
+ if (pathMap.size > 0) {
7270
+ next = rewriteTraitConfigPagePaths(next, pathMap);
7271
+ }
7272
+ next = applyEventRenames(next, ref.events);
7273
+ return next;
7274
+ });
7275
+ const renamedPrimaryEntity = rewriteRoleLiteralsInEntity(
7276
+ renameEntityRelationTargets(
7277
+ rewriteEntityFieldsInEntity(
7278
+ {
7279
+ ...upstreamEntity,
7280
+ name: primaryFinalName,
7281
+ id: primaryId
7282
+ },
7283
+ fieldSubs
7284
+ ),
7285
+ subs,
7286
+ entityIds
7287
+ ),
7288
+ roleFields,
7289
+ ref.roles ?? {}
7290
+ );
7291
+ const extendResult = applyExtendFields(
7292
+ renamedPrimaryEntity,
7293
+ ref.extend,
7294
+ fieldSubs,
7295
+ consumerEntityIds,
7296
+ localName
7297
+ );
7298
+ if (extendResult.errors.length > 0) return { success: false, errors: extendResult.errors };
7299
+ const primaryEntity = extendResult.entity;
7300
+ const finalAuxEntities = auxEntities.map((e) => {
7301
+ const finalName = subs.get(e.name);
7302
+ return rewriteRoleLiteralsInEntity(
7303
+ renameEntityRelationTargets(
7304
+ rewriteEntityFieldsInEntity(
7305
+ {
7306
+ ...e,
7307
+ name: finalName,
7308
+ id: entityIds.get(finalName)
7309
+ },
7310
+ fieldSubs
7311
+ ),
7312
+ subs,
7313
+ entityIds
7314
+ ),
7315
+ roleFields,
7316
+ ref.roles ?? {}
7317
+ );
7318
+ });
7319
+ const finalPages = upstreamPages.map((rp) => {
7320
+ const original = rp.page;
7321
+ const mountNames = ref.mounts?.[original.path] ?? [];
7322
+ const finalPageTraits = [
7323
+ ...(original.traits ?? []).filter((tr) => !removedNames.has(tr.ref)).map((tr) => {
7324
+ const finalRef = subs.get(tr.ref) ?? tr.ref;
7325
+ const refId = idByName.get(finalRef);
7326
+ return {
7327
+ ...tr,
7328
+ ref: finalRef,
7329
+ ...refId !== void 0 ? { refId } : {},
7330
+ ...tr.linkedEntity !== void 0 ? { linkedEntity: subs.get(tr.linkedEntity) ?? tr.linkedEntity } : {}
7331
+ };
7332
+ }),
7333
+ ...mountNames.map((name) => ({ ref: name }))
7334
+ ];
7335
+ return {
7336
+ ...original,
7337
+ // Gap (E) — unconditionally prefixed, same as traits/entities (§4.3):
7338
+ // two imports of the same upstream orbital with distinct `pages {}`
7339
+ // path maps must not collide on page NAME (`Duplicate page name`).
7340
+ // `id` is the page-scope sibling of `deriveMaterializedId` (never
7341
+ // `mintId`) — fresh and pairwise-disjoint across imports, same as
7342
+ // trait/entity ids above.
7343
+ name: `${localName}${original.name}`,
7344
+ id: asPageId(deriveMaterializedId(original.id, upstream.id, original.name, localName, "page")),
7345
+ path: pathMap.get(original.path) ?? original.path,
7346
+ ...original.primaryEntity !== void 0 ? { primaryEntity: subs.get(original.primaryEntity) ?? original.primaryEntity } : {},
7347
+ traits: finalPageTraits
7348
+ };
7349
+ });
7350
+ const forwardedKnobs = /* @__PURE__ */ new Set();
7351
+ for (const rt of keptTraits) {
7352
+ for (const field of Object.values(rt.trait.config ?? {})) {
7353
+ if (typeof field.default === "string" && field.default.startsWith("@config.")) {
7354
+ const knob = field.default.slice("@config.".length);
7355
+ if (knob.length > 0 && !knob.includes(".")) forwardedKnobs.add(knob);
7356
+ }
7357
+ }
7358
+ }
7359
+ const prunedConfig = foldedConfig ? Object.fromEntries(Object.entries(foldedConfig).filter(([key]) => forwardedKnobs.has(key))) : void 0;
7360
+ const orbitalId = localId ?? (upstream.id ? asOrbitalId(deriveId(upstream.id, localName)) : void 0);
7361
+ refResolverLog.info("orbital-import:materialize", {
7362
+ local: localName,
7363
+ upstream: upstream.name,
7364
+ traits: finalTraits.length,
7365
+ pages: finalPages.length
7366
+ });
7367
+ return {
7368
+ success: true,
7369
+ data: {
7370
+ ...upstream,
7371
+ name: localName,
7372
+ ...orbitalId ? { id: orbitalId } : {},
7373
+ entity: primaryEntity,
7374
+ ...finalAuxEntities.length > 0 ? { auxiliaryEntities: finalAuxEntities } : {},
7375
+ traits: finalTraits,
7376
+ pages: finalPages,
7377
+ emits: void 0,
7378
+ listens: void 0,
7379
+ exposes: void 0,
7380
+ ...prunedConfig ? { config: prunedConfig } : { config: void 0 },
7381
+ uses: void 0,
7382
+ reference: void 0
7383
+ },
7384
+ warnings: []
7385
+ };
7386
+ }
4956
7387
  /**
4957
7388
  * Add local traits for resolution.
4958
7389
  */
@@ -4972,28 +7403,36 @@ var ReferenceResolver = class {
4972
7403
  }
4973
7404
  };
4974
7405
  async function resolveSchema(schema, options) {
4975
- const resolver = new ReferenceResolver(options);
7406
+ const resolver = new ReferenceResolver({ ...options, schemaConfig: schema.config });
4976
7407
  const errors = [];
4977
7408
  const warnings = [];
4978
7409
  const resolved = [];
4979
- for (const orbital of schema.orbitals) {
7410
+ const flattenResult = await resolver.resolveOrbitalImports(schema);
7411
+ if (!flattenResult.success) {
7412
+ return { success: false, errors: flattenResult.errors };
7413
+ }
7414
+ const orbitals = flattenResult.data;
7415
+ for (const orbital of orbitals) {
4980
7416
  const inlineTraits = orbital.traits.filter(
4981
7417
  (t) => typeof t !== "string" && "stateMachine" in t
4982
7418
  );
4983
7419
  resolver.addLocalTraits(inlineTraits);
4984
7420
  }
4985
- for (const orbital of schema.orbitals) {
7421
+ resolver.seedSchemaEntityIds(orbitals);
7422
+ for (const orbital of orbitals) {
4986
7423
  const result = await resolver.resolve(orbital);
4987
7424
  if (!result.success) {
4988
7425
  errors.push(`Orbital "${orbital.name}": ${result.errors.join(", ")}`);
4989
7426
  } else {
4990
7427
  resolved.push(result.data);
7428
+ resolver.noteResolvedEntityIds(result.data);
4991
7429
  warnings.push(...result.warnings.map((w) => `Orbital "${orbital.name}": ${w}`));
4992
7430
  }
4993
7431
  }
4994
7432
  if (errors.length > 0) {
4995
7433
  return { success: false, errors };
4996
7434
  }
7435
+ resolver.uniquifyCrossOrbitalPulledSiblings(resolved);
4997
7436
  return { success: true, data: resolved, warnings };
4998
7437
  }
4999
7438
 
@@ -5208,4 +7647,4 @@ var InMemoryPersistence = class {
5208
7647
  }
5209
7648
  };
5210
7649
 
5211
- export { EffectExecutor, EventBus, HANDLER_MANIFEST, InMemoryPersistence, MockPersistenceAdapter, StateMachineManager, TickScheduler, buildEmitsFromTraits, collectDeclaredConfigDefaults, collectDeclaredEntityDefaults, createInitialTraitState, createMockPersistence, createTestExecutor, createTickScheduler, createUnifiedLoader, findInitialState, findTransition, formatPayloadValidationError, getIsolatedCollectionName, getNamespacedEvent, isBrowser, isElectron, isNamespacedEvent, isNode, isValidDurationString, normalizeEventKey, parseDurationString, parseNamespacedEvent, preprocessSchema, processEvent, validateEventPayload, validatePayloadShapes };
7650
+ 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, normalizeEventKey, parseDurationString, parseNamespacedEvent, preprocessSchema, processEvent, validateEventPayload, validatePayloadShapes };