Skip to content

Commit 0f9a7de

Browse files
authored
feat(fis): Adding the admin.installations() API for deleting Firebase installation IDs (#1187)
* feat(fis): Added admin.installations() API * fix: Marked IID APIs deprecated * fix: Deprecated App.instanceId() method; Added more unit and integration tests * fix: Throwing FirebaseInstallationsError from constructor * fix: Some docs updates * fix: Minor update to API doc comment * fix: Added Installations class to API ref toc * fix: Minor doc updates
1 parent 9872b9b commit 0f9a7de

20 files changed

+617
-75
lines changed

docgen/content-sources/node/toc.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@ toc:
144144
- title: "admin.firestore"
145145
path: /docs/reference/admin/node/admin.firestore
146146

147+
- title: "admin.installations"
148+
path: /docs/reference/admin/node/admin.installations
149+
section:
150+
- title: "Installations"
151+
path: /docs/reference/admin/node/admin.installations.Installations-1
152+
147153
- title: "admin.instanceId"
148154
path: /docs/reference/admin/node/admin.instanceId
149155
section:

etc/firebase-admin.api.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ export namespace app {
2525
// (undocumented)
2626
firestore(): firestore.Firestore;
2727
// (undocumented)
28+
installations(): installations.Installations;
29+
// @deprecated (undocumented)
2830
instanceId(): instanceId.InstanceId;
2931
// (undocumented)
3032
machineLearning(): machineLearning.MachineLearning;
@@ -542,13 +544,27 @@ export interface GoogleOAuthAccessToken {
542544
export function initializeApp(options?: AppOptions, name?: string): app.App;
543545

544546
// @public
547+
export function installations(app?: app.App): installations.Installations;
548+
549+
// @public (undocumented)
550+
export namespace installations {
551+
export interface Installations {
552+
// (undocumented)
553+
app: app.App;
554+
deleteInstallation(fid: string): Promise<void>;
555+
}
556+
}
557+
558+
// @public @deprecated
545559
export function instanceId(app?: app.App): instanceId.InstanceId;
546560

547561
// @public (undocumented)
548562
export namespace instanceId {
563+
// @deprecated
549564
export interface InstanceId {
550565
// (undocumented)
551566
app: app.App;
567+
// @deprecated
552568
deleteInstanceId(instanceId: string): Promise<void>;
553569
}
554570
}

src/firebase-app.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +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 { Installations } from './installations/installations';
3435
import { InstanceId } from './instance-id/instance-id';
3536
import { ProjectManagement } from './project-management/project-management';
3637
import { SecurityRules } from './security-rules/security-rules';
@@ -256,9 +257,23 @@ export class FirebaseApp implements app.App {
256257
return service.client;
257258
}
258259

260+
/**
261+
* Returns the `Installations` service instance associated with this app.
262+
*
263+
* @return The `Installations` service instance of this app.
264+
*/
265+
public installations(): Installations {
266+
return this.ensureService_('installations', () => {
267+
const fisService: typeof Installations = require('./installations/installations').Installations;
268+
return new fisService(this);
269+
});
270+
}
271+
259272
/**
260273
* Returns the InstanceId service instance associated with this app.
261274
*
275+
* This API is deprecated. Use the `installations()` API instead.
276+
*
262277
* @return The InstanceId service instance of this app.
263278
*/
264279
public instanceId(): InstanceId {

src/firebase-namespace-api.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { auth } from './auth/index';
2020
import { credential } from './credential/index';
2121
import { database } from './database/index';
2222
import { firestore } from './firestore/index';
23+
import { installations } from './installations/index';
2324
import { instanceId } from './instance-id/index';
2425
import { machineLearning } from './machine-learning/index';
2526
import { messaging } from './messaging/index';
@@ -227,6 +228,8 @@ export namespace app {
227228
auth(): auth.Auth;
228229
database(url?: string): database.Database;
229230
firestore(): firestore.Firestore;
231+
installations(): installations.Installations;
232+
/** @deprecated */
230233
instanceId(): instanceId.InstanceId;
231234
machineLearning(): machineLearning.MachineLearning;
232235
messaging(): messaging.Messaging;

src/firebase-namespace.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export * from './app-check/index';
2020
export * from './auth/index';
2121
export * from './database/index';
2222
export * from './firestore/index';
23+
export * from './installations/index';
2324
export * from './instance-id/index';
2425
export * from './machine-learning/index';
2526
export * from './messaging/index';

src/firebase-namespace.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { appCheck } from './app-check/index';
2727
import { auth } from './auth/index';
2828
import { database } from './database/index';
2929
import { firestore } from './firestore/index';
30+
import { installations } from './installations/index';
3031
import { instanceId } from './instance-id/index';
3132
import { machineLearning } from './machine-learning/index';
3233
import { messaging } from './messaging/index';
@@ -43,6 +44,7 @@ import AppCheck = appCheck.AppCheck;
4344
import Auth = auth.Auth;
4445
import Database = database.Database;
4546
import Firestore = firestore.Firestore;
47+
import Installations = installations.Installations;
4648
import InstanceId = instanceId.InstanceId;
4749
import MachineLearning = machineLearning.MachineLearning;
4850
import Messaging = messaging.Messaging;
@@ -311,6 +313,18 @@ export class FirebaseNamespace {
311313
return Object.assign(fn, { MachineLearning: machineLearning });
312314
}
313315

316+
/**
317+
* Gets the `Installations` service namespace. The returned namespace can be used to get the
318+
* `Installations` service for the default app or an explicitly specified app.
319+
*/
320+
get installations(): FirebaseServiceNamespace<Installations> {
321+
const fn: FirebaseServiceNamespace<Installations> = (app?: App) => {
322+
return this.ensureApp(app).installations();
323+
};
324+
const installations = require('./installations/installations').Installations;
325+
return Object.assign(fn, { Installations: installations });
326+
}
327+
314328
/**
315329
* Gets the `InstanceId` service namespace. The returned namespace can be used to get the
316330
* `Instance` service for the default app or an explicitly specified app.

src/installations/index.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*!
2+
* Copyright 2021 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { app } from '../firebase-namespace-api';
18+
19+
/**
20+
* Gets the {@link installations.Installations `Installations`} service for the
21+
* default app or a given app.
22+
*
23+
* `admin.installations()` can be called with no arguments to access the default
24+
* app's {@link installations.Installations `Installations`} service or as
25+
* `admin.installations(app)` to access the
26+
* {@link installations.Installations `Installations`} service associated with a
27+
* specific app.
28+
*
29+
* @example
30+
* ```javascript
31+
* // Get the Installations service for the default app
32+
* var defaultInstallations = admin.installations();
33+
* ```
34+
*
35+
* @example
36+
* ```javascript
37+
* // Get the Installations service for a given app
38+
* var otherInstallations = admin.installations(otherApp);
39+
*```
40+
*
41+
* @param app Optional app whose `Installations` service to
42+
* return. If not provided, the default `Installations` service is
43+
* returned.
44+
*
45+
* @return The default `Installations` service if
46+
* no app is provided or the `Installations` service associated with the
47+
* provided app.
48+
*/
49+
export declare function installations(app?: app.App): installations.Installations;
50+
51+
/* eslint-disable @typescript-eslint/no-namespace */
52+
export namespace installations {
53+
/**
54+
* Gets the {@link Installations `Installations`} service for the
55+
* current app.
56+
*
57+
* @example
58+
* ```javascript
59+
* var installations = app.installations();
60+
* // The above is shorthand for:
61+
* // var installations = admin.installations(app);
62+
* ```
63+
*
64+
* @return The `Installations` service for the
65+
* current app.
66+
*/
67+
export interface Installations {
68+
app: app.App;
69+
70+
/**
71+
* Deletes the specified installation 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 installation ID does
75+
* not delete Analytics data. See
76+
* [Delete a Firebase installation](/docs/projects/manage-installations#delete-installation)
77+
* for more information.
78+
*
79+
* @param fid The Firebase installation ID to be deleted.
80+
*
81+
* @return A promise fulfilled when the installation ID is deleted.
82+
*/
83+
deleteInstallation(fid: string): Promise<void>;
84+
}
85+
}

src/instance-id/instance-id-request-internal.ts renamed to src/installations/installations-request-handler.ts

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*!
22
* @license
3-
* Copyright 2017 Google Inc.
3+
* Copyright 2021 Google Inc.
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
1616
*/
1717

1818
import { FirebaseApp } from '../firebase-app';
19-
import { FirebaseInstanceIdError, InstanceIdClientErrorCode } from '../utils/error';
19+
import { FirebaseInstallationsError, InstallationsClientErrorCode } from '../utils/error';
2020
import {
2121
ApiSettings, AuthorizedHttpClient, HttpRequestConfig, HttpError,
2222
} from '../utils/api-request';
@@ -33,50 +33,50 @@ const FIREBASE_IID_TIMEOUT = 10000;
3333

3434
/** HTTP error codes raised by the backend server. */
3535
const ERROR_CODES: {[key: number]: string} = {
36-
400: 'Malformed instance ID argument.',
36+
400: 'Malformed installation ID argument.',
3737
401: 'Request not authorized.',
38-
403: 'Project does not match instance ID or the client does not have sufficient privileges.',
39-
404: 'Failed to find the instance ID.',
38+
403: 'Project does not match installation ID or the client does not have sufficient privileges.',
39+
404: 'Failed to find the installation ID.',
4040
409: 'Already deleted.',
4141
429: 'Request throttled out by the backend server.',
4242
500: 'Internal server error.',
4343
503: 'Backend servers are over capacity. Try again later.',
4444
};
4545

4646
/**
47-
* Class that provides mechanism to send requests to the Firebase Instance ID backend endpoints.
47+
* Class that provides mechanism to send requests to the FIS backend endpoints.
4848
*/
49-
export class FirebaseInstanceIdRequestHandler {
49+
export class FirebaseInstallationsRequestHandler {
5050

5151
private readonly host: string = FIREBASE_IID_HOST;
5252
private readonly timeout: number = FIREBASE_IID_TIMEOUT;
5353
private readonly httpClient: AuthorizedHttpClient;
5454
private path: string;
5555

5656
/**
57-
* @param {FirebaseApp} app The app used to fetch access tokens to sign API requests.
57+
* @param app The app used to fetch access tokens to sign API requests.
5858
*
5959
* @constructor
6060
*/
6161
constructor(private readonly app: FirebaseApp) {
6262
this.httpClient = new AuthorizedHttpClient(app);
6363
}
6464

65-
public deleteInstanceId(instanceId: string): Promise<void> {
66-
if (!validator.isNonEmptyString(instanceId)) {
67-
return Promise.reject(new FirebaseInstanceIdError(
68-
InstanceIdClientErrorCode.INVALID_INSTANCE_ID,
69-
'Instance ID must be a non-empty string.',
65+
public deleteInstallation(fid: string): Promise<void> {
66+
if (!validator.isNonEmptyString(fid)) {
67+
return Promise.reject(new FirebaseInstallationsError(
68+
InstallationsClientErrorCode.INVALID_INSTALLATION_ID,
69+
'Installation ID must be a non-empty string.',
7070
));
7171
}
72-
return this.invokeRequestHandler(new ApiSettings(instanceId, 'DELETE'));
72+
return this.invokeRequestHandler(new ApiSettings(fid, 'DELETE'));
7373
}
7474

7575
/**
7676
* Invokes the request handler based on the API settings object passed.
7777
*
78-
* @param {ApiSettings} apiSettings The API endpoint settings to apply to request and response.
79-
* @return {Promise<void>} A promise that resolves when the request is complete.
78+
* @param apiSettings The API endpoint settings to apply to request and response.
79+
* @return A promise that resolves when the request is complete.
8080
*/
8181
private invokeRequestHandler(apiSettings: ApiSettings): Promise<void> {
8282
return this.getPathPrefix()
@@ -98,8 +98,8 @@ export class FirebaseInstanceIdRequestHandler {
9898
response.data.error : response.text;
9999
const template: string = ERROR_CODES[response.status];
100100
const message: string = template ?
101-
`Instance ID "${apiSettings.getEndpoint()}": ${template}` : errorMessage;
102-
throw new FirebaseInstanceIdError(InstanceIdClientErrorCode.API_ERROR, message);
101+
`Installation ID "${apiSettings.getEndpoint()}": ${template}` : errorMessage;
102+
throw new FirebaseInstallationsError(InstallationsClientErrorCode.API_ERROR, message);
103103
}
104104
// In case of timeouts and other network errors, the HttpClient returns a
105105
// FirebaseError wrapped in the response. Simply throw it here.
@@ -116,9 +116,9 @@ export class FirebaseInstanceIdRequestHandler {
116116
.then((projectId) => {
117117
if (!validator.isNonEmptyString(projectId)) {
118118
// Assert for an explicit projct ID (either via AppOptions or the cert itself).
119-
throw new FirebaseInstanceIdError(
120-
InstanceIdClientErrorCode.INVALID_PROJECT_ID,
121-
'Failed to determine project ID for InstanceId. Initialize the '
119+
throw new FirebaseInstallationsError(
120+
InstallationsClientErrorCode.INVALID_PROJECT_ID,
121+
'Failed to determine project ID for Installations. Initialize the '
122122
+ 'SDK with service account credentials or set project ID as an app option. '
123123
+ 'Alternatively set the GOOGLE_CLOUD_PROJECT environment variable.',
124124
);

0 commit comments

Comments
 (0)