/**
 * hosting/sqliteSessions — conversations in a file, so a restart is not an
 * amnesia event.
 *
 * `memorySessions()` keeps conversations in a `Map` and says what that costs in
 * its own docstring: restart the process and every conversation is gone. Until
 * now the next step up was "bring a Redis", and the step between those two —
 * *one machine, one file, nothing to install* — was a store every consumer had
 * to write for themselves. This is that store.
 *
 * A paused run was in the same position from the other direction. `agent.run()`
 * hands back a checkpoint that is documented as JSON you can keep anywhere, and
 * "anywhere" was the whole of the offer: the library named a shape and left the
 * keeping to you. Both halves land in the same table here, because
 * {@link CheckpointEnvelope} was already a union of the two and a session store
 * has no business caring which one it is holding.
 *
 * ── What this is, said plainly ──────────────────────────────────────────────
 * **One process on one machine, writing one file.** That is the whole claim,
 * and it is worth stating as a ceiling rather than leaving it to be discovered:
 *
 *   • It survives a restart, a crash, a deploy — anything that ends the process
 *     and leaves the disk alone.
 *   • It is NOT a distributed store. Two machines do not share a session by
 *     both opening this file over a network filesystem, and nothing here tries
 *     to make that work.
 *   • WAL lets readers and one writer run at once, and **one writer at a time
 *     is the ceiling** — a second writer waits for the lock up to
 *     `busyTimeoutMs` and then fails loudly rather than queueing forever.
 *     Several processes on one box is fine at that scale; a fleet is not what
 *     this is.
 *
 * When you outgrow it you swap the one argument to `standingAgent`, which is
 * the entire point of the port.
 *
 * ── Zero dependencies, and the version floor that buys ──────────────────────
 * SQLite is *inside Node* — `node:sqlite`, no install, no native build, no
 * peer dependency. The price is a version floor this package does not otherwise
 * have: the module ships with Node 22.5 and newer. Rather than raise `engines`
 * for one optional adapter and break every consumer on Node 20, the module is
 * loaded when you actually construct a store, and its absence is refused by
 * name with the version you are on and what to do about it — see
 * {@link SqliteUnavailableError}. There is deliberately **no fallback to
 * memory**: a store that silently forgot everything on restart is
 * indistinguishable, from the outside, from a brand-new user.
 *
 * ── The two laws it inherits rather than re-implements ──────────────────────
 * `checkEnvelope` is called on the way out AND on the way in, so an envelope
 * whose `format` this runtime does not know is refused by name, and a stored
 * session that is PRESENT but unreadable is refused by name too. Only a session
 * that was never written hydrates as `undefined`. Validating on the way in as
 * well is the cheap half of that promise: a row this store could not read back
 * never gets written in the first place.
 */
import type { SessionLifecycle, SessionSweep } from './types.js';
/** One prepared statement, as this adapter calls it. */
export interface SqliteStatementLike {
    run(...params: readonly unknown[]): unknown;
    get(...params: readonly unknown[]): unknown;
    all(...params: readonly unknown[]): unknown[];
}
/** One open database, as this adapter calls it. */
export interface SqliteDatabaseLike {
    exec(sql: string): void;
    prepare(sql: string): SqliteStatementLike;
    close(): void;
}
/**
 * The shape of `node:sqlite` this adapter needs — declared locally, the same
 * way every other adapter here declares the slice of its backend it uses, so
 * nothing takes a hard import on a module that does not exist on every
 * supported Node.
 */
export interface SqliteModuleLike {
    new (path: string): SqliteDatabaseLike;
}
/** Options for {@link sqliteSessions}. */
export interface SqliteSessionsOptions {
    /**
     * The database file. Created if it does not exist, along with its parent
     * directory — "no infrastructure" would be a thin promise if you still had to
     * `mkdir` first.
     *
     * `':memory:'` is refused: it looks like a file, keeps nothing across a
     * restart, and a store that quietly forgets is the exact failure this adapter
     * exists to remove. Use `memorySessions()` when that is what you want — it
     * says so in its name.
     */
    readonly file: string;
    /**
     * How long a write waits for another writer's lock before failing, in
     * milliseconds. Default 5000.
     *
     * It fails rather than waits forever on purpose: a request hung on a lock
     * looks exactly like a slow model, and the two need different fixes.
     */
    readonly busyTimeoutMs?: number;
    /**
     * @internal Test seam only — the `node:sqlite` module, injected. Lets the
     * suite exercise the refusal path on a Node that HAS the module, and the
     * failure paths without corrupting a real file. Not public API, not
     * supported, and not a place to plug in another SQLite driver.
     */
    readonly _sqlite?: SqliteModuleLike;
}
/**
 * A session store in a file.
 *
 * It is a {@link SessionLifecycle} plus the three things a real store owns
 * beyond the port — closing, forgetting, and telling you what the file actually
 * got — because the port deliberately asks for only two methods and leaves the
 * rest to whoever implements it.
 */
