Skip to content

Commit ffd268a

Browse files
committed
Merge branch 'master' of github.com:FirebasePrivate/firebase-functions
2 parents bb92d38 + dbf9b5e commit ffd268a

File tree

3 files changed

+64
-27
lines changed

3 files changed

+64
-27
lines changed

spec/providers/database.spec.ts

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ describe('Database Functions', () => {
3232

3333
before(() => {
3434
process.env.FIREBASE_CONFIG = JSON.stringify({
35-
databaseURL: 'https://subdomain.firebaseio.com',
35+
databaseURL: 'https://subdomain.apse.firebasedatabase.app',
3636
});
3737
appsNamespace.init();
3838
});
@@ -424,29 +424,51 @@ describe('Database Functions', () => {
424424
});
425425
});
426426

427-
describe('resourceToInstanceAndPath', () => {
428-
it('should return the correct instance and path strings', () => {
429-
const [instance, path] = database.resourceToInstanceAndPath(
430-
'projects/_/instances/foo/refs/bar'
427+
describe('extractInstanceAndPath', () => {
428+
it('should return correct us-central prod instance and path strings if domain is missing', () => {
429+
const [instance, path] = database.extractInstanceAndPath(
430+
'projects/_/instances/foo/refs/bar',
431+
undefined
431432
);
432433
expect(instance).to.equal('https://foo.firebaseio.com');
433434
expect(path).to.equal('/bar');
434435
});
435436

437+
it('should return the correct staging instance and path strings if domain is present', () => {
438+
const [instance, path] = database.extractInstanceAndPath(
439+
'projects/_/instances/foo/refs/bar',
440+
'firebaseio-staging.com'
441+
);
442+
expect(instance).to.equal('https://foo.firebaseio-staging.com');
443+
expect(path).to.equal('/bar');
444+
});
445+
446+
it('should return the correct multi-region instance and path strings if domain is present', () => {
447+
const [instance, path] = database.extractInstanceAndPath(
448+
'projects/_/instances/foo/refs/bar',
449+
'euw1.firebasedatabase.app'
450+
);
451+
expect(instance).to.equal('https://foo.euw1.firebasedatabase.app');
452+
expect(path).to.equal('/bar');
453+
});
454+
436455
it('should throw an error if the given instance name contains anything except alphanumerics and dashes', () => {
437456
expect(() => {
438-
return database.resourceToInstanceAndPath(
439-
'projects/_/instances/a.bad.name/refs/bar'
457+
return database.extractInstanceAndPath(
458+
'projects/_/instances/a.bad.name/refs/bar',
459+
undefined
440460
);
441461
}).to.throw(Error);
442462
expect(() => {
443-
return database.resourceToInstanceAndPath(
444-
'projects/_/instances/a_different_bad_name/refs/bar'
463+
return database.extractInstanceAndPath(
464+
'projects/_/instances/a_different_bad_name/refs/bar',
465+
undefined
445466
);
446467
}).to.throw(Error);
447468
expect(() => {
448-
return database.resourceToInstanceAndPath(
449-
'projects/_/instances/BAD!!!!/refs/bar'
469+
return database.extractInstanceAndPath(
470+
'projects/_/instances/BAD!!!!/refs/bar',
471+
undefined
450472
);
451473
}).to.throw(Error);
452474
});
@@ -457,8 +479,9 @@ describe('Database Functions', () => {
457479
const apps = new appsNamespace.Apps();
458480

459481
const populate = (data: any) => {
460-
const [instance, path] = database.resourceToInstanceAndPath(
461-
'projects/_/instances/other-subdomain/refs/foo'
482+
const [instance, path] = database.extractInstanceAndPath(
483+
'projects/_/instances/other-subdomain/refs/foo',
484+
'firebaseio-staging.com'
462485
);
463486
subject = new database.DataSnapshot(data, path, apps.admin, instance);
464487
};
@@ -467,7 +490,7 @@ describe('Database Functions', () => {
467490
it('should return a ref for correct instance, not the default instance', () => {
468491
populate({});
469492
expect(subject.ref.toJSON()).to.equal(
470-
'https://other-subdomain.firebaseio.com/foo'
493+
'https://other-subdomain.firebaseio-staging.com/foo'
471494
);
472495
});
473496
});
@@ -648,8 +671,9 @@ describe('Database Functions', () => {
648671
});
649672

650673
it('should return null for the root', () => {
651-
const [instance, path] = database.resourceToInstanceAndPath(
652-
'projects/_/instances/foo/refs/'
674+
const [instance, path] = database.extractInstanceAndPath(
675+
'projects/_/instances/foo/refs/',
676+
undefined
653677
);
654678
const snapshot = new database.DataSnapshot(
655679
null,

src/cloud-functions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export interface Event {
3939
timestamp: string;
4040
eventType: string;
4141
resource: Resource;
42+
domain?: string;
4243
};
4344
data: any;
4445
}

src/providers/database.ts

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ export const provider = 'google.firebase.database';
4040
/** @hidden */
4141
export const service = 'firebaseio.com';
4242

43-
// NOTE(inlined): Should we relax this a bit to allow staging or alternate implementations of our API?
44-
const databaseURLRegex = new RegExp('https://([^.]+).firebaseio.com');
43+
const databaseURLRegex = new RegExp('^https://([^.]+).');
4544

4645
/**
4746
* Registers a function that triggers on events from a specific
@@ -215,8 +214,9 @@ export class RefBuilder {
215214
) => PromiseLike<any> | any
216215
): CloudFunction<DataSnapshot> {
217216
const dataConstructor = (raw: Event) => {
218-
const [dbInstance, path] = resourceToInstanceAndPath(
219-
raw.context.resource.name
217+
const [dbInstance, path] = extractInstanceAndPath(
218+
raw.context.resource.name,
219+
raw.context.domain
220220
);
221221
return new DataSnapshot(
222222
raw.data.delta,
@@ -243,8 +243,9 @@ export class RefBuilder {
243243
) => PromiseLike<any> | any
244244
): CloudFunction<DataSnapshot> {
245245
const dataConstructor = (raw: Event) => {
246-
const [dbInstance, path] = resourceToInstanceAndPath(
247-
raw.context.resource.name
246+
const [dbInstance, path] = extractInstanceAndPath(
247+
raw.context.resource.name,
248+
raw.context.domain
248249
);
249250
return new DataSnapshot(raw.data.data, path, this.apps.admin, dbInstance);
250251
};
@@ -271,8 +272,9 @@ export class RefBuilder {
271272
}
272273

273274
private changeConstructor = (raw: Event): Change<DataSnapshot> => {
274-
const [dbInstance, path] = resourceToInstanceAndPath(
275-
raw.context.resource.name
275+
const [dbInstance, path] = extractInstanceAndPath(
276+
raw.context.resource.name,
277+
raw.context.domain
276278
);
277279
const before = new DataSnapshot(
278280
raw.data.data,
@@ -293,9 +295,19 @@ export class RefBuilder {
293295
};
294296
}
295297

296-
/* Utility function to extract database reference from resource string */
298+
/**
299+
* Utility function to extract database reference from resource string
300+
*
301+
* @param optional database domain override for the original of the source database.
302+
* It defaults to `firebaseio.com`.
303+
* Multi-region RTDB will be served from different domains.
304+
* Since region is not part of the resource name, it is provided through context.
305+
*/
297306
/** @hidden */
298-
export function resourceToInstanceAndPath(resource: string) {
307+
export function extractInstanceAndPath(
308+
resource: string,
309+
domain = 'firebaseio.com'
310+
) {
299311
const resourceRegex = `projects/([^/]+)/instances/([a-zA-Z0-9\-^/]+)/refs(/.+)?`;
300312
const match = resource.match(new RegExp(resourceRegex));
301313
if (!match) {
@@ -310,7 +322,7 @@ export function resourceToInstanceAndPath(resource: string) {
310322
`Expect project to be '_' in a Firebase Realtime Database event`
311323
);
312324
}
313-
const dbInstance = 'https://' + dbInstanceName + '.firebaseio.com';
325+
const dbInstance = 'https://' + dbInstanceName + '.' + domain;
314326
return [dbInstance, path];
315327
}
316328

0 commit comments

Comments
 (0)