From 828469c747dbe5984f52ce09e5a1d65ee0383187 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 28 Jan 2026 11:13:28 -0600 Subject: [PATCH 01/18] Change override to use permissions over user --- .../handlers/handle-publish-realm.ts | 77 ++++++++++--------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/packages/realm-server/handlers/handle-publish-realm.ts b/packages/realm-server/handlers/handle-publish-realm.ts index 7e452568ed..bd487fdfac 100644 --- a/packages/realm-server/handlers/handle-publish-realm.ts +++ b/packages/realm-server/handlers/handle-publish-realm.ts @@ -11,6 +11,7 @@ import { asExpressions, param, PUBLISHED_DIRECTORY_NAME, + type DBAdapter, type PublishedRealmTable, fetchRealmPermissions, uuidv4, @@ -34,37 +35,22 @@ import { passwordFromSeed } from '@cardstack/runtime-common/matrix-client'; const log = logger('handle-publish'); // Workaround to override published realm URLs to support custom domains. Remove in CS-9061. -const PUBLISHED_REALM_DOMAIN_OVERRIDES: Record< - string, - Record -> = { - '@buck:stack.cards': { - 'custombuck.staging.boxel.build': 'custombuck.stack.cards', - }, - '@ctse:stack.cards': { - 'docs.staging.boxel.build': 'docs.stack.cards', - 'home.staging.boxel.build': 'home.stack.cards', - 'whitepaper.staging.boxel.build': 'whitepaper.stack.cards', - }, - '@bucktest:boxel.ai': { - 'custombuck.boxel.site': 'custombuck.boxel.ai', - }, - '@official:boxel.ai': { - 'docs.boxel.site': 'docs.boxel.ai', - 'home.boxel.site': 'home.boxel.ai', - 'whitepaper.boxel.site': 'whitepaper.boxel.ai', - }, +const PUBLISHED_REALM_DOMAIN_OVERRIDES: Record = { + 'custombuck.staging.boxel.build': 'custombuck.stack.cards', + 'docs.staging.boxel.build': 'docs.stack.cards', + 'home.staging.boxel.build': 'home.stack.cards', + 'whitepaper.staging.boxel.build': 'whitepaper.stack.cards', + 'custombuck.boxel.site': 'custombuck.boxel.ai', + 'docs.boxel.site': 'docs.boxel.ai', + 'home.boxel.site': 'home.boxel.ai', + 'whitepaper.boxel.site': 'whitepaper.boxel.ai', }; -function maybeOverridePublishedRealmURL( +async function maybeOverridePublishedRealmURL( + dbAdapter: DBAdapter, ownerUserId: string, publishedRealmURL: string, -): string { - let userOverrides = PUBLISHED_REALM_DOMAIN_OVERRIDES[ownerUserId]; - if (!userOverrides) { - return publishedRealmURL; - } - +): Promise { let publishedURL: URL; try { publishedURL = new URL(publishedRealmURL); @@ -72,7 +58,8 @@ function maybeOverridePublishedRealmURL( return publishedRealmURL; } - let overrideDomain = userOverrides[publishedURL.host.toLowerCase()]; + let overrideDomain = + PUBLISHED_REALM_DOMAIN_OVERRIDES[publishedURL.host.toLowerCase()]; if (!overrideDomain) { return publishedRealmURL; } @@ -80,8 +67,21 @@ function maybeOverridePublishedRealmURL( let overriddenURL = new URL(publishedRealmURL); overriddenURL.host = overrideDomain; - let overriddenRealmURL = overriddenURL.toString(); - return ensureTrailingSlash(overriddenRealmURL); + let overriddenRealmURL = ensureTrailingSlash(overriddenURL.toString()); + let permissions = await fetchRealmPermissions( + dbAdapter, + new URL(overriddenRealmURL), + ); + let effectivePermissions = new Set([ + ...(permissions['*'] ?? []), + ...(permissions['users'] ?? []), + ...(permissions[ownerUserId] ?? []), + ]); + if (!effectivePermissions.has('write')) { + return publishedRealmURL; + } + + return overriddenRealmURL; } function rewriteHostHomeForPublishedRealm( @@ -175,11 +175,22 @@ export default function handlePublishRealm({ } let { user: ownerUserId, sessionRoom: tokenSessionRoom } = token; + let overriddenPublishedRealmURL = await maybeOverridePublishedRealmURL( + dbAdapter, + ownerUserId, + publishedRealmURL, + ); let permissions = await fetchRealmPermissions( dbAdapter, new URL(sourceRealmURL), ); - if (!permissions[ownerUserId]?.includes('realm-owner')) { + let hasOverrideWithWritePermission = + overriddenPublishedRealmURL !== publishedRealmURL; + if ( + !permissions[ownerUserId]?.includes('realm-owner') && + // TODO: Remove with CS-9061 once custom domain overrides are no longer needed. + !hasOverrideWithWritePermission + ) { await sendResponseForForbiddenRequest( ctxt, `${ownerUserId} does not have enough permission to publish this realm`, @@ -187,10 +198,6 @@ export default function handlePublishRealm({ return; } - let overriddenPublishedRealmURL = maybeOverridePublishedRealmURL( - ownerUserId, - publishedRealmURL, - ); if (overriddenPublishedRealmURL !== publishedRealmURL) { log.info( `Overriding publishedRealmURL for ${ownerUserId} from ${publishedRealmURL} to ${overriddenPublishedRealmURL}`, From d2e64bfa45fb8d495341f21885edf66d713e1cc1 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 28 Jan 2026 11:14:21 -0600 Subject: [PATCH 02/18] Add teal paper domain --- packages/realm-server/handlers/handle-publish-realm.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/realm-server/handlers/handle-publish-realm.ts b/packages/realm-server/handlers/handle-publish-realm.ts index bd487fdfac..3da763b353 100644 --- a/packages/realm-server/handlers/handle-publish-realm.ts +++ b/packages/realm-server/handlers/handle-publish-realm.ts @@ -36,13 +36,17 @@ const log = logger('handle-publish'); // Workaround to override published realm URLs to support custom domains. Remove in CS-9061. const PUBLISHED_REALM_DOMAIN_OVERRIDES: Record = { + // staging 'custombuck.staging.boxel.build': 'custombuck.stack.cards', 'docs.staging.boxel.build': 'docs.stack.cards', 'home.staging.boxel.build': 'home.stack.cards', 'whitepaper.staging.boxel.build': 'whitepaper.stack.cards', + + // production 'custombuck.boxel.site': 'custombuck.boxel.ai', 'docs.boxel.site': 'docs.boxel.ai', 'home.boxel.site': 'home.boxel.ai', + 'tealpaper.boxel.site': 'tealpaper.cardstack.com', 'whitepaper.boxel.site': 'whitepaper.boxel.ai', }; From d240409c8adb44ebd142a07d225c8d7a69327726 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 28 Jan 2026 12:26:05 -0600 Subject: [PATCH 03/18] Add UI for override --- .../operator-mode/publish-realm-modal.gts | 77 +++++++++++++++++++ .../handlers/handle-publish-realm.ts | 17 +--- packages/runtime-common/constants.ts | 16 ++++ 3 files changed, 94 insertions(+), 16 deletions(-) diff --git a/packages/host/app/components/operator-mode/publish-realm-modal.gts b/packages/host/app/components/operator-mode/publish-realm-modal.gts index c31f0b9723..922c5dda19 100644 --- a/packages/host/app/components/operator-mode/publish-realm-modal.gts +++ b/packages/host/app/components/operator-mode/publish-realm-modal.gts @@ -30,6 +30,9 @@ import WithLoadedRealm from '@cardstack/host/components/with-loaded-realm'; import config from '@cardstack/host/config/environment'; +import { ensureTrailingSlash } from '@cardstack/runtime-common'; +import { PUBLISHED_REALM_DOMAIN_OVERRIDES } from '@cardstack/runtime-common/constants'; + import type HostModeService from '@cardstack/host/services/host-mode-service'; import type MatrixService from '@cardstack/host/services/matrix-service'; import type RealmService from '@cardstack/host/services/realm'; @@ -221,6 +224,43 @@ export default class PublishRealmModal extends Component { return config.publishedRealmBoxelSiteDomain; } + // TODO: Remove with CS-9061 once published realm domain overrides are removed. + private getPublishedRealmOverrideUrl( + publishedRealmURL: string | null, + ): string | null { + if (!publishedRealmURL) { + return null; + } + + let publishedURL: URL; + try { + publishedURL = new URL(publishedRealmURL); + } catch { + return null; + } + + let overrideDomain = + PUBLISHED_REALM_DOMAIN_OVERRIDES[publishedURL.host.toLowerCase()]; + if (!overrideDomain) { + return null; + } + + let overriddenURL = new URL(publishedRealmURL); + overriddenURL.host = overrideDomain; + return ensureTrailingSlash(overriddenURL.toString()); + } + + get customSubdomainOverrideUrl() { + return this.getPublishedRealmOverrideUrl(this.claimedDomainPublishedUrl); + } + + get shouldShowCustomSubdomainOverride() { + return ( + !!this.customSubdomainOverrideUrl && + this.realm.canWrite(this.currentRealmURL) + ); + } + get customSubdomainDisplay() { if (this.claimedDomain) { return this.claimedDomain.subdomain; @@ -1027,6 +1067,19 @@ export default class PublishRealmModal extends Component { {{/if}} + + {{#if this.shouldShowCustomSubdomainOverride}} +
+
+ This site will publish to +
+
+ {{this.customSubdomainOverrideUrl}} +
+
+ {{/if}} @@ -1159,6 +1212,30 @@ export default class PublishRealmModal extends Component { border-bottom: 1px solid var(--boxel-200); } + .domain-override { + margin-left: calc(18px + var(--boxel-sp-sm)); + margin-top: calc(var(--boxel-sp-xs) * -1); + padding: var(--boxel-sp-sm); + border-radius: var(--boxel-border-radius-lg); + background-color: var(--boxel-50); + border: 1px dashed var(--boxel-200); + display: flex; + flex-direction: column; + gap: var(--boxel-sp-xxs); + } + + .domain-override-title { + font-size: var(--boxel-font-size-xs); + color: var(--boxel-450); + font-weight: 600; + } + + .domain-override-url { + font-size: var(--boxel-font-size-sm); + color: var(--boxel-dark); + word-break: break-word; + } + .cancel { grid-area: cancel; } diff --git a/packages/realm-server/handlers/handle-publish-realm.ts b/packages/realm-server/handlers/handle-publish-realm.ts index 3da763b353..75204fb640 100644 --- a/packages/realm-server/handlers/handle-publish-realm.ts +++ b/packages/realm-server/handlers/handle-publish-realm.ts @@ -11,6 +11,7 @@ import { asExpressions, param, PUBLISHED_DIRECTORY_NAME, + PUBLISHED_REALM_DOMAIN_OVERRIDES, type DBAdapter, type PublishedRealmTable, fetchRealmPermissions, @@ -34,22 +35,6 @@ import { passwordFromSeed } from '@cardstack/runtime-common/matrix-client'; const log = logger('handle-publish'); -// Workaround to override published realm URLs to support custom domains. Remove in CS-9061. -const PUBLISHED_REALM_DOMAIN_OVERRIDES: Record = { - // staging - 'custombuck.staging.boxel.build': 'custombuck.stack.cards', - 'docs.staging.boxel.build': 'docs.stack.cards', - 'home.staging.boxel.build': 'home.stack.cards', - 'whitepaper.staging.boxel.build': 'whitepaper.stack.cards', - - // production - 'custombuck.boxel.site': 'custombuck.boxel.ai', - 'docs.boxel.site': 'docs.boxel.ai', - 'home.boxel.site': 'home.boxel.ai', - 'tealpaper.boxel.site': 'tealpaper.cardstack.com', - 'whitepaper.boxel.site': 'whitepaper.boxel.ai', -}; - async function maybeOverridePublishedRealmURL( dbAdapter: DBAdapter, ownerUserId: string, diff --git a/packages/runtime-common/constants.ts b/packages/runtime-common/constants.ts index 680a64ba11..113ab4f44d 100644 --- a/packages/runtime-common/constants.ts +++ b/packages/runtime-common/constants.ts @@ -86,4 +86,20 @@ export const DEFAULT_PERMISSIONS = Object.freeze([ 'realm-owner', ]) as RealmPermissions['user']; +// Workaround to override published realm URLs to support custom domains. Remove in CS-9061. +export const PUBLISHED_REALM_DOMAIN_OVERRIDES: Record = { + // staging + 'custombuck.staging.boxel.build': 'custombuck.stack.cards', + 'docs.staging.boxel.build': 'docs.stack.cards', + 'home.staging.boxel.build': 'home.stack.cards', + 'whitepaper.staging.boxel.build': 'whitepaper.stack.cards', + + // production + 'custombuck.boxel.site': 'custombuck.boxel.ai', + 'docs.boxel.site': 'docs.boxel.ai', + 'home.boxel.site': 'home.boxel.ai', + 'tealpaper.boxel.site': 'tealpaper.cardstack.com', + 'whitepaper.boxel.site': 'whitepaper.boxel.ai', +}; + export const PUBLISHED_DIRECTORY_NAME = '_published'; From f2c65a2eaf6e2caf8c6f59feee783e7482bd7f32 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 28 Jan 2026 12:38:23 -0600 Subject: [PATCH 04/18] Fix import order --- .../app/components/operator-mode/publish-realm-modal.gts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/host/app/components/operator-mode/publish-realm-modal.gts b/packages/host/app/components/operator-mode/publish-realm-modal.gts index 922c5dda19..991e3a51d7 100644 --- a/packages/host/app/components/operator-mode/publish-realm-modal.gts +++ b/packages/host/app/components/operator-mode/publish-realm-modal.gts @@ -24,15 +24,15 @@ import { import { not } from '@cardstack/boxel-ui/helpers'; import { IconX, Warning as WarningIcon } from '@cardstack/boxel-ui/icons'; +import { ensureTrailingSlash } from '@cardstack/runtime-common'; +import { PUBLISHED_REALM_DOMAIN_OVERRIDES } from '@cardstack/runtime-common/constants'; + import ModalContainer from '@cardstack/host/components/modal-container'; import PrivateDependencyViolationComponent from '@cardstack/host/components/operator-mode/private-dependency-violation'; import WithLoadedRealm from '@cardstack/host/components/with-loaded-realm'; import config from '@cardstack/host/config/environment'; -import { ensureTrailingSlash } from '@cardstack/runtime-common'; -import { PUBLISHED_REALM_DOMAIN_OVERRIDES } from '@cardstack/runtime-common/constants'; - import type HostModeService from '@cardstack/host/services/host-mode-service'; import type MatrixService from '@cardstack/host/services/matrix-service'; import type RealmService from '@cardstack/host/services/realm'; From e30523e2b63c48e95a64127c5cd02abc82af5309 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 28 Jan 2026 13:11:50 -0600 Subject: [PATCH 05/18] Change mapping to use base realm URL --- .../operator-mode/publish-realm-modal.gts | 23 ++++++++++++------- .../handlers/handle-publish-realm.ts | 14 ++++++----- packages/runtime-common/constants.ts | 14 ++++------- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/packages/host/app/components/operator-mode/publish-realm-modal.gts b/packages/host/app/components/operator-mode/publish-realm-modal.gts index 991e3a51d7..085bcd8b4f 100644 --- a/packages/host/app/components/operator-mode/publish-realm-modal.gts +++ b/packages/host/app/components/operator-mode/publish-realm-modal.gts @@ -25,7 +25,9 @@ import { not } from '@cardstack/boxel-ui/helpers'; import { IconX, Warning as WarningIcon } from '@cardstack/boxel-ui/icons'; import { ensureTrailingSlash } from '@cardstack/runtime-common'; -import { PUBLISHED_REALM_DOMAIN_OVERRIDES } from '@cardstack/runtime-common/constants'; +import { + PUBLISHED_REALM_DOMAIN_OVERRIDES, +} from '@cardstack/runtime-common/constants'; import ModalContainer from '@cardstack/host/components/modal-container'; import PrivateDependencyViolationComponent from '@cardstack/host/components/operator-mode/private-dependency-violation'; @@ -228,6 +230,12 @@ export default class PublishRealmModal extends Component { private getPublishedRealmOverrideUrl( publishedRealmURL: string | null, ): string | null { + let overrideDomain = + PUBLISHED_REALM_DOMAIN_OVERRIDES[ensureTrailingSlash(this.currentRealmURL)]; + if (!overrideDomain) { + return null; + } + if (!publishedRealmURL) { return null; } @@ -239,19 +247,18 @@ export default class PublishRealmModal extends Component { return null; } - let overrideDomain = - PUBLISHED_REALM_DOMAIN_OVERRIDES[publishedURL.host.toLowerCase()]; - if (!overrideDomain) { - return null; - } - let overriddenURL = new URL(publishedRealmURL); overriddenURL.host = overrideDomain; return ensureTrailingSlash(overriddenURL.toString()); } get customSubdomainOverrideUrl() { - return this.getPublishedRealmOverrideUrl(this.claimedDomainPublishedUrl); + let publishedRealmURL = + this.claimedDomainPublishedUrl ?? + this.buildPublishedRealmUrl( + `${this.customSubdomainDisplay}.${this.customSubdomainBase}`, + ); + return this.getPublishedRealmOverrideUrl(publishedRealmURL); } get shouldShowCustomSubdomainOverride() { diff --git a/packages/realm-server/handlers/handle-publish-realm.ts b/packages/realm-server/handlers/handle-publish-realm.ts index 75204fb640..110cfe0292 100644 --- a/packages/realm-server/handlers/handle-publish-realm.ts +++ b/packages/realm-server/handlers/handle-publish-realm.ts @@ -38,8 +38,15 @@ const log = logger('handle-publish'); async function maybeOverridePublishedRealmURL( dbAdapter: DBAdapter, ownerUserId: string, + sourceRealmURL: string, publishedRealmURL: string, ): Promise { + let overrideDomain = + PUBLISHED_REALM_DOMAIN_OVERRIDES[ensureTrailingSlash(sourceRealmURL)]; + if (!overrideDomain) { + return publishedRealmURL; + } + let publishedURL: URL; try { publishedURL = new URL(publishedRealmURL); @@ -47,12 +54,6 @@ async function maybeOverridePublishedRealmURL( return publishedRealmURL; } - let overrideDomain = - PUBLISHED_REALM_DOMAIN_OVERRIDES[publishedURL.host.toLowerCase()]; - if (!overrideDomain) { - return publishedRealmURL; - } - let overriddenURL = new URL(publishedRealmURL); overriddenURL.host = overrideDomain; @@ -167,6 +168,7 @@ export default function handlePublishRealm({ let overriddenPublishedRealmURL = await maybeOverridePublishedRealmURL( dbAdapter, ownerUserId, + sourceRealmURL, publishedRealmURL, ); let permissions = await fetchRealmPermissions( diff --git a/packages/runtime-common/constants.ts b/packages/runtime-common/constants.ts index 113ab4f44d..b3bb34dbf9 100644 --- a/packages/runtime-common/constants.ts +++ b/packages/runtime-common/constants.ts @@ -89,17 +89,13 @@ export const DEFAULT_PERMISSIONS = Object.freeze([ // Workaround to override published realm URLs to support custom domains. Remove in CS-9061. export const PUBLISHED_REALM_DOMAIN_OVERRIDES: Record = { // staging - 'custombuck.staging.boxel.build': 'custombuck.stack.cards', - 'docs.staging.boxel.build': 'docs.stack.cards', - 'home.staging.boxel.build': 'home.stack.cards', - 'whitepaper.staging.boxel.build': 'whitepaper.stack.cards', + 'https://realms-staging.stack.cards/buck/load-testing/': + 'custombuck.stack.cards', // production - 'custombuck.boxel.site': 'custombuck.boxel.ai', - 'docs.boxel.site': 'docs.boxel.ai', - 'home.boxel.site': 'home.boxel.ai', - 'tealpaper.boxel.site': 'tealpaper.cardstack.com', - 'whitepaper.boxel.site': 'whitepaper.boxel.ai', + 'https://app.boxel.ai/bucktest/20251216/': 'custombuck.boxel.ai', + 'https://app.boxel.ai/official/cardstack-reward/': 'tealpaper.cardstack.com', + 'https://app.boxel.ai/official/boxel-whitepaper/': 'whitepaper.boxel.ai', }; export const PUBLISHED_DIRECTORY_NAME = '_published'; From 9e9655e651d8f21bb99a242f4ba96cb02dcf1bd6 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 28 Jan 2026 13:40:43 -0600 Subject: [PATCH 06/18] Fix lint errors --- .../operator-mode/publish-realm-modal.gts | 15 ++++----------- .../realm-server/handlers/handle-publish-realm.ts | 7 ------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/packages/host/app/components/operator-mode/publish-realm-modal.gts b/packages/host/app/components/operator-mode/publish-realm-modal.gts index 085bcd8b4f..5a891cdae3 100644 --- a/packages/host/app/components/operator-mode/publish-realm-modal.gts +++ b/packages/host/app/components/operator-mode/publish-realm-modal.gts @@ -25,9 +25,7 @@ import { not } from '@cardstack/boxel-ui/helpers'; import { IconX, Warning as WarningIcon } from '@cardstack/boxel-ui/icons'; import { ensureTrailingSlash } from '@cardstack/runtime-common'; -import { - PUBLISHED_REALM_DOMAIN_OVERRIDES, -} from '@cardstack/runtime-common/constants'; +import { PUBLISHED_REALM_DOMAIN_OVERRIDES } from '@cardstack/runtime-common/constants'; import ModalContainer from '@cardstack/host/components/modal-container'; import PrivateDependencyViolationComponent from '@cardstack/host/components/operator-mode/private-dependency-violation'; @@ -231,7 +229,9 @@ export default class PublishRealmModal extends Component { publishedRealmURL: string | null, ): string | null { let overrideDomain = - PUBLISHED_REALM_DOMAIN_OVERRIDES[ensureTrailingSlash(this.currentRealmURL)]; + PUBLISHED_REALM_DOMAIN_OVERRIDES[ + ensureTrailingSlash(this.currentRealmURL) + ]; if (!overrideDomain) { return null; } @@ -240,13 +240,6 @@ export default class PublishRealmModal extends Component { return null; } - let publishedURL: URL; - try { - publishedURL = new URL(publishedRealmURL); - } catch { - return null; - } - let overriddenURL = new URL(publishedRealmURL); overriddenURL.host = overrideDomain; return ensureTrailingSlash(overriddenURL.toString()); diff --git a/packages/realm-server/handlers/handle-publish-realm.ts b/packages/realm-server/handlers/handle-publish-realm.ts index 110cfe0292..79edd30a8b 100644 --- a/packages/realm-server/handlers/handle-publish-realm.ts +++ b/packages/realm-server/handlers/handle-publish-realm.ts @@ -47,13 +47,6 @@ async function maybeOverridePublishedRealmURL( return publishedRealmURL; } - let publishedURL: URL; - try { - publishedURL = new URL(publishedRealmURL); - } catch { - return publishedRealmURL; - } - let overriddenURL = new URL(publishedRealmURL); overriddenURL.host = overrideDomain; From 10d883587e352cf5a026b12259dfd0a4ad2a69e0 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 28 Jan 2026 13:52:30 -0600 Subject: [PATCH 07/18] Add environment variable for more overrides --- .../operator-mode/publish-realm-modal.gts | 4 +-- .../handlers/handle-publish-realm.ts | 6 +++- packages/realm-server/server.ts | 3 ++ packages/runtime-common/constants.ts | 36 +++++++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/packages/host/app/components/operator-mode/publish-realm-modal.gts b/packages/host/app/components/operator-mode/publish-realm-modal.gts index 5a891cdae3..a75632fc90 100644 --- a/packages/host/app/components/operator-mode/publish-realm-modal.gts +++ b/packages/host/app/components/operator-mode/publish-realm-modal.gts @@ -25,7 +25,7 @@ import { not } from '@cardstack/boxel-ui/helpers'; import { IconX, Warning as WarningIcon } from '@cardstack/boxel-ui/icons'; import { ensureTrailingSlash } from '@cardstack/runtime-common'; -import { PUBLISHED_REALM_DOMAIN_OVERRIDES } from '@cardstack/runtime-common/constants'; +import { getPublishedRealmDomainOverrides } from '@cardstack/runtime-common/constants'; import ModalContainer from '@cardstack/host/components/modal-container'; import PrivateDependencyViolationComponent from '@cardstack/host/components/operator-mode/private-dependency-violation'; @@ -229,7 +229,7 @@ export default class PublishRealmModal extends Component { publishedRealmURL: string | null, ): string | null { let overrideDomain = - PUBLISHED_REALM_DOMAIN_OVERRIDES[ + getPublishedRealmDomainOverrides(config.publishedRealmDomainOverrides)[ ensureTrailingSlash(this.currentRealmURL) ]; if (!overrideDomain) { diff --git a/packages/realm-server/handlers/handle-publish-realm.ts b/packages/realm-server/handlers/handle-publish-realm.ts index 79edd30a8b..3200691ae6 100644 --- a/packages/realm-server/handlers/handle-publish-realm.ts +++ b/packages/realm-server/handlers/handle-publish-realm.ts @@ -11,12 +11,12 @@ import { asExpressions, param, PUBLISHED_DIRECTORY_NAME, - PUBLISHED_REALM_DOMAIN_OVERRIDES, type DBAdapter, type PublishedRealmTable, fetchRealmPermissions, uuidv4, } from '@cardstack/runtime-common'; +import { getPublishedRealmDomainOverrides } from '@cardstack/runtime-common/constants'; import { ensureDirSync, copySync, readJsonSync, writeJsonSync } from 'fs-extra'; import { resolve, join } from 'path'; import { @@ -35,6 +35,10 @@ import { passwordFromSeed } from '@cardstack/runtime-common/matrix-client'; const log = logger('handle-publish'); +const PUBLISHED_REALM_DOMAIN_OVERRIDES = getPublishedRealmDomainOverrides( + process.env.PUBLISHED_REALM_DOMAIN_OVERRIDES, +); + async function maybeOverridePublishedRealmURL( dbAdapter: DBAdapter, ownerUserId: string, diff --git a/packages/realm-server/server.ts b/packages/realm-server/server.ts index be917d2bf5..7838c1840c 100644 --- a/packages/realm-server/server.ts +++ b/packages/realm-server/server.ts @@ -466,6 +466,9 @@ export class RealmServer { assetsURL: this.assetsURL.href, realmServerURL: this.serverURL.href, cardSizeLimitBytes: this.cardSizeLimitBytes, + publishedRealmDomainOverrides: + process.env.PUBLISHED_REALM_DOMAIN_OVERRIDES ?? + config.publishedRealmDomainOverrides, }); return `${g1}${encodeURIComponent(JSON.stringify(config))}${g3}`; }, diff --git a/packages/runtime-common/constants.ts b/packages/runtime-common/constants.ts index b3bb34dbf9..97e1fff9ba 100644 --- a/packages/runtime-common/constants.ts +++ b/packages/runtime-common/constants.ts @@ -98,4 +98,40 @@ export const PUBLISHED_REALM_DOMAIN_OVERRIDES: Record = { 'https://app.boxel.ai/official/boxel-whitepaper/': 'whitepaper.boxel.ai', }; +export function parsePublishedRealmDomainOverrides( + rawOverrides: string | undefined, +): Record { + if (!rawOverrides) { + return {}; + } + + try { + let parsed = JSON.parse(rawOverrides); + if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { + return {}; + } + + return Object.fromEntries( + Object.entries(parsed).filter( + ([key, value]) => typeof key === 'string' && typeof value === 'string', + ), + ); + } catch { + return {}; + } +} + +export function getPublishedRealmDomainOverrides( + rawOverrides?: string | Record, +): Record { + let envOverrides = + typeof rawOverrides === 'string' + ? parsePublishedRealmDomainOverrides(rawOverrides) + : rawOverrides ?? {}; + return { + ...PUBLISHED_REALM_DOMAIN_OVERRIDES, + ...envOverrides, + }; +} + export const PUBLISHED_DIRECTORY_NAME = '_published'; From 9696704f34b9b29d27ea910d4de4eb110f40549f Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 28 Jan 2026 14:33:57 -0600 Subject: [PATCH 08/18] Add variable to host config --- packages/host/app/config/environment.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/host/app/config/environment.d.ts b/packages/host/app/config/environment.d.ts index a9b3d0a34e..62fe4f1d45 100644 --- a/packages/host/app/config/environment.d.ts +++ b/packages/host/app/config/environment.d.ts @@ -38,6 +38,7 @@ declare const config: { }; publishedRealmBoxelSpaceDomain: string; publishedRealmBoxelSiteDomain: string; + publishedRealmDomainOverrides: string; defaultSystemCardId: string; cardSizeLimitBytes: number; }; From 43c21de39844be7db16035eeb8b10dcc5196d456 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 28 Jan 2026 14:34:57 -0600 Subject: [PATCH 09/18] Fix types in parsing --- packages/runtime-common/constants.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/runtime-common/constants.ts b/packages/runtime-common/constants.ts index 97e1fff9ba..448f685222 100644 --- a/packages/runtime-common/constants.ts +++ b/packages/runtime-common/constants.ts @@ -111,11 +111,13 @@ export function parsePublishedRealmDomainOverrides( return {}; } - return Object.fromEntries( - Object.entries(parsed).filter( - ([key, value]) => typeof key === 'string' && typeof value === 'string', - ), - ); + let overrides: Record = {}; + for (let [key, value] of Object.entries(parsed)) { + if (typeof key === 'string' && typeof value === 'string') { + overrides[key] = value; + } + } + return overrides; } catch { return {}; } From 1fa17f1869470cf584ec6e3c6be285377df8db49 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 28 Jan 2026 14:47:20 -0600 Subject: [PATCH 10/18] Extract handling into contained helper --- .../handlers/handle-publish-realm.ts | 125 ++++++++++-------- 1 file changed, 68 insertions(+), 57 deletions(-) diff --git a/packages/realm-server/handlers/handle-publish-realm.ts b/packages/realm-server/handlers/handle-publish-realm.ts index 3200691ae6..85c6ccdc52 100644 --- a/packages/realm-server/handlers/handle-publish-realm.ts +++ b/packages/realm-server/handlers/handle-publish-realm.ts @@ -1,6 +1,5 @@ import type Koa from 'koa'; import { - ensureTrailingSlash, fetchUserPermissions, query, SupportedMimeType, @@ -11,6 +10,7 @@ import { asExpressions, param, PUBLISHED_DIRECTORY_NAME, + ensureTrailingSlash, type DBAdapter, type PublishedRealmTable, fetchRealmPermissions, @@ -39,25 +39,30 @@ const PUBLISHED_REALM_DOMAIN_OVERRIDES = getPublishedRealmDomainOverrides( process.env.PUBLISHED_REALM_DOMAIN_OVERRIDES, ); -async function maybeOverridePublishedRealmURL( +async function maybeApplyPublishedRealmOverride( dbAdapter: DBAdapter, ownerUserId: string, sourceRealmURL: string, publishedRealmURL: string, -): Promise { - let overrideDomain = - PUBLISHED_REALM_DOMAIN_OVERRIDES[ensureTrailingSlash(sourceRealmURL)]; +): Promise<{ applied: boolean; publishedRealmURL: string }> { + let overrideDomain = PUBLISHED_REALM_DOMAIN_OVERRIDES[sourceRealmURL]; if (!overrideDomain) { - return publishedRealmURL; + return { applied: false, publishedRealmURL }; } - let overriddenURL = new URL(publishedRealmURL); - overriddenURL.host = overrideDomain; + let publishedURL: URL; + try { + publishedURL = new URL(publishedRealmURL); + } catch { + return { applied: false, publishedRealmURL }; + } + if (publishedURL.host.toLowerCase() !== overrideDomain.toLowerCase()) { + return { applied: false, publishedRealmURL }; + } - let overriddenRealmURL = ensureTrailingSlash(overriddenURL.toString()); let permissions = await fetchRealmPermissions( dbAdapter, - new URL(overriddenRealmURL), + new URL(sourceRealmURL), ); let effectivePermissions = new Set([ ...(permissions['*'] ?? []), @@ -65,10 +70,15 @@ async function maybeOverridePublishedRealmURL( ...(permissions[ownerUserId] ?? []), ]); if (!effectivePermissions.has('write')) { - return publishedRealmURL; + return { applied: false, publishedRealmURL }; } - return overriddenRealmURL; + let overriddenURL = new URL(publishedRealmURL); + overriddenURL.host = overrideDomain; + return { + applied: true, + publishedRealmURL: ensureTrailingSlash(overriddenURL.toString()), + }; } function rewriteHostHomeForPublishedRealm( @@ -136,61 +146,62 @@ export default function handlePublishRealm({ ? json.publishedRealmURL : `${json.publishedRealmURL}/`; - let validPublishedRealmDomains = Object.values( - domainsForPublishedRealms || {}, - ); - try { - let publishedURL = new URL(publishedRealmURL); - if (validPublishedRealmDomains && validPublishedRealmDomains.length > 0) { - let isValidDomain = validPublishedRealmDomains.some((domain) => - publishedURL.host.endsWith(domain), - ); - if (!isValidDomain) { - await sendResponseForBadRequest( - ctxt, - `publishedRealmURL must use a valid domain ending with one of: ${validPublishedRealmDomains.join(', ')}`, - ); - return; - } - } - } catch (e) { - await sendResponseForBadRequest( - ctxt, - 'publishedRealmURL is not a valid URL', - ); - return; - } - let { user: ownerUserId, sessionRoom: tokenSessionRoom } = token; - let overriddenPublishedRealmURL = await maybeOverridePublishedRealmURL( + + let overrideResult = await maybeApplyPublishedRealmOverride( dbAdapter, ownerUserId, sourceRealmURL, publishedRealmURL, ); - let permissions = await fetchRealmPermissions( - dbAdapter, - new URL(sourceRealmURL), - ); - let hasOverrideWithWritePermission = - overriddenPublishedRealmURL !== publishedRealmURL; - if ( - !permissions[ownerUserId]?.includes('realm-owner') && - // TODO: Remove with CS-9061 once custom domain overrides are no longer needed. - !hasOverrideWithWritePermission - ) { - await sendResponseForForbiddenRequest( - ctxt, - `${ownerUserId} does not have enough permission to publish this realm`, + + if (overrideResult.applied) { + log.info( + `Overriding publishedRealmURL for ${ownerUserId} from ${publishedRealmURL} to ${overrideResult.publishedRealmURL}`, ); - return; + publishedRealmURL = overrideResult.publishedRealmURL; } - if (overriddenPublishedRealmURL !== publishedRealmURL) { - log.info( - `Overriding publishedRealmURL for ${ownerUserId} from ${publishedRealmURL} to ${overriddenPublishedRealmURL}`, + if (!overrideResult.applied) { + let validPublishedRealmDomains = Object.values( + domainsForPublishedRealms || {}, + ); + try { + let publishedURL = new URL(publishedRealmURL); + if ( + validPublishedRealmDomains && + validPublishedRealmDomains.length > 0 + ) { + let isValidDomain = validPublishedRealmDomains.some((domain) => + publishedURL.host.endsWith(domain), + ); + if (!isValidDomain) { + await sendResponseForBadRequest( + ctxt, + `publishedRealmURL must use a valid domain ending with one of: ${validPublishedRealmDomains.join(', ')}`, + ); + return; + } + } + } catch (e) { + await sendResponseForBadRequest( + ctxt, + 'publishedRealmURL is not a valid URL', + ); + return; + } + + let permissions = await fetchRealmPermissions( + dbAdapter, + new URL(sourceRealmURL), ); - publishedRealmURL = overriddenPublishedRealmURL; + if (!permissions[ownerUserId]?.includes('realm-owner')) { + await sendResponseForForbiddenRequest( + ctxt, + `${ownerUserId} does not have enough permission to publish this realm`, + ); + return; + } } try { From 54da3b08b2f4a9ab2fee36264f09670582e83076 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 28 Jan 2026 15:07:21 -0600 Subject: [PATCH 11/18] Fix lint error --- packages/runtime-common/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-common/constants.ts b/packages/runtime-common/constants.ts index 448f685222..5f6c27b410 100644 --- a/packages/runtime-common/constants.ts +++ b/packages/runtime-common/constants.ts @@ -129,7 +129,7 @@ export function getPublishedRealmDomainOverrides( let envOverrides = typeof rawOverrides === 'string' ? parsePublishedRealmDomainOverrides(rawOverrides) - : rawOverrides ?? {}; + : (rawOverrides ?? {}); return { ...PUBLISHED_REALM_DOMAIN_OVERRIDES, ...envOverrides, From f49235ebc1d6aa53913bbbaf144ba85f8a8571df Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 28 Jan 2026 15:45:07 -0600 Subject: [PATCH 12/18] Update colours of override warning --- .../app/components/operator-mode/publish-realm-modal.gts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/host/app/components/operator-mode/publish-realm-modal.gts b/packages/host/app/components/operator-mode/publish-realm-modal.gts index a75632fc90..90eb7d2fd0 100644 --- a/packages/host/app/components/operator-mode/publish-realm-modal.gts +++ b/packages/host/app/components/operator-mode/publish-realm-modal.gts @@ -1217,7 +1217,9 @@ export default class PublishRealmModal extends Component { margin-top: calc(var(--boxel-sp-xs) * -1); padding: var(--boxel-sp-sm); border-radius: var(--boxel-border-radius-lg); - background-color: var(--boxel-50); + border: 1px solid var(--boxel-error-200); + background-color: rgb(from var(--boxel-error-200) r g b / 8%); + color: var(--boxel-error-200); border: 1px dashed var(--boxel-200); display: flex; flex-direction: column; @@ -1226,13 +1228,11 @@ export default class PublishRealmModal extends Component { .domain-override-title { font-size: var(--boxel-font-size-xs); - color: var(--boxel-450); font-weight: 600; } .domain-override-url { font-size: var(--boxel-font-size-sm); - color: var(--boxel-dark); word-break: break-word; } From 4be20c6cc313f6f69e5b817d131cdf8698370004 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 28 Jan 2026 15:45:17 -0600 Subject: [PATCH 13/18] Add lint autofix ugh what is happening --- .../app/components/operator-mode/publish-realm-modal.gts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/host/app/components/operator-mode/publish-realm-modal.gts b/packages/host/app/components/operator-mode/publish-realm-modal.gts index 90eb7d2fd0..c612dd7764 100644 --- a/packages/host/app/components/operator-mode/publish-realm-modal.gts +++ b/packages/host/app/components/operator-mode/publish-realm-modal.gts @@ -228,10 +228,9 @@ export default class PublishRealmModal extends Component { private getPublishedRealmOverrideUrl( publishedRealmURL: string | null, ): string | null { - let overrideDomain = - getPublishedRealmDomainOverrides(config.publishedRealmDomainOverrides)[ - ensureTrailingSlash(this.currentRealmURL) - ]; + let overrideDomain = getPublishedRealmDomainOverrides( + config.publishedRealmDomainOverrides, + )[ensureTrailingSlash(this.currentRealmURL)]; if (!overrideDomain) { return null; } From fab1e034c7603f48bc86b023f16ceecbe0c25759 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 29 Jan 2026 13:10:57 -0600 Subject: [PATCH 14/18] Update handling on both sides --- .../operator-mode/publish-realm-modal.gts | 166 ++++++++++++++---- .../handlers/handle-publish-realm.ts | 36 +++- 2 files changed, 168 insertions(+), 34 deletions(-) diff --git a/packages/host/app/components/operator-mode/publish-realm-modal.gts b/packages/host/app/components/operator-mode/publish-realm-modal.gts index c612dd7764..01e22f3003 100644 --- a/packages/host/app/components/operator-mode/publish-realm-modal.gts +++ b/packages/host/app/components/operator-mode/publish-realm-modal.gts @@ -260,6 +260,29 @@ export default class PublishRealmModal extends Component { ); } + get isCustomSubdomainOverrideSelected() { + if (!this.customSubdomainOverrideUrl) { + return false; + } + return this.selectedPublishedRealmURLs.includes( + this.customSubdomainOverrideUrl, + ); + } + + get isCustomSubdomainOverridePublished() { + if (!this.customSubdomainOverrideUrl) { + return false; + } + return this.hostModeService.isPublished(this.customSubdomainOverrideUrl); + } + + get customSubdomainOverrideLastPublishedTime() { + if (!this.customSubdomainOverrideUrl) { + return null; + } + return this.getFormattedLastPublishedTime(this.customSubdomainOverrideUrl); + } + get customSubdomainDisplay() { if (this.claimedDomain) { return this.claimedDomain.subdomain; @@ -497,6 +520,20 @@ export default class PublishRealmModal extends Component { } } + @action + toggleCustomSubdomainOverride(event: Event) { + const overrideUrl = this.customSubdomainOverrideUrl; + if (!overrideUrl) { + return; + } + const input = event.target as HTMLInputElement; + if (input.checked) { + this.addPublishedRealmUrl(overrideUrl); + } else { + this.removePublishedRealmUrl(overrideUrl); + } + } + private addPublishedRealmUrl(url: string) { if (!this.selectedPublishedRealmURLs.includes(url)) { this.selectedPublishedRealmURLs = [ @@ -658,6 +695,13 @@ export default class PublishRealmModal extends Component { return this.getPublishErrorForUrl(this.claimedDomainPublishedUrl); } + get publishErrorForCustomSubdomainOverride() { + if (!this.customSubdomainOverrideUrl) { + return null; + } + return this.getPublishErrorForUrl(this.customSubdomainOverrideUrl); + } + ensureInitialSelectionsTask = restartableTask( async (claim: ClaimedDomain | null = null) => { await this.realm.ensureRealmMeta(this.currentRealmURL); @@ -1068,15 +1112,97 @@ export default class PublishRealmModal extends Component { {{#if this.shouldShowCustomSubdomainOverride}} -
-
- This site will publish to -
-
- {{this.customSubdomainOverrideUrl}} +
+ + +
+ + + +
+ {{this.customSubdomainOverrideUrl}} + {{#if this.isCustomSubdomainOverridePublished}} +
+ {{#if this.customSubdomainOverrideLastPublishedTime}} + Published + {{this.customSubdomainOverrideLastPublishedTime}} + {{/if}} + + {{#if + (this.isUnpublishingRealm + this.customSubdomainOverrideUrl + ) + }} + + Unpublishing… + {{else}} + + Unpublish + {{/if}} + +
+ {{else}} + Not published yet + {{/if}} +
+ {{#if this.isCustomSubdomainOverridePublished}} + + + Open Site + + {{/if}} + {{#if this.publishErrorForCustomSubdomainOverride}} +
+ {{this.publishErrorForCustomSubdomainOverride}} +
+ {{/if}}
{{/if}}
@@ -1211,30 +1337,6 @@ export default class PublishRealmModal extends Component { border-bottom: 1px solid var(--boxel-200); } - .domain-override { - margin-left: calc(18px + var(--boxel-sp-sm)); - margin-top: calc(var(--boxel-sp-xs) * -1); - padding: var(--boxel-sp-sm); - border-radius: var(--boxel-border-radius-lg); - border: 1px solid var(--boxel-error-200); - background-color: rgb(from var(--boxel-error-200) r g b / 8%); - color: var(--boxel-error-200); - border: 1px dashed var(--boxel-200); - display: flex; - flex-direction: column; - gap: var(--boxel-sp-xxs); - } - - .domain-override-title { - font-size: var(--boxel-font-size-xs); - font-weight: 600; - } - - .domain-override-url { - font-size: var(--boxel-font-size-sm); - word-break: break-word; - } - .cancel { grid-area: cancel; } diff --git a/packages/realm-server/handlers/handle-publish-realm.ts b/packages/realm-server/handlers/handle-publish-realm.ts index 85c6ccdc52..f7467c5852 100644 --- a/packages/realm-server/handlers/handle-publish-realm.ts +++ b/packages/realm-server/handlers/handle-publish-realm.ts @@ -39,6 +39,27 @@ const PUBLISHED_REALM_DOMAIN_OVERRIDES = getPublishedRealmDomainOverrides( process.env.PUBLISHED_REALM_DOMAIN_OVERRIDES, ); +type OverrideHost = { + host: string; + hostname: string; + port: string; +}; + +function parseOverrideHost(rawOverride: string): OverrideHost | null { + try { + let overrideURL = rawOverride.includes('://') + ? new URL(rawOverride) + : new URL(`https://${rawOverride}`); + return { + host: overrideURL.host.toLowerCase(), + hostname: overrideURL.hostname.toLowerCase(), + port: overrideURL.port, + }; + } catch { + return null; + } +} + async function maybeApplyPublishedRealmOverride( dbAdapter: DBAdapter, ownerUserId: string, @@ -50,13 +71,24 @@ async function maybeApplyPublishedRealmOverride( return { applied: false, publishedRealmURL }; } + let overrideHost = parseOverrideHost(overrideDomain); + if (!overrideHost) { + return { applied: false, publishedRealmURL }; + } + let publishedURL: URL; try { publishedURL = new URL(publishedRealmURL); } catch { return { applied: false, publishedRealmURL }; } - if (publishedURL.host.toLowerCase() !== overrideDomain.toLowerCase()) { + + let publishedHost = publishedURL.host.toLowerCase(); + let publishedHostname = publishedURL.hostname.toLowerCase(); + let matchesOverride = overrideHost.port + ? publishedHost === overrideHost.host + : publishedHostname === overrideHost.hostname; + if (!matchesOverride) { return { applied: false, publishedRealmURL }; } @@ -74,7 +106,7 @@ async function maybeApplyPublishedRealmOverride( } let overriddenURL = new URL(publishedRealmURL); - overriddenURL.host = overrideDomain; + overriddenURL.host = overrideHost.host; return { applied: true, publishedRealmURL: ensureTrailingSlash(overriddenURL.toString()), From b18f115ee0b94c1c9561525a9aba3a9775953627 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 29 Jan 2026 14:03:57 -0600 Subject: [PATCH 15/18] Add formatting autofix --- .../host/app/components/operator-mode/publish-realm-modal.gts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/host/app/components/operator-mode/publish-realm-modal.gts b/packages/host/app/components/operator-mode/publish-realm-modal.gts index 01e22f3003..56cc04b5e9 100644 --- a/packages/host/app/components/operator-mode/publish-realm-modal.gts +++ b/packages/host/app/components/operator-mode/publish-realm-modal.gts @@ -1149,9 +1149,7 @@ export default class PublishRealmModal extends Component { class='unpublish-button' {{on 'click' - (fn - @handleUnpublish this.customSubdomainOverrideUrl - ) + (fn @handleUnpublish this.customSubdomainOverrideUrl) }} data-test-unpublish-custom-subdomain-override-button > From b41e9b9e1ad5ec70bd02da191876f3250ade3021 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 29 Jan 2026 14:12:33 -0600 Subject: [PATCH 16/18] Fix type error --- .../operator-mode/publish-realm-modal.gts | 163 +++++++++--------- 1 file changed, 78 insertions(+), 85 deletions(-) diff --git a/packages/host/app/components/operator-mode/publish-realm-modal.gts b/packages/host/app/components/operator-mode/publish-realm-modal.gts index 56cc04b5e9..5ad4c45217 100644 --- a/packages/host/app/components/operator-mode/publish-realm-modal.gts +++ b/packages/host/app/components/operator-mode/publish-realm-modal.gts @@ -1112,96 +1112,89 @@ export default class PublishRealmModal extends Component {
{{#if this.shouldShowCustomSubdomainOverride}} -
- - -
- - - -
- {{this.customSubdomainOverrideUrl}} - {{#if this.isCustomSubdomainOverridePublished}} -
- {{#if this.customSubdomainOverrideLastPublishedTime}} - Published - {{this.customSubdomainOverrideLastPublishedTime}} + {{#let this.customSubdomainOverrideUrl as |overrideUrl|}} + {{#if overrideUrl}} +
+ + +
+ + + +
+ {{overrideUrl}} + {{#if this.isCustomSubdomainOverridePublished}} +
+ {{#if this.customSubdomainOverrideLastPublishedTime}} + Published + {{this.customSubdomainOverrideLastPublishedTime}} + {{/if}} + + {{#if (this.isUnpublishingRealm overrideUrl)}} + + Unpublishing… + {{else}} + + Unpublish + {{/if}} + +
+ {{else}} + Not published yet {{/if}} - - {{#if - (this.isUnpublishingRealm - this.customSubdomainOverrideUrl - ) - }} - - Unpublishing… - {{else}} - - Unpublish - {{/if}} -
- {{else}} - Not published yet +
+ {{#if this.isCustomSubdomainOverridePublished}} + + + Open Site + + {{/if}} + {{#if this.publishErrorForCustomSubdomainOverride}} +
+ {{this.publishErrorForCustomSubdomainOverride}} +
{{/if}} -
-
- {{#if this.isCustomSubdomainOverridePublished}} - - - Open Site - - {{/if}} - {{#if this.publishErrorForCustomSubdomainOverride}} -
- {{this.publishErrorForCustomSubdomainOverride}}
{{/if}} -
+ {{/let}} {{/if}}
From 13975e58aeb6b382360639d4e2cea2b599c76217 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 29 Jan 2026 14:23:02 -0600 Subject: [PATCH 17/18] Add formatting autofixes --- .../components/operator-mode/publish-realm-modal.gts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/host/app/components/operator-mode/publish-realm-modal.gts b/packages/host/app/components/operator-mode/publish-realm-modal.gts index 5ad4c45217..4631cfa141 100644 --- a/packages/host/app/components/operator-mode/publish-realm-modal.gts +++ b/packages/host/app/components/operator-mode/publish-realm-modal.gts @@ -1129,7 +1129,10 @@ export default class PublishRealmModal extends Component { for='custom-subdomain-override-checkbox' >Custom Domain Override
- +
@@ -1178,7 +1181,11 @@ export default class PublishRealmModal extends Component { rel='noopener noreferrer' data-test-open-custom-subdomain-override-button > - + Open Site {{/if}} From a522c04328445f9d4dafa84bc6449a3be0b60382 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 29 Jan 2026 16:00:06 -0600 Subject: [PATCH 18/18] Move overrides entirely into environment variables --- packages/runtime-common/constants.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/packages/runtime-common/constants.ts b/packages/runtime-common/constants.ts index 5f6c27b410..76f1b15117 100644 --- a/packages/runtime-common/constants.ts +++ b/packages/runtime-common/constants.ts @@ -87,16 +87,7 @@ export const DEFAULT_PERMISSIONS = Object.freeze([ ]) as RealmPermissions['user']; // Workaround to override published realm URLs to support custom domains. Remove in CS-9061. -export const PUBLISHED_REALM_DOMAIN_OVERRIDES: Record = { - // staging - 'https://realms-staging.stack.cards/buck/load-testing/': - 'custombuck.stack.cards', - - // production - 'https://app.boxel.ai/bucktest/20251216/': 'custombuck.boxel.ai', - 'https://app.boxel.ai/official/cardstack-reward/': 'tealpaper.cardstack.com', - 'https://app.boxel.ai/official/boxel-whitepaper/': 'whitepaper.boxel.ai', -}; +export const PUBLISHED_REALM_DOMAIN_OVERRIDES: Record = {}; export function parsePublishedRealmDomainOverrides( rawOverrides: string | undefined,