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 83 84 85 86 87 88 89 | 1x 1x 1x 1x 1x 1x 4x 4x 2x 2x 1x 2x 1x 2x 1x 1x 14x 8x 8x 7x 4x 4x 3x 3x 3x 4x 4x 4x 4x 5x 5x 1x 7x 7x | import { getLibsqlUrl } from '@api/constants';
import type {
CacheStorageConnector,
LogsStorageConnector,
UserDataStorageConnector,
} from '@api/types/connector';
import type { AppContext } from '@api/types/hono';
import { info } from '@shared/console-logging';
import {
getLibsqlClient,
libsqlCacheStorageConnector,
libsqlLogsStorageConnector,
libsqlUserDataStorageConnector,
migrateLibsql,
} from './libsql';
import {
supabaseCacheStorageConnector,
supabaseLogsStorageConnector,
supabaseUserDataStorageConnector,
} from './supabase';
/**
* Storage backend selection.
*
* Setting `LIBSQL_URL` chooses libSQL; leaving it unset keeps Supabase, which
* is what every existing deployment does. One variable covers both shapes
* because the URL scheme carries the rest of the decision: `file:` is an
* embedded database for the single-container deployment, `libsql://` or
* `https://` is a remote one for Workers or any multi-instance deployment.
*
* The choice is made per request rather than at module load because on
* Cloudflare Workers there is no environment until a request arrives — `c.env`
* is populated from the request context, and `server.ts` merges `process.env`
* into it so Node resolves the same way.
*/
export const usesLibsql = (c: AppContext): boolean => Boolean(getLibsqlUrl(c));
export const resolveUserDataConnector = (
c: AppContext,
): UserDataStorageConnector =>
usesLibsql(c)
? libsqlUserDataStorageConnector
: supabaseUserDataStorageConnector;
export const resolveLogsConnector = (c: AppContext): LogsStorageConnector =>
usesLibsql(c) ? libsqlLogsStorageConnector : supabaseLogsStorageConnector;
export const resolveCacheConnector = (c: AppContext): CacheStorageConnector =>
usesLibsql(c) ? libsqlCacheStorageConnector : supabaseCacheStorageConnector;
/**
* Migration state for the life of the process (or the Worker isolate).
*
* The promise is cached rather than a boolean so that requests arriving while
* the first migration is still running wait for it instead of starting their
* own. A failure clears the cache so the next request retries rather than
* inheriting a rejected promise forever.
*
* Postgres is migrated by the `migrations` service in docker-compose, so this
* only ever applies to libSQL.
*/
let migration: Promise<void> | null = null;
export const ensureStorageReady = async (c: AppContext): Promise<void> => {
if (!usesLibsql(c)) {
return;
}
if (!migration) {
migration = migrateLibsql(getLibsqlClient(c))
.then((applied) => {
if (applied.length > 0) {
info(`[libsql] applied ${applied.length} migration(s)`);
}
})
.catch((e: unknown) => {
migration = null;
throw e;
});
}
await migration;
};
/** Test helper: forget that migrations have run. */
export const resetStorageReady = (): void => {
migration = null;
};
|