1
0
mirror of https://github.com/musix-org/musix-oss synced 2025-01-12 18:14:51 +00:00
musix-oss/node_modules/@firebase/installations/dist/index.esm.js
2019-10-10 16:43:04 +03:00

1124 lines
45 KiB
JavaScript

import firebase from '@firebase/app';
import { __awaiter, __generator, __spread, __assign } from 'tslib';
import { ErrorFactory, FirebaseError } from '@firebase/util';
import { openDb } from 'idb';
var version = "0.2.6";
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var PENDING_TIMEOUT_MS = 10000;
var PACKAGE_VERSION = "w:" + version;
var INTERNAL_AUTH_VERSION = 'FIS_v2';
var INSTALLATIONS_API_URL = 'https://firebaseinstallations.googleapis.com/v1';
var TOKEN_EXPIRATION_BUFFER = 60 * 60 * 1000; // One hour
var SERVICE = 'installations';
var SERVICE_NAME = 'Installations';
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var _a;
var ERROR_DESCRIPTION_MAP = (_a = {},
_a["missing-app-config-values" /* MISSING_APP_CONFIG_VALUES */] = 'Missing App configuration values.',
_a["create-installation-failed" /* CREATE_INSTALLATION_FAILED */] = 'Could not register Firebase Installation.',
_a["generate-token-failed" /* GENERATE_TOKEN_FAILED */] = 'Could not generate Auth Token.',
_a["not-registered" /* NOT_REGISTERED */] = 'Firebase Installation is not registered.',
_a["installation-not-found" /* INSTALLATION_NOT_FOUND */] = 'Firebase Installation not found.',
_a["request-failed" /* REQUEST_FAILED */] = '{$requestName} request failed with error "{$serverCode} {$serverStatus}: {$serverMessage}"',
_a["app-offline" /* APP_OFFLINE */] = 'Could not process request. Application offline.',
_a["delete-pending-registration" /* DELETE_PENDING_REGISTRATION */] = "Can't delete installation while there is a pending registration request.",
_a);
var ERROR_FACTORY = new ErrorFactory(SERVICE, SERVICE_NAME, ERROR_DESCRIPTION_MAP);
/** Returns true if error is a FirebaseError that is based on an error from the server. */
function isServerError(error) {
return (error instanceof FirebaseError &&
error.code.includes("request-failed" /* REQUEST_FAILED */));
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function extractAppConfig(app) {
if (!app || !app.options) {
throw ERROR_FACTORY.create("missing-app-config-values" /* MISSING_APP_CONFIG_VALUES */);
}
var appName = app.name;
var _a = app.options, projectId = _a.projectId, apiKey = _a.apiKey, appId = _a.appId;
if (!appName || !projectId || !apiKey || !appId) {
throw ERROR_FACTORY.create("missing-app-config-values" /* MISSING_APP_CONFIG_VALUES */);
}
return { appName: appName, projectId: projectId, apiKey: apiKey, appId: appId };
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function getInstallationsEndpoint(_a) {
var projectId = _a.projectId;
return INSTALLATIONS_API_URL + "/projects/" + projectId + "/installations";
}
function extractAuthTokenInfoFromResponse(response) {
return {
token: response.token,
requestStatus: 2 /* COMPLETED */,
expiresIn: getExpiresInFromResponseExpiresIn(response.expiresIn),
creationTime: Date.now()
};
}
function getErrorFromResponse(requestName, response) {
return __awaiter(this, void 0, void 0, function () {
var responseJson, errorData;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, response.json()];
case 1:
responseJson = _a.sent();
errorData = responseJson.error;
return [2 /*return*/, ERROR_FACTORY.create("request-failed" /* REQUEST_FAILED */, {
requestName: requestName,
serverCode: errorData.code,
serverMessage: errorData.message,
serverStatus: errorData.status
})];
}
});
});
}
function getHeaders(_a) {
var apiKey = _a.apiKey;
return new Headers({
'Content-Type': 'application/json',
Accept: 'application/json',
'x-goog-api-key': apiKey
});
}
function getHeadersWithAuth(appConfig, _a) {
var refreshToken = _a.refreshToken;
var headers = getHeaders(appConfig);
headers.append('Authorization', getAuthorizationHeader(refreshToken));
return headers;
}
/**
* Calls the passed in fetch wrapper and returns the response.
* If the returned response has a status of 5xx, re-runs the function once and
* returns the response.
*/
function retryIfServerError(fn) {
return __awaiter(this, void 0, void 0, function () {
var result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, fn()];
case 1:
result = _a.sent();
if (result.status >= 500 && result.status < 600) {
// Internal Server Error. Retry request.
return [2 /*return*/, fn()];
}
return [2 /*return*/, result];
}
});
});
}
function getExpiresInFromResponseExpiresIn(responseExpiresIn) {
// This works because the server will never respond with fractions of a second.
return Number(responseExpiresIn.replace('s', '000'));
}
function getAuthorizationHeader(refreshToken) {
return INTERNAL_AUTH_VERSION + " " + refreshToken;
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function createInstallation(appConfig, _a) {
var fid = _a.fid;
return __awaiter(this, void 0, void 0, function () {
var endpoint, headers, body, request, response, responseValue, registeredInstallationEntry;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
endpoint = getInstallationsEndpoint(appConfig);
headers = getHeaders(appConfig);
body = {
fid: fid,
authVersion: INTERNAL_AUTH_VERSION,
appId: appConfig.appId,
sdkVersion: PACKAGE_VERSION
};
request = {
method: 'POST',
headers: headers,
body: JSON.stringify(body)
};
return [4 /*yield*/, retryIfServerError(function () { return fetch(endpoint, request); })];
case 1:
response = _b.sent();
if (!response.ok) return [3 /*break*/, 3];
return [4 /*yield*/, response.json()];
case 2:
responseValue = _b.sent();
registeredInstallationEntry = {
fid: responseValue.fid || fid,
registrationStatus: 2 /* COMPLETED */,
refreshToken: responseValue.refreshToken,
authToken: extractAuthTokenInfoFromResponse(responseValue.authToken)
};
return [2 /*return*/, registeredInstallationEntry];
case 3: return [4 /*yield*/, getErrorFromResponse('Create Installation', response)];
case 4: throw _b.sent();
}
});
});
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** Returns a promise that resolves after given time passes. */
function sleep(ms) {
return new Promise(function (resolve) {
setTimeout(resolve, ms);
});
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function bufferToBase64UrlSafe(array) {
var b64 = btoa(String.fromCharCode.apply(String, __spread(array)));
return b64.replace(/\+/g, '-').replace(/\//g, '_');
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var VALID_FID_PATTERN = /^[cdef][\w-]{21}$/;
var INVALID_FID = '';
/**
* Generates a new FID using random values from Web Crypto API.
* Returns an empty string if FID generation fails for any reason.
*/
function generateFid() {
try {
// A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5
// bytes. our implementation generates a 17 byte array instead.
var fidByteArray = new Uint8Array(17);
var crypto_1 = self.crypto || self.msCrypto;
crypto_1.getRandomValues(fidByteArray);
// Replace the first 4 random bits with the constant FID header of 0b0111.
fidByteArray[0] = 112 + (fidByteArray[0] % 16);
var fid = encode(fidByteArray);
return VALID_FID_PATTERN.test(fid) ? fid : INVALID_FID;
}
catch (_a) {
// FID generation errored
return INVALID_FID;
}
}
/** Converts a FID Uint8Array to a base64 string representation. */
function encode(fidByteArray) {
var b64String = bufferToBase64UrlSafe(fidByteArray);
// Remove the 23rd character that was added because of the extra 4 bits at the
// end of our 17 byte array, and the '=' padding.
return b64String.substr(0, 22);
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var DATABASE_NAME = 'firebase-installations-database';
var DATABASE_VERSION = 1;
var OBJECT_STORE_NAME = 'firebase-installations-store';
var dbPromise = null;
function getDbPromise() {
if (!dbPromise) {
dbPromise = openDb(DATABASE_NAME, DATABASE_VERSION, function (upgradeDB) {
// We don't use 'break' in this switch statement, the fall-through
// behavior is what we want, because if there are multiple versions between
// the old version and the current version, we want ALL the migrations
// that correspond to those versions to run, not only the last one.
// eslint-disable-next-line default-case
switch (upgradeDB.oldVersion) {
case 0:
upgradeDB.createObjectStore(OBJECT_STORE_NAME);
}
});
}
return dbPromise;
}
/** Assigns or overwrites the record for the given key with the given value. */
function set(appConfig, value) {
return __awaiter(this, void 0, void 0, function () {
var key, db, tx;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
key = getKey(appConfig);
return [4 /*yield*/, getDbPromise()];
case 1:
db = _a.sent();
tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
return [4 /*yield*/, tx.objectStore(OBJECT_STORE_NAME).put(value, key)];
case 2:
_a.sent();
return [4 /*yield*/, tx.complete];
case 3:
_a.sent();
return [2 /*return*/, value];
}
});
});
}
/** Removes record(s) from the objectStore that match the given key. */
function remove(appConfig) {
return __awaiter(this, void 0, void 0, function () {
var key, db, tx;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
key = getKey(appConfig);
return [4 /*yield*/, getDbPromise()];
case 1:
db = _a.sent();
tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
return [4 /*yield*/, tx.objectStore(OBJECT_STORE_NAME).delete(key)];
case 2:
_a.sent();
return [4 /*yield*/, tx.complete];
case 3:
_a.sent();
return [2 /*return*/];
}
});
});
}
/**
* Atomically updates a record with the result of updateFn, which gets
* called with the current value. If newValue is undefined, the record is
* deleted instead.
* @return Updated value
*/
function update(appConfig, updateFn) {
return __awaiter(this, void 0, void 0, function () {
var key, db, tx, store, oldValue, newValue;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
key = getKey(appConfig);
return [4 /*yield*/, getDbPromise()];
case 1:
db = _a.sent();
tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
store = tx.objectStore(OBJECT_STORE_NAME);
return [4 /*yield*/, store.get(key)];
case 2:
oldValue = _a.sent();
newValue = updateFn(oldValue);
if (newValue === oldValue) {
return [2 /*return*/, newValue];
}
if (!(newValue === undefined)) return [3 /*break*/, 4];
return [4 /*yield*/, store.delete(key)];
case 3:
_a.sent();
return [3 /*break*/, 6];
case 4: return [4 /*yield*/, store.put(newValue, key)];
case 5:
_a.sent();
_a.label = 6;
case 6: return [4 /*yield*/, tx.complete];
case 7:
_a.sent();
return [2 /*return*/, newValue];
}
});
});
}
function getKey(appConfig) {
return appConfig.appName + "!" + appConfig.appId;
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Updates and returns the InstallationEntry from the database.
* Also triggers a registration request if it is necessary and possible.
*/
function getInstallationEntry(appConfig) {
return __awaiter(this, void 0, void 0, function () {
var registrationPromise, installationEntry, _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, update(appConfig, function (oldEntry) {
var installationEntry = updateOrCreateInstallationEntry(oldEntry);
var entryWithPromise = triggerRegistrationIfNecessary(appConfig, installationEntry);
registrationPromise = entryWithPromise.registrationPromise;
return entryWithPromise.installationEntry;
})];
case 1:
installationEntry = _b.sent();
if (!(installationEntry.fid === INVALID_FID)) return [3 /*break*/, 3];
_a = {};
return [4 /*yield*/, registrationPromise];
case 2:
// FID generation failed. Waiting for the FID from the server.
return [2 /*return*/, (_a.installationEntry = _b.sent(), _a)];
case 3: return [2 /*return*/, {
installationEntry: installationEntry,
registrationPromise: registrationPromise
}];
}
});
});
}
function updateOrCreateInstallationEntry(oldEntry) {
var entry = oldEntry || {
fid: generateFid(),
registrationStatus: 0 /* NOT_STARTED */
};
if (hasInstallationRequestTimedOut(entry)) {
return {
fid: entry.fid,
registrationStatus: 0 /* NOT_STARTED */
};
}
return entry;
}
/**
* If the Firebase Installation is not registered yet, this will trigger the registration
* and return an InProgressInstallationEntry.
*/
function triggerRegistrationIfNecessary(appConfig, installationEntry) {
if (installationEntry.registrationStatus === 0 /* NOT_STARTED */) {
if (!navigator.onLine) {
// Registration required but app is offline.
var registrationPromiseWithError = Promise.reject(ERROR_FACTORY.create("app-offline" /* APP_OFFLINE */));
return {
installationEntry: installationEntry,
registrationPromise: registrationPromiseWithError
};
}
// Try registering. Change status to IN_PROGRESS.
var inProgressEntry = {
fid: installationEntry.fid,
registrationStatus: 1 /* IN_PROGRESS */,
registrationTime: Date.now()
};
var registrationPromise = registerInstallation(appConfig, inProgressEntry);
return { installationEntry: inProgressEntry, registrationPromise: registrationPromise };
}
else if (installationEntry.registrationStatus === 1 /* IN_PROGRESS */) {
return {
installationEntry: installationEntry,
registrationPromise: waitUntilFidRegistration(appConfig)
};
}
else {
return { installationEntry: installationEntry };
}
}
/** This will be executed only once for each new Firebase Installation. */
function registerInstallation(appConfig, installationEntry) {
return __awaiter(this, void 0, void 0, function () {
var registeredInstallationEntry, e_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 7]);
return [4 /*yield*/, createInstallation(appConfig, installationEntry)];
case 1:
registeredInstallationEntry = _a.sent();
return [2 /*return*/, set(appConfig, registeredInstallationEntry)];
case 2:
e_1 = _a.sent();
if (!(isServerError(e_1) && e_1.serverCode === 409)) return [3 /*break*/, 4];
// Server returned a "FID can not be used" error.
// Generate a new ID next time.
return [4 /*yield*/, remove(appConfig)];
case 3:
// Server returned a "FID can not be used" error.
// Generate a new ID next time.
_a.sent();
return [3 /*break*/, 6];
case 4:
// Registration failed. Set FID as not registered.
return [4 /*yield*/, set(appConfig, {
fid: installationEntry.fid,
registrationStatus: 0 /* NOT_STARTED */
})];
case 5:
// Registration failed. Set FID as not registered.
_a.sent();
_a.label = 6;
case 6: throw e_1;
case 7: return [2 /*return*/];
}
});
});
}
/** Call if FID registration is pending. */
function waitUntilFidRegistration(appConfig) {
return __awaiter(this, void 0, void 0, function () {
var entry;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, updateInstallationRequest(appConfig)];
case 1:
entry = _a.sent();
_a.label = 2;
case 2:
if (!(entry.registrationStatus === 1 /* IN_PROGRESS */)) return [3 /*break*/, 5];
// createInstallation request still in progress.
return [4 /*yield*/, sleep(100)];
case 3:
// createInstallation request still in progress.
_a.sent();
return [4 /*yield*/, updateInstallationRequest(appConfig)];
case 4:
entry = _a.sent();
return [3 /*break*/, 2];
case 5:
if (entry.registrationStatus === 0 /* NOT_STARTED */) {
throw ERROR_FACTORY.create("create-installation-failed" /* CREATE_INSTALLATION_FAILED */);
}
return [2 /*return*/, entry];
}
});
});
}
/**
* Called only if there is a CreateInstallation request in progress.
*
* Updates the InstallationEntry in the DB based on the status of the
* CreateInstallation request.
*
* Returns the updated InstallationEntry.
*/
function updateInstallationRequest(appConfig) {
return update(appConfig, function (oldEntry) {
if (!oldEntry) {
throw ERROR_FACTORY.create("installation-not-found" /* INSTALLATION_NOT_FOUND */);
}
if (hasInstallationRequestTimedOut(oldEntry)) {
return {
fid: oldEntry.fid,
registrationStatus: 0 /* NOT_STARTED */
};
}
return oldEntry;
});
}
function hasInstallationRequestTimedOut(installationEntry) {
return (installationEntry.registrationStatus === 1 /* IN_PROGRESS */ &&
installationEntry.registrationTime + PENDING_TIMEOUT_MS < Date.now());
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function generateAuthToken(appConfig, installationEntry) {
return __awaiter(this, void 0, void 0, function () {
var endpoint, headers, body, request, response, responseValue, completedAuthToken;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
endpoint = getGenerateAuthTokenEndpoint(appConfig, installationEntry);
headers = getHeadersWithAuth(appConfig, installationEntry);
body = {
installation: {
sdkVersion: PACKAGE_VERSION
}
};
request = {
method: 'POST',
headers: headers,
body: JSON.stringify(body)
};
return [4 /*yield*/, retryIfServerError(function () { return fetch(endpoint, request); })];
case 1:
response = _a.sent();
if (!response.ok) return [3 /*break*/, 3];
return [4 /*yield*/, response.json()];
case 2:
responseValue = _a.sent();
completedAuthToken = extractAuthTokenInfoFromResponse(responseValue);
return [2 /*return*/, completedAuthToken];
case 3: return [4 /*yield*/, getErrorFromResponse('Generate Auth Token', response)];
case 4: throw _a.sent();
}
});
});
}
function getGenerateAuthTokenEndpoint(appConfig, _a) {
var fid = _a.fid;
return getInstallationsEndpoint(appConfig) + "/" + fid + "/authTokens:generate";
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Returns a valid authentication token for the installation. Generates a new
* token if one doesn't exist, is expired or about to expire.
*
* Should only be called if the Firebase Installation is registered.
*/
function refreshAuthToken(appConfig) {
return __awaiter(this, void 0, void 0, function () {
var tokenPromise, entry, authToken, _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, update(appConfig, function (oldEntry) {
if (!isEntryRegistered(oldEntry)) {
throw ERROR_FACTORY.create("not-registered" /* NOT_REGISTERED */);
}
var oldAuthToken = oldEntry.authToken;
if (isAuthTokenValid(oldAuthToken)) {
// There is a valid token in the DB.
return oldEntry;
}
else if (oldAuthToken.requestStatus === 1 /* IN_PROGRESS */) {
// There already is a token request in progress.
tokenPromise = waitUntilAuthTokenRequest(appConfig);
return oldEntry;
}
else {
// No token or token expired.
if (!navigator.onLine) {
throw ERROR_FACTORY.create("app-offline" /* APP_OFFLINE */);
}
var inProgressEntry = makeAuthTokenRequestInProgressEntry(oldEntry);
tokenPromise = fetchAuthTokenFromServer(appConfig, inProgressEntry);
return inProgressEntry;
}
})];
case 1:
entry = _b.sent();
if (!tokenPromise) return [3 /*break*/, 3];
return [4 /*yield*/, tokenPromise];
case 2:
_a = _b.sent();
return [3 /*break*/, 4];
case 3:
_a = entry.authToken;
_b.label = 4;
case 4:
authToken = _a;
return [2 /*return*/, authToken.token];
}
});
});
}
/**
* Call only if FID is registered and Auth Token request is in progress.
*/
function waitUntilAuthTokenRequest(appConfig) {
return __awaiter(this, void 0, void 0, function () {
var entry, authToken;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, updateAuthTokenRequest(appConfig)];
case 1:
entry = _a.sent();
_a.label = 2;
case 2:
if (!(entry.authToken.requestStatus === 1 /* IN_PROGRESS */)) return [3 /*break*/, 5];
// generateAuthToken still in progress.
return [4 /*yield*/, sleep(100)];
case 3:
// generateAuthToken still in progress.
_a.sent();
return [4 /*yield*/, updateAuthTokenRequest(appConfig)];
case 4:
entry = _a.sent();
return [3 /*break*/, 2];
case 5:
authToken = entry.authToken;
if (authToken.requestStatus === 0 /* NOT_STARTED */) {
throw ERROR_FACTORY.create("generate-token-failed" /* GENERATE_TOKEN_FAILED */);
}
else {
return [2 /*return*/, authToken];
}
return [2 /*return*/];
}
});
});
}
/**
* Called only if there is a GenerateAuthToken request in progress.
*
* Updates the InstallationEntry in the DB based on the status of the
* GenerateAuthToken request.
*
* Returns the updated InstallationEntry.
*/
function updateAuthTokenRequest(appConfig) {
return update(appConfig, function (oldEntry) {
if (!isEntryRegistered(oldEntry)) {
throw ERROR_FACTORY.create("not-registered" /* NOT_REGISTERED */);
}
var oldAuthToken = oldEntry.authToken;
if (hasAuthTokenRequestTimedOut(oldAuthToken)) {
return __assign({}, oldEntry, { authToken: { requestStatus: 0 /* NOT_STARTED */ } });
}
return oldEntry;
});
}
function fetchAuthTokenFromServer(appConfig, installationEntry) {
return __awaiter(this, void 0, void 0, function () {
var authToken, updatedInstallationEntry, e_1, updatedInstallationEntry;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 3, , 8]);
return [4 /*yield*/, generateAuthToken(appConfig, installationEntry)];
case 1:
authToken = _a.sent();
updatedInstallationEntry = __assign({}, installationEntry, { authToken: authToken });
return [4 /*yield*/, set(appConfig, updatedInstallationEntry)];
case 2:
_a.sent();
return [2 /*return*/, authToken];
case 3:
e_1 = _a.sent();
if (!(isServerError(e_1) && (e_1.serverCode === 401 || e_1.serverCode === 404))) return [3 /*break*/, 5];
// Server returned a "FID not found" or a "Invalid authentication" error.
// Generate a new ID next time.
return [4 /*yield*/, remove(appConfig)];
case 4:
// Server returned a "FID not found" or a "Invalid authentication" error.
// Generate a new ID next time.
_a.sent();
return [3 /*break*/, 7];
case 5:
updatedInstallationEntry = __assign({}, installationEntry, { authToken: { requestStatus: 0 /* NOT_STARTED */ } });
return [4 /*yield*/, set(appConfig, updatedInstallationEntry)];
case 6:
_a.sent();
_a.label = 7;
case 7: throw e_1;
case 8: return [2 /*return*/];
}
});
});
}
function isEntryRegistered(installationEntry) {
return (installationEntry !== undefined &&
installationEntry.registrationStatus === 2 /* COMPLETED */);
}
function isAuthTokenValid(authToken) {
return (authToken.requestStatus === 2 /* COMPLETED */ &&
!isAuthTokenExpired(authToken));
}
function isAuthTokenExpired(authToken) {
var now = Date.now();
return (now < authToken.creationTime ||
authToken.creationTime + authToken.expiresIn < now + TOKEN_EXPIRATION_BUFFER);
}
/** Returns an updated InstallationEntry with an InProgressAuthToken. */
function makeAuthTokenRequestInProgressEntry(oldEntry) {
var inProgressAuthToken = {
requestStatus: 1 /* IN_PROGRESS */,
requestTime: Date.now()
};
return __assign({}, oldEntry, { authToken: inProgressAuthToken });
}
function hasAuthTokenRequestTimedOut(authToken) {
return (authToken.requestStatus === 1 /* IN_PROGRESS */ &&
authToken.requestTime + PENDING_TIMEOUT_MS < Date.now());
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function getId(app) {
return __awaiter(this, void 0, void 0, function () {
var appConfig, _a, installationEntry, registrationPromise;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
appConfig = extractAppConfig(app);
return [4 /*yield*/, getInstallationEntry(appConfig)];
case 1:
_a = _b.sent(), installationEntry = _a.installationEntry, registrationPromise = _a.registrationPromise;
if (registrationPromise) {
// Suppress registration errors as they are not a problem for getId.
registrationPromise.catch(function () { });
}
if (installationEntry.registrationStatus === 2 /* COMPLETED */) {
// If the installation is already registered, update the authentication
// token if needed. Suppress errors as they are not relevant to getId.
refreshAuthToken(appConfig).catch(function () { });
}
return [2 /*return*/, installationEntry.fid];
}
});
});
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function getToken(app) {
return __awaiter(this, void 0, void 0, function () {
var appConfig;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
appConfig = extractAppConfig(app);
return [4 /*yield*/, completeInstallationRegistration(appConfig)];
case 1:
_a.sent();
// At this point we either have a Registered Installation in the DB, or we've
// already thrown an error.
return [2 /*return*/, refreshAuthToken(appConfig)];
}
});
});
}
function completeInstallationRegistration(appConfig) {
return __awaiter(this, void 0, void 0, function () {
var _a, installationEntry, registrationPromise;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, getInstallationEntry(appConfig)];
case 1:
_a = _b.sent(), installationEntry = _a.installationEntry, registrationPromise = _a.registrationPromise;
if (!registrationPromise) return [3 /*break*/, 3];
// A createInstallation request is in progress. Wait until it finishes.
return [4 /*yield*/, registrationPromise];
case 2:
// A createInstallation request is in progress. Wait until it finishes.
_b.sent();
return [3 /*break*/, 4];
case 3:
if (installationEntry.registrationStatus !== 2 /* COMPLETED */) {
// Installation ID can't be registered.
throw ERROR_FACTORY.create("create-installation-failed" /* CREATE_INSTALLATION_FAILED */);
}
_b.label = 4;
case 4: return [2 /*return*/];
}
});
});
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function deleteInstallation(appConfig, installationEntry) {
return __awaiter(this, void 0, void 0, function () {
var endpoint, headers, request, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
endpoint = getDeleteEndpoint(appConfig, installationEntry);
headers = getHeadersWithAuth(appConfig, installationEntry);
request = {
method: 'DELETE',
headers: headers
};
return [4 /*yield*/, retryIfServerError(function () { return fetch(endpoint, request); })];
case 1:
response = _a.sent();
if (!!response.ok) return [3 /*break*/, 3];
return [4 /*yield*/, getErrorFromResponse('Delete Installation', response)];
case 2: throw _a.sent();
case 3: return [2 /*return*/];
}
});
});
}
function getDeleteEndpoint(appConfig, _a) {
var fid = _a.fid;
return getInstallationsEndpoint(appConfig) + "/" + fid;
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function deleteInstallation$1(app) {
return __awaiter(this, void 0, void 0, function () {
var appConfig, entry;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
appConfig = extractAppConfig(app);
return [4 /*yield*/, update(appConfig, function (oldEntry) {
if (oldEntry && oldEntry.registrationStatus === 0 /* NOT_STARTED */) {
// Delete the unregistered entry without sending a deleteInstallation request.
return undefined;
}
return oldEntry;
})];
case 1:
entry = _a.sent();
if (!entry) return [3 /*break*/, 6];
if (!(entry.registrationStatus === 1 /* IN_PROGRESS */)) return [3 /*break*/, 2];
// Can't delete while trying to register.
throw ERROR_FACTORY.create("delete-pending-registration" /* DELETE_PENDING_REGISTRATION */);
case 2:
if (!(entry.registrationStatus === 2 /* COMPLETED */)) return [3 /*break*/, 6];
if (!!navigator.onLine) return [3 /*break*/, 3];
throw ERROR_FACTORY.create("app-offline" /* APP_OFFLINE */);
case 3: return [4 /*yield*/, deleteInstallation(appConfig, entry)];
case 4:
_a.sent();
return [4 /*yield*/, remove(appConfig)];
case 5:
_a.sent();
_a.label = 6;
case 6: return [2 /*return*/];
}
});
});
}
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function registerInstallations(instance) {
var installationsName = 'installations';
var factoryMethod = function (app) {
// Throws if app isn't configured properly.
extractAppConfig(app);
return {
app: app,
getId: function () { return getId(app); },
getToken: function () { return getToken(app); },
delete: function () { return deleteInstallation$1(app); }
};
};
instance.INTERNAL.registerService(installationsName, factoryMethod);
}
registerInstallations(firebase);
export { registerInstallations };
//# sourceMappingURL=index.esm.js.map