Skip to content

Commit 9cbe153

Browse files
backspaceclaude
andcommitted
Make CardStore.virtualNetwork required
Tighten the CardStore interface so every implementation must expose a VirtualNetwork. Implementations updated: - gc-card-store.ts's CardStoreWithGarbageCollection already had it - render-service.ts's CardStoreWithErrors gains a public getter that exposes its existing #virtualNetwork field - field-configuration-test.gts's DeferredLinkStore test stub gains a `virtualNetwork: new VirtualNetwork()` field - card-api.gts's FallbackCardStore.virtualNetwork getter throws when the active loader can't supply one (was `undefined` before); the loadCardDocument / loadFileMetaDocument methods that previously threw on missing VN drop their now-redundant runtime checks virtualNetworkFor's external contract stays `VirtualNetwork | undefined` — that's the documented out-of-scope item for CS-11374 (detached instances, static parsers). It wraps the getStore(instance).virtualNetwork access in try/catch so a FallbackCardStore-without-loader-VN reaches the function as undefined the way callers already expect. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 1c26be1 commit 9cbe153

3 files changed

Lines changed: 28 additions & 24 deletions

File tree

packages/base/card-api.gts

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -469,10 +469,10 @@ export type GetSearchResourceFunc<T extends CardDef | FileDef = CardDef> = (
469469

470470
export interface CardStore {
471471
// The VirtualNetwork that owns this store's realm mappings, used for
472-
// prefix/RRI resolution during (de)serialization. Optional so test doubles
473-
// don't need to implement it; resolution sites degrade — URL-form refs
474-
// still URL-join, prefix-form refs pass through unchanged.
475-
virtualNetwork?: VirtualNetwork;
472+
// prefix/RRI resolution during (de)serialization. Required — every store
473+
// implementation must supply one (production stores, test stubs, the
474+
// FallbackCardStore).
475+
virtualNetwork: VirtualNetwork;
476476
getCard(url: string): CardDef | undefined;
477477
getFileMeta(url: string): FileDef | undefined;
478478
setCard(url: string, instance: CardDef): void;
@@ -4653,12 +4653,17 @@ function getStore(instance: BaseDef): CardStore {
46534653
}
46544654

46554655
// The VirtualNetwork associated with an instance's store, for prefix/RRI
4656-
// resolution outside this module. Returns undefined when the store can't
4657-
// supply one — callers handle that by degrading to URL math or throwing.
4656+
// resolution outside this module. Returns undefined when the instance is
4657+
// detached (no store, no loader-attached VN) — callers handle that by
4658+
// degrading to URL math or throwing.
46584659
export function virtualNetworkFor(
46594660
instance: BaseDef,
46604661
): VirtualNetwork | undefined {
4661-
return getStore(instance).virtualNetwork;
4662+
try {
4663+
return getStore(instance).virtualNetwork;
4664+
} catch {
4665+
return undefined;
4666+
}
46624667
}
46634668

46644669
// Resolve a (possibly prefix-form or relative) reference to an absolute URL
@@ -4712,8 +4717,14 @@ class FallbackCardStore implements CardStore {
47124717
#inFlight: Set<Promise<unknown>> = new Set();
47134718
#loadGeneration = 0; // mirrors host store tracking to detect new loads
47144719

4715-
get virtualNetwork(): VirtualNetwork | undefined {
4716-
return myLoader().getVirtualNetwork();
4720+
get virtualNetwork(): VirtualNetwork {
4721+
let vn = myLoader().getVirtualNetwork();
4722+
if (!vn) {
4723+
throw new Error(
4724+
`FallbackCardStore.virtualNetwork requires the active Loader to have a VirtualNetwork`,
4725+
);
4726+
}
4727+
return vn;
47174728
}
47184729

47194730
getCard(id: string) {
@@ -4774,13 +4785,7 @@ class FallbackCardStore implements CardStore {
47744785
opts?: { dependencyTrackingContext?: RuntimeDependencyTrackingContext },
47754786
) {
47764787
trackRuntimeInstanceDependency(url, opts?.dependencyTrackingContext);
4777-
let vn = this.virtualNetwork;
4778-
if (!vn) {
4779-
throw new Error(
4780-
`CardStore.loadCardDocument requires a Loader with a VirtualNetwork`,
4781-
);
4782-
}
4783-
let promise = loadCardDocument(fetch, url, vn);
4788+
let promise = loadCardDocument(fetch, url, this.virtualNetwork);
47844789
this.trackLoad(promise);
47854790
return await promise;
47864791
}
@@ -4790,13 +4795,7 @@ class FallbackCardStore implements CardStore {
47904795
opts?: { dependencyTrackingContext?: RuntimeDependencyTrackingContext },
47914796
) {
47924797
trackRuntimeFileDependency(url, opts?.dependencyTrackingContext);
4793-
let vn = this.virtualNetwork;
4794-
if (!vn) {
4795-
throw new Error(
4796-
`CardStore.loadFileMetaDocument requires a Loader with a VirtualNetwork`,
4797-
);
4798-
}
4799-
let promise = loadFileMetaDocument(fetch, url, vn);
4798+
let promise = loadFileMetaDocument(fetch, url, this.virtualNetwork);
48004799
this.trackLoad(promise);
48014800
return await promise;
48024801
}

packages/host/app/services/render-service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ export class CardStoreWithErrors implements CardStore {
6868
this.#virtualNetwork = virtualNetwork;
6969
}
7070

71+
get virtualNetwork(): VirtualNetwork {
72+
return this.#virtualNetwork;
73+
}
74+
7175
getCard(id: string): CardDef | undefined {
7276
id = this.normalizeKey(id);
7377
return this.#cards.get(id);

packages/host/tests/integration/field-configuration-test.gts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { settled } from '@ember/test-helpers';
44
import { getService } from '@universal-ember/test-support';
55
import { module, test } from 'qunit';
66

7-
import { baseRealm, Deferred } from '@cardstack/runtime-common';
7+
import { baseRealm, Deferred, VirtualNetwork } from '@cardstack/runtime-common';
88
import type {
99
SingleCardDocument,
1010
SingleFileMetaDocument,
@@ -44,6 +44,7 @@ import { setupRenderingTest } from '../helpers/setup';
4444
let loader: Loader;
4545

4646
class DeferredLinkStore implements CardStore {
47+
virtualNetwork: VirtualNetwork = new VirtualNetwork();
4748
private cardInstances = new Map<string, CardDefType>();
4849
private fileMetaInstances = new Map<string, FileDef>();
4950
private readyCardDocs = new Map<string, SingleCardDocument>();

0 commit comments

Comments
 (0)