"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/index.ts
var index_exports = {};
__export(index_exports, {
  APIError: () => APIError,
  AuthError: () => AuthError,
  Client: () => Client,
  ConflictError: () => ConflictError,
  InvariantDBError: () => InvariantDBError,
  NotFoundError: () => NotFoundError,
  RateLimitError: () => RateLimitError,
  ServerError: () => ServerError,
  TransportError: () => TransportError,
  VERSION: () => VERSION,
  ValidationError: () => ValidationError,
  denormalizeValue: () => denormalizeValue,
  normalizeOp: () => normalizeOp,
  normalizeOps: () => normalizeOps,
  normalizeValue: () => normalizeValue
});
module.exports = __toCommonJS(index_exports);

// src/errors.ts
var InvariantDBError = class extends Error {
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
  }
};
var TransportError = class extends InvariantDBError {
};
var APIError = class extends InvariantDBError {
  statusCode;
  body;
  requestId;
  constructor(message, opts) {
    super(message);
    this.statusCode = opts.statusCode;
    this.body = opts.body;
    this.requestId = opts.requestId;
  }
};
var AuthError = class extends APIError {
};
var NotFoundError = class extends APIError {
};
var ConflictError = class extends APIError {
};
var ValidationError = class extends APIError {
};
var RateLimitError = class extends APIError {
};
var ServerError = class extends APIError {
};
function errorFromResponse(status, body, requestId) {
  const message = extractMessage(body) ?? `HTTP ${status}`;
  const opts = { statusCode: status, body, requestId };
  if (status === 401 || status === 403) return new AuthError(message, opts);
  if (status === 404) return new NotFoundError(message, opts);
  if (status === 409) return new ConflictError(message, opts);
  if (status === 400 || status === 422) return new ValidationError(message, opts);
  if (status === 429) return new RateLimitError(message, opts);
  if (status >= 500 && status < 600) return new ServerError(message, opts);
  return new APIError(message, opts);
}
function extractMessage(body) {
  if (body && typeof body === "object") {
    const obj = body;
    for (const key of ["error", "message", "detail"]) {
      const value = obj[key];
      if (typeof value === "string" && value.length > 0) return value;
    }
  }
  if (typeof body === "string" && body.length > 0) return body;
  return void 0;
}

// src/transport.ts
var USER_AGENT = "invariantdb-node/0.2.0";
var Transport = class {
  url;
  apiKey;
  capability;
  timeoutMs;
  fetchImpl;
  constructor(opts) {
    if (opts.apiKey && opts.capability) {
      throw new Error("pass apiKey or capability, not both");
    }
    this.url = opts.url.replace(/\/+$/, "");
    this.apiKey = opts.apiKey;
    this.capability = opts.capability;
    this.timeoutMs = opts.timeoutMs ?? 6e4;
    this.fetchImpl = opts.fetchImpl ?? ((...args) => fetch(...args));
  }
  async request(opts) {
    const url = new URL(this.url + opts.path);
    if (opts.params) {
      for (const [key, value] of Object.entries(opts.params)) {
        if (value === void 0 || value === null) continue;
        url.searchParams.set(key, String(value));
      }
    }
    const headers = {
      "User-Agent": USER_AGENT,
      Accept: "application/json"
    };
    if (this.apiKey) {
      headers["Authorization"] = `Bearer ${this.apiKey}`;
    } else if (this.capability) {
      headers["Authorization"] = `Capability ${this.capability}`;
    }
    const init = { method: opts.method, headers };
    if (opts.json !== void 0) {
      headers["Content-Type"] = "application/json";
      init.body = JSON.stringify(opts.json);
    }
    const controller = new AbortController();
    init.signal = controller.signal;
    const timer = setTimeout(() => controller.abort(), this.timeoutMs);
    let response;
    try {
      response = await this.fetchImpl(url, init);
    } catch (err) {
      throw new TransportError(
        `${opts.method} ${opts.path} failed: ${err.message}`
      );
    } finally {
      clearTimeout(timer);
    }
    const requestId = response.headers.get("x-request-id") ?? void 0;
    if (!response.ok) {
      const body = await safeJson(response);
      throw errorFromResponse(response.status, body, requestId);
    }
    const text = await response.text();
    if (!text) return null;
    try {
      return JSON.parse(text);
    } catch {
      return text;
    }
  }
};
async function safeJson(response) {
  const text = await response.text();
  if (!text) return null;
  try {
    return JSON.parse(text);
  } catch {
    return text;
  }
}

