Skip to content

Commit d68c9da

Browse files
authored
feat: Added instanceId() modularized API (#1136)
* feat: Added instanceId() modularized API * fix: Cleaned up the tests
1 parent 641dee0 commit d68c9da

File tree

10 files changed

+133
-64
lines changed

10 files changed

+133
-64
lines changed

etc/firebase-admin.api.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -498,15 +498,18 @@ export interface GoogleOAuthAccessToken {
498498
export function initializeApp(options?: AppOptions, name?: string): app.App;
499499

500500
// @public
501-
export function instanceId(app?: app.App): instanceId.InstanceId;
501+
export class InstanceId {
502+
get app(): App;
503+
deleteInstanceId(instanceId: string): Promise<void>;
504+
}
505+
506+
// @public
507+
export function instanceId(app?: App): InstanceId;
502508

503509
// @public (undocumented)
504510
export namespace instanceId {
505-
export interface InstanceId {
506-
// (undocumented)
507-
app: app.App;
508-
deleteInstanceId(instanceId: string): Promise<void>;
509-
}
511+
// (undocumented)
512+
export type InstanceId = InstanceId;
510513
}
511514

512515
// @public

gulpfile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ gulp.task('compile', function() {
8888
'lib/firebase-namespace-api.d.ts',
8989
'lib/core.d.ts',
9090
'lib/app/*.d.ts',
91+
'lib/instance-id/*.d.ts',
9192
'!lib/utils/index.d.ts',
9293
];
9394

src/app/firebase-app.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { database } from '../database/index';
3131
import { DatabaseService } from '../database/database-internal';
3232
import { Firestore } from '@google-cloud/firestore';
3333
import { FirestoreService } from '../firestore/firestore-internal';
34-
import { InstanceId } from '../instance-id/instance-id';
34+
import { InstanceId } from '../instance-id/index';
3535
import { ProjectManagement } from '../project-management/project-management';
3636
import { SecurityRules } from '../security-rules/security-rules';
3737
import { RemoteConfig } from '../remote-config/remote-config';
@@ -231,6 +231,8 @@ export class FirebaseAppInternals {
231231

232232
/**
233233
* Global context object for a collection of services using a shared authentication state.
234+
*
235+
* @internal
234236
*/
235237
export class FirebaseApp implements app.App {
236238
public INTERNAL: FirebaseAppInternals;
@@ -333,10 +335,8 @@ export class FirebaseApp implements app.App {
333335
* @return The InstanceId service instance of this app.
334336
*/
335337
public instanceId(): InstanceId {
336-
return this.ensureService_('iid', () => {
337-
const iidService: typeof InstanceId = require('../instance-id/instance-id').InstanceId;
338-
return new iidService(this);
339-
});
338+
const fn = require('../instance-id/index').instanceId;
339+
return fn(this);
340340
}
341341

342342
/**
@@ -410,6 +410,13 @@ export class FirebaseApp implements app.App {
410410
return deepCopy(this.options_);
411411
}
412412

413+
/**
414+
* @internal
415+
*/
416+
public getOrInitService<T>(name: string, init: (app: FirebaseApp) => T): T {
417+
return this.ensureService_(name, () => init(this));
418+
}
419+
413420
/**
414421
* Deletes the FirebaseApp instance.
415422
*

src/instance-id/index.ts

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { app } from '../firebase-namespace-api';
17+
import { FirebaseApp } from '../app/firebase-app';
18+
import { App, getApp } from '../app/index';
19+
import { InstanceId } from './instance-id';
20+
21+
export { InstanceId };
1822

1923
/**
2024
* Gets the {@link instanceId.InstanceId `InstanceId`} service for the
@@ -46,40 +50,18 @@ import { app } from '../firebase-namespace-api';
4650
* no app is provided or the `InstanceId` service associated with the
4751
* provided app.
4852
*/
49-
export declare function instanceId(app?: app.App): instanceId.InstanceId;
53+
export function instanceId(app?: App): InstanceId {
54+
if (typeof app === 'undefined') {
55+
app = getApp();
56+
}
57+
58+
const firebaseApp: FirebaseApp = app as FirebaseApp;
59+
return firebaseApp.getOrInitService('instanceId', (app) => new InstanceId(app));
60+
}
61+
62+
import { InstanceId as TInstanceId } from './instance-id';
5063

5164
/* eslint-disable @typescript-eslint/no-namespace */
5265
export namespace instanceId {
53-
/**
54-
* Gets the {@link InstanceId `InstanceId`} service for the
55-
* current app.
56-
*
57-
* @example
58-
* ```javascript
59-
* var instanceId = app.instanceId();
60-
* // The above is shorthand for:
61-
* // var instanceId = admin.instanceId(app);
62-
* ```
63-
*
64-
* @return The `InstanceId` service for the
65-
* current app.
66-
*/
67-
export interface InstanceId {
68-
app: app.App;
69-
70-
/**
71-
* Deletes the specified instance ID and the associated data from Firebase.
72-
*
73-
* Note that Google Analytics for Firebase uses its own form of Instance ID to
74-
* keep track of analytics data. Therefore deleting a Firebase Instance ID does
75-
* not delete Analytics data. See
76-
* [Delete an Instance ID](/support/privacy/manage-iids#delete_an_instance_id)
77-
* for more information.
78-
*
79-
* @param instanceId The instance ID to be deleted.
80-
*
81-
* @return A promise fulfilled when the instance ID is deleted.
82-
*/
83-
deleteInstanceId(instanceId: string): Promise<void>;
84-
}
66+
export type InstanceId = TInstanceId;
8567
}

src/instance-id/instance-id-request-internal.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18+
import { App } from '../app/index';
1819
import { FirebaseApp } from '../app/firebase-app';
1920
import { FirebaseInstanceIdError, InstanceIdClientErrorCode } from '../utils/error';
2021
import {
@@ -54,12 +55,12 @@ export class FirebaseInstanceIdRequestHandler {
5455
private path: string;
5556

5657
/**
57-
* @param {FirebaseApp} app The app used to fetch access tokens to sign API requests.
58+
* @param app The app used to fetch access tokens to sign API requests.
5859
*
5960
* @constructor
6061
*/
61-
constructor(private readonly app: FirebaseApp) {
62-
this.httpClient = new AuthorizedHttpClient(app);
62+
constructor(private readonly app: App) {
63+
this.httpClient = new AuthorizedHttpClient(app as FirebaseApp);
6364
}
6465

6566
public deleteInstanceId(instanceId: string): Promise<void> {

src/instance-id/instance-id.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,11 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { FirebaseApp } from '../app/firebase-app';
17+
import { App } from '../app/index';
1818
import { FirebaseInstanceIdError, InstanceIdClientErrorCode } from '../utils/error';
1919
import { FirebaseInstanceIdRequestHandler } from './instance-id-request-internal';
20-
import { instanceId } from './index';
2120
import * as validator from '../utils/validator';
2221

23-
import InstanceIdInterface = instanceId.InstanceId;
24-
2522
/**
2623
* Gets the {@link InstanceId `InstanceId`} service for the
2724
* current app.
@@ -36,20 +33,21 @@ import InstanceIdInterface = instanceId.InstanceId;
3633
* @return The `InstanceId` service for the
3734
* current app.
3835
*/
39-
export class InstanceId implements InstanceIdInterface {
36+
export class InstanceId {
4037

41-
private app_: FirebaseApp;
38+
private app_: App;
4239
private requestHandler: FirebaseInstanceIdRequestHandler;
4340

4441
/**
45-
* @param {FirebaseApp} app The app for this InstanceId service.
42+
* @param app The app for this InstanceId service.
4643
* @constructor
44+
* @internal
4745
*/
48-
constructor(app: FirebaseApp) {
46+
constructor(app: App) {
4947
if (!validator.isNonNullObject(app) || !('options' in app)) {
5048
throw new FirebaseInstanceIdError(
5149
InstanceIdClientErrorCode.INVALID_ARGUMENT,
52-
'First argument passed to admin.instanceId() must be a valid Firebase app instance.',
50+
'First argument passed to instanceId() must be a valid Firebase app instance.',
5351
);
5452
}
5553

@@ -80,9 +78,9 @@ export class InstanceId implements InstanceIdInterface {
8078
/**
8179
* Returns the app associated with this InstanceId instance.
8280
*
83-
* @return {FirebaseApp} The app associated with this InstanceId instance.
81+
* @return The app associated with this InstanceId instance.
8482
*/
85-
get app(): FirebaseApp {
83+
get app(): App {
8684
return this.app_;
8785
}
8886
}

src/utils/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { app as _app } from '../firebase-namespace-api';
18+
import { App } from '../app/index';
1919
import {
2020
ServiceAccountCredential, ComputeEngineCredential
2121
} from '../credential/credential-internal';
2222
import * as validator from './validator';
2323

2424
let sdkVersion: string;
2525

26+
// TODO: Move to firebase-admin/app as an internal member.
2627
export function getSdkVersion(): string {
2728
if (!sdkVersion) {
2829
const { version } = require('../../package.json'); // eslint-disable-line @typescript-eslint/no-var-requires
@@ -76,7 +77,7 @@ export function addReadonlyGetter(obj: object, prop: string, value: any): void {
7677
*
7778
* @return A project ID string or null.
7879
*/
79-
export function getExplicitProjectId(app: _app.App): string | null {
80+
export function getExplicitProjectId(app: App): string | null {
8081
const options = app.options;
8182
if (validator.isNonEmptyString(options.projectId)) {
8283
return options.projectId;
@@ -105,7 +106,7 @@ export function getExplicitProjectId(app: _app.App): string | null {
105106
*
106107
* @return A project ID string or null.
107108
*/
108-
export function findProjectId(app: _app.App): Promise<string | null> {
109+
export function findProjectId(app: App): Promise<string | null> {
109110
const projectId = getExplicitProjectId(app);
110111
if (projectId) {
111112
return Promise.resolve(projectId);

test/unit/index.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ import './storage/storage.spec';
6060
import './firestore/firestore.spec';
6161

6262
// InstanceId
63+
import './instance-id/index.spec';
6364
import './instance-id/instance-id.spec';
6465
import './instance-id/instance-id-request.spec';
6566

test/unit/instance-id/index.spec.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*!
2+
* @license
3+
* Copyright 2021 Google Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
'use strict';
19+
20+
import * as chai from 'chai';
21+
import * as sinonChai from 'sinon-chai';
22+
import * as chaiAsPromised from 'chai-as-promised';
23+
24+
import * as mocks from '../../resources/mocks';
25+
import { App } from '../../../src/app/index';
26+
import { instanceId, InstanceId } from '../../../src/instance-id/index';
27+
28+
chai.should();
29+
chai.use(sinonChai);
30+
chai.use(chaiAsPromised);
31+
32+
const expect = chai.expect;
33+
34+
describe('InstanceId', () => {
35+
let mockApp: App;
36+
let mockCredentialApp: App;
37+
38+
const noProjectIdError = 'Failed to determine project ID for InstanceId. Initialize the SDK '
39+
+ 'with service account credentials or set project ID as an app option. Alternatively set the '
40+
+ 'GOOGLE_CLOUD_PROJECT environment variable.';
41+
42+
beforeEach(() => {
43+
mockApp = mocks.app();
44+
mockCredentialApp = mocks.mockCredentialApp();
45+
});
46+
47+
describe('instanceId()', () => {
48+
it('should throw when default app is not available', () => {
49+
expect(() => {
50+
return instanceId();
51+
}).to.throw('The default Firebase app does not exist.');
52+
});
53+
54+
it('should reject given an invalid credential without project ID', () => {
55+
// Project ID not set in the environment.
56+
delete process.env.GOOGLE_CLOUD_PROJECT;
57+
delete process.env.GCLOUD_PROJECT;
58+
const iid = instanceId(mockCredentialApp);
59+
return iid.deleteInstanceId('iid')
60+
.should.eventually.rejectedWith(noProjectIdError);
61+
});
62+
63+
it('should not throw given a valid app', () => {
64+
expect(() => {
65+
return instanceId(mockApp);
66+
}).not.to.throw();
67+
});
68+
69+
it('should return the same instance for a given app instance', () => {
70+
const iid1: InstanceId = instanceId(mockApp);
71+
const iid2: InstanceId = instanceId(mockApp);
72+
expect(iid1).to.equal(iid2);
73+
});
74+
});
75+
});

test/unit/instance-id/instance-id.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,15 @@ describe('InstanceId', () => {
8383
expect(() => {
8484
const iidAny: any = InstanceId;
8585
return new iidAny(invalidApp);
86-
}).to.throw('First argument passed to admin.instanceId() must be a valid Firebase app instance.');
86+
}).to.throw('First argument passed to instanceId() must be a valid Firebase app instance.');
8787
});
8888
});
8989

9090
it('should throw given no app', () => {
9191
expect(() => {
9292
const iidAny: any = InstanceId;
9393
return new iidAny();
94-
}).to.throw('First argument passed to admin.instanceId() must be a valid Firebase app instance.');
94+
}).to.throw('First argument passed to instanceId() must be a valid Firebase app instance.');
9595
});
9696

9797
it('should reject given an invalid credential without project ID', () => {

0 commit comments

Comments
 (0)