@@ -479,10 +479,10 @@ export type GetSearchResourceFunc<T extends CardDef | FileDef = CardDef> = (
479479
480480export interface CardStore {
481481 // The VirtualNetwork that owns this store's realm mappings, used for
482- // prefix/RRI resolution during (de)serialization. Optional so test doubles
483- // don't need to implement it; resolution sites degrade — URL-form refs
484- // still URL-join, prefix-form refs pass through unchanged .
485- virtualNetwork? : VirtualNetwork ;
482+ // prefix/RRI resolution during (de)serialization. Required — every store
483+ // implementation must supply one (production stores, test stubs, the
484+ // FallbackCardStore) .
485+ virtualNetwork: VirtualNetwork ;
486486 getCard(url : string ): CardDef | undefined ;
487487 getFileMeta(url : string ): FileDef | undefined ;
488488 setCard(url : string , instance : CardDef ): void ;
@@ -1450,7 +1450,7 @@ class LinksTo<CardT extends LinkableDefConstructor> implements Field<CardT> {
14501450 if (reference == null || reference === ' ' ) {
14511451 return null ;
14521452 }
1453- let href = resolveRef (store , reference , relativeTo );
1453+ let href = resolveRef (store . virtualNetwork , reference , relativeTo );
14541454 let cachedInstance = isFileDef (this .card )
14551455 ? store .getFileMeta (href )
14561456 : store .getCard (href );
@@ -2030,7 +2030,11 @@ class LinksToMany<FieldT extends LinkableDefConstructor> implements Field<
20302030 if (reference == null ) {
20312031 return null ;
20322032 }
2033- let normalizedReference = resolveRef (store , reference , relativeTo );
2033+ let normalizedReference = resolveRef (
2034+ store .virtualNetwork ,
2035+ reference ,
2036+ relativeTo ,
2037+ );
20342038 let cachedInstance = isFileDef (this .card )
20352039 ? store .getFileMeta (normalizedReference )
20362040 : store .getCard (normalizedReference );
@@ -2480,7 +2484,7 @@ export class BaseDef {
24802484 return maybeRelativeReference ;
24812485 }
24822486 return resolveRef (
2483- getStore (value ),
2487+ getStore (value ). virtualNetwork ,
24842488 maybeRelativeReference ,
24852489 value [relativeTo ],
24862490 );
@@ -2507,7 +2511,7 @@ export class BaseDef {
25072511 let normalizedId = rawValue .reference ;
25082512 if (value [relativeTo ]) {
25092513 normalizedId = resolveRef (
2510- getStore (value ),
2514+ getStore (value ). virtualNetwork ,
25112515 normalizedId ,
25122516 value [relativeTo ],
25132517 );
@@ -3480,7 +3484,11 @@ function lazilyLoadLink(
34803484 inflightLinkLoads .set (instance , inflightLoads );
34813485 }
34823486 let store = getStore (instance );
3483- let reference = resolveRef (store , link , instance .id ?? instance [relativeTo ]);
3487+ let reference = resolveRef (
3488+ store .virtualNetwork ,
3489+ link ,
3490+ instance .id ?? instance [relativeTo ],
3491+ );
34843492 let key = ` ${field .name }/${reference } ` ;
34853493 let promise = inflightLoads .get (key );
34863494 if (promise ) {
@@ -3552,7 +3560,7 @@ function lazilyLoadLink(
35523560 continue ;
35533561 }
35543562 let notLoadedRef = resolveRef (
3555- store ,
3563+ store . virtualNetwork ,
35563564 item .reference ,
35573565 instance .id ?? instance [relativeTo ],
35583566 );
@@ -3640,7 +3648,7 @@ function lazilyLoadLink(
36403648 continue ;
36413649 }
36423650 let notLoadedRef = resolveRef (
3643- store ,
3651+ store . virtualNetwork ,
36443652 item .reference ,
36453653 instance .id ?? instance [relativeTo ],
36463654 );
@@ -4682,30 +4690,34 @@ function getStore(instance: BaseDef): CardStore {
46824690}
46834691
46844692// The VirtualNetwork associated with an instance's store, for prefix/RRI
4685- // resolution outside this module. Returns undefined when the store can't
4686- // supply one — callers handle that by degrading to URL math or throwing.
4693+ // resolution outside this module. Returns undefined when the instance is
4694+ // detached (no store, no loader-attached VN) — callers handle that by
4695+ // degrading to URL math or throwing.
46874696export function virtualNetworkFor(
46884697 instance : BaseDef ,
46894698): VirtualNetwork | undefined {
4690- return getStore (instance ).virtualNetwork ;
4699+ try {
4700+ return getStore (instance ).virtualNetwork ;
4701+ } catch {
4702+ return undefined ;
4703+ }
46914704}
46924705
46934706// Resolve a (possibly prefix-form or relative) reference to an absolute URL
4694- // string through the store's VirtualNetwork. When the store doesn 't carry
4695- // a VN (test stubs, detached instances), fall back to plain URL math: it
4707+ // string through the supplied VirtualNetwork. When the caller can 't supply
4708+ // one (test stubs, detached instances), fall back to plain URL math: it
46964709// covers URL-form refs and relative refs against URL-form bases. Prefix-form
46974710// refs and refs against prefix-form bases can't be resolved without a VN —
46984711// `new URL()` throws on those, so we return the raw reference unchanged
46994712// instead of bubbling the error to callers (e.g. relationship deserialize
47004713// uses the returned string as a "did this resolve?" signal).
47014714function resolveRef(
4702- store : CardStore | undefined ,
4715+ virtualNetwork : VirtualNetwork | undefined ,
47034716 reference : string ,
47044717 relativeTo : RealmResourceIdentifier | URL | undefined ,
47054718): string {
4706- let vn = store ?.virtualNetwork ;
4707- if (vn ) {
4708- return vn .resolveURL (reference , relativeTo ).href ;
4719+ if (virtualNetwork ) {
4720+ return virtualNetwork .resolveURL (reference , relativeTo ).href ;
47094721 }
47104722 let base: URL | string | undefined ;
47114723 if (relativeTo instanceof URL ) {
@@ -4742,8 +4754,14 @@ class FallbackCardStore implements CardStore {
47424754 #inFlight: Set <Promise <unknown >> = new Set ();
47434755 #loadGeneration = 0 ; // mirrors host store tracking to detect new loads
47444756
4745- get virtualNetwork(): VirtualNetwork | undefined {
4746- return myLoader ().getVirtualNetwork ();
4757+ get virtualNetwork(): VirtualNetwork {
4758+ let vn = myLoader ().getVirtualNetwork ();
4759+ if (! vn ) {
4760+ throw new Error (
4761+ ` FallbackCardStore.virtualNetwork requires the active Loader to have a VirtualNetwork ` ,
4762+ );
4763+ }
4764+ return vn ;
47474765 }
47484766
47494767 getCard(id : string ) {
@@ -4804,13 +4822,7 @@ class FallbackCardStore implements CardStore {
48044822 opts ? : { dependencyTrackingContext? : RuntimeDependencyTrackingContext },
48054823 ) {
48064824 trackRuntimeInstanceDependency (url , opts ?.dependencyTrackingContext );
4807- let vn = this .virtualNetwork ;
4808- if (! vn ) {
4809- throw new Error (
4810- ` CardStore.loadCardDocument requires a Loader with a VirtualNetwork ` ,
4811- );
4812- }
4813- let promise = loadCardDocument (fetch , url , vn );
4825+ let promise = loadCardDocument (fetch , url , this .virtualNetwork );
48144826 this .trackLoad (promise );
48154827 return await promise ;
48164828 }
@@ -4820,13 +4832,7 @@ class FallbackCardStore implements CardStore {
48204832 opts ? : { dependencyTrackingContext? : RuntimeDependencyTrackingContext },
48214833 ) {
48224834 trackRuntimeFileDependency (url , opts ?.dependencyTrackingContext );
4823- let vn = this .virtualNetwork ;
4824- if (! vn ) {
4825- throw new Error (
4826- ` CardStore.loadFileMetaDocument requires a Loader with a VirtualNetwork ` ,
4827- );
4828- }
4829- let promise = loadFileMetaDocument (fetch , url , vn );
4835+ let promise = loadFileMetaDocument (fetch , url , this .virtualNetwork );
48304836 this .trackLoad (promise );
48314837 return await promise ;
48324838 }
0 commit comments