export interface SqliteSessions extends SessionLifecycle {
    /**
     * The journalling mode the file **actually has**, read back from SQLite
     * rather than assumed from what was asked for.
     *
     * It is normally `'wal'`. It is something else when the file lives somewhere
     * WAL cannot work — a network filesystem is the usual reason — and that is a
     * fact worth being able to read: the store still works, with one writer *or*
     * one reader at a time instead of both. A silent downgrade is the kind of
     * thing that is only ever discovered under load.
     */
    readonly journalMode: string;
    /** Forget one session. No-op if there is nothing stored for it. */
    forget(sessionId: string): Promise<void>;
    /**
     * How conversations here stop existing: **this store deletes them**, when a
     * job of yours asks it to (9.42.0).
     *
     * Narrowed from the port's optional member to a required one, and to the one
     * arm a file-backed store can be — a caller holding a `SqliteSessions` needs
     * no feature check, and reaching for a backend policy that does not exist
     * here is a compile error rather than a surprise at 3am.
     */
    retention(): SessionSweep;
    /**
     * Close the file. Idempotent — a shutdown hook and an explicit close can
     * coexist. Reading or writing afterwards refuses by name rather than
     * reopening behind your back.
     */
    close(): void;
}
/**
 * Raised when `node:sqlite` is not available in the running Node.
 *
 * The class moved to `lib/sqliteUnavailable.ts` in 8.9.0 so the SQLite vector
 * store raises the SAME error for the same missing module — a consumer
 * catching it should not have to know which of our stores was being built.
 * Constructed with no third argument it produces exactly the message it always
 * did, and it is re-exported here under its own name, so nothing that imports
 * it from this module changes.
 */
export { SqliteUnavailableError } from '../lib/sqliteUnavailable.js';
/**
 * Raised when the file exists but this runtime cannot use it as a session
 * store.
 *
 * The same law {@link UnreadableEnvelopeError} states for one stored value,
 * one level up: **an unreadable store and an empty one are different facts, and
 * only one of them is safe to answer with a fresh start.** A store that opened
 * a corrupt file as an empty database would hand every returning user a blank
 * slate and log nothing.
 *
 * `problem` is the fact to branch on — the three cases need different actions:
 *
 *  - `'cannot-open'` — not a SQLite database, or not readable (permissions, a
 *    directory, a truncated file).
 *  - `'not-our-schema'` — a database whose `agent_sessions` table is somebody
 *    else's table of that name. Point the store at its own file.
 *  - `'newer-schema'` — written by a newer agentfootprint than this one. Same
 *    answer the envelope `format` field gives: refuse, never half-read.
 */
export declare class UnreadableSessionFileError extends Error {
    readonly code: "ERR_UNREADABLE_SESSION_FILE";
    /** The file that was refused. */
    readonly file: string;
    /** Which of the three cases this is. */
    readonly problem: 'cannot-open' | 'not-our-schema' | 'newer-schema';
    constructor(file: string, problem: UnreadableSessionFileError['problem'], detail: string);
}
/**
 * A session store in one SQLite file — the battery-included place to keep a
 * conversation, or a run that stopped to ask a person something, so that a
 * restart does not lose it.
 *
 * @throws SqliteUnavailableError when the running Node has no `node:sqlite`.
 * @throws UnreadableSessionFileError when the file exists but cannot be used —
 *   never answered with an empty store.
 *
 * @example  A standing agent whose conversations survive a restart
 *   import { standingAgent, nodeHost, sqliteSessions } from 'agentfootprint/hosting';
 *
 *   const handle = await standingAgent({
 *     agent,
 *     sessions: sqliteSessions({ file: './sessions.db' }),
 *     host: nodeHost({ port: 8080 }),
 *   });
 *
 * @example  Keeping a paused run yourself, without the composer
 *   const sessions = sqliteSessions({ file: './sessions.db' });
 *   const out = await agent.run({ message });
 *   if (isPaused(out)) {
 *     await sessions.persist(sessionId, toPausedEnvelope({
 *       checkpoint: out.checkpoint,
 *       conversation: agent.checkpoint()!,
 *       pending: { pauseData: out.pauseData },
 *     }));
 *   }
 *   // …a deploy later, in a new process:
 *   const paused = readPausedRun(await sessions.hydrate(sessionId));
 *   const answer = await agent.resume(paused.checkpoint, decision);
 */
export declare function sqliteSessions(options: SqliteSessionsOptions): SqliteSessions;
//# sourceMappingURL=sqliteSessions.d.ts.map