| 21 | * PRAGMAs (foreign_keys + WAL). Used for the long-lived FumaDB handle. |
| 22 | */ |
| 23 | export const openLocalLibsql = async (path: string): Promise<Client> => { |
| 24 | const client = createClient({ url: toLibsqlFileUrl(path) }); |
| 25 | // foreign_keys is strictly per-connection; WAL is a file-level mode set on |
| 26 | // first enabling. Re-apply both since libSQL gives no shared handle. |
| 27 | await client.execute("PRAGMA foreign_keys = ON"); |
| 28 | await client.execute("PRAGMA journal_mode = WAL"); |
| 29 | // busy_timeout is per-connection (default 0 = fail immediately on a lock). |
| 30 | // Under the supervised-daemon model a single process owns this file, but a |
| 31 | // second OS process can still transiently hold the write lock (e.g. a CLI |
| 32 | // tool, the v1→v2 migration reader, or a launchd restart racing the old |
| 33 | // pid). Give writers a 5s retry window instead of an instant SQLITE_BUSY. |
| 34 | // Matches the self-host open path (self-host-db.ts). |
| 35 | await client.execute("PRAGMA busy_timeout = 5000"); |
| 36 | return client; |
| 37 | }; |
| 38 | |
| 39 | const asRows = <T>(result: ResultSet): readonly T[] => |
| 40 | // oxlint-disable-next-line executor/no-double-cast -- boundary: SQLite result columns are the schema contract for T; libSQL rows are narrowed once here |