diff --git a/packages/database/index.node.ts b/packages/database/index.node.ts index 71bcfa964ea..a58988c507f 100644 --- a/packages/database/index.node.ts +++ b/packages/database/index.node.ts @@ -15,9 +15,7 @@ * limitations under the License. */ -import firebase from '@firebase/app'; -import { CONSTANTS, isNodeSdk } from '@firebase/util'; -import { FirebaseApp, FirebaseNamespace } from '@firebase/app-types'; +import { FirebaseNamespace, FirebaseApp } from '@firebase/app-types'; import { _FirebaseNamespace } from '@firebase/app-types/private'; import { Database } from './src/api/Database'; import { DataSnapshot } from './src/api/DataSnapshot'; @@ -29,6 +27,10 @@ import * as INTERNAL from './src/api/internal'; import * as TEST_ACCESS from './src/api/test_access'; import './src/nodePatches'; import * as types from '@firebase/database-types'; +import { setSDKVersion } from './src/core/version'; +import { CONSTANTS, isNodeSdk } from '@firebase/util'; + +const ServerValue = Database.ServerValue; /** * A one off register function which returns a database based on the app and @@ -36,23 +38,15 @@ import * as types from '@firebase/database-types'; * * @param app A valid FirebaseApp-like object * @param url A valid Firebase databaseURL + * @param version custom version e.g. firebase-admin version */ - -const ServerValue = Database.ServerValue; - -export function initStandalone( - app: FirebaseApp, - url: string, - version?: string -) { +export function initStandalone(app: FirebaseApp, url: string, version: string) { /** * This should allow the firebase-admin package to provide a custom version * to the backend */ CONSTANTS.NODE_ADMIN = true; - if (version) { - firebase.SDK_VERSION = version; - } + setSDKVersion(version); return { instance: RepoManager.getInstance().databaseFromApp(app, url), @@ -70,6 +64,9 @@ export function initStandalone( } export function registerDatabase(instance: FirebaseNamespace) { + // set SDK_VERSION + setSDKVersion(instance.SDK_VERSION); + // Register the Database Service with the 'firebase' namespace. const namespace = (instance as _FirebaseNamespace).INTERNAL.registerService( 'database', @@ -94,7 +91,21 @@ export function registerDatabase(instance: FirebaseNamespace) { } } -registerDatabase(firebase); +try { + // If @firebase/app is not present, skip registering database. + // It could happen when this package is used in firebase-admin which doesn't depend on @firebase/app. + // Previously firebase-admin depends on @firebase/app, which causes version conflict on + // @firebase/app when used together with the js sdk. More detail: + // https://github.com/firebase/firebase-js-sdk/issues/1696#issuecomment-501546596 + const firebase = require('@firebase/app').default; + registerDatabase(firebase); +} catch (err) { + // catch and ignore 'MODULE_NOT_FOUND' error in firebase-admin context + // we can safely ignore this error because RTDB in firebase-admin works without @firebase/app + if (err.code !== 'MODULE_NOT_FOUND') { + throw err; + } +} // Types to export for the admin SDK export { Database, Query, Reference, enableLogging, ServerValue }; diff --git a/packages/database/index.ts b/packages/database/index.ts index 5039eb0c6ae..00a3848447c 100644 --- a/packages/database/index.ts +++ b/packages/database/index.ts @@ -16,7 +16,7 @@ */ import firebase from '@firebase/app'; -import { FirebaseApp, FirebaseNamespace } from '@firebase/app-types'; +import { FirebaseNamespace } from '@firebase/app-types'; import { _FirebaseNamespace } from '@firebase/app-types/private'; import { Database } from './src/api/Database'; import { DataSnapshot } from './src/api/DataSnapshot'; @@ -28,10 +28,14 @@ import * as INTERNAL from './src/api/internal'; import * as TEST_ACCESS from './src/api/test_access'; import { isNodeSdk } from '@firebase/util'; import * as types from '@firebase/database-types'; +import { setSDKVersion } from './src/core/version'; const ServerValue = Database.ServerValue; export function registerDatabase(instance: FirebaseNamespace) { + // set SDK_VERSION + setSDKVersion(instance.SDK_VERSION); + // Register the Database Service with the 'firebase' namespace. const namespace = (instance as _FirebaseNamespace).INTERNAL.registerService( 'database', diff --git a/packages/database/src/core/PersistentConnection.ts b/packages/database/src/core/PersistentConnection.ts index b53c500b989..08f9261f8d4 100644 --- a/packages/database/src/core/PersistentConnection.ts +++ b/packages/database/src/core/PersistentConnection.ts @@ -15,8 +15,7 @@ * limitations under the License. */ -import firebase from '@firebase/app'; -import { contains, isEmpty, safeGet } from '@firebase/util'; +import { contains, isEmpty, safeGet, CONSTANTS } from '@firebase/util'; import { stringify } from '@firebase/util'; import { assert } from '@firebase/util'; import { error, log, logWrapper, warn, ObjectToUniqueKey } from './util/util'; @@ -25,12 +24,12 @@ import { VisibilityMonitor } from './util/VisibilityMonitor'; import { OnlineMonitor } from './util/OnlineMonitor'; import { isAdmin, isValidFormat } from '@firebase/util'; import { Connection } from '../realtime/Connection'; -import { CONSTANTS } from '@firebase/util'; import { isMobileCordova, isReactNative, isNodeSdk } from '@firebase/util'; import { ServerActions } from './ServerActions'; import { AuthTokenProvider } from './AuthTokenProvider'; import { RepoInfo } from './RepoInfo'; import { Query } from '../api/Query'; +import { SDK_VERSION } from './version'; const RECONNECT_MIN_DELAY = 1000; const RECONNECT_MAX_DELAY_DEFAULT = 60 * 5 * 1000; // 5 minutes in milliseconds (Case: 1858) @@ -926,9 +925,7 @@ export class PersistentConnection extends ServerActions { clientName = 'node'; } - stats[ - 'sdk.' + clientName + '.' + firebase.SDK_VERSION.replace(/\./g, '-') - ] = 1; + stats['sdk.' + clientName + '.' + SDK_VERSION.replace(/\./g, '-')] = 1; if (isMobileCordova()) { stats['framework.cordova'] = 1; diff --git a/packages/database/src/core/version.ts b/packages/database/src/core/version.ts new file mode 100644 index 00000000000..cbdb1b09894 --- /dev/null +++ b/packages/database/src/core/version.ts @@ -0,0 +1,24 @@ +/** + * @license + * Copyright 2019 Google Inc. + * + * 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. */ +export let SDK_VERSION = ''; + +// SDK_VERSION should be set before any database instance is created +export function setSDKVersion(version: string): void { + SDK_VERSION = version; +} diff --git a/packages/database/src/realtime/WebSocketConnection.ts b/packages/database/src/realtime/WebSocketConnection.ts index 58d9423206d..4601e9b4a76 100644 --- a/packages/database/src/realtime/WebSocketConnection.ts +++ b/packages/database/src/realtime/WebSocketConnection.ts @@ -19,8 +19,7 @@ import { RepoInfo } from '../core/RepoInfo'; declare const MozWebSocket: any; -import firebase from '@firebase/app'; -import { assert } from '@firebase/util'; +import { assert, CONSTANTS as ENV_CONSTANTS } from '@firebase/util'; import { logWrapper, splitStringBySize } from '../core/util/util'; import { StatsManager } from '../core/stats/StatsManager'; import { @@ -33,12 +32,12 @@ import { VERSION_PARAM, WEBSOCKET } from './Constants'; -import { CONSTANTS as ENV_CONSTANTS } from '@firebase/util'; import { PersistentStorage } from '../core/storage/storage'; import { jsonEval, stringify } from '@firebase/util'; import { isNodeSdk } from '@firebase/util'; import { Transport } from './Transport'; import { StatsCollection } from '../core/stats/StatsCollection'; +import { SDK_VERSION } from '../core/version'; const WEBSOCKET_MAX_FRAME_SIZE = 16384; const WEBSOCKET_KEEPALIVE_INTERVAL = 45000; @@ -150,9 +149,9 @@ export class WebSocketConnection implements Transport { // UA Format: Firebase//// const options: { [k: string]: object } = { headers: { - 'User-Agent': `Firebase/${PROTOCOL_VERSION}/${ - firebase.SDK_VERSION - }/${process.platform}/${device}` + 'User-Agent': `Firebase/${PROTOCOL_VERSION}/${SDK_VERSION}/${ + process.platform + }/${device}` } };