# plugin/plugin _(no submodules)_ ## Purpose `createVaultPlugin(options)` is the factory that returns a typed `PluginDescriptor` ready to register with the host's `PluginRegistry`. Third instance of the 3-way plug-and-play contract: the plugin owns its `.surql` DDL, its Zod schemas, and its OpenAPI routes, and applies all three during `onInit`. Depends on `api-plugin-auth` so every route's principal scoping has a typed upstream supplier. ## Features - Zod-validated options via `VaultPluginOptionsSchema` — invalid input raises `VaultPluginError(VAULT_PLUGIN_INVALID_INPUT)` carrying the `ZodError`. - Declares `dependencies: ["auth"]` so the registry refuses to load the plugin without `api-plugin-auth` registered upstream. - 6-step `onInit` lifecycle: resolve services → apply schema → construct `vaultService` → register `vaultService` → register routes → (no global middleware — `requireAuth()` is per-route). - `routePrefix`-aware route mounting — paths are rebuilt at the prefix the operator chose, both in the served Hono app and in the `OpenAPIRegistry` snapshot. Default `/vault`. - Collision detection — pre-existing routes under the configured prefix raise `VAULT_PLUGIN_ROUTE_PREFIX_COLLISION`. - Graceful degradation — when `openAPIRegistry` is absent, routes mount on the Hono app directly (no doc); when neither `migrationRunner` nor `db` is available with `applySchemaOnInit: true`, init fails fast with `VAULT_PLUGIN_SERVICE_NOT_AVAILABLE`. ## Usage: Basic ```ts import { defineApp } from "@suaveplan/api"; import { createAuthPlugin } from "@suaveplan/api-plugin-auth"; import { createVaultPlugin } from "@suaveplan/api-plugin-vault"; const app = await defineApp() .name("my-api") .use(createAuthPlugin({ betterAuth: { /* ... */ } })) .use(createVaultPlugin({ storage: driveAdapter })) .start(); ``` ## Usage: Advanced ```ts const plugin = createVaultPlugin({ storage: driveAdapter, routePrefix: "/v1/vault", maxItemSizeBytes: 4 * 1024 * 1024, serverPepper: process.env["VAULT_SERVER_PEPPER"]!, unlockExtractor: (c) => c.req.header("X-Custom-Vault-Unlock") ?? null, applySchemaOnInit: false, // operator runs migrations externally }); ``` ## API Reference ### `createVaultPlugin(options: VaultPluginOptions): PluginDescriptor` Returns a `definePlugin` descriptor. `name: "vault"`, `version: "0.1.0"`, `dependencies: ["auth"]`. The `defaults` field carries every resolved option after Zod validation — the registry passes that to `onInit` via `ctx.getOwnConfig()`. `onInit(ctx)` resolves services, applies the schema, constructs the service, registers it, and registers the 5 routes. ## Implementation Notes - The plugin DOES NOT install global middleware. `requireAuth()` from `api-plugin-auth` is applied per-route inside `buildVaultRoutes` so the public `/openapi.json` doc only carries vault routes for the authenticated scope and operators can leave the vault prefix out of public-facing API documentation tooling. - The `rewritePath` helper preserves `{id}` segments verbatim — when the operator chooses `/v1/vault`, the route path `/vault/items/{id}` becomes `/v1/vault/items/{id}`. - The collision check inspects every previously registered route whose path starts with the configured prefix — operators wiring multiple vault plugin instances under different prefixes are unaffected. - The plugin does not provide an `onClose` hook because the `vaultService` is stateless across requests — every handle is opened + closed within a single request lifecycle.