Files
skills/docs/security-stack/security/vault-sync/src/schemas/schemas.md
2026-05-29 08:20:56 +01:00

3.9 KiB

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<string, non-negative-int>
  • 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

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

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<Record<string, number>> — keys must be non-empty strings; values must be non-negative integers.
  • VaultHistoryEntrySchema: ZodSchema<VaultHistoryEntry> — strict.
  • VaultItemSchema: ZodSchema<VaultItem> — 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<SyncOperation> — strict; fields validated with VaultItemSchema.partial() so any subset of vault fields is acceptable.
  • VaultSnapshotSchema: ZodSchema<VaultSnapshot> — strict.
  • EncryptedSyncPayloadSchema: ZodSchema<EncryptedSyncPayload> — 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.