Move docs/ package mirror into document-navigator plugin
Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# vault Zod schemas
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
`schemas.ts` defines Zod schemas for every public boundary type in `@suaveplan/vault`: `ItemFields`, `VaultItem`, `SearchQuery`, `ListOptions`, `Attachment`, `ShareLink`, and the bitpacker-packed `VaultManifest`. Each schema is `strict` — unknown keys are rejected at validation time so that callers can never sneak extra fields through that the orchestration layer would silently drop or misroute into the SQLite schema.
|
||||
|
||||
The schemas serve three roles: (1) public-API input validation (`vault.items.create` validates `ItemFields` before encryption); (2) deserialisation guard (loading a snapshot from drive validates each item before re-hydration); and (3) manifest sanity-check before bitpack/unpack. The latter doubles as defence-in-depth: even if a corrupt blob gets past AEAD authentication (it cannot, by construction, but never trust a single layer), the schema fails the load with a typed `VAULT.MANIFEST_INVALID`.
|
||||
|
||||
## Features
|
||||
|
||||
- `ItemFieldsSchema` / `PartialItemFieldsSchema` / `VaultItemSchema` — strict item shapes with bounded length budgets.
|
||||
- `SearchQuerySchema` / `ListOptionsSchema` — query options with size caps to prevent pathological FTS5 queries.
|
||||
- `AttachmentSchema` / `ShareLinkSchema` — record envelopes with bounded filenames / URLs.
|
||||
- `ManifestArgon2idSchema` / `VaultManifestSchema` — pre-bitpacking sanity-check for the manifest struct, including a 32-byte `vaultIdHash` length refinement.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { ItemFieldsSchema } from "@suaveplan/vault/schemas/schemas";
|
||||
|
||||
const parsed = ItemFieldsSchema.safeParse(input);
|
||||
if (!parsed.success) {
|
||||
throw new VaultError(VAULT_CODES["ITEM.VALIDATION_FAILED"], "...");
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { VaultManifestSchema } from "@suaveplan/vault/schemas/schemas";
|
||||
|
||||
function loadManifest(decoded: unknown) {
|
||||
const result = VaultManifestSchema.safeParse(decoded);
|
||||
if (!result.success) {
|
||||
throw new VaultError(
|
||||
VAULT_CODES.MANIFEST_INVALID,
|
||||
"error.vault.manifest.invalid",
|
||||
{ context: { issues: result.error.issues.length } }
|
||||
);
|
||||
}
|
||||
return result.data;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `ItemFieldsSchema` — strict `{ title, category, fields, concealedFields, tags, favorite }`.
|
||||
- `PartialItemFieldsSchema` — `ItemFieldsSchema.partial()` for updates.
|
||||
- `VaultItemSchema` — `ItemFieldsSchema` extended with `id`, `createdAt`, `updatedAt`, `version`, `deleted`.
|
||||
- `SearchQuerySchema` — `{ query?, category?, tags?, favorite?, limit? }` with size caps.
|
||||
- `ListOptionsSchema` — `{ category?, favorite?, limit?, offset? }`.
|
||||
- `AttachmentSchema` — `{ id, itemId, filename, mimeType, size, createdAt }`.
|
||||
- `ShareLinkSchema` — `{ id, itemId, url, expiresAt, maxViews, createdAt }`.
|
||||
- `ManifestArgon2idSchema` — `{ memoryKB, iterations, parallelism }` with bit-width caps matching the bitpacker manifest schema.
|
||||
- `VaultManifestSchema` — full manifest validation with 32-byte `vaultIdHash` refinement.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- All schemas use `.strict()` to block unknown keys; this is critical for the manifest where forward-compatibility is handled by the bitpacker `_version` strategy, not by silent passthrough.
|
||||
- Bit-width caps on numeric manifest fields (e.g. `argon2idMemoryKB ≤ 0xFFFFFFFF`) match the `u32` / `u16` / `u8` widths used by the bitpacker schema in `manifest/manifest.ts`.
|
||||
- The `VaultManifestSchema.vaultIdHash` refinement asserts 32 bytes — the SHA-256 hash size. The vault layer derives this hash deterministically from `vaultId`; mismatches at load time indicate a corrupt or tampered blob.
|
||||
- Search query `limit` is hard-capped at 1000 so a misbehaving caller cannot trigger an O(N) FTS5 fetch that monopolises the in-memory SQLite connection.
|
||||
Reference in New Issue
Block a user