@typicalday/firegraph 0.12.0 → 0.13.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 (70) hide show
  1. package/README.md +317 -73
  2. package/dist/backend-DuvHGgK1.d.cts +1897 -0
  3. package/dist/backend-DuvHGgK1.d.ts +1897 -0
  4. package/dist/backend.cjs +222 -3
  5. package/dist/backend.cjs.map +1 -1
  6. package/dist/backend.d.cts +25 -5
  7. package/dist/backend.d.ts +25 -5
  8. package/dist/backend.js +197 -4
  9. package/dist/backend.js.map +1 -1
  10. package/dist/chunk-2DHMNTV6.js +16 -0
  11. package/dist/chunk-2DHMNTV6.js.map +1 -0
  12. package/dist/chunk-4MMQ5W74.js +288 -0
  13. package/dist/chunk-4MMQ5W74.js.map +1 -0
  14. package/dist/chunk-D4J7Z4FE.js +67 -0
  15. package/dist/chunk-D4J7Z4FE.js.map +1 -0
  16. package/dist/chunk-N5HFDWQX.js +23 -0
  17. package/dist/chunk-N5HFDWQX.js.map +1 -0
  18. package/dist/chunk-PAD7WFFU.js +573 -0
  19. package/dist/chunk-PAD7WFFU.js.map +1 -0
  20. package/dist/{chunk-AWW4MUJ5.js → chunk-TK64DNVK.js} +12 -1
  21. package/dist/chunk-TK64DNVK.js.map +1 -0
  22. package/dist/{chunk-HONQY4HF.js → chunk-WRTFC5NG.js} +362 -17
  23. package/dist/chunk-WRTFC5NG.js.map +1 -0
  24. package/dist/client-BKi3vk0Q.d.ts +34 -0
  25. package/dist/client-BrsaXtDV.d.cts +34 -0
  26. package/dist/cloudflare/index.cjs +930 -3
  27. package/dist/cloudflare/index.cjs.map +1 -1
  28. package/dist/cloudflare/index.d.cts +213 -12
  29. package/dist/cloudflare/index.d.ts +213 -12
  30. package/dist/cloudflare/index.js +562 -281
  31. package/dist/cloudflare/index.js.map +1 -1
  32. package/dist/codegen/index.d.cts +1 -1
  33. package/dist/codegen/index.d.ts +1 -1
  34. package/dist/errors-BRc3I_eH.d.cts +73 -0
  35. package/dist/errors-BRc3I_eH.d.ts +73 -0
  36. package/dist/firestore-enterprise/index.cjs +3877 -0
  37. package/dist/firestore-enterprise/index.cjs.map +1 -0
  38. package/dist/firestore-enterprise/index.d.cts +141 -0
  39. package/dist/firestore-enterprise/index.d.ts +141 -0
  40. package/dist/firestore-enterprise/index.js +985 -0
  41. package/dist/firestore-enterprise/index.js.map +1 -0
  42. package/dist/firestore-standard/index.cjs +3117 -0
  43. package/dist/firestore-standard/index.cjs.map +1 -0
  44. package/dist/firestore-standard/index.d.cts +49 -0
  45. package/dist/firestore-standard/index.d.ts +49 -0
  46. package/dist/firestore-standard/index.js +283 -0
  47. package/dist/firestore-standard/index.js.map +1 -0
  48. package/dist/index.cjs +590 -550
  49. package/dist/index.cjs.map +1 -1
  50. package/dist/index.d.cts +9 -37
  51. package/dist/index.d.ts +9 -37
  52. package/dist/index.js +178 -555
  53. package/dist/index.js.map +1 -1
  54. package/dist/{registry-Fi074zVa.d.ts → registry-Bc7h6WTM.d.cts} +1 -1
  55. package/dist/{registry-B1qsVL0E.d.cts → registry-C2KUPVZj.d.ts} +1 -1
  56. package/dist/{scope-path-B1G3YiA7.d.cts → scope-path-CROFZGr9.d.cts} +1 -56
  57. package/dist/{scope-path-B1G3YiA7.d.ts → scope-path-CROFZGr9.d.ts} +1 -56
  58. package/dist/sqlite/index.cjs +3631 -0
  59. package/dist/sqlite/index.cjs.map +1 -0
  60. package/dist/sqlite/index.d.cts +111 -0
  61. package/dist/sqlite/index.d.ts +111 -0
  62. package/dist/sqlite/index.js +1164 -0
  63. package/dist/sqlite/index.js.map +1 -0
  64. package/package.json +33 -3
  65. package/dist/backend-BsR0lnFL.d.ts +0 -200
  66. package/dist/backend-Ct-fLlkG.d.cts +0 -200
  67. package/dist/chunk-AWW4MUJ5.js.map +0 -1
  68. package/dist/chunk-HONQY4HF.js.map +0 -1
  69. package/dist/types-DxYLy8Ol.d.cts +0 -770
  70. package/dist/types-DxYLy8Ol.d.ts +0 -770
