@almadar/runtime 6.33.0 → 6.35.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-BY-qzEQ_.d.ts} +59 -7
- package/dist/OrbitalServerRuntime.d.ts +2 -2
- package/dist/OrbitalServerRuntime.js +66 -24
- package/dist/ServerBridge.d.ts +1 -1
- package/dist/{chunk-JZDLN2FS.js → chunk-VCEF5JOX.js} +354 -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,12 +950,17 @@ 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, targetTrait) {
|
|
853
960
|
const results = [];
|
|
854
961
|
const scope = scopeOf(entityData);
|
|
855
962
|
for (const [traitName, trait] of this.traits) {
|
|
963
|
+
if (targetTrait !== void 0 && traitName !== targetTrait) continue;
|
|
856
964
|
const traitState = this.getOrInitState(traitName, scope);
|
|
857
965
|
if (!traitState) continue;
|
|
858
966
|
const key = compositeKey(traitName, scope);
|
|
@@ -861,6 +969,7 @@ var StateMachineManager = class {
|
|
|
861
969
|
traitState,
|
|
862
970
|
trait,
|
|
863
971
|
eventKey,
|
|
972
|
+
eventId,
|
|
864
973
|
payload,
|
|
865
974
|
entityData: perTraitEntity,
|
|
866
975
|
config: this.traitConfigs.get(traitName),
|
|
@@ -902,12 +1011,12 @@ var StateMachineManager = class {
|
|
|
902
1011
|
* trait to process them sequentially (actor-model guarantee: one event
|
|
903
1012
|
* at a time per trait, effects fully awaited before the next event).
|
|
904
1013
|
*/
|
|
905
|
-
enqueueEvent(eventKey, payload, entityData, entityByTrait) {
|
|
1014
|
+
enqueueEvent(eventKey, payload, entityData, entityByTrait, eventId) {
|
|
906
1015
|
const scope = scopeOf(entityData);
|
|
907
1016
|
for (const [traitName] of this.traits) {
|
|
908
1017
|
const key = compositeKey(traitName, scope);
|
|
909
1018
|
const queue = this.queues.get(key) ?? [];
|
|
910
|
-
queue.push({ eventKey, payload, entityData, entityByTrait });
|
|
1019
|
+
queue.push({ eventKey, eventId, payload, entityData, entityByTrait });
|
|
911
1020
|
this.queues.set(key, queue);
|
|
912
1021
|
}
|
|
913
1022
|
}
|
|
@@ -932,6 +1041,7 @@ var StateMachineManager = class {
|
|
|
932
1041
|
traitState,
|
|
933
1042
|
trait,
|
|
934
1043
|
eventKey: entry.eventKey,
|
|
1044
|
+
eventId: entry.eventId,
|
|
935
1045
|
payload: entry.payload,
|
|
936
1046
|
entityData: perTraitEntity,
|
|
937
1047
|
config: this.traitConfigs.get(traitName),
|
|
@@ -2212,6 +2322,8 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
|
|
|
2212
2322
|
stores = /* @__PURE__ */ new Map();
|
|
2213
2323
|
schemas = /* @__PURE__ */ new Map();
|
|
2214
2324
|
idCounters = /* @__PURE__ */ new Map();
|
|
2325
|
+
/** entityId -> normalized store name, so relation lookups can prefer the id sibling over `relation.entity` name-matching. */
|
|
2326
|
+
storeNameById = /* @__PURE__ */ new Map();
|
|
2215
2327
|
config;
|
|
2216
2328
|
constructor(config = {}) {
|
|
2217
2329
|
this.config = {
|
|
@@ -2263,6 +2375,9 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
|
|
|
2263
2375
|
registerEntity(schema, seedCount) {
|
|
2264
2376
|
const normalized = schema.name.toLowerCase();
|
|
2265
2377
|
this.schemas.set(normalized, schema);
|
|
2378
|
+
if (schema.id) {
|
|
2379
|
+
this.storeNameById.set(schema.id, normalized);
|
|
2380
|
+
}
|
|
2266
2381
|
if (schema.seedData && schema.seedData.length > 0) {
|
|
2267
2382
|
this.seedFromInstances(schema.name, schema.seedData);
|
|
2268
2383
|
} else {
|
|
@@ -2294,7 +2409,8 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
|
|
|
2294
2409
|
if (relationFields.length === 0) continue;
|
|
2295
2410
|
for (const row of store.values()) {
|
|
2296
2411
|
for (const field of relationFields) {
|
|
2297
|
-
const
|
|
2412
|
+
const targetNormalized = (field.relation.entityId && this.storeNameById.get(field.relation.entityId)) ?? field.relation.entity.toLowerCase();
|
|
2413
|
+
const targetStore = this.stores.get(targetNormalized);
|
|
2298
2414
|
if (!targetStore || targetStore.size === 0) continue;
|
|
2299
2415
|
const selfId = row["id"];
|
|
2300
2416
|
const sameStore = targetStore === store;
|
|
@@ -2972,7 +3088,7 @@ async function getExternalLoaderModule() {
|
|
|
2972
3088
|
return null;
|
|
2973
3089
|
}
|
|
2974
3090
|
try {
|
|
2975
|
-
externalLoaderModule = await import('./external-loader-
|
|
3091
|
+
externalLoaderModule = await import('./external-loader-FNK5AU6U.js');
|
|
2976
3092
|
return externalLoaderModule;
|
|
2977
3093
|
} catch {
|
|
2978
3094
|
return null;
|
|
@@ -3307,10 +3423,10 @@ function substituteConfig(expr, subs) {
|
|
|
3307
3423
|
function buildTemplate(trait) {
|
|
3308
3424
|
const raw = renderOnlyTemplate(trait);
|
|
3309
3425
|
const emits = trait.emits ?? [];
|
|
3310
|
-
if (raw === null) return { template: null, emits };
|
|
3426
|
+
if (raw === null) return { template: null, emits, traitName: trait.name, id: trait.id, embedIds: trait.traitEmbedIds };
|
|
3311
3427
|
const defaults = collectDeclaredConfigDefaults(trait);
|
|
3312
3428
|
const template = defaults ? substituteConfig(raw, defaults) : raw;
|
|
3313
|
-
return { template, emits };
|
|
3429
|
+
return { template, emits, traitName: trait.name, id: trait.id, embedIds: trait.traitEmbedIds };
|
|
3314
3430
|
}
|
|
3315
3431
|
function isLambdaForm(expr) {
|
|
3316
3432
|
return expr.length === 3 && (expr[0] === "fn" || expr[0] === "lambda");
|
|
@@ -3320,7 +3436,8 @@ function spliceExpr(expr, inLambda, st) {
|
|
|
3320
3436
|
if (!inLambda || !expr.startsWith(TRAIT_BINDING_PREFIX)) return expr;
|
|
3321
3437
|
const name = expr.slice(TRAIT_BINDING_PREFIX.length);
|
|
3322
3438
|
if (name.length === 0 || name.includes(".")) return expr;
|
|
3323
|
-
const
|
|
3439
|
+
const embedId = st.embedIds?.[name];
|
|
3440
|
+
const entry = (embedId !== void 0 ? st.templatesById.get(embedId) : void 0) ?? st.templates.get(name);
|
|
3324
3441
|
if (entry === void 0) return expr;
|
|
3325
3442
|
if (entry.template === null) {
|
|
3326
3443
|
throw new LambdaSpliceError(
|
|
@@ -3330,10 +3447,13 @@ function spliceExpr(expr, inLambda, st) {
|
|
|
3330
3447
|
}
|
|
3331
3448
|
if (st.visiting.includes(name)) return expr;
|
|
3332
3449
|
st.visiting.push(name);
|
|
3450
|
+
const prevEmbedIds = st.embedIds;
|
|
3451
|
+
st.embedIds = entry.embedIds;
|
|
3333
3452
|
const expanded = spliceExpr(entry.template, true, st);
|
|
3453
|
+
st.embedIds = prevEmbedIds;
|
|
3334
3454
|
st.visiting.pop();
|
|
3335
|
-
for (const emit of entry.emits) st.merged.push([
|
|
3336
|
-
st.spliced.add(
|
|
3455
|
+
for (const emit of entry.emits) st.merged.push([entry.traitName, emit]);
|
|
3456
|
+
st.spliced.add(entry.traitName);
|
|
3337
3457
|
st.changed = true;
|
|
3338
3458
|
return expanded;
|
|
3339
3459
|
}
|
|
@@ -3382,28 +3502,38 @@ function mergeWrapperEmits(host, incoming) {
|
|
|
3382
3502
|
return emits;
|
|
3383
3503
|
}
|
|
3384
3504
|
function removeConsumedWrappers(traits, pages, spliced) {
|
|
3505
|
+
const idToName = /* @__PURE__ */ new Map();
|
|
3506
|
+
for (const { trait } of traits) {
|
|
3507
|
+
if (trait.id) idToName.set(trait.id, trait.name);
|
|
3508
|
+
}
|
|
3385
3509
|
for (; ; ) {
|
|
3386
3510
|
const stillReferenced = /* @__PURE__ */ new Set();
|
|
3387
3511
|
for (const { trait } of traits) {
|
|
3512
|
+
const rawTokens = /* @__PURE__ */ new Set();
|
|
3388
3513
|
for (const t of trait.stateMachine?.transitions ?? []) {
|
|
3389
3514
|
if (t.guard !== void 0 && t.guard !== null) {
|
|
3390
|
-
collectTraitRefsFromValue(t.guard,
|
|
3515
|
+
collectTraitRefsFromValue(t.guard, rawTokens);
|
|
3391
3516
|
}
|
|
3392
|
-
collectTraitRefsFromEffects(t.effects,
|
|
3517
|
+
collectTraitRefsFromEffects(t.effects, rawTokens);
|
|
3393
3518
|
}
|
|
3394
3519
|
for (const tick of trait.ticks ?? []) {
|
|
3395
3520
|
if (tick.guard !== void 0 && tick.guard !== null) {
|
|
3396
|
-
collectTraitRefsFromValue(tick.guard,
|
|
3521
|
+
collectTraitRefsFromValue(tick.guard, rawTokens);
|
|
3397
3522
|
}
|
|
3398
|
-
collectTraitRefsFromEffects(tick.effects,
|
|
3523
|
+
collectTraitRefsFromEffects(tick.effects, rawTokens);
|
|
3399
3524
|
}
|
|
3400
3525
|
if (trait.config) {
|
|
3401
3526
|
for (const field of Object.values(trait.config)) {
|
|
3402
3527
|
if (field && typeof field === "object" && "default" in field && field.default !== void 0) {
|
|
3403
|
-
collectTraitRefsFromValue(field.default,
|
|
3528
|
+
collectTraitRefsFromValue(field.default, rawTokens);
|
|
3404
3529
|
}
|
|
3405
3530
|
}
|
|
3406
3531
|
}
|
|
3532
|
+
for (const token of rawTokens) {
|
|
3533
|
+
const embedId = trait.traitEmbedIds?.[token];
|
|
3534
|
+
const resolvedName = (embedId !== void 0 ? idToName.get(embedId) : void 0) ?? token;
|
|
3535
|
+
stillReferenced.add(resolvedName);
|
|
3536
|
+
}
|
|
3407
3537
|
}
|
|
3408
3538
|
const removable = /* @__PURE__ */ new Set();
|
|
3409
3539
|
for (const { trait } of traits) {
|
|
@@ -3435,14 +3565,19 @@ function removeConsumedWrappers(traits, pages, spliced) {
|
|
|
3435
3565
|
function spliceLambdaTraitRefs(traits, pages) {
|
|
3436
3566
|
if (traits.length === 0) return;
|
|
3437
3567
|
const templates = /* @__PURE__ */ new Map();
|
|
3568
|
+
const templatesById = /* @__PURE__ */ new Map();
|
|
3438
3569
|
for (const { trait } of traits) {
|
|
3439
|
-
|
|
3570
|
+
const entry = buildTemplate(trait);
|
|
3571
|
+
templates.set(trait.name, entry);
|
|
3572
|
+
if (trait.id) templatesById.set(trait.id, entry);
|
|
3440
3573
|
}
|
|
3441
3574
|
const spliced = /* @__PURE__ */ new Set();
|
|
3442
3575
|
for (const resolved of traits) {
|
|
3443
3576
|
const host = resolved.trait;
|
|
3444
3577
|
const st = {
|
|
3445
3578
|
templates,
|
|
3579
|
+
templatesById,
|
|
3580
|
+
embedIds: host.traitEmbedIds,
|
|
3446
3581
|
// Seed with the host itself so a self-reference never self-splices.
|
|
3447
3582
|
visiting: [host.name],
|
|
3448
3583
|
merged: [],
|
|
@@ -3477,6 +3612,42 @@ function spliceLambdaTraitRefs(traits, pages) {
|
|
|
3477
3612
|
|
|
3478
3613
|
// src/resolver/reference-resolver.ts
|
|
3479
3614
|
var refResolverLog = createLogger("almadar:runtime:ref-resolver");
|
|
3615
|
+
function indexOrbitalNodes(orbital, idIndex) {
|
|
3616
|
+
for (const traitRef of orbital.traits ?? []) {
|
|
3617
|
+
if (typeof traitRef !== "string" && "stateMachine" in traitRef) {
|
|
3618
|
+
const trait = traitRef;
|
|
3619
|
+
if (trait.id) {
|
|
3620
|
+
idIndex.set(trait.id, { kind: "trait", node: trait });
|
|
3621
|
+
}
|
|
3622
|
+
for (const ev of trait.stateMachine?.events ?? []) {
|
|
3623
|
+
if (ev.id) {
|
|
3624
|
+
idIndex.set(ev.id, { kind: "event", node: ev });
|
|
3625
|
+
}
|
|
3626
|
+
}
|
|
3627
|
+
}
|
|
3628
|
+
}
|
|
3629
|
+
const entityRef = orbital.entity;
|
|
3630
|
+
if (entityRef && typeof entityRef !== "string" && !("extends" in entityRef) && entityRef.id) {
|
|
3631
|
+
const entity = entityRef;
|
|
3632
|
+
idIndex.set(entity.id, { kind: "entity", node: entity });
|
|
3633
|
+
}
|
|
3634
|
+
for (const pageRef of orbital.pages ?? []) {
|
|
3635
|
+
if (typeof pageRef !== "string" && !("ref" in pageRef)) {
|
|
3636
|
+
const page = pageRef;
|
|
3637
|
+
if (page.id) {
|
|
3638
|
+
idIndex.set(page.id, { kind: "page", node: page });
|
|
3639
|
+
}
|
|
3640
|
+
}
|
|
3641
|
+
}
|
|
3642
|
+
}
|
|
3643
|
+
function buildIdIndex(orbital, orbitals) {
|
|
3644
|
+
const idIndex = /* @__PURE__ */ new Map();
|
|
3645
|
+
indexOrbitalNodes(orbital, idIndex);
|
|
3646
|
+
for (const imported of orbitals.values()) {
|
|
3647
|
+
indexOrbitalNodes(imported.orbital, idIndex);
|
|
3648
|
+
}
|
|
3649
|
+
return idIndex;
|
|
3650
|
+
}
|
|
3480
3651
|
function renameEventsInRenderUiConfig(node, rename) {
|
|
3481
3652
|
if (node === null || node === void 0) return node;
|
|
3482
3653
|
if (Array.isArray(node)) {
|
|
@@ -3526,25 +3697,30 @@ function renameEventsInEffects(effects, rename) {
|
|
|
3526
3697
|
return effect;
|
|
3527
3698
|
});
|
|
3528
3699
|
}
|
|
3529
|
-
|
|
3700
|
+
var REBIND_ENTITY_PROPS = /* @__PURE__ */ new Set(["entity"]);
|
|
3701
|
+
var ID_ENTITY_PROPS = /* @__PURE__ */ new Set(["entity", "entityType", "source"]);
|
|
3702
|
+
function renameEntityInRenderUiConfig(node, rename, props) {
|
|
3530
3703
|
if (node === null || node === void 0) return node;
|
|
3531
3704
|
if (Array.isArray(node)) {
|
|
3532
|
-
return node.map((item) => renameEntityInRenderUiConfig(item,
|
|
3705
|
+
return node.map((item) => renameEntityInRenderUiConfig(item, rename, props));
|
|
3533
3706
|
}
|
|
3534
3707
|
if (typeof node !== "object") return node;
|
|
3535
3708
|
const obj = node;
|
|
3536
3709
|
const next = { ...obj };
|
|
3537
3710
|
for (const [key, value] of Object.entries(obj)) {
|
|
3538
|
-
if (key
|
|
3539
|
-
|
|
3540
|
-
|
|
3711
|
+
if (props.has(key) && typeof value === "string") {
|
|
3712
|
+
const replaced = rename(value);
|
|
3713
|
+
if (replaced !== void 0) {
|
|
3714
|
+
next[key] = replaced;
|
|
3715
|
+
continue;
|
|
3716
|
+
}
|
|
3541
3717
|
}
|
|
3542
|
-
next[key] = renameEntityInRenderUiConfig(value,
|
|
3718
|
+
next[key] = renameEntityInRenderUiConfig(value, rename, props);
|
|
3543
3719
|
}
|
|
3544
3720
|
return next;
|
|
3545
3721
|
}
|
|
3546
|
-
function renameEntityInEffects(effects,
|
|
3547
|
-
return effects.map((effect) => renameEntityInEffect(effect,
|
|
3722
|
+
function renameEntityInEffects(effects, rename, props) {
|
|
3723
|
+
return effects.map((effect) => renameEntityInEffect(effect, rename, props));
|
|
3548
3724
|
}
|
|
3549
3725
|
var ENTITY_AT_POS_1 = /* @__PURE__ */ new Set(["fetch", "ref", "deref", "spawn"]);
|
|
3550
3726
|
var ALL_ARGS_ARE_EFFECTS = /* @__PURE__ */ new Set([
|
|
@@ -3563,20 +3739,22 @@ var ARGS_FROM_POS_2_ARE_EFFECTS = /* @__PURE__ */ new Set([
|
|
|
3563
3739
|
"async/throttle",
|
|
3564
3740
|
"async/interval"
|
|
3565
3741
|
]);
|
|
3566
|
-
function renameEntityInEffect(effect,
|
|
3742
|
+
function renameEntityInEffect(effect, rename, props) {
|
|
3567
3743
|
if (!Array.isArray(effect) || effect.length === 0) return effect;
|
|
3568
3744
|
const op = effect[0];
|
|
3569
3745
|
if (typeof op !== "string") return effect;
|
|
3570
3746
|
if (op === "render-ui" && effect.length >= 3) {
|
|
3571
3747
|
const [, slot, config, ...rest] = effect;
|
|
3572
|
-
const nextConfig = renameEntityInRenderUiConfig(config,
|
|
3748
|
+
const nextConfig = renameEntityInRenderUiConfig(config, rename, props);
|
|
3573
3749
|
return [op, slot, nextConfig, ...rest];
|
|
3574
3750
|
}
|
|
3575
|
-
if (op === "persist" && effect.length >= 3 && effect[2] ===
|
|
3576
|
-
|
|
3751
|
+
if (op === "persist" && effect.length >= 3 && typeof effect[2] === "string") {
|
|
3752
|
+
const replaced = rename(effect[2]);
|
|
3753
|
+
if (replaced !== void 0) return [op, effect[1], replaced, ...effect.slice(3)];
|
|
3577
3754
|
}
|
|
3578
|
-
if (ENTITY_AT_POS_1.has(op) && effect[1] ===
|
|
3579
|
-
|
|
3755
|
+
if (ENTITY_AT_POS_1.has(op) && typeof effect[1] === "string") {
|
|
3756
|
+
const replaced = rename(effect[1]);
|
|
3757
|
+
if (replaced !== void 0) return [op, replaced, ...effect.slice(2)];
|
|
3580
3758
|
}
|
|
3581
3759
|
const skipFirstNonEffectArg = ARGS_FROM_POS_2_ARE_EFFECTS.has(op);
|
|
3582
3760
|
const recurseAll = ALL_ARGS_ARE_EFFECTS.has(op);
|
|
@@ -3585,7 +3763,7 @@ function renameEntityInEffect(effect, oldName, newName) {
|
|
|
3585
3763
|
return effect.map((arg, i) => {
|
|
3586
3764
|
if (i < startIndex) return arg;
|
|
3587
3765
|
if (Array.isArray(arg)) {
|
|
3588
|
-
return renameEntityInEffect(arg,
|
|
3766
|
+
return renameEntityInEffect(arg, rename, props);
|
|
3589
3767
|
}
|
|
3590
3768
|
return arg;
|
|
3591
3769
|
});
|
|
@@ -3597,11 +3775,12 @@ function applyLinkedEntityRename(trait, linkedEntity) {
|
|
|
3597
3775
|
if (!linkedEntity || !atomLinked || linkedEntity === atomLinked) return trait;
|
|
3598
3776
|
const sm = trait.stateMachine;
|
|
3599
3777
|
if (!sm) return { ...trait, linkedEntity };
|
|
3778
|
+
const rename = (name) => name === atomLinked ? linkedEntity : void 0;
|
|
3600
3779
|
const nextTransitions = (sm.transitions ?? []).map((t) => {
|
|
3601
3780
|
const nextEffects = t.effects ? renameEntityInEffects(
|
|
3602
3781
|
t.effects,
|
|
3603
|
-
|
|
3604
|
-
|
|
3782
|
+
rename,
|
|
3783
|
+
REBIND_ENTITY_PROPS
|
|
3605
3784
|
) : t.effects;
|
|
3606
3785
|
return { ...t, effects: nextEffects };
|
|
3607
3786
|
});
|
|
@@ -3617,6 +3796,88 @@ function applyLinkedEntityRename(trait, linkedEntity) {
|
|
|
3617
3796
|
stateMachine: { ...sm, transitions: nextTransitions }
|
|
3618
3797
|
};
|
|
3619
3798
|
}
|
|
3799
|
+
function resolveEntityTokensById(trait, idIndex) {
|
|
3800
|
+
const map = trait.entityRefIds;
|
|
3801
|
+
if (!map) return trait;
|
|
3802
|
+
const rewrites = /* @__PURE__ */ new Map();
|
|
3803
|
+
for (const [tokenName, entityId] of Object.entries(map)) {
|
|
3804
|
+
const entry = idIndex.get(entityId);
|
|
3805
|
+
if (entry && entry.kind === "entity") {
|
|
3806
|
+
const currentName = entry.node.name;
|
|
3807
|
+
if (currentName && currentName !== tokenName) {
|
|
3808
|
+
rewrites.set(tokenName, currentName);
|
|
3809
|
+
}
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3812
|
+
if (rewrites.size === 0) return trait;
|
|
3813
|
+
const rename = (name) => rewrites.get(name);
|
|
3814
|
+
const sm = trait.stateMachine;
|
|
3815
|
+
const nextTransitions = sm?.transitions ? sm.transitions.map((t) => ({
|
|
3816
|
+
...t,
|
|
3817
|
+
effects: t.effects ? renameEntityInEffects(
|
|
3818
|
+
t.effects,
|
|
3819
|
+
rename,
|
|
3820
|
+
ID_ENTITY_PROPS
|
|
3821
|
+
) : t.effects
|
|
3822
|
+
})) : sm?.transitions;
|
|
3823
|
+
const nextTicks = trait.ticks ? trait.ticks.map((tick) => ({
|
|
3824
|
+
...tick,
|
|
3825
|
+
effects: renameEntityInEffects(
|
|
3826
|
+
tick.effects,
|
|
3827
|
+
rename,
|
|
3828
|
+
ID_ENTITY_PROPS
|
|
3829
|
+
)
|
|
3830
|
+
})) : trait.ticks;
|
|
3831
|
+
const nextInitial = trait.initialEffects ? renameEntityInEffects(
|
|
3832
|
+
trait.initialEffects,
|
|
3833
|
+
rename,
|
|
3834
|
+
ID_ENTITY_PROPS
|
|
3835
|
+
) : trait.initialEffects;
|
|
3836
|
+
const nextLinked = trait.linkedEntity !== void 0 ? rewrites.get(trait.linkedEntity) ?? trait.linkedEntity : trait.linkedEntity;
|
|
3837
|
+
refResolverLog.info("entity-ref:id-resolve", {
|
|
3838
|
+
trait: trait.name,
|
|
3839
|
+
rewrites: Object.fromEntries(rewrites)
|
|
3840
|
+
});
|
|
3841
|
+
return {
|
|
3842
|
+
...trait,
|
|
3843
|
+
linkedEntity: nextLinked,
|
|
3844
|
+
...sm ? { stateMachine: { ...sm, transitions: nextTransitions ?? [] } } : {},
|
|
3845
|
+
...nextTicks !== void 0 ? { ticks: nextTicks } : {},
|
|
3846
|
+
...nextInitial !== void 0 ? { initialEffects: nextInitial } : {}
|
|
3847
|
+
};
|
|
3848
|
+
}
|
|
3849
|
+
var REFERENCE_CONFIG_TYPE_TO_ID_KIND = {
|
|
3850
|
+
entity: "entity",
|
|
3851
|
+
trait: "trait",
|
|
3852
|
+
event: "event"
|
|
3853
|
+
};
|
|
3854
|
+
function resolveConfigRefsById(trait, idIndex) {
|
|
3855
|
+
const schema = trait.config;
|
|
3856
|
+
if (!schema) return trait;
|
|
3857
|
+
let nextSchema;
|
|
3858
|
+
const rewrites = [];
|
|
3859
|
+
for (const [key, field] of Object.entries(schema)) {
|
|
3860
|
+
if (!field.refId || !isReferenceConfigType(field.type)) continue;
|
|
3861
|
+
const expectedKind = REFERENCE_CONFIG_TYPE_TO_ID_KIND[field.type];
|
|
3862
|
+
if (!expectedKind) continue;
|
|
3863
|
+
const entry = idIndex.get(field.refId);
|
|
3864
|
+
if (!entry || entry.kind !== expectedKind) continue;
|
|
3865
|
+
const currentName = entry.kind === "entity" ? entry.node.name : entry.kind === "event" ? entry.node.key : entry.node.name;
|
|
3866
|
+
if (!currentName) continue;
|
|
3867
|
+
const isTraitBinding = entry.kind === "trait" && typeof field.default === "string" && field.default.startsWith("@trait.");
|
|
3868
|
+
const nextDefault = isTraitBinding ? `@trait.${currentName}` : currentName;
|
|
3869
|
+
if (nextDefault === field.default) continue;
|
|
3870
|
+
nextSchema ??= { ...schema };
|
|
3871
|
+
nextSchema[key] = { ...field, default: nextDefault };
|
|
3872
|
+
rewrites.push({ key, from: field.default, to: nextDefault });
|
|
3873
|
+
}
|
|
3874
|
+
if (!nextSchema) return trait;
|
|
3875
|
+
refResolverLog.info("config-ref:id-resolve", {
|
|
3876
|
+
trait: trait.name,
|
|
3877
|
+
rewrites
|
|
3878
|
+
});
|
|
3879
|
+
return { ...trait, config: nextSchema };
|
|
3880
|
+
}
|
|
3620
3881
|
function applyEventRenames(trait, renames) {
|
|
3621
3882
|
if (!renames || Object.keys(renames).length === 0) return trait;
|
|
3622
3883
|
const rename = (k) => k !== void 0 && k in renames ? renames[k] : k;
|
|
@@ -3678,17 +3939,24 @@ var ReferenceResolver = class {
|
|
|
3678
3939
|
loader;
|
|
3679
3940
|
options;
|
|
3680
3941
|
localTraits;
|
|
3942
|
+
/** id-keyed mirror of `localTraits`, populated wherever the trait carries an `id`. */
|
|
3943
|
+
localTraitsById = /* @__PURE__ */ new Map();
|
|
3681
3944
|
loaderInitialized = false;
|
|
3682
3945
|
constructor(options) {
|
|
3683
3946
|
this.options = options;
|
|
3684
3947
|
this.loader = options.loader;
|
|
3685
3948
|
this.localTraits = options.localTraits ?? /* @__PURE__ */ new Map();
|
|
3949
|
+
for (const trait of this.localTraits.values()) {
|
|
3950
|
+
if (trait.id) {
|
|
3951
|
+
this.localTraitsById.set(trait.id, trait);
|
|
3952
|
+
}
|
|
3953
|
+
}
|
|
3686
3954
|
}
|
|
3687
3955
|
async ensureLoader() {
|
|
3688
3956
|
if (this.loader || this.loaderInitialized) return;
|
|
3689
3957
|
this.loaderInitialized = true;
|
|
3690
3958
|
try {
|
|
3691
|
-
const { ExternalOrbitalLoader } = await import('./external-loader-
|
|
3959
|
+
const { ExternalOrbitalLoader } = await import('./external-loader-FNK5AU6U.js');
|
|
3692
3960
|
this.loader = new ExternalOrbitalLoader(this.options);
|
|
3693
3961
|
} catch {
|
|
3694
3962
|
}
|
|
@@ -3705,11 +3973,12 @@ var ReferenceResolver = class {
|
|
|
3705
3973
|
} };
|
|
3706
3974
|
const traitsList = orbital.traits ?? [];
|
|
3707
3975
|
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);
|
|
3976
|
+
const importsResult = alreadyResolved ? { success: true, data: { orbitals: /* @__PURE__ */ new Map(), idIndex: /* @__PURE__ */ new Map() }} : await this.resolveImports(orbital.uses ?? [], sourcePath, importChain);
|
|
3709
3977
|
if (!importsResult.success) {
|
|
3710
3978
|
return { success: false, errors: importsResult.errors };
|
|
3711
3979
|
}
|
|
3712
3980
|
const imports = importsResult.data;
|
|
3981
|
+
imports.idIndex = buildIdIndex(orbital, imports.orbitals);
|
|
3713
3982
|
const entityResult = this.resolveEntity(orbital.entity, imports);
|
|
3714
3983
|
if (!entityResult.success) {
|
|
3715
3984
|
errors.push(...entityResult.errors);
|
|
@@ -3728,6 +3997,10 @@ var ReferenceResolver = class {
|
|
|
3728
3997
|
if (!entityResult.success || !traitsResult.success || !pagesResult.success) {
|
|
3729
3998
|
return { success: false, errors: ["Internal error: unexpected failure state"] };
|
|
3730
3999
|
}
|
|
4000
|
+
for (const resolvedTrait of traitsResult.data) {
|
|
4001
|
+
resolvedTrait.trait = resolveEntityTokensById(resolvedTrait.trait, imports.idIndex);
|
|
4002
|
+
resolvedTrait.trait = resolveConfigRefsById(resolvedTrait.trait, imports.idIndex);
|
|
4003
|
+
}
|
|
3731
4004
|
try {
|
|
3732
4005
|
spliceLambdaTraitRefs(traitsResult.data, pagesResult.data);
|
|
3733
4006
|
} catch (e) {
|
|
@@ -3759,7 +4032,7 @@ var ReferenceResolver = class {
|
|
|
3759
4032
|
if (this.options.skipExternalLoading) {
|
|
3760
4033
|
return {
|
|
3761
4034
|
success: true,
|
|
3762
|
-
data: { orbitals },
|
|
4035
|
+
data: { orbitals, idIndex: /* @__PURE__ */ new Map() },
|
|
3763
4036
|
warnings: ["External loading skipped"]
|
|
3764
4037
|
};
|
|
3765
4038
|
}
|
|
@@ -3793,7 +4066,7 @@ var ReferenceResolver = class {
|
|
|
3793
4066
|
if (errors.length > 0) {
|
|
3794
4067
|
return { success: false, errors };
|
|
3795
4068
|
}
|
|
3796
|
-
return { success: true, data: { orbitals }, warnings: [] };
|
|
4069
|
+
return { success: true, data: { orbitals, idIndex: /* @__PURE__ */ new Map() }, warnings: [] };
|
|
3797
4070
|
}
|
|
3798
4071
|
/**
|
|
3799
4072
|
* Resolve entity reference.
|
|
@@ -3924,7 +4197,8 @@ var ReferenceResolver = class {
|
|
|
3924
4197
|
refObj.linkedEntity,
|
|
3925
4198
|
refObj.name,
|
|
3926
4199
|
refObj.events,
|
|
3927
|
-
refObj.listens
|
|
4200
|
+
refObj.listens,
|
|
4201
|
+
refObj.refId
|
|
3928
4202
|
);
|
|
3929
4203
|
}
|
|
3930
4204
|
if (typeof traitRef === "string") {
|
|
@@ -3938,7 +4212,7 @@ var ReferenceResolver = class {
|
|
|
3938
4212
|
/**
|
|
3939
4213
|
* Resolve a trait reference string.
|
|
3940
4214
|
*/
|
|
3941
|
-
resolveTraitRefString(ref, imports, config, linkedEntity, overrideName, eventRenames, listensOverride) {
|
|
4215
|
+
resolveTraitRefString(ref, imports, config, linkedEntity, overrideName, eventRenames, listensOverride, refId) {
|
|
3942
4216
|
const parsed = parseImportedTraitRef(ref);
|
|
3943
4217
|
if (parsed) {
|
|
3944
4218
|
const imported = imports.orbitals.get(parsed.alias);
|
|
@@ -3950,7 +4224,7 @@ var ReferenceResolver = class {
|
|
|
3950
4224
|
]
|
|
3951
4225
|
};
|
|
3952
4226
|
}
|
|
3953
|
-
const trait = this.findTraitInOrbital(imported.orbital, parsed.traitName);
|
|
4227
|
+
const trait = this.findTraitInOrbital(imported.orbital, parsed.traitName, refId, imports.idIndex);
|
|
3954
4228
|
if (!trait) {
|
|
3955
4229
|
return {
|
|
3956
4230
|
success: false,
|
|
@@ -3986,7 +4260,7 @@ var ReferenceResolver = class {
|
|
|
3986
4260
|
warnings: []
|
|
3987
4261
|
};
|
|
3988
4262
|
}
|
|
3989
|
-
const localTrait = this.localTraits.get(ref);
|
|
4263
|
+
const localTrait = (refId && this.localTraitsById.get(refId)) ?? this.localTraits.get(ref);
|
|
3990
4264
|
if (localTrait) {
|
|
3991
4265
|
const baseLocal = overrideName ? { ...localTrait, name: overrideName } : localTrait;
|
|
3992
4266
|
const { trait: configResolvedLocal, errors: localConfigRefErrors } = resolveConfigRefEmitNames(baseLocal, config);
|
|
@@ -4023,9 +4297,17 @@ var ReferenceResolver = class {
|
|
|
4023
4297
|
};
|
|
4024
4298
|
}
|
|
4025
4299
|
/**
|
|
4026
|
-
* Find a trait in an orbital by name.
|
|
4300
|
+
* Find a trait in an orbital by name. Id-primary: when the calling ref
|
|
4301
|
+
* carries a `refId` and the id index has a matching trait entry, return it
|
|
4302
|
+
* directly — else fall back to the existing name match unchanged.
|
|
4027
4303
|
*/
|
|
4028
|
-
findTraitInOrbital(orbital, traitName) {
|
|
4304
|
+
findTraitInOrbital(orbital, traitName, refId, idIndex) {
|
|
4305
|
+
if (refId && idIndex) {
|
|
4306
|
+
const entry = idIndex.get(refId);
|
|
4307
|
+
if (entry && entry.kind === "trait") {
|
|
4308
|
+
return entry.node;
|
|
4309
|
+
}
|
|
4310
|
+
}
|
|
4029
4311
|
for (const traitRef of orbital.traits) {
|
|
4030
4312
|
if (typeof traitRef !== "string" && "stateMachine" in traitRef) {
|
|
4031
4313
|
if (traitRef.name === traitName) {
|
|
@@ -4099,7 +4381,7 @@ var ReferenceResolver = class {
|
|
|
4099
4381
|
/**
|
|
4100
4382
|
* Resolve a page reference string.
|
|
4101
4383
|
*/
|
|
4102
|
-
resolvePageRefString(ref, imports) {
|
|
4384
|
+
resolvePageRefString(ref, imports, refId) {
|
|
4103
4385
|
const parsed = parsePageRef(ref);
|
|
4104
4386
|
if (!parsed) {
|
|
4105
4387
|
return {
|
|
@@ -4116,7 +4398,7 @@ var ReferenceResolver = class {
|
|
|
4116
4398
|
]
|
|
4117
4399
|
};
|
|
4118
4400
|
}
|
|
4119
|
-
const page = this.findPageInOrbital(imported.orbital, parsed.pageName);
|
|
4401
|
+
const page = this.findPageInOrbital(imported.orbital, parsed.pageName, refId, imports.idIndex);
|
|
4120
4402
|
if (!page) {
|
|
4121
4403
|
return {
|
|
4122
4404
|
success: false,
|
|
@@ -4139,7 +4421,7 @@ var ReferenceResolver = class {
|
|
|
4139
4421
|
* Resolve a page reference object with optional path override.
|
|
4140
4422
|
*/
|
|
4141
4423
|
resolvePageRefObject(refObj, imports) {
|
|
4142
|
-
const baseResult = this.resolvePageRefString(refObj.ref, imports);
|
|
4424
|
+
const baseResult = this.resolvePageRefString(refObj.ref, imports, refObj.refId);
|
|
4143
4425
|
if (!baseResult.success) {
|
|
4144
4426
|
return baseResult;
|
|
4145
4427
|
}
|
|
@@ -4160,9 +4442,17 @@ var ReferenceResolver = class {
|
|
|
4160
4442
|
};
|
|
4161
4443
|
}
|
|
4162
4444
|
/**
|
|
4163
|
-
* Find a page in an orbital by name.
|
|
4445
|
+
* Find a page in an orbital by name. Id-primary: when the calling ref
|
|
4446
|
+
* carries a `refId` and the id index has a matching page entry, return it
|
|
4447
|
+
* directly — else fall back to the existing name match unchanged.
|
|
4164
4448
|
*/
|
|
4165
|
-
findPageInOrbital(orbital, pageName) {
|
|
4449
|
+
findPageInOrbital(orbital, pageName, refId, idIndex) {
|
|
4450
|
+
if (refId && idIndex) {
|
|
4451
|
+
const entry = idIndex.get(refId);
|
|
4452
|
+
if (entry && entry.kind === "page") {
|
|
4453
|
+
return { ...entry.node };
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4166
4456
|
const pages = orbital.pages;
|
|
4167
4457
|
if (!pages) return null;
|
|
4168
4458
|
for (const pageRef of pages) {
|
|
@@ -4195,6 +4485,9 @@ var ReferenceResolver = class {
|
|
|
4195
4485
|
addLocalTraits(traits) {
|
|
4196
4486
|
for (const trait of traits) {
|
|
4197
4487
|
this.localTraits.set(trait.name, trait);
|
|
4488
|
+
if (trait.id) {
|
|
4489
|
+
this.localTraitsById.set(trait.id, trait);
|
|
4490
|
+
}
|
|
4198
4491
|
}
|
|
4199
4492
|
}
|
|
4200
4493
|
/**
|