Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | 1x 1x 1x 1x 1x 1x 239x 239x 179x 179x 60x 239x 239x 239x 239x 239x 1x 184x 184x 1x 1x 1x 1x 183x 183x 1x 61x 2x 2x 59x 59x 59x 1x 101x 101x | import { getLibsqlAuthToken, getLibsqlUrl } from '@api/constants';
import type { AppContext } from '@api/types/hono';
import { type Client, createClient } from '@libsql/client';
/**
* `@libsql/client` declares a `workerd` export condition that resolves to its
* HTTP-only build, so this plain specifier is safe on both runtimes: Node gets
* the full client (local files included) and Workers gets the remote-only one.
* Importing `@libsql/client/node` explicitly would break the Worker bundle.
*/
/**
* One client per URL for the lifetime of the process.
*
* A libSQL client owns a connection pool, so building one per request would
* leak file handles against a local database and sockets against a remote one.
* Keyed by URL so tests can hold several independent databases at once.
*/
const clients = new Map<string, Client>();
/** Applied once per client; SQLite leaves foreign keys unenforced otherwise. */
const initialised = new WeakSet<Client>();
const isFileUrl = (url: string): boolean =>
url.startsWith('file:') || url.startsWith(':memory:');
/**
* Build a client for an explicit URL. Prefer `getLibsqlClient` in request
* handling code; this exists for the migration runner and for tests.
*/
export const createLibsqlClient = (url: string, authToken?: string): Client => {
const existing = clients.get(url);
if (existing) {
return existing;
}
// A remote database rejects an empty auth token, and a local file rejects a
// token it has no use for, so only pass one when it is actually set.
const client = createClient(
authToken && !isFileUrl(url) ? { url, authToken } : { url },
);
clients.set(url, client);
return client;
};
/**
* The client for this deployment's configured database.
*
* Throws when `LIBSQL_URL` is unset rather than falling back to a default path,
* so that a misconfigured deployment fails at the first query instead of
* quietly writing to a file nobody will think to look in.
*/
export const getLibsqlClient = (c: AppContext): Client => {
const url = getLibsqlUrl(c);
if (!url) {
throw new Error(
'LIBSQL_URL is not set. Set it to a file path (file:/app/data/super-agents.db) or a remote libSQL URL (libsql://...).',
);
}
return createLibsqlClient(url, getLibsqlAuthToken(c));
};
/**
* Turn on foreign key enforcement, which SQLite leaves off per connection.
* Without this the schema's ON DELETE CASCADE rules never fire and the libSQL
* backend would silently keep rows Postgres would have removed.
*/
export const ensureForeignKeys = async (client: Client): Promise<void> => {
if (initialised.has(client)) {
return;
}
await client.execute('PRAGMA foreign_keys = ON');
initialised.add(client);
};
/** Test helper: drop cached clients so each case starts from a clean slate. */
export const resetLibsqlClients = (): void => {
clients.clear();
};
|