From 1dba7a99b4330a73bfc21ce990fdb10fbe2d1e6f Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 2 Jul 2026 16:32:14 -0500 Subject: [PATCH 1/2] refactor: resolve markdown pill slots without VirtualNetwork (CS-11734) With the realm serving instance ids in canonical form (CS-11458), card.id / file.id are canonical, so the base MarkdownTemplate can resolve BFM reference slots in RRI space (resolveRRIReference) and match its loaded-instance map keys without a VirtualNetwork. Drops rich-markdown's per-component virtualNetwork getter and the @cardReferenceVirtualNetwork thread, simplifies baseUrl to the canonical id as-is (no toURL), and removes the last virtualNetworkFor consumer in the markdown display path. Stacked on the CS-11458 serve change; not valid without it. Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/base/default-templates/markdown.gts | 39 +++++++------------- packages/base/rich-markdown.gts | 32 +++++----------- 2 files changed, 23 insertions(+), 48 deletions(-) diff --git a/packages/base/default-templates/markdown.gts b/packages/base/default-templates/markdown.gts index c7e0bf55bf..c2ca883c55 100644 --- a/packages/base/default-templates/markdown.gts +++ b/packages/base/default-templates/markdown.gts @@ -16,8 +16,9 @@ import { extractMermaidBlocks, processKatexPlaceholders, replaceMermaidSvgs, + resolveRRIReference, + rri, trimJsonExtension, - type VirtualNetwork, } from '@cardstack/runtime-common'; import { hasCodeBlocks, @@ -79,24 +80,16 @@ interface RenderSlot { typeName?: string; // present when state === 'unresolved' } -function resolveUrl( - raw: string, - baseUrl: string | null | undefined, - virtualNetwork: VirtualNetwork | undefined, -): string { - // With a VN, resolve through it so prefix-form bases and registered - // prefix-form refs round-trip correctly. Without a VN, plain - // `new URL(raw, baseUrl)` still handles the common case — URL-form - // refs (with or without a base) and relative refs against a URL-form - // base. Prefix-form bases need a VN; `new URL()` throws on those and - // we fall back to the raw ref. +function resolveUrl(raw: string, baseUrl: string | null | undefined): string { + // Resolve in RRI space (no VirtualNetwork), the same way the reference + // extractors resolve the refs behind `linkedCards`/`linkedFiles`. Instance + // ids are canonical (the realm serves prefix form for mapped realms, URL for + // unmapped), so this produces the same form as a loaded card's `id` — the + // slot key (`card.id` / `file.id`) matches without a VirtualNetwork. try { - if (virtualNetwork) { - return trimJsonExtension( - virtualNetwork.resolveURL(raw, baseUrl || undefined).href, - ); - } - return trimJsonExtension(new URL(raw, baseUrl || undefined).href); + return trimJsonExtension( + resolveRRIReference(raw, baseUrl ? rri(baseUrl) : undefined), + ); } catch { return trimJsonExtension(raw); } @@ -108,7 +101,6 @@ export default class MarkDownTemplate extends GlimmerComponent<{ linkedCards?: CardDef[] | null; linkedFiles?: FileDef[] | null; cardReferenceBaseUrl?: string | null; - cardReferenceVirtualNetwork?: VirtualNetwork; }; }> { @tracked monacoContextInternal: any = undefined; @@ -208,7 +200,6 @@ export default class MarkDownTemplate extends GlimmerComponent<{ let linkedCards = this.args.linkedCards; let linkedFiles = this.args.linkedFiles; let baseUrl = this.args.cardReferenceBaseUrl; - let virtualNetwork = this.args.cardReferenceVirtualNetwork; let pendingUpdate = false; let pendingToken: unknown = undefined; // On the very first modifier run the linked instances are likely still @@ -278,7 +269,7 @@ export default class MarkDownTemplate extends GlimmerComponent<{ ); } - let resolvedUrl = resolveUrl(rawUrl, baseUrl, virtualNetwork); + let resolvedUrl = resolveUrl(rawUrl, baseUrl); let instance = refType === 'file' @@ -569,8 +560,7 @@ export default class MarkDownTemplate extends GlimmerComponent<{ /> {{else}}