Skip to content

feat: Added instanceId() modularized API #1136

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions etc/firebase-admin.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,15 +498,18 @@ export interface GoogleOAuthAccessToken {
export function initializeApp(options?: AppOptions, name?: string): app.App;

// @public
export function instanceId(app?: app.App): instanceId.InstanceId;
export class InstanceId {
get app(): App;
deleteInstanceId(instanceId: string): Promise<void>;
}
Copy link
Member

Choose a reason for hiding this comment

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

This is generated from the api-extractor, isn't it? Is there an indentation issue here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, this is auto-generated. Not sure what we can do about the indentation issue. Everything looks good in source and the generated d.ts files.


// @public
export function instanceId(app?: App): InstanceId;

// @public (undocumented)
export namespace instanceId {
export interface InstanceId {
// (undocumented)
app: app.App;
deleteInstanceId(instanceId: string): Promise<void>;
}
// (undocumented)
export type InstanceId = InstanceId;
}

// @public
Expand Down
1 change: 1 addition & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ gulp.task('compile', function() {
'lib/firebase-namespace-api.d.ts',
'lib/core.d.ts',
'lib/app/*.d.ts',
'lib/instance-id/*.d.ts',
'!lib/utils/index.d.ts',
];

Expand Down
17 changes: 12 additions & 5 deletions src/app/firebase-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { database } from '../database/index';
import { DatabaseService } from '../database/database-internal';
import { Firestore } from '@google-cloud/firestore';
import { FirestoreService } from '../firestore/firestore-internal';
import { InstanceId } from '../instance-id/instance-id';
import { InstanceId } from '../instance-id/index';
import { ProjectManagement } from '../project-management/project-management';
import { SecurityRules } from '../security-rules/security-rules';
import { RemoteConfig } from '../remote-config/remote-config';
Expand Down Expand Up @@ -231,6 +231,8 @@ export class FirebaseAppInternals {

/**
* Global context object for a collection of services using a shared authentication state.
*
* @internal
*/
export class FirebaseApp implements app.App {
public INTERNAL: FirebaseAppInternals;
Expand Down Expand Up @@ -333,10 +335,8 @@ export class FirebaseApp implements app.App {
* @return The InstanceId service instance of this app.
*/
public instanceId(): InstanceId {
return this.ensureService_('iid', () => {
const iidService: typeof InstanceId = require('../instance-id/instance-id').InstanceId;
return new iidService(this);
});
const fn = require('../instance-id/index').instanceId;
return fn(this);
}

/**
Expand Down Expand Up @@ -410,6 +410,13 @@ export class FirebaseApp implements app.App {
return deepCopy(this.options_);
}

/**
* @internal
*/
public getOrInitService<T>(name: string, init: (app: FirebaseApp) => T): T {
return this.ensureService_(name, () => init(this));
}

/**
* Deletes the FirebaseApp instance.
*
Expand Down
50 changes: 16 additions & 34 deletions src/instance-id/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
* limitations under the License.
*/

import { app } from '../firebase-namespace-api';
import { FirebaseApp } from '../app/firebase-app';
import { App, getApp } from '../app/index';
import { InstanceId } from './instance-id';

export { InstanceId };

/**
* Gets the {@link instanceId.InstanceId `InstanceId`} service for the
Expand Down Expand Up @@ -46,40 +50,18 @@ import { app } from '../firebase-namespace-api';
* no app is provided or the `InstanceId` service associated with the
* provided app.
*/
export declare function instanceId(app?: app.App): instanceId.InstanceId;
export function instanceId(app?: App): InstanceId {
if (typeof app === 'undefined') {
app = getApp();
}

const firebaseApp: FirebaseApp = app as FirebaseApp;
return firebaseApp.getOrInitService('instanceId', (app) => new InstanceId(app));
}

import { InstanceId as TInstanceId } from './instance-id';

/* eslint-disable @typescript-eslint/no-namespace */
export namespace instanceId {
/**
* Gets the {@link InstanceId `InstanceId`} service for the
* current app.
*
* @example
* ```javascript
* var instanceId = app.instanceId();
* // The above is shorthand for:
* // var instanceId = admin.instanceId(app);
* ```
*
* @return The `InstanceId` service for the
* current app.
*/
export interface InstanceId {
app: app.App;

/**
* Deletes the specified instance ID and the associated data from Firebase.
*
* Note that Google Analytics for Firebase uses its own form of Instance ID to
* keep track of analytics data. Therefore deleting a Firebase Instance ID does
* not delete Analytics data. See
* [Delete an Instance ID](/support/privacy/manage-iids#delete_an_instance_id)
* for more information.
*
* @param instanceId The instance ID to be deleted.
*
* @return A promise fulfilled when the instance ID is deleted.
*/
deleteInstanceId(instanceId: string): Promise<void>;
}
export type InstanceId = TInstanceId;
}
7 changes: 4 additions & 3 deletions src/instance-id/instance-id-request-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* limitations under the License.
*/

import { App } from '../app/index';
import { FirebaseApp } from '../app/firebase-app';
import { FirebaseInstanceIdError, InstanceIdClientErrorCode } from '../utils/error';
import {
Expand Down Expand Up @@ -54,12 +55,12 @@ export class FirebaseInstanceIdRequestHandler {
private path: string;

/**
* @param {FirebaseApp} app The app used to fetch access tokens to sign API requests.
* @param app The app used to fetch access tokens to sign API requests.
*
* @constructor
*/
constructor(private readonly app: FirebaseApp) {
this.httpClient = new AuthorizedHttpClient(app);
constructor(private readonly app: App) {
this.httpClient = new AuthorizedHttpClient(app as FirebaseApp);
}

public deleteInstanceId(instanceId: string): Promise<void> {
Expand Down
20 changes: 9 additions & 11 deletions src/instance-id/instance-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,11 @@
* limitations under the License.
*/

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

import InstanceIdInterface = instanceId.InstanceId;

/**
* Gets the {@link InstanceId `InstanceId`} service for the
* current app.
Expand All @@ -36,20 +33,21 @@ import InstanceIdInterface = instanceId.InstanceId;
* @return The `InstanceId` service for the
* current app.
*/
export class InstanceId implements InstanceIdInterface {
export class InstanceId {

private app_: FirebaseApp;
private app_: App;
private requestHandler: FirebaseInstanceIdRequestHandler;

/**
* @param {FirebaseApp} app The app for this InstanceId service.
* @param app The app for this InstanceId service.
* @constructor
* @internal
*/
constructor(app: FirebaseApp) {
constructor(app: App) {
if (!validator.isNonNullObject(app) || !('options' in app)) {
throw new FirebaseInstanceIdError(
InstanceIdClientErrorCode.INVALID_ARGUMENT,
'First argument passed to admin.instanceId() must be a valid Firebase app instance.',
'First argument passed to instanceId() must be a valid Firebase app instance.',
);
}

Expand Down Expand Up @@ -80,9 +78,9 @@ export class InstanceId implements InstanceIdInterface {
/**
* Returns the app associated with this InstanceId instance.
*
* @return {FirebaseApp} The app associated with this InstanceId instance.
* @return The app associated with this InstanceId instance.
*/
get app(): FirebaseApp {
get app(): App {
return this.app_;
}
}
7 changes: 4 additions & 3 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@
* limitations under the License.
*/

import { app as _app } from '../firebase-namespace-api';
import { App } from '../app/index';
import {
ServiceAccountCredential, ComputeEngineCredential
} from '../credential/credential-internal';
import * as validator from './validator';

let sdkVersion: string;

// TODO: Move to firebase-admin/app as an internal member.
export function getSdkVersion(): string {
if (!sdkVersion) {
const { version } = require('../../package.json'); // eslint-disable-line @typescript-eslint/no-var-requires
Expand Down Expand Up @@ -76,7 +77,7 @@ export function addReadonlyGetter(obj: object, prop: string, value: any): void {
*
* @return A project ID string or null.
*/
export function getExplicitProjectId(app: _app.App): string | null {
export function getExplicitProjectId(app: App): string | null {
const options = app.options;
if (validator.isNonEmptyString(options.projectId)) {
return options.projectId;
Expand Down Expand Up @@ -105,7 +106,7 @@ export function getExplicitProjectId(app: _app.App): string | null {
*
* @return A project ID string or null.
*/
export function findProjectId(app: _app.App): Promise<string | null> {
export function findProjectId(app: App): Promise<string | null> {
const projectId = getExplicitProjectId(app);
if (projectId) {
return Promise.resolve(projectId);
Expand Down
1 change: 1 addition & 0 deletions test/unit/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import './storage/storage.spec';
import './firestore/firestore.spec';

// InstanceId
import './instance-id/index.spec';
import './instance-id/instance-id.spec';
import './instance-id/instance-id-request.spec';

Expand Down
75 changes: 75 additions & 0 deletions test/unit/instance-id/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*!
* @license
* Copyright 2021 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.
*/

'use strict';

import * as chai from 'chai';
import * as sinonChai from 'sinon-chai';
import * as chaiAsPromised from 'chai-as-promised';

import * as mocks from '../../resources/mocks';
import { App } from '../../../src/app/index';
import { instanceId, InstanceId } from '../../../src/instance-id/index';

chai.should();
chai.use(sinonChai);
chai.use(chaiAsPromised);

const expect = chai.expect;

describe('InstanceId', () => {
let mockApp: App;
let mockCredentialApp: App;

const noProjectIdError = 'Failed to determine project ID for InstanceId. Initialize the SDK '
+ 'with service account credentials or set project ID as an app option. Alternatively set the '
+ 'GOOGLE_CLOUD_PROJECT environment variable.';

beforeEach(() => {
mockApp = mocks.app();
mockCredentialApp = mocks.mockCredentialApp();
});

describe('instanceId()', () => {
it('should throw when default app is not available', () => {
expect(() => {
return instanceId();
}).to.throw('The default Firebase app does not exist.');
});

it('should reject given an invalid credential without project ID', () => {
// Project ID not set in the environment.
delete process.env.GOOGLE_CLOUD_PROJECT;
delete process.env.GCLOUD_PROJECT;
const iid = instanceId(mockCredentialApp);
return iid.deleteInstanceId('iid')
.should.eventually.rejectedWith(noProjectIdError);
});

it('should not throw given a valid app', () => {
expect(() => {
return instanceId(mockApp);
}).not.to.throw();
});

it('should return the same instance for a given app instance', () => {
const iid1: InstanceId = instanceId(mockApp);
const iid2: InstanceId = instanceId(mockApp);
expect(iid1).to.equal(iid2);
});
});
});
4 changes: 2 additions & 2 deletions test/unit/instance-id/instance-id.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,15 @@ describe('InstanceId', () => {
expect(() => {
const iidAny: any = InstanceId;
return new iidAny(invalidApp);
}).to.throw('First argument passed to admin.instanceId() must be a valid Firebase app instance.');
}).to.throw('First argument passed to instanceId() must be a valid Firebase app instance.');
});
});

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

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