refactor(sync): extract stats-sync engine behind a DB-driver interface

Move snapshot/merge/quiescence engine and ssh helpers from launcher/sync
into src/core/services/stats-sync, parameterized on a minimal SyncDb
driver. The launcher binds it to bun:sqlite via launcher/sync/bun-driver;
the sync command becomes a thin adapter over the shared sync flow.
This commit is contained in:
2026-07-11 20:14:28 -07:00
parent 93d4bbe9a5
commit 04095eebf7
15 changed files with 1124 additions and 897 deletions
+5 -42
View File
@@ -43,48 +43,11 @@ export function queryLocalWatchHistory(dbPath: string): HistoryVideoRow[] {
return withReadonlyWalRetry(dbPath, (options) => readHistoryRows(dbPath, options));
}
export function withReadonlyWalRetry<T>(
dbPath: string,
query: (options: { readonly?: boolean; readwrite?: boolean; create?: boolean }) => T,
): T {
try {
return query({ readonly: true });
} catch (error) {
if (!isReadonlyWalRetryError(error, dbPath)) throw error;
return query({ readwrite: true, create: false });
}
}
export function isReadonlyWalRetryError(error: unknown, dbPath: string): boolean {
if (!isWalModeSqliteDatabase(dbPath)) return false;
const code =
typeof error === 'object' && error !== null && 'code' in error
? String((error as { code?: unknown }).code ?? '')
: '';
const message = error instanceof Error ? error.message : String(error);
const text = `${code} ${message}`.toLowerCase();
return (
text.includes('readonly') ||
text.includes('read-only') ||
text.includes('attempt to write a readonly database') ||
text.includes('sqlite_cantopen') ||
text.includes('unable to open database file')
);
}
function isWalModeSqliteDatabase(dbPath: string): boolean {
const header = Buffer.alloc(20);
let fd: number | null = null;
try {
fd = fs.openSync(dbPath, 'r');
if (fs.readSync(fd, header, 0, header.length, 0) < header.length) return false;
} catch {
return false;
} finally {
if (fd !== null) fs.closeSync(fd);
}
return header.subarray(0, 16).toString('ascii') === 'SQLite format 3\0' && header[18] === 2;
}
export {
withReadonlyWalRetry,
isReadonlyWalRetryError,
} from '../src/core/services/stats-sync/wal-retry.js';
import { withReadonlyWalRetry } from '../src/core/services/stats-sync/wal-retry.js';
function tableExists(db: Database, tableName: string): boolean {
return Boolean(