# `provider` — `AuthProviderAdapter` contract + path-prefix validation _(no submodules)_ ## Purpose The `provider` module is the type-level + thin-runtime heart of `@suaveplan/api-auth-provider`. It declares the abstract `AuthProviderAdapter` interface every concrete account-lifecycle provider (Better-Auth, the rolled reference, future Cognito/Auth0 bridges) structurally implements, and ships the Zod-validated `authPathPrefix` constructor that asserts a deployment's configured prefix is a legal segment-aligned mount point. By splitting the contract from any concrete provider we keep this package optional: a hosted-IdP deployment installs the session resolver (`api-auth`) only and never pulls in a provider implementation. ## Features - `AuthProviderAdapter` interface with `id`, configurable `pathPrefix`, `routes(router, ctx)` registration callback, and the four-hook `AuthProviderLifecycle` quartet (`install`/`start`/`stop`/`uninstall`). - `AuthPathPrefix` opaque brand — protects against accidental string substitution at the install boundary. - `AuthPathPrefixSchema` — a Zod schema enforcing leading slash, no trailing slash (except `/`), no path parameters, no whitespace. - `authPathPrefix(value)` constructor — returns the branded value or throws `AUTH_PROVIDER.PROVIDER_LIFECYCLE_FAILED` with a structured `reason`. - `isAuthPathPrefix(value)` predicate — non-throwing variant for tests. - `DEFAULT_AUTH_PATH_PREFIX` constant (`"/auth"`). ## Usage: Basic ```ts import { authPathPrefix, DEFAULT_AUTH_PATH_PREFIX, type AuthProviderAdapter, } from "@suaveplan/api-auth-provider/provider"; const myProvider: AuthProviderAdapter = { id: "rolled", pathPrefix: authPathPrefix(DEFAULT_AUTH_PATH_PREFIX), routes(router) { router.post("/login", { auth: null }, async () => new Response()); }, lifecycle: { install: async () => {}, start: async () => {}, stop: async () => {}, uninstall: async () => {}, }, }; ``` ## Usage: Advanced A deployment that mounts its provider under a non-standard prefix MUST run the input through `authPathPrefix` so the value is validated before the host records the claim in the path-ownership registry. ```ts import { authPathPrefix } from "@suaveplan/api-auth-provider/provider"; const prefix = authPathPrefix(process.env.AUTH_PREFIX ?? "/auth/v2"); // Throws AUTH_PROVIDER.PROVIDER_LIFECYCLE_FAILED on input like // "/auth/v2/" or "/auth/:tenant". ``` ## API Reference - `interface AuthProviderAdapter` — provider contract. - `interface AuthProviderLifecycle` — install/start/stop/uninstall. - `type AuthPathPrefix` — branded prefix string. - `const AuthPathPrefixSchema: ZodType` — validation schema. - `function authPathPrefix(value: string): AuthPathPrefix` — throwing constructor. - `function isAuthPathPrefix(value: string): boolean` — predicate. - `const DEFAULT_AUTH_PATH_PREFIX = "/auth"` — host default. ## Implementation Notes The brand is purely a TypeScript construct (`unique symbol`) — at runtime `authPathPrefix("/auth")` returns the string unchanged. The schema's order of refinements is significant: the leading-slash check fires first so callers see the most actionable error message. Whitespace is rejected before the parameter check because shell-supplied configuration is the typical source of both classes of error. The constructor surfaces failures as `PROVIDER_LIFECYCLE_FAILED` (not a hypothetical `INVALID_PREFIX`) because the install lifecycle is the only legitimate call site — keeping the code small makes the error registry tighter and the metadata table denser.