// src/wire.ts
var TAGGED_KEYS = /* @__PURE__ */ new Set([
  "Null",
  "null",
  "Bool",
  "bool",
  "Int",
  "int",
  "Float",
  "float",
  "Str",
  "String",
  "string",
  "Array",
  "array",
  "Object",
  "object",
  "Bytes",
  "bytes",
  "Time",
  "time",
  // Cypher executor's `Value::Core(...)` wrapper. Serializes as
  // {"core": {"String": "..."}} — the outer "core" tag wraps a
  // gq_core::Value which is itself tagged. Denormalize recurses.
  "Core",
  "core",
  // #293 (StaticOwl): graph entities. The executor emits MATCH-bound
  // nodes/edges as `{"node": {...}}` / `{"edge": {...}}`. Inner is
  // `{id, labels, properties, span}` — properties values are themselves
  // tagged, but the denormalize recursion handles those.
  "Node",
  "node",
  "Edge",
  "edge",
  "NodeId",
  "node_id",
  "EdgeId",
  "edge_id",
  "Path",
  "path"
]);
var TAGGED_KEYS_LOWER = new Set(Array.from(TAGGED_KEYS, (k) => k.toLowerCase()));
var OPS_WITH_PROPERTIES = /* @__PURE__ */ new Set([
  "createNode",
  "createEdge",
  "updateNodeProperties",
  "updateEdgeProperties",
  "setNodeProperties",
  "setEdgeProperties",
  "mergeNode",
  "mergeEdge"
]);
var OP_FIELD_RENAMES = {
  createEdge: { type: "edge_type" },
  mergeEdge: { type: "edge_type" }
};
function normalizeValue(v) {
  if (v !== null && typeof v === "object" && !Array.isArray(v) && Object.keys(v).length === 1) {
    const onlyKey = Object.keys(v)[0];
    if (TAGGED_KEYS.has(onlyKey)) return v;
  }
  if (v === null || v === void 0) return { Null: null };
  if (typeof v === "boolean") return { Bool: v };
  if (typeof v === "number") {
    return Number.isInteger(v) ? { Int: v } : { Float: v };
  }
  if (typeof v === "bigint") return { Int: Number(v) };
  if (typeof v === "string") return { Str: v };
  if (Array.isArray(v)) return { Array: v.map(normalizeValue) };
  if (v instanceof Uint8Array) return { Bytes: Array.from(v) };
  if (typeof v === "object") {
    const out = {};
    for (const [k, val] of Object.entries(v)) {
      out[k] = normalizeValue(val);
    }
    return { Object: out };
  }
  throw new TypeError(`unsupported property value type: ${typeof v}`);
}
function normalizeOp(op) {
  const entries = Object.entries(op);
  if (entries.length !== 1) return op;
  const [name, payload] = entries[0];
  if (!payload || typeof payload !== "object" || Array.isArray(payload)) return op;
  const newPayload = { ...payload };
  const renames = OP_FIELD_RENAMES[name];
  if (renames) {
    for (const [src, dst] of Object.entries(renames)) {
      if (src in newPayload && !(dst in newPayload)) {
        newPayload[dst] = newPayload[src];
        delete newPayload[src];
      }
    }
  }
  if (OPS_WITH_PROPERTIES.has(name)) {
    const props = newPayload["properties"];
    if (props && typeof props === "object" && !Array.isArray(props)) {
      const newProps = {};
      for (const [k, val] of Object.entries(props)) {
        newProps[k] = normalizeValue(val);
      }
      newPayload["properties"] = newProps;
    }
  }
  return { [name]: newPayload };
}
function normalizeOps(ops) {
  return Array.from(ops, normalizeOp);
}
function denormalizeValue(v) {
  if (Array.isArray(v)) return v.map(denormalizeValue);
  if (v === null || typeof v !== "object") return v;
  const obj = v;
  const keys = Object.keys(obj);
  if (keys.length === 1) {
    const only = keys[0];
    if (TAGGED_KEYS_LOWER.has(only.toLowerCase())) {
      const inner = obj[only];
      const tag = only.toLowerCase();
      if (tag === "null") return null;
      if (tag === "array") {
        return Array.isArray(inner) ? inner.map(denormalizeValue) : inner;
      }
      if (tag === "object") {
        if (inner && typeof inner === "object" && !Array.isArray(inner)) {
          const out2 = {};
          for (const [k, val] of Object.entries(inner)) {
            out2[k] = denormalizeValue(val);
          }
          return out2;
        }
        return inner;
      }
      if (tag === "bytes") {
        return Array.isArray(inner) ? new Uint8Array(inner) : inner;
      }
      if (tag === "core") {
        return denormalizeValue(inner);
      }
      if (tag === "node" || tag === "edge" || tag === "path") {
        return denormalizeValue(inner);
      }
      if (tag === "node_id" || tag === "edge_id") return inner;
      if (tag === "timestamp" || tag === "time") {
        if (typeof inner === "number" && !isFinite(inner)) return null;
        if (typeof inner === "number" && (inner <= -(2 ** 62) || inner >= 2 ** 62)) {
          return null;
        }
        return inner;
      }
      return inner;
    }
  }
  const out = {};
  for (const [k, val] of Object.entries(obj)) {
    out[k] = denormalizeValue(val);
  }
  return out;
}
function denormalizeRows(rows) {
  return rows.map((row) => row.map(denormalizeValue));
}

