@firebase/installations 0.6.10 → 0.6.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.esm2017.js +1102 -1102
- package/dist/esm/index.esm2017.js.map +1 -1
- package/dist/esm/src/api/delete-installations.d.ts +24 -24
- package/dist/esm/src/api/delete-installations.test.d.ts +17 -17
- package/dist/esm/src/api/get-id.d.ts +25 -25
- package/dist/esm/src/api/get-id.test.d.ts +17 -17
- package/dist/esm/src/api/get-installations.d.ts +26 -26
- package/dist/esm/src/api/get-token.d.ts +26 -26
- package/dist/esm/src/api/get-token.test.d.ts +17 -17
- package/dist/esm/src/api/index.d.ts +21 -21
- package/dist/esm/src/api/on-id-change.d.ts +39 -39
- package/dist/esm/src/api/on-id-change.test.d.ts +17 -17
- package/dist/esm/src/functions/common.d.ts +38 -38
- package/dist/esm/src/functions/common.test.d.ts +17 -17
- package/dist/esm/src/functions/config.d.ts +17 -17
- package/dist/esm/src/functions/create-installation-request.d.ts +19 -19
- package/dist/esm/src/functions/create-installation-request.test.d.ts +17 -17
- package/dist/esm/src/functions/delete-installation-request.d.ts +19 -19
- package/dist/esm/src/functions/delete-installation-request.test.d.ts +17 -17
- package/dist/esm/src/functions/generate-auth-token-request.d.ts +19 -19
- package/dist/esm/src/functions/generate-auth-token-request.test.d.ts +17 -17
- package/dist/esm/src/helpers/buffer-to-base64-url-safe.d.ts +17 -17
- package/dist/esm/src/helpers/buffer-to-base64-url-safe.test.d.ts +17 -17
- package/dist/esm/src/helpers/extract-app-config.d.ts +19 -19
- package/dist/esm/src/helpers/extract-app-config.test.d.ts +17 -17
- package/dist/esm/src/helpers/fid-changed.d.ts +25 -25
- package/dist/esm/src/helpers/fid-changed.test.d.ts +17 -17
- package/dist/esm/src/helpers/generate-fid.d.ts +23 -23
- package/dist/esm/src/helpers/generate-fid.test.d.ts +17 -17
- package/dist/esm/src/helpers/get-installation-entry.d.ts +28 -28
- package/dist/esm/src/helpers/get-installation-entry.test.d.ts +17 -17
- package/dist/esm/src/helpers/idb-manager.d.ts +32 -32
- package/dist/esm/src/helpers/idb-manager.test.d.ts +17 -17
- package/dist/esm/src/helpers/refresh-auth-token.d.ts +25 -25
- package/dist/esm/src/helpers/refresh-auth-token.test.d.ts +17 -17
- package/dist/esm/src/index.d.ts +8 -8
- package/dist/esm/src/interfaces/api-response.d.ts +31 -31
- package/dist/esm/src/interfaces/installation-entry.d.ts +85 -85
- package/dist/esm/src/interfaces/installation-impl.d.ts +29 -29
- package/dist/esm/src/interfaces/public-types.d.ts +50 -50
- package/dist/esm/src/testing/compare-headers.d.ts +21 -21
- package/dist/esm/src/testing/compare-headers.test.d.ts +17 -17
- package/dist/esm/src/testing/fake-generators.d.ts +21 -21
- package/dist/esm/src/testing/setup.d.ts +17 -17
- package/dist/esm/src/util/constants.d.ts +23 -23
- package/dist/esm/src/util/errors.d.ts +46 -46
- package/dist/esm/src/util/get-key.d.ts +19 -19
- package/dist/esm/src/util/sleep.d.ts +18 -18
- package/dist/esm/src/util/sleep.test.d.ts +17 -17
- package/dist/index.cjs.js +1102 -1102
- package/dist/index.cjs.js.map +1 -1
- package/dist/src/api/delete-installations.d.ts +24 -24
- package/dist/src/api/delete-installations.test.d.ts +17 -17
- package/dist/src/api/get-id.d.ts +25 -25
- package/dist/src/api/get-id.test.d.ts +17 -17
- package/dist/src/api/get-installations.d.ts +26 -26
- package/dist/src/api/get-token.d.ts +26 -26
- package/dist/src/api/get-token.test.d.ts +17 -17
- package/dist/src/api/index.d.ts +21 -21
- package/dist/src/api/on-id-change.d.ts +39 -39
- package/dist/src/api/on-id-change.test.d.ts +17 -17
- package/dist/src/functions/common.d.ts +38 -38
- package/dist/src/functions/common.test.d.ts +17 -17
- package/dist/src/functions/config.d.ts +17 -17
- package/dist/src/functions/create-installation-request.d.ts +19 -19
- package/dist/src/functions/create-installation-request.test.d.ts +17 -17
- package/dist/src/functions/delete-installation-request.d.ts +19 -19
- package/dist/src/functions/delete-installation-request.test.d.ts +17 -17
- package/dist/src/functions/generate-auth-token-request.d.ts +19 -19
- package/dist/src/functions/generate-auth-token-request.test.d.ts +17 -17
- package/dist/src/helpers/buffer-to-base64-url-safe.d.ts +17 -17
- package/dist/src/helpers/buffer-to-base64-url-safe.test.d.ts +17 -17
- package/dist/src/helpers/extract-app-config.d.ts +19 -19
- package/dist/src/helpers/extract-app-config.test.d.ts +17 -17
- package/dist/src/helpers/fid-changed.d.ts +25 -25
- package/dist/src/helpers/fid-changed.test.d.ts +17 -17
- package/dist/src/helpers/generate-fid.d.ts +23 -23
- package/dist/src/helpers/generate-fid.test.d.ts +17 -17
- package/dist/src/helpers/get-installation-entry.d.ts +28 -28
- package/dist/src/helpers/get-installation-entry.test.d.ts +17 -17
- package/dist/src/helpers/idb-manager.d.ts +32 -32
- package/dist/src/helpers/idb-manager.test.d.ts +17 -17
- package/dist/src/helpers/refresh-auth-token.d.ts +25 -25
- package/dist/src/helpers/refresh-auth-token.test.d.ts +17 -17
- package/dist/src/index.d.ts +8 -8
- package/dist/src/interfaces/api-response.d.ts +31 -31
- package/dist/src/interfaces/installation-entry.d.ts +85 -85
- package/dist/src/interfaces/installation-impl.d.ts +29 -29
- package/dist/src/interfaces/public-types.d.ts +50 -50
- package/dist/src/testing/compare-headers.d.ts +21 -21
- package/dist/src/testing/compare-headers.test.d.ts +17 -17
- package/dist/src/testing/fake-generators.d.ts +21 -21
- package/dist/src/testing/setup.d.ts +17 -17
- package/dist/src/util/constants.d.ts +23 -23
- package/dist/src/util/errors.d.ts +46 -46
- package/dist/src/util/get-key.d.ts +19 -19
- package/dist/src/util/sleep.d.ts +18 -18
- package/dist/src/util/sleep.test.d.ts +17 -17
- package/package.json +5 -5
|
@@ -4,1151 +4,1151 @@ import { ErrorFactory, FirebaseError } from '@firebase/util';
|
|
|
4
4
|
import { openDB } from 'idb';
|
|
5
5
|
|
|
6
6
|
const name = "@firebase/installations";
|
|
7
|
-
const version = "0.6.
|
|
7
|
+
const version = "0.6.11";
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* @license
|
|
11
|
-
* Copyright 2019 Google LLC
|
|
12
|
-
*
|
|
13
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
14
|
-
* you may not use this file except in compliance with the License.
|
|
15
|
-
* You may obtain a copy of the License at
|
|
16
|
-
*
|
|
17
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
18
|
-
*
|
|
19
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
20
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
21
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
22
|
-
* See the License for the specific language governing permissions and
|
|
23
|
-
* limitations under the License.
|
|
24
|
-
*/
|
|
25
|
-
const PENDING_TIMEOUT_MS = 10000;
|
|
26
|
-
const PACKAGE_VERSION = `w:${version}`;
|
|
27
|
-
const INTERNAL_AUTH_VERSION = 'FIS_v2';
|
|
28
|
-
const INSTALLATIONS_API_URL = 'https://firebaseinstallations.googleapis.com/v1';
|
|
29
|
-
const TOKEN_EXPIRATION_BUFFER = 60 * 60 * 1000; // One hour
|
|
30
|
-
const SERVICE = 'installations';
|
|
9
|
+
/**
|
|
10
|
+
* @license
|
|
11
|
+
* Copyright 2019 Google LLC
|
|
12
|
+
*
|
|
13
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
14
|
+
* you may not use this file except in compliance with the License.
|
|
15
|
+
* You may obtain a copy of the License at
|
|
16
|
+
*
|
|
17
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
18
|
+
*
|
|
19
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
20
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
21
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
22
|
+
* See the License for the specific language governing permissions and
|
|
23
|
+
* limitations under the License.
|
|
24
|
+
*/
|
|
25
|
+
const PENDING_TIMEOUT_MS = 10000;
|
|
26
|
+
const PACKAGE_VERSION = `w:${version}`;
|
|
27
|
+
const INTERNAL_AUTH_VERSION = 'FIS_v2';
|
|
28
|
+
const INSTALLATIONS_API_URL = 'https://firebaseinstallations.googleapis.com/v1';
|
|
29
|
+
const TOKEN_EXPIRATION_BUFFER = 60 * 60 * 1000; // One hour
|
|
30
|
+
const SERVICE = 'installations';
|
|
31
31
|
const SERVICE_NAME = 'Installations';
|
|
32
32
|
|
|
33
|
-
/**
|
|
34
|
-
* @license
|
|
35
|
-
* Copyright 2019 Google LLC
|
|
36
|
-
*
|
|
37
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
38
|
-
* you may not use this file except in compliance with the License.
|
|
39
|
-
* You may obtain a copy of the License at
|
|
40
|
-
*
|
|
41
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
42
|
-
*
|
|
43
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
44
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
45
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
46
|
-
* See the License for the specific language governing permissions and
|
|
47
|
-
* limitations under the License.
|
|
48
|
-
*/
|
|
49
|
-
const ERROR_DESCRIPTION_MAP = {
|
|
50
|
-
["missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */]: 'Missing App configuration value: "{$valueName}"',
|
|
51
|
-
["not-registered" /* ErrorCode.NOT_REGISTERED */]: 'Firebase Installation is not registered.',
|
|
52
|
-
["installation-not-found" /* ErrorCode.INSTALLATION_NOT_FOUND */]: 'Firebase Installation not found.',
|
|
53
|
-
["request-failed" /* ErrorCode.REQUEST_FAILED */]: '{$requestName} request failed with error "{$serverCode} {$serverStatus}: {$serverMessage}"',
|
|
54
|
-
["app-offline" /* ErrorCode.APP_OFFLINE */]: 'Could not process request. Application offline.',
|
|
55
|
-
["delete-pending-registration" /* ErrorCode.DELETE_PENDING_REGISTRATION */]: "Can't delete installation while there is a pending registration request."
|
|
56
|
-
};
|
|
57
|
-
const ERROR_FACTORY = new ErrorFactory(SERVICE, SERVICE_NAME, ERROR_DESCRIPTION_MAP);
|
|
58
|
-
/** Returns true if error is a FirebaseError that is based on an error from the server. */
|
|
59
|
-
function isServerError(error) {
|
|
60
|
-
return (error instanceof FirebaseError &&
|
|
61
|
-
error.code.includes("request-failed" /* ErrorCode.REQUEST_FAILED */));
|
|
33
|
+
/**
|
|
34
|
+
* @license
|
|
35
|
+
* Copyright 2019 Google LLC
|
|
36
|
+
*
|
|
37
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
38
|
+
* you may not use this file except in compliance with the License.
|
|
39
|
+
* You may obtain a copy of the License at
|
|
40
|
+
*
|
|
41
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
42
|
+
*
|
|
43
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
44
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
45
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
46
|
+
* See the License for the specific language governing permissions and
|
|
47
|
+
* limitations under the License.
|
|
48
|
+
*/
|
|
49
|
+
const ERROR_DESCRIPTION_MAP = {
|
|
50
|
+
["missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */]: 'Missing App configuration value: "{$valueName}"',
|
|
51
|
+
["not-registered" /* ErrorCode.NOT_REGISTERED */]: 'Firebase Installation is not registered.',
|
|
52
|
+
["installation-not-found" /* ErrorCode.INSTALLATION_NOT_FOUND */]: 'Firebase Installation not found.',
|
|
53
|
+
["request-failed" /* ErrorCode.REQUEST_FAILED */]: '{$requestName} request failed with error "{$serverCode} {$serverStatus}: {$serverMessage}"',
|
|
54
|
+
["app-offline" /* ErrorCode.APP_OFFLINE */]: 'Could not process request. Application offline.',
|
|
55
|
+
["delete-pending-registration" /* ErrorCode.DELETE_PENDING_REGISTRATION */]: "Can't delete installation while there is a pending registration request."
|
|
56
|
+
};
|
|
57
|
+
const ERROR_FACTORY = new ErrorFactory(SERVICE, SERVICE_NAME, ERROR_DESCRIPTION_MAP);
|
|
58
|
+
/** Returns true if error is a FirebaseError that is based on an error from the server. */
|
|
59
|
+
function isServerError(error) {
|
|
60
|
+
return (error instanceof FirebaseError &&
|
|
61
|
+
error.code.includes("request-failed" /* ErrorCode.REQUEST_FAILED */));
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
/**
|
|
65
|
-
* @license
|
|
66
|
-
* Copyright 2019 Google LLC
|
|
67
|
-
*
|
|
68
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
69
|
-
* you may not use this file except in compliance with the License.
|
|
70
|
-
* You may obtain a copy of the License at
|
|
71
|
-
*
|
|
72
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
73
|
-
*
|
|
74
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
75
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
76
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
77
|
-
* See the License for the specific language governing permissions and
|
|
78
|
-
* limitations under the License.
|
|
79
|
-
*/
|
|
80
|
-
function getInstallationsEndpoint({ projectId }) {
|
|
81
|
-
return `${INSTALLATIONS_API_URL}/projects/${projectId}/installations`;
|
|
82
|
-
}
|
|
83
|
-
function extractAuthTokenInfoFromResponse(response) {
|
|
84
|
-
return {
|
|
85
|
-
token: response.token,
|
|
86
|
-
requestStatus: 2 /* RequestStatus.COMPLETED */,
|
|
87
|
-
expiresIn: getExpiresInFromResponseExpiresIn(response.expiresIn),
|
|
88
|
-
creationTime: Date.now()
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
async function getErrorFromResponse(requestName, response) {
|
|
92
|
-
const responseJson = await response.json();
|
|
93
|
-
const errorData = responseJson.error;
|
|
94
|
-
return ERROR_FACTORY.create("request-failed" /* ErrorCode.REQUEST_FAILED */, {
|
|
95
|
-
requestName,
|
|
96
|
-
serverCode: errorData.code,
|
|
97
|
-
serverMessage: errorData.message,
|
|
98
|
-
serverStatus: errorData.status
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
function getHeaders({ apiKey }) {
|
|
102
|
-
return new Headers({
|
|
103
|
-
'Content-Type': 'application/json',
|
|
104
|
-
Accept: 'application/json',
|
|
105
|
-
'x-goog-api-key': apiKey
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
function getHeadersWithAuth(appConfig, { refreshToken }) {
|
|
109
|
-
const headers = getHeaders(appConfig);
|
|
110
|
-
headers.append('Authorization', getAuthorizationHeader(refreshToken));
|
|
111
|
-
return headers;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Calls the passed in fetch wrapper and returns the response.
|
|
115
|
-
* If the returned response has a status of 5xx, re-runs the function once and
|
|
116
|
-
* returns the response.
|
|
117
|
-
*/
|
|
118
|
-
async function retryIfServerError(fn) {
|
|
119
|
-
const result = await fn();
|
|
120
|
-
if (result.status >= 500 && result.status < 600) {
|
|
121
|
-
// Internal Server Error. Retry request.
|
|
122
|
-
return fn();
|
|
123
|
-
}
|
|
124
|
-
return result;
|
|
125
|
-
}
|
|
126
|
-
function getExpiresInFromResponseExpiresIn(responseExpiresIn) {
|
|
127
|
-
// This works because the server will never respond with fractions of a second.
|
|
128
|
-
return Number(responseExpiresIn.replace('s', '000'));
|
|
129
|
-
}
|
|
130
|
-
function getAuthorizationHeader(refreshToken) {
|
|
131
|
-
return `${INTERNAL_AUTH_VERSION} ${refreshToken}`;
|
|
64
|
+
/**
|
|
65
|
+
* @license
|
|
66
|
+
* Copyright 2019 Google LLC
|
|
67
|
+
*
|
|
68
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
69
|
+
* you may not use this file except in compliance with the License.
|
|
70
|
+
* You may obtain a copy of the License at
|
|
71
|
+
*
|
|
72
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
73
|
+
*
|
|
74
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
75
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
76
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
77
|
+
* See the License for the specific language governing permissions and
|
|
78
|
+
* limitations under the License.
|
|
79
|
+
*/
|
|
80
|
+
function getInstallationsEndpoint({ projectId }) {
|
|
81
|
+
return `${INSTALLATIONS_API_URL}/projects/${projectId}/installations`;
|
|
82
|
+
}
|
|
83
|
+
function extractAuthTokenInfoFromResponse(response) {
|
|
84
|
+
return {
|
|
85
|
+
token: response.token,
|
|
86
|
+
requestStatus: 2 /* RequestStatus.COMPLETED */,
|
|
87
|
+
expiresIn: getExpiresInFromResponseExpiresIn(response.expiresIn),
|
|
88
|
+
creationTime: Date.now()
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
async function getErrorFromResponse(requestName, response) {
|
|
92
|
+
const responseJson = await response.json();
|
|
93
|
+
const errorData = responseJson.error;
|
|
94
|
+
return ERROR_FACTORY.create("request-failed" /* ErrorCode.REQUEST_FAILED */, {
|
|
95
|
+
requestName,
|
|
96
|
+
serverCode: errorData.code,
|
|
97
|
+
serverMessage: errorData.message,
|
|
98
|
+
serverStatus: errorData.status
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function getHeaders({ apiKey }) {
|
|
102
|
+
return new Headers({
|
|
103
|
+
'Content-Type': 'application/json',
|
|
104
|
+
Accept: 'application/json',
|
|
105
|
+
'x-goog-api-key': apiKey
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
function getHeadersWithAuth(appConfig, { refreshToken }) {
|
|
109
|
+
const headers = getHeaders(appConfig);
|
|
110
|
+
headers.append('Authorization', getAuthorizationHeader(refreshToken));
|
|
111
|
+
return headers;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Calls the passed in fetch wrapper and returns the response.
|
|
115
|
+
* If the returned response has a status of 5xx, re-runs the function once and
|
|
116
|
+
* returns the response.
|
|
117
|
+
*/
|
|
118
|
+
async function retryIfServerError(fn) {
|
|
119
|
+
const result = await fn();
|
|
120
|
+
if (result.status >= 500 && result.status < 600) {
|
|
121
|
+
// Internal Server Error. Retry request.
|
|
122
|
+
return fn();
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
function getExpiresInFromResponseExpiresIn(responseExpiresIn) {
|
|
127
|
+
// This works because the server will never respond with fractions of a second.
|
|
128
|
+
return Number(responseExpiresIn.replace('s', '000'));
|
|
129
|
+
}
|
|
130
|
+
function getAuthorizationHeader(refreshToken) {
|
|
131
|
+
return `${INTERNAL_AUTH_VERSION} ${refreshToken}`;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
/**
|
|
135
|
-
* @license
|
|
136
|
-
* Copyright 2019 Google LLC
|
|
137
|
-
*
|
|
138
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
139
|
-
* you may not use this file except in compliance with the License.
|
|
140
|
-
* You may obtain a copy of the License at
|
|
141
|
-
*
|
|
142
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
143
|
-
*
|
|
144
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
145
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
146
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
147
|
-
* See the License for the specific language governing permissions and
|
|
148
|
-
* limitations under the License.
|
|
149
|
-
*/
|
|
150
|
-
async function createInstallationRequest({ appConfig, heartbeatServiceProvider }, { fid }) {
|
|
151
|
-
const endpoint = getInstallationsEndpoint(appConfig);
|
|
152
|
-
const headers = getHeaders(appConfig);
|
|
153
|
-
// If heartbeat service exists, add the heartbeat string to the header.
|
|
154
|
-
const heartbeatService = heartbeatServiceProvider.getImmediate({
|
|
155
|
-
optional: true
|
|
156
|
-
});
|
|
157
|
-
if (heartbeatService) {
|
|
158
|
-
const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader();
|
|
159
|
-
if (heartbeatsHeader) {
|
|
160
|
-
headers.append('x-firebase-client', heartbeatsHeader);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
const body = {
|
|
164
|
-
fid,
|
|
165
|
-
authVersion: INTERNAL_AUTH_VERSION,
|
|
166
|
-
appId: appConfig.appId,
|
|
167
|
-
sdkVersion: PACKAGE_VERSION
|
|
168
|
-
};
|
|
169
|
-
const request = {
|
|
170
|
-
method: 'POST',
|
|
171
|
-
headers,
|
|
172
|
-
body: JSON.stringify(body)
|
|
173
|
-
};
|
|
174
|
-
const response = await retryIfServerError(() => fetch(endpoint, request));
|
|
175
|
-
if (response.ok) {
|
|
176
|
-
const responseValue = await response.json();
|
|
177
|
-
const registeredInstallationEntry = {
|
|
178
|
-
fid: responseValue.fid || fid,
|
|
179
|
-
registrationStatus: 2 /* RequestStatus.COMPLETED */,
|
|
180
|
-
refreshToken: responseValue.refreshToken,
|
|
181
|
-
authToken: extractAuthTokenInfoFromResponse(responseValue.authToken)
|
|
182
|
-
};
|
|
183
|
-
return registeredInstallationEntry;
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
throw await getErrorFromResponse('Create Installation', response);
|
|
187
|
-
}
|
|
134
|
+
/**
|
|
135
|
+
* @license
|
|
136
|
+
* Copyright 2019 Google LLC
|
|
137
|
+
*
|
|
138
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
139
|
+
* you may not use this file except in compliance with the License.
|
|
140
|
+
* You may obtain a copy of the License at
|
|
141
|
+
*
|
|
142
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
143
|
+
*
|
|
144
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
145
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
146
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
147
|
+
* See the License for the specific language governing permissions and
|
|
148
|
+
* limitations under the License.
|
|
149
|
+
*/
|
|
150
|
+
async function createInstallationRequest({ appConfig, heartbeatServiceProvider }, { fid }) {
|
|
151
|
+
const endpoint = getInstallationsEndpoint(appConfig);
|
|
152
|
+
const headers = getHeaders(appConfig);
|
|
153
|
+
// If heartbeat service exists, add the heartbeat string to the header.
|
|
154
|
+
const heartbeatService = heartbeatServiceProvider.getImmediate({
|
|
155
|
+
optional: true
|
|
156
|
+
});
|
|
157
|
+
if (heartbeatService) {
|
|
158
|
+
const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader();
|
|
159
|
+
if (heartbeatsHeader) {
|
|
160
|
+
headers.append('x-firebase-client', heartbeatsHeader);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const body = {
|
|
164
|
+
fid,
|
|
165
|
+
authVersion: INTERNAL_AUTH_VERSION,
|
|
166
|
+
appId: appConfig.appId,
|
|
167
|
+
sdkVersion: PACKAGE_VERSION
|
|
168
|
+
};
|
|
169
|
+
const request = {
|
|
170
|
+
method: 'POST',
|
|
171
|
+
headers,
|
|
172
|
+
body: JSON.stringify(body)
|
|
173
|
+
};
|
|
174
|
+
const response = await retryIfServerError(() => fetch(endpoint, request));
|
|
175
|
+
if (response.ok) {
|
|
176
|
+
const responseValue = await response.json();
|
|
177
|
+
const registeredInstallationEntry = {
|
|
178
|
+
fid: responseValue.fid || fid,
|
|
179
|
+
registrationStatus: 2 /* RequestStatus.COMPLETED */,
|
|
180
|
+
refreshToken: responseValue.refreshToken,
|
|
181
|
+
authToken: extractAuthTokenInfoFromResponse(responseValue.authToken)
|
|
182
|
+
};
|
|
183
|
+
return registeredInstallationEntry;
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
throw await getErrorFromResponse('Create Installation', response);
|
|
187
|
+
}
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
/**
|
|
191
|
-
* @license
|
|
192
|
-
* Copyright 2019 Google LLC
|
|
193
|
-
*
|
|
194
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
195
|
-
* you may not use this file except in compliance with the License.
|
|
196
|
-
* You may obtain a copy of the License at
|
|
197
|
-
*
|
|
198
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
199
|
-
*
|
|
200
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
201
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
202
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
203
|
-
* See the License for the specific language governing permissions and
|
|
204
|
-
* limitations under the License.
|
|
205
|
-
*/
|
|
206
|
-
/** Returns a promise that resolves after given time passes. */
|
|
207
|
-
function sleep(ms) {
|
|
208
|
-
return new Promise(resolve => {
|
|
209
|
-
setTimeout(resolve, ms);
|
|
210
|
-
});
|
|
190
|
+
/**
|
|
191
|
+
* @license
|
|
192
|
+
* Copyright 2019 Google LLC
|
|
193
|
+
*
|
|
194
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
195
|
+
* you may not use this file except in compliance with the License.
|
|
196
|
+
* You may obtain a copy of the License at
|
|
197
|
+
*
|
|
198
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
199
|
+
*
|
|
200
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
201
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
202
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
203
|
+
* See the License for the specific language governing permissions and
|
|
204
|
+
* limitations under the License.
|
|
205
|
+
*/
|
|
206
|
+
/** Returns a promise that resolves after given time passes. */
|
|
207
|
+
function sleep(ms) {
|
|
208
|
+
return new Promise(resolve => {
|
|
209
|
+
setTimeout(resolve, ms);
|
|
210
|
+
});
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
/**
|
|
214
|
-
* @license
|
|
215
|
-
* Copyright 2019 Google LLC
|
|
216
|
-
*
|
|
217
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
218
|
-
* you may not use this file except in compliance with the License.
|
|
219
|
-
* You may obtain a copy of the License at
|
|
220
|
-
*
|
|
221
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
222
|
-
*
|
|
223
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
224
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
225
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
226
|
-
* See the License for the specific language governing permissions and
|
|
227
|
-
* limitations under the License.
|
|
228
|
-
*/
|
|
229
|
-
function bufferToBase64UrlSafe(array) {
|
|
230
|
-
const b64 = btoa(String.fromCharCode(...array));
|
|
231
|
-
return b64.replace(/\+/g, '-').replace(/\//g, '_');
|
|
213
|
+
/**
|
|
214
|
+
* @license
|
|
215
|
+
* Copyright 2019 Google LLC
|
|
216
|
+
*
|
|
217
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
218
|
+
* you may not use this file except in compliance with the License.
|
|
219
|
+
* You may obtain a copy of the License at
|
|
220
|
+
*
|
|
221
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
222
|
+
*
|
|
223
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
224
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
225
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
226
|
+
* See the License for the specific language governing permissions and
|
|
227
|
+
* limitations under the License.
|
|
228
|
+
*/
|
|
229
|
+
function bufferToBase64UrlSafe(array) {
|
|
230
|
+
const b64 = btoa(String.fromCharCode(...array));
|
|
231
|
+
return b64.replace(/\+/g, '-').replace(/\//g, '_');
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
/**
|
|
235
|
-
* @license
|
|
236
|
-
* Copyright 2019 Google LLC
|
|
237
|
-
*
|
|
238
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
239
|
-
* you may not use this file except in compliance with the License.
|
|
240
|
-
* You may obtain a copy of the License at
|
|
241
|
-
*
|
|
242
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
243
|
-
*
|
|
244
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
245
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
246
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
247
|
-
* See the License for the specific language governing permissions and
|
|
248
|
-
* limitations under the License.
|
|
249
|
-
*/
|
|
250
|
-
const VALID_FID_PATTERN = /^[cdef][\w-]{21}$/;
|
|
251
|
-
const INVALID_FID = '';
|
|
252
|
-
/**
|
|
253
|
-
* Generates a new FID using random values from Web Crypto API.
|
|
254
|
-
* Returns an empty string if FID generation fails for any reason.
|
|
255
|
-
*/
|
|
256
|
-
function generateFid() {
|
|
257
|
-
try {
|
|
258
|
-
// A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5
|
|
259
|
-
// bytes. our implementation generates a 17 byte array instead.
|
|
260
|
-
const fidByteArray = new Uint8Array(17);
|
|
261
|
-
const crypto = self.crypto || self.msCrypto;
|
|
262
|
-
crypto.getRandomValues(fidByteArray);
|
|
263
|
-
// Replace the first 4 random bits with the constant FID header of 0b0111.
|
|
264
|
-
fidByteArray[0] = 0b01110000 + (fidByteArray[0] % 0b00010000);
|
|
265
|
-
const fid = encode(fidByteArray);
|
|
266
|
-
return VALID_FID_PATTERN.test(fid) ? fid : INVALID_FID;
|
|
267
|
-
}
|
|
268
|
-
catch (_a) {
|
|
269
|
-
// FID generation errored
|
|
270
|
-
return INVALID_FID;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
/** Converts a FID Uint8Array to a base64 string representation. */
|
|
274
|
-
function encode(fidByteArray) {
|
|
275
|
-
const b64String = bufferToBase64UrlSafe(fidByteArray);
|
|
276
|
-
// Remove the 23rd character that was added because of the extra 4 bits at the
|
|
277
|
-
// end of our 17 byte array, and the '=' padding.
|
|
278
|
-
return b64String.substr(0, 22);
|
|
234
|
+
/**
|
|
235
|
+
* @license
|
|
236
|
+
* Copyright 2019 Google LLC
|
|
237
|
+
*
|
|
238
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
239
|
+
* you may not use this file except in compliance with the License.
|
|
240
|
+
* You may obtain a copy of the License at
|
|
241
|
+
*
|
|
242
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
243
|
+
*
|
|
244
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
245
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
246
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
247
|
+
* See the License for the specific language governing permissions and
|
|
248
|
+
* limitations under the License.
|
|
249
|
+
*/
|
|
250
|
+
const VALID_FID_PATTERN = /^[cdef][\w-]{21}$/;
|
|
251
|
+
const INVALID_FID = '';
|
|
252
|
+
/**
|
|
253
|
+
* Generates a new FID using random values from Web Crypto API.
|
|
254
|
+
* Returns an empty string if FID generation fails for any reason.
|
|
255
|
+
*/
|
|
256
|
+
function generateFid() {
|
|
257
|
+
try {
|
|
258
|
+
// A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5
|
|
259
|
+
// bytes. our implementation generates a 17 byte array instead.
|
|
260
|
+
const fidByteArray = new Uint8Array(17);
|
|
261
|
+
const crypto = self.crypto || self.msCrypto;
|
|
262
|
+
crypto.getRandomValues(fidByteArray);
|
|
263
|
+
// Replace the first 4 random bits with the constant FID header of 0b0111.
|
|
264
|
+
fidByteArray[0] = 0b01110000 + (fidByteArray[0] % 0b00010000);
|
|
265
|
+
const fid = encode(fidByteArray);
|
|
266
|
+
return VALID_FID_PATTERN.test(fid) ? fid : INVALID_FID;
|
|
267
|
+
}
|
|
268
|
+
catch (_a) {
|
|
269
|
+
// FID generation errored
|
|
270
|
+
return INVALID_FID;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/** Converts a FID Uint8Array to a base64 string representation. */
|
|
274
|
+
function encode(fidByteArray) {
|
|
275
|
+
const b64String = bufferToBase64UrlSafe(fidByteArray);
|
|
276
|
+
// Remove the 23rd character that was added because of the extra 4 bits at the
|
|
277
|
+
// end of our 17 byte array, and the '=' padding.
|
|
278
|
+
return b64String.substr(0, 22);
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
-
/**
|
|
282
|
-
* @license
|
|
283
|
-
* Copyright 2019 Google LLC
|
|
284
|
-
*
|
|
285
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
286
|
-
* you may not use this file except in compliance with the License.
|
|
287
|
-
* You may obtain a copy of the License at
|
|
288
|
-
*
|
|
289
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
290
|
-
*
|
|
291
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
292
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
293
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
294
|
-
* See the License for the specific language governing permissions and
|
|
295
|
-
* limitations under the License.
|
|
296
|
-
*/
|
|
297
|
-
/** Returns a string key that can be used to identify the app. */
|
|
298
|
-
function getKey(appConfig) {
|
|
299
|
-
return `${appConfig.appName}!${appConfig.appId}`;
|
|
281
|
+
/**
|
|
282
|
+
* @license
|
|
283
|
+
* Copyright 2019 Google LLC
|
|
284
|
+
*
|
|
285
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
286
|
+
* you may not use this file except in compliance with the License.
|
|
287
|
+
* You may obtain a copy of the License at
|
|
288
|
+
*
|
|
289
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
290
|
+
*
|
|
291
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
292
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
293
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
294
|
+
* See the License for the specific language governing permissions and
|
|
295
|
+
* limitations under the License.
|
|
296
|
+
*/
|
|
297
|
+
/** Returns a string key that can be used to identify the app. */
|
|
298
|
+
function getKey(appConfig) {
|
|
299
|
+
return `${appConfig.appName}!${appConfig.appId}`;
|
|
300
300
|
}
|
|
301
301
|
|
|
302
|
-
/**
|
|
303
|
-
* @license
|
|
304
|
-
* Copyright 2019 Google LLC
|
|
305
|
-
*
|
|
306
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
307
|
-
* you may not use this file except in compliance with the License.
|
|
308
|
-
* You may obtain a copy of the License at
|
|
309
|
-
*
|
|
310
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
311
|
-
*
|
|
312
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
313
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
314
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
315
|
-
* See the License for the specific language governing permissions and
|
|
316
|
-
* limitations under the License.
|
|
317
|
-
*/
|
|
318
|
-
const fidChangeCallbacks = new Map();
|
|
319
|
-
/**
|
|
320
|
-
* Calls the onIdChange callbacks with the new FID value, and broadcasts the
|
|
321
|
-
* change to other tabs.
|
|
322
|
-
*/
|
|
323
|
-
function fidChanged(appConfig, fid) {
|
|
324
|
-
const key = getKey(appConfig);
|
|
325
|
-
callFidChangeCallbacks(key, fid);
|
|
326
|
-
broadcastFidChange(key, fid);
|
|
327
|
-
}
|
|
328
|
-
function addCallback(appConfig, callback) {
|
|
329
|
-
// Open the broadcast channel if it's not already open,
|
|
330
|
-
// to be able to listen to change events from other tabs.
|
|
331
|
-
getBroadcastChannel();
|
|
332
|
-
const key = getKey(appConfig);
|
|
333
|
-
let callbackSet = fidChangeCallbacks.get(key);
|
|
334
|
-
if (!callbackSet) {
|
|
335
|
-
callbackSet = new Set();
|
|
336
|
-
fidChangeCallbacks.set(key, callbackSet);
|
|
337
|
-
}
|
|
338
|
-
callbackSet.add(callback);
|
|
339
|
-
}
|
|
340
|
-
function removeCallback(appConfig, callback) {
|
|
341
|
-
const key = getKey(appConfig);
|
|
342
|
-
const callbackSet = fidChangeCallbacks.get(key);
|
|
343
|
-
if (!callbackSet) {
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
callbackSet.delete(callback);
|
|
347
|
-
if (callbackSet.size === 0) {
|
|
348
|
-
fidChangeCallbacks.delete(key);
|
|
349
|
-
}
|
|
350
|
-
// Close broadcast channel if there are no more callbacks.
|
|
351
|
-
closeBroadcastChannel();
|
|
352
|
-
}
|
|
353
|
-
function callFidChangeCallbacks(key, fid) {
|
|
354
|
-
const callbacks = fidChangeCallbacks.get(key);
|
|
355
|
-
if (!callbacks) {
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
for (const callback of callbacks) {
|
|
359
|
-
callback(fid);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
function broadcastFidChange(key, fid) {
|
|
363
|
-
const channel = getBroadcastChannel();
|
|
364
|
-
if (channel) {
|
|
365
|
-
channel.postMessage({ key, fid });
|
|
366
|
-
}
|
|
367
|
-
closeBroadcastChannel();
|
|
368
|
-
}
|
|
369
|
-
let broadcastChannel = null;
|
|
370
|
-
/** Opens and returns a BroadcastChannel if it is supported by the browser. */
|
|
371
|
-
function getBroadcastChannel() {
|
|
372
|
-
if (!broadcastChannel && 'BroadcastChannel' in self) {
|
|
373
|
-
broadcastChannel = new BroadcastChannel('[Firebase] FID Change');
|
|
374
|
-
broadcastChannel.onmessage = e => {
|
|
375
|
-
callFidChangeCallbacks(e.data.key, e.data.fid);
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
return broadcastChannel;
|
|
379
|
-
}
|
|
380
|
-
function closeBroadcastChannel() {
|
|
381
|
-
if (fidChangeCallbacks.size === 0 && broadcastChannel) {
|
|
382
|
-
broadcastChannel.close();
|
|
383
|
-
broadcastChannel = null;
|
|
384
|
-
}
|
|
302
|
+
/**
|
|
303
|
+
* @license
|
|
304
|
+
* Copyright 2019 Google LLC
|
|
305
|
+
*
|
|
306
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
307
|
+
* you may not use this file except in compliance with the License.
|
|
308
|
+
* You may obtain a copy of the License at
|
|
309
|
+
*
|
|
310
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
311
|
+
*
|
|
312
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
313
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
314
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
315
|
+
* See the License for the specific language governing permissions and
|
|
316
|
+
* limitations under the License.
|
|
317
|
+
*/
|
|
318
|
+
const fidChangeCallbacks = new Map();
|
|
319
|
+
/**
|
|
320
|
+
* Calls the onIdChange callbacks with the new FID value, and broadcasts the
|
|
321
|
+
* change to other tabs.
|
|
322
|
+
*/
|
|
323
|
+
function fidChanged(appConfig, fid) {
|
|
324
|
+
const key = getKey(appConfig);
|
|
325
|
+
callFidChangeCallbacks(key, fid);
|
|
326
|
+
broadcastFidChange(key, fid);
|
|
327
|
+
}
|
|
328
|
+
function addCallback(appConfig, callback) {
|
|
329
|
+
// Open the broadcast channel if it's not already open,
|
|
330
|
+
// to be able to listen to change events from other tabs.
|
|
331
|
+
getBroadcastChannel();
|
|
332
|
+
const key = getKey(appConfig);
|
|
333
|
+
let callbackSet = fidChangeCallbacks.get(key);
|
|
334
|
+
if (!callbackSet) {
|
|
335
|
+
callbackSet = new Set();
|
|
336
|
+
fidChangeCallbacks.set(key, callbackSet);
|
|
337
|
+
}
|
|
338
|
+
callbackSet.add(callback);
|
|
339
|
+
}
|
|
340
|
+
function removeCallback(appConfig, callback) {
|
|
341
|
+
const key = getKey(appConfig);
|
|
342
|
+
const callbackSet = fidChangeCallbacks.get(key);
|
|
343
|
+
if (!callbackSet) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
callbackSet.delete(callback);
|
|
347
|
+
if (callbackSet.size === 0) {
|
|
348
|
+
fidChangeCallbacks.delete(key);
|
|
349
|
+
}
|
|
350
|
+
// Close broadcast channel if there are no more callbacks.
|
|
351
|
+
closeBroadcastChannel();
|
|
352
|
+
}
|
|
353
|
+
function callFidChangeCallbacks(key, fid) {
|
|
354
|
+
const callbacks = fidChangeCallbacks.get(key);
|
|
355
|
+
if (!callbacks) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
for (const callback of callbacks) {
|
|
359
|
+
callback(fid);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function broadcastFidChange(key, fid) {
|
|
363
|
+
const channel = getBroadcastChannel();
|
|
364
|
+
if (channel) {
|
|
365
|
+
channel.postMessage({ key, fid });
|
|
366
|
+
}
|
|
367
|
+
closeBroadcastChannel();
|
|
368
|
+
}
|
|
369
|
+
let broadcastChannel = null;
|
|
370
|
+
/** Opens and returns a BroadcastChannel if it is supported by the browser. */
|
|
371
|
+
function getBroadcastChannel() {
|
|
372
|
+
if (!broadcastChannel && 'BroadcastChannel' in self) {
|
|
373
|
+
broadcastChannel = new BroadcastChannel('[Firebase] FID Change');
|
|
374
|
+
broadcastChannel.onmessage = e => {
|
|
375
|
+
callFidChangeCallbacks(e.data.key, e.data.fid);
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
return broadcastChannel;
|
|
379
|
+
}
|
|
380
|
+
function closeBroadcastChannel() {
|
|
381
|
+
if (fidChangeCallbacks.size === 0 && broadcastChannel) {
|
|
382
|
+
broadcastChannel.close();
|
|
383
|
+
broadcastChannel = null;
|
|
384
|
+
}
|
|
385
385
|
}
|
|
386
386
|
|
|
387
|
-
/**
|
|
388
|
-
* @license
|
|
389
|
-
* Copyright 2019 Google LLC
|
|
390
|
-
*
|
|
391
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
392
|
-
* you may not use this file except in compliance with the License.
|
|
393
|
-
* You may obtain a copy of the License at
|
|
394
|
-
*
|
|
395
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
396
|
-
*
|
|
397
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
398
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
399
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
400
|
-
* See the License for the specific language governing permissions and
|
|
401
|
-
* limitations under the License.
|
|
402
|
-
*/
|
|
403
|
-
const DATABASE_NAME = 'firebase-installations-database';
|
|
404
|
-
const DATABASE_VERSION = 1;
|
|
405
|
-
const OBJECT_STORE_NAME = 'firebase-installations-store';
|
|
406
|
-
let dbPromise = null;
|
|
407
|
-
function getDbPromise() {
|
|
408
|
-
if (!dbPromise) {
|
|
409
|
-
dbPromise = openDB(DATABASE_NAME, DATABASE_VERSION, {
|
|
410
|
-
upgrade: (db, oldVersion) => {
|
|
411
|
-
// We don't use 'break' in this switch statement, the fall-through
|
|
412
|
-
// behavior is what we want, because if there are multiple versions between
|
|
413
|
-
// the old version and the current version, we want ALL the migrations
|
|
414
|
-
// that correspond to those versions to run, not only the last one.
|
|
415
|
-
// eslint-disable-next-line default-case
|
|
416
|
-
switch (oldVersion) {
|
|
417
|
-
case 0:
|
|
418
|
-
db.createObjectStore(OBJECT_STORE_NAME);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
return dbPromise;
|
|
424
|
-
}
|
|
425
|
-
/** Assigns or overwrites the record for the given key with the given value. */
|
|
426
|
-
async function set(appConfig, value) {
|
|
427
|
-
const key = getKey(appConfig);
|
|
428
|
-
const db = await getDbPromise();
|
|
429
|
-
const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
|
|
430
|
-
const objectStore = tx.objectStore(OBJECT_STORE_NAME);
|
|
431
|
-
const oldValue = (await objectStore.get(key));
|
|
432
|
-
await objectStore.put(value, key);
|
|
433
|
-
await tx.done;
|
|
434
|
-
if (!oldValue || oldValue.fid !== value.fid) {
|
|
435
|
-
fidChanged(appConfig, value.fid);
|
|
436
|
-
}
|
|
437
|
-
return value;
|
|
438
|
-
}
|
|
439
|
-
/** Removes record(s) from the objectStore that match the given key. */
|
|
440
|
-
async function remove(appConfig) {
|
|
441
|
-
const key = getKey(appConfig);
|
|
442
|
-
const db = await getDbPromise();
|
|
443
|
-
const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
|
|
444
|
-
await tx.objectStore(OBJECT_STORE_NAME).delete(key);
|
|
445
|
-
await tx.done;
|
|
446
|
-
}
|
|
447
|
-
/**
|
|
448
|
-
* Atomically updates a record with the result of updateFn, which gets
|
|
449
|
-
* called with the current value. If newValue is undefined, the record is
|
|
450
|
-
* deleted instead.
|
|
451
|
-
* @return Updated value
|
|
452
|
-
*/
|
|
453
|
-
async function update(appConfig, updateFn) {
|
|
454
|
-
const key = getKey(appConfig);
|
|
455
|
-
const db = await getDbPromise();
|
|
456
|
-
const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
|
|
457
|
-
const store = tx.objectStore(OBJECT_STORE_NAME);
|
|
458
|
-
const oldValue = (await store.get(key));
|
|
459
|
-
const newValue = updateFn(oldValue);
|
|
460
|
-
if (newValue === undefined) {
|
|
461
|
-
await store.delete(key);
|
|
462
|
-
}
|
|
463
|
-
else {
|
|
464
|
-
await store.put(newValue, key);
|
|
465
|
-
}
|
|
466
|
-
await tx.done;
|
|
467
|
-
if (newValue && (!oldValue || oldValue.fid !== newValue.fid)) {
|
|
468
|
-
fidChanged(appConfig, newValue.fid);
|
|
469
|
-
}
|
|
470
|
-
return newValue;
|
|
387
|
+
/**
|
|
388
|
+
* @license
|
|
389
|
+
* Copyright 2019 Google LLC
|
|
390
|
+
*
|
|
391
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
392
|
+
* you may not use this file except in compliance with the License.
|
|
393
|
+
* You may obtain a copy of the License at
|
|
394
|
+
*
|
|
395
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
396
|
+
*
|
|
397
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
398
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
399
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
400
|
+
* See the License for the specific language governing permissions and
|
|
401
|
+
* limitations under the License.
|
|
402
|
+
*/
|
|
403
|
+
const DATABASE_NAME = 'firebase-installations-database';
|
|
404
|
+
const DATABASE_VERSION = 1;
|
|
405
|
+
const OBJECT_STORE_NAME = 'firebase-installations-store';
|
|
406
|
+
let dbPromise = null;
|
|
407
|
+
function getDbPromise() {
|
|
408
|
+
if (!dbPromise) {
|
|
409
|
+
dbPromise = openDB(DATABASE_NAME, DATABASE_VERSION, {
|
|
410
|
+
upgrade: (db, oldVersion) => {
|
|
411
|
+
// We don't use 'break' in this switch statement, the fall-through
|
|
412
|
+
// behavior is what we want, because if there are multiple versions between
|
|
413
|
+
// the old version and the current version, we want ALL the migrations
|
|
414
|
+
// that correspond to those versions to run, not only the last one.
|
|
415
|
+
// eslint-disable-next-line default-case
|
|
416
|
+
switch (oldVersion) {
|
|
417
|
+
case 0:
|
|
418
|
+
db.createObjectStore(OBJECT_STORE_NAME);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
return dbPromise;
|
|
424
|
+
}
|
|
425
|
+
/** Assigns or overwrites the record for the given key with the given value. */
|
|
426
|
+
async function set(appConfig, value) {
|
|
427
|
+
const key = getKey(appConfig);
|
|
428
|
+
const db = await getDbPromise();
|
|
429
|
+
const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
|
|
430
|
+
const objectStore = tx.objectStore(OBJECT_STORE_NAME);
|
|
431
|
+
const oldValue = (await objectStore.get(key));
|
|
432
|
+
await objectStore.put(value, key);
|
|
433
|
+
await tx.done;
|
|
434
|
+
if (!oldValue || oldValue.fid !== value.fid) {
|
|
435
|
+
fidChanged(appConfig, value.fid);
|
|
436
|
+
}
|
|
437
|
+
return value;
|
|
438
|
+
}
|
|
439
|
+
/** Removes record(s) from the objectStore that match the given key. */
|
|
440
|
+
async function remove(appConfig) {
|
|
441
|
+
const key = getKey(appConfig);
|
|
442
|
+
const db = await getDbPromise();
|
|
443
|
+
const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
|
|
444
|
+
await tx.objectStore(OBJECT_STORE_NAME).delete(key);
|
|
445
|
+
await tx.done;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Atomically updates a record with the result of updateFn, which gets
|
|
449
|
+
* called with the current value. If newValue is undefined, the record is
|
|
450
|
+
* deleted instead.
|
|
451
|
+
* @return Updated value
|
|
452
|
+
*/
|
|
453
|
+
async function update(appConfig, updateFn) {
|
|
454
|
+
const key = getKey(appConfig);
|
|
455
|
+
const db = await getDbPromise();
|
|
456
|
+
const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
|
|
457
|
+
const store = tx.objectStore(OBJECT_STORE_NAME);
|
|
458
|
+
const oldValue = (await store.get(key));
|
|
459
|
+
const newValue = updateFn(oldValue);
|
|
460
|
+
if (newValue === undefined) {
|
|
461
|
+
await store.delete(key);
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
await store.put(newValue, key);
|
|
465
|
+
}
|
|
466
|
+
await tx.done;
|
|
467
|
+
if (newValue && (!oldValue || oldValue.fid !== newValue.fid)) {
|
|
468
|
+
fidChanged(appConfig, newValue.fid);
|
|
469
|
+
}
|
|
470
|
+
return newValue;
|
|
471
471
|
}
|
|
472
472
|
|
|
473
|
-
/**
|
|
474
|
-
* @license
|
|
475
|
-
* Copyright 2019 Google LLC
|
|
476
|
-
*
|
|
477
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
478
|
-
* you may not use this file except in compliance with the License.
|
|
479
|
-
* You may obtain a copy of the License at
|
|
480
|
-
*
|
|
481
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
482
|
-
*
|
|
483
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
484
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
485
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
486
|
-
* See the License for the specific language governing permissions and
|
|
487
|
-
* limitations under the License.
|
|
488
|
-
*/
|
|
489
|
-
/**
|
|
490
|
-
* Updates and returns the InstallationEntry from the database.
|
|
491
|
-
* Also triggers a registration request if it is necessary and possible.
|
|
492
|
-
*/
|
|
493
|
-
async function getInstallationEntry(installations) {
|
|
494
|
-
let registrationPromise;
|
|
495
|
-
const installationEntry = await update(installations.appConfig, oldEntry => {
|
|
496
|
-
const installationEntry = updateOrCreateInstallationEntry(oldEntry);
|
|
497
|
-
const entryWithPromise = triggerRegistrationIfNecessary(installations, installationEntry);
|
|
498
|
-
registrationPromise = entryWithPromise.registrationPromise;
|
|
499
|
-
return entryWithPromise.installationEntry;
|
|
500
|
-
});
|
|
501
|
-
if (installationEntry.fid === INVALID_FID) {
|
|
502
|
-
// FID generation failed. Waiting for the FID from the server.
|
|
503
|
-
return { installationEntry: await registrationPromise };
|
|
504
|
-
}
|
|
505
|
-
return {
|
|
506
|
-
installationEntry,
|
|
507
|
-
registrationPromise
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
* Creates a new Installation Entry if one does not exist.
|
|
512
|
-
* Also clears timed out pending requests.
|
|
513
|
-
*/
|
|
514
|
-
function updateOrCreateInstallationEntry(oldEntry) {
|
|
515
|
-
const entry = oldEntry || {
|
|
516
|
-
fid: generateFid(),
|
|
517
|
-
registrationStatus: 0 /* RequestStatus.NOT_STARTED */
|
|
518
|
-
};
|
|
519
|
-
return clearTimedOutRequest(entry);
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* If the Firebase Installation is not registered yet, this will trigger the
|
|
523
|
-
* registration and return an InProgressInstallationEntry.
|
|
524
|
-
*
|
|
525
|
-
* If registrationPromise does not exist, the installationEntry is guaranteed
|
|
526
|
-
* to be registered.
|
|
527
|
-
*/
|
|
528
|
-
function triggerRegistrationIfNecessary(installations, installationEntry) {
|
|
529
|
-
if (installationEntry.registrationStatus === 0 /* RequestStatus.NOT_STARTED */) {
|
|
530
|
-
if (!navigator.onLine) {
|
|
531
|
-
// Registration required but app is offline.
|
|
532
|
-
const registrationPromiseWithError = Promise.reject(ERROR_FACTORY.create("app-offline" /* ErrorCode.APP_OFFLINE */));
|
|
533
|
-
return {
|
|
534
|
-
installationEntry,
|
|
535
|
-
registrationPromise: registrationPromiseWithError
|
|
536
|
-
};
|
|
537
|
-
}
|
|
538
|
-
// Try registering. Change status to IN_PROGRESS.
|
|
539
|
-
const inProgressEntry = {
|
|
540
|
-
fid: installationEntry.fid,
|
|
541
|
-
registrationStatus: 1 /* RequestStatus.IN_PROGRESS */,
|
|
542
|
-
registrationTime: Date.now()
|
|
543
|
-
};
|
|
544
|
-
const registrationPromise = registerInstallation(installations, inProgressEntry);
|
|
545
|
-
return { installationEntry: inProgressEntry, registrationPromise };
|
|
546
|
-
}
|
|
547
|
-
else if (installationEntry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */) {
|
|
548
|
-
return {
|
|
549
|
-
installationEntry,
|
|
550
|
-
registrationPromise: waitUntilFidRegistration(installations)
|
|
551
|
-
};
|
|
552
|
-
}
|
|
553
|
-
else {
|
|
554
|
-
return { installationEntry };
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
/** This will be executed only once for each new Firebase Installation. */
|
|
558
|
-
async function registerInstallation(installations, installationEntry) {
|
|
559
|
-
try {
|
|
560
|
-
const registeredInstallationEntry = await createInstallationRequest(installations, installationEntry);
|
|
561
|
-
return set(installations.appConfig, registeredInstallationEntry);
|
|
562
|
-
}
|
|
563
|
-
catch (e) {
|
|
564
|
-
if (isServerError(e) && e.customData.serverCode === 409) {
|
|
565
|
-
// Server returned a "FID cannot be used" error.
|
|
566
|
-
// Generate a new ID next time.
|
|
567
|
-
await remove(installations.appConfig);
|
|
568
|
-
}
|
|
569
|
-
else {
|
|
570
|
-
// Registration failed. Set FID as not registered.
|
|
571
|
-
await set(installations.appConfig, {
|
|
572
|
-
fid: installationEntry.fid,
|
|
573
|
-
registrationStatus: 0 /* RequestStatus.NOT_STARTED */
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
throw e;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
/** Call if FID registration is pending in another request. */
|
|
580
|
-
async function waitUntilFidRegistration(installations) {
|
|
581
|
-
// Unfortunately, there is no way of reliably observing when a value in
|
|
582
|
-
// IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers),
|
|
583
|
-
// so we need to poll.
|
|
584
|
-
let entry = await updateInstallationRequest(installations.appConfig);
|
|
585
|
-
while (entry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */) {
|
|
586
|
-
// createInstallation request still in progress.
|
|
587
|
-
await sleep(100);
|
|
588
|
-
entry = await updateInstallationRequest(installations.appConfig);
|
|
589
|
-
}
|
|
590
|
-
if (entry.registrationStatus === 0 /* RequestStatus.NOT_STARTED */) {
|
|
591
|
-
// The request timed out or failed in a different call. Try again.
|
|
592
|
-
const { installationEntry, registrationPromise } = await getInstallationEntry(installations);
|
|
593
|
-
if (registrationPromise) {
|
|
594
|
-
return registrationPromise;
|
|
595
|
-
}
|
|
596
|
-
else {
|
|
597
|
-
// if there is no registrationPromise, entry is registered.
|
|
598
|
-
return installationEntry;
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
return entry;
|
|
602
|
-
}
|
|
603
|
-
/**
|
|
604
|
-
* Called only if there is a CreateInstallation request in progress.
|
|
605
|
-
*
|
|
606
|
-
* Updates the InstallationEntry in the DB based on the status of the
|
|
607
|
-
* CreateInstallation request.
|
|
608
|
-
*
|
|
609
|
-
* Returns the updated InstallationEntry.
|
|
610
|
-
*/
|
|
611
|
-
function updateInstallationRequest(appConfig) {
|
|
612
|
-
return update(appConfig, oldEntry => {
|
|
613
|
-
if (!oldEntry) {
|
|
614
|
-
throw ERROR_FACTORY.create("installation-not-found" /* ErrorCode.INSTALLATION_NOT_FOUND */);
|
|
615
|
-
}
|
|
616
|
-
return clearTimedOutRequest(oldEntry);
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
|
-
function clearTimedOutRequest(entry) {
|
|
620
|
-
if (hasInstallationRequestTimedOut(entry)) {
|
|
621
|
-
return {
|
|
622
|
-
fid: entry.fid,
|
|
623
|
-
registrationStatus: 0 /* RequestStatus.NOT_STARTED */
|
|
624
|
-
};
|
|
625
|
-
}
|
|
626
|
-
return entry;
|
|
627
|
-
}
|
|
628
|
-
function hasInstallationRequestTimedOut(installationEntry) {
|
|
629
|
-
return (installationEntry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */ &&
|
|
630
|
-
installationEntry.registrationTime + PENDING_TIMEOUT_MS < Date.now());
|
|
473
|
+
/**
|
|
474
|
+
* @license
|
|
475
|
+
* Copyright 2019 Google LLC
|
|
476
|
+
*
|
|
477
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
478
|
+
* you may not use this file except in compliance with the License.
|
|
479
|
+
* You may obtain a copy of the License at
|
|
480
|
+
*
|
|
481
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
482
|
+
*
|
|
483
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
484
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
485
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
486
|
+
* See the License for the specific language governing permissions and
|
|
487
|
+
* limitations under the License.
|
|
488
|
+
*/
|
|
489
|
+
/**
|
|
490
|
+
* Updates and returns the InstallationEntry from the database.
|
|
491
|
+
* Also triggers a registration request if it is necessary and possible.
|
|
492
|
+
*/
|
|
493
|
+
async function getInstallationEntry(installations) {
|
|
494
|
+
let registrationPromise;
|
|
495
|
+
const installationEntry = await update(installations.appConfig, oldEntry => {
|
|
496
|
+
const installationEntry = updateOrCreateInstallationEntry(oldEntry);
|
|
497
|
+
const entryWithPromise = triggerRegistrationIfNecessary(installations, installationEntry);
|
|
498
|
+
registrationPromise = entryWithPromise.registrationPromise;
|
|
499
|
+
return entryWithPromise.installationEntry;
|
|
500
|
+
});
|
|
501
|
+
if (installationEntry.fid === INVALID_FID) {
|
|
502
|
+
// FID generation failed. Waiting for the FID from the server.
|
|
503
|
+
return { installationEntry: await registrationPromise };
|
|
504
|
+
}
|
|
505
|
+
return {
|
|
506
|
+
installationEntry,
|
|
507
|
+
registrationPromise
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Creates a new Installation Entry if one does not exist.
|
|
512
|
+
* Also clears timed out pending requests.
|
|
513
|
+
*/
|
|
514
|
+
function updateOrCreateInstallationEntry(oldEntry) {
|
|
515
|
+
const entry = oldEntry || {
|
|
516
|
+
fid: generateFid(),
|
|
517
|
+
registrationStatus: 0 /* RequestStatus.NOT_STARTED */
|
|
518
|
+
};
|
|
519
|
+
return clearTimedOutRequest(entry);
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* If the Firebase Installation is not registered yet, this will trigger the
|
|
523
|
+
* registration and return an InProgressInstallationEntry.
|
|
524
|
+
*
|
|
525
|
+
* If registrationPromise does not exist, the installationEntry is guaranteed
|
|
526
|
+
* to be registered.
|
|
527
|
+
*/
|
|
528
|
+
function triggerRegistrationIfNecessary(installations, installationEntry) {
|
|
529
|
+
if (installationEntry.registrationStatus === 0 /* RequestStatus.NOT_STARTED */) {
|
|
530
|
+
if (!navigator.onLine) {
|
|
531
|
+
// Registration required but app is offline.
|
|
532
|
+
const registrationPromiseWithError = Promise.reject(ERROR_FACTORY.create("app-offline" /* ErrorCode.APP_OFFLINE */));
|
|
533
|
+
return {
|
|
534
|
+
installationEntry,
|
|
535
|
+
registrationPromise: registrationPromiseWithError
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
// Try registering. Change status to IN_PROGRESS.
|
|
539
|
+
const inProgressEntry = {
|
|
540
|
+
fid: installationEntry.fid,
|
|
541
|
+
registrationStatus: 1 /* RequestStatus.IN_PROGRESS */,
|
|
542
|
+
registrationTime: Date.now()
|
|
543
|
+
};
|
|
544
|
+
const registrationPromise = registerInstallation(installations, inProgressEntry);
|
|
545
|
+
return { installationEntry: inProgressEntry, registrationPromise };
|
|
546
|
+
}
|
|
547
|
+
else if (installationEntry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */) {
|
|
548
|
+
return {
|
|
549
|
+
installationEntry,
|
|
550
|
+
registrationPromise: waitUntilFidRegistration(installations)
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
else {
|
|
554
|
+
return { installationEntry };
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
/** This will be executed only once for each new Firebase Installation. */
|
|
558
|
+
async function registerInstallation(installations, installationEntry) {
|
|
559
|
+
try {
|
|
560
|
+
const registeredInstallationEntry = await createInstallationRequest(installations, installationEntry);
|
|
561
|
+
return set(installations.appConfig, registeredInstallationEntry);
|
|
562
|
+
}
|
|
563
|
+
catch (e) {
|
|
564
|
+
if (isServerError(e) && e.customData.serverCode === 409) {
|
|
565
|
+
// Server returned a "FID cannot be used" error.
|
|
566
|
+
// Generate a new ID next time.
|
|
567
|
+
await remove(installations.appConfig);
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
// Registration failed. Set FID as not registered.
|
|
571
|
+
await set(installations.appConfig, {
|
|
572
|
+
fid: installationEntry.fid,
|
|
573
|
+
registrationStatus: 0 /* RequestStatus.NOT_STARTED */
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
throw e;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
/** Call if FID registration is pending in another request. */
|
|
580
|
+
async function waitUntilFidRegistration(installations) {
|
|
581
|
+
// Unfortunately, there is no way of reliably observing when a value in
|
|
582
|
+
// IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers),
|
|
583
|
+
// so we need to poll.
|
|
584
|
+
let entry = await updateInstallationRequest(installations.appConfig);
|
|
585
|
+
while (entry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */) {
|
|
586
|
+
// createInstallation request still in progress.
|
|
587
|
+
await sleep(100);
|
|
588
|
+
entry = await updateInstallationRequest(installations.appConfig);
|
|
589
|
+
}
|
|
590
|
+
if (entry.registrationStatus === 0 /* RequestStatus.NOT_STARTED */) {
|
|
591
|
+
// The request timed out or failed in a different call. Try again.
|
|
592
|
+
const { installationEntry, registrationPromise } = await getInstallationEntry(installations);
|
|
593
|
+
if (registrationPromise) {
|
|
594
|
+
return registrationPromise;
|
|
595
|
+
}
|
|
596
|
+
else {
|
|
597
|
+
// if there is no registrationPromise, entry is registered.
|
|
598
|
+
return installationEntry;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
return entry;
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Called only if there is a CreateInstallation request in progress.
|
|
605
|
+
*
|
|
606
|
+
* Updates the InstallationEntry in the DB based on the status of the
|
|
607
|
+
* CreateInstallation request.
|
|
608
|
+
*
|
|
609
|
+
* Returns the updated InstallationEntry.
|
|
610
|
+
*/
|
|
611
|
+
function updateInstallationRequest(appConfig) {
|
|
612
|
+
return update(appConfig, oldEntry => {
|
|
613
|
+
if (!oldEntry) {
|
|
614
|
+
throw ERROR_FACTORY.create("installation-not-found" /* ErrorCode.INSTALLATION_NOT_FOUND */);
|
|
615
|
+
}
|
|
616
|
+
return clearTimedOutRequest(oldEntry);
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
function clearTimedOutRequest(entry) {
|
|
620
|
+
if (hasInstallationRequestTimedOut(entry)) {
|
|
621
|
+
return {
|
|
622
|
+
fid: entry.fid,
|
|
623
|
+
registrationStatus: 0 /* RequestStatus.NOT_STARTED */
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
return entry;
|
|
627
|
+
}
|
|
628
|
+
function hasInstallationRequestTimedOut(installationEntry) {
|
|
629
|
+
return (installationEntry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */ &&
|
|
630
|
+
installationEntry.registrationTime + PENDING_TIMEOUT_MS < Date.now());
|
|
631
631
|
}
|
|
632
632
|
|
|
633
|
-
/**
|
|
634
|
-
* @license
|
|
635
|
-
* Copyright 2019 Google LLC
|
|
636
|
-
*
|
|
637
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
638
|
-
* you may not use this file except in compliance with the License.
|
|
639
|
-
* You may obtain a copy of the License at
|
|
640
|
-
*
|
|
641
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
642
|
-
*
|
|
643
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
644
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
645
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
646
|
-
* See the License for the specific language governing permissions and
|
|
647
|
-
* limitations under the License.
|
|
648
|
-
*/
|
|
649
|
-
async function generateAuthTokenRequest({ appConfig, heartbeatServiceProvider }, installationEntry) {
|
|
650
|
-
const endpoint = getGenerateAuthTokenEndpoint(appConfig, installationEntry);
|
|
651
|
-
const headers = getHeadersWithAuth(appConfig, installationEntry);
|
|
652
|
-
// If heartbeat service exists, add the heartbeat string to the header.
|
|
653
|
-
const heartbeatService = heartbeatServiceProvider.getImmediate({
|
|
654
|
-
optional: true
|
|
655
|
-
});
|
|
656
|
-
if (heartbeatService) {
|
|
657
|
-
const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader();
|
|
658
|
-
if (heartbeatsHeader) {
|
|
659
|
-
headers.append('x-firebase-client', heartbeatsHeader);
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
const body = {
|
|
663
|
-
installation: {
|
|
664
|
-
sdkVersion: PACKAGE_VERSION,
|
|
665
|
-
appId: appConfig.appId
|
|
666
|
-
}
|
|
667
|
-
};
|
|
668
|
-
const request = {
|
|
669
|
-
method: 'POST',
|
|
670
|
-
headers,
|
|
671
|
-
body: JSON.stringify(body)
|
|
672
|
-
};
|
|
673
|
-
const response = await retryIfServerError(() => fetch(endpoint, request));
|
|
674
|
-
if (response.ok) {
|
|
675
|
-
const responseValue = await response.json();
|
|
676
|
-
const completedAuthToken = extractAuthTokenInfoFromResponse(responseValue);
|
|
677
|
-
return completedAuthToken;
|
|
678
|
-
}
|
|
679
|
-
else {
|
|
680
|
-
throw await getErrorFromResponse('Generate Auth Token', response);
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
function getGenerateAuthTokenEndpoint(appConfig, { fid }) {
|
|
684
|
-
return `${getInstallationsEndpoint(appConfig)}/${fid}/authTokens:generate`;
|
|
633
|
+
/**
|
|
634
|
+
* @license
|
|
635
|
+
* Copyright 2019 Google LLC
|
|
636
|
+
*
|
|
637
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
638
|
+
* you may not use this file except in compliance with the License.
|
|
639
|
+
* You may obtain a copy of the License at
|
|
640
|
+
*
|
|
641
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
642
|
+
*
|
|
643
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
644
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
645
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
646
|
+
* See the License for the specific language governing permissions and
|
|
647
|
+
* limitations under the License.
|
|
648
|
+
*/
|
|
649
|
+
async function generateAuthTokenRequest({ appConfig, heartbeatServiceProvider }, installationEntry) {
|
|
650
|
+
const endpoint = getGenerateAuthTokenEndpoint(appConfig, installationEntry);
|
|
651
|
+
const headers = getHeadersWithAuth(appConfig, installationEntry);
|
|
652
|
+
// If heartbeat service exists, add the heartbeat string to the header.
|
|
653
|
+
const heartbeatService = heartbeatServiceProvider.getImmediate({
|
|
654
|
+
optional: true
|
|
655
|
+
});
|
|
656
|
+
if (heartbeatService) {
|
|
657
|
+
const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader();
|
|
658
|
+
if (heartbeatsHeader) {
|
|
659
|
+
headers.append('x-firebase-client', heartbeatsHeader);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
const body = {
|
|
663
|
+
installation: {
|
|
664
|
+
sdkVersion: PACKAGE_VERSION,
|
|
665
|
+
appId: appConfig.appId
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
const request = {
|
|
669
|
+
method: 'POST',
|
|
670
|
+
headers,
|
|
671
|
+
body: JSON.stringify(body)
|
|
672
|
+
};
|
|
673
|
+
const response = await retryIfServerError(() => fetch(endpoint, request));
|
|
674
|
+
if (response.ok) {
|
|
675
|
+
const responseValue = await response.json();
|
|
676
|
+
const completedAuthToken = extractAuthTokenInfoFromResponse(responseValue);
|
|
677
|
+
return completedAuthToken;
|
|
678
|
+
}
|
|
679
|
+
else {
|
|
680
|
+
throw await getErrorFromResponse('Generate Auth Token', response);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
function getGenerateAuthTokenEndpoint(appConfig, { fid }) {
|
|
684
|
+
return `${getInstallationsEndpoint(appConfig)}/${fid}/authTokens:generate`;
|
|
685
685
|
}
|
|
686
686
|
|
|
687
|
-
/**
|
|
688
|
-
* @license
|
|
689
|
-
* Copyright 2019 Google LLC
|
|
690
|
-
*
|
|
691
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
692
|
-
* you may not use this file except in compliance with the License.
|
|
693
|
-
* You may obtain a copy of the License at
|
|
694
|
-
*
|
|
695
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
696
|
-
*
|
|
697
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
698
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
699
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
700
|
-
* See the License for the specific language governing permissions and
|
|
701
|
-
* limitations under the License.
|
|
702
|
-
*/
|
|
703
|
-
/**
|
|
704
|
-
* Returns a valid authentication token for the installation. Generates a new
|
|
705
|
-
* token if one doesn't exist, is expired or about to expire.
|
|
706
|
-
*
|
|
707
|
-
* Should only be called if the Firebase Installation is registered.
|
|
708
|
-
*/
|
|
709
|
-
async function refreshAuthToken(installations, forceRefresh = false) {
|
|
710
|
-
let tokenPromise;
|
|
711
|
-
const entry = await update(installations.appConfig, oldEntry => {
|
|
712
|
-
if (!isEntryRegistered(oldEntry)) {
|
|
713
|
-
throw ERROR_FACTORY.create("not-registered" /* ErrorCode.NOT_REGISTERED */);
|
|
714
|
-
}
|
|
715
|
-
const oldAuthToken = oldEntry.authToken;
|
|
716
|
-
if (!forceRefresh && isAuthTokenValid(oldAuthToken)) {
|
|
717
|
-
// There is a valid token in the DB.
|
|
718
|
-
return oldEntry;
|
|
719
|
-
}
|
|
720
|
-
else if (oldAuthToken.requestStatus === 1 /* RequestStatus.IN_PROGRESS */) {
|
|
721
|
-
// There already is a token request in progress.
|
|
722
|
-
tokenPromise = waitUntilAuthTokenRequest(installations, forceRefresh);
|
|
723
|
-
return oldEntry;
|
|
724
|
-
}
|
|
725
|
-
else {
|
|
726
|
-
// No token or token expired.
|
|
727
|
-
if (!navigator.onLine) {
|
|
728
|
-
throw ERROR_FACTORY.create("app-offline" /* ErrorCode.APP_OFFLINE */);
|
|
729
|
-
}
|
|
730
|
-
const inProgressEntry = makeAuthTokenRequestInProgressEntry(oldEntry);
|
|
731
|
-
tokenPromise = fetchAuthTokenFromServer(installations, inProgressEntry);
|
|
732
|
-
return inProgressEntry;
|
|
733
|
-
}
|
|
734
|
-
});
|
|
735
|
-
const authToken = tokenPromise
|
|
736
|
-
? await tokenPromise
|
|
737
|
-
: entry.authToken;
|
|
738
|
-
return authToken;
|
|
739
|
-
}
|
|
740
|
-
/**
|
|
741
|
-
* Call only if FID is registered and Auth Token request is in progress.
|
|
742
|
-
*
|
|
743
|
-
* Waits until the current pending request finishes. If the request times out,
|
|
744
|
-
* tries once in this thread as well.
|
|
745
|
-
*/
|
|
746
|
-
async function waitUntilAuthTokenRequest(installations, forceRefresh) {
|
|
747
|
-
// Unfortunately, there is no way of reliably observing when a value in
|
|
748
|
-
// IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers),
|
|
749
|
-
// so we need to poll.
|
|
750
|
-
let entry = await updateAuthTokenRequest(installations.appConfig);
|
|
751
|
-
while (entry.authToken.requestStatus === 1 /* RequestStatus.IN_PROGRESS */) {
|
|
752
|
-
// generateAuthToken still in progress.
|
|
753
|
-
await sleep(100);
|
|
754
|
-
entry = await updateAuthTokenRequest(installations.appConfig);
|
|
755
|
-
}
|
|
756
|
-
const authToken = entry.authToken;
|
|
757
|
-
if (authToken.requestStatus === 0 /* RequestStatus.NOT_STARTED */) {
|
|
758
|
-
// The request timed out or failed in a different call. Try again.
|
|
759
|
-
return refreshAuthToken(installations, forceRefresh);
|
|
760
|
-
}
|
|
761
|
-
else {
|
|
762
|
-
return authToken;
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
/**
|
|
766
|
-
* Called only if there is a GenerateAuthToken request in progress.
|
|
767
|
-
*
|
|
768
|
-
* Updates the InstallationEntry in the DB based on the status of the
|
|
769
|
-
* GenerateAuthToken request.
|
|
770
|
-
*
|
|
771
|
-
* Returns the updated InstallationEntry.
|
|
772
|
-
*/
|
|
773
|
-
function updateAuthTokenRequest(appConfig) {
|
|
774
|
-
return update(appConfig, oldEntry => {
|
|
775
|
-
if (!isEntryRegistered(oldEntry)) {
|
|
776
|
-
throw ERROR_FACTORY.create("not-registered" /* ErrorCode.NOT_REGISTERED */);
|
|
777
|
-
}
|
|
778
|
-
const oldAuthToken = oldEntry.authToken;
|
|
779
|
-
if (hasAuthTokenRequestTimedOut(oldAuthToken)) {
|
|
780
|
-
return Object.assign(Object.assign({}, oldEntry), { authToken: { requestStatus: 0 /* RequestStatus.NOT_STARTED */ } });
|
|
781
|
-
}
|
|
782
|
-
return oldEntry;
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
async function fetchAuthTokenFromServer(installations, installationEntry) {
|
|
786
|
-
try {
|
|
787
|
-
const authToken = await generateAuthTokenRequest(installations, installationEntry);
|
|
788
|
-
const updatedInstallationEntry = Object.assign(Object.assign({}, installationEntry), { authToken });
|
|
789
|
-
await set(installations.appConfig, updatedInstallationEntry);
|
|
790
|
-
return authToken;
|
|
791
|
-
}
|
|
792
|
-
catch (e) {
|
|
793
|
-
if (isServerError(e) &&
|
|
794
|
-
(e.customData.serverCode === 401 || e.customData.serverCode === 404)) {
|
|
795
|
-
// Server returned a "FID not found" or a "Invalid authentication" error.
|
|
796
|
-
// Generate a new ID next time.
|
|
797
|
-
await remove(installations.appConfig);
|
|
798
|
-
}
|
|
799
|
-
else {
|
|
800
|
-
const updatedInstallationEntry = Object.assign(Object.assign({}, installationEntry), { authToken: { requestStatus: 0 /* RequestStatus.NOT_STARTED */ } });
|
|
801
|
-
await set(installations.appConfig, updatedInstallationEntry);
|
|
802
|
-
}
|
|
803
|
-
throw e;
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
function isEntryRegistered(installationEntry) {
|
|
807
|
-
return (installationEntry !== undefined &&
|
|
808
|
-
installationEntry.registrationStatus === 2 /* RequestStatus.COMPLETED */);
|
|
809
|
-
}
|
|
810
|
-
function isAuthTokenValid(authToken) {
|
|
811
|
-
return (authToken.requestStatus === 2 /* RequestStatus.COMPLETED */ &&
|
|
812
|
-
!isAuthTokenExpired(authToken));
|
|
813
|
-
}
|
|
814
|
-
function isAuthTokenExpired(authToken) {
|
|
815
|
-
const now = Date.now();
|
|
816
|
-
return (now < authToken.creationTime ||
|
|
817
|
-
authToken.creationTime + authToken.expiresIn < now + TOKEN_EXPIRATION_BUFFER);
|
|
818
|
-
}
|
|
819
|
-
/** Returns an updated InstallationEntry with an InProgressAuthToken. */
|
|
820
|
-
function makeAuthTokenRequestInProgressEntry(oldEntry) {
|
|
821
|
-
const inProgressAuthToken = {
|
|
822
|
-
requestStatus: 1 /* RequestStatus.IN_PROGRESS */,
|
|
823
|
-
requestTime: Date.now()
|
|
824
|
-
};
|
|
825
|
-
return Object.assign(Object.assign({}, oldEntry), { authToken: inProgressAuthToken });
|
|
826
|
-
}
|
|
827
|
-
function hasAuthTokenRequestTimedOut(authToken) {
|
|
828
|
-
return (authToken.requestStatus === 1 /* RequestStatus.IN_PROGRESS */ &&
|
|
829
|
-
authToken.requestTime + PENDING_TIMEOUT_MS < Date.now());
|
|
687
|
+
/**
|
|
688
|
+
* @license
|
|
689
|
+
* Copyright 2019 Google LLC
|
|
690
|
+
*
|
|
691
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
692
|
+
* you may not use this file except in compliance with the License.
|
|
693
|
+
* You may obtain a copy of the License at
|
|
694
|
+
*
|
|
695
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
696
|
+
*
|
|
697
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
698
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
699
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
700
|
+
* See the License for the specific language governing permissions and
|
|
701
|
+
* limitations under the License.
|
|
702
|
+
*/
|
|
703
|
+
/**
|
|
704
|
+
* Returns a valid authentication token for the installation. Generates a new
|
|
705
|
+
* token if one doesn't exist, is expired or about to expire.
|
|
706
|
+
*
|
|
707
|
+
* Should only be called if the Firebase Installation is registered.
|
|
708
|
+
*/
|
|
709
|
+
async function refreshAuthToken(installations, forceRefresh = false) {
|
|
710
|
+
let tokenPromise;
|
|
711
|
+
const entry = await update(installations.appConfig, oldEntry => {
|
|
712
|
+
if (!isEntryRegistered(oldEntry)) {
|
|
713
|
+
throw ERROR_FACTORY.create("not-registered" /* ErrorCode.NOT_REGISTERED */);
|
|
714
|
+
}
|
|
715
|
+
const oldAuthToken = oldEntry.authToken;
|
|
716
|
+
if (!forceRefresh && isAuthTokenValid(oldAuthToken)) {
|
|
717
|
+
// There is a valid token in the DB.
|
|
718
|
+
return oldEntry;
|
|
719
|
+
}
|
|
720
|
+
else if (oldAuthToken.requestStatus === 1 /* RequestStatus.IN_PROGRESS */) {
|
|
721
|
+
// There already is a token request in progress.
|
|
722
|
+
tokenPromise = waitUntilAuthTokenRequest(installations, forceRefresh);
|
|
723
|
+
return oldEntry;
|
|
724
|
+
}
|
|
725
|
+
else {
|
|
726
|
+
// No token or token expired.
|
|
727
|
+
if (!navigator.onLine) {
|
|
728
|
+
throw ERROR_FACTORY.create("app-offline" /* ErrorCode.APP_OFFLINE */);
|
|
729
|
+
}
|
|
730
|
+
const inProgressEntry = makeAuthTokenRequestInProgressEntry(oldEntry);
|
|
731
|
+
tokenPromise = fetchAuthTokenFromServer(installations, inProgressEntry);
|
|
732
|
+
return inProgressEntry;
|
|
733
|
+
}
|
|
734
|
+
});
|
|
735
|
+
const authToken = tokenPromise
|
|
736
|
+
? await tokenPromise
|
|
737
|
+
: entry.authToken;
|
|
738
|
+
return authToken;
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Call only if FID is registered and Auth Token request is in progress.
|
|
742
|
+
*
|
|
743
|
+
* Waits until the current pending request finishes. If the request times out,
|
|
744
|
+
* tries once in this thread as well.
|
|
745
|
+
*/
|
|
746
|
+
async function waitUntilAuthTokenRequest(installations, forceRefresh) {
|
|
747
|
+
// Unfortunately, there is no way of reliably observing when a value in
|
|
748
|
+
// IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers),
|
|
749
|
+
// so we need to poll.
|
|
750
|
+
let entry = await updateAuthTokenRequest(installations.appConfig);
|
|
751
|
+
while (entry.authToken.requestStatus === 1 /* RequestStatus.IN_PROGRESS */) {
|
|
752
|
+
// generateAuthToken still in progress.
|
|
753
|
+
await sleep(100);
|
|
754
|
+
entry = await updateAuthTokenRequest(installations.appConfig);
|
|
755
|
+
}
|
|
756
|
+
const authToken = entry.authToken;
|
|
757
|
+
if (authToken.requestStatus === 0 /* RequestStatus.NOT_STARTED */) {
|
|
758
|
+
// The request timed out or failed in a different call. Try again.
|
|
759
|
+
return refreshAuthToken(installations, forceRefresh);
|
|
760
|
+
}
|
|
761
|
+
else {
|
|
762
|
+
return authToken;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Called only if there is a GenerateAuthToken request in progress.
|
|
767
|
+
*
|
|
768
|
+
* Updates the InstallationEntry in the DB based on the status of the
|
|
769
|
+
* GenerateAuthToken request.
|
|
770
|
+
*
|
|
771
|
+
* Returns the updated InstallationEntry.
|
|
772
|
+
*/
|
|
773
|
+
function updateAuthTokenRequest(appConfig) {
|
|
774
|
+
return update(appConfig, oldEntry => {
|
|
775
|
+
if (!isEntryRegistered(oldEntry)) {
|
|
776
|
+
throw ERROR_FACTORY.create("not-registered" /* ErrorCode.NOT_REGISTERED */);
|
|
777
|
+
}
|
|
778
|
+
const oldAuthToken = oldEntry.authToken;
|
|
779
|
+
if (hasAuthTokenRequestTimedOut(oldAuthToken)) {
|
|
780
|
+
return Object.assign(Object.assign({}, oldEntry), { authToken: { requestStatus: 0 /* RequestStatus.NOT_STARTED */ } });
|
|
781
|
+
}
|
|
782
|
+
return oldEntry;
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
async function fetchAuthTokenFromServer(installations, installationEntry) {
|
|
786
|
+
try {
|
|
787
|
+
const authToken = await generateAuthTokenRequest(installations, installationEntry);
|
|
788
|
+
const updatedInstallationEntry = Object.assign(Object.assign({}, installationEntry), { authToken });
|
|
789
|
+
await set(installations.appConfig, updatedInstallationEntry);
|
|
790
|
+
return authToken;
|
|
791
|
+
}
|
|
792
|
+
catch (e) {
|
|
793
|
+
if (isServerError(e) &&
|
|
794
|
+
(e.customData.serverCode === 401 || e.customData.serverCode === 404)) {
|
|
795
|
+
// Server returned a "FID not found" or a "Invalid authentication" error.
|
|
796
|
+
// Generate a new ID next time.
|
|
797
|
+
await remove(installations.appConfig);
|
|
798
|
+
}
|
|
799
|
+
else {
|
|
800
|
+
const updatedInstallationEntry = Object.assign(Object.assign({}, installationEntry), { authToken: { requestStatus: 0 /* RequestStatus.NOT_STARTED */ } });
|
|
801
|
+
await set(installations.appConfig, updatedInstallationEntry);
|
|
802
|
+
}
|
|
803
|
+
throw e;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
function isEntryRegistered(installationEntry) {
|
|
807
|
+
return (installationEntry !== undefined &&
|
|
808
|
+
installationEntry.registrationStatus === 2 /* RequestStatus.COMPLETED */);
|
|
809
|
+
}
|
|
810
|
+
function isAuthTokenValid(authToken) {
|
|
811
|
+
return (authToken.requestStatus === 2 /* RequestStatus.COMPLETED */ &&
|
|
812
|
+
!isAuthTokenExpired(authToken));
|
|
813
|
+
}
|
|
814
|
+
function isAuthTokenExpired(authToken) {
|
|
815
|
+
const now = Date.now();
|
|
816
|
+
return (now < authToken.creationTime ||
|
|
817
|
+
authToken.creationTime + authToken.expiresIn < now + TOKEN_EXPIRATION_BUFFER);
|
|
818
|
+
}
|
|
819
|
+
/** Returns an updated InstallationEntry with an InProgressAuthToken. */
|
|
820
|
+
function makeAuthTokenRequestInProgressEntry(oldEntry) {
|
|
821
|
+
const inProgressAuthToken = {
|
|
822
|
+
requestStatus: 1 /* RequestStatus.IN_PROGRESS */,
|
|
823
|
+
requestTime: Date.now()
|
|
824
|
+
};
|
|
825
|
+
return Object.assign(Object.assign({}, oldEntry), { authToken: inProgressAuthToken });
|
|
826
|
+
}
|
|
827
|
+
function hasAuthTokenRequestTimedOut(authToken) {
|
|
828
|
+
return (authToken.requestStatus === 1 /* RequestStatus.IN_PROGRESS */ &&
|
|
829
|
+
authToken.requestTime + PENDING_TIMEOUT_MS < Date.now());
|
|
830
830
|
}
|
|
831
831
|
|
|
832
|
-
/**
|
|
833
|
-
* @license
|
|
834
|
-
* Copyright 2019 Google LLC
|
|
835
|
-
*
|
|
836
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
837
|
-
* you may not use this file except in compliance with the License.
|
|
838
|
-
* You may obtain a copy of the License at
|
|
839
|
-
*
|
|
840
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
841
|
-
*
|
|
842
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
843
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
844
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
845
|
-
* See the License for the specific language governing permissions and
|
|
846
|
-
* limitations under the License.
|
|
847
|
-
*/
|
|
848
|
-
/**
|
|
849
|
-
* Creates a Firebase Installation if there isn't one for the app and
|
|
850
|
-
* returns the Installation ID.
|
|
851
|
-
* @param installations - The `Installations` instance.
|
|
852
|
-
*
|
|
853
|
-
* @public
|
|
854
|
-
*/
|
|
855
|
-
async function getId(installations) {
|
|
856
|
-
const installationsImpl = installations;
|
|
857
|
-
const { installationEntry, registrationPromise } = await getInstallationEntry(installationsImpl);
|
|
858
|
-
if (registrationPromise) {
|
|
859
|
-
registrationPromise.catch(console.error);
|
|
860
|
-
}
|
|
861
|
-
else {
|
|
862
|
-
// If the installation is already registered, update the authentication
|
|
863
|
-
// token if needed.
|
|
864
|
-
refreshAuthToken(installationsImpl).catch(console.error);
|
|
865
|
-
}
|
|
866
|
-
return installationEntry.fid;
|
|
832
|
+
/**
|
|
833
|
+
* @license
|
|
834
|
+
* Copyright 2019 Google LLC
|
|
835
|
+
*
|
|
836
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
837
|
+
* you may not use this file except in compliance with the License.
|
|
838
|
+
* You may obtain a copy of the License at
|
|
839
|
+
*
|
|
840
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
841
|
+
*
|
|
842
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
843
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
844
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
845
|
+
* See the License for the specific language governing permissions and
|
|
846
|
+
* limitations under the License.
|
|
847
|
+
*/
|
|
848
|
+
/**
|
|
849
|
+
* Creates a Firebase Installation if there isn't one for the app and
|
|
850
|
+
* returns the Installation ID.
|
|
851
|
+
* @param installations - The `Installations` instance.
|
|
852
|
+
*
|
|
853
|
+
* @public
|
|
854
|
+
*/
|
|
855
|
+
async function getId(installations) {
|
|
856
|
+
const installationsImpl = installations;
|
|
857
|
+
const { installationEntry, registrationPromise } = await getInstallationEntry(installationsImpl);
|
|
858
|
+
if (registrationPromise) {
|
|
859
|
+
registrationPromise.catch(console.error);
|
|
860
|
+
}
|
|
861
|
+
else {
|
|
862
|
+
// If the installation is already registered, update the authentication
|
|
863
|
+
// token if needed.
|
|
864
|
+
refreshAuthToken(installationsImpl).catch(console.error);
|
|
865
|
+
}
|
|
866
|
+
return installationEntry.fid;
|
|
867
867
|
}
|
|
868
868
|
|
|
869
|
-
/**
|
|
870
|
-
* @license
|
|
871
|
-
* Copyright 2019 Google LLC
|
|
872
|
-
*
|
|
873
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
874
|
-
* you may not use this file except in compliance with the License.
|
|
875
|
-
* You may obtain a copy of the License at
|
|
876
|
-
*
|
|
877
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
878
|
-
*
|
|
879
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
880
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
881
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
882
|
-
* See the License for the specific language governing permissions and
|
|
883
|
-
* limitations under the License.
|
|
884
|
-
*/
|
|
885
|
-
/**
|
|
886
|
-
* Returns a Firebase Installations auth token, identifying the current
|
|
887
|
-
* Firebase Installation.
|
|
888
|
-
* @param installations - The `Installations` instance.
|
|
889
|
-
* @param forceRefresh - Force refresh regardless of token expiration.
|
|
890
|
-
*
|
|
891
|
-
* @public
|
|
892
|
-
*/
|
|
893
|
-
async function getToken(installations, forceRefresh = false) {
|
|
894
|
-
const installationsImpl = installations;
|
|
895
|
-
await completeInstallationRegistration(installationsImpl);
|
|
896
|
-
// At this point we either have a Registered Installation in the DB, or we've
|
|
897
|
-
// already thrown an error.
|
|
898
|
-
const authToken = await refreshAuthToken(installationsImpl, forceRefresh);
|
|
899
|
-
return authToken.token;
|
|
900
|
-
}
|
|
901
|
-
async function completeInstallationRegistration(installations) {
|
|
902
|
-
const { registrationPromise } = await getInstallationEntry(installations);
|
|
903
|
-
if (registrationPromise) {
|
|
904
|
-
// A createInstallation request is in progress. Wait until it finishes.
|
|
905
|
-
await registrationPromise;
|
|
906
|
-
}
|
|
869
|
+
/**
|
|
870
|
+
* @license
|
|
871
|
+
* Copyright 2019 Google LLC
|
|
872
|
+
*
|
|
873
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
874
|
+
* you may not use this file except in compliance with the License.
|
|
875
|
+
* You may obtain a copy of the License at
|
|
876
|
+
*
|
|
877
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
878
|
+
*
|
|
879
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
880
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
881
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
882
|
+
* See the License for the specific language governing permissions and
|
|
883
|
+
* limitations under the License.
|
|
884
|
+
*/
|
|
885
|
+
/**
|
|
886
|
+
* Returns a Firebase Installations auth token, identifying the current
|
|
887
|
+
* Firebase Installation.
|
|
888
|
+
* @param installations - The `Installations` instance.
|
|
889
|
+
* @param forceRefresh - Force refresh regardless of token expiration.
|
|
890
|
+
*
|
|
891
|
+
* @public
|
|
892
|
+
*/
|
|
893
|
+
async function getToken(installations, forceRefresh = false) {
|
|
894
|
+
const installationsImpl = installations;
|
|
895
|
+
await completeInstallationRegistration(installationsImpl);
|
|
896
|
+
// At this point we either have a Registered Installation in the DB, or we've
|
|
897
|
+
// already thrown an error.
|
|
898
|
+
const authToken = await refreshAuthToken(installationsImpl, forceRefresh);
|
|
899
|
+
return authToken.token;
|
|
900
|
+
}
|
|
901
|
+
async function completeInstallationRegistration(installations) {
|
|
902
|
+
const { registrationPromise } = await getInstallationEntry(installations);
|
|
903
|
+
if (registrationPromise) {
|
|
904
|
+
// A createInstallation request is in progress. Wait until it finishes.
|
|
905
|
+
await registrationPromise;
|
|
906
|
+
}
|
|
907
907
|
}
|
|
908
908
|
|
|
909
|
-
/**
|
|
910
|
-
* @license
|
|
911
|
-
* Copyright 2019 Google LLC
|
|
912
|
-
*
|
|
913
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
914
|
-
* you may not use this file except in compliance with the License.
|
|
915
|
-
* You may obtain a copy of the License at
|
|
916
|
-
*
|
|
917
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
918
|
-
*
|
|
919
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
920
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
921
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
922
|
-
* See the License for the specific language governing permissions and
|
|
923
|
-
* limitations under the License.
|
|
924
|
-
*/
|
|
925
|
-
async function deleteInstallationRequest(appConfig, installationEntry) {
|
|
926
|
-
const endpoint = getDeleteEndpoint(appConfig, installationEntry);
|
|
927
|
-
const headers = getHeadersWithAuth(appConfig, installationEntry);
|
|
928
|
-
const request = {
|
|
929
|
-
method: 'DELETE',
|
|
930
|
-
headers
|
|
931
|
-
};
|
|
932
|
-
const response = await retryIfServerError(() => fetch(endpoint, request));
|
|
933
|
-
if (!response.ok) {
|
|
934
|
-
throw await getErrorFromResponse('Delete Installation', response);
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
function getDeleteEndpoint(appConfig, { fid }) {
|
|
938
|
-
return `${getInstallationsEndpoint(appConfig)}/${fid}`;
|
|
909
|
+
/**
|
|
910
|
+
* @license
|
|
911
|
+
* Copyright 2019 Google LLC
|
|
912
|
+
*
|
|
913
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
914
|
+
* you may not use this file except in compliance with the License.
|
|
915
|
+
* You may obtain a copy of the License at
|
|
916
|
+
*
|
|
917
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
918
|
+
*
|
|
919
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
920
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
921
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
922
|
+
* See the License for the specific language governing permissions and
|
|
923
|
+
* limitations under the License.
|
|
924
|
+
*/
|
|
925
|
+
async function deleteInstallationRequest(appConfig, installationEntry) {
|
|
926
|
+
const endpoint = getDeleteEndpoint(appConfig, installationEntry);
|
|
927
|
+
const headers = getHeadersWithAuth(appConfig, installationEntry);
|
|
928
|
+
const request = {
|
|
929
|
+
method: 'DELETE',
|
|
930
|
+
headers
|
|
931
|
+
};
|
|
932
|
+
const response = await retryIfServerError(() => fetch(endpoint, request));
|
|
933
|
+
if (!response.ok) {
|
|
934
|
+
throw await getErrorFromResponse('Delete Installation', response);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
function getDeleteEndpoint(appConfig, { fid }) {
|
|
938
|
+
return `${getInstallationsEndpoint(appConfig)}/${fid}`;
|
|
939
939
|
}
|
|
940
940
|
|
|
941
|
-
/**
|
|
942
|
-
* @license
|
|
943
|
-
* Copyright 2019 Google LLC
|
|
944
|
-
*
|
|
945
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
946
|
-
* you may not use this file except in compliance with the License.
|
|
947
|
-
* You may obtain a copy of the License at
|
|
948
|
-
*
|
|
949
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
950
|
-
*
|
|
951
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
952
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
953
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
954
|
-
* See the License for the specific language governing permissions and
|
|
955
|
-
* limitations under the License.
|
|
956
|
-
*/
|
|
957
|
-
/**
|
|
958
|
-
* Deletes the Firebase Installation and all associated data.
|
|
959
|
-
* @param installations - The `Installations` instance.
|
|
960
|
-
*
|
|
961
|
-
* @public
|
|
962
|
-
*/
|
|
963
|
-
async function deleteInstallations(installations) {
|
|
964
|
-
const { appConfig } = installations;
|
|
965
|
-
const entry = await update(appConfig, oldEntry => {
|
|
966
|
-
if (oldEntry && oldEntry.registrationStatus === 0 /* RequestStatus.NOT_STARTED */) {
|
|
967
|
-
// Delete the unregistered entry without sending a deleteInstallation request.
|
|
968
|
-
return undefined;
|
|
969
|
-
}
|
|
970
|
-
return oldEntry;
|
|
971
|
-
});
|
|
972
|
-
if (entry) {
|
|
973
|
-
if (entry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */) {
|
|
974
|
-
// Can't delete while trying to register.
|
|
975
|
-
throw ERROR_FACTORY.create("delete-pending-registration" /* ErrorCode.DELETE_PENDING_REGISTRATION */);
|
|
976
|
-
}
|
|
977
|
-
else if (entry.registrationStatus === 2 /* RequestStatus.COMPLETED */) {
|
|
978
|
-
if (!navigator.onLine) {
|
|
979
|
-
throw ERROR_FACTORY.create("app-offline" /* ErrorCode.APP_OFFLINE */);
|
|
980
|
-
}
|
|
981
|
-
else {
|
|
982
|
-
await deleteInstallationRequest(appConfig, entry);
|
|
983
|
-
await remove(appConfig);
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
}
|
|
941
|
+
/**
|
|
942
|
+
* @license
|
|
943
|
+
* Copyright 2019 Google LLC
|
|
944
|
+
*
|
|
945
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
946
|
+
* you may not use this file except in compliance with the License.
|
|
947
|
+
* You may obtain a copy of the License at
|
|
948
|
+
*
|
|
949
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
950
|
+
*
|
|
951
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
952
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
953
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
954
|
+
* See the License for the specific language governing permissions and
|
|
955
|
+
* limitations under the License.
|
|
956
|
+
*/
|
|
957
|
+
/**
|
|
958
|
+
* Deletes the Firebase Installation and all associated data.
|
|
959
|
+
* @param installations - The `Installations` instance.
|
|
960
|
+
*
|
|
961
|
+
* @public
|
|
962
|
+
*/
|
|
963
|
+
async function deleteInstallations(installations) {
|
|
964
|
+
const { appConfig } = installations;
|
|
965
|
+
const entry = await update(appConfig, oldEntry => {
|
|
966
|
+
if (oldEntry && oldEntry.registrationStatus === 0 /* RequestStatus.NOT_STARTED */) {
|
|
967
|
+
// Delete the unregistered entry without sending a deleteInstallation request.
|
|
968
|
+
return undefined;
|
|
969
|
+
}
|
|
970
|
+
return oldEntry;
|
|
971
|
+
});
|
|
972
|
+
if (entry) {
|
|
973
|
+
if (entry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */) {
|
|
974
|
+
// Can't delete while trying to register.
|
|
975
|
+
throw ERROR_FACTORY.create("delete-pending-registration" /* ErrorCode.DELETE_PENDING_REGISTRATION */);
|
|
976
|
+
}
|
|
977
|
+
else if (entry.registrationStatus === 2 /* RequestStatus.COMPLETED */) {
|
|
978
|
+
if (!navigator.onLine) {
|
|
979
|
+
throw ERROR_FACTORY.create("app-offline" /* ErrorCode.APP_OFFLINE */);
|
|
980
|
+
}
|
|
981
|
+
else {
|
|
982
|
+
await deleteInstallationRequest(appConfig, entry);
|
|
983
|
+
await remove(appConfig);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
987
|
}
|
|
988
988
|
|
|
989
|
-
/**
|
|
990
|
-
* @license
|
|
991
|
-
* Copyright 2019 Google LLC
|
|
992
|
-
*
|
|
993
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
994
|
-
* you may not use this file except in compliance with the License.
|
|
995
|
-
* You may obtain a copy of the License at
|
|
996
|
-
*
|
|
997
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
998
|
-
*
|
|
999
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
1000
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1001
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1002
|
-
* See the License for the specific language governing permissions and
|
|
1003
|
-
* limitations under the License.
|
|
1004
|
-
*/
|
|
1005
|
-
/**
|
|
1006
|
-
* Sets a new callback that will get called when Installation ID changes.
|
|
1007
|
-
* Returns an unsubscribe function that will remove the callback when called.
|
|
1008
|
-
* @param installations - The `Installations` instance.
|
|
1009
|
-
* @param callback - The callback function that is invoked when FID changes.
|
|
1010
|
-
* @returns A function that can be called to unsubscribe.
|
|
1011
|
-
*
|
|
1012
|
-
* @public
|
|
1013
|
-
*/
|
|
1014
|
-
function onIdChange(installations, callback) {
|
|
1015
|
-
const { appConfig } = installations;
|
|
1016
|
-
addCallback(appConfig, callback);
|
|
1017
|
-
return () => {
|
|
1018
|
-
removeCallback(appConfig, callback);
|
|
1019
|
-
};
|
|
989
|
+
/**
|
|
990
|
+
* @license
|
|
991
|
+
* Copyright 2019 Google LLC
|
|
992
|
+
*
|
|
993
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
994
|
+
* you may not use this file except in compliance with the License.
|
|
995
|
+
* You may obtain a copy of the License at
|
|
996
|
+
*
|
|
997
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
998
|
+
*
|
|
999
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
1000
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1001
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1002
|
+
* See the License for the specific language governing permissions and
|
|
1003
|
+
* limitations under the License.
|
|
1004
|
+
*/
|
|
1005
|
+
/**
|
|
1006
|
+
* Sets a new callback that will get called when Installation ID changes.
|
|
1007
|
+
* Returns an unsubscribe function that will remove the callback when called.
|
|
1008
|
+
* @param installations - The `Installations` instance.
|
|
1009
|
+
* @param callback - The callback function that is invoked when FID changes.
|
|
1010
|
+
* @returns A function that can be called to unsubscribe.
|
|
1011
|
+
*
|
|
1012
|
+
* @public
|
|
1013
|
+
*/
|
|
1014
|
+
function onIdChange(installations, callback) {
|
|
1015
|
+
const { appConfig } = installations;
|
|
1016
|
+
addCallback(appConfig, callback);
|
|
1017
|
+
return () => {
|
|
1018
|
+
removeCallback(appConfig, callback);
|
|
1019
|
+
};
|
|
1020
1020
|
}
|
|
1021
1021
|
|
|
1022
|
-
/**
|
|
1023
|
-
* @license
|
|
1024
|
-
* Copyright 2020 Google LLC
|
|
1025
|
-
*
|
|
1026
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1027
|
-
* you may not use this file except in compliance with the License.
|
|
1028
|
-
* You may obtain a copy of the License at
|
|
1029
|
-
*
|
|
1030
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1031
|
-
*
|
|
1032
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
1033
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1034
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1035
|
-
* See the License for the specific language governing permissions and
|
|
1036
|
-
* limitations under the License.
|
|
1037
|
-
*/
|
|
1038
|
-
/**
|
|
1039
|
-
* Returns an instance of {@link Installations} associated with the given
|
|
1040
|
-
* {@link @firebase/app#FirebaseApp} instance.
|
|
1041
|
-
* @param app - The {@link @firebase/app#FirebaseApp} instance.
|
|
1042
|
-
*
|
|
1043
|
-
* @public
|
|
1044
|
-
*/
|
|
1045
|
-
function getInstallations(app = getApp()) {
|
|
1046
|
-
const installationsImpl = _getProvider(app, 'installations').getImmediate();
|
|
1047
|
-
return installationsImpl;
|
|
1022
|
+
/**
|
|
1023
|
+
* @license
|
|
1024
|
+
* Copyright 2020 Google LLC
|
|
1025
|
+
*
|
|
1026
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1027
|
+
* you may not use this file except in compliance with the License.
|
|
1028
|
+
* You may obtain a copy of the License at
|
|
1029
|
+
*
|
|
1030
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1031
|
+
*
|
|
1032
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
1033
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1034
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1035
|
+
* See the License for the specific language governing permissions and
|
|
1036
|
+
* limitations under the License.
|
|
1037
|
+
*/
|
|
1038
|
+
/**
|
|
1039
|
+
* Returns an instance of {@link Installations} associated with the given
|
|
1040
|
+
* {@link @firebase/app#FirebaseApp} instance.
|
|
1041
|
+
* @param app - The {@link @firebase/app#FirebaseApp} instance.
|
|
1042
|
+
*
|
|
1043
|
+
* @public
|
|
1044
|
+
*/
|
|
1045
|
+
function getInstallations(app = getApp()) {
|
|
1046
|
+
const installationsImpl = _getProvider(app, 'installations').getImmediate();
|
|
1047
|
+
return installationsImpl;
|
|
1048
1048
|
}
|
|
1049
1049
|
|
|
1050
|
-
/**
|
|
1051
|
-
* @license
|
|
1052
|
-
* Copyright 2019 Google LLC
|
|
1053
|
-
*
|
|
1054
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1055
|
-
* you may not use this file except in compliance with the License.
|
|
1056
|
-
* You may obtain a copy of the License at
|
|
1057
|
-
*
|
|
1058
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1059
|
-
*
|
|
1060
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
1061
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1062
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1063
|
-
* See the License for the specific language governing permissions and
|
|
1064
|
-
* limitations under the License.
|
|
1065
|
-
*/
|
|
1066
|
-
function extractAppConfig(app) {
|
|
1067
|
-
if (!app || !app.options) {
|
|
1068
|
-
throw getMissingValueError('App Configuration');
|
|
1069
|
-
}
|
|
1070
|
-
if (!app.name) {
|
|
1071
|
-
throw getMissingValueError('App Name');
|
|
1072
|
-
}
|
|
1073
|
-
// Required app config keys
|
|
1074
|
-
const configKeys = [
|
|
1075
|
-
'projectId',
|
|
1076
|
-
'apiKey',
|
|
1077
|
-
'appId'
|
|
1078
|
-
];
|
|
1079
|
-
for (const keyName of configKeys) {
|
|
1080
|
-
if (!app.options[keyName]) {
|
|
1081
|
-
throw getMissingValueError(keyName);
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
return {
|
|
1085
|
-
appName: app.name,
|
|
1086
|
-
projectId: app.options.projectId,
|
|
1087
|
-
apiKey: app.options.apiKey,
|
|
1088
|
-
appId: app.options.appId
|
|
1089
|
-
};
|
|
1090
|
-
}
|
|
1091
|
-
function getMissingValueError(valueName) {
|
|
1092
|
-
return ERROR_FACTORY.create("missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */, {
|
|
1093
|
-
valueName
|
|
1094
|
-
});
|
|
1050
|
+
/**
|
|
1051
|
+
* @license
|
|
1052
|
+
* Copyright 2019 Google LLC
|
|
1053
|
+
*
|
|
1054
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1055
|
+
* you may not use this file except in compliance with the License.
|
|
1056
|
+
* You may obtain a copy of the License at
|
|
1057
|
+
*
|
|
1058
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1059
|
+
*
|
|
1060
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
1061
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1062
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1063
|
+
* See the License for the specific language governing permissions and
|
|
1064
|
+
* limitations under the License.
|
|
1065
|
+
*/
|
|
1066
|
+
function extractAppConfig(app) {
|
|
1067
|
+
if (!app || !app.options) {
|
|
1068
|
+
throw getMissingValueError('App Configuration');
|
|
1069
|
+
}
|
|
1070
|
+
if (!app.name) {
|
|
1071
|
+
throw getMissingValueError('App Name');
|
|
1072
|
+
}
|
|
1073
|
+
// Required app config keys
|
|
1074
|
+
const configKeys = [
|
|
1075
|
+
'projectId',
|
|
1076
|
+
'apiKey',
|
|
1077
|
+
'appId'
|
|
1078
|
+
];
|
|
1079
|
+
for (const keyName of configKeys) {
|
|
1080
|
+
if (!app.options[keyName]) {
|
|
1081
|
+
throw getMissingValueError(keyName);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
return {
|
|
1085
|
+
appName: app.name,
|
|
1086
|
+
projectId: app.options.projectId,
|
|
1087
|
+
apiKey: app.options.apiKey,
|
|
1088
|
+
appId: app.options.appId
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
function getMissingValueError(valueName) {
|
|
1092
|
+
return ERROR_FACTORY.create("missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */, {
|
|
1093
|
+
valueName
|
|
1094
|
+
});
|
|
1095
1095
|
}
|
|
1096
1096
|
|
|
1097
|
-
/**
|
|
1098
|
-
* @license
|
|
1099
|
-
* Copyright 2020 Google LLC
|
|
1100
|
-
*
|
|
1101
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1102
|
-
* you may not use this file except in compliance with the License.
|
|
1103
|
-
* You may obtain a copy of the License at
|
|
1104
|
-
*
|
|
1105
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1106
|
-
*
|
|
1107
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
1108
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1109
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1110
|
-
* See the License for the specific language governing permissions and
|
|
1111
|
-
* limitations under the License.
|
|
1112
|
-
*/
|
|
1113
|
-
const INSTALLATIONS_NAME = 'installations';
|
|
1114
|
-
const INSTALLATIONS_NAME_INTERNAL = 'installations-internal';
|
|
1115
|
-
const publicFactory = (container) => {
|
|
1116
|
-
const app = container.getProvider('app').getImmediate();
|
|
1117
|
-
// Throws if app isn't configured properly.
|
|
1118
|
-
const appConfig = extractAppConfig(app);
|
|
1119
|
-
const heartbeatServiceProvider = _getProvider(app, 'heartbeat');
|
|
1120
|
-
const installationsImpl = {
|
|
1121
|
-
app,
|
|
1122
|
-
appConfig,
|
|
1123
|
-
heartbeatServiceProvider,
|
|
1124
|
-
_delete: () => Promise.resolve()
|
|
1125
|
-
};
|
|
1126
|
-
return installationsImpl;
|
|
1127
|
-
};
|
|
1128
|
-
const internalFactory = (container) => {
|
|
1129
|
-
const app = container.getProvider('app').getImmediate();
|
|
1130
|
-
// Internal FIS instance relies on public FIS instance.
|
|
1131
|
-
const installations = _getProvider(app, INSTALLATIONS_NAME).getImmediate();
|
|
1132
|
-
const installationsInternal = {
|
|
1133
|
-
getId: () => getId(installations),
|
|
1134
|
-
getToken: (forceRefresh) => getToken(installations, forceRefresh)
|
|
1135
|
-
};
|
|
1136
|
-
return installationsInternal;
|
|
1137
|
-
};
|
|
1138
|
-
function registerInstallations() {
|
|
1139
|
-
_registerComponent(new Component(INSTALLATIONS_NAME, publicFactory, "PUBLIC" /* ComponentType.PUBLIC */));
|
|
1140
|
-
_registerComponent(new Component(INSTALLATIONS_NAME_INTERNAL, internalFactory, "PRIVATE" /* ComponentType.PRIVATE */));
|
|
1097
|
+
/**
|
|
1098
|
+
* @license
|
|
1099
|
+
* Copyright 2020 Google LLC
|
|
1100
|
+
*
|
|
1101
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1102
|
+
* you may not use this file except in compliance with the License.
|
|
1103
|
+
* You may obtain a copy of the License at
|
|
1104
|
+
*
|
|
1105
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1106
|
+
*
|
|
1107
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
1108
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1109
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1110
|
+
* See the License for the specific language governing permissions and
|
|
1111
|
+
* limitations under the License.
|
|
1112
|
+
*/
|
|
1113
|
+
const INSTALLATIONS_NAME = 'installations';
|
|
1114
|
+
const INSTALLATIONS_NAME_INTERNAL = 'installations-internal';
|
|
1115
|
+
const publicFactory = (container) => {
|
|
1116
|
+
const app = container.getProvider('app').getImmediate();
|
|
1117
|
+
// Throws if app isn't configured properly.
|
|
1118
|
+
const appConfig = extractAppConfig(app);
|
|
1119
|
+
const heartbeatServiceProvider = _getProvider(app, 'heartbeat');
|
|
1120
|
+
const installationsImpl = {
|
|
1121
|
+
app,
|
|
1122
|
+
appConfig,
|
|
1123
|
+
heartbeatServiceProvider,
|
|
1124
|
+
_delete: () => Promise.resolve()
|
|
1125
|
+
};
|
|
1126
|
+
return installationsImpl;
|
|
1127
|
+
};
|
|
1128
|
+
const internalFactory = (container) => {
|
|
1129
|
+
const app = container.getProvider('app').getImmediate();
|
|
1130
|
+
// Internal FIS instance relies on public FIS instance.
|
|
1131
|
+
const installations = _getProvider(app, INSTALLATIONS_NAME).getImmediate();
|
|
1132
|
+
const installationsInternal = {
|
|
1133
|
+
getId: () => getId(installations),
|
|
1134
|
+
getToken: (forceRefresh) => getToken(installations, forceRefresh)
|
|
1135
|
+
};
|
|
1136
|
+
return installationsInternal;
|
|
1137
|
+
};
|
|
1138
|
+
function registerInstallations() {
|
|
1139
|
+
_registerComponent(new Component(INSTALLATIONS_NAME, publicFactory, "PUBLIC" /* ComponentType.PUBLIC */));
|
|
1140
|
+
_registerComponent(new Component(INSTALLATIONS_NAME_INTERNAL, internalFactory, "PRIVATE" /* ComponentType.PRIVATE */));
|
|
1141
1141
|
}
|
|
1142
1142
|
|
|
1143
|
-
/**
|
|
1144
|
-
* The Firebase Installations Web SDK.
|
|
1145
|
-
* This SDK does not work in a Node.js environment.
|
|
1146
|
-
*
|
|
1147
|
-
* @packageDocumentation
|
|
1148
|
-
*/
|
|
1149
|
-
registerInstallations();
|
|
1150
|
-
registerVersion(name, version);
|
|
1151
|
-
// BUILD_TARGET will be replaced by values like esm2017, cjs2017, etc during the compilation
|
|
1143
|
+
/**
|
|
1144
|
+
* The Firebase Installations Web SDK.
|
|
1145
|
+
* This SDK does not work in a Node.js environment.
|
|
1146
|
+
*
|
|
1147
|
+
* @packageDocumentation
|
|
1148
|
+
*/
|
|
1149
|
+
registerInstallations();
|
|
1150
|
+
registerVersion(name, version);
|
|
1151
|
+
// BUILD_TARGET will be replaced by values like esm2017, cjs2017, etc during the compilation
|
|
1152
1152
|
registerVersion(name, version, 'esm2017');
|
|
1153
1153
|
|
|
1154
1154
|
export { deleteInstallations, getId, getInstallations, getToken, onIdChange };
|