# `route-surface` — canonical auth-provider route surface _(no submodules)_ ## Purpose `route-surface` declares the closed set of paths an auth provider OWNS relative to its `pathPrefix`. The set is the union of the routes any realistic concrete provider exposes — register, login, logout, refresh, two OAuth-flow endpoints, email verification, and the forgot/reset-password pair. Providers MAY implement a subset; the canonical list is the bar the collision detector measures against and the manifest the OpenAPI emitter projects when stitching a unified document at build time. ## Features - `PROVIDER_ROUTE_SURFACE` — frozen array of `ProviderRouteEntry` records, every entry carrying `path`, `method`, stable `name`, and OpenAPI `summary`. - `ProviderRouteName` literal union — exhaustive narrowing in switch blocks. - `lookupProviderRoute(name)` — name → entry lookup. - `resolveProviderRoutePath(prefix, entry)` — mount under a given prefix (handles `"/"` as a no-op). - `listProviderRouteNames()` — declaration-order name iteration; used by the conformance harness to verify every canonical name has a scenario. ## Usage: Basic ```ts import { PROVIDER_ROUTE_SURFACE, resolveProviderRoutePath, } from "@suaveplan/api-auth-provider/route-surface"; for (const entry of PROVIDER_ROUTE_SURFACE) { console.log(entry.method, resolveProviderRoutePath("/auth", entry)); } ``` ## Usage: Advanced The OpenAPI emitter walks the surface to generate the global `paths` block for the unified document, projecting `summary` directly into the OpenAPI operation and using `name` as `operationId` after kebab → camelCase conversion. ```ts import { PROVIDER_ROUTE_SURFACE, resolveProviderRoutePath, } from "@suaveplan/api-auth-provider/route-surface"; const openapiPaths: Record = {}; for (const entry of PROVIDER_ROUTE_SURFACE) { const path = resolveProviderRoutePath(provider.pathPrefix, entry); openapiPaths[path] = { [entry.method.toLowerCase()]: { operationId: entry.name.replace(/[-.]/g, "_"), summary: entry.summary, tags: ["auth"], }, }; } ``` ## API Reference - `interface ProviderRouteEntry { path; method; name; summary }` - `type ProviderRouteName` — closed union of 9 names. - `const PROVIDER_ROUTE_SURFACE: ReadonlyArray` - `function lookupProviderRoute(name: ProviderRouteName): ProviderRouteEntry | undefined` - `function resolveProviderRoutePath(prefix: string, entry: ProviderRouteEntry): string` - `function listProviderRouteNames(): ReadonlyArray` ## Implementation Notes The surface is frozen at module-load with two layers of `Object.freeze` — once around the outer array and once around each entry — to keep downstream hosts from mutating the table at runtime. `resolveProviderRoutePath` treats `"/"` as the empty-prefix case so a deployment that mounts the provider at the host root produces `"/login"` rather than `"//login"`. Adding a new canonical route requires an OpenSpec change because the conformance harness and the OpenAPI projector both treat the surface as authoritative; touching either side without the other is the bug class this list-as-data design guards against.