127 lines
13 KiB
Markdown
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
|
|
```
|
|
|