@firebase/messaging 0.12.26-20260505185142 → 0.12.26-eap-crashlytics.3dd4e65d9

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.
Files changed (51) hide show
  1. package/dist/esm/index.esm.js +773 -79
  2. package/dist/esm/index.esm.js.map +1 -1
  3. package/dist/esm/index.sw.esm.js +496 -77
  4. package/dist/esm/index.sw.esm.js.map +1 -1
  5. package/dist/esm/src/api/onRegistered.d.ts +27 -0
  6. package/dist/esm/src/api/onUnregistered.d.ts +27 -0
  7. package/dist/esm/src/api/register.d.ts +31 -0
  8. package/dist/esm/src/api/unregister.d.ts +25 -0
  9. package/dist/esm/src/api.d.ts +59 -2
  10. package/dist/esm/src/helpers/fid-change-registration.d.ts +24 -0
  11. package/dist/esm/src/helpers/logToFirelog.d.ts +2 -0
  12. package/dist/esm/src/helpers/migrate-old-database.d.ts +1 -1
  13. package/dist/esm/src/index.d.ts +1 -1
  14. package/dist/esm/src/index.sw.d.ts +1 -1
  15. package/dist/esm/src/interfaces/public-types.d.ts +11 -0
  16. package/dist/esm/src/internals/idb-manager.d.ts +16 -4
  17. package/dist/esm/src/internals/register-fid.d.ts +27 -0
  18. package/dist/esm/src/internals/requests.d.ts +35 -1
  19. package/dist/esm/src/messaging-service.d.ts +27 -2
  20. package/dist/esm/src/testing/fakes/token-details.d.ts +1 -1
  21. package/dist/esm/src/util/errors.d.ts +11 -1
  22. package/dist/index-public.d.ts +68 -0
  23. package/dist/index.cjs.js +776 -78
  24. package/dist/index.cjs.js.map +1 -1
  25. package/dist/index.sw.cjs +497 -76
  26. package/dist/index.sw.cjs.map +1 -1
  27. package/dist/internal.d.ts +73 -0
  28. package/dist/private.d.ts +73 -0
  29. package/dist/src/api/onRegistered.d.ts +27 -0
  30. package/dist/src/api/onUnregistered.d.ts +27 -0
  31. package/dist/src/api/register.d.ts +31 -0
  32. package/dist/src/api/unregister.d.ts +25 -0
  33. package/dist/src/api.d.ts +59 -2
  34. package/dist/src/helpers/fid-change-registration.d.ts +24 -0
  35. package/dist/src/helpers/logToFirelog.d.ts +2 -0
  36. package/dist/src/helpers/migrate-old-database.d.ts +1 -1
  37. package/dist/src/index.d.ts +1 -1
  38. package/dist/src/index.sw.d.ts +1 -1
  39. package/dist/src/interfaces/public-types.d.ts +11 -0
  40. package/dist/src/internals/idb-manager.d.ts +16 -4
  41. package/dist/src/internals/register-fid.d.ts +27 -0
  42. package/dist/src/internals/requests.d.ts +35 -1
  43. package/dist/src/messaging-service.d.ts +27 -2
  44. package/dist/src/testing/fakes/token-details.d.ts +1 -1
  45. package/dist/src/util/errors.d.ts +11 -1
  46. package/dist/sw/index-public.d.ts +35 -1
  47. package/dist/sw/internal.d.ts +38 -1
  48. package/dist/sw/private.d.ts +38 -1
  49. package/package.json +7 -7
  50. /package/dist/esm/src/interfaces/{token-details.d.ts → registration-details.d.ts} +0 -0
  51. /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');
@@ -223,6 +223,53 @@ function checkTokenDetails(tokenDetails) {
223
223
  subscriptionOptions.vapidKey.length > 0);
224
224
  }
225
225
 
