# schemas/vault-item ## Purpose Zod schemas describing the wire shape of every body, parameter, and response handled by the 5 vault routes. Every schema is the single source of truth: `RouteBuilder` registers them on the OpenAPI document, Hono's `c.req.valid("json")` inference flows from them, and downstream test fixtures derive sample data from them via `z.infer`. The schemas exist at the boundary, not inside the encrypted container — they describe what clients send and receive, not what is persisted on disk. Persistence schemas live with `@suaveplan/vault` itself. ## Features - 8 schemas: `VaultItemMetadataSchema`, `VaultItemSummarySchema`, `VaultItemSchema`, `VaultItemResponseSchema`, `VaultItemListResponseSchema`, `CreateVaultItemBodySchema`, `UpdateVaultItemBodySchema` (strict mode), `DeleteVaultItemResponseSchema`, plus `VaultItemParamsSchema` for the URL `{id}` segment. - `UpdateVaultItemBodySchema` uses `.strict()` so unknown fields cause a Zod parse error — protects against typos and prevents schema-drift by silently accepting client-side keys the server does not understand. - `body` is `z.string()` so clients can carry arbitrary JSON, base64, or text; size enforcement happens at the route layer against `options.maxItemSizeBytes`. - Paginated response carries `meta: { total }` — sufficient for v1; a cursor field will land in a follow-up change once the underlying vault library exposes one. ## Usage: Basic ```ts import { CreateVaultItemBodySchema } from "@suaveplan/api-plugin-vault"; const parsed = CreateVaultItemBodySchema.parse({ title: "API key", kind: "credential", body: JSON.stringify({ user: "alice", key: "k..." }), }); ``` ## Usage: Advanced ```ts import { type CreateVaultItemBody, type UpdateVaultItemBody, UpdateVaultItemBodySchema, } from "@suaveplan/api-plugin-vault"; const result = UpdateVaultItemBodySchema.safeParse({ title: "X", evil: "Y", }); // result.success === false; result.error lists "Unrecognized key(s): evil" ``` ## API Reference ### `VaultItemSummarySchema` Object with `id`, `ownerId`, `title` (1..512), `kind` (1..128), `metadata` (optional record), `createdAt`, `updatedAt`. ### `VaultItemSchema` Extends `VaultItemSummarySchema` with `body: string`. ### `VaultItemResponseSchema`, `VaultItemListResponseSchema`, `DeleteVaultItemResponseSchema` Envelope responses returned by the 5 routes. The success envelope is the standard `{ success: true, data }` shape used across suaveplan; errors use the shared `ErrorResponseSchema` from `@suaveplan/api-openapi`. ### `CreateVaultItemBodySchema` POST body: `title`, `kind`, `body`, optional `metadata`. All four fields validated as non-empty/length-bounded where applicable. ### `UpdateVaultItemBodySchema` PATCH body (strict). Every field optional; `metadata` may be set to omit. Unknown fields rejected. ### `VaultItemParamsSchema` URL params: `{ id: string }`. ### Type aliases `VaultItemSummaryType`, `VaultItemType`, `VaultItemResponseType`, `VaultItemListResponseType`, `CreateVaultItemBody`, `UpdateVaultItemBody`, `DeleteVaultItemResponseType`, `VaultItemParams`. ## Implementation Notes - `metadata` uses `z.record(z.string(), z.unknown())` rather than an explicit nested shape because callers attach app-specific fields (tags, labels, custom expiry hints) that vary across consumers. The strict `UpdateVaultItemBodySchema` mode does NOT recurse into `metadata` — strict only blocks unknown top-level keys. - `createdAt`/`updatedAt` are ISO-8601 strings, not numbers. SurrealDB serialises `datetime` as ISO strings; the wire matches the persistence layer. - `body` is intentionally string-typed, not byte-typed. Clients base64-encode binary payloads before sending. This keeps the wire JSON-safe and consistent across HTTP/2, HTTP/3, and SSE transports without forcing a multipart envelope.