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

127 lines
13 KiB
Markdown

# @suaveplan/vault-sync - Domain-specific sync and conflict-resolution engine for the Vaulted password-manager ecosystem: vector-clock causal ordering, CRDT merge strategies (LWW / append / atomic), RFC 6902 JSON Patch incremental sync, durable offline queue with operation collapsing, and end-to-end-encrypted sync payloads via XChaCha20-Poly1305.
## Summary
Domain-specific sync and conflict-resolution engine for the Vaulted
password-manager ecosystem. Builds on `@suaveplan/crdt` and
`@suaveplan/diff` (RFC 6902 JSON Patch) to provide offline-first,
end-to-end-encrypted vault synchronisation. Implements vault-item merge
strategies (last-write-wins for passwords, append-only for audit history,
atomic for folder moves), durable queues with operation collapsing,
vector-clock causal ordering, and XChaCha20-Poly1305 sync payloads.
<!-- begin:auto-docs -->
## Documentation tree
- [crypto-sync](./src/crypto-sync/crypto-sync.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [crypto-sync](./src/crypto-sync/crypto-sync.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [codes](./src/errors/codes.md) — `codes.ts` defines the canonical, frozen registry of every fully-qualified error code emitted by `@suaveplan/vault-sync…
- [vault-sync-error](./src/errors/vault-sync-error.md) — `VaultSyncError` is the single concrete error class thrown from every production path inside `@suaveplan/vault-sync`. I…
- [merge](./src/merge/merge.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [merge](./src/merge/merge.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [otel](./src/otel/instruments.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [instruments](./src/otel/instruments.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [patch](./src/patch/patch.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [patch](./src/patch/patch.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [queue](./src/queue/queue.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [queue](./src/queue/queue.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [types](./src/types/types.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [types](./src/types/types.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [vector-clock](./src/vector-clock/vector-clock.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [vector-clock](./src/vector-clock/vector-clock.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
<!-- end:auto-docs --> - [crypto-sync](./src/crypto-sync/crypto-sync.md) — <!-- begin:auto-docs --> _(no submodules)_- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_- [codes](./src/errors/codes.md) — `codes.ts` defines the canonical, frozen registry of every fully-qualified error code emitted by `@suaveplan/vault-sync…
- [vault-sync-error](./src/errors/vault-sync-error.md) — `VaultSyncError` is the single concrete error class thrown from every production path inside `@suaveplan/vault-sync`. I…
- [merge](./src/merge/merge.md) — <!-- begin:auto-docs --> _(no submodules)_- [merge](./src/merge/merge.md) — <!-- begin:auto-docs --> _(no submodules)_- [otel](./src/otel/instruments.md) — <!-- begin:auto-docs --> _(no submodules)_- [instruments](./src/otel/instruments.md) — <!-- begin:auto-docs --> _(no submodules)_- [patch](./src/patch/patch.md) — <!-- begin:auto-docs --> _(no submodules)_- [patch](./src/patch/patch.md) — <!-- begin:auto-docs --> _(no submodules)_- [queue](./src/queue/queue.md) — <!-- begin:auto-docs --> _(no submodules)_- [queue](./src/queue/queue.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/types/types.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/types/types.md) — <!-- begin:auto-docs --> _(no submodules)_- [vector-clock](./src/vector-clock/vector-clock.md) — <!-- begin:auto-docs --> _(no submodules)_- [vector-clock](./src/vector-clock/vector-clock.md) — <!-- begin:auto-docs --> _(no submodules)_- [crypto-sync](./src/crypto-sync/crypto-sync.md) — <!-- begin:auto-docs --> _(no submodules)_- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_- [codes](./src/errors/codes.md) — `codes.ts` defines the canonical, frozen registry of every fully-qualified error code emitted by `@suaveplan/vault-sync…
- [vault-sync-error](./src/errors/vault-sync-error.md) — `VaultSyncError` is the single concrete error class thrown from every production path inside `@suaveplan/vault-sync`. I…
- [merge](./src/merge/merge.md) — <!-- begin:auto-docs --> _(no submodules)_- [merge](./src/merge/merge.md) — <!-- begin:auto-docs --> _(no submodules)_- [otel](./src/otel/instruments.md) — <!-- begin:auto-docs --> _(no submodules)_- [instruments](./src/otel/instruments.md) — <!-- begin:auto-docs --> _(no submodules)_- [patch](./src/patch/patch.md) — <!-- begin:auto-docs --> _(no submodules)_- [patch](./src/patch/patch.md) — <!-- begin:auto-docs --> _(no submodules)_- [queue](./src/queue/queue.md) — <!-- begin:auto-docs --> _(no submodules)_- [queue](./src/queue/queue.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/types/types.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/types/types.md) — <!-- begin:auto-docs --> _(no submodules)_- [vector-clock](./src/vector-clock/vector-clock.md) — <!-- begin:auto-docs --> _(no submodules)_- [vector-clock](./src/vector-clock/vector-clock.md) — <!-- begin:auto-docs --> _(no submodules)_- [crypto-sync](./src/crypto-sync/crypto-sync.md) — <!-- begin:auto-docs --> _(no submodules)_- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_- [codes](./src/errors/codes.md) — `codes.ts` defines the canonical, frozen registry of every fully-qualified error code emitted by `@suaveplan/vault-sync…
- [vault-sync-error](./src/errors/vault-sync-error.md) — `VaultSyncError` is the single concrete error class thrown from every production path inside `@suaveplan/vault-sync`. I…
- [merge](./src/merge/merge.md) — <!-- begin:auto-docs --> _(no submodules)_- [merge](./src/merge/merge.md) — <!-- begin:auto-docs --> _(no submodules)_- [otel](./src/otel/instruments.md) — <!-- begin:auto-docs --> _(no submodules)_- [instruments](./src/otel/instruments.md) — <!-- begin:auto-docs --> _(no submodules)_- [patch](./src/patch/patch.md) — <!-- begin:auto-docs --> _(no submodules)_- [patch](./src/patch/patch.md) — <!-- begin:auto-docs --> _(no submodules)_- [queue](./src/queue/queue.md) — <!-- begin:auto-docs --> _(no submodules)_- [queue](./src/queue/queue.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/types/types.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/types/types.md) — <!-- begin:auto-docs --> _(no submodules)_- [vector-clock](./src/vector-clock/vector-clock.md) — <!-- begin:auto-docs --> _(no submodules)_- [vector-clock](./src/vector-clock/vector-clock.md) — <!-- begin:auto-docs --> _(no submodules)_- [crypto-sync](./src/crypto-sync/crypto-sync.md) — <!-- begin:auto-docs --> _(no submodules)_- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_ - [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_- [codes](./src/errors/codes.md) — `codes.ts` defines the canonical, frozen registry of every fully-qualified error code emitted by `@suaveplan/vault-sync…
- [vault-sync-error](./src/errors/vault-sync-error.md) — `VaultSyncError` is the single concrete error class thrown from every production path inside `@suaveplan/vault-sync`. I…
- [merge](./src/merge/merge.md) — <!-- begin:auto-docs --> _(no submodules)_ - [merge](./src/merge/merge.md) — <!-- begin:auto-docs --> _(no submodules)_- [otel](./src/otel/instruments.md) — <!-- begin:auto-docs --> _(no submodules)_ - [instruments](./src/otel/instruments.md) — <!-- begin:auto-docs --> _(no submodules)_- [patch](./src/patch/patch.md) — <!-- begin:auto-docs --> _(no submodules)_ - [patch](./src/patch/patch.md) — <!-- begin:auto-docs --> _(no submodules)_- [queue](./src/queue/queue.md) — <!-- begin:auto-docs --> _(no submodules)_ - [queue](./src/queue/queue.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ - [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/types/types.md) — <!-- begin:auto-docs --> _(no submodules)_ - [types](./src/types/types.md) — <!-- begin:auto-docs --> _(no submodules)_- [vector-clock](./src/vector-clock/vector-clock.md) — <!-- begin:auto-docs --> _(no submodules)_ - [vector-clock](./src/vector-clock/vector-clock.md) — <!-- begin:auto-docs --> _(no submodules)_
## Install
```bash
bun add @suaveplan/vault-sync
```
## Quick start
```ts
import {
applyPatch,
decryptSyncPayload,
diffVaultItems,
encryptSyncPayload,
mergeVaultItems,
SyncEngine,
SyncQueue,
VaultSyncError,
} from "@suaveplan/vault-sync";
const local = {
id: "i1",
title: "Email",
password: "old",
folderId: null,
history: [],
nodeId: "device-a",
updatedAt: 1,
clock: { "device-a": 1 },
};
const remote = { ...local, password: "new", updatedAt: 2 };
const merged = mergeVaultItems(local, remote, "lww");
const patch = diffVaultItems(local, merged);
const restored = applyPatch(local, patch);
const queue = new SyncQueue({ nodeId: "device-a" });
queue.enqueue({ kind: "update", itemId: "i1", fields: { password: "new" } });
const drained = queue.flush();
const key = crypto.getRandomValues(new Uint8Array(32));
const envelope = encryptSyncPayload(new TextEncoder().encode("snap"), key);
const plaintext = decryptSyncPayload(envelope, key);
```
## Modules
- [merge](./src/merge/merge.md) — `mergeVaultItems` with `lww` / `append` / `atomic`
- [patch](./src/patch/patch.md) — RFC 6902 diff and apply for vault items
- [engine](./src/engine/engine.md) — `SyncEngine` orchestrator (`pull` / `push` / `sync`)
- [queue](./src/queue/queue.md) — `SyncQueue` durable mutation buffer
- [crypto-sync](./src/crypto-sync/crypto-sync.md) — XChaCha20-Poly1305 envelope
- [vector-clock](./src/vector-clock/vector-clock.md) — causal-ordering primitives
- [errors / codes](./src/errors/codes.md) — `VAULT_SYNC_CODES`
- [errors / VaultSyncError](./src/errors/vault-sync-error.md) — `VaultSyncError`
- [otel](./src/otel/instruments.md) — OTel meter / tracer accessors
- [schemas](./src/schemas/schemas.md) — Zod schemas for every public boundary
- [types](./src/types/types.md) — types-only contracts
## Error codes
| Code | Thrown by |
|---|---|
| `VAULTSYNC.MERGE.STRATEGY_UNKNOWN` | `mergeVaultItems` / `assertMergeStrategy` |
| `VAULTSYNC.MERGE.CONFLICT_UNRESOLVED` | `mergeVaultItems` (atomic) / id mismatch |
| `VAULTSYNC.PATCH.INVALID` | `applyPatch` |
| `VAULTSYNC.SYNC.PAYLOAD_TAMPERED` | `decryptSyncPayload` |
| `VAULTSYNC.SYNC.PAYLOAD_INVALID_VERSION` | `decryptSyncPayload` |
| `VAULTSYNC.SYNC.PAYLOAD_TOO_LARGE` | `encryptSyncPayload` |
| `VAULTSYNC.SYNC.TRANSPORT_FAILED` | `SyncEngine.pull` / `SyncEngine.push` |
| `VAULTSYNC.QUEUE.DEPTH_EXCEEDED` | `SyncQueue.enqueue` |
| `VAULTSYNC.QUEUE.SERIALIZATION_FAILED` | `SyncQueue.serialize` / `SyncQueue.deserialize` |
| `VAULTSYNC.VECTOR_CLOCK.REGRESSION` | `increment` (saturation guard) |
## Testing & coverage
```bash
bunx turbo test --filter=@suaveplan/vault-sync
bunx turbo test:coverage --filter=@suaveplan/vault-sync # 100/100/100/100
bunx turbo lint typecheck --filter=@suaveplan/vault-sync
```