Initial Commit
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user