refactor: derive hosts and display name from config
What
Hosts, support addresses, the transactional sender and the desktop display name now come from config instead of literals. A later domain or display-name change then needs only env vars plus a text swap.
No behaviour change by default. With no new env var set, every derived host, URL, address and display name equals today's literal. A test checks this.
This supersedes #8360 and #8379. I re-applied both on today's main instead of resolving the old conflicts, and routed literals added since then through the same constants: the CLI SUPERSET_API_URL/SUPERSET_WEB_URL defaults, the hosts add install URL, and the email preview links.
Hosts (from #8360)
@superset/sharedCANONICAL_URLS(MARKETING,API,APP,DOCS) are built fromNEXT_PUBLIC_ROOT_DOMAIN, orEXPO_PUBLIC_ROOT_DOMAINon mobile.- They ignore
NEXT_PUBLIC_MARKETING_URL/NEXT_PUBLIC_DOCS_URL, so preview and local deployments keep printing production URLs as they do today. - New
COMPANY.SUPPORT_EMAIL;MAIL_TOis built from it. IOS_APPand the root domain move toapp-identity.ts, which is now the only shared fileapps/mobile/app.config.tsloads.
@superset/email/senderNOREPLY_FROMis built fromEMAIL_SENDING_DOMAIN(defaultsuperset.sh).- Every transactional
from:uses it: auth, support, marketing forms and YC deals. - It is separate from the root domain on purpose. A new sending domain needs weeks of warm-up, so mail can stay on the old domain after the root domain changes.
- Call sites that now use the constants:
- API: discovery, OpenAPI, MCP, OAuth metadata, Slack links, connector
client_uri - Docs:
llms.txt, MCP instructions, source links - Marketing:
next.config(API origin,/mcpredirect,Linkheader), install commands,llms, contact/enterprise inbox - Desktop: docs links, billing mailtos, sample prompts
- Web: billing mailto
- Mobile: terms, privacy, share URL, web URL default
- CLI: hints, docs URL
- Email templates
- API: discovery, OpenAPI, MCP, OAuth metadata, Slack links, connector
- Desktop build
defineEnvfalls back when a value is empty, but only if a fallback is given. Unset secrets reach the build as empty strings.- Vite defines, env defaults and the renderer CSP API origin are built from the root domain.
- Cookie import protects both the configured domain and
superset.sh.
- CLI build bakes in
NEXT_PUBLIC_ROOT_DOMAIN. SettingSUPERSET_API_URL/SUPERSET_WEB_URLat runtime still overrides it. - Env plumbing
NEXT_PUBLIC_ROOT_DOMAINgoes to the api/web/marketing/docs deploys (production and preview),build-desktop.ymlandbuild-cli.yml.EMAIL_SENDING_DOMAINgoes to every deploy that hasRESEND_API_KEY.RELAY_BACKUP_URLgoes to the web deploy:next.configalready read it, but nothing set it..env.example,.env.local.example(empty, so the vars stay unset) andturbo.jsoncare updated.- No secret needs to be set now.
Display name (from #8379)
getAppDisplayName()replaces the first word ofapp.namewithCOMPANY.NAMEand keeps the suffix ("Canary", "(workspace)").- The macOS app menu, About/Hide/Quit labels, About panel and notification registration use it.
CFBundleName,CFBundleDisplayNameand the Linux desktop entryName=come from adisplayNamevalue in the electron-builder configs. Canary overridesName=so it keeps "Superset Canary".- These stay unchanged:
productName(userData, logs, sessionData, keychain entry, updater bundle and Windows install folder all come from it), appId, thesuperset://scheme, the CLI binary,~/.supersetand theSUPERSET_*env vars.
Left out on purpose
- Relay, realtime, usercontent, sandbox gate,
cdn.hosts, the published SDK defaults, plugin manifests and the scaffold$schema. - The Slack manifest,
wrangler/flyconfigs, seed data, desktop dev-only preview notices,cli-framework(it has no@superset/shareddependency), commit author identities, and comments. - Copy that names a domain: the contact page, SOC 2 FAQ answers, the web design showcase.
- Translated strings that name
support@superset.sh: the mobile delete-account error andserverError.user.theRecoveryPeriodHasEndedContact. Changing them would re-key the catalogs in all locales, so they are part of the later text swap. The server's raw message usesCOMPANY.SUPPORT_EMAIL, which gives the same string.
Released clients
No tRPC procedure, input or output shape changes. The only server-side differences are string values built from constants that equal the old literals.
Mobile fingerprint
The evaluated Expo config is identical; I checked with @expo/fingerprint. But app.config.ts now loads app-identity.ts instead of constants.ts, so the runtime fingerprint changes once, as any constants.ts edit already does today. After this PR, edits to constants.ts no longer change it.
How I tested
- New tests:
packages/shared/src/app-identity.test.ts: with default env,CANONICAL_URLSandCOMPANY(domain, support/team email,MAIL_TO, terms, privacy, status, trust) equal the old literals. Empty vars keep the defaults, both root-domain vars change them, and per-deployment URL overrides don't. I made it fail once by changing the default.packages/email/src/lib/sender.test.ts:NOREPLY_FROMequalsSuperset <noreply@superset.sh>by default and followsEMAIL_SENDING_DOMAIN, not the root domain.app-display-name.test.ts: display names are unchanged with the default brand.chrome-cookie-import.test.ts: the protected-domain list.
- Test suites, all passing: shared (1376), email (5), cli (423), i18n (164), marketing (160), api (236), trpc user/support/connectors (59).
- Desktop: 8234 pass, 36 fail. The same 36 tests fail on main (v1 git-utils and shell-env suites under full-suite load), and they pass when run alone.
- Typecheck:
- shared, email, i18n and docs pass.
- auth, trpc, api, web, marketing, cli, desktop and mobile fail locally, all with better-auth type-inference errors (
addMember,activeOrganizationId,deletionRequestedAt, …) that come from@superset/auth/@superset/trpc. Untouched main gives the same errors for@superset/authon my machine; my install has two@better-auth/corecopies. CI on main is green. - One real error from this change (a
menu.tsreplace that hit the non-macOS Quit item) was found and fixed. - None of these errors are on a line this PR changes.
bun run lint,bun run check:i18n(no catalog changes) andlint:proseinapps/marketing(0 errors) pass.- Rendered output, compared with main:
- Marketing dev server:
llms.txt,llms-full.txt,llms.md,robots.txt,sitemap.xmland all 7 sub-sitemaps,index.md,auth.md,agents.mdand.well-known/did.jsonare byte-identical. So are the/Linkheader and the/mcpredirect. - Docs dev server:
llms.mdx, the server card and the MCPinitializeinstructions are identical.llms.txtandllms-full.txthave the same lines, but page order changes between dev-server runs of the same code.
- Marketing dev server:
- Not run end to end: a packaged desktop build (bundle plist and menu labels), a mobile build, and real email sends.
Summary by cubic
Hosts, support addresses, and the desktop display name now come from env-driven config instead of hardcoded literals, so a later domain or branding change needs only env vars. With no new env vars set, every derived value stays exactly equal to today's literal.
Refactors
CANONICAL_URLS(marketing, api, app, docs) and theCOMPANYblock build offNEXT_PUBLIC_ROOT_DOMAIN(EXPO_PUBLIC_ROOT_DOMAINon mobile, read after dotenv loads), ignoring preview URL overrides.- The transactional sender comes from
EMAIL_SENDING_DOMAIN, kept separate from the root domain so mail can stay on a warmed-up sending domain after a change. - Desktop menu labels, About/Quit entries, and bundle names derive from
COMPANY.NAME; the About/Hide/Quit labels are i18n placeholders translated in every locale, andproductNamestays fixed since userData, logs, and the keychain entry come from it. - Desktop URL defaults derive from the root domain in
env.main.tsdirectly, because@superset/shared's extensionless imports fail under plain Node in the Vite config; cookie import protects both the configured domain andsuperset.sh.
Summary by CodeRabbit
- Features
- Web, desktop, and mobile builds can use a configurable root domain, with production defaults preserved.
- App links, documentation, support contacts, and email sender addresses now follow the configured company identity and domain.
- Desktop app names and menu labels display the configured brand consistently.
- Improvements
- Protected-domain checks now cover company domains and their subdomains when importing browser cookies.