UNPKG

195 kBSource Map (JSON)View Raw
1{"version":3,"file":"firebase-messaging.js","sources":["../../node_modules/tslib/tslib.es6.js","../util/src/errors.ts","../util/src/subscribe.ts","../../node_modules/idb/lib/idb.mjs","../installations/src/util/constants.ts","../installations/src/util/errors.ts","../installations/src/helpers/extract-app-config.ts","../installations/src/api/common.ts","../installations/src/util/sleep.ts","../installations/src/helpers/generate-fid.ts","../installations/src/helpers/buffer-to-base64-url-safe.ts","../installations/src/helpers/idb-manager.ts","../installations/src/helpers/get-installation-entry.ts","../installations/src/api/create-installation.ts","../installations/src/api/generate-auth-token.ts","../installations/src/helpers/refresh-auth-token.ts","../installations/src/functions/get-token.ts","../installations/src/api/delete-installation.ts","../installations/src/index.ts","../installations/src/functions/get-id.ts","../installations/src/functions/delete-installation.ts","../messaging/src/models/errors.ts","../messaging/src/models/worker-page-message.ts","../messaging/src/models/fcm-details.ts","../messaging/src/helpers/is-array-buffer-equal.ts","../messaging/src/helpers/array-buffer-to-base64.ts","../messaging/src/models/subscription-manager.ts","../messaging/src/helpers/base64-to-array-buffer.ts","../messaging/src/models/clean-v1-undefined.ts","../messaging/src/models/db-interface.ts","../messaging/src/models/token-details-model.ts","../messaging/src/models/vapid-details-model.ts","../messaging/src/controllers/base-controller.ts","../messaging/src/controllers/sw-controller.ts","../messaging/src/models/default-sw.ts","../messaging/index.ts","../messaging/src/controllers/window-controller.ts"],"sourcesContent":["/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation. All rights reserved.\r\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\r\nthis file except in compliance with the License. You may obtain a copy of the\r\nLicense at http://www.apache.org/licenses/LICENSE-2.0\r\n\r\nTHIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r\nKIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED\r\nWARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,\r\nMERCHANTABLITY OR NON-INFRINGEMENT.\r\n\r\nSee the Apache Version 2.0 License for specific language governing permissions\r\nand limitations under the License.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport function __exportStar(m, exports) {\r\n for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];\r\n}\r\n\r\nexport function __values(o) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator], i = 0;\r\n if (m) return m.call(o);\r\n return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n};\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];\r\n result.default = mod;\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * @fileoverview Standardized Firebase Error.\n *\n * Usage:\n *\n * // Typescript string literals for type-safe codes\n * type Err =\n * 'unknown' |\n * 'object-not-found'\n * ;\n *\n * // Closure enum for type-safe error codes\n * // at-enum {string}\n * var Err = {\n * UNKNOWN: 'unknown',\n * OBJECT_NOT_FOUND: 'object-not-found',\n * }\n *\n * let errors: Map<Err, string> = {\n * 'generic-error': \"Unknown error\",\n * 'file-not-found': \"Could not find file: {$file}\",\n * };\n *\n * // Type-safe function - must pass a valid error code as param.\n * let error = new ErrorFactory<Err>('service', 'Service', errors);\n *\n * ...\n * throw error.create(Err.GENERIC);\n * ...\n * throw error.create(Err.FILE_NOT_FOUND, {'file': fileName});\n * ...\n * // Service: Could not file file: foo.txt (service/file-not-found).\n *\n * catch (e) {\n * assert(e.message === \"Could not find file: foo.txt.\");\n * if (e.code === 'service/file-not-found') {\n * console.log(\"Could not read file: \" + e['file']);\n * }\n * }\n */\n\nexport type ErrorMap<ErrorCode extends string> = {\n readonly [K in ErrorCode]: string;\n};\n\nconst ERROR_NAME = 'FirebaseError';\n\nexport interface StringLike {\n toString(): string;\n}\n\nexport interface ErrorData {\n [key: string]: StringLike | undefined;\n}\n\nexport interface FirebaseError extends Error, ErrorData {\n // Unique code for error - format is service/error-code-string.\n readonly code: string;\n\n // Developer-friendly error message.\n readonly message: string;\n\n // Always 'FirebaseError'.\n readonly name: typeof ERROR_NAME;\n\n // Where available - stack backtrace in a string.\n readonly stack?: string;\n}\n\n// Based on code from:\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Custom_Error_Types\nexport class FirebaseError extends Error {\n readonly name = ERROR_NAME;\n\n constructor(readonly code: string, message: string) {\n super(message);\n\n // Fix For ES5\n // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work\n Object.setPrototypeOf(this, FirebaseError.prototype);\n\n // Maintains proper stack trace for where our error was thrown.\n // Only available on V8.\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ErrorFactory.prototype.create);\n }\n }\n}\n\nexport class ErrorFactory<\n ErrorCode extends string,\n ErrorParams extends { readonly [K in ErrorCode]?: ErrorData } = {}\n> {\n constructor(\n private readonly service: string,\n private readonly serviceName: string,\n private readonly errors: ErrorMap<ErrorCode>\n ) {}\n\n create<K extends ErrorCode>(\n code: K,\n ...data: K extends keyof ErrorParams ? [ErrorParams[K]] : []\n ): FirebaseError {\n const customData = (data[0] as ErrorData) || {};\n const fullCode = `${this.service}/${code}`;\n const template = this.errors[code];\n\n const message = template ? replaceTemplate(template, customData) : 'Error';\n // Service Name: Error message (service/code).\n const fullMessage = `${this.serviceName}: ${message} (${fullCode}).`;\n\n const error = new FirebaseError(fullCode, fullMessage);\n\n // Keys with an underscore at the end of their name are not included in\n // error.data for some reason.\n // TODO: Replace with Object.entries when lib is updated to es2017.\n for (const key of Object.keys(customData)) {\n if (key.slice(-1) !== '_') {\n if (key in error) {\n console.warn(\n `Overwriting FirebaseError base field \"${key}\" can cause unexpected behavior.`\n );\n }\n error[key] = customData[key];\n }\n }\n\n return error;\n }\n}\n\nfunction replaceTemplate(template: string, data: ErrorData): string {\n return template.replace(PATTERN, (_, key) => {\n const value = data[key];\n return value != null ? value.toString() : `<${key}?>`;\n });\n}\n\nconst PATTERN = /\\{\\$([^}]+)}/g;\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nexport type NextFn<T> = (value: T) => void;\nexport type ErrorFn = (error: Error) => void;\nexport type CompleteFn = () => void;\n\nexport interface Observer<T> {\n // Called once for each value in a stream of values.\n next: NextFn<T>;\n\n // A stream terminates by a single call to EITHER error() or complete().\n error: ErrorFn;\n\n // No events will be sent to next() once complete() is called.\n complete: CompleteFn;\n}\n\nexport type PartialObserver<T> = Partial<Observer<T>>;\n\n// TODO: Support also Unsubscribe.unsubscribe?\nexport type Unsubscribe = () => void;\n\n/**\n * The Subscribe interface has two forms - passing the inline function\n * callbacks, or a object interface with callback properties.\n */\nexport interface Subscribe<T> {\n (next?: NextFn<T>, error?: ErrorFn, complete?: CompleteFn): Unsubscribe;\n (observer: PartialObserver<T>): Unsubscribe;\n}\n\nexport interface Observable<T> {\n // Subscribe method\n subscribe: Subscribe<T>;\n}\n\nexport type Executor<T> = (observer: Observer<T>) => void;\n\n/**\n * Helper to make a Subscribe function (just like Promise helps make a\n * Thenable).\n *\n * @param executor Function which can make calls to a single Observer\n * as a proxy.\n * @param onNoObservers Callback when count of Observers goes to zero.\n */\nexport function createSubscribe<T>(\n executor: Executor<T>,\n onNoObservers?: Executor<T>\n): Subscribe<T> {\n const proxy = new ObserverProxy<T>(executor, onNoObservers);\n return proxy.subscribe.bind(proxy);\n}\n\n/**\n * Implement fan-out for any number of Observers attached via a subscribe\n * function.\n */\nclass ObserverProxy<T> implements Observer<T> {\n private observers: Array<Observer<T>> | undefined = [];\n private unsubscribes: Unsubscribe[] = [];\n private onNoObservers: Executor<T> | undefined;\n private observerCount = 0;\n // Micro-task scheduling by calling task.then().\n private task = Promise.resolve();\n private finalized = false;\n private finalError?: Error;\n\n /**\n * @param executor Function which can make calls to a single Observer\n * as a proxy.\n * @param onNoObservers Callback when count of Observers goes to zero.\n */\n constructor(executor: Executor<T>, onNoObservers?: Executor<T>) {\n this.onNoObservers = onNoObservers;\n // Call the executor asynchronously so subscribers that are called\n // synchronously after the creation of the subscribe function\n // can still receive the very first value generated in the executor.\n this.task\n .then(() => {\n executor(this);\n })\n .catch(e => {\n this.error(e);\n });\n }\n\n next(value: T): void {\n this.forEachObserver((observer: Observer<T>) => {\n observer.next(value);\n });\n }\n\n error(error: Error): void {\n this.forEachObserver((observer: Observer<T>) => {\n observer.error(error);\n });\n this.close(error);\n }\n\n complete(): void {\n this.forEachObserver((observer: Observer<T>) => {\n observer.complete();\n });\n this.close();\n }\n\n /**\n * Subscribe function that can be used to add an Observer to the fan-out list.\n *\n * - We require that no event is sent to a subscriber sychronously to their\n * call to subscribe().\n */\n subscribe(\n nextOrObserver?: PartialObserver<T> | Function,\n error?: ErrorFn,\n complete?: CompleteFn\n ): Unsubscribe {\n let observer: Observer<T>;\n\n if (\n nextOrObserver === undefined &&\n error === undefined &&\n complete === undefined\n ) {\n throw new Error('Missing Observer.');\n }\n\n // Assemble an Observer object when passed as callback functions.\n if (\n implementsAnyMethods(nextOrObserver as { [key: string]: unknown }, [\n 'next',\n 'error',\n 'complete'\n ])\n ) {\n observer = nextOrObserver as Observer<T>;\n } else {\n observer = {\n next: nextOrObserver as NextFn<T>,\n error,\n complete\n } as Observer<T>;\n }\n\n if (observer.next === undefined) {\n observer.next = noop as NextFn<T>;\n }\n if (observer.error === undefined) {\n observer.error = noop as ErrorFn;\n }\n if (observer.complete === undefined) {\n observer.complete = noop as CompleteFn;\n }\n\n const unsub = this.unsubscribeOne.bind(this, this.observers!.length);\n\n // Attempt to subscribe to a terminated Observable - we\n // just respond to the Observer with the final error or complete\n // event.\n if (this.finalized) {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.task.then(() => {\n try {\n if (this.finalError) {\n observer.error(this.finalError);\n } else {\n observer.complete();\n }\n } catch (e) {\n // nothing\n }\n return;\n });\n }\n\n this.observers!.push(observer as Observer<T>);\n\n return unsub;\n }\n\n // Unsubscribe is synchronous - we guarantee that no events are sent to\n // any unsubscribed Observer.\n private unsubscribeOne(i: number): void {\n if (this.observers === undefined || this.observers[i] === undefined) {\n return;\n }\n\n delete this.observers[i];\n\n this.observerCount -= 1;\n if (this.observerCount === 0 && this.onNoObservers !== undefined) {\n this.onNoObservers(this);\n }\n }\n\n private forEachObserver(fn: (observer: Observer<T>) => void): void {\n if (this.finalized) {\n // Already closed by previous event....just eat the additional values.\n return;\n }\n\n // Since sendOne calls asynchronously - there is no chance that\n // this.observers will become undefined.\n for (let i = 0; i < this.observers!.length; i++) {\n this.sendOne(i, fn);\n }\n }\n\n // Call the Observer via one of it's callback function. We are careful to\n // confirm that the observe has not been unsubscribed since this asynchronous\n // function had been queued.\n private sendOne(i: number, fn: (observer: Observer<T>) => void): void {\n // Execute the callback asynchronously\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.task.then(() => {\n if (this.observers !== undefined && this.observers[i] !== undefined) {\n try {\n fn(this.observers[i]);\n } catch (e) {\n // Ignore exceptions raised in Observers or missing methods of an\n // Observer.\n // Log error to console. b/31404806\n if (typeof console !== 'undefined' && console.error) {\n console.error(e);\n }\n }\n }\n });\n }\n\n private close(err?: Error): void {\n if (this.finalized) {\n return;\n }\n this.finalized = true;\n if (err !== undefined) {\n this.finalError = err;\n }\n // Proxy is no longer needed - garbage collect references\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.task.then(() => {\n this.observers = undefined;\n this.onNoObservers = undefined;\n });\n }\n}\n\n/** Turn synchronous function into one called asynchronously. */\nexport function async(fn: Function, onError?: ErrorFn): Function {\n return (...args: unknown[]) => {\n Promise.resolve(true)\n .then(() => {\n fn(...args);\n })\n .catch((error: Error) => {\n if (onError) {\n onError(error);\n }\n });\n };\n}\n\n/**\n * Return true if the object passed in implements any of the named methods.\n */\nfunction implementsAnyMethods(\n obj: { [key: string]: unknown },\n methods: string[]\n): boolean {\n if (typeof obj !== 'object' || obj === null) {\n return false;\n }\n\n for (const method of methods) {\n if (method in obj && typeof obj[method] === 'function') {\n return true;\n }\n }\n\n return false;\n}\n\nfunction noop(): void {\n // do nothing\n}\n","function toArray(arr) {\n return Array.prototype.slice.call(arr);\n}\n\nfunction promisifyRequest(request) {\n return new Promise(function(resolve, reject) {\n request.onsuccess = function() {\n resolve(request.result);\n };\n\n request.onerror = function() {\n reject(request.error);\n };\n });\n}\n\nfunction promisifyRequestCall(obj, method, args) {\n var request;\n var p = new Promise(function(resolve, reject) {\n request = obj[method].apply(obj, args);\n promisifyRequest(request).then(resolve, reject);\n });\n\n p.request = request;\n return p;\n}\n\nfunction promisifyCursorRequestCall(obj, method, args) {\n var p = promisifyRequestCall(obj, method, args);\n return p.then(function(value) {\n if (!value) return;\n return new Cursor(value, p.request);\n });\n}\n\nfunction proxyProperties(ProxyClass, targetProp, properties) {\n properties.forEach(function(prop) {\n Object.defineProperty(ProxyClass.prototype, prop, {\n get: function() {\n return this[targetProp][prop];\n },\n set: function(val) {\n this[targetProp][prop] = val;\n }\n });\n });\n}\n\nfunction proxyRequestMethods(ProxyClass, targetProp, Constructor, properties) {\n properties.forEach(function(prop) {\n if (!(prop in Constructor.prototype)) return;\n ProxyClass.prototype[prop] = function() {\n return promisifyRequestCall(this[targetProp], prop, arguments);\n };\n });\n}\n\nfunction proxyMethods(ProxyClass, targetProp, Constructor, properties) {\n properties.forEach(function(prop) {\n if (!(prop in Constructor.prototype)) return;\n ProxyClass.prototype[prop] = function() {\n return this[targetProp][prop].apply(this[targetProp], arguments);\n };\n });\n}\n\nfunction proxyCursorRequestMethods(ProxyClass, targetProp, Constructor, properties) {\n properties.forEach(function(prop) {\n if (!(prop in Constructor.prototype)) return;\n ProxyClass.prototype[prop] = function() {\n return promisifyCursorRequestCall(this[targetProp], prop, arguments);\n };\n });\n}\n\nfunction Index(index) {\n this._index = index;\n}\n\nproxyProperties(Index, '_index', [\n 'name',\n 'keyPath',\n 'multiEntry',\n 'unique'\n]);\n\nproxyRequestMethods(Index, '_index', IDBIndex, [\n 'get',\n 'getKey',\n 'getAll',\n 'getAllKeys',\n 'count'\n]);\n\nproxyCursorRequestMethods(Index, '_index', IDBIndex, [\n 'openCursor',\n 'openKeyCursor'\n]);\n\nfunction Cursor(cursor, request) {\n this._cursor = cursor;\n this._request = request;\n}\n\nproxyProperties(Cursor, '_cursor', [\n 'direction',\n 'key',\n 'primaryKey',\n 'value'\n]);\n\nproxyRequestMethods(Cursor, '_cursor', IDBCursor, [\n 'update',\n 'delete'\n]);\n\n// proxy 'next' methods\n['advance', 'continue', 'continuePrimaryKey'].forEach(function(methodName) {\n if (!(methodName in IDBCursor.prototype)) return;\n Cursor.prototype[methodName] = function() {\n var cursor = this;\n var args = arguments;\n return Promise.resolve().then(function() {\n cursor._cursor[methodName].apply(cursor._cursor, args);\n return promisifyRequest(cursor._request).then(function(value) {\n if (!value) return;\n return new Cursor(value, cursor._request);\n });\n });\n };\n});\n\nfunction ObjectStore(store) {\n this._store = store;\n}\n\nObjectStore.prototype.createIndex = function() {\n return new Index(this._store.createIndex.apply(this._store, arguments));\n};\n\nObjectStore.prototype.index = function() {\n return new Index(this._store.index.apply(this._store, arguments));\n};\n\nproxyProperties(ObjectStore, '_store', [\n 'name',\n 'keyPath',\n 'indexNames',\n 'autoIncrement'\n]);\n\nproxyRequestMethods(ObjectStore, '_store', IDBObjectStore, [\n 'put',\n 'add',\n 'delete',\n 'clear',\n 'get',\n 'getAll',\n 'getKey',\n 'getAllKeys',\n 'count'\n]);\n\nproxyCursorRequestMethods(ObjectStore, '_store', IDBObjectStore, [\n 'openCursor',\n 'openKeyCursor'\n]);\n\nproxyMethods(ObjectStore, '_store', IDBObjectStore, [\n 'deleteIndex'\n]);\n\nfunction Transaction(idbTransaction) {\n this._tx = idbTransaction;\n this.complete = new Promise(function(resolve, reject) {\n idbTransaction.oncomplete = function() {\n resolve();\n };\n idbTransaction.onerror = function() {\n reject(idbTransaction.error);\n };\n idbTransaction.onabort = function() {\n reject(idbTransaction.error);\n };\n });\n}\n\nTransaction.prototype.objectStore = function() {\n return new ObjectStore(this._tx.objectStore.apply(this._tx, arguments));\n};\n\nproxyProperties(Transaction, '_tx', [\n 'objectStoreNames',\n 'mode'\n]);\n\nproxyMethods(Transaction, '_tx', IDBTransaction, [\n 'abort'\n]);\n\nfunction UpgradeDB(db, oldVersion, transaction) {\n this._db = db;\n this.oldVersion = oldVersion;\n this.transaction = new Transaction(transaction);\n}\n\nUpgradeDB.prototype.createObjectStore = function() {\n return new ObjectStore(this._db.createObjectStore.apply(this._db, arguments));\n};\n\nproxyProperties(UpgradeDB, '_db', [\n 'name',\n 'version',\n 'objectStoreNames'\n]);\n\nproxyMethods(UpgradeDB, '_db', IDBDatabase, [\n 'deleteObjectStore',\n 'close'\n]);\n\nfunction DB(db) {\n this._db = db;\n}\n\nDB.prototype.transaction = function() {\n return new Transaction(this._db.transaction.apply(this._db, arguments));\n};\n\nproxyProperties(DB, '_db', [\n 'name',\n 'version',\n 'objectStoreNames'\n]);\n\nproxyMethods(DB, '_db', IDBDatabase, [\n 'close'\n]);\n\n// Add cursor iterators\n// TODO: remove this once browsers do the right thing with promises\n['openCursor', 'openKeyCursor'].forEach(function(funcName) {\n [ObjectStore, Index].forEach(function(Constructor) {\n // Don't create iterateKeyCursor if openKeyCursor doesn't exist.\n if (!(funcName in Constructor.prototype)) return;\n\n Constructor.prototype[funcName.replace('open', 'iterate')] = function() {\n var args = toArray(arguments);\n var callback = args[args.length - 1];\n var nativeObject = this._store || this._index;\n var request = nativeObject[funcName].apply(nativeObject, args.slice(0, -1));\n request.onsuccess = function() {\n callback(request.result);\n };\n };\n });\n});\n\n// polyfill getAll\n[Index, ObjectStore].forEach(function(Constructor) {\n if (Constructor.prototype.getAll) return;\n Constructor.prototype.getAll = function(query, count) {\n var instance = this;\n var items = [];\n\n return new Promise(function(resolve) {\n instance.iterateCursor(query, function(cursor) {\n if (!cursor) {\n resolve(items);\n return;\n }\n items.push(cursor.value);\n\n if (count !== undefined && items.length == count) {\n resolve(items);\n return;\n }\n cursor.continue();\n });\n });\n };\n});\n\nexport function openDb(name, version, upgradeCallback) {\n var p = promisifyRequestCall(indexedDB, 'open', [name, version]);\n var request = p.request;\n\n if (request) {\n request.onupgradeneeded = function(event) {\n if (upgradeCallback) {\n upgradeCallback(new UpgradeDB(request.result, event.oldVersion, request.transaction));\n }\n };\n }\n\n return p.then(function(db) {\n return new DB(db);\n });\n}\n\nexport function deleteDb(name) {\n return promisifyRequestCall(indexedDB, 'deleteDatabase', [name]);\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { version } from '../../package.json';\n\nexport const PENDING_TIMEOUT_MS = 10000;\n\nexport const PACKAGE_VERSION = `w:${version}`;\nexport const INTERNAL_AUTH_VERSION = 'FIS_v2';\n\nexport const INSTALLATIONS_API_URL =\n 'https://firebaseinstallations.googleapis.com/v1';\n\nexport const TOKEN_EXPIRATION_BUFFER = 60 * 60 * 1000; // One hour\n\nexport const SERVICE = 'installations';\nexport const SERVICE_NAME = 'Installations';\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ErrorFactory, FirebaseError } from '@firebase/util';\nimport { SERVICE, SERVICE_NAME } from './constants';\n\nexport const enum ErrorCode {\n MISSING_APP_CONFIG_VALUES = 'missing-app-config-values',\n NOT_REGISTERED = 'not-registered',\n INSTALLATION_NOT_FOUND = 'installation-not-found',\n REQUEST_FAILED = 'request-failed',\n APP_OFFLINE = 'app-offline',\n DELETE_PENDING_REGISTRATION = 'delete-pending-registration'\n}\n\nconst ERROR_DESCRIPTION_MAP: { readonly [key in ErrorCode]: string } = {\n [ErrorCode.MISSING_APP_CONFIG_VALUES]:\n 'Missing App configuration value: \"{$valueName}\"',\n [ErrorCode.NOT_REGISTERED]: 'Firebase Installation is not registered.',\n [ErrorCode.INSTALLATION_NOT_FOUND]: 'Firebase Installation not found.',\n [ErrorCode.REQUEST_FAILED]:\n '{$requestName} request failed with error \"{$serverCode} {$serverStatus}: {$serverMessage}\"',\n [ErrorCode.APP_OFFLINE]: 'Could not process request. Application offline.',\n [ErrorCode.DELETE_PENDING_REGISTRATION]:\n \"Can't delete installation while there is a pending registration request.\"\n};\n\ninterface ErrorParams {\n [ErrorCode.MISSING_APP_CONFIG_VALUES]: {\n valueName: string;\n };\n [ErrorCode.REQUEST_FAILED]: {\n requestName: string;\n } & ServerErrorData;\n}\n\nexport const ERROR_FACTORY = new ErrorFactory<ErrorCode, ErrorParams>(\n SERVICE,\n SERVICE_NAME,\n ERROR_DESCRIPTION_MAP\n);\n\nexport interface ServerErrorData {\n serverCode: number;\n serverMessage: string;\n serverStatus: string;\n}\n\nexport type ServerError = FirebaseError & ServerErrorData;\n\n/** Returns true if error is a FirebaseError that is based on an error from the server. */\nexport function isServerError(error: unknown): error is ServerError {\n return (\n error instanceof FirebaseError &&\n error.code.includes(ErrorCode.REQUEST_FAILED)\n );\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FirebaseApp, FirebaseOptions } from '@firebase/app-types';\nimport { AppConfig } from '../interfaces/app-config';\nimport { ERROR_FACTORY, ErrorCode } from '../util/errors';\nimport { FirebaseError } from '@firebase/util';\n\nexport function extractAppConfig(app: FirebaseApp): AppConfig {\n if (!app || !app.options) {\n throw getMissingValueError('App Configuration');\n }\n\n if (!app.name) {\n throw getMissingValueError('App Name');\n }\n\n // Required app config keys\n const configKeys: Array<keyof FirebaseOptions> = [\n 'projectId',\n 'apiKey',\n 'appId'\n ];\n\n for (const keyName of configKeys) {\n if (!app.options[keyName]) {\n throw getMissingValueError(keyName);\n }\n }\n\n return {\n appName: app.name,\n projectId: app.options.projectId!,\n apiKey: app.options.apiKey!,\n appId: app.options.appId!\n };\n}\n\nfunction getMissingValueError(valueName: string): FirebaseError {\n return ERROR_FACTORY.create(ErrorCode.MISSING_APP_CONFIG_VALUES, {\n valueName\n });\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FirebaseError } from '@firebase/util';\nimport { GenerateAuthTokenResponse } from '../interfaces/api-response';\nimport { AppConfig } from '../interfaces/app-config';\nimport {\n CompletedAuthToken,\n RegisteredInstallationEntry,\n RequestStatus\n} from '../interfaces/installation-entry';\nimport {\n INSTALLATIONS_API_URL,\n INTERNAL_AUTH_VERSION\n} from '../util/constants';\nimport { ERROR_FACTORY, ErrorCode } from '../util/errors';\n\nexport function getInstallationsEndpoint({ projectId }: AppConfig): string {\n return `${INSTALLATIONS_API_URL}/projects/${projectId}/installations`;\n}\n\nexport function extractAuthTokenInfoFromResponse(\n response: GenerateAuthTokenResponse\n): CompletedAuthToken {\n return {\n token: response.token,\n requestStatus: RequestStatus.COMPLETED,\n expiresIn: getExpiresInFromResponseExpiresIn(response.expiresIn),\n creationTime: Date.now()\n };\n}\n\nexport async function getErrorFromResponse(\n requestName: string,\n response: Response\n): Promise<FirebaseError> {\n const responseJson: ErrorResponse = await response.json();\n const errorData = responseJson.error;\n return ERROR_FACTORY.create(ErrorCode.REQUEST_FAILED, {\n requestName,\n serverCode: errorData.code,\n serverMessage: errorData.message,\n serverStatus: errorData.status\n });\n}\n\nexport function getHeaders({ apiKey }: AppConfig): Headers {\n return new Headers({\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n 'x-goog-api-key': apiKey\n });\n}\n\nexport function getHeadersWithAuth(\n appConfig: AppConfig,\n { refreshToken }: RegisteredInstallationEntry\n): Headers {\n const headers = getHeaders(appConfig);\n headers.append('Authorization', getAuthorizationHeader(refreshToken));\n return headers;\n}\n\nexport interface ErrorResponse {\n error: {\n code: number;\n message: string;\n status: string;\n };\n}\n\n/**\n * Calls the passed in fetch wrapper and returns the response.\n * If the returned response has a status of 5xx, re-runs the function once and\n * returns the response.\n */\nexport async function retryIfServerError(\n fn: () => Promise<Response>\n): Promise<Response> {\n const result = await fn();\n\n if (result.status >= 500 && result.status < 600) {\n // Internal Server Error. Retry request.\n return fn();\n }\n\n return result;\n}\n\nfunction getExpiresInFromResponseExpiresIn(responseExpiresIn: string): number {\n // This works because the server will never respond with fractions of a second.\n return Number(responseExpiresIn.replace('s', '000'));\n}\n\nfunction getAuthorizationHeader(refreshToken: string): string {\n return `${INTERNAL_AUTH_VERSION} ${refreshToken}`;\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** Returns a promise that resolves after given time passes. */\nexport function sleep(ms: number): Promise<void> {\n return new Promise<void>(resolve => {\n setTimeout(resolve, ms);\n });\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { bufferToBase64UrlSafe } from './buffer-to-base64-url-safe';\n\nexport const VALID_FID_PATTERN = /^[cdef][\\w-]{21}$/;\nexport const INVALID_FID = '';\n\n/**\n * Generates a new FID using random values from Web Crypto API.\n * Returns an empty string if FID generation fails for any reason.\n */\nexport function generateFid(): string {\n try {\n // A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5\n // bytes. our implementation generates a 17 byte array instead.\n const fidByteArray = new Uint8Array(17);\n const crypto =\n self.crypto || ((self as unknown) as { msCrypto: Crypto }).msCrypto;\n crypto.getRandomValues(fidByteArray);\n\n // Replace the first 4 random bits with the constant FID header of 0b0111.\n fidByteArray[0] = 0b01110000 + (fidByteArray[0] % 0b00010000);\n\n const fid = encode(fidByteArray);\n\n return VALID_FID_PATTERN.test(fid) ? fid : INVALID_FID;\n } catch {\n // FID generation errored\n return INVALID_FID;\n }\n}\n\n/** Converts a FID Uint8Array to a base64 string representation. */\nfunction encode(fidByteArray: Uint8Array): string {\n const b64String = bufferToBase64UrlSafe(fidByteArray);\n\n // Remove the 23rd character that was added because of the extra 4 bits at the\n // end of our 17 byte array, and the '=' padding.\n return b64String.substr(0, 22);\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function bufferToBase64UrlSafe(array: Uint8Array): string {\n const b64 = btoa(String.fromCharCode(...array));\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_');\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DB, openDb } from 'idb';\nimport { AppConfig } from '../interfaces/app-config';\nimport { InstallationEntry } from '../interfaces/installation-entry';\n\nconst DATABASE_NAME = 'firebase-installations-database';\nconst DATABASE_VERSION = 1;\nconst OBJECT_STORE_NAME = 'firebase-installations-store';\n\nlet dbPromise: Promise<DB> | null = null;\nfunction getDbPromise(): Promise<DB> {\n if (!dbPromise) {\n dbPromise = openDb(DATABASE_NAME, DATABASE_VERSION, upgradeDB => {\n // We don't use 'break' in this switch statement, the fall-through\n // behavior is what we want, because if there are multiple versions between\n // the old version and the current version, we want ALL the migrations\n // that correspond to those versions to run, not only the last one.\n // eslint-disable-next-line default-case\n switch (upgradeDB.oldVersion) {\n case 0:\n upgradeDB.createObjectStore(OBJECT_STORE_NAME);\n }\n });\n }\n return dbPromise;\n}\n\n/** Gets record(s) from the objectStore that match the given key. */\nexport async function get(\n appConfig: AppConfig\n): Promise<InstallationEntry | undefined> {\n const key = getKey(appConfig);\n const db = await getDbPromise();\n return db\n .transaction(OBJECT_STORE_NAME)\n .objectStore(OBJECT_STORE_NAME)\n .get(key);\n}\n\n/** Assigns or overwrites the record for the given key with the given value. */\nexport async function set<ValueType extends InstallationEntry>(\n appConfig: AppConfig,\n value: ValueType\n): Promise<ValueType> {\n const key = getKey(appConfig);\n const db = await getDbPromise();\n const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');\n await tx.objectStore(OBJECT_STORE_NAME).put(value, key);\n await tx.complete;\n return value;\n}\n\n/** Removes record(s) from the objectStore that match the given key. */\nexport async function remove(appConfig: AppConfig): Promise<void> {\n const key = getKey(appConfig);\n const db = await getDbPromise();\n const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');\n await tx.objectStore(OBJECT_STORE_NAME).delete(key);\n await tx.complete;\n}\n\n/**\n * Atomically updates a record with the result of updateFn, which gets\n * called with the current value. If newValue is undefined, the record is\n * deleted instead.\n * @return Updated value\n */\nexport async function update<ValueType extends InstallationEntry | undefined>(\n appConfig: AppConfig,\n updateFn: (previousValue: InstallationEntry | undefined) => ValueType\n): Promise<ValueType> {\n const key = getKey(appConfig);\n const db = await getDbPromise();\n const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');\n const store = tx.objectStore(OBJECT_STORE_NAME);\n const oldValue: InstallationEntry | undefined = await store.get(key);\n const newValue = updateFn(oldValue);\n\n if (newValue === undefined) {\n await store.delete(key);\n } else {\n await store.put(newValue, key);\n }\n\n await tx.complete;\n return newValue;\n}\n\nexport async function clear(): Promise<void> {\n const db = await getDbPromise();\n const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');\n await tx.objectStore(OBJECT_STORE_NAME).clear();\n await tx.complete;\n}\n\nfunction getKey(appConfig: AppConfig): string {\n return `${appConfig.appName}!${appConfig.appId}`;\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createInstallation } from '../api/create-installation';\nimport { AppConfig } from '../interfaces/app-config';\nimport {\n InProgressInstallationEntry,\n InstallationEntry,\n RequestStatus,\n RegisteredInstallationEntry\n} from '../interfaces/installation-entry';\nimport { PENDING_TIMEOUT_MS } from '../util/constants';\nimport { ERROR_FACTORY, ErrorCode, isServerError } from '../util/errors';\nimport { sleep } from '../util/sleep';\nimport { generateFid, INVALID_FID } from './generate-fid';\nimport { remove, set, update } from './idb-manager';\n\nexport interface InstallationEntryWithRegistrationPromise {\n installationEntry: InstallationEntry;\n /** Exist iff the installationEntry is not registered. */\n registrationPromise?: Promise<RegisteredInstallationEntry>;\n}\n\n/**\n * Updates and returns the InstallationEntry from the database.\n * Also triggers a registration request if it is necessary and possible.\n */\nexport async function getInstallationEntry(\n appConfig: AppConfig\n): Promise<InstallationEntryWithRegistrationPromise> {\n let registrationPromise: Promise<RegisteredInstallationEntry> | undefined;\n\n const installationEntry = await update(appConfig, oldEntry => {\n const installationEntry = updateOrCreateInstallationEntry(oldEntry);\n const entryWithPromise = triggerRegistrationIfNecessary(\n appConfig,\n installationEntry\n );\n registrationPromise = entryWithPromise.registrationPromise;\n return entryWithPromise.installationEntry;\n });\n\n if (installationEntry.fid === INVALID_FID) {\n // FID generation failed. Waiting for the FID from the server.\n return { installationEntry: await registrationPromise! };\n }\n\n return {\n installationEntry,\n registrationPromise\n };\n}\n\n/**\n * Creates a new Installation Entry if one does not exist.\n * Also clears timed out pending requests.\n */\nfunction updateOrCreateInstallationEntry(\n oldEntry: InstallationEntry | undefined\n): InstallationEntry {\n const entry: InstallationEntry = oldEntry || {\n fid: generateFid(),\n registrationStatus: RequestStatus.NOT_STARTED\n };\n\n return clearTimedOutRequest(entry);\n}\n\n/**\n * If the Firebase Installation is not registered yet, this will trigger the\n * registration and return an InProgressInstallationEntry.\n *\n * If registrationPromise does not exist, the installationEntry is guaranteed\n * to be registered.\n */\nfunction triggerRegistrationIfNecessary(\n appConfig: AppConfig,\n installationEntry: InstallationEntry\n): InstallationEntryWithRegistrationPromise {\n if (installationEntry.registrationStatus === RequestStatus.NOT_STARTED) {\n if (!navigator.onLine) {\n // Registration required but app is offline.\n const registrationPromiseWithError = Promise.reject(\n ERROR_FACTORY.create(ErrorCode.APP_OFFLINE)\n );\n return {\n installationEntry,\n registrationPromise: registrationPromiseWithError\n };\n }\n\n // Try registering. Change status to IN_PROGRESS.\n const inProgressEntry: InProgressInstallationEntry = {\n fid: installationEntry.fid,\n registrationStatus: RequestStatus.IN_PROGRESS,\n registrationTime: Date.now()\n };\n const registrationPromise = registerInstallation(\n appConfig,\n inProgressEntry\n );\n return { installationEntry: inProgressEntry, registrationPromise };\n } else if (\n installationEntry.registrationStatus === RequestStatus.IN_PROGRESS\n ) {\n return {\n installationEntry,\n registrationPromise: waitUntilFidRegistration(appConfig)\n };\n } else {\n return { installationEntry };\n }\n}\n\n/** This will be executed only once for each new Firebase Installation. */\nasync function registerInstallation(\n appConfig: AppConfig,\n installationEntry: InProgressInstallationEntry\n): Promise<RegisteredInstallationEntry> {\n try {\n const registeredInstallationEntry = await createInstallation(\n appConfig,\n installationEntry\n );\n return set(appConfig, registeredInstallationEntry);\n } catch (e) {\n if (isServerError(e) && e.serverCode === 409) {\n // Server returned a \"FID can not be used\" error.\n // Generate a new ID next time.\n await remove(appConfig);\n } else {\n // Registration failed. Set FID as not registered.\n await set(appConfig, {\n fid: installationEntry.fid,\n registrationStatus: RequestStatus.NOT_STARTED\n });\n }\n throw e;\n }\n}\n\n/** Call if FID registration is pending in another request. */\nasync function waitUntilFidRegistration(\n appConfig: AppConfig\n): Promise<RegisteredInstallationEntry> {\n // Unfortunately, there is no way of reliably observing when a value in\n // IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers),\n // so we need to poll.\n\n let entry: InstallationEntry = await updateInstallationRequest(appConfig);\n while (entry.registrationStatus === RequestStatus.IN_PROGRESS) {\n // createInstallation request still in progress.\n await sleep(100);\n\n entry = await updateInstallationRequest(appConfig);\n }\n\n if (entry.registrationStatus === RequestStatus.NOT_STARTED) {\n // The request timed out or failed in a different call. Try again.\n const {\n installationEntry,\n registrationPromise\n } = await getInstallationEntry(appConfig);\n\n if (registrationPromise) {\n return registrationPromise;\n } else {\n // if there is no registrationPromise, entry is registered.\n return installationEntry as RegisteredInstallationEntry;\n }\n }\n\n return entry;\n}\n\n/**\n * Called only if there is a CreateInstallation request in progress.\n *\n * Updates the InstallationEntry in the DB based on the status of the\n * CreateInstallation request.\n *\n * Returns the updated InstallationEntry.\n */\nfunction updateInstallationRequest(\n appConfig: AppConfig\n): Promise<InstallationEntry> {\n return update(appConfig, oldEntry => {\n if (!oldEntry) {\n throw ERROR_FACTORY.create(ErrorCode.INSTALLATION_NOT_FOUND);\n }\n return clearTimedOutRequest(oldEntry);\n });\n}\n\nfunction clearTimedOutRequest(entry: InstallationEntry): InstallationEntry {\n if (hasInstallationRequestTimedOut(entry)) {\n return {\n fid: entry.fid,\n registrationStatus: RequestStatus.NOT_STARTED\n };\n }\n\n return entry;\n}\n\nfunction hasInstallationRequestTimedOut(\n installationEntry: InstallationEntry\n): boolean {\n return (\n installationEntry.registrationStatus === RequestStatus.IN_PROGRESS &&\n installationEntry.registrationTime + PENDING_TIMEOUT_MS < Date.now()\n );\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CreateInstallationResponse } from '../interfaces/api-response';\nimport { AppConfig } from '../interfaces/app-config';\nimport {\n InProgressInstallationEntry,\n RegisteredInstallationEntry,\n RequestStatus\n} from '../interfaces/installation-entry';\nimport { INTERNAL_AUTH_VERSION, PACKAGE_VERSION } from '../util/constants';\nimport {\n extractAuthTokenInfoFromResponse,\n getErrorFromResponse,\n getHeaders,\n getInstallationsEndpoint,\n retryIfServerError\n} from './common';\n\nexport async function createInstallation(\n appConfig: AppConfig,\n { fid }: InProgressInstallationEntry\n): Promise<RegisteredInstallationEntry> {\n const endpoint = getInstallationsEndpoint(appConfig);\n\n const headers = getHeaders(appConfig);\n const body = {\n fid,\n authVersion: INTERNAL_AUTH_VERSION,\n appId: appConfig.appId,\n sdkVersion: PACKAGE_VERSION\n };\n\n const request: RequestInit = {\n method: 'POST',\n headers,\n body: JSON.stringify(body)\n };\n\n const response = await retryIfServerError(() => fetch(endpoint, request));\n if (response.ok) {\n const responseValue: CreateInstallationResponse = await response.json();\n const registeredInstallationEntry: RegisteredInstallationEntry = {\n fid: responseValue.fid || fid,\n registrationStatus: RequestStatus.COMPLETED,\n refreshToken: responseValue.refreshToken,\n authToken: extractAuthTokenInfoFromResponse(responseValue.authToken)\n };\n return registeredInstallationEntry;\n } else {\n throw await getErrorFromResponse('Create Installation', response);\n }\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { GenerateAuthTokenResponse } from '../interfaces/api-response';\nimport { AppConfig } from '../interfaces/app-config';\nimport {\n CompletedAuthToken,\n RegisteredInstallationEntry\n} from '../interfaces/installation-entry';\nimport { PACKAGE_VERSION } from '../util/constants';\nimport {\n extractAuthTokenInfoFromResponse,\n getErrorFromResponse,\n getHeadersWithAuth,\n getInstallationsEndpoint,\n retryIfServerError\n} from './common';\n\nexport async function generateAuthToken(\n appConfig: AppConfig,\n installationEntry: RegisteredInstallationEntry\n): Promise<CompletedAuthToken> {\n const endpoint = getGenerateAuthTokenEndpoint(appConfig, installationEntry);\n\n const headers = getHeadersWithAuth(appConfig, installationEntry);\n const body = {\n installation: {\n sdkVersion: PACKAGE_VERSION\n }\n };\n\n const request: RequestInit = {\n method: 'POST',\n headers,\n body: JSON.stringify(body)\n };\n\n const response = await retryIfServerError(() => fetch(endpoint, request));\n if (response.ok) {\n const responseValue: GenerateAuthTokenResponse = await response.json();\n const completedAuthToken: CompletedAuthToken = extractAuthTokenInfoFromResponse(\n responseValue\n );\n return completedAuthToken;\n } else {\n throw await getErrorFromResponse('Generate Auth Token', response);\n }\n}\n\nfunction getGenerateAuthTokenEndpoint(\n appConfig: AppConfig,\n { fid }: RegisteredInstallationEntry\n): string {\n return `${getInstallationsEndpoint(appConfig)}/${fid}/authTokens:generate`;\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { generateAuthToken } from '../api/generate-auth-token';\nimport { AppConfig } from '../interfaces/app-config';\nimport {\n AuthToken,\n CompletedAuthToken,\n InProgressAuthToken,\n InstallationEntry,\n RegisteredInstallationEntry,\n RequestStatus\n} from '../interfaces/installation-entry';\nimport { PENDING_TIMEOUT_MS, TOKEN_EXPIRATION_BUFFER } from '../util/constants';\nimport { ERROR_FACTORY, ErrorCode, isServerError } from '../util/errors';\nimport { sleep } from '../util/sleep';\nimport { remove, set, update } from './idb-manager';\n\n/**\n * Returns a valid authentication token for the installation. Generates a new\n * token if one doesn't exist, is expired or about to expire.\n *\n * Should only be called if the Firebase Installation is registered.\n */\nexport async function refreshAuthToken(\n appConfig: AppConfig,\n forceRefresh = false\n): Promise<CompletedAuthToken> {\n let tokenPromise: Promise<CompletedAuthToken> | undefined;\n const entry = await update(appConfig, oldEntry => {\n if (!isEntryRegistered(oldEntry)) {\n throw ERROR_FACTORY.create(ErrorCode.NOT_REGISTERED);\n }\n\n const oldAuthToken = oldEntry.authToken;\n if (!forceRefresh && isAuthTokenValid(oldAuthToken)) {\n // There is a valid token in the DB.\n return oldEntry;\n } else if (oldAuthToken.requestStatus === RequestStatus.IN_PROGRESS) {\n // There already is a token request in progress.\n tokenPromise = waitUntilAuthTokenRequest(appConfig, forceRefresh);\n return oldEntry;\n } else {\n // No token or token expired.\n if (!navigator.onLine) {\n throw ERROR_FACTORY.create(ErrorCode.APP_OFFLINE);\n }\n\n const inProgressEntry = makeAuthTokenRequestInProgressEntry(oldEntry);\n tokenPromise = fetchAuthTokenFromServer(appConfig, inProgressEntry);\n return inProgressEntry;\n }\n });\n\n const authToken = tokenPromise\n ? await tokenPromise\n : (entry.authToken as CompletedAuthToken);\n return authToken;\n}\n\n/**\n * Call only if FID is registered and Auth Token request is in progress.\n */\nasync function waitUntilAuthTokenRequest(\n appConfig: AppConfig,\n forceRefresh: boolean\n): Promise<CompletedAuthToken> {\n // Unfortunately, there is no way of reliably observing when a value in\n // IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers),\n // so we need to poll.\n\n let entry = await updateAuthTokenRequest(appConfig);\n while (entry.authToken.requestStatus === RequestStatus.IN_PROGRESS) {\n // generateAuthToken still in progress.\n await sleep(100);\n\n entry = await updateAuthTokenRequest(appConfig);\n }\n\n const authToken = entry.authToken;\n if (authToken.requestStatus === RequestStatus.NOT_STARTED) {\n // The request timed out or failed in a different call. Try again.\n return refreshAuthToken(appConfig, forceRefresh);\n } else {\n return authToken;\n }\n}\n\n/**\n * Called only if there is a GenerateAuthToken request in progress.\n *\n * Updates the InstallationEntry in the DB based on the status of the\n * GenerateAuthToken request.\n *\n * Returns the updated InstallationEntry.\n */\nfunction updateAuthTokenRequest(\n appConfig: AppConfig\n): Promise<RegisteredInstallationEntry> {\n return update(appConfig, oldEntry => {\n if (!isEntryRegistered(oldEntry)) {\n throw ERROR_FACTORY.create(ErrorCode.NOT_REGISTERED);\n }\n\n const oldAuthToken = oldEntry.authToken;\n if (hasAuthTokenRequestTimedOut(oldAuthToken)) {\n return {\n ...oldEntry,\n authToken: { requestStatus: RequestStatus.NOT_STARTED }\n };\n }\n\n return oldEntry;\n });\n}\n\nasync function fetchAuthTokenFromServer(\n appConfig: AppConfig,\n installationEntry: RegisteredInstallationEntry\n): Promise<CompletedAuthToken> {\n try {\n const authToken = await generateAuthToken(appConfig, installationEntry);\n const updatedInstallationEntry: RegisteredInstallationEntry = {\n ...installationEntry,\n authToken\n };\n await set(appConfig, updatedInstallationEntry);\n return authToken;\n } catch (e) {\n if (isServerError(e) && (e.serverCode === 401 || e.serverCode === 404)) {\n // Server returned a \"FID not found\" or a \"Invalid authentication\" error.\n // Generate a new ID next time.\n await remove(appConfig);\n } else {\n const updatedInstallationEntry: RegisteredInstallationEntry = {\n ...installationEntry,\n authToken: { requestStatus: RequestStatus.NOT_STARTED }\n };\n await set(appConfig, updatedInstallationEntry);\n }\n throw e;\n }\n}\n\nfunction isEntryRegistered(\n installationEntry: InstallationEntry | undefined\n): installationEntry is RegisteredInstallationEntry {\n return (\n installationEntry !== undefined &&\n installationEntry.registrationStatus === RequestStatus.COMPLETED\n );\n}\n\nfunction isAuthTokenValid(authToken: AuthToken): boolean {\n return (\n authToken.requestStatus === RequestStatus.COMPLETED &&\n !isAuthTokenExpired(authToken)\n );\n}\n\nfunction isAuthTokenExpired(authToken: CompletedAuthToken): boolean {\n const now = Date.now();\n return (\n now < authToken.creationTime ||\n authToken.creationTime + authToken.expiresIn < now + TOKEN_EXPIRATION_BUFFER\n );\n}\n\n/** Returns an updated InstallationEntry with an InProgressAuthToken. */\nfunction makeAuthTokenRequestInProgressEntry(\n oldEntry: RegisteredInstallationEntry\n): RegisteredInstallationEntry {\n const inProgressAuthToken: InProgressAuthToken = {\n requestStatus: RequestStatus.IN_PROGRESS,\n requestTime: Date.now()\n };\n return {\n ...oldEntry,\n authToken: inProgressAuthToken\n };\n}\n\nfunction hasAuthTokenRequestTimedOut(authToken: AuthToken): boolean {\n return (\n authToken.requestStatus === RequestStatus.IN_PROGRESS &&\n authToken.requestTime + PENDING_TIMEOUT_MS < Date.now()\n );\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FirebaseApp } from '@firebase/app-types';\nimport { extractAppConfig } from '../helpers/extract-app-config';\nimport { getInstallationEntry } from '../helpers/get-installation-entry';\nimport { refreshAuthToken } from '../helpers/refresh-auth-token';\nimport { AppConfig } from '../interfaces/app-config';\n\nexport async function getToken(\n app: FirebaseApp,\n forceRefresh = false\n): Promise<string> {\n const appConfig = extractAppConfig(app);\n\n await completeInstallationRegistration(appConfig);\n\n // At this point we either have a Registered Installation in the DB, or we've\n // already thrown an error.\n const authToken = await refreshAuthToken(appConfig, forceRefresh);\n return authToken.token;\n}\n\nasync function completeInstallationRegistration(\n appConfig: AppConfig\n): Promise<void> {\n const { registrationPromise } = await getInstallationEntry(appConfig);\n\n if (registrationPromise) {\n // A createInstallation request is in progress. Wait until it finishes.\n await registrationPromise;\n }\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AppConfig } from '../interfaces/app-config';\nimport { RegisteredInstallationEntry } from '../interfaces/installation-entry';\nimport {\n getErrorFromResponse,\n getHeadersWithAuth,\n getInstallationsEndpoint,\n retryIfServerError\n} from './common';\n\nexport async function deleteInstallation(\n appConfig: AppConfig,\n installationEntry: RegisteredInstallationEntry\n): Promise<void> {\n const endpoint = getDeleteEndpoint(appConfig, installationEntry);\n\n const headers = getHeadersWithAuth(appConfig, installationEntry);\n const request: RequestInit = {\n method: 'DELETE',\n headers\n };\n\n const response = await retryIfServerError(() => fetch(endpoint, request));\n if (!response.ok) {\n throw await getErrorFromResponse('Delete Installation', response);\n }\n}\n\nfunction getDeleteEndpoint(\n appConfig: AppConfig,\n { fid }: RegisteredInstallationEntry\n): string {\n return `${getInstallationsEndpoint(appConfig)}/${fid}`;\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport firebase from '@firebase/app';\nimport {\n _FirebaseNamespace,\n FirebaseServiceFactory\n} from '@firebase/app-types/private';\nimport { FirebaseInstallations } from '@firebase/installations-types';\n\nimport { deleteInstallation, getId, getToken } from './functions';\nimport { extractAppConfig } from './helpers/extract-app-config';\n\nexport function registerInstallations(instance: _FirebaseNamespace): void {\n const installationsName = 'installations';\n\n const factoryMethod: FirebaseServiceFactory = app => {\n // Throws if app isn't configured properly.\n extractAppConfig(app);\n\n return {\n app,\n getId: () => getId(app),\n getToken: (forceRefresh?: boolean) => getToken(app, forceRefresh),\n delete: () => deleteInstallation(app)\n };\n };\n\n instance.INTERNAL.registerService(installationsName, factoryMethod);\n}\n\nregisterInstallations(firebase as _FirebaseNamespace);\n\n/**\n * Define extension behavior of `registerInstallations`\n */\ndeclare module '@firebase/app-types' {\n interface FirebaseNamespace {\n installations(app?: FirebaseApp): FirebaseInstallations;\n }\n interface FirebaseApp {\n installations(): FirebaseInstallations;\n }\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FirebaseApp } from '@firebase/app-types';\nimport { extractAppConfig } from '../helpers/extract-app-config';\nimport { getInstallationEntry } from '../helpers/get-installation-entry';\nimport { refreshAuthToken } from '../helpers/refresh-auth-token';\n\nexport async function getId(app: FirebaseApp): Promise<string> {\n const appConfig = extractAppConfig(app);\n const { installationEntry, registrationPromise } = await getInstallationEntry(\n appConfig\n );\n\n if (registrationPromise) {\n registrationPromise.catch(console.error);\n } else {\n // If the installation is already registered, update the authentication\n // token if needed.\n refreshAuthToken(appConfig).catch(console.error);\n }\n\n return installationEntry.fid;\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FirebaseApp } from '@firebase/app-types';\nimport { deleteInstallation as deleteInstallationRequest } from '../api/delete-installation';\nimport { extractAppConfig } from '../helpers/extract-app-config';\nimport { remove, update } from '../helpers/idb-manager';\nimport { RequestStatus } from '../interfaces/installation-entry';\nimport { ERROR_FACTORY, ErrorCode } from '../util/errors';\n\nexport async function deleteInstallation(app: FirebaseApp): Promise<void> {\n const appConfig = extractAppConfig(app);\n\n const entry = await update(appConfig, oldEntry => {\n if (oldEntry && oldEntry.registrationStatus === RequestStatus.NOT_STARTED) {\n // Delete the unregistered entry without sending a deleteInstallation request.\n return undefined;\n }\n return oldEntry;\n });\n\n if (entry) {\n if (entry.registrationStatus === RequestStatus.IN_PROGRESS) {\n // Can't delete while trying to register.\n throw ERROR_FACTORY.create(ErrorCode.DELETE_PENDING_REGISTRATION);\n } else if (entry.registrationStatus === RequestStatus.COMPLETED) {\n if (!navigator.onLine) {\n throw ERROR_FACTORY.create(ErrorCode.APP_OFFLINE);\n } else {\n await deleteInstallationRequest(appConfig, entry);\n await remove(appConfig);\n }\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ErrorFactory, ErrorMap } from '@firebase/util';\n\nexport const enum ErrorCode {\n AVAILABLE_IN_WINDOW = 'only-available-in-window',\n AVAILABLE_IN_SW = 'only-available-in-sw',\n SHOULD_BE_INHERITED = 'should-be-overriden',\n BAD_SENDER_ID = 'bad-sender-id',\n PERMISSION_DEFAULT = 'permission-default',\n PERMISSION_BLOCKED = 'permission-blocked',\n UNSUPPORTED_BROWSER = 'unsupported-browser',\n NOTIFICATIONS_BLOCKED = 'notifications-blocked',\n FAILED_DEFAULT_REGISTRATION = 'failed-serviceworker-registration',\n SW_REGISTRATION_EXPECTED = 'sw-registration-expected',\n GET_SUBSCRIPTION_FAILED = 'get-subscription-failed',\n INVALID_SAVED_TOKEN = 'invalid-saved-token',\n SW_REG_REDUNDANT = 'sw-reg-redundant',\n TOKEN_SUBSCRIBE_FAILED = 'token-subscribe-failed',\n TOKEN_SUBSCRIBE_NO_TOKEN = 'token-subscribe-no-token',\n TOKEN_UNSUBSCRIBE_FAILED = 'token-unsubscribe-failed',\n TOKEN_UPDATE_FAILED = 'token-update-failed',\n TOKEN_UPDATE_NO_TOKEN = 'token-update-no-token',\n USE_SW_BEFORE_GET_TOKEN = 'use-sw-before-get-token',\n INVALID_DELETE_TOKEN = 'invalid-delete-token',\n DELETE_TOKEN_NOT_FOUND = 'delete-token-not-found',\n DELETE_SCOPE_NOT_FOUND = 'delete-scope-not-found',\n BG_HANDLER_FUNCTION_EXPECTED = 'bg-handler-function-expected',\n NO_WINDOW_CLIENT_TO_MSG = 'no-window-client-to-msg',\n UNABLE_TO_RESUBSCRIBE = 'unable-to-resubscribe',\n NO_FCM_TOKEN_FOR_RESUBSCRIBE = 'no-fcm-token-for-resubscribe',\n FAILED_TO_DELETE_TOKEN = 'failed-to-delete-token',\n NO_SW_IN_REG = 'no-sw-in-reg',\n BAD_SCOPE = 'bad-scope',\n BAD_VAPID_KEY = 'bad-vapid-key',\n BAD_SUBSCRIPTION = 'bad-subscription',\n BAD_TOKEN = 'bad-token',\n FAILED_DELETE_VAPID_KEY = 'failed-delete-vapid-key',\n INVALID_PUBLIC_VAPID_KEY = 'invalid-public-vapid-key',\n USE_PUBLIC_KEY_BEFORE_GET_TOKEN = 'use-public-key-before-get-token',\n PUBLIC_KEY_DECRYPTION_FAILED = 'public-vapid-key-decryption-failed'\n}\n\nexport const ERROR_MAP: ErrorMap<ErrorCode> = {\n [ErrorCode.AVAILABLE_IN_WINDOW]:\n 'This method is available in a Window context.',\n [ErrorCode.AVAILABLE_IN_SW]:\n 'This method is available in a service worker context.',\n [ErrorCode.SHOULD_BE_INHERITED]:\n 'This method should be overriden by extended classes.',\n [ErrorCode.BAD_SENDER_ID]:\n \"Please ensure that 'messagingSenderId' is set \" +\n 'correctly in the options passed into firebase.initializeApp().',\n [ErrorCode.PERMISSION_DEFAULT]:\n 'The required permissions were not granted and dismissed instead.',\n [ErrorCode.PERMISSION_BLOCKED]:\n 'The required permissions were not granted and blocked instead.',\n [ErrorCode.UNSUPPORTED_BROWSER]:\n \"This browser doesn't support the API's \" +\n 'required to use the firebase SDK.',\n [ErrorCode.NOTIFICATIONS_BLOCKED]: 'Notifications have been blocked.',\n [ErrorCode.FAILED_DEFAULT_REGISTRATION]:\n 'We are unable to register the ' +\n 'default service worker. {$browserErrorMessage}',\n [ErrorCode.SW_REGISTRATION_EXPECTED]:\n 'A service worker registration was the expected input.',\n [ErrorCode.GET_SUBSCRIPTION_FAILED]:\n 'There was an error when trying to get ' +\n 'any existing Push Subscriptions.',\n [ErrorCode.INVALID_SAVED_TOKEN]:\n 'Unable to access details of the saved token.',\n [ErrorCode.SW_REG_REDUNDANT]:\n 'The service worker being used for push was made redundant.',\n [ErrorCode.TOKEN_SUBSCRIBE_FAILED]:\n 'A problem occured while subscribing the user to FCM: {$errorInfo}',\n [ErrorCode.TOKEN_SUBSCRIBE_NO_TOKEN]:\n 'FCM returned no token when subscribing the user to push.',\n [ErrorCode.TOKEN_UNSUBSCRIBE_FAILED]:\n 'A problem occured while unsubscribing the ' +\n 'user from FCM: {$errorInfo}',\n [ErrorCode.TOKEN_UPDATE_FAILED]:\n 'A problem occured while updating the user from FCM: {$errorInfo}',\n [ErrorCode.TOKEN_UPDATE_NO_TOKEN]:\n 'FCM returned no token when updating the user to push.',\n [ErrorCode.USE_SW_BEFORE_GET_TOKEN]:\n 'The useServiceWorker() method may only be called once and must be ' +\n 'called before calling getToken() to ensure your service worker is used.',\n [ErrorCode.INVALID_DELETE_TOKEN]:\n 'You must pass a valid token into ' +\n 'deleteToken(), i.e. the token from getToken().',\n [ErrorCode.DELETE_TOKEN_NOT_FOUND]:\n 'The deletion attempt for token could not ' +\n 'be performed as the token was not found.',\n [ErrorCode.DELETE_SCOPE_NOT_FOUND]:\n 'The deletion attempt for service worker ' +\n 'scope could not be performed as the scope was not found.',\n [ErrorCode.BG_HANDLER_FUNCTION_EXPECTED]:\n 'The input to setBackgroundMessageHandler() must be a function.',\n [ErrorCode.NO_WINDOW_CLIENT_TO_MSG]:\n 'An attempt was made to message a non-existant window client.',\n [ErrorCode.UNABLE_TO_RESUBSCRIBE]:\n 'There was an error while re-subscribing ' +\n 'the FCM token for push messaging. Will have to resubscribe the ' +\n 'user on next visit. {$errorInfo}',\n [ErrorCode.NO_FCM_TOKEN_FOR_RESUBSCRIBE]:\n 'Could not find an FCM token ' +\n 'and as a result, unable to resubscribe. Will have to resubscribe the ' +\n 'user on next visit.',\n [ErrorCode.FAILED_TO_DELETE_TOKEN]:\n 'Unable to delete the currently saved token.',\n [ErrorCode.NO_SW_IN_REG]:\n 'Even though the service worker registration was ' +\n 'successful, there was a problem accessing the service worker itself.',\n [ErrorCode.BAD_SCOPE]:\n 'The service worker scope must be a string with at ' +\n 'least one character.',\n [ErrorCode.BAD_VAPID_KEY]:\n 'The public VAPID key is not a Uint8Array with 65 bytes.',\n [ErrorCode.BAD_SUBSCRIPTION]:\n 'The subscription must be a valid PushSubscription.',\n [ErrorCode.BAD_TOKEN]:\n 'The FCM Token used for storage / lookup was not ' +\n 'a valid token string.',\n [ErrorCode.FAILED_DELETE_VAPID_KEY]: 'The VAPID key could not be deleted.',\n [ErrorCode.INVALID_PUBLIC_VAPID_KEY]:\n 'The public VAPID key must be a string.',\n [ErrorCode.USE_PUBLIC_KEY_BEFORE_GET_TOKEN]:\n 'The usePublicVapidKey() method may only be called once and must be ' +\n 'called before calling getToken() to ensure your VAPID key is used.',\n [ErrorCode.PUBLIC_KEY_DECRYPTION_FAILED]:\n 'The public VAPID key did not equal 65 bytes when decrypted.'\n};\n\ninterface ErrorParams {\n [ErrorCode.FAILED_DEFAULT_REGISTRATION]: { browserErrorMessage: string };\n [ErrorCode.TOKEN_SUBSCRIBE_FAILED]: { errorInfo: string };\n [ErrorCode.TOKEN_UNSUBSCRIBE_FAILED]: { errorInfo: string };\n [ErrorCode.TOKEN_UPDATE_FAILED]: { errorInfo: string };\n [ErrorCode.UNABLE_TO_RESUBSCRIBE]: { errorInfo: string };\n}\n\nexport const errorFactory = new ErrorFactory<ErrorCode, ErrorParams>(\n 'messaging',\n 'Messaging',\n ERROR_MAP\n);\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { MessagePayload } from '../interfaces/message-payload';\n\nexport enum MessageType {\n PUSH_MSG_RECEIVED = 'push-msg-received',\n NOTIFICATION_CLICKED = 'notification-clicked'\n}\n\nexport interface InternalMessage {\n firebaseMessagingType: MessageType;\n firebaseMessagingData: MessagePayload;\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport const DEFAULT_PUBLIC_VAPID_KEY = new Uint8Array([\n 0x04,\n 0x33,\n 0x94,\n 0xf7,\n 0xdf,\n 0xa1,\n 0xeb,\n 0xb1,\n 0xdc,\n 0x03,\n 0xa2,\n 0x5e,\n 0x15,\n 0x71,\n 0xdb,\n 0x48,\n 0xd3,\n 0x2e,\n 0xed,\n 0xed,\n 0xb2,\n 0x34,\n 0xdb,\n 0xb7,\n 0x47,\n 0x3a,\n 0x0c,\n 0x8f,\n 0xc4,\n 0xcc,\n 0xe1,\n 0x6f,\n 0x3c,\n 0x8c,\n 0x84,\n 0xdf,\n 0xab,\n 0xb6,\n 0x66,\n 0x3e,\n 0xf2,\n 0x0c,\n 0xd4,\n 0x8b,\n 0xfe,\n 0xe3,\n 0xf9,\n 0x76,\n 0x2f,\n 0x14,\n 0x1c,\n 0x63,\n 0x08,\n 0x6a,\n 0x6f,\n 0x2d,\n 0xb1,\n 0x1a,\n 0x95,\n 0xb0,\n 0xce,\n 0x37,\n 0xc0,\n 0x9c,\n 0x6e\n]);\n\nexport const SUBSCRIPTION_DETAILS = {\n userVisibleOnly: true,\n applicationServerKey: DEFAULT_PUBLIC_VAPID_KEY\n};\n\nexport const ENDPOINT = 'https://fcmregistrations.googleapis.com/v1';\n\nexport const FN_CAMPAIGN_ID = 'google.c.a.c_id';\nexport const FN_CAMPAIGN_NAME = 'google.c.a.c_l';\nexport const FN_CAMPAIGN_TIME = 'google.c.a.ts';\n/** Set to '1' if Analytics is enabled for the campaign */\nexport const FN_CAMPAIGN_ANALYTICS_ENABLED = 'google.c.a.e';\n","/**\n * @license\n * Copyright 2018 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function isArrayBufferEqual(\n a: ArrayBufferLike | undefined | null,\n b: ArrayBufferLike | undefined | null\n): boolean {\n if (a == null || b == null) {\n return false;\n }\n\n if (a === b) {\n return true;\n }\n\n if (a.byteLength !== b.byteLength) {\n return false;\n }\n\n const viewA = new DataView(a);\n const viewB = new DataView(b);\n\n for (let i = 0; i < a.byteLength; i++) {\n if (viewA.getUint8(i) !== viewB.getUint8(i)) {\n return false;\n }\n }\n\n return true;\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nfunction toBase64(arrayBuffer: ArrayBuffer | Uint8Array): string {\n const uint8Version = new Uint8Array(arrayBuffer);\n return btoa(String.fromCharCode(...uint8Version));\n}\n\nexport function arrayBufferToBase64(\n arrayBuffer: ArrayBuffer | Uint8Array\n): string {\n const base64String = toBase64(arrayBuffer);\n return base64String\n .replace(/=/g, '')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_');\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { arrayBufferToBase64 } from '../helpers/array-buffer-to-base64';\nimport { isArrayBufferEqual } from '../helpers/is-array-buffer-equal';\nimport { ErrorCode, errorFactory } from './errors';\nimport { DEFAULT_PUBLIC_VAPID_KEY, ENDPOINT } from './fcm-details';\nimport { FirebaseApp } from '@firebase/app-types';\nimport '@firebase/installations';\nimport { TokenDetails } from '../interfaces/token-details';\n\ninterface ApiResponse {\n token?: string;\n error?: { message: string };\n}\n\ninterface TokenRequestBody {\n web: {\n endpoint: string;\n p256dh: string;\n auth: string;\n applicationPubKey?: string;\n };\n}\n\nexport class SubscriptionManager {\n async getToken(\n app: FirebaseApp,\n subscription: PushSubscription,\n vapidKey: Uint8Array\n ): Promise<string> {\n const headers = await getHeaders(app);\n const body = getBody(subscription, vapidKey);\n\n const subscribeOptions = {\n method: 'POST',\n headers,\n body: JSON.stringify(body)\n };\n\n let responseData: ApiResponse;\n try {\n const response = await fetch(getEndpoint(app), subscribeOptions);\n responseData = await response.json();\n } catch (err) {\n throw errorFactory.create(ErrorCode.TOKEN_SUBSCRIBE_FAILED, {\n errorInfo: err\n });\n }\n\n if (responseData.error) {\n const message = responseData.error.message;\n throw errorFactory.create(ErrorCode.TOKEN_SUBSCRIBE_FAILED, {\n errorInfo: message\n });\n }\n\n if (!responseData.token) {\n throw errorFactory.create(ErrorCode.TOKEN_SUBSCRIBE_NO_TOKEN);\n }\n\n return responseData.token;\n }\n\n /**\n * Update the underlying token details for fcmToken.\n */\n async updateToken(\n tokenDetails: TokenDetails,\n app: FirebaseApp,\n subscription: PushSubscription,\n vapidKey: Uint8Array\n ): Promise<string> {\n const headers = await getHeaders(app);\n const body = getBody(subscription, vapidKey);\n\n const updateOptions = {\n method: 'PATCH',\n headers,\n body: JSON.stringify(body)\n };\n\n let responseData: ApiResponse;\n try {\n const response = await fetch(\n `${getEndpoint(app)}/${tokenDetails.fcmToken}`,\n updateOptions\n );\n responseData = await response.json();\n } catch (err) {\n throw errorFactory.create(ErrorCode.TOKEN_UPDATE_FAILED, {\n errorInfo: err\n });\n }\n\n if (responseData.error) {\n const message = responseData.error.message;\n throw errorFactory.create(ErrorCode.TOKEN_UPDATE_FAILED, {\n errorInfo: message\n });\n }\n\n if (!responseData.token) {\n throw errorFactory.create(ErrorCode.TOKEN_UPDATE_NO_TOKEN);\n }\n\n return responseData.token;\n }\n\n async deleteToken(\n app: FirebaseApp,\n tokenDetails: TokenDetails\n ): Promise<void> {\n // TODO: Add FIS header\n const headers = await getHeaders(app);\n\n const unsubscribeOptions = {\n method: 'DELETE',\n headers\n };\n\n try {\n const response = await fetch(\n `${getEndpoint(app)}/${tokenDetails.fcmToken}`,\n unsubscribeOptions\n );\n const responseData: ApiResponse = await response.json();\n if (responseData.error) {\n const message = responseData.error.message;\n throw errorFactory.create(ErrorCode.TOKEN_UNSUBSCRIBE_FAILED, {\n errorInfo: message\n });\n }\n } catch (err) {\n throw errorFactory.create(ErrorCode.TOKEN_UNSUBSCRIBE_FAILED, {\n errorInfo: err\n });\n }\n }\n}\n\nfunction getEndpoint(app: FirebaseApp): string {\n return `${ENDPOINT}/projects/${app.options.projectId!}/registrations`;\n}\n\nasync function getHeaders(app: FirebaseApp): Promise<Headers> {\n const installations = app.installations();\n const authToken = await installations.getToken();\n\n return new Headers({\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n 'x-goog-api-key': app.options.apiKey!,\n 'x-goog-firebase-installations-auth': `FIS ${authToken}`\n });\n}\n\nfunction getBody(\n subscription: PushSubscription,\n vapidKey: Uint8Array\n): TokenRequestBody {\n const p256dh = arrayBufferToBase64(subscription.getKey('p256dh')!);\n const auth = arrayBufferToBase64(subscription.getKey('auth')!);\n const body: TokenRequestBody = {\n web: {\n endpoint: subscription.endpoint,\n p256dh,\n auth\n }\n };\n\n if (!isArrayBufferEqual(vapidKey.buffer, DEFAULT_PUBLIC_VAPID_KEY.buffer)) {\n body.web.applicationPubKey = arrayBufferToBase64(vapidKey);\n }\n\n return body;\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function base64ToArrayBuffer(base64String: string): Uint8Array {\n const padding = '='.repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding)\n .replace(/\\-/g, '+')\n .replace(/_/g, '/');\n\n const rawData = atob(base64);\n const outputArray = new Uint8Array(rawData.length);\n\n for (let i = 0; i < rawData.length; ++i) {\n outputArray[i] = rawData.charCodeAt(i);\n }\n return outputArray;\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * There seems to have been a bug in the messaging SDK versions <= 4.9.x\n * where the IndexedDB model was using a database name of 'undefined'.\n *\n * In 4.10.x we changed the model implementation, but kept the database\n * name as it should have been. This however introduced an issue where\n * two tokens were pointing to the same underlying PushSubscription.\n *\n * This code will look for the undefined database and delete any of the\n * underlying tokens.\n */\n\nimport { SubscriptionManager } from './subscription-manager';\nimport { FirebaseApp } from '@firebase/app-types';\n\nconst OLD_DB_NAME = 'undefined';\nconst OLD_OBJECT_STORE_NAME = 'fcm_token_object_Store';\n\nfunction handleDb(db: IDBDatabase, app: FirebaseApp): void {\n if (!db.objectStoreNames.contains(OLD_OBJECT_STORE_NAME)) {\n // We found a database with the name 'undefined', but our expected object\n // store isn't defined.\n return;\n }\n\n const transaction = db.transaction(OLD_OBJECT_STORE_NAME);\n const objectStore = transaction.objectStore(OLD_OBJECT_STORE_NAME);\n\n const subscriptionManager = new SubscriptionManager();\n\n const openCursorRequest: IDBRequest = objectStore.openCursor();\n openCursorRequest.onerror = event => {\n // NOOP - Nothing we can do.\n console.warn('Unable to cleanup old IDB.', event);\n };\n\n openCursorRequest.onsuccess = () => {\n const cursor = openCursorRequest.result;\n if (cursor) {\n // cursor.value contains the current record being iterated through\n // this is where you'd do something with the result\n const tokenDetails = cursor.value;\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n subscriptionManager.deleteToken(app, tokenDetails);\n\n cursor.continue();\n } else {\n db.close();\n indexedDB.deleteDatabase(OLD_DB_NAME);\n }\n };\n}\n\nexport function cleanV1(app: FirebaseApp): void {\n const request: IDBOpenDBRequest = indexedDB.open(OLD_DB_NAME);\n request.onerror = _event => {\n // NOOP - Nothing we can do.\n };\n request.onsuccess = _event => {\n const db = request.result;\n handleDb(db, app);\n };\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport abstract class DbInterface {\n private dbPromise: Promise<IDBDatabase> | null = null;\n\n protected abstract readonly dbName: string;\n protected abstract readonly dbVersion: number;\n protected abstract readonly objectStoreName: string;\n\n /**\n * Database initialization.\n *\n * This function should create and update object stores.\n */\n protected abstract onDbUpgrade(\n request: IDBOpenDBRequest,\n event: IDBVersionChangeEvent\n ): void;\n\n /** Gets record(s) from the objectStore that match the given key. */\n get<T>(key: IDBValidKey): Promise<T | undefined> {\n return this.createTransaction(objectStore => objectStore.get(key));\n }\n\n /** Gets record(s) from the objectStore that match the given index. */\n getIndex<T>(index: string, key: IDBValidKey): Promise<T | undefined> {\n function runRequest(objectStore: IDBObjectStore): IDBRequest {\n const idbIndex = objectStore.index(index);\n return idbIndex.get(key);\n }\n\n return this.createTransaction(runRequest);\n }\n\n /** Assigns or overwrites the record for the given value. */\n // IndexedDB values are of type \"any\"\n put(value: unknown): Promise<void> {\n return this.createTransaction(\n objectStore => objectStore.put(value),\n 'readwrite'\n );\n }\n\n /** Deletes record(s) from the objectStore that match the given key. */\n delete(key: IDBValidKey | IDBKeyRange): Promise<void> {\n return this.createTransaction(\n objectStore => objectStore.delete(key),\n 'readwrite'\n );\n }\n\n /**\n * Close the currently open database.\n */\n async closeDatabase(): Promise<void> {\n if (this.dbPromise) {\n const db = await this.dbPromise;\n db.close();\n this.dbPromise = null;\n }\n }\n\n /**\n * Creates an IndexedDB Transaction and passes its objectStore to the\n * runRequest function, which runs the database request.\n *\n * @return Promise that resolves with the result of the runRequest function\n */\n private async createTransaction<T>(\n runRequest: (objectStore: IDBObjectStore) => IDBRequest,\n mode: 'readonly' | 'readwrite' = 'readonly'\n ): Promise<T> {\n const db = await this.getDb();\n const transaction = db.transaction(this.objectStoreName, mode);\n const request = transaction.objectStore(this.objectStoreName);\n const result = await promisify<T>(runRequest(request));\n\n return new Promise<T>((resolve, reject) => {\n transaction.oncomplete = () => {\n resolve(result);\n };\n transaction.onerror = () => {\n reject(transaction.error);\n };\n });\n }\n\n /** Gets the cached db connection or opens a new one. */\n private getDb(): Promise<IDBDatabase> {\n if (!this.dbPromise) {\n this.dbPromise = new Promise<IDBDatabase>((resolve, reject) => {\n const request = indexedDB.open(this.dbName, this.dbVersion);\n request.onsuccess = () => {\n resolve(request.result);\n };\n request.onerror = () => {\n this.dbPromise = null;\n reject(request.error);\n };\n request.onupgradeneeded = event => this.onDbUpgrade(request, event);\n });\n }\n\n return this.dbPromise;\n }\n}\n\n/** Promisifies an IDBRequest. Resolves with the IDBRequest's result. */\nfunction promisify<T>(request: IDBRequest): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n request.onsuccess = () => {\n resolve(request.result);\n };\n request.onerror = () => {\n reject(request.error);\n };\n });\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { base64ToArrayBuffer } from '../helpers/base64-to-array-buffer';\nimport { TokenDetails } from '../interfaces/token-details';\nimport { cleanV1 } from './clean-v1-undefined';\nimport { DbInterface } from './db-interface';\nimport { ErrorCode, errorFactory } from './errors';\nimport { FirebaseApp } from '@firebase/app-types';\n\nexport class TokenDetailsModel extends DbInterface {\n protected readonly dbName: string = 'fcm_token_details_db';\n protected readonly dbVersion: number = 4;\n protected readonly objectStoreName: string = 'fcm_token_object_Store';\n\n constructor(private readonly app: FirebaseApp) {\n super();\n }\n\n protected onDbUpgrade(\n request: IDBOpenDBRequest,\n event: IDBVersionChangeEvent\n ): void {\n const db: IDBDatabase = request.result;\n\n // Lack of 'break' statements is intentional.\n switch (event.oldVersion) {\n case 0: {\n // New IDB instance\n const objectStore = db.createObjectStore(this.objectStoreName, {\n keyPath: 'swScope'\n });\n\n // Make sure the sender ID can be searched\n objectStore.createIndex('fcmSenderId', 'fcmSenderId', {\n unique: false\n });\n\n objectStore.createIndex('fcmToken', 'fcmToken', { unique: true });\n }\n\n case 1: {\n // Prior to version 2, we were using either 'fcm_token_details_db'\n // or 'undefined' as the database name due to bug in the SDK\n // So remove the old tokens and databases.\n cleanV1(this.app);\n }\n\n case 2: {\n // Update from v2 to v4 directly in a single openCursor request.\n // We need to do this because for some reason, doing a subsequent update on the same data\n // in the same transaction drops the first update.\n const objectStore = request.transaction!.objectStore(\n this.objectStoreName\n );\n const cursorRequest = objectStore.openCursor();\n cursorRequest.onsuccess = () => {\n const cursor: IDBCursorWithValue | null = cursorRequest.result;\n if (cursor) {\n const value = cursor.value;\n const newValue = { ...value };\n\n if (!value.createTime) {\n newValue.createTime = Date.now();\n }\n\n if (typeof value.vapidKey === 'string') {\n newValue.vapidKey = base64ToArrayBuffer(value.vapidKey);\n }\n\n if (typeof value.auth === 'string') {\n newValue.auth = base64ToArrayBuffer(value.auth).buffer;\n }\n\n if (typeof value.auth === 'string') {\n newValue.p256dh = base64ToArrayBuffer(value.p256dh).buffer;\n }\n\n if (typeof value.fcmPushSet === 'string') {\n delete newValue.fcmPushSet;\n }\n\n cursor.update(newValue);\n cursor.continue();\n }\n };\n // Break here as we've already updated to v4.\n break;\n }\n\n case 3: {\n // Update from V3 to V4.\n const objectStore = request.transaction!.objectStore(\n this.objectStoreName\n );\n const cursorRequest = objectStore.openCursor();\n cursorRequest.onsuccess = () => {\n const cursor: IDBCursorWithValue | null = cursorRequest.result;\n if (cursor) {\n const value = cursor.value;\n const newValue = { ...value };\n\n if (typeof value.fcmPushSet === 'string') {\n delete newValue.fcmPushSet;\n }\n\n cursor.update(newValue);\n cursor.continue();\n }\n };\n }\n\n default: // ignore\n }\n }\n\n /**\n * Given a token, this method will look up the details in indexedDB.\n */\n async getTokenDetailsFromToken(\n fcmToken: string\n ): Promise<TokenDetails | undefined> {\n if (!fcmToken) {\n throw errorFactory.create(ErrorCode.BAD_TOKEN);\n }\n\n validateInputs({ fcmToken });\n\n return this.getIndex<TokenDetails>('fcmToken', fcmToken);\n }\n\n /**\n * Given a service worker scope, this method will look up the details in\n * indexedDB.\n * @return The details associated with that token.\n */\n async getTokenDetailsFromSWScope(\n swScope: string\n ): Promise<TokenDetails | undefined> {\n if (!swScope) {\n throw errorFactory.create(ErrorCode.BAD_SCOPE);\n }\n\n validateInputs({ swScope });\n\n return this.get<TokenDetails>(swScope);\n }\n\n /**\n * Save the details for the fcm token for re-use at a later date.\n * @param input A plain js object containing args to save.\n */\n async saveTokenDetails(tokenDetails: TokenDetails): Promise<void> {\n if (!tokenDetails.swScope) {\n throw errorFactory.create(ErrorCode.BAD_SCOPE);\n }\n\n if (!tokenDetails.vapidKey) {\n throw errorFactory.create(ErrorCode.BAD_VAPID_KEY);\n }\n\n if (!tokenDetails.endpoint || !tokenDetails.auth || !tokenDetails.p256dh) {\n throw errorFactory.create(ErrorCode.BAD_SUBSCRIPTION);\n }\n\n if (!tokenDetails.fcmSenderId) {\n throw errorFactory.create(ErrorCode.BAD_SENDER_ID);\n }\n\n if (!tokenDetails.fcmToken) {\n throw errorFactory.create(ErrorCode.BAD_TOKEN);\n }\n\n validateInputs(tokenDetails);\n\n return this.put(tokenDetails);\n }\n\n /**\n * This method deletes details of the current FCM token.\n * It's returning a promise in case we need to move to an async\n * method for deleting at a later date.\n *\n * @return Resolves once the FCM token details have been deleted and returns\n * the deleted details.\n */\n async deleteToken(token: string): Promise<TokenDetails> {\n if (typeof token !== 'string' || token.length === 0) {\n return Promise.reject(\n errorFactory.create(ErrorCode.INVALID_DELETE_TOKEN)\n );\n }\n\n const details = await this.getTokenDetailsFromToken(token);\n if (!details) {\n throw errorFactory.create(ErrorCode.DELETE_TOKEN_NOT_FOUND);\n }\n\n await this.delete(details.swScope);\n return details;\n }\n}\n\n/**\n * This method takes an object and will check for known arguments and\n * validate the input.\n * @return Promise that resolves if input is valid, rejects otherwise.\n */\nfunction validateInputs(input: Partial<TokenDetails>): void {\n if (input.fcmToken) {\n if (typeof input.fcmToken !== 'string' || input.fcmToken.length === 0) {\n throw errorFactory.create(ErrorCode.BAD_TOKEN);\n }\n }\n\n if (input.swScope) {\n if (typeof input.swScope !== 'string' || input.swScope.length === 0) {\n throw errorFactory.create(ErrorCode.BAD_SCOPE);\n }\n }\n\n if (input.vapidKey) {\n if (\n !(input.vapidKey instanceof Uint8Array) ||\n input.vapidKey.length !== 65\n ) {\n throw errorFactory.create(ErrorCode.BAD_VAPID_KEY);\n }\n }\n\n if (input.endpoint) {\n if (typeof input.endpoint !== 'string' || input.endpoint.length === 0) {\n throw errorFactory.create(ErrorCode.BAD_SUBSCRIPTION);\n }\n }\n\n if (input.auth) {\n if (!(input.auth instanceof ArrayBuffer)) {\n throw errorFactory.create(ErrorCode.BAD_SUBSCRIPTION);\n }\n }\n\n if (input.p256dh) {\n if (!(input.p256dh instanceof ArrayBuffer)) {\n throw errorFactory.create(ErrorCode.BAD_SUBSCRIPTION);\n }\n }\n\n if (input.fcmSenderId) {\n if (\n typeof input.fcmSenderId !== 'string' ||\n input.fcmSenderId.length === 0\n ) {\n throw errorFactory.create(ErrorCode.BAD_SENDER_ID);\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { VapidDetails } from '../interfaces/vapid-details';\nimport { DbInterface } from './db-interface';\nimport { ErrorCode, errorFactory } from './errors';\n\nconst UNCOMPRESSED_PUBLIC_KEY_SIZE = 65;\n\nexport class VapidDetailsModel extends DbInterface {\n protected readonly dbName: string = 'fcm_vapid_details_db';\n protected readonly dbVersion: number = 1;\n protected readonly objectStoreName: string = 'fcm_vapid_object_Store';\n\n protected onDbUpgrade(request: IDBOpenDBRequest): void {\n const db: IDBDatabase = request.result;\n db.createObjectStore(this.objectStoreName, { keyPath: 'swScope' });\n }\n\n /**\n * Given a service worker scope, this method will look up the vapid key\n * in indexedDB.\n */\n async getVapidFromSWScope(swScope: string): Promise<Uint8Array | undefined> {\n if (typeof swScope !== 'string' || swScope.length === 0) {\n throw errorFactory.create(ErrorCode.BAD_SCOPE);\n }\n\n const result = await this.get<VapidDetails>(swScope);\n return result ? result.vapidKey : undefined;\n }\n\n /**\n * Save a vapid key against a swScope for later date.\n */\n async saveVapidDetails(swScope: string, vapidKey: Uint8Array): Promise<void> {\n if (typeof swScope !== 'string' || swScope.length === 0) {\n throw errorFactory.create(ErrorCode.BAD_SCOPE);\n }\n\n if (vapidKey === null || vapidKey.length !== UNCOMPRESSED_PUBLIC_KEY_SIZE) {\n throw errorFactory.create(ErrorCode.BAD_VAPID_KEY);\n }\n\n const details: VapidDetails = {\n swScope,\n vapidKey\n };\n\n return this.put(details);\n }\n\n /**\n * This method deletes details of the current FCM VAPID key for a SW scope.\n * Resolves once the scope/vapid details have been deleted and returns the\n * deleted vapid key.\n */\n async deleteVapidDetails(swScope: string): Promise<Uint8Array> {\n const vapidKey = await this.getVapidFromSWScope(swScope);\n if (!vapidKey) {\n throw errorFactory.create(ErrorCode.DELETE_SCOPE_NOT_FOUND);\n }\n\n await this.delete(swScope);\n return vapidKey;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FirebaseApp } from '@firebase/app-types';\nimport { FirebaseServiceInternals } from '@firebase/app-types/private';\nimport { FirebaseMessaging } from '@firebase/messaging-types';\nimport {\n CompleteFn,\n ErrorFn,\n NextFn,\n Observer,\n Unsubscribe\n} from '@firebase/util';\n\nimport { isArrayBufferEqual } from '../helpers/is-array-buffer-equal';\nimport { MessagePayload } from '../interfaces/message-payload';\nimport { TokenDetails } from '../interfaces/token-details';\nimport { ErrorCode, errorFactory } from '../models/errors';\nimport { SubscriptionManager } from '../models/subscription-manager';\nimport { TokenDetailsModel } from '../models/token-details-model';\nimport { VapidDetailsModel } from '../models/vapid-details-model';\n\nexport type BgMessageHandler = (\n payload: MessagePayload\n) => Promise<unknown> | void;\n\n// Token should be refreshed once a week.\nexport const TOKEN_EXPIRATION_MILLIS = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nexport abstract class BaseController implements FirebaseMessaging {\n INTERNAL: FirebaseServiceInternals;\n private readonly tokenDetailsModel: TokenDetailsModel;\n private readonly vapidDetailsModel = new VapidDetailsModel();\n private readonly subscriptionManager = new SubscriptionManager();\n\n constructor(readonly app: FirebaseApp) {\n if (\n !app.options.messagingSenderId ||\n typeof app.options.messagingSenderId !== 'string'\n ) {\n throw errorFactory.create(ErrorCode.BAD_SENDER_ID);\n }\n\n this.INTERNAL = {\n delete: () => this.delete()\n };\n\n this.tokenDetailsModel = new TokenDetailsModel(app);\n }\n\n async getToken(): Promise<string | null> {\n // Check with permissions\n const currentPermission = this.getNotificationPermission_();\n if (currentPermission === 'denied') {\n throw errorFactory.create(ErrorCode.NOTIFICATIONS_BLOCKED);\n } else if (currentPermission !== 'granted') {\n // We must wait for permission to be granted\n return null;\n }\n\n const swReg = await this.getSWRegistration_();\n const publicVapidKey = await this.getPublicVapidKey_();\n // If a PushSubscription exists it's returned, otherwise a new subscription\n // is generated and returned.\n const pushSubscription = await this.getPushSubscription(\n swReg,\n publicVapidKey\n );\n const tokenDetails = await this.tokenDetailsModel.getTokenDetailsFromSWScope(\n swReg.scope\n );\n\n if (tokenDetails) {\n return this.manageExistingToken(\n swReg,\n pushSubscription,\n publicVapidKey,\n tokenDetails\n );\n }\n return this.getNewToken(swReg, pushSubscription, publicVapidKey);\n }\n\n /**\n * manageExistingToken is triggered if there's an existing FCM token in the\n * database and it can take 3 different actions:\n * 1) Retrieve the existing FCM token from the database.\n * 2) If VAPID details have changed: Delete the existing token and create a\n * new one with the new VAPID key.\n * 3) If the database cache is invalidated: Send a request to FCM to update\n * the token, and to check if the token is still valid on FCM-side.\n */\n private async manageExistingToken(\n swReg: ServiceWorkerRegistration,\n pushSubscription: PushSubscription,\n publicVapidKey: Uint8Array,\n tokenDetails: TokenDetails\n ): Promise<string> {\n const isTokenValid = isTokenStillValid(\n pushSubscription,\n publicVapidKey,\n tokenDetails\n );\n\n if (isTokenValid) {\n const now = Date.now();\n if (now < tokenDetails.createTime + TOKEN_EXPIRATION_MILLIS) {\n return tokenDetails.fcmToken;\n } else {\n return this.updateToken(\n swReg,\n pushSubscription,\n publicVapidKey,\n tokenDetails\n );\n }\n } else {\n // If the token is no longer valid (for example if the VAPID details\n // have changed), delete the existing token from the FCM client and server\n // database. No need to unsubscribe from the Service Worker as we have a\n // good push subscription that we'd like to use in getNewToken.\n await this.deleteTokenFromDB(tokenDetails.fcmToken);\n return this.getNewToken(swReg, pushSubscription, publicVapidKey);\n }\n }\n\n private async updateToken(\n swReg: ServiceWorkerRegistration,\n pushSubscription: PushSubscription,\n publicVapidKey: Uint8Array,\n tokenDetails: TokenDetails\n ): Promise<string> {\n try {\n const updatedToken = await this.subscriptionManager.updateToken(\n tokenDetails,\n this.app,\n pushSubscription,\n publicVapidKey\n );\n\n const allDetails: TokenDetails = {\n swScope: swReg.scope,\n vapidKey: publicVapidKey,\n fcmSenderId: this.app.options.messagingSenderId!,\n fcmToken: updatedToken,\n createTime: Date.now(),\n endpoint: pushSubscription.endpoint,\n auth: pushSubscription.getKey('auth')!,\n p256dh: pushSubscription.getKey('p256dh')!\n };\n\n await this.tokenDetailsModel.saveTokenDetails(allDetails);\n await this.vapidDetailsModel.saveVapidDetails(\n swReg.scope,\n publicVapidKey\n );\n return updatedToken;\n } catch (e) {\n await this.deleteToken(tokenDetails.fcmToken);\n throw e;\n }\n }\n\n private async getNewToken(\n swReg: ServiceWorkerRegistration,\n pushSubscription: PushSubscription,\n publicVapidKey: Uint8Array\n ): Promise<string> {\n const newToken = await this.subscriptionManager.getToken(\n this.app,\n pushSubscription,\n publicVapidKey\n );\n const allDetails: TokenDetails = {\n swScope: swReg.scope,\n vapidKey: publicVapidKey,\n fcmSenderId: this.app.options.messagingSenderId!,\n fcmToken: newToken,\n createTime: Date.now(),\n endpoint: pushSubscription.endpoint,\n auth: pushSubscription.getKey('auth')!,\n p256dh: pushSubscription.getKey('p256dh')!\n };\n await this.tokenDetailsModel.saveTokenDetails(allDetails);\n await this.vapidDetailsModel.saveVapidDetails(swReg.scope, publicVapidKey);\n return newToken;\n }\n\n /**\n * This method deletes tokens that the token manager looks after,\n * unsubscribes the token from FCM and then unregisters the push\n * subscription if it exists. It returns a promise that indicates\n * whether or not the unsubscribe request was processed successfully.\n */\n async deleteToken(token: string): Promise<boolean> {\n // Delete the token details from the database.\n await this.deleteTokenFromDB(token);\n // Unsubscribe from the SW.\n const registration = await this.getSWRegistration_();\n if (registration) {\n const pushSubscription = await registration.pushManager.getSubscription();\n if (pushSubscription) {\n return pushSubscription.unsubscribe();\n }\n }\n // If there's no SW, consider it a success.\n return true;\n }\n\n /**\n * This method will delete the token from the client database, and make a\n * call to FCM to remove it from the server DB. Does not temper with the\n * push subscription.\n */\n private async deleteTokenFromDB(token: string): Promise<void> {\n const tokenDetails = await this.tokenDetailsModel.deleteToken(token);\n await this.subscriptionManager.deleteToken(this.app, tokenDetails);\n }\n\n // Visible for testing\n // TODO: Make protected\n abstract getSWRegistration_(): Promise<ServiceWorkerRegistration>;\n\n // Visible for testing\n // TODO: Make protected\n abstract getPublicVapidKey_(): Promise<Uint8Array>;\n\n /**\n * Gets a PushSubscription for the current user.\n */\n async getPushSubscription(\n swRegistration: ServiceWorkerRegistration,\n publicVapidKey: Uint8Array\n ): Promise<PushSubscription> {\n const subscription = await swRegistration.pushManager.getSubscription();\n if (subscription) {\n return subscription;\n }\n return swRegistration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey: publicVapidKey\n });\n }\n\n //\n // The following methods should only be available in the window.\n //\n\n /**\n * @deprecated Use Notification.requestPermission() instead.\n * https://developer.mozilla.org/en-US/docs/Web/API/Notification/requestPermission\n */\n requestPermission(): Promise<void> {\n throw errorFactory.create(ErrorCode.AVAILABLE_IN_WINDOW);\n }\n\n useServiceWorker(_registration: ServiceWorkerRegistration): void {\n throw errorFactory.create(ErrorCode.AVAILABLE_IN_WINDOW);\n }\n\n usePublicVapidKey(_b64PublicKey: string): void {\n throw errorFactory.create(ErrorCode.AVAILABLE_IN_WINDOW);\n }\n\n onMessage(\n _nextOrObserver: NextFn<object> | Observer<object>,\n _error?: ErrorFn,\n _completed?: CompleteFn\n ): Unsubscribe {\n throw errorFactory.create(ErrorCode.AVAILABLE_IN_WINDOW);\n }\n\n onTokenRefresh(\n _nextOrObserver: NextFn<object> | Observer<object>,\n _error?: ErrorFn,\n _completed?: CompleteFn\n ): Unsubscribe {\n throw errorFactory.create(ErrorCode.AVAILABLE_IN_WINDOW);\n }\n\n //\n // The following methods are used by the service worker only.\n //\n\n setBackgroundMessageHandler(_callback: BgMessageHandler): void {\n throw errorFactory.create(ErrorCode.AVAILABLE_IN_SW);\n }\n\n //\n // The following methods are used by the service themselves and not exposed\n // publicly or not expected to be used by developers.\n //\n\n /**\n * This method is required to adhere to the Firebase interface.\n * It closes any currently open indexdb database connections.\n */\n async delete(): Promise<void> {\n await Promise.all([\n this.tokenDetailsModel.closeDatabase(),\n this.vapidDetailsModel.closeDatabase()\n ]);\n }\n\n /**\n * Returns the current Notification Permission state.\n */\n getNotificationPermission_(): NotificationPermission {\n return Notification.permission;\n }\n\n getTokenDetailsModel(): TokenDetailsModel {\n return this.tokenDetailsModel;\n }\n\n getVapidDetailsModel(): VapidDetailsModel {\n return this.vapidDetailsModel;\n }\n\n // Visible for testing\n // TODO: make protected\n getSubscriptionManager(): SubscriptionManager {\n return this.subscriptionManager;\n }\n}\n\n/**\n * Checks if the tokenDetails match the details provided in the clients.\n */\nfunction isTokenStillValid(\n pushSubscription: PushSubscription,\n publicVapidKey: Uint8Array,\n tokenDetails: TokenDetails\n): boolean {\n if (\n !tokenDetails.vapidKey ||\n !isArrayBufferEqual(publicVapidKey.buffer, tokenDetails.vapidKey.buffer)\n ) {\n return false;\n }\n\n const isEndpointEqual = pushSubscription.endpoint === tokenDetails.endpoint;\n const isAuthEqual = isArrayBufferEqual(\n pushSubscription.getKey('auth'),\n tokenDetails.auth\n );\n const isP256dhEqual = isArrayBufferEqual(\n pushSubscription.getKey('p256dh'),\n tokenDetails.p256dh\n );\n\n return isEndpointEqual && isAuthEqual && isP256dhEqual;\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport './sw-types';\n\nimport { FirebaseApp } from '@firebase/app-types';\n\nimport {\n MessagePayload,\n NotificationDetails\n} from '../interfaces/message-payload';\nimport { ErrorCode, errorFactory } from '../models/errors';\nimport {\n DEFAULT_PUBLIC_VAPID_KEY,\n FN_CAMPAIGN_ID\n} from '../models/fcm-details';\nimport { InternalMessage, MessageType } from '../models/worker-page-message';\nimport { BaseController, BgMessageHandler } from './base-controller';\n\n// Let TS know that this is a service worker\ndeclare const self: ServiceWorkerGlobalScope;\n\nconst FCM_MSG = 'FCM_MSG';\n\nexport class SwController extends BaseController {\n private bgMessageHandler: BgMessageHandler | null = null;\n\n constructor(app: FirebaseApp) {\n super(app);\n\n self.addEventListener('push', e => {\n this.onPush(e);\n });\n self.addEventListener('pushsubscriptionchange', e => {\n this.onSubChange(e);\n });\n self.addEventListener('notificationclick', e => {\n this.onNotificationClick(e);\n });\n }\n\n // Visible for testing\n // TODO: Make private\n onPush(event: PushEvent): void {\n event.waitUntil(this.onPush_(event));\n }\n\n // Visible for testing\n // TODO: Make private\n onSubChange(event: PushSubscriptionChangeEvent): void {\n event.waitUntil(this.onSubChange_(event));\n }\n\n // Visible for testing\n // TODO: Make private\n onNotificationClick(event: NotificationEvent): void {\n event.waitUntil(this.onNotificationClick_(event));\n }\n\n /**\n * A handler for push events that shows notifications based on the content of\n * the payload.\n *\n * The payload must be a JSON-encoded Object with a `notification` key. The\n * value of the `notification` property will be used as the NotificationOptions\n * object passed to showNotification. Additionally, the `title` property of the\n * notification object will be used as the title.\n *\n * If there is no notification data in the payload then no notification will be\n * shown.\n */\n private async onPush_(event: PushEvent): Promise<void> {\n if (!event.data) {\n return;\n }\n\n let msgPayload: MessagePayload;\n try {\n msgPayload = event.data.json();\n } catch (err) {\n // Not JSON so not an FCM message\n return;\n }\n\n const hasVisibleClients = await this.hasVisibleClients_();\n if (hasVisibleClients) {\n // App in foreground. Send to page.\n return this.sendMessageToWindowClients_(msgPayload);\n }\n\n const notificationDetails = this.getNotificationData_(msgPayload);\n if (notificationDetails) {\n const notificationTitle = notificationDetails.title || '';\n const reg = await this.getSWRegistration_();\n\n const { actions } = notificationDetails;\n const { maxActions } = Notification;\n if (actions && maxActions && actions.length > maxActions) {\n console.warn(\n `This browser only supports ${maxActions} actions.` +\n `The remaining actions will not be displayed.`\n );\n }\n\n return reg.showNotification(notificationTitle, notificationDetails);\n } else if (this.bgMessageHandler) {\n await this.bgMessageHandler(msgPayload);\n return;\n }\n }\n\n private async onSubChange_(\n _event: PushSubscriptionChangeEvent\n ): Promise<void> {\n let registration: ServiceWorkerRegistration;\n try {\n registration = await this.getSWRegistration_();\n } catch (err) {\n throw errorFactory.create(ErrorCode.UNABLE_TO_RESUBSCRIBE, {\n errorInfo: err\n });\n }\n\n try {\n await registration.pushManager.getSubscription();\n // TODO: Check if it's still valid. If not, then update token.\n } catch (err) {\n // The best thing we can do is log this to the terminal so\n // developers might notice the error.\n const tokenDetailsModel = this.getTokenDetailsModel();\n const tokenDetails = await tokenDetailsModel.getTokenDetailsFromSWScope(\n registration.scope\n );\n if (!tokenDetails) {\n // This should rarely occure, but could if indexedDB\n // is corrupted or wiped\n throw err;\n }\n\n // Attempt to delete the token if we know it's bad\n await this.deleteToken(tokenDetails.fcmToken);\n throw err;\n }\n }\n\n private async onNotificationClick_(event: NotificationEvent): Promise<void> {\n if (\n !event.notification ||\n !event.notification.data ||\n !event.notification.data[FCM_MSG]\n ) {\n // Not an FCM notification, do nothing.\n return;\n } else if (event.action) {\n // User clicked on an action button.\n // This will allow devs to act on action button clicks by using a custom\n // onNotificationClick listener that they define.\n return;\n }\n\n // Prevent other listeners from receiving the event\n event.stopImmediatePropagation();\n event.notification.close();\n\n const msgPayload: MessagePayload = event.notification.data[FCM_MSG];\n if (!msgPayload.notification) {\n // Nothing to do.\n return;\n }\n\n let link =\n (msgPayload.fcmOptions && msgPayload.fcmOptions.link) ||\n msgPayload.notification.click_action;\n if (!link) {\n if (msgPayload.data && FN_CAMPAIGN_ID in msgPayload.data) {\n link = self.location.origin;\n } else {\n // Nothing to do.\n return;\n }\n }\n\n let windowClient = await this.getWindowClient_(link);\n if (!windowClient) {\n // Unable to find window client so need to open one.\n windowClient = await self.clients.openWindow(link);\n // Wait three seconds for the client to initialize and set up the message\n // handler so that it can receive the message.\n await sleep(3000);\n } else {\n windowClient = await windowClient.focus();\n }\n\n if (!windowClient) {\n // Window Client will not be returned if it's for a third party origin.\n return;\n }\n\n // Delete notification and fcmOptions data from payload before sending to\n // the page.\n delete msgPayload.notification;\n delete msgPayload.fcmOptions;\n\n const internalMsg = createNewMsg(\n MessageType.NOTIFICATION_CLICKED,\n msgPayload\n );\n\n // Attempt to send a message to the client to handle the data\n // Is affected by: https://github.com/slightlyoff/ServiceWorker/issues/728\n return this.attemptToMessageClient_(windowClient, internalMsg);\n }\n\n // Visible for testing\n // TODO: Make private\n getNotificationData_(\n msgPayload: MessagePayload\n ): NotificationDetails | undefined {\n if (!msgPayload) {\n return;\n }\n\n if (typeof msgPayload.notification !== 'object') {\n return;\n }\n\n const notificationInformation: NotificationDetails = {\n ...msgPayload.notification\n };\n\n // Put the message payload under FCM_MSG name so we can identify the\n // notification as being an FCM notification vs a notification from\n // somewhere else (i.e. normal web push or developer generated\n // notification).\n notificationInformation.data = {\n ...msgPayload.notification.data,\n [FCM_MSG]: msgPayload\n };\n\n return notificationInformation;\n }\n\n /**\n * Calling setBackgroundMessageHandler will opt in to some specific\n * behaviours.\n * 1.) If a notification doesn't need to be shown due to a window already\n * being visible, then push messages will be sent to the page.\n * 2.) If a notification needs to be shown, and the message contains no\n * notification data this method will be called\n * and the promise it returns will be passed to event.waitUntil.\n * If you do not set this callback then all push messages will let and the\n * developer can handle them in a their own 'push' event callback\n *\n * @param callback The callback to be called when a push message is received\n * and a notification must be shown. The callback will be given the data from\n * the push message.\n */\n setBackgroundMessageHandler(callback: BgMessageHandler): void {\n if (!callback || typeof callback !== 'function') {\n throw errorFactory.create(ErrorCode.BG_HANDLER_FUNCTION_EXPECTED);\n }\n\n this.bgMessageHandler = callback;\n }\n\n /**\n * @param url The URL to look for when focusing a client.\n * @return Returns an existing window client or a newly opened WindowClient.\n */\n // Visible for testing\n // TODO: Make private\n async getWindowClient_(url: string): Promise<WindowClient | null> {\n // Use URL to normalize the URL when comparing to windowClients.\n // This at least handles whether to include trailing slashes or not\n const parsedURL = new URL(url, self.location.href).href;\n\n const clientList = await getClientList();\n\n let suitableClient: WindowClient | null = null;\n for (let i = 0; i < clientList.length; i++) {\n const parsedClientUrl = new URL(clientList[i].url, self.location.href)\n .href;\n if (parsedClientUrl === parsedURL) {\n suitableClient = clientList[i];\n break;\n }\n }\n\n return suitableClient;\n }\n\n /**\n * This message will attempt to send the message to a window client.\n * @param client The WindowClient to send the message to.\n * @param message The message to send to the client.\n * @returns Returns a promise that resolves after sending the message. This\n * does not guarantee that the message was successfully received.\n */\n // Visible for testing\n // TODO: Make private\n async attemptToMessageClient_(\n client: WindowClient,\n message: InternalMessage\n ): Promise<void> {\n // NOTE: This returns a promise in case this API is abstracted later on to\n // do additional work\n if (!client) {\n throw errorFactory.create(ErrorCode.NO_WINDOW_CLIENT_TO_MSG);\n }\n\n client.postMessage(message);\n }\n\n /**\n * @returns If there is currently a visible WindowClient, this method will\n * resolve to true, otherwise false.\n */\n // Visible for testing\n // TODO: Make private\n async hasVisibleClients_(): Promise<boolean> {\n const clientList = await getClientList();\n\n return clientList.some(\n (client: WindowClient) =>\n client.visibilityState === 'visible' &&\n // Ignore chrome-extension clients as that matches the background pages\n // of extensions, which are always considered visible.\n !client.url.startsWith('chrome-extension://')\n );\n }\n\n /**\n * @param msgPayload The data from the push event that should be sent to all\n * available pages.\n * @returns Returns a promise that resolves once the message has been sent to\n * all WindowClients.\n */\n // Visible for testing\n // TODO: Make private\n async sendMessageToWindowClients_(msgPayload: MessagePayload): Promise<void> {\n const clientList = await getClientList();\n\n const internalMsg = createNewMsg(MessageType.PUSH_MSG_RECEIVED, msgPayload);\n\n await Promise.all(\n clientList.map(client =>\n this.attemptToMessageClient_(client, internalMsg)\n )\n );\n }\n\n /**\n * This will register the default service worker and return the registration.\n * @return he service worker registration to be used for the push service.\n */\n async getSWRegistration_(): Promise<ServiceWorkerRegistration> {\n return self.registration;\n }\n\n /**\n * This will return the default VAPID key or the uint8array version of the\n * public VAPID key provided by the developer.\n */\n async getPublicVapidKey_(): Promise<Uint8Array> {\n const swReg = await this.getSWRegistration_();\n if (!swReg) {\n throw errorFactory.create(ErrorCode.SW_REGISTRATION_EXPECTED);\n }\n\n const vapidKeyFromDatabase = await this.getVapidDetailsModel().getVapidFromSWScope(\n swReg.scope\n );\n if (vapidKeyFromDatabase == null) {\n return DEFAULT_PUBLIC_VAPID_KEY;\n }\n\n return vapidKeyFromDatabase;\n }\n}\n\nfunction getClientList(): Promise<WindowClient[]> {\n return self.clients.matchAll({\n type: 'window',\n includeUncontrolled: true\n // TS doesn't know that \"type: 'window'\" means it'll return WindowClient[]\n }) as Promise<WindowClient[]>;\n}\n\nfunction createNewMsg(\n msgType: MessageType,\n msgData: MessagePayload\n): InternalMessage {\n return {\n firebaseMessagingType: msgType,\n firebaseMessagingData: msgData\n };\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise<void>(resolve => {\n setTimeout(resolve, ms);\n });\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport const DEFAULT_SW_PATH = '/firebase-messaging-sw.js';\nexport const DEFAULT_SW_SCOPE = '/firebase-cloud-messaging-push-scope';\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport firebase from '@firebase/app';\nimport {\n _FirebaseNamespace,\n FirebaseServiceFactory\n} from '@firebase/app-types/private';\nimport { FirebaseMessaging } from '@firebase/messaging-types';\n\nimport { SwController } from './src/controllers/sw-controller';\nimport { WindowController } from './src/controllers/window-controller';\nimport { ErrorCode, errorFactory } from './src/models/errors';\n\nexport function registerMessaging(instance: _FirebaseNamespace): void {\n const messagingName = 'messaging';\n\n const factoryMethod: FirebaseServiceFactory = app => {\n if (!isSupported()) {\n throw errorFactory.create(ErrorCode.UNSUPPORTED_BROWSER);\n }\n\n if (self && 'ServiceWorkerGlobalScope' in self) {\n // Running in ServiceWorker context\n return new SwController(app);\n } else {\n // Assume we are in the window context.\n return new WindowController(app);\n }\n };\n\n const namespaceExports = {\n isSupported\n };\n\n instance.INTERNAL.registerService(\n messagingName,\n factoryMethod,\n namespaceExports\n );\n}\n\nregisterMessaging(firebase as _FirebaseNamespace);\n\n/**\n * Define extension behavior of `registerMessaging`\n */\ndeclare module '@firebase/app-types' {\n interface FirebaseNamespace {\n messaging: {\n (app?: FirebaseApp): FirebaseMessaging;\n isSupported(): boolean;\n };\n }\n interface FirebaseApp {\n messaging(): FirebaseMessaging;\n }\n}\n\nexport function isSupported(): boolean {\n if (self && 'ServiceWorkerGlobalScope' in self) {\n // Running in ServiceWorker context\n return isSWControllerSupported();\n } else {\n // Assume we are in the window context.\n return isWindowControllerSupported();\n }\n}\n\n/**\n * Checks to see if the required APIs exist.\n */\nfunction isWindowControllerSupported(): boolean {\n return (\n navigator.cookieEnabled &&\n 'serviceWorker' in navigator &&\n 'PushManager' in window &&\n 'Notification' in window &&\n 'fetch' in window &&\n ServiceWorkerRegistration.prototype.hasOwnProperty('showNotification') &&\n PushSubscription.prototype.hasOwnProperty('getKey')\n );\n}\n\n/**\n * Checks to see if the required APIs exist within SW Context.\n */\nfunction isSWControllerSupported(): boolean {\n return (\n 'PushManager' in self &&\n 'Notification' in self &&\n ServiceWorkerRegistration.prototype.hasOwnProperty('showNotification') &&\n PushSubscription.prototype.hasOwnProperty('getKey')\n );\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FirebaseApp } from '@firebase/app-types';\nimport { _FirebaseApp } from '@firebase/app-types/private';\nimport {\n CompleteFn,\n createSubscribe,\n ErrorFn,\n NextFn,\n Observer,\n Subscribe,\n Unsubscribe\n} from '@firebase/util';\n\nimport { base64ToArrayBuffer } from '../helpers/base64-to-array-buffer';\nimport { DEFAULT_SW_PATH, DEFAULT_SW_SCOPE } from '../models/default-sw';\nimport { ErrorCode, errorFactory } from '../models/errors';\nimport {\n DEFAULT_PUBLIC_VAPID_KEY,\n FN_CAMPAIGN_ID,\n FN_CAMPAIGN_NAME,\n FN_CAMPAIGN_TIME,\n FN_CAMPAIGN_ANALYTICS_ENABLED\n} from '../models/fcm-details';\nimport { InternalMessage, MessageType } from '../models/worker-page-message';\nimport { BaseController } from './base-controller';\n\nexport class WindowController extends BaseController {\n private registrationToUse: ServiceWorkerRegistration | null = null;\n private publicVapidKeyToUse: Uint8Array | null = null;\n\n private messageObserver: Observer<object> | null = null;\n // @ts-ignore: Unused variable error, this is not implemented yet.\n private tokenRefreshObserver: Observer<object> | null = null;\n\n private readonly onMessageInternal: Subscribe<object> = createSubscribe(\n observer => {\n this.messageObserver = observer;\n }\n );\n\n private readonly onTokenRefreshInternal: Subscribe<object> = createSubscribe(\n observer => {\n this.tokenRefreshObserver = observer;\n }\n );\n\n /**\n * A service that provides a MessagingService instance.\n */\n constructor(app: FirebaseApp) {\n super(app);\n\n this.setupSWMessageListener_();\n }\n\n /**\n * Request permission if it is not currently granted\n *\n * @return Resolves if the permission was granted, otherwise rejects\n *\n * @deprecated Use Notification.requestPermission() instead.\n * https://developer.mozilla.org/en-US/docs/Web/API/Notification/requestPermission\n */\n async requestPermission(): Promise<void> {\n if (this.getNotificationPermission_() === 'granted') {\n return;\n }\n\n const permissionResult = await Notification.requestPermission();\n if (permissionResult === 'granted') {\n return;\n } else if (permissionResult === 'denied') {\n throw errorFactory.create(ErrorCode.PERMISSION_BLOCKED);\n } else {\n throw errorFactory.create(ErrorCode.PERMISSION_DEFAULT);\n }\n }\n\n /**\n * This method allows a developer to override the default service worker and\n * instead use a custom service worker.\n *\n * @param registration The service worker registration that should be used to\n * receive the push messages.\n */\n useServiceWorker(registration: ServiceWorkerRegistration): void {\n if (!(registration instanceof ServiceWorkerRegistration)) {\n throw errorFactory.create(ErrorCode.SW_REGISTRATION_EXPECTED);\n }\n\n if (this.registrationToUse != null) {\n throw errorFactory.create(ErrorCode.USE_SW_BEFORE_GET_TOKEN);\n }\n\n this.registrationToUse = registration;\n }\n\n /**\n * This method allows a developer to override the default vapid key\n * and instead use a custom VAPID public key.\n *\n * @param publicKey A URL safe base64 encoded string.\n */\n usePublicVapidKey(publicKey: string): void {\n if (typeof publicKey !== 'string') {\n throw errorFactory.create(ErrorCode.INVALID_PUBLIC_VAPID_KEY);\n }\n\n if (this.publicVapidKeyToUse != null) {\n throw errorFactory.create(ErrorCode.USE_PUBLIC_KEY_BEFORE_GET_TOKEN);\n }\n\n const parsedKey = base64ToArrayBuffer(publicKey);\n\n if (parsedKey.length !== 65) {\n throw errorFactory.create(ErrorCode.PUBLIC_KEY_DECRYPTION_FAILED);\n }\n\n this.publicVapidKeyToUse = parsedKey;\n }\n\n /**\n * @export\n * @param nextOrObserver An observer object or a function triggered on\n * message.\n * @param error A function triggered on message error.\n * @param completed function triggered when the observer is removed.\n * @return The unsubscribe function for the observer.\n */\n onMessage(\n nextOrObserver: NextFn<object> | Observer<object>,\n error?: ErrorFn,\n completed?: CompleteFn\n ): Unsubscribe {\n if (typeof nextOrObserver === 'function') {\n return this.onMessageInternal(nextOrObserver, error, completed);\n } else {\n return this.onMessageInternal(nextOrObserver);\n }\n }\n\n /**\n * @param nextOrObserver An observer object or a function triggered on token\n * refresh.\n * @param error A function triggered on token refresh error.\n * @param completed function triggered when the observer is removed.\n * @return The unsubscribe function for the observer.\n */\n onTokenRefresh(\n nextOrObserver: NextFn<object> | Observer<object>,\n error?: ErrorFn,\n completed?: CompleteFn\n ): Unsubscribe {\n if (typeof nextOrObserver === 'function') {\n return this.onTokenRefreshInternal(nextOrObserver, error, completed);\n } else {\n return this.onTokenRefreshInternal(nextOrObserver);\n }\n }\n\n /**\n * Given a registration, wait for the service worker it relates to\n * become activer\n * @param registration Registration to wait for service worker to become active\n * @return Wait for service worker registration to become active\n */\n // Visible for testing\n // TODO: Make private\n waitForRegistrationToActivate_(\n registration: ServiceWorkerRegistration\n ): Promise<ServiceWorkerRegistration> {\n const serviceWorker =\n registration.installing || registration.waiting || registration.active;\n\n return new Promise<ServiceWorkerRegistration>((resolve, reject) => {\n if (!serviceWorker) {\n // This is a rare scenario but has occured in firefox\n reject(errorFactory.create(ErrorCode.NO_SW_IN_REG));\n return;\n }\n // Because the Promise function is called on next tick there is a\n // small chance that the worker became active or redundant already.\n if (serviceWorker.state === 'activated') {\n resolve(registration);\n return;\n }\n\n if (serviceWorker.state === 'redundant') {\n reject(errorFactory.create(ErrorCode.SW_REG_REDUNDANT));\n return;\n }\n\n const stateChangeListener = (): void => {\n if (serviceWorker.state === 'activated') {\n resolve(registration);\n } else if (serviceWorker.state === 'redundant') {\n reject(errorFactory.create(ErrorCode.SW_REG_REDUNDANT));\n } else {\n // Return early and wait to next state change\n return;\n }\n serviceWorker.removeEventListener('statechange', stateChangeListener);\n };\n serviceWorker.addEventListener('statechange', stateChangeListener);\n });\n }\n\n /**\n * This will register the default service worker and return the registration\n * @return The service worker registration to be used for the push service.\n */\n getSWRegistration_(): Promise<ServiceWorkerRegistration> {\n if (this.registrationToUse) {\n return this.waitForRegistrationToActivate_(this.registrationToUse);\n }\n\n // Make the registration null so we know useServiceWorker will not\n // use a new service worker as registrationToUse is no longer undefined\n this.registrationToUse = null;\n\n return navigator.serviceWorker\n .register(DEFAULT_SW_PATH, {\n scope: DEFAULT_SW_SCOPE\n })\n .catch((err: Error) => {\n throw errorFactory.create(ErrorCode.FAILED_DEFAULT_REGISTRATION, {\n browserErrorMessage: err.message\n });\n })\n .then((registration: ServiceWorkerRegistration) => {\n return this.waitForRegistrationToActivate_(registration).then(() => {\n this.registrationToUse = registration;\n\n // We update after activation due to an issue with Firefox v49 where\n // a race condition occassionally causes the service worker to not\n // install\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n registration.update();\n\n return registration;\n });\n });\n }\n\n /**\n * This will return the default VAPID key or the uint8array version of the\n * public VAPID key provided by the developer.\n */\n async getPublicVapidKey_(): Promise<Uint8Array> {\n if (this.publicVapidKeyToUse) {\n return this.publicVapidKeyToUse;\n }\n\n return DEFAULT_PUBLIC_VAPID_KEY;\n }\n\n /**\n * This method will set up a message listener to handle\n * events from the service worker that should trigger\n * events in the page.\n */\n // Visible for testing\n // TODO: Make private\n setupSWMessageListener_(): void {\n navigator.serviceWorker.addEventListener(\n 'message',\n event => {\n if (\n !event.data ||\n !event.data.firebaseMessagingType ||\n !event.data.firebaseMessagingData\n ) {\n // Not a message from FCM\n return;\n }\n\n const {\n firebaseMessagingType,\n firebaseMessagingData\n }: InternalMessage = event.data;\n\n if (this.messageObserver) {\n this.messageObserver.next(firebaseMessagingData);\n }\n\n const { data } = firebaseMessagingData;\n if (\n data &&\n FN_CAMPAIGN_ID in data &&\n data[FN_CAMPAIGN_ANALYTICS_ENABLED] === '1'\n ) {\n // This message has a campaign id, meaning it was sent using the FN Console.\n // Analytics is enabled on this message, so we should log it.\n const eventType = getEventType(firebaseMessagingType);\n (this.app as _FirebaseApp).INTERNAL.analytics.logEvent(\n eventType,\n /* eslint-disable camelcase */\n {\n message_name: data[FN_CAMPAIGN_NAME],\n message_id: data[FN_CAMPAIGN_ID],\n message_time: data[FN_CAMPAIGN_TIME],\n message_device_time: Math.floor(Date.now() / 1000)\n }\n /* eslint-enable camelcase */\n );\n }\n },\n false\n );\n }\n}\n\nfunction getEventType(messageType: MessageType): string {\n switch (messageType) {\n case MessageType.NOTIFICATION_CLICKED:\n return 'notification_open';\n case MessageType.PUSH_MSG_RECEIVED:\n return 'notification_foreground';\n default:\n throw new Error();\n }\n}\n"],"names":["extendStatics","d","b","Object","setPrototypeOf","__proto__","Array","p","hasOwnProperty","__extends","__","this","constructor","prototype","create","__assign","assign","t","s","i","n","arguments","length","call","apply","__awaiter","thisArg","_arguments","P","generator","Promise","resolve","reject","fulfilled","value","step","next","e","rejected","result","done","then","__generator","body","f","y","g","_","label","sent","trys","ops","verb","throw","return","Symbol","iterator","v","op","TypeError","pop","push","__read","o","m","r","ar","error","__spread","concat","Error","code","message","_super","_this","FirebaseError","captureStackTrace","ErrorFactory","_i","data","customData","fullCode","service","template","errors","replace","PATTERN","key","toString","replaceTemplate","fullMessage","serviceName","_b","keys","_a","slice","console","warn","createSubscribe","executor","onNoObservers","proxy","ObserverProxy","subscribe","bind","forEachObserver","observer","close","complete","nextOrObserver","undefined","obj","methods","methods_1","method","implementsAnyMethods","noop","unsub","unsubscribeOne","observers","finalized","task","finalError","observerCount","fn","sendOne","err","catch","promisifyRequest","request","onsuccess","onerror","promisifyRequestCall","args","proxyProperties","ProxyClass","targetProp","properties","forEach","prop","defineProperty","get","set","val","proxyRequestMethods","Constructor","proxyMethods","proxyCursorRequestMethods","Cursor","promisifyCursorRequestCall","Index","index","_index","cursor","_cursor","_request","ObjectStore","store","_store","Transaction","idbTransaction","_tx","oncomplete","onabort","UpgradeDB","db","oldVersion","transaction","_db","DB","IDBIndex","IDBCursor","methodName","createIndex","IDBObjectStore","objectStore","IDBTransaction","createObjectStore","IDBDatabase","funcName","arr","toArray","callback","nativeObject","getAll","query","count","instance","items","iterateCursor","continue","PENDING_TIMEOUT_MS","PACKAGE_VERSION","INTERNAL_AUTH_VERSION","INSTALLATIONS_API_URL","TOKEN_EXPIRATION_BUFFER","ERROR_DESCRIPTION_MAP","ERROR_FACTORY","isServerError","includes","extractAppConfig","app","options","getMissingValueError","name","configKeys_1","__values","keyName","appName","projectId","apiKey","appId","valueName","getInstallationsEndpoint","extractAuthTokenInfoFromResponse","response","token","requestStatus","expiresIn","responseExpiresIn","Number","getExpiresInFromResponseExpiresIn","creationTime","Date","now","getErrorFromResponse","requestName","json","responseJson","errorData","serverCode","serverMessage","serverStatus","status","getHeaders","Headers","Content-Type","Accept","x-goog-api-key","getHeadersWithAuth","appConfig","refreshToken","headers","append","getAuthorizationHeader","retryIfServerError","sleep","ms","setTimeout","VALID_FID_PATTERN","INVALID_FID","generateFid","fidByteArray","Uint8Array","self","crypto","msCrypto","getRandomValues","fid","array","btoa","String","fromCharCode","bufferToBase64UrlSafe","substr","encode","test","DATABASE_NAME","DATABASE_VERSION","OBJECT_STORE_NAME","dbPromise","getDbPromise","version","upgradeCallback","indexedDB","onupgradeneeded","event","openDb","upgradeDB","getKey","tx","put","remove","delete","update","updateFn","oldValue","newValue","getInstallationEntry","oldEntry","installationEntry","clearTimedOutRequest","registrationStatus","updateOrCreateInstallationEntry","entryWithPromise","registrationPromise","updateInstallationRequest","entry","waitUntilFidRegistration","navigator","onLine","registrationPromiseWithError","inProgressEntry","registrationTime","endpoint","authVersion","sdkVersion","JSON","stringify","fetch","ok","responseValue","authToken","createInstallation","registeredInstallationEntry","e_1","registerInstallation","triggerRegistrationIfNecessary","hasInstallationRequestTimedOut","generateAuthToken","getGenerateAuthTokenEndpoint","installation","refreshAuthToken","forceRefresh","isEntryRegistered","oldAuthToken","isAuthTokenExpired","isAuthTokenValid","tokenPromise","updateAuthTokenRequest","waitUntilAuthTokenRequest","inProgressAuthToken","requestTime","makeAuthTokenRequestInProgressEntry","updatedInstallationEntry","fetchAuthTokenFromServer","hasAuthTokenRequestTimedOut","getToken","completeInstallationRegistration","deleteInstallation","getDeleteEndpoint","firebase","INTERNAL","registerService","getId","deleteInstallationRequest","MessageType","ERROR_MAP","errorFactory","DEFAULT_PUBLIC_VAPID_KEY","FN_CAMPAIGN_ID","isArrayBufferEqual","a","byteLength","viewA","DataView","viewB","getUint8","arrayBufferToBase64","arrayBuffer","uint8Version","toBase64","SubscriptionManager","subscription","vapidKey","getBody","subscribeOptions","getEndpoint","responseData","errorInfo","err_1","tokenDetails","updateOptions","fcmToken","err_2","unsubscribeOptions","err_3","ENDPOINT","installations","x-goog-firebase-installations-auth","p256dh","auth","web","buffer","applicationPubKey","base64ToArrayBuffer","base64String","base64","repeat","rawData","atob","outputArray","charCodeAt","OLD_DB_NAME","OLD_OBJECT_STORE_NAME","cleanV1","open","_event","objectStoreNames","contains","subscriptionManager","openCursorRequest","openCursor","deleteToken","deleteDatabase","handleDb","DbInterface","createTransaction","runRequest","mode","getDb","objectStoreName","promisify","dbName","dbVersion","onDbUpgrade","TokenDetailsModel","keyPath","unique","cursorRequest_1","createTime","fcmPushSet","cursorRequest_2","validateInputs","getIndex","swScope","fcmSenderId","getTokenDetailsFromToken","details","input","ArrayBuffer","VapidDetailsModel","getVapidFromSWScope","BaseController","currentPermission","getNotificationPermission_","getSWRegistration_","swReg","getPublicVapidKey_","publicVapidKey","getPushSubscription","pushSubscription","tokenDetailsModel","getTokenDetailsFromSWScope","scope","manageExistingToken","getNewToken","isEndpointEqual","isAuthEqual","isP256dhEqual","isTokenStillValid","updateToken","deleteTokenFromDB","updatedToken","allDetails","messagingSenderId","saveTokenDetails","vapidDetailsModel","saveVapidDetails","newToken","registration","pushManager","getSubscription","unsubscribe","swRegistration","userVisibleOnly","applicationServerKey","_registration","_b64PublicKey","_nextOrObserver","_error","_completed","_callback","all","closeDatabase","Notification","permission","FCM_MSG","SwController","waitUntil","onPush_","onSubChange_","onNotificationClick_","msgPayload","hasVisibleClients_","sendMessageToWindowClients_","notificationDetails","getNotificationData_","notificationTitle","title","reg","actions","maxActions","showNotification","bgMessageHandler","getTokenDetailsModel","notification","action","stopImmediatePropagation","link","fcmOptions","click_action","location","origin","getWindowClient_","windowClient","clients","openWindow","focus","internalMsg","createNewMsg","NOTIFICATION_CLICKED","attemptToMessageClient_","notificationInformation","url","parsedURL","URL","href","getClientList","clientList","suitableClient","client","postMessage","some","visibilityState","startsWith","PUSH_MSG_RECEIVED","map","getVapidDetailsModel","vapidKeyFromDatabase","addEventListener","onPush","onSubChange","onNotificationClick","matchAll","type","includeUncontrolled","msgType","msgData","firebaseMessagingType","firebaseMessagingData","namespaceExports","WindowController","requestPermission","permissionResult","ServiceWorkerRegistration","registrationToUse","publicKey","publicVapidKeyToUse","parsedKey","completed","onMessageInternal","onTokenRefreshInternal","serviceWorker","installing","waiting","active","state","stateChangeListener","removeEventListener","waitForRegistrationToActivate_","register","browserErrorMessage","messageObserver","eventType","messageType","getEventType","analytics","logEvent","message_name","message_id","message_time","message_device_time","Math","floor","tokenRefreshObserver","setupSWMessageListener_","isSupported","PushSubscription","cookieEnabled","window"],"mappings":"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"}
\No newline at end of file