import { z } from 'zod'; /** * The hostname map (K-26; control-plane.md §4.7). * * §4.2 provisions a scope; nothing gave it a URL. This is the directory data a * single environment-wide router resolves against — `hostname → (tenant, scope, * vertical, surface, region)` — before dispatching to the vertical's worker. */ /** * Which app answers on this hostname. * * §5.5 originally specified one hostname per scope, which is already wrong: the * shop fronts a storefront AND a back office from ONE scope, and RallyPoint a * player app and a manager console. Same data, different audience and chrome — the * split is deliberate and never a second source of truth. * * Vertical vocabulary, deliberately: the kernel never branches on it, exactly as it * never branches on `scope.kind`. It is carried so the router knows where to send * the request, and the vertical decides what that name means. */ export declare const surfaceName: z.ZodString; /** * A surface a vertical DECLARES it serves (package.json `substrat.surfaces` → the * deploy manifest → the registry). Labels only, today — the kernel and router stay * indifferent; what the declaration buys is operator UX: a hostname-binding picker * instead of free text, and a push-time warning when a version stops declaring a * surface that hostnames are still bound to. Free-text `surfaceName` remains valid * everywhere — an undeclared surface is not an error. * * This object is also the anchor #111 ("app as a first-class surface") extends when a * surface grows into a real authority boundary: a per-surface OPERATION-SET (the * scoped subset an app token may call, and the filter its OAS view is cut by) attaches * HERE, as optional additive fields — never as a second, competing surface list. Until * then the declaration must not be read as enforcement: it names, it does not gate. */ export declare const declaredSurface: z.ZodObject<{ name: z.ZodString; label: z.ZodString; }, z.core.$strip>; export type DeclaredSurface = z.infer; /** * Where the hostname's traffic may be processed. * * The DO jurisdiction (K-7) pins storage and execution and is fixed at provisioning. * This is the OTHER half: Regional Services pins TLS termination and processing. * * **This column records the region; it does not cause it** (K-30). TLS terminates * before any of our code runs, so nothing read from here can move it — the region is * enforced by a wildcard Regional Hostnames config per jurisdiction * (`*.eu.substrat.run`), and default hostnames carry the jurisdiction in the name. * What this column is *for* — per K-30 — is letting the router detect a CONTRADICTION * between the edge configuration and the directory, and refuse the request. **Nothing * does that today** (#958), and this docblock used to say otherwise. The resolved route * target carries no jurisdiction to compare a region against — neither adapter's * hostname read joins `scopes.jurisdiction` — and `apps/router/src/worker.ts` declines * the comparison by name, calling it a third enforcement point that can disagree. So * read this as a region RECORDED: a value to compare, not a comparison anyone makes. * * The same reasoning says it should be derived from the scope's jurisdiction rather than * accepted as an independent input: two values that must agree, supplied separately, * eventually disagree — and this is the one an EU claim rests on. `bindHostname` does * not enforce that yet either. * * Null means unconstrained. Widening beyond `eu` is additive; Cloudflare also offers * `us` and `fedramp`, and `us` is needed as soon as a second jurisdiction ships. */ export declare const hostnameRegion: z.ZodNullable>; export type HostnameRegion = z.infer; /** * Where a hostname is in its provisioning lifecycle (§4.2). * * Custom domains ride Cloudflare for SaaS, so a hostname is not a string somebody * sets — it is DNS validation and certificate issuance, which take time and can * fail. Treating it as a column would make "the domain does not work yet" and "the * domain is broken" the same state. * * `pending` — recorded, nothing asked of Cloudflare yet * `verifying` — DNS validation and cert issuance in flight * `active` — serving * `failed` — validation or issuance failed; `note` says why */ export declare const hostnameStatus: z.ZodEnum<{ active: "active"; failed: "failed"; pending: "pending"; verifying: "verifying"; }>; export type HostnameStatus = z.infer; /** * A DNS record the tenant must publish for Cloudflare for SaaS to validate ownership * and route traffic. Two kinds ride the same shape: * * - `hostname` — the routing CNAME (`legal.acme.com → edge.substrat.run`). Present as * soon as the custom hostname is created. * - `txt` — a DCV (domain-control-validation) TXT record, when the cert uses TXT * validation (`_cf-custom-hostname.legal.acme.com`). CNAME-validated certs omit it. * * The dashboard renders these verbatim ("add this record with your DNS provider"), so * the shape is exactly name/value/type — what a DNS UI asks for, nothing router- or * Cloudflare-specific. `status` mirrors Cloudflare's per-record validation state when * known, so a half-validated domain can say *which* record is still missing. */ export declare const dnsRecord: z.ZodObject<{ type: z.ZodEnum<{ hostname: "hostname"; txt: "txt"; }>; name: z.ZodString; value: z.ZodString; status: z.ZodDefault>; }, z.core.$strip>; export type DnsRecord = z.infer; /** * A hostname, normalized to lower case. * * DNS is case-insensitive, so `ACME.example.com` and `acme.example.com` are the same * name — and if the map stored them as two rows, the global-uniqueness check would * let two different scopes each hold "the same" hostname, and a request would resolve * to whichever casing it happened to arrive in. Normalizing in the schema means both * adapters inherit it rather than each remembering to. * * 253 is the maximum length of a fully-qualified domain name. */ export declare const hostname: z.ZodString; export declare const hostnameBinding: z.ZodObject<{ hostname: z.ZodString; tenantId: z.core.$ZodBranded; scopeId: z.core.$ZodBranded; verticalSlug: z.ZodNullable; surface: z.ZodString; region: z.ZodNullable>; status: z.ZodEnum<{ active: "active"; failed: "failed"; pending: "pending"; verifying: "verifying"; }>; statusNote: z.ZodNullable; canonical: z.ZodBoolean; createdAt: z.core.$ZodBranded; customHostnameId: z.ZodDefault>; validationRecords: z.ZodDefault; name: z.ZodString; value: z.ZodString; status: z.ZodDefault>; }, z.core.$strip>>>; }, z.core.$strip>; export type HostnameBinding = z.infer; export declare const bindHostnameInput: z.ZodObject<{ hostname: z.ZodString; tenantId: z.core.$ZodBranded; scopeId: z.core.$ZodBranded; surface: z.ZodString; region: z.ZodNullable>; canonical: z.ZodBoolean; }, z.core.$strip>; export type BindHostnameInput = z.infer; /** * What the router needs to dispatch. Deliberately smaller than the full binding: a * per-request hot path should read what it uses and nothing else. */ export declare const routeTarget: z.ZodObject<{ tenantId: z.core.$ZodBranded; scopeId: z.core.$ZodBranded; verticalSlug: z.ZodNullable; deploymentRef: z.ZodNullable; surface: z.ZodString; region: z.ZodNullable>; outboundHosts: z.ZodDefault>>; }, z.core.$strip>; export type RouteTarget = z.infer; //# sourceMappingURL=routing.d.ts.map