import { describe, expect, it } from 'vitest'; import { exportResource, mergeVault, type VaultProfile } from './accountVault'; import type { SavedResource } from '../database'; const resource = (modifiedAt = 10): SavedResource => ({ id: 'AAAAAAAAAAAAAAAAAAAAAA', kind: 'channel', mode: 'enc', role: 'owner', link: 'https://drop.test/c/a#k=secret', endpointSecret: new Uint8Array(32).fill(7), localScope: 'account:alice', createdAt: 1, modifiedAt, expiresAt: 100, maxMembers: 3, name: `version-${modifiedAt}` }); const profile = (): VaultProfile => ({ v: 3, keys: { publicKey: {}, privateKey: {}, signing: { publicKey: {}, privateKey: {} } }, resources: [exportResource(resource(20))], deletes: [] }); describe('account vault portability and merge', () => { it('never synchronizes device identity or local scope', () => { const exported = exportResource(resource()); expect(exported).not.toHaveProperty('endpointSecret'); expect(exported).not.toHaveProperty('localScope'); expect(exported.link).toContain('secret'); }); it('a stale device does not overwrite a newer remote resource', () => { expect(mergeVault(profile(), [resource(10)], []).resources[0]?.name).toBe('version-20'); }); it('resource removal survives a stale device syncing its old copy', () => { const remote = { ...profile(), resources: [], deletes: [{ id: resource().id, modifiedAt: 30 }] }; expect(mergeVault(remote, [resource(20)], []).resources).toEqual([]); expect(mergeVault(profile(), [], [{ id: resource().id, modifiedAt: 30 }]).resources).toEqual([]); }); it('explicitly rejoining after removal restores the resource', () => { const remote = { ...profile(), resources: [], deletes: [{ id: resource().id, modifiedAt: 30 }] }; const merged = mergeVault(remote, [resource(40)], []); expect(merged.resources).toHaveLength(1); expect(merged.deletes).toEqual([]); }); });