# schemas _(no submodules)_ ## Purpose `schemas.ts` provides Zod runtime validators for every public boundary type declared in `types.ts`. The validators are the contract enforced at API entry and exit: a `VaultItem` reaching `mergeVaultItems`, a `SyncOperation` queued by `SyncQueue.enqueue`, an `EncryptedSyncPayload` decoded by `decryptSyncPayload` — all are first parsed by the appropriate schema so a malformed input fails fast with a structured error rather than producing a hard-to-debug shape mismatch later in the pipeline. ## Features - `VectorClockSchema` — `Record` - `VaultHistoryEntrySchema` — `{ historyId; timestamp; note }`, strict - `VaultItemSchema` — full canonical vault-item shape, strict - `MergeStrategySchema` — `"lww" | "append" | "atomic"` - `SyncOperationKindSchema` — `"create" | "update" | "delete"` - `SyncOperationSchema` — durable-queue entry shape with partial `fields` - `VaultSnapshotSchema` — `{ items; clock; snapshotAt }`, strict - `EncryptedSyncPayloadSchema` — version + 24-byte nonce + ciphertext - All schemas are `.strict()` — extra keys raise an error ## Usage: Basic Example ```ts import { VaultItemSchema } from "@suaveplan/vault-sync/schemas/schemas"; const parsed = VaultItemSchema.safeParse({ id: "i1", title: "Email", password: "hunter2", folderId: null, history: [], nodeId: "n1", updatedAt: 0, clock: { n1: 1 }, }); if (!parsed.success) throw new Error("invalid item"); ``` ## Usage: Advanced Example ```ts import { EncryptedSyncPayloadSchema, SyncOperationSchema, VaultSnapshotSchema, } from "@suaveplan/vault-sync/schemas/schemas"; import { VaultSyncError } from "@suaveplan/vault-sync"; import { VAULT_SYNC_CODES } from "@suaveplan/vault-sync/errors"; function asPayload(input: unknown): import("@suaveplan/vault-sync/types").EncryptedSyncPayload { const parsed = EncryptedSyncPayloadSchema.safeParse(input); if (!parsed.success) { throw new VaultSyncError( VAULT_SYNC_CODES["SYNC.PAYLOAD_INVALID_VERSION"], "error.vault-sync.sync.payload-invalid-version", { context: { issues: parsed.error.issues.length } } ); } return parsed.data; } declare const wireSnapshot: unknown; declare const wireOperation: unknown; const snapshot = VaultSnapshotSchema.parse(wireSnapshot); const operation = SyncOperationSchema.parse(wireOperation); ``` ## API Reference - `VectorClockSchema: ZodSchema>` — keys must be non-empty strings; values must be non-negative integers. - `VaultHistoryEntrySchema: ZodSchema` — strict. - `VaultItemSchema: ZodSchema` — strict; `folderId` is `string | null`; `history` is an array; `clock` validated by `VectorClockSchema`. - `MergeStrategySchema: ZodUnion<[lww, append, atomic]>`. - `SyncOperationKindSchema: ZodUnion<[create, update, delete]>`. - `SyncOperationSchema: ZodSchema` — strict; `fields` validated with `VaultItemSchema.partial()` so any subset of vault fields is acceptable. - `VaultSnapshotSchema: ZodSchema` — strict. - `EncryptedSyncPayloadSchema: ZodSchema` — `version` must equal `"v1"`; `nonce` must be exactly 24 bytes (XChaCha20). ## Implementation Notes Strict mode (`.strict()`) is intentional — `vault-sync` is a wire boundary, and silently accepting unknown fields opens a downgrade attack where a malicious peer adds a future-version field that gets ignored. The `nonce` byte-length check is duplicated (also enforced by `crypto-cipher`'s XChaCha primitive) so callers parsing a payload without attempting to decrypt still see a clear schema-level failure. All schemas are pure values — they take no constructor arguments, they have no shared state, and they are safe to use in any execution context.