diff --git a/packages/host/tests/live-test.js b/packages/host/tests/live-test.js index 89c28308934..551961f1ccc 100644 --- a/packages/host/tests/live-test.js +++ b/packages/host/tests/live-test.js @@ -67,6 +67,13 @@ export async function loadRealmTests(application) { import('@cardstack/host/config/environment'), ]); + // Mutate the shared config module object directly (not just the copy + // handed to loaderInstance's shim below) so every app instance created + // later by individual tests' setupApplicationTest — which import + // '@cardstack/host/config/environment' as a normal static import, not + // through this loader — also sees the real catalog realm address. + hostConfigEnvironment.default.resolvedCatalogRealmURL = realmURL; + const loaderInstance = application.buildInstance({ rootElement: '#ember-testing-loader', }); diff --git a/packages/host/tests/unit/plan-install-test.ts b/packages/host/tests/unit/plan-install-test.ts index c70ace04df8..bd8863fa35a 100644 --- a/packages/host/tests/unit/plan-install-test.ts +++ b/packages/host/tests/unit/plan-install-test.ts @@ -21,6 +21,10 @@ const baseRealmURL = new URL('https://cardstack.com/base/'); const foreignRealmURL = new URL('https://localhost:4201/user1/personal-realm/'); const virtualNetwork = new VirtualNetwork(); +// The install planner canonicalizes module refs through the virtual +// network's realm mappings, so register the base realm prefix the same way +// the host's network service does at construction. +virtualNetwork.addRealmMapping('@cardstack/base/', baseRealmURL.href); module('Unit | Catalog | Install Plan Builder', function () { test('when listing name is not provided, just provides uuid (in this case uuid="xyz")', function (assert) { diff --git a/packages/runtime-common/catalog.ts b/packages/runtime-common/catalog.ts index ab3df314423..5a83b8716e0 100644 --- a/packages/runtime-common/catalog.ts +++ b/packages/runtime-common/catalog.ts @@ -7,7 +7,7 @@ import type { CardDef } from '@cardstack/base/card-api'; import { RealmPaths, join } from './paths.ts'; import type { ResolvedCodeRef } from './code-ref.ts'; import { resolveAdoptedCodeRef } from './code-ref.ts'; -import { realmURL } from './constants.ts'; +import { baseRealmRRI, realmURL } from './constants.ts'; import { logger } from './log.ts'; import type { LocalPath } from './paths.ts'; import { rri } from './realm-identifiers.ts'; @@ -23,7 +23,22 @@ export interface Listing extends CardDef { skills: any[]; } -const baseRealmPath = new RealmPaths(new URL('https://cardstack.com/base/')); +// A codeRef.module for a base-realm class may reach the planner as the +// literal symbolic `https://cardstack.com/base/` URL or as the base realm's +// real backing URL (e.g. `https://localhost:4201/base/skill`), so +// canonicalize once to RRI form and compare against the `@cardstack/base/` +// prefix. This requires the base realm's URL and realm mappings to be +// registered on the VirtualNetwork the caller hands us — every production +// VirtualNetwork registers them at construction (see the host's network +// service), and tests must do the same. The durable end-state is for refs +// to already be canonical before they reach this layer, at which point the +// unresolveURL call collapses to a no-op prefix check. +function isInBaseRealm( + module: RealmResourceIdentifier, + virtualNetwork: VirtualNetwork, +): boolean { + return virtualNetwork.unresolveURL(module).startsWith(baseRealmRRI); +} // sourceCodeRef -- (installs module) --> targetCodeRef // sourceCodeRef: code ref of the code from the source realm @@ -222,7 +237,7 @@ function resolveTargetCodeRef( resolver: ListingPathResolver, virtualNetwork: VirtualNetwork, ): ResolvedCodeRef { - if (baseRealmPath.inRealm(codeRef.module)) { + if (isInBaseRealm(codeRef.module, virtualNetwork)) { return codeRef; } else { let moduleURL = virtualNetwork.toURL(codeRef.module); @@ -249,7 +264,7 @@ export function planModuleInstall( }; }); let modulesCopy = codeRefs.flatMap((sourceCodeRef: ResolvedCodeRef) => { - if (baseRealmPath.inRealm(sourceCodeRef.module)) { + if (isInBaseRealm(sourceCodeRef.module, virtualNetwork)) { return []; } let targetCodeRef = resolveTargetCodeRef( @@ -276,10 +291,10 @@ export function planInstanceInstall( for (let instance of instances) { let sourceCodeRef = resolveAdoptedCodeRef(instance, virtualNetwork); let lid = resolver.local(virtualNetwork.toURL(instance.id).href); - if (baseRealmPath.inRealm(rri(instance.id))) { + if (isInBaseRealm(rri(instance.id), virtualNetwork)) { throw new Error('Cannot install instance from base realm'); } - if (!baseRealmPath.inRealm(sourceCodeRef.module)) { + if (!isInBaseRealm(sourceCodeRef.module, virtualNetwork)) { let targetCodeRef = resolveTargetCodeRef( sourceCodeRef, resolver,