@@ -10,7 +10,7 @@ import {
1010 createLogger ,
1111 type ILogger
1212} from '@powersync/common' ;
13- import { getNavigatorLocks } from '../..// shared/navigator' ;
13+ import { getNavigatorLocks } from '../../shared/navigator' ;
1414import { AsyncDatabaseConnection , ConnectionClosedError } from './AsyncDatabaseConnection' ;
1515import { SharedConnectionWorker , WebDBAdapter } from './WebDBAdapter' ;
1616import { WorkerWrappedAsyncDatabaseConnection } from './WorkerWrappedAsyncDatabaseConnection' ;
@@ -120,8 +120,9 @@ export class LockedAsyncDatabaseAdapter
120120 // Dispose any previous table change listener.
121121 this . _disposeTableChangeListener ?.( ) ;
122122 this . _disposeTableChangeListener = null ;
123-
123+ this . _db ?. close ( ) . catch ( ( ex ) => this . logger . warn ( `Error closing database before opening new instance` , ex ) ) ;
124124 const isReOpen = ! ! this . _db ;
125+ this . _db = null ;
125126
126127 this . _db = await this . options . openConnection ( ) ;
127128 await this . _db . init ( ) ;
@@ -159,7 +160,23 @@ export class LockedAsyncDatabaseAdapter
159160 }
160161
161162 protected async _init ( ) {
162- await this . openInternalDB ( ) ;
163+ /**
164+ * For OPFS, we can see this open call sometimes fail due to NoModificationAllowedError.
165+ * We should be able to recover from this by re-opening the database.
166+ */
167+ const maxAttempts = 3 ;
168+ for ( let count = 0 ; count < maxAttempts ; count ++ ) {
169+ try {
170+ await this . openInternalDB ( ) ;
171+ break ;
172+ } catch ( ex ) {
173+ if ( count == maxAttempts - 1 ) {
174+ throw ex ;
175+ }
176+ this . logger . warn ( `Attempt ${ count + 1 } of ${ maxAttempts } to open database failed, retrying in 1 second...` , ex ) ;
177+ await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) ) ;
178+ }
179+ }
163180 this . iterateListeners ( ( cb ) => cb . initialized ?.( ) ) ;
164181 }
165182
0 commit comments