@firebase/messaging 0.12.26 → 0.13.0-20260526192810
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.esm.js +919 -206
- package/dist/esm/index.esm.js.map +1 -1
- package/dist/esm/index.sw.esm.js +798 -85
- package/dist/esm/index.sw.esm.js.map +1 -1
- package/dist/esm/src/api/onRegistered.d.ts +27 -0
- package/dist/esm/src/api/onUnregistered.d.ts +27 -0
- package/dist/esm/src/api/register.d.ts +31 -0
- package/dist/esm/src/api/unregister.d.ts +25 -0
- package/dist/esm/src/api.d.ts +59 -2
- package/dist/esm/src/helpers/fid-change-registration.d.ts +30 -0
- package/dist/esm/src/helpers/logToFirelog.d.ts +2 -0
- package/dist/esm/src/helpers/migrate-old-database.d.ts +1 -1
- package/dist/esm/src/index.d.ts +1 -1
- package/dist/esm/src/index.sw.d.ts +1 -1
- package/dist/esm/src/interfaces/internal-message-payload.d.ts +7 -1
- package/dist/esm/src/interfaces/public-types.d.ts +11 -0
- package/dist/esm/src/internals/idb-manager.d.ts +17 -4
- package/dist/esm/src/internals/register-fid.d.ts +27 -0
- package/dist/esm/src/internals/requests.d.ts +35 -1
- package/dist/esm/src/internals/token-manager.d.ts +6 -3
- package/dist/esm/src/messaging-service.d.ts +27 -2
- package/dist/esm/src/testing/fakes/token-details.d.ts +1 -1
- package/dist/esm/src/util/errors.d.ts +11 -1
- package/dist/index-public.d.ts +68 -0
- package/dist/index.cjs.js +922 -205
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.sw.cjs +799 -84
- package/dist/index.sw.cjs.map +1 -1
- package/dist/internal.d.ts +73 -0
- package/dist/private.d.ts +73 -0
- package/dist/src/api/onRegistered.d.ts +27 -0
- package/dist/src/api/onUnregistered.d.ts +27 -0
- package/dist/src/api/register.d.ts +31 -0
- package/dist/src/api/unregister.d.ts +25 -0
- package/dist/src/api.d.ts +59 -2
- package/dist/src/helpers/fid-change-registration.d.ts +30 -0
- package/dist/src/helpers/logToFirelog.d.ts +2 -0
- package/dist/src/helpers/migrate-old-database.d.ts +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.sw.d.ts +1 -1
- package/dist/src/interfaces/internal-message-payload.d.ts +7 -1
- package/dist/src/interfaces/public-types.d.ts +11 -0
- package/dist/src/internals/idb-manager.d.ts +17 -4
- package/dist/src/internals/register-fid.d.ts +27 -0
- package/dist/src/internals/requests.d.ts +35 -1
- package/dist/src/internals/token-manager.d.ts +6 -3
- package/dist/src/messaging-service.d.ts +27 -2
- package/dist/src/testing/fakes/token-details.d.ts +1 -1
- package/dist/src/util/errors.d.ts +11 -1
- package/dist/sw/index-public.d.ts +35 -1
- package/dist/sw/internal.d.ts +38 -1
- package/dist/sw/private.d.ts +38 -1
- package/package.json +2 -2
- /package/dist/esm/src/interfaces/{token-details.d.ts → registration-details.d.ts} +0 -0
- /package/dist/src/interfaces/{token-details.d.ts → registration-details.d.ts} +0 -0
package/dist/esm/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import '@firebase/installations';
|
|
1
|
+
import { onIdChange } from '@firebase/installations';
|
|
2
2
|
import { Component } from '@firebase/component';
|
|
3
3
|
import { openDB, deleteDB } from 'idb';
|
|
4
4
|
import { ErrorFactory, validateIndexedDBOpenable, isIndexedDBAvailable, areCookiesEnabled, getModularInstance } from '@firebase/util';
|
|
@@ -54,6 +54,7 @@ var MessageType;
|
|
|
54
54
|
(function (MessageType) {
|
|
55
55
|
MessageType["PUSH_RECEIVED"] = "push-received";
|
|
56
56
|
MessageType["NOTIFICATION_CLICKED"] = "notification-clicked";
|
|
57
|
+
MessageType["FID_REGISTERED"] = "fid-registered";
|
|
57
58
|
})(MessageType || (MessageType = {}));
|
|
58
59
|
|
|
59
60
|
/**
|
|
@@ -219,6 +220,53 @@ function checkTokenDetails(tokenDetails) {
|
|
|
219
220
|
subscriptionOptions.vapidKey.length > 0);
|
|
220
221
|
}
|
|
221
222
|
|
|
223
|
+
/**
|
|
224
|
+
* @license
|
|
225
|
+
* Copyright 2017 Google LLC
|
|
226
|
+
*
|
|
227
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
228
|
+
* you may not use this file except in compliance with the License.
|
|
229
|
+
* You may obtain a copy of the License at
|
|
230
|
+
*
|
|
231
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
232
|
+
*
|
|
233
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
234
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
235
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
236
|
+
* See the License for the specific language governing permissions and
|
|
237
|
+
* limitations under the License.
|
|
238
|
+
*/
|
|
239
|
+
const ERROR_MAP = {
|
|
240
|
+
["missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */]: 'Missing App configuration value: "{$valueName}"',
|
|
241
|
+
["only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */]: 'This method is available in a Window context.',
|
|
242
|
+
["only-available-in-sw" /* ErrorCode.AVAILABLE_IN_SW */]: 'This method is available in a service worker context.',
|
|
243
|
+
["permission-default" /* ErrorCode.PERMISSION_DEFAULT */]: 'The notification permission was not granted and dismissed instead.',
|
|
244
|
+
["permission-blocked" /* ErrorCode.PERMISSION_BLOCKED */]: 'The notification permission was not granted and blocked instead.',
|
|
245
|
+
["unsupported-browser" /* ErrorCode.UNSUPPORTED_BROWSER */]: "This browser doesn't support the API's required to use the Firebase SDK.",
|
|
246
|
+
["indexed-db-unsupported" /* ErrorCode.INDEXED_DB_UNSUPPORTED */]: "This browser doesn't support indexedDb.open() (ex. Safari iFrame, Firefox Private Browsing, etc)",
|
|
247
|
+
["failed-service-worker-registration" /* ErrorCode.FAILED_DEFAULT_REGISTRATION */]: 'We are unable to register the default service worker. {$browserErrorMessage}',
|
|
248
|
+
["token-subscribe-failed" /* ErrorCode.TOKEN_SUBSCRIBE_FAILED */]: 'A problem occurred while subscribing the user to FCM: {$errorInfo}',
|
|
249
|
+
["token-subscribe-no-token" /* ErrorCode.TOKEN_SUBSCRIBE_NO_TOKEN */]: 'FCM returned no token when subscribing the user to push.',
|
|
250
|
+
["fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */]: 'A problem occurred while creating an FCM registration via FID: {$errorInfo}',
|
|
251
|
+
["fid-unregister-failed" /* ErrorCode.FID_UNREGISTER_FAILED */]: 'A problem occurred while unregistering the FCM registration via FID: {$errorInfo}',
|
|
252
|
+
["fid-registration-idb-schema-unavailable" /* ErrorCode.FID_REGISTRATION_IDB_SCHEMA_UNAVAILABLE */]: 'Unable to read or persist FID registration metadata because the messaging ' +
|
|
253
|
+
'IndexedDB schema is unavailable (for example, the database could not be ' +
|
|
254
|
+
'upgraded to the latest version).',
|
|
255
|
+
["token-unsubscribe-failed" /* ErrorCode.TOKEN_UNSUBSCRIBE_FAILED */]: 'A problem occurred while unsubscribing the ' +
|
|
256
|
+
'user from FCM: {$errorInfo}',
|
|
257
|
+
["token-update-failed" /* ErrorCode.TOKEN_UPDATE_FAILED */]: 'A problem occurred while updating the user from FCM: {$errorInfo}',
|
|
258
|
+
["token-update-no-token" /* ErrorCode.TOKEN_UPDATE_NO_TOKEN */]: 'FCM returned no token when updating the user to push.',
|
|
259
|
+
["use-sw-after-get-token" /* ErrorCode.USE_SW_AFTER_GET_TOKEN */]: 'The useServiceWorker() method may only be called once and must be ' +
|
|
260
|
+
'called before calling getToken() to ensure your service worker is used.',
|
|
261
|
+
["invalid-sw-registration" /* ErrorCode.INVALID_SW_REGISTRATION */]: 'The input to useServiceWorker() must be a ServiceWorkerRegistration.',
|
|
262
|
+
["invalid-bg-handler" /* ErrorCode.INVALID_BG_HANDLER */]: 'The input to setBackgroundMessageHandler() must be a function.',
|
|
263
|
+
["invalid-vapid-key" /* ErrorCode.INVALID_VAPID_KEY */]: 'The public VAPID key must be a string.',
|
|
264
|
+
["use-vapid-key-after-get-token" /* ErrorCode.USE_VAPID_KEY_AFTER_GET_TOKEN */]: 'The usePublicVapidKey() method may only be called once and must be ' +
|
|
265
|
+
'called before calling getToken() to ensure your VAPID key is used.',
|
|
266
|
+
["invalid-on-registered-handler" /* ErrorCode.INVALID_ON_REGISTERED_HANDLER */]: 'No onRegistered callback handler was provided or registered. Implement onRegistered() before register().'
|
|
267
|
+
};
|
|
268
|
+
const ERROR_FACTORY = new ErrorFactory('messaging', 'Messaging', ERROR_MAP);
|
|
269
|
+
|
|
222
270
|
/**
|
|
223
271
|
* @license
|
|
224
272
|
* Copyright 2019 Google LLC
|
|
@@ -235,41 +283,74 @@ function checkTokenDetails(tokenDetails) {
|
|
|
235
283
|
* See the License for the specific language governing permissions and
|
|
236
284
|
* limitations under the License.
|
|
237
285
|
*/
|
|
238
|
-
// Exported for tests.
|
|
239
286
|
const DATABASE_NAME = 'firebase-messaging-database';
|
|
240
|
-
const DATABASE_VERSION =
|
|
241
|
-
const
|
|
287
|
+
const DATABASE_VERSION = 2;
|
|
288
|
+
const TOKEN_OBJECT_STORE_NAME = 'firebase-messaging-store';
|
|
289
|
+
const FID_REGISTRATION_OBJECT_STORE_NAME = 'firebase-messaging-fid-registration-store';
|
|
290
|
+
const defaultIdb = { openDB, deleteDB };
|
|
291
|
+
let idbImpl = defaultIdb;
|
|
292
|
+
// Open v2, but fall back to v1 if upgrade/open fails. Cache as `unknown` and guard store access.
|
|
242
293
|
let dbPromise = null;
|
|
294
|
+
function migrateMessagingDb(upgradeDb, oldVersion, targetSchemaVersion) {
|
|
295
|
+
// Intentional fall-through for v2: run all intermediate migrations.
|
|
296
|
+
// eslint-disable-next-line default-case
|
|
297
|
+
switch (oldVersion) {
|
|
298
|
+
case 0:
|
|
299
|
+
upgradeDb.createObjectStore(TOKEN_OBJECT_STORE_NAME);
|
|
300
|
+
if (targetSchemaVersion === 1) {
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
// fall through
|
|
304
|
+
case 1:
|
|
305
|
+
if (targetSchemaVersion === 2) {
|
|
306
|
+
upgradeDb.createObjectStore(FID_REGISTRATION_OBJECT_STORE_NAME);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
function createOpenDbOptions(targetSchemaVersion) {
|
|
311
|
+
return {
|
|
312
|
+
upgrade: (upgradeDb, oldVersion) => {
|
|
313
|
+
migrateMessagingDb(upgradeDb, oldVersion, targetSchemaVersion);
|
|
314
|
+
},
|
|
315
|
+
blocked: () => {
|
|
316
|
+
/* no-op */
|
|
317
|
+
},
|
|
318
|
+
blocking: (_currentVersion, _blockedVersion, event) => {
|
|
319
|
+
dbPromise = null;
|
|
320
|
+
event.target?.close();
|
|
321
|
+
},
|
|
322
|
+
terminated: () => {
|
|
323
|
+
dbPromise = null;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
}
|
|
243
327
|
function getDbPromise() {
|
|
244
328
|
if (!dbPromise) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
// because if there are multiple versions between the old version and the current version, we
|
|
249
|
-
// want ALL the migrations that correspond to those versions to run, not only the last one.
|
|
250
|
-
// eslint-disable-next-line default-case
|
|
251
|
-
switch (oldVersion) {
|
|
252
|
-
case 0:
|
|
253
|
-
upgradeDb.createObjectStore(OBJECT_STORE_NAME);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
});
|
|
329
|
+
const openLatest = idbImpl.openDB(DATABASE_NAME, DATABASE_VERSION, createOpenDbOptions(2));
|
|
330
|
+
// Assign synchronously to avoid concurrent openDB() calls.
|
|
331
|
+
dbPromise = openLatest.catch(() => idbImpl.openDB(DATABASE_NAME, DATABASE_VERSION - 1, createOpenDbOptions(1)));
|
|
257
332
|
}
|
|
258
333
|
return dbPromise;
|
|
259
334
|
}
|
|
260
|
-
|
|
335
|
+
function hasObjectStore(db, storeName) {
|
|
336
|
+
return db.objectStoreNames.contains(storeName);
|
|
337
|
+
}
|
|
338
|
+
function assertFidRegistrationObjectStore(db) {
|
|
339
|
+
if (!hasObjectStore(db, FID_REGISTRATION_OBJECT_STORE_NAME)) {
|
|
340
|
+
throw ERROR_FACTORY.create("fid-registration-idb-schema-unavailable" /* ErrorCode.FID_REGISTRATION_IDB_SCHEMA_UNAVAILABLE */);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
261
343
|
async function dbGet(firebaseDependencies) {
|
|
262
344
|
const key = getKey(firebaseDependencies);
|
|
263
345
|
const db = await getDbPromise();
|
|
264
346
|
const tokenDetails = (await db
|
|
265
|
-
.transaction(
|
|
266
|
-
.objectStore(
|
|
347
|
+
.transaction(TOKEN_OBJECT_STORE_NAME)
|
|
348
|
+
.objectStore(TOKEN_OBJECT_STORE_NAME)
|
|
267
349
|
.get(key));
|
|
268
350
|
if (tokenDetails) {
|
|
269
351
|
return tokenDetails;
|
|
270
352
|
}
|
|
271
353
|
else {
|
|
272
|
-
// Check if there is a tokenDetails object in the old DB.
|
|
273
354
|
const oldTokenDetails = await migrateOldDatabase(firebaseDependencies.appConfig.senderId);
|
|
274
355
|
if (oldTokenDetails) {
|
|
275
356
|
await dbSet(firebaseDependencies, oldTokenDetails);
|
|
@@ -277,67 +358,62 @@ async function dbGet(firebaseDependencies) {
|
|
|
277
358
|
}
|
|
278
359
|
}
|
|
279
360
|
}
|
|
280
|
-
/** Assigns or overwrites the record for the given key with the given value. */
|
|
281
361
|
async function dbSet(firebaseDependencies, tokenDetails) {
|
|
282
362
|
const key = getKey(firebaseDependencies);
|
|
283
363
|
const db = await getDbPromise();
|
|
284
|
-
const
|
|
285
|
-
|
|
364
|
+
const stores = [TOKEN_OBJECT_STORE_NAME];
|
|
365
|
+
const hasFidStore = hasObjectStore(db, FID_REGISTRATION_OBJECT_STORE_NAME);
|
|
366
|
+
if (hasFidStore) {
|
|
367
|
+
stores.push(FID_REGISTRATION_OBJECT_STORE_NAME);
|
|
368
|
+
}
|
|
369
|
+
const tx = db.transaction(stores, 'readwrite');
|
|
370
|
+
await tx.objectStore(TOKEN_OBJECT_STORE_NAME).put(tokenDetails, key);
|
|
371
|
+
if (hasFidStore) {
|
|
372
|
+
await tx.objectStore(FID_REGISTRATION_OBJECT_STORE_NAME).delete(key);
|
|
373
|
+
}
|
|
286
374
|
await tx.done;
|
|
287
375
|
return tokenDetails;
|
|
288
376
|
}
|
|
289
|
-
/** Removes record(s) from the objectStore that match the given key. */
|
|
290
377
|
async function dbRemove(firebaseDependencies) {
|
|
291
378
|
const key = getKey(firebaseDependencies);
|
|
292
379
|
const db = await getDbPromise();
|
|
293
|
-
const tx = db.transaction(
|
|
294
|
-
await tx.objectStore(
|
|
380
|
+
const tx = db.transaction(TOKEN_OBJECT_STORE_NAME, 'readwrite');
|
|
381
|
+
await tx.objectStore(TOKEN_OBJECT_STORE_NAME).delete(key);
|
|
382
|
+
await tx.done;
|
|
383
|
+
}
|
|
384
|
+
async function dbGetFidRegistration(firebaseDependencies) {
|
|
385
|
+
const key = getKey(firebaseDependencies);
|
|
386
|
+
const db = await getDbPromise();
|
|
387
|
+
assertFidRegistrationObjectStore(db);
|
|
388
|
+
return (await db
|
|
389
|
+
.transaction(FID_REGISTRATION_OBJECT_STORE_NAME)
|
|
390
|
+
.objectStore(FID_REGISTRATION_OBJECT_STORE_NAME)
|
|
391
|
+
.get(key));
|
|
392
|
+
}
|
|
393
|
+
async function dbSetFidRegistration(firebaseDependencies, details) {
|
|
394
|
+
const key = getKey(firebaseDependencies);
|
|
395
|
+
const db = await getDbPromise();
|
|
396
|
+
assertFidRegistrationObjectStore(db);
|
|
397
|
+
const tx = db.transaction([TOKEN_OBJECT_STORE_NAME, FID_REGISTRATION_OBJECT_STORE_NAME], 'readwrite');
|
|
398
|
+
await tx.objectStore(FID_REGISTRATION_OBJECT_STORE_NAME).put(details, key);
|
|
399
|
+
await tx.objectStore(TOKEN_OBJECT_STORE_NAME).delete(key);
|
|
400
|
+
await tx.done;
|
|
401
|
+
return details;
|
|
402
|
+
}
|
|
403
|
+
async function dbRemoveFidRegistration(firebaseDependencies) {
|
|
404
|
+
const key = getKey(firebaseDependencies);
|
|
405
|
+
const db = await getDbPromise();
|
|
406
|
+
assertFidRegistrationObjectStore(db);
|
|
407
|
+
const tx = db.transaction(FID_REGISTRATION_OBJECT_STORE_NAME, 'readwrite');
|
|
408
|
+
await tx.objectStore(FID_REGISTRATION_OBJECT_STORE_NAME).delete(key);
|
|
295
409
|
await tx.done;
|
|
296
410
|
}
|
|
297
411
|
function getKey({ appConfig }) {
|
|
298
412
|
return appConfig.appId;
|
|
299
413
|
}
|
|
300
414
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
* Copyright 2017 Google LLC
|
|
304
|
-
*
|
|
305
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
306
|
-
* you may not use this file except in compliance with the License.
|
|
307
|
-
* You may obtain a copy of the License at
|
|
308
|
-
*
|
|
309
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
310
|
-
*
|
|
311
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
312
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
313
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
314
|
-
* See the License for the specific language governing permissions and
|
|
315
|
-
* limitations under the License.
|
|
316
|
-
*/
|
|
317
|
-
const ERROR_MAP = {
|
|
318
|
-
["missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */]: 'Missing App configuration value: "{$valueName}"',
|
|
319
|
-
["only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */]: 'This method is available in a Window context.',
|
|
320
|
-
["only-available-in-sw" /* ErrorCode.AVAILABLE_IN_SW */]: 'This method is available in a service worker context.',
|
|
321
|
-
["permission-default" /* ErrorCode.PERMISSION_DEFAULT */]: 'The notification permission was not granted and dismissed instead.',
|
|
322
|
-
["permission-blocked" /* ErrorCode.PERMISSION_BLOCKED */]: 'The notification permission was not granted and blocked instead.',
|
|
323
|
-
["unsupported-browser" /* ErrorCode.UNSUPPORTED_BROWSER */]: "This browser doesn't support the API's required to use the Firebase SDK.",
|
|
324
|
-
["indexed-db-unsupported" /* ErrorCode.INDEXED_DB_UNSUPPORTED */]: "This browser doesn't support indexedDb.open() (ex. Safari iFrame, Firefox Private Browsing, etc)",
|
|
325
|
-
["failed-service-worker-registration" /* ErrorCode.FAILED_DEFAULT_REGISTRATION */]: 'We are unable to register the default service worker. {$browserErrorMessage}',
|
|
326
|
-
["token-subscribe-failed" /* ErrorCode.TOKEN_SUBSCRIBE_FAILED */]: 'A problem occurred while subscribing the user to FCM: {$errorInfo}',
|
|
327
|
-
["token-subscribe-no-token" /* ErrorCode.TOKEN_SUBSCRIBE_NO_TOKEN */]: 'FCM returned no token when subscribing the user to push.',
|
|
328
|
-
["token-unsubscribe-failed" /* ErrorCode.TOKEN_UNSUBSCRIBE_FAILED */]: 'A problem occurred while unsubscribing the ' +
|
|
329
|
-
'user from FCM: {$errorInfo}',
|
|
330
|
-
["token-update-failed" /* ErrorCode.TOKEN_UPDATE_FAILED */]: 'A problem occurred while updating the user from FCM: {$errorInfo}',
|
|
331
|
-
["token-update-no-token" /* ErrorCode.TOKEN_UPDATE_NO_TOKEN */]: 'FCM returned no token when updating the user to push.',
|
|
332
|
-
["use-sw-after-get-token" /* ErrorCode.USE_SW_AFTER_GET_TOKEN */]: 'The useServiceWorker() method may only be called once and must be ' +
|
|
333
|
-
'called before calling getToken() to ensure your service worker is used.',
|
|
334
|
-
["invalid-sw-registration" /* ErrorCode.INVALID_SW_REGISTRATION */]: 'The input to useServiceWorker() must be a ServiceWorkerRegistration.',
|
|
335
|
-
["invalid-bg-handler" /* ErrorCode.INVALID_BG_HANDLER */]: 'The input to setBackgroundMessageHandler() must be a function.',
|
|
336
|
-
["invalid-vapid-key" /* ErrorCode.INVALID_VAPID_KEY */]: 'The public VAPID key must be a string.',
|
|
337
|
-
["use-vapid-key-after-get-token" /* ErrorCode.USE_VAPID_KEY_AFTER_GET_TOKEN */]: 'The usePublicVapidKey() method may only be called once and must be ' +
|
|
338
|
-
'called before calling getToken() to ensure your VAPID key is used.'
|
|
339
|
-
};
|
|
340
|
-
const ERROR_FACTORY = new ErrorFactory('messaging', 'Messaging', ERROR_MAP);
|
|
415
|
+
const name = "@firebase/messaging";
|
|
416
|
+
const version = "0.13.0-20260526192810";
|
|
341
417
|
|
|
342
418
|
/**
|
|
343
419
|
* @license
|
|
@@ -355,9 +431,14 @@ const ERROR_FACTORY = new ErrorFactory('messaging', 'Messaging', ERROR_MAP);
|
|
|
355
431
|
* See the License for the specific language governing permissions and
|
|
356
432
|
* limitations under the License.
|
|
357
433
|
*/
|
|
434
|
+
/** Max attempts (initial fetch + retries) when CreateRegistration `fetch()` throws. */
|
|
435
|
+
const FID_REGISTRATION_FETCH_MAX_ATTEMPTS = 3;
|
|
436
|
+
/** Base delay in ms; backoff is `BASE * 2^attempt` after each failed attempt. */
|
|
437
|
+
const FID_REGISTRATION_FETCH_BASE_BACKOFF_MS = 1000;
|
|
358
438
|
async function requestGetToken(firebaseDependencies, subscriptionOptions) {
|
|
359
439
|
const headers = await getHeaders(firebaseDependencies);
|
|
360
|
-
const body = getBody(subscriptionOptions
|
|
440
|
+
const body = getBody(subscriptionOptions, firebaseDependencies.appConfig.appName,
|
|
441
|
+
/* includeSdkVersion= */ false);
|
|
361
442
|
const subscribeOptions = {
|
|
362
443
|
method: 'POST',
|
|
363
444
|
headers,
|
|
@@ -384,9 +465,128 @@ async function requestGetToken(firebaseDependencies, subscriptionOptions) {
|
|
|
384
465
|
}
|
|
385
466
|
return responseData.token;
|
|
386
467
|
}
|
|
468
|
+
async function requestCreateRegistration(firebaseDependencies, subscriptionOptions) {
|
|
469
|
+
const headers = await getHeaders(firebaseDependencies);
|
|
470
|
+
const body = getBody(subscriptionOptions, firebaseDependencies.appConfig.appName,
|
|
471
|
+
/* includeSdkVersion= */ true);
|
|
472
|
+
const subscribeOptions = {
|
|
473
|
+
method: 'POST',
|
|
474
|
+
headers,
|
|
475
|
+
body: JSON.stringify(body)
|
|
476
|
+
};
|
|
477
|
+
let response;
|
|
478
|
+
try {
|
|
479
|
+
response = await fetchWithExponentialRetry(() => fetch(getEndpoint(firebaseDependencies.appConfig), subscribeOptions), FID_REGISTRATION_FETCH_MAX_ATTEMPTS, FID_REGISTRATION_FETCH_BASE_BACKOFF_MS);
|
|
480
|
+
}
|
|
481
|
+
catch (err) {
|
|
482
|
+
throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
|
|
483
|
+
errorInfo: err?.toString()
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
if (response.ok) {
|
|
487
|
+
const responseFid = await parseCreateRegistrationSuccessFid(response);
|
|
488
|
+
return { responseFid };
|
|
489
|
+
}
|
|
490
|
+
// `fetch()` succeeded, but the backend returned a non-2xx response.
|
|
491
|
+
// Best-effort parse the body to extract `error.message`, but always fail with
|
|
492
|
+
// `FID_REGISTRATION_FAILED` to keep the error surface uniform.
|
|
493
|
+
// Best-effort extraction of error details; the main signal is response.ok / status.
|
|
494
|
+
let responseData;
|
|
495
|
+
try {
|
|
496
|
+
responseData = (await response.json());
|
|
497
|
+
}
|
|
498
|
+
catch (err) {
|
|
499
|
+
throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
|
|
500
|
+
errorInfo: response.statusText
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
const message = responseData.error?.message ?? response.statusText;
|
|
504
|
+
throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
|
|
505
|
+
errorInfo: message
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Deletes an FCM Web registration via DeleteRegistration using the Firebase Installation ID (FID).
|
|
510
|
+
*/
|
|
511
|
+
async function requestDeleteRegistration(firebaseDependencies, fid) {
|
|
512
|
+
const headers = await getHeaders(firebaseDependencies);
|
|
513
|
+
const options = {
|
|
514
|
+
method: 'DELETE',
|
|
515
|
+
headers
|
|
516
|
+
};
|
|
517
|
+
let response;
|
|
518
|
+
try {
|
|
519
|
+
response = await fetch(`${getEndpoint(firebaseDependencies.appConfig)}/${fid}`, options);
|
|
520
|
+
}
|
|
521
|
+
catch (err) {
|
|
522
|
+
throw ERROR_FACTORY.create("fid-unregister-failed" /* ErrorCode.FID_UNREGISTER_FAILED */, {
|
|
523
|
+
errorInfo: err?.toString()
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
if (response.ok) {
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
// Best-effort parse error details; surface uniform error code.
|
|
530
|
+
try {
|
|
531
|
+
const responseData = (await response.json());
|
|
532
|
+
const message = responseData.error?.message ?? response.statusText;
|
|
533
|
+
throw message;
|
|
534
|
+
}
|
|
535
|
+
catch (err) {
|
|
536
|
+
// If parsing failed, fall back to status text.
|
|
537
|
+
throw ERROR_FACTORY.create("fid-unregister-failed" /* ErrorCode.FID_UNREGISTER_FAILED */, {
|
|
538
|
+
errorInfo: (typeof err === 'string' && err) ||
|
|
539
|
+
response.statusText ||
|
|
540
|
+
err?.toString()
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Parses a successful CreateRegistration body. The backend must return JSON with a non-empty
|
|
546
|
+
* string `name`: a resource name `projects/{projectId}/registrations/{fid}`
|
|
547
|
+
*/
|
|
548
|
+
async function parseCreateRegistrationSuccessFid(response) {
|
|
549
|
+
const text = await response.text();
|
|
550
|
+
if (!text.trim()) {
|
|
551
|
+
throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
|
|
552
|
+
errorInfo: 'CreateRegistration succeeded but response body is empty'
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
let data;
|
|
556
|
+
try {
|
|
557
|
+
data = JSON.parse(text);
|
|
558
|
+
}
|
|
559
|
+
catch {
|
|
560
|
+
throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
|
|
561
|
+
errorInfo: 'CreateRegistration succeeded but response body is not valid JSON'
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
const name = data.name;
|
|
565
|
+
if (typeof name !== 'string' || name.length === 0) {
|
|
566
|
+
throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
|
|
567
|
+
errorInfo: 'CreateRegistration succeeded but response did not include a non-empty name'
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
return parseFidFromRegistrationResourceName(name);
|
|
571
|
+
}
|
|
572
|
+
const REGISTRATIONS_NAME_SEGMENT = '/registrations/';
|
|
573
|
+
/** Extracts the Firebase Installation ID from CreateRegistration `name` (resource path). */
|
|
574
|
+
function parseFidFromRegistrationResourceName(name) {
|
|
575
|
+
const segmentIndex = name.indexOf(REGISTRATIONS_NAME_SEGMENT);
|
|
576
|
+
if (segmentIndex !== -1) {
|
|
577
|
+
const fid = name.slice(segmentIndex + REGISTRATIONS_NAME_SEGMENT.length);
|
|
578
|
+
if (fid.length > 0) {
|
|
579
|
+
return fid;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
|
|
583
|
+
errorInfo: 'CreateRegistration succeeded but response name is not a valid registration resource name'
|
|
584
|
+
});
|
|
585
|
+
}
|
|
387
586
|
async function requestUpdateToken(firebaseDependencies, tokenDetails) {
|
|
388
587
|
const headers = await getHeaders(firebaseDependencies);
|
|
389
|
-
const body = getBody(tokenDetails.subscriptionOptions
|
|
588
|
+
const body = getBody(tokenDetails.subscriptionOptions, firebaseDependencies.appConfig.appName,
|
|
589
|
+
/* includeSdkVersion= */ false);
|
|
390
590
|
const updateOptions = {
|
|
391
591
|
method: 'PATCH',
|
|
392
592
|
headers,
|
|
@@ -435,6 +635,26 @@ async function requestDeleteToken(firebaseDependencies, token) {
|
|
|
435
635
|
});
|
|
436
636
|
}
|
|
437
637
|
}
|
|
638
|
+
/**
|
|
639
|
+
* Re-runs `operation` when it throws, with exponential backoff between attempts.
|
|
640
|
+
* Rethrows the last error if all attempts fail.
|
|
641
|
+
*/
|
|
642
|
+
async function fetchWithExponentialRetry(operation, maxAttempts, baseBackoffMs) {
|
|
643
|
+
let lastError;
|
|
644
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
645
|
+
try {
|
|
646
|
+
return await operation();
|
|
647
|
+
}
|
|
648
|
+
catch (err) {
|
|
649
|
+
lastError = err;
|
|
650
|
+
if (attempt < maxAttempts - 1) {
|
|
651
|
+
const delayMs = baseBackoffMs * Math.pow(2, attempt);
|
|
652
|
+
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
throw lastError;
|
|
657
|
+
}
|
|
438
658
|
function getEndpoint({ projectId }) {
|
|
439
659
|
return `${ENDPOINT}/projects/${projectId}/registrations`;
|
|
440
660
|
}
|
|
@@ -447,14 +667,45 @@ async function getHeaders({ appConfig, installations }) {
|
|
|
447
667
|
'x-goog-firebase-installations-auth': `FIS ${authToken}`
|
|
448
668
|
});
|
|
449
669
|
}
|
|
450
|
-
|
|
670
|
+
/**
|
|
671
|
+
* Hostname for the registering web client (e.g. `www.example.com`), or the app name
|
|
672
|
+
* (`appNameFallback`) when the scope cannot be resolved (e.g. some test environments).
|
|
673
|
+
*/
|
|
674
|
+
function getRegistrationOrigin(swScope, appNameFallback) {
|
|
675
|
+
try {
|
|
676
|
+
if (/^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(swScope)) {
|
|
677
|
+
return new URL(swScope).host;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
catch {
|
|
681
|
+
// Fall through to relative-scope handling.
|
|
682
|
+
}
|
|
683
|
+
try {
|
|
684
|
+
if (typeof self !== 'undefined' && self.location?.href) {
|
|
685
|
+
return new URL(swScope, self.location.origin).host;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
catch {
|
|
689
|
+
// Fall through.
|
|
690
|
+
}
|
|
691
|
+
if (typeof self !== 'undefined' && self.location?.host) {
|
|
692
|
+
return self.location.host;
|
|
693
|
+
}
|
|
694
|
+
return appNameFallback;
|
|
695
|
+
}
|
|
696
|
+
function getBody({ p256dh, auth, endpoint, vapidKey, swScope }, appNameFallback, includeSdkVersion) {
|
|
451
697
|
const body = {
|
|
452
698
|
web: {
|
|
699
|
+
origin: getRegistrationOrigin(swScope, appNameFallback),
|
|
453
700
|
endpoint,
|
|
454
701
|
auth,
|
|
455
702
|
p256dh
|
|
456
703
|
}
|
|
457
704
|
};
|
|
705
|
+
if (includeSdkVersion) {
|
|
706
|
+
// eslint-disable-next-line camelcase
|
|
707
|
+
body.fcm_sdk_version = version;
|
|
708
|
+
}
|
|
458
709
|
if (vapidKey !== DEFAULT_VAPID_KEY) {
|
|
459
710
|
body.web.applicationPubKey = vapidKey;
|
|
460
711
|
}
|
|
@@ -480,7 +731,7 @@ function getBody({ p256dh, auth, endpoint, vapidKey }) {
|
|
|
480
731
|
// UpdateRegistration will be called once every week.
|
|
481
732
|
const TOKEN_EXPIRATION_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
482
733
|
async function getTokenInternal(messaging) {
|
|
483
|
-
const pushSubscription = await getPushSubscription(messaging.swRegistration, messaging.vapidKey);
|
|
734
|
+
const pushSubscription = await getPushSubscription$1(messaging.swRegistration, messaging.vapidKey);
|
|
484
735
|
const subscriptionOptions = {
|
|
485
736
|
vapidKey: messaging.vapidKey,
|
|
486
737
|
swScope: messaging.swRegistration.scope,
|
|
@@ -518,14 +769,42 @@ async function getTokenInternal(messaging) {
|
|
|
518
769
|
}
|
|
519
770
|
}
|
|
520
771
|
/**
|
|
521
|
-
*
|
|
522
|
-
*
|
|
772
|
+
* Legacy getToken() path: there is a token row in IndexedDB. Revoke it with FCM, drop the row, and
|
|
773
|
+
* clear any leftover FID registration metadata (apps may mix APIs).
|
|
774
|
+
*/
|
|
775
|
+
async function revokeLegacyFcmTokenAndClearCaches(messaging, tokenDetails) {
|
|
776
|
+
await requestDeleteToken(messaging.firebaseDependencies, tokenDetails.token);
|
|
777
|
+
await dbRemove(messaging.firebaseDependencies);
|
|
778
|
+
await removeFidRegistrationBestEffort(messaging.firebaseDependencies);
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* No legacy token row: the client may only have FID-based registration (register() flow). If so,
|
|
782
|
+
* delete that registration on the server, always scrub local FID metadata, then surface
|
|
783
|
+
* onUnregistered when we actually had an FID.
|
|
784
|
+
*/
|
|
785
|
+
async function revokeFidRegistrationIfStored(messaging) {
|
|
786
|
+
const stored = await dbGetFidRegistration(messaging.firebaseDependencies).catch(() => undefined);
|
|
787
|
+
const fid = stored?.fid;
|
|
788
|
+
if (fid) {
|
|
789
|
+
await requestDeleteRegistration(messaging.firebaseDependencies, fid);
|
|
790
|
+
}
|
|
791
|
+
await removeFidRegistrationBestEffort(messaging.firebaseDependencies);
|
|
792
|
+
if (fid) {
|
|
793
|
+
notifyOnUnregistered(messaging, fid);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Revokes the app's FCM registration: legacy token (getToken/deleteToken) and/or FID-based
|
|
798
|
+
* registration (register/unregister), clears local caches, notifies onUnregistered when a stored
|
|
799
|
+
* FID existed, then unsubscribes the push subscription when present.
|
|
523
800
|
*/
|
|
524
|
-
async function
|
|
801
|
+
async function revokeRegistrationInternal(messaging) {
|
|
525
802
|
const tokenDetails = await dbGet(messaging.firebaseDependencies);
|
|
526
803
|
if (tokenDetails) {
|
|
527
|
-
await
|
|
528
|
-
|
|
804
|
+
await revokeLegacyFcmTokenAndClearCaches(messaging, tokenDetails);
|
|
805
|
+
}
|
|
806
|
+
else {
|
|
807
|
+
await revokeFidRegistrationIfStored(messaging);
|
|
529
808
|
}
|
|
530
809
|
// Unsubscribe from the push subscription.
|
|
531
810
|
const pushSubscription = await messaging.swRegistration.pushManager.getSubscription();
|
|
@@ -563,7 +842,7 @@ async function getNewToken(firebaseDependencies, subscriptionOptions) {
|
|
|
563
842
|
/**
|
|
564
843
|
* Gets a PushSubscription for the current user.
|
|
565
844
|
*/
|
|
566
|
-
async function getPushSubscription(swRegistration, vapidKey) {
|
|
845
|
+
async function getPushSubscription$1(swRegistration, vapidKey) {
|
|
567
846
|
const subscription = await swRegistration.pushManager.getSubscription();
|
|
568
847
|
if (subscription) {
|
|
569
848
|
return subscription;
|
|
@@ -585,6 +864,338 @@ function isTokenValid(dbOptions, currentOptions) {
|
|
|
585
864
|
const isP256dhEqual = currentOptions.p256dh === dbOptions.p256dh;
|
|
586
865
|
return isVapidKeyEqual && isEndpointEqual && isAuthEqual && isP256dhEqual;
|
|
587
866
|
}
|
|
867
|
+
/** Clears FID registration metadata; apps may mix legacy getToken() with FID register/unregister. */
|
|
868
|
+
async function removeFidRegistrationBestEffort(firebaseDependencies) {
|
|
869
|
+
try {
|
|
870
|
+
await dbRemoveFidRegistration(firebaseDependencies);
|
|
871
|
+
}
|
|
872
|
+
catch {
|
|
873
|
+
// Ignore.
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
function notifyOnRegistered(messaging, fid) {
|
|
877
|
+
const handler = messaging.onRegisteredHandler;
|
|
878
|
+
if (!handler) {
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (typeof handler === 'function') {
|
|
882
|
+
handler(fid);
|
|
883
|
+
}
|
|
884
|
+
else {
|
|
885
|
+
handler.next(fid);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
function notifyOnUnregistered(messaging, fid) {
|
|
889
|
+
const handler = messaging.onUnregisteredHandler;
|
|
890
|
+
if (!handler) {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
if (typeof handler === 'function') {
|
|
894
|
+
handler(fid);
|
|
895
|
+
}
|
|
896
|
+
else {
|
|
897
|
+
handler.next(fid);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
/**
|
|
902
|
+
* @license
|
|
903
|
+
* Copyright 2020 Google LLC
|
|
904
|
+
*
|
|
905
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
906
|
+
* you may not use this file except in compliance with the License.
|
|
907
|
+
* You may obtain a copy of the License at
|
|
908
|
+
*
|
|
909
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
910
|
+
*
|
|
911
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
912
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
913
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
914
|
+
* See the License for the specific language governing permissions and
|
|
915
|
+
* limitations under the License.
|
|
916
|
+
*/
|
|
917
|
+
async function registerDefaultSw(messaging) {
|
|
918
|
+
try {
|
|
919
|
+
messaging.swRegistration = await navigator.serviceWorker.register(DEFAULT_SW_PATH, {
|
|
920
|
+
scope: DEFAULT_SW_SCOPE
|
|
921
|
+
});
|
|
922
|
+
// The timing when browser updates sw when sw has an update is unreliable from experiment. It
|
|
923
|
+
// leads to version conflict when the SDK upgrades to a newer version in the main page, but sw
|
|
924
|
+
// is stuck with the old version. For example,
|
|
925
|
+
// https://github.com/firebase/firebase-js-sdk/issues/2590 The following line reliably updates
|
|
926
|
+
// sw if there was an update.
|
|
927
|
+
messaging.swRegistration.update().catch(() => {
|
|
928
|
+
/* it is non blocking and we don't care if it failed */
|
|
929
|
+
});
|
|
930
|
+
await waitForRegistrationActive(messaging.swRegistration);
|
|
931
|
+
}
|
|
932
|
+
catch (e) {
|
|
933
|
+
throw ERROR_FACTORY.create("failed-service-worker-registration" /* ErrorCode.FAILED_DEFAULT_REGISTRATION */, {
|
|
934
|
+
browserErrorMessage: e?.message
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* Waits for registration to become active. MDN documentation claims that
|
|
940
|
+
* a service worker registration should be ready to use after awaiting
|
|
941
|
+
* navigator.serviceWorker.register() but that doesn't seem to be the case in
|
|
942
|
+
* practice, causing the SDK to throw errors when calling
|
|
943
|
+
* swRegistration.pushManager.subscribe() too soon after register(). The only
|
|
944
|
+
* solution seems to be waiting for the service worker registration `state`
|
|
945
|
+
* to become "active".
|
|
946
|
+
*/
|
|
947
|
+
async function waitForRegistrationActive(registration) {
|
|
948
|
+
return new Promise((resolve, reject) => {
|
|
949
|
+
const rejectTimeout = setTimeout(() => reject(new Error(`Service worker not registered after ${DEFAULT_REGISTRATION_TIMEOUT} ms`)), DEFAULT_REGISTRATION_TIMEOUT);
|
|
950
|
+
const incomingSw = registration.installing || registration.waiting;
|
|
951
|
+
if (registration.active) {
|
|
952
|
+
clearTimeout(rejectTimeout);
|
|
953
|
+
resolve();
|
|
954
|
+
}
|
|
955
|
+
else if (incomingSw) {
|
|
956
|
+
incomingSw.onstatechange = ev => {
|
|
957
|
+
if (ev.target?.state === 'activated') {
|
|
958
|
+
incomingSw.onstatechange = null;
|
|
959
|
+
clearTimeout(rejectTimeout);
|
|
960
|
+
resolve();
|
|
961
|
+
}
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
else {
|
|
965
|
+
clearTimeout(rejectTimeout);
|
|
966
|
+
reject(new Error('No incoming service worker found.'));
|
|
967
|
+
}
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
/**
|
|
972
|
+
* @license
|
|
973
|
+
* Copyright 2020 Google LLC
|
|
974
|
+
*
|
|
975
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
976
|
+
* you may not use this file except in compliance with the License.
|
|
977
|
+
* You may obtain a copy of the License at
|
|
978
|
+
*
|
|
979
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
980
|
+
*
|
|
981
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
982
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
983
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
984
|
+
* See the License for the specific language governing permissions and
|
|
985
|
+
* limitations under the License.
|
|
986
|
+
*/
|
|
987
|
+
async function updateSwReg(messaging, swRegistration) {
|
|
988
|
+
if (!swRegistration && !messaging.swRegistration) {
|
|
989
|
+
await registerDefaultSw(messaging);
|
|
990
|
+
}
|
|
991
|
+
if (!swRegistration && !!messaging.swRegistration) {
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
if (!(swRegistration instanceof ServiceWorkerRegistration)) {
|
|
995
|
+
throw ERROR_FACTORY.create("invalid-sw-registration" /* ErrorCode.INVALID_SW_REGISTRATION */);
|
|
996
|
+
}
|
|
997
|
+
messaging.swRegistration = swRegistration;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
/**
|
|
1001
|
+
* @license
|
|
1002
|
+
* Copyright 2020 Google LLC
|
|
1003
|
+
*
|
|
1004
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1005
|
+
* you may not use this file except in compliance with the License.
|
|
1006
|
+
* You may obtain a copy of the License at
|
|
1007
|
+
*
|
|
1008
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1009
|
+
*
|
|
1010
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
1011
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1012
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1013
|
+
* See the License for the specific language governing permissions and
|
|
1014
|
+
* limitations under the License.
|
|
1015
|
+
*/
|
|
1016
|
+
async function updateVapidKey(messaging, vapidKey) {
|
|
1017
|
+
if (!!vapidKey) {
|
|
1018
|
+
messaging.vapidKey = vapidKey;
|
|
1019
|
+
}
|
|
1020
|
+
else if (!messaging.vapidKey) {
|
|
1021
|
+
messaging.vapidKey = DEFAULT_VAPID_KEY;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* @license
|
|
1027
|
+
* Copyright 2020 Google LLC
|
|
1028
|
+
*
|
|
1029
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1030
|
+
* you may not use this file except in compliance with the License.
|
|
1031
|
+
* You may obtain a copy of the License at
|
|
1032
|
+
*
|
|
1033
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1034
|
+
*
|
|
1035
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
1036
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1037
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1038
|
+
* See the License for the specific language governing permissions and
|
|
1039
|
+
* limitations under the License.
|
|
1040
|
+
*/
|
|
1041
|
+
/** Retries when CreateRegistration echoes an FID that does not match Installations.getId(). */
|
|
1042
|
+
const FID_REGISTRATION_FID_MATCH_MAX_ATTEMPTS = 3;
|
|
1043
|
+
/**
|
|
1044
|
+
* For the new FID-based register path:
|
|
1045
|
+
* - Create (or refresh) an FCM Web registration in the backend via CreateRegistration.
|
|
1046
|
+
* - Use the FIS auth token produced by the installations instance (implicitly associated with FID).
|
|
1047
|
+
* - CreateRegistration must echo the installation in `name` (e.g.
|
|
1048
|
+
* `projects/{projectId}/registrations/{fid}`); it must match `expectedFid` from
|
|
1049
|
+
* Installations.getId(). On mismatch we refresh the auth token and retry, then fail with
|
|
1050
|
+
* `fid-registration-failed`.
|
|
1051
|
+
*/
|
|
1052
|
+
async function registerFcmRegistrationWithFid(messaging, expectedFid) {
|
|
1053
|
+
const pushSubscription = await getPushSubscription(messaging.swRegistration, messaging.vapidKey);
|
|
1054
|
+
const subscriptionOptions = {
|
|
1055
|
+
vapidKey: messaging.vapidKey,
|
|
1056
|
+
swScope: messaging.swRegistration.scope,
|
|
1057
|
+
endpoint: pushSubscription.endpoint,
|
|
1058
|
+
auth: arrayToBase64(pushSubscription.getKey('auth')),
|
|
1059
|
+
p256dh: arrayToBase64(pushSubscription.getKey('p256dh'))
|
|
1060
|
+
};
|
|
1061
|
+
const installations = messaging.firebaseDependencies.installations;
|
|
1062
|
+
for (let attempt = 0; attempt < FID_REGISTRATION_FID_MATCH_MAX_ATTEMPTS; attempt++) {
|
|
1063
|
+
const { responseFid } = await requestCreateRegistration(messaging.firebaseDependencies, subscriptionOptions);
|
|
1064
|
+
if (responseFid === expectedFid) {
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
// If CreateRegistration echoes an unexpected FID, the FIS auth token used for the request may
|
|
1068
|
+
// be stale relative to the installation the backend associates with the call. Force-refresh
|
|
1069
|
+
// the token before retrying so the next attempt uses credentials aligned with Installations.
|
|
1070
|
+
if (attempt < FID_REGISTRATION_FID_MATCH_MAX_ATTEMPTS - 1) {
|
|
1071
|
+
await installations.getToken(true);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
|
|
1075
|
+
errorInfo: 'CreateRegistration response FID does not match Firebase Installation ID'
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
async function getPushSubscription(swRegistration, vapidKey) {
|
|
1079
|
+
const subscription = await swRegistration.pushManager.getSubscription();
|
|
1080
|
+
if (subscription) {
|
|
1081
|
+
return subscription;
|
|
1082
|
+
}
|
|
1083
|
+
// Chrome/Firefox require applicationServerKey to be of type Uint8Array.
|
|
1084
|
+
return swRegistration.pushManager.subscribe({
|
|
1085
|
+
userVisibleOnly: true,
|
|
1086
|
+
// `PushManager.subscribe` expects a `BufferSource`; `base64ToArray` produces a typed array.
|
|
1087
|
+
// Cast to satisfy the lib typing differences across TS DOM versions.
|
|
1088
|
+
applicationServerKey: base64ToArray(vapidKey)
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* @license
|
|
1094
|
+
* Copyright 2020 Google LLC
|
|
1095
|
+
*
|
|
1096
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1097
|
+
* you may not use this file except in compliance with the License.
|
|
1098
|
+
* You may obtain a copy of the License at
|
|
1099
|
+
*
|
|
1100
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1101
|
+
*
|
|
1102
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
1103
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1104
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1105
|
+
* See the License for the specific language governing permissions and
|
|
1106
|
+
* limitations under the License.
|
|
1107
|
+
*/
|
|
1108
|
+
const FID_REGISTRATION_REFRESH_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
1109
|
+
/**
|
|
1110
|
+
* Registers the app instance with FCM using its Firebase Installation ID (FID). The FID is
|
|
1111
|
+
* delivered via the `onRegistered` callback. Call this to establish an FID-based identity.
|
|
1112
|
+
* Once `onRegistered` provides an FID, instruct your backend to remove any legacy token
|
|
1113
|
+
* previously associated with this instance. The backend send API supports FID as a target.
|
|
1114
|
+
*
|
|
1115
|
+
* When called multiple times, `onRegistered` is invoked on each call with the current FID.
|
|
1116
|
+
* Backend registration sync runs on first register, when the FID changes, or on weekly refresh.
|
|
1117
|
+
*
|
|
1118
|
+
* @param messaging - The MessagingService instance.
|
|
1119
|
+
* @param options - Optional. Same options as getToken (vapidKey, serviceWorkerRegistration).
|
|
1120
|
+
*/
|
|
1121
|
+
async function register$1(messaging, options) {
|
|
1122
|
+
if (!navigator) {
|
|
1123
|
+
throw ERROR_FACTORY.create("only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */);
|
|
1124
|
+
}
|
|
1125
|
+
if (Notification.permission === 'default') {
|
|
1126
|
+
await Notification.requestPermission();
|
|
1127
|
+
}
|
|
1128
|
+
if (Notification.permission !== 'granted') {
|
|
1129
|
+
throw ERROR_FACTORY.create("permission-blocked" /* ErrorCode.PERMISSION_BLOCKED */);
|
|
1130
|
+
}
|
|
1131
|
+
if (!messaging.onRegisteredHandler) {
|
|
1132
|
+
throw ERROR_FACTORY.create("invalid-on-registered-handler" /* ErrorCode.INVALID_ON_REGISTERED_HANDLER */);
|
|
1133
|
+
}
|
|
1134
|
+
await updateVapidKey(messaging, options?.vapidKey);
|
|
1135
|
+
await updateSwReg(messaging, options?.serviceWorkerRegistration);
|
|
1136
|
+
// Keep the queue alive after a failed register() so future calls can retry.
|
|
1137
|
+
const prev = messaging._registerNotifyChain.catch(() => { });
|
|
1138
|
+
messaging._registerNotifyChain = prev.then(async () => {
|
|
1139
|
+
const fid = await messaging.firebaseDependencies.installations.getId();
|
|
1140
|
+
const stored = await dbGetFidRegistration(messaging.firebaseDependencies);
|
|
1141
|
+
const now = Date.now();
|
|
1142
|
+
const shouldRefresh = !stored ||
|
|
1143
|
+
stored.fid !== fid ||
|
|
1144
|
+
now >= stored.lastRegisterTime + FID_REGISTRATION_REFRESH_MS;
|
|
1145
|
+
if (shouldRefresh) {
|
|
1146
|
+
await registerFcmRegistrationWithFid(messaging, fid);
|
|
1147
|
+
await dbSetFidRegistration(messaging.firebaseDependencies, {
|
|
1148
|
+
fid,
|
|
1149
|
+
lastRegisterTime: now,
|
|
1150
|
+
vapidKey: messaging.vapidKey
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
const handler = messaging.onRegisteredHandler;
|
|
1154
|
+
if (!handler) {
|
|
1155
|
+
throw ERROR_FACTORY.create("invalid-on-registered-handler" /* ErrorCode.INVALID_ON_REGISTERED_HANDLER */);
|
|
1156
|
+
}
|
|
1157
|
+
notifyOnRegistered(messaging, fid);
|
|
1158
|
+
});
|
|
1159
|
+
return messaging._registerNotifyChain;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/**
|
|
1163
|
+
* @license
|
|
1164
|
+
* Copyright 2026 Google LLC
|
|
1165
|
+
*
|
|
1166
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1167
|
+
* you may not use this file except in compliance with the License.
|
|
1168
|
+
* You may obtain a copy of the License at
|
|
1169
|
+
*
|
|
1170
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1171
|
+
*
|
|
1172
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
1173
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1174
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1175
|
+
* See the License for the specific language governing permissions and
|
|
1176
|
+
* limitations under the License.
|
|
1177
|
+
*/
|
|
1178
|
+
/**
|
|
1179
|
+
* When the Firebase Installation ID changes, re-run `register()` so FCM registration and
|
|
1180
|
+
* onRegistered run for the new FID. No-op if no onRegistered handler is set or the app
|
|
1181
|
+
* instance was never registered with FCM.
|
|
1182
|
+
*/
|
|
1183
|
+
function subscribeFidChangeRegistration(messaging, installations) {
|
|
1184
|
+
return onIdChange(installations, () => {
|
|
1185
|
+
void (async () => {
|
|
1186
|
+
if (!messaging.onRegisteredHandler) {
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
const stored = await dbGetFidRegistration(messaging.firebaseDependencies);
|
|
1190
|
+
if (!stored) {
|
|
1191
|
+
return;
|
|
1192
|
+
}
|
|
1193
|
+
await register$1(messaging).catch(() => {
|
|
1194
|
+
// Best-effort: permission may be revoked or SW unavailable after FID rotation.
|
|
1195
|
+
});
|
|
1196
|
+
})();
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
588
1199
|
|
|
589
1200
|
/**
|
|
590
1201
|
* @license
|
|
@@ -783,8 +1394,25 @@ class MessagingService {
|
|
|
783
1394
|
this.deliveryMetricsExportedToBigQueryEnabled = false;
|
|
784
1395
|
this.onBackgroundMessageHandler = null;
|
|
785
1396
|
this.onMessageHandler = null;
|
|
1397
|
+
/** Observer for the event that the app instance is registered with FCM via Firebase Installation ID (FID). */
|
|
1398
|
+
this.onRegisteredHandler = null;
|
|
1399
|
+
/** Observer for the event that the app instance is unregistered from FCM (FID no longer active). */
|
|
1400
|
+
this.onUnregisteredHandler = null;
|
|
1401
|
+
/**
|
|
1402
|
+
* Serializes the FID get + compare + notify step so concurrent register() calls
|
|
1403
|
+
* do not race each other.
|
|
1404
|
+
*/
|
|
1405
|
+
this._registerNotifyChain = Promise.resolve();
|
|
1406
|
+
/** Unsubscribe from Installations `onIdChange` when messaging is deleted. */
|
|
1407
|
+
this._fidChangeUnsubscribe = null;
|
|
786
1408
|
this.logEvents = [];
|
|
787
|
-
|
|
1409
|
+
/**
|
|
1410
|
+
* Single source of truth for the logging loop lifecycle.
|
|
1411
|
+
*
|
|
1412
|
+
* `scheduled` holds the active timer id; `flushing` indicates an async dispatch
|
|
1413
|
+
* is in progress (prevents duplicate starts); `stopped` means idle.
|
|
1414
|
+
*/
|
|
1415
|
+
this.logQueue = { state: 'stopped' };
|
|
788
1416
|
const appConfig = extractAppConfig(app);
|
|
789
1417
|
this.firebaseDependencies = {
|
|
790
1418
|
app,
|
|
@@ -794,131 +1422,15 @@ class MessagingService {
|
|
|
794
1422
|
};
|
|
795
1423
|
}
|
|
796
1424
|
_delete() {
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
/**
|
|
802
|
-
* @license
|
|
803
|
-
* Copyright 2020 Google LLC
|
|
804
|
-
*
|
|
805
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
806
|
-
* you may not use this file except in compliance with the License.
|
|
807
|
-
* You may obtain a copy of the License at
|
|
808
|
-
*
|
|
809
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
810
|
-
*
|
|
811
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
812
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
813
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
814
|
-
* See the License for the specific language governing permissions and
|
|
815
|
-
* limitations under the License.
|
|
816
|
-
*/
|
|
817
|
-
async function registerDefaultSw(messaging) {
|
|
818
|
-
try {
|
|
819
|
-
messaging.swRegistration = await navigator.serviceWorker.register(DEFAULT_SW_PATH, {
|
|
820
|
-
scope: DEFAULT_SW_SCOPE
|
|
821
|
-
});
|
|
822
|
-
// The timing when browser updates sw when sw has an update is unreliable from experiment. It
|
|
823
|
-
// leads to version conflict when the SDK upgrades to a newer version in the main page, but sw
|
|
824
|
-
// is stuck with the old version. For example,
|
|
825
|
-
// https://github.com/firebase/firebase-js-sdk/issues/2590 The following line reliably updates
|
|
826
|
-
// sw if there was an update.
|
|
827
|
-
messaging.swRegistration.update().catch(() => {
|
|
828
|
-
/* it is non blocking and we don't care if it failed */
|
|
829
|
-
});
|
|
830
|
-
await waitForRegistrationActive(messaging.swRegistration);
|
|
831
|
-
}
|
|
832
|
-
catch (e) {
|
|
833
|
-
throw ERROR_FACTORY.create("failed-service-worker-registration" /* ErrorCode.FAILED_DEFAULT_REGISTRATION */, {
|
|
834
|
-
browserErrorMessage: e?.message
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
/**
|
|
839
|
-
* Waits for registration to become active. MDN documentation claims that
|
|
840
|
-
* a service worker registration should be ready to use after awaiting
|
|
841
|
-
* navigator.serviceWorker.register() but that doesn't seem to be the case in
|
|
842
|
-
* practice, causing the SDK to throw errors when calling
|
|
843
|
-
* swRegistration.pushManager.subscribe() too soon after register(). The only
|
|
844
|
-
* solution seems to be waiting for the service worker registration `state`
|
|
845
|
-
* to become "active".
|
|
846
|
-
*/
|
|
847
|
-
async function waitForRegistrationActive(registration) {
|
|
848
|
-
return new Promise((resolve, reject) => {
|
|
849
|
-
const rejectTimeout = setTimeout(() => reject(new Error(`Service worker not registered after ${DEFAULT_REGISTRATION_TIMEOUT} ms`)), DEFAULT_REGISTRATION_TIMEOUT);
|
|
850
|
-
const incomingSw = registration.installing || registration.waiting;
|
|
851
|
-
if (registration.active) {
|
|
852
|
-
clearTimeout(rejectTimeout);
|
|
853
|
-
resolve();
|
|
854
|
-
}
|
|
855
|
-
else if (incomingSw) {
|
|
856
|
-
incomingSw.onstatechange = ev => {
|
|
857
|
-
if (ev.target?.state === 'activated') {
|
|
858
|
-
incomingSw.onstatechange = null;
|
|
859
|
-
clearTimeout(rejectTimeout);
|
|
860
|
-
resolve();
|
|
861
|
-
}
|
|
862
|
-
};
|
|
1425
|
+
if (this._fidChangeUnsubscribe) {
|
|
1426
|
+
this._fidChangeUnsubscribe();
|
|
1427
|
+
this._fidChangeUnsubscribe = null;
|
|
863
1428
|
}
|
|
864
|
-
|
|
865
|
-
clearTimeout(
|
|
866
|
-
reject(new Error('No incoming service worker found.'));
|
|
1429
|
+
if (this.logQueue.state === 'scheduled') {
|
|
1430
|
+
clearTimeout(this.logQueue.timerId);
|
|
867
1431
|
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
/**
|
|
872
|
-
* @license
|
|
873
|
-
* Copyright 2020 Google LLC
|
|
874
|
-
*
|
|
875
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
876
|
-
* you may not use this file except in compliance with the License.
|
|
877
|
-
* You may obtain a copy of the License at
|
|
878
|
-
*
|
|
879
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
880
|
-
*
|
|
881
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
882
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
883
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
884
|
-
* See the License for the specific language governing permissions and
|
|
885
|
-
* limitations under the License.
|
|
886
|
-
*/
|
|
887
|
-
async function updateSwReg(messaging, swRegistration) {
|
|
888
|
-
if (!swRegistration && !messaging.swRegistration) {
|
|
889
|
-
await registerDefaultSw(messaging);
|
|
890
|
-
}
|
|
891
|
-
if (!swRegistration && !!messaging.swRegistration) {
|
|
892
|
-
return;
|
|
893
|
-
}
|
|
894
|
-
if (!(swRegistration instanceof ServiceWorkerRegistration)) {
|
|
895
|
-
throw ERROR_FACTORY.create("invalid-sw-registration" /* ErrorCode.INVALID_SW_REGISTRATION */);
|
|
896
|
-
}
|
|
897
|
-
messaging.swRegistration = swRegistration;
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
/**
|
|
901
|
-
* @license
|
|
902
|
-
* Copyright 2020 Google LLC
|
|
903
|
-
*
|
|
904
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
905
|
-
* you may not use this file except in compliance with the License.
|
|
906
|
-
* You may obtain a copy of the License at
|
|
907
|
-
*
|
|
908
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
909
|
-
*
|
|
910
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
911
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
912
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
913
|
-
* See the License for the specific language governing permissions and
|
|
914
|
-
* limitations under the License.
|
|
915
|
-
*/
|
|
916
|
-
async function updateVapidKey(messaging, vapidKey) {
|
|
917
|
-
if (!!vapidKey) {
|
|
918
|
-
messaging.vapidKey = vapidKey;
|
|
919
|
-
}
|
|
920
|
-
else if (!messaging.vapidKey) {
|
|
921
|
-
messaging.vapidKey = DEFAULT_VAPID_KEY;
|
|
1432
|
+
this.logQueue = { state: 'stopped' };
|
|
1433
|
+
return Promise.resolve();
|
|
922
1434
|
}
|
|
923
1435
|
}
|
|
924
1436
|
|
|
@@ -1022,6 +1534,16 @@ async function messageEventListener(messaging, event) {
|
|
|
1022
1534
|
messaging.onMessageHandler.next(externalizePayload(internalPayload));
|
|
1023
1535
|
}
|
|
1024
1536
|
}
|
|
1537
|
+
if (messaging.onRegisteredHandler &&
|
|
1538
|
+
internalPayload.messageType === MessageType.FID_REGISTERED) {
|
|
1539
|
+
const fid = internalPayload.fid;
|
|
1540
|
+
if (typeof messaging.onRegisteredHandler === 'function') {
|
|
1541
|
+
messaging.onRegisteredHandler(fid);
|
|
1542
|
+
}
|
|
1543
|
+
else {
|
|
1544
|
+
messaging.onRegisteredHandler.next(fid);
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1025
1547
|
// Log to Scion if applicable
|
|
1026
1548
|
const dataPayload = internalPayload.data;
|
|
1027
1549
|
if (isConsoleMessage(dataPayload) &&
|
|
@@ -1030,9 +1552,6 @@ async function messageEventListener(messaging, event) {
|
|
|
1030
1552
|
}
|
|
1031
1553
|
}
|
|
1032
1554
|
|
|
1033
|
-
const name = "@firebase/messaging";
|
|
1034
|
-
const version = "0.12.26";
|
|
1035
|
-
|
|
1036
1555
|
/**
|
|
1037
1556
|
* @license
|
|
1038
1557
|
* Copyright 2020 Google LLC
|
|
@@ -1052,6 +1571,7 @@ const version = "0.12.26";
|
|
|
1052
1571
|
const WindowMessagingFactory = (container) => {
|
|
1053
1572
|
const messaging = new MessagingService(container.getProvider('app').getImmediate(), container.getProvider('installations-internal').getImmediate(), container.getProvider('analytics-internal'));
|
|
1054
1573
|
navigator.serviceWorker.addEventListener('message', e => messageEventListener(messaging, e));
|
|
1574
|
+
messaging._fidChangeUnsubscribe = subscribeFidChangeRegistration(messaging, container.getProvider('installations').getImmediate());
|
|
1055
1575
|
return messaging;
|
|
1056
1576
|
};
|
|
1057
1577
|
const WindowMessagingInternalFactory = (container) => {
|
|
@@ -1059,7 +1579,8 @@ const WindowMessagingInternalFactory = (container) => {
|
|
|
1059
1579
|
.getProvider('messaging')
|
|
1060
1580
|
.getImmediate();
|
|
1061
1581
|
const messagingInternal = {
|
|
1062
|
-
getToken: (options) => getToken$1(messaging, options)
|
|
1582
|
+
getToken: (options) => getToken$1(messaging, options),
|
|
1583
|
+
register: (options) => register$1(messaging, options)
|
|
1063
1584
|
};
|
|
1064
1585
|
return messagingInternal;
|
|
1065
1586
|
};
|
|
@@ -1139,7 +1660,7 @@ async function deleteToken$1(messaging) {
|
|
|
1139
1660
|
if (!messaging.swRegistration) {
|
|
1140
1661
|
await registerDefaultSw(messaging);
|
|
1141
1662
|
}
|
|
1142
|
-
return
|
|
1663
|
+
return revokeRegistrationInternal(messaging);
|
|
1143
1664
|
}
|
|
1144
1665
|
|
|
1145
1666
|
/**
|
|
@@ -1168,6 +1689,129 @@ function onMessage$1(messaging, nextOrObserver) {
|
|
|
1168
1689
|
};
|
|
1169
1690
|
}
|
|
1170
1691
|
|
|
1692
|
+
/**
|
|
1693
|
+
* @license
|
|
1694
|
+
* Copyright 2020 Google LLC
|
|
1695
|
+
*
|
|
1696
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1697
|
+
* you may not use this file except in compliance with the License.
|
|
1698
|
+
* You may obtain a copy of the License at
|
|
1699
|
+
*
|
|
1700
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1701
|
+
*
|
|
1702
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
1703
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1704
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1705
|
+
* See the License for the specific language governing permissions and
|
|
1706
|
+
* limitations under the License.
|
|
1707
|
+
*/
|
|
1708
|
+
/**
|
|
1709
|
+
* Subscribes to an event that the app instance is registered with FCM via Firebase Installation ID (FID).
|
|
1710
|
+
* Use the FID passed to the callback to upload it to your application server.
|
|
1711
|
+
*
|
|
1712
|
+
* @param messaging - The {@link MessagingService} instance.
|
|
1713
|
+
* @param nextOrObserver - A function or observer object called when an FID is registered.
|
|
1714
|
+
* @returns Unsubscribe function to stop listening.
|
|
1715
|
+
*/
|
|
1716
|
+
function onRegistered$1(messaging, nextOrObserver) {
|
|
1717
|
+
messaging.onRegisteredHandler = nextOrObserver;
|
|
1718
|
+
return () => {
|
|
1719
|
+
if (messaging.onRegisteredHandler === nextOrObserver) {
|
|
1720
|
+
messaging.onRegisteredHandler = null;
|
|
1721
|
+
}
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
/**
|
|
1726
|
+
* @license
|
|
1727
|
+
* Copyright 2026 Google LLC
|
|
1728
|
+
*
|
|
1729
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1730
|
+
* you may not use this file except in compliance with the License.
|
|
1731
|
+
* You may obtain a copy of the License at
|
|
1732
|
+
*
|
|
1733
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1734
|
+
*
|
|
1735
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
1736
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1737
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1738
|
+
* See the License for the specific language governing permissions and
|
|
1739
|
+
* limitations under the License.
|
|
1740
|
+
*/
|
|
1741
|
+
/**
|
|
1742
|
+
* Subscribes to an event that the app instance is unregistered from FCM so the FID is no longer active.
|
|
1743
|
+
* Use this to notify your backend to remove this FID to prevent 404 errors on send.
|
|
1744
|
+
*
|
|
1745
|
+
* @param messaging - The {@link MessagingService} instance.
|
|
1746
|
+
* @param nextOrObserver - A function or observer object called with the unregistered FID.
|
|
1747
|
+
* @returns Unsubscribe function to stop listening.
|
|
1748
|
+
*/
|
|
1749
|
+
function onUnregistered$1(messaging, nextOrObserver) {
|
|
1750
|
+
messaging.onUnregisteredHandler = nextOrObserver;
|
|
1751
|
+
return () => {
|
|
1752
|
+
if (messaging.onUnregisteredHandler === nextOrObserver) {
|
|
1753
|
+
messaging.onUnregisteredHandler = null;
|
|
1754
|
+
}
|
|
1755
|
+
};
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
/**
|
|
1759
|
+
* @license
|
|
1760
|
+
* Copyright 2026 Google LLC
|
|
1761
|
+
*
|
|
1762
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1763
|
+
* you may not use this file except in compliance with the License.
|
|
1764
|
+
* You may obtain a copy of the License at
|
|
1765
|
+
*
|
|
1766
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1767
|
+
*
|
|
1768
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
1769
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1770
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1771
|
+
* See the License for the specific language governing permissions and
|
|
1772
|
+
* limitations under the License.
|
|
1773
|
+
*/
|
|
1774
|
+
/**
|
|
1775
|
+
* Unregisters the app instance from FCM by deleting its FID-based registration.
|
|
1776
|
+
*
|
|
1777
|
+
* On success, triggers the `onUnregistered` callback (if set) with the unregistered FID.
|
|
1778
|
+
*
|
|
1779
|
+
* @param messaging - The MessagingService instance.
|
|
1780
|
+
*/
|
|
1781
|
+
async function unregister$1(messaging) {
|
|
1782
|
+
if (!navigator) {
|
|
1783
|
+
throw ERROR_FACTORY.create("only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */);
|
|
1784
|
+
}
|
|
1785
|
+
// Prefer the last successfully registered FID from local metadata when available.
|
|
1786
|
+
const stored = await dbGetFidRegistration(messaging.firebaseDependencies).catch(() => undefined);
|
|
1787
|
+
const fid = stored?.fid ?? (await messaging.firebaseDependencies.installations.getId());
|
|
1788
|
+
await requestDeleteRegistration(messaging.firebaseDependencies, fid);
|
|
1789
|
+
// Best-effort local cleanup; still resolve even if schema is unavailable.
|
|
1790
|
+
try {
|
|
1791
|
+
await dbRemoveFidRegistration(messaging.firebaseDependencies);
|
|
1792
|
+
}
|
|
1793
|
+
catch {
|
|
1794
|
+
// Ignore.
|
|
1795
|
+
}
|
|
1796
|
+
// Best-effort cleanup of legacy token details created via getToken().
|
|
1797
|
+
try {
|
|
1798
|
+
await dbRemove(messaging.firebaseDependencies);
|
|
1799
|
+
}
|
|
1800
|
+
catch {
|
|
1801
|
+
// Ignore.
|
|
1802
|
+
}
|
|
1803
|
+
const handler = messaging.onUnregisteredHandler;
|
|
1804
|
+
if (!handler) {
|
|
1805
|
+
return;
|
|
1806
|
+
}
|
|
1807
|
+
if (typeof handler === 'function') {
|
|
1808
|
+
handler(fid);
|
|
1809
|
+
}
|
|
1810
|
+
else {
|
|
1811
|
+
handler.next(fid);
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1171
1815
|
/**
|
|
1172
1816
|
* @license
|
|
1173
1817
|
* Copyright 2017 Google LLC
|
|
@@ -1220,6 +1864,9 @@ function getMessagingInWindow(app = getApp()) {
|
|
|
1220
1864
|
*
|
|
1221
1865
|
* @returns The promise resolves with an FCM registration token.
|
|
1222
1866
|
*
|
|
1867
|
+
* @deprecated Use {@link register} together with {@link onRegistered} for Firebase
|
|
1868
|
+
* Installation ID-based messaging instead of retrieving an FCM registration token with this API.
|
|
1869
|
+
*
|
|
1223
1870
|
* @public
|
|
1224
1871
|
*/
|
|
1225
1872
|
async function getToken(messaging, options) {
|
|
@@ -1230,10 +1877,18 @@ async function getToken(messaging, options) {
|
|
|
1230
1877
|
* Deletes the registration token associated with this {@link Messaging} instance and unsubscribes
|
|
1231
1878
|
* the {@link Messaging} instance from the push subscription.
|
|
1232
1879
|
*
|
|
1880
|
+
* If there is no legacy registration token but the client has FID-based registration metadata
|
|
1881
|
+
* (from {@link register}), this deletes that registration on the server, clears local metadata, and
|
|
1882
|
+
* invokes {@link onUnregistered} with the removed FID when successful.
|
|
1883
|
+
*
|
|
1233
1884
|
* @param messaging - The {@link Messaging} instance.
|
|
1234
1885
|
*
|
|
1235
1886
|
* @returns The promise resolves when the token has been successfully deleted.
|
|
1236
1887
|
*
|
|
1888
|
+
* @deprecated Use {@link onUnregistered} to observe when the client is no longer
|
|
1889
|
+
* registered and update your backend accordingly, instead of explicitly deleting the
|
|
1890
|
+
* registration token with this API.
|
|
1891
|
+
*
|
|
1237
1892
|
* @public
|
|
1238
1893
|
*/
|
|
1239
1894
|
function deleteToken(messaging) {
|
|
@@ -1257,6 +1912,64 @@ function onMessage(messaging, nextOrObserver) {
|
|
|
1257
1912
|
messaging = getModularInstance(messaging);
|
|
1258
1913
|
return onMessage$1(messaging, nextOrObserver);
|
|
1259
1914
|
}
|
|
1915
|
+
/**
|
|
1916
|
+
* Registers the app instance with FCM using its Firebase Installation ID (FID). The FID is
|
|
1917
|
+
* delivered via the {@link onRegistered} callback, not as a return value. Call this to establish
|
|
1918
|
+
* an FID-based identity; once {@link onRegistered} provides an FID, instruct your backend to
|
|
1919
|
+
* remove any legacy token previously associated with this instance. The backend send API
|
|
1920
|
+
* supports FID as a target.
|
|
1921
|
+
*
|
|
1922
|
+
* @param messaging - The {@link Messaging} instance.
|
|
1923
|
+
* @param options - Optional. VAPID key and/or service worker registration (same as getToken).
|
|
1924
|
+
* @returns Promise that resolves when registration has been initiated; FID is delivered via onRegistered.
|
|
1925
|
+
*
|
|
1926
|
+
* @public
|
|
1927
|
+
*/
|
|
1928
|
+
async function register(messaging, options) {
|
|
1929
|
+
messaging = getModularInstance(messaging);
|
|
1930
|
+
return register$1(messaging, options);
|
|
1931
|
+
}
|
|
1932
|
+
/**
|
|
1933
|
+
* Unregisters the app instance from FCM by deleting its FID-based registration.
|
|
1934
|
+
* On success, triggers {@link onUnregistered} (if registered) with the unregistered FID.
|
|
1935
|
+
*
|
|
1936
|
+
* @param messaging - The {@link Messaging} instance.
|
|
1937
|
+
*
|
|
1938
|
+
* @public
|
|
1939
|
+
*/
|
|
1940
|
+
async function unregister(messaging) {
|
|
1941
|
+
messaging = getModularInstance(messaging);
|
|
1942
|
+
return unregister$1(messaging);
|
|
1943
|
+
}
|
|
1944
|
+
/**
|
|
1945
|
+
* Subscribes to an event that the app instance is registered with FCM via Firebase Installation ID (FID).
|
|
1946
|
+
* Use the FID passed to the callback to upload it to your application server. When you receive an FID
|
|
1947
|
+
* after calling {@link register}, instruct your backend to remove any legacy token for this instance.
|
|
1948
|
+
*
|
|
1949
|
+
* @param messaging - The {@link Messaging} instance.
|
|
1950
|
+
* @param nextOrObserver - A function or observer object called when an FID is registered.
|
|
1951
|
+
* @returns Unsubscribe function to stop listening.
|
|
1952
|
+
*
|
|
1953
|
+
* @public
|
|
1954
|
+
*/
|
|
1955
|
+
function onRegistered(messaging, nextOrObserver) {
|
|
1956
|
+
messaging = getModularInstance(messaging);
|
|
1957
|
+
return onRegistered$1(messaging, nextOrObserver);
|
|
1958
|
+
}
|
|
1959
|
+
/**
|
|
1960
|
+
* Subscribes to an event that the app instance is unregistered from FCM (FID no longer active).
|
|
1961
|
+
* Use this to notify your backend to remove this FID to prevent 404 errors on send.
|
|
1962
|
+
*
|
|
1963
|
+
* @param messaging - The {@link Messaging} instance.
|
|
1964
|
+
* @param nextOrObserver - A function or observer object called with the unregistered FID.
|
|
1965
|
+
* @returns Unsubscribe function to stop listening.
|
|
1966
|
+
*
|
|
1967
|
+
* @public
|
|
1968
|
+
*/
|
|
1969
|
+
function onUnregistered(messaging, nextOrObserver) {
|
|
1970
|
+
messaging = getModularInstance(messaging);
|
|
1971
|
+
return onUnregistered$1(messaging, nextOrObserver);
|
|
1972
|
+
}
|
|
1260
1973
|
|
|
1261
1974
|
/**
|
|
1262
1975
|
* The Firebase Cloud Messaging Web SDK.
|
|
@@ -1266,5 +1979,5 @@ function onMessage(messaging, nextOrObserver) {
|
|
|
1266
1979
|
*/
|
|
1267
1980
|
registerMessagingInWindow();
|
|
1268
1981
|
|
|
1269
|
-
export { deleteToken, getMessagingInWindow as getMessaging, getToken, isWindowSupported as isSupported, onMessage };
|
|
1982
|
+
export { deleteToken, getMessagingInWindow as getMessaging, getToken, isWindowSupported as isSupported, onMessage, onRegistered, onUnregistered, register, unregister };
|
|
1270
1983
|
//# sourceMappingURL=index.esm.js.map
|