@nicia-ai/typegraph 0.31.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/backend/postgres/index.cjs +16 -16
  2. package/dist/backend/postgres/index.d.cts +5 -5
  3. package/dist/backend/postgres/index.d.ts +5 -5
  4. package/dist/backend/postgres/index.js +6 -6
  5. package/dist/backend/postgres/pglite.cjs +9 -9
  6. package/dist/backend/postgres/pglite.d.cts +2 -2
  7. package/dist/backend/postgres/pglite.d.ts +2 -2
  8. package/dist/backend/postgres/pglite.js +6 -6
  9. package/dist/backend/sqlite/index.cjs +14 -14
  10. package/dist/backend/sqlite/index.d.cts +6 -6
  11. package/dist/backend/sqlite/index.d.ts +6 -6
  12. package/dist/backend/sqlite/index.js +5 -5
  13. package/dist/backend/sqlite/libsql.cjs +10 -10
  14. package/dist/backend/sqlite/libsql.d.cts +2 -2
  15. package/dist/backend/sqlite/libsql.d.ts +2 -2
  16. package/dist/backend/sqlite/libsql.js +6 -6
  17. package/dist/backend/sqlite/local.cjs +10 -10
  18. package/dist/backend/sqlite/local.d.cts +2 -2
  19. package/dist/backend/sqlite/local.d.ts +2 -2
  20. package/dist/backend/sqlite/local.js +6 -6
  21. package/dist/{chunk-XKJQQQVR.js → chunk-2BVHPOIG.js} +3 -3
  22. package/dist/{chunk-XKJQQQVR.js.map → chunk-2BVHPOIG.js.map} +1 -1
  23. package/dist/{chunk-RZ4DH4E7.cjs → chunk-2LAT5BIK.cjs} +662 -217
  24. package/dist/chunk-2LAT5BIK.cjs.map +1 -0
  25. package/dist/{chunk-CIINW6PS.cjs → chunk-3HQDMOBK.cjs} +64 -64
  26. package/dist/{chunk-CIINW6PS.cjs.map → chunk-3HQDMOBK.cjs.map} +1 -1
  27. package/dist/{chunk-6SA7UIQJ.cjs → chunk-3QRBXYT5.cjs} +6 -6
  28. package/dist/{chunk-6SA7UIQJ.cjs.map → chunk-3QRBXYT5.cjs.map} +1 -1
  29. package/dist/{chunk-4A4GUZTQ.js → chunk-7WW3WL6E.js} +5 -5
  30. package/dist/{chunk-4A4GUZTQ.js.map → chunk-7WW3WL6E.js.map} +1 -1
  31. package/dist/{chunk-2HZGWCB4.js → chunk-C4C4Q7A6.js} +3 -3
  32. package/dist/chunk-C4C4Q7A6.js.map +1 -0
  33. package/dist/{chunk-SFFJ2IKN.cjs → chunk-CAMMC3E4.cjs} +58 -58
  34. package/dist/{chunk-SFFJ2IKN.cjs.map → chunk-CAMMC3E4.cjs.map} +1 -1
  35. package/dist/{chunk-O4VUR6SI.js → chunk-CEF2QOTO.js} +3 -3
  36. package/dist/{chunk-O4VUR6SI.js.map → chunk-CEF2QOTO.js.map} +1 -1
  37. package/dist/{chunk-V4IQYOQ4.cjs → chunk-CFNT3ITG.cjs} +3 -3
  38. package/dist/chunk-CFNT3ITG.cjs.map +1 -0
  39. package/dist/{chunk-LJLMDDCW.js → chunk-CWFPJ3RC.js} +3 -3
  40. package/dist/{chunk-LJLMDDCW.js.map → chunk-CWFPJ3RC.js.map} +1 -1
  41. package/dist/{chunk-7JGLPAFV.cjs → chunk-EEYV6UOE.cjs} +16 -16
  42. package/dist/chunk-EEYV6UOE.cjs.map +1 -0
  43. package/dist/{chunk-ASYQDPPU.cjs → chunk-FDN43KXV.cjs} +19 -19
  44. package/dist/{chunk-ASYQDPPU.cjs.map → chunk-FDN43KXV.cjs.map} +1 -1
  45. package/dist/{chunk-THX25XW6.js → chunk-HFBRAOF7.js} +27 -7
  46. package/dist/chunk-HFBRAOF7.js.map +1 -0
  47. package/dist/{chunk-54JVNOAQ.cjs → chunk-JKRKIEVA.cjs} +5 -5
  48. package/dist/{chunk-54JVNOAQ.cjs.map → chunk-JKRKIEVA.cjs.map} +1 -1
  49. package/dist/{chunk-5DTPBFX5.cjs → chunk-LAZGHOZW.cjs} +10 -10
  50. package/dist/{chunk-5DTPBFX5.cjs.map → chunk-LAZGHOZW.cjs.map} +1 -1
  51. package/dist/{chunk-N2MBPTAF.cjs → chunk-LM2IC4ZJ.cjs} +14 -14
  52. package/dist/{chunk-N2MBPTAF.cjs.map → chunk-LM2IC4ZJ.cjs.map} +1 -1
  53. package/dist/{chunk-STP7QVUB.js → chunk-NDM5PXEH.js} +5 -5
  54. package/dist/{chunk-STP7QVUB.js.map → chunk-NDM5PXEH.js.map} +1 -1
  55. package/dist/{chunk-2ZY4K43M.js → chunk-PIHXFF73.js} +3 -3
  56. package/dist/{chunk-2ZY4K43M.js.map → chunk-PIHXFF73.js.map} +1 -1
  57. package/dist/{chunk-ATTXBMAX.js → chunk-PRMKPFN5.js} +3 -3
  58. package/dist/{chunk-ATTXBMAX.js.map → chunk-PRMKPFN5.js.map} +1 -1
  59. package/dist/{chunk-3JBJEYWE.cjs → chunk-SB65GJNY.cjs} +32 -12
  60. package/dist/chunk-SB65GJNY.cjs.map +1 -0
  61. package/dist/{chunk-VZX2KSY3.js → chunk-TUA3MEJJ.js} +5 -5
  62. package/dist/{chunk-VZX2KSY3.js.map → chunk-TUA3MEJJ.js.map} +1 -1
  63. package/dist/{chunk-MAQJYNJR.js → chunk-W4ZX2GCP.js} +14 -16
  64. package/dist/chunk-W4ZX2GCP.js.map +1 -0
  65. package/dist/{chunk-UIFEEPME.js → chunk-WNORITK6.js} +593 -149
  66. package/dist/chunk-WNORITK6.js.map +1 -0
  67. package/dist/{chunk-VMEWZU2N.cjs → chunk-WWVV44DY.cjs} +11 -11
  68. package/dist/{chunk-VMEWZU2N.cjs.map → chunk-WWVV44DY.cjs.map} +1 -1
  69. package/dist/{chunk-UJ4V3YUQ.js → chunk-XKNAK27R.js} +3 -3
  70. package/dist/{chunk-UJ4V3YUQ.js.map → chunk-XKNAK27R.js.map} +1 -1
  71. package/dist/{chunk-GKFWM3DS.js → chunk-XQFAJVYW.js} +3 -3
  72. package/dist/{chunk-GKFWM3DS.js.map → chunk-XQFAJVYW.js.map} +1 -1
  73. package/dist/{chunk-FLOI7QOT.cjs → chunk-YL4F3CMD.cjs} +59 -59
  74. package/dist/{chunk-FLOI7QOT.cjs.map → chunk-YL4F3CMD.cjs.map} +1 -1
  75. package/dist/{chunk-5CN7B4CZ.cjs → chunk-YW7GHMF4.cjs} +17 -17
  76. package/dist/{chunk-5CN7B4CZ.cjs.map → chunk-YW7GHMF4.cjs.map} +1 -1
  77. package/dist/{ddl-BJcPrB4L.d.ts → ddl-C8e8zDAE.d.ts} +3 -3
  78. package/dist/{ddl-CPZ7mB7X.d.cts → ddl-CwyG4HoQ.d.cts} +3 -3
  79. package/dist/graph-merge/index.cjs +193 -49
  80. package/dist/graph-merge/index.cjs.map +1 -1
  81. package/dist/graph-merge/index.d.cts +3 -3
  82. package/dist/graph-merge/index.d.ts +3 -3
  83. package/dist/graph-merge/index.js +180 -36
  84. package/dist/graph-merge/index.js.map +1 -1
  85. package/dist/index.cjs +89 -85
  86. package/dist/index.d.cts +7 -7
  87. package/dist/index.d.ts +7 -7
  88. package/dist/index.js +12 -12
  89. package/dist/indexes/index.cjs +10 -10
  90. package/dist/indexes/index.d.cts +4 -4
  91. package/dist/indexes/index.d.ts +4 -4
  92. package/dist/indexes/index.js +3 -3
  93. package/dist/interchange/index.cjs +15 -15
  94. package/dist/interchange/index.d.cts +7 -7
  95. package/dist/interchange/index.d.ts +7 -7
  96. package/dist/interchange/index.js +2 -2
  97. package/dist/{manager-By-WEd8M.d.ts → manager-8htmuGr-.d.ts} +1 -1
  98. package/dist/{manager-Np7VVSlE.d.cts → manager-aVgxbGt-.d.cts} +1 -1
  99. package/dist/{postgres-BdIb7tS_.d.ts → postgres-Dhom7iiX.d.ts} +1 -1
  100. package/dist/{postgres-4J2tmauh.d.cts → postgres-jgXmD45C.d.cts} +1 -1
  101. package/dist/profiler/index.d.cts +5 -5
  102. package/dist/profiler/index.d.ts +5 -5
  103. package/dist/schema/index.cjs +26 -26
  104. package/dist/schema/index.d.cts +4 -4
  105. package/dist/schema/index.d.ts +4 -4
  106. package/dist/schema/index.js +3 -3
  107. package/dist/{sqlite-aM_PAz-O.d.ts → sqlite-BfLsCEqO.d.ts} +1 -1
  108. package/dist/{sqlite-Gatk_iw_.d.cts → sqlite-DcQ_BCUW.d.cts} +1 -1
  109. package/dist/{store-DuCbdqsh.d.cts → store-view-lTcb_cnp.d.cts} +639 -311
  110. package/dist/{store-MloRPwb9.d.ts → store-view-pBOUrQte.d.ts} +639 -311
  111. package/dist/{types-DoByHGyU.d.cts → types-5RQwzWXx.d.cts} +1 -1
  112. package/dist/{types-K3vpaJAL.d.ts → types-DGDiXAYc.d.ts} +1 -1
  113. package/dist/{types-BKQljXom.d.ts → types-Dk8r09KY.d.ts} +1 -1
  114. package/dist/{types-C1CYxWrL.d.cts → types-Dvmn-eal.d.cts} +1 -1
  115. package/dist/{where-Dt49bvo6.d.ts → where-CHZFELX0.d.ts} +1 -1
  116. package/dist/{where-DydZjGOb.d.cts → where-Cx_glEEB.d.cts} +1 -1
  117. package/package.json +2 -2
  118. package/dist/chunk-2HZGWCB4.js.map +0 -1
  119. package/dist/chunk-3JBJEYWE.cjs.map +0 -1
  120. package/dist/chunk-7JGLPAFV.cjs.map +0 -1
  121. package/dist/chunk-MAQJYNJR.js.map +0 -1
  122. package/dist/chunk-RZ4DH4E7.cjs.map +0 -1
  123. package/dist/chunk-THX25XW6.js.map +0 -1
  124. package/dist/chunk-UIFEEPME.js.map +0 -1
  125. package/dist/chunk-V4IQYOQ4.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/backend/drizzle/columns/vector.ts","../src/query/dialect/vector/pgvector-strategy.ts"],"names":["customType","assertFiniteEmbedding","sql","vectorPhysicalName","quoteIdentifier","VECTOR_CONTRIBUTION_PREFIX","quotedTableName","vectorScoreExpression","vectorMinScoreCondition"],"mappings":"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","file":"chunk-5CN7B4CZ.cjs","sourcesContent":["/**\n * Custom Drizzle column type for pgvector's VECTOR type.\n *\n * Provides native support for PostgreSQL vector embeddings without\n * requiring runtime casts in queries.\n *\n * @example\n * ```typescript\n * import { pgTable, text, integer } from \"drizzle-orm/pg-core\";\n * import { vector } from \"./columns/vector\";\n *\n * const embeddings = pgTable(\"embeddings\", {\n * id: text(\"id\").primaryKey(),\n * embedding: vector(\"embedding\"),\n * dimensions: integer(\"dimensions\"),\n * });\n * ```\n */\nimport { customType } from \"drizzle-orm/pg-core\";\n\n/**\n * PostgreSQL vector column type for pgvector extension.\n *\n * Stores embeddings as native VECTOR type, enabling efficient\n * similarity search without runtime casts.\n *\n * The column type is unparameterized (`VECTOR` not `VECTOR(N)`)\n * to support multiple embedding dimensions in a single table.\n * Dimension validation is handled at the application level.\n *\n * @example\n * ```typescript\n * // In table definition\n * embedding: vector(\"embedding\").notNull(),\n *\n * // In queries - no cast needed\n * db.execute(sql`\n * SELECT * FROM embeddings\n * WHERE embedding <=> ${formatVector([0.1, 0.2, 0.3])} < 0.5\n * `);\n * ```\n */\nexport const vector = customType<{\n data: number[];\n driverData: string;\n config: { dimensions?: number };\n}>({\n dataType(config) {\n // Use parameterized type if dimensions specified, otherwise unparameterized\n return config?.dimensions ? `vector(${config.dimensions})` : \"vector\";\n },\n\n toDriver(value: number[]): string {\n // Format as pgvector literal: [1.0,2.0,3.0]\n return `[${value.join(\",\")}]`;\n },\n\n fromDriver(value: string): number[] {\n // pgvector returns '[1,2,3]' format\n // Handle both string and already-parsed array (some drivers differ)\n if (Array.isArray(value)) {\n return value as number[];\n }\n // Parse the string representation\n const content = value.slice(1, -1); // Remove [ and ]\n if (content === \"\") {\n return [];\n }\n return content.split(\",\").map((s) => Number.parseFloat(s.trim()));\n },\n});\n\n/**\n * Formats a number array as a pgvector literal string.\n *\n * Use this when building raw SQL queries with embeddings.\n *\n * @example\n * ```typescript\n * const embedding = [0.1, 0.2, 0.3];\n * db.execute(sql`\n * SELECT * FROM embeddings\n * WHERE embedding <=> ${formatVector(embedding)}::vector < 0.5\n * `);\n * ```\n */\nexport function formatVector(embedding: readonly number[]): string {\n return `[${embedding.join(\",\")}]`;\n}\n","/**\n * pgvector strategy.\n *\n * Postgres' pgvector extension is the one engine where the *same* SQL serves\n * brute-force and ANN: `ORDER BY embedding <=> q LIMIT k` scans sequentially\n * with no index and is rewritten to an HNSW/IVFFlat scan the moment a matching\n * index exists — the planner picks it up automatically. So `buildSearch` never\n * branches on `slot.indexType`; it emits one relevance scan and lets Postgres\n * decide. (Contrast libSQL/sqlite-vec, whose ANN needs distinct syntax.)\n *\n * Storage is per-`(nodeKind, fieldPath)`: a `vector(N)` column carrying the\n * field's fixed dimension `N`, with the operator-class-typed ANN index folded\n * into the same table contribution so materialization builds table + index\n * together. The typed column means the index does not need the legacy\n * `::vector(N)` cast-in-index escape hatch the old shared table relied on.\n *\n * Metric support is the full pgvector set — `cosine`, `l2`, `inner_product` —\n * advertised as data on `capabilities`, mirroring `vector_cosine_ops` /\n * `vector_l2_ops` / `vector_ip_ops` and the `<=>` / `<->` / `<#>` operators.\n *\n * Mirrors the `libsqlVectorStrategy` / `sqliteVecStrategy` structure while\n * letting Postgres' planner pick the ANN index when one exists.\n */\nimport { type SQL, sql } from \"drizzle-orm\";\n\nimport { formatVector } from \"../../../backend/drizzle/columns/vector\";\nimport { quotedTableName } from \"../../../backend/drizzle/operations/shared\";\nimport { type StrategyTableContribution } from \"../../../backend/table-contribution\";\nimport {\n type DeleteEmbeddingParams,\n type UpsertEmbeddingParams,\n type VectorCapabilities,\n type VectorMetric,\n type VectorSearchParams,\n} from \"../../../backend/types\";\nimport {\n assertFiniteEmbedding,\n quoteIdentifier,\n VECTOR_CONTRIBUTION_PREFIX,\n vectorMinScoreCondition,\n vectorPhysicalName,\n vectorScoreExpression,\n type VectorSlot,\n type VectorStrategy,\n} from \"../vector-strategy\";\n\n/** Physical-name prefixes for the per-field table and its ANN index. */\nconst TABLE_PREFIX = \"tg_vec\";\nconst INDEX_PREFIX = \"tg_vecidx\";\n\n/**\n * pgvector defines `hnsw.ef_search` as an integer GUC with a valid range\n * of 1..1000; `SET hnsw.ef_search = 1001` errors at the server. The\n * backend validates a per-search `efSearch` against this ceiling before\n * inlining it into `SET LOCAL`, surfacing a clear message instead of a raw\n * pgvector error.\n */\nexport const MAX_HNSW_EF_SEARCH = 1000;\n\n/**\n * Validates a per-search `efSearch` override against pgvector's\n * `hnsw.ef_search` valid range. `undefined` (no override) is accepted.\n */\nexport function assertPgvectorEfSearch(efSearch?: number): void {\n if (efSearch === undefined) return;\n if (!Number.isInteger(efSearch) || efSearch <= 0) {\n throw new Error(`efSearch must be a positive integer, got: ${efSearch}`);\n }\n if (efSearch > MAX_HNSW_EF_SEARCH) {\n throw new RangeError(\n `efSearch must be ≤ ${MAX_HNSW_EF_SEARCH} (pgvector's hnsw.ef_search ` +\n `valid range is 1..${MAX_HNSW_EF_SEARCH}), got: ${efSearch}`,\n );\n }\n}\n\n/**\n * pgvector's `vector` type caps at 16,000 dimensions for a stored column\n * (2,000 for an indexed column, but the column-type ceiling is what governs\n * storage; recall degradation beyond 2,000 is a tuning concern, not a hard\n * limit advertised here).\n */\nconst PGVECTOR_MAX_DIMENSIONS = 16_000;\n\n/** Default HNSW `m` (max connections per layer) — pgvector's own default. */\nconst DEFAULT_HNSW_M = 16;\n/** Default HNSW `ef_construction` (build candidate list) — pgvector's own default. */\nconst DEFAULT_HNSW_EF_CONSTRUCTION = 64;\n/** Default IVFFlat `lists` (inverted lists) — pgvector's own default. */\nconst DEFAULT_IVFFLAT_LISTS = 100;\n\nconst PGVECTOR_CAPABILITIES: VectorCapabilities = {\n supported: true,\n metrics: [\"cosine\", \"l2\", \"inner_product\"],\n indexTypes: [\"hnsw\", \"ivfflat\", \"none\"],\n maxDimensions: PGVECTOR_MAX_DIMENSIONS,\n};\n\n/** Whether a slot's declared index type materializes a real pgvector ANN index. */\nfunction usesAnnIndex(slot: VectorSlot): boolean {\n return slot.indexType === \"hnsw\" || slot.indexType === \"ivfflat\";\n}\n\n/**\n * pgvector operator class for a metric's ANN index — `vector_cosine_ops` /\n * `vector_l2_ops` / `vector_ip_ops`, mirroring the `<=>` / `<->` / `<#>`\n * distance operators this strategy emits.\n */\nfunction operatorClass(metric: VectorMetric): string {\n switch (metric) {\n case \"cosine\": {\n return \"vector_cosine_ops\";\n }\n case \"l2\": {\n return \"vector_l2_ops\";\n }\n case \"inner_product\": {\n return \"vector_ip_ops\";\n }\n default: {\n const _exhaustive: never = metric;\n throw new Error(`Unsupported vector metric: ${String(_exhaustive)}`);\n }\n }\n}\n\n/**\n * Formats an embedding as a `::vector` literal. The value is bound as a\n * parameter (not interpolated) — Postgres parses the `[a,b,c]` text and the\n * cast types it. Finiteness is validated first so a NaN names its index.\n */\nfunction vectorLiteral(embedding: readonly number[], name: string): SQL {\n assertFiniteEmbedding(embedding, name);\n return sql`${formatVector(embedding)}::vector`;\n}\n\nfunction distanceExpression(\n embeddingColumn: SQL,\n queryEmbedding: readonly number[],\n metric: VectorMetric,\n): SQL {\n const query = vectorLiteral(queryEmbedding, \"queryEmbedding\");\n switch (metric) {\n case \"cosine\": {\n return sql`(${embeddingColumn} <=> ${query})`;\n }\n case \"l2\": {\n return sql`(${embeddingColumn} <-> ${query})`;\n }\n case \"inner_product\": {\n return sql`(${embeddingColumn} <#> ${query})`;\n }\n default: {\n const _exhaustive: never = metric;\n throw new Error(`Unsupported vector metric: ${String(_exhaustive)}`);\n }\n }\n}\n\nexport const pgvectorStrategy: VectorStrategy = {\n name: \"pgvector\",\n capabilities: PGVECTOR_CAPABILITIES,\n\n tableName(graphId, nodeKind, fieldPath) {\n return vectorPhysicalName(TABLE_PREFIX, graphId, nodeKind, fieldPath);\n },\n\n ownedTables(slot): readonly StrategyTableContribution[] {\n const table = this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath);\n const name = quoteIdentifier(table);\n\n // No standalone graph_id index: the PRIMARY KEY (graph_id, node_id) already\n // covers `WHERE graph_id = ?` via its leading column, so a separate index\n // would be pure write amplification.\n const createDdl = [\n `CREATE TABLE IF NOT EXISTS ${name} (\n \"graph_id\" TEXT NOT NULL,\n \"node_id\" TEXT NOT NULL,\n \"embedding\" vector(${slot.dimensions}) NOT NULL,\n \"created_at\" TIMESTAMPTZ NOT NULL,\n \"updated_at\" TIMESTAMPTZ NOT NULL,\n PRIMARY KEY (\"graph_id\", \"node_id\")\n);`,\n ];\n\n // The HNSW/IVFFlat index is intentionally NOT created here. pgvector\n // similarity SQL is planner-driven (`ORDER BY embedding <=> q LIMIT k`\n // uses the index when present, sequential-scans when not), so the index\n // is a pure materialization concern: `buildCreateIndex` builds it through\n // `materializeIndexes()` with the field's declared `m`/`ef_construction`/\n // `lists`. Building it eagerly here would bake in default tuning (the\n // write-ensure slot has no `indexParams`) and `CREATE INDEX IF NOT EXISTS`\n // would then mask the tuned index materialization would emit.\n\n return [\n {\n logicalName: `${VECTOR_CONTRIBUTION_PREFIX}:${slot.nodeKind}.${slot.fieldPath}`,\n owner: \"pgvector\",\n tableName: table,\n createDdl,\n runtimeEnsure: true,\n },\n ];\n },\n\n buildUpsert(slot, params: UpsertEmbeddingParams, timestamp): readonly SQL[] {\n const table = quotedTableName(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n const value = vectorLiteral(params.embedding, \"embedding\");\n return [\n sql`\n INSERT INTO ${table} (\"graph_id\", \"node_id\", \"embedding\", \"created_at\", \"updated_at\")\n VALUES (${params.graphId}, ${params.nodeId}, ${value}, ${timestamp}, ${timestamp})\n ON CONFLICT (\"graph_id\", \"node_id\")\n DO UPDATE SET \"embedding\" = EXCLUDED.\"embedding\", \"updated_at\" = EXCLUDED.\"updated_at\"\n `,\n ];\n },\n\n buildDelete(slot, params: DeleteEmbeddingParams): readonly SQL[] {\n const table = quotedTableName(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n return [\n sql`\n DELETE FROM ${table}\n WHERE \"graph_id\" = ${params.graphId} AND \"node_id\" = ${params.nodeId}\n `,\n ];\n },\n\n buildSearch(slot, params: VectorSearchParams): SQL {\n const table = quotedTableName(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n const embeddingColumn = sql`${table}.\"embedding\"`;\n const distance = distanceExpression(\n embeddingColumn,\n params.queryEmbedding,\n params.metric,\n );\n const score = vectorScoreExpression(distance, params.metric);\n\n // Same SQL for brute-force and ANN: with a matching HNSW/IVFFlat index the\n // Postgres planner rewrites this `ORDER BY distance LIMIT k` into an index\n // scan automatically, so the strategy never branches on `slot.indexType`.\n const conditions: SQL[] = [sql`${table}.\"graph_id\" = ${params.graphId}`];\n if (params.minScore !== undefined) {\n conditions.push(\n vectorMinScoreCondition(distance, params.metric, params.minScore),\n );\n }\n return sql`\n SELECT ${table}.\"node_id\" AS node_id, ${score} AS score\n FROM ${table}\n WHERE ${sql.join(conditions, sql` AND `)}\n ORDER BY ${distance} ASC\n LIMIT ${params.limit}\n `;\n },\n\n distanceExpression(embeddingColumn, queryEmbedding, metric) {\n return distanceExpression(embeddingColumn, queryEmbedding, metric);\n },\n\n buildCreateIndex(slot, options): SQL | undefined {\n if (!usesAnnIndex(slot)) return undefined;\n return sql.raw(\n pgvectorIndexDdl(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n slot,\n options?.concurrent === true,\n ),\n );\n },\n\n buildDropIndex(slot): SQL | undefined {\n if (!usesAnnIndex(slot)) return undefined;\n const indexName = pgvectorIndexName(slot);\n return sql.raw(`DROP INDEX IF EXISTS ${quoteIdentifier(indexName)}`);\n },\n\n buildDropStorage(slot): readonly string[] {\n const table = quoteIdentifier(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n // CASCADE drops the ANN index along with the table.\n return [`DROP TABLE IF EXISTS ${table} CASCADE`];\n },\n};\n\nfunction pgvectorIndexName(slot: VectorSlot): string {\n return vectorPhysicalName(\n INDEX_PREFIX,\n slot.graphId,\n slot.nodeKind,\n slot.fieldPath,\n );\n}\n\nfunction pgvectorIndexDdl(\n table: string,\n slot: VectorSlot,\n concurrent: boolean,\n): string {\n const indexName = quoteIdentifier(pgvectorIndexName(slot));\n const quotedTable = quoteIdentifier(table);\n const opClass = operatorClass(slot.metric);\n // Honor the field's declared tuning; fall back to pgvector defaults.\n const m = slot.indexParams?.m ?? DEFAULT_HNSW_M;\n const efConstruction =\n slot.indexParams?.efConstruction ?? DEFAULT_HNSW_EF_CONSTRUCTION;\n const lists = slot.indexParams?.lists ?? DEFAULT_IVFFLAT_LISTS;\n // CONCURRENTLY builds without taking a write-blocking lock on the live table\n // (materializeIndexes passes concurrent on Postgres). Run outside a tx.\n const create = `CREATE INDEX${concurrent ? \" CONCURRENTLY\" : \"\"} IF NOT EXISTS`;\n\n switch (slot.indexType) {\n case \"hnsw\": {\n return `${create} ${indexName} ON ${quotedTable} USING hnsw (\"embedding\" ${opClass}) WITH (m = ${m}, ef_construction = ${efConstruction});`;\n }\n case \"ivfflat\": {\n return `${create} ${indexName} ON ${quotedTable} USING ivfflat (\"embedding\" ${opClass}) WITH (lists = ${lists});`;\n }\n case \"none\": {\n throw new Error(\n \"pgvectorIndexDdl called for a brute-force-only slot (indexType 'none').\",\n );\n }\n default: {\n const _exhaustive: never = slot.indexType;\n throw new Error(`Unsupported vector index type: ${String(_exhaustive)}`);\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/backend/drizzle/columns/vector.ts","../src/query/dialect/vector/pgvector-strategy.ts"],"names":["customType","assertFiniteEmbedding","sql","vectorPhysicalName","quoteIdentifier","VECTOR_CONTRIBUTION_PREFIX","quotedTableName","vectorScoreExpression","vectorMinScoreCondition"],"mappings":"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","file":"chunk-YW7GHMF4.cjs","sourcesContent":["/**\n * Custom Drizzle column type for pgvector's VECTOR type.\n *\n * Provides native support for PostgreSQL vector embeddings without\n * requiring runtime casts in queries.\n *\n * @example\n * ```typescript\n * import { pgTable, text, integer } from \"drizzle-orm/pg-core\";\n * import { vector } from \"./columns/vector\";\n *\n * const embeddings = pgTable(\"embeddings\", {\n * id: text(\"id\").primaryKey(),\n * embedding: vector(\"embedding\"),\n * dimensions: integer(\"dimensions\"),\n * });\n * ```\n */\nimport { customType } from \"drizzle-orm/pg-core\";\n\n/**\n * PostgreSQL vector column type for pgvector extension.\n *\n * Stores embeddings as native VECTOR type, enabling efficient\n * similarity search without runtime casts.\n *\n * The column type is unparameterized (`VECTOR` not `VECTOR(N)`)\n * to support multiple embedding dimensions in a single table.\n * Dimension validation is handled at the application level.\n *\n * @example\n * ```typescript\n * // In table definition\n * embedding: vector(\"embedding\").notNull(),\n *\n * // In queries - no cast needed\n * db.execute(sql`\n * SELECT * FROM embeddings\n * WHERE embedding <=> ${formatVector([0.1, 0.2, 0.3])} < 0.5\n * `);\n * ```\n */\nexport const vector = customType<{\n data: number[];\n driverData: string;\n config: { dimensions?: number };\n}>({\n dataType(config) {\n // Use parameterized type if dimensions specified, otherwise unparameterized\n return config?.dimensions ? `vector(${config.dimensions})` : \"vector\";\n },\n\n toDriver(value: number[]): string {\n // Format as pgvector literal: [1.0,2.0,3.0]\n return `[${value.join(\",\")}]`;\n },\n\n fromDriver(value: string): number[] {\n // pgvector returns '[1,2,3]' format\n // Handle both string and already-parsed array (some drivers differ)\n if (Array.isArray(value)) {\n return value as number[];\n }\n // Parse the string representation\n const content = value.slice(1, -1); // Remove [ and ]\n if (content === \"\") {\n return [];\n }\n return content.split(\",\").map((s) => Number.parseFloat(s.trim()));\n },\n});\n\n/**\n * Formats a number array as a pgvector literal string.\n *\n * Use this when building raw SQL queries with embeddings.\n *\n * @example\n * ```typescript\n * const embedding = [0.1, 0.2, 0.3];\n * db.execute(sql`\n * SELECT * FROM embeddings\n * WHERE embedding <=> ${formatVector(embedding)}::vector < 0.5\n * `);\n * ```\n */\nexport function formatVector(embedding: readonly number[]): string {\n return `[${embedding.join(\",\")}]`;\n}\n","/**\n * pgvector strategy.\n *\n * Postgres' pgvector extension is the one engine where the *same* SQL serves\n * brute-force and ANN: `ORDER BY embedding <=> q LIMIT k` scans sequentially\n * with no index and is rewritten to an HNSW/IVFFlat scan the moment a matching\n * index exists — the planner picks it up automatically. So `buildSearch` never\n * branches on `slot.indexType`; it emits one relevance scan and lets Postgres\n * decide. (Contrast libSQL/sqlite-vec, whose ANN needs distinct syntax.)\n *\n * Storage is per-`(nodeKind, fieldPath)`: a `vector(N)` column carrying the\n * field's fixed dimension `N`, with the operator-class-typed ANN index folded\n * into the same table contribution so materialization builds table + index\n * together. The typed column means the index does not need the legacy\n * `::vector(N)` cast-in-index escape hatch the old shared table relied on.\n *\n * Metric support is the full pgvector set — `cosine`, `l2`, `inner_product` —\n * advertised as data on `capabilities`, mirroring `vector_cosine_ops` /\n * `vector_l2_ops` / `vector_ip_ops` and the `<=>` / `<->` / `<#>` operators.\n *\n * Mirrors the `libsqlVectorStrategy` / `sqliteVecStrategy` structure while\n * letting Postgres' planner pick the ANN index when one exists.\n */\nimport { type SQL, sql } from \"drizzle-orm\";\n\nimport { formatVector } from \"../../../backend/drizzle/columns/vector\";\nimport { quotedTableName } from \"../../../backend/drizzle/operations/shared\";\nimport { type StrategyTableContribution } from \"../../../backend/table-contribution\";\nimport {\n type DeleteEmbeddingParams,\n type UpsertEmbeddingParams,\n type VectorCapabilities,\n type VectorMetric,\n type VectorSearchParams,\n} from \"../../../backend/types\";\nimport {\n assertFiniteEmbedding,\n quoteIdentifier,\n VECTOR_CONTRIBUTION_PREFIX,\n vectorMinScoreCondition,\n vectorPhysicalName,\n vectorScoreExpression,\n type VectorSlot,\n type VectorStrategy,\n} from \"../vector-strategy\";\n\n/** Physical-name prefixes for the per-field table and its ANN index. */\nconst TABLE_PREFIX = \"tg_vec\";\nconst INDEX_PREFIX = \"tg_vecidx\";\n\n/**\n * pgvector defines `hnsw.ef_search` as an integer GUC with a valid range\n * of 1..1000; `SET hnsw.ef_search = 1001` errors at the server. The\n * backend validates a per-search `efSearch` against this ceiling before\n * inlining it into `SET LOCAL`, surfacing a clear message instead of a raw\n * pgvector error.\n */\nexport const MAX_HNSW_EF_SEARCH = 1000;\n\n/**\n * Validates a per-search `efSearch` override against pgvector's\n * `hnsw.ef_search` valid range. `undefined` (no override) is accepted.\n */\nexport function assertPgvectorEfSearch(efSearch?: number): void {\n if (efSearch === undefined) return;\n if (!Number.isInteger(efSearch) || efSearch <= 0) {\n throw new Error(`efSearch must be a positive integer, got: ${efSearch}`);\n }\n if (efSearch > MAX_HNSW_EF_SEARCH) {\n throw new RangeError(\n `efSearch must be ≤ ${MAX_HNSW_EF_SEARCH} (pgvector's hnsw.ef_search ` +\n `valid range is 1..${MAX_HNSW_EF_SEARCH}), got: ${efSearch}`,\n );\n }\n}\n\n/**\n * pgvector's `vector` type caps at 16,000 dimensions for a stored column\n * (2,000 for an indexed column, but the column-type ceiling is what governs\n * storage; recall degradation beyond 2,000 is a tuning concern, not a hard\n * limit advertised here).\n */\nconst PGVECTOR_MAX_DIMENSIONS = 16_000;\n\n/** Default HNSW `m` (max connections per layer) — pgvector's own default. */\nconst DEFAULT_HNSW_M = 16;\n/** Default HNSW `ef_construction` (build candidate list) — pgvector's own default. */\nconst DEFAULT_HNSW_EF_CONSTRUCTION = 64;\n/** Default IVFFlat `lists` (inverted lists) — pgvector's own default. */\nconst DEFAULT_IVFFLAT_LISTS = 100;\n\nconst PGVECTOR_CAPABILITIES: VectorCapabilities = {\n supported: true,\n metrics: [\"cosine\", \"l2\", \"inner_product\"],\n indexTypes: [\"hnsw\", \"ivfflat\", \"none\"],\n maxDimensions: PGVECTOR_MAX_DIMENSIONS,\n};\n\n/** Whether a slot's declared index type materializes a real pgvector ANN index. */\nfunction usesAnnIndex(slot: VectorSlot): boolean {\n return slot.indexType === \"hnsw\" || slot.indexType === \"ivfflat\";\n}\n\n/**\n * pgvector operator class for a metric's ANN index — `vector_cosine_ops` /\n * `vector_l2_ops` / `vector_ip_ops`, mirroring the `<=>` / `<->` / `<#>`\n * distance operators this strategy emits.\n */\nfunction operatorClass(metric: VectorMetric): string {\n switch (metric) {\n case \"cosine\": {\n return \"vector_cosine_ops\";\n }\n case \"l2\": {\n return \"vector_l2_ops\";\n }\n case \"inner_product\": {\n return \"vector_ip_ops\";\n }\n default: {\n const _exhaustive: never = metric;\n throw new Error(`Unsupported vector metric: ${String(_exhaustive)}`);\n }\n }\n}\n\n/**\n * Formats an embedding as a `::vector` literal. The value is bound as a\n * parameter (not interpolated) — Postgres parses the `[a,b,c]` text and the\n * cast types it. Finiteness is validated first so a NaN names its index.\n */\nfunction vectorLiteral(embedding: readonly number[], name: string): SQL {\n assertFiniteEmbedding(embedding, name);\n return sql`${formatVector(embedding)}::vector`;\n}\n\nfunction distanceExpression(\n embeddingColumn: SQL,\n queryEmbedding: readonly number[],\n metric: VectorMetric,\n): SQL {\n const query = vectorLiteral(queryEmbedding, \"queryEmbedding\");\n switch (metric) {\n case \"cosine\": {\n return sql`(${embeddingColumn} <=> ${query})`;\n }\n case \"l2\": {\n return sql`(${embeddingColumn} <-> ${query})`;\n }\n case \"inner_product\": {\n return sql`(${embeddingColumn} <#> ${query})`;\n }\n default: {\n const _exhaustive: never = metric;\n throw new Error(`Unsupported vector metric: ${String(_exhaustive)}`);\n }\n }\n}\n\nexport const pgvectorStrategy: VectorStrategy = {\n name: \"pgvector\",\n capabilities: PGVECTOR_CAPABILITIES,\n\n tableName(graphId, nodeKind, fieldPath) {\n return vectorPhysicalName(TABLE_PREFIX, graphId, nodeKind, fieldPath);\n },\n\n ownedTables(slot): readonly StrategyTableContribution[] {\n const table = this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath);\n const name = quoteIdentifier(table);\n\n // No standalone graph_id index: the PRIMARY KEY (graph_id, node_id) already\n // covers `WHERE graph_id = ?` via its leading column, so a separate index\n // would be pure write amplification.\n const createDdl = [\n `CREATE TABLE IF NOT EXISTS ${name} (\n \"graph_id\" TEXT NOT NULL,\n \"node_id\" TEXT NOT NULL,\n \"embedding\" vector(${slot.dimensions}) NOT NULL,\n \"created_at\" TIMESTAMPTZ NOT NULL,\n \"updated_at\" TIMESTAMPTZ NOT NULL,\n PRIMARY KEY (\"graph_id\", \"node_id\")\n);`,\n ];\n\n // The HNSW/IVFFlat index is intentionally NOT created here. pgvector\n // similarity SQL is planner-driven (`ORDER BY embedding <=> q LIMIT k`\n // uses the index when present, sequential-scans when not), so the index\n // is a pure materialization concern: `buildCreateIndex` builds it through\n // `materializeIndexes()` with the field's declared `m`/`ef_construction`/\n // `lists`. Building it eagerly here would bake in default tuning (the\n // write-ensure slot has no `indexParams`) and `CREATE INDEX IF NOT EXISTS`\n // would then mask the tuned index materialization would emit.\n\n return [\n {\n logicalName: `${VECTOR_CONTRIBUTION_PREFIX}:${slot.nodeKind}.${slot.fieldPath}`,\n owner: \"pgvector\",\n tableName: table,\n createDdl,\n runtimeEnsure: true,\n },\n ];\n },\n\n buildUpsert(slot, params: UpsertEmbeddingParams, timestamp): readonly SQL[] {\n const table = quotedTableName(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n const value = vectorLiteral(params.embedding, \"embedding\");\n return [\n sql`\n INSERT INTO ${table} (\"graph_id\", \"node_id\", \"embedding\", \"created_at\", \"updated_at\")\n VALUES (${params.graphId}, ${params.nodeId}, ${value}, ${timestamp}, ${timestamp})\n ON CONFLICT (\"graph_id\", \"node_id\")\n DO UPDATE SET \"embedding\" = EXCLUDED.\"embedding\", \"updated_at\" = EXCLUDED.\"updated_at\"\n `,\n ];\n },\n\n buildDelete(slot, params: DeleteEmbeddingParams): readonly SQL[] {\n const table = quotedTableName(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n return [\n sql`\n DELETE FROM ${table}\n WHERE \"graph_id\" = ${params.graphId} AND \"node_id\" = ${params.nodeId}\n `,\n ];\n },\n\n buildSearch(slot, params: VectorSearchParams): SQL {\n const table = quotedTableName(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n const embeddingColumn = sql`${table}.\"embedding\"`;\n const distance = distanceExpression(\n embeddingColumn,\n params.queryEmbedding,\n params.metric,\n );\n const score = vectorScoreExpression(distance, params.metric);\n\n // Same SQL for brute-force and ANN: with a matching HNSW/IVFFlat index the\n // Postgres planner rewrites this `ORDER BY distance LIMIT k` into an index\n // scan automatically, so the strategy never branches on `slot.indexType`.\n const conditions: SQL[] = [sql`${table}.\"graph_id\" = ${params.graphId}`];\n if (params.minScore !== undefined) {\n conditions.push(\n vectorMinScoreCondition(distance, params.metric, params.minScore),\n );\n }\n return sql`\n SELECT ${table}.\"node_id\" AS node_id, ${score} AS score\n FROM ${table}\n WHERE ${sql.join(conditions, sql` AND `)}\n ORDER BY ${distance} ASC\n LIMIT ${params.limit}\n `;\n },\n\n distanceExpression(embeddingColumn, queryEmbedding, metric) {\n return distanceExpression(embeddingColumn, queryEmbedding, metric);\n },\n\n buildCreateIndex(slot, options): SQL | undefined {\n if (!usesAnnIndex(slot)) return undefined;\n return sql.raw(\n pgvectorIndexDdl(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n slot,\n options?.concurrent === true,\n ),\n );\n },\n\n buildDropIndex(slot): SQL | undefined {\n if (!usesAnnIndex(slot)) return undefined;\n const indexName = pgvectorIndexName(slot);\n return sql.raw(`DROP INDEX IF EXISTS ${quoteIdentifier(indexName)}`);\n },\n\n buildDropStorage(slot): readonly string[] {\n const table = quoteIdentifier(\n this.tableName(slot.graphId, slot.nodeKind, slot.fieldPath),\n );\n // CASCADE drops the ANN index along with the table.\n return [`DROP TABLE IF EXISTS ${table} CASCADE`];\n },\n};\n\nfunction pgvectorIndexName(slot: VectorSlot): string {\n return vectorPhysicalName(\n INDEX_PREFIX,\n slot.graphId,\n slot.nodeKind,\n slot.fieldPath,\n );\n}\n\nfunction pgvectorIndexDdl(\n table: string,\n slot: VectorSlot,\n concurrent: boolean,\n): string {\n const indexName = quoteIdentifier(pgvectorIndexName(slot));\n const quotedTable = quoteIdentifier(table);\n const opClass = operatorClass(slot.metric);\n // Honor the field's declared tuning; fall back to pgvector defaults.\n const m = slot.indexParams?.m ?? DEFAULT_HNSW_M;\n const efConstruction =\n slot.indexParams?.efConstruction ?? DEFAULT_HNSW_EF_CONSTRUCTION;\n const lists = slot.indexParams?.lists ?? DEFAULT_IVFFLAT_LISTS;\n // CONCURRENTLY builds without taking a write-blocking lock on the live table\n // (materializeIndexes passes concurrent on Postgres). Run outside a tx.\n const create = `CREATE INDEX${concurrent ? \" CONCURRENTLY\" : \"\"} IF NOT EXISTS`;\n\n switch (slot.indexType) {\n case \"hnsw\": {\n return `${create} ${indexName} ON ${quotedTable} USING hnsw (\"embedding\" ${opClass}) WITH (m = ${m}, ef_construction = ${efConstruction});`;\n }\n case \"ivfflat\": {\n return `${create} ${indexName} ON ${quotedTable} USING ivfflat (\"embedding\" ${opClass}) WITH (lists = ${lists});`;\n }\n case \"none\": {\n throw new Error(\n \"pgvectorIndexDdl called for a brute-force-only slot (indexType 'none').\",\n );\n }\n default: {\n const _exhaustive: never = slot.indexType;\n throw new Error(`Unsupported vector index type: ${String(_exhaustive)}`);\n }\n }\n}\n"]}
