@typicalday/firegraph 0.13.0 → 0.14.1
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 +57 -1
- package/dist/backend.cjs +2 -3
- package/dist/backend.cjs.map +1 -1
- package/dist/backend.js +1 -1
- package/dist/{chunk-WRTFC5NG.js → chunk-3AHHXMWX.js} +2 -2
- package/dist/{chunk-PAD7WFFU.js → chunk-DJI3VXXA.js} +36 -10
- package/dist/chunk-DJI3VXXA.js.map +1 -0
- package/dist/{chunk-4MMQ5W74.js → chunk-NNBSUOOF.js} +7 -6
- package/dist/chunk-NNBSUOOF.js.map +1 -0
- package/dist/{chunk-TK64DNVK.js → chunk-SIHE4UY4.js} +3 -4
- package/dist/chunk-SIHE4UY4.js.map +1 -0
- package/dist/cloudflare/index.cjs +7 -7
- package/dist/cloudflare/index.cjs.map +1 -1
- package/dist/cloudflare/index.js +3 -3
- package/dist/firestore-enterprise/index.cjs +57 -48
- package/dist/firestore-enterprise/index.cjs.map +1 -1
- package/dist/firestore-enterprise/index.d.cts +41 -11
- package/dist/firestore-enterprise/index.d.ts +41 -11
- package/dist/firestore-enterprise/index.js +31 -42
- package/dist/firestore-enterprise/index.js.map +1 -1
- package/dist/firestore-standard/index.cjs +34 -37
- package/dist/firestore-standard/index.cjs.map +1 -1
- package/dist/firestore-standard/index.js +9 -34
- package/dist/firestore-standard/index.js.map +1 -1
- package/dist/index.cjs +2 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/sqlite/index.cjs +7 -7
- package/dist/sqlite/index.cjs.map +1 -1
- package/dist/sqlite/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-4MMQ5W74.js.map +0 -1
- package/dist/chunk-PAD7WFFU.js.map +0 -1
- package/dist/chunk-TK64DNVK.js.map +0 -1
- /package/dist/{chunk-WRTFC5NG.js.map → chunk-3AHHXMWX.js.map} +0 -0
|
@@ -92,10 +92,15 @@ interface FirestoreEnterpriseOptions {
|
|
|
92
92
|
* (search, aggregate, etc., once implemented) always use pipelines
|
|
93
93
|
* regardless of this option.
|
|
94
94
|
*
|
|
95
|
-
* The emulator does not execute
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
95
|
+
* The legacy / standard-edition Firestore emulator does not execute
|
|
96
|
+
* pipeline queries, so this option is coerced to `'classic'` whenever
|
|
97
|
+
* `FIRESTORE_EMULATOR_HOST` is set AND the caller has NOT opted into
|
|
98
|
+
* the enterprise-edition emulator via `FIRESTORE_EMULATOR_EDITION=enterprise`
|
|
99
|
+
* (case-insensitive). When that env var is set, the requested mode is
|
|
100
|
+
* honored end-to-end — pipelines work in firebase-tools v15.14+ with
|
|
101
|
+
* `--database-edition enterprise`. A one-time `console.warn` fires when
|
|
102
|
+
* the emulator forces the fallback after the caller explicitly asked for
|
|
103
|
+
* pipeline mode.
|
|
99
104
|
*/
|
|
100
105
|
defaultQueryMode?: FirestoreEnterpriseQueryMode;
|
|
101
106
|
/**
|
|
@@ -127,15 +132,40 @@ interface FirestoreEnterpriseOptions {
|
|
|
127
132
|
/** Internal: the logical scope path inherited from a parent subgraph. */
|
|
128
133
|
scopePath?: string;
|
|
129
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* The runtime shape returned from `createFirestoreEnterpriseBackend`.
|
|
137
|
+
*
|
|
138
|
+
* Extends `StorageBackend<FirestoreEnterpriseCapability>` with the
|
|
139
|
+
* `queryMode` field. The field always reflects the *effective* mode after
|
|
140
|
+
* emulator coercion, not the mode the caller requested. The public
|
|
141
|
+
* `GraphClient` surface does not expose the backend, so to introspect
|
|
142
|
+
* `queryMode` keep a reference to the backend before passing it to
|
|
143
|
+
* `createGraphClient`:
|
|
144
|
+
*
|
|
145
|
+
* ```ts
|
|
146
|
+
* const backend = createFirestoreEnterpriseBackend(db, 'firegraph', { defaultQueryMode: 'pipeline' });
|
|
147
|
+
* console.log(backend.queryMode);
|
|
148
|
+
* const client = createGraphClient(backend);
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
interface FirestoreEnterpriseBackend extends StorageBackend<FirestoreEnterpriseCapability> {
|
|
152
|
+
readonly queryMode: FirestoreEnterpriseQueryMode;
|
|
153
|
+
}
|
|
130
154
|
/**
|
|
131
155
|
* Create a Firestore Enterprise-edition `StorageBackend`.
|
|
132
156
|
*
|
|
133
|
-
* Pipeline mode is the default.
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
157
|
+
* Pipeline mode is the default. The legacy / standard-edition Firestore
|
|
158
|
+
* emulator does not execute pipelines, so the effective mode is coerced
|
|
159
|
+
* to `'classic'` whenever `FIRESTORE_EMULATOR_HOST` is set AND the caller
|
|
160
|
+
* has NOT opted into the enterprise-edition emulator via
|
|
161
|
+
* `FIRESTORE_EMULATOR_EDITION=enterprise` (case-insensitive). The opt-in
|
|
162
|
+
* env var mirrors firebase-tools v15.14+'s `--database-edition enterprise`
|
|
163
|
+
* (and `firestore.edition` in `firebase.json`); when set, pipelines work
|
|
164
|
+
* end-to-end against the local emulator without patching firegraph. If
|
|
165
|
+
* the caller explicitly asked for pipeline mode in a non-enterprise
|
|
166
|
+
* emulator, a one-time `console.warn` surfaces the override so the
|
|
167
|
+
* deployment mismatch is visible without breaking the test run.
|
|
138
168
|
*/
|
|
139
|
-
declare function createFirestoreEnterpriseBackend(db: Firestore, collectionPath: string, options?: FirestoreEnterpriseOptions):
|
|
169
|
+
declare function createFirestoreEnterpriseBackend(db: Firestore, collectionPath: string, options?: FirestoreEnterpriseOptions): FirestoreEnterpriseBackend;
|
|
140
170
|
|
|
141
|
-
export { type FirestoreEnterpriseCapability, type FirestoreEnterpriseOptions, type FirestoreEnterpriseQueryMode, createFirestoreEnterpriseBackend };
|
|
171
|
+
export { type FirestoreEnterpriseBackend, type FirestoreEnterpriseCapability, type FirestoreEnterpriseOptions, type FirestoreEnterpriseQueryMode, createFirestoreEnterpriseBackend };
|
|
@@ -92,10 +92,15 @@ interface FirestoreEnterpriseOptions {
|
|
|
92
92
|
* (search, aggregate, etc., once implemented) always use pipelines
|
|
93
93
|
* regardless of this option.
|
|
94
94
|
*
|
|
95
|
-
* The emulator does not execute
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
95
|
+
* The legacy / standard-edition Firestore emulator does not execute
|
|
96
|
+
* pipeline queries, so this option is coerced to `'classic'` whenever
|
|
97
|
+
* `FIRESTORE_EMULATOR_HOST` is set AND the caller has NOT opted into
|
|
98
|
+
* the enterprise-edition emulator via `FIRESTORE_EMULATOR_EDITION=enterprise`
|
|
99
|
+
* (case-insensitive). When that env var is set, the requested mode is
|
|
100
|
+
* honored end-to-end — pipelines work in firebase-tools v15.14+ with
|
|
101
|
+
* `--database-edition enterprise`. A one-time `console.warn` fires when
|
|
102
|
+
* the emulator forces the fallback after the caller explicitly asked for
|
|
103
|
+
* pipeline mode.
|
|
99
104
|
*/
|
|
100
105
|
defaultQueryMode?: FirestoreEnterpriseQueryMode;
|
|
101
106
|
/**
|
|
@@ -127,15 +132,40 @@ interface FirestoreEnterpriseOptions {
|
|
|
127
132
|
/** Internal: the logical scope path inherited from a parent subgraph. */
|
|
128
133
|
scopePath?: string;
|
|
129
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* The runtime shape returned from `createFirestoreEnterpriseBackend`.
|
|
137
|
+
*
|
|
138
|
+
* Extends `StorageBackend<FirestoreEnterpriseCapability>` with the
|
|
139
|
+
* `queryMode` field. The field always reflects the *effective* mode after
|
|
140
|
+
* emulator coercion, not the mode the caller requested. The public
|
|
141
|
+
* `GraphClient` surface does not expose the backend, so to introspect
|
|
142
|
+
* `queryMode` keep a reference to the backend before passing it to
|
|
143
|
+
* `createGraphClient`:
|
|
144
|
+
*
|
|
145
|
+
* ```ts
|
|
146
|
+
* const backend = createFirestoreEnterpriseBackend(db, 'firegraph', { defaultQueryMode: 'pipeline' });
|
|
147
|
+
* console.log(backend.queryMode);
|
|
148
|
+
* const client = createGraphClient(backend);
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
interface FirestoreEnterpriseBackend extends StorageBackend<FirestoreEnterpriseCapability> {
|
|
152
|
+
readonly queryMode: FirestoreEnterpriseQueryMode;
|
|
153
|
+
}
|
|
130
154
|
/**
|
|
131
155
|
* Create a Firestore Enterprise-edition `StorageBackend`.
|
|
132
156
|
*
|
|
133
|
-
* Pipeline mode is the default.
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
157
|
+
* Pipeline mode is the default. The legacy / standard-edition Firestore
|
|
158
|
+
* emulator does not execute pipelines, so the effective mode is coerced
|
|
159
|
+
* to `'classic'` whenever `FIRESTORE_EMULATOR_HOST` is set AND the caller
|
|
160
|
+
* has NOT opted into the enterprise-edition emulator via
|
|
161
|
+
* `FIRESTORE_EMULATOR_EDITION=enterprise` (case-insensitive). The opt-in
|
|
162
|
+
* env var mirrors firebase-tools v15.14+'s `--database-edition enterprise`
|
|
163
|
+
* (and `firestore.edition` in `firebase.json`); when set, pipelines work
|
|
164
|
+
* end-to-end against the local emulator without patching firegraph. If
|
|
165
|
+
* the caller explicitly asked for pipeline mode in a non-enterprise
|
|
166
|
+
* emulator, a one-time `console.warn` surfaces the override so the
|
|
167
|
+
* deployment mismatch is visible without breaking the test run.
|
|
138
168
|
*/
|
|
139
|
-
declare function createFirestoreEnterpriseBackend(db: Firestore, collectionPath: string, options?: FirestoreEnterpriseOptions):
|
|
169
|
+
declare function createFirestoreEnterpriseBackend(db: Firestore, collectionPath: string, options?: FirestoreEnterpriseOptions): FirestoreEnterpriseBackend;
|
|
140
170
|
|
|
141
|
-
export { type FirestoreEnterpriseCapability, type FirestoreEnterpriseOptions, type FirestoreEnterpriseQueryMode, createFirestoreEnterpriseBackend };
|
|
171
|
+
export { type FirestoreEnterpriseBackend, type FirestoreEnterpriseCapability, type FirestoreEnterpriseOptions, type FirestoreEnterpriseQueryMode, createFirestoreEnterpriseBackend };
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
compileEngineTraversal
|
|
3
3
|
} from "../chunk-D4J7Z4FE.js";
|
|
4
4
|
import {
|
|
5
|
+
buildFirestoreUpdateArgs,
|
|
5
6
|
bulkRemoveEdges,
|
|
6
7
|
createBatchAdapter,
|
|
7
8
|
createFirestoreAdapter,
|
|
@@ -11,10 +12,8 @@ import {
|
|
|
11
12
|
runFirestoreClassicExpand,
|
|
12
13
|
runFirestoreFindEdgesProjected,
|
|
13
14
|
runFirestoreFindNearest
|
|
14
|
-
} from "../chunk-
|
|
15
|
-
import
|
|
16
|
-
deserializeFirestoreTypes
|
|
17
|
-
} from "../chunk-C2QMD7RY.js";
|
|
15
|
+
} from "../chunk-DJI3VXXA.js";
|
|
16
|
+
import "../chunk-C2QMD7RY.js";
|
|
18
17
|
import {
|
|
19
18
|
createCapabilities
|
|
20
19
|
} from "../chunk-N5HFDWQX.js";
|
|
@@ -27,13 +26,11 @@ import {
|
|
|
27
26
|
createMergedRegistry,
|
|
28
27
|
createRegistry,
|
|
29
28
|
generateId
|
|
30
|
-
} from "../chunk-
|
|
29
|
+
} from "../chunk-3AHHXMWX.js";
|
|
31
30
|
import {
|
|
32
31
|
FiregraphError,
|
|
33
|
-
assertSafePath,
|
|
34
|
-
assertUpdatePayloadExclusive,
|
|
35
32
|
flattenPatch
|
|
36
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-SIHE4UY4.js";
|
|
37
34
|
import "../chunk-EQJUUVFG.js";
|
|
38
35
|
|
|
39
36
|
// src/firestore-enterprise/backend.ts
|
|
@@ -50,6 +47,13 @@ async function getFirestoreSurface() {
|
|
|
50
47
|
}
|
|
51
48
|
return { P: _Pipelines, Ts: _Timestamp };
|
|
52
49
|
}
|
|
50
|
+
var UNESCAPED_FIELD_NAME_RE = /^[_A-Za-z][_A-Za-z0-9]*$/;
|
|
51
|
+
function buildDataPathAlias(segments) {
|
|
52
|
+
const encoded = segments.map(
|
|
53
|
+
(seg) => UNESCAPED_FIELD_NAME_RE.test(seg) ? seg : "`" + seg.replace(/\\/g, "\\\\").replace(/`/g, "\\`") + "`"
|
|
54
|
+
);
|
|
55
|
+
return ["data", ...encoded].join(".");
|
|
56
|
+
}
|
|
53
57
|
function buildFilterExpression(P, filter) {
|
|
54
58
|
const { field: fieldName, op, value } = filter;
|
|
55
59
|
switch (op) {
|
|
@@ -127,7 +131,7 @@ async function runFirestorePipelineUpdate(db, collectionPath, filters, patch, _o
|
|
|
127
131
|
}
|
|
128
132
|
const { P, Ts } = await getFirestoreSurface();
|
|
129
133
|
const transforms = ops.map((op) => {
|
|
130
|
-
const alias =
|
|
134
|
+
const alias = buildDataPathAlias(op.path);
|
|
131
135
|
return P.constant(op.value).as(alias);
|
|
132
136
|
});
|
|
133
137
|
transforms.push(P.constant(Ts.now()).as("updatedAt"));
|
|
@@ -472,10 +476,13 @@ function decodeTree(rootRows, hops) {
|
|
|
472
476
|
}
|
|
473
477
|
async function runFirestoreEngineTraversal(db, collectionPath, params) {
|
|
474
478
|
if (process.env.FIRESTORE_EMULATOR_HOST) {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
+
const emulatorEdition = (process.env.FIRESTORE_EMULATOR_EDITION ?? "").trim().toLowerCase();
|
|
480
|
+
if (emulatorEdition !== "enterprise") {
|
|
481
|
+
throw new FiregraphError(
|
|
482
|
+
"engine traversal requires Pipelines \u2014 not supported on the default Firestore emulator. Run firebase-tools v15.14+ with `--database-edition enterprise` and set `FIRESTORE_EMULATOR_EDITION=enterprise` to opt in.",
|
|
483
|
+
"UNSUPPORTED_OPERATION"
|
|
484
|
+
);
|
|
485
|
+
}
|
|
479
486
|
}
|
|
480
487
|
const compiled = compileEngineTraversal(params);
|
|
481
488
|
if (!compiled.eligible) {
|
|
@@ -582,28 +589,6 @@ var ENTERPRISE_BASE_CAPS = /* @__PURE__ */ new Set([
|
|
|
582
589
|
var _emulatorFallbackWarned = false;
|
|
583
590
|
var _classicInProductionWarned = false;
|
|
584
591
|
var _previewDmlWarned = false;
|
|
585
|
-
function dottedDataPath(op) {
|
|
586
|
-
assertSafePath(op.path);
|
|
587
|
-
return `data.${op.path.join(".")}`;
|
|
588
|
-
}
|
|
589
|
-
function buildFirestoreUpdate(update, db) {
|
|
590
|
-
assertUpdatePayloadExclusive(update);
|
|
591
|
-
const out = {
|
|
592
|
-
updatedAt: FieldValue.serverTimestamp()
|
|
593
|
-
};
|
|
594
|
-
if (update.replaceData) {
|
|
595
|
-
out.data = deserializeFirestoreTypes(update.replaceData, db);
|
|
596
|
-
} else if (update.dataOps) {
|
|
597
|
-
for (const op of update.dataOps) {
|
|
598
|
-
const key = dottedDataPath(op);
|
|
599
|
-
out[key] = op.delete ? FieldValue.delete() : op.value;
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
if (update.v !== void 0) {
|
|
603
|
-
out.v = update.v;
|
|
604
|
-
}
|
|
605
|
-
return out;
|
|
606
|
-
}
|
|
607
592
|
function stampWritableRecord(record) {
|
|
608
593
|
const now = FieldValue.serverTimestamp();
|
|
609
594
|
const out = {
|
|
@@ -638,7 +623,7 @@ var FirestoreEnterpriseTransactionBackend = class {
|
|
|
638
623
|
);
|
|
639
624
|
}
|
|
640
625
|
async updateDoc(docId, update) {
|
|
641
|
-
this.adapter.updateDoc(docId,
|
|
626
|
+
this.adapter.updateDoc(docId, buildFirestoreUpdateArgs(update, this.db));
|
|
642
627
|
}
|
|
643
628
|
async deleteDoc(docId) {
|
|
644
629
|
this.adapter.deleteDoc(docId);
|
|
@@ -657,7 +642,7 @@ var FirestoreEnterpriseBatchBackend = class {
|
|
|
657
642
|
);
|
|
658
643
|
}
|
|
659
644
|
updateDoc(docId, update) {
|
|
660
|
-
this.adapter.updateDoc(docId,
|
|
645
|
+
this.adapter.updateDoc(docId, buildFirestoreUpdateArgs(update, this.db));
|
|
661
646
|
}
|
|
662
647
|
deleteDoc(docId) {
|
|
663
648
|
this.adapter.deleteDoc(docId);
|
|
@@ -669,8 +654,8 @@ var FirestoreEnterpriseBatchBackend = class {
|
|
|
669
654
|
var FirestoreEnterpriseBackendImpl = class _FirestoreEnterpriseBackendImpl {
|
|
670
655
|
constructor(db, collectionPath, queryMode, scopePath, previewDml) {
|
|
671
656
|
this.db = db;
|
|
672
|
-
this.queryMode = queryMode;
|
|
673
657
|
this.previewDml = previewDml;
|
|
658
|
+
this.queryMode = queryMode;
|
|
674
659
|
this.collectionPath = collectionPath;
|
|
675
660
|
this.scopePath = scopePath;
|
|
676
661
|
this.adapter = createFirestoreAdapter(db, collectionPath);
|
|
@@ -683,6 +668,7 @@ var FirestoreEnterpriseBackendImpl = class _FirestoreEnterpriseBackendImpl {
|
|
|
683
668
|
capabilities;
|
|
684
669
|
collectionPath;
|
|
685
670
|
scopePath;
|
|
671
|
+
queryMode;
|
|
686
672
|
adapter;
|
|
687
673
|
pipelineAdapter;
|
|
688
674
|
// --- Reads ---
|
|
@@ -704,7 +690,7 @@ var FirestoreEnterpriseBackendImpl = class _FirestoreEnterpriseBackendImpl {
|
|
|
704
690
|
);
|
|
705
691
|
}
|
|
706
692
|
updateDoc(docId, update) {
|
|
707
|
-
return this.adapter.updateDoc(docId,
|
|
693
|
+
return this.adapter.updateDoc(docId, buildFirestoreUpdateArgs(update, this.db));
|
|
708
694
|
}
|
|
709
695
|
deleteDoc(docId) {
|
|
710
696
|
return this.adapter.deleteDoc(docId);
|
|
@@ -944,11 +930,14 @@ var FirestoreEnterpriseBackendImpl = class _FirestoreEnterpriseBackendImpl {
|
|
|
944
930
|
function createFirestoreEnterpriseBackend(db, collectionPath, options = {}) {
|
|
945
931
|
const requestedMode = options.defaultQueryMode ?? "pipeline";
|
|
946
932
|
const isEmulator = !!process.env.FIRESTORE_EMULATOR_HOST;
|
|
947
|
-
const
|
|
948
|
-
|
|
933
|
+
const emulatorEdition = (process.env.FIRESTORE_EMULATOR_EDITION ?? "").trim().toLowerCase();
|
|
934
|
+
const emulatorIsEnterprise = emulatorEdition === "enterprise";
|
|
935
|
+
const emulatorForcesClassic = isEmulator && !emulatorIsEnterprise;
|
|
936
|
+
const effectiveMode = emulatorForcesClassic && requestedMode === "pipeline" ? "classic" : requestedMode;
|
|
937
|
+
if (emulatorForcesClassic && requestedMode === "pipeline" && effectiveMode === "classic" && !_emulatorFallbackWarned) {
|
|
949
938
|
_emulatorFallbackWarned = true;
|
|
950
939
|
console.warn(
|
|
951
|
-
"[firegraph] Firestore Enterprise pipeline mode is unavailable in the emulator; falling back to classic Query API for this run.
|
|
940
|
+
"[firegraph] Firestore Enterprise pipeline mode is unavailable in the default emulator; falling back to classic Query API for this run. If you are running firebase-tools v15.14+ with the enterprise-edition emulator (`firebase emulators:start --database-edition enterprise`), set `FIRESTORE_EMULATOR_EDITION=enterprise` in your environment to honor pipeline mode. Otherwise set `defaultQueryMode: 'classic'` to silence this warning."
|
|
952
941
|
);
|
|
953
942
|
}
|
|
954
943
|
if (!isEmulator && requestedMode === "classic" && !_classicInProductionWarned) {
|