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 }, strictVaultItemSchema— full canonical vault-item shape, strictMergeStrategySchema—"lww" | "append" | "atomic"SyncOperationKindSchema—"create" | "update" | "delete"SyncOperationSchema— durable-queue entry shape with partialfieldsVaultSnapshotSchema—{ items; clock; snapshotAt }, strictEncryptedSyncPayloadSchema— 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;folderIdisstring | null;historyis an array;clockvalidated byVectorClockSchema.MergeStrategySchema: ZodUnion<[lww, append, atomic]>.SyncOperationKindSchema: ZodUnion<[create, update, delete]>.SyncOperationSchema: ZodSchema<SyncOperation>— strict;fieldsvalidated withVaultItemSchema.partial()so any subset of vault fields is acceptable.VaultSnapshotSchema: ZodSchema<VaultSnapshot>— strict.EncryptedSyncPayloadSchema: ZodSchema<EncryptedSyncPayload>—versionmust equal"v1";noncemust 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.