import { VAULT_PLUGIN_CODES, VaultPluginError, } from "../../src/error-codes/error-codes.js"; import type { VaultService } from "../../src/services/vault-service.js"; import type { VaultHandle, VaultItem, VaultItemSummary, } from "../../src/types/types.js"; /** * Lightweight in-memory `VaultService` used by unit tests so route * coverage does not pay for a real Argon2id pipeline. Stores items in a * per-principal Map. */ export interface FakeVaultServiceOptions { /** Maps principalId → expected password. Wrong password rejects. */ readonly passwords?: Record; } export function createFakeVaultService( options?: FakeVaultServiceOptions ): VaultService { const passwords = options?.passwords ?? {}; const byPrincipal = new Map>(); const handles = new WeakMap(); let idCounter = 0; function bucket(principalId: string): Map { let b = byPrincipal.get(principalId); if (b === undefined) { b = new Map(); byPrincipal.set(principalId, b); } return b; } function getState(handle: VaultHandle) { const s = handles.get(handle); if (s === undefined) { throw new VaultPluginError( VAULT_PLUGIN_CODES.FORBIDDEN, "fake handle invalid", { context: { statusCode: 403 } } ); } return s; } return { async openForPrincipal(principal, password) { const expected = passwords[principal.id]; if (expected !== undefined && expected !== password) { throw new VaultPluginError( VAULT_PLUGIN_CODES.UNLOCK_FAILED, "fake unlock failed", { context: { statusCode: 401 } } ); } const handle: VaultHandle = Object.freeze({ __brand: "VaultHandle" as const, principalId: principal.id, }); handles.set(handle, { principalId: principal.id }); return handle; }, async listItemsForOwner(ownerId) { const b = byPrincipal.get(ownerId); if (b === undefined) return []; const out: VaultItemSummary[] = []; for (const i of b.values()) { const { body: _b, ...rest } = i; void _b; out.push(rest); } return out; }, async listItems(handle) { const { principalId } = getState(handle); return Array.from(bucket(principalId).values()); }, async readItem(handle, itemId) { const { principalId } = getState(handle); return bucket(principalId).get(itemId) ?? null; }, async createItem(handle, input) { const { principalId } = getState(handle); idCounter += 1; const now = new Date().toISOString(); const item: VaultItem = { id: `item-${idCounter}`, ownerId: principalId, title: input.title, kind: input.kind, body: input.body, createdAt: now, updatedAt: now, ...(input.metadata !== undefined ? { metadata: input.metadata } : {}), }; bucket(principalId).set(item.id, item); return item; }, async updateItem(handle, itemId, patch) { const { principalId } = getState(handle); const existing = bucket(principalId).get(itemId); if (existing === undefined) return null; const updated: VaultItem = { ...existing, ...(patch.title !== undefined ? { title: patch.title } : {}), ...(patch.kind !== undefined ? { kind: patch.kind } : {}), ...(patch.body !== undefined ? { body: patch.body } : {}), ...(patch.metadata !== undefined ? { metadata: patch.metadata } : {}), updatedAt: new Date().toISOString(), }; bucket(principalId).set(itemId, updated); return updated; }, async deleteItem(handle, itemId) { const { principalId } = getState(handle); return bucket(principalId).delete(itemId); }, async close(handle) { handles.delete(handle); }, }; }