Skip to content

Apex and subdomains

ShowPony serves two surfaces from one app:

HostSurfaceTenant
show-pony.localhost:4180 (apex)Host login + dashboardnone (null)
demo.show-pony.localhost:4180Public RSVP pagetenant key demo
SurfaceLocalCloud
Host login (apex)http://show-pony.localhost:4180/loginhttps://show-pony.kumiko.rocks/login
Demo invite (rooftop)http://demo.show-pony.localhost:4180/e/rooftop-launchhttps://demo.show-pony.kumiko.rocks/e/rooftop-launch
Acme invite (offsite)http://acme.show-pony.localhost:4180/e/acme-offsitehttps://acme.show-pony.kumiko.rocks/e/acme-offsite

The host is decided by the subdomain a request arrives on, never by anything the guest sends. That is what makes a shared, anonymous app safe.

flowchart LR
  subgraph apex["apex : show-pony.localhost"]
    Landing[Marketing]
    Login[Login]
    Dash[Host dashboard]
  end
  subgraph demo["demo.show-pony.localhost"]
    Invite[Invite page]
    RSVP[Anonymous RSVP]
  end
  Guest((Guest)) --> Invite
  Invite --> RSVP
  Visitor((Visitor)) --> Landing
  Host((Host)) --> Login --> Dash

The same app process serves two HTML bundles. The server picks one by the Host header:

Host sees the event list on the apex
Guests see the invite page on the demo subdomain

Port comes off the Host header first; then the subdomain suffix maps to tenant.key:

export function hostnameOf(host: string): string {
const i = host.indexOf(":");
return i === -1 ? host : host.slice(0, i);
}
// Apex / www: login, not a guest surface : no tenant.
if (host === baseDomain || host === `www.${baseDomain}`) return null;
// <key>.<baseDomain>: subdomain IS the tenant key.
if (host.endsWith(`.${baseDomain}`)) {
return enabledTenantByKey(db, host.slice(0, -(baseDomain.length + 1)));
}
From src/tenant-routing.ts.

resolverTrust: "authoritative" is what actually closes this: a client-supplied X-Tenant header that disagrees with the hostname-resolved tenant is rejected with 400 tenant_mismatch before tenantExists ever runs. tenantExists alone only proves a real, enabled row, not that it matches the subdomain.

