@typicalday/firegraph 0.13.0 → 0.14.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.
@@ -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 pipeline queries, so this option is
96
- * forced to `'classic'` whenever `FIRESTORE_EMULATOR_HOST` is set, with
97
- * a one-time `console.warn` if the caller explicitly asked for pipeline
98
- * mode.
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. When `FIRESTORE_EMULATOR_HOST` is set the
134
- * effective mode is forced to `'classic'` because the emulator does not
135
- * execute pipelines; if the caller explicitly asked for pipeline mode in
136
- * that environment, a one-time `console.warn` surfaces the override so
137
- * the deployment mismatch is visible without breaking the test run.
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): StorageBackend<FirestoreEnterpriseCapability>;
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 pipeline queries, so this option is
96
- * forced to `'classic'` whenever `FIRESTORE_EMULATOR_HOST` is set, with
97
- * a one-time `console.warn` if the caller explicitly asked for pipeline
98
- * mode.
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. When `FIRESTORE_EMULATOR_HOST` is set the
134
- * effective mode is forced to `'classic'` because the emulator does not
135
- * execute pipelines; if the caller explicitly asked for pipeline mode in
136
- * that environment, a one-time `console.warn` surfaces the override so
137
- * the deployment mismatch is visible without breaking the test run.
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): StorageBackend<FirestoreEnterpriseCapability>;
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 };
@@ -472,10 +472,13 @@ function decodeTree(rootRows, hops) {
472
472
  }
473
473
  async function runFirestoreEngineTraversal(db, collectionPath, params) {
474
474
  if (process.env.FIRESTORE_EMULATOR_HOST) {
475
- throw new FiregraphError(
476
- "engine traversal requires Pipelines \u2014 not supported on the Firestore emulator",
477
- "UNSUPPORTED_OPERATION"
478
- );
475
+ const emulatorEdition = (process.env.FIRESTORE_EMULATOR_EDITION ?? "").trim().toLowerCase();
476
+ if (emulatorEdition !== "enterprise") {
477
+ throw new FiregraphError(
478
+ "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.",
479
+ "UNSUPPORTED_OPERATION"
480
+ );
481
+ }
479
482
  }
480
483
  const compiled = compileEngineTraversal(params);
481
484
  if (!compiled.eligible) {
@@ -669,8 +672,8 @@ var FirestoreEnterpriseBatchBackend = class {
669
672
  var FirestoreEnterpriseBackendImpl = class _FirestoreEnterpriseBackendImpl {
670
673
  constructor(db, collectionPath, queryMode, scopePath, previewDml) {
671
674
  this.db = db;
672
- this.queryMode = queryMode;
673
675
  this.previewDml = previewDml;
676
+ this.queryMode = queryMode;
674
677
  this.collectionPath = collectionPath;
675
678
  this.scopePath = scopePath;
676
679
  this.adapter = createFirestoreAdapter(db, collectionPath);
@@ -683,6 +686,7 @@ var FirestoreEnterpriseBackendImpl = class _FirestoreEnterpriseBackendImpl {
683
686
  capabilities;
684
687
  collectionPath;
685
688
  scopePath;
689
+ queryMode;
686
690
  adapter;
687
691
  pipelineAdapter;
688
692
  // --- Reads ---
@@ -944,11 +948,14 @@ var FirestoreEnterpriseBackendImpl = class _FirestoreEnterpriseBackendImpl {
944
948
  function createFirestoreEnterpriseBackend(db, collectionPath, options = {}) {
945
949
  const requestedMode = options.defaultQueryMode ?? "pipeline";
946
950
  const isEmulator = !!process.env.FIRESTORE_EMULATOR_HOST;
947
- const effectiveMode = isEmulator && requestedMode === "pipeline" ? "classic" : requestedMode;
948
- if (isEmulator && requestedMode === "pipeline" && effectiveMode === "classic" && !_emulatorFallbackWarned) {
951
+ const emulatorEdition = (process.env.FIRESTORE_EMULATOR_EDITION ?? "").trim().toLowerCase();
952
+ const emulatorIsEnterprise = emulatorEdition === "enterprise";
953
+ const emulatorForcesClassic = isEmulator && !emulatorIsEnterprise;
954
+ const effectiveMode = emulatorForcesClassic && requestedMode === "pipeline" ? "classic" : requestedMode;
955
+ if (emulatorForcesClassic && requestedMode === "pipeline" && effectiveMode === "classic" && !_emulatorFallbackWarned) {
949
956
  _emulatorFallbackWarned = true;
950
957
  console.warn(
951
- "[firegraph] Firestore Enterprise pipeline mode is unavailable in the emulator; falling back to classic Query API for this run. Set `defaultQueryMode: 'classic'` to silence this warning."
958
+ "[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
959
  );
953
960
  }
954
961
  if (!isEmulator && requestedMode === "classic" && !_classicInProductionWarned) {