/**
 * FactoryStorage — a pluggable application-storage backend contract.
 *
 * One `FactoryStorage` instance powers both sides of an application
 * deployment's persistence:
 *
 * - **Agent state** (threads, messages, memory, observational memory) via
 *   {@link FactoryStorage.getMastraStorage}, which callers feed to the
 *   Mastra instance and all agent-related wiring.
 * - **App tables** (application-owned collections: settings, audit trails,
 *   work items, integration state, ...) via the generic
 *   {@link FactoryStorageOps} query surface plus declarative
 *   {@link CollectionSchema} DDL mapping.
 *
 * App-table domains are written once against `ops`; backends implement the
 * small query surface once (M + N, not M × N). Nothing outside a backend
 * implementation may branch on the database dialect — optional capabilities
 * such as {@link FactoryStorage.authDatabase} are feature-gated on presence.
 *
 * Contract discipline: the ops surface is deliberately small — equality-filter
 * CRUD, conflict-key upsert, ordered/limit/keyset-cursor lists, and atomic
 * read-modify-write. Anything not expressible here is a deliberate, reviewed
 * contract extension — never raw SQL from a domain.
 *
 * Store packages (`@mastra/pg`, `@mastra/libsql`) ship implementations next
 * to their `MastraCompositeStore` adapters, sharing one connection between
 * agent state and app tables.
 */
import type { MastraCompositeStore } from './base.js';
import { StorageDomain } from './domains/base.js';
/** Values storable in (and filterable on) a collection column. */
export type CollectionValue = string | number | boolean | Date | null;
/**
 * Row filter: column → required value. Multiple entries AND together.
 * - A {@link CollectionValue} matches by equality; `null` matches SQL `IS NULL`.
 * - `{ in: [...] }` matches any of the listed values (SQL `IN`).
 * - `{}` matches every row.
 *
 * Column names must be declared in the collection's schema — backends reject
 * unknown collections/columns instead of interpolating them.
 */
export type CollectionWhere = Record<string, CollectionValue | {
    in: CollectionValue[];
}>;
/**
 * Keyset cursor for stable pagination: the `orderBy` column values of the
 * last row of the previous page, in the same order as `orderBy`. The next
 * page contains rows strictly after that position in the sort order.
 */
export interface CollectionCursor {
    values: CollectionValue[];
}
export interface CollectionListOptions {
    /** Sort order; required when `cursor` is set. */
    orderBy?: [column: string, dir: 'asc' | 'desc'][];
    limit?: number;
    /** Keyset cursor over the `orderBy` columns (see {@link CollectionCursor}). */
    cursor?: CollectionCursor;
}
/**
 * Closed column-type union, mapped to backend-native types.
 *
 * `uuid-pk` declares the collection's generated primary key: the ops layer
 * assigns a UUID client-side on insert when the caller doesn't provide one,
 * so every backend produces identical rows. A collection may instead mark one
 * caller-supplied column with `primaryKey: true` (natural keys, e.g. a
 * session id).
 *
 * Value normalization is part of the contract regardless of dialect:
 * `timestamp` columns round-trip as `Date`, `json` as parsed values,
 * `boolean` as booleans, and `bigint` as JS numbers (safe integers — e.g.
 * GitHub ids fit well inside 2^53).
 */
export type CollectionColumnType = 'text' | 'bigint' | 'integer' | 'boolean' | 'json' | 'timestamp' | 'uuid-pk';
export interface CollectionColumnSpec {
    type: CollectionColumnType;
    /** Columns are NOT NULL unless marked nullable. */
    nullable?: boolean;
    /**
     * Natural primary key (caller-supplied on insert). Mutually exclusive with
     * a `uuid-pk` column; exactly one primary key per collection.
     */
    primaryKey?: boolean;
    /**
     * DDL-level default literal. Required when additively introducing a
     * NOT NULL column to a collection that may already have rows (e.g.
     * `actor_type text NOT NULL DEFAULT 'human'`).
     */
    default?: string | number | boolean;
}
/**
 * Unique index. The optional partial forms cover the two shapes app schemas
 * need: `whereNotNull` (unique per non-null natural key) and `whereNull`
 * (unique per scope where an owner column is absent).
 */
export interface CollectionUniqueIndexSpec {
    name: string;
    columns: string[];
    /** Index only rows where this column IS NOT NULL. */
    whereNotNull?: string;
    /** Index only rows where this column IS NULL. */
    whereNull?: string;
}
export interface CollectionIndexSpec {
    name: string;
    columns: string[];
}
/**
 * Declarative collection definition, mapped to backend DDL by
 * {@link FactoryStorage.ensureCollections}. Evolution is additive only:
 * re-running with new columns/indexes adds them; nothing is dropped or
 * retyped.
 */
export interface CollectionSchema {
    name: string;
    /** Column name → spec. Rows returned by ops are keyed by these names. */
    columns: Record<string, CollectionColumnSpec>;
    uniqueIndexes?: CollectionUniqueIndexSpec[];
    indexes?: CollectionIndexSpec[];
}
/**
 * Tagged database handle for auth libraries (e.g. better-auth). Consumers
 * narrow on `dialect` to build their driver adapter — a supported contract,
 * unlike sniffing store internals. `custom` passes an adapter/instance the
 * auth library accepts as-is.
 */
export type FactoryAuthDatabase = {
    dialect: 'postgres';
    pool: unknown;
} | {
    dialect: 'libsql';
    client: unknown;
} | {
    dialect: 'custom';
    database: unknown;
};
/**
 * Thrown by `insertOne`/`upsertOne` when a unique constraint rejects the row.
 * Backends map their native duplicate-key errors onto this type so domains
 * can implement insert-or-recover races portably.
 */
