Skip to content
9 changes: 9 additions & 0 deletions src/auth/credential.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,15 @@ export class ApplicationDefaultCredential implements FirebaseCredential {
}
}

export class DatabaseEmulatorCredential implements Credential {
public getAccessToken(): Promise<GoogleOAuthAccessToken> {
return Promise.resolve({
expires_in: 1000,
access_token: 'owner',
});
}
}

function credentialFromFile(filePath: string, httpAgent?: Agent): Credential {
const credentialsFile = readCredentialFile(filePath);
if (typeof credentialsFile !== 'object') {
Expand Down
28 changes: 28 additions & 0 deletions src/database/database.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
import {DatabaseEmulatorCredential} from '../auth/credential';
import {FirebaseApp} from '../firebase-app';
import {FirebaseDatabaseError} from '../utils/error';
import {FirebaseServiceInterface, FirebaseServiceInternalsInterface} from '../firebase-service';
import {Database} from '@firebase/database';

import * as validator from '../utils/validator';

const APP_OPTIONS_PROJECT_ID = 'projectId';
const APP_OPTIONS_CREDENTIAL = 'credential';

/**
* Constant holding the fully-qualified domain URI for a database emulator
* instance. If specified, the contents of this variable will be used to
* set `databaseURL` in FirebaseAppOptions. The varaible should be a complete
* URI specifying a transfer protocol, hostname, and port number:
*
* FIREBASE_DATABASE_EMULATOR_HOST=http://localhost:9000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I am not mistaken, the protocol is omitted in FIRESTORE_EMULATOR_HOST. I see that it might make sense to include it here (since we need to include the namespace). Should we come up with a consistent pattern that apploes to both RTDB and Firestore? @ryanpbrewster

Copy link
Contributor

@ryanpbrewster ryanpbrewster Jul 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the protocol should not be included in the FIRESTORE_EMULATOR_HOST variable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we care about the consistency between FIRESTORE_EMULATOR_HOST and FIREBASE_DATABASE_EMULATOR_HOST?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, ideally neither should include the protocol.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is dated, neither emulator host variable has a protocol.

*
*
* If a `projectId` is specified in FirebaseAppOptions, the database url will
* include the `ns=${projectId}` query parameter to identify the appropriate
* namespace within the emulator. The final `databaseURL` for a firebase project
* called "test" would be:
*
* http://localhost:9000?ns=test
*/
const FIREBASE_DATABASE_EMULATOR_HOST_VAR = 'FIREBASE_DATABASE_EMULATOR_HOST';
const DEFAULT_DATABASE_EMULATOR_PROJECT_ID = 'fake-server';

/**
* Internals of a Database instance.
Expand Down Expand Up @@ -55,6 +77,12 @@ export class DatabaseService implements FirebaseServiceInterface {
}

public getDatabase(url?: string): Database {
const emulatorUrl = process.env[FIREBASE_DATABASE_EMULATOR_HOST_VAR];
if (emulatorUrl) {
url = `${emulatorUrl}?ns=${this.appInternal.options[APP_OPTIONS_PROJECT_ID] ||
DEFAULT_DATABASE_EMULATOR_PROJECT_ID }`;
this.appInternal.options[APP_OPTIONS_CREDENTIAL] = new DatabaseEmulatorCredential();
}
const dbUrl: string = this.ensureUrl(url);
if (!validator.isNonEmptyString(dbUrl)) {
throw new FirebaseDatabaseError({
Expand Down