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