# VaultSyncError ## Purpose `VaultSyncError` is the single concrete error class thrown from every production path inside `@suaveplan/vault-sync`. It extends the foundational `SuaveplanError` from `@suaveplan/error` and parameterises the `code` field on the literal union `VaultSyncCode` so consumers can switch on `err.code` with full TypeScript exhaustiveness. A unique brand symbol is attached at construction so cross-realm or duck-typed impersonators are rejected by the `VaultSyncError.is(value)` guard. ## Features - Extends `SuaveplanError` for narrowed `code` checks - Brand symbol prevents prototype-chain impersonation across realms - `VaultSyncError.is(value)` runs both `instanceof` and brand verification - Carries structured `context`, `cause`, `traceId`, and `timestamp` from the base - Pairs with the `VAULT_SYNC_CODES` registry so every code in the union is reachable ## Usage: Basic Example ```ts import { VaultSyncError } from "@suaveplan/vault-sync"; import { VAULT_SYNC_CODES } from "@suaveplan/vault-sync/errors"; throw new VaultSyncError( VAULT_SYNC_CODES["MERGE.STRATEGY_UNKNOWN"], "error.vault-sync.merge.strategy-unknown", { context: { strategy: "smart-merge" } } ); ``` ## Usage: Advanced Example ```ts import { VaultSyncError } from "@suaveplan/vault-sync"; import { VAULT_SYNC_CODES } from "@suaveplan/vault-sync/errors"; async function safeFlush(input: () => Promise): Promise<{ ok: true } | { ok: false; code: string }> { try { await input(); return { ok: true }; } catch (err) { // Defence-in-depth: instanceof can break across worker boundaries. if (VaultSyncError.is(err)) { return { ok: false, code: err.code }; } throw err; } } const result = await safeFlush(async () => { throw new VaultSyncError( VAULT_SYNC_CODES["QUEUE.DEPTH_EXCEEDED"], "error.vault-sync.queue.depth-exceeded", { context: { depth: 10_001, limit: 10_000 } } ); }); ``` ## API Reference - `class VaultSyncError extends SuaveplanError` — concrete error type for every failure inside `vault-sync`. - `constructor(code: VaultSyncCode, messageKey: string, options?: SuaveplanErrorOptions)` — `messageKey` is forwarded to the i18n resolver. `options.context` may carry safe-by-construction fields (no key bytes, no plaintext, no item IDs). - `static is(value: unknown): value is VaultSyncError` — narrow guard that verifies both `instanceof` and the unique brand symbol attached at construction. Use whenever errors might cross `iframe`, `Worker`, or serialization boundaries. - Inherited fields: `code`, `message`, `context`, `cause`, `timestamp`, `traceId`. See `@suaveplan/error` for full semantics. ## Implementation Notes The brand symbol is module-private — a third party cannot construct a duck-typed value that satisfies `VaultSyncError.is`. Subclasses are discouraged: if a more specific error is needed, attach metadata via `options.context` rather than introducing a new class. Centralising on a single throwable simplifies dependent-package error handling, reduces `instanceof` chains, and keeps the public API surface minimal. All thrown errors flow through this class — no plain `Error`, no anonymous throws.