/**
 * Thin HTTP transport.
 *
 * Uses Node 18+'s built-in fetch. The rest of the SDK doesn't touch
 * fetch directly so we have one place to apply auth, retries, and error
 * mapping. The transport is also the seam where tests inject fake
 * responses via the {@link Transport.fetchImpl} option.
 */
type FetchLike = (input: string | URL, init?: RequestInit) => Promise<Response>;
interface TransportOptions {
    url: string;
    apiKey?: string | undefined;
    /** Capability token (#150). Mutually exclusive with `apiKey`. */
    capability?: string | undefined;
    /** Per-request timeout in milliseconds. Default 60_000. */
    timeoutMs?: number;
    /**
     * Replace the underlying fetch implementation — useful for tests
     * (inject a mock), proxies, or custom transports. Defaults to the
     * global fetch.
     */
    fetchImpl?: FetchLike;
}
interface RequestOptions {
    method: string;
    path: string;
    json?: unknown;
    params?: Record<string, string | number | boolean | undefined | null>;
}
declare class Transport {
    readonly url: string;
    readonly apiKey: string | undefined;
    readonly capability: string | undefined;
    readonly timeoutMs: number;
    private readonly fetchImpl;
    constructor(opts: TransportOptions);
    request<T = unknown>(opts: RequestOptions): Promise<T | null>;
}

/**
 * Typed result objects.
 *
 * These are simple interfaces + factory functions, not classes — the SDK
 * is a thin layer over fetch, and structural typing on plain objects
 * matches Node ergonomics. Helpers are exposed as named exports.
 */
interface GraphSummary {
    name: string;
    currentSnapshotSeq: number | null;
    nextSeq: number;
}
interface GraphInfo {
    name: string;
    description: string;
    createdAt: string | undefined;
}
interface CypherStats {
    nodesCreated: number;
    nodesDeleted: number;
    edgesCreated: number;
    edgesDeleted: number;
    propertiesSet: number;
    labelsAdded: number;
    rowsReturned: number;
}
interface CypherResult {
    columns: string[];
    rows: unknown[][];
    stats: CypherStats;
    mutationsApplied: number;
    lastSeq: number | null;
    /** Rows zipped to objects keyed by column name. */
    asDicts(): Record<string, unknown>[];
}
interface SchemaVersion {
    version: number;
    appliedAtNanos: number;
    body: unknown;
}
interface SearchHit {
    nodeId: number | undefined;
    strId: string | undefined;
    score: number;
    label: string | undefined;
    property: string | undefined;
    snippet: string | undefined;
}
interface AuditStatus {
    status: string;
    records: number | undefined;
    lastSeq: number | undefined;
    reason: string | undefined;
    raw: Record<string, unknown>;
    readonly isClean: boolean;
}
interface Job {
    id: string;
    kind: string;
    graph: string;
    state: string;
    createdAt: string | undefined;
    updatedAt: string | undefined;
    error: string | undefined;
    raw: Record<string, unknown>;
    readonly isTerminal: boolean;
    readonly isSucceeded: boolean;
}

/**
 * Wire-format helpers.
 *
 * The Rust engine deserializes properties as tagged `Value` enums:
 *
 *     {"Str": "Ada"}   {"Int": 42}   {"Bool": true}   {"Null": null}
 *     {"Array": [{"Int": 1}, {"Int": 2}]}   {"Object": {"k": {"Str": "v"}}}
 *
 * Callers shouldn't have to write that by hand. `normalizeValue` walks
 * an arbitrary value and wraps raw scalars; already-tagged values pass
 * through unchanged. `normalizeOp` applies that normalization to the
 * `properties` dict inside each CmdOp / MutationOp, and also rewrites
 * the friendly `type` field on edge ops to the engine's `edge_type`.
 */
type CmdOp = Record<string, Record<string, unknown>>;
declare function normalizeValue(v: unknown): unknown;
declare function normalizeOp(op: CmdOp): CmdOp;
declare function normalizeOps(ops: Iterable<CmdOp>): CmdOp[];
declare function denormalizeValue(v: unknown): unknown;

/**
 * The Client class — the public entry point.
 *
 * The surface is organized into namespaces (`client.graphs`,
 * `client.schema`, `client.search`, ...) that group related endpoints.
 * Top-level `client.cypher` is also exposed since it's the dominant op.
 */

