Files
2026-05-27 23:47:53 +01:00

22 KiB

@suaveplan/vault - Vault orchestration layer for the Vaulted password-manager ecosystem: drive-backed encrypted SQLite container, lifecycle state machine (open → unlock → lock), per-item field encryption, attachments / shares / sync delegation, and OpaqueKeyHandle boundary enforcement.

Summary

Vault orchestration layer for the Vaulted password-manager ecosystem. Provides a drive-backed encrypted SQLite-style container, a strict locked ↔ unlocked lifecycle state machine, per-item field encryption for concealed values, attachment / share / sync delegation behind injectable adapter interfaces, and OpaqueKeyHandle boundary enforcement so raw key bytes never leave @suaveplan/crypto-vault.

Documentation tree

  • attachments — (no submodules)
  • container — (no submodules)
  • encryption — (no submodules)
  • codes — codes.ts defines the stable error-code registry for @suaveplan/vault. Every failure raised by the orchestration lay…
  • vault-error — vault-error.ts defines VaultError, the concrete SuaveplanError subclass thrown by every public path in `@suavepla…
  • items — (no submodules) - migrations — _(no submodule…
    • migrations — (no submodules)
    • helpers — items-helpers.ts extracts the pure transformation helpers used by the items repository: row-to-item projection (with…
    • items — (no submodules) - migrations — _(no submodule…
  • manifest — (no submodules)
  • otel — (no submodules)
  • schemas — (no submodules)
  • search — (no submodules)
  • shares — (no submodules)
  • sync — (no submodules)
    • sync — (no submodules)
  • types — (no submodules)
    • adapters — adapters.ts defines the Phase-1 adapter contracts the vault orchestration layer uses to talk to blob storage, share-l…
    • types — (no submodules)
  • vault — (no submodules) - wiring — wiring.ts extracts the per-unlock module…
    • lifecycle — lifecycle.ts extracts the two side-effecting helpers that drive the unlock path: deriveVaultKeyBuffer (running 2SKD…
    • vault — (no submodules) - wiring — wiring.ts extracts the per-unlock module…
    • wiring — wiring.ts extracts the per-unlock module factories used by Vault: buildItems, buildSearch, buildAttachments,…
- [attachments](./src/attachments/attachments.md) — _(no submodules)_- [container](./src/container/container.md) — _(no submodules)_- [container](./src/container/container.md) — _(no submodules)_- [encryption](./src/encryption/field-encryption.md) — _(no submodules)_- [field-encryption](./src/encryption/field-encryption.md) — _(no submodules)_- [codes](./src/errors/codes.md) — `codes.ts` defines the stable error-code registry for `@suaveplan/vault`. Every failure raised by the orchestration lay…
  • vault-error — vault-error.ts defines VaultError, the concrete SuaveplanError subclass thrown by every public path in `@suavepla…
  • items — (no submodules)- migrations — (no submodules)- migrations — (no submodules)- helpers — items-helpers.ts extracts the pure transformation helpers used by the items repository: row-to-item projection (with…
    • items — (no submodules)- manifest — (no submodules)- manifest — (no submodules)- otel — (no submodules)- instruments — (no submodules)- schemas — (no submodules)- schemas — (no submodules)- search — (no submodules)- search — (no submodules)- shares — (no submodules)- shares — (no submodules)- sync — (no submodules)- sync — (no submodules)- types — (no submodules)- adapters — adapters.ts defines the Phase-1 adapter contracts the vault orchestration layer uses to talk to blob storage, share-l…
    • types — (no submodules)- vault — (no submodules)- wiring — wiring.ts extracts the per-unlock module…
    • lifecycle — lifecycle.ts extracts the two side-effecting helpers that drive the unlock path: deriveVaultKeyBuffer (running 2SKD…
    • vault — (no submodules)- wiring — wiring.ts extracts the per-unlock module…
    • wiring — wiring.ts extracts the per-unlock module factories used by Vault: buildItems, buildSearch, buildAttachments,…
  • attachments — (no submodules)- container — (no submodules)- container — (no submodules)- encryption — (no submodules)- field-encryption — (no submodules)- codes — codes.ts defines the stable error-code registry for @suaveplan/vault. Every failure raised by the orchestration lay…
  • vault-error — vault-error.ts defines VaultError, the concrete SuaveplanError subclass thrown by every public path in `@suavepla…
  • items — (no submodules)- migrations — <!-- begin:auto…
    • migrations — (no submodules)- migrations — (no submodules)- helpers — items-helpers.ts extracts the pure transformation helpers used by the items repository: row-to-item projection (with…
    • items — (no submodules)- migrations — <!-- begin:auto…
  • manifest — (no submodules)- manifest — (no submodules)- otel — (no submodules)- instruments — (no submodules)- schemas — (no submodules)- schemas — (no submodules)- search — (no submodules)- search — (no submodules)- shares — (no submodules)- shares — (no submodules)- sync — (no submodules)- sync — (no submodules)- types — (no submodules)- adapters — adapters.ts defines the Phase-1 adapter contracts the vault orchestration layer uses to talk to blob storage, share-l…
    • types — (no submodules)- vault — (no submodules)- wiring — wiring.ts extracts the per-unlock module…
    • lifecycle — lifecycle.ts extracts the two side-effecting helpers that drive the unlock path: deriveVaultKeyBuffer (running 2SKD…
    • vault — (no submodules)- wiring — wiring.ts extracts the per-unlock module…
    • wiring — wiring.ts extracts the per-unlock module factories used by Vault: buildItems, buildSearch, buildAttachments,…
  • attachments — (no submodules)- container — (no submodules)- container — (no submodules)- encryption — (no submodules)- field-encryption — (no submodules)- codes — codes.ts defines the stable error-code registry for @suaveplan/vault. Every failure raised by the orchestration lay…
  • vault-error — vault-error.ts defines VaultError, the concrete SuaveplanError subclass thrown by every public path in `@suavepla…
  • items — (no submodules)- migrations — _(no submodul…
    • migrations — (no submodules)- migrations — (no submodules)- helpers — items-helpers.ts extracts the pure transformation helpers used by the items repository: row-to-item projection (with…
    • items — (no submodules)- migrations — _(no submodul…
  • manifest — (no submodules)- manifest — (no submodules)- otel — (no submodules)- instruments — (no submodules)- schemas — (no submodules)- schemas — (no submodules)- search — (no submodules)- search — (no submodules)- shares — (no submodules)- shares — (no submodules)- sync — (no submodules)- sync — (no submodules)- types — (no submodules)- adapters — adapters.ts defines the Phase-1 adapter contracts the vault orchestration layer uses to talk to blob storage, share-l…
    • types — (no submodules)- vault — (no submodules)- wiring — wiring.ts extracts the per-unlock module…
    • lifecycle — lifecycle.ts extracts the two side-effecting helpers that drive the unlock path: deriveVaultKeyBuffer (running 2SKD…
    • vault — (no submodules)- wiring — wiring.ts extracts the per-unlock module…
    • wiring — wiring.ts extracts the per-unlock module factories used by Vault: buildItems, buildSearch, buildAttachments,…
  • attachments — (no submodules)- container — (no submodules) - container — (no submodules)- encryption — (no submodules) - field-encryption — (no submodules)- codes — codes.ts defines the stable error-code registry for @suaveplan/vault. Every failure raised by the orchestration lay…
  • vault-error — vault-error.ts defines VaultError, the concrete SuaveplanError subclass thrown by every public path in `@suavepla…
  • items — (no submodules) - migrations — (no submodules) - migrations — (no submodules) - helpers — items-helpers.ts extracts the pure transformation helpers used by the items repository: row-to-item projection (with…
    • items — (no submodules)- manifest — (no submodules) - manifest — (no submodules)- otel — (no submodules) - instruments — (no submodules)- schemas — (no submodules) - schemas — (no submodules)- search — (no submodules) - search — (no submodules)- shares — (no submodules) - shares — (no submodules)- sync — (no submodules) - sync — (no submodules)- types — (no submodules) - adapters — adapters.ts defines the Phase-1 adapter contracts the vault orchestration layer uses to talk to blob storage, share-l…
    • types — (no submodules)- vault — (no submodules) - lifecycle — lifecycle.ts extracts the two side-effecting helpers that drive the unlock path: deriveVaultKeyBuffer (running 2SKD…
    • vault — (no submodules) - wiring — wiring.ts extracts the per-unlock module factories used by Vault: buildItems, buildSearch, buildAttachments,…

Install

bun add @suaveplan/vault

Quick start

import { Vault } from "@suaveplan/vault";

const vault = Vault.open({
    vaultId: "personal",
    email: "user@example.com",
    containerPath: "/personal.vault",
    attachmentsPrefix: "/personal/attachments",
    argon2id: { memoryKB: 65536, iterations: 3, parallelism: 4, outputLength: 32 },
    argon2idSalt: argon2idSaltBytes,
    drive,
    driveSharing,
    sync,
});

await vault.unlock(password, secretKey);

const item = vault.items.create({
    title: "GitHub",
    category: "login",
    fields: { username: "alice", url: "https://github.com" },
    concealedFields: { password: "p@ssw0rd" },
    tags: ["work"],
    favorite: true,
});

const fetched = vault.items.get(item.id);
const matches = vault.search.search({ query: "github", category: "login" });

await vault.lock(); // zeroizes all key material

Modules

Security model

  • 2SKD: Argon2id(HMAC-SHA256(secretKey, password ‖ 0x00 ‖ email), salt, params) produces the AUK, which is HKDF-derived through personal-keyset → vault-key → item-key. Intermediate buffers are zeroized eagerly.
  • OpaqueKeyHandle boundary: the vault key is wrapped in a SecureBuffer and accessed only through @suaveplan/crypto-vault's unwrap — never as raw bytes across module boundaries.
  • Defence in depth: even if the drive-level AEAD is compromised, concealed fields (passwords, PINs, secure notes) remain encrypted with per-item keys inside the SQLite-style container.
  • Manifest binding: the bitpacker-packed manifest header is bound as AAD to the container's AEAD, so any tampering invalidates the authentication tag.
  • zeroizeAll() on lock: every live SecureBuffer is overwritten with zeros and the references released.

Performance

  • Unlock is dominated by Argon2id (≥ 64 MiB / 3 iterations / parallelism configurable). Default parameters ship at OWASP minimums.
  • Items, search, attachments, and share operations are all in-memory after unlock; flushes are debounced (default 500 ms; configurable via flushDebounceMs).
  • Drive I/O happens twice per unlock at most: once on read, once for the freshly-encrypted blob if creating a new vault. Ongoing operations only touch drive on flush + lock.

Phased delivery

This is the Phase-1 landing. Adapter interfaces (DriveLike, DriveSharingLike, VaultSyncLike) are defined inline; production wiring binds the real @suaveplan/drive, @suaveplan/drive-sharing, and @suaveplan/vault-sync packages without changes to this surface.