// src/types.ts
var num = (v, fallback = 0) => typeof v === "number" ? v : typeof v === "string" ? Number(v) : fallback;
var str = (v) => typeof v === "string" ? v : void 0;
function graphSummaryFromDict(d) {
  const snap = d["current_snapshot_seq"];
  return {
    name: String(d["name"] ?? ""),
    currentSnapshotSeq: snap === null || snap === void 0 ? null : num(snap),
    nextSeq: num(d["next_seq"])
  };
}
function graphInfoFromDict(d) {
  return {
    name: String(d["name"] ?? ""),
    description: String(d["description"] ?? ""),
    createdAt: str(d["created_at"] ?? d["createdAt"])
  };
}
function cypherStatsFromDict(d) {
  return {
    nodesCreated: num(d["nodes_created"]),
    nodesDeleted: num(d["nodes_deleted"]),
    edgesCreated: num(d["edges_created"]),
    edgesDeleted: num(d["edges_deleted"]),
    propertiesSet: num(d["properties_set"]),
    labelsAdded: num(d["labels_added"]),
    rowsReturned: num(d["rows_returned"])
  };
}
function cypherResultFromDict(d) {
  const columns = Array.isArray(d["columns"]) ? d["columns"].map(String) : [];
  const rawRows = Array.isArray(d["rows"]) ? d["rows"] : [];
  const rows = denormalizeRows(rawRows);
  const stats = cypherStatsFromDict(
    d["stats"] ?? {}
  );
  const lastSeqRaw = d["last_seq"];
  return {
    columns,
    rows,
    stats,
    mutationsApplied: num(d["mutations_applied"]),
    lastSeq: lastSeqRaw === null || lastSeqRaw === void 0 ? null : num(lastSeqRaw),
    asDicts() {
      return rows.map((row) => {
        const out = {};
        columns.forEach((col, i) => {
          out[col] = row[i];
        });
        return out;
      });
    }
  };
}
function schemaVersionFromDict(d) {
  return {
    version: num(d["version"]),
    appliedAtNanos: num(d["applied_at_nanos"]),
    body: d["body"]
  };
}
function searchHitFromDict(d) {
  return {
    nodeId: typeof d["node_id"] === "number" ? d["node_id"] : void 0,
    strId: str(d["str_id"] ?? d["strId"]),
    score: num(d["score"]),
    label: str(d["label"]),
    property: str(d["property"]),
    snippet: str(d["snippet"])
  };
}
function auditStatusFromDict(d) {
  const status = String(d["status"] ?? "unknown");
  return {
    status,
    records: typeof d["records"] === "number" ? d["records"] : void 0,
    lastSeq: typeof d["last_seq"] === "number" ? d["last_seq"] : void 0,
    reason: str(d["reason"] ?? d["message"]),
    raw: d,
    get isClean() {
      return status === "clean";
    }
  };
}
function jobFromDict(d) {
  const state = String(d["state"] ?? "");
  return {
    id: String(d["id"] ?? ""),
    kind: String(d["kind"] ?? ""),
    graph: String(d["graph"] ?? ""),
    state,
    createdAt: str(d["created_at"] ?? d["createdAt"]),
    updatedAt: str(d["updated_at"] ?? d["updatedAt"]),
    error: str(d["error"]),
    raw: d,
    get isTerminal() {
      return state === "completed" || state === "failed" || state === "cancelled";
    },
    get isSucceeded() {
      return state === "completed";
    }
  };
}

