/**
 * adapters/memory/sqliteVector — a corpus in a file, so you embed it once.
 *
 * `InMemoryStore` is a `Map`, and its cost is the one nobody notices until the
 * bill arrives: **restart the process and the whole corpus is re-embedded.**
 * That is fine for three documents and absurd for ten thousand. The step up was
 * "bring a vector database", 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.
 *
 * ── The two-phase cost model this exists to fix ─────────────────────────────
 * **Index time** embeds the corpus. It happens once, in its own process, and
 * its cost scales with the size of your documents. **Query time** embeds one
 * thing — the user's question — per retrieval, and its cost scales with
 * traffic. A 10,000-chunk corpus is 10,000 embeddings *once* and one embedding
 * per question thereafter. With a `Map` it is 10,000 embeddings *per restart*.
 * That is the whole argument for a file.
 *
 * ── Exact search, and the ceiling said out loud ─────────────────────────────
 * Vectors live in SQLite as `Float32Array` blobs. On the first search of a
 * namespace they are hydrated into ONE resident `Float32Array` matrix,
 * normalised, and every later query is an exact dot product across it. There is
 * **no approximate index and no pretence of one**: this returns the true top-K,
 * or it does not answer.
 *
 * Measured against THIS implementation on Node 22.16, Apple silicon, one
 * namespace, median of five queries:
 *
 * | corpus | query | resident matrix | file | first search (hydration) |
 * |---|---|---|---|---|
 * | 10,000 × 384-d | 6 ms | 15 MB | 21 MB | 45 ms |
 * | 50,000 × 384-d | 31 ms | 77 MB | 105 MB | 251 ms |
 * | 100,000 × 384-d | 65 ms | 154 MB | 211 MB | 939 ms |
 * | 10,000 × 1536-d | 16 ms | 61 MB | 83 MB | 122 ms |
 * | 50,000 × 1536-d | 89 ms | 307 MB | 413 MB | **5.7 s** |
 *
 * **The documented ceiling is 50,000 chunks.** Below it, every query is under
 * 100 ms at every embedder this library ships and the resident matrix is under
 * ~300 MB. It degrades linearly and predictably to about 100,000. Above that,
 * or when the process cannot hold the matrix, move to a managed vector database
 * — `MemoryStore` is the seam, and nothing else in your code changes. For scale
 * intuition: 50,000 chunks at ~1,000 characters is roughly 50 MB of text, on
 * the order of 25,000 pages.
 *
 * **It is a RECOMMENDATION, not an enforced limit, and the difference matters
 * when you are planning.** Nothing in this store counts chunks, refuses a write
 * at 50,000, or degrades on purpose past it: chunk 50,001 is stored and searched
 * exactly like chunk 3. The number is the point on the measured curve where this
 * implementation stops being obviously the right tool — published so the
 * decision is yours and dated, rather than discovered in production. The refusals
 * this store DOES enforce are named on the constructor: a missing `node:sqlite`,
 * an unreadable file, a schema-identity or schema-version mismatch, `':memory:'`,
 * and an embedder-fingerprint conflict.
 *
 * **Hydration is the number to plan around, not the query.** Steady-state
 * search is fast everywhere in that table; reading the vectors off disk the
 * FIRST time is what costs, and at 50,000 × 1536 it is 5.7 seconds. Paid
 * lazily, that lands on whoever asks the first question after a deploy. Call
 * {@link SqliteVectorStore.warm} at boot to pay it somewhere you chose — see
 * that method. Smaller vectors are dramatically cheaper here: 384 dimensions
 * hydrates 100,000 chunks in under a second, which is one more reason a
 * 384-dimension embedder is the better default for a corpus this size.
 *
 * A loadable extension (sqlite-vec) was measured against this and deliberately
 * NOT taken: it is roughly 2× faster at these sizes, and costs a native binary
 * on a five-platform matrix (no musl, no Windows/arm64) plus a pre-1.0
 * dependency. Two times, at sizes where we are already under 100 ms, does not
 * buy that.
 *
 * ── One process on one machine ──────────────────────────────────────────────
 * The same ceiling `sqliteSessions` states, for the same reason. It survives a
 * restart, a crash, a deploy. It is NOT distributed. WAL gives one writer and
 * many readers at once; a second writer waits up to `busyTimeoutMs` and then
 * fails loudly rather than queueing forever.
 *
 * ── Zero dependencies, and the version floor that buys ──────────────────────
 * SQLite is *inside Node* — no install, no native build, no peer dependency.
 * The price is a version floor this package does not otherwise have, so the
 * module is loaded when you actually construct a store and its absence is
 * refused by name. There is deliberately **no fallback to memory**: a corpus
 * that silently forgot every document on restart looks, from the outside,
 * exactly like a corpus that was never built.
 */
