# vault items _(no submodules)_ - [migrations](./migrations/migrations.md) — _(no submodules)_- [helpers](./helpers.md) — `items-helpers.ts` extracts the pure transformation helpers used by the items repository: row-to-item projection (with… - [items](./items.md) — _(no submodules)_- migrations — _(no submodule… - [migrations](./migrations/migrations.md) — _(no submodules)_- [helpers](./helpers.md) — `items-helpers.ts` extracts the pure transformation helpers used by the items repository: row-to-item projection (with… - [items](./items.md) — _(no submodules)_- [migrations](./migrations/migrations.md) — _(no submodules)_- [helpers](./helpers.md) — `items-helpers.ts` extracts the pure transformation helpers used by the items repository: row-to-item projection (with… - [items](./items.md) — _(no submodules)_- migrations — _(no submodules)_- [helpers](./helpers.md) — `items-helpers.ts` extracts the pure transformation helpers used by the items repository: row-to-item projection (with… - [items](./items.md) — _(no submodules)_- migrations — _(no submodul… - [migrations](./migrations/migrations.md) — _(no submodules)_- [helpers](./helpers.md) — `items-helpers.ts` extracts the pure transformation helpers used by the items repository: row-to-item projection (with… - [items](./items.md) — _(no submodules)_ ## Purpose `items.ts` exposes the `VaultItems` class, the in-memory CRUD repository over the vault container's item map. It is the boundary between the public `vault.items` surface and the underlying state — every public method validates input via Zod, mutates the container `Map`, appends an audit entry to the container history, encrypts concealed-field values per item, and notifies the orchestrator that a flush is due. The repository operates on the in-memory state loaded from the encrypted container blob. It does NOT touch drive directly; persistence is the orchestrator's job (debounced flush + on lock). Concealed-field values (passwords / PINs / secure notes) are encrypted with per-item keys derived from the vault key, so even a leaked container snapshot keeps concealed values as ciphertext until decrypted on demand by `rowToItem`. ## Features - `create(fields) → VaultItem` — Zod-validated insert with concealed-field encryption. - `get(id) → VaultItem | null` — lazy decryption; returns null for missing or tombstoned ids. - `update(id, patch, expectedVersion?) → VaultItem` — optimistic concurrency via `version`; throws `VAULT.ITEM.VERSION_CONFLICT` on stale writes. - `delete(id)` — tombstone (not physical delete) so sync can propagate the deletion. - `list(options?) → VaultItem[]` — filters by category / favorite, with offset / limit pagination. - `allRows()` — snapshot of non-deleted rows for the search index. - Every operation records a histogram sample and an outcome counter; OTel attributes are limited to `{ op, status }` — no item ids, no field names, no plaintext. - Mutations call `onMutation()` so the orchestrator can debounce flushes. ## Usage: Basic Example ```ts import { VaultItems } from "@suaveplan/vault/items/items"; const items = new VaultItems({ state, vaultKey, clock: Date.now, rng: undefined, onMutation: () => scheduleFlush(), }); const created = items.create({ title: "GitHub", category: "login", fields: { username: "alice", url: "https://github.com" }, concealedFields: { password: "p@ssw0rd" }, tags: ["work"], favorite: true, }); ``` ## Usage: Advanced Example ```ts import { VaultItems } from "@suaveplan/vault/items/items"; import { VaultError, VAULT_CODES } from "@suaveplan/vault/errors"; // Optimistic concurrency: capture version, retry on conflict. function updateWithRetry(items: VaultItems, id: string, patch: Partial) { for (let attempt = 0; attempt < 3; attempt++) { const current = items.get(id); if (current === null) throw new Error("missing"); try { return items.update(id, patch, current.version); } catch (err) { if ( VaultError.is(err) && err.code === VAULT_CODES["ITEM.VERSION_CONFLICT"] && attempt < 2 ) continue; throw err; } } } ``` ## API Reference - `class VaultItems` — public surface for `vault.items`. - `constructor(options: ItemsOptions)`. - `create(fields: ItemFields): VaultItem` — throws `ITEM.VALIDATION_FAILED`. - `get(id: string): VaultItem | null`. - `update(id: string, patch: Partial, expectedVersion?: number): VaultItem` — throws `ITEM.NOT_FOUND` / `ITEM.VERSION_CONFLICT` / `ITEM.VALIDATION_FAILED`. - `delete(id: string): void` — throws `ITEM.NOT_FOUND`. - `list(options?: ListOptions): VaultItem[]` — throws `ITEM.VALIDATION_FAILED`. - `allRows(): VaultItemRow[]` — read-only snapshot for search. - `interface ItemsOptions` — `{ state, vaultKey, clock, rng, onMutation }`. ## Implementation Notes - The repository is **stateful** — it holds references to the container state map, the vault key, and the orchestrator's mutation callback. The vault layer creates a new `VaultItems` on every unlock; the state map is replaced when the container reloads from drive. - `update` always increments `version` by 1 per successful call. Concurrent writers using `expectedVersion` will see exactly one winner; the others receive `VAULT.ITEM.VERSION_CONFLICT`. - `delete` is a tombstone — the row stays in the map with `deleted: true` so the sync layer can propagate the deletion. A future garbage-collection pass (out of scope for this version) would prune tombstones older than a retention window. - The history log is append-only: every successful `create` / `update` / `delete` appends one row with `(itemId, version, timestamp, operation)`. This feeds the audit-trail and CRDT merge paths. - `list` walks the map insertion order — the same order in which rows were created or last updated. Callers that need stable cross-process ordering should sort by `createdAt` or `updatedAt` after fetch. - The OTel `outcome` counter uses a fixed allowlist (`success | not_found | conflict | rejected`) — adding a new value requires an OpenSpec change in lockstep with `getVaultInstruments`.