@almadar/runtime 6.33.0 → 6.34.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.
- package/dist/{OrbitalServerRuntime-Cep380it.d.ts → OrbitalServerRuntime-BrHSXDfp.d.ts} +52 -7
- package/dist/OrbitalServerRuntime.d.ts +2 -2
- package/dist/OrbitalServerRuntime.js +61 -23
- package/dist/ServerBridge.d.ts +1 -1
- package/dist/{chunk-JZDLN2FS.js → chunk-TRA44DDY.js} +350 -61
- package/dist/createOsHandlers.d.ts +1 -1
- package/dist/{external-loader-OPXVTNC4.js → external-loader-FNK5AU6U.js} +27 -1
- package/dist/index.d.ts +11 -7
- package/dist/index.js +44 -4
- package/dist/{types-ConZnrpe.d.ts → types-C8RsO0xa.d.ts} +13 -3
- package/package.json +4 -4
|
@@ -5,7 +5,7 @@ import { createLogger, setNamespaceLevel } from '@almadar/logger';
|
|
|
5
5
|
import { createMinimalContext, resolveBinding, evaluate, evaluateGuard, SExpressionEvaluator } from '@almadar/evaluator';
|
|
6
6
|
export { createMinimalContext } from '@almadar/evaluator';
|
|
7
7
|
import { isKnownStdOperator } from '@almadar/std/registry';
|
|
8
|
-
import { OrbitalSchemaSchema, isInlineTrait, isEntityCall, isEntityReference, parseEntityRef, parseImportedTraitRef, isPageReference, isPageReferenceString, isPageReferenceObject, parsePageRef, configRefEventKnob, normalizeCallSiteConfigToValues, resolveConfigRefEventName } from '@almadar/core';
|
|
8
|
+
import { OrbitalSchemaSchema, isInlineTrait, isEntityCall, isEntityReference, parseEntityRef, parseImportedTraitRef, isPageReference, isPageReferenceString, isPageReferenceObject, parsePageRef, isReferenceConfigType, configRefEventKnob, normalizeCallSiteConfigToValues, resolveConfigRefEventName } from '@almadar/core';
|
|
9
9
|
export { normalizeCallSiteConfigToValues } from '@almadar/core';
|
|
10
10
|
|
|
11
11
|
var log = createLogger("almadar:runtime:eventbus");
|
|
@@ -26,7 +26,7 @@ var EventBus = class {
|
|
|
26
26
|
* beyond `maxDepth`, the event is dropped and an error is logged.
|
|
27
27
|
* This prevents infinite loops from circular emit/listen chains.
|
|
28
28
|
*/
|
|
29
|
-
emit(type, payload, source) {
|
|
29
|
+
emit(type, payload, source, routingKey) {
|
|
30
30
|
if (this.depth >= this.maxDepth) {
|
|
31
31
|
log.error("circular event loop dropped", { type, depth: this.depth, maxDepth: this.maxDepth });
|
|
32
32
|
return;
|
|
@@ -37,12 +37,13 @@ var EventBus = class {
|
|
|
37
37
|
timestamp: Date.now(),
|
|
38
38
|
source
|
|
39
39
|
};
|
|
40
|
-
const
|
|
40
|
+
const deliveryKey = routingKey ?? type;
|
|
41
|
+
const listeners = this.listeners.get(deliveryKey);
|
|
41
42
|
const listenerCount = listeners?.size ?? 0;
|
|
42
43
|
if (listenerCount > 0) {
|
|
43
44
|
log.debug("emit", { type, listenerCount, depth: this.depth });
|
|
44
45
|
} else {
|
|
45
|
-
log.
|
|
46
|
+
log.debug("emit no listeners", { type });
|
|
46
47
|
}
|
|
47
48
|
this.depth++;
|
|
48
49
|
try {
|
|
@@ -394,6 +395,7 @@ function interpolateValue(value, ctx) {
|
|
|
394
395
|
}
|
|
395
396
|
return value;
|
|
396
397
|
}
|
|
398
|
+
var inFlightConfigRecursions = /* @__PURE__ */ new Set();
|
|
397
399
|
function interpolateString(value, ctx) {
|
|
398
400
|
if (value.startsWith("@") && isPureBinding(value)) {
|
|
399
401
|
if (isClientOnlyBinding(value)) {
|
|
@@ -402,6 +404,15 @@ function interpolateString(value, ctx) {
|
|
|
402
404
|
}
|
|
403
405
|
const resolved = resolveBinding(value, ctx);
|
|
404
406
|
bindLog.debug("resolve", { binding: value, resolvedType: typeof resolved });
|
|
407
|
+
if (value.startsWith("@config.") && resolved !== null && typeof resolved === "object" && containsBindings(resolved) && !inFlightConfigRecursions.has(value)) {
|
|
408
|
+
inFlightConfigRecursions.add(value);
|
|
409
|
+
try {
|
|
410
|
+
bindLog.debug("resolve:config-recurse", { binding: value });
|
|
411
|
+
return interpolateValue(resolved, ctx);
|
|
412
|
+
} finally {
|
|
413
|
+
inFlightConfigRecursions.delete(value);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
405
416
|
return resolved;
|
|
406
417
|
}
|
|
407
418
|
if (value.includes("@")) {
|
|
@@ -443,12 +454,25 @@ function interpolateArray(value, ctx) {
|
|
|
443
454
|
let anyChanged = false;
|
|
444
455
|
for (let i = 0; i < value.length; i++) {
|
|
445
456
|
const item = value[i];
|
|
457
|
+
if (Array.isArray(item) && isRenderChildrenMap(item)) {
|
|
458
|
+
const expanded = evaluate(item, ctx);
|
|
459
|
+
if (Array.isArray(expanded)) {
|
|
460
|
+
for (const node of expanded) mapped.push(node);
|
|
461
|
+
}
|
|
462
|
+
anyChanged = true;
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
446
465
|
const interpolated = interpolateValue(item, ctx);
|
|
447
466
|
mapped.push(interpolated);
|
|
448
467
|
if (interpolated !== item) anyChanged = true;
|
|
449
468
|
}
|
|
450
469
|
return anyChanged ? mapped : value;
|
|
451
470
|
}
|
|
471
|
+
function isRenderChildrenMap(value) {
|
|
472
|
+
if (value.length !== 3 || value[0] !== "array/map") return false;
|
|
473
|
+
const lambda = value[2];
|
|
474
|
+
return Array.isArray(lambda) && lambda.length === 3 && lambda[0] === "fn" && typeof lambda[1] === "string";
|
|
475
|
+
}
|
|
452
476
|
function isSExpression(value) {
|
|
453
477
|
if (value.length === 0) return false;
|
|
454
478
|
const first = value[0];
|
|
@@ -526,19 +550,21 @@ function createInitialTraitState(trait) {
|
|
|
526
550
|
context: {}
|
|
527
551
|
};
|
|
528
552
|
}
|
|
529
|
-
function findMatchingTransitions(trait, currentState, eventKey) {
|
|
553
|
+
function findMatchingTransitions(trait, currentState, eventKey, eventId) {
|
|
530
554
|
if (!trait.transitions || trait.transitions.length === 0) {
|
|
531
555
|
return [];
|
|
532
556
|
}
|
|
533
557
|
return trait.transitions.filter((t) => {
|
|
534
|
-
|
|
535
|
-
|
|
558
|
+
const fromMatches = Array.isArray(t.from) ? t.from.includes(currentState) : t.from === currentState;
|
|
559
|
+
if (!fromMatches) return false;
|
|
560
|
+
if (eventId && t.eventId) {
|
|
561
|
+
return t.eventId === eventId;
|
|
536
562
|
}
|
|
537
|
-
return t.
|
|
563
|
+
return t.event === eventKey;
|
|
538
564
|
});
|
|
539
565
|
}
|
|
540
|
-
function findTransition(trait, currentState, eventKey) {
|
|
541
|
-
return findMatchingTransitions(trait, currentState, eventKey)[0];
|
|
566
|
+
function findTransition(trait, currentState, eventKey, eventId) {
|
|
567
|
+
return findMatchingTransitions(trait, currentState, eventKey, eventId)[0];
|
|
542
568
|
}
|
|
543
569
|
function normalizeEventKey(eventKey) {
|
|
544
570
|
if (!eventKey) return "";
|
|
@@ -549,6 +575,7 @@ function processEvent(options) {
|
|
|
549
575
|
traitState,
|
|
550
576
|
trait,
|
|
551
577
|
eventKey,
|
|
578
|
+
eventId,
|
|
552
579
|
payload,
|
|
553
580
|
entityData,
|
|
554
581
|
config,
|
|
@@ -557,7 +584,7 @@ function processEvent(options) {
|
|
|
557
584
|
contextExtensions
|
|
558
585
|
} = options;
|
|
559
586
|
const normalizedEvent = normalizeEventKey(eventKey);
|
|
560
|
-
const candidates = findMatchingTransitions(trait, traitState.currentState, normalizedEvent);
|
|
587
|
+
const candidates = findMatchingTransitions(trait, traitState.currentState, normalizedEvent, eventId);
|
|
561
588
|
if (candidates.length === 0) {
|
|
562
589
|
smLog.debug("noTransition", { trait: trait.name, event: normalizedEvent, currentState: traitState.currentState });
|
|
563
590
|
return {
|
|
@@ -676,6 +703,15 @@ function compositeKey(traitName, scope) {
|
|
|
676
703
|
}
|
|
677
704
|
var StateMachineManager = class {
|
|
678
705
|
traits = /* @__PURE__ */ new Map();
|
|
706
|
+
/**
|
|
707
|
+
* V4 identity index: trait id → trait name. Populated for traits that
|
|
708
|
+
* carry an `id` (ledger-backed schemas). Lets callers resolve a trait's
|
|
709
|
+
* state by its stable id, which survives a mid-session rename — the
|
|
710
|
+
* name-keyed maps are re-pointed on rename via {@link renameTrait}, but
|
|
711
|
+
* an id holder never has to observe the rename at all. Empty for legacy
|
|
712
|
+
* id-free schemas, where every lookup stays name-keyed (unchanged).
|
|
713
|
+
*/
|
|
714
|
+
traitIdToName = /* @__PURE__ */ new Map();
|
|
679
715
|
/**
|
|
680
716
|
* Per-trait call-site config, surfaced to guard expressions so
|
|
681
717
|
* `@config.X` resolves at runtime. Populated by the orbital's
|
|
@@ -726,6 +762,69 @@ var StateMachineManager = class {
|
|
|
726
762
|
*/
|
|
727
763
|
addTrait(trait) {
|
|
728
764
|
this.traits.set(trait.name, trait);
|
|
765
|
+
if (trait.id !== void 0) {
|
|
766
|
+
this.traitIdToName.set(trait.id, trait.name);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Resolve a trait by its V4 id. Returns undefined when no trait carries
|
|
771
|
+
* that id (legacy schema, or unknown id). Exact-match only — no name
|
|
772
|
+
* similarity.
|
|
773
|
+
*/
|
|
774
|
+
getTraitById(traitId) {
|
|
775
|
+
const name = this.traitIdToName.get(traitId);
|
|
776
|
+
return name === void 0 ? void 0 : this.traits.get(name);
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Get a trait's current state by its V4 id (id-first lookup). Falls back
|
|
780
|
+
* to `undefined` when the id is unknown. The id survives a rename, so a
|
|
781
|
+
* holder of the id reads the right state without ever seeing the new name.
|
|
782
|
+
*/
|
|
783
|
+
getStateById(traitId, entityId) {
|
|
784
|
+
const name = this.traitIdToName.get(traitId);
|
|
785
|
+
return name === void 0 ? void 0 : this.getState(name, entityId);
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Apply a mid-session trait rename: re-point the name-keyed maps from
|
|
789
|
+
* `oldName` to `newName`, preserving live state, queues, and the id
|
|
790
|
+
* index. A no-op when the trait isn't registered under `oldName`. This
|
|
791
|
+
* is the interpreter-side of a ledger `curName` edit for the trait's own
|
|
792
|
+
* name-keyed storage; id-keyed references need no update.
|
|
793
|
+
*/
|
|
794
|
+
renameTrait(oldName, newName) {
|
|
795
|
+
const trait = this.traits.get(oldName);
|
|
796
|
+
if (!trait || oldName === newName) return;
|
|
797
|
+
const renamed = { ...trait, name: newName };
|
|
798
|
+
this.traits.delete(oldName);
|
|
799
|
+
this.traits.set(newName, renamed);
|
|
800
|
+
if (renamed.id !== void 0) {
|
|
801
|
+
this.traitIdToName.set(renamed.id, newName);
|
|
802
|
+
}
|
|
803
|
+
const remap = (m) => {
|
|
804
|
+
const prefix2 = `${oldName}::`;
|
|
805
|
+
for (const key of [...m.keys()]) {
|
|
806
|
+
if (key.startsWith(prefix2)) {
|
|
807
|
+
const scope = key.slice(prefix2.length);
|
|
808
|
+
const v = m.get(key);
|
|
809
|
+
m.delete(key);
|
|
810
|
+
m.set(`${newName}::${scope}`, v);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
remap(this.states);
|
|
815
|
+
remap(this.queues);
|
|
816
|
+
const prefix = `${oldName}::`;
|
|
817
|
+
for (const key of [...this.processing]) {
|
|
818
|
+
if (key.startsWith(prefix)) {
|
|
819
|
+
this.processing.delete(key);
|
|
820
|
+
this.processing.add(`${newName}::${key.slice(prefix.length)}`);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
const cfg = this.traitConfigs.get(oldName);
|
|
824
|
+
if (cfg !== void 0) {
|
|
825
|
+
this.traitConfigs.set(newName, cfg);
|
|
826
|
+
this.traitConfigs.delete(oldName);
|
|
827
|
+
}
|
|
729
828
|
}
|
|
730
829
|
/**
|
|
731
830
|
* Bind the call-site config for a trait so guard `@config.X`
|
|
@@ -744,6 +843,10 @@ var StateMachineManager = class {
|
|
|
744
843
|
* Remove a trait from the manager.
|
|
745
844
|
*/
|
|
746
845
|
removeTrait(traitName) {
|
|
846
|
+
const removed = this.traits.get(traitName);
|
|
847
|
+
if (removed?.id !== void 0) {
|
|
848
|
+
this.traitIdToName.delete(removed.id);
|
|
849
|
+
}
|
|
747
850
|
this.traits.delete(traitName);
|
|
748
851
|
const prefix = `${traitName}::`;
|
|
749
852
|
for (const key of [...this.states.keys()]) {
|
|
@@ -831,11 +934,11 @@ var StateMachineManager = class {
|
|
|
831
934
|
/**
|
|
832
935
|
* Check if a trait can handle an event from its current state.
|
|
833
936
|
*/
|
|
834
|
-
canHandleEvent(traitName, eventKey, entityId) {
|
|
937
|
+
canHandleEvent(traitName, eventKey, entityId, eventId) {
|
|
835
938
|
const trait = this.traits.get(traitName);
|
|
836
939
|
const state = this.getOrInitState(traitName, entityId ?? SINGLETON_SCOPE);
|
|
837
940
|
if (!trait || !state) return false;
|
|
838
|
-
return !!findTransition(trait, state.currentState, normalizeEventKey(eventKey));
|
|
941
|
+
return !!findTransition(trait, state.currentState, normalizeEventKey(eventKey), eventId);
|
|
839
942
|
}
|
|
840
943
|
/**
|
|
841
944
|
* Send an event to all traits.
|
|
@@ -847,9 +950,13 @@ var StateMachineManager = class {
|
|
|
847
950
|
* `@entity.X` see prior step writes — required for [runtime] entities
|
|
848
951
|
* that have no persistence row to reload.
|
|
849
952
|
*
|
|
953
|
+
* `eventId` is the V4 dual-carry id sibling of `eventKey` (see
|
|
954
|
+
* {@link ProcessEventOptions.eventId}) — additive and optional, threaded
|
|
955
|
+
* through to `processEvent` for id-primary transition matching.
|
|
956
|
+
*
|
|
850
957
|
* @returns Array of transition results (one per trait that had a matching transition)
|
|
851
958
|
*/
|
|
852
|
-
sendEvent(eventKey, payload, entityData, entityByTrait) {
|
|
959
|
+
sendEvent(eventKey, payload, entityData, entityByTrait, eventId) {
|
|
853
960
|
const results = [];
|
|
854
961
|
const scope = scopeOf(entityData);
|
|
855
962
|
for (const [traitName, trait] of this.traits) {
|
|
@@ -861,6 +968,7 @@ var StateMachineManager = class {
|
|
|
861
968
|
traitState,
|
|
862
969
|
trait,
|
|
863
970
|
eventKey,
|
|
971
|
+
eventId,
|
|
864
972
|
payload,
|
|
865
973
|
entityData: perTraitEntity,
|
|
866
974
|
config: this.traitConfigs.get(traitName),
|
|
@@ -902,12 +1010,12 @@ var StateMachineManager = class {
|
|
|
902
1010
|
* trait to process them sequentially (actor-model guarantee: one event
|
|
903
1011
|
* at a time per trait, effects fully awaited before the next event).
|
|
904
1012
|
*/
|
|
905
|
-
enqueueEvent(eventKey, payload, entityData, entityByTrait) {
|
|
1013
|
+
enqueueEvent(eventKey, payload, entityData, entityByTrait, eventId) {
|
|
906
1014
|
const scope = scopeOf(entityData);
|
|
907
1015
|
for (const [traitName] of this.traits) {
|
|
908
1016
|
const key = compositeKey(traitName, scope);
|
|
909
1017
|
const queue = this.queues.get(key) ?? [];
|
|
910
|
-
queue.push({ eventKey, payload, entityData, entityByTrait });
|
|
1018
|
+
queue.push({ eventKey, eventId, payload, entityData, entityByTrait });
|
|
911
1019
|
this.queues.set(key, queue);
|
|
912
1020
|
}
|
|
913
1021
|
}
|
|
@@ -932,6 +1040,7 @@ var StateMachineManager = class {
|
|
|
932
1040
|
traitState,
|
|
933
1041
|
trait,
|
|
934
1042
|
eventKey: entry.eventKey,
|
|
1043
|
+
eventId: entry.eventId,
|
|
935
1044
|
payload: entry.payload,
|
|
936
1045
|
entityData: perTraitEntity,
|
|
937
1046
|
config: this.traitConfigs.get(traitName),
|
|
@@ -2212,6 +2321,8 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
|
|
|
2212
2321
|
stores = /* @__PURE__ */ new Map();
|
|
2213
2322
|
schemas = /* @__PURE__ */ new Map();
|
|
2214
2323
|
idCounters = /* @__PURE__ */ new Map();
|
|
2324
|
+
/** entityId -> normalized store name, so relation lookups can prefer the id sibling over `relation.entity` name-matching. */
|
|
2325
|
+
storeNameById = /* @__PURE__ */ new Map();
|
|
2215
2326
|
config;
|
|
2216
2327
|
constructor(config = {}) {
|
|
2217
2328
|
this.config = {
|
|
@@ -2263,6 +2374,9 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
|
|
|
2263
2374
|
registerEntity(schema, seedCount) {
|
|
2264
2375
|
const normalized = schema.name.toLowerCase();
|
|
2265
2376
|
this.schemas.set(normalized, schema);
|
|
2377
|
+
if (schema.id) {
|
|
2378
|
+
this.storeNameById.set(schema.id, normalized);
|
|
2379
|
+
}
|
|
2266
2380
|
if (schema.seedData && schema.seedData.length > 0) {
|
|
2267
2381
|
this.seedFromInstances(schema.name, schema.seedData);
|
|
2268
2382
|
} else {
|
|
@@ -2294,7 +2408,8 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
|
|
|
2294
2408
|
if (relationFields.length === 0) continue;
|
|
2295
2409
|
for (const row of store.values()) {
|
|
2296
2410
|
for (const field of relationFields) {
|
|
2297
|
-
const
|
|
2411
|
+
const targetNormalized = (field.relation.entityId && this.storeNameById.get(field.relation.entityId)) ?? field.relation.entity.toLowerCase();
|
|
2412
|
+
const targetStore = this.stores.get(targetNormalized);
|
|
2298
2413
|
if (!targetStore || targetStore.size === 0) continue;
|
|
2299
2414
|
const selfId = row["id"];
|
|
2300
2415
|
const sameStore = targetStore === store;
|
|
@@ -2972,7 +3087,7 @@ async function getExternalLoaderModule() {
|
|
|
2972
3087
|
return null;
|
|
2973
3088
|
}
|
|
2974
3089
|
try {
|
|
2975
|
-
externalLoaderModule = await import('./external-loader-
|
|
3090
|
+
externalLoaderModule = await import('./external-loader-FNK5AU6U.js');
|
|
2976
3091
|
return externalLoaderModule;
|
|
2977
3092
|
} catch {
|
|
2978
3093
|
return null;
|
|
@@ -3307,10 +3422,10 @@ function substituteConfig(expr, subs) {
|
|
|
3307
3422
|
function buildTemplate(trait) {
|
|
3308
3423
|
const raw = renderOnlyTemplate(trait);
|
|
3309
3424
|
const emits = trait.emits ?? [];
|
|
3310
|
-
if (raw === null) return { template: null, emits };
|
|
3425
|
+
if (raw === null) return { template: null, emits, traitName: trait.name, id: trait.id, embedIds: trait.traitEmbedIds };
|
|
3311
3426
|
const defaults = collectDeclaredConfigDefaults(trait);
|
|
3312
3427
|
const template = defaults ? substituteConfig(raw, defaults) : raw;
|
|
3313
|
-
return { template, emits };
|
|
3428
|
+
return { template, emits, traitName: trait.name, id: trait.id, embedIds: trait.traitEmbedIds };
|
|
3314
3429
|
}
|
|
3315
3430
|
function isLambdaForm(expr) {
|
|
3316
3431
|
return expr.length === 3 && (expr[0] === "fn" || expr[0] === "lambda");
|
|
@@ -3320,7 +3435,8 @@ function spliceExpr(expr, inLambda, st) {
|
|
|
3320
3435
|
if (!inLambda || !expr.startsWith(TRAIT_BINDING_PREFIX)) return expr;
|
|
3321
3436
|
const name = expr.slice(TRAIT_BINDING_PREFIX.length);
|
|
3322
3437
|
if (name.length === 0 || name.includes(".")) return expr;
|
|
3323
|
-
const
|
|
3438
|
+
const embedId = st.embedIds?.[name];
|
|
3439
|
+
const entry = (embedId !== void 0 ? st.templatesById.get(embedId) : void 0) ?? st.templates.get(name);
|
|
3324
3440
|
if (entry === void 0) return expr;
|
|
3325
3441
|
if (entry.template === null) {
|
|
3326
3442
|
throw new LambdaSpliceError(
|
|
@@ -3330,10 +3446,13 @@ function spliceExpr(expr, inLambda, st) {
|
|
|
3330
3446
|
}
|
|
3331
3447
|
if (st.visiting.includes(name)) return expr;
|
|
3332
3448
|
st.visiting.push(name);
|
|
3449
|
+
const prevEmbedIds = st.embedIds;
|
|
3450
|
+
st.embedIds = entry.embedIds;
|
|
3333
3451
|
const expanded = spliceExpr(entry.template, true, st);
|
|
3452
|
+
st.embedIds = prevEmbedIds;
|
|
3334
3453
|
st.visiting.pop();
|
|
3335
|
-
for (const emit of entry.emits) st.merged.push([
|
|
3336
|
-
st.spliced.add(
|
|
3454
|
+
for (const emit of entry.emits) st.merged.push([entry.traitName, emit]);
|
|
3455
|
+
st.spliced.add(entry.traitName);
|
|
3337
3456
|
st.changed = true;
|
|
3338
3457
|
return expanded;
|
|
3339
3458
|
}
|
|
@@ -3382,28 +3501,38 @@ function mergeWrapperEmits(host, incoming) {
|
|
|
3382
3501
|
return emits;
|
|
3383
3502
|
}
|
|
3384
3503
|
function removeConsumedWrappers(traits, pages, spliced) {
|
|
3504
|
+
const idToName = /* @__PURE__ */ new Map();
|
|
3505
|
+
for (const { trait } of traits) {
|
|
3506
|
+
if (trait.id) idToName.set(trait.id, trait.name);
|
|
3507
|
+
}
|
|
3385
3508
|
for (; ; ) {
|
|
3386
3509
|
const stillReferenced = /* @__PURE__ */ new Set();
|
|
3387
3510
|
for (const { trait } of traits) {
|
|
3511
|
+
const rawTokens = /* @__PURE__ */ new Set();
|
|
3388
3512
|
for (const t of trait.stateMachine?.transitions ?? []) {
|
|
3389
3513
|
if (t.guard !== void 0 && t.guard !== null) {
|
|
3390
|
-
collectTraitRefsFromValue(t.guard,
|
|
3514
|
+
collectTraitRefsFromValue(t.guard, rawTokens);
|
|
3391
3515
|
}
|
|
3392
|
-
collectTraitRefsFromEffects(t.effects,
|
|
3516
|
+
collectTraitRefsFromEffects(t.effects, rawTokens);
|
|
3393
3517
|
}
|
|
3394
3518
|
for (const tick of trait.ticks ?? []) {
|
|
3395
3519
|
if (tick.guard !== void 0 && tick.guard !== null) {
|
|
3396
|
-
collectTraitRefsFromValue(tick.guard,
|
|
3520
|
+
collectTraitRefsFromValue(tick.guard, rawTokens);
|
|
3397
3521
|
}
|
|
3398
|
-
collectTraitRefsFromEffects(tick.effects,
|
|
3522
|
+
collectTraitRefsFromEffects(tick.effects, rawTokens);
|
|
3399
3523
|
}
|
|
3400
3524
|
if (trait.config) {
|
|
3401
3525
|
for (const field of Object.values(trait.config)) {
|
|
3402
3526
|
if (field && typeof field === "object" && "default" in field && field.default !== void 0) {
|
|
3403
|
-
collectTraitRefsFromValue(field.default,
|
|
3527
|
+
collectTraitRefsFromValue(field.default, rawTokens);
|
|
3404
3528
|
}
|
|
3405
3529
|
}
|
|
3406
3530
|
}
|
|
3531
|
+
for (const token of rawTokens) {
|
|
3532
|
+
const embedId = trait.traitEmbedIds?.[token];
|
|
3533
|
+
const resolvedName = (embedId !== void 0 ? idToName.get(embedId) : void 0) ?? token;
|
|
3534
|
+
stillReferenced.add(resolvedName);
|
|
3535
|
+
}
|
|
3407
3536
|
}
|
|
3408
3537
|
const removable = /* @__PURE__ */ new Set();
|
|
3409
3538
|
for (const { trait } of traits) {
|
|
@@ -3435,14 +3564,19 @@ function removeConsumedWrappers(traits, pages, spliced) {
|
|
|
3435
3564
|
function spliceLambdaTraitRefs(traits, pages) {
|
|
3436
3565
|
if (traits.length === 0) return;
|
|
3437
3566
|
const templates = /* @__PURE__ */ new Map();
|
|
3567
|
+
const templatesById = /* @__PURE__ */ new Map();
|
|
3438
3568
|
for (const { trait } of traits) {
|
|
3439
|
-
|
|
3569
|
+
const entry = buildTemplate(trait);
|
|
3570
|
+
templates.set(trait.name, entry);
|
|
3571
|
+
if (trait.id) templatesById.set(trait.id, entry);
|
|
3440
3572
|
}
|
|
3441
3573
|
const spliced = /* @__PURE__ */ new Set();
|
|
3442
3574
|
for (const resolved of traits) {
|
|
3443
3575
|
const host = resolved.trait;
|
|
3444
3576
|
const st = {
|
|
3445
3577
|
templates,
|
|
3578
|
+
templatesById,
|
|
3579
|
+
embedIds: host.traitEmbedIds,
|
|
3446
3580
|
// Seed with the host itself so a self-reference never self-splices.
|
|
3447
3581
|
visiting: [host.name],
|
|
3448
3582
|
merged: [],
|
|
@@ -3477,6 +3611,42 @@ function spliceLambdaTraitRefs(traits, pages) {
|
|
|
3477
3611
|
|
|
3478
3612
|
// src/resolver/reference-resolver.ts
|
|
3479
3613
|
var refResolverLog = createLogger("almadar:runtime:ref-resolver");
|
|
3614
|
+
function indexOrbitalNodes(orbital, idIndex) {
|
|
3615
|
+
for (const traitRef of orbital.traits ?? []) {
|
|
3616
|
+
if (typeof traitRef !== "string" && "stateMachine" in traitRef) {
|
|
3617
|
+
const trait = traitRef;
|
|
3618
|
+
if (trait.id) {
|
|
3619
|
+
idIndex.set(trait.id, { kind: "trait", node: trait });
|
|
3620
|
+
}
|
|
3621
|
+
for (const ev of trait.stateMachine?.events ?? []) {
|
|
3622
|
+
if (ev.id) {
|
|
3623
|
+
idIndex.set(ev.id, { kind: "event", node: ev });
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
}
|
|
3627
|
+
}
|
|
3628
|
+
const entityRef = orbital.entity;
|
|
3629
|
+
if (entityRef && typeof entityRef !== "string" && !("extends" in entityRef) && entityRef.id) {
|
|
3630
|
+
const entity = entityRef;
|
|
3631
|
+
idIndex.set(entity.id, { kind: "entity", node: entity });
|
|
3632
|
+
}
|
|
3633
|
+
for (const pageRef of orbital.pages ?? []) {
|
|
3634
|
+
if (typeof pageRef !== "string" && !("ref" in pageRef)) {
|
|
3635
|
+
const page = pageRef;
|
|
3636
|
+
if (page.id) {
|
|
3637
|
+
idIndex.set(page.id, { kind: "page", node: page });
|
|
3638
|
+
}
|
|
3639
|
+
}
|
|
3640
|
+
}
|
|
3641
|
+
}
|
|
3642
|
+
function buildIdIndex(orbital, orbitals) {
|
|
3643
|
+
const idIndex = /* @__PURE__ */ new Map();
|
|
3644
|
+
indexOrbitalNodes(orbital, idIndex);
|
|
3645
|
+
for (const imported of orbitals.values()) {
|
|
3646
|
+
indexOrbitalNodes(imported.orbital, idIndex);
|
|
3647
|
+
}
|
|
3648
|
+
return idIndex;
|
|
3649
|
+
}
|
|
3480
3650
|
function renameEventsInRenderUiConfig(node, rename) {
|
|
3481
3651
|
if (node === null || node === void 0) return node;
|
|
3482
3652
|
if (Array.isArray(node)) {
|
|
@@ -3526,25 +3696,30 @@ function renameEventsInEffects(effects, rename) {
|
|
|
3526
3696
|
return effect;
|
|
3527
3697
|
});
|
|
3528
3698
|
}
|
|
3529
|
-
|
|
3699
|
+
var REBIND_ENTITY_PROPS = /* @__PURE__ */ new Set(["entity"]);
|
|
3700
|
+
var ID_ENTITY_PROPS = /* @__PURE__ */ new Set(["entity", "entityType", "source"]);
|
|
3701
|
+
function renameEntityInRenderUiConfig(node, rename, props) {
|
|
3530
3702
|
if (node === null || node === void 0) return node;
|
|
3531
3703
|
if (Array.isArray(node)) {
|
|
3532
|
-
return node.map((item) => renameEntityInRenderUiConfig(item,
|
|
3704
|
+
return node.map((item) => renameEntityInRenderUiConfig(item, rename, props));
|
|
3533
3705
|
}
|
|
3534
3706
|
if (typeof node !== "object") return node;
|
|
3535
3707
|
const obj = node;
|
|
3536
3708
|
const next = { ...obj };
|
|
3537
3709
|
for (const [key, value] of Object.entries(obj)) {
|
|
3538
|
-
if (key
|
|
3539
|
-
|
|
3540
|
-
|
|
3710
|
+
if (props.has(key) && typeof value === "string") {
|
|
3711
|
+
const replaced = rename(value);
|
|
3712
|
+
if (replaced !== void 0) {
|
|
3713
|
+
next[key] = replaced;
|
|
3714
|
+
continue;
|
|
3715
|
+
}
|
|
3541
3716
|
}
|
|
3542
|
-
next[key] = renameEntityInRenderUiConfig(value,
|
|
3717
|
+
next[key] = renameEntityInRenderUiConfig(value, rename, props);
|
|
3543
3718
|
}
|
|
3544
3719
|
return next;
|
|
3545
3720
|
}
|
|
3546
|
-
function renameEntityInEffects(effects,
|
|
3547
|
-
return effects.map((effect) => renameEntityInEffect(effect,
|
|
3721
|
+
function renameEntityInEffects(effects, rename, props) {
|
|
3722
|
+
return effects.map((effect) => renameEntityInEffect(effect, rename, props));
|
|
3548
3723
|
}
|
|
3549
3724
|
var ENTITY_AT_POS_1 = /* @__PURE__ */ new Set(["fetch", "ref", "deref", "spawn"]);
|
|
3550
3725
|
var ALL_ARGS_ARE_EFFECTS = /* @__PURE__ */ new Set([
|
|
@@ -3563,20 +3738,22 @@ var ARGS_FROM_POS_2_ARE_EFFECTS = /* @__PURE__ */ new Set([
|
|
|
3563
3738
|
"async/throttle",
|
|
3564
3739
|
"async/interval"
|
|
3565
3740
|
]);
|
|
3566
|
-
function renameEntityInEffect(effect,
|
|
3741
|
+
function renameEntityInEffect(effect, rename, props) {
|
|
3567
3742
|
if (!Array.isArray(effect) || effect.length === 0) return effect;
|
|
3568
3743
|
const op = effect[0];
|
|
3569
3744
|
if (typeof op !== "string") return effect;
|
|
3570
3745
|
if (op === "render-ui" && effect.length >= 3) {
|
|
3571
3746
|
const [, slot, config, ...rest] = effect;
|
|
3572
|
-
const nextConfig = renameEntityInRenderUiConfig(config,
|
|
3747
|
+
const nextConfig = renameEntityInRenderUiConfig(config, rename, props);
|
|
3573
3748
|
return [op, slot, nextConfig, ...rest];
|
|
3574
3749
|
}
|
|
3575
|
-
if (op === "persist" && effect.length >= 3 && effect[2] ===
|
|
3576
|
-
|
|
3750
|
+
if (op === "persist" && effect.length >= 3 && typeof effect[2] === "string") {
|
|
3751
|
+
const replaced = rename(effect[2]);
|
|
3752
|
+
if (replaced !== void 0) return [op, effect[1], replaced, ...effect.slice(3)];
|
|
3577
3753
|
}
|
|
3578
|
-
if (ENTITY_AT_POS_1.has(op) && effect[1] ===
|
|
3579
|
-
|
|
3754
|
+
if (ENTITY_AT_POS_1.has(op) && typeof effect[1] === "string") {
|
|
3755
|
+
const replaced = rename(effect[1]);
|
|
3756
|
+
if (replaced !== void 0) return [op, replaced, ...effect.slice(2)];
|
|
3580
3757
|
}
|
|
3581
3758
|
const skipFirstNonEffectArg = ARGS_FROM_POS_2_ARE_EFFECTS.has(op);
|
|
3582
3759
|
const recurseAll = ALL_ARGS_ARE_EFFECTS.has(op);
|
|
@@ -3585,7 +3762,7 @@ function renameEntityInEffect(effect, oldName, newName) {
|
|
|
3585
3762
|
return effect.map((arg, i) => {
|
|
3586
3763
|
if (i < startIndex) return arg;
|
|
3587
3764
|
if (Array.isArray(arg)) {
|
|
3588
|
-
return renameEntityInEffect(arg,
|
|
3765
|
+
return renameEntityInEffect(arg, rename, props);
|
|
3589
3766
|
}
|
|
3590
3767
|
return arg;
|
|
3591
3768
|
});
|
|
@@ -3597,11 +3774,12 @@ function applyLinkedEntityRename(trait, linkedEntity) {
|
|
|
3597
3774
|
if (!linkedEntity || !atomLinked || linkedEntity === atomLinked) return trait;
|
|
3598
3775
|
const sm = trait.stateMachine;
|
|
3599
3776
|
if (!sm) return { ...trait, linkedEntity };
|
|
3777
|
+
const rename = (name) => name === atomLinked ? linkedEntity : void 0;
|
|
3600
3778
|
const nextTransitions = (sm.transitions ?? []).map((t) => {
|
|
3601
3779
|
const nextEffects = t.effects ? renameEntityInEffects(
|
|
3602
3780
|
t.effects,
|
|
3603
|
-
|
|
3604
|
-
|
|
3781
|
+
rename,
|
|
3782
|
+
REBIND_ENTITY_PROPS
|
|
3605
3783
|
) : t.effects;
|
|
3606
3784
|
return { ...t, effects: nextEffects };
|
|
3607
3785
|
});
|
|
@@ -3617,6 +3795,85 @@ function applyLinkedEntityRename(trait, linkedEntity) {
|
|
|
3617
3795
|
stateMachine: { ...sm, transitions: nextTransitions }
|
|
3618
3796
|
};
|
|
3619
3797
|
}
|
|
3798
|
+
function resolveEntityTokensById(trait, idIndex) {
|
|
3799
|
+
const map = trait.entityRefIds;
|
|
3800
|
+
if (!map) return trait;
|
|
3801
|
+
const rewrites = /* @__PURE__ */ new Map();
|
|
3802
|
+
for (const [tokenName, entityId] of Object.entries(map)) {
|
|
3803
|
+
const entry = idIndex.get(entityId);
|
|
3804
|
+
if (entry && entry.kind === "entity") {
|
|
3805
|
+
const currentName = entry.node.name;
|
|
3806
|
+
if (currentName && currentName !== tokenName) {
|
|
3807
|
+
rewrites.set(tokenName, currentName);
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3810
|
+
}
|
|
3811
|
+
if (rewrites.size === 0) return trait;
|
|
3812
|
+
const rename = (name) => rewrites.get(name);
|
|
3813
|
+
const sm = trait.stateMachine;
|
|
3814
|
+
const nextTransitions = sm?.transitions ? sm.transitions.map((t) => ({
|
|
3815
|
+
...t,
|
|
3816
|
+
effects: t.effects ? renameEntityInEffects(
|
|
3817
|
+
t.effects,
|
|
3818
|
+
rename,
|
|
3819
|
+
ID_ENTITY_PROPS
|
|
3820
|
+
) : t.effects
|
|
3821
|
+
})) : sm?.transitions;
|
|
3822
|
+
const nextTicks = trait.ticks ? trait.ticks.map((tick) => ({
|
|
3823
|
+
...tick,
|
|
3824
|
+
effects: renameEntityInEffects(
|
|
3825
|
+
tick.effects,
|
|
3826
|
+
rename,
|
|
3827
|
+
ID_ENTITY_PROPS
|
|
3828
|
+
)
|
|
3829
|
+
})) : trait.ticks;
|
|
3830
|
+
const nextInitial = trait.initialEffects ? renameEntityInEffects(
|
|
3831
|
+
trait.initialEffects,
|
|
3832
|
+
rename,
|
|
3833
|
+
ID_ENTITY_PROPS
|
|
3834
|
+
) : trait.initialEffects;
|
|
3835
|
+
const nextLinked = trait.linkedEntity !== void 0 ? rewrites.get(trait.linkedEntity) ?? trait.linkedEntity : trait.linkedEntity;
|
|
3836
|
+
refResolverLog.info("entity-ref:id-resolve", {
|
|
3837
|
+
trait: trait.name,
|
|
3838
|
+
rewrites: Object.fromEntries(rewrites)
|
|
3839
|
+
});
|
|
3840
|
+
return {
|
|
3841
|
+
...trait,
|
|
3842
|
+
linkedEntity: nextLinked,
|
|
3843
|
+
...sm ? { stateMachine: { ...sm, transitions: nextTransitions ?? [] } } : {},
|
|
3844
|
+
...nextTicks !== void 0 ? { ticks: nextTicks } : {},
|
|
3845
|
+
...nextInitial !== void 0 ? { initialEffects: nextInitial } : {}
|
|
3846
|
+
};
|
|
3847
|
+
}
|
|
3848
|
+
var REFERENCE_CONFIG_TYPE_TO_ID_KIND = {
|
|
3849
|
+
entity: "entity",
|
|
3850
|
+
trait: "trait",
|
|
3851
|
+
event: "event"
|
|
3852
|
+
};
|
|
3853
|
+
function resolveConfigRefsById(trait, idIndex) {
|
|
3854
|
+
const schema = trait.config;
|
|
3855
|
+
if (!schema) return trait;
|
|
3856
|
+
let nextSchema;
|
|
3857
|
+
const rewrites = [];
|
|
3858
|
+
for (const [key, field] of Object.entries(schema)) {
|
|
3859
|
+
if (!field.refId || !isReferenceConfigType(field.type)) continue;
|
|
3860
|
+
const expectedKind = REFERENCE_CONFIG_TYPE_TO_ID_KIND[field.type];
|
|
3861
|
+
if (!expectedKind) continue;
|
|
3862
|
+
const entry = idIndex.get(field.refId);
|
|
3863
|
+
if (!entry || entry.kind !== expectedKind) continue;
|
|
3864
|
+
const currentName = entry.kind === "entity" ? entry.node.name : entry.kind === "event" ? entry.node.key : entry.node.name;
|
|
3865
|
+
if (!currentName || currentName === field.default) continue;
|
|
3866
|
+
nextSchema ??= { ...schema };
|
|
3867
|
+
nextSchema[key] = { ...field, default: currentName };
|
|
3868
|
+
rewrites.push({ key, from: field.default, to: currentName });
|
|
3869
|
+
}
|
|
3870
|
+
if (!nextSchema) return trait;
|
|
3871
|
+
refResolverLog.info("config-ref:id-resolve", {
|
|
3872
|
+
trait: trait.name,
|
|
3873
|
+
rewrites
|
|
3874
|
+
});
|
|
3875
|
+
return { ...trait, config: nextSchema };
|
|
3876
|
+
}
|
|
3620
3877
|
function applyEventRenames(trait, renames) {
|
|
3621
3878
|
if (!renames || Object.keys(renames).length === 0) return trait;
|
|
3622
3879
|
const rename = (k) => k !== void 0 && k in renames ? renames[k] : k;
|
|
@@ -3678,17 +3935,24 @@ var ReferenceResolver = class {
|
|
|
3678
3935
|
loader;
|
|
3679
3936
|
options;
|
|
3680
3937
|
localTraits;
|
|
3938
|
+
/** id-keyed mirror of `localTraits`, populated wherever the trait carries an `id`. */
|
|
3939
|
+
localTraitsById = /* @__PURE__ */ new Map();
|
|
3681
3940
|
loaderInitialized = false;
|
|
3682
3941
|
constructor(options) {
|
|
3683
3942
|
this.options = options;
|
|
3684
3943
|
this.loader = options.loader;
|
|
3685
3944
|
this.localTraits = options.localTraits ?? /* @__PURE__ */ new Map();
|
|
3945
|
+
for (const trait of this.localTraits.values()) {
|
|
3946
|
+
if (trait.id) {
|
|
3947
|
+
this.localTraitsById.set(trait.id, trait);
|
|
3948
|
+
}
|
|
3949
|
+
}
|
|
3686
3950
|
}
|
|
3687
3951
|
async ensureLoader() {
|
|
3688
3952
|
if (this.loader || this.loaderInitialized) return;
|
|
3689
3953
|
this.loaderInitialized = true;
|
|
3690
3954
|
try {
|
|
3691
|
-
const { ExternalOrbitalLoader } = await import('./external-loader-
|
|
3955
|
+
const { ExternalOrbitalLoader } = await import('./external-loader-FNK5AU6U.js');
|
|
3692
3956
|
this.loader = new ExternalOrbitalLoader(this.options);
|
|
3693
3957
|
} catch {
|
|
3694
3958
|
}
|
|
@@ -3705,11 +3969,12 @@ var ReferenceResolver = class {
|
|
|
3705
3969
|
} };
|
|
3706
3970
|
const traitsList = orbital.traits ?? [];
|
|
3707
3971
|
const alreadyResolved = traitsList.length > 0 && traitsList.every((t) => isInlineTrait(t));
|
|
3708
|
-
const importsResult = alreadyResolved ? { success: true, data: { orbitals: /* @__PURE__ */ new Map() }} : await this.resolveImports(orbital.uses ?? [], sourcePath, importChain);
|
|
3972
|
+
const importsResult = alreadyResolved ? { success: true, data: { orbitals: /* @__PURE__ */ new Map(), idIndex: /* @__PURE__ */ new Map() }} : await this.resolveImports(orbital.uses ?? [], sourcePath, importChain);
|
|
3709
3973
|
if (!importsResult.success) {
|
|
3710
3974
|
return { success: false, errors: importsResult.errors };
|
|
3711
3975
|
}
|
|
3712
3976
|
const imports = importsResult.data;
|
|
3977
|
+
imports.idIndex = buildIdIndex(orbital, imports.orbitals);
|
|
3713
3978
|
const entityResult = this.resolveEntity(orbital.entity, imports);
|
|
3714
3979
|
if (!entityResult.success) {
|
|
3715
3980
|
errors.push(...entityResult.errors);
|
|
@@ -3728,6 +3993,10 @@ var ReferenceResolver = class {
|
|
|
3728
3993
|
if (!entityResult.success || !traitsResult.success || !pagesResult.success) {
|
|
3729
3994
|
return { success: false, errors: ["Internal error: unexpected failure state"] };
|
|
3730
3995
|
}
|
|
3996
|
+
for (const resolvedTrait of traitsResult.data) {
|
|
3997
|
+
resolvedTrait.trait = resolveEntityTokensById(resolvedTrait.trait, imports.idIndex);
|
|
3998
|
+
resolvedTrait.trait = resolveConfigRefsById(resolvedTrait.trait, imports.idIndex);
|
|
3999
|
+
}
|
|
3731
4000
|
try {
|
|
3732
4001
|
spliceLambdaTraitRefs(traitsResult.data, pagesResult.data);
|
|
3733
4002
|
} catch (e) {
|
|
@@ -3759,7 +4028,7 @@ var ReferenceResolver = class {
|
|
|
3759
4028
|
if (this.options.skipExternalLoading) {
|
|
3760
4029
|
return {
|
|
3761
4030
|
success: true,
|
|
3762
|
-
data: { orbitals },
|
|
4031
|
+
data: { orbitals, idIndex: /* @__PURE__ */ new Map() },
|
|
3763
4032
|
warnings: ["External loading skipped"]
|
|
3764
4033
|
};
|
|
3765
4034
|
}
|
|
@@ -3793,7 +4062,7 @@ var ReferenceResolver = class {
|
|
|
3793
4062
|
if (errors.length > 0) {
|
|
3794
4063
|
return { success: false, errors };
|
|
3795
4064
|
}
|
|
3796
|
-
return { success: true, data: { orbitals }, warnings: [] };
|
|
4065
|
+
return { success: true, data: { orbitals, idIndex: /* @__PURE__ */ new Map() }, warnings: [] };
|
|
3797
4066
|
}
|
|
3798
4067
|
/**
|
|
3799
4068
|
* Resolve entity reference.
|
|
@@ -3924,7 +4193,8 @@ var ReferenceResolver = class {
|
|
|
3924
4193
|
refObj.linkedEntity,
|
|
3925
4194
|
refObj.name,
|
|
3926
4195
|
refObj.events,
|
|
3927
|
-
refObj.listens
|
|
4196
|
+
refObj.listens,
|
|
4197
|
+
refObj.refId
|
|
3928
4198
|
);
|
|
3929
4199
|
}
|
|
3930
4200
|
if (typeof traitRef === "string") {
|
|
@@ -3938,7 +4208,7 @@ var ReferenceResolver = class {
|
|
|
3938
4208
|
/**
|
|
3939
4209
|
* Resolve a trait reference string.
|
|
3940
4210
|
*/
|
|
3941
|
-
resolveTraitRefString(ref, imports, config, linkedEntity, overrideName, eventRenames, listensOverride) {
|
|
4211
|
+
resolveTraitRefString(ref, imports, config, linkedEntity, overrideName, eventRenames, listensOverride, refId) {
|
|
3942
4212
|
const parsed = parseImportedTraitRef(ref);
|
|
3943
4213
|
if (parsed) {
|
|
3944
4214
|
const imported = imports.orbitals.get(parsed.alias);
|
|
@@ -3950,7 +4220,7 @@ var ReferenceResolver = class {
|
|
|
3950
4220
|
]
|
|
3951
4221
|
};
|
|
3952
4222
|
}
|
|
3953
|
-
const trait = this.findTraitInOrbital(imported.orbital, parsed.traitName);
|
|
4223
|
+
const trait = this.findTraitInOrbital(imported.orbital, parsed.traitName, refId, imports.idIndex);
|
|
3954
4224
|
if (!trait) {
|
|
3955
4225
|
return {
|
|
3956
4226
|
success: false,
|
|
@@ -3986,7 +4256,7 @@ var ReferenceResolver = class {
|
|
|
3986
4256
|
warnings: []
|
|
3987
4257
|
};
|
|
3988
4258
|
}
|
|
3989
|
-
const localTrait = this.localTraits.get(ref);
|
|
4259
|
+
const localTrait = (refId && this.localTraitsById.get(refId)) ?? this.localTraits.get(ref);
|
|
3990
4260
|
if (localTrait) {
|
|
3991
4261
|
const baseLocal = overrideName ? { ...localTrait, name: overrideName } : localTrait;
|
|
3992
4262
|
const { trait: configResolvedLocal, errors: localConfigRefErrors } = resolveConfigRefEmitNames(baseLocal, config);
|
|
@@ -4023,9 +4293,17 @@ var ReferenceResolver = class {
|
|
|
4023
4293
|
};
|
|
4024
4294
|
}
|
|
4025
4295
|
/**
|
|
4026
|
-
* Find a trait in an orbital by name.
|
|
4296
|
+
* Find a trait in an orbital by name. Id-primary: when the calling ref
|
|
4297
|
+
* carries a `refId` and the id index has a matching trait entry, return it
|
|
4298
|
+
* directly — else fall back to the existing name match unchanged.
|
|
4027
4299
|
*/
|
|
4028
|
-
findTraitInOrbital(orbital, traitName) {
|
|
4300
|
+
findTraitInOrbital(orbital, traitName, refId, idIndex) {
|
|
4301
|
+
if (refId && idIndex) {
|
|
4302
|
+
const entry = idIndex.get(refId);
|
|
4303
|
+
if (entry && entry.kind === "trait") {
|
|
4304
|
+
return entry.node;
|
|
4305
|
+
}
|
|
4306
|
+
}
|
|
4029
4307
|
for (const traitRef of orbital.traits) {
|
|
4030
4308
|
if (typeof traitRef !== "string" && "stateMachine" in traitRef) {
|
|
4031
4309
|
if (traitRef.name === traitName) {
|
|
@@ -4099,7 +4377,7 @@ var ReferenceResolver = class {
|
|
|
4099
4377
|
/**
|
|
4100
4378
|
* Resolve a page reference string.
|
|
4101
4379
|
*/
|
|
4102
|
-
resolvePageRefString(ref, imports) {
|
|
4380
|
+
resolvePageRefString(ref, imports, refId) {
|
|
4103
4381
|
const parsed = parsePageRef(ref);
|
|
4104
4382
|
if (!parsed) {
|
|
4105
4383
|
return {
|
|
@@ -4116,7 +4394,7 @@ var ReferenceResolver = class {
|
|
|
4116
4394
|
]
|
|
4117
4395
|
};
|
|
4118
4396
|
}
|
|
4119
|
-
const page = this.findPageInOrbital(imported.orbital, parsed.pageName);
|
|
4397
|
+
const page = this.findPageInOrbital(imported.orbital, parsed.pageName, refId, imports.idIndex);
|
|
4120
4398
|
if (!page) {
|
|
4121
4399
|
return {
|
|
4122
4400
|
success: false,
|
|
@@ -4139,7 +4417,7 @@ var ReferenceResolver = class {
|
|
|
4139
4417
|
* Resolve a page reference object with optional path override.
|
|
4140
4418
|
*/
|
|
4141
4419
|
resolvePageRefObject(refObj, imports) {
|
|
4142
|
-
const baseResult = this.resolvePageRefString(refObj.ref, imports);
|
|
4420
|
+
const baseResult = this.resolvePageRefString(refObj.ref, imports, refObj.refId);
|
|
4143
4421
|
if (!baseResult.success) {
|
|
4144
4422
|
return baseResult;
|
|
4145
4423
|
}
|
|
@@ -4160,9 +4438,17 @@ var ReferenceResolver = class {
|
|
|
4160
4438
|
};
|
|
4161
4439
|
}
|
|
4162
4440
|
/**
|
|
4163
|
-
* Find a page in an orbital by name.
|
|
4441
|
+
* Find a page in an orbital by name. Id-primary: when the calling ref
|
|
4442
|
+
* carries a `refId` and the id index has a matching page entry, return it
|
|
4443
|
+
* directly — else fall back to the existing name match unchanged.
|
|
4164
4444
|
*/
|
|
4165
|
-
findPageInOrbital(orbital, pageName) {
|
|
4445
|
+
findPageInOrbital(orbital, pageName, refId, idIndex) {
|
|
4446
|
+
if (refId && idIndex) {
|
|
4447
|
+
const entry = idIndex.get(refId);
|
|
4448
|
+
if (entry && entry.kind === "page") {
|
|
4449
|
+
return { ...entry.node };
|
|
4450
|
+
}
|
|
4451
|
+
}
|
|
4166
4452
|
const pages = orbital.pages;
|
|
4167
4453
|
if (!pages) return null;
|
|
4168
4454
|
for (const pageRef of pages) {
|
|
@@ -4195,6 +4481,9 @@ var ReferenceResolver = class {
|
|
|
4195
4481
|
addLocalTraits(traits) {
|
|
4196
4482
|
for (const trait of traits) {
|
|
4197
4483
|
this.localTraits.set(trait.name, trait);
|
|
4484
|
+
if (trait.id) {
|
|
4485
|
+
this.localTraitsById.set(trait.id, trait);
|
|
4486
|
+
}
|
|
4198
4487
|
}
|
|
4199
4488
|
}
|
|
4200
4489
|
/**
|