{"version":3,"sources":["../src/backend/capabilities/lineage.ts"],"names":["ConfigurationError"],"mappings":";;;;;AAgIO,SAAS,cAAA,CACd,SACA,SAAA,EACgB;AAChB,EAAA,MAAM,UAAU,OAAA,CAAQ,OAAA;AACxB,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,MAAM,IAAIA,oCAAA;AAAA,MACR,GAAG,SAAS,CAAA,qFAAA,CAAA;AAAA,MACZ,EAAE,IAAA,EAAM,qBAAA,EAAuB,SAAA,EAAU;AAAA,MACzC;AAAA,QACE,UAAA,EACE;AAAA;AACJ,KACF;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT","file":"chunk-3HMEGR7U.cjs","sourcesContent":["/**\n * The backend's optional lineage capability: an opaque, whole-database\n * revision an engine can report and compare, plus the delta of one graph's\n * rows that changed since an earlier revision.\n *\n * This is a query surface over GRAPH state: neither member writes a graph\n * row, a sidecar row keyed to graph content, or a status row, and an\n * engine's own `lineage` (a backend that declares one directly) writes\n * nothing at all — a caller uses it to avoid a full-graph scan when it\n * already holds an earlier revision it trusts, and `changesSince` either\n * names exactly what changed or admits it cannot and asks the caller to\n * fall back to scanning everything. The one carve-out is the bundled\n * recorded-relations derivation's `revision()`\n * (`recordedRelationsLineage`, `store/recorded-capture/lineage.ts`): its\n * FIRST call for a graph mints that graph's durable revision-origin row\n * (`typegraph_revision_origins`) if none exists yet, deliberately off the\n * `session` argument and onto the store's own backend, because the token it\n * returns must stay comparable across a `Store.clear()` boundary — see that\n * module's own doc for why the mint cannot go through `session` and why\n * `LineageMembers`'s general \"read on the session you are given\" rule\n * (below) does not reach this one graph-identity row.\n */\nimport { ConfigurationError } from \"../../errors\";\nimport { type GraphBackend, type TransactionBackend } from \"../types\";\n\ndeclare const ENGINE_REVISION_BRAND: unique symbol;\n\n/**\n * The connection a `revision()`/`changesSince()` read runs on — the\n * narrowest existing execution-target type a root backend and a\n * `transaction()` handle both satisfy. Reused rather than invented: it is\n * the same `Pick<TransactionBackend, \"execute\" | \"executeRaw\">` shape the\n * engine assembly layer already threads as `rawSql`/`rawSqlMembers`\n * (`backend/drizzle/engine/profile.ts`, `.../operation-layer.ts`) — a\n * `GraphBackend` is assignable to it for the identical reason those two\n * members are: `TransactionBackend`'s `execute`/`executeRaw` are themselves\n * `Pick<GraphBackend, …>` projections, so the two types share the exact same\n * member signatures.\n */\nexport type LineageSession = Pick<TransactionBackend, \"execute\" | \"executeRaw\">;\n\n/**\n * An opaque token identifying the engine's current committed state of the\n * whole database — comparable only by equality, never parsed or ordered by\n * a caller. Two backends never share a comparable revision space; a\n * revision is only ever compared against another revision the SAME\n * `lineage` produced.\n */\nexport type EngineRevision = string &\n  Readonly<{ [ENGINE_REVISION_BRAND]: \"EngineRevision\" }>;\n\n/** One node or edge row, identified the way every lineage delta names a row. */\nexport type EntityKey = Readonly<{ kind: string; id: string }>;\n\n/**\n * What changed in one graph since a given revision, or an admission that\n * the source cannot answer.\n *\n * `\"keys\"` lists every node and edge inserted, updated, deleted, or\n * resurrected after the anchored revision — deduplicated, and covering a\n * hard delete the same as any other change (a row's disappearance is still\n * a change a caller must not miss). `\"unbounded\"` means the source cannot\n * bound the change set for the given revision — the anchor is unknown, or\n * older than what the source retains — and the caller must fall back to a\n * full comparison rather than guess.\n */\nexport type LineageDelta =\n  | Readonly<{\n      kind: \"keys\";\n      nodes: readonly EntityKey[];\n      edges: readonly EntityKey[];\n    }>\n  | Readonly<{ kind: \"unbounded\" }>;\n\n/**\n * The backend's lineage surface. Optional: a custom backend that omits it\n * loses only the callers that consult it directly, all of which already\n * fall back to a full scan when it is absent — see {@link requireLineage}.\n *\n * Both members take a {@link LineageSession} as their first argument: the\n * connection the CALLER'S decision is bound to, not a connection `lineage`\n * chooses for itself. A caller planning outside any transaction passes the\n * root backend it holds (`branch()`, `staging.ts`, `base-version.ts`'s\n * `lineageDeltaSinceAnchor` all do exactly this). A commit-time guard that\n * already holds an open transaction passes that transaction handle instead\n * — `graph-merge/merge.ts`'s `assertTargetUnchanged` is the concrete\n * caller this exists for: it reads `lineage` off the pinned transaction\n * handle and invokes both members WITH that same handle as the session, so\n * the read observes the transaction's own snapshot rather than whatever a\n * separately-held connection happens to see. An implementation MUST run its\n * read on the session it is given — one that opens its own connection, or\n * reads through a connection it closed over instead of the argument, is a\n * defect: it answers from a snapshot the caller never asked for, and inside\n * an open transaction it also risks colliding with whatever exclusion the\n * caller's own connection is holding (the bundled caller-serialized SQLite\n * backend's reentrancy guard refuses exactly this collision with a typed\n * `ConfigurationError` rather than hanging — see\n * `tests/graph-merge/base-version-engine-anchor.test.ts`'s\n * ignores-the-session case). A `session` is always either the backend that\n * declared this `lineage` or a `transaction()` handle it built, so an\n * implementation can freely call `session.execute`/`session.executeRaw`\n * without opening anything of its own. The one documented exception is the\n * origin half of the bundled recorded-relations `revision()` (see the file\n * doc above): a graph-identity row that must be ensured and minted off\n * `session` regardless of which one is passed, not a fact this transaction's\n * snapshot could answer differently anyway.\n */\nexport type LineageMembers = Readonly<{\n  /** The engine's current committed revision of the whole database, read on `session`. */\n  revision: (this: void, session: LineageSession) => Promise<EngineRevision>;\n  /**\n   * What changed in `graphId` after `revision`, read on `session`, or\n   * `{ kind: \"unbounded\" }` when the source cannot answer for that revision.\n   */\n  changesSince: (\n    this: void,\n    session: LineageSession,\n    revision: EngineRevision,\n    graphId: string,\n  ) => Promise<LineageDelta>;\n}>;\n\n/**\n * THE refusal for a caller that needs the backend's lineage capability and\n * finds it absent, naming the missing member so a caller can add it — or\n * fall back to the full comparison every lineage-aware caller already\n * knows how to run — instead of chasing a `TypeError` deep into a diff.\n */\nexport function requireLineage(\n  backend: Pick<GraphBackend, \"lineage\">,\n  operation: string,\n): LineageMembers {\n  const lineage = backend.lineage;\n  if (lineage === undefined) {\n    throw new ConfigurationError(\n      `${operation} requires the backend's lineage capability, but this backend declares no \\`lineage\\`.`,\n      { code: \"LINEAGE_UNAVAILABLE\", operation },\n      {\n        suggestion:\n          \"Implement `lineage` on this backend, or accept the full comparison this caller falls back to without it.\",\n      },\n    );\n  }\n  return lineage;\n}\n"]}