import { FirebaseError } from '@firebase/util'; import { Logger } from '@firebase/logger'; import { _removeServiceInstance, getApp, _getProvider, _registerComponent, registerVersion, SDK_VERSION as SDK_VERSION$1 } from '@firebase/app'; import { Component } from '@firebase/component'; /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const Code = { OTHER: 'other', ALREADY_INITIALIZED: 'already-initialized', NOT_INITIALIZED: 'not-initialized', NOT_SUPPORTED: 'not-supported', INVALID_ARGUMENT: 'invalid-argument', PARTIAL_ERROR: 'partial-error', UNAUTHORIZED: 'unauthorized' }; /** An error returned by a DataConnect operation. */ class DataConnectError extends FirebaseError { /** @hideconstructor */ constructor( /** * The backend error code associated with this error. */ code, /** * A custom error description. */ message) { super(code, message); this.code = code; this.message = message; // HACK: We write a toString property directly because Error is not a real // class and so inheritance does not work correctly. We could alternatively // do the same "back-door inheritance" trick that FirebaseError does. this.toString = () => `${this.name}: [code=${this.code}]: ${this.message}`; } } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** The semver (www.semver.org) version of the SDK. */ let SDK_VERSION = ''; /** * SDK_VERSION should be set before any database instance is created * @internal */ function setSDKVersion(version) { SDK_VERSION = version; } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const logger = new Logger('@firebase/data-connect'); function setLogLevel(logLevel) { logger.setLogLevel(logLevel); } function logDebug(msg) { logger.debug(`DataConnect (${SDK_VERSION}): ${msg}`); } function logError(msg) { logger.error(`DataConnect (${SDK_VERSION}): ${msg}`); } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ let connectFetch = globalThis.fetch; function initializeFetch(fetchImpl) { connectFetch = fetchImpl; } function getGoogApiClientValue(_isUsingGen) { let str = 'gl-js/ fire/' + SDK_VERSION; if (_isUsingGen) { str += ' js/gen'; } return str; } function dcFetch(url, body, { signal }, appId, accessToken, appCheckToken, _isUsingGen) { if (!connectFetch) { throw new DataConnectError(Code.OTHER, 'No Fetch Implementation detected!'); } const headers = { 'Content-Type': 'application/json', 'X-Goog-Api-Client': getGoogApiClientValue(_isUsingGen) }; if (accessToken) { headers['X-Firebase-Auth-Token'] = accessToken; } if (appId) { headers['x-firebase-gmpid'] = appId; } if (appCheckToken) { headers['X-Firebase-AppCheck'] = appCheckToken; } const bodyStr = JSON.stringify(body); logDebug(`Making request out to ${url} with body: ${bodyStr}`); return connectFetch(url, { body: bodyStr, method: 'POST', headers, signal }) .catch(err => { throw new DataConnectError(Code.OTHER, 'Failed to fetch: ' + JSON.stringify(err)); }) .then(async (response) => { let jsonResponse = null; try { jsonResponse = await response.json(); } catch (e) { throw new DataConnectError(Code.OTHER, JSON.stringify(e)); } const message = getMessage(jsonResponse); if (response.status >= 400) { logError('Error while performing request: ' + JSON.stringify(jsonResponse)); if (response.status === 401) { throw new DataConnectError(Code.UNAUTHORIZED, message); } throw new DataConnectError(Code.OTHER, message); } return jsonResponse; }) .then(res => { if (res.errors && res.errors.length) { const stringified = JSON.stringify(res.errors); logError('DataConnect error while performing request: ' + stringified); throw new DataConnectError(Code.OTHER, stringified); } return res; }); } function getMessage(obj) { if ('message' in obj) { return obj.message; } return JSON.stringify(obj); } const name = "@firebase/data-connect"; const version = "0.1.1"; /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @internal * Abstraction around AppCheck's token fetching capabilities. */ class AppCheckTokenProvider { constructor(appName_, appCheckProvider) { this.appName_ = appName_; this.appCheckProvider = appCheckProvider; this.appCheck = appCheckProvider === null || appCheckProvider === void 0 ? void 0 : appCheckProvider.getImmediate({ optional: true }); if (!this.appCheck) { void (appCheckProvider === null || appCheckProvider === void 0 ? void 0 : appCheckProvider.get().then(appCheck => (this.appCheck = appCheck)).catch()); } } getToken(forceRefresh) { if (!this.appCheck) { return new Promise((resolve, reject) => { // Support delayed initialization of FirebaseAppCheck. This allows our // customers to initialize the RTDB SDK before initializing Firebase // AppCheck and ensures that all requests are authenticated if a token // becomes available before the timoeout below expires. setTimeout(() => { if (this.appCheck) { this.getToken(forceRefresh).then(resolve, reject); } else { resolve(null); } }, 0); }); } return this.appCheck.getToken(forceRefresh); } addTokenChangeListener(listener) { var _a; void ((_a = this.appCheckProvider) === null || _a === void 0 ? void 0 : _a.get().then(appCheck => appCheck.addTokenListener(listener))); } } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // @internal class FirebaseAuthProvider { constructor(_appName, _options, _authProvider) { this._appName = _appName; this._options = _options; this._authProvider = _authProvider; this._auth = _authProvider.getImmediate({ optional: true }); if (!this._auth) { _authProvider.onInit(auth => (this._auth = auth)); } } getToken(forceRefresh) { if (!this._auth) { return new Promise((resolve, reject) => { setTimeout(() => { if (this._auth) { this.getToken(forceRefresh).then(resolve, reject); } else { resolve(null); } }, 0); }); } return this._auth.getToken(forceRefresh).catch(error => { if (error && error.code === 'auth/token-not-initialized') { logDebug('Got auth/token-not-initialized error. Treating as null token.'); return null; } else { logError('Error received when attempting to retrieve token: ' + JSON.stringify(error)); return Promise.reject(error); } }); } addTokenChangeListener(listener) { var _a; (_a = this._auth) === null || _a === void 0 ? void 0 : _a.addAuthTokenListener(listener); } removeTokenChangeListener(listener) { this._authProvider .get() .then(auth => auth.removeAuthTokenListener(listener)) .catch(err => logError(err)); } } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const QUERY_STR = 'query'; const MUTATION_STR = 'mutation'; const SOURCE_SERVER = 'SERVER'; const SOURCE_CACHE = 'CACHE'; /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ let encoderImpl; function setEncoder(encoder) { encoderImpl = encoder; } setEncoder(o => JSON.stringify(o)); /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function setIfNotExists(map, key, val) { if (!map.has(key)) { map.set(key, val); } } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function getRefSerializer(queryRef, data, source) { return function toJSON() { return { data, refInfo: { name: queryRef.name, variables: queryRef.variables, connectorConfig: Object.assign({ projectId: queryRef.dataConnect.app.options.projectId }, queryRef.dataConnect.getSettings()) }, fetchTime: Date.now().toLocaleString(), source }; }; } class QueryManager { constructor(transport) { this.transport = transport; this._queries = new Map(); } track(queryName, variables, initialCache) { const ref = { name: queryName, variables, refType: QUERY_STR }; const key = encoderImpl(ref); const newTrackedQuery = { ref, subscriptions: [], currentCache: initialCache || null, lastError: null }; // @ts-ignore setIfNotExists(this._queries, key, newTrackedQuery); return this._queries.get(key); } addSubscription(queryRef, onResultCallback, onErrorCallback, initialCache) { const key = encoderImpl({ name: queryRef.name, variables: queryRef.variables, refType: QUERY_STR }); const trackedQuery = this._queries.get(key); const subscription = { userCallback: onResultCallback, errCallback: onErrorCallback }; const unsubscribe = () => { const trackedQuery = this._queries.get(key); trackedQuery.subscriptions = trackedQuery.subscriptions.filter(sub => sub !== subscription); }; if (initialCache && trackedQuery.currentCache !== initialCache) { logDebug('Initial cache found. Comparing dates.'); if (!trackedQuery.currentCache || (trackedQuery.currentCache && compareDates(trackedQuery.currentCache.fetchTime, initialCache.fetchTime))) { trackedQuery.currentCache = initialCache; } } if (trackedQuery.currentCache !== null) { const cachedData = trackedQuery.currentCache.data; onResultCallback({ data: cachedData, source: SOURCE_CACHE, ref: queryRef, toJSON: getRefSerializer(queryRef, trackedQuery.currentCache.data, SOURCE_CACHE), fetchTime: trackedQuery.currentCache.fetchTime }); if (trackedQuery.lastError !== null && onErrorCallback) { onErrorCallback(undefined); } } trackedQuery.subscriptions.push({ userCallback: onResultCallback, errCallback: onErrorCallback, unsubscribe }); if (!trackedQuery.currentCache) { logDebug(`No cache available for query ${queryRef.name} with variables ${JSON.stringify(queryRef.variables)}. Calling executeQuery.`); const promise = this.executeQuery(queryRef); // We want to ignore the error and let subscriptions handle it promise.then(undefined, err => { }); } return unsubscribe; } executeQuery(queryRef) { if (queryRef.refType !== QUERY_STR) { throw new DataConnectError(Code.INVALID_ARGUMENT, `ExecuteQuery can only execute query operation`); } const key = encoderImpl({ name: queryRef.name, variables: queryRef.variables, refType: QUERY_STR }); const trackedQuery = this._queries.get(key); const result = this.transport.invokeQuery(queryRef.name, queryRef.variables); const newR = result.then(res => { const fetchTime = new Date().toString(); const result = Object.assign(Object.assign({}, res), { source: SOURCE_SERVER, ref: queryRef, toJSON: getRefSerializer(queryRef, res.data, SOURCE_SERVER), fetchTime }); trackedQuery.subscriptions.forEach(subscription => { subscription.userCallback(result); }); trackedQuery.currentCache = { data: res.data, source: SOURCE_CACHE, fetchTime }; return result; }, err => { trackedQuery.lastError = err; trackedQuery.subscriptions.forEach(subscription => { if (subscription.errCallback) { subscription.errCallback(err); } }); throw err; }); return newR; } enableEmulator(host, port) { this.transport.useEmulator(host, port); } } function compareDates(str1, str2) { const date1 = new Date(str1); const date2 = new Date(str2); return date1.getTime() < date2.getTime(); } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function urlBuilder(projectConfig, transportOptions) { const { connector, location, projectId: project, service } = projectConfig; const { host, sslEnabled, port } = transportOptions; const protocol = sslEnabled ? 'https' : 'http'; const realHost = host || `firebasedataconnect.googleapis.com`; let baseUrl = `${protocol}://${realHost}`; if (typeof port === 'number') { baseUrl += `:${port}`; } else if (typeof port !== 'undefined') { logError('Port type is of an invalid type'); throw new DataConnectError(Code.INVALID_ARGUMENT, 'Incorrect type for port passed in!'); } return `${baseUrl}/v1beta/projects/${project}/locations/${location}/services/${service}/connectors/${connector}`; } function addToken(url, apiKey) { if (!apiKey) { return url; } const newUrl = new URL(url); newUrl.searchParams.append('key', apiKey); return newUrl.toString(); } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class RESTTransport { constructor(options, apiKey, appId, authProvider, appCheckProvider, transportOptions, _isUsingGen = false) { var _a, _b; this.apiKey = apiKey; this.appId = appId; this.authProvider = authProvider; this.appCheckProvider = appCheckProvider; this._isUsingGen = _isUsingGen; this._host = ''; this._location = 'l'; this._connectorName = ''; this._secure = true; this._project = 'p'; this._accessToken = null; this._appCheckToken = null; this._lastToken = null; // TODO(mtewani): Update U to include shape of body defined in line 13. this.invokeQuery = (queryName, body) => { const abortController = new AbortController(); // TODO(mtewani): Update to proper value const withAuth = this.withRetry(() => dcFetch(addToken(`${this.endpointUrl}:executeQuery`, this.apiKey), { name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`, operationName: queryName, variables: body }, // TODO(mtewani): This is a patch, fix this. abortController, this.appId, this._accessToken, this._appCheckToken, this._isUsingGen)); return { then: withAuth.then.bind(withAuth), catch: withAuth.catch.bind(withAuth) }; }; this.invokeMutation = (mutationName, body) => { const abortController = new AbortController(); const taskResult = this.withRetry(() => { return dcFetch(addToken(`${this.endpointUrl}:executeMutation`, this.apiKey), { name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`, operationName: mutationName, variables: body }, abortController, this.appId, this._accessToken, this._appCheckToken, this._isUsingGen); }); return { then: taskResult.then.bind(taskResult), // catch: taskResult.catch.bind(taskResult), // finally: taskResult.finally.bind(taskResult), cancel: () => abortController.abort() }; }; if (transportOptions) { if (typeof transportOptions.port === 'number') { this._port = transportOptions.port; } if (typeof transportOptions.sslEnabled !== 'undefined') { this._secure = transportOptions.sslEnabled; } this._host = transportOptions.host; } const { location, projectId: project, connector, service } = options; if (location) { this._location = location; } if (project) { this._project = project; } this._serviceName = service; if (!connector) { throw new DataConnectError(Code.INVALID_ARGUMENT, 'Connector Name required!'); } this._connectorName = connector; (_a = this.authProvider) === null || _a === void 0 ? void 0 : _a.addTokenChangeListener(token => { logDebug(`New Token Available: ${token}`); this._accessToken = token; }); (_b = this.appCheckProvider) === null || _b === void 0 ? void 0 : _b.addTokenChangeListener(result => { const { token } = result; logDebug(`New App Check Token Available: ${token}`); this._appCheckToken = token; }); } get endpointUrl() { return urlBuilder({ connector: this._connectorName, location: this._location, projectId: this._project, service: this._serviceName }, { host: this._host, sslEnabled: this._secure, port: this._port }); } useEmulator(host, port, isSecure) { this._host = host; if (typeof port === 'number') { this._port = port; } if (typeof isSecure !== 'undefined') { this._secure = isSecure; } } onTokenChanged(newToken) { this._accessToken = newToken; } async getWithAuth(forceToken = false) { var _a; let starterPromise = new Promise(resolve => resolve(this._accessToken)); if (this.appCheckProvider) { this._appCheckToken = (_a = (await this.appCheckProvider.getToken())) === null || _a === void 0 ? void 0 : _a.token; } if (this.authProvider) { starterPromise = this.authProvider .getToken(/*forceToken=*/ forceToken) .then(data => { if (!data) { return null; } this._accessToken = data.accessToken; return this._accessToken; }); } else { starterPromise = new Promise(resolve => resolve('')); } return starterPromise; } _setLastToken(lastToken) { this._lastToken = lastToken; } withRetry(promiseFactory, retry = false) { let isNewToken = false; return this.getWithAuth(retry) .then(res => { isNewToken = this._lastToken !== res; this._lastToken = res; return res; }) .then(promiseFactory) .catch(err => { // Only retry if the result is unauthorized and the last token isn't the same as the new one. if ('code' in err && err.code === Code.UNAUTHORIZED && !retry && isNewToken) { logDebug('Retrying due to unauthorized'); return this.withRetry(promiseFactory, true); } throw err; }); } } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * * @param dcInstance Data Connect instance * @param mutationName name of mutation * @param variables variables to send with mutation * @returns `MutationRef` */ function mutationRef(dcInstance, mutationName, variables) { dcInstance.setInitialized(); const ref = { dataConnect: dcInstance, name: mutationName, refType: MUTATION_STR, variables: variables }; return ref; } /** * @internal */ class MutationManager { constructor(_transport) { this._transport = _transport; this._inflight = []; } executeMutation(mutationRef) { const result = this._transport.invokeMutation(mutationRef.name, mutationRef.variables); const withRefPromise = result.then(res => { const obj = Object.assign(Object.assign({}, res), { source: SOURCE_SERVER, ref: mutationRef, fetchTime: Date.now().toLocaleString() }); return obj; }); this._inflight.push(result); const removePromise = () => (this._inflight = this._inflight.filter(promise => promise !== result)); result.then(removePromise, removePromise); return withRefPromise; } } /** * Execute Mutation * @param mutationRef mutation to execute * @returns `MutationRef` */ function executeMutation(mutationRef) { return mutationRef.dataConnect._mutationManager.executeMutation(mutationRef); } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR = 'FIREBASE_DATA_CONNECT_EMULATOR_HOST'; /** * * @param fullHost * @returns TransportOptions * @internal */ function parseOptions(fullHost) { const [protocol, hostName] = fullHost.split('://'); const isSecure = protocol === 'https'; const [host, portAsString] = hostName.split(':'); const port = Number(portAsString); return { host, port, sslEnabled: isSecure }; } /** * Class representing Firebase Data Connect */ class DataConnect { // @internal constructor(app, // TODO(mtewani): Replace with _dataConnectOptions in the future dataConnectOptions, _authProvider, _appCheckProvider) { this.app = app; this.dataConnectOptions = dataConnectOptions; this._authProvider = _authProvider; this._appCheckProvider = _appCheckProvider; this.isEmulator = false; this._initialized = false; this._isUsingGeneratedSdk = false; if (typeof process !== 'undefined' && process.env) { const host = process.env[FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR]; if (host) { logDebug('Found custom host. Using emulator'); this.isEmulator = true; this._transportOptions = parseOptions(host); } } } // @internal _useGeneratedSdk() { if (!this._isUsingGeneratedSdk) { this._isUsingGeneratedSdk = true; } } _delete() { _removeServiceInstance(this.app, 'data-connect', JSON.stringify(this.getSettings())); return Promise.resolve(); } // @internal getSettings() { const copy = JSON.parse(JSON.stringify(this.dataConnectOptions)); delete copy.projectId; return copy; } // @internal setInitialized() { if (this._initialized) { return; } if (this._transportClass === undefined) { logDebug('transportClass not provided. Defaulting to RESTTransport.'); this._transportClass = RESTTransport; } if (this._authProvider) { this._authTokenProvider = new FirebaseAuthProvider(this.app.name, this.app.options, this._authProvider); } if (this._appCheckProvider) { this._appCheckTokenProvider = new AppCheckTokenProvider(this.app.name, this._appCheckProvider); } this._initialized = true; this._transport = new this._transportClass(this.dataConnectOptions, this.app.options.apiKey, this.app.options.appId, this._authTokenProvider, this._appCheckTokenProvider, undefined, this._isUsingGeneratedSdk); if (this._transportOptions) { this._transport.useEmulator(this._transportOptions.host, this._transportOptions.port, this._transportOptions.sslEnabled); } this._queryManager = new QueryManager(this._transport); this._mutationManager = new MutationManager(this._transport); } // @internal enableEmulator(transportOptions) { if (this._initialized) { logError('enableEmulator called after initialization'); throw new DataConnectError(Code.ALREADY_INITIALIZED, 'DataConnect instance already initialized!'); } this._transportOptions = transportOptions; this.isEmulator = true; } } /** * Connect to the DataConnect Emulator * @param dc Data Connect instance * @param host host of emulator server * @param port port of emulator server * @param sslEnabled use https */ function connectDataConnectEmulator(dc, host, port, sslEnabled = false) { dc.enableEmulator({ host, port, sslEnabled }); } function getDataConnect(appOrOptions, optionalOptions) { let app; let dcOptions; if ('location' in appOrOptions) { dcOptions = appOrOptions; app = getApp(); } else { dcOptions = optionalOptions; app = appOrOptions; } if (!app || Object.keys(app).length === 0) { app = getApp(); } const provider = _getProvider(app, 'data-connect'); const identifier = JSON.stringify(dcOptions); if (provider.isInitialized(identifier)) { const dcInstance = provider.getImmediate({ identifier }); const options = provider.getOptions(identifier); const optionsValid = Object.keys(options).length > 0; if (optionsValid) { logDebug('Re-using cached instance'); return dcInstance; } } validateDCOptions(dcOptions); logDebug('Creating new DataConnect instance'); // Initialize with options. return provider.initialize({ instanceIdentifier: identifier, options: dcOptions }); } /** * * @param dcOptions * @returns {void} * @internal */ function validateDCOptions(dcOptions) { const fields = ['connector', 'location', 'service']; if (!dcOptions) { throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required'); } fields.forEach(field => { if (dcOptions[field] === null || dcOptions[field] === undefined) { throw new DataConnectError(Code.INVALID_ARGUMENT, `${field} Required`); } }); return true; } /** * Delete DataConnect instance * @param dataConnect DataConnect instance * @returns */ function terminate(dataConnect) { return dataConnect._delete(); // TODO(mtewani): Stop pending tasks } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function registerDataConnect(variant) { setSDKVersion(SDK_VERSION$1); _registerComponent(new Component('data-connect', (container, { instanceIdentifier: settings, options }) => { const app = container.getProvider('app').getImmediate(); const authProvider = container.getProvider('auth-internal'); const appCheckProvider = container.getProvider('app-check-internal'); let newOpts = options; if (settings) { newOpts = JSON.parse(settings); } if (!app.options.projectId) { throw new DataConnectError(Code.INVALID_ARGUMENT, 'Project ID must be provided. Did you pass in a proper projectId to initializeApp?'); } return new DataConnect(app, Object.assign(Object.assign({}, newOpts), { projectId: app.options.projectId }), authProvider, appCheckProvider); }, "PUBLIC" /* ComponentType.PUBLIC */).setMultipleInstances(true)); registerVersion(name, version, variant); // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation registerVersion(name, version, 'esm2017'); } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Execute Query * @param queryRef query to execute. * @returns `QueryPromise` */ function executeQuery(queryRef) { return queryRef.dataConnect._queryManager.executeQuery(queryRef); } /** * Execute Query * @param dcInstance Data Connect instance to use. * @param queryName Query to execute * @param variables Variables to execute with * @param initialCache initial cache to use for client hydration * @returns `QueryRef` */ function queryRef(dcInstance, queryName, variables, initialCache) { dcInstance.setInitialized(); dcInstance._queryManager.track(queryName, variables, initialCache); return { dataConnect: dcInstance, refType: QUERY_STR, name: queryName, variables: variables }; } /** * Converts serialized ref to query ref * @param serializedRef ref to convert to `QueryRef` * @returns `QueryRef` */ function toQueryRef(serializedRef) { const { refInfo: { name, variables, connectorConfig } } = serializedRef; return queryRef(getDataConnect(connectorConfig), name, variables); } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * The generated SDK will allow the user to pass in either the variable or the data connect instance with the variable, * and this function validates the variables and returns back the DataConnect instance and variables based on the arguments passed in. * @param connectorConfig * @param dcOrVars * @param vars * @param validateVars * @returns {DataConnect} and {Variables} instance * @internal */ function validateArgs(connectorConfig, dcOrVars, vars, validateVars) { let dcInstance; let realVars; if (dcOrVars && 'enableEmulator' in dcOrVars) { dcInstance = dcOrVars; realVars = vars; } else { dcInstance = getDataConnect(connectorConfig); realVars = dcOrVars; } if (!dcInstance || (!realVars && validateVars)) { throw new DataConnectError(Code.INVALID_ARGUMENT, 'Variables required.'); } return { dc: dcInstance, vars: realVars }; } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Subscribe to a `QueryRef` * @param queryRefOrSerializedResult query ref or serialized result. * @param observerOrOnNext observer object or next function. * @param onError Callback to call when error gets thrown. * @param onComplete Called when subscription completes. * @returns `SubscriptionOptions` */ function subscribe(queryRefOrSerializedResult, observerOrOnNext, onError, onComplete) { let ref; let initialCache; if ('refInfo' in queryRefOrSerializedResult) { const serializedRef = queryRefOrSerializedResult; const { data, source, fetchTime } = serializedRef; initialCache = { data, source, fetchTime }; ref = toQueryRef(serializedRef); } else { ref = queryRefOrSerializedResult; } let onResult = undefined; if (typeof observerOrOnNext === 'function') { onResult = observerOrOnNext; } else { onResult = observerOrOnNext.onNext; onError = observerOrOnNext.onErr; observerOrOnNext.onComplete; } if (!onResult) { throw new DataConnectError(Code.INVALID_ARGUMENT, 'Must provide onNext'); } return ref.dataConnect._queryManager.addSubscription(ref, onResult, onError, initialCache); } /** * @license * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ initializeFetch(fetch); registerDataConnect('node'); export { DataConnect, MUTATION_STR, MutationManager, QUERY_STR, SOURCE_CACHE, SOURCE_SERVER, connectDataConnectEmulator, executeMutation, executeQuery, getDataConnect, mutationRef, parseOptions, queryRef, setLogLevel, subscribe, terminate, toQueryRef, validateArgs, validateDCOptions }; //# sourceMappingURL=index.node.esm.js.map