export declare class UniqueViolationError extends Error {
    readonly collection: string;
    constructor(collection: string, options?: {
        cause?: unknown;
    });
}
/**
 * The generic query surface app-table domains are written against.
 *
 * Rows (`T`) are plain objects keyed by schema column names; domains own any
 * mapping to their public camelCase shapes. All methods throw if the
 * collection (or any referenced column) was not registered via
 * `ensureCollections`.
 */
export interface FactoryStorageOps {
    findOne<T extends Record<string, unknown>>(collection: string, where: CollectionWhere): Promise<T | null>;
    findMany<T extends Record<string, unknown>>(collection: string, where: CollectionWhere, opts?: CollectionListOptions): Promise<T[]>;
    /**
     * Insert one row, returning it (with the generated `uuid-pk` populated).
     * Throws {@link UniqueViolationError} on any unique-constraint conflict.
     */
    insertOne<T extends Record<string, unknown>>(collection: string, row: Partial<T>): Promise<T>;
    /**
     * Insert, or update the existing row that matches `conflictKeys` (which
     * must be covered by a unique index). Non-key columns present in `row`
     * replace the stored values; the existing primary key is preserved.
     */
    upsertOne<T extends Record<string, unknown>>(collection: string, conflictKeys: string[], row: Partial<T>): Promise<T>;
    /** Set columns on every matching row. Returns the number of rows updated. */
    updateMany(collection: string, where: CollectionWhere, set: Record<string, unknown>): Promise<number>;
    /** Delete every matching row. Returns the number of rows deleted. */
    deleteMany(collection: string, where: CollectionWhere): Promise<number>;
    /**
     * Atomic read-modify-write of one matching row. `fn` receives the current
     * row and returns the columns to set — or `null` to abort without writing
     * (the unmodified row is returned; use a closure flag to distinguish abort
     * from success). Returns `null` when no row matches.
     *
     * Isolation: pg runs `fn` inside a `SELECT ... FOR UPDATE` transaction;
     * libsql serializes through its single-writer path. Either way, concurrent
     * `updateAtomic` calls on the same row never lose each other's writes.
     */
    updateAtomic<T extends Record<string, unknown>>(collection: string, where: CollectionWhere, fn: (row: T) => Partial<T> | null | Promise<Partial<T> | null>): Promise<T | null>;
}
/**
 * Base class for application domains owned by a {@link FactoryStorage}.
 * Domains are bound once when registered and share their owner's connection.
 */
export declare abstract class FactoryStorageDomain extends StorageDomain {
    #private;
    readonly name: string;
    protected constructor(name: string);
    /** @internal Bound by {@link FactoryStorage.registerDomain}. */
    __bindFactoryStorage(storage: FactoryStorage): void;
    protected get storage(): FactoryStorage;
    /**
     * Initialize this domain (via its owning storage) if it hasn't been yet.
     * Lets consumers holding a domain handle run the same fail-soft readiness
     * check as {@link FactoryStorage.ensureDomainReady} without also needing a
     * reference to the storage backend.
     */
    ensureReady(): Promise<void>;
    protected get ops(): FactoryStorageOps;
    protected ensureCollections(schemas: CollectionSchema[]): Promise<void>;
}
/**
 * A pluggable application-storage backend: one database powering agent state
 * (via {@link getMastraStorage}) and app-owned collections (via {@link ops}).
 */
export declare abstract class FactoryStorage {
    #private;
    /**
     * Agent-state store (threads, messages, memory, OM) for this database,
     * sharing this backend's connection. Callers pass the result to the Mastra
     * instance and all agent-related wiring. Lazily constructed; returns the
     * same instance on repeat calls.
     */
    abstract getMastraStorage(): MastraCompositeStore;
    /** Open/validate the backend, then initialize registered domains fail-soft. */
    init(): Promise<void>;
    /** Backend-specific connection initialization. */
    protected abstract initStorage(): Promise<void>;
    registerDomain<T extends FactoryStorageDomain>(domain: T): T;
    getDomain<T extends FactoryStorageDomain = FactoryStorageDomain>(name: string): T;
    hasDomain(name: string): boolean;
    domainNames(): string[];
    isDomainReady(name: string): boolean;
    domainInitError(name: string): unknown;
    ensureDomainReady(name: string): Promise<void>;
    /**
     * Map each domain's declarative schema to backend DDL. Idempotent and
     * additive: safe to re-run, never drops or retypes anything. Registers the
     * schemas so `ops` can validate identifiers and normalize values.
     */
    abstract ensureCollections(schemas: CollectionSchema[]): Promise<void>;
    /** The generic query surface domains are written against. */
    abstract readonly ops: FactoryStorageOps;
    /**
     * Run a group of app-table operations atomically. The callback receives an
     * ops instance bound to the transaction; callers must not use `this.ops`
     * inside it. Serializable callbacks may be retried after a serialization
     * failure and therefore must contain database operations only.
     */
    abstract withTransaction<T>(fn: (ops: FactoryStorageOps) => Promise<T>, options?: {
        isolationLevel?: 'serializable';
    }): Promise<T>;
    /** Release the backend's connections (tests, shutdown). */
    abstract close(): Promise<void>;
    /**
     * A tagged database handle auth libraries can consume (see
     * {@link FactoryAuthDatabase}). Absent → auth integrations require a
     * user-provided instance.
     */
    authDatabase?(): FactoryAuthDatabase;
}
//# sourceMappingURL=factory-storage.d.ts.map