interface ClientOptions {
    url: string;
    apiKey?: string | undefined;
    /** Capability token (#150). Mutually exclusive with apiKey. */
    capability?: string | undefined;
    timeoutMs?: number;
    fetchImpl?: FetchLike;
}
interface WriteOpts {
    /** Auto-wrap raw scalar property values as tagged Value envelopes. */
    normalize?: boolean;
}
interface SearchFulltextOpts {
    label: string;
    property: string;
    query: string;
    k?: number;
}
interface SearchVectorOpts {
    label: string;
    property: string;
    vector: number[];
    k?: number;
    metric?: "cosine" | "euclidean" | "dot";
}
interface EdgesBetweenOpts {
    source: string;
    target: string;
    edgeType?: string;
}
interface JobsListOpts {
    state?: string;
    graph?: string;
    limit?: number;
}
interface JobWaitOpts {
    /** Wall-clock timeout in milliseconds; throws if elapsed. */
    timeoutMs?: number;
    /** Polling interval in milliseconds. Default 1000. */
    pollIntervalMs?: number;
}
interface CreateIndexOpts {
    label: string;
    property: string;
    valueType?: "string" | "int" | "float";
    unique?: boolean;
}
declare class Client {
    private readonly t;
    readonly graphs: Graphs;
    readonly schema: Schema;
    readonly indexes: Indexes;
    readonly audit: Audit;
    readonly backup: Backup;
    readonly jobs: Jobs;
    readonly search: Search;
    readonly compliance: Compliance;
    readonly admin: Admin;
    readonly ai: AI;
    readonly cluster: Cluster;
    readonly procedures: Procedures;
    readonly capabilities: Capabilities;
    readonly cursor: Cursor;
    constructor(opts: ClientOptions);
    /**
     * Execute a Cypher query and return the typed result.
     *
     * Pass `parameters` to bind `$placeholder` values in the query.
     * Values are sent as native JSON and coerced server-side. Arrays
     * and nested objects round-trip. Works in: WHERE filters, inline
     * property maps on MATCH/CREATE/MERGE, SET values, UNWIND arrays.
     *
     *   await c.cypher(g, "MATCH (v:Verse {id: $id}) RETURN v",
     *                  { parameters: { id: "gen-1-1" } });
     *   await c.cypher(g, "UNWIND $rows AS r MERGE (v:Verse {id: r.id})",
     *                  { parameters: { rows: [...] } });
     *
     * An unbound `$placeholder` errors with `parameter $X not bound` —
     * no silent zero-row mismatch.
     */
    cypher(graph: string, query: string, opts?: {
        parameters?: Record<string, unknown>;
    }): Promise<CypherResult>;
    /**
     * Planner analysis without execution (#172). Returns
     * `{plan, policy}`. Use to pre-check queries against the engine's
     * execution policy.
     */
    explain(graph: string, query: string): Promise<{
        plan: string;
        policy: Record<string, unknown>;
    }>;
    /**
     * Apply a batch of atomic write operations.
     *
     * Each op is an object like `{createNode: {...}}` or `{createEdge: {...}}`.
     * Raw scalars inside `properties` are auto-wrapped in the tagged
     * `Value` format the engine expects. Pass `{normalize: false}` to
     * send the body untouched.
     */
    write(graph: string, ops: CmdOp[], opts?: WriteOpts): Promise<unknown>;
    /** Force a compaction + snapshot publish. */
    flush(graph: string): Promise<unknown>;
    /** Liveness + Raft state. */
    health(): Promise<Record<string, unknown>>;
    /** Engine info — graph dir, seq, auth summary. */
    info(): Promise<Record<string, unknown>>;
    /** Look up a node by string ID on the engine's default graph. */
    nodeByStr(strId: string): Promise<unknown>;
    /** Look up an edge by string ID on the engine's default graph. */
    edgeByStr(strId: string): Promise<unknown>;
    edgesBetween(graph: string, opts: EdgesBetweenOpts): Promise<unknown[]>;
    listLabel(graph: string, label: string, limit?: number): Promise<unknown[]>;
}
declare abstract class Namespace {
    protected readonly t: Transport;
    constructor(t: Transport);
}
declare class Graphs extends Namespace {
    list(): Promise<GraphInfo[]>;
    create(name: string): Promise<GraphSummary>;
    info(name: string): Promise<GraphSummary>;
    exists(name: string): Promise<boolean>;
    drop(name: string): Promise<void>;
    clone(opts: {
        source: string;
        destination: string;
    }): Promise<GraphSummary>;
    rebuildDerived(name: string): Promise<unknown>;
    /**
     * Idempotently provision a graph (#170). Returns `{created, summary}`.
     * `created` is true only when this call materialized the graph.
     */
    ensure(name: string): Promise<{
        created: boolean;
        summary: GraphSummary;
    }>;
}
declare class Schema extends Namespace {
    get(graph: string): Promise<Record<string, unknown>>;
    put(graph: string, body: unknown): Promise<number>;
    history(graph: string): Promise<SchemaVersion[]>;
}
declare class Indexes extends Namespace {
    create(graph: string, opts: CreateIndexOpts): Promise<unknown>;
    /**
     * Idempotently provision a batch of property indexes (#170).
     *
     * Pre-existing indexes are no-op. Returns one entry per spec with
     * `{spec, created, error?}`. Non-conflict errors abort the batch and
     * are thrown — the caller's migration shouldn't proceed if e.g. auth
     * fails halfway through.
     */
    ensure(graph: string, specs: CreateIndexOpts[]): Promise<Array<{
        spec: CreateIndexOpts;
        created: boolean;
        error?: string;
    }>>;
}
declare class Audit extends Namespace {
    verify(graph: string): Promise<AuditStatus>;
}
declare class Backup extends Namespace {
    create(graph: string, opts: {
        outputPath: string;
    }): Promise<unknown>;
    restore(graph: string, opts: {
        inputPath: string;
    }): Promise<unknown>;
}
declare class Jobs extends Namespace {
    list(opts?: JobsListOpts): Promise<Job[]>;
    get(jobId: string): Promise<Job>;
    result(jobId: string): Promise<unknown>;
    wait(jobId: string, opts?: JobWaitOpts): Promise<Job>;
}
declare class Search extends Namespace {
    fulltext(graph: string, opts: SearchFulltextOpts): Promise<SearchHit[]>;
    vector(graph: string, opts: SearchVectorOpts): Promise<SearchHit[]>;
    rebuild(graph?: string): Promise<unknown>;
}
declare class Compliance extends Namespace {
    export(graph: string, opts: {
        output: string;
    }): Promise<unknown>;
    summary(graph: string): Promise<unknown>;
    /** Is WORM (write-once-read-many) mode engaged on this graph? */
    wormStatus(graph: string): Promise<{
        engaged: boolean;
        note?: string;
    }>;
    /**
     * Irrevocably engage WORM mode on this graph. Once engaged, deletes
     * and updates are rejected by the engine. There is no disengage
     * endpoint by design — compliance contracts require the gate to be
     * one-way.
     */
    engageWorm(graph: string): Promise<{
        engaged: boolean;
        note?: string;
    }>;
}
declare class Admin extends Namespace {
    createApiKey(opts: {
        tenant: string;
    }): Promise<unknown>;
    listApiKeys(opts?: {
        includeRevoked?: boolean;
    }): Promise<unknown[]>;
    revokeApiKey(keyId: string): Promise<unknown>;
    debugStorage(): Promise<unknown>;
    backup(opts: {
        outputPath: string;
    }): Promise<unknown>;
}
declare class AI extends Namespace {
    nlq(graph: string, question: string, opts?: {
        mode?: string;
        schema?: unknown;
    }): Promise<unknown>;
    investigate(graph: string, question: string, opts?: {
        contextQuery?: string;
        provider?: string;
    }): Promise<unknown>;
    agent(graph: string, message: string, extra?: Record<string, unknown>): Promise<unknown>;
}
declare class Cluster extends Namespace {
    info(): Promise<unknown>;
    init(opts: {
        nodeId: number;
        advertiseAddr: string;
    }): Promise<unknown>;
    addLearner(opts: {
        nodeId: number;
        addr: string;
    }): Promise<unknown>;
    changeMembership(opts: {
        members: number[];
    }): Promise<unknown>;
    read(): Promise<unknown>;
    write(payload: unknown): Promise<unknown>;
}
/**
 * `client.capabilities.*` — issue scoped, time-limited tokens (#150).
 */