226
+ /**
227
+ * @license
228
+ * Copyright 2017 Google LLC
229
+ *
230
+ * Licensed under the Apache License, Version 2.0 (the "License");
231
+ * you may not use this file except in compliance with the License.
232
+ * You may obtain a copy of the License at
233
+ *
234
+ * http://www.apache.org/licenses/LICENSE-2.0
235
+ *
236
+ * Unless required by applicable law or agreed to in writing, software
237
+ * distributed under the License is distributed on an "AS IS" BASIS,
238
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
239
+ * See the License for the specific language governing permissions and
240
+ * limitations under the License.
241
+ */
242
+ const ERROR_MAP = {
243
+ ["missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */]: 'Missing App configuration value: "{$valueName}"',
244
+ ["only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */]: 'This method is available in a Window context.',
245
+ ["only-available-in-sw" /* ErrorCode.AVAILABLE_IN_SW */]: 'This method is available in a service worker context.',
246
+ ["permission-default" /* ErrorCode.PERMISSION_DEFAULT */]: 'The notification permission was not granted and dismissed instead.',
247
+ ["permission-blocked" /* ErrorCode.PERMISSION_BLOCKED */]: 'The notification permission was not granted and blocked instead.',
248
+ ["unsupported-browser" /* ErrorCode.UNSUPPORTED_BROWSER */]: "This browser doesn't support the API's required to use the Firebase SDK.",
249
+ ["indexed-db-unsupported" /* ErrorCode.INDEXED_DB_UNSUPPORTED */]: "This browser doesn't support indexedDb.open() (ex. Safari iFrame, Firefox Private Browsing, etc)",
250
+ ["failed-service-worker-registration" /* ErrorCode.FAILED_DEFAULT_REGISTRATION */]: 'We are unable to register the default service worker. {$browserErrorMessage}',
251
+ ["token-subscribe-failed" /* ErrorCode.TOKEN_SUBSCRIBE_FAILED */]: 'A problem occurred while subscribing the user to FCM: {$errorInfo}',
252
+ ["token-subscribe-no-token" /* ErrorCode.TOKEN_SUBSCRIBE_NO_TOKEN */]: 'FCM returned no token when subscribing the user to push.',
253
+ ["fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */]: 'A problem occurred while creating an FCM registration via FID: {$errorInfo}',
254
+ ["fid-unregister-failed" /* ErrorCode.FID_UNREGISTER_FAILED */]: 'A problem occurred while unregistering the FCM registration via FID: {$errorInfo}',
255
+ ["fid-registration-idb-schema-unavailable" /* ErrorCode.FID_REGISTRATION_IDB_SCHEMA_UNAVAILABLE */]: 'Unable to read or persist FID registration metadata because the messaging ' +
256
+ 'IndexedDB schema is unavailable (for example, the database could not be ' +
257
+ 'upgraded to the latest version).',
258
+ ["token-unsubscribe-failed" /* ErrorCode.TOKEN_UNSUBSCRIBE_FAILED */]: 'A problem occurred while unsubscribing the ' +
259
+ 'user from FCM: {$errorInfo}',
260
+ ["token-update-failed" /* ErrorCode.TOKEN_UPDATE_FAILED */]: 'A problem occurred while updating the user from FCM: {$errorInfo}',
261
+ ["token-update-no-token" /* ErrorCode.TOKEN_UPDATE_NO_TOKEN */]: 'FCM returned no token when updating the user to push.',
262
+ ["use-sw-after-get-token" /* ErrorCode.USE_SW_AFTER_GET_TOKEN */]: 'The useServiceWorker() method may only be called once and must be ' +
263
+ 'called before calling getToken() to ensure your service worker is used.',
264
+ ["invalid-sw-registration" /* ErrorCode.INVALID_SW_REGISTRATION */]: 'The input to useServiceWorker() must be a ServiceWorkerRegistration.',
265
+ ["invalid-bg-handler" /* ErrorCode.INVALID_BG_HANDLER */]: 'The input to setBackgroundMessageHandler() must be a function.',
266
+ ["invalid-vapid-key" /* ErrorCode.INVALID_VAPID_KEY */]: 'The public VAPID key must be a string.',
267
+ ["use-vapid-key-after-get-token" /* ErrorCode.USE_VAPID_KEY_AFTER_GET_TOKEN */]: 'The usePublicVapidKey() method may only be called once and must be ' +
268
+ 'called before calling getToken() to ensure your VAPID key is used.',
269
+ ["invalid-on-registered-handler" /* ErrorCode.INVALID_ON_REGISTERED_HANDLER */]: 'No onRegistered callback handler was provided or registered. Implement onRegistered() before register().'
270
+ };
271
+ const ERROR_FACTORY = new util.ErrorFactory('messaging', 'Messaging', ERROR_MAP);
272
+
226
273
  /**
227
274
  * @license
228
275
  * Copyright 2019 Google LLC
@@ -239,41 +286,74 @@ function checkTokenDetails(tokenDetails) {
239
286
  * See the License for the specific language governing permissions and
240
287
  * limitations under the License.
241
288
  */
242
- // Exported for tests.
243
289
  const DATABASE_NAME = 'firebase-messaging-database';
244
- const DATABASE_VERSION = 1;
245
- const OBJECT_STORE_NAME = 'firebase-messaging-store';
290
+ const DATABASE_VERSION = 2;
291
+ const TOKEN_OBJECT_STORE_NAME = 'firebase-messaging-store';
292
+ const FID_REGISTRATION_OBJECT_STORE_NAME = 'firebase-messaging-fid-registration-store';
293
+ const defaultIdb = { openDB: idb.openDB, deleteDB: idb.deleteDB };
294
+ let idbImpl = defaultIdb;
295
+ // Open v2, but fall back to v1 if upgrade/open fails. Cache as `unknown` and guard store access.
246
296
  let dbPromise = null;
297
+ function migrateMessagingDb(upgradeDb, oldVersion, targetSchemaVersion) {
298
+ // Intentional fall-through for v2: run all intermediate migrations.
299
+ // eslint-disable-next-line default-case
300
+ switch (oldVersion) {
301
+ case 0:
302
+ upgradeDb.createObjectStore(TOKEN_OBJECT_STORE_NAME);
303
+ if (targetSchemaVersion === 1) {
304
+ break;
305
+ }
306
+ // fall through
307
+ case 1:
308
+ if (targetSchemaVersion === 2) {
309
+ upgradeDb.createObjectStore(FID_REGISTRATION_OBJECT_STORE_NAME);
310
+ }
311
+ }
312
+ }
313
+ function createOpenDbOptions(targetSchemaVersion) {
314
+ return {
315
+ upgrade: (upgradeDb, oldVersion) => {
316
+ migrateMessagingDb(upgradeDb, oldVersion, targetSchemaVersion);
317
+ },
318
+ blocked: () => {
319
+ /* no-op */
320
+ },
321
+ blocking: (_currentVersion, _blockedVersion, event) => {
322
+ dbPromise = null;
323
+ event.target?.close();
324
+ },
325
+ terminated: () => {
326
+ dbPromise = null;
327
+ }
328
+ };
329
+ }
247
330
  function getDbPromise() {
248
331
  if (!dbPromise) {
249
- dbPromise = idb.openDB(DATABASE_NAME, DATABASE_VERSION, {
250
- upgrade: (upgradeDb, oldVersion) => {
251
- // We don't use 'break' in this switch statement, the fall-through behavior is what we want,
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
- });
332
+ const openLatest = idbImpl.openDB(DATABASE_NAME, DATABASE_VERSION, createOpenDbOptions(2));
333
+ // Assign synchronously to avoid concurrent openDB() calls.
334
+ dbPromise = openLatest.catch(() => idbImpl.openDB(DATABASE_NAME, DATABASE_VERSION - 1, createOpenDbOptions(1)));
261
335
  }
262
336
  return dbPromise;
263
337
  }
264
- /** Gets record(s) from the objectStore that match the given key. */
338
+ function hasObjectStore(db, storeName) {
339
+ return db.objectStoreNames.contains(storeName);
340
+ }
341
+ function assertFidRegistrationObjectStore(db) {
342
+ if (!hasObjectStore(db, FID_REGISTRATION_OBJECT_STORE_NAME)) {
343
+ throw ERROR_FACTORY.create("fid-registration-idb-schema-unavailable" /* ErrorCode.FID_REGISTRATION_IDB_SCHEMA_UNAVAILABLE */);
344
+ }
345
+ }
265
346
  async function dbGet(firebaseDependencies) {
266
347
  const key = getKey(firebaseDependencies);
267
348
  const db = await getDbPromise();
268
349
  const tokenDetails = (await db
269
- .transaction(OBJECT_STORE_NAME)
270
- .objectStore(OBJECT_STORE_NAME)
350
+ .transaction(TOKEN_OBJECT_STORE_NAME)
351
+ .objectStore(TOKEN_OBJECT_STORE_NAME)
271
352
  .get(key));
272
353
  if (tokenDetails) {
273
354
  return tokenDetails;
274
355
  }
275
356
  else {
276
- // Check if there is a tokenDetails object in the old DB.
277
357
  const oldTokenDetails = await migrateOldDatabase(firebaseDependencies.appConfig.senderId);
278
358
  if (oldTokenDetails) {
279
359
  await dbSet(firebaseDependencies, oldTokenDetails);
@@ -281,67 +361,53 @@ async function dbGet(firebaseDependencies) {
281
361
  }
282
362
  }
283
363
  }
284
- /** Assigns or overwrites the record for the given key with the given value. */
285
364
  async function dbSet(firebaseDependencies, tokenDetails) {
286
365
  const key = getKey(firebaseDependencies);
287
366
  const db = await getDbPromise();
288
- const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
289
- await tx.objectStore(OBJECT_STORE_NAME).put(tokenDetails, key);
367
+ const tx = db.transaction(TOKEN_OBJECT_STORE_NAME, 'readwrite');
368
+ await tx.objectStore(TOKEN_OBJECT_STORE_NAME).put(tokenDetails, key);
290
369
  await tx.done;
291
370
  return tokenDetails;
292
371
  }
293
- /** Removes record(s) from the objectStore that match the given key. */
294
372
  async function dbRemove(firebaseDependencies) {
295
373
  const key = getKey(firebaseDependencies);
296
374
  const db = await getDbPromise();
297
- const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
298
- await tx.objectStore(OBJECT_STORE_NAME).delete(key);
375
+ const tx = db.transaction(TOKEN_OBJECT_STORE_NAME, 'readwrite');
376
+ await tx.objectStore(TOKEN_OBJECT_STORE_NAME).delete(key);
377
+ await tx.done;
378
+ }
379
+ async function dbGetFidRegistration(firebaseDependencies) {
380
+ const key = getKey(firebaseDependencies);
381
+ const db = await getDbPromise();
382
+ assertFidRegistrationObjectStore(db);
383
+ return (await db
384
+ .transaction(FID_REGISTRATION_OBJECT_STORE_NAME)
385
+ .objectStore(FID_REGISTRATION_OBJECT_STORE_NAME)
386
+ .get(key));
387
+ }
388
+ async function dbSetFidRegistration(firebaseDependencies, details) {
389
+ const key = getKey(firebaseDependencies);
390
+ const db = await getDbPromise();
391
+ assertFidRegistrationObjectStore(db);
392
+ const tx = db.transaction(FID_REGISTRATION_OBJECT_STORE_NAME, 'readwrite');
393
+ await tx.objectStore(FID_REGISTRATION_OBJECT_STORE_NAME).put(details, key);
394
+ await tx.done;
395
+ return details;
396
+ }
397
+ async function dbRemoveFidRegistration(firebaseDependencies) {
398
+ const key = getKey(firebaseDependencies);
399
+ const db = await getDbPromise();
400
+ assertFidRegistrationObjectStore(db);
401
+ const tx = db.transaction(FID_REGISTRATION_OBJECT_STORE_NAME, 'readwrite');
402
+ await tx.objectStore(FID_REGISTRATION_OBJECT_STORE_NAME).delete(key);
299
403
  await tx.done;
300
404
  }
301
405
  function getKey({ appConfig }) {
302
406
  return appConfig.appId;
303
407
  }
304
408
 
305
- /**
306
- * @license
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);
409
+ const name = "@firebase/messaging";
410
+ const version = "0.12.26-eap-crashlytics.3dd4e65d9";
345
411
 
346
412
  /**
347
413
  * @license
@@ -359,9 +425,14 @@ const ERROR_FACTORY = new util.ErrorFactory('messaging', 'Messaging', ERROR_MAP)
359
425
  * See the License for the specific language governing permissions and
360
426
  * limitations under the License.
361
427
  */
428
+ /** Max attempts (initial fetch + retries) when CreateRegistration `fetch()` throws. */
429
+ const FID_REGISTRATION_FETCH_MAX_ATTEMPTS = 3;
430
+ /** Base delay in ms; backoff is `BASE * 2^attempt` after each failed attempt. */
431
+ const FID_REGISTRATION_FETCH_BASE_BACKOFF_MS = 1000;
362
432
  async function requestGetToken(firebaseDependencies, subscriptionOptions) {
363
433
  const headers = await getHeaders(firebaseDependencies);
364
- const body = getBody(subscriptionOptions);
434
+ const body = getBody(subscriptionOptions, firebaseDependencies.appConfig.appName,
435
+ /* includeSdkVersion= */ false);
365
436
  const subscribeOptions = {
366
437
  method: 'POST',
367
438
  headers,
@@ -388,9 +459,128 @@ async function requestGetToken(firebaseDependencies, subscriptionOptions) {
388
459
  }
389
460
  return responseData.token;
390
461
  }
462
+ async function requestCreateRegistration(firebaseDependencies, subscriptionOptions) {
463
+ const headers = await getHeaders(firebaseDependencies);
464
+ const body = getBody(subscriptionOptions, firebaseDependencies.appConfig.appName,
465
+ /* includeSdkVersion= */ true);
466
+ const subscribeOptions = {
467
+ method: 'POST',
468
+ headers,
469
+ body: JSON.stringify(body)
470
+ };
471
+ let response;
472
+ try {
473
+ response = await fetchWithExponentialRetry(() => fetch(getEndpoint(firebaseDependencies.appConfig), subscribeOptions), FID_REGISTRATION_FETCH_MAX_ATTEMPTS, FID_REGISTRATION_FETCH_BASE_BACKOFF_MS);
474
+ }
475
+ catch (err) {
476
+ throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
477
+ errorInfo: err?.toString()
478
+ });
479
+ }
480
+ if (response.ok) {
481
+ const responseFid = await parseCreateRegistrationSuccessFid(response);
482
+ return { responseFid };
483
+ }
484
+ // `fetch()` succeeded, but the backend returned a non-2xx response.
485
+ // Best-effort parse the body to extract `error.message`, but always fail with
486
+ // `FID_REGISTRATION_FAILED` to keep the error surface uniform.
487
+ // Best-effort extraction of error details; the main signal is response.ok / status.
488
+ let responseData;
489
+ try {
490
+ responseData = (await response.json());
491
+ }
492
+ catch (err) {
493
+ throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
494
+ errorInfo: response.statusText
495
+ });
496
+ }
497
+ const message = responseData.error?.message ?? response.statusText;
498
+ throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
499
+ errorInfo: message
500
+ });
501
+ }
502
+ /**
503
+ * Deletes an FCM Web registration via DeleteRegistration using the Firebase Installation ID (FID).
504
+ */
505
+ async function requestDeleteRegistration(firebaseDependencies, fid) {
506
+ const headers = await getHeaders(firebaseDependencies);
507
+ const options = {
508
+ method: 'DELETE',
509
+ headers
510
+ };
511
+ let response;
512
+ try {
513
+ response = await fetch(`${getEndpoint(firebaseDependencies.appConfig)}/${fid}`, options);
514
+ }
515
+ catch (err) {
516
+ throw ERROR_FACTORY.create("fid-unregister-failed" /* ErrorCode.FID_UNREGISTER_FAILED */, {
517
+ errorInfo: err?.toString()
518
+ });
519
+ }
520
+ if (response.ok) {
521
+ return;
522
+ }
523
+ // Best-effort parse error details; surface uniform error code.
524
+ try {
525
+ const responseData = (await response.json());
526
+ const message = responseData.error?.message ?? response.statusText;
527
+ throw message;
528
+ }
529
+ catch (err) {
530
+ // If parsing failed, fall back to status text.
531
+ throw ERROR_FACTORY.create("fid-unregister-failed" /* ErrorCode.FID_UNREGISTER_FAILED */, {
532
+ errorInfo: (typeof err === 'string' && err) ||
533
+ response.statusText ||
534
+ err?.toString()
535
+ });
536
+ }
537
+ }
538
+ /**
539
+ * Parses a successful CreateRegistration body. The backend must return JSON with a non-empty
540
+ * string `name`: a resource name `projects/{projectId}/registrations/{fid}`
541
+ */
542
+ async function parseCreateRegistrationSuccessFid(response) {
543
+ const text = await response.text();
544
+ if (!text.trim()) {
545
+ throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
546
+ errorInfo: 'CreateRegistration succeeded but response body is empty'
547
+ });
548
+ }
549
+ let data;
550
+ try {
551
+ data = JSON.parse(text);
552
+ }
553
+ catch {
554
+ throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
555
+ errorInfo: 'CreateRegistration succeeded but response body is not valid JSON'
556
+ });
557
+ }
558
+ const name = data.name;
559
+ if (typeof name !== 'string' || name.length === 0) {
560
+ throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
561
+ errorInfo: 'CreateRegistration succeeded but response did not include a non-empty name'
562
+ });
563
+ }
564
+ return parseFidFromRegistrationResourceName(name);
565
+ }
566
+ const REGISTRATIONS_NAME_SEGMENT = '/registrations/';
567
+ /** Extracts the Firebase Installation ID from CreateRegistration `name` (resource path). */
568
+ function parseFidFromRegistrationResourceName(name) {
569
+ const segmentIndex = name.indexOf(REGISTRATIONS_NAME_SEGMENT);
570
+ if (segmentIndex !== -1) {
571
+ const fid = name.slice(segmentIndex + REGISTRATIONS_NAME_SEGMENT.length);
572
+ if (fid.length > 0) {
573
+ return fid;
574
+ }
575
+ }
576
+ throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
577
+ errorInfo: 'CreateRegistration succeeded but response name is not a valid registration resource name'
578
+ });
579
+ }
391
580
  async function requestUpdateToken(firebaseDependencies, tokenDetails) {
392
581
  const headers = await getHeaders(firebaseDependencies);
393
- const body = getBody(tokenDetails.subscriptionOptions);
582
+ const body = getBody(tokenDetails.subscriptionOptions, firebaseDependencies.appConfig.appName,
583
+ /* includeSdkVersion= */ false);
394
584
  const updateOptions = {
395
585
  method: 'PATCH',
396
586
  headers,
@@ -439,6 +629,26 @@ async function requestDeleteToken(firebaseDependencies, token) {
439
629
  });
440
630
  }
