first commit
This commit is contained in:
121
docs/api-stack/api/api-plugin-auth/src/plugin/plugin.md
Normal file
121
docs/api-stack/api/api-plugin-auth/src/plugin/plugin.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# plugin/plugin
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`createAuthPlugin(options)` is the factory that returns a typed
|
||||
`PluginDescriptor<AuthPluginConfig>` ready to register with the host's
|
||||
`PluginRegistry`. It is the canonical exemplar of the 3-way
|
||||
plug-and-play contract every `@suaveplan/api-plugin-*` package follows:
|
||||
the plugin owns its `.surql` DDL, its Zod schemas, and its OpenAPI
|
||||
routes, and applies all three during `onInit`.
|
||||
|
||||
## Features
|
||||
|
||||
- Zod-validated options via `AuthPluginOptionsSchema` — invalid input
|
||||
raises `AuthError(AUTH_INVALID_INPUT)` carrying the `ZodError`.
|
||||
- 6-step `onInit` lifecycle: resolve services → apply schema →
|
||||
construct Better-Auth → register `authService` → register routes →
|
||||
install session middleware.
|
||||
- `routePrefix`-aware route mounting — paths are rebuilt at the
|
||||
prefix the operator chose, both in the served Hono app and in the
|
||||
`OpenAPIRegistry` snapshot.
|
||||
- Graceful degradation — when `openAPIRegistry` is absent, routes
|
||||
mount on the Hono app directly and a warning is logged. When neither
|
||||
`migrationRunner` nor `db` is available with `applySchemaOnInit: true`,
|
||||
init fails fast with `AUTH_SERVICE_NOT_AVAILABLE`.
|
||||
- Collision detection — pre-existing routes under the configured
|
||||
prefix raise `AUTH_ROUTE_PREFIX_COLLISION`.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { defineApp } from "@suaveplan/api";
|
||||
import { createAuthPlugin } from "@suaveplan/api-plugin-auth";
|
||||
|
||||
const app = await defineApp()
|
||||
.name("my-api")
|
||||
.use(
|
||||
createAuthPlugin({
|
||||
betterAuth: {
|
||||
secret: process.env.BETTER_AUTH_SECRET!,
|
||||
baseURL: "http://localhost:3000",
|
||||
emailAndPassword: { enabled: true },
|
||||
database: surrealAdapter,
|
||||
},
|
||||
})
|
||||
)
|
||||
.start();
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Mount the plugin under a versioned prefix, disable the in-plugin
|
||||
schema apply step (an external migration tool handles DDL), and inject
|
||||
a custom principal mapping that decorates the Better-Auth user with
|
||||
roles derived from the active organisation:
|
||||
|
||||
```ts
|
||||
import { defineApp } from "@suaveplan/api";
|
||||
import {
|
||||
createAuthPlugin,
|
||||
mapBetterAuthUserToPrincipal,
|
||||
} from "@suaveplan/api-plugin-auth";
|
||||
|
||||
const app = await defineApp()
|
||||
.name("my-api")
|
||||
.use(
|
||||
createAuthPlugin({
|
||||
betterAuth: { /* … */ },
|
||||
routePrefix: "/api/v1/auth",
|
||||
applySchemaOnInit: false,
|
||||
principalMapping: (view) => {
|
||||
const base = mapBetterAuthUserToPrincipal(view);
|
||||
const session = view.session as { roles?: string[] };
|
||||
return {
|
||||
...base,
|
||||
roles: [...base.roles, ...(session.roles ?? [])],
|
||||
};
|
||||
},
|
||||
})
|
||||
)
|
||||
.start();
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `function createAuthPlugin(options: AuthPluginOptions): PluginDescriptor<AuthPluginConfig>`
|
||||
|
||||
- Validates `options` via `AuthPluginOptionsSchema`.
|
||||
- Returns a `PluginDescriptor` with `name: "auth"`, `version: "0.1.0"`,
|
||||
`tags: ["auth", "security"]`, and the 4 lifecycle hooks (only
|
||||
`onInit` + `onClose` are wired; `onRegister` and `onReady` are
|
||||
default no-ops).
|
||||
- `onInit` runs the canonical 6-step lifecycle described above. It
|
||||
raises `AUTH_*` codes on the explicit failure modes — see
|
||||
`../error-codes/error-codes.md`.
|
||||
- `onClose` releases the cached Better-Auth reference so the registry
|
||||
can re-init the plugin on subsequent boots.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The descriptor's `configSchema` is the `AuthPluginOptionsSchema` so
|
||||
the host registry re-validates the merged config at registration
|
||||
time. The `defaults` field carries the resolved options so plugins
|
||||
registered without an explicit config still see the parsed shape.
|
||||
- The session middleware is installed AFTER routes are registered so
|
||||
the OpenAPI doc snapshot is taken before any per-request work
|
||||
begins. Order does not affect runtime behaviour but keeps the
|
||||
registry's events ordered consistently across reboots.
|
||||
- The runtime check against `openAPIRegistry === undefined` exists
|
||||
even though the registry's TS-level slot is non-optional —
|
||||
`ctx.getService` adds `| undefined` to every slot's return type, so
|
||||
the absent-runtime case still type-checks.
|
||||
- `applySchema` prefers the migration runner over the raw `db`
|
||||
adapter so operators get migration-record tracking when the runner
|
||||
is wired. Falling back to `applyBetterAuthSchema(db)` ensures the
|
||||
plugin still boots in lightweight deployments that ship without
|
||||
`@suaveplan/api-migrations`.
|
||||
Reference in New Issue
Block a user