bin/server.ts passes the anonymous-access helper into the dev server (subdomain resolver + SYSTEM tenant on the apex for /legal/*):

anonymousAccess: ({ db }) => createShowPonyAnonymousAccess({ db, baseDomain: BASE_DOMAIN }),
From bin/server.ts.

Production uses the same resolver shape in bin/main.ts with https origins.

The apex serves static marketing pages (/, /de, /features, /pricing) and the admin SPA at /login (and authenticated app routes). Every subdomain serves index.html (public guest bundle). The server decides, rather than client-side hostname checks:

hostDispatch: (req) => {
const host = hostnameOf(req.headers.get("host") ?? "");
const path = new URL(req.url).pathname;
if (host === BASE_DOMAIN || host === `www.${BASE_DOMAIN}`) {
const dispatched = dispatchShowPonyApexStaticDev(path);
if (dispatched !== null) return dispatched;
return { kind: "html", entryName: "admin", injectSchema: true };
}
return { kind: "html", entryName: "public", injectSchema: false };
},
From bin/server.ts.
// Subdomain → host tenant. The anonymous RSVP write needs the tenant from the
// request envelope (the Host header), never from the payload — otherwise a
// guest could forge it. We map <key>.<baseDomain> straight onto the bundled
// `tenant.key`, so there's no extra profile schema. Apex / www / unknown all
// resolve to null (no tenant).
//
// createShowPonyAnonymousAccess is the shared implementation:
// createShowPonyTenantRoutingFeature (auth-foundation providers, production
// since #1374) builds both its resolver and existence plugin on it, and
// isolated test stacks that inject Resolved callbacks without mounting
// providers call it directly.
//
// tenantExists is the defense-in-depth check against a forged X-Tenant header:
// only a real, enabled tenant row counts.
import {
type AuthProviderBuildDeps,
EXT_TENANT_EXISTENCE,
EXT_TENANT_RESOLVER,
type TenantExistenceProvider,
type TenantExistsFn,
type TenantResolverFn,
type TenantResolverProvider,
} from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
import { tenantTable } from "@cosmicdrift/kumiko-bundled-features/tenant";
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
import {
defineFeature,
type FeatureDefinition,
isSystemTenant,
type TenantId,
} from "@cosmicdrift/kumiko-framework/engine";
// Strip the port: "acme.show-pony.localhost:4180" → "acme.show-pony.localhost".
export function hostnameOf(host: string): string {
const i = host.indexOf(":");
return i === -1 ? host : host.slice(0, i);
}
type TenantRow = { id: TenantId; isEnabled: boolean };
async function enabledTenantByKey(db: DbConnection, key: string): Promise<TenantId | null> {
const row = await fetchOne<TenantRow>(db, tenantTable, { key });
return row !== undefined && row.isEnabled === true ? row.id : null;
}
async function isTenantEnabled(db: DbConnection, id: TenantId): Promise<boolean> {
const row = await fetchOne<TenantRow>(db, tenantTable, { id });
return row !== undefined && row.isEnabled === true;
}
export function createShowPonyTenantResolver(config: { db: DbConnection; baseDomain: string }) {
const { db, baseDomain } = config;
return {
tenantResolver: async (c: {
req: { header: (n: string) => string | undefined };
}): Promise<TenantId | null> => {
const host = hostnameOf(c.req.header("Host") ?? "");
// Apex / www: the host's own login, not a guest surface — no tenant.
if (host === baseDomain || host === `www.${baseDomain}`) return null;
// <key>.<baseDomain>: the subdomain IS the tenant key.
if (host.endsWith(`.${baseDomain}`)) {
return enabledTenantByKey(db, host.slice(0, -(baseDomain.length + 1)));
}
return null;
},
tenantExists: (id: TenantId): Promise<boolean> =>
isSystemTenant(id) ? Promise.resolve(true) : isTenantEnabled(db, id),
// Host-derived, not client-controlled — see createShowPonyAnonymousAccess.
resolverTrust: "authoritative" as const,
};
}
/** Apex anonymous routes (legal pages) need SYSTEM tenant; subdomains keep host tenant. */
// Module-global singleton, not per-stack state: acceptable because
// buildAppFeatures(...)/resolveApexTenant are wired once at static boot,
// never per request, and this process only ever runs one app stack. Bind
// BEFORE the first request that needs it (bindSubdomainPageResolver at
// boot) — a second stack in the same process would silently share this db.
let subdomainPageResolver: { db: DbConnection; baseDomain: string } | null = null;
/** Wire db for managed-pages `resolveApexTenant` (boot hook — wired once at static boot). */
export function bindSubdomainPageResolver(config: { db: DbConnection; baseDomain: string }): void {
subdomainPageResolver = config;
}
/** Host → tenantId for managed-pages branding reads (subdomain = tenant.key). */
export async function resolveSubdomainPageTenant(host: string): Promise<TenantId | null> {
if (!subdomainPageResolver) return null;
const { db, baseDomain } = subdomainPageResolver;
const h = hostnameOf(host);
if (h === baseDomain || h === `www.${baseDomain}`) return null;
if (h.endsWith(`.${baseDomain}`)) {
return enabledTenantByKey(db, h.slice(0, -(baseDomain.length + 1)));
}
return null;
}
export function createShowPonyAnonymousAccess(config: { db: DbConnection; baseDomain: string }) {
const subdomain = createShowPonyTenantResolver(config);
const { baseDomain } = config;
return {
tenantResolver: async (c: {
req: { header: (n: string) => string | undefined };
}): Promise<TenantId | null> => {
const host = hostnameOf(c.req.header("Host") ?? "");
// Apex has no anonymous tenant: legal/marketing pages are pre-rendered
// static HTML (renderAllMarketingPages) and branding reads go through
// the separate resolveSubdomainPageTenant/bindSubdomainPageResolver
// pipeline, not this resolver. Returning null here (not
// SYSTEM_TENANT_ID) means an apex-origin anonymous /api/write or
// /api/query — with or without an X-Tenant header — gets
// "tenant_required" from the authoritative resolver instead of
// silently landing on SYSTEM_TENANT_ID.
if (host === baseDomain || host === `www.${baseDomain}`) return null;
return subdomain.tenantResolver(c);
},
tenantExists: subdomain.tenantExists,
// Host-derived, not client-controlled — the resolver's answer is final.
// A client-supplied X-Tenant header disagreeing with the subdomain (e.g.
// a guest on acme.show-pony.<domain> claiming Globex's real tenant id)
// is rejected with 400 tenant_mismatch instead of silently overriding
// the subdomain (kumiko-platform#278/1 / #51).
resolverTrust: "authoritative" as const,
};
}
export type ShowPonyTenantRoutingFeatureConfig = {
readonly baseDomain: string;
};
/**
* Registers subdomain tenantResolver + tenantExists as auth-foundation
* providers (#1374). Mount alongside auth-foundation; boot merges them into
* anonymousAccess via resolveAnonymousAccessFromRegistry.
*/
export function createShowPonyTenantRoutingFeature(
config: ShowPonyTenantRoutingFeatureConfig,
): FeatureDefinition {
const { baseDomain } = config;
return defineFeature("show-pony-tenant-routing", (r) => {
r.requires("auth-foundation");
const resolverPlugin: TenantResolverProvider = {
trust: "authoritative",
build: (deps: AuthProviderBuildDeps) => {
const built = createShowPonyAnonymousAccess({ db: deps.db, baseDomain });
return built.tenantResolver as TenantResolverFn;
},
};
const existencePlugin: TenantExistenceProvider = {
build: (deps: AuthProviderBuildDeps) => {
const built = createShowPonyAnonymousAccess({ db: deps.db, baseDomain });
return built.tenantExists as TenantExistsFn;
},
};
r.useExtension(EXT_TENANT_RESOLVER, "subdomain", resolverPlugin);
r.useExtension(EXT_TENANT_EXISTENCE, "db", existencePlugin);
});
}

📄 On GitHub: src/tenant-routing.ts

Next: define the entities that flow through these two surfaces: chapter 5. For the marketing apex itself see chapter 12 and chapter 13.