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