@@ -0,0 +1,49 @@
1
+ export { c as createGraphClient } from '../client-BrsaXtDV.cjs';
2
+ export { M as META_EDGE_TYPE, a as META_NODE_TYPE, b as createMergedRegistry, d as createRegistry, f as generateId } from '../registry-Bc7h6WTM.cjs';
3
+ import { Firestore } from '@google-cloud/firestore';
4
+ import { S as StorageBackend } from '../backend-DuvHGgK1.cjs';
5
+
6
+ /**
7
+ * Firestore Standard edition `StorageBackend`.
8
+ *
9
+ * The Standard edition only has the classic Query API — pipelines and
10
+ * Enterprise-only product features (full-text search, geo) are not
11
+ * available. This file deliberately does not import the pipeline adapter so
12
+ * a Standard-only deployment never pulls Pipeline code into its bundle.
13
+ *
14
+ * Capability declarations follow the conservative invariant established in
15
+ * Phase 1: only declare what the file actually implements at runtime.
16
+ * `query.aggregate` (Phase 6), `query.select` (Phase 7), `search.vector`
17
+ * (Phase 8), and `query.join` (Phase 13a — chunked classic-API fan-out)
18
+ * are wired; `realtime.listen` will be added in a later phase once the
19
+ * matching backend method exists. `query.dml` stays unwired because the
20
+ * classic Query API has no server-side DML statement; mass-delete /
21
+ * mass-update are still routed through the existing `bulkRemoveEdges`
22
+ * fetch-then-write loop.
23
+ */
24
+
25
+ /**
26
+ * Capability union declared by the Firestore Standard backend.
27
+ *
28
+ * Conservative declaration: only capabilities backed by an actual runtime
29
+ * method are listed. `query.aggregate` (Phase 6) and `query.select`
30
+ * (Phase 7) are now wired; `search.vector` and `realtime.listen` will be
31
+ * layered in by their respective phases — this union and the matching
32
+ * cap-set literal are updated in lockstep.
33
+ */
34
+ type FirestoreStandardCapability = 'core.read' | 'core.write' | 'core.transactions' | 'core.batch' | 'core.subgraph' | 'query.aggregate' | 'query.select' | 'query.join' | 'search.vector' | 'raw.firestore';
35
+ interface FirestoreStandardOptions {
36
+ /** Internal: the logical scope path inherited from a parent subgraph. */
37
+ scopePath?: string;
38
+ }
39
+ /**
40
+ * Create a Firestore Standard-edition `StorageBackend`.
41
+ *
42
+ * Standard Firestore does not support pipelines or any Enterprise-only
43
+ * features. `data.*` filters require composite indexes; callers that mostly
44
+ * filter on built-in fields (`aUid`, `axbType`, `bUid`) avoid that
45
+ * requirement.
46
+ */
47
+ declare function createFirestoreStandardBackend(db: Firestore, collectionPath: string, options?: FirestoreStandardOptions): StorageBackend<FirestoreStandardCapability>;
48
+
49
+ export { type FirestoreStandardCapability, type FirestoreStandardOptions, createFirestoreStandardBackend };
@@ -0,0 +1,49 @@
1
+ export { c as createGraphClient } from '../client-BKi3vk0Q.js';
2
+ export { M as META_EDGE_TYPE, a as META_NODE_TYPE, b as createMergedRegistry, d as createRegistry, f as generateId } from '../registry-C2KUPVZj.js';
3
+ import { Firestore } from '@google-cloud/firestore';
4
+ import { S as StorageBackend } from '../backend-DuvHGgK1.js';
5
+
6
+ /**
7
+ * Firestore Standard edition `StorageBackend`.
8
+ *
9
+ * The Standard edition only has the classic Query API — pipelines and
10
+ * Enterprise-only product features (full-text search, geo) are not
11
+ * available. This file deliberately does not import the pipeline adapter so
12
+ * a Standard-only deployment never pulls Pipeline code into its bundle.
13
+ *
14
+ * Capability declarations follow the conservative invariant established in
15
+ * Phase 1: only declare what the file actually implements at runtime.
16
+ * `query.aggregate` (Phase 6), `query.select` (Phase 7), `search.vector`
17
+ * (Phase 8), and `query.join` (Phase 13a — chunked classic-API fan-out)
18
+ * are wired; `realtime.listen` will be added in a later phase once the
19
+ * matching backend method exists. `query.dml` stays unwired because the
20
+ * classic Query API has no server-side DML statement; mass-delete /
21
+ * mass-update are still routed through the existing `bulkRemoveEdges`
22
+ * fetch-then-write loop.
23
+ */
24
+
25
+ /**
26
+ * Capability union declared by the Firestore Standard backend.
27
+ *
28
+ * Conservative declaration: only capabilities backed by an actual runtime
29
+ * method are listed. `query.aggregate` (Phase 6) and `query.select`
30
+ * (Phase 7) are now wired; `search.vector` and `realtime.listen` will be
31
+ * layered in by their respective phases — this union and the matching
32
+ * cap-set literal are updated in lockstep.
33
+ */
34
+ type FirestoreStandardCapability = 'core.read' | 'core.write' | 'core.transactions' | 'core.batch' | 'core.subgraph' | 'query.aggregate' | 'query.select' | 'query.join' | 'search.vector' | 'raw.firestore';
35
+ interface FirestoreStandardOptions {
36
+ /** Internal: the logical scope path inherited from a parent subgraph. */
37
+ scopePath?: string;
38
+ }
39
+ /**
40
+ * Create a Firestore Standard-edition `StorageBackend`.
41
+ *
42
+ * Standard Firestore does not support pipelines or any Enterprise-only
43
+ * features. `data.*` filters require composite indexes; callers that mostly
44
+ * filter on built-in fields (`aUid`, `axbType`, `bUid`) avoid that
45
+ * requirement.
46
+ */
47
+ declare function createFirestoreStandardBackend(db: Firestore, collectionPath: string, options?: FirestoreStandardOptions): StorageBackend<FirestoreStandardCapability>;
48
+
49
+ export { type FirestoreStandardCapability, type FirestoreStandardOptions, createFirestoreStandardBackend };
@@ -0,0 +1,283 @@
1
+ import {
2
+ bulkRemoveEdges,
3
+ createBatchAdapter,
4
+ createFirestoreAdapter,
5
+ createTransactionAdapter,
6
+ removeNodeCascade,
7
+ runFirestoreAggregate,
8
+ runFirestoreClassicExpand,
9
+ runFirestoreFindEdgesProjected,
10
+ runFirestoreFindNearest
11
+ } from "../chunk-PAD7WFFU.js";
12
+ import {
13
+ deserializeFirestoreTypes
14
+ } from "../chunk-C2QMD7RY.js";
15
+ import {
16
+ createCapabilities
17
+ } from "../chunk-N5HFDWQX.js";
18
+ import {
19
+ META_EDGE_TYPE,
20
+ META_NODE_TYPE,
21
+ buildEdgeQueryPlan,
22
+ createGraphClient,
23
+ createMergedRegistry,
24
+ createRegistry,
25
+ generateId
26
+ } from "../chunk-WRTFC5NG.js";
27
+ import {
28
+ FiregraphError,
29
+ assertSafePath,
30
+ assertUpdatePayloadExclusive
31
+ } from "../chunk-TK64DNVK.js";
32
+ import "../chunk-EQJUUVFG.js";
33
+
34
+ // src/firestore-standard/backend.ts
35
+ import { FieldValue } from "@google-cloud/firestore";
36
+ var STANDARD_CAPS = /* @__PURE__ */ new Set([
37
+ "core.read",
38
+ "core.write",
39
+ "core.transactions",
40
+ "core.batch",
41
+ "core.subgraph",
42
+ "query.aggregate",
43
+ "query.select",
44
+ "query.join",
45
+ "search.vector",
46
+ "raw.firestore"
47
+ ]);
48
+ function dottedDataPath(op) {
49
+ assertSafePath(op.path);
50
+ return `data.${op.path.join(".")}`;
51
+ }
52
+ function buildFirestoreUpdate(update, db) {
53
+ assertUpdatePayloadExclusive(update);
54
+ const out = {
55
+ updatedAt: FieldValue.serverTimestamp()
56
+ };
57
+ if (update.replaceData) {
58
+ out.data = deserializeFirestoreTypes(update.replaceData, db);
59
+ } else if (update.dataOps) {
60
+ for (const op of update.dataOps) {
61
+ const key = dottedDataPath(op);
62
+ out[key] = op.delete ? FieldValue.delete() : op.value;
63
+ }
64
+ }
65
+ if (update.v !== void 0) {
66
+ out.v = update.v;
67
+ }
68
+ return out;
69
+ }
70
+ function stampWritableRecord(record) {
71
+ const now = FieldValue.serverTimestamp();
72
+ const out = {
73
+ aType: record.aType,
74
+ aUid: record.aUid,
75
+ axbType: record.axbType,
76
+ bType: record.bType,
77
+ bUid: record.bUid,
78
+ data: record.data,
79
+ createdAt: now,
80
+ updatedAt: now
81
+ };
82
+ if (record.v !== void 0) out.v = record.v;
83
+ return out;
84
+ }
85
+ var FirestoreStandardTransactionBackend = class {
86
+ constructor(adapter, db) {
87
+ this.adapter = adapter;
88
+ this.db = db;
89
+ }
90
+ getDoc(docId) {
91
+ return this.adapter.getDoc(docId);
92
+ }
93
+ query(filters, options) {
94
+ return this.adapter.query(filters, options);
95
+ }
96
+ async setDoc(docId, record, mode) {
97
+ this.adapter.setDoc(
98
+ docId,
99
+ stampWritableRecord(record),
100
+ mode === "merge" ? { merge: true } : void 0
101
+ );
102
+ }
103
+ async updateDoc(docId, update) {
104
+ this.adapter.updateDoc(docId, buildFirestoreUpdate(update, this.db));
105
+ }
106
+ async deleteDoc(docId) {
107
+ this.adapter.deleteDoc(docId);
108
+ }
109
+ };
110
+ var FirestoreStandardBatchBackend = class {
111
+ constructor(adapter, db) {
112
+ this.adapter = adapter;
113
+ this.db = db;
114
+ }
115
+ setDoc(docId, record, mode) {
116
+ this.adapter.setDoc(
117
+ docId,
118
+ stampWritableRecord(record),
119
+ mode === "merge" ? { merge: true } : void 0
120
+ );
121
+ }
122
+ updateDoc(docId, update) {
123
+ this.adapter.updateDoc(docId, buildFirestoreUpdate(update, this.db));
124
+ }
125
+ deleteDoc(docId) {
126
+ this.adapter.deleteDoc(docId);
127
+ }
128
+ commit() {
129
+ return this.adapter.commit();
130
+ }
131
+ };
132
+ var FirestoreStandardBackendImpl = class _FirestoreStandardBackendImpl {
133
+ constructor(db, collectionPath, scopePath) {
134
+ this.db = db;
135
+ this.collectionPath = collectionPath;
136
+ this.scopePath = scopePath;
137
+ this.adapter = createFirestoreAdapter(db, collectionPath);
138
+ }
139
+ capabilities = createCapabilities(STANDARD_CAPS);
140
+ collectionPath;
141
+ scopePath;
142
+ adapter;
143
+ // --- Reads ---
144
+ getDoc(docId) {
145
+ return this.adapter.getDoc(docId);
146
+ }
147
+ query(filters, options) {
148
+ return this.adapter.query(filters, options);
149
+ }
150
+ // --- Writes ---
151
+ setDoc(docId, record, mode) {
152
+ return this.adapter.setDoc(
153
+ docId,
154
+ stampWritableRecord(record),
155
+ mode === "merge" ? { merge: true } : void 0
156
+ );
157
+ }
158
+ updateDoc(docId, update) {
159
+ return this.adapter.updateDoc(docId, buildFirestoreUpdate(update, this.db));
160
+ }
161
+ deleteDoc(docId) {
162
+ return this.adapter.deleteDoc(docId);
163
+ }
164
+ // --- Transactions / Batches ---
165
+ runTransaction(fn) {
166
+ return this.db.runTransaction(async (firestoreTx) => {
167
+ const txAdapter = createTransactionAdapter(this.db, this.collectionPath, firestoreTx);
168
+ return fn(new FirestoreStandardTransactionBackend(txAdapter, this.db));
169
+ });
170
+ }
171
+ createBatch() {
172
+ const batchAdapter = createBatchAdapter(this.db, this.collectionPath);
173
+ return new FirestoreStandardBatchBackend(batchAdapter, this.db);
174
+ }
175
+ // --- Subgraphs ---
176
+ subgraph(parentNodeUid, name) {
177
+ const subPath = `${this.collectionPath}/${parentNodeUid}/${name}`;
178
+ const newScope = this.scopePath ? `${this.scopePath}/${name}` : name;
179
+ return new _FirestoreStandardBackendImpl(this.db, subPath, newScope);
180
+ }
181
+ // --- Cascade & bulk ---
182
+ removeNodeCascade(uid, reader, options) {
183
+ return removeNodeCascade(this.db, this.collectionPath, reader, uid, options);
184
+ }
185
+ bulkRemoveEdges(params, reader, options) {
186
+ return bulkRemoveEdges(this.db, this.collectionPath, reader, params, options);
187
+ }
188
+ // --- Cross-collection ---
189
+ async findEdgesGlobal(params, collectionName) {
190
+ const name = collectionName ?? this.collectionPath.split("/").pop();
191
+ const plan = buildEdgeQueryPlan(params);
192
+ if (plan.strategy === "get") {
193
+ throw new FiregraphError(
194
+ "findEdgesGlobal() requires a query, not a direct document lookup. Omit one of aUid/axbType/bUid to force a query strategy.",
195
+ "INVALID_QUERY"
196
+ );
197
+ }
198
+ const collectionGroupRef = this.db.collectionGroup(name);
199
+ let q = collectionGroupRef;
200
+ for (const f of plan.filters) {
201
+ q = q.where(f.field, f.op, f.value);
202
+ }
203
+ if (plan.options?.orderBy) {
204
+ q = q.orderBy(plan.options.orderBy.field, plan.options.orderBy.direction ?? "asc");
205
+ }
206
+ if (plan.options?.limit !== void 0) {
207
+ q = q.limit(plan.options.limit);
208
+ }
209
+ const snap = await q.get();
210
+ return snap.docs.map((doc) => doc.data());
211
+ }
212
+ // --- Aggregate ---
213
+ aggregate(spec, filters) {
214
+ return runFirestoreAggregate(this.db.collection(this.collectionPath), spec, filters, {
215
+ edition: "standard"
216
+ });
217
+ }
218
+ // --- Server-side projection (capability: query.select) ---
219
+ /**
220
+ * Run a projecting query via the shared classic-API helper. Both Firestore
221
+ * editions delegate to one implementation so the projection contract
222
+ * (bare-name normalization, builtin / `data.*` resolution, dedup,
223
+ * original-key preservation) stays consistent across editions. See
224
+ * `runFirestoreFindEdgesProjected` for the resolution rules.
225
+ */
226
+ findEdgesProjected(select, filters, options) {
227
+ return runFirestoreFindEdgesProjected(
228
+ this.db.collection(this.collectionPath),
229
+ select,
230
+ filters,
231
+ options
232
+ );
233
+ }
234
+ // --- Native vector / nearest-neighbour search (capability: search.vector) ---
235
+ /**
236
+ * Run a vector / nearest-neighbour query via the shared classic-API
237
+ * helper. Both Firestore editions delegate to one implementation so the
238
+ * field-path normalisation and result shape stay consistent across
239
+ * editions. See `runFirestoreFindNearest` for the resolution rules and
240
+ * the validation surface.
241
+ *
242
+ * Standard-edition note: vector search requires a single-field vector
243
+ * index on the indexed `vectorField`, plus a composite index whenever
244
+ * additional `where` filters narrow the candidate set before the ANN
245
+ * walk. Both indexes are configured per project in the Firestore
246
+ * console — firegraph does not auto-provision them.
247
+ */
248
+ findNearest(params) {
249
+ return runFirestoreFindNearest(this.db.collection(this.collectionPath), params);
250
+ }
251
+ // --- Server-side multi-source fan-out (capability: query.join) ---
252
+ /**
253
+ * Fan out from `params.sources` over a single edge type via the chunked
254
+ * classic-API helper. The classic `'in'` operator caps at 30 elements
255
+ * per call, so the helper splits sources into 30-element chunks and
256
+ * dispatches them in parallel via `Promise.all`. With 100 sources this
257
+ * is `ceil(100/30) = 4` round trips; the per-source `findEdges` loop in
258
+ * `traverse.ts` would have been 100. Enterprise can collapse this
259
+ * further to a single Pipelines `equalAny(...)` call — Standard cannot,
260
+ * so chunked classic is the best Standard can do.
261
+ *
262
+ * The helper applies a cross-chunk re-sort + total-limit slice so the
263
+ * observable contract matches the SQL backends'
264
+ * `WHERE … IN (?,?,…) ORDER BY … LIMIT N` semantics.
265
+ */
266
+ expand(params) {
267
+ return runFirestoreClassicExpand(this.adapter, params);
268
+ }
269
+ };
270
+ function createFirestoreStandardBackend(db, collectionPath, options = {}) {
271
+ const scopePath = options.scopePath ?? "";
272
+ return new FirestoreStandardBackendImpl(db, collectionPath, scopePath);
273
+ }
274
+ export {
275
+ META_EDGE_TYPE,
276
+ META_NODE_TYPE,
277
+ createFirestoreStandardBackend,
278
+ createGraphClient,
279
+ createMergedRegistry,
280
+ createRegistry,
281
+ generateId
282
+ };
283
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/firestore-standard/backend.ts"],"sourcesContent":["/**\n * Firestore Standard edition `StorageBackend`.\n *\n * The Standard edition only has the classic Query API — pipelines and\n * Enterprise-only product features (full-text search, geo) are not\n * available. This file deliberately does not import the pipeline adapter so\n * a Standard-only deployment never pulls Pipeline code into its bundle.\n *\n * Capability declarations follow the conservative invariant established in\n * Phase 1: only declare what the file actually implements at runtime.\n * `query.aggregate` (Phase 6), `query.select` (Phase 7), `search.vector`\n * (Phase 8), and `query.join` (Phase 13a — chunked classic-API fan-out)\n * are wired; `realtime.listen` will be added in a later phase once the\n * matching backend method exists. `query.dml` stays unwired because the\n * classic Query API has no server-side DML statement; mass-delete /\n * mass-update are still routed through the existing `bulkRemoveEdges`\n * fetch-then-write loop.\n */\n\nimport type { Firestore, Query, Transaction } from '@google-cloud/firestore';\nimport { FieldValue } from '@google-cloud/firestore';\n\nimport {\n bulkRemoveEdges as bulkRemoveEdgesImpl,\n removeNodeCascade as removeNodeCascadeImpl,\n} from '../bulk.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 { runFirestoreAggregate } from '../internal/firestore-aggregate.js';\nimport type {\n BatchAdapter,\n FirestoreAdapter,\n TransactionAdapter,\n} from '../internal/firestore-classic-adapter.js';\nimport {\n createBatchAdapter,\n createFirestoreAdapter,\n createTransactionAdapter,\n} from '../internal/firestore-classic-adapter.js';\nimport { runFirestoreClassicExpand } from '../internal/firestore-classic-expand.js';\nimport { runFirestoreFindEdgesProjected } from '../internal/firestore-projection.js';\nimport { runFirestoreFindNearest } from '../internal/firestore-vector.js';\nimport type { DataPathOp } from '../internal/write-plan.js';\nimport { assertSafePath, assertUpdatePayloadExclusive } from '../internal/write-plan.js';\nimport { buildEdgeQueryPlan } from '../query.js';\nimport { deserializeFirestoreTypes } from '../serialization.js';\nimport type {\n AggregateSpec,\n BulkOptions,\n BulkResult,\n CascadeResult,\n ExpandParams,\n ExpandResult,\n FindEdgesParams,\n FindNearestParams,\n GraphReader,\n QueryFilter,\n QueryOptions,\n StoredGraphRecord,\n} from '../types.js';\n\n/**\n * Capability union declared by the Firestore Standard backend.\n *\n * Conservative declaration: only capabilities backed by an actual runtime\n * method are listed. `query.aggregate` (Phase 6) and `query.select`\n * (Phase 7) are now wired; `search.vector` and `realtime.listen` will be\n * layered in by their respective phases — this union and the matching\n * cap-set literal are updated in lockstep.\n */\nexport type FirestoreStandardCapability =\n | 'core.read'\n | 'core.write'\n | 'core.transactions'\n | 'core.batch'\n | 'core.subgraph'\n | 'query.aggregate'\n | 'query.select'\n | 'query.join'\n | 'search.vector'\n | 'raw.firestore';\n\nconst STANDARD_CAPS: ReadonlySet<FirestoreStandardCapability> =\n new Set<FirestoreStandardCapability>([\n 'core.read',\n 'core.write',\n 'core.transactions',\n 'core.batch',\n 'core.subgraph',\n 'query.aggregate',\n 'query.select',\n 'query.join',\n 'search.vector',\n 'raw.firestore',\n ]);\n\nexport interface FirestoreStandardOptions {\n /** Internal: the logical scope path inherited from a parent subgraph. */\n scopePath?: string;\n}\n\n/** Build a `data.a.b.c` dotted path for Firestore's `update()` API. */\nfunction dottedDataPath(op: DataPathOp): string {\n assertSafePath(op.path);\n return `data.${op.path.join('.')}`;\n}\n\nfunction buildFirestoreUpdate(update: UpdatePayload, db: Firestore): Record<string, unknown> {\n assertUpdatePayloadExclusive(update);\n const out: Record<string, unknown> = {\n updatedAt: FieldValue.serverTimestamp(),\n };\n if (update.replaceData) {\n out.data = deserializeFirestoreTypes(update.replaceData, db);\n } else if (update.dataOps) {\n for (const op of update.dataOps) {\n const key = dottedDataPath(op);\n out[key] = op.delete ? FieldValue.delete() : op.value;\n }\n }\n if (update.v !== undefined) {\n out.v = update.v;\n }\n return out;\n}\n\nfunction stampWritableRecord(record: WritableRecord): Record<string, unknown> {\n const now = FieldValue.serverTimestamp();\n const out: Record<string, unknown> = {\n aType: record.aType,\n aUid: record.aUid,\n axbType: record.axbType,\n bType: record.bType,\n bUid: record.bUid,\n data: record.data,\n createdAt: now,\n updatedAt: now,\n };\n if (record.v !== undefined) out.v = record.v;\n return out;\n}\n\nclass FirestoreStandardTransactionBackend implements TransactionBackend {\n constructor(\n private readonly adapter: TransactionAdapter,\n private readonly db: Firestore,\n ) {}\n\n getDoc(docId: string): Promise<StoredGraphRecord | null> {\n return this.adapter.getDoc(docId);\n }\n\n query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]> {\n return this.adapter.query(filters, options);\n }\n\n async setDoc(docId: string, record: WritableRecord, mode: WriteMode): Promise<void> {\n this.adapter.setDoc(\n docId,\n stampWritableRecord(record),\n mode === 'merge' ? { merge: true } : undefined,\n );\n }\n\n async updateDoc(docId: string, update: UpdatePayload): Promise<void> {\n this.adapter.updateDoc(docId, buildFirestoreUpdate(update, this.db));\n }\n\n async deleteDoc(docId: string): Promise<void> {\n this.adapter.deleteDoc(docId);\n }\n}\n\nclass FirestoreStandardBatchBackend implements BatchBackend {\n constructor(\n private readonly adapter: BatchAdapter,\n private readonly db: Firestore,\n ) {}\n\n setDoc(docId: string, record: WritableRecord, mode: WriteMode): void {\n this.adapter.setDoc(\n docId,\n stampWritableRecord(record),\n mode === 'merge' ? { merge: true } : undefined,\n );\n }\n\n updateDoc(docId: string, update: UpdatePayload): void {\n this.adapter.updateDoc(docId, buildFirestoreUpdate(update, this.db));\n }\n\n deleteDoc(docId: string): void {\n this.adapter.deleteDoc(docId);\n }\n\n commit(): Promise<void> {\n return this.adapter.commit();\n }\n}\n\nclass FirestoreStandardBackendImpl implements StorageBackend<FirestoreStandardCapability> {\n readonly capabilities: BackendCapabilities<FirestoreStandardCapability> =\n createCapabilities(STANDARD_CAPS);\n readonly collectionPath: string;\n readonly scopePath: string;\n private readonly adapter: FirestoreAdapter;\n\n constructor(\n private readonly db: Firestore,\n collectionPath: string,\n scopePath: string,\n ) {\n this.collectionPath = collectionPath;\n this.scopePath = scopePath;\n this.adapter = createFirestoreAdapter(db, collectionPath);\n }\n\n // --- Reads ---\n\n getDoc(docId: string): Promise<StoredGraphRecord | null> {\n return this.adapter.getDoc(docId);\n }\n\n query(filters: QueryFilter[], options?: QueryOptions): Promise<StoredGraphRecord[]> {\n return this.adapter.query(filters, options);\n }\n\n // --- Writes ---\n\n setDoc(docId: string, record: WritableRecord, mode: WriteMode): Promise<void> {\n return this.adapter.setDoc(\n docId,\n stampWritableRecord(record),\n mode === 'merge' ? { merge: true } : undefined,\n );\n }\n\n updateDoc(docId: string, update: UpdatePayload): Promise<void> {\n return this.adapter.updateDoc(docId, buildFirestoreUpdate(update, this.db));\n }\n\n deleteDoc(docId: string): Promise<void> {\n return this.adapter.deleteDoc(docId);\n }\n\n // --- Transactions / Batches ---\n\n runTransaction<T>(fn: (tx: TransactionBackend) => Promise<T>): Promise<T> {\n return this.db.runTransaction(async (firestoreTx: Transaction) => {\n const txAdapter = createTransactionAdapter(this.db, this.collectionPath, firestoreTx);\n return fn(new FirestoreStandardTransactionBackend(txAdapter, this.db));\n });\n }\n\n createBatch(): BatchBackend {\n const batchAdapter = createBatchAdapter(this.db, this.collectionPath);\n return new FirestoreStandardBatchBackend(batchAdapter, this.db);\n }\n\n // --- Subgraphs ---\n\n subgraph(parentNodeUid: string, name: string): StorageBackend {\n const subPath = `${this.collectionPath}/${parentNodeUid}/${name}`;\n const newScope = this.scopePath ? `${this.scopePath}/${name}` : name;\n return new FirestoreStandardBackendImpl(this.db, subPath, newScope);\n }\n\n // --- Cascade & bulk ---\n\n removeNodeCascade(\n uid: string,\n reader: GraphReader,\n options?: BulkOptions,\n ): Promise<CascadeResult> {\n return removeNodeCascadeImpl(this.db, this.collectionPath, reader, uid, options);\n }\n\n bulkRemoveEdges(\n params: FindEdgesParams,\n reader: GraphReader,\n options?: BulkOptions,\n ): Promise<BulkResult> {\n return bulkRemoveEdgesImpl(this.db, this.collectionPath, reader, params, options);\n }\n\n // --- Cross-collection ---\n\n async findEdgesGlobal(\n params: FindEdgesParams,\n collectionName?: string,\n ): Promise<StoredGraphRecord[]> {\n const name = collectionName ?? this.collectionPath.split('/').pop()!;\n const plan = buildEdgeQueryPlan(params);\n\n if (plan.strategy === 'get') {\n throw new FiregraphError(\n 'findEdgesGlobal() requires a query, not a direct document lookup. ' +\n 'Omit one of aUid/axbType/bUid to force a query strategy.',\n 'INVALID_QUERY',\n );\n }\n\n const collectionGroupRef = this.db.collectionGroup(name);\n let q: Query = collectionGroupRef;\n for (const f of plan.filters) {\n q = q.where(f.field, f.op, f.value);\n }\n if (plan.options?.orderBy) {\n q = q.orderBy(plan.options.orderBy.field, plan.options.orderBy.direction ?? 'asc');\n }\n if (plan.options?.limit !== undefined) {\n q = q.limit(plan.options.limit);\n }\n const snap = await q.get();\n return snap.docs.map((doc) => doc.data() as StoredGraphRecord);\n }\n\n // --- Aggregate ---\n\n aggregate(spec: AggregateSpec, filters: QueryFilter[]): Promise<Record<string, number>> {\n return runFirestoreAggregate(this.db.collection(this.collectionPath), spec, filters, {\n edition: 'standard',\n });\n }\n\n // --- Server-side projection (capability: query.select) ---\n\n /**\n * Run a projecting query via the shared classic-API helper. Both Firestore\n * editions delegate to one implementation so the projection contract\n * (bare-name normalization, builtin / `data.*` resolution, dedup,\n * original-key preservation) stays consistent across editions. See\n * `runFirestoreFindEdgesProjected` for the resolution rules.\n */\n findEdgesProjected(\n select: ReadonlyArray<string>,\n filters: QueryFilter[],\n options?: QueryOptions,\n ): Promise<Array<Record<string, unknown>>> {\n return runFirestoreFindEdgesProjected(\n this.db.collection(this.collectionPath),\n select,\n filters,\n options,\n );\n }\n\n // --- Native vector / nearest-neighbour search (capability: search.vector) ---\n\n /**\n * Run a vector / nearest-neighbour query via the shared classic-API\n * helper. Both Firestore editions delegate to one implementation so the\n * field-path normalisation and result shape stay consistent across\n * editions. See `runFirestoreFindNearest` for the resolution rules and\n * the validation surface.\n *\n * Standard-edition note: vector search requires a single-field vector\n * index on the indexed `vectorField`, plus a composite index whenever\n * additional `where` filters narrow the candidate set before the ANN\n * walk. Both indexes are configured per project in the Firestore\n * console — firegraph does not auto-provision them.\n */\n findNearest(params: FindNearestParams): Promise<StoredGraphRecord[]> {\n return runFirestoreFindNearest(this.db.collection(this.collectionPath), params);\n }\n\n // --- Server-side multi-source fan-out (capability: query.join) ---\n\n /**\n * Fan out from `params.sources` over a single edge type via the chunked\n * classic-API helper. The classic `'in'` operator caps at 30 elements\n * per call, so the helper splits sources into 30-element chunks and\n * dispatches them in parallel via `Promise.all`. With 100 sources this\n * is `ceil(100/30) = 4` round trips; the per-source `findEdges` loop in\n * `traverse.ts` would have been 100. Enterprise can collapse this\n * further to a single Pipelines `equalAny(...)` call — Standard cannot,\n * so chunked classic is the best Standard can do.\n *\n * The helper applies a cross-chunk re-sort + total-limit slice so the\n * observable contract matches the SQL backends'\n * `WHERE … IN (?,?,…) ORDER BY … LIMIT N` semantics.\n */\n expand(params: ExpandParams): Promise<ExpandResult> {\n return runFirestoreClassicExpand(this.adapter, params);\n }\n}\n\n/**\n * Create a Firestore Standard-edition `StorageBackend`.\n *\n * Standard Firestore does not support pipelines or any Enterprise-only\n * features. `data.*` filters require composite indexes; callers that mostly\n * filter on built-in fields (`aUid`, `axbType`, `bUid`) avoid that\n * requirement.\n */\nexport function createFirestoreStandardBackend(\n db: Firestore,\n collectionPath: string,\n options: FirestoreStandardOptions = {},\n): StorageBackend<FirestoreStandardCapability> {\n const scopePath = options.scopePath ?? '';\n return new FirestoreStandardBackendImpl(db, collectionPath, scopePath);\n}\n"],"mappings":"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","names":[]}