Can't use multiple RTDB instances with emulator (original) (raw)

[REQUIRED] Describe your environment

[REQUIRED] Describe the problem

When using multiple database instances (via app.database(URL)) with the firebase-tools emulator errors are thrown.

Steps to reproduce:

const { app } = require('firebase-admin')

const _app = require('firebase-admin').initializeApp({ databaseURL: 'https://against-emulator.firebaseio.com' })

Promise.resolve(app).then(async app => { const mainInstance = app.database() console.log('Main DB:', mainInstance['repo']['repoInfo_']) const mainInstanceRef = mainInstance.ref('root') console.log('Main DB ref:', mainInstanceRef.toString()) const otherInstance = app.database('https://against-emulator-other-instance.firebaseio.com') console.log('Other DB:', otherInstance['repo_']['repoInfo_']) const otherInstanceRef = otherInstance.ref('root') console.log('Other DB ref:', otherInstanceRef.toString()) }) .catch(err => console.error('Error - ', err)) .finally(() => _app.delete())

Run the above code with just node script.js and the following is outputted with no errors:

Main DB: RepoInfo {
  secure: true,
  namespace: 'against-emulator',
  webSocketOnly: false,
  persistenceKey: '',
  includeNamespaceInQueryParams: false,
  host: 'against-emulator.firebaseio.com',
  domain: 'firebaseio.com',
  internalHost: 'against-emulator.firebaseio.com'
}
Main DB ref: https://against-emulator.firebaseio.com/root
Other DB: RepoInfo {
  secure: true,
  namespace: 'against-emulator-other-instance',
  webSocketOnly: false,
  persistenceKey: '',
  includeNamespaceInQueryParams: false,
  host: 'against-emulator-other-instance.firebaseio.com',
  domain: 'firebaseio.com',
  internalHost: 'against-emulator-other-instance.firebaseio.com'
}
Other DB ref: https://against-emulator-other-instance.firebaseio.com/root

Now running against the DB emulator firebase emulators:exec --project against-emulator --only database 'node script.js', errors occur:

Main DB: RepoInfo {
  secure: false,
  namespace: 'against-emulator',
  webSocketOnly: false,
  persistenceKey: '',
  includeNamespaceInQueryParams: true,
  host: 'localhost:9000',
  domain: 'localhost:9000',
  internalHost: 'localhost:9000'
}
Main DB ref: http://localhost:9000/root
[2020-08-25T13:22:27.260Z]  @firebase/database: FIREBASE FATAL ERROR: Database initialized multiple times. Please make sure the format of the database URL matches with each database() call. 
Error -  Error: FIREBASE FATAL ERROR: Database initialized multiple times. Please make sure the format of the database URL matches with each database() call. 
    at fatal (<path>/node_modules/@firebase/database/dist/index.node.cjs.js:341:11)
    at RepoManager.createRepo (<path>/node_modules/@firebase/database/dist/index.node.cjs.js:15047:13)
    at RepoManager.databaseFromApp (<path>/node_modules/@firebase/database/dist/index.node.cjs.js:15014:25)
    at Object.initStandalone (<path>/node_modules/@firebase/database/dist/index.node.cjs.js:15389:45)
    at DatabaseService.getDatabase (<path>/node_modules/firebase-admin/lib/database/database-internal.js:82:23)
    at FirebaseApp.database (<path>/node_modules/firebase-admin/lib/firebase-app.js:232:24)
    at <path>/script.js:12:30

Relevant Code:

This is the bit of code throwing the error:

let repo = safeGet(appRepos, repoInfo.toURLString());
if (repo) {
fatal(
'Database initialized multiple times. Please make sure the format of the database URL matches with each database() call.'
);
}

It seems that RepoInfo#toURLString:

toURLString(): string {
return (this.secure ? 'https://' : 'http://') + this.host;
}

Doesn't take into account the namespace of the RepoInfo which the emulator uses to distinguish between different DB instances.