From 5f4f937e3b890b97b2d57668e799a9a8814d18a5 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 10 Sep 2026 22:07:00 -0400 Subject: [PATCH 01/13] Serve @cardstack/base/date/day from the host bundle The virtual network's shimAsyncModule resolves the module through a lazy import(), so Vite emits it as its own chunk and a loader import of `@cardstack/base/date/day` is answered from the bundle instead of a fetch of realm-server-transpiled source. The host test helper imports DayField statically for the same reason. Base modules import host tools as `@cardstack/boxel-host/tools/*`, which the virtual network shims at runtime; the Vite alias gives the bundler the same mapping so a bundled base module resolves them too. Co-Authored-By: Claude Fable 5.1 --- packages/host/app/lib/externals.ts | 5 +++++ packages/host/tests/helpers/base-realm.ts | 11 ++--------- packages/host/vite.config.mjs | 10 ++++++++++ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/host/app/lib/externals.ts b/packages/host/app/lib/externals.ts index 74c869f0d48..92b00b9e3ee 100644 --- a/packages/host/app/lib/externals.ts +++ b/packages/host/app/lib/externals.ts @@ -242,6 +242,11 @@ export function shimExternals(virtualNetwork: VirtualNetwork) { resolve: () => import('@cardstack/runtime-common/helpers/ai'), }); + virtualNetwork.shimAsyncModule({ + id: '@cardstack/base/date/day', + resolve: () => import('@cardstack/base/date/day'), + }); + shimModulesForLiveTests(virtualNetwork); // Some realm modules use host-only types or helpers. Provide a safe shim so diff --git a/packages/host/tests/helpers/base-realm.ts b/packages/host/tests/helpers/base-realm.ts index 1025f3a47d1..514a14d9e0c 100644 --- a/packages/host/tests/helpers/base-realm.ts +++ b/packages/host/tests/helpers/base-realm.ts @@ -8,7 +8,6 @@ import type * as CardsGridModule from '@cardstack/base/cards-grid'; import type * as CodeRefModule from '@cardstack/base/code-ref'; import type * as ColorFieldModule from '@cardstack/base/color'; import type * as DateFieldModule from '@cardstack/base/date'; -import type * as DayFieldModule from '@cardstack/base/date/day'; import type * as MonthFieldModule from '@cardstack/base/date/month'; import type * as MonthDayFieldModule from '@cardstack/base/date/month-day'; import type * as MonthYearFieldModule from '@cardstack/base/date/month-year'; @@ -40,6 +39,8 @@ import type * as RelativeTimeFieldModule from '@cardstack/base/time/relative-tim import type * as TimeRangeFieldModule from '@cardstack/base/time/time-range'; import type * as WorkspaceModule from '@cardstack/base/workspace'; +export { default as DayField } from '@cardstack/base/date/day'; + type StringField = (typeof StringFieldModule)['default']; let StringField: StringField; @@ -61,9 +62,6 @@ let DatetimeStampField: DatetimeStampField; type DateRangeField = (typeof DateRangeFieldModule)['default']; let DateRangeField: DateRangeField; -type DayField = (typeof DayFieldModule)['default']; -let DayField: DayField; - type MonthField = (typeof MonthFieldModule)['default']; let MonthField: MonthField; @@ -244,10 +242,6 @@ async function initialize() { ) ).default; - DayField = ( - await loader.import('@cardstack/base/date/day') - ).default; - MonthField = ( await loader.import('@cardstack/base/date/month') ).default; @@ -465,7 +459,6 @@ export { ColorField, DatetimeStampField, DateRangeField, - DayField, MonthField, MonthDayField, MonthYearField, diff --git a/packages/host/vite.config.mjs b/packages/host/vite.config.mjs index 7c334dadba3..305e487c76c 100644 --- a/packages/host/vite.config.mjs +++ b/packages/host/vite.config.mjs @@ -298,6 +298,16 @@ export default defineConfig(({ mode }) => ({ }, resolve: { alias: [ + // Base-realm modules served from the host bundle (see shimExternals in + // app/lib/externals.ts) import host tools as + // `@cardstack/boxel-host/tools/*` or `@cardstack/boxel-host/commands/*`. + // At runtime the virtual network shims those specifiers to app/tools + // modules (see app/tools/index.ts); this alias gives the bundler the + // same 1:1 mapping. + { + find: /^@cardstack\/boxel-host\/(?:tools|commands)\//, + replacement: `${__dirname}/app/tools/`, + }, { find: 'path', replacement: require.resolve('path-browserify') }, { find: 'stream', replacement: require.resolve('stream-browserify') }, { find: /^util$/, replacement: require.resolve('util/') }, From 5d86c7e5b140e7026b28667820895a59cbe8bbf9 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 10 Sep 2026 22:07:16 -0400 Subject: [PATCH 02/13] Serve @cardstack/base/date/month from the host bundle Same shape as date/day: a lazy shimAsyncModule entry and a static import in the host test helper. Co-Authored-By: Claude Fable 5.1 --- packages/host/app/lib/externals.ts | 5 +++++ packages/host/tests/helpers/base-realm.ts | 10 +--------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/host/app/lib/externals.ts b/packages/host/app/lib/externals.ts index 92b00b9e3ee..55a5e44bec5 100644 --- a/packages/host/app/lib/externals.ts +++ b/packages/host/app/lib/externals.ts @@ -247,6 +247,11 @@ export function shimExternals(virtualNetwork: VirtualNetwork) { resolve: () => import('@cardstack/base/date/day'), }); + virtualNetwork.shimAsyncModule({ + id: '@cardstack/base/date/month', + resolve: () => import('@cardstack/base/date/month'), + }); + shimModulesForLiveTests(virtualNetwork); // Some realm modules use host-only types or helpers. Provide a safe shim so diff --git a/packages/host/tests/helpers/base-realm.ts b/packages/host/tests/helpers/base-realm.ts index 514a14d9e0c..a5347477498 100644 --- a/packages/host/tests/helpers/base-realm.ts +++ b/packages/host/tests/helpers/base-realm.ts @@ -8,7 +8,6 @@ import type * as CardsGridModule from '@cardstack/base/cards-grid'; import type * as CodeRefModule from '@cardstack/base/code-ref'; import type * as ColorFieldModule from '@cardstack/base/color'; import type * as DateFieldModule from '@cardstack/base/date'; -import type * as MonthFieldModule from '@cardstack/base/date/month'; import type * as MonthDayFieldModule from '@cardstack/base/date/month-day'; import type * as MonthYearFieldModule from '@cardstack/base/date/month-year'; import type * as QuarterFieldModule from '@cardstack/base/date/quarter'; @@ -40,6 +39,7 @@ import type * as TimeRangeFieldModule from '@cardstack/base/time/time-range'; import type * as WorkspaceModule from '@cardstack/base/workspace'; export { default as DayField } from '@cardstack/base/date/day'; +export { default as MonthField } from '@cardstack/base/date/month'; type StringField = (typeof StringFieldModule)['default']; let StringField: StringField; @@ -62,9 +62,6 @@ let DatetimeStampField: DatetimeStampField; type DateRangeField = (typeof DateRangeFieldModule)['default']; let DateRangeField: DateRangeField; -type MonthField = (typeof MonthFieldModule)['default']; -let MonthField: MonthField; - type MonthDayField = (typeof MonthDayFieldModule)['default']; let MonthDayField: MonthDayField; @@ -242,10 +239,6 @@ async function initialize() { ) ).default; - MonthField = ( - await loader.import('@cardstack/base/date/month') - ).default; - MonthDayField = ( await loader.import( '@cardstack/base/date/month-day', @@ -459,7 +452,6 @@ export { ColorField, DatetimeStampField, DateRangeField, - MonthField, MonthDayField, MonthYearField, YearField, From fdbbeda537571ec0a3c11b056f951f83ef9721fe Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 11 Sep 2026 18:15:20 +0200 Subject: [PATCH 03/13] Serve @cardstack/base/date/month-day from the host bundle Same shape as date/day: a lazy shimAsyncModule entry and a static import in the host test helper. Co-Authored-By: Claude Fable 5.1 --- packages/host/app/lib/externals.ts | 5 +++++ packages/host/tests/helpers/base-realm.ts | 12 +----------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/host/app/lib/externals.ts b/packages/host/app/lib/externals.ts index 55a5e44bec5..4c859e681dc 100644 --- a/packages/host/app/lib/externals.ts +++ b/packages/host/app/lib/externals.ts @@ -252,6 +252,11 @@ export function shimExternals(virtualNetwork: VirtualNetwork) { resolve: () => import('@cardstack/base/date/month'), }); + virtualNetwork.shimAsyncModule({ + id: '@cardstack/base/date/month-day', + resolve: () => import('@cardstack/base/date/month-day'), + }); + shimModulesForLiveTests(virtualNetwork); // Some realm modules use host-only types or helpers. Provide a safe shim so diff --git a/packages/host/tests/helpers/base-realm.ts b/packages/host/tests/helpers/base-realm.ts index a5347477498..cc1d67732d2 100644 --- a/packages/host/tests/helpers/base-realm.ts +++ b/packages/host/tests/helpers/base-realm.ts @@ -8,7 +8,6 @@ import type * as CardsGridModule from '@cardstack/base/cards-grid'; import type * as CodeRefModule from '@cardstack/base/code-ref'; import type * as ColorFieldModule from '@cardstack/base/color'; import type * as DateFieldModule from '@cardstack/base/date'; -import type * as MonthDayFieldModule from '@cardstack/base/date/month-day'; import type * as MonthYearFieldModule from '@cardstack/base/date/month-year'; import type * as QuarterFieldModule from '@cardstack/base/date/quarter'; import type * as WeekFieldModule from '@cardstack/base/date/week'; @@ -40,6 +39,7 @@ import type * as WorkspaceModule from '@cardstack/base/workspace'; export { default as DayField } from '@cardstack/base/date/day'; export { default as MonthField } from '@cardstack/base/date/month'; +export { default as MonthDayField } from '@cardstack/base/date/month-day'; type StringField = (typeof StringFieldModule)['default']; let StringField: StringField; @@ -62,9 +62,6 @@ let DatetimeStampField: DatetimeStampField; type DateRangeField = (typeof DateRangeFieldModule)['default']; let DateRangeField: DateRangeField; -type MonthDayField = (typeof MonthDayFieldModule)['default']; -let MonthDayField: MonthDayField; - type MonthYearField = (typeof MonthYearFieldModule)['default']; let MonthYearField: MonthYearField; @@ -239,12 +236,6 @@ async function initialize() { ) ).default; - MonthDayField = ( - await loader.import( - '@cardstack/base/date/month-day', - ) - ).default; - MonthYearField = ( await loader.import( '@cardstack/base/date/month-year', @@ -452,7 +443,6 @@ export { ColorField, DatetimeStampField, DateRangeField, - MonthDayField, MonthYearField, YearField, WeekField, From dce5a7e584cc2d31f528b90cafc4f5142d280f10 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 11 Sep 2026 18:15:40 +0200 Subject: [PATCH 04/13] Serve @cardstack/base/date/month-year from the host bundle Same shape as date/day: a lazy shimAsyncModule entry and a static import in the host test helper. Co-Authored-By: Claude Fable 5.1 --- packages/host/app/lib/externals.ts | 5 +++++ packages/host/tests/helpers/base-realm.ts | 12 +----------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/host/app/lib/externals.ts b/packages/host/app/lib/externals.ts index 4c859e681dc..ec6dbb6bb77 100644 --- a/packages/host/app/lib/externals.ts +++ b/packages/host/app/lib/externals.ts @@ -257,6 +257,11 @@ export function shimExternals(virtualNetwork: VirtualNetwork) { resolve: () => import('@cardstack/base/date/month-day'), }); + virtualNetwork.shimAsyncModule({ + id: '@cardstack/base/date/month-year', + resolve: () => import('@cardstack/base/date/month-year'), + }); + shimModulesForLiveTests(virtualNetwork); // Some realm modules use host-only types or helpers. Provide a safe shim so diff --git a/packages/host/tests/helpers/base-realm.ts b/packages/host/tests/helpers/base-realm.ts index cc1d67732d2..3d6b3d8981c 100644 --- a/packages/host/tests/helpers/base-realm.ts +++ b/packages/host/tests/helpers/base-realm.ts @@ -8,7 +8,6 @@ import type * as CardsGridModule from '@cardstack/base/cards-grid'; import type * as CodeRefModule from '@cardstack/base/code-ref'; import type * as ColorFieldModule from '@cardstack/base/color'; import type * as DateFieldModule from '@cardstack/base/date'; -import type * as MonthYearFieldModule from '@cardstack/base/date/month-year'; import type * as QuarterFieldModule from '@cardstack/base/date/quarter'; import type * as WeekFieldModule from '@cardstack/base/date/week'; import type * as YearFieldModule from '@cardstack/base/date/year'; @@ -40,6 +39,7 @@ import type * as WorkspaceModule from '@cardstack/base/workspace'; export { default as DayField } from '@cardstack/base/date/day'; export { default as MonthField } from '@cardstack/base/date/month'; export { default as MonthDayField } from '@cardstack/base/date/month-day'; +export { default as MonthYearField } from '@cardstack/base/date/month-year'; type StringField = (typeof StringFieldModule)['default']; let StringField: StringField; @@ -62,9 +62,6 @@ let DatetimeStampField: DatetimeStampField; type DateRangeField = (typeof DateRangeFieldModule)['default']; let DateRangeField: DateRangeField; -type MonthYearField = (typeof MonthYearFieldModule)['default']; -let MonthYearField: MonthYearField; - type YearField = (typeof YearFieldModule)['default']; let YearField: YearField; @@ -236,12 +233,6 @@ async function initialize() { ) ).default; - MonthYearField = ( - await loader.import( - '@cardstack/base/date/month-year', - ) - ).default; - YearField = ( await loader.import('@cardstack/base/date/year') ).default; @@ -443,7 +434,6 @@ export { ColorField, DatetimeStampField, DateRangeField, - MonthYearField, YearField, WeekField, QuarterField, From eedf2a063c3979e234bb4a65d63085e5e3167bd2 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 11 Sep 2026 18:16:01 +0200 Subject: [PATCH 05/13] Serve @cardstack/base/date/year from the host bundle Same shape as date/day: a lazy shimAsyncModule entry and a static import in the host test helper. Co-Authored-By: Claude Fable 5.1 --- packages/host/app/lib/externals.ts | 5 +++++ packages/host/tests/helpers/base-realm.ts | 10 +--------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/host/app/lib/externals.ts b/packages/host/app/lib/externals.ts index ec6dbb6bb77..949cd8c45d2 100644 --- a/packages/host/app/lib/externals.ts +++ b/packages/host/app/lib/externals.ts @@ -262,6 +262,11 @@ export function shimExternals(virtualNetwork: VirtualNetwork) { resolve: () => import('@cardstack/base/date/month-year'), }); + virtualNetwork.shimAsyncModule({ + id: '@cardstack/base/date/year', + resolve: () => import('@cardstack/base/date/year'), + }); + shimModulesForLiveTests(virtualNetwork); // Some realm modules use host-only types or helpers. Provide a safe shim so diff --git a/packages/host/tests/helpers/base-realm.ts b/packages/host/tests/helpers/base-realm.ts index 3d6b3d8981c..afcc8408dc1 100644 --- a/packages/host/tests/helpers/base-realm.ts +++ b/packages/host/tests/helpers/base-realm.ts @@ -10,7 +10,6 @@ import type * as ColorFieldModule from '@cardstack/base/color'; import type * as DateFieldModule from '@cardstack/base/date'; import type * as QuarterFieldModule from '@cardstack/base/date/quarter'; import type * as WeekFieldModule from '@cardstack/base/date/week'; -import type * as YearFieldModule from '@cardstack/base/date/year'; import type * as DateRangeFieldModule from '@cardstack/base/date-range-field'; import type * as DateTimeFieldModule from '@cardstack/base/datetime'; import type * as DatetimeStampFieldModule from '@cardstack/base/datetime-stamp'; @@ -40,6 +39,7 @@ export { default as DayField } from '@cardstack/base/date/day'; export { default as MonthField } from '@cardstack/base/date/month'; export { default as MonthDayField } from '@cardstack/base/date/month-day'; export { default as MonthYearField } from '@cardstack/base/date/month-year'; +export { default as YearField } from '@cardstack/base/date/year'; type StringField = (typeof StringFieldModule)['default']; let StringField: StringField; @@ -62,9 +62,6 @@ let DatetimeStampField: DatetimeStampField; type DateRangeField = (typeof DateRangeFieldModule)['default']; let DateRangeField: DateRangeField; -type YearField = (typeof YearFieldModule)['default']; -let YearField: YearField; - type WeekField = (typeof WeekFieldModule)['default']; let WeekField: WeekField; @@ -233,10 +230,6 @@ async function initialize() { ) ).default; - YearField = ( - await loader.import('@cardstack/base/date/year') - ).default; - WeekField = ( await loader.import('@cardstack/base/date/week') ).default; @@ -434,7 +427,6 @@ export { ColorField, DatetimeStampField, DateRangeField, - YearField, WeekField, QuarterField, TimeField, From b745145f188bbe41354414d7064b1b4ef3cbdaec Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 11 Sep 2026 18:16:20 +0200 Subject: [PATCH 06/13] Serve @cardstack/base/date/week from the host bundle Same shape as date/day: a lazy shimAsyncModule entry and a static import in the host test helper. Co-Authored-By: Claude Fable 5.1 --- packages/host/app/lib/externals.ts | 5 +++++ packages/host/tests/helpers/base-realm.ts | 10 +--------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/host/app/lib/externals.ts b/packages/host/app/lib/externals.ts index 949cd8c45d2..caa72f01473 100644 --- a/packages/host/app/lib/externals.ts +++ b/packages/host/app/lib/externals.ts @@ -267,6 +267,11 @@ export function shimExternals(virtualNetwork: VirtualNetwork) { resolve: () => import('@cardstack/base/date/year'), }); + virtualNetwork.shimAsyncModule({ + id: '@cardstack/base/date/week', + resolve: () => import('@cardstack/base/date/week'), + }); + shimModulesForLiveTests(virtualNetwork); // Some realm modules use host-only types or helpers. Provide a safe shim so diff --git a/packages/host/tests/helpers/base-realm.ts b/packages/host/tests/helpers/base-realm.ts index afcc8408dc1..e8ab346f013 100644 --- a/packages/host/tests/helpers/base-realm.ts +++ b/packages/host/tests/helpers/base-realm.ts @@ -9,7 +9,6 @@ import type * as CodeRefModule from '@cardstack/base/code-ref'; import type * as ColorFieldModule from '@cardstack/base/color'; import type * as DateFieldModule from '@cardstack/base/date'; import type * as QuarterFieldModule from '@cardstack/base/date/quarter'; -import type * as WeekFieldModule from '@cardstack/base/date/week'; import type * as DateRangeFieldModule from '@cardstack/base/date-range-field'; import type * as DateTimeFieldModule from '@cardstack/base/datetime'; import type * as DatetimeStampFieldModule from '@cardstack/base/datetime-stamp'; @@ -40,6 +39,7 @@ export { default as MonthField } from '@cardstack/base/date/month'; export { default as MonthDayField } from '@cardstack/base/date/month-day'; export { default as MonthYearField } from '@cardstack/base/date/month-year'; export { default as YearField } from '@cardstack/base/date/year'; +export { default as WeekField } from '@cardstack/base/date/week'; type StringField = (typeof StringFieldModule)['default']; let StringField: StringField; @@ -62,9 +62,6 @@ let DatetimeStampField: DatetimeStampField; type DateRangeField = (typeof DateRangeFieldModule)['default']; let DateRangeField: DateRangeField; -type WeekField = (typeof WeekFieldModule)['default']; -let WeekField: WeekField; - type QuarterField = (typeof QuarterFieldModule)['default']; let QuarterField: QuarterField; @@ -230,10 +227,6 @@ async function initialize() { ) ).default; - WeekField = ( - await loader.import('@cardstack/base/date/week') - ).default; - QuarterField = ( await loader.import( '@cardstack/base/date/quarter', @@ -427,7 +420,6 @@ export { ColorField, DatetimeStampField, DateRangeField, - WeekField, QuarterField, TimeField, TimeRangeField, From c0d641d7c4195e80f74c2663f4d1ae7a7a79c8f9 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 11 Sep 2026 18:16:40 +0200 Subject: [PATCH 07/13] Serve @cardstack/base/date/quarter from the host bundle Same shape as date/day: a lazy shimAsyncModule entry and a static import in the host test helper. Co-Authored-By: Claude Fable 5.1 --- packages/host/app/lib/externals.ts | 5 +++++ packages/host/tests/helpers/base-realm.ts | 12 +----------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/host/app/lib/externals.ts b/packages/host/app/lib/externals.ts index caa72f01473..eb7637f4b7e 100644 --- a/packages/host/app/lib/externals.ts +++ b/packages/host/app/lib/externals.ts @@ -272,6 +272,11 @@ export function shimExternals(virtualNetwork: VirtualNetwork) { resolve: () => import('@cardstack/base/date/week'), }); + virtualNetwork.shimAsyncModule({ + id: '@cardstack/base/date/quarter', + resolve: () => import('@cardstack/base/date/quarter'), + }); + shimModulesForLiveTests(virtualNetwork); // Some realm modules use host-only types or helpers. Provide a safe shim so diff --git a/packages/host/tests/helpers/base-realm.ts b/packages/host/tests/helpers/base-realm.ts index e8ab346f013..3cd079d822c 100644 --- a/packages/host/tests/helpers/base-realm.ts +++ b/packages/host/tests/helpers/base-realm.ts @@ -8,7 +8,6 @@ import type * as CardsGridModule from '@cardstack/base/cards-grid'; import type * as CodeRefModule from '@cardstack/base/code-ref'; import type * as ColorFieldModule from '@cardstack/base/color'; import type * as DateFieldModule from '@cardstack/base/date'; -import type * as QuarterFieldModule from '@cardstack/base/date/quarter'; import type * as DateRangeFieldModule from '@cardstack/base/date-range-field'; import type * as DateTimeFieldModule from '@cardstack/base/datetime'; import type * as DatetimeStampFieldModule from '@cardstack/base/datetime-stamp'; @@ -40,6 +39,7 @@ export { default as MonthDayField } from '@cardstack/base/date/month-day'; export { default as MonthYearField } from '@cardstack/base/date/month-year'; export { default as YearField } from '@cardstack/base/date/year'; export { default as WeekField } from '@cardstack/base/date/week'; +export { default as QuarterField } from '@cardstack/base/date/quarter'; type StringField = (typeof StringFieldModule)['default']; let StringField: StringField; @@ -62,9 +62,6 @@ let DatetimeStampField: DatetimeStampField; type DateRangeField = (typeof DateRangeFieldModule)['default']; let DateRangeField: DateRangeField; -type QuarterField = (typeof QuarterFieldModule)['default']; -let QuarterField: QuarterField; - type TimeField = (typeof TimeFieldModule)['default']; let TimeField: TimeField; @@ -227,12 +224,6 @@ async function initialize() { ) ).default; - QuarterField = ( - await loader.import( - '@cardstack/base/date/quarter', - ) - ).default; - TimeField = ( await loader.import('@cardstack/base/time') ).default; @@ -420,7 +411,6 @@ export { ColorField, DatetimeStampField, DateRangeField, - QuarterField, TimeField, TimeRangeField, DurationField, From e42ae20a13eedfc19ea39da98a2005fe5e46e5bb Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 11 Sep 2026 19:30:06 +0200 Subject: [PATCH 08/13] Serve virtual-network module shims from the loader's fetch path A shim registered for a realm-mapped identifier such as `@cardstack/base/date/day` is keyed by the realm URL that identifier resolves to, because the realm mapping also feeds the network's import map. A loader import of the identifier resolves to the same realm URL, but the network's fetch pipeline only answers shims on the fake `https://packages/` origin, so such a shim was never served and the module was fetched from the realm server instead. The Loader now asks the network for a shim from its module-fetch path, which is the one place that knows the request is for a module rather than a card instance that may live at the same realm URL. The lookup folds every spelling of the identifier onto the real URL, so the prefix, virtual-alias, and url-mapped forms all land on one module. Co-Authored-By: Claude Fable 5.1 --- packages/host/tests/unit/loader-test.ts | 43 ++++++++++++++++++- packages/runtime-common/loader.ts | 13 ++++-- .../runtime-common/package-shim-handler.ts | 15 +++++++ packages/runtime-common/virtual-network.ts | 9 ++++ 4 files changed, 75 insertions(+), 5 deletions(-) diff --git a/packages/host/tests/unit/loader-test.ts b/packages/host/tests/unit/loader-test.ts index 0f2885416ac..0a1ff1700c5 100644 --- a/packages/host/tests/unit/loader-test.ts +++ b/packages/host/tests/unit/loader-test.ts @@ -4,7 +4,7 @@ import { getService } from '@universal-ember/test-support'; import { module, test } from 'qunit'; -import { baseRealm, Loader } from '@cardstack/runtime-common'; +import { baseRealm, Loader, VirtualNetwork } from '@cardstack/runtime-common'; import { testRealmURL, @@ -396,6 +396,47 @@ module('Unit | loader', function (hooks) { ); }); + test('a module shimmed on the virtual network is served to the loader without a fetch, under every spelling', async function (assert) { + // A shim for a realm-mapped identifier is keyed by the realm URL the + // identifier resolves to, and a loader import resolves to that same URL. + // The network's fetch pipeline only answers shims on the fake packages + // origin, so the loader has to ask the network for the shim itself. + let virtualNetwork = new VirtualNetwork(); + let realmURL = 'https://shimmed-realm.example/'; + let aliasURL = 'https://shimmed-alias.example/'; + virtualNetwork.addURLMapping(new URL(aliasURL), new URL(realmURL)); + virtualNetwork.addRealmMapping('@test-loader-shim/', realmURL); + class Shimmed {} + virtualNetwork.shimAsyncModule({ + id: '@test-loader-shim/shimmed-module', + resolve: async () => ({ default: Shimmed }), + }); + let throwIfFetch = new Loader( + async () => { + throw new Error( + 'fetch should not be invoked for a module the virtual network shims', + ); + }, + virtualNetwork.resolveImport, + { virtualNetwork }, + ); + + for (let spelling of [ + '@test-loader-shim/shimmed-module', + `${realmURL}shimmed-module`, + `${aliasURL}shimmed-module`, + ]) { + let module = await throwIfFetch.import<{ default: typeof Shimmed }>( + spelling, + ); + assert.strictEqual( + module.default, + Shimmed, + `${spelling} is served from the shim`, + ); + } + }); + test('identify preserves original module for reexports', function (assert) { let throwIfFetch = new Loader(async () => { throw new Error( diff --git a/packages/runtime-common/loader.ts b/packages/runtime-common/loader.ts index 53fc5f84547..339985b04e7 100644 --- a/packages/runtime-common/loader.ts +++ b/packages/runtime-common/loader.ts @@ -1122,16 +1122,21 @@ export class Loader { init?: RequestInit, ): Promise => { try { - let shimmedModule = this.moduleShims.get( - this.asRequest(urlOrRequest, init).url, - ); + let request = this.asRequest(urlOrRequest, init); + // A module shimmed on the virtual network is keyed by the URL its + // identifier resolves to, and the network's fetch pipeline only answers + // shims on the fake packages origin. This is the one path that knows a + // request is for a module (not a card instance that may live at the same + // realm URL), so the lookup belongs here, ahead of any fetch. + let shimmedModule = + this.moduleShims.get(request.url) ?? + (await this.virtualNetwork?.getShimmedModule(request.url)); if (shimmedModule) { let response = new Response(); (response as any)[Symbol.for('shimmed-module')] = shimmedModule; return response; } - let request = this.asRequest(urlOrRequest, init); return await cachedFetch(this.fetchImplementation, request); } catch (err: any) { let url = diff --git a/packages/runtime-common/package-shim-handler.ts b/packages/runtime-common/package-shim-handler.ts index eff8e2610ab..7914eb9cf37 100644 --- a/packages/runtime-common/package-shim-handler.ts +++ b/packages/runtime-common/package-shim-handler.ts @@ -519,6 +519,21 @@ export class PackageShimHandler { } } + // Module lookup for the Loader's module-fetch path. That path sees the URL + // an identifier resolves to — for a realm-mapped prefix such as + // `@cardstack/base/`, the realm URL — which is also the key a shim for such + // an identifier is registered under. `handle` only answers on the fake + // packages origin because, in the general fetch pipeline, a realm URL may + // name a card instance as well as a module; the Loader knows it is asking + // for a module, so it may be served a shim registered under any URL. + async lookupModule(url: string): Promise { + let module = + (await this.getModule(url)) ?? (await this.getModuleByPrefix(url)); + return module + ? wrapWithStrictNamespace(url, module, this.findExportSources) + : undefined; + } + private async getModule(url: string): Promise { let key = trimModuleIdentifier(url); let resolver = this.moduleIds.get(key); diff --git a/packages/runtime-common/virtual-network.ts b/packages/runtime-common/virtual-network.ts index a1bb531ad34..35cb114e96e 100644 --- a/packages/runtime-common/virtual-network.ts +++ b/packages/runtime-common/virtual-network.ts @@ -196,6 +196,15 @@ export class VirtualNetwork { this.packageShimHandler.shimAsyncModule(descriptor); } + // Lets a Loader serve a module shimmed on this network from its module-fetch + // path, whatever URL the shim is registered under. The lookup folds every + // spelling of the identifier (realm-prefix form, virtual alias, url-mapped + // alias) onto the real URL, which is the form shims for realm-mapped + // identifiers are keyed by, so all spellings converge on one module. + getShimmedModule(url: string): Promise { + return this.packageShimHandler.lookupModule(this.toRealURLHref(url)); + } + addURLMapping(from: URL, to: URL) { this.urlMappings.push([from.href, to.href]); // unresolveURL and toRealURLHref chase through urlMappings (the latter via From ed59585f15dc78efa75c29a6bdc5ee7ab1cc40f3 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 11 Sep 2026 19:30:14 +0200 Subject: [PATCH 09/13] Load base modules in the host test helper through the loader Host-side code loads base modules via `loader.import`; the helper's static re-exports bypassed the shims the loader is meant to hit, so the tests that consumed them could pass whether or not a shim answered. Co-Authored-By: Claude Fable 5.1 --- packages/host/tests/helpers/base-realm.ts | 77 ++++++++++++++++++++--- 1 file changed, 69 insertions(+), 8 deletions(-) diff --git a/packages/host/tests/helpers/base-realm.ts b/packages/host/tests/helpers/base-realm.ts index 3cd079d822c..1025f3a47d1 100644 --- a/packages/host/tests/helpers/base-realm.ts +++ b/packages/host/tests/helpers/base-realm.ts @@ -8,6 +8,13 @@ import type * as CardsGridModule from '@cardstack/base/cards-grid'; import type * as CodeRefModule from '@cardstack/base/code-ref'; import type * as ColorFieldModule from '@cardstack/base/color'; import type * as DateFieldModule from '@cardstack/base/date'; +import type * as DayFieldModule from '@cardstack/base/date/day'; +import type * as MonthFieldModule from '@cardstack/base/date/month'; +import type * as MonthDayFieldModule from '@cardstack/base/date/month-day'; +import type * as MonthYearFieldModule from '@cardstack/base/date/month-year'; +import type * as QuarterFieldModule from '@cardstack/base/date/quarter'; +import type * as WeekFieldModule from '@cardstack/base/date/week'; +import type * as YearFieldModule from '@cardstack/base/date/year'; import type * as DateRangeFieldModule from '@cardstack/base/date-range-field'; import type * as DateTimeFieldModule from '@cardstack/base/datetime'; import type * as DatetimeStampFieldModule from '@cardstack/base/datetime-stamp'; @@ -33,14 +40,6 @@ import type * as RelativeTimeFieldModule from '@cardstack/base/time/relative-tim import type * as TimeRangeFieldModule from '@cardstack/base/time/time-range'; import type * as WorkspaceModule from '@cardstack/base/workspace'; -export { default as DayField } from '@cardstack/base/date/day'; -export { default as MonthField } from '@cardstack/base/date/month'; -export { default as MonthDayField } from '@cardstack/base/date/month-day'; -export { default as MonthYearField } from '@cardstack/base/date/month-year'; -export { default as YearField } from '@cardstack/base/date/year'; -export { default as WeekField } from '@cardstack/base/date/week'; -export { default as QuarterField } from '@cardstack/base/date/quarter'; - type StringField = (typeof StringFieldModule)['default']; let StringField: StringField; @@ -62,6 +61,27 @@ let DatetimeStampField: DatetimeStampField; type DateRangeField = (typeof DateRangeFieldModule)['default']; let DateRangeField: DateRangeField; +type DayField = (typeof DayFieldModule)['default']; +let DayField: DayField; + +type MonthField = (typeof MonthFieldModule)['default']; +let MonthField: MonthField; + +type MonthDayField = (typeof MonthDayFieldModule)['default']; +let MonthDayField: MonthDayField; + +type MonthYearField = (typeof MonthYearFieldModule)['default']; +let MonthYearField: MonthYearField; + +type YearField = (typeof YearFieldModule)['default']; +let YearField: YearField; + +type WeekField = (typeof WeekFieldModule)['default']; +let WeekField: WeekField; + +type QuarterField = (typeof QuarterFieldModule)['default']; +let QuarterField: QuarterField; + type TimeField = (typeof TimeFieldModule)['default']; let TimeField: TimeField; @@ -224,6 +244,40 @@ async function initialize() { ) ).default; + DayField = ( + await loader.import('@cardstack/base/date/day') + ).default; + + MonthField = ( + await loader.import('@cardstack/base/date/month') + ).default; + + MonthDayField = ( + await loader.import( + '@cardstack/base/date/month-day', + ) + ).default; + + MonthYearField = ( + await loader.import( + '@cardstack/base/date/month-year', + ) + ).default; + + YearField = ( + await loader.import('@cardstack/base/date/year') + ).default; + + WeekField = ( + await loader.import('@cardstack/base/date/week') + ).default; + + QuarterField = ( + await loader.import( + '@cardstack/base/date/quarter', + ) + ).default; + TimeField = ( await loader.import('@cardstack/base/time') ).default; @@ -411,6 +465,13 @@ export { ColorField, DatetimeStampField, DateRangeField, + DayField, + MonthField, + MonthDayField, + MonthYearField, + YearField, + WeekField, + QuarterField, TimeField, TimeRangeField, DurationField, From ecf41e780c67c031bab6c235b248fd201a84d33e Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 11 Sep 2026 19:30:17 +0200 Subject: [PATCH 10/13] Register bundled base modules from one table and prove the loader serves them `BUNDLED_BASE_MODULES` in externals.ts lists each bundled module with its literal `import()`, and the shim registration loops over it. The new integration test imports every entry through the loader and asserts the exports are the bundled module's own and that no request reached the base realm. Co-Authored-By: Claude Fable 5.1 --- packages/host/app/lib/externals.ts | 56 ++++++++----------- .../integration/bundled-base-modules-test.ts | 46 +++++++++++++++ 2 files changed, 68 insertions(+), 34 deletions(-) create mode 100644 packages/host/tests/integration/bundled-base-modules-test.ts diff --git a/packages/host/app/lib/externals.ts b/packages/host/app/lib/externals.ts index eb7637f4b7e..81c85707663 100644 --- a/packages/host/app/lib/externals.ts +++ b/packages/host/app/lib/externals.ts @@ -65,6 +65,25 @@ import { import { shimHostTools } from '../tools'; +// Base modules compiled into the host bundle, keyed by their path under +// `@cardstack/base/`. Each is served to the loader in place of a fetch of the +// module from the base realm; the literal `import()` per entry is what lets +// Vite give each module its own chunk. Registered after the `@cardstack/base/` +// realm mapping, so an entry's id resolves to the realm URL a loader import of +// it also resolves to. +export const BUNDLED_BASE_MODULES: Record< + string, + () => Promise> +> = { + 'date/day': () => import('@cardstack/base/date/day'), + 'date/month': () => import('@cardstack/base/date/month'), + 'date/month-day': () => import('@cardstack/base/date/month-day'), + 'date/month-year': () => import('@cardstack/base/date/month-year'), + 'date/year': () => import('@cardstack/base/date/year'), + 'date/week': () => import('@cardstack/base/date/week'), + 'date/quarter': () => import('@cardstack/base/date/quarter'), +}; + export function shimExternals(virtualNetwork: VirtualNetwork) { // Always shim qunit on the virtual network. In non-test environments (code // mode, card rendering), this no-op stub prevents realm cards that co-locate @@ -242,40 +261,9 @@ export function shimExternals(virtualNetwork: VirtualNetwork) { resolve: () => import('@cardstack/runtime-common/helpers/ai'), }); - virtualNetwork.shimAsyncModule({ - id: '@cardstack/base/date/day', - resolve: () => import('@cardstack/base/date/day'), - }); - - virtualNetwork.shimAsyncModule({ - id: '@cardstack/base/date/month', - resolve: () => import('@cardstack/base/date/month'), - }); - - virtualNetwork.shimAsyncModule({ - id: '@cardstack/base/date/month-day', - resolve: () => import('@cardstack/base/date/month-day'), - }); - - virtualNetwork.shimAsyncModule({ - id: '@cardstack/base/date/month-year', - resolve: () => import('@cardstack/base/date/month-year'), - }); - - virtualNetwork.shimAsyncModule({ - id: '@cardstack/base/date/year', - resolve: () => import('@cardstack/base/date/year'), - }); - - virtualNetwork.shimAsyncModule({ - id: '@cardstack/base/date/week', - resolve: () => import('@cardstack/base/date/week'), - }); - - virtualNetwork.shimAsyncModule({ - id: '@cardstack/base/date/quarter', - resolve: () => import('@cardstack/base/date/quarter'), - }); + for (let [name, resolve] of Object.entries(BUNDLED_BASE_MODULES)) { + virtualNetwork.shimAsyncModule({ id: `@cardstack/base/${name}`, resolve }); + } shimModulesForLiveTests(virtualNetwork); diff --git a/packages/host/tests/integration/bundled-base-modules-test.ts b/packages/host/tests/integration/bundled-base-modules-test.ts new file mode 100644 index 00000000000..7142e08333a --- /dev/null +++ b/packages/host/tests/integration/bundled-base-modules-test.ts @@ -0,0 +1,46 @@ +import { getService } from '@universal-ember/test-support'; + +import { module, test } from 'qunit'; + +import { BUNDLED_BASE_MODULES } from '@cardstack/host/lib/externals'; + +import { setupRenderingTest } from '../helpers/setup'; + +module('Integration | bundled base modules', function (hooks) { + setupRenderingTest(hooks); + + test('the loader serves every bundled base module from the host bundle, not the base realm', async function (assert) { + let network = getService('network'); + let loader = getService('loader-service').loader; + let baseRealmRequests: string[] = []; + let spy = async (request: Request) => { + if (request.url.includes('/base/')) { + baseRealmRequests.push(request.url); + } + return null; + }; + network.virtualNetwork.mount(spy, { prepend: true }); + try { + for (let [name, resolveBundled] of Object.entries(BUNDLED_BASE_MODULES)) { + let bundled = await resolveBundled(); + let served = await loader.import>( + `@cardstack/base/${name}`, + ); + for (let key of Object.keys(bundled)) { + assert.strictEqual( + served[key], + bundled[key], + `${name}: the loader's ${key} export is the bundled one`, + ); + } + } + assert.deepEqual( + baseRealmRequests, + [], + 'no bundled module was fetched from the base realm', + ); + } finally { + network.virtualNetwork.unmount(spy); + } + }); +}); From 2408a135778137788078ccd3822d72fdecdf7e1c Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 11 Sep 2026 19:30:45 +0200 Subject: [PATCH 11/13] Serve the base time modules from the host bundle time, time/time-range, time/duration, and time/relative-time join the bundled-module table. Co-Authored-By: Claude Fable 5.1 --- packages/host/app/lib/externals.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/host/app/lib/externals.ts b/packages/host/app/lib/externals.ts index 81c85707663..d1c2531110e 100644 --- a/packages/host/app/lib/externals.ts +++ b/packages/host/app/lib/externals.ts @@ -82,6 +82,10 @@ export const BUNDLED_BASE_MODULES: Record< 'date/year': () => import('@cardstack/base/date/year'), 'date/week': () => import('@cardstack/base/date/week'), 'date/quarter': () => import('@cardstack/base/date/quarter'), + time: () => import('@cardstack/base/time'), + 'time/time-range': () => import('@cardstack/base/time/time-range'), + 'time/duration': () => import('@cardstack/base/time/duration'), + 'time/relative-time': () => import('@cardstack/base/time/relative-time'), }; export function shimExternals(virtualNetwork: VirtualNetwork) { From a816159366eac53bac816ab96841bafcc3157e36 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 11 Sep 2026 19:31:14 +0200 Subject: [PATCH 12/13] Serve the base primitive field modules from the host bundle string, number, boolean, big-integer, email, ethereum-address, phone-number, text-area, markdown, rich-markdown, color, code-ref, realm, enum, searchable, and base64-image join the bundled-module table. string.ts is `export default StringField` from card-api and is resolved from there: importing the `.ts` module directly makes TypeScript classify it as CommonJS (the base package declares no `type`), which retypes its default export as a namespace for every host importer. Co-Authored-By: Claude Fable 5.1 --- packages/host/app/lib/externals.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/host/app/lib/externals.ts b/packages/host/app/lib/externals.ts index d1c2531110e..153d0789ca4 100644 --- a/packages/host/app/lib/externals.ts +++ b/packages/host/app/lib/externals.ts @@ -86,6 +86,29 @@ export const BUNDLED_BASE_MODULES: Record< 'time/time-range': () => import('@cardstack/base/time/time-range'), 'time/duration': () => import('@cardstack/base/time/duration'), 'time/relative-time': () => import('@cardstack/base/time/relative-time'), + // string.ts is `export default StringField` from card-api, so it is + // resolved there. Importing string.ts itself would have TypeScript classify + // that `.ts` module as CommonJS (this package declares no `type`) and + // retype its default export as a namespace for every host importer. + string: () => + import('@cardstack/base/card-api').then(({ StringField }) => ({ + default: StringField, + })), + number: () => import('@cardstack/base/number'), + boolean: () => import('@cardstack/base/boolean'), + 'big-integer': () => import('@cardstack/base/big-integer'), + email: () => import('@cardstack/base/email'), + 'ethereum-address': () => import('@cardstack/base/ethereum-address'), + 'phone-number': () => import('@cardstack/base/phone-number'), + 'text-area': () => import('@cardstack/base/text-area'), + markdown: () => import('@cardstack/base/markdown'), + 'rich-markdown': () => import('@cardstack/base/rich-markdown'), + color: () => import('@cardstack/base/color'), + 'code-ref': () => import('@cardstack/base/code-ref'), + realm: () => import('@cardstack/base/realm'), + enum: () => import('@cardstack/base/enum'), + searchable: () => import('@cardstack/base/searchable'), + 'base64-image': () => import('@cardstack/base/base64-image'), }; export function shimExternals(virtualNetwork: VirtualNetwork) { From c35f3ac7708b340bb1d7efd05fc19079bcf8431c Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 11 Sep 2026 19:49:50 +0200 Subject: [PATCH 13/13] Register the bundled base modules from their own module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The boxel-cli parse workspace has to resolve declarations for every specifier the host shims for card code, and `card-runtime-packages` enforces that by reading literal shim ids out of externals.ts. A table whose ids are built by template literal is unreadable to it, so the guard failed rather than silently covering less than it claims. `@cardstack/base/*` is not a specifier that guard has to chase — parse resolves it through a tsconfig path alias onto bundled sources, which is recorded in its own list — so the registration moves to app/lib/bundled-base.ts, alongside the table, and the network service calls it after shimExternals. Co-Authored-By: Claude Opus 5 (1M context) --- packages/host/app/lib/bundled-base.ts | 60 +++++++++++++++++++ packages/host/app/lib/externals.ts | 50 ---------------- packages/host/app/services/network.ts | 2 + .../integration/bundled-base-modules-test.ts | 2 +- packages/host/vite.config.mjs | 4 +- 5 files changed, 65 insertions(+), 53 deletions(-) create mode 100644 packages/host/app/lib/bundled-base.ts diff --git a/packages/host/app/lib/bundled-base.ts b/packages/host/app/lib/bundled-base.ts new file mode 100644 index 00000000000..ea20432a6f5 --- /dev/null +++ b/packages/host/app/lib/bundled-base.ts @@ -0,0 +1,60 @@ +import type { VirtualNetwork } from '@cardstack/runtime-common'; + +// Base modules compiled into the host bundle, keyed by their path under +// `@cardstack/base/`. Each is served to the loader in place of a fetch of the +// module from the base realm; the literal `import()` per entry is what lets +// Vite give each module its own chunk. +// +// Registered from a table, as the host tools are, rather than as literal +// `shimAsyncModule` calls in externals.ts: the boxel-cli guard that reads +// literal shim ids out of that file covers `@cardstack/base/*` through its +// path alias already, so nothing is lost to it here. +export const BUNDLED_BASE_MODULES: Record< + string, + () => Promise> +> = { + 'date/day': () => import('@cardstack/base/date/day'), + 'date/month': () => import('@cardstack/base/date/month'), + 'date/month-day': () => import('@cardstack/base/date/month-day'), + 'date/month-year': () => import('@cardstack/base/date/month-year'), + 'date/year': () => import('@cardstack/base/date/year'), + 'date/week': () => import('@cardstack/base/date/week'), + 'date/quarter': () => import('@cardstack/base/date/quarter'), + time: () => import('@cardstack/base/time'), + 'time/time-range': () => import('@cardstack/base/time/time-range'), + 'time/duration': () => import('@cardstack/base/time/duration'), + 'time/relative-time': () => import('@cardstack/base/time/relative-time'), + // string.ts is `export default StringField` from card-api, so it is + // resolved there. Importing string.ts itself would have TypeScript classify + // that `.ts` module as CommonJS (this package declares no `type`) and + // retype its default export as a namespace for every host importer. + string: () => + import('@cardstack/base/card-api').then(({ StringField }) => ({ + default: StringField, + })), + number: () => import('@cardstack/base/number'), + boolean: () => import('@cardstack/base/boolean'), + 'big-integer': () => import('@cardstack/base/big-integer'), + email: () => import('@cardstack/base/email'), + 'ethereum-address': () => import('@cardstack/base/ethereum-address'), + 'phone-number': () => import('@cardstack/base/phone-number'), + 'text-area': () => import('@cardstack/base/text-area'), + markdown: () => import('@cardstack/base/markdown'), + 'rich-markdown': () => import('@cardstack/base/rich-markdown'), + color: () => import('@cardstack/base/color'), + 'code-ref': () => import('@cardstack/base/code-ref'), + realm: () => import('@cardstack/base/realm'), + enum: () => import('@cardstack/base/enum'), + searchable: () => import('@cardstack/base/searchable'), + 'base64-image': () => import('@cardstack/base/base64-image'), +}; + +// Registers on the virtual network, so every loader that shares it serves the +// bundled modules. Must run after the `@cardstack/base/` realm mapping is +// registered: a shim id resolves at registration time, and it has to land on +// the same realm URL a loader import of the id resolves to. +export function shimBundledBase(virtualNetwork: VirtualNetwork) { + for (let [name, resolve] of Object.entries(BUNDLED_BASE_MODULES)) { + virtualNetwork.shimAsyncModule({ id: `@cardstack/base/${name}`, resolve }); + } +} diff --git a/packages/host/app/lib/externals.ts b/packages/host/app/lib/externals.ts index 153d0789ca4..74c869f0d48 100644 --- a/packages/host/app/lib/externals.ts +++ b/packages/host/app/lib/externals.ts @@ -65,52 +65,6 @@ import { import { shimHostTools } from '../tools'; -// Base modules compiled into the host bundle, keyed by their path under -// `@cardstack/base/`. Each is served to the loader in place of a fetch of the -// module from the base realm; the literal `import()` per entry is what lets -// Vite give each module its own chunk. Registered after the `@cardstack/base/` -// realm mapping, so an entry's id resolves to the realm URL a loader import of -// it also resolves to. -export const BUNDLED_BASE_MODULES: Record< - string, - () => Promise> -> = { - 'date/day': () => import('@cardstack/base/date/day'), - 'date/month': () => import('@cardstack/base/date/month'), - 'date/month-day': () => import('@cardstack/base/date/month-day'), - 'date/month-year': () => import('@cardstack/base/date/month-year'), - 'date/year': () => import('@cardstack/base/date/year'), - 'date/week': () => import('@cardstack/base/date/week'), - 'date/quarter': () => import('@cardstack/base/date/quarter'), - time: () => import('@cardstack/base/time'), - 'time/time-range': () => import('@cardstack/base/time/time-range'), - 'time/duration': () => import('@cardstack/base/time/duration'), - 'time/relative-time': () => import('@cardstack/base/time/relative-time'), - // string.ts is `export default StringField` from card-api, so it is - // resolved there. Importing string.ts itself would have TypeScript classify - // that `.ts` module as CommonJS (this package declares no `type`) and - // retype its default export as a namespace for every host importer. - string: () => - import('@cardstack/base/card-api').then(({ StringField }) => ({ - default: StringField, - })), - number: () => import('@cardstack/base/number'), - boolean: () => import('@cardstack/base/boolean'), - 'big-integer': () => import('@cardstack/base/big-integer'), - email: () => import('@cardstack/base/email'), - 'ethereum-address': () => import('@cardstack/base/ethereum-address'), - 'phone-number': () => import('@cardstack/base/phone-number'), - 'text-area': () => import('@cardstack/base/text-area'), - markdown: () => import('@cardstack/base/markdown'), - 'rich-markdown': () => import('@cardstack/base/rich-markdown'), - color: () => import('@cardstack/base/color'), - 'code-ref': () => import('@cardstack/base/code-ref'), - realm: () => import('@cardstack/base/realm'), - enum: () => import('@cardstack/base/enum'), - searchable: () => import('@cardstack/base/searchable'), - 'base64-image': () => import('@cardstack/base/base64-image'), -}; - export function shimExternals(virtualNetwork: VirtualNetwork) { // Always shim qunit on the virtual network. In non-test environments (code // mode, card rendering), this no-op stub prevents realm cards that co-locate @@ -288,10 +242,6 @@ export function shimExternals(virtualNetwork: VirtualNetwork) { resolve: () => import('@cardstack/runtime-common/helpers/ai'), }); - for (let [name, resolve] of Object.entries(BUNDLED_BASE_MODULES)) { - virtualNetwork.shimAsyncModule({ id: `@cardstack/base/${name}`, resolve }); - } - shimModulesForLiveTests(virtualNetwork); // Some realm modules use host-only types or helpers. Provide a safe shim so diff --git a/packages/host/app/services/network.ts b/packages/host/app/services/network.ts index 377c411533b..eee31e3589d 100644 --- a/packages/host/app/services/network.ts +++ b/packages/host/app/services/network.ts @@ -13,6 +13,7 @@ import { import config from '@cardstack/host/config/environment'; +import { shimBundledBase } from '../lib/bundled-base'; import { shimExternals } from '../lib/externals'; import { authErrorEventMiddleware } from '../utils/auth-error-guard'; import { scheduleNativeTimeout } from '../utils/render-timer-stub'; @@ -97,6 +98,7 @@ export default class NetworkService extends Service { virtualNetwork.addRealmMapping(prefix, resolvedRealmURL.href); } shimExternals(virtualNetwork); + shimBundledBase(virtualNetwork); virtualNetwork.addImportMap('@cardstack/boxel-icons/', (rest) => { return `${config.iconsURL}/@cardstack/boxel-icons/v1/icons/${rest}.js`; }); diff --git a/packages/host/tests/integration/bundled-base-modules-test.ts b/packages/host/tests/integration/bundled-base-modules-test.ts index 7142e08333a..a9ed5d1509c 100644 --- a/packages/host/tests/integration/bundled-base-modules-test.ts +++ b/packages/host/tests/integration/bundled-base-modules-test.ts @@ -2,7 +2,7 @@ import { getService } from '@universal-ember/test-support'; import { module, test } from 'qunit'; -import { BUNDLED_BASE_MODULES } from '@cardstack/host/lib/externals'; +import { BUNDLED_BASE_MODULES } from '@cardstack/host/lib/bundled-base'; import { setupRenderingTest } from '../helpers/setup'; diff --git a/packages/host/vite.config.mjs b/packages/host/vite.config.mjs index 305e487c76c..6130a473bfa 100644 --- a/packages/host/vite.config.mjs +++ b/packages/host/vite.config.mjs @@ -298,8 +298,8 @@ export default defineConfig(({ mode }) => ({ }, resolve: { alias: [ - // Base-realm modules served from the host bundle (see shimExternals in - // app/lib/externals.ts) import host tools as + // Base-realm modules served from the host bundle (see shimBundledBase in + // app/lib/bundled-base.ts) import host tools as // `@cardstack/boxel-host/tools/*` or `@cardstack/boxel-host/commands/*`. // At runtime the virtual network shims those specifiers to app/tools // modules (see app/tools/index.ts); this alias gives the bundler the