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