@depup/firebase__data-connect 0.4.0-depup.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 (86) hide show
  1. package/README.md +31 -0
  2. package/changes.json +10 -0
  3. package/dist/index.cjs.js +2069 -0
  4. package/dist/index.cjs.js.map +1 -0
  5. package/dist/index.esm.js +2039 -0
  6. package/dist/index.esm.js.map +1 -0
  7. package/dist/index.node.cjs.js +2084 -0
  8. package/dist/index.node.cjs.js.map +1 -0
  9. package/dist/internal.d.ts +748 -0
  10. package/dist/node-esm/index.node.esm.js +2054 -0
  11. package/dist/node-esm/index.node.esm.js.map +1 -0
  12. package/dist/node-esm/package.json +1 -0
  13. package/dist/node-esm/src/api/DataConnect.d.ts +159 -0
  14. package/dist/node-esm/src/api/Mutation.d.ts +61 -0
  15. package/dist/node-esm/src/api/Reference.d.ts +53 -0
  16. package/dist/node-esm/src/api/index.d.ts +25 -0
  17. package/dist/node-esm/src/api/query.d.ts +71 -0
  18. package/dist/node-esm/src/api.browser.d.ts +18 -0
  19. package/dist/node-esm/src/api.node.d.ts +18 -0
  20. package/dist/node-esm/src/cache/Cache.d.ts +53 -0
  21. package/dist/node-esm/src/cache/CacheProvider.d.ts +25 -0
  22. package/dist/node-esm/src/cache/EntityDataObject.d.ts +37 -0
  23. package/dist/node-esm/src/cache/EntityNode.d.ts +56 -0
  24. package/dist/node-esm/src/cache/ImpactedQueryRefsAccumulator.d.ts +23 -0
  25. package/dist/node-esm/src/cache/InMemoryCacheProvider.d.ts +30 -0
  26. package/dist/node-esm/src/cache/ResultTree.d.ts +42 -0
  27. package/dist/node-esm/src/cache/ResultTreeProcessor.d.ts +40 -0
  28. package/dist/node-esm/src/cache/cacheUtils.d.ts +20 -0
  29. package/dist/node-esm/src/core/AppCheckTokenProvider.d.ts +31 -0
  30. package/dist/node-esm/src/core/FirebaseAuthProvider.d.ts +36 -0
  31. package/dist/node-esm/src/core/error.d.ts +53 -0
  32. package/dist/node-esm/src/core/query/QueryManager.d.ts +47 -0
  33. package/dist/node-esm/src/core/query/queryOptions.d.ts +25 -0
  34. package/dist/node-esm/src/core/query/subscribe.d.ts +67 -0
  35. package/dist/node-esm/src/core/version.d.ts +23 -0
  36. package/dist/node-esm/src/index.d.ts +29 -0
  37. package/dist/node-esm/src/index.node.d.ts +18 -0
  38. package/dist/node-esm/src/logger.d.ts +20 -0
  39. package/dist/node-esm/src/network/fetch.d.ts +24 -0
  40. package/dist/node-esm/src/network/index.d.ts +17 -0
  41. package/dist/node-esm/src/network/transport/index.d.ts +81 -0
  42. package/dist/node-esm/src/network/transport/rest.d.ts +49 -0
  43. package/dist/node-esm/src/register.d.ts +1 -0
  44. package/dist/node-esm/src/util/encoder.d.ts +22 -0
  45. package/dist/node-esm/src/util/map.d.ts +17 -0
  46. package/dist/node-esm/src/util/url.d.ts +20 -0
  47. package/dist/node-esm/src/util/validateArgs.d.ts +33 -0
  48. package/dist/private.d.ts +655 -0
  49. package/dist/public.d.ts +350 -0
  50. package/dist/src/api/DataConnect.d.ts +159 -0
  51. package/dist/src/api/Mutation.d.ts +61 -0
  52. package/dist/src/api/Reference.d.ts +53 -0
  53. package/dist/src/api/index.d.ts +25 -0
  54. package/dist/src/api/query.d.ts +71 -0
  55. package/dist/src/api.browser.d.ts +18 -0
  56. package/dist/src/api.node.d.ts +18 -0
  57. package/dist/src/cache/Cache.d.ts +53 -0
  58. package/dist/src/cache/CacheProvider.d.ts +25 -0
  59. package/dist/src/cache/EntityDataObject.d.ts +37 -0
  60. package/dist/src/cache/EntityNode.d.ts +56 -0
  61. package/dist/src/cache/ImpactedQueryRefsAccumulator.d.ts +23 -0
  62. package/dist/src/cache/InMemoryCacheProvider.d.ts +30 -0
  63. package/dist/src/cache/ResultTree.d.ts +42 -0
  64. package/dist/src/cache/ResultTreeProcessor.d.ts +40 -0
  65. package/dist/src/cache/cacheUtils.d.ts +20 -0
  66. package/dist/src/core/AppCheckTokenProvider.d.ts +31 -0
  67. package/dist/src/core/FirebaseAuthProvider.d.ts +36 -0
  68. package/dist/src/core/error.d.ts +53 -0
  69. package/dist/src/core/query/QueryManager.d.ts +47 -0
  70. package/dist/src/core/query/queryOptions.d.ts +25 -0
  71. package/dist/src/core/query/subscribe.d.ts +67 -0
  72. package/dist/src/core/version.d.ts +23 -0
  73. package/dist/src/index.d.ts +29 -0
  74. package/dist/src/index.node.d.ts +18 -0
  75. package/dist/src/logger.d.ts +20 -0
  76. package/dist/src/network/fetch.d.ts +24 -0
  77. package/dist/src/network/index.d.ts +17 -0
  78. package/dist/src/network/transport/index.d.ts +81 -0
  79. package/dist/src/network/transport/rest.d.ts +49 -0
  80. package/dist/src/register.d.ts +1 -0
  81. package/dist/src/tsdoc-metadata.json +11 -0
  82. package/dist/src/util/encoder.d.ts +22 -0
  83. package/dist/src/util/map.d.ts +17 -0
  84. package/dist/src/util/url.d.ts +20 -0
  85. package/dist/src/util/validateArgs.d.ts +33 -0
  86. package/package.json +99 -0
