15
15
* limitations under the License.
16
16
*/
17
17
18
+ import { getUA } from '@firebase/util' ;
18
19
import { assert } from '../util/assert' ;
19
20
import { Code , FirestoreError } from '../util/error' ;
20
- import { debug } from '../util/log' ;
21
+ import { debug , error } from '../util/log' ;
21
22
import { Deferred } from '../util/promise' ;
22
23
import { SCHEMA_VERSION } from './indexeddb_schema' ;
23
24
import { PersistencePromise } from './persistence_promise' ;
@@ -149,8 +150,7 @@ export class SimpleDb {
149
150
}
150
151
151
152
// Check the UA string to find out the browser.
152
- // TODO(mikelehen): Move this logic into packages/util/environment.ts
153
- const ua = window . navigator . userAgent ;
153
+ const ua = getUA ( ) ;
154
154
155
155
// IE 10
156
156
// ua = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)';
@@ -195,7 +195,12 @@ export class SimpleDb {
195
195
/** Parse User Agent to determine iOS version. Returns -1 if not found. */
196
196
static getIOSVersion ( ua : string ) : number {
197
197
const iOSVersionRegex = ua . match ( / i (?: p h o n e | p a d | p o d ) o s ( [ \d _ ] + ) / i) ;
198
- const version = iOSVersionRegex ? iOSVersionRegex [ 1 ] . split ( '_' ) [ 0 ] : '-1' ;
198
+ const version = iOSVersionRegex
199
+ ? iOSVersionRegex [ 1 ]
200
+ . split ( '_' )
201
+ . slice ( 0 , 2 )
202
+ . join ( '.' )
203
+ : '-1' ;
199
204
return Number ( version ) ;
200
205
}
201
206
@@ -212,7 +217,21 @@ export class SimpleDb {
212
217
return Number ( version ) ;
213
218
}
214
219
215
- constructor ( private db : IDBDatabase ) { }
220
+ constructor ( private db : IDBDatabase ) {
221
+ const iOSVersion = SimpleDb . getIOSVersion ( getUA ( ) ) ;
222
+ // NOTE: According to https://bugs.webkit.org/show_bug.cgi?id=197050, the
223
+ // bug we're checking for should exist in iOS >= 12.2 and < 13, but for
224
+ // whatever reason it's much harder to hit after 12.2 so we only proactively
225
+ // log on 12.2.
226
+ if ( iOSVersion === 12.2 ) {
227
+ error (
228
+ 'Firestore persistence suffers from a bug in iOS 12.2 ' +
229
+ 'Safari that may cause your app to stop working. See ' +
230
+ 'https://stackoverflow.com/q/56496296/110915 for details ' +
231
+ 'and a potential workaround.'
232
+ ) ;
233
+ }
234
+ }
216
235
217
236
setVersionChangeListener (
218
237
versionChangeListener : ( event : IDBVersionChangeEvent ) => void
@@ -359,7 +378,9 @@ export class SimpleDbTransaction {
359
378
}
360
379
} ;
361
380
this . transaction . onerror = ( event : Event ) => {
362
- this . completionDeferred . reject ( ( event . target as IDBRequest ) . error ! ) ;
381
+ const error = ( event . target as IDBRequest ) . error ! ;
382
+ checkForAndReportiOSError ( error ) ;
383
+ this . completionDeferred . reject ( error ) ;
363
384
} ;
364
385
}
365
386
@@ -578,7 +599,9 @@ export class SimpleDbStore<
578
599
const cursorRequest = this . cursor ( { } ) ;
579
600
return new PersistencePromise ( ( resolve , reject ) => {
580
601
cursorRequest . onerror = ( event : Event ) => {
581
- reject ( ( event . target as IDBRequest ) . error ! ) ;
602
+ const error = ( event . target as IDBRequest ) . error ! ;
603
+ checkForAndReportiOSError ( error ) ;
604
+ reject ( error ) ;
582
605
} ;
583
606
cursorRequest . onsuccess = ( event : Event ) => {
584
607
const cursor : IDBCursorWithValue = ( event . target as IDBRequest ) . result ;
@@ -692,7 +715,35 @@ function wrapRequest<R>(request: IDBRequest): PersistencePromise<R> {
692
715
} ;
693
716
694
717
request . onerror = ( event : Event ) => {
695
- reject ( ( event . target as IDBRequest ) . error ! ) ;
718
+ const error = ( event . target as IDBRequest ) . error ! ;
719
+ checkForAndReportiOSError ( error ) ;
720
+ reject ( error ) ;
696
721
} ;
697
722
} ) ;
698
723
}
724
+
725
+ // Guard so we only report the error once.
726
+ let reportedIOSError = false ;
727
+ function checkForAndReportiOSError ( error : DOMException ) : void {
728
+ if ( reportedIOSError ) {
729
+ return ;
730
+ }
731
+ const iOSVersion = SimpleDb . getIOSVersion ( getUA ( ) ) ;
732
+ if ( iOSVersion >= 12.2 && iOSVersion < 13 ) {
733
+ const IOS_ERROR =
734
+ 'An internal error was encountered in the Indexed Database server' ;
735
+ if ( error . message . indexOf ( IOS_ERROR ) >= 0 ) {
736
+ reportedIOSError = true ;
737
+ // Throw a global exception outside of this promise chain, for the user to
738
+ // potentially catch.
739
+ setTimeout ( ( ) => {
740
+ throw new FirestoreError (
741
+ 'internal' ,
742
+ `IOS_INDEXEDDB_BUG1: IndexedDb has thrown '${ IOS_ERROR } '. This is likely ` +
743
+ `due to an unavoidable bug in iOS. See https://stackoverflow.com/q/56496296/110915 ` +
744
+ `for details and a potential workaround.`
745
+ ) ;
746
+ } , 0 ) ;
747
+ }
748
+ }
749
+ }
0 commit comments