import { describe, expect, it } from 'bun:test'; import { Database } from 'bun:sqlite'; import { readSyncMeta, writeSyncMeta, hasSyncedBefore } from './sync-meta'; // Moving an account's sync position out of Postgres and into its own emails.db. Both failure modes are // expensive and neither is loud, so they are pinned here: // // migrate when we should not -> a restored older mailbox inherits a newer position and SKIPS mail // fail to migrate -> an existing account looks brand new and re-downloads everything const freshDb = () => { const db = new Database(':memory:'); db.exec('CREATE TABLE IF NOT EXISTS sync_meta (key TEXT PRIMARY KEY, value TEXT)'); return db; }; describe('readSyncMeta', () => { it('reads what the file already knows', () => { const db = freshDb(); writeSyncMeta(db, { last_sync_at: '2026-01-01T00:00:00Z', 'imap_lastuid:INBOX': '4200' }); expect(readSyncMeta(db)).toEqual({ last_sync_at: '2026-01-01T00:00:00Z', 'imap_lastuid:INBOX': '4200' }); }); it('migrates from Postgres exactly once, when the file has nothing', () => { // The account existed before the move. Without this it looks like a first sync and re-downloads // the entire mailbox. const db = freshDb(); const pg = { last_sync_at: '2026-01-01T00:00:00Z', 'imap_uidvalidity:INBOX': '99' }; expect(readSyncMeta(db, pg)).toEqual({ last_sync_at: '2026-01-01T00:00:00Z', 'imap_uidvalidity:INBOX': '99' }); // Backfilled, so the fallback is never consulted again. expect(readSyncMeta(db)).toEqual({ last_sync_at: '2026-01-01T00:00:00Z', 'imap_uidvalidity:INBOX': '99' }); }); it('NEVER lets Postgres override a position the file already has', () => { // The dangerous direction. Restore an older emails.db onto a server whose Postgres row is newer, // and topping up from Postgres would advance past mail this file does not contain — skipped // permanently, because nothing looks below lastuid again. The file wins, always. const db = freshDb(); writeSyncMeta(db, { 'imap_lastuid:INBOX': '100' }); const meta = readSyncMeta(db, { 'imap_lastuid:INBOX': '9999', last_sync_at: '2026-06-01T00:00:00Z' }); expect(meta['imap_lastuid:INBOX']).toBe('100'); expect(meta.last_sync_at).toBeUndefined(); }); it('ignores non-string values rather than stringifying them', () => { // The Postgres column is free-form jsonb. An object coerced to "[object Object]" would be a // position that parses as a number nowhere and compares as garbage. const db = freshDb(); expect(readSyncMeta(db, { good: 'yes', bad: { nested: true }, alsoBad: 42 } as never)).toEqual({ good: 'yes' }); }); it('is empty for a genuinely new account', () => { expect(readSyncMeta(freshDb(), {})).toEqual({}); expect(readSyncMeta(freshDb(), null)).toEqual({}); }); }); describe('writeSyncMeta', () => { it('upserts rather than duplicating, so a checkpoint mid-sync is safe to repeat', () => { const db = freshDb(); writeSyncMeta(db, { 'imap_lastuid:INBOX': '10' }); writeSyncMeta(db, { 'imap_lastuid:INBOX': '20' }); expect(readSyncMeta(db)).toEqual({ 'imap_lastuid:INBOX': '20' }); }); it('skips null and undefined instead of writing them as text', () => { // "null" as a stored lastuid would parse to NaN and compare false against every real UID. const db = freshDb(); writeSyncMeta(db, { a: '1', b: null, c: undefined }); expect(readSyncMeta(db)).toEqual({ a: '1' }); }); it('stores numbers as their text form, since UIDs arrive both ways', () => { const db = freshDb(); writeSyncMeta(db, { 'imap_lastuid:INBOX': 4200 }); expect(readSyncMeta(db)['imap_lastuid:INBOX']).toBe('4200'); }); }); describe('hasSyncedBefore', () => { it('is false for a new account and true once the file records a sync', () => { const db = freshDb(); expect(hasSyncedBefore(db)).toBe(false); writeSyncMeta(db, { last_sync_at: '2026-01-01T00:00:00Z' }); expect(hasSyncedBefore(db)).toBe(true); }); it('is true for an account that synced before the move but has not migrated yet', () => { // The whole point: an unmigrated account must not be treated as new. This is the check that stands // between an existing user and an unnecessary full re-sync of their mailbox. expect(hasSyncedBefore(freshDb(), { last_sync_at: '2026-01-01T00:00:00Z' })).toBe(true); }); it('is false when Postgres holds a position but no completed sync', () => { // Folder UIDs without last_sync_at means a sync started and never finished. expect(hasSyncedBefore(freshDb(), { 'imap_uidvalidity:INBOX': '99' })).toBe(false); }); });