|  | 
| 18 | 18 | import { getGlobal, getUA, isIndexedDBAvailable } from '@firebase/util'; | 
| 19 | 19 | 
 | 
| 20 | 20 | import { debugAssert } from '../util/assert'; | 
|  | 21 | +import { generateUniqueDebugId } from '../util/debug_uid'; | 
| 21 | 22 | import { Code, FirestoreError } from '../util/error'; | 
| 22 |  | -import { logDebug, logError, logWarn } from '../util/log'; | 
|  | 23 | +import { logDebug, logError } from '../util/log'; | 
| 23 | 24 | import { Deferred } from '../util/promise'; | 
| 24 | 25 | 
 | 
| 25 |  | -import { DatabaseDeletedListener } from './persistence'; | 
|  | 26 | +import { | 
|  | 27 | +  ClearSiteDataDatabaseDeletedEvent, | 
|  | 28 | +  DatabaseDeletedListener, | 
|  | 29 | +  VersionChangeDatabaseDeletedEvent | 
|  | 30 | +} from './persistence'; | 
| 26 | 31 | import { PersistencePromise } from './persistence_promise'; | 
| 27 | 32 | 
 | 
| 28 | 33 | // References to `indexedDB` are guarded by SimpleDb.isAvailable() and getGlobal() | 
| @@ -299,9 +304,33 @@ export class SimpleDb { | 
| 299 | 304 |         // https://developer.mozilla.org/en-US/docs/Web/API/IDBVersionChangeRequest/setVersion | 
| 300 | 305 |         const request = indexedDB.open(this.name, this.version); | 
| 301 | 306 | 
 | 
|  | 307 | +        // Store information about "Clear Site Data" being detected in the | 
|  | 308 | +        // "onupgradeneeded" event listener and handle it in the "onsuccess" | 
|  | 309 | +        // event listener, as opposed to throwing directly from the | 
|  | 310 | +        // "onupgradeneeded" event listener. Do this because throwing from the | 
|  | 311 | +        // "onupgradeneeded" event listener results in a generic error being | 
|  | 312 | +        // reported to the "onerror" event listener that cannot be distinguished | 
|  | 313 | +        // from other errors. | 
|  | 314 | +        const clearSiteDataEvent: ClearSiteDataDatabaseDeletedEvent[] = []; | 
|  | 315 | + | 
| 302 | 316 |         request.onsuccess = (event: Event) => { | 
|  | 317 | +          let error: unknown; | 
|  | 318 | +          if (clearSiteDataEvent.length > 0) { | 
|  | 319 | +            try { | 
|  | 320 | +              this.databaseDeletedListener?.(clearSiteDataEvent[0]); | 
|  | 321 | +            } catch (e) { | 
|  | 322 | +              error = e; | 
|  | 323 | +            } | 
|  | 324 | +          } | 
|  | 325 | + | 
| 303 | 326 |           const db = (event.target as IDBOpenDBRequest).result; | 
| 304 |  | -          resolve(db); | 
|  | 327 | + | 
|  | 328 | +          if (error) { | 
|  | 329 | +            reject(error); | 
|  | 330 | +            db.close(); | 
|  | 331 | +          } else { | 
|  | 332 | +            resolve(db); | 
|  | 333 | +          } | 
| 305 | 334 |         }; | 
| 306 | 335 | 
 | 
| 307 | 336 |         request.onblocked = () => { | 
| @@ -353,18 +382,14 @@ export class SimpleDb { | 
| 353 | 382 |             this.lastClosedDbVersion !== null && | 
| 354 | 383 |             this.lastClosedDbVersion !== event.oldVersion | 
| 355 | 384 |           ) { | 
| 356 |  | -            // This thrown error will get passed to the `onerror` callback | 
| 357 |  | -            // registered above, and will then be propagated correctly. | 
| 358 |  | -            throw new Error( | 
| 359 |  | -              `refusing to open IndexedDB database due to potential ` + | 
| 360 |  | -                `corruption of the IndexedDB database data; this corruption ` + | 
| 361 |  | -                `could be caused by clicking the "clear site data" button in ` + | 
| 362 |  | -                `a web browser; try reloading the web page to re-initialize ` + | 
| 363 |  | -                `the IndexedDB database: ` + | 
| 364 |  | -                `lastClosedDbVersion=${this.lastClosedDbVersion}, ` + | 
| 365 |  | -                `event.oldVersion=${event.oldVersion}, ` + | 
| 366 |  | -                `event.newVersion=${event.newVersion}, ` + | 
| 367 |  | -                `db.version=${db.version}` | 
|  | 385 | +            clearSiteDataEvent.push( | 
|  | 386 | +              new ClearSiteDataDatabaseDeletedEvent({ | 
|  | 387 | +                eventId: generateUniqueDebugId(), | 
|  | 388 | +                lastClosedVersion: this.lastClosedDbVersion, | 
|  | 389 | +                eventOldVersion: event.oldVersion, | 
|  | 390 | +                eventNewVersion: event.newVersion, | 
|  | 391 | +                dbVersion: db.version | 
|  | 392 | +              }) | 
| 368 | 393 |             ); | 
| 369 | 394 |           } | 
| 370 | 395 |           this.schemaConverter | 
| @@ -399,11 +424,12 @@ export class SimpleDb { | 
| 399 | 424 |         // Notify the listener if another tab attempted to delete the IndexedDb | 
| 400 | 425 |         // database, such as by calling clearIndexedDbPersistence(). | 
| 401 | 426 |         if (event.newVersion === null) { | 
| 402 |  | -          logWarn( | 
| 403 |  | -            `Received "versionchange" event with newVersion===null; ` + | 
| 404 |  | -              'notifying the registered DatabaseDeletedListener, if any' | 
|  | 427 | +          this.databaseDeletedListener?.( | 
|  | 428 | +            new VersionChangeDatabaseDeletedEvent({ | 
|  | 429 | +              eventId: generateUniqueDebugId(), | 
|  | 430 | +              eventNewVersion: event.newVersion | 
|  | 431 | +            }) | 
| 405 | 432 |           ); | 
| 406 |  | -          this.databaseDeletedListener?.(); | 
| 407 | 433 |         } | 
| 408 | 434 |       }, | 
| 409 | 435 |       { passive: true } | 
|  | 
0 commit comments