import type { Migration, MigrationProvider } from 'kysely/migration'; import { Migrator } from 'kysely/migration'; import type { Kysely } from 'kysely'; import type { Database } from '../schema.js'; /** * The migration registry. * * Deliberately a static import map rather than Kysely's `FileMigrationProvider`: filesystem * discovery cannot work inside a Cloudflare Worker, where there is no `fs` and the bundle is a * single file. An explicit map is the only form that works identically in Node, in a Worker, and * in the migration CLI — which is what keeps one migration source of truth across all three. * * Keys are ordered lexicographically by Kysely, so the zero-padded numeric prefix is load-bearing. * Add new migrations here; never renumber or edit one that has shipped. */ export declare const migrations: Record; export declare class StaticMigrationProvider implements MigrationProvider { getMigrations(): Promise>; } export declare function createMigrator(db: Kysely): Migrator; export interface MigrationOutcome { applied: string[]; error?: unknown; } /** * Apply all pending migrations. * * Returns the list of migrations that ran rather than logging, so callers (CLI, tests, a future * admin screen) can present the result however they like. */ export declare function migrateToLatest(db: Kysely): Promise; export interface SchemaState { /** * `empty` — no migration has ever run here, so there are no tables at all. * `behind` — the schema exists and some migrations have not been applied. * `ready` — every migration this build knows about has run. */ status: 'empty' | 'behind' | 'ready'; /** How many migrations have not run. Zero when `ready`. */ pending: number; /** Every migration this build carries, applied or not. */ total: number; } /** * What state this database's schema is in, without touching a table that may not exist. * * **The question every screen assumed had one answer.** A Taproot deployment has always been * created by somebody running `npm run db:migrate` from a machine holding an API token, so by the * time any code ran, the tables were there. A one-click deploy breaks that: Cloudflare provisions * an empty D1 and deploys the Worker, and the first request lands on a database with no `users` * table — so `countUsers` throws, the setup screen 500s, and the deployment is unreachable by every * route it offers. There is nothing wrong with it; nobody has created the schema. * * `getMigrations()` is the probe because it is the only one that answers on an empty database: * verified to create nothing and to read nothing but its own bookkeeping table, whose absence is * itself the answer. A `select` against `users` would throw, and catching that would mean reading * a driver's error text to tell "no schema" from "the database is down" — which is exactly the * distinction that must not be guessed. * * It works on D1 for a reason worth knowing: the migrator asks the introspector for its table list, * and `D1Introspector` answers from `sqlite_master` because D1 refuses PRAGMA. Anything built on * this inherits that, and nothing here needs column metadata — which the D1 introspector does not * have. */ export declare function schemaState(db: Kysely): Promise;