import type { MemoryIdentity } from '../../memory/identity/index.js';
import type { MemoryStore } from '../../memory/store/types.js';
/** One prepared statement, as this adapter calls it. */
export interface SqliteVectorStatementLike {
    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 SqliteVectorDatabaseLike {
    exec(sql: string): void;
    prepare(sql: string): SqliteVectorStatementLike;
    close(): void;
}
/** The shape of `node:sqlite` this adapter needs, declared locally. */
export interface SqliteVectorModuleLike {
    new (path: string): SqliteVectorDatabaseLike;
}
export interface SqliteVectorStoreOptions {
    /**
     * 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 re-embedding the corpus on every boot is the exact cost this
     * store exists to remove. Use `InMemoryStore` 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 waiting 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. Not public
     * API, not supported, and not a place to plug in another SQLite driver.
     */
    readonly _sqlite?: SqliteVectorModuleLike;
}
/**
 * Raised when the file exists but this runtime cannot use it as a vector index.
 *
 * The law `sqliteSessions` states for a session file, one domain over: **an
 * unreadable index and an empty one are different facts, and only one of them
 * is safe to answer with "no matches".** A store that opened a corrupt file as
 * an empty database would answer every question from the model's own weights
 * and log nothing.
 *
 * `problem` is the fact to branch on:
 *
 *  - `'cannot-open'` — not a SQLite database, or not readable.
 *  - `'not-our-schema'` — a database whose `af_vectors` 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.
 */
export declare class UnreadableIndexFileError extends Error {
    readonly code: "ERR_UNREADABLE_INDEX_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: UnreadableIndexFileError['problem'], detail: string);
}
/**
 * Raised when a vector meets an index built by a different embedder.
 *
 * Since 9.3.0 this is ONE class shared by every store that can make the check
 * (`lib/embedderMismatch.ts`), re-exported here so the import path that has
 * worked since 8.9.0 keeps working. A second class of the same name would make
 * `instanceof` depend on which store threw.
 */
export { EmbedderMismatchError } from '../../lib/embedderMismatch.js';
/** A durable vector store, plus the three things a file owns beyond the port. */
export interface SqliteVectorStore extends MemoryStore {
    /**
     * The journalling mode the file **actually has**, read back from SQLite
     * rather than assumed from what was asked for.
     *
     * Normally `'wal'`. Something else when the file lives where 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 only ever discovered under load.
     */
    readonly journalMode: string;
    /** The file this store is backed by. */
    readonly file: string;
    /**
     * The embedder fingerprint (`'<id>@<dims>'`) a namespace was built with, or
     * `undefined` when nothing with a vector has been written to it yet.
     *
     * Read this before an embedder swap: it is the fact `EmbedderMismatchError`
     * refuses on, available up front instead of at the first failed write.
     */
    fingerprintOf(identity: MemoryIdentity): string | undefined;
    /**
     * Read a namespace's vectors into memory NOW, and report how many and how
     * long it took.
     *
     * The first search of a namespace pays for hydration — 251 ms for 50,000
     * 384-dimension vectors, 5.7 s for 50,000 at 1536. Left alone that bill
     * lands on whoever asks the first question after a deploy, which is the
     * worst possible person to hand it to and the hardest latency to explain
     * afterwards.
     *
     * Calling this at boot moves the cost somewhere you chose. It is optional,
     * idempotent, and changes no result: a warmed store and a cold one answer
     * identically, one of them just answers the first question faster.
     *
     * ```ts
     * const store = sqliteVectorStore({ file: './corpus.db' });
     * const { count, durationMs } = await store.warm({ conversationId: '_global' });
     * console.log(`corpus ready: ${count} vectors in ${durationMs}ms`);
     * ```
     */
    warm(identity: MemoryIdentity): Promise<{
        count: number;
        durationMs: number;
    }>;
    /**
     * 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;
}
/**
 * Open (or create) a vector index in one SQLite file.
 *
 * @throws SqliteUnavailableError when the running Node has no `node:sqlite`.
 * @throws UnreadableIndexFileError when the file exists but cannot be used —
 *   never answered with an empty index.
 * @throws EmbedderMismatchError from `put`/`putMany`/`search` when a vector
 *   meets a namespace built by a different embedder.
 *
 * @example  Embed the corpus once, ever
 * ```ts
 * import { indexDocuments, defineRAG } from 'agentfootprint';
 * import { sqliteVectorStore } from 'agentfootprint/memory';
 * import { staticEmbedder } from 'agentfootprint/providers';
 *
 * const store = sqliteVectorStore({ file: './corpus.db' });
 * const embedder = staticEmbedder();
 *
 * // First boot indexes; every boot after this one finds the vectors already there.
 * await indexDocuments(store, embedder, docs, { embedderId: embedder.id });
 *
 * const agent = Agent.create({ provider })
 *   .rag(defineRAG({ id: 'docs', store, embedder, embedderId: embedder.id }))
 *   .build();
 * ```
 */
export declare function sqliteVectorStore(options: SqliteVectorStoreOptions): SqliteVectorStore;