declare class Capabilities extends Namespace {
    issue(opts: {
        graph: string;
        principal: string;
        scope?: string[];
        ttlSeconds: number;
    }): Promise<{
        token: string;
        graph: string;
        principal: string;
        scope: string[];
        issued_at_nanos: number;
        expires_at_nanos: number;
    }>;
}
/**
 * `client.procedures.*` — Cypher CALL helpers with friendly args.
 *
 * Wraps the engine's built-in procedures (db.changes / db.diff /
 * db.changeRate) so callers can pass Dates, ISO strings, or epoch
 * nanos as integers without remembering CALL/YIELD wire syntax.
 */
declare class Procedures {
    private readonly client;
    constructor(client: Client);
    private static toNanos;
    /** `CALL db.changes(from, to)` — every mutation in the window. */
    changes(graph: string, fromTs: number | string | Date, toTs: number | string | Date): Promise<Record<string, unknown>[]>;
    /**
     * `CALL db.delta(from, to)` — per-entity summary of what changed.
     *
     * The Cypher procedure is named `db.delta` (not `db.diff`) because
     * `DIFF` is a reserved word in this engine's Cypher dialect.
     */
    diff(graph: string, fromTs: number | string | Date, toTs: number | string | Date): Promise<Record<string, unknown>[]>;
    /** `CALL db.changeRate(window)` — mutations/sec over the last window. */
    changeRate(graph: string, windowSeconds: number): Promise<{
        rate: number;
        n_mutations: number;
        window_seconds: number;
    }>;
    private static q;
    /** `CALL db.subjectExport(subjectStrId)` — GDPR Article 20 portability. */
    subjectExport(graph: string, subjectStrId: string): Promise<Record<string, unknown>[]>;
    /** `CALL db.destroySubjectKey(subjectId)` — GDPR Article 17 erasure. */
    destroySubjectKey(graph: string, subjectId: string): Promise<{
        subjectId: string;
        destroyedAt: number;
    } | Record<string, unknown>>;
    /** `CALL db.aclEvents([sinceId [, principal [, limit]]])` — ACL audit replay. */
    aclEvents(graph: string, opts?: {
        sinceId?: number;
        principal?: string;
        limit?: number;
    }): Promise<Record<string, unknown>[]>;
    /** `CALL db.linkDerivedFrom(nodeStrId, sourceIds [, kind])`. */
    linkDerivedFrom(graph: string, nodeStrId: string, sourceStrIds: readonly string[], kind?: string): Promise<Record<string, unknown>>;
    /** `CALL db.derivedFrom(nodeStrId [, maxDepth])`. */
    derivedFrom(graph: string, nodeStrId: string, maxDepth?: number): Promise<Record<string, unknown>[]>;
    /**
     * `CALL db.propertyProvenance(nodeRef, prop)`. `ref` may be:
     *  - a string (treated as the node's strId — the common case),
     *  - a number (numeric nodeId),
     *  - or an object `{ strId?, nodeId? }` for explicit disambiguation.
     *
     * The engine procedure accepts both Int and String for arg 0 (#287),
     * so passing a strId works without an SDK-side lookup.
     *
     * @example
     *   client.procedures.propertyProvenance(G, 'art:1', 'title')
     *   client.procedures.propertyProvenance(G, 42, 'title')
     *   client.procedures.propertyProvenance(G, { strId: 'art:1' }, 'title')
     */
    propertyProvenance(graph: string, ref: string | number | {
        strId?: string;
        nodeId?: number;
    }, property: string): Promise<Record<string, unknown>[]>;
    /** `CALL db.recordEpisode(sessionId, kind, text [, payload])`. */
    recordEpisode(graph: string, sessionId: string, kind: string, text: string, payload?: string): Promise<Record<string, unknown>>;
    /** `CALL db.replayEpisodes(sessionId [, limit])`. */
    replayEpisodes(graph: string, sessionId: string, limit?: number): Promise<Record<string, unknown>[]>;
    /** `CALL db.consolidateSession(sessionId, summary [, sinceTs])`. */
    consolidateSession(graph: string, sessionId: string, summary: string, sinceTs?: number): Promise<Record<string, unknown>>;
    /** `CALL db.sessionSummaries(sessionId)`. */
    sessionSummaries(graph: string, sessionId: string): Promise<Record<string, unknown>[]>;
    /** `CALL db.applySalienceDecay(label, halfLifeSeconds [, floor])`. */
    applySalienceDecay(graph: string, label: string, halfLifeSeconds: number, floor?: number): Promise<Record<string, unknown>>;
    /** `CALL db.reinforceSalience(strId [, amount])`. */
    reinforceSalience(graph: string, strId: string, amount?: number): Promise<Record<string, unknown>>;
    /** `CALL db.recordBelief(beliefId, claim, confidence [, evidenceIds])`. */
    recordBelief(graph: string, beliefId: string, claim: string, confidence: number, evidenceStrIds?: readonly string[]): Promise<Record<string, unknown>>;
    /** `CALL db.reviseBelief(beliefId, newClaim, newConfidence, reason)`. */
    reviseBelief(graph: string, beliefId: string, newClaim: string, newConfidence: number, reason: string): Promise<Record<string, unknown>>;
    /** `CALL db.beliefLineage(beliefId)`. */
    beliefLineage(graph: string, beliefId: string): Promise<Record<string, unknown>[]>;
    /** `CALL db.proveErasure(subjectId)` — receipts + chain status. */
    proveErasure(graph: string, subjectId: string): Promise<Record<string, unknown>[]>;
    /** `CALL db.verifyAclChain()` — tamper-evidence check on ACL log. */
    verifyAclChain(graph: string): Promise<Record<string, unknown>>;
    /** `CALL db.embeddingModelDrift(label, prop)`. */
    embeddingModelDrift(graph: string, label: string, prop: string): Promise<Record<string, unknown>>;
    /** `CALL gds.semanticMatchExpand(label, prop, query, k, hops [, edgeTypes [, threshold]])`. */
    semanticMatchExpand(graph: string, label: string, prop: string, query: readonly number[], k: number, hops: number, opts?: {
        edgeTypes?: readonly string[];
        threshold?: number;
    }): Promise<Record<string, unknown>[]>;
}
/**
 * `client.cursor.*` — #279 cursor-paginated query reads.
 *
 * Use {@link Cursor.stream} for the common "give me an async iterator
 * over every row" pattern. Use {@link open} / {@link next} / {@link close}
 * for direct cursor lifecycle control.
 */
