Skip to content

Commit 031edc2

Browse files
authored
Allow instance-id to auto-generate typings, separate internal vs external APIs (#969)
* Allow instance-id to auto-generate typings, separate internal vs external APIs (#969)
1 parent 300f7ab commit 031edc2

File tree

8 files changed

+167
-73
lines changed

8 files changed

+167
-73
lines changed

gulpfile.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ var paths = {
5252

5353
build: 'lib/',
5454

55-
curatedTypings: ['src/*.d.ts'],
55+
curatedTypings: ['src/*.d.ts', '!src/instance-id.d.ts'],
5656
};
5757

5858
const TEMPORARY_TYPING_EXCLUDES = [
@@ -63,7 +63,6 @@ const TEMPORARY_TYPING_EXCLUDES = [
6363
'!lib/auth/*.d.ts',
6464
'!lib/database/*.d.ts',
6565
'!lib/firestore/*.d.ts',
66-
'!lib/instance-id/*.d.ts',
6766
'!lib/machine-learning/*.d.ts',
6867
'!lib/messaging/*.d.ts',
6968
'!lib/project-management/*.d.ts',

src/firebase-app.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { DatabaseService } from './database/database';
3030
import { Firestore } from '@google-cloud/firestore';
3131
import { FirestoreService } from './firestore/firestore';
3232
import { InstanceId } from './instance-id/instance-id';
33+
import { InstanceIdImpl } from './instance-id/instance-id-internal';
3334

3435
import { ProjectManagement } from './project-management/project-management';
3536
import { SecurityRules } from './security-rules/security-rules';
@@ -352,7 +353,7 @@ export class FirebaseApp {
352353
*/
353354
public instanceId(): InstanceId {
354355
return this.ensureService_('iid', () => {
355-
const iidService: typeof InstanceId = require('./instance-id/instance-id').InstanceId;
356+
const iidService: typeof InstanceIdImpl = require('./instance-id/instance-id-internal').InstanceIdImpl;
356357
return new iidService(this);
357358
});
358359
}

src/firebase-namespace.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ export class FirebaseNamespace {
425425
const fn: FirebaseServiceNamespace<InstanceId> = (app?: FirebaseApp) => {
426426
return this.ensureApp(app).instanceId();
427427
};
428-
const instanceId = require('./instance-id/instance-id').InstanceId;
428+
const instanceId = require('./instance-id/instance-id-internal').InstanceIdImpl;
429429
return Object.assign(fn, { InstanceId: instanceId });
430430
}
431431

src/instance-id/index.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*!
2+
* Copyright 2020 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 { FirebaseApp } from '../firebase-app';
18+
import * as instanceIdApi from './instance-id';
19+
import * as firebaseAdmin from '../index';
20+
21+
export function instanceId(app?: FirebaseApp): instanceIdApi.InstanceId {
22+
if (typeof(app) === 'undefined') {
23+
app = firebaseAdmin.app();
24+
}
25+
return app.instanceId();
26+
}
27+
28+
/**
29+
* We must define a namespace to make the typings work correctly. Otherwise
30+
* `admin.instanceId()` cannot be called like a function. Temporarily,
31+
* admin.instanceId is used as the namespace name because we cannot barrel
32+
* re-export the contents from instance-id, and we want it to
33+
* match the namespacing in the re-export inside src/index.d.ts
34+
*/
35+
/* eslint-disable @typescript-eslint/no-namespace */
36+
export namespace admin.instanceId {
37+
// See https://github.com/microsoft/TypeScript/issues/4336
38+
/* eslint-disable @typescript-eslint/no-unused-vars */
39+
// See https://github.com/typescript-eslint/typescript-eslint/issues/363
40+
export import InstanceId = instanceIdApi.InstanceId;
41+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*!
2+
* Copyright 2020 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 { FirebaseApp } from '../firebase-app';
18+
import { InstanceId } from './instance-id';
19+
import { FirebaseInstanceIdError, InstanceIdClientErrorCode } from '../utils/error';
20+
import { FirebaseServiceInterface, FirebaseServiceInternalsInterface } from '../firebase-service';
21+
import { FirebaseInstanceIdRequestHandler } from './instance-id-request';
22+
23+
import * as validator from '../utils/validator';
24+
25+
/**
26+
* Internals of an InstanceId service instance.
27+
*/
28+
class InstanceIdInternals implements FirebaseServiceInternalsInterface {
29+
/**
30+
* Deletes the service and its associated resources.
31+
*
32+
* @return {Promise<()>} An empty Promise that will be fulfilled when the service is deleted.
33+
*/
34+
public delete(): Promise<void> {
35+
// There are no resources to clean up
36+
return Promise.resolve(undefined);
37+
}
38+
}
39+
40+
export class InstanceIdImpl implements FirebaseServiceInterface, InstanceId {
41+
public INTERNAL: InstanceIdInternals = new InstanceIdInternals();
42+
43+
private app_: FirebaseApp;
44+
private requestHandler: FirebaseInstanceIdRequestHandler;
45+
46+
/**
47+
* @param {FirebaseApp} app The app for this InstanceId service.
48+
* @constructor
49+
*/
50+
constructor(app: FirebaseApp) {
51+
if (!validator.isNonNullObject(app) || !('options' in app)) {
52+
throw new FirebaseInstanceIdError(
53+
InstanceIdClientErrorCode.INVALID_ARGUMENT,
54+
'First argument passed to admin.instanceId() must be a valid Firebase app instance.',
55+
);
56+
}
57+
58+
this.app_ = app;
59+
this.requestHandler = new FirebaseInstanceIdRequestHandler(app);
60+
}
61+
62+
/**
63+
* Deletes the specified instance ID from Firebase. This can be used to delete an instance ID
64+
* and associated user data from a Firebase project, pursuant to the General Data Protection
65+
* Regulation (GDPR).
66+
*
67+
* @param {string} instanceId The instance ID to be deleted
68+
* @return {Promise<void>} A promise that resolves when the instance ID is successfully deleted.
69+
*/
70+
public deleteInstanceId(instanceId: string): Promise<void> {
71+
return this.requestHandler.deleteInstanceId(instanceId)
72+
.then(() => {
73+
// Return nothing on success
74+
});
75+
}
76+
77+
/**
78+
* Returns the app associated with this InstanceId instance.
79+
*
80+
* @return {FirebaseApp} The app associated with this InstanceId instance.
81+
*/
82+
get app(): FirebaseApp {
83+
return this.app_;
84+
}
85+
}

src/instance-id/instance-id.ts

Lines changed: 25 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*!
2-
* Copyright 2017 Google Inc.
2+
* Copyright 2020 Google Inc.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,70 +15,36 @@
1515
*/
1616

1717
import { FirebaseApp } from '../firebase-app';
18-
import { FirebaseInstanceIdError, InstanceIdClientErrorCode } from '../utils/error';
19-
import { FirebaseServiceInterface, FirebaseServiceInternalsInterface } from '../firebase-service';
20-
import { FirebaseInstanceIdRequestHandler } from './instance-id-request';
21-
22-
import * as validator from '../utils/validator';
2318

2419
/**
25-
* Internals of an InstanceId service instance.
20+
* Gets the {@link InstanceId `InstanceId`} service for the
21+
* current app.
22+
*
23+
* @example
24+
* ```javascript
25+
* var instanceId = app.instanceId();
26+
* // The above is shorthand for:
27+
* // var instanceId = admin.instanceId(app);
28+
* ```
29+
*
30+
* @return The `InstanceId` service for the
31+
* current app.
2632
*/
27-
class InstanceIdInternals implements FirebaseServiceInternalsInterface {
28-
/**
29-
* Deletes the service and its associated resources.
30-
*
31-
* @return {Promise<()>} An empty Promise that will be fulfilled when the service is deleted.
32-
*/
33-
public delete(): Promise<void> {
34-
// There are no resources to clean up
35-
return Promise.resolve(undefined);
36-
}
37-
}
38-
39-
export class InstanceId implements FirebaseServiceInterface {
40-
public INTERNAL: InstanceIdInternals = new InstanceIdInternals();
41-
42-
private app_: FirebaseApp;
43-
private requestHandler: FirebaseInstanceIdRequestHandler;
33+
export interface InstanceId {
34+
app: FirebaseApp;
4435

4536
/**
46-
* @param {FirebaseApp} app The app for this InstanceId service.
47-
* @constructor
48-
*/
49-
constructor(app: FirebaseApp) {
50-
if (!validator.isNonNullObject(app) || !('options' in app)) {
51-
throw new FirebaseInstanceIdError(
52-
InstanceIdClientErrorCode.INVALID_ARGUMENT,
53-
'First argument passed to admin.instanceId() must be a valid Firebase app instance.',
54-
);
55-
}
56-
57-
this.app_ = app;
58-
this.requestHandler = new FirebaseInstanceIdRequestHandler(app);
59-
}
60-
61-
/**
62-
* Deletes the specified instance ID from Firebase. This can be used to delete an instance ID
63-
* and associated user data from a Firebase project, pursuant to the General Data Protection
64-
* Regulation (GDPR).
37+
* Deletes the specified instance ID and the associated data from Firebase.
6538
*
66-
* @param {string} instanceId The instance ID to be deleted
67-
* @return {Promise<void>} A promise that resolves when the instance ID is successfully deleted.
68-
*/
69-
public deleteInstanceId(instanceId: string): Promise<void> {
70-
return this.requestHandler.deleteInstanceId(instanceId)
71-
.then(() => {
72-
// Return nothing on success
73-
});
74-
}
75-
76-
/**
77-
* Returns the app associated with this InstanceId instance.
39+
* Note that Google Analytics for Firebase uses its own form of Instance ID to
40+
* keep track of analytics data. Therefore deleting a Firebase Instance ID does
41+
* not delete Analytics data. See
42+
* [Delete an Instance ID](/support/privacy/manage-iids#delete_an_instance_id)
43+
* for more information.
44+
*
45+
* @param instanceId The instance ID to be deleted.
7846
*
79-
* @return {FirebaseApp} The app associated with this InstanceId instance.
47+
* @return A promise fulfilled when the instance ID is deleted.
8048
*/
81-
get app(): FirebaseApp {
82-
return this.app_;
83-
}
49+
deleteInstanceId(instanceId: string): Promise<void>;
8450
}

test/unit/firebase-namespace.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import {
4949
setLogFunction,
5050
} from '@google-cloud/firestore';
5151
import { InstanceId } from '../../src/instance-id/instance-id';
52+
import { InstanceIdImpl } from '../../src/instance-id/instance-id-internal';
5253
import { ProjectManagement } from '../../src/project-management/project-management';
5354
import { SecurityRules } from '../../src/security-rules/security-rules';
5455
import { RemoteConfig } from '../../src/remote-config/remote-config';
@@ -623,7 +624,7 @@ describe('FirebaseNamespace', () => {
623624
});
624625

625626
it('should return a reference to InstanceId type', () => {
626-
expect(firebaseNamespace.instanceId.InstanceId).to.be.deep.equal(InstanceId);
627+
expect(firebaseNamespace.instanceId.InstanceId).to.be.deep.equal(InstanceIdImpl);
627628
});
628629
});
629630

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import * as utils from '../utils';
2626
import * as mocks from '../../resources/mocks';
2727

2828
import { InstanceId } from '../../../src/instance-id/instance-id';
29+
import { InstanceIdImpl } from '../../../src/instance-id/instance-id-internal';
2930
import { FirebaseInstanceIdRequestHandler } from '../../../src/instance-id/instance-id-request';
3031
import { FirebaseApp } from '../../../src/firebase-app';
3132
import { FirebaseInstanceIdError, InstanceIdClientErrorCode } from '../../../src/utils/error';
@@ -57,14 +58,14 @@ describe('InstanceId', () => {
5758
mockApp = mocks.app();
5859
getTokenStub = utils.stubGetAccessToken(undefined, mockApp);
5960
mockCredentialApp = mocks.mockCredentialApp();
60-
iid = new InstanceId(mockApp);
61+
iid = new InstanceIdImpl(mockApp);
6162

6263
googleCloudProject = process.env.GOOGLE_CLOUD_PROJECT;
6364
gcloudProject = process.env.GCLOUD_PROJECT;
6465

65-
nullAccessTokenClient = new InstanceId(mocks.appReturningNullAccessToken());
66-
malformedAccessTokenClient = new InstanceId(mocks.appReturningMalformedAccessToken());
67-
rejectedPromiseAccessTokenClient = new InstanceId(mocks.appRejectedWhileFetchingAccessToken());
66+
nullAccessTokenClient = new InstanceIdImpl(mocks.appReturningNullAccessToken());
67+
malformedAccessTokenClient = new InstanceIdImpl(mocks.appReturningMalformedAccessToken());
68+
rejectedPromiseAccessTokenClient = new InstanceIdImpl(mocks.appRejectedWhileFetchingAccessToken());
6869
});
6970

7071
afterEach(() => {
@@ -80,15 +81,15 @@ describe('InstanceId', () => {
8081
invalidApps.forEach((invalidApp) => {
8182
it('should throw given invalid app: ' + JSON.stringify(invalidApp), () => {
8283
expect(() => {
83-
const iidAny: any = InstanceId;
84+
const iidAny: any = InstanceIdImpl;
8485
return new iidAny(invalidApp);
8586
}).to.throw('First argument passed to admin.instanceId() must be a valid Firebase app instance.');
8687
});
8788
});
8889

8990
it('should throw given no app', () => {
9091
expect(() => {
91-
const iidAny: any = InstanceId;
92+
const iidAny: any = InstanceIdImpl;
9293
return new iidAny();
9394
}).to.throw('First argument passed to admin.instanceId() must be a valid Firebase app instance.');
9495
});
@@ -97,14 +98,14 @@ describe('InstanceId', () => {
9798
// Project ID not set in the environment.
9899
delete process.env.GOOGLE_CLOUD_PROJECT;
99100
delete process.env.GCLOUD_PROJECT;
100-
const instanceId = new InstanceId(mockCredentialApp);
101+
const instanceId = new InstanceIdImpl(mockCredentialApp);
101102
return instanceId.deleteInstanceId('iid')
102103
.should.eventually.rejectedWith(noProjectIdError);
103104
});
104105

105106
it('should not throw given a valid app', () => {
106107
expect(() => {
107-
return new InstanceId(mockApp);
108+
return new InstanceIdImpl(mockApp);
108109
}).not.to.throw();
109110
});
110111
});
@@ -118,7 +119,7 @@ describe('InstanceId', () => {
118119
it('is read-only', () => {
119120
expect(() => {
120121
(iid as any).app = mockApp;
121-
}).to.throw('Cannot set property app of #<InstanceId> which has only a getter');
122+
}).to.throw('Cannot set property app of #<InstanceIdImpl> which has only a getter');
122123
});
123124
});
124125

0 commit comments

Comments
 (0)