// src/client.ts
var Client = class {
  t;
  graphs;
  schema;
  indexes;
  audit;
  backup;
  jobs;
  search;
  compliance;
  admin;
  ai;
  cluster;
  procedures;
  capabilities;
  cursor;
  constructor(opts) {
    this.t = new Transport(opts);
    this.graphs = new Graphs(this.t);
    this.schema = new Schema(this.t);
    this.indexes = new Indexes(this.t);
    this.audit = new Audit(this.t);
    this.backup = new Backup(this.t);
    this.jobs = new Jobs(this.t);
    this.search = new Search(this.t);
    this.compliance = new Compliance(this.t);
    this.admin = new Admin(this.t);
    this.ai = new AI(this.t);
    this.cluster = new Cluster(this.t);
    this.procedures = new Procedures(this);
    this.capabilities = new Capabilities(this.t);
    this.cursor = new Cursor(this.t);
  }
  /**
   * 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.
   */
  async cypher(graph, query, opts = {}) {
    const json = { query };
    if (opts.parameters && Object.keys(opts.parameters).length > 0) {
      json.parameters = opts.parameters;
    }
    const body = await this.t.request({
      method: "POST",
      path: `/graphs/${graph}/cypher`,
      json
    });
    return cypherResultFromDict(body ?? {});
  }
  /**
   * Planner analysis without execution (#172). Returns
   * `{plan, policy}`. Use to pre-check queries against the engine's
   * execution policy.
   */
  async explain(graph, query) {
    const body = await this.t.request({
      method: "POST",
      path: `/graphs/${graph}/explain`,
      json: { query }
    });
    return body ?? { plan: "", policy: {} };
  }
  /**
   * 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.
   */
  async write(graph, ops, opts = {}) {
    const normalize = opts.normalize ?? true;
    const body = normalize ? normalizeOps(ops) : ops;
    return this.t.request({
      method: "POST",
      path: `/graphs/${graph}/execute`,
      json: body
    });
  }
  /** Force a compaction + snapshot publish. */
  async flush(graph) {
    return this.t.request({ method: "POST", path: `/graphs/${graph}/flush` });
  }
  /** Liveness + Raft state. */
  async health() {
    return await this.t.request({
      method: "GET",
      path: "/healthz"
    }) ?? {};
  }
  /** Engine info — graph dir, seq, auth summary. */
  async info() {
    return await this.t.request({
      method: "GET",
      path: "/info"
    }) ?? {};
  }
  /** Look up a node by string ID on the engine's default graph. */
  async nodeByStr(strId) {
    const body = await this.t.request({
      method: "GET",
      path: `/node-by-str/${encodeURIComponent(strId)}`
    });
    return denormalizeValue(body ?? {});
  }
  /** Look up an edge by string ID on the engine's default graph. */
  async edgeByStr(strId) {
    const body = await this.t.request({
      method: "GET",
      path: `/edge-by-str/${encodeURIComponent(strId)}`
    });
    return denormalizeValue(body ?? {});
  }
  async edgesBetween(graph, opts) {
    const result = await this.t.request({
      method: "GET",
      path: `/graphs/${graph}/edges-between`,
      params: {
        source: opts.source,
        target: opts.target,
        edge_type: opts.edgeType
      }
    });
    const list = Array.isArray(result) ? result : result && typeof result === "object" && Array.isArray(result["edges"]) ? result["edges"] : [];
    return list.map(denormalizeValue);
  }
  async listLabel(graph, label, limit) {
    const result = await this.t.request({
      method: "GET",
      path: `/graphs/${graph}/collections/${encodeURIComponent(label)}`,
      params: { limit }
    });
    const list = Array.isArray(result) ? result : result && typeof result === "object" ? result["nodes"] ?? result["items"] ?? [] : [];
    return list.map(denormalizeValue);
  }
};
var Namespace = class {
  constructor(t) {
    this.t = t;
  }
  t;
};
var Graphs = class extends Namespace {
  async list() {
    const rows = await this.t.request({
      method: "GET",
      path: "/graphs"
    }) ?? [];
    return rows.map(graphInfoFromDict);
  }
  async create(name) {
    const body = await this.t.request({
      method: "POST",
      path: "/graphs",
      json: { name }
    });
    return graphSummaryFromDict(body ?? { name });
  }
  async info(name) {
    const body = await this.t.request({
      method: "GET",
      path: `/graphs/${name}`
    });
    return graphSummaryFromDict(body ?? { name });
  }
  async exists(name) {
    try {
      await this.info(name);
      return true;
    } catch (err) {
      if (err instanceof NotFoundError) return false;
      if (err instanceof ValidationError && isNotFoundBody(err.body)) return false;
      throw err;
    }
  }
  async drop(name) {
    await this.t.request({ method: "DELETE", path: `/graphs/${name}` });
  }
  async clone(opts) {
    const body = await this.t.request({
      method: "POST",
      path: `/graphs/${opts.destination}/clone-from/${opts.source}`
    });
    return graphSummaryFromDict(body ?? { name: opts.destination });
  }
  async rebuildDerived(name) {
    return this.t.request({
      method: "POST",
      path: `/graphs/${name}/rebuild-derived`
    });
  }
  /**
   * Idempotently provision a graph (#170). Returns `{created, summary}`.
   * `created` is true only when this call materialized the graph.
   */
  async ensure(name) {
    try {
      const summary = await this.create(name);
      return { created: true, summary };
    } catch (err) {
      if (err instanceof ConflictError) {
        const summary = await this.info(name);
        return { created: false, summary };
      }
      throw err;
    }
  }
};
var Schema = class extends Namespace {
  async get(graph) {
    return await this.t.request({
      method: "GET",
      path: `/graphs/${graph}/schema`
    }) ?? {};
  }
  async put(graph, body) {
    const resp = await this.t.request({
      method: "POST",
      path: `/graphs/${graph}/schema`,
      json: { body }
    });
    return Number(resp?.["version"] ?? 0);
  }
  async history(graph) {
    const rows = await this.t.request({
      method: "GET",
      path: `/graphs/${graph}/schema/history`
    }) ?? [];
    return rows.map(schemaVersionFromDict);
  }
};
var Indexes = class extends Namespace {
  async create(graph, opts) {
    return this.t.request({
      method: "POST",
      path: `/graphs/${graph}/admin/create-index`,
      json: {
        label: opts.label,
        property: opts.property,
        value_type: opts.valueType ?? "string",
        unique: opts.unique ?? false
      }
    });
  }
  /**
   * 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.
   */
  async ensure(graph, specs) {
    const out = [];
    for (const spec of specs) {
      try {
        await this.create(graph, spec);
        out.push({ spec, created: true });
      } catch (err) {
        if (err instanceof ConflictError) {
          out.push({ spec, created: false, error: String(err) });
        } else {
          throw err;
        }
      }
    }
    return out;
  }
};
var Audit = class extends Namespace {
  async verify(graph) {
    const body = await this.t.request({
      method: "GET",
      path: `/graphs/${graph}/audit/verify`
    });
    return auditStatusFromDict(body ?? {});
  }
};
var Backup = class extends Namespace {
  async create(graph, opts) {
    return this.t.request({
      method: "POST",
      path: `/graphs/${graph}/backup`,
      json: { output_path: opts.outputPath }
    });
  }
  async restore(graph, opts) {
    return this.t.request({
      method: "POST",
      path: `/graphs/${graph}/restore`,
      json: { input_path: opts.inputPath }
    });
  }
};
var Jobs = class extends Namespace {
  async list(opts = {}) {
    const body = await this.t.request({
      method: "GET",
      path: "/jobs",
      params: { state: opts.state, graph: opts.graph, limit: opts.limit }
    });
    const rows = Array.isArray(body) ? body : body && typeof body === "object" && Array.isArray(body["jobs"]) ? body["jobs"] : [];
    return rows.map((r) => jobFromDict(r));
  }
  async get(jobId) {
    const body = await this.t.request({
      method: "GET",
      path: `/jobs/${jobId}`
    });
    return jobFromDict(body ?? { id: jobId });
  }
  async result(jobId) {
    return this.t.request({ method: "GET", path: `/jobs/${jobId}/result` });
  }
  async wait(jobId, opts = {}) {
    const deadline = opts.timeoutMs === void 0 ? null : Date.now() + opts.timeoutMs;
    const pollMs = opts.pollIntervalMs ?? 1e3;
    while (true) {
      const job = await this.get(jobId);
      if (job.isTerminal) return job;
      if (deadline !== null && Date.now() >= deadline) {
        throw new Error(`job ${jobId} did not finish within ${opts.timeoutMs}ms`);
      }
      await sleep(pollMs);
    }
  }
};
var Search = class extends Namespace {
  async fulltext(graph, opts) {
    const resp = await this.t.request({
      method: "POST",
      path: `/graphs/${graph}/search/fulltext`,
      json: {
        label: opts.label,
        property: opts.property,
        query: opts.query,
        k: opts.k ?? 10
      }
    });
    const hits = Array.isArray(resp?.["hits"]) ? resp["hits"] : [];
    return hits.map((h) => searchHitFromDict(h));
  }
  async vector(graph, opts) {
    const resp = await this.t.request({
      method: "POST",
      path: `/graphs/${graph}/search/vector`,
      json: {
        label: opts.label,
        property: opts.property,
        query: opts.vector,
        k: opts.k ?? 10,
        metric: opts.metric ?? "cosine"
      }
    });
    const hits = Array.isArray(resp?.["hits"]) ? resp["hits"] : [];
    return hits.map((h) => searchHitFromDict(h));
  }
  async rebuild(graph) {
    const path = graph ? `/graphs/${graph}/search/rebuild` : "/search/rebuild";
    return this.t.request({ method: "POST", path });
  }
};
var Compliance = class extends Namespace {
  async export(graph, opts) {
    return this.t.request({
      method: "POST",
      path: `/graphs/${graph}/compliance/export`,
      json: { output: opts.output }
    });
  }
  async summary(graph) {
    return this.t.request({
      method: "GET",
      path: `/graphs/${graph}/compliance/summary`
    });
  }
  /** Is WORM (write-once-read-many) mode engaged on this graph? */
  async wormStatus(graph) {
    const body = await this.t.request({
      method: "GET",
      path: `/graphs/${graph}/worm`
    }) ?? { engaged: false };
    return body;
  }
  /**
   * 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.
   */
  async engageWorm(graph) {
    const body = await this.t.request({
      method: "POST",
      path: `/graphs/${graph}/worm/engage`
    }) ?? { engaged: true };
    return body;
  }
};
var Admin = class extends Namespace {
  async createApiKey(opts) {
    return this.t.request({
      method: "POST",
      path: "/admin/api-keys",
      json: { tenant: opts.tenant }
    });
  }
  async listApiKeys(opts = {}) {
    const body = await this.t.request({
      method: "GET",
      path: "/admin/api-keys",
      params: { include_revoked: opts.includeRevoked ? "true" : void 0 }
    });
    return body ?? [];
  }
  async revokeApiKey(keyId) {
    return this.t.request({
      method: "DELETE",
      path: `/admin/api-keys/${keyId}`
    });
  }
  async debugStorage() {
    return this.t.request({ method: "GET", path: "/admin/debug/storage" });
  }
  async backup(opts) {
    return this.t.request({
      method: "POST",
      path: "/admin/backup",
      json: { output_path: opts.outputPath }
    });
  }
};
var AI = class extends Namespace {
  async nlq(graph, question, opts = {}) {
    const body = { question };
    if (opts.mode !== void 0) body["mode"] = opts.mode;
    if (opts.schema !== void 0) body["schema"] = opts.schema;
    return this.t.request({
      method: "POST",
      path: `/graphs/${graph}/nlq`,
      json: body
    });
  }
  async investigate(graph, question, opts = {}) {
    const body = { question };
    if (opts.contextQuery !== void 0) body["context_query"] = opts.contextQuery;
    if (opts.provider !== void 0) body["provider"] = opts.provider;
    return this.t.request({
      method: "POST",
      path: `/graphs/${graph}/investigate`,
      json: body
    });
  }
  async agent(graph, message, extra = {}) {
    return this.t.request({
      method: "POST",
      path: `/graphs/${graph}/agent`,
      json: { message, ...extra }
    });
  }
};
var Cluster = class extends Namespace {
  async info() {
    return this.t.request({ method: "GET", path: "/cluster/info" });
  }
  async init(opts) {
    return this.t.request({
      method: "POST",
      path: "/cluster/init",
      json: { node_id: opts.nodeId, advertise_addr: opts.advertiseAddr }
    });
  }
  async addLearner(opts) {
    return this.t.request({
      method: "POST",
      path: "/cluster/add-learner",
      json: { node_id: opts.nodeId, addr: opts.addr }
    });
  }
  async changeMembership(opts) {
    return this.t.request({
      method: "POST",
      path: "/cluster/change-membership",
      json: { members: opts.members }
    });
  }
  async read() {
    return this.t.request({ method: "GET", path: "/cluster/read" });
  }
  async write(payload) {
    return this.t.request({
      method: "POST",
      path: "/cluster/write",
      json: payload
    });
  }
};
var Capabilities = class extends Namespace {
  async issue(opts) {
    const body = await this.t.request({
      method: "POST",
      path: "/capabilities/issue",
      json: {
        graph: opts.graph,
        principal: opts.principal,
        scope: opts.scope ?? [],
        ttl_seconds: opts.ttlSeconds
      }
    });
    if (!body) throw new Error("empty capability response");
    return body;
  }
};
var Procedures = class _Procedures {
  constructor(client) {
    this.client = client;
  }
  client;
  static toNanos(ts) {
    if (typeof ts === "number") return ts;
    if (ts instanceof Date) return ts.getTime() * 1e6;
    if (typeof ts === "string") return new Date(ts).getTime() * 1e6;
    throw new TypeError(`unsupported timestamp type: ${typeof ts}`);
  }
  /** `CALL db.changes(from, to)` — every mutation in the window. */
  async changes(graph, fromTs, toTs) {
    const f = _Procedures.toNanos(fromTs);
    const t = _Procedures.toNanos(toTs);
    const result = await this.client.cypher(
      graph,
      `CALL db.changes(${f}, ${t}) YIELD kind, op, entity_id, label, txn_at, applied_seq RETURN kind, op, entity_id, label, txn_at, applied_seq`
    );
    return result.asDicts();
  }
  /**
   * `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.
   */
  async diff(graph, fromTs, toTs) {
    const f = _Procedures.toNanos(fromTs);
    const t = _Procedures.toNanos(toTs);
    const result = await this.client.cypher(
      graph,
      `CALL db.delta(${f}, ${t}) YIELD kind, entity_id, label, first_op, last_op, n_changes RETURN kind, entity_id, label, first_op, last_op, n_changes`
    );
    return result.asDicts();
  }
  /** `CALL db.changeRate(window)` — mutations/sec over the last window. */
  async changeRate(graph, windowSeconds) {
    const result = await this.client.cypher(
      graph,
      `CALL db.changeRate(${Math.floor(windowSeconds)}) YIELD rate, n_mutations, window_seconds RETURN rate, n_mutations, window_seconds`
    );
    const rows = result.asDicts();
    if (rows.length === 0) {
      return { rate: 0, n_mutations: 0, window_seconds: windowSeconds };
    }
    const row = rows[0];
    return {
      rate: Number(row["rate"] ?? 0),
      n_mutations: Number(row["n_mutations"] ?? 0),
      window_seconds: Number(row["window_seconds"] ?? windowSeconds)
    };
  }
  // ─── Moat procedures (ADR-0062) ───────────────────────────────────────
  static q(s) {
    return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
  }
  /** `CALL db.subjectExport(subjectStrId)` — GDPR Article 20 portability. */
  async subjectExport(graph, subjectStrId) {
    const q = `CALL db.subjectExport('${_Procedures.q(subjectStrId)}') YIELD type, id, kind, payload RETURN type, id, kind, payload`;
    return (await this.client.cypher(graph, q)).asDicts();
  }
  /** `CALL db.destroySubjectKey(subjectId)` — GDPR Article 17 erasure. */
  async destroySubjectKey(graph, subjectId) {
    const q = `CALL db.destroySubjectKey('${_Procedures.q(subjectId)}') YIELD subjectId, destroyedAt RETURN subjectId, destroyedAt`;
    const rows = (await this.client.cypher(graph, q)).asDicts();
    return rows[0] ?? {};
  }
  /** `CALL db.aclEvents([sinceId [, principal [, limit]]])` — ACL audit replay. */
  async aclEvents(graph, opts = {}) {
    const since = Math.floor(opts.sinceId ?? 0);
    const principalArg = opts.principal ? `'${_Procedures.q(opts.principal)}'` : "NULL";
    const limit = Math.floor(opts.limit ?? 1024);
    const q = `CALL db.aclEvents(${since}, ${principalArg}, ${limit}) YIELD eventId, ts, principal, label, property, action, denied, reason RETURN eventId, ts, principal, label, property, action, denied, reason`;
    return (await this.client.cypher(graph, q)).asDicts();
  }
  /** `CALL db.linkDerivedFrom(nodeStrId, sourceIds [, kind])`. */
  async linkDerivedFrom(graph, nodeStrId, sourceStrIds, kind) {
    const sources = sourceStrIds.map((s) => `'${_Procedures.q(s)}'`).join(", ");
    const kindArg = kind ? `, '${_Procedures.q(kind)}'` : "";
    const q = `CALL db.linkDerivedFrom('${_Procedures.q(nodeStrId)}', [${sources}]${kindArg}) YIELD linked RETURN linked`;
    const rows = (await this.client.cypher(graph, q)).asDicts();
    return rows[0] ?? { linked: 0 };
  }
  /** `CALL db.derivedFrom(nodeStrId [, maxDepth])`. */
  async derivedFrom(graph, nodeStrId, maxDepth) {
    const depthArg = maxDepth != null ? `, ${Math.floor(maxDepth)}` : "";
    const q = `CALL db.derivedFrom('${_Procedures.q(nodeStrId)}'${depthArg}) YIELD sourceStrId, depth, kind RETURN sourceStrId, depth, kind`;
    return (await this.client.cypher(graph, q)).asDicts();
  }
  /**
   * `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')
   */
  async propertyProvenance(graph, ref, property) {
    let refExpr;
    if (typeof ref === "string") {
      refExpr = `'${_Procedures.q(ref)}'`;
    } else if (typeof ref === "number") {
      refExpr = String(Math.floor(ref));
    } else if (ref && typeof ref === "object") {
      if (ref.strId != null) refExpr = `'${_Procedures.q(ref.strId)}'`;
      else if (ref.nodeId != null) refExpr = String(Math.floor(ref.nodeId));
      else throw new TypeError("propertyProvenance: provide strId or nodeId");
    } else {
      throw new TypeError("propertyProvenance: ref must be a string, number, or {strId?, nodeId?}");
    }
    const q = `CALL db.propertyProvenance(${refExpr}, '${_Procedures.q(property)}') YIELD valueIndex, value, validFrom, validTo, actor, source, reason, requestId, confidence RETURN valueIndex, value, validFrom, validTo, actor, source, reason, requestId, confidence`;
    return (await this.client.cypher(graph, q)).asDicts();
  }
  /** `CALL db.recordEpisode(sessionId, kind, text [, payload])`. */
  async recordEpisode(graph, sessionId, kind, text, payload) {
    const payloadArg = payload != null ? `, '${_Procedures.q(payload)}'` : "";
    const q = `CALL db.recordEpisode('${_Procedures.q(sessionId)}', '${_Procedures.q(kind)}', '${_Procedures.q(text)}'${payloadArg}) YIELD eventId, ts RETURN eventId, ts`;
    const rows = (await this.client.cypher(graph, q)).asDicts();
    return rows[0] ?? {};
  }
  /** `CALL db.replayEpisodes(sessionId [, limit])`. */
  async replayEpisodes(graph, sessionId, limit) {
    const limitArg = limit != null ? `, ${Math.floor(limit)}` : "";
    const q = `CALL db.replayEpisodes('${_Procedures.q(sessionId)}'${limitArg}) YIELD eventId, kind, ts, text, payload RETURN eventId, kind, ts, text, payload`;
    return (await this.client.cypher(graph, q)).asDicts();
  }
  /** `CALL db.consolidateSession(sessionId, summary [, sinceTs])`. */
  async consolidateSession(graph, sessionId, summary, sinceTs) {
    const sinceArg = sinceTs != null ? `, ${Math.floor(sinceTs)}` : "";
    const q = `CALL db.consolidateSession('${_Procedures.q(sessionId)}', '${_Procedures.q(summary)}'${sinceArg}) YIELD summaryId, eventCount RETURN summaryId, eventCount`;
    const rows = (await this.client.cypher(graph, q)).asDicts();
    return rows[0] ?? {};
  }
  /** `CALL db.sessionSummaries(sessionId)`. */
  async sessionSummaries(graph, sessionId) {
    const q = `CALL db.sessionSummaries('${_Procedures.q(sessionId)}') YIELD summaryId, summary, createdAt, eventCount RETURN summaryId, summary, createdAt, eventCount`;
    return (await this.client.cypher(graph, q)).asDicts();
  }
  /** `CALL db.applySalienceDecay(label, halfLifeSeconds [, floor])`. */
  async applySalienceDecay(graph, label, halfLifeSeconds, floor) {
    const floorArg = floor != null ? `, ${floor}` : "";
    const q = `CALL db.applySalienceDecay('${_Procedures.q(label)}', ${Math.floor(halfLifeSeconds)}${floorArg}) YIELD decayed, mean RETURN decayed, mean`;
    const rows = (await this.client.cypher(graph, q)).asDicts();
    return rows[0] ?? {};
  }
  /** `CALL db.reinforceSalience(strId [, amount])`. */
  async reinforceSalience(graph, strId, amount) {
    const amountArg = amount != null ? `, ${amount}` : "";
    const q = `CALL db.reinforceSalience('${_Procedures.q(strId)}'${amountArg}) YIELD salience RETURN salience`;
    const rows = (await this.client.cypher(graph, q)).asDicts();
    return rows[0] ?? {};
  }
  /** `CALL db.recordBelief(beliefId, claim, confidence [, evidenceIds])`. */
  async recordBelief(graph, beliefId, claim, confidence, evidenceStrIds) {
    const evidenceArg = evidenceStrIds ? `, [${evidenceStrIds.map((s) => `'${_Procedures.q(s)}'`).join(", ")}]` : "";
    const q = `CALL db.recordBelief('${_Procedures.q(beliefId)}', '${_Procedures.q(claim)}', ${confidence}${evidenceArg}) YIELD beliefId, createdAt RETURN beliefId, createdAt`;
    const rows = (await this.client.cypher(graph, q)).asDicts();
    return rows[0] ?? {};
  }
  /** `CALL db.reviseBelief(beliefId, newClaim, newConfidence, reason)`. */
  async reviseBelief(graph, beliefId, newClaim, newConfidence, reason) {
    const q = `CALL db.reviseBelief('${_Procedures.q(beliefId)}', '${_Procedures.q(newClaim)}', ${newConfidence}, '${_Procedures.q(reason)}') YIELD newBeliefId, revisedAt RETURN newBeliefId, revisedAt`;
    const rows = (await this.client.cypher(graph, q)).asDicts();
    return rows[0] ?? {};
  }
  /** `CALL db.beliefLineage(beliefId)`. */
  async beliefLineage(graph, beliefId) {
    const q = `CALL db.beliefLineage('${_Procedures.q(beliefId)}') YIELD beliefId, claim, confidence, createdAt, supersededAt, depth RETURN beliefId, claim, confidence, createdAt, supersededAt, depth`;
    return (await this.client.cypher(graph, q)).asDicts();
  }
  /** `CALL db.proveErasure(subjectId)` — receipts + chain status. */
  async proveErasure(graph, subjectId) {
    const q = `CALL db.proveErasure('${_Procedures.q(subjectId)}') YIELD receiptId, destroyedAt, anchorHistorySeq, anchorHistoryHash, ownChainHash, chainStatus RETURN receiptId, destroyedAt, anchorHistorySeq, anchorHistoryHash, ownChainHash, chainStatus`;
    return (await this.client.cypher(graph, q)).asDicts();
  }
  /** `CALL db.verifyAclChain()` — tamper-evidence check on ACL log. */
  async verifyAclChain(graph) {
    const q = `CALL db.verifyAclChain() YIELD status, entries, brokenAtEventId, reason RETURN status, entries, brokenAtEventId, reason`;
    const rows = (await this.client.cypher(graph, q)).asDicts();
    return rows[0] ?? {};
  }
  /** `CALL db.embeddingModelDrift(label, prop)`. */
  async embeddingModelDrift(graph, label, prop) {
    const q = `CALL db.embeddingModelDrift('${_Procedures.q(label)}', '${_Procedures.q(prop)}') YIELD declaredModel, declaredVersion, drifted, sample RETURN declaredModel, declaredVersion, drifted, sample`;
    const rows = (await this.client.cypher(graph, q)).asDicts();
    return rows[0] ?? {};
  }
  /** `CALL gds.semanticMatchExpand(label, prop, query, k, hops [, edgeTypes [, threshold]])`. */
  async semanticMatchExpand(graph, label, prop, query, k, hops, opts = {}) {
    const vec = "[" + query.join(", ") + "]";
    let edges = "";
    if (opts.edgeTypes && opts.edgeTypes.length > 0) {
      edges = `, [${opts.edgeTypes.map((t) => `'${_Procedures.q(t)}'`).join(", ")}]`;
    } else if (opts.threshold != null) {
      edges = ", []";
    }
    const thresholdArg = opts.threshold != null ? `, ${opts.threshold}` : "";
    const q = `CALL gds.semanticMatchExpand('${_Procedures.q(label)}', '${_Procedures.q(prop)}', ${vec}, ${Math.floor(k)}, ${Math.floor(hops)}${edges}${thresholdArg}) YIELD nodeStrId, score, hops, path RETURN nodeStrId, score, hops, path`;
    return (await this.client.cypher(graph, q)).asDicts();
  }
};
var Cursor = class extends Namespace {
  async open(graph, query, opts = {}) {
    const body = { query, batch_size: opts.batchSize ?? 1e3 };
    if (opts.parameters) body.parameters = opts.parameters;
    return await this.t.request({
      method: "POST",
      path: `/graphs/${graph}/cursor`,
      json: body
    }) ?? {};
  }
  async next(graph, cursorId, opts = {}) {
    return await this.t.request({
      method: "GET",
      path: `/graphs/${graph}/cursor/${cursorId}`,
      params: { batch: opts.batch ?? 1e3 }
    }) ?? {};
  }
  async close(graph, cursorId) {
    return await this.t.request({
      method: "DELETE",
      path: `/graphs/${graph}/cursor/${cursorId}`
    }) ?? {};
  }
  /** Async-iterate every row yielded by `query`. Releases the cursor
   * when iteration completes or the caller breaks out. */
  async *stream(graph, query, opts = {}) {
    const first = await this.open(graph, query, opts);
    const columns = first.columns ?? [];
    const batchSize = opts.batchSize ?? 1e3;
    const rowsToYield = (rows) => rows.map((row) => Object.fromEntries(columns.map((c, i) => [c, row[i]])));
    const firstBatch = first.batch ?? [];
    for (const row of rowsToYield(firstBatch)) {
      yield row;
    }
    if (!first.has_more) return;
    const cursorId = first.cursor_id;
    try {
      while (true) {
        const page = await this.next(graph, cursorId, { batch: batchSize });
        const pageBatch = page.batch ?? [];
        for (const row of rowsToYield(pageBatch)) {
          yield row;
        }
        if (!page.has_more) return;
      }
    } finally {
      try {
        await this.close(graph, cursorId);
      } catch {
      }
    }
  }
};
function isNotFoundBody(body) {
  if (!body || typeof body !== "object") return false;
  const obj = body;
  for (const key of ["message", "error"]) {
    const v = obj[key];
    if (typeof v === "string") {
      const lower = v.toLowerCase();
      if (lower.includes("not found") || lower.includes("does not exist")) {
        return true;
      }
    }
  }
  return false;
}
function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

// src/index.ts
var VERSION = "0.2.0";
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  APIError,
  AuthError,
  Client,
  ConflictError,
  InvariantDBError,
  NotFoundError,
  RateLimitError,
  ServerError,
  TransportError,
  VERSION,
  ValidationError,
  denormalizeValue,
  normalizeOp,
  normalizeOps,
  normalizeValue
});
