3.3 KiB
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 ofProviderRouteEntryrecords, every entry carryingpath,method, stablename, and OpenAPIsummary.ProviderRouteNameliteral 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
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.
import {
PROVIDER_ROUTE_SURFACE,
resolveProviderRoutePath,
} from "@suaveplan/api-auth-provider/route-surface";
const openapiPaths: Record<string, unknown> = {};
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<ProviderRouteEntry>function lookupProviderRoute(name: ProviderRouteName): ProviderRouteEntry | undefinedfunction resolveProviderRoutePath(prefix: string, entry: ProviderRouteEntry): stringfunction listProviderRouteNames(): ReadonlyArray<ProviderRouteName>
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.