declare class Cursor extends Namespace {
    open(graph: string, query: string, opts?: {
        parameters?: Record<string, unknown>;
        batchSize?: number;
    }): Promise<Record<string, unknown>>;
    next(graph: string, cursorId: string, opts?: {
        batch?: number;
    }): Promise<Record<string, unknown>>;
    close(graph: string, cursorId: string): Promise<Record<string, unknown>>;
    /** Async-iterate every row yielded by `query`. Releases the cursor
     * when iteration completes or the caller breaks out. */
    stream(graph: string, query: string, opts?: {
        parameters?: Record<string, unknown>;
        batchSize?: number;
    }): AsyncGenerator<Record<string, unknown>, void, unknown>;
}

/**
 * Exception hierarchy.
 *
 * All errors thrown by this client extend {@link InvariantDBError} so
 * callers can catch a single base type. The more specific subclasses let
 * callers branch on the failure category without parsing HTTP status codes.
 */
declare class InvariantDBError extends Error {
    constructor(message: string);
}
/** Network-level failure: connection refused, DNS, timeout, TLS. */
declare class TransportError extends InvariantDBError {
}
/** HTTP response with a non-2xx status code. */
declare class APIError extends InvariantDBError {
    readonly statusCode: number;
    readonly body: unknown;
    readonly requestId: string | undefined;
    constructor(message: string, opts: {
        statusCode: number;
        body?: unknown;
        requestId?: string;
    });
}
/** 401 / 403 — missing, invalid, or insufficient credentials. */
declare class AuthError extends APIError {
}
/** 404 — the requested graph, job, or resource does not exist. */
declare class NotFoundError extends APIError {
}
/** 409 — the operation conflicts with current state (e.g. graph exists). */
declare class ConflictError extends APIError {
}
/** 400 / 422 — the request body was malformed or semantically invalid. */
declare class ValidationError extends APIError {
}
/** 429 — too many requests; retry after the indicated window. */
declare class RateLimitError extends APIError {
}
/** 5xx — the server failed to process a valid request. */
declare class ServerError extends APIError {
}

/**
 * Official Node/TypeScript client for InvariantDB.
 *
 * Quickstart:
 *
 * ```ts
 * import { Client } from "invariantdb";
 *
 * const c = new Client({ url: "https://invariantdb.com", apiKey: "gq_..." });
 * const result = await c.cypher("my_graph", "MATCH (n:Person) RETURN n LIMIT 10");
 * for (const row of result.asDicts()) {
 *   console.log(row);
 * }
 * ```
 */

declare const VERSION = "0.2.0";

export { APIError, type AuditStatus, AuthError, Client, type ClientOptions, type CmdOp, ConflictError, type CreateIndexOpts, type CypherResult, type CypherStats, type EdgesBetweenOpts, type GraphInfo, type GraphSummary, InvariantDBError, type Job, type JobWaitOpts, type JobsListOpts, NotFoundError, RateLimitError, type SchemaVersion, type SearchFulltextOpts, type SearchHit, type SearchVectorOpts, ServerError, TransportError, VERSION, ValidationError, type WriteOpts, denormalizeValue, normalizeOp, normalizeOps, normalizeValue };
