@typicalday/firegraph 0.15.0 → 0.16.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.
- package/README.md +39 -17
- package/dist/{backend-CvImIwTY.d.cts → backend-CE3pM9-T.d.ts} +32 -2
- package/dist/{backend-BpYLdwCW.d.cts → backend-DNzv8KSR.d.cts} +33 -19
- package/dist/{backend-BpYLdwCW.d.ts → backend-DNzv8KSR.d.ts} +33 -19
- package/dist/{backend-YH5HtawN.d.ts → backend-EjFfw9yO.d.cts} +32 -2
- package/dist/backend.cjs.map +1 -1
- package/dist/backend.d.cts +2 -2
- package/dist/backend.d.ts +2 -2
- package/dist/backend.js +1 -1
- package/dist/{chunk-FODIMIWY.js → chunk-5JBNLH5W.js} +17 -6
- package/dist/chunk-5JBNLH5W.js.map +1 -0
- package/dist/{chunk-5HIRYV2S.js → chunk-6IO74NKD.js} +12 -10
- package/dist/{chunk-5HIRYV2S.js.map → chunk-6IO74NKD.js.map} +1 -1
- package/dist/{chunk-ULRDQ6HZ.js → chunk-NZVSLWNY.js} +6 -1
- package/dist/chunk-NZVSLWNY.js.map +1 -0
- package/dist/{chunk-N5HFDWQX.js → chunk-PWIO46RT.js} +1 -1
- package/dist/{chunk-N5HFDWQX.js.map → chunk-PWIO46RT.js.map} +1 -1
- package/dist/{client-B5o39X79.d.ts → client-CNAwJayO.d.ts} +1 -1
- package/dist/{client-BGHwxwPg.d.cts → client-CaXH5D5C.d.cts} +1 -1
- package/dist/cloudflare/index.cjs +11 -9
- package/dist/cloudflare/index.cjs.map +1 -1
- package/dist/cloudflare/index.d.cts +3 -3
- package/dist/cloudflare/index.d.ts +3 -3
- package/dist/cloudflare/index.js +3 -3
- package/dist/codegen/index.d.cts +1 -1
- package/dist/codegen/index.d.ts +1 -1
- package/dist/firestore-enterprise/index.cjs +11 -9
- package/dist/firestore-enterprise/index.cjs.map +1 -1
- package/dist/firestore-enterprise/index.d.cts +3 -3
- package/dist/firestore-enterprise/index.d.ts +3 -3
- package/dist/firestore-enterprise/index.js +2 -2
- package/dist/firestore-standard/index.cjs +11 -9
- package/dist/firestore-standard/index.cjs.map +1 -1
- package/dist/firestore-standard/index.d.cts +3 -3
- package/dist/firestore-standard/index.d.ts +3 -3
- package/dist/firestore-standard/index.js +2 -2
- package/dist/index.cjs +11 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/{registry-tKTb5Kx1.d.ts → registry-By1i-zge.d.ts} +1 -1
- package/dist/{registry-BGh7Jqpb.d.cts → registry-CNToyEra.d.cts} +1 -1
- package/dist/sqlite/index.cjs +24 -12
- package/dist/sqlite/index.cjs.map +1 -1
- package/dist/sqlite/index.d.cts +4 -4
- package/dist/sqlite/index.d.ts +4 -4
- package/dist/sqlite/index.js +4 -4
- package/dist/sqlite/local.cjs +474 -47
- package/dist/sqlite/local.cjs.map +1 -1
- package/dist/sqlite/local.d.cts +31 -5
- package/dist/sqlite/local.d.ts +31 -5
- package/dist/sqlite/local.js +429 -4
- package/dist/sqlite/local.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-FODIMIWY.js.map +0 -1
- package/dist/chunk-ULRDQ6HZ.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sqlite/catalog.ts","../src/sqlite/backend.ts"],"sourcesContent":["/**\n * Graph catalog for the table-per-graph SQLite edition.\n *\n * Each graph (the root, and every subgraph reached via chained\n * `subgraph()` calls) lives in its own SQLite table. The catalog is a\n * small bookkeeping table — `<rootTable>_graphs` — mapping each graph's\n * storage scope (the interleaved `parentUid/name` path that uniquely\n * identifies a subgraph position) to its physical table name and its\n * logical scope path (chained subgraph names, used for `allowedIn`\n * matching).\n *\n * The catalog is what makes registry-free cascade possible: deleting a\n * node with subgraphs prefix-matches descendant storage scopes in the\n * catalog and drops each listed table, with no need to know the subgraph\n * topology from a schema registry.\n */\n\nimport { quoteIdent, validateTableName } from '../internal/sqlite-schema.js';\nimport type { CompiledStatement } from '../internal/sqlite-sql.js';\n\n/** Name of the catalog table that tracks every graph under `rootTable`. */\nexport function catalogTableName(rootTable: string): string {\n validateTableName(rootTable);\n return `${rootTable}_graphs`;\n}\n\n/**\n * Deterministically mangle a storage scope into a SQL-identifier-safe\n * table-name suffix. The encoding is injective so two distinct scopes can\n * never collide on the same table:\n *\n * - `[A-Za-z0-9]` pass through\n * - `_` → `__` (escape char, doubled)\n * - `-` → `_h` (nanoid alphabet includes `-`)\n * - `/` → `_s` (scope segment separator)\n * - anything else → `_u<hex codepoint>_`\n *\n * Every escape sequence starts with `_` and no passthrough character is\n * `_`, so decoding is unambiguous (not that we ever decode — the catalog\n * stores the original scope alongside the table name).\n */\nexport function mangleStorageScope(scope: string): string {\n let out = '';\n for (const ch of scope) {\n if (/[A-Za-z0-9]/.test(ch)) out += ch;\n else if (ch === '_') out += '__';\n else if (ch === '-') out += '_h';\n else if (ch === '/') out += '_s';\n else out += `_u${ch.codePointAt(0)!.toString(16)}_`;\n }\n return out;\n}\n\n/**\n * Resolve the physical table for a graph position. The root graph\n * (`storageScope === ''`) uses `rootTable` itself; subgraphs get\n * `<rootTable>_g_<mangled scope>`.\n *\n * The `_g_` infix keeps subgraph tables disjoint from both the root table\n * and the catalog (`<rootTable>_graphs` — `_graphs` is never `_g_<x>`).\n */\nexport function tableForScope(rootTable: string, storageScope: string): string {\n validateTableName(rootTable);\n if (storageScope === '') return rootTable;\n return `${rootTable}_g_${mangleStorageScope(storageScope)}`;\n}\n\n/**\n * Escape LIKE wildcards in a literal prefix. The nanoid alphabet includes\n * `_` (a single-char LIKE wildcard), so prefix matches against storage\n * scopes MUST escape and carry an `ESCAPE '\\'` clause — otherwise a scope\n * containing `_` would match unrelated siblings.\n */\nexport function escapeLikePrefix(prefix: string): string {\n return prefix.replace(/[\\\\%_]/g, (c) => `\\\\${c}`);\n}\n\n/** DDL for the catalog table. Idempotent. */\nexport function buildCatalogDDL(rootTable: string): string {\n const t = quoteIdent(catalogTableName(rootTable));\n return `CREATE TABLE IF NOT EXISTS ${t} (\n storage_scope TEXT NOT NULL PRIMARY KEY,\n table_name TEXT NOT NULL UNIQUE,\n scope_path TEXT NOT NULL\n )`;\n}\n\n/** Register a graph in the catalog. Idempotent (`INSERT OR IGNORE`). */\nexport function compileCatalogRegister(\n rootTable: string,\n storageScope: string,\n tableName: string,\n scopePath: string,\n): CompiledStatement {\n const t = quoteIdent(catalogTableName(rootTable));\n return {\n sql: `INSERT OR IGNORE INTO ${t} (storage_scope, table_name, scope_path) VALUES (?, ?, ?)`,\n params: [storageScope, tableName, scopePath],\n };\n}\n\n/**\n * List every descendant graph whose storage scope starts with\n * `scopePrefix + '/'`. Used by cascade delete to discover which tables to\n * drop. Ordered by scope for deterministic statement order.\n */\nexport function compileCatalogDescendants(\n rootTable: string,\n scopePrefix: string,\n): CompiledStatement {\n const t = quoteIdent(catalogTableName(rootTable));\n return {\n sql:\n `SELECT storage_scope, table_name FROM ${t} ` +\n `WHERE storage_scope LIKE ? ESCAPE '\\\\' ORDER BY storage_scope`,\n params: [`${escapeLikePrefix(scopePrefix)}/%`],\n };\n}\n\n/** Remove one graph's catalog row (paired with its DROP TABLE). */\nexport function compileCatalogDelete(rootTable: string, storageScope: string): CompiledStatement {\n const t = quoteIdent(catalogTableName(rootTable));\n return {\n sql: `DELETE FROM ${t} WHERE storage_scope = ?`,\n params: [storageScope],\n };\n}\n","/**\n * SQLite implementation of `StorageBackend`.\n *\n * Table-per-graph design: the root graph lives in `tableName`, and each\n * subgraph lives in its own physical table (`<tableName>_g_<mangled scope>`,\n * see `tableForScope`). There is no `scope` column — the table a row lives\n * in *is* its scope, exactly like the Cloudflare DO edition where each\n * subgraph is its own Durable Object.\n *\n * A small catalog table (`<tableName>_graphs`) records every graph's\n * storage scope → table mapping. Cascade delete prefix-matches descendant\n * scopes in the catalog and drops each listed table — no registry topology\n * required.\n *\n * Schema is ensured lazily: the first operation on a backend instance runs\n * `CREATE TABLE IF NOT EXISTS` for the graph's table, its indexes, and the\n * catalog, then registers the graph in the catalog. Callers no longer\n * pre-create tables.\n */\n\nimport { computeEdgeDocId, computeNodeDocId } from '../docid.js';\nimport { FiregraphError } from '../errors.js';\nimport type {\n BackendCapabilities,\n BatchBackend,\n StorageBackend,\n TransactionBackend,\n UpdatePayload,\n WritableRecord,\n WriteMode,\n} from '../internal/backend.js';\nimport { createCapabilities } from '../internal/backend.js';\nimport { NODE_RELATION } from '../internal/constants.js';\nimport type { SqliteExecutor, SqliteTxExecutor } from '../internal/sqlite-executor.js';\nimport { buildSchemaStatements, quoteIdent, validateTableName } from '../internal/sqlite-schema.js';\nimport type { CompiledStatement } from '../internal/sqlite-sql.js';\nimport {\n compileAggregate,\n compileBulkDelete,\n compileBulkUpdate,\n compileDelete,\n compileExpand,\n compileExpandHydrate,\n compileFindEdgesProjected,\n compileSelect,\n compileSelectByDocId,\n compileSet,\n compileUpdate,\n decodeProjectedRow,\n rowToRecord,\n} from '../internal/sqlite-sql.js';\nimport type {\n AggregateSpec,\n BulkBatchError,\n BulkOptions,\n BulkResult,\n BulkUpdatePatch,\n CascadeResult,\n ExpandParams,\n ExpandResult,\n FindEdgesParams,\n GraphReader,\n GraphRegistry,\n IndexSpec,\n QueryFilter,\n QueryOptions,\n StoredGraphRecord,\n} from '../types.js';\nimport {\n buildCatalogDDL,\n compileCatalogDelete,\n compileCatalogDescendants,\n compileCatalogRegister,\n tableForScope,\n} from './catalog.js';\n\nexport interface SqliteBackendOptions {\n /** Logical scope path (chained subgraph names) — used for `allowedIn` matching. */\n scopePath?: string;\n /**\n * Internal storage scope (interleaved parent-uid/name path). Determines\n * which physical table this backend reads and writes — `''` (the default)\n * is the root graph in `tableName` itself.\n *\n * @internal Used by `subgraph()` to derive child backends. Setting it\n * directly bypasses catalog registration consistency checks (the graph\n * still self-registers, but ancestors are not validated) — always derive\n * subgraph backends via `subgraph()` instead.\n */\n storageScope?: string;\n /**\n * Registry contributing per-entry `indexes` declarations, applied to\n * every graph table this backend (and its subgraphs) lazily creates.\n */\n registry?: GraphRegistry;\n /**\n * Replaces the built-in core index preset for lazily created tables.\n * Pass `[]` to disable core indexes entirely.\n */\n coreIndexes?: IndexSpec[];\n /**\n * Extra DDL statements appended to every graph table's lazy bootstrap.\n * Called with the physical table name; the returned statements run after\n * the core table/index DDL inside the same chunked batch. Statements MUST\n * be idempotent (`IF NOT EXISTS` / `INSERT OR IGNORE` / re-runnable DML)\n * — the bootstrap re-runs after self-heal and once per backend instance,\n * including every lazily created subgraph table.\n *\n * @internal Used by `firegraph/sqlite-local` to install FTS5 index\n * tables, sync triggers, and backfill statements. Propagated to subgraph\n * backends derived via `subgraph()`.\n */\n extraTableDDL?: (tableName: string) => string[];\n}\n\n/**\n * The shape `createSqliteBackend` actually returns: `StorageBackend` plus\n * internal hooks the `firegraph/sqlite-local` search wrapper needs.\n */\nexport interface SqliteStorageBackend extends StorageBackend<SqliteCapability> {\n /**\n * Force the lazy schema bootstrap (table + indexes + catalog + any\n * `extraTableDDL` artifacts). Pass `force: true` to reset the bootstrap\n * cache first — mirrors the self-heal path in `withSchema` for callers\n * that issue their own SQL against this graph's table and hit a\n * \"no such table\" error after a parent cascade dropped it.\n *\n * @internal Used by the `firegraph/sqlite-local` search wrapper.\n */\n ensureReady(force?: boolean): Promise<void>;\n subgraph(parentNodeUid: string, name: string): SqliteStorageBackend;\n}\n\n/**\n * Default per-chunk retry budget for bulk/cascade operations. Mirrors the\n * Firestore bulk path (`src/bulk.ts`) so behaviour is consistent across\n * backends. Callers override via `BulkOptions.maxRetries`.\n */\nconst DEFAULT_MAX_RETRIES = 3;\nconst BASE_RETRY_DELAY_MS = 200;\n/**\n * Upper bound for the exponential backoff between chunk retries. Without\n * this cap, `maxRetries: 10` would push the final wait past 100s; legitimate\n * transient errors recover well within a few seconds, and longer waits just\n * delay the surfacing of permanent failures.\n */\nconst MAX_RETRY_DELAY_MS = 5000;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Return the smaller of two optional positive numbers, treating `undefined`\n * as \"no cap.\" Used to combine caller-supplied `BulkOptions.batchSize` with\n * the driver's own `maxBatchSize` so the more restrictive cap wins.\n */\nfunction minDefined(a: number | undefined, b: number | undefined): number | undefined {\n if (a === undefined) return b;\n if (b === undefined) return a;\n return Math.min(a, b);\n}\n\n/**\n * Split `statements` into chunks that respect both a per-batch statement\n * count cap (`maxStatements`) and a per-batch total bound-parameter cap\n * (`maxParams`). When neither cap is provided the entire list is returned\n * as a single chunk (preserves cross-batch atomicity for drivers like\n * DO SQLite that have no caps).\n *\n * Single-statement edge case: if a single statement's parameter count\n * already exceeds `maxParams`, it's emitted as its own chunk anyway. The\n * driver will reject it, which is the correct behavior — silently\n * dropping it would be worse.\n */\nfunction chunkStatements<T extends { params: unknown[] }>(\n statements: T[],\n maxStatements: number | undefined,\n maxParams: number | undefined,\n): T[][] {\n const stmtCap =\n maxStatements && maxStatements > 0 && Number.isFinite(maxStatements)\n ? Math.floor(maxStatements)\n : Infinity;\n const paramCap =\n maxParams && maxParams > 0 && Number.isFinite(maxParams) ? Math.floor(maxParams) : Infinity;\n\n if (stmtCap === Infinity && paramCap === Infinity) {\n return [statements];\n }\n\n const chunks: T[][] = [];\n let current: T[] = [];\n let currentParamCount = 0;\n for (const stmt of statements) {\n const stmtParams = stmt.params.length;\n const wouldExceedStmt = current.length + 1 > stmtCap;\n const wouldExceedParam = currentParamCount + stmtParams > paramCap;\n if (current.length > 0 && (wouldExceedStmt || wouldExceedParam)) {\n chunks.push(current);\n current = [];\n currentParamCount = 0;\n }\n current.push(stmt);\n currentParamCount += stmtParams;\n }\n if (current.length > 0) chunks.push(current);\n return chunks;\n}\n\nclass SqliteTransactionBackendImpl implements TransactionBackend {\n constructor(\n private readonly tx: SqliteTxExecutor,\n private readonly tableName: string,\n ) {}\n\n async getDoc(docId: string): Promise<StoredGraphRecord | null> {\n const stmt = compileSelectByDocId(this.tableName, docId);\n const rows = await this.tx.all(stmt.sql, stmt.params);\n return rows.length === 0 ? null : rowToRecord(rows[0]);\n }\n\n async query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]> {\n const stmt = compileSelect(this.tableName, filters, options);\n const rows = await this.tx.all(stmt.sql, stmt.params);\n return rows.map(rowToRecord);\n }\n\n async setDoc(docId: string, record: WritableRecord, mode: WriteMode): Promise<void> {\n const stmt = compileSet(this.tableName, docId, record, Date.now(), mode);\n await this.tx.run(stmt.sql, stmt.params);\n }\n\n async updateDoc(docId: string, update: UpdatePayload): Promise<void> {\n const stmt = compileUpdate(this.tableName, docId, update, Date.now());\n // RETURNING + `all()` for parity with Firestore — see SqliteBackendImpl.updateDoc.\n const sqlWithReturning = `${stmt.sql} RETURNING \"doc_id\"`;\n const rows = await this.tx.all(sqlWithReturning, stmt.params);\n if (rows.length === 0) {\n throw new FiregraphError(\n `updateDoc: no document found for doc_id=${docId} (table=${this.tableName})`,\n 'NOT_FOUND',\n );\n }\n }\n\n async deleteDoc(docId: string): Promise<void> {\n const stmt = compileDelete(this.tableName, docId);\n await this.tx.run(stmt.sql, stmt.params);\n }\n}\n\nclass SqliteBatchBackendImpl implements BatchBackend {\n private readonly statements: CompiledStatement[] = [];\n\n constructor(\n private readonly executor: SqliteExecutor,\n private readonly tableName: string,\n private readonly ensureSchema: () => Promise<void>,\n ) {}\n\n setDoc(docId: string, record: WritableRecord, mode: WriteMode): void {\n this.statements.push(compileSet(this.tableName, docId, record, Date.now(), mode));\n }\n\n updateDoc(docId: string, update: UpdatePayload): void {\n this.statements.push(compileUpdate(this.tableName, docId, update, Date.now()));\n }\n\n deleteDoc(docId: string): void {\n this.statements.push(compileDelete(this.tableName, docId));\n }\n\n async commit(): Promise<void> {\n if (this.statements.length === 0) return;\n await this.ensureSchema();\n await this.executor.batch(this.statements);\n this.statements.length = 0;\n }\n}\n\n/**\n * Capability union declared by the SQLite-backed `StorageBackend`.\n *\n * `core.transactions` is part of the static union because `runTransaction`\n * is always present as a method on the class. The runtime cap-set determines\n * whether that method is *functional*: D1 leaves `executor.transaction`\n * undefined and the call throws `UNSUPPORTED_OPERATION`; DO SQLite and\n * better-sqlite3 wire the executor and the call works. The static type\n * therefore promises only that the method exists — callers that care about\n * portability check `client.capabilities.has('core.transactions')` before\n * opening a tx, and code that runs against an unknown driver can rely on the\n * runtime guard inside `runTransaction`.\n *\n * The `query.*` extension capabilities follow the same conservative\n * declaration rule as the cap descriptor itself — only land in the union\n * when the corresponding method is actually wired up. Today that's\n * `query.aggregate` (Phase 4), `query.dml` (Phase 5), `query.join`\n * (Phase 6 — fan-out via `IN (…)` in one statement), and `query.select`\n * (Phase 7 — server-side projection via `json_extract`).\n */\nexport type SqliteCapability =\n | 'core.read'\n | 'core.write'\n | 'core.transactions'\n | 'core.batch'\n | 'core.subgraph'\n | 'query.aggregate'\n | 'query.dml'\n | 'query.join'\n | 'query.select'\n | 'raw.sql';\n\nconst SQLITE_CORE_CAPS: ReadonlyArray<SqliteCapability> = [\n 'core.read',\n 'core.write',\n 'core.batch',\n 'core.subgraph',\n 'query.aggregate',\n 'query.dml',\n 'query.join',\n 'query.select',\n 'raw.sql',\n];\n\nclass SqliteBackendImpl implements StorageBackend<SqliteCapability> {\n readonly capabilities: BackendCapabilities<SqliteCapability>;\n /** Physical table holding this graph's triples. */\n readonly collectionPath: string;\n readonly scopePath: string;\n /** Storage scope (interleaved parent UIDs + subgraph names) — `''` at root. */\n private readonly storageScope: string;\n /** Root graph's table name — prefix for subgraph tables and the catalog. */\n private readonly rootTable: string;\n private readonly registry: GraphRegistry | undefined;\n private readonly coreIndexes: IndexSpec[] | undefined;\n private readonly extraTableDDL: ((tableName: string) => string[]) | undefined;\n private ensured: Promise<void> | null = null;\n\n constructor(\n private readonly executor: SqliteExecutor,\n rootTable: string,\n storageScope: string,\n scopePath: string,\n registry: GraphRegistry | undefined,\n coreIndexes: IndexSpec[] | undefined,\n extraTableDDL?: (tableName: string) => string[],\n ) {\n validateTableName(rootTable);\n this.rootTable = rootTable;\n this.collectionPath = tableForScope(rootTable, storageScope);\n this.storageScope = storageScope;\n this.scopePath = scopePath;\n this.registry = registry;\n this.coreIndexes = coreIndexes;\n this.extraTableDDL = extraTableDDL;\n const caps = new Set<SqliteCapability>(SQLITE_CORE_CAPS);\n if (typeof executor.transaction === 'function') {\n caps.add('core.transactions');\n }\n this.capabilities = createCapabilities(caps);\n }\n\n /**\n * Lazily create this graph's table + indexes + the catalog, and register\n * the graph in the catalog. Runs once per backend instance; the DDL is\n * all `IF NOT EXISTS` / `INSERT OR IGNORE`, so concurrent instances over\n * the same database converge safely.\n */\n private ensureSchema(): Promise<void> {\n if (!this.ensured) {\n this.ensured = this.doEnsureSchema().catch((err) => {\n // Allow retry on the next operation rather than caching the failure.\n this.ensured = null;\n throw err;\n });\n }\n return this.ensured;\n }\n\n /** @internal See `SqliteStorageBackend.ensureReady`. */\n async ensureReady(force = false): Promise<void> {\n if (force) this.ensured = null;\n await this.ensureSchema();\n }\n\n private async doEnsureSchema(): Promise<void> {\n const ddl = [\n ...buildSchemaStatements(this.collectionPath, {\n coreIndexes: this.coreIndexes,\n registry: this.registry,\n }),\n ...(this.extraTableDDL ? this.extraTableDDL(this.collectionPath) : []),\n buildCatalogDDL(this.rootTable),\n ];\n const statements: CompiledStatement[] = ddl.map((sql) => ({ sql, params: [] }));\n statements.push(\n compileCatalogRegister(\n this.rootTable,\n this.storageScope,\n this.collectionPath,\n this.scopePath,\n ),\n );\n // Respect the driver's batch caps (D1 ≈ 100 statements / ≈ 1000 params) —\n // a registry with many index declarations could push the DDL list past\n // them. Every statement is IF NOT EXISTS / INSERT OR IGNORE, so losing\n // cross-chunk atomicity here is harmless: a partial bootstrap converges\n // on the next attempt.\n const chunks = chunkStatements(\n statements,\n this.executor.maxBatchSize,\n this.executor.maxBatchParams,\n );\n for (const chunk of chunks) {\n await this.executor.batch(chunk);\n }\n }\n\n /**\n * Run `op` with the schema bootstrap applied, self-healing when this\n * graph's table was dropped out from under the instance — a parent's\n * cascade delete DROPs descendant tables, but subgraph handles created\n * before the cascade still point at this (now missing) table with a\n * resolved bootstrap cache. On a \"no such table: <own table>\" error the\n * cache resets, the empty graph is recreated, and the op retries once.\n * This matches Firestore semantics, where a deleted subcollection reads\n * as empty and writes recreate it.\n */\n private async withSchema<T>(op: () => Promise<T>): Promise<T> {\n await this.ensureSchema();\n try {\n return await op();\n } catch (err) {\n if (!this.isMissingOwnTable(err)) throw err;\n this.ensured = null;\n await this.ensureSchema();\n return op();\n }\n }\n\n /** True when `err` is SQLite's missing-table error naming OUR table. */\n private isMissingOwnTable(err: unknown): boolean {\n const message = err instanceof Error ? err.message : String(err);\n return message.includes(`no such table: ${this.collectionPath}`);\n }\n\n // --- Reads ---\n\n async getDoc(docId: string): Promise<StoredGraphRecord | null> {\n return this.withSchema(async () => {\n const stmt = compileSelectByDocId(this.collectionPath, docId);\n const rows = await this.executor.all(stmt.sql, stmt.params);\n return rows.length === 0 ? null : rowToRecord(rows[0]);\n });\n }\n\n async query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]> {\n return this.withSchema(async () => {\n const stmt = compileSelect(this.collectionPath, filters, options);\n const rows = await this.executor.all(stmt.sql, stmt.params);\n return rows.map(rowToRecord);\n });\n }\n\n // --- Writes ---\n\n async setDoc(docId: string, record: WritableRecord, mode: WriteMode): Promise<void> {\n return this.withSchema(async () => {\n const stmt = compileSet(this.collectionPath, docId, record, Date.now(), mode);\n await this.executor.run(stmt.sql, stmt.params);\n });\n }\n\n async updateDoc(docId: string, update: UpdatePayload): Promise<void> {\n return this.withSchema(async () => {\n const stmt = compileUpdate(this.collectionPath, docId, update, Date.now());\n // Use RETURNING + `all()` so missing rows surface as an error, matching\n // Firestore's `update()` semantics (NOT_FOUND when the doc doesn't exist).\n // SQLite ≥3.35 supports UPDATE … RETURNING; better-sqlite3, D1, and DO\n // SQLite all run on a recent enough engine.\n const sqlWithReturning = `${stmt.sql} RETURNING \"doc_id\"`;\n const rows = await this.executor.all(sqlWithReturning, stmt.params);\n if (rows.length === 0) {\n throw new FiregraphError(\n `updateDoc: no document found for doc_id=${docId} (table=${this.collectionPath})`,\n 'NOT_FOUND',\n );\n }\n });\n }\n\n async deleteDoc(docId: string): Promise<void> {\n return this.withSchema(async () => {\n const stmt = compileDelete(this.collectionPath, docId);\n await this.executor.run(stmt.sql, stmt.params);\n });\n }\n\n // --- Transactions / Batches ---\n\n async runTransaction<T>(fn: (tx: TransactionBackend) => Promise<T>): Promise<T> {\n if (!this.executor.transaction) {\n throw new FiregraphError(\n 'Interactive transactions are not supported by this SQLite driver. ' +\n 'D1 in particular has no read-then-conditional-write transactions; ' +\n 'use a Durable Object SQLite client instead, or rewrite the code path ' +\n 'as a batch().',\n 'UNSUPPORTED_OPERATION',\n );\n }\n // Schema must exist before the tx opens — DDL inside an interactive\n // transaction would commit with it, complicating rollback semantics.\n await this.ensureSchema();\n return this.executor.transaction(async (tx) => {\n const txBackend = new SqliteTransactionBackendImpl(tx, this.collectionPath);\n return fn(txBackend);\n });\n }\n\n createBatch(): BatchBackend {\n return new SqliteBatchBackendImpl(this.executor, this.collectionPath, () =>\n this.ensureSchema(),\n );\n }\n\n // --- Subgraphs ---\n\n subgraph(parentNodeUid: string, name: string): SqliteStorageBackend {\n // Defense-in-depth: the public `GraphClient.subgraph()` also validates,\n // but backend users (traversal, cross-graph hops, custom integrations)\n // reach this method directly. A bad UID or a name containing '/' would\n // corrupt the materialized-path scope encoding — reject loudly.\n if (!parentNodeUid || parentNodeUid.includes('/')) {\n throw new FiregraphError(\n `Invalid parentNodeUid for subgraph: \"${parentNodeUid}\". ` +\n 'Must be a non-empty string without \"/\".',\n 'INVALID_SUBGRAPH',\n );\n }\n if (!name || name.includes('/')) {\n throw new FiregraphError(\n `Subgraph name must not contain \"/\" and must be non-empty: got \"${name}\". ` +\n 'Use chained .subgraph() calls for nested subgraphs.',\n 'INVALID_SUBGRAPH',\n );\n }\n const newStorageScope = this.storageScope\n ? `${this.storageScope}/${parentNodeUid}/${name}`\n : `${parentNodeUid}/${name}`;\n const newScope = this.scopePath ? `${this.scopePath}/${name}` : name;\n return new SqliteBackendImpl(\n this.executor,\n this.rootTable,\n newStorageScope,\n newScope,\n this.registry,\n this.coreIndexes,\n this.extraTableDDL,\n );\n }\n\n // --- Cascade & bulk ---\n\n async removeNodeCascade(\n uid: string,\n reader: GraphReader,\n options?: BulkOptions,\n ): Promise<CascadeResult> {\n await this.ensureSchema();\n // Collect all edges touching the node in the current graph (excluding self-loop).\n const [outgoingRaw, incomingRaw] = await Promise.all([\n reader.findEdges({ aUid: uid, allowCollectionScan: true, limit: 0 }),\n reader.findEdges({ bUid: uid, allowCollectionScan: true, limit: 0 }),\n ]);\n\n const seen = new Set<string>();\n const edgeDocIds: string[] = [];\n for (const edge of [...outgoingRaw, ...incomingRaw]) {\n if (edge.axbType === NODE_RELATION) continue;\n const docId = computeEdgeDocId(edge.aUid, edge.axbType, edge.bUid);\n if (!seen.has(docId)) {\n seen.add(docId);\n edgeDocIds.push(docId);\n }\n }\n\n const nodeDocId = computeNodeDocId(uid);\n const shouldDeleteSubgraphs = options?.deleteSubcollections !== false;\n\n // Discover descendant graphs via the catalog — every subgraph under this\n // node has a storage scope starting with `<scope>/<uid>/`. Pre-count\n // each table's rows so the returned `deleted` total reflects actual\n // records removed by the DROPs, not bookkeeping statements.\n const descendants: Array<{ storageScope: string; tableName: string }> = [];\n let subgraphRowCount = 0;\n if (shouldDeleteSubgraphs) {\n const prefix = this.storageScope ? `${this.storageScope}/${uid}` : uid;\n const descStmt = compileCatalogDescendants(this.rootTable, prefix);\n const rows = await this.executor.all(descStmt.sql, descStmt.params);\n for (const row of rows) {\n const tableName = String(row.table_name);\n // Catalog rows are written exclusively by `doEnsureSchema` with\n // mangled names, but validate anyway — these get interpolated into\n // DROP TABLE statements.\n validateTableName(tableName);\n descendants.push({ storageScope: String(row.storage_scope), tableName });\n }\n for (const d of descendants) {\n const countRows = await this.executor.all(\n `SELECT COUNT(*) AS n FROM ${quoteIdent(d.tableName)}`,\n [],\n );\n const n = (countRows[0] as Record<string, unknown> | undefined)?.n;\n subgraphRowCount += typeof n === 'bigint' ? Number(n) : Number(n ?? 0);\n }\n }\n\n // Build the full statement list. Order: edges → node → per-descendant\n // (DROP TABLE + catalog row delete). When the executor's `batch()` is\n // fully atomic the chunking loop below collapses to a single batch and\n // the operation is atomic. When the executor caps batches (D1, ~100\n // statements) we lose cross-batch atomicity, but `removeNodeCascade` is\n // idempotent so a caller can retry after a partial failure.\n const writeStatements: CompiledStatement[] = edgeDocIds.map((id) =>\n compileDelete(this.collectionPath, id),\n );\n writeStatements.push(compileDelete(this.collectionPath, nodeDocId));\n for (const d of descendants) {\n writeStatements.push({ sql: `DROP TABLE IF EXISTS ${quoteIdent(d.tableName)}`, params: [] });\n writeStatements.push(compileCatalogDelete(this.rootTable, d.storageScope));\n }\n\n const {\n deleted: stmtDeleted,\n batches,\n errors,\n } = await this.executeChunkedBatches(writeStatements, options);\n\n // `nodeDeleted` / `edgesDeleted` reflect best-effort completion: a\n // chunk failure leaves us unable to know which sub-batch contained the\n // node-row delete, so we conservatively flag both as incomplete when\n // any batch fails. The caller can retry — cascade is idempotent.\n const allOk = errors.length === 0;\n const edgesDeleted = allOk ? edgeDocIds.length : 0;\n // `nodeDeleted: true` means \"the node doc is gone\" — deletes are\n // idempotent, so a nonexistent node still reports true. This matches the\n // Firestore edition and the cross-backend contract pinned by\n // tests/integration/bulk.test.ts (\"handles nonexistent node gracefully\").\n const nodeDeleted = allOk;\n\n // `stmtDeleted` counts committed *statements*. Replace the per-descendant\n // bookkeeping statements' contribution (DROP + catalog delete = 2 each)\n // with the pre-computed row totals so callers see a true record count.\n // Only credit subgraph rows when every chunk succeeded — partial failure\n // means we can't be sure the chunks containing the DROPs committed.\n const bookkeepingContribution = allOk ? descendants.length * 2 : 0;\n const deleted = stmtDeleted - bookkeepingContribution + (allOk ? subgraphRowCount : 0);\n\n return { deleted, batches, errors, edgesDeleted, nodeDeleted };\n }\n\n async bulkRemoveEdges(\n params: FindEdgesParams,\n reader: GraphReader,\n options?: BulkOptions,\n ): Promise<BulkResult> {\n await this.ensureSchema();\n // Override default query limit for bulk deletion — we need all matching edges.\n // limit: 0 bypasses DEFAULT_QUERY_LIMIT; an explicit user limit is preserved.\n // allowCollectionScan: true — bulk deletion inherently implies scanning.\n const effectiveParams =\n params.limit !== undefined\n ? { ...params, allowCollectionScan: params.allowCollectionScan ?? true }\n : { ...params, limit: 0, allowCollectionScan: params.allowCollectionScan ?? true };\n const edges = await reader.findEdges(effectiveParams);\n const docIds = edges.map((e) => computeEdgeDocId(e.aUid, e.axbType, e.bUid));\n\n if (docIds.length === 0) {\n return { deleted: 0, batches: 0, errors: [] };\n }\n\n const statements = docIds.map((id) => compileDelete(this.collectionPath, id));\n\n return this.executeChunkedBatches(statements, options);\n }\n\n /**\n * Submit `statements` to the executor as one or more `batch()` calls,\n * chunking by `executor.maxBatchSize` (e.g. D1's ~100-statement cap).\n * Drivers that don't advertise a cap submit everything in one batch,\n * preserving cross-batch atomicity.\n *\n * Each chunk is retried with exponential backoff up to `maxRetries`\n * (default 3) before being recorded in `errors`. The loop continues past\n * a permanently failed chunk so the caller still gets partial progress\n * visibility — to halt on first failure, set `maxRetries: 0` and check\n * `result.errors.length` after the call.\n *\n * Returns `BulkResult`-shaped fields. `deleted` reflects only the\n * statement count of *successfully committed* batches — a DROP TABLE\n * statement contributes 1 to that total even though it may remove many\n * rows; `removeNodeCascade` patches that up with pre-counted row totals.\n *\n * **Atomicity caveat (D1):** when chunking kicks in, atomicity is lost\n * across chunk boundaries — one chunk may commit while a later one fails.\n * `removeNodeCascade` is idempotent (deleting the same docs again is a\n * no-op) so a caller can simply retry on partial failure. `bulkRemoveEdges`\n * is also idempotent for the same reason. DO SQLite leaves `maxBatchSize`\n * unset, so everything funnels through one atomic `transactionSync` and\n * this caveat does not apply.\n */\n private async executeChunkedBatches(\n statements: CompiledStatement[],\n options?: BulkOptions,\n ): Promise<{ deleted: number; batches: number; errors: BulkBatchError[] }> {\n if (statements.length === 0) {\n return { deleted: 0, batches: 0, errors: [] };\n }\n const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;\n\n // Split `statements` into chunks up front. Chunking honors the smallest\n // of: caller-supplied `batchSize` (used by callers who want progress\n // granularity), the driver's statement-count cap (`maxBatchSize`, D1 ≈\n // 100), and the driver's total bound-parameter cap (`maxBatchParams`,\n // D1 ≈ 1000). Most cascade/bulk statements are 1-param DELETEs so the\n // param cap rarely triggers, but we respect it defensively. Drivers with\n // no declared caps and no caller cap submit everything in one batch (DO\n // SQLite's atomic `transactionSync`).\n const callerBatchSize = options?.batchSize;\n const stmtCap = minDefined(callerBatchSize, this.executor.maxBatchSize);\n const chunks = chunkStatements(statements, stmtCap, this.executor.maxBatchParams);\n\n const errors: BulkBatchError[] = [];\n let deleted = 0;\n let batches = 0;\n const totalBatches = chunks.length;\n\n const driverParamCap = this.executor.maxBatchParams;\n\n for (let batchIndex = 0; batchIndex < chunks.length; batchIndex++) {\n const chunk = chunks[batchIndex];\n\n // A chunk that's a single statement whose param count already exceeds\n // the driver's per-batch param cap will be rejected on every attempt —\n // retrying just adds latency before surfacing the failure. `chunkStatements`\n // intentionally emits such statements as their own chunk (failing loudly\n // beats silently dropping); fast-fail here closes the loop.\n const isUnretriableOversize =\n chunk.length === 1 &&\n driverParamCap !== undefined &&\n chunk[0].params.length > driverParamCap;\n\n let committed = false;\n let lastError: Error | null = null;\n const effectiveRetries = isUnretriableOversize ? 0 : maxRetries;\n for (let attempt = 0; attempt <= effectiveRetries; attempt++) {\n try {\n await this.executor.batch(chunk);\n committed = true;\n break;\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n if (attempt < effectiveRetries) {\n const delay = Math.min(BASE_RETRY_DELAY_MS * Math.pow(2, attempt), MAX_RETRY_DELAY_MS);\n await sleep(delay);\n }\n }\n }\n\n if (committed) {\n deleted += chunk.length;\n batches += 1;\n } else if (lastError) {\n errors.push({\n batchIndex,\n error: lastError,\n operationCount: chunk.length,\n });\n }\n\n if (options?.onProgress) {\n options.onProgress({\n completedBatches: batches,\n totalBatches,\n deletedSoFar: deleted,\n });\n }\n }\n\n return { deleted, batches, errors };\n }\n\n // `findEdgesGlobal` is deliberately NOT defined on this class. Each graph\n // is its own table, so a \"collection group\" query would mean scanning every\n // table listed in the catalog — an unbounded fan-out the cross-backend\n // contract treats as unsupported (the Cloudflare DO edition makes the same\n // call: no cross-DO index, no `findEdgesGlobal`). The client surfaces\n // `UNSUPPORTED_OPERATION` when the method is absent.\n\n // --- Aggregate ---\n\n /**\n * Run an aggregate query in a single SQL statement. Supports the full\n * count/sum/avg/min/max set — the SQLite engine evaluates each aggregate\n * function over the filtered row set and the executor returns one row\n * with one column per alias. SUM/MIN/MAX of an empty set returns 0\n * (SQLite's `SUM(NULL) = NULL` is mapped to a clean number for the\n * cross-backend contract); AVG returns NaN, matching the mathematical\n * convention and the Firestore Standard helper.\n */\n async aggregate(spec: AggregateSpec, filters: QueryFilter[]): Promise<Record<string, number>> {\n const { stmt, aliases } = compileAggregate(this.collectionPath, spec, filters);\n const rows = await this.withSchema(() => this.executor.all(stmt.sql, stmt.params));\n const row = rows[0] ?? {};\n const out: Record<string, number> = {};\n for (const alias of aliases) {\n const v = row[alias];\n if (v === null || v === undefined) {\n // SQLite returns NULL for SUM/MIN/MAX over an empty set. Resolve\n // to 0 for SUM/MIN/MAX (well-defined) and NaN for AVG (empty-set\n // average is undefined). COUNT(*) is never null.\n const op = spec[alias].op;\n out[alias] = op === 'avg' ? Number.NaN : 0;\n } else if (typeof v === 'bigint') {\n out[alias] = Number(v);\n } else if (typeof v === 'number') {\n out[alias] = v;\n } else {\n // Some drivers return strings for very large or precise numerics.\n // Coerce defensively — the contract is `number`.\n out[alias] = Number(v);\n }\n }\n return out;\n }\n\n // --- Server-side DML ---\n\n /**\n * Delete every row matching `filters` in a single SQL DELETE statement.\n *\n * Uses `RETURNING \"doc_id\"` to count rows touched — the SQLite executor's\n * `run` returns void, so RETURNING + `all()` is the portable way to learn\n * how many rows the engine actually deleted. SQLite ≥ 3.35 supports\n * `DELETE … RETURNING`; better-sqlite3, D1, and DO SQLite all run on a\n * recent enough engine.\n *\n * Single-statement DML doesn't chunk: the engine handles N rows in one\n * shot, so `BulkOptions.batchSize` is intentionally ignored. The retry\n * loop here exists only for transient driver errors (e.g. D1 surface\n * congestion); a permanent failure is surfaced via the `errors` array\n * with `batchIndex: 0` so callers see the same shape as `bulkRemoveEdges`.\n *\n * Subgraph isolation is physical — the statement only ever touches this\n * graph's table, so no scoping predicate is needed.\n */\n async bulkDelete(filters: QueryFilter[], options?: BulkOptions): Promise<BulkResult> {\n await this.ensureSchema();\n const stmt = compileBulkDelete(this.collectionPath, filters);\n return this.executeDmlWithReturning(stmt, options);\n }\n\n /**\n * Update every row matching `filters` with `patch.data` in a single SQL\n * UPDATE statement. The patch is deep-merged into each row's `data`\n * column via the same `flattenPatch` → `compileDataOpsExpr` pipeline that\n * `compileUpdate` (single-row) uses.\n *\n * Same contract notes as `bulkDelete` apply: single-statement, no\n * chunking, `RETURNING \"doc_id\"` for the affected count, retry loop for\n * transient driver errors.\n */\n async bulkUpdate(\n filters: QueryFilter[],\n patch: BulkUpdatePatch,\n options?: BulkOptions,\n ): Promise<BulkResult> {\n await this.ensureSchema();\n const stmt = compileBulkUpdate(this.collectionPath, filters, patch.data, Date.now());\n return this.executeDmlWithReturning(stmt, options);\n }\n\n /**\n * Multi-source fan-out — `query.join` capability.\n *\n * Issues a single `SELECT … WHERE \"aUid\" IN (?, ?, …)` statement that\n * matches every edge from every source UID in one round trip. When\n * `params.hydrate === true`, follows up with a second statement that\n * fetches the target node rows; both queries hit the same table so\n * the executor amortises connection / parsing cost across them.\n *\n * Empty `params.sources` short-circuits to an empty result without\n * touching the executor — `IN ()` is not valid SQL.\n *\n * Per-source ordering / strict per-source LIMIT enforcement is NOT\n * implemented here; see the `ExpandParams.limitPerSource` JSDoc and\n * `compileExpand` for the cap semantics. Strict per-source caps would\n * require window functions and were judged out of scope for the\n * round-trip-collapse goal.\n */\n async expand(params: ExpandParams): Promise<ExpandResult> {\n if (params.sources.length === 0) {\n return params.hydrate ? { edges: [], targets: [] } : { edges: [] };\n }\n const stmt = compileExpand(this.collectionPath, params);\n const rows = await this.withSchema(() => this.executor.all(stmt.sql, stmt.params));\n const edges = rows.map(rowToRecord);\n if (!params.hydrate) {\n return { edges };\n }\n // Hydration: fetch target nodes for every edge in one IN-clause statement.\n // The \"target\" side depends on direction — forward hops point at `bUid`,\n // reverse hops point at `aUid`.\n const direction = params.direction ?? 'forward';\n const targetUids = edges.map((e) => (direction === 'forward' ? e.bUid : e.aUid));\n const uniqueTargets = [...new Set(targetUids)];\n if (uniqueTargets.length === 0) {\n return { edges, targets: [] };\n }\n const hydrateStmt = compileExpandHydrate(this.collectionPath, uniqueTargets);\n const hydrateRows = await this.executor.all(hydrateStmt.sql, hydrateStmt.params);\n const byUid = new Map<string, StoredGraphRecord>();\n for (const row of hydrateRows) {\n const node = rowToRecord(row);\n // Node UID is `bUid` (== `aUid` for self-loop) by convention. Key the\n // map by `bUid` so the alignment loop below indexes correctly.\n byUid.set(node.bUid, node);\n }\n const targets = targetUids.map((uid) => byUid.get(uid) ?? null);\n return { edges, targets };\n }\n\n /**\n * Server-side projection — `query.select` capability.\n *\n * Issues a single `SELECT json_extract(data, '$.f1'), …` statement that\n * returns only the requested fields. The compiler emits one column per\n * unique field plus a paired `json_type` column for `data.*` projections\n * so the decoder can recover JSON-encoded objects/arrays without a\n * second round trip. Migrations are NOT applied — the caller asked for\n * a partial shape, and rehydrating that into the migration pipeline\n * would require synthesising every absent field.\n *\n * The wire-payload reduction is the entire reason this method exists:\n * a list view that only needs `title` / `date` no longer drags the\n * full `data` JSON across the network. Callers that need the full\n * record should use `findEdges` (with migration support).\n */\n async findEdgesProjected(\n select: ReadonlyArray<string>,\n filters: QueryFilter[],\n options?: QueryOptions,\n ): Promise<Array<Record<string, unknown>>> {\n const { stmt, columns } = compileFindEdgesProjected(\n this.collectionPath,\n select,\n filters,\n options,\n );\n const rows = await this.withSchema(() => this.executor.all(stmt.sql, stmt.params));\n return rows.map((row) => decodeProjectedRow(row, columns));\n }\n\n /**\n * Run a DML statement with `RETURNING \"doc_id\"` so we can count the\n * rows the engine touched, with the same retry/backoff contract as\n * `executeChunkedBatches`. Single statement, single batch.\n */\n private async executeDmlWithReturning(\n stmt: CompiledStatement,\n options?: BulkOptions,\n ): Promise<BulkResult> {\n const sqlWithReturning = `${stmt.sql} RETURNING \"doc_id\"`;\n const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;\n let lastError: Error | null = null;\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const rows = await this.executor.all(sqlWithReturning, stmt.params);\n const deleted = rows.length;\n if (options?.onProgress) {\n options.onProgress({\n completedBatches: 1,\n totalBatches: 1,\n deletedSoFar: deleted,\n });\n }\n return { deleted, batches: 1, errors: [] };\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n if (attempt < maxRetries) {\n const delay = Math.min(BASE_RETRY_DELAY_MS * Math.pow(2, attempt), MAX_RETRY_DELAY_MS);\n await sleep(delay);\n }\n }\n }\n // `operationCount` is genuinely unknown for a server-side DML — we\n // don't know how many rows the failed statement would have touched.\n // Report 0 as the lower bound; callers concerned about partial state\n // should re-query and reconcile.\n return {\n deleted: 0,\n batches: 0,\n errors: [\n {\n batchIndex: 0,\n error: lastError ?? new Error('bulk DML failed for unknown reason'),\n operationCount: 0,\n },\n ],\n };\n }\n}\n\n/**\n * Create a SQLite-backed `StorageBackend`.\n *\n * `tableName` is the root graph's table; subgraphs get their own tables\n * derived from it (see `tableForScope`). Schema (tables, indexes, and the\n * graph catalog) is created lazily on first use — no manual DDL step.\n * Pass `options.registry` so per-entry `indexes` declarations land in\n * every lazily created table.\n */\nexport function createSqliteBackend(\n executor: SqliteExecutor,\n tableName: string,\n options: SqliteBackendOptions = {},\n): SqliteStorageBackend {\n const storageScope = options.storageScope ?? '';\n const scopePath = options.scopePath ?? '';\n return new SqliteBackendImpl(\n executor,\n tableName,\n storageScope,\n scopePath,\n options.registry,\n options.coreIndexes,\n options.extraTableDDL,\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1750,7 +1750,7 @@ var GraphClientImpl = class _GraphClientImpl {
|
|
|
1750
1750
|
async findNearest(params) {
|
|
1751
1751
|
if (!this.backend.findNearest) {
|
|
1752
1752
|
throw new FiregraphError(
|
|
1753
|
-
"findNearest() is not supported by the current storage backend. Vector search requires a backend that declares `search.vector` (currently Firestore Standard and
|
|
1753
|
+
"findNearest() is not supported by the current storage backend. Vector search requires a backend that declares `search.vector` (currently Firestore Standard, Firestore Enterprise, and the local better-sqlite3 backend). There is no client-side fallback because emulating ANN on top of the generic backend surface does not scale beyond toy datasets.",
|
|
1754
1754
|
"UNSUPPORTED_OPERATION"
|
|
1755
1755
|
);
|
|
1756
1756
|
}
|
|
@@ -1766,13 +1766,15 @@ var GraphClientImpl = class _GraphClientImpl {
|
|
|
1766
1766
|
* Native full-text search (capability `search.fullText`).
|
|
1767
1767
|
*
|
|
1768
1768
|
* Returns the top-N records by relevance, ordered by the search
|
|
1769
|
-
* index's score.
|
|
1770
|
-
*
|
|
1771
|
-
*
|
|
1772
|
-
*
|
|
1773
|
-
*
|
|
1774
|
-
*
|
|
1775
|
-
*
|
|
1769
|
+
* index's score. Firestore Enterprise declares this capability (via
|
|
1770
|
+
* the Pipelines `search({ query: documentMatches(...) })` stage over
|
|
1771
|
+
* Enterprise's FTS index), as does the local better-sqlite3 backend
|
|
1772
|
+
* (`firegraph/sqlite-local`, via a trigger-synced FTS5 index ranked
|
|
1773
|
+
* by `bm25()`). Standard does not declare the cap (FTS is an
|
|
1774
|
+
* Enterprise-only product feature, not a typed-API gap); D1 and the
|
|
1775
|
+
* Cloudflare DO edition have no FTS trigger infrastructure. Backends
|
|
1776
|
+
* without `search.fullText` throw `UNSUPPORTED_OPERATION` from this
|
|
1777
|
+
* wrapper.
|
|
1776
1778
|
*
|
|
1777
1779
|
* Scan-protection mirrors `findNearest`: a search with no
|
|
1778
1780
|
* identifying filters (`aType` / `axbType` / `bType`) walks every
|
|
@@ -1788,7 +1790,7 @@ var GraphClientImpl = class _GraphClientImpl {
|
|
|
1788
1790
|
async fullTextSearch(params) {
|
|
1789
1791
|
if (!this.backend.fullTextSearch) {
|
|
1790
1792
|
throw new FiregraphError(
|
|
1791
|
-
"fullTextSearch() is not supported by the current storage backend. Full-text search requires a backend that declares `search.fullText` (currently Firestore Enterprise
|
|
1793
|
+
"fullTextSearch() is not supported by the current storage backend. Full-text search requires a backend that declares `search.fullText` (currently Firestore Enterprise and the local better-sqlite3 backend). There is no client-side fallback because emulating FTS over the generic backend surface would not scale beyond toy datasets.",
|
|
1792
1794
|
"UNSUPPORTED_OPERATION"
|
|
1793
1795
|
);
|
|
1794
1796
|
}
|
|
@@ -2034,4 +2036,4 @@ export {
|
|
|
2034
2036
|
createGraphClientFromBackend,
|
|
2035
2037
|
generateId
|
|
2036
2038
|
};
|
|
2037
|
-
//# sourceMappingURL=chunk-
|
|
2039
|
+
//# sourceMappingURL=chunk-6IO74NKD.js.map
|