import { Effect } from "effect";
/** Structural client interface so this module stays dependency-free;
 *  `@libsql/client` satisfies it. */
export interface SqliteDataMigrationClient {
    execute(stmt: string | {
        readonly sql: string;
        readonly args: readonly unknown[];
    }): Promise<{
        readonly rows: readonly Record<string, unknown>[];
    }>;
}
declare const DataMigrationError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
    readonly _tag: "DataMigrationError";
} & Readonly<A>;
export declare class DataMigrationError extends DataMigrationError_base<{
    /** The migration that failed, or null when the ledger itself did. */
    readonly migration: string | null;
    readonly cause: unknown;
}> {
}
declare const DuplicateDataMigrationError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
    readonly _tag: "DuplicateDataMigrationError";
} & Readonly<A>;
export declare class DuplicateDataMigrationError extends DuplicateDataMigrationError_base<{
    readonly name: string;
}> {
}
export interface SqliteDataMigration {
    /** Stable unique id, date-prefixed so the registry reads in order
     *  (e.g. "2026-06-05-auth-config-placements"). Renaming an applied
     *  migration re-runs it — never rename. */
    readonly name: string;
    readonly run: (client: SqliteDataMigrationClient) => Effect.Effect<void, DataMigrationError>;
}
/** Wrap a promise-shaped migration body as a registry entry. */
export declare const sqliteDataMigration: (name: string, run: (client: SqliteDataMigrationClient) => Promise<unknown>) => SqliteDataMigration;
/**
 * Run every registry entry whose name has no stamp row, in registry order,
 * stamping each on success. Returns the applied names.
 *
 * Atomicity is the migration's own job (the existing migrations run their
 * rewrites inside BEGIN…COMMIT), so the runner does not wrap them — SQLite
 * has no nested transactions. The stamp is written after the migration
 * succeeds; a crash between the two re-runs the (idempotent) migration on
 * the next boot, which is a no-op. A failed migration leaves no stamp and
 * fails the boot.
 */
export declare const runSqliteDataMigrations: (client: SqliteDataMigrationClient, migrations: readonly SqliteDataMigration[]) => Effect.Effect<readonly string[], DataMigrationError | DuplicateDataMigrationError>;
export {};
//# sourceMappingURL=sqlite-data-migrations.d.ts.map