Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
# `route-surface` — canonical auth-provider route surface
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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<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 | undefined`
- `function resolveProviderRoutePath(prefix: string, entry: ProviderRouteEntry): string`
- `function 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.