From 1853af671c5e7592a2b56e616f990fc7fe1d5696 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Thu, 14 Apr 2022 10:59:35 -0700 Subject: [PATCH 1/7] Add idb 7 --- packages/app/package.json | 5 +-- packages/app/src/indexeddb.ts | 20 +++++++---- packages/installations/package.json | 1 + .../installations/src/helpers/idb-manager.ts | 25 ++++++++----- packages/messaging/package.json | 1 + .../messaging/src/internals/idb-manager.ts | 35 ++++++++++++------- yarn.lock | 5 +++ 7 files changed, 62 insertions(+), 30 deletions(-) diff --git a/packages/app/package.json b/packages/app/package.json index 8ba2bc09bc6..af2aeac5dc8 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -40,12 +40,13 @@ "@firebase/util": "1.5.2", "@firebase/logger": "0.3.2", "@firebase/component": "0.5.13", + "idb": "7.0.1", "tslib": "^2.1.0" }, "license": "Apache-2.0", "devDependencies": { - "rollup": "2.57.0", "@rollup/plugin-json": "4.1.0", + "rollup": "2.57.0", "rollup-plugin-replace": "2.2.0", "rollup-plugin-typescript2": "0.30.0", "typescript": "4.2.2" @@ -65,4 +66,4 @@ ], "reportDir": "./coverage/node" } -} \ No newline at end of file +} diff --git a/packages/app/src/indexeddb.ts b/packages/app/src/indexeddb.ts index e136d895f1f..fc90ed55def 100644 --- a/packages/app/src/indexeddb.ts +++ b/packages/app/src/indexeddb.ts @@ -15,18 +15,26 @@ * limitations under the License. */ -import { DBWrapper, openDB } from '@firebase/util'; +import { DBSchema, openDB, IDBPDatabase } from 'idb'; import { AppError, ERROR_FACTORY } from './errors'; import { FirebaseApp } from './public-types'; import { HeartbeatsInIndexedDB } from './types'; + const DB_NAME = 'firebase-heartbeat-database'; const DB_VERSION = 1; const STORE_NAME = 'firebase-heartbeat-store'; -let dbPromise: Promise | null = null; -function getDbPromise(): Promise { +interface AppDB extends DBSchema { + 'firebase-heartbeat-store': { + key: string, + value: HeartbeatsInIndexedDB + } +} + +let dbPromise: Promise> | null = null; +function getDbPromise(): Promise> { if (!dbPromise) { - dbPromise = openDB(DB_NAME, DB_VERSION, (db, oldVersion) => { + dbPromise = openDB(DB_NAME, DB_VERSION, {upgrade: (db, oldVersion) => { // We don't use 'break' in this switch statement, the fall-through // behavior is what we want, because if there are multiple versions between // the old version and the current version, we want ALL the migrations @@ -36,7 +44,7 @@ function getDbPromise(): Promise { case 0: db.createObjectStore(STORE_NAME); } - }).catch(e => { + }}).catch(e => { throw ERROR_FACTORY.create(AppError.STORAGE_OPEN, { originalErrorMessage: e.message }); @@ -70,7 +78,7 @@ export async function writeHeartbeatsToIndexedDB( const tx = db.transaction(STORE_NAME, 'readwrite'); const objectStore = tx.objectStore(STORE_NAME); await objectStore.put(heartbeatObject, computeKey(app)); - return tx.complete; + return tx.done; } catch (e) { throw ERROR_FACTORY.create(AppError.STORAGE_WRITE, { originalErrorMessage: e.message diff --git a/packages/installations/package.json b/packages/installations/package.json index 68aa7dc18e1..c99ab961b26 100644 --- a/packages/installations/package.json +++ b/packages/installations/package.json @@ -64,6 +64,7 @@ "dependencies": { "@firebase/util": "1.5.2", "@firebase/component": "0.5.13", + "idb": "7.0.1", "tslib": "^2.1.0" } } \ No newline at end of file diff --git a/packages/installations/src/helpers/idb-manager.ts b/packages/installations/src/helpers/idb-manager.ts index 6c502ae4bb9..2f9594a7ff3 100644 --- a/packages/installations/src/helpers/idb-manager.ts +++ b/packages/installations/src/helpers/idb-manager.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { DBWrapper, openDB } from '@firebase/util'; +import { DBSchema, IDBPDatabase, openDB } from 'idb'; import { AppConfig } from '../interfaces/installation-impl'; import { InstallationEntry } from '../interfaces/installation-entry'; import { getKey } from '../util/get-key'; @@ -25,10 +25,17 @@ const DATABASE_NAME = 'firebase-installations-database'; const DATABASE_VERSION = 1; const OBJECT_STORE_NAME = 'firebase-installations-store'; -let dbPromise: Promise | null = null; -function getDbPromise(): Promise { +interface InstallationsDB extends DBSchema { + 'firebase-installations-store': { + key: string, + value: InstallationEntry | undefined + } +} + +let dbPromise: Promise> | null = null; +function getDbPromise(): Promise> { if (!dbPromise) { - dbPromise = openDB(DATABASE_NAME, DATABASE_VERSION, (db, oldVersion) => { + dbPromise = openDB(DATABASE_NAME, DATABASE_VERSION, {upgrade: (db, oldVersion) => { // We don't use 'break' in this switch statement, the fall-through // behavior is what we want, because if there are multiple versions between // the old version and the current version, we want ALL the migrations @@ -38,7 +45,7 @@ function getDbPromise(): Promise { case 0: db.createObjectStore(OBJECT_STORE_NAME); } - }); + }}); } return dbPromise; } @@ -66,7 +73,7 @@ export async function set( const objectStore = tx.objectStore(OBJECT_STORE_NAME); const oldValue = (await objectStore.get(key)) as InstallationEntry; await objectStore.put(value, key); - await tx.complete; + await tx.done; if (!oldValue || oldValue.fid !== value.fid) { fidChanged(appConfig, value.fid); @@ -81,7 +88,7 @@ export async function remove(appConfig: AppConfig): Promise { const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); await tx.objectStore(OBJECT_STORE_NAME).delete(key); - await tx.complete; + await tx.done; } /** @@ -108,7 +115,7 @@ export async function update( } else { await store.put(newValue, key); } - await tx.complete; + await tx.done; if (newValue && (!oldValue || oldValue.fid !== newValue.fid)) { fidChanged(appConfig, newValue.fid); @@ -121,5 +128,5 @@ export async function clear(): Promise { const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); await tx.objectStore(OBJECT_STORE_NAME).clear(); - await tx.complete; + await tx.done; } diff --git a/packages/messaging/package.json b/packages/messaging/package.json index c9448943e15..ac0ef0f7757 100644 --- a/packages/messaging/package.json +++ b/packages/messaging/package.json @@ -56,6 +56,7 @@ "@firebase/messaging-interop-types": "0.1.0", "@firebase/util": "1.5.2", "@firebase/component": "0.5.13", + "idb": "7.0.1", "tslib": "^2.1.0" }, "devDependencies": { diff --git a/packages/messaging/src/internals/idb-manager.ts b/packages/messaging/src/internals/idb-manager.ts index 1aa82734757..d1a9163e9b6 100644 --- a/packages/messaging/src/internals/idb-manager.ts +++ b/packages/messaging/src/internals/idb-manager.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { DBWrapper, deleteDB, openDB } from '@firebase/util'; +import { DBSchema, IDBPDatabase, deleteDB, openDB } from 'idb'; import { FirebaseInternalDependencies } from '../interfaces/internal-dependencies'; import { TokenDetails } from '../interfaces/token-details'; @@ -26,20 +26,29 @@ export const DATABASE_NAME = 'firebase-messaging-database'; const DATABASE_VERSION = 1; const OBJECT_STORE_NAME = 'firebase-messaging-store'; -let dbPromise: Promise | null = null; -function getDbPromise(): Promise { +interface MessagingDB extends DBSchema { + 'firebase-messaging-store': { + key: string, + value: TokenDetails + } +} + +let dbPromise: Promise> | null = null; +function getDbPromise(): Promise> { if (!dbPromise) { dbPromise = openDB( DATABASE_NAME, DATABASE_VERSION, - (upgradeDb, oldVersion) => { - // We don't use 'break' in this switch statement, the fall-through behavior is what we want, - // because if there are multiple versions between the old version and the current version, we - // want ALL the migrations that correspond to those versions to run, not only the last one. - // eslint-disable-next-line default-case - switch (oldVersion) { - case 0: - upgradeDb.createObjectStore(OBJECT_STORE_NAME); + { + upgrade: (upgradeDb, oldVersion) => { + // We don't use 'break' in this switch statement, the fall-through behavior is what we want, + // because if there are multiple versions between the old version and the current version, we + // want ALL the migrations that correspond to those versions to run, not only the last one. + // eslint-disable-next-line default-case + switch (oldVersion) { + case 0: + upgradeDb.createObjectStore(OBJECT_STORE_NAME); + } } } ); @@ -81,7 +90,7 @@ export async function dbSet( const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); await tx.objectStore(OBJECT_STORE_NAME).put(tokenDetails, key); - await tx.complete; + await tx.done; return tokenDetails; } @@ -93,7 +102,7 @@ export async function dbRemove( const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); await tx.objectStore(OBJECT_STORE_NAME).delete(key); - await tx.complete; + await tx.done; } /** Deletes the DB. Useful for tests. */ diff --git a/yarn.lock b/yarn.lock index d5226730178..fc67a1a8f6f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9015,6 +9015,11 @@ iconv-lite@0.6.3, iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" +idb@7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz#d2875b3a2f205d854ee307f6d196f246fea590a7" + integrity sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg== + ieee754@^1.1.13, ieee754@^1.1.4: version "1.2.1" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" From f356da7c026ee313e246f1e615b4d001dbc8c62a Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Thu, 14 Apr 2022 11:22:48 -0700 Subject: [PATCH 2/7] Clean up messaging --- .../src/helpers/migrate-old-database.test.ts | 8 +- .../src/helpers/migrate-old-database.ts | 128 +++++++++--------- packages/messaging/src/testing/setup.ts | 2 +- 3 files changed, 70 insertions(+), 68 deletions(-) diff --git a/packages/messaging/src/helpers/migrate-old-database.test.ts b/packages/messaging/src/helpers/migrate-old-database.test.ts index 2ae03c7545d..39dccd0028a 100644 --- a/packages/messaging/src/helpers/migrate-old-database.test.ts +++ b/packages/messaging/src/helpers/migrate-old-database.test.ts @@ -28,7 +28,7 @@ import { FakePushSubscription } from '../testing/fakes/service-worker'; import { base64ToArray } from './array-base64-translator'; import { expect } from 'chai'; import { getFakeTokenDetails } from '../testing/fakes/token-details'; -import { openDB } from '@firebase/util'; +import { openDB } from 'idb'; describe('migrateOldDb', () => { it("does nothing if old DB didn't exist", async () => { @@ -179,7 +179,7 @@ describe('migrateOldDb', () => { }); async function put(version: number, value: object): Promise { - const db = await openDB('fcm_token_details_db', version, (db, oldVersion) => { + const db = await openDB('fcm_token_details_db', version, {upgrade: (db, oldVersion) => { if (oldVersion === 0) { const objectStore = db.createObjectStore('fcm_token_object_Store', { keyPath: 'swScope' @@ -188,13 +188,13 @@ async function put(version: number, value: object): Promise { unique: false }); objectStore.createIndex('fcmToken', 'fcmToken', { unique: true }); - } + }} }); try { const tx = db.transaction('fcm_token_object_Store', 'readwrite'); await tx.objectStore('fcm_token_object_Store').put(value); - await tx.complete; + await tx.done; } finally { db.close(); } diff --git a/packages/messaging/src/helpers/migrate-old-database.ts b/packages/messaging/src/helpers/migrate-old-database.ts index 0117faca131..b2e2dbcdd11 100644 --- a/packages/messaging/src/helpers/migrate-old-database.ts +++ b/packages/messaging/src/helpers/migrate-old-database.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { deleteDB, openDB } from '@firebase/util'; +import { deleteDB, openDB } from 'idb'; import { TokenDetails } from '../interfaces/token-details'; import { arrayToBase64 } from './array-base64-translator'; @@ -91,75 +91,77 @@ export async function migrateOldDatabase( const db = await openDB( OLD_DB_NAME, OLD_DB_VERSION, - async (db, oldVersion, newVersion, upgradeTransaction) => { - if (oldVersion < 2) { - // Database too old, skip migration. - return; - } - - if (!db.objectStoreNames.contains(OLD_OBJECT_STORE_NAME)) { - // Database did not exist. Nothing to do. - return; - } - - const objectStore = upgradeTransaction.objectStore(OLD_OBJECT_STORE_NAME); - const value = await objectStore.index('fcmSenderId').get(senderId); - await objectStore.clear(); + { + upgrade: async (db, oldVersion, newVersion, upgradeTransaction) => { + if (oldVersion < 2) { + // Database too old, skip migration. + return; + } - if (!value) { - // No entry in the database, nothing to migrate. - return; - } + if (!db.objectStoreNames.contains(OLD_OBJECT_STORE_NAME)) { + // Database did not exist. Nothing to do. + return; + } - if (oldVersion === 2) { - const oldDetails = value as V2TokenDetails; + const objectStore = upgradeTransaction.objectStore(OLD_OBJECT_STORE_NAME); + const value = await objectStore.index('fcmSenderId').get(senderId); + await objectStore.clear(); - if (!oldDetails.auth || !oldDetails.p256dh || !oldDetails.endpoint) { + if (!value) { + // No entry in the database, nothing to migrate. return; } - tokenDetails = { - token: oldDetails.fcmToken, - createTime: oldDetails.createTime ?? Date.now(), - subscriptionOptions: { - auth: oldDetails.auth, - p256dh: oldDetails.p256dh, - endpoint: oldDetails.endpoint, - swScope: oldDetails.swScope, - vapidKey: - typeof oldDetails.vapidKey === 'string' - ? oldDetails.vapidKey - : arrayToBase64(oldDetails.vapidKey) - } - }; - } else if (oldVersion === 3) { - const oldDetails = value as V3TokenDetails; - - tokenDetails = { - token: oldDetails.fcmToken, - createTime: oldDetails.createTime, - subscriptionOptions: { - auth: arrayToBase64(oldDetails.auth), - p256dh: arrayToBase64(oldDetails.p256dh), - endpoint: oldDetails.endpoint, - swScope: oldDetails.swScope, - vapidKey: arrayToBase64(oldDetails.vapidKey) - } - }; - } else if (oldVersion === 4) { - const oldDetails = value as V4TokenDetails; - - tokenDetails = { - token: oldDetails.fcmToken, - createTime: oldDetails.createTime, - subscriptionOptions: { - auth: arrayToBase64(oldDetails.auth), - p256dh: arrayToBase64(oldDetails.p256dh), - endpoint: oldDetails.endpoint, - swScope: oldDetails.swScope, - vapidKey: arrayToBase64(oldDetails.vapidKey) + if (oldVersion === 2) { + const oldDetails = value as V2TokenDetails; + + if (!oldDetails.auth || !oldDetails.p256dh || !oldDetails.endpoint) { + return; } - }; + + tokenDetails = { + token: oldDetails.fcmToken, + createTime: oldDetails.createTime ?? Date.now(), + subscriptionOptions: { + auth: oldDetails.auth, + p256dh: oldDetails.p256dh, + endpoint: oldDetails.endpoint, + swScope: oldDetails.swScope, + vapidKey: + typeof oldDetails.vapidKey === 'string' + ? oldDetails.vapidKey + : arrayToBase64(oldDetails.vapidKey) + } + }; + } else if (oldVersion === 3) { + const oldDetails = value as V3TokenDetails; + + tokenDetails = { + token: oldDetails.fcmToken, + createTime: oldDetails.createTime, + subscriptionOptions: { + auth: arrayToBase64(oldDetails.auth), + p256dh: arrayToBase64(oldDetails.p256dh), + endpoint: oldDetails.endpoint, + swScope: oldDetails.swScope, + vapidKey: arrayToBase64(oldDetails.vapidKey) + } + }; + } else if (oldVersion === 4) { + const oldDetails = value as V4TokenDetails; + + tokenDetails = { + token: oldDetails.fcmToken, + createTime: oldDetails.createTime, + subscriptionOptions: { + auth: arrayToBase64(oldDetails.auth), + p256dh: arrayToBase64(oldDetails.p256dh), + endpoint: oldDetails.endpoint, + swScope: oldDetails.swScope, + vapidKey: arrayToBase64(oldDetails.vapidKey) + } + }; + } } } ); diff --git a/packages/messaging/src/testing/setup.ts b/packages/messaging/src/testing/setup.ts index 7aa969119c6..69b47f3de81 100644 --- a/packages/messaging/src/testing/setup.ts +++ b/packages/messaging/src/testing/setup.ts @@ -19,7 +19,7 @@ import chaiAsPromised from 'chai-as-promised'; import sinonChai from 'sinon-chai'; import { dbDelete } from '../internals/idb-manager'; -import { deleteDB } from '@firebase/util'; +import { deleteDB } from 'idb'; import { restore } from 'sinon'; import { use } from 'chai'; From ce42a1f6dda9ba4160811f6828547ed9939241c9 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Thu, 14 Apr 2022 11:23:53 -0700 Subject: [PATCH 3/7] Remove indexeddb from util --- .../src/helpers/migrate-old-database.test.ts | 22 +- packages/util/index.node.ts | 3 - packages/util/index.ts | 1 - packages/util/src/indexeddb.ts | 195 ------------------ 4 files changed, 12 insertions(+), 209 deletions(-) delete mode 100644 packages/util/src/indexeddb.ts diff --git a/packages/messaging/src/helpers/migrate-old-database.test.ts b/packages/messaging/src/helpers/migrate-old-database.test.ts index 39dccd0028a..11d61121ebb 100644 --- a/packages/messaging/src/helpers/migrate-old-database.test.ts +++ b/packages/messaging/src/helpers/migrate-old-database.test.ts @@ -179,16 +179,18 @@ describe('migrateOldDb', () => { }); async function put(version: number, value: object): Promise { - const db = await openDB('fcm_token_details_db', version, {upgrade: (db, oldVersion) => { - if (oldVersion === 0) { - const objectStore = db.createObjectStore('fcm_token_object_Store', { - keyPath: 'swScope' - }); - objectStore.createIndex('fcmSenderId', 'fcmSenderId', { - unique: false - }); - objectStore.createIndex('fcmToken', 'fcmToken', { unique: true }); - }} + const db = await openDB('fcm_token_details_db', version, { + upgrade: (db, oldVersion) => { + if (oldVersion === 0) { + const objectStore = db.createObjectStore('fcm_token_object_Store', { + keyPath: 'swScope' + }); + objectStore.createIndex('fcmSenderId', 'fcmSenderId', { + unique: false + }); + objectStore.createIndex('fcmToken', 'fcmToken', { unique: true }); + } + } }); try { diff --git a/packages/util/index.node.ts b/packages/util/index.node.ts index e27c304145c..8dace3b8e1e 100644 --- a/packages/util/index.node.ts +++ b/packages/util/index.node.ts @@ -39,6 +39,3 @@ export * from './src/utf8'; export * from './src/exponential_backoff'; export * from './src/formatters'; export * from './src/compat'; -// This can't be used in Node but it will cause errors if libraries import -// these methods and they aren't here. -export * from './src/indexeddb'; diff --git a/packages/util/index.ts b/packages/util/index.ts index 0cf518fbd81..00d661734b8 100644 --- a/packages/util/index.ts +++ b/packages/util/index.ts @@ -34,4 +34,3 @@ export * from './src/utf8'; export * from './src/exponential_backoff'; export * from './src/formatters'; export * from './src/compat'; -export * from './src/indexeddb'; diff --git a/packages/util/src/indexeddb.ts b/packages/util/src/indexeddb.ts deleted file mode 100644 index 5c459c44f26..00000000000 --- a/packages/util/src/indexeddb.ts +++ /dev/null @@ -1,195 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @internal - */ -function promisifyRequest( - request: IDBRequest, - errorMessage: string -): Promise { - return new Promise((resolve, reject) => { - request.onsuccess = event => { - resolve((event.target as IDBRequest).result); - }; - request.onerror = event => { - reject(`${errorMessage}: ${(event.target as IDBRequest).error?.message}`); - }; - }); -} - -/** - * @internal - */ -export class DBWrapper { - objectStoreNames: DOMStringList; - constructor(private _db: IDBDatabase) { - this.objectStoreNames = this._db.objectStoreNames; - } - transaction( - storeNames: string[] | string, - mode: IDBTransactionMode = 'readonly' - ): TransactionWrapper { - return new TransactionWrapper( - this._db.transaction.call(this._db, storeNames, mode) - ); - } - createObjectStore( - storeName: string, - options?: IDBObjectStoreParameters - ): ObjectStoreWrapper { - return new ObjectStoreWrapper( - this._db.createObjectStore(storeName, options) - ); - } - close(): void { - this._db.close(); - } -} - -/** - * @internal - */ -class TransactionWrapper { - complete: Promise; - constructor(private _transaction: IDBTransaction) { - this.complete = new Promise((resolve, reject) => { - this._transaction.oncomplete = function () { - resolve(); - }; - this._transaction.onerror = () => { - reject(this._transaction.error); - }; - this._transaction.onabort = () => { - reject(this._transaction.error); - }; - }); - } - objectStore(storeName: string): ObjectStoreWrapper { - return new ObjectStoreWrapper(this._transaction.objectStore(storeName)); - } -} - -/** - * @internal - */ -class ObjectStoreWrapper { - constructor(private _store: IDBObjectStore) {} - index(name: string): IndexWrapper { - return new IndexWrapper(this._store.index(name)); - } - createIndex( - name: string, - keypath: string, - options: IDBIndexParameters - ): IndexWrapper { - return new IndexWrapper(this._store.createIndex(name, keypath, options)); - } - get(key: string): Promise { - const request = this._store.get(key); - return promisifyRequest(request, 'Error reading from IndexedDB'); - } - put(value: unknown, key?: string): Promise { - const request = this._store.put(value, key); - return promisifyRequest(request, 'Error writing to IndexedDB'); - } - delete(key: string): Promise { - const request = this._store.delete(key); - return promisifyRequest(request, 'Error deleting from IndexedDB'); - } - clear(): Promise { - const request = this._store.clear(); - return promisifyRequest(request, 'Error clearing IndexedDB object store'); - } -} - -/** - * @internal - */ -class IndexWrapper { - constructor(private _index: IDBIndex) {} - get(key: string): Promise { - const request = this._index.get(key); - return promisifyRequest(request, 'Error reading from IndexedDB'); - } -} - -/** - * @internal - */ -export function openDB( - dbName: string, - dbVersion: number, - upgradeCallback: ( - db: DBWrapper, - oldVersion: number, - newVersion: number | null, - transaction: TransactionWrapper - ) => void -): Promise { - return new Promise((resolve, reject) => { - try { - const request = indexedDB.open(dbName, dbVersion); - - request.onsuccess = event => { - resolve(new DBWrapper((event.target as IDBOpenDBRequest).result)); - }; - - request.onerror = event => { - reject( - `Error opening indexedDB: ${ - (event.target as IDBRequest).error?.message - }` - ); - }; - - request.onupgradeneeded = event => { - upgradeCallback( - new DBWrapper(request.result), - event.oldVersion, - event.newVersion, - new TransactionWrapper(request.transaction!) - ); - }; - } catch (e) { - reject(`Error opening indexedDB: ${e.message}`); - } - }); -} - -/** - * @internal - */ -export async function deleteDB(dbName: string): Promise { - return new Promise((resolve, reject) => { - try { - const request = indexedDB.deleteDatabase(dbName); - request.onsuccess = () => { - resolve(); - }; - request.onerror = event => { - reject( - `Error deleting indexedDB database "${dbName}": ${ - (event.target as IDBRequest).error?.message - }` - ); - }; - } catch (e) { - reject(`Error deleting indexedDB database "${dbName}": ${e.message}`); - } - }); -} From c949c8ee264ea267813b30ce5bc07760539622b8 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Thu, 14 Apr 2022 11:24:39 -0700 Subject: [PATCH 4/7] format --- common/api-review/util.api.md | 29 ---- packages/app/src/indexeddb.ts | 28 ++-- .../installations/src/helpers/idb-manager.ts | 28 ++-- .../src/helpers/migrate-old-database.ts | 132 +++++++++--------- .../messaging/src/internals/idb-manager.ts | 30 ++-- 5 files changed, 107 insertions(+), 140 deletions(-) diff --git a/common/api-review/util.api.md b/common/api-review/util.api.md index 21bcea8b894..adfb36a4b09 100644 --- a/common/api-review/util.api.md +++ b/common/api-review/util.api.md @@ -87,25 +87,6 @@ export function createMockUserToken(token: EmulatorMockTokenOptions, projectId?: // @public export function createSubscribe(executor: Executor, onNoObservers?: Executor): Subscribe; -// Warning: (ae-internal-missing-underscore) The name "DBWrapper" should be prefixed with an underscore because the declaration is marked as @internal -// -// @internal (undocumented) -export class DBWrapper { - constructor(_db: IDBDatabase); - // (undocumented) - close(): void; - // Warning: (ae-forgotten-export) The symbol "ObjectStoreWrapper" needs to be exported by the entry point index.d.ts - // - // (undocumented) - createObjectStore(storeName: string, options?: IDBObjectStoreParameters): ObjectStoreWrapper; - // (undocumented) - objectStoreNames: DOMStringList; - // Warning: (ae-forgotten-export) The symbol "TransactionWrapper" needs to be exported by the entry point index.d.ts - // - // (undocumented) - transaction(storeNames: string[] | string, mode?: IDBTransactionMode): TransactionWrapper; -} - // Warning: (ae-forgotten-export) The symbol "DecodedToken" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "decode" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -141,11 +122,6 @@ export class Deferred { wrapCallback(callback?: (error?: unknown, value?: unknown) => void): (error: unknown, value?: unknown) => void; } -// Warning: (ae-internal-missing-underscore) The name "deleteDB" should be prefixed with an underscore because the declaration is marked as @internal -// -// @internal (undocumented) -export function deleteDB(dbName: string): Promise; - // Warning: (ae-forgotten-export) The symbol "FirebaseIdToken" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "EmulatorMockTokenOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -360,11 +336,6 @@ export interface Observer { next: NextFn; } -// Warning: (ae-internal-missing-underscore) The name "openDB" should be prefixed with an underscore because the declaration is marked as @internal -// -// @internal (undocumented) -export function openDB(dbName: string, dbVersion: number, upgradeCallback: (db: DBWrapper, oldVersion: number, newVersion: number | null, transaction: TransactionWrapper) => void): Promise; - // Warning: (ae-missing-release-tag) "ordinal" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public diff --git a/packages/app/src/indexeddb.ts b/packages/app/src/indexeddb.ts index fc90ed55def..bf49522faab 100644 --- a/packages/app/src/indexeddb.ts +++ b/packages/app/src/indexeddb.ts @@ -26,25 +26,27 @@ const STORE_NAME = 'firebase-heartbeat-store'; interface AppDB extends DBSchema { 'firebase-heartbeat-store': { - key: string, - value: HeartbeatsInIndexedDB - } + key: string; + value: HeartbeatsInIndexedDB; + }; } let dbPromise: Promise> | null = null; function getDbPromise(): Promise> { if (!dbPromise) { - dbPromise = openDB(DB_NAME, DB_VERSION, {upgrade: (db, oldVersion) => { - // We don't use 'break' in this switch statement, the fall-through - // behavior is what we want, because if there are multiple versions between - // the old version and the current version, we want ALL the migrations - // that correspond to those versions to run, not only the last one. - // eslint-disable-next-line default-case - switch (oldVersion) { - case 0: - db.createObjectStore(STORE_NAME); + dbPromise = openDB(DB_NAME, DB_VERSION, { + upgrade: (db, oldVersion) => { + // We don't use 'break' in this switch statement, the fall-through + // behavior is what we want, because if there are multiple versions between + // the old version and the current version, we want ALL the migrations + // that correspond to those versions to run, not only the last one. + // eslint-disable-next-line default-case + switch (oldVersion) { + case 0: + db.createObjectStore(STORE_NAME); + } } - }}).catch(e => { + }).catch(e => { throw ERROR_FACTORY.create(AppError.STORAGE_OPEN, { originalErrorMessage: e.message }); diff --git a/packages/installations/src/helpers/idb-manager.ts b/packages/installations/src/helpers/idb-manager.ts index 2f9594a7ff3..32a42d6fe73 100644 --- a/packages/installations/src/helpers/idb-manager.ts +++ b/packages/installations/src/helpers/idb-manager.ts @@ -27,25 +27,27 @@ const OBJECT_STORE_NAME = 'firebase-installations-store'; interface InstallationsDB extends DBSchema { 'firebase-installations-store': { - key: string, - value: InstallationEntry | undefined - } + key: string; + value: InstallationEntry | undefined; + }; } let dbPromise: Promise> | null = null; function getDbPromise(): Promise> { if (!dbPromise) { - dbPromise = openDB(DATABASE_NAME, DATABASE_VERSION, {upgrade: (db, oldVersion) => { - // We don't use 'break' in this switch statement, the fall-through - // behavior is what we want, because if there are multiple versions between - // the old version and the current version, we want ALL the migrations - // that correspond to those versions to run, not only the last one. - // eslint-disable-next-line default-case - switch (oldVersion) { - case 0: - db.createObjectStore(OBJECT_STORE_NAME); + dbPromise = openDB(DATABASE_NAME, DATABASE_VERSION, { + upgrade: (db, oldVersion) => { + // We don't use 'break' in this switch statement, the fall-through + // behavior is what we want, because if there are multiple versions between + // the old version and the current version, we want ALL the migrations + // that correspond to those versions to run, not only the last one. + // eslint-disable-next-line default-case + switch (oldVersion) { + case 0: + db.createObjectStore(OBJECT_STORE_NAME); + } } - }}); + }); } return dbPromise; } diff --git a/packages/messaging/src/helpers/migrate-old-database.ts b/packages/messaging/src/helpers/migrate-old-database.ts index b2e2dbcdd11..a0fce5b3531 100644 --- a/packages/messaging/src/helpers/migrate-old-database.ts +++ b/packages/messaging/src/helpers/migrate-old-database.ts @@ -88,83 +88,79 @@ export async function migrateOldDatabase( let tokenDetails: TokenDetails | null = null; - const db = await openDB( - OLD_DB_NAME, - OLD_DB_VERSION, - { - upgrade: async (db, oldVersion, newVersion, upgradeTransaction) => { - if (oldVersion < 2) { - // Database too old, skip migration. - return; - } + const db = await openDB(OLD_DB_NAME, OLD_DB_VERSION, { + upgrade: async (db, oldVersion, newVersion, upgradeTransaction) => { + if (oldVersion < 2) { + // Database too old, skip migration. + return; + } - if (!db.objectStoreNames.contains(OLD_OBJECT_STORE_NAME)) { - // Database did not exist. Nothing to do. - return; - } + if (!db.objectStoreNames.contains(OLD_OBJECT_STORE_NAME)) { + // Database did not exist. Nothing to do. + return; + } - const objectStore = upgradeTransaction.objectStore(OLD_OBJECT_STORE_NAME); - const value = await objectStore.index('fcmSenderId').get(senderId); - await objectStore.clear(); + const objectStore = upgradeTransaction.objectStore(OLD_OBJECT_STORE_NAME); + const value = await objectStore.index('fcmSenderId').get(senderId); + await objectStore.clear(); + + if (!value) { + // No entry in the database, nothing to migrate. + return; + } - if (!value) { - // No entry in the database, nothing to migrate. + if (oldVersion === 2) { + const oldDetails = value as V2TokenDetails; + + if (!oldDetails.auth || !oldDetails.p256dh || !oldDetails.endpoint) { return; } - if (oldVersion === 2) { - const oldDetails = value as V2TokenDetails; - - if (!oldDetails.auth || !oldDetails.p256dh || !oldDetails.endpoint) { - return; + tokenDetails = { + token: oldDetails.fcmToken, + createTime: oldDetails.createTime ?? Date.now(), + subscriptionOptions: { + auth: oldDetails.auth, + p256dh: oldDetails.p256dh, + endpoint: oldDetails.endpoint, + swScope: oldDetails.swScope, + vapidKey: + typeof oldDetails.vapidKey === 'string' + ? oldDetails.vapidKey + : arrayToBase64(oldDetails.vapidKey) } - - tokenDetails = { - token: oldDetails.fcmToken, - createTime: oldDetails.createTime ?? Date.now(), - subscriptionOptions: { - auth: oldDetails.auth, - p256dh: oldDetails.p256dh, - endpoint: oldDetails.endpoint, - swScope: oldDetails.swScope, - vapidKey: - typeof oldDetails.vapidKey === 'string' - ? oldDetails.vapidKey - : arrayToBase64(oldDetails.vapidKey) - } - }; - } else if (oldVersion === 3) { - const oldDetails = value as V3TokenDetails; - - tokenDetails = { - token: oldDetails.fcmToken, - createTime: oldDetails.createTime, - subscriptionOptions: { - auth: arrayToBase64(oldDetails.auth), - p256dh: arrayToBase64(oldDetails.p256dh), - endpoint: oldDetails.endpoint, - swScope: oldDetails.swScope, - vapidKey: arrayToBase64(oldDetails.vapidKey) - } - }; - } else if (oldVersion === 4) { - const oldDetails = value as V4TokenDetails; - - tokenDetails = { - token: oldDetails.fcmToken, - createTime: oldDetails.createTime, - subscriptionOptions: { - auth: arrayToBase64(oldDetails.auth), - p256dh: arrayToBase64(oldDetails.p256dh), - endpoint: oldDetails.endpoint, - swScope: oldDetails.swScope, - vapidKey: arrayToBase64(oldDetails.vapidKey) - } - }; - } + }; + } else if (oldVersion === 3) { + const oldDetails = value as V3TokenDetails; + + tokenDetails = { + token: oldDetails.fcmToken, + createTime: oldDetails.createTime, + subscriptionOptions: { + auth: arrayToBase64(oldDetails.auth), + p256dh: arrayToBase64(oldDetails.p256dh), + endpoint: oldDetails.endpoint, + swScope: oldDetails.swScope, + vapidKey: arrayToBase64(oldDetails.vapidKey) + } + }; + } else if (oldVersion === 4) { + const oldDetails = value as V4TokenDetails; + + tokenDetails = { + token: oldDetails.fcmToken, + createTime: oldDetails.createTime, + subscriptionOptions: { + auth: arrayToBase64(oldDetails.auth), + p256dh: arrayToBase64(oldDetails.p256dh), + endpoint: oldDetails.endpoint, + swScope: oldDetails.swScope, + vapidKey: arrayToBase64(oldDetails.vapidKey) + } + }; } } - ); + }); db.close(); // Delete all old databases. diff --git a/packages/messaging/src/internals/idb-manager.ts b/packages/messaging/src/internals/idb-manager.ts index d1a9163e9b6..de471066afc 100644 --- a/packages/messaging/src/internals/idb-manager.ts +++ b/packages/messaging/src/internals/idb-manager.ts @@ -28,30 +28,26 @@ const OBJECT_STORE_NAME = 'firebase-messaging-store'; interface MessagingDB extends DBSchema { 'firebase-messaging-store': { - key: string, - value: TokenDetails - } + key: string; + value: TokenDetails; + }; } let dbPromise: Promise> | null = null; function getDbPromise(): Promise> { if (!dbPromise) { - dbPromise = openDB( - DATABASE_NAME, - DATABASE_VERSION, - { - upgrade: (upgradeDb, oldVersion) => { - // We don't use 'break' in this switch statement, the fall-through behavior is what we want, - // because if there are multiple versions between the old version and the current version, we - // want ALL the migrations that correspond to those versions to run, not only the last one. - // eslint-disable-next-line default-case - switch (oldVersion) { - case 0: - upgradeDb.createObjectStore(OBJECT_STORE_NAME); - } + dbPromise = openDB(DATABASE_NAME, DATABASE_VERSION, { + upgrade: (upgradeDb, oldVersion) => { + // We don't use 'break' in this switch statement, the fall-through behavior is what we want, + // because if there are multiple versions between the old version and the current version, we + // want ALL the migrations that correspond to those versions to run, not only the last one. + // eslint-disable-next-line default-case + switch (oldVersion) { + case 0: + upgradeDb.createObjectStore(OBJECT_STORE_NAME); } } - ); + }); } return dbPromise; } From bde166b009653b5525e6697d9d9cb0b58558f55f Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Fri, 15 Apr 2022 12:00:22 -0700 Subject: [PATCH 5/7] Fix typing issue in messaging --- .../messaging/src/listeners/sw-listeners.test.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/messaging/src/listeners/sw-listeners.test.ts b/packages/messaging/src/listeners/sw-listeners.test.ts index 5c1b85e6dd9..84e8f1043dc 100644 --- a/packages/messaging/src/listeners/sw-listeners.test.ts +++ b/packages/messaging/src/listeners/sw-listeners.test.ts @@ -39,6 +39,7 @@ import { } from '../interfaces/internal-message-payload'; import { NotificationEvent, + PushSubscriptionChangeEvent, ServiceWorkerGlobalScope, ServiceWorkerGlobalScopeEventMap, WindowClient @@ -427,9 +428,9 @@ describe('SwController', () => { describe('onSubChange', () => { it('calls deleteToken if there is no new subscription', async () => { - const event = makeEvent('pushsubscriptionchange', { + const event = makeFakePushSubscriptionChangeEvent({ oldSubscription: new FakePushSubscription(), - newSubscription: undefined + newSubscription: null }); await callEventListener(event); @@ -439,7 +440,7 @@ describe('SwController', () => { }); it('calls deleteToken and getToken if subscription changed', async () => { - const event = makeEvent('pushsubscriptionchange', { + const event = makeFakePushSubscriptionChangeEvent({ oldSubscription: new FakePushSubscription(), newSubscription: new FakePushSubscription() }); @@ -474,3 +475,12 @@ function makeEvent( Object.assign(event, data); return event as unknown as ServiceWorkerGlobalScopeEventMap[K]; } + +function makeFakePushSubscriptionChangeEvent(data: { + newSubscription: PushSubscription | null, + oldSubscription: PushSubscription | null +}): PushSubscriptionChangeEvent { + const event = new FakeEvent('pushsubscriptionchange'); + Object.assign(event, data); + return event as unknown as PushSubscriptionChangeEvent; +} \ No newline at end of file From 40c98477065eed9be0e1f16844780bc97533df5a Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Mon, 18 Apr 2022 15:32:07 -0700 Subject: [PATCH 6/7] Add changeset --- .changeset/four-steaks-relate.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .changeset/four-steaks-relate.md diff --git a/.changeset/four-steaks-relate.md b/.changeset/four-steaks-relate.md new file mode 100644 index 00000000000..642691b32dc --- /dev/null +++ b/.changeset/four-steaks-relate.md @@ -0,0 +1,8 @@ +--- +'@firebase/util': minor +'@firebase/app': patch +'@firebase/installations': patch +'@firebase/messaging': patch +--- + +Replace stopgap firebase/util IndexedDB methods with `idb` library. From 61bfd0e45c8989434193b3a48fccb0e8bcc5ef00 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Mon, 25 Apr 2022 10:35:48 -0700 Subject: [PATCH 7/7] format --- packages/messaging/src/listeners/sw-listeners.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/messaging/src/listeners/sw-listeners.test.ts b/packages/messaging/src/listeners/sw-listeners.test.ts index 84e8f1043dc..4019c2d5288 100644 --- a/packages/messaging/src/listeners/sw-listeners.test.ts +++ b/packages/messaging/src/listeners/sw-listeners.test.ts @@ -477,10 +477,10 @@ function makeEvent( } function makeFakePushSubscriptionChangeEvent(data: { - newSubscription: PushSubscription | null, - oldSubscription: PushSubscription | null + newSubscription: PushSubscription | null; + oldSubscription: PushSubscription | null; }): PushSubscriptionChangeEvent { const event = new FakeEvent('pushsubscriptionchange'); Object.assign(event, data); - return event as unknown as PushSubscriptionChangeEvent; -} \ No newline at end of file + return event as unknown as PushSubscriptionChangeEvent; +}