441
631
  }
632
+ /**
633
+ * Re-runs `operation` when it throws, with exponential backoff between attempts.
634
+ * Rethrows the last error if all attempts fail.
635
+ */
636
+ async function fetchWithExponentialRetry(operation, maxAttempts, baseBackoffMs) {
637
+ let lastError;
638
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
639
+ try {
640
+ return await operation();
641
+ }
642
+ catch (err) {
643
+ lastError = err;
644
+ if (attempt < maxAttempts - 1) {
645
+ const delayMs = baseBackoffMs * Math.pow(2, attempt);
646
+ await new Promise(resolve => setTimeout(resolve, delayMs));
647
+ }
648
+ }
649
+ }
650
+ throw lastError;
651
+ }
442
652
  function getEndpoint({ projectId }) {
443
653
  return `${ENDPOINT}/projects/${projectId}/registrations`;
444
654
  }
@@ -451,14 +661,45 @@ async function getHeaders({ appConfig, installations }) {
451
661
  'x-goog-firebase-installations-auth': `FIS ${authToken}`
452
662
  });
453
663
  }
454
- function getBody({ p256dh, auth, endpoint, vapidKey }) {
664
+ /**
665
+ * Hostname for the registering web client (e.g. `www.example.com`), or the app name
666
+ * (`appNameFallback`) when the scope cannot be resolved (e.g. some test environments).
667
+ */
668
+ function getRegistrationOrigin(swScope, appNameFallback) {
669
+ try {
670
+ if (/^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(swScope)) {
671
+ return new URL(swScope).host;
672
+ }
673
+ }
674
+ catch {
675
+ // Fall through to relative-scope handling.
676
+ }
677
+ try {
678
+ if (typeof self !== 'undefined' && self.location?.href) {
679
+ return new URL(swScope, self.location.origin).host;
680
+ }
681
+ }
682
+ catch {
683
+ // Fall through.
684
+ }
685
+ if (typeof self !== 'undefined' && self.location?.host) {
686
+ return self.location.host;
687
+ }
688
+ return appNameFallback;
689
+ }
690
+ function getBody({ p256dh, auth, endpoint, vapidKey, swScope }, appNameFallback, includeSdkVersion) {
455
691
  const body = {
456
692
  web: {
693
+ origin: getRegistrationOrigin(swScope, appNameFallback),
457
694
  endpoint,
458
695
  auth,
459
696
  p256dh
460
697
  }
461
698
  };
699
+ if (includeSdkVersion) {
700
+ // eslint-disable-next-line camelcase
701
+ body.fcm_sdk_version = version;
702
+ }
462
703
  if (vapidKey !== DEFAULT_VAPID_KEY) {
463
704
  body.web.applicationPubKey = vapidKey;
464
705
  }
@@ -484,7 +725,7 @@ function getBody({ p256dh, auth, endpoint, vapidKey }) {
484
725
  // UpdateRegistration will be called once every week.
485
726
  const TOKEN_EXPIRATION_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
486
727
  async function getTokenInternal(messaging) {
487
- const pushSubscription = await getPushSubscription(messaging.swRegistration, messaging.vapidKey);
728
+ const pushSubscription = await getPushSubscription$1(messaging.swRegistration, messaging.vapidKey);
488
729
  const subscriptionOptions = {
489
730
  vapidKey: messaging.vapidKey,
490
731
  swScope: messaging.swRegistration.scope,
@@ -492,6 +733,8 @@ async function getTokenInternal(messaging) {
492
733
  auth: arrayToBase64(pushSubscription.getKey('auth')),
493
734
  p256dh: arrayToBase64(pushSubscription.getKey('p256dh'))
494
735
  };
736
+ // Best-effort cleanup when switching from FID register/unregister to legacy getToken().
737
+ await removeFidRegistrationBestEffort(messaging.firebaseDependencies);
495
738
  const tokenDetails = await dbGet(messaging.firebaseDependencies);
496
739
  if (!tokenDetails) {
497
740
  // No token, get a new one.
@@ -521,6 +764,31 @@ async function getTokenInternal(messaging) {
521
764
  return tokenDetails.token;
522
765
  }
523
766
  }
767
+ /**
768
+ * Legacy getToken() path: there is a token row in IndexedDB. Revoke it with FCM, drop the row, and
769
+ * clear any leftover FID registration metadata (apps may mix APIs).
770
+ */
771
+ async function revokeLegacyFcmTokenAndClearCaches(messaging, tokenDetails) {
772
+ await requestDeleteToken(messaging.firebaseDependencies, tokenDetails.token);
773
+ await dbRemove(messaging.firebaseDependencies);
774
+ await removeFidRegistrationBestEffort(messaging.firebaseDependencies);
775
+ }
776
+ /**
777
+ * No legacy token row: the client may only have FID-based registration (register() flow). If so,
778
+ * delete that registration on the server, always scrub local FID metadata, then surface
779
+ * onUnregistered when we actually had an FID.
780
+ */
781
+ async function revokeFidRegistrationIfStored(messaging) {
782
+ const stored = await dbGetFidRegistration(messaging.firebaseDependencies).catch(() => undefined);
783
+ const fid = stored?.fid;
784
+ if (fid) {
785
+ await requestDeleteRegistration(messaging.firebaseDependencies, fid);
786
+ }
787
+ await removeFidRegistrationBestEffort(messaging.firebaseDependencies);
788
+ if (fid) {
789
+ notifyOnUnregistered(messaging, fid);
790
+ }
791
+ }
524
792
  /**
525
793
  * This method deletes the token from the database, unsubscribes the token from FCM, and unregisters
526
794
  * the push subscription if it exists.
@@ -528,8 +796,10 @@ async function getTokenInternal(messaging) {
528
796
  async function deleteTokenInternal(messaging) {
529
797
  const tokenDetails = await dbGet(messaging.firebaseDependencies);
530
798
  if (tokenDetails) {
531
- await requestDeleteToken(messaging.firebaseDependencies, tokenDetails.token);
532
- await dbRemove(messaging.firebaseDependencies);
799
+ await revokeLegacyFcmTokenAndClearCaches(messaging, tokenDetails);
800
+ }
801
+ else {
802
+ await revokeFidRegistrationIfStored(messaging);
533
803
  }
534
804
  // Unsubscribe from the push subscription.
535
805
  const pushSubscription = await messaging.swRegistration.pushManager.getSubscription();
@@ -567,7 +837,7 @@ async function getNewToken(firebaseDependencies, subscriptionOptions) {
567
837
  /**
568
838
  * Gets a PushSubscription for the current user.
569
839
  */
570
- async function getPushSubscription(swRegistration, vapidKey) {
840
+ async function getPushSubscription$1(swRegistration, vapidKey) {
571
841
  const subscription = await swRegistration.pushManager.getSubscription();
572
842
  if (subscription) {
573
843
  return subscription;
@@ -589,6 +859,27 @@ function isTokenValid(dbOptions, currentOptions) {
589
859
  const isP256dhEqual = currentOptions.p256dh === dbOptions.p256dh;
590
860
  return isVapidKeyEqual && isEndpointEqual && isAuthEqual && isP256dhEqual;
591
861
  }
862
+ /** Clears FID registration metadata; apps may mix legacy getToken() with FID register/unregister. */
863
+ async function removeFidRegistrationBestEffort(firebaseDependencies) {
864
+ try {
865
+ await dbRemoveFidRegistration(firebaseDependencies);
866
+ }
867
+ catch {
868
+ // Ignore.
869
+ }
870
+ }
871
+ function notifyOnUnregistered(messaging, fid) {
872
+ const handler = messaging.onUnregisteredHandler;
873
+ if (!handler) {
874
+ return;
875
+ }
876
+ if (typeof handler === 'function') {
877
+ handler(fid);
878
+ }
879
+ else {
880
+ handler.next(fid);
881
+ }
882
+ }
592
883
 
593
884
  /**
594
885
  * @license
@@ -787,8 +1078,25 @@ class MessagingService {
787
1078
  this.deliveryMetricsExportedToBigQueryEnabled = false;
788
1079
  this.onBackgroundMessageHandler = null;
789
1080
  this.onMessageHandler = null;
1081
+ /** Observer for the event that the app instance is registered with FCM via Firebase Installation ID (FID). */
1082
+ this.onRegisteredHandler = null;
1083
+ /** Observer for the event that the app instance is unregistered from FCM (FID no longer active). */
1084
+ this.onUnregisteredHandler = null;
1085
+ /**
1086
+ * Serializes the FID get + compare + notify step so concurrent register() calls
1087
+ * do not race each other.
1088
+ */
1089
+ this._registerNotifyChain = Promise.resolve();
1090
+ /** Unsubscribe from Installations `onIdChange` when messaging is deleted. */
1091
+ this._fidChangeUnsubscribe = null;
790
1092
  this.logEvents = [];
791
- this.isLogServiceStarted = false;
1093
+ /**
1094
+ * Single source of truth for the logging loop lifecycle.
1095
+ *
1096
+ * `scheduled` holds the active timer id; `flushing` indicates an async dispatch
1097
+ * is in progress (prevents duplicate starts); `stopped` means idle.
1098
+ */
1099
+ this.logQueue = { state: 'stopped' };
792
1100
  const appConfig = extractAppConfig(app);
793
1101
  this.firebaseDependencies = {
794
1102
  app,
@@ -798,6 +1106,14 @@ class MessagingService {
798
1106
  };
799
1107
  }
800
1108
  _delete() {
1109
+ if (this._fidChangeUnsubscribe) {
1110
+ this._fidChangeUnsubscribe();
1111
+ this._fidChangeUnsubscribe = null;
1112
+ }
1113
+ if (this.logQueue.state === 'scheduled') {
1114
+ clearTimeout(this.logQueue.timerId);
1115
+ }
1116
+ this.logQueue = { state: 'stopped' };
801
1117
  return Promise.resolve();
802
1118
  }
803
1119
  }
@@ -957,6 +1273,193 @@ async function getToken$1(messaging, options) {
957
1273
  return getTokenInternal(messaging);
958
1274
  }
959
1275
 
1276
+ /**
1277
+ * @license
1278
+ * Copyright 2020 Google LLC
1279
+ *
1280
+ * Licensed under the Apache License, Version 2.0 (the "License");
1281
+ * you may not use this file except in compliance with the License.
1282
+ * You may obtain a copy of the License at
1283
+ *
1284
+ * http://www.apache.org/licenses/LICENSE-2.0
1285
+ *
1286
+ * Unless required by applicable law or agreed to in writing, software
1287
+ * distributed under the License is distributed on an "AS IS" BASIS,
1288
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1289
+ * See the License for the specific language governing permissions and
1290
+ * limitations under the License.
1291
+ */
1292
+ /** Retries when CreateRegistration echoes an FID that does not match Installations.getId(). */
1293
+ const FID_REGISTRATION_FID_MATCH_MAX_ATTEMPTS = 3;
1294
+ /**
1295
+ * For the new FID-based register path:
1296
+ * - Create (or refresh) an FCM Web registration in the backend via CreateRegistration.
1297
+ * - Use the FIS auth token produced by the installations instance (implicitly associated with FID).
1298
+ * - CreateRegistration must echo the installation in `name` (e.g.
1299
+ * `projects/{projectId}/registrations/{fid}`); it must match `expectedFid` from
1300
+ * Installations.getId(). On mismatch we refresh the auth token and retry, then fail with
1301
+ * `fid-registration-failed`.
1302
+ */
1303
+ async function registerFcmRegistrationWithFid(messaging, expectedFid) {
1304
+ const pushSubscription = await getPushSubscription(messaging.swRegistration, messaging.vapidKey);
1305
+ const subscriptionOptions = {
1306
+ vapidKey: messaging.vapidKey,
1307
+ swScope: messaging.swRegistration.scope,
1308
+ endpoint: pushSubscription.endpoint,
1309
+ auth: arrayToBase64(pushSubscription.getKey('auth')),
1310
+ p256dh: arrayToBase64(pushSubscription.getKey('p256dh'))
1311
+ };
1312
+ const installations = messaging.firebaseDependencies.installations;
1313
+ for (let attempt = 0; attempt < FID_REGISTRATION_FID_MATCH_MAX_ATTEMPTS; attempt++) {
1314
+ const { responseFid } = await requestCreateRegistration(messaging.firebaseDependencies, subscriptionOptions);
1315
+ if (responseFid === expectedFid) {
1316
+ return;
1317
+ }
1318
+ // If CreateRegistration echoes an unexpected FID, the FIS auth token used for the request may
1319
+ // be stale relative to the installation the backend associates with the call. Force-refresh
1320
+ // the token before retrying so the next attempt uses credentials aligned with Installations.
1321
+ if (attempt < FID_REGISTRATION_FID_MATCH_MAX_ATTEMPTS - 1) {
1322
+ await installations.getToken(true);
1323
+ }
1324
+ }
1325
+ throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, {
1326
+ errorInfo: 'CreateRegistration response FID does not match Firebase Installation ID'
1327
+ });
1328
+ }
1329
+ async function getPushSubscription(swRegistration, vapidKey) {
1330
+ const subscription = await swRegistration.pushManager.getSubscription();
1331
+ if (subscription) {
1332
+ return subscription;
1333
+ }
1334
+ // Chrome/Firefox require applicationServerKey to be of type Uint8Array.
1335
+ return swRegistration.pushManager.subscribe({
1336
+ userVisibleOnly: true,
1337
+ // `PushManager.subscribe` expects a `BufferSource`; `base64ToArray` produces a typed array.
1338
+ // Cast to satisfy the lib typing differences across TS DOM versions.
1339
+ applicationServerKey: base64ToArray(vapidKey)
1340
+ });
1341
+ }
1342
+
1343
+ /**
1344
+ * @license
1345
+ * Copyright 2020 Google LLC
1346
+ *
1347
+ * Licensed under the Apache License, Version 2.0 (the "License");
1348
+ * you may not use this file except in compliance with the License.
1349
+ * You may obtain a copy of the License at
1350
+ *
1351
+ * http://www.apache.org/licenses/LICENSE-2.0
1352
+ *
1353
+ * Unless required by applicable law or agreed to in writing, software
1354
+ * distributed under the License is distributed on an "AS IS" BASIS,
1355
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1356
+ * See the License for the specific language governing permissions and
1357
+ * limitations under the License.
1358
+ */
1359
+ const FID_REGISTRATION_REFRESH_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
1360
+ /**
1361
+ * Registers the app instance with FCM using its Firebase Installation ID (FID). The FID is
1362
+ * delivered via the `onRegistered` callback. Call this to establish an FID-based identity.
1363
+ * Once `onRegistered` provides an FID, instruct your backend to remove any legacy token
1364
+ * previously associated with this instance. The backend send API supports FID as a target.
1365
+ *
1366
+ * When called multiple times, `onRegistered` is invoked on each call with the current FID.
1367
+ * Backend registration sync runs on first register, when the FID changes, or on weekly refresh.
1368
+ *
1369
+ * @param messaging - The MessagingService instance.
1370
+ * @param options - Optional. Same options as getToken (vapidKey, serviceWorkerRegistration).
1371
+ */
1372
+ async function register$1(messaging, options) {
1373
+ if (!navigator) {
1374
+ throw ERROR_FACTORY.create("only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */);
1375
+ }
1376
+ if (Notification.permission === 'default') {
1377
+ await Notification.requestPermission();
1378
+ }
1379
+ if (Notification.permission !== 'granted') {
1380
+ throw ERROR_FACTORY.create("permission-blocked" /* ErrorCode.PERMISSION_BLOCKED */);
1381
+ }
1382
+ if (!messaging.onRegisteredHandler) {
1383
+ throw ERROR_FACTORY.create("invalid-on-registered-handler" /* ErrorCode.INVALID_ON_REGISTERED_HANDLER */);
1384
+ }
1385
+ await updateVapidKey(messaging, options?.vapidKey);
1386
+ await updateSwReg(messaging, options?.serviceWorkerRegistration);
1387
+ // Keep the queue alive after a failed register() so future calls can retry.
1388
+ const prev = messaging._registerNotifyChain.catch(() => { });
1389
+ messaging._registerNotifyChain = prev.then(async () => {
1390
+ const fid = await messaging.firebaseDependencies.installations.getId();
1391
+ const stored = await dbGetFidRegistration(messaging.firebaseDependencies);
1392
+ const now = Date.now();
1393
+ const shouldRefresh = !stored ||
1394
+ stored.fid !== fid ||
1395
+ now >= stored.lastRegisterTime + FID_REGISTRATION_REFRESH_MS;
1396
+ if (shouldRefresh) {
1397
+ // Best-effort cleanup of legacy token details, since apps may switch from
1398
+ // getToken() to the FID-based register() API over time.
1399
+ try {
1400
+ await dbRemove(messaging.firebaseDependencies);
1401
+ }
1402
+ catch {
1403
+ // Ignore.
1404
+ }
1405
+ await registerFcmRegistrationWithFid(messaging, fid);
1406
+ await dbSetFidRegistration(messaging.firebaseDependencies, {
1407
+ fid,
1408
+ lastRegisterTime: now
1409
+ });
1410
+ }
1411
+ const handler = messaging.onRegisteredHandler;
1412
+ if (!handler) {
1413
+ throw ERROR_FACTORY.create("invalid-on-registered-handler" /* ErrorCode.INVALID_ON_REGISTERED_HANDLER */);
1414
+ }
1415
+ if (typeof handler === 'function') {
1416
+ handler(fid);
1417
+ }
1418
+ else {
1419
+ handler.next(fid);
1420
+ }
1421
+ });
1422
+ return messaging._registerNotifyChain;
1423
+ }
1424
+
1425
+ /**
1426
+ * @license
1427
+ * Copyright 2026 Google LLC
1428
+ *
1429
+ * Licensed under the Apache License, Version 2.0 (the "License");
1430
+ * you may not use this file except in compliance with the License.
1431
+ * You may obtain a copy of the License at
1432
+ *
1433
+ * http://www.apache.org/licenses/LICENSE-2.0
1434
+ *
1435
+ * Unless required by applicable law or agreed to in writing, software
1436
+ * distributed under the License is distributed on an "AS IS" BASIS,
1437
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1438
+ * See the License for the specific language governing permissions and
1439
+ * limitations under the License.
1440
+ */
1441
+ /**
1442
+ * When the Firebase Installation ID changes, re-run `register()` so FCM registration and
1443
+ * onRegistered run for the new FID. No-op if no onRegistered handler is set or the app
1444
+ * instance was never registered with FCM.
1445
+ */
1446
+ function subscribeFidChangeRegistration(messaging, installations$1) {
1447
+ return installations.onIdChange(installations$1, () => {
1448
+ void (async () => {
1449
+ if (!messaging.onRegisteredHandler) {
1450
+ return;
1451
+ }
1452
+ const stored = await dbGetFidRegistration(messaging.firebaseDependencies);
1453
+ if (!stored) {
1454
+ return;
1455
+ }
1456
+ await register$1(messaging).catch(() => {
1457
+ // Best-effort: permission may be revoked or SW unavailable after FID rotation.
1458
+ });
1459
+ })();
1460
+ });
1461
+ }
1462
+
960
1463
  /**
961
1464
  * @license
962
1465
  * Copyright 2019 Google LLC
@@ -1034,9 +1537,6 @@ async function messageEventListener(messaging, event) {
1034
1537
  }
1035
1538
  }
1036
1539
 
1037
- const name = "@firebase/messaging";
1038
- const version = "0.12.26-20260505185142";
1039
-
1040
1540
  /**
1041
1541
  * @license
1042
1542
  * Copyright 2020 Google LLC
@@ -1056,6 +1556,7 @@ const version = "0.12.26-20260505185142";
1056
1556
  const WindowMessagingFactory = (container) => {
1057
1557
  const messaging = new MessagingService(container.getProvider('app').getImmediate(), container.getProvider('installations-internal').getImmediate(), container.getProvider('analytics-internal'));
1058
1558
  navigator.serviceWorker.addEventListener('message', e => messageEventListener(messaging, e));
1559
+ messaging._fidChangeUnsubscribe = subscribeFidChangeRegistration(messaging, container.getProvider('installations').getImmediate());
1059
1560
  return messaging;
1060
1561
  };
1061
1562
  const WindowMessagingInternalFactory = (container) => {
@@ -1063,7 +1564,8 @@ const WindowMessagingInternalFactory = (container) => {
1063
1564
  .getProvider('messaging')
1064
1565
  .getImmediate();
1065
1566
  const messagingInternal = {
1066
- getToken: (options) => getToken$1(messaging, options)
1567
+ getToken: (options) => getToken$1(messaging, options),
1568
+ register: (options) => register$1(messaging, options)
1067
1569
  };
1068
1570
  return messagingInternal;
1069
1571
  };
@@ -1172,6 +1674,129 @@ function onMessage$1(messaging, nextOrObserver) {
1172
1674
  };
1173
1675
  }
1174
1676
 
1677
+ /**
1678
+ * @license
1679
+ * Copyright 2020 Google LLC
1680
+ *
1681
+ * Licensed under the Apache License, Version 2.0 (the "License");
1682
+ * you may not use this file except in compliance with the License.
1683
+ * You may obtain a copy of the License at
1684
+ *
1685
+ * http://www.apache.org/licenses/LICENSE-2.0
1686
+ *
1687
+ * Unless required by applicable law or agreed to in writing, software
1688
+ * distributed under the License is distributed on an "AS IS" BASIS,
1689
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1690
+ * See the License for the specific language governing permissions and
1691
+ * limitations under the License.
1692
+ */
1693
+ /**
1694
+ * Subscribes to an event that the app instance is registered with FCM via Firebase Installation ID (FID).
1695
+ * Use the FID passed to the callback to upload it to your application server.
1696
+ *
1697
+ * @param messaging - The {@link MessagingService} instance.
1698
+ * @param nextOrObserver - A function or observer object called when an FID is registered.
1699
+ * @returns Unsubscribe function to stop listening.
1700
+ */
1701
+ function onRegistered$1(messaging, nextOrObserver) {
1702
+ messaging.onRegisteredHandler = nextOrObserver;
1703
+ return () => {
1704
+ if (messaging.onRegisteredHandler === nextOrObserver) {
1705
+ messaging.onRegisteredHandler = null;
1706
+ }
1707
+ };
1708
+ }
1709
+
1710
+ /**
1711
+ * @license
1712
+ * Copyright 2026 Google LLC
1713
+ *
1714
+ * Licensed under the Apache License, Version 2.0 (the "License");
1715
+ * you may not use this file except in compliance with the License.
1716
+ * You may obtain a copy of the License at
1717
+ *
1718
+ * http://www.apache.org/licenses/LICENSE-2.0
1719
+ *
1720
+ * Unless required by applicable law or agreed to in writing, software
1721
+ * distributed under the License is distributed on an "AS IS" BASIS,
1722
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1723
+ * See the License for the specific language governing permissions and
1724
+ * limitations under the License.
1725
+ */
1726
+ /**
1727
+ * Subscribes to an event that the app instance is unregistered from FCM so the FID is no longer active.
1728
+ * Use this to notify your backend to remove this FID to prevent 404 errors on send.
1729
+ *
1730
+ * @param messaging - The {@link MessagingService} instance.
1731
+ * @param nextOrObserver - A function or observer object called with the unregistered FID.
1732
+ * @returns Unsubscribe function to stop listening.
1733
+ */
1734
+ function onUnregistered$1(messaging, nextOrObserver) {
1735
+ messaging.onUnregisteredHandler = nextOrObserver;
1736
+ return () => {
1737
+ if (messaging.onUnregisteredHandler === nextOrObserver) {
1738
+ messaging.onUnregisteredHandler = null;
1739
+ }
1740
+ };
1741
+ }
1742
+
1743
+ /**
1744
+ * @license
1745
+ * Copyright 2026 Google LLC
1746
+ *
1747
+ * Licensed under the Apache License, Version 2.0 (the "License");
1748
+ * you may not use this file except in compliance with the License.
1749
+ * You may obtain a copy of the License at
1750
+ *
1751
+ * http://www.apache.org/licenses/LICENSE-2.0
1752
+ *
1753
+ * Unless required by applicable law or agreed to in writing, software
1754
+ * distributed under the License is distributed on an "AS IS" BASIS,
1755
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1756
+ * See the License for the specific language governing permissions and
1757
+ * limitations under the License.
1758
+ */
1759
+ /**
1760
+ * Unregisters the app instance from FCM by deleting its FID-based registration.
1761
+ *
1762
+ * On success, triggers the `onUnregistered` callback (if set) with the unregistered FID.
1763
+ *
1764
+ * @param messaging - The MessagingService instance.
1765
+ */
1766
+ async function unregister$1(messaging) {
1767
+ if (!navigator) {
1768
+ throw ERROR_FACTORY.create("only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */);
1769
+ }
1770
+ // Prefer the last successfully registered FID from local metadata when available.
1771
+ const stored = await dbGetFidRegistration(messaging.firebaseDependencies).catch(() => undefined);
1772
+ const fid = stored?.fid ?? (await messaging.firebaseDependencies.installations.getId());
1773
+ await requestDeleteRegistration(messaging.firebaseDependencies, fid);
1774
+ // Best-effort local cleanup; still resolve even if schema is unavailable.
1775
+ try {
1776
+ await dbRemoveFidRegistration(messaging.firebaseDependencies);
1777
+ }
1778
+ catch {
1779
+ // Ignore.
1780
+ }
1781
+ // Best-effort cleanup of legacy token details created via getToken().
1782
+ try {
1783
+ await dbRemove(messaging.firebaseDependencies);
1784
+ }
1785
+ catch {
1786
+ // Ignore.
1787
+ }
1788
+ const handler = messaging.onUnregisteredHandler;
1789
+ if (!handler) {
1790
+ return;
1791
+ }
1792
+ if (typeof handler === 'function') {
1793
+ handler(fid);
1794
+ }
1795
+ else {
1796
+ handler.next(fid);
1797
+ }
1798
+ }
1799
+
1175
1800
  /**
1176
1801
  * @license
1177
1802
  * Copyright 2017 Google LLC
@@ -1224,6 +1849,9 @@ function getMessagingInWindow(app$1 = app.getApp()) {
1224
1849
  *
1225
1850
  * @returns The promise resolves with an FCM registration token.
1226
1851
  *
1852
+ * @deprecated Use {@link register} together with {@link onRegistered} for Firebase
1853
+ * Installation ID-based messaging instead of retrieving an FCM registration token with this API.
1854
+ *
1227
1855
  * @public
1228
1856
  */
1229
1857
  async function getToken(messaging, options) {
@@ -1234,10 +1862,18 @@ async function getToken(messaging, options) {
1234
1862
  * Deletes the registration token associated with this {@link Messaging} instance and unsubscribes
1235
1863
  * the {@link Messaging} instance from the push subscription.
1236
1864
  *
1865
+ * If there is no legacy registration token but the client has FID-based registration metadata
1866
+ * (from {@link register}), this deletes that registration on the server, clears local metadata, and
1867
+ * invokes {@link onUnregistered} with the removed FID when successful.
1868
+ *
1237
1869
  * @param messaging - The {@link Messaging} instance.
1238
1870
  *
1239
1871
  * @returns The promise resolves when the token has been successfully deleted.
1240
1872
  *
1873
+ * @deprecated Use {@link onUnregistered} to observe when the client is no longer
1874
+ * registered and update your backend accordingly, instead of explicitly deleting the
1875
+ * registration token with this API.
1876
+ *
1241
1877
  * @public
1242
1878
  */
1243
1879
  function deleteToken(messaging) {
@@ -1261,6 +1897,64 @@ function onMessage(messaging, nextOrObserver) {
1261
1897
  messaging = util.getModularInstance(messaging);
1262
1898
  return onMessage$1(messaging, nextOrObserver);
1263
1899
  }
1900
+ /**
1901
+ * Registers the app instance with FCM using its Firebase Installation ID (FID). The FID is
1902
+ * delivered via the {@link onRegistered} callback, not as a return value. Call this to establish
1903
+ * an FID-based identity; once {@link onRegistered} provides an FID, instruct your backend to
1904
+ * remove any legacy token previously associated with this instance. The backend send API
1905
+ * supports FID as a target.
1906
+ *
1907
+ * @param messaging - The {@link Messaging} instance.
1908
+ * @param options - Optional. VAPID key and/or service worker registration (same as getToken).
1909
+ * @returns Promise that resolves when registration has been initiated; FID is delivered via onRegistered.
1910
+ *
1911
+ * @public
1912
+ */
1913
+ async function register(messaging, options) {
1914
+ messaging = util.getModularInstance(messaging);
1915
+ return register$1(messaging, options);
1916
+ }
1917
+ /**
1918
+ * Unregisters the app instance from FCM by deleting its FID-based registration.
1919
+ * On success, triggers {@link onUnregistered} (if registered) with the unregistered FID.
1920
+ *
1921
+ * @param messaging - The {@link Messaging} instance.
1922
+ *
1923
+ * @public
1924
+ */
1925
+ async function unregister(messaging) {
1926
+ messaging = util.getModularInstance(messaging);
1927
+ return unregister$1(messaging);
1928
+ }
1929
+ /**
1930
+ * Subscribes to an event that the app instance is registered with FCM via Firebase Installation ID (FID).
1931
+ * Use the FID passed to the callback to upload it to your application server. When you receive an FID
1932
+ * after calling {@link register}, instruct your backend to remove any legacy token for this instance.
1933
+ *
1934
+ * @param messaging - The {@link Messaging} instance.
1935
+ * @param nextOrObserver - A function or observer object called when an FID is registered.
1936
+ * @returns Unsubscribe function to stop listening.
1937
+ *
1938
+ * @public
1939
+ */
1940
+ function onRegistered(messaging, nextOrObserver) {
1941
+ messaging = util.getModularInstance(messaging);
1942
+ return onRegistered$1(messaging, nextOrObserver);
1943
+ }
1944
+ /**
1945
+ * Subscribes to an event that the app instance is unregistered from FCM (FID no longer active).
1946
+ * Use this to notify your backend to remove this FID to prevent 404 errors on send.
1947
+ *
1948
+ * @param messaging - The {@link Messaging} instance.
1949
+ * @param nextOrObserver - A function or observer object called with the unregistered FID.
1950
+ * @returns Unsubscribe function to stop listening.
1951
+ *
1952
+ * @public
1953
+ */
1954
+ function onUnregistered(messaging, nextOrObserver) {
1955
+ messaging = util.getModularInstance(messaging);
1956
+ return onUnregistered$1(messaging, nextOrObserver);
1957
+ }
1264
1958
 
1265
1959
  /**
1266
1960
  * The Firebase Cloud Messaging Web SDK.
@@ -1275,4 +1969,8 @@ exports.getMessaging = getMessagingInWindow;
1275
1969
  exports.getToken = getToken;
1276
1970
  exports.isSupported = isWindowSupported;
1277
1971
  exports.onMessage = onMessage;
1972
+ exports.onRegistered = onRegistered;
1973
+ exports.onUnregistered = onUnregistered;
1974
+ exports.register = register;
1975
+ exports.unregister = unregister;
1278
1976
  //# sourceMappingURL=index.cjs.js.map