@@ -1,6 +1,6 @@
1
- import { F as FulltextStrategy } from './types-BKQljXom.js';
2
- import { P as PostgresTables } from './postgres-BdIb7tS_.js';
3
- import { S as SqliteTables } from './sqlite-aM_PAz-O.js';
1
+ import { F as FulltextStrategy } from './types-Dk8r09KY.js';
2
+ import { P as PostgresTables } from './postgres-Dhom7iiX.js';
3
+ import { S as SqliteTables } from './sqlite-BfLsCEqO.js';
4
4
 
5
5
  /**
6
6
  * Generates all DDL statements for the given SQLite tables.
@@ -1,6 +1,6 @@
1
- import { F as FulltextStrategy } from './types-C1CYxWrL.cjs';
2
- import { P as PostgresTables } from './postgres-4J2tmauh.cjs';
3
- import { S as SqliteTables } from './sqlite-Gatk_iw_.cjs';
1
+ import { F as FulltextStrategy } from './types-Dvmn-eal.cjs';
2
+ import { P as PostgresTables } from './postgres-jgXmD45C.cjs';
3
+ import { S as SqliteTables } from './sqlite-DcQ_BCUW.cjs';
4
4
 
5
5
  /**
6
6
  * Generates all DDL statements for the given SQLite tables.
@@ -1,18 +1,18 @@
1
1
  'use strict';
2
2
 
3
- var chunkRZ4DH4E7_cjs = require('../chunk-RZ4DH4E7.cjs');
3
+ var chunk2LAT5BIK_cjs = require('../chunk-2LAT5BIK.cjs');
4
4
  require('../chunk-HTGDWIDE.cjs');
5
- var chunk3JBJEYWE_cjs = require('../chunk-3JBJEYWE.cjs');
6
- var chunk5DTPBFX5_cjs = require('../chunk-5DTPBFX5.cjs');
7
- var chunk7JGLPAFV_cjs = require('../chunk-7JGLPAFV.cjs');
8
- require('../chunk-6SA7UIQJ.cjs');
5
+ var chunkSB65GJNY_cjs = require('../chunk-SB65GJNY.cjs');
6
+ var chunkLAZGHOZW_cjs = require('../chunk-LAZGHOZW.cjs');
7
+ var chunkEEYV6UOE_cjs = require('../chunk-EEYV6UOE.cjs');
8
+ require('../chunk-3QRBXYT5.cjs');
9
9
  require('../chunk-6RMLO5O4.cjs');
10
10
  require('../chunk-YQGLVWB2.cjs');
11
11
  require('../chunk-ZFWNO3GE.cjs');
12
12
  var chunkKTIEB7VH_cjs = require('../chunk-KTIEB7VH.cjs');
13
13
  require('../chunk-6G35I3VW.cjs');
14
14
  var chunkRP7YITHX_cjs = require('../chunk-RP7YITHX.cjs');
15
- require('../chunk-V4IQYOQ4.cjs');
15
+ require('../chunk-CFNT3ITG.cjs');
16
16
  var chunk73KASJGO_cjs = require('../chunk-73KASJGO.cjs');
17
17
  var chunkJIEJCTDS_cjs = require('../chunk-JIEJCTDS.cjs');
18
18
  require('../chunk-FLRCVI2G.cjs');
@@ -228,8 +228,8 @@ function byId(left, right) {
228
228
  }
229
229
  async function diffAgainstBase(baseStore, forkStore) {
230
230
  const graph = baseStore.graph;
231
- const nodeKinds = chunk7JGLPAFV_cjs.getNodeKinds(graph);
232
- const edgeKinds = chunk7JGLPAFV_cjs.getEdgeKinds(graph);
231
+ const nodeKinds = chunkEEYV6UOE_cjs.getNodeKinds(graph);
232
+ const edgeKinds = chunkEEYV6UOE_cjs.getEdgeKinds(graph);
233
233
  const newNodes = [];
234
234
  const modifiedNodes = [];
235
235
  const deletedNodes = [];
@@ -311,19 +311,16 @@ async function readActiveSchemaVersion(backend, graphId) {
311
311
  }
312
312
  async function computeSchemaComponent(store) {
313
313
  const version = await readActiveSchemaVersion(store.backend, store.graphId);
314
- return chunk5DTPBFX5_cjs.computeSchemaHash(chunk5DTPBFX5_cjs.serializeSchema(store.graph, version));
314
+ return chunkLAZGHOZW_cjs.computeSchemaHash(chunkLAZGHOZW_cjs.serializeSchema(store.graph, version));
315
315
  }
316
316
  function byDigestEntry(left, right) {
317
317
  const byKind = compareStrings(left.kind, right.kind);
318
318
  return byKind === 0 ? compareStrings(left.id, right.id) : byKind;
319
319
  }
320
320
  var CONTENT_FINGERPRINT_BYTES = 16;
321
- async function computeContentFingerprint(store) {
322
- const backend = store.backend;
323
- const graphId = store.graphId;
324
- const graph = store.graph;
325
- const nodeKinds = chunk7JGLPAFV_cjs.getNodeKinds(graph);
326
- const edgeKinds = chunk7JGLPAFV_cjs.getEdgeKinds(graph);
321
+ async function computeContentComponent(backend, graphId, graph) {
322
+ const nodeKinds = chunkEEYV6UOE_cjs.getNodeKinds(graph);
323
+ const edgeKinds = chunkEEYV6UOE_cjs.getEdgeKinds(graph);
327
324
  const nodeDigest = [];
328
325
  for (const kind of nodeKinds) {
329
326
  const rows = await enumerateAllNodes(backend, graphId, kind);
@@ -369,12 +366,16 @@ async function computeContentFingerprint(store) {
369
366
  async function computeBaseVersion(store) {
370
367
  const [schemaComponent, contentComponent] = await Promise.all([
371
368
  computeSchemaComponent(store),
372
- computeContentFingerprint(store)
369
+ computeContentComponent(store.backend, store.graphId, store.graph)
373
370
  ]);
374
371
  return asBaseVersion(
375
372
  `${schemaComponent}${TOKEN_SEPARATOR}${contentComponent}`
376
373
  );
377
374
  }
375
+ function contentComponentOf(version) {
376
+ const separatorIndex = version.indexOf(TOKEN_SEPARATOR);
377
+ return separatorIndex === -1 ? version : version.slice(separatorIndex + 1);
378
+ }
378
379
 
379
380
  // src/graph-merge/errors.ts
380
381
  var MERGE_ERROR_CODES = {
@@ -445,17 +446,17 @@ var CLONE_IMPORT_BATCH_SIZE = 1e3;
445
446
  function cloneWorkingCopyStrategy(makeBackend) {
446
447
  return {
447
448
  create: async (baseStore) => {
448
- const data = await chunk3JBJEYWE_cjs.exportGraph(baseStore, {
449
+ const data = await chunkSB65GJNY_cjs.exportGraph(baseStore, {
449
450
  includeMeta: true,
450
451
  includeDeleted: false
451
452
  });
452
453
  const backend = await makeBackend();
453
454
  try {
454
- const [freshStore] = await chunkRZ4DH4E7_cjs.createStoreWithSchema(
455
+ const [freshStore] = await chunk2LAT5BIK_cjs.createStoreWithSchema(
455
456
  baseStore.graph,
456
457
  backend
457
458
  );
458
- const result = await chunk3JBJEYWE_cjs.importGraph(freshStore, data, {
459
+ const result = await chunkSB65GJNY_cjs.importGraph(freshStore, data, {
459
460
  onConflict: "error",
460
461
  onUnknownProperty: "error",
461
462
  validateReferences: true,
@@ -483,7 +484,7 @@ function cloneWorkingCopyStrategy(makeBackend) {
483
484
  async function branch(baseStore, makeBackend, options, strategy) {
484
485
  try {
485
486
  const base = await computeBaseVersion(baseStore);
486
- const id = options?.id ?? asBranchId(chunkRZ4DH4E7_cjs.generateId());
487
+ const id = options?.id ?? asBranchId(chunk2LAT5BIK_cjs.generateId());
487
488
  const workingCopyStrategy = strategy ?? cloneWorkingCopyStrategy(makeBackend);
488
489
  const store = await workingCopyStrategy.create(baseStore);
489
490
  return chunkKTIEB7VH_cjs.ok({ id, base, store });
@@ -512,7 +513,7 @@ function constraintSignature(node, constraint) {
512
513
  return void 0;
513
514
  }
514
515
  }
515
- return `${constraint.name}${KEY_PART_SEPARATOR}${chunkRZ4DH4E7_cjs.computeUniqueKey(
516
+ return `${constraint.name}${KEY_PART_SEPARATOR}${chunk2LAT5BIK_cjs.computeUniqueKey(
516
517
  props,
517
518
  constraint.fields,
518
519
  constraint.collation
@@ -2055,7 +2056,7 @@ function normalizeMergeOptions(options = {}) {
2055
2056
  ...provenanceWeights === void 0 ? {} : { provenanceWeights }
2056
2057
  };
2057
2058
  }
2058
- var Provenance = chunk5DTPBFX5_cjs.defineNode("Provenance", {
2059
+ var Provenance = chunkLAZGHOZW_cjs.defineNode("Provenance", {
2059
2060
  schema: zod.z.object({
2060
2061
  targetGraphId: zod.z.string(),
2061
2062
  role: zod.z.enum(["node", "edge"]),
@@ -2069,14 +2070,14 @@ function provenanceGraphId(targetGraphId) {
2069
2070
  return `${targetGraphId}::merge-provenance`;
2070
2071
  }
2071
2072
  function buildProvenanceGraph(targetGraphId) {
2072
- return chunk7JGLPAFV_cjs.defineGraph({
2073
+ return chunkEEYV6UOE_cjs.defineGraph({
2073
2074
  id: provenanceGraphId(targetGraphId),
2074
2075
  nodes: { Provenance: { type: Provenance } },
2075
2076
  edges: {}
2076
2077
  });
2077
2078
  }
2078
2079
  async function openProvenanceStore(backend, targetGraphId) {
2079
- const [store] = await chunkRZ4DH4E7_cjs.createStoreWithSchema(
2080
+ const [store] = await chunk2LAT5BIK_cjs.createStoreWithSchema(
2080
2081
  buildProvenanceGraph(targetGraphId),
2081
2082
  backend
2082
2083
  );
@@ -2507,6 +2508,48 @@ async function stageBranches(baseStore, branches) {
2507
2508
  };
2508
2509
  }
2509
2510
 
2511
+ // src/graph-merge/tx-retry.ts
2512
+ var RETRYABLE_SQLSTATES = /* @__PURE__ */ new Set(["40001", "40P01"]);
2513
+ var RETRYABLE_MESSAGE_PATTERN = /could not serialize access|deadlock detected/i;
2514
+ var MAX_COMMIT_ATTEMPTS = 3;
2515
+ function isRetryableTxConflict(error) {
2516
+ const seen = /* @__PURE__ */ new Set();
2517
+ let current = error;
2518
+ while (current !== void 0 && current !== null && typeof current === "object" && !seen.has(current)) {
2519
+ seen.add(current);
2520
+ const candidate = current;
2521
+ if (typeof candidate.code === "string" && RETRYABLE_SQLSTATES.has(candidate.code)) {
2522
+ return true;
2523
+ }
2524
+ if (typeof candidate.message === "string" && RETRYABLE_MESSAGE_PATTERN.test(candidate.message)) {
2525
+ return true;
2526
+ }
2527
+ current = candidate.cause;
2528
+ }
2529
+ return false;
2530
+ }
2531
+ async function withTxConflictRetry(commit) {
2532
+ let lastConflict;
2533
+ for (let attempt = 1; attempt <= MAX_COMMIT_ATTEMPTS; attempt += 1) {
2534
+ try {
2535
+ return await commit();
2536
+ } catch (error) {
2537
+ if (!isRetryableTxConflict(error)) {
2538
+ throw error;
2539
+ }
2540
+ lastConflict = error;
2541
+ }
2542
+ }
2543
+ throw new MergeError(
2544
+ `Merge commit aborted by transaction conflicts (serialization failure or deadlock) on ${MAX_COMMIT_ATTEMPTS} consecutive attempts; giving up.`,
2545
+ {
2546
+ cause: lastConflict,
2547
+ details: { attempts: MAX_COMMIT_ATTEMPTS },
2548
+ suggestion: "Reduce concurrent writes to the merge target, or serialize merges against it."
2549
+ }
2550
+ );
2551
+ }
2552
+
2510
2553
  // src/graph-merge/type-reconcile.ts