@@ -0,0 +1,2054 @@
1
+ import { FirebaseError, isCloudWorkstation, generateSHA256Hash, pingServer, updateEmulatorBanner } from '@firebase/util';
2
+ import { Logger } from '@firebase/logger';
3
+ import { _isFirebaseServerApp, _removeServiceInstance, getApp, _getProvider, _registerComponent, registerVersion, SDK_VERSION as SDK_VERSION$1 } from '@firebase/app';
4
+ import { Component } from '@firebase/component';
5
+
6
+ /**
7
+ * @license
8
+ * Copyright 2024 Google LLC
9
+ *
10
+ * Licensed under the Apache License, Version 2.0 (the "License");
11
+ * you may not use this file except in compliance with the License.
12
+ * You may obtain a copy of the License at
13
+ *
14
+ * http://www.apache.org/licenses/LICENSE-2.0
15
+ *
16
+ * Unless required by applicable law or agreed to in writing, software
17
+ * distributed under the License is distributed on an "AS IS" BASIS,
18
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ * See the License for the specific language governing permissions and
20
+ * limitations under the License.
21
+ */
22
+ const Code = {
23
+ OTHER: 'other',
24
+ ALREADY_INITIALIZED: 'already-initialized',
25
+ NOT_INITIALIZED: 'not-initialized',
26
+ NOT_SUPPORTED: 'not-supported',
27
+ INVALID_ARGUMENT: 'invalid-argument',
28
+ PARTIAL_ERROR: 'partial-error',
29
+ UNAUTHORIZED: 'unauthorized'
30
+ };
31
+ /** An error returned by a DataConnect operation. */
32
+ class DataConnectError extends FirebaseError {
33
+ constructor(code, message) {
34
+ super(code, message);
35
+ /** @internal */
36
+ this.name = 'DataConnectError';
37
+ // Ensure the instanceof operator works as expected on subclasses of Error.
38
+ // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#custom_error_types
39
+ // and https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget
40
+ Object.setPrototypeOf(this, DataConnectError.prototype);
41
+ }
42
+ /** @internal */
43
+ toString() {
44
+ return `${this.name}[code=${this.code}]: ${this.message}`;
45
+ }
46
+ }
47
+ /** An error returned by a DataConnect operation. */
48
+ class DataConnectOperationError extends DataConnectError {
49
+ /** @hideconstructor */
50
+ constructor(message, response) {
51
+ super(Code.PARTIAL_ERROR, message);
52
+ /** @internal */
53
+ this.name = 'DataConnectOperationError';
54
+ this.response = response;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * @license
60
+ * Copyright 2024 Google LLC
61
+ *
62
+ * Licensed under the Apache License, Version 2.0 (the "License");
63
+ * you may not use this file except in compliance with the License.
64
+ * You may obtain a copy of the License at
65
+ *
66
+ * http://www.apache.org/licenses/LICENSE-2.0
67
+ *
68
+ * Unless required by applicable law or agreed to in writing, software
69
+ * distributed under the License is distributed on an "AS IS" BASIS,
70
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
71
+ * See the License for the specific language governing permissions and
72
+ * limitations under the License.
73
+ */
74
+ /** The semver (www.semver.org) version of the SDK. */
75
+ let SDK_VERSION = '';
76
+ /**
77
+ * SDK_VERSION should be set before any database instance is created
78
+ * @internal
79
+ */
80
+ function setSDKVersion(version) {
81
+ SDK_VERSION = version;
82
+ }
83
+
84
+ /**
85
+ * @license
86
+ * Copyright 2024 Google LLC
87
+ *
88
+ * Licensed under the Apache License, Version 2.0 (the "License");
89
+ * you may not use this file except in compliance with the License.
90
+ * You may obtain a copy of the License at
91
+ *
92
+ * http://www.apache.org/licenses/LICENSE-2.0
93
+ *
94
+ * Unless required by applicable law or agreed to in writing, software
95
+ * distributed under the License is distributed on an "AS IS" BASIS,
96
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
97
+ * See the License for the specific language governing permissions and
98
+ * limitations under the License.
99
+ */
100
+ const logger = new Logger('@firebase/data-connect');
101
+ function setLogLevel(logLevel) {
102
+ logger.setLogLevel(logLevel);
103
+ }
104
+ function logDebug(msg) {
105
+ logger.debug(`DataConnect (${SDK_VERSION}): ${msg}`);
106
+ }
107
+ function logError(msg) {
108
+ logger.error(`DataConnect (${SDK_VERSION}): ${msg}`);
109
+ }
110
+
111
+ /**
112
+ * @license
113
+ * Copyright 2024 Google LLC
114
+ *
115
+ * Licensed under the Apache License, Version 2.0 (the "License");
116
+ * you may not use this file except in compliance with the License.
117
+ * You may obtain a copy of the License at
118
+ *
119
+ * http://www.apache.org/licenses/LICENSE-2.0
120
+ *
121
+ * Unless required by applicable law or agreed to in writing, software
122
+ * distributed under the License is distributed on an "AS IS" BASIS,
123
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124
+ * See the License for the specific language governing permissions and
125
+ * limitations under the License.
126
+ */
127
+ const CallerSdkTypeEnum = {
128
+ Base: 'Base', // Core JS SDK
129
+ Generated: 'Generated', // Generated JS SDK
130
+ TanstackReactCore: 'TanstackReactCore', // Tanstack non-generated React SDK
131
+ GeneratedReact: 'GeneratedReact', // Tanstack non-generated Angular SDK
132
+ TanstackAngularCore: 'TanstackAngularCore', // Tanstack non-generated Angular SDK
133
+ GeneratedAngular: 'GeneratedAngular' // Generated Angular SDK
134
+ };
135
+
136
+ /**
137
+ * @license
138
+ * Copyright 2024 Google LLC
139
+ *
140
+ * Licensed under the Apache License, Version 2.0 (the "License");
141
+ * you may not use this file except in compliance with the License.
142
+ * You may obtain a copy of the License at
143
+ *
144
+ * http://www.apache.org/licenses/LICENSE-2.0
145
+ *
146
+ * Unless required by applicable law or agreed to in writing, software
147
+ * distributed under the License is distributed on an "AS IS" BASIS,
148
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
149
+ * See the License for the specific language governing permissions and
150
+ * limitations under the License.
151
+ */
152
+ let connectFetch = globalThis.fetch;
153
+ function initializeFetch(fetchImpl) {
154
+ connectFetch = fetchImpl;
155
+ }
156
+ function getGoogApiClientValue(_isUsingGen, _callerSdkType) {
157
+ let str = 'gl-js/ fire/' + SDK_VERSION;
158
+ if (_callerSdkType !== CallerSdkTypeEnum.Base &&
159
+ _callerSdkType !== CallerSdkTypeEnum.Generated) {
160
+ str += ' js/' + _callerSdkType.toLowerCase();
161
+ }
162
+ else if (_isUsingGen || _callerSdkType === CallerSdkTypeEnum.Generated) {
163
+ str += ' js/gen';
164
+ }
165
+ return str;
166
+ }
167
+ async function dcFetch(url, body, { signal }, appId, accessToken, appCheckToken, _isUsingGen, _callerSdkType, _isUsingEmulator) {
168
+ if (!connectFetch) {
169
+ throw new DataConnectError(Code.OTHER, 'No Fetch Implementation detected!');
170
+ }
171
+ const headers = {
172
+ 'Content-Type': 'application/json',
173
+ 'X-Goog-Api-Client': getGoogApiClientValue(_isUsingGen, _callerSdkType)
174
+ };
175
+ if (accessToken) {
176
+ headers['X-Firebase-Auth-Token'] = accessToken;
177
+ }
178
+ if (appId) {
179
+ headers['x-firebase-gmpid'] = appId;
180
+ }
181
+ if (appCheckToken) {
182
+ headers['X-Firebase-AppCheck'] = appCheckToken;
183
+ }
184
+ const bodyStr = JSON.stringify(body);
185
+ const fetchOptions = {
186
+ body: bodyStr,
187
+ method: 'POST',
188
+ headers,
189
+ signal
190
+ };
191
+ if (isCloudWorkstation(url) && _isUsingEmulator) {
192
+ fetchOptions.credentials = 'include';
193
+ }
194
+ let response;
195
+ try {
196
+ response = await connectFetch(url, fetchOptions);
197
+ }
198
+ catch (err) {
199
+ throw new DataConnectError(Code.OTHER, 'Failed to fetch: ' + JSON.stringify(err));
200
+ }
201
+ let jsonResponse;
202
+ try {
203
+ jsonResponse = await response.json();
204
+ }
205
+ catch (e) {
206
+ throw new DataConnectError(Code.OTHER, JSON.stringify(e));
207
+ }
208
+ const message = getErrorMessage(jsonResponse);
209
+ if (response.status >= 400) {
210
+ logError('Error while performing request: ' + JSON.stringify(jsonResponse));
211
+ if (response.status === 401) {
212
+ throw new DataConnectError(Code.UNAUTHORIZED, message);
213
+ }
214
+ throw new DataConnectError(Code.OTHER, message);
215
+ }
216
+ if (jsonResponse.errors && jsonResponse.errors.length) {
217
+ const stringified = JSON.stringify(jsonResponse.errors);
218
+ const failureResponse = {
219
+ errors: jsonResponse.errors,
220
+ data: jsonResponse.data
221
+ };
222
+ throw new DataConnectOperationError('DataConnect error while performing request: ' + stringified, failureResponse);
223
+ }
224
+ if (!jsonResponse.extensions) {
225
+ jsonResponse.extensions = {
226
+ dataConnect: []
227
+ };
228
+ }
229
+ return jsonResponse;
230
+ }
231
+ function getErrorMessage(obj) {
232
+ if ('message' in obj && obj.message) {
233
+ return obj.message;
234
+ }
235
+ return JSON.stringify(obj);
236
+ }
237
+
238
+ const name = "@firebase/data-connect";
239
+ const version = "0.4.0";
240
+
241
+ /**
242
+ * @license
243
+ * Copyright 2025 Google LLC
244
+ *
245
+ * Licensed under the Apache License, Version 2.0 (the "License");
246
+ * you may not use this file except in compliance with the License.
247
+ * You may obtain a copy of the License at
248
+ *
249
+ * http://www.apache.org/licenses/LICENSE-2.0
250
+ *
251
+ * Unless required by applicable law or agreed to in writing, software
252
+ * distributed under the License is distributed on an "AS IS" BASIS,
253
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
254
+ * See the License for the specific language governing permissions and
255
+ * limitations under the License.
256
+ */
257
+ class EntityDataObject {
258
+ getServerValue(key) {
259
+ return this.serverValues[key];
260
+ }
261
+ constructor(globalID) {
262
+ this.globalID = globalID;
263
+ this.serverValues = {};
264
+ this.referencedFrom = new Set();
265
+ }
266
+ getServerValues() {
267
+ return this.serverValues;
268
+ }
269
+ toJSON() {
270
+ return {
271
+ globalID: this.globalID,
272
+ map: this.serverValues,
273
+ referencedFrom: Array.from(this.referencedFrom)
274
+ };
275
+ }
276
+ static fromJSON(json) {
277
+ const edo = new EntityDataObject(json.globalID);
278
+ edo.serverValues = json.map;
279
+ edo.referencedFrom = new Set(json.referencedFrom);
280
+ return edo;
281
+ }
282
+ updateServerValue(key, value, requestedFrom) {
283
+ this.serverValues[key] = value;
284
+ this.referencedFrom.add(requestedFrom);
285
+ return Array.from(this.referencedFrom);
286
+ }
287
+ }
288
+
289
+ /**
290
+ * @license
291
+ * Copyright 2025 Google LLC
292
+ *
293
+ * Licensed under the Apache License, Version 2.0 (the "License");
294
+ * you may not use this file except in compliance with the License.
295
+ * You may obtain a copy of the License at
296
+ *
297
+ * http://www.apache.org/licenses/LICENSE-2.0
298
+ *
299
+ * Unless required by applicable law or agreed to in writing, software
300
+ * distributed under the License is distributed on an "AS IS" BASIS,
301
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
302
+ * See the License for the specific language governing permissions and
303
+ * limitations under the License.
304
+ */
305
+ class InMemoryCacheProvider {
306
+ constructor(_keyId) {
307
+ this._keyId = _keyId;
308
+ this.edos = new Map();
309
+ this.resultTrees = new Map();
310
+ }
311
+ async setResultTree(queryId, rt) {
312
+ this.resultTrees.set(queryId, rt);
313
+ }
314
+ async getResultTree(queryId) {
315
+ return this.resultTrees.get(queryId);
316
+ }
317
+ async updateEntityData(entityData) {
318
+ this.edos.set(entityData.globalID, entityData);
319
+ }
320
+ async getEntityData(globalId) {
321
+ if (!this.edos.has(globalId)) {
322
+ this.edos.set(globalId, new EntityDataObject(globalId));
323
+ }
324
+ // Because of the above, we can guarantee that there will be an EDO at the globalId.
325
+ return this.edos.get(globalId);
326
+ }
327
+ close() {
328
+ // No-op
329
+ return Promise.resolve();
330
+ }
331
+ }
332
+
333
+ /**
334
+ * @license
335
+ * Copyright 2025 Google LLC
336
+ *
337
+ * Licensed under the Apache License, Version 2.0 (the "License");
338
+ * you may not use this file except in compliance with the License.
339
+ * You may obtain a copy of the License at
340
+ *
341
+ * http://www.apache.org/licenses/LICENSE-2.0
342
+ *
343
+ * Unless required by applicable law or agreed to in writing, software
344
+ * distributed under the License is distributed on an "AS IS" BASIS,
345
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
346
+ * See the License for the specific language governing permissions and
347
+ * limitations under the License.
348
+ */
349
+ const GLOBAL_ID_KEY = '_id';
350
+ const OBJECT_LISTS_KEY = '_objectLists';
351
+ const REFERENCES_KEY = '_references';
352
+ const SCALARS_KEY = '_scalars';
353
+ const ENTITY_DATA_KEYS_KEY = '_entity_data_keys';
354
+ class EntityNode {
355
+ constructor() {
356
+ this.scalars = {};
357
+ this.references = {};
358
+ this.objectLists = {};
359
+ this.entityDataKeys = new Set();
360
+ }
361
+ async loadData(queryId, values, entityIds, acc, cacheProvider) {
362
+ if (values === undefined) {
363
+ return;
364
+ }
365
+ if (typeof values !== 'object' || Array.isArray(values)) {
366
+ throw new DataConnectError(Code.INVALID_ARGUMENT, 'EntityNode initialized with non-object value');
367
+ }
368
+ if (values === null) {
369
+ return;
370
+ }
371
+ if (typeof values === 'object' &&
372
+ entityIds &&
373
+ entityIds[GLOBAL_ID_KEY] &&
374
+ typeof entityIds[GLOBAL_ID_KEY] === 'string') {
375
+ this.globalId = entityIds[GLOBAL_ID_KEY];
376
+ this.entityData = await cacheProvider.getEntityData(this.globalId);
377
+ }
378
+ for (const key in values) {
379
+ if (values.hasOwnProperty(key)) {
380
+ if (typeof values[key] === 'object') {
381
+ if (Array.isArray(values[key])) {
382
+ const ids = entityIds && entityIds[key];
383
+ const objArray = [];
384
+ const scalarArray = [];
385
+ for (const [index, value] of values[key].entries()) {
386
+ if (typeof value === 'object') {
387
+ if (Array.isArray(value)) ;
388
+ else {
389
+ const entityNode = new EntityNode();
390
+ await entityNode.loadData(queryId, value, ids && ids[index], acc, cacheProvider);
391
+ objArray.push(entityNode);
392
+ }
393
+ }
394
+ else {
395
+ scalarArray.push(value);
396
+ }
397
+ }
398
+ if (scalarArray.length > 0 && objArray.length > 0) {
399
+ this.scalars[key] = values[key];
400
+ }
401
+ else if (scalarArray.length > 0) {
402
+ if (this.entityData) {
403
+ const impactedRefs = this.entityData.updateServerValue(key, scalarArray, queryId);
404
+ this.entityDataKeys.add(key);
405
+ acc.add(impactedRefs);
406
+ }
407
+ else {
408
+ this.scalars[key] = scalarArray;
409
+ }
410
+ }
411
+ else if (objArray.length > 0) {
412
+ this.objectLists[key] = objArray;
413
+ }
414
+ else {
415
+ this.scalars[key] = [];
416
+ }
417
+ }
418
+ else {
419
+ if (values[key] === null) {
420
+ this.scalars[key] = null;
421
+ continue;
422
+ }
423
+ const entityNode = new EntityNode();
424
+ // TODO: Load Data might need to be pushed into ResultTreeProcessor instead.
425
+ await entityNode.loadData(queryId, values[key], entityIds && entityIds[key], acc, cacheProvider);
426
+ this.references[key] = entityNode;
427
+ }
428
+ }
429
+ else {
430
+ if (this.entityData) {
431
+ const impactedRefs = this.entityData.updateServerValue(key, values[key], queryId);
432
+ this.entityDataKeys.add(key);
433
+ acc.add(impactedRefs);
434
+ }
435
+ else {
436
+ this.scalars[key] = values[key];
437
+ }
438
+ }
439
+ }
440
+ }
441
+ if (this.entityData) {
442
+ await cacheProvider.updateEntityData(this.entityData);
443
+ }
444
+ }
445
+ toJSON(mode) {
446
+ const resultObject = {};
447
+ if (mode === EncodingMode.hydrated) {
448
+ if (this.entityData) {
449
+ for (const key of this.entityDataKeys) {
450
+ resultObject[key] = this.entityData.getServerValue(key);
451
+ }
452
+ }
453
+ if (this.scalars) {
454
+ Object.assign(resultObject, this.scalars);
455
+ }
456
+ if (this.references) {
457
+ for (const key in this.references) {
458
+ if (this.references.hasOwnProperty(key)) {
459
+ resultObject[key] = this.references[key].toJSON(mode);
460
+ }
461
+ }
462
+ }
463
+ if (this.objectLists) {
464
+ for (const key in this.objectLists) {
465
+ if (this.objectLists.hasOwnProperty(key)) {
466
+ resultObject[key] = this.objectLists[key].map(obj => obj.toJSON(mode));
467
+ }
468
+ }
469
+ }
470
+ return resultObject;
471
+ }
472
+ else {
473
+ // Get JSON representation of dehydrated list
474
+ if (this.entityData) {
475
+ resultObject[GLOBAL_ID_KEY] = this.entityData.globalID;
476
+ }
477
+ resultObject[ENTITY_DATA_KEYS_KEY] = Array.from(this.entityDataKeys);
478
+ if (this.scalars) {
479
+ resultObject[SCALARS_KEY] = this.scalars;
480
+ }
481
+ if (this.references) {
482
+ const references = {};
483
+ for (const key in this.references) {
484
+ if (this.references.hasOwnProperty(key)) {
485
+ references[key] = this.references[key].toJSON(mode);
486
+ }
487
+ }
488
+ resultObject[REFERENCES_KEY] = references;
489
+ }
490
+ if (this.objectLists) {
491
+ const objectLists = {};
492
+ for (const key in this.objectLists) {
493
+ if (this.objectLists.hasOwnProperty(key)) {
494
+ objectLists[key] = this.objectLists[key].map(obj => obj.toJSON(mode));
495
+ }
496
+ }
497
+ resultObject[OBJECT_LISTS_KEY] = objectLists;
498
+ }
499
+ }
500
+ return resultObject;
501
+ }
502
+ static fromJson(obj) {
503
+ const sdo = new EntityNode();
504
+ if (obj.backingData) {
505
+ sdo.entityData = EntityDataObject.fromJSON(obj.backingData);
506
+ }
507
+ sdo.globalId = obj.globalID;
508
+ sdo.scalars = obj.scalars;
509
+ if (obj.references) {
510
+ const references = {};
511
+ for (const key in obj.references) {
512
+ if (obj.references.hasOwnProperty(key)) {
513
+ references[key] = EntityNode.fromJson(obj.references[key]);
514
+ }
515
+ }
516
+ sdo.references = references;
517
+ }
518
+ if (obj.objectLists) {
519
+ const objectLists = {};
520
+ for (const key in obj.objectLists) {
521
+ if (obj.objectLists.hasOwnProperty(key)) {
522
+ objectLists[key] = obj.objectLists[key].map(obj => EntityNode.fromJson(obj));
523
+ }
524
+ }
525
+ sdo.objectLists = objectLists;
526
+ }
527
+ return sdo;
528
+ }
529
+ }
530
+ // Helpful for storing in persistent cache, which is not available yet.
531
+ var EncodingMode;
532
+ (function (EncodingMode) {
533
+ EncodingMode[EncodingMode["hydrated"] = 0] = "hydrated";
534
+ EncodingMode[EncodingMode["dehydrated"] = 1] = "dehydrated";
535
+ })(EncodingMode || (EncodingMode = {}));
536
+
537
+ /**
538
+ * @license
539
+ * Copyright 2025 Google LLC
540
+ *
541
+ * Licensed under the Apache License, Version 2.0 (the "License");
542
+ * you may not use this file except in compliance with the License.
543
+ * You may obtain a copy of the License at
544
+ *
545
+ * http://www.apache.org/licenses/LICENSE-2.0
546
+ *
547
+ * Unless required by applicable law or agreed to in writing, software
548
+ * distributed under the License is distributed on an "AS IS" BASIS,
549
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
550
+ * See the License for the specific language governing permissions and
551
+ * limitations under the License.
552
+ */
553
+ class ResultTree {
554
+ /**
555
+ * Create a {@link ResultTree} from a dehydrated JSON object.
556
+ * @param value The dehydrated JSON object.
557
+ * @returns The {@link ResultTree}.
558
+ */
559
+ static fromJson(value) {
560
+ return new ResultTree(EntityNode.fromJson(value.rootStub), value.maxAge, value.cachedAt, value.lastAccessed);
561
+ }
562
+ constructor(rootStub, maxAge = 0, cachedAt, _lastAccessed) {
563
+ this.rootStub = rootStub;
564
+ this.maxAge = maxAge;
565
+ this.cachedAt = cachedAt;
566
+ this._lastAccessed = _lastAccessed;
567
+ }
568
+ isStale() {
569
+ return (Date.now() - new Date(this.cachedAt.getTime()).getTime() >
570
+ this.maxAge * 1000);
571
+ }
572
+ updateMaxAge(maxAgeInSeconds) {
573
+ this.maxAge = maxAgeInSeconds;
574
+ }
575
+ updateAccessed() {
576
+ this._lastAccessed = new Date();
577
+ }
578
+ get lastAccessed() {
579
+ return this._lastAccessed;
580
+ }
581
+ getRootStub() {
582
+ return this.rootStub;
583
+ }
584
+ }
585
+
586
+ /**
587
+ * @license
588
+ * Copyright 2025 Google LLC
589
+ *
590
+ * Licensed under the Apache License, Version 2.0 (the "License");
591
+ * you may not use this file except in compliance with the License.
592
+ * You may obtain a copy of the License at
593
+ *
594
+ * http://www.apache.org/licenses/LICENSE-2.0
595
+ *
596
+ * Unless required by applicable law or agreed to in writing, software
597
+ * distributed under the License is distributed on an "AS IS" BASIS,
598
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
599
+ * See the License for the specific language governing permissions and
600
+ * limitations under the License.
601
+ */
602
+ class ImpactedQueryRefsAccumulator {
603
+ constructor(queryId) {
604
+ this.queryId = queryId;
605
+ this.impacted = new Set();
606
+ }
607
+ add(impacted) {
608
+ impacted
609
+ .filter(ref => ref !== this.queryId)
610
+ .forEach(ref => this.impacted.add(ref));
611
+ }
612
+ consumeEvents() {
613
+ const events = Array.from(this.impacted);
614
+ this.impacted.clear();
615
+ return events;
616
+ }
617
+ }
618
+
619
+ /**
620
+ * @license
621
+ * Copyright 2025 Google LLC
622
+ *
623
+ * Licensed under the Apache License, Version 2.0 (the "License");
624
+ * you may not use this file except in compliance with the License.
625
+ * You may obtain a copy of the License at
626
+ *
627
+ * http://www.apache.org/licenses/LICENSE-2.0
628
+ *
629
+ * Unless required by applicable law or agreed to in writing, software
630
+ * distributed under the License is distributed on an "AS IS" BASIS,
631
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
632
+ * See the License for the specific language governing permissions and
633
+ * limitations under the License.
634
+ */
635
+ class ResultTreeProcessor {
636
+ /**
637
+ * Hydrate the EntityNode into a JSON object so that it can be returned to the user.
638
+ * @param rootStubObject
639
+ * @returns {string}
640
+ */
641
+ hydrateResults(rootStubObject) {
642
+ return rootStubObject.toJSON(EncodingMode.hydrated);
643
+ }
644
+ /**
645
+ * Dehydrate results so that they can be stored in the cache.
646
+ * @param json
647
+ * @param entityIds
648
+ * @param cacheProvider
649
+ * @param queryId
650
+ * @returns {Promise<DehydratedResults>}
651
+ */
652
+ async dehydrateResults(json, entityIds, cacheProvider, queryId) {
653
+ const acc = new ImpactedQueryRefsAccumulator(queryId);
654
+ const entityNode = new EntityNode();
655
+ await entityNode.loadData(queryId, json, entityIds, acc, cacheProvider);
656
+ return {
657
+ entityNode,
658
+ impacted: acc.consumeEvents()
659
+ };
660
+ }
661
+ }
662
+
663
+ /**
664
+ * @license
665
+ * Copyright 2025 Google LLC
666
+ *
667
+ * Licensed under the Apache License, Version 2.0 (the "License");
668
+ * you may not use this file except in compliance with the License.
669
+ * You may obtain a copy of the License at
670
+ *
671
+ * http://www.apache.org/licenses/LICENSE-2.0
672
+ *
673
+ * Unless required by applicable law or agreed to in writing, software
674
+ * distributed under the License is distributed on an "AS IS" BASIS,
675
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
676
+ * See the License for the specific language governing permissions and
677
+ * limitations under the License.
678
+ */
679
+ class DataConnectCache {
680
+ constructor(authProvider, projectId, connectorConfig, host, cacheSettings) {
681
+ this.authProvider = authProvider;
682
+ this.projectId = projectId;
683
+ this.connectorConfig = connectorConfig;
684
+ this.host = host;
685
+ this.cacheSettings = cacheSettings;
686
+ this.cacheProvider = null;
687
+ this.uid = null;
688
+ this.authProvider.addTokenChangeListener(async (_) => {
689
+ const newUid = this.authProvider.getAuth().getUid();
690
+ // We should only close if the token changes and so does the new UID
691
+ if (this.uid !== newUid) {
692
+ this.cacheProvider?.close();
693
+ this.uid = newUid;
694
+ const identifier = await this.getIdentifier(this.uid);
695
+ this.cacheProvider = this.initializeNewProviders(identifier);
696
+ }
697
+ });
698
+ }
699
+ async initialize() {
700
+ if (!this.cacheProvider) {
701
+ const identifier = await this.getIdentifier(this.uid);
702
+ this.cacheProvider = this.initializeNewProviders(identifier);
703
+ }
704
+ }
705
+ async getIdentifier(uid) {
706
+ const identifier = `${'memory' // TODO: replace this with indexeddb when persistence is available.
707
+ }-${this.projectId}-${this.connectorConfig.service}-${this.connectorConfig.connector}-${this.connectorConfig.location}-${uid}-${this.host}`;
708
+ const sha256 = await generateSHA256Hash(identifier);
709
+ return sha256;
710
+ }
711
+ initializeNewProviders(identifier) {
712
+ return this.cacheSettings.cacheProvider.initialize(identifier);
713
+ }
714
+ async containsResultTree(queryId) {
715
+ await this.initialize();
716
+ const resultTree = await this.cacheProvider.getResultTree(queryId);
717
+ return resultTree !== undefined;
718
+ }
719
+ async getResultTree(queryId) {
720
+ await this.initialize();
721
+ return this.cacheProvider.getResultTree(queryId);
722
+ }
723
+ async getResultJSON(queryId) {
724
+ await this.initialize();
725
+ const processor = new ResultTreeProcessor();
726
+ const cacheProvider = this.cacheProvider;
727
+ const resultTree = await cacheProvider.getResultTree(queryId);
728
+ if (!resultTree) {
729
+ throw new DataConnectError(Code.INVALID_ARGUMENT, `${queryId} not found in cache. Call "update()" first.`);
730
+ }
731
+ return processor.hydrateResults(resultTree.getRootStub());
732
+ }
733
+ async update(queryId, serverValues, entityIds) {
734
+ await this.initialize();
735
+ const processor = new ResultTreeProcessor();
736
+ const cacheProvider = this.cacheProvider;
737
+ const { entityNode: stubDataObject, impacted } = await processor.dehydrateResults(serverValues, entityIds, cacheProvider, queryId);
738
+ const now = new Date();
739
+ await cacheProvider.setResultTree(queryId, new ResultTree(stubDataObject, serverValues.maxAge || this.cacheSettings.maxAgeSeconds, now, now));
740
+ return impacted;
741
+ }
742
+ }
743
+ class MemoryStub {
744
+ constructor() {
745
+ this.type = 'MEMORY';
746
+ }
747
+ /**
748
+ * @internal
749
+ */
750
+ initialize(cacheId) {
751
+ return new InMemoryCacheProvider(cacheId);
752
+ }
753
+ }
754
+
755
+ /**
756
+ * @license
757
+ * Copyright 2024 Google LLC
758
+ *
759
+ * Licensed under the Apache License, Version 2.0 (the "License");
760
+ * you may not use this file except in compliance with the License.
761
+ * You may obtain a copy of the License at
762
+ *
763
+ * http://www.apache.org/licenses/LICENSE-2.0
764
+ *
765
+ * Unless required by applicable law or agreed to in writing, software
766
+ * distributed under the License is distributed on an "AS IS" BASIS,
767
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
768
+ * See the License for the specific language governing permissions and
769
+ * limitations under the License.
770
+ */
771
+ /**
772
+ * @internal
773
+ * Abstraction around AppCheck's token fetching capabilities.
774
+ */
775
+ class AppCheckTokenProvider {
776
+ constructor(app, appCheckProvider) {
777
+ this.appCheckProvider = appCheckProvider;
778
+ if (_isFirebaseServerApp(app) && app.settings.appCheckToken) {
779
+ this.serverAppAppCheckToken = app.settings.appCheckToken;
780
+ }
781
+ this.appCheck = appCheckProvider?.getImmediate({ optional: true });
782
+ if (!this.appCheck) {
783
+ void appCheckProvider
784
+ ?.get()
785
+ .then(appCheck => (this.appCheck = appCheck))
786
+ .catch();
787
+ }
788
+ }
789
+ getToken() {
790
+ if (this.serverAppAppCheckToken) {
791
+ return Promise.resolve({ token: this.serverAppAppCheckToken });
792
+ }
793
+ if (!this.appCheck) {
794
+ return new Promise((resolve, reject) => {
795
+ // Support delayed initialization of FirebaseAppCheck. This allows our
796
+ // customers to initialize the RTDB SDK before initializing Firebase
797
+ // AppCheck and ensures that all requests are authenticated if a token
798
+ // becomes available before the timoeout below expires.
799
+ setTimeout(() => {
800
+ if (this.appCheck) {
801
+ this.getToken().then(resolve, reject);
802
+ }
803
+ else {
804
+ resolve(null);
805
+ }
806
+ }, 0);
807
+ });
808
+ }
809
+ return this.appCheck.getToken();
810
+ }
811
+ addTokenChangeListener(listener) {
812
+ void this.appCheckProvider
813
+ ?.get()
814
+ .then(appCheck => appCheck.addTokenListener(listener));
815
+ }
816
+ }
817
+
818
+ /**
819
+ * @license
820
+ * Copyright 2024 Google LLC
821
+ *
822
+ * Licensed under the Apache License, Version 2.0 (the "License");
823
+ * you may not use this file except in compliance with the License.
824
+ * You may obtain a copy of the License at
825
+ *
826
+ * http://www.apache.org/licenses/LICENSE-2.0
827
+ *
828
+ * Unless required by applicable law or agreed to in writing, software
829
+ * distributed under the License is distributed on an "AS IS" BASIS,
830
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
831
+ * See the License for the specific language governing permissions and
832
+ * limitations under the License.
833
+ */
834
+ // @internal
835
+ class FirebaseAuthProvider {
836
+ constructor(_appName, _options, _authProvider) {
837
+ this._appName = _appName;
838
+ this._options = _options;
839
+ this._authProvider = _authProvider;
840
+ this._auth = _authProvider.getImmediate({ optional: true });
841
+ if (!this._auth) {
842
+ _authProvider.onInit(auth => (this._auth = auth));
843
+ }
844
+ }
845
+ getAuth() {
846
+ return this._auth;
847
+ }
848
+ getToken(forceRefresh) {
849
+ if (!this._auth) {
850
+ return new Promise((resolve, reject) => {
851
+ setTimeout(() => {
852
+ if (this._auth) {
853
+ this.getToken(forceRefresh).then(resolve, reject);
854
+ }
855
+ else {
856
+ resolve(null);
857
+ }
858
+ }, 0);
859
+ });
860
+ }
861
+ return this._auth.getToken(forceRefresh).catch(error => {
862
+ if (error && error.code === 'auth/token-not-initialized') {
863
+ logDebug('Got auth/token-not-initialized error. Treating as null token.');
864
+ return null;
865
+ }
866
+ else {
867
+ logError('Error received when attempting to retrieve token: ' +
868
+ JSON.stringify(error));
869
+ return Promise.reject(error);
870
+ }
871
+ });
872
+ }
873
+ addTokenChangeListener(listener) {
874
+ this._auth?.addAuthTokenListener(listener);
875
+ }
876
+ removeTokenChangeListener(listener) {
877
+ this._authProvider
878
+ .get()
879
+ .then(auth => auth.removeAuthTokenListener(listener))
880
+ .catch(err => logError(err));
881
+ }
882
+ }
883
+
884
+ /**
885
+ * @license
886
+ * Copyright 2024 Google LLC
887
+ *
888
+ * Licensed under the Apache License, Version 2.0 (the "License");
889
+ * you may not use this file except in compliance with the License.
890
+ * You may obtain a copy of the License at
891
+ *
892
+ * http://www.apache.org/licenses/LICENSE-2.0
893
+ *
894
+ * Unless required by applicable law or agreed to in writing, software
895
+ * distributed under the License is distributed on an "AS IS" BASIS,
896
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
897
+ * See the License for the specific language governing permissions and
898
+ * limitations under the License.
899
+ */
900
+ const QUERY_STR = 'query';
901
+ const MUTATION_STR = 'mutation';
902
+ const SOURCE_SERVER = 'SERVER';
903
+ const SOURCE_CACHE = 'CACHE';
904
+
905
+ /**
906
+ * @license
907
+ * Copyright 2026 Google LLC
908
+ *
909
+ * Licensed under the Apache License, Version 2.0 (the "License");
910
+ * you may not use this file except in compliance with the License.
911
+ * You may obtain a copy of the License at
912
+ *
913
+ * http://www.apache.org/licenses/LICENSE-2.0
914
+ *
915
+ * Unless required by applicable law or agreed to in writing, software
916
+ * distributed under the License is distributed on an "AS IS" BASIS,
917
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
918
+ * See the License for the specific language governing permissions and
919
+ * limitations under the License.
920
+ */
921
+ function parseEntityIds(result) {
922
+ // Iterate through extensions.dataConnect
923
+ const dataConnectExtensions = result.extensions?.dataConnect;
924
+ const dataCopy = Object.assign(result);
925
+ if (!dataConnectExtensions) {
926
+ return dataCopy;
927
+ }
928
+ const ret = {};
929
+ for (const extension of dataConnectExtensions) {
930
+ const { path } = extension;
931
+ populatePath(path, ret, extension);
932
+ }
933
+ return ret;
934
+ }
935
+ // mutates the object to update the path
936
+ function populatePath(path, toUpdate, extension) {
937
+ let curObj = toUpdate;
938
+ for (const slice of path) {
939
+ if (typeof curObj[slice] !== 'object') {
940
+ curObj[slice] = {};
941
+ }
942
+ curObj = curObj[slice];
943
+ }
944
+ if ('entityId' in extension && extension.entityId) {
945
+ curObj['_id'] = extension.entityId;
946
+ }
947
+ else if ('entityIds' in extension) {
948
+ const entityArr = extension.entityIds;
949
+ for (let i = 0; i < entityArr.length; i++) {
950
+ const entityId = entityArr[i];
951
+ if (typeof curObj[i] === 'undefined') {
952
+ curObj[i] = {};
953
+ }
954
+ curObj[i]._id = entityId;
955
+ }
956
+ }
957
+ }
958
+
959
+ /**
960
+ * @license
961
+ * Copyright 2024 Google LLC
962
+ *
963
+ * Licensed under the Apache License, Version 2.0 (the "License");
964
+ * you may not use this file except in compliance with the License.
965
+ * You may obtain a copy of the License at
966
+ *
967
+ * http://www.apache.org/licenses/LICENSE-2.0
968
+ *
969
+ * Unless required by applicable law or agreed to in writing, software
970
+ * distributed under the License is distributed on an "AS IS" BASIS,
971
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
972
+ * See the License for the specific language governing permissions and
973
+ * limitations under the License.
974
+ */
975
+ let encoderImpl;
976
+ let decoderImpl;
977
+ function setEncoder(encoder) {
978
+ encoderImpl = encoder;
979
+ }
980
+ function setDecoder(decoder) {
981
+ decoderImpl = decoder;
982
+ }
983
+ function sortKeysForObj(o) {
984
+ return Object.keys(o)
985
+ .sort()
986
+ .reduce((accumulator, currentKey) => {
987
+ accumulator[currentKey] = o[currentKey];
988
+ return accumulator;
989
+ }, {});
990
+ }
991
+ setEncoder((o) => JSON.stringify(sortKeysForObj(o)));
992
+ setDecoder(s => sortKeysForObj(JSON.parse(s)));
993
+
994
+ /**
995
+ * @license
996
+ * Copyright 2024 Google LLC
997
+ *
998
+ * Licensed under the Apache License, Version 2.0 (the "License");
999
+ * you may not use this file except in compliance with the License.
1000
+ * You may obtain a copy of the License at
1001
+ *
1002
+ * http://www.apache.org/licenses/LICENSE-2.0
1003
+ *
1004
+ * Unless required by applicable law or agreed to in writing, software
1005
+ * distributed under the License is distributed on an "AS IS" BASIS,
1006
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1007
+ * See the License for the specific language governing permissions and
1008
+ * limitations under the License.
1009
+ */
1010
+ function getRefSerializer(queryRef, data, source, fetchTime) {
1011
+ return function toJSON() {
1012
+ return {
1013
+ data,
1014
+ refInfo: {
1015
+ name: queryRef.name,
1016
+ variables: queryRef.variables,
1017
+ connectorConfig: {
1018
+ projectId: queryRef.dataConnect.app.options.projectId,
1019
+ ...queryRef.dataConnect.getSettings()
1020
+ }
1021
+ },
1022
+ fetchTime,
1023
+ source
1024
+ };
1025
+ };
1026
+ }
1027
+ class QueryManager {
1028
+ async preferCacheResults(queryRef, allowStale = false) {
1029
+ let cacheResult;
1030
+ try {
1031
+ cacheResult = await this.fetchCacheResults(queryRef, allowStale);
1032
+ }
1033
+ catch (e) {
1034
+ // Ignore the error and try to fetch from the server.
1035
+ }
1036
+ if (cacheResult) {
1037
+ return cacheResult;
1038
+ }
1039
+ return this.fetchServerResults(queryRef);
1040
+ }
1041
+ constructor(transport, dc, cache) {
1042
+ this.transport = transport;
1043
+ this.dc = dc;
1044
+ this.cache = cache;
1045
+ this.callbacks = new Map();
1046
+ this.subscriptionCache = new Map();
1047
+ this.queue = [];
1048
+ }
1049
+ async waitForQueuedWrites() {
1050
+ for (const promise of this.queue) {
1051
+ await promise;
1052
+ }
1053
+ this.queue = [];
1054
+ }
1055
+ updateSSR(updatedData) {
1056
+ this.queue.push(this.updateCache(updatedData).then(async (result) => this.publishCacheResultsToSubscribers(result, updatedData.fetchTime)));
1057
+ }
1058
+ async updateCache(result, extensions) {
1059
+ await this.waitForQueuedWrites();
1060
+ if (this.cache) {
1061
+ const entityIds = parseEntityIds(result);
1062
+ const updatedMaxAge = getMaxAgeFromExtensions(extensions);
1063
+ if (updatedMaxAge !== undefined) {
1064
+ this.cache.cacheSettings.maxAgeSeconds = updatedMaxAge;
1065
+ }
1066
+ return this.cache.update(encoderImpl({
1067
+ name: result.ref.name,
1068
+ variables: result.ref.variables,
1069
+ refType: QUERY_STR
1070
+ }), result.data, entityIds);
1071
+ }
1072
+ else {
1073
+ const key = encoderImpl({
1074
+ name: result.ref.name,
1075
+ variables: result.ref.variables,
1076
+ refType: QUERY_STR
1077
+ });
1078
+ this.subscriptionCache.set(key, result);
1079
+ return [key];
1080
+ }
1081
+ }
1082
+ addSubscription(queryRef, onResultCallback, onCompleteCallback, onErrorCallback, initialCache) {
1083
+ const key = encoderImpl({
1084
+ name: queryRef.name,
1085
+ variables: queryRef.variables,
1086
+ refType: QUERY_STR
1087
+ });
1088
+ const unsubscribe = () => {
1089
+ if (this.callbacks.has(key)) {
1090
+ const callbackList = this.callbacks.get(key);
1091
+ this.callbacks.set(key, callbackList.filter(callback => callback !== subscription));
1092
+ onCompleteCallback?.();
1093
+ }
1094
+ };
1095
+ const subscription = {
1096
+ userCallback: onResultCallback,
1097
+ errCallback: onErrorCallback,
1098
+ unsubscribe
1099
+ };
1100
+ if (initialCache) {
1101
+ this.updateSSR(initialCache);
1102
+ }
1103
+ const promise = this.preferCacheResults(queryRef, /*allowStale=*/ true);
1104
+ // We want to ignore the error and let subscriptions handle it
1105
+ promise.then(undefined, err => { });
1106
+ if (!this.callbacks.has(key)) {
1107
+ this.callbacks.set(key, []);
1108
+ }
1109
+ this.callbacks
1110
+ .get(key)
1111
+ .push(subscription);
1112
+ return unsubscribe;
1113
+ }
1114
+ async fetchServerResults(queryRef) {
1115
+ await this.waitForQueuedWrites();
1116
+ const key = encoderImpl({
1117
+ name: queryRef.name,
1118
+ variables: queryRef.variables,
1119
+ refType: QUERY_STR
1120
+ });
1121
+ try {
1122
+ const result = await this.transport.invokeQuery(queryRef.name, queryRef.variables);
1123
+ const fetchTime = Date.now().toString();
1124
+ const originalExtensions = result.extensions;
1125
+ const queryResult = {
1126
+ ...result,
1127
+ ref: queryRef,
1128
+ source: SOURCE_SERVER,
1129
+ fetchTime,
1130
+ data: result.data,
1131
+ extensions: getDataConnectExtensionsWithoutMaxAge(originalExtensions),
1132
+ toJSON: getRefSerializer(queryRef, result.data, SOURCE_SERVER, fetchTime)
1133
+ };
1134
+ let updatedKeys = [];
1135
+ updatedKeys = await this.updateCache(queryResult, originalExtensions?.dataConnect);
1136
+ this.publishDataToSubscribers(key, queryResult);
1137
+ if (this.cache) {
1138
+ await this.publishCacheResultsToSubscribers(updatedKeys, fetchTime);
1139
+ }
1140
+ else {
1141
+ this.subscriptionCache.set(key, queryResult);
1142
+ }
1143
+ return queryResult;
1144
+ }
1145
+ catch (e) {
1146
+ this.publishErrorToSubscribers(key, e);
1147
+ throw e;
1148
+ }
1149
+ }
1150
+ async fetchCacheResults(queryRef, allowStale = false) {
1151
+ await this.waitForQueuedWrites();
1152
+ let result;
1153
+ if (!this.cache) {
1154
+ result = await this.getFromSubscriberCache(queryRef);
1155
+ }
1156
+ else {
1157
+ result = await this.getFromResultTreeCache(queryRef, allowStale);
1158
+ }
1159
+ if (!result) {
1160
+ throw new DataConnectError(Code.OTHER, 'No cache entry found for query: ' + queryRef.name);
1161
+ }
1162
+ const fetchTime = Date.now().toString();
1163
+ const queryResult = {
1164
+ ...result,
1165
+ ref: queryRef,
1166
+ source: SOURCE_CACHE,
1167
+ fetchTime,
1168
+ data: result.data,
1169
+ extensions: result.extensions,
1170
+ toJSON: getRefSerializer(queryRef, result.data, SOURCE_CACHE, fetchTime)
1171
+ };
1172
+ if (this.cache) {
1173
+ const key = encoderImpl({
1174
+ name: queryRef.name,
1175
+ variables: queryRef.variables,
1176
+ refType: QUERY_STR
1177
+ });
1178
+ await this.publishCacheResultsToSubscribers([key], fetchTime);
1179
+ }
1180
+ else {
1181
+ const key = encoderImpl({
1182
+ name: queryRef.name,
1183
+ variables: queryRef.variables,
1184
+ refType: QUERY_STR
1185
+ });
1186
+ this.subscriptionCache.set(key, queryResult);
1187
+ this.publishDataToSubscribers(key, queryResult);
1188
+ }
1189
+ return queryResult;
1190
+ }
1191
+ publishErrorToSubscribers(key, err) {
1192
+ this.callbacks.get(key)?.forEach(subscription => {
1193
+ if (subscription.errCallback) {
1194
+ subscription.errCallback(err);
1195
+ }
1196
+ });
1197
+ }
1198
+ async getFromResultTreeCache(queryRef, allowStale = false) {
1199
+ const key = encoderImpl({
1200
+ name: queryRef.name,
1201
+ variables: queryRef.variables,
1202
+ refType: QUERY_STR
1203
+ });
1204
+ if (!this.cache || !(await this.cache.containsResultTree(key))) {
1205
+ return null;
1206
+ }
1207
+ const cacheResult = (await this.cache.getResultJSON(key));
1208
+ const resultTree = await this.cache.getResultTree(key);
1209
+ if (!allowStale && resultTree.isStale()) {
1210
+ return null;
1211
+ }
1212
+ const result = {
1213
+ source: SOURCE_CACHE,
1214
+ ref: queryRef,
1215
+ data: cacheResult,
1216
+ toJSON: getRefSerializer(queryRef, cacheResult, SOURCE_CACHE, resultTree.cachedAt.toString()),
1217
+ fetchTime: resultTree.cachedAt.toString()
1218
+ };
1219
+ (await this.cache.getResultTree(key)).updateAccessed();
1220
+ return result;
1221
+ }
1222
+ async getFromSubscriberCache(queryRef) {
1223
+ const key = encoderImpl({
1224
+ name: queryRef.name,
1225
+ variables: queryRef.variables,
1226
+ refType: QUERY_STR
1227
+ });
1228
+ if (!this.subscriptionCache.has(key)) {
1229
+ return;
1230
+ }
1231
+ const result = this.subscriptionCache.get(key);
1232
+ result.source = SOURCE_CACHE;
1233
+ result.toJSON = getRefSerializer(result.ref, result.data, SOURCE_CACHE, result.fetchTime);
1234
+ return result;
1235
+ }
1236
+ publishDataToSubscribers(key, queryResult) {
1237
+ if (!this.callbacks.has(key)) {
1238
+ return;
1239
+ }
1240
+ const subscribers = this.callbacks.get(key);
1241
+ subscribers.forEach(callback => {
1242
+ callback.userCallback(queryResult);
1243
+ });
1244
+ }
1245
+ async publishCacheResultsToSubscribers(impactedQueries, fetchTime) {
1246
+ if (!this.cache) {
1247
+ return;
1248
+ }
1249
+ for (const query of impactedQueries) {
1250
+ const callbacks = this.callbacks.get(query);
1251
+ if (!callbacks) {
1252
+ continue;
1253
+ }
1254
+ const newJson = (await this.cache.getResultTree(query))
1255
+ .getRootStub()
1256
+ .toJSON(EncodingMode.hydrated);
1257
+ const { name, variables } = decoderImpl(query);
1258
+ const queryRef = {
1259
+ dataConnect: this.dc,
1260
+ refType: QUERY_STR,
1261
+ name,
1262
+ variables
1263
+ };
1264
+ this.publishDataToSubscribers(query, {
1265
+ data: newJson,
1266
+ fetchTime,
1267
+ ref: queryRef,
1268
+ source: SOURCE_CACHE,
1269
+ toJSON: getRefSerializer(queryRef, newJson, SOURCE_CACHE, fetchTime)
1270
+ });
1271
+ }
1272
+ }
1273
+ enableEmulator(host, port) {
1274
+ this.transport.useEmulator(host, port);
1275
+ }
1276
+ }
1277
+ function getMaxAgeFromExtensions(extensions) {
1278
+ if (!extensions) {
1279
+ return;
1280
+ }
1281
+ for (const extension of extensions) {
1282
+ if ('maxAge' in extension &&
1283
+ extension.maxAge !== undefined &&
1284
+ extension.maxAge !== null) {
1285
+ if (extension.maxAge.endsWith('s')) {
1286
+ return Number(extension.maxAge.substring(0, extension.maxAge.length - 1));
1287
+ }
1288
+ }
1289
+ }
1290
+ }
1291
+ function getDataConnectExtensionsWithoutMaxAge(extensions) {
1292
+ return {
1293
+ dataConnect: extensions.dataConnect?.filter(extension => 'entityId' in extension || 'entityIds' in extension)
1294
+ };
1295
+ }
1296
+
1297
+ /**
1298
+ * @license
1299
+ * Copyright 2024 Google LLC
1300
+ *
1301
+ * Licensed under the Apache License, Version 2.0 (the "License");
1302
+ * you may not use this file except in compliance with the License.
1303
+ * You may obtain a copy of the License at
1304
+ *
1305
+ * http://www.apache.org/licenses/LICENSE-2.0
1306
+ *
1307
+ * Unless required by applicable law or agreed to in writing, software
1308
+ * distributed under the License is distributed on an "AS IS" BASIS,
1309
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1310
+ * See the License for the specific language governing permissions and
1311
+ * limitations under the License.
1312
+ */
1313
+ const PROD_HOST = 'firebasedataconnect.googleapis.com';
1314
+ function urlBuilder(projectConfig, transportOptions) {
1315
+ const { connector, location, projectId: project, service } = projectConfig;
1316
+ const { host, sslEnabled, port } = transportOptions;
1317
+ const protocol = sslEnabled ? 'https' : 'http';
1318
+ const realHost = host || PROD_HOST;
1319
+ let baseUrl = `${protocol}://${realHost}`;
1320
+ if (typeof port === 'number') {
1321
+ baseUrl += `:${port}`;
1322
+ }
1323
+ else if (typeof port !== 'undefined') {
1324
+ logError('Port type is of an invalid type');
1325
+ throw new DataConnectError(Code.INVALID_ARGUMENT, 'Incorrect type for port passed in!');
1326
+ }
1327
+ return `${baseUrl}/v1/projects/${project}/locations/${location}/services/${service}/connectors/${connector}`;
1328
+ }
1329
+ function addToken(url, apiKey) {
1330
+ if (!apiKey) {
1331
+ return url;
1332
+ }
1333
+ const newUrl = new URL(url);
1334
+ newUrl.searchParams.append('key', apiKey);
1335
+ return newUrl.toString();
1336
+ }
1337
+
1338
+ /**
1339
+ * @license
1340
+ * Copyright 2024 Google LLC
1341
+ *
1342
+ * Licensed under the Apache License, Version 2.0 (the "License");
1343
+ * you may not use this file except in compliance with the License.
1344
+ * You may obtain a copy of the License at
1345
+ *
1346
+ * http://www.apache.org/licenses/LICENSE-2.0
1347
+ *
1348
+ * Unless required by applicable law or agreed to in writing, software
1349
+ * distributed under the License is distributed on an "AS IS" BASIS,
1350
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351
+ * See the License for the specific language governing permissions and
1352
+ * limitations under the License.
1353
+ */
1354
+ class RESTTransport {
1355
+ constructor(options, apiKey, appId, authProvider, appCheckProvider, transportOptions, _isUsingGen = false, _callerSdkType = CallerSdkTypeEnum.Base) {
1356
+ this.apiKey = apiKey;
1357
+ this.appId = appId;
1358
+ this.authProvider = authProvider;
1359
+ this.appCheckProvider = appCheckProvider;
1360
+ this._isUsingGen = _isUsingGen;
1361
+ this._callerSdkType = _callerSdkType;
1362
+ this._host = '';
1363
+ this._location = 'l';
1364
+ this._connectorName = '';
1365
+ this._secure = true;
1366
+ this._project = 'p';
1367
+ this._accessToken = null;
1368
+ this._appCheckToken = null;
1369
+ this._lastToken = null;
1370
+ this._isUsingEmulator = false;
1371
+ // TODO(mtewani): Update U to include shape of body defined in line 13.
1372
+ this.invokeQuery = (queryName, body) => {
1373
+ const abortController = new AbortController();
1374
+ // TODO(mtewani): Update to proper value
1375
+ const withAuth = this.withRetry(() => dcFetch(addToken(`${this.endpointUrl}:executeQuery`, this.apiKey), {
1376
+ name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`,
1377
+ operationName: queryName,
1378
+ variables: body
1379
+ }, abortController, this.appId, this._accessToken, this._appCheckToken, this._isUsingGen, this._callerSdkType, this._isUsingEmulator));
1380
+ return withAuth;
1381
+ };
1382
+ this.invokeMutation = (mutationName, body) => {
1383
+ const abortController = new AbortController();
1384
+ const taskResult = this.withRetry(() => {
1385
+ return dcFetch(addToken(`${this.endpointUrl}:executeMutation`, this.apiKey), {
1386
+ name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`,
1387
+ operationName: mutationName,
1388
+ variables: body
1389
+ }, abortController, this.appId, this._accessToken, this._appCheckToken, this._isUsingGen, this._callerSdkType, this._isUsingEmulator);
1390
+ });
1391
+ return taskResult;
1392
+ };
1393
+ if (transportOptions) {
1394
+ if (typeof transportOptions.port === 'number') {
1395
+ this._port = transportOptions.port;
1396
+ }
1397
+ if (typeof transportOptions.sslEnabled !== 'undefined') {
1398
+ this._secure = transportOptions.sslEnabled;
1399
+ }
1400
+ this._host = transportOptions.host;
1401
+ }
1402
+ const { location, projectId: project, connector, service } = options;
1403
+ if (location) {
1404
+ this._location = location;
1405
+ }
1406
+ if (project) {
1407
+ this._project = project;
1408
+ }
1409
+ this._serviceName = service;
1410
+ if (!connector) {
1411
+ throw new DataConnectError(Code.INVALID_ARGUMENT, 'Connector Name required!');
1412
+ }
1413
+ this._connectorName = connector;
1414
+ this.authProvider?.addTokenChangeListener(token => {
1415
+ logDebug(`New Token Available: ${token}`);
1416
+ this._accessToken = token;
1417
+ });
1418
+ this.appCheckProvider?.addTokenChangeListener(result => {
1419
+ const { token } = result;
1420
+ logDebug(`New App Check Token Available: ${token}`);
1421
+ this._appCheckToken = token;
1422
+ });
1423
+ }
1424
+ get endpointUrl() {
1425
+ return urlBuilder({
1426
+ connector: this._connectorName,
1427
+ location: this._location,
1428
+ projectId: this._project,
1429
+ service: this._serviceName
1430
+ }, { host: this._host, sslEnabled: this._secure, port: this._port });
1431
+ }
1432
+ useEmulator(host, port, isSecure) {
1433
+ this._host = host;
1434
+ this._isUsingEmulator = true;
1435
+ if (typeof port === 'number') {
1436
+ this._port = port;
1437
+ }
1438
+ if (typeof isSecure !== 'undefined') {
1439
+ this._secure = isSecure;
1440
+ }
1441
+ }
1442
+ onTokenChanged(newToken) {
1443
+ this._accessToken = newToken;
1444
+ }
1445
+ async getWithAuth(forceToken = false) {
1446
+ let starterPromise = new Promise(resolve => resolve(this._accessToken));
1447
+ if (this.appCheckProvider) {
1448
+ const appCheckToken = await this.appCheckProvider.getToken();
1449
+ if (appCheckToken) {
1450
+ this._appCheckToken = appCheckToken.token;
1451
+ }
1452
+ }
1453
+ if (this.authProvider) {
1454
+ starterPromise = this.authProvider
1455
+ .getToken(/*forceToken=*/ forceToken)
1456
+ .then(data => {
1457
+ if (!data) {
1458
+ return null;
1459
+ }
1460
+ this._accessToken = data.accessToken;
1461
+ return this._accessToken;
1462
+ });
1463
+ }
1464
+ else {
1465
+ starterPromise = new Promise(resolve => resolve(''));
1466
+ }
1467
+ return starterPromise;
1468
+ }
1469
+ _setLastToken(lastToken) {
1470
+ this._lastToken = lastToken;
1471
+ }
1472
+ withRetry(promiseFactory, retry = false) {
1473
+ let isNewToken = false;
1474
+ return this.getWithAuth(retry)
1475
+ .then(res => {
1476
+ isNewToken = this._lastToken !== res;
1477
+ this._lastToken = res;
1478
+ return res;
1479
+ })
1480
+ .then(promiseFactory)
1481
+ .catch(err => {
1482
+ // Only retry if the result is unauthorized and the last token isn't the same as the new one.
1483
+ if ('code' in err &&
1484
+ err.code === Code.UNAUTHORIZED &&
1485
+ !retry &&
1486
+ isNewToken) {
1487
+ logDebug('Retrying due to unauthorized');
1488
+ return this.withRetry(promiseFactory, true);
1489
+ }
1490
+ throw err;
1491
+ });
1492
+ }
1493
+ _setCallerSdkType(callerSdkType) {
1494
+ this._callerSdkType = callerSdkType;
1495
+ }
1496
+ }
1497
+
1498
+ /**
1499
+ * @license
1500
+ * Copyright 2024 Google LLC
1501
+ *
1502
+ * Licensed under the Apache License, Version 2.0 (the "License");
1503
+ * you may not use this file except in compliance with the License.
1504
+ * You may obtain a copy of the License at
1505
+ *
1506
+ * http://www.apache.org/licenses/LICENSE-2.0
1507
+ *
1508
+ * Unless required by applicable law or agreed to in writing, software
1509
+ * distributed under the License is distributed on an "AS IS" BASIS,
1510
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1511
+ * See the License for the specific language governing permissions and
1512
+ * limitations under the License.
1513
+ */
1514
+ /**
1515
+ *
1516
+ * @param dcInstance Data Connect instance
1517
+ * @param mutationName name of mutation
1518
+ * @param variables variables to send with mutation
1519
+ * @returns `MutationRef`
1520
+ */
1521
+ function mutationRef(dcInstance, mutationName, variables) {
1522
+ dcInstance.setInitialized();
1523
+ const ref = {
1524
+ dataConnect: dcInstance,
1525
+ name: mutationName,
1526
+ refType: MUTATION_STR,
1527
+ variables: variables
1528
+ };
1529
+ return ref;
1530
+ }
1531
+ /**
1532
+ * @internal
1533
+ */
1534
+ class MutationManager {
1535
+ constructor(_transport) {
1536
+ this._transport = _transport;
1537
+ this._inflight = [];
1538
+ }
1539
+ executeMutation(mutationRef) {
1540
+ const result = this._transport.invokeMutation(mutationRef.name, mutationRef.variables);
1541
+ const withRefPromise = result.then(res => {
1542
+ const obj = {
1543
+ ...res, // Double check that the result is result.data, not just result
1544
+ source: SOURCE_SERVER,
1545
+ ref: mutationRef,
1546
+ fetchTime: Date.now().toLocaleString()
1547
+ };
1548
+ return obj;
1549
+ });
1550
+ this._inflight.push(result);
1551
+ const removePromise = () => (this._inflight = this._inflight.filter(promise => promise !== result));
1552
+ result.then(removePromise, removePromise);
1553
+ return withRefPromise;
1554
+ }
1555
+ }
1556
+ /**
1557
+ * Execute Mutation
1558
+ * @param mutationRef mutation to execute
1559
+ * @returns `MutationRef`
1560
+ */
1561
+ function executeMutation(mutationRef) {
1562
+ return mutationRef.dataConnect._mutationManager.executeMutation(mutationRef);
1563
+ }
1564
+
1565
+ /**
1566
+ * @license
1567
+ * Copyright 2024 Google LLC
1568
+ *
1569
+ * Licensed under the Apache License, Version 2.0 (the "License");
1570
+ * you may not use this file except in compliance with the License.
1571
+ * You may obtain a copy of the License at
1572
+ *
1573
+ * http://www.apache.org/licenses/LICENSE-2.0
1574
+ *
1575
+ * Unless required by applicable law or agreed to in writing, software
1576
+ * distributed under the License is distributed on an "AS IS" BASIS,
1577
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1578
+ * See the License for the specific language governing permissions and
1579
+ * limitations under the License.
1580
+ */
1581
+ const FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR = 'FIREBASE_DATA_CONNECT_EMULATOR_HOST';
1582
+ /**
1583
+ *
1584
+ * @param fullHost
1585
+ * @returns TransportOptions
1586
+ * @internal
1587
+ */
1588
+ function parseOptions(fullHost) {
1589
+ const [protocol, hostName] = fullHost.split('://');
1590
+ const isSecure = protocol === 'https';
1591
+ const [host, portAsString] = hostName.split(':');
1592
+ const port = Number(portAsString);
1593
+ return { host, port, sslEnabled: isSecure };
1594
+ }
1595
+ /**
1596
+ * Class representing Firebase Data Connect
1597
+ */
1598
+ class DataConnect {
1599
+ // @internal
1600
+ constructor(app,
1601
+ // TODO(mtewani): Replace with _dataConnectOptions in the future
1602
+ dataConnectOptions, _authProvider, _appCheckProvider) {
1603
+ this.app = app;
1604
+ this.dataConnectOptions = dataConnectOptions;
1605
+ this._authProvider = _authProvider;
1606
+ this._appCheckProvider = _appCheckProvider;
1607
+ this.isEmulator = false;
1608
+ this._initialized = false;
1609
+ this._isUsingGeneratedSdk = false;
1610
+ this._callerSdkType = CallerSdkTypeEnum.Base;
1611
+ if (typeof process !== 'undefined' && process.env) {
1612
+ const host = process.env[FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR];
1613
+ if (host) {
1614
+ logDebug('Found custom host. Using emulator');
1615
+ this.isEmulator = true;
1616
+ this._transportOptions = parseOptions(host);
1617
+ }
1618
+ }
1619
+ }
1620
+ /**
1621
+ * @internal
1622
+ */
1623
+ getCache() {
1624
+ return this.cache;
1625
+ }
1626
+ // @internal
1627
+ _useGeneratedSdk() {
1628
+ if (!this._isUsingGeneratedSdk) {
1629
+ this._isUsingGeneratedSdk = true;
1630
+ }
1631
+ }
1632
+ _setCallerSdkType(callerSdkType) {
1633
+ this._callerSdkType = callerSdkType;
1634
+ if (this._initialized) {
1635
+ this._transport._setCallerSdkType(callerSdkType);
1636
+ }
1637
+ }
1638
+ _delete() {
1639
+ _removeServiceInstance(this.app, 'data-connect', JSON.stringify(this.getSettings()));
1640
+ return Promise.resolve();
1641
+ }
1642
+ // @internal
1643
+ getSettings() {
1644
+ const copy = JSON.parse(JSON.stringify(this.dataConnectOptions));
1645
+ delete copy.projectId;
1646
+ return copy;
1647
+ }
1648
+ /**
1649
+ * @internal
1650
+ */
1651
+ setCacheSettings(cacheSettings) {
1652
+ this._cacheSettings = cacheSettings;
1653
+ }
1654
+ // @internal
1655
+ setInitialized() {
1656
+ if (this._initialized) {
1657
+ return;
1658
+ }
1659
+ if (this._transportClass === undefined) {
1660
+ logDebug('transportClass not provided. Defaulting to RESTTransport.');
1661
+ this._transportClass = RESTTransport;
1662
+ }
1663
+ this._authTokenProvider = new FirebaseAuthProvider(this.app.name, this.app.options, this._authProvider);
1664
+ const connectorConfig = {
1665
+ connector: this.dataConnectOptions.connector,
1666
+ service: this.dataConnectOptions.service,
1667
+ location: this.dataConnectOptions.location
1668
+ };
1669
+ if (this._cacheSettings) {
1670
+ this.cache = new DataConnectCache(this._authTokenProvider, this.app.options.projectId, connectorConfig, this._transportOptions?.host || PROD_HOST, this._cacheSettings);
1671
+ }
1672
+ if (this._appCheckProvider) {
1673
+ this._appCheckTokenProvider = new AppCheckTokenProvider(this.app, this._appCheckProvider);
1674
+ }
1675
+ this._transport = new this._transportClass(this.dataConnectOptions, this.app.options.apiKey, this.app.options.appId, this._authTokenProvider, this._appCheckTokenProvider, undefined, this._isUsingGeneratedSdk, this._callerSdkType);
1676
+ if (this._transportOptions) {
1677
+ this._transport.useEmulator(this._transportOptions.host, this._transportOptions.port, this._transportOptions.sslEnabled);
1678
+ }
1679
+ this._queryManager = new QueryManager(this._transport, this, this.cache);
1680
+ this._mutationManager = new MutationManager(this._transport);
1681
+ this._initialized = true;
1682
+ }
1683
+ // @internal
1684
+ enableEmulator(transportOptions) {
1685
+ if (this._transportOptions &&
1686
+ this._initialized &&
1687
+ !areTransportOptionsEqual(this._transportOptions, transportOptions)) {
1688
+ logError('enableEmulator called after initialization');
1689
+ throw new DataConnectError(Code.ALREADY_INITIALIZED, 'DataConnect instance already initialized!');
1690
+ }
1691
+ this._transportOptions = transportOptions;
1692
+ this.isEmulator = true;
1693
+ }
1694
+ }
1695
+ /**
1696
+ * @internal
1697
+ * @param transportOptions1
1698
+ * @param transportOptions2
1699
+ * @returns
1700
+ */
1701
+ function areTransportOptionsEqual(transportOptions1, transportOptions2) {
1702
+ return (transportOptions1.host === transportOptions2.host &&
1703
+ transportOptions1.port === transportOptions2.port &&
1704
+ transportOptions1.sslEnabled === transportOptions2.sslEnabled);
1705
+ }
1706
+ /**
1707
+ * Connect to the DataConnect Emulator
1708
+ * @param dc Data Connect instance
1709
+ * @param host host of emulator server
1710
+ * @param port port of emulator server
1711
+ * @param sslEnabled use https
1712
+ */
1713
+ function connectDataConnectEmulator(dc, host, port, sslEnabled = false) {
1714
+ // Workaround to get cookies in Firebase Studio
1715
+ if (isCloudWorkstation(host)) {
1716
+ void pingServer(`https://${host}${port ? `:${port}` : ''}`);
1717
+ updateEmulatorBanner('Data Connect', true);
1718
+ }
1719
+ dc.enableEmulator({ host, port, sslEnabled });
1720
+ }
1721
+ function getDataConnect(appOrConnectorConfig, settingsOrConnectorConfig, settings) {
1722
+ let app;
1723
+ let connectorConfig;
1724
+ let realSettings;
1725
+ if ('location' in appOrConnectorConfig) {
1726
+ connectorConfig = appOrConnectorConfig;
1727
+ app = getApp();
1728
+ realSettings = settingsOrConnectorConfig;
1729
+ }
1730
+ else {
1731
+ app = appOrConnectorConfig;
1732
+ connectorConfig = settingsOrConnectorConfig;
1733
+ realSettings = settings;
1734
+ }
1735
+ if (!app || Object.keys(app).length === 0) {
1736
+ app = getApp();
1737
+ }
1738
+ // Options to store in Firebase Component Provider.
1739
+ const serializedOptions = {
1740
+ ...connectorConfig,
1741
+ projectId: app.options.projectId
1742
+ };
1743
+ // We should sort the keys before initialization.
1744
+ const sortedSerialized = Object.fromEntries(Object.entries(serializedOptions).sort());
1745
+ const provider = _getProvider(app, 'data-connect');
1746
+ const identifier = JSON.stringify(sortedSerialized);
1747
+ if (provider.isInitialized(identifier)) {
1748
+ const dcInstance = provider.getImmediate({ identifier });
1749
+ const options = provider.getOptions(identifier);
1750
+ const optionsValid = Object.keys(options).length > 0;
1751
+ if (optionsValid) {
1752
+ logDebug('Re-using cached instance');
1753
+ return dcInstance;
1754
+ }
1755
+ }
1756
+ validateDCOptions(connectorConfig);
1757
+ logDebug('Creating new DataConnect instance');
1758
+ // Initialize with options.
1759
+ const dataConnect = provider.initialize({
1760
+ instanceIdentifier: identifier,
1761
+ options: Object.fromEntries(Object.entries({
1762
+ ...sortedSerialized
1763
+ }).sort())
1764
+ });
1765
+ if (realSettings?.cacheSettings) {
1766
+ dataConnect.setCacheSettings(realSettings.cacheSettings);
1767
+ }
1768
+ return dataConnect;
1769
+ }
1770
+ /**
1771
+ *
1772
+ * @param dcOptions
1773
+ * @returns {void}
1774
+ * @internal
1775
+ */
1776
+ function validateDCOptions(dcOptions) {
1777
+ const fields = ['connector', 'location', 'service'];
1778
+ if (!dcOptions) {
1779
+ throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required');
1780
+ }
1781
+ fields.forEach(field => {
1782
+ if (dcOptions[field] === null ||
1783
+ dcOptions[field] === undefined) {
1784
+ throw new DataConnectError(Code.INVALID_ARGUMENT, `${field} Required`);
1785
+ }
1786
+ });
1787
+ return true;
1788
+ }
1789
+ /**
1790
+ * Delete DataConnect instance
1791
+ * @param dataConnect DataConnect instance
1792
+ * @returns
1793
+ */
1794
+ function terminate(dataConnect) {
1795
+ return dataConnect._delete();
1796
+ // TODO(mtewani): Stop pending tasks
1797
+ }
1798
+ const StorageType = {
1799
+ MEMORY: 'MEMORY'
1800
+ };
1801
+ function makeMemoryCacheProvider() {
1802
+ return new MemoryStub();
1803
+ }
1804
+
1805
+ /**
1806
+ * @license
1807
+ * Copyright 2024 Google LLC
1808
+ *
1809
+ * Licensed under the Apache License, Version 2.0 (the "License");
1810
+ * you may not use this file except in compliance with the License.
1811
+ * You may obtain a copy of the License at
1812
+ *
1813
+ * http://www.apache.org/licenses/LICENSE-2.0
1814
+ *
1815
+ * Unless required by applicable law or agreed to in writing, software
1816
+ * distributed under the License is distributed on an "AS IS" BASIS,
1817
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1818
+ * See the License for the specific language governing permissions and
1819
+ * limitations under the License.
1820
+ */
1821
+ function registerDataConnect(variant) {
1822
+ setSDKVersion(SDK_VERSION$1);
1823
+ _registerComponent(new Component('data-connect', (container, { instanceIdentifier: connectorConfigStr, options }) => {
1824
+ const app = container.getProvider('app').getImmediate();
1825
+ const authProvider = container.getProvider('auth-internal');
1826
+ const appCheckProvider = container.getProvider('app-check-internal');
1827
+ let newOpts = options;
1828
+ if (connectorConfigStr) {
1829
+ newOpts = {
1830
+ ...JSON.parse(connectorConfigStr),
1831
+ ...newOpts
1832
+ };
1833
+ }
1834
+ if (!app.options.projectId) {
1835
+ throw new DataConnectError(Code.INVALID_ARGUMENT, 'Project ID must be provided. Did you pass in a proper projectId to initializeApp?');
1836
+ }
1837
+ return new DataConnect(app, { ...newOpts, projectId: app.options.projectId }, authProvider, appCheckProvider);
1838
+ }, "PUBLIC" /* ComponentType.PUBLIC */).setMultipleInstances(true));
1839
+ registerVersion(name, version, variant);
1840
+ // BUILD_TARGET will be replaced by values like esm, cjs, etc during the compilation
1841
+ registerVersion(name, version, 'esm2020');
1842
+ }
1843
+
1844
+ /**
1845
+ * @license
1846
+ * Copyright 2025 Google LLC
1847
+ *
1848
+ * Licensed under the Apache License, Version 2.0 (the "License");
1849
+ * you may not use this file except in compliance with the License.
1850
+ * You may obtain a copy of the License at
1851
+ *
1852
+ * http://www.apache.org/licenses/LICENSE-2.0
1853
+ *
1854
+ * Unless required by applicable law or agreed to in writing, software
1855
+ * distributed under the License is distributed on an "AS IS" BASIS,
1856
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1857
+ * See the License for the specific language governing permissions and
1858
+ * limitations under the License.
1859
+ */
1860
+ const QueryFetchPolicy = {
1861
+ PREFER_CACHE: 'PREFER_CACHE',
1862
+ CACHE_ONLY: 'CACHE_ONLY',
1863
+ SERVER_ONLY: 'SERVER_ONLY'
1864
+ };
1865
+
1866
+ /**
1867
+ * @license
1868
+ * Copyright 2024 Google LLC
1869
+ *
1870
+ * Licensed under the Apache License, Version 2.0 (the "License");
1871
+ * you may not use this file except in compliance with the License.
1872
+ * You may obtain a copy of the License at
1873
+ *
1874
+ * http://www.apache.org/licenses/LICENSE-2.0
1875
+ *
1876
+ * Unless required by applicable law or agreed to in writing, software
1877
+ * distributed under the License is distributed on an "AS IS" BASIS,
1878
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1879
+ * See the License for the specific language governing permissions and
1880
+ * limitations under the License.
1881
+ */
1882
+ /**
1883
+ * Execute Query
1884
+ * @param queryRef query to execute.
1885
+ * @returns `QueryPromise`
1886
+ */
1887
+ function executeQuery(queryRef, options) {
1888
+ if (queryRef.refType !== QUERY_STR) {
1889
+ return Promise.reject(new DataConnectError(Code.INVALID_ARGUMENT, `ExecuteQuery can only execute query operations`));
1890
+ }
1891
+ const queryManager = queryRef.dataConnect._queryManager;
1892
+ const fetchPolicy = options?.fetchPolicy ?? QueryFetchPolicy.PREFER_CACHE;
1893
+ switch (fetchPolicy) {
1894
+ case QueryFetchPolicy.SERVER_ONLY:
1895
+ return queryManager.fetchServerResults(queryRef);
1896
+ case QueryFetchPolicy.CACHE_ONLY:
1897
+ return queryManager.fetchCacheResults(queryRef, true);
1898
+ case QueryFetchPolicy.PREFER_CACHE:
1899
+ return queryManager.preferCacheResults(queryRef, false);
1900
+ default:
1901
+ throw new DataConnectError(Code.INVALID_ARGUMENT, `Invalid fetch policy: ${fetchPolicy}`);
1902
+ }
1903
+ }
1904
+ /**
1905
+ * Execute Query
1906
+ * @param dcInstance Data Connect instance to use.
1907
+ * @param queryName Query to execute
1908
+ * @param variables Variables to execute with
1909
+ * @param initialCache initial cache to use for client hydration
1910
+ * @returns `QueryRef`
1911
+ */
1912
+ function queryRef(dcInstance, queryName, variables, initialCache) {
1913
+ dcInstance.setInitialized();
1914
+ if (initialCache !== undefined) {
1915
+ dcInstance._queryManager.updateSSR(initialCache);
1916
+ }
1917
+ return {
1918
+ dataConnect: dcInstance,
1919
+ refType: QUERY_STR,
1920
+ name: queryName,
1921
+ variables: variables
1922
+ };
1923
+ }
1924
+ /**
1925
+ * Converts serialized ref to query ref
1926
+ * @param serializedRef ref to convert to `QueryRef`
1927
+ * @returns `QueryRef`
1928
+ */
1929
+ function toQueryRef(serializedRef) {
1930
+ const { refInfo: { name, variables, connectorConfig } } = serializedRef;
1931
+ return queryRef(getDataConnect(connectorConfig), name, variables);
1932
+ }
1933
+
1934
+ /**
1935
+ * @license
1936
+ * Copyright 2024 Google LLC
1937
+ *
1938
+ * Licensed under the Apache License, Version 2.0 (the "License");
1939
+ * you may not use this file except in compliance with the License.
1940
+ * You may obtain a copy of the License at
1941
+ *
1942
+ * http://www.apache.org/licenses/LICENSE-2.0
1943
+ *
1944
+ * Unless required by applicable law or agreed to in writing, software
1945
+ * distributed under the License is distributed on an "AS IS" BASIS,
1946
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1947
+ * See the License for the specific language governing permissions and
1948
+ * limitations under the License.
1949
+ */
1950
+ /**
1951
+ * The generated SDK will allow the user to pass in either the variable or the data connect instance with the variable,
1952
+ * and this function validates the variables and returns back the DataConnect instance and variables based on the arguments passed in.
1953
+ * @param connectorConfig
1954
+ * @param dcOrVars
1955
+ * @param vars
1956
+ * @param validateVars
1957
+ * @returns {DataConnect} and {Variables} instance
1958
+ * @internal
1959
+ */
1960
+ function validateArgs(connectorConfig, dcOrVars, vars, validateVars) {
1961
+ let dcInstance;
1962
+ let realVars;
1963
+ if (dcOrVars && 'enableEmulator' in dcOrVars) {
1964
+ dcInstance = dcOrVars;
1965
+ realVars = vars;
1966
+ }
1967
+ else {
1968
+ dcInstance = getDataConnect(connectorConfig);
1969
+ realVars = dcOrVars;
1970
+ }
1971
+ if (!dcInstance || (!realVars && validateVars)) {
1972
+ throw new DataConnectError(Code.INVALID_ARGUMENT, 'Variables required.');
1973
+ }
1974
+ return { dc: dcInstance, vars: realVars };
1975
+ }
1976
+
1977
+ /**
1978
+ * @license
1979
+ * Copyright 2025 Google LLC
1980
+ *
1981
+ * Licensed under the Apache License, Version 2.0 (the "License");
1982
+ * you may not use this file except in compliance with the License.
1983
+ * You may obtain a copy of the License at
1984
+ *
1985
+ * http://www.apache.org/licenses/LICENSE-2.0
1986
+ *
1987
+ * Unless required by applicable law or agreed to in writing, software
1988
+ * distributed under the License is distributed on an "AS IS" BASIS,
1989
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1990
+ * See the License for the specific language governing permissions and
1991
+ * limitations under the License.
1992
+ */
1993
+ /**
1994
+ * Subscribe to a `QueryRef`
1995
+ * @param queryRefOrSerializedResult query ref or serialized result.
1996
+ * @param observerOrOnNext observer object or next function.
1997
+ * @param onError Callback to call when error gets thrown.
1998
+ * @param onComplete Called when subscription completes.
1999
+ * @returns `SubscriptionOptions`
2000
+ */
2001
+ function subscribe(queryRefOrSerializedResult, observerOrOnNext, onError, onComplete) {
2002
+ let ref;
2003
+ let initialCache;
2004
+ if ('refInfo' in queryRefOrSerializedResult) {
2005
+ const serializedRef = queryRefOrSerializedResult;
2006
+ const { data, source, fetchTime } = serializedRef;
2007
+ ref = toQueryRef(serializedRef);
2008
+ initialCache = {
2009
+ data,
2010
+ source,
2011
+ fetchTime,
2012
+ ref,
2013
+ toJSON: getRefSerializer(ref, data, source, fetchTime)
2014
+ };
2015
+ }
2016
+ else {
2017
+ ref = queryRefOrSerializedResult;
2018
+ }
2019
+ let onResult = undefined;
2020
+ if (typeof observerOrOnNext === 'function') {
2021
+ onResult = observerOrOnNext;
2022
+ }
2023
+ else {
2024
+ onResult = observerOrOnNext.onNext;
2025
+ onError = observerOrOnNext.onErr;
2026
+ onComplete = observerOrOnNext.onComplete;
2027
+ }
2028
+ if (!onResult) {
2029
+ throw new DataConnectError(Code.INVALID_ARGUMENT, 'Must provide onNext');
2030
+ }
2031
+ return ref.dataConnect._queryManager.addSubscription(ref, onResult, onComplete, onError, initialCache);
2032
+ }
2033
+
2034
+ /**
2035
+ * @license
2036
+ * Copyright 2024 Google LLC
2037
+ *
2038
+ * Licensed under the Apache License, Version 2.0 (the "License");
2039
+ * you may not use this file except in compliance with the License.
2040
+ * You may obtain a copy of the License at
2041
+ *
2042
+ * http://www.apache.org/licenses/LICENSE-2.0
2043
+ *
2044
+ * Unless required by applicable law or agreed to in writing, software
2045
+ * distributed under the License is distributed on an "AS IS" BASIS,
2046
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2047
+ * See the License for the specific language governing permissions and
2048
+ * limitations under the License.
2049
+ */
2050
+ initializeFetch(fetch);
2051
+ registerDataConnect('node');
2052
+
2053
+ export { CallerSdkTypeEnum, Code, DataConnect, DataConnectError, DataConnectOperationError, MUTATION_STR, MutationManager, QUERY_STR, QueryFetchPolicy, SOURCE_CACHE, SOURCE_SERVER, StorageType, areTransportOptionsEqual, connectDataConnectEmulator, executeMutation, executeQuery, getDataConnect, makeMemoryCacheProvider, mutationRef, parseOptions, queryRef, setLogLevel, subscribe, terminate, toQueryRef, validateArgs, validateDCOptions };
2054
+ //# sourceMappingURL=index.node.esm.js.map