2511
2554
  var INCOMPATIBLE_TYPES_FLAG_REASON = "type-reconcile:incompatible-kinds";
2512
2555
  function distinctKinds(kinds) {
@@ -3226,20 +3269,48 @@ async function applyMergePlan(plan, nodesApi, edgesApi) {
3226
3269
  }
3227
3270
  return { nodes: committedNodeIds.size, edges: committedEdges };
3228
3271
  }
3229
- async function commitPlan(target, plan) {
3272
+ async function commitPlan(target, plan, expectedBaseVersion) {
3230
3273
  if (!target.backend.capabilities.transactions) {
3231
3274
  throw new MergeError(
3232
3275
  "merge() requires a transaction-capable target backend. The merged plan (canonical upserts, soft-deletes, edge upserts) must commit atomically; a non-transactional fallback would leave a partially-merged graph on a mid-commit failure. (mergeIncremental() enforces the same requirement.)",
3233
3276
  { details: { capability: "transactions" } }
3234
3277
  );
3235
3278
  }
3236
- return target.transaction(
3237
- (tx) => applyMergePlan(
3238
- plan,
3239
- tx.nodes,
3240
- tx.edges
3241
- )
3279
+ return withTxConflictRetry(
3280
+ () => target.transaction(async (tx) => {
3281
+ if (expectedBaseVersion !== void 0) {
3282
+ await assertTargetUnchanged(tx.backend, target, expectedBaseVersion);
3283
+ }
3284
+ return applyMergePlan(
3285
+ plan,
3286
+ tx.nodes,
3287
+ tx.edges
3288
+ );
3289
+ }, MERGE_COMMIT_TX_OPTIONS)
3290
+ );
3291
+ }
3292
+ var MERGE_COMMIT_TX_OPTIONS = {
3293
+ isolationLevel: "serializable"
3294
+ };
3295
+ async function assertTargetUnchanged(txBackend, target, expectedBaseVersion) {
3296
+ const liveContent = await computeContentComponent(
3297
+ txBackend,
3298
+ target.graphId,
3299
+ target.graph
3242
3300
  );
3301
+ const expectedContent = contentComponentOf(expectedBaseVersion);
3302
+ if (liveContent !== expectedContent) {
3303
+ throw new BaseVersionMismatchError(
3304
+ "The merge target was modified between the base@V check and the commit transaction; the resolved plan no longer describes the live target and was not applied.",
3305
+ {
3306
+ details: {
3307
+ expectedContentFingerprint: expectedContent,
3308
+ liveContentFingerprint: liveContent
3309
+ },
3310
+ suggestion: "Re-run the merge (and re-branch if the divergence is real), or serialize writers against merges on this target."
3311
+ }
3312
+ );
3313
+ }
3243
3314
  }
3244
3315
  function nodeCollection(nodes, kind) {
3245
3316
  const collection = nodes[kind];
@@ -3277,7 +3348,7 @@ async function validateBaseVersions(target, branches) {
3277
3348
  );
3278
3349
  }
3279
3350
  }
3280
- return chunkKTIEB7VH_cjs.ok();
3351
+ return chunkKTIEB7VH_cjs.ok(targetVersion);
3281
3352
  }
3282
3353
  function tryNormalize(optionsInput) {
3283
3354
  try {
@@ -3286,7 +3357,7 @@ function tryNormalize(optionsInput) {
3286
3357
  return chunkKTIEB7VH_cjs.err(new MergeError("Invalid merge options.", { cause: error }));
3287
3358
  }
3288
3359
  }
3289
- async function resolveMerge(store, target, branches, options, useBaseSources, incremental) {
3360
+ async function resolveMerge(store, target, branches, options, useBaseSources, incremental, expectedBaseVersion) {
3290
3361
  let targetBranchSeen = false;
3291
3362
  for (const branch2 of branches) {
3292
3363
  if (branch2.id === BASE_PROVENANCE_BRANCH) {
@@ -3357,7 +3428,16 @@ async function resolveMerge(store, target, branches, options, useBaseSources, in
3357
3428
  subClassClosure,
3358
3429
  preferredBranchId
3359
3430
  );
3360
- const merged = incremental === void 0 ? await commitPlan(target, plan) : await commitIncrementalPlan(target, plan);
3431
+ const merged = incremental === void 0 ? await commitPlan(target, plan, expectedBaseVersion) : await commitIncrementalPlan(target, plan, {
3432
+ stagedNewByKind: newNodesByKind(staging),
3433
+ options,
3434
+ introspectionKinds,
3435
+ // The committed (kind, id) keys the base sources matched at PLAN time;
3436
+ // anything NEW the in-tx re-probe surfaces is a window write.
3437
+ plannedBaseMatchKeys: new Set(
3438
+ candidates.data.baseMembers.map((member) => mergeKeyOf(member))
3439
+ )
3440
+ });
3361
3441
  const provenance = options.provenance ? buildProvenanceIndex(plan.provenanceRecords) : { byBranch: () => ({ nodeIds: [], edgeIds: [] }) };
3362
3442
  const warnings = [...plan.warnings];
3363
3443
  let provenancePersisted;
@@ -3418,7 +3498,15 @@ async function merge(store, branches, optionsInput = {}) {
3418
3498
  if (chunkKTIEB7VH_cjs.isErr(precondition)) {
3419
3499
  return chunkKTIEB7VH_cjs.err(precondition.error);
3420
3500
  }
3421
- return resolveMerge(store, target, branches, options, false);
3501
+ return resolveMerge(
3502
+ store,
3503
+ target,
3504
+ branches,
3505
+ options,
3506
+ false,
3507
+ void 0,
3508
+ precondition.data
3509
+ );
3422
3510
  }
3423
3511
  async function validateForkPointVersions(forkPoint, branches) {
3424
3512
  const forkVersion = await computeBaseVersion(forkPoint);
@@ -3651,13 +3739,12 @@ async function validateIncrementalEdgeWrites(target, edgesApi, plan) {
3651
3739
  }
3652
3740
  const notFound = [...plannedKindById.keys()].filter((id) => !existingById.has(id)).sort((left, right) => compareStrings(left, right));
3653
3741
  if (notFound.length > 0) {
3654
- const perKind = await Promise.all(
3655
- Object.keys(target.graph.edges).map(
3656
- (kind) => edgeCollection(edgesApi, kind).getByIds(notFound, INCLUDE_TOMBSTONES)
3657
- )
3658
- );
3659
3742
  const crossKindById = /* @__PURE__ */ new Map();
3660
- for (const rows of perKind) {
3743
+ for (const kind of Object.keys(target.graph.edges)) {
3744
+ const rows = await edgeCollection(edgesApi, kind).getByIds(
3745
+ notFound,
3746
+ INCLUDE_TOMBSTONES
3747
+ );
3661
3748
  for (const [index, id] of notFound.entries()) {
3662
3749
  const row = rows[index];
3663
3750
  if (row !== void 0 && !crossKindById.has(id)) {
@@ -3725,20 +3812,77 @@ async function validateIncrementalEdgeWrites(target, edgesApi, plan) {
3725
3812
  }
3726
3813
  }
3727
3814
  }
3728
- async function commitIncrementalPlan(target, plan) {
3815
+ async function collectBaseMatchKeys(lookupStore, guard) {
3816
+ const matched = /* @__PURE__ */ new Set();
3817
+ for (const [kind, stagedNodes] of guard.stagedNewByKind) {
3818
+ const resolveConfig = guard.options.resolve[kind];
3819
+ if (resolveConfig === void 0) {
3820
+ continue;
3821
+ }
3822
+ const collection = lookupStore.nodes[kind];
3823
+ if (collection === void 0 || stagedNodes.length === 0) {
3824
+ continue;
3825
+ }
3826
+ const items = stagedNodes.map((staged) => ({ props: staged.node.props }));
3827
+ for (const constraint of uniqueConstraintsFor(
3828
+ guard.introspectionKinds,
3829
+ kind
3830
+ )) {
3831
+ const matches = await collection.bulkFindByConstraint(
3832
+ constraint.name,
3833
+ items
3834
+ );
3835
+ for (const base of matches) {
3836
+ if (base !== void 0) {
3837
+ matched.add(mergeKeyOf(base));
3838
+ }
3839
+ }
3840
+ }
3841
+ if (resolveConfig.blockIndex !== void 0) {
3842
+ const matchesByItem = await collection.bulkFindByIndex(
3843
+ resolveConfig.blockIndex,
3844
+ items
3845
+ );
3846
+ for (const perItem of matchesByItem) {
3847
+ for (const base of perItem) {
3848
+ matched.add(mergeKeyOf(base));
3849
+ }
3850
+ }
3851
+ }
3852
+ }
3853
+ return matched;
3854
+ }
3855
+ async function assertBaseResolutionStable(lookupStore, guard) {
3856
+ const liveKeys = await collectBaseMatchKeys(lookupStore, guard);
3857
+ const appeared = [...liveKeys].filter((key) => !guard.plannedBaseMatchKeys.has(key)).sort((left, right) => compareMergeKeys(left, right));
3858
+ if (appeared.length === 0) {
3859
+ return;
3860
+ }
3861
+ throw new BaseVersionMismatchError(
3862
+ `mergeIncremental() resolved its branch additions against the target as of planning, but ${appeared.length} committed row(s) matching a branch addition's identity key (a unique constraint or block index) were inserted before the commit transaction. Committing the plan would create duplicate entities the base-source resolution would otherwise have collapsed.`,
3863
+ {
3864
+ details: { appeared },
3865
+ suggestion: "Re-run mergeIncremental(); the re-planned merge resolves the branch additions against the now-committed rows."
3866
+ }
3867
+ );
3868
+ }
3869
+ async function commitIncrementalPlan(target, plan, guard) {
3729
3870
  if (!target.backend.capabilities.transactions) {
3730
3871
  throw new MergeError(
3731
3872
  "mergeIncremental() requires a transaction-capable target backend. Incremental writes must preflight existing rows and commit atomically; non-transactional fallback would allow partial graph writes.",
3732
3873
  { details: { capability: "transactions" } }
3733
3874
  );
3734
3875
  }
3735
- return target.transaction(async (tx) => {
3736
- const nodesApi = tx.nodes;
3737
- const edgesApi = tx.edges;
3738
- await validateIncrementalNodeWrites(target, nodesApi, plan);
3739
- await validateIncrementalEdgeWrites(target, edgesApi, plan);
3740
- return applyMergePlan(plan, nodesApi, edgesApi);
3741
- });
3876
+ return withTxConflictRetry(
3877
+ () => target.transaction(async (tx) => {
3878
+ const nodesApi = tx.nodes;
3879
+ const edgesApi = tx.edges;
3880
+ await assertBaseResolutionStable(tx, guard);
3881
+ await validateIncrementalNodeWrites(target, nodesApi, plan);
3882
+ await validateIncrementalEdgeWrites(target, edgesApi, plan);
3883
+ return applyMergePlan(plan, nodesApi, edgesApi);
3884
+ }, MERGE_COMMIT_TX_OPTIONS)
3885
+ );
3742
3886
  }
3743
3887
  async function mergeIncremental(args) {
3744
3888
  const { forkPoint, target, branches } = args;