@@ -464,6 +464,9 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
464464 protected async connectInternal ( ) {
465465 let appliedOptions : PowerSyncConnectionOptions | null = null ;
466466
467+ // This method ensures a disconnect before any connection attempt
468+ await this . disconnectInternal ( ) ;
469+
467470 /**
468471 * This portion creates a sync implementation which can be racy when disconnecting or
469472 * if multiple tabs on web are in use.
@@ -474,13 +477,15 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
474477 if ( this . closed ) {
475478 throw new Error ( 'Cannot connect using a closed client' ) ;
476479 }
480+
481+ // Always await this if present since we will be populating a new sync implementation shortly
482+ await this . disconnectingPromise ;
483+
477484 if ( ! this . pendingConnectionOptions ) {
478485 // A disconnect could have cleared this.
479486 return ;
480487 }
481-
482488 // get pending options and clear it in order for other connect attempts to queue other options
483-
484489 const { connector, options } = this . pendingConnectionOptions ;
485490 appliedOptions = options ;
486491 this . pendingConnectionOptions = null ;
@@ -510,6 +515,10 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
510515 return ;
511516 }
512517
518+ // It might be possible that a disconnect triggered between the last check
519+ // and this point. Awaiting here allows the sync stream to be cleared if disconnected.
520+ await this . disconnectingPromise ;
521+
513522 this . syncStreamImplementation ?. triggerCrudUpload ( ) ;
514523 this . options . logger ?. debug ( 'Attempting to connect to PowerSync instance' ) ;
515524 await this . syncStreamImplementation ?. connect ( appliedOptions ! ) ;
@@ -519,25 +528,44 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
519528 * Connects to stream of events from the PowerSync instance.
520529 */
521530 async connect ( connector : PowerSyncBackendConnector , options ?: PowerSyncConnectionOptions ) {
522- // This overrides options if present.
531+ // Keep track if there were pending operations before this call
532+ const hadPendingOptions = ! ! this . pendingConnectionOptions ;
533+
534+ // Update pending options to the latest values
523535 this . pendingConnectionOptions = {
524536 connector,
525537 options : options ?? { }
526538 } ;
527539
528540 await this . waitForReady ( ) ;
529- await this . disconnectInternal ( ) ;
530541
531- const chain = ( result ) => {
542+ // Disconnecting here provides aborting in progress connection attempts.
543+ // The connectInternal method will clear pending options once it starts connecting (with the options).
544+ // We only need to trigger a disconnect here if we have already reached the point of connecting.
545+ // If we do already have pending options, a disconnect has already been performed.
546+ // The connectInternal method also does a sanity disconnect to prevent straggler connections.
547+ if ( ! hadPendingOptions ) {
548+ await this . disconnectInternal ( ) ;
549+ }
550+
551+ // Triggers a connect which checks if pending options are available after the connect completes.
552+ // The completion can be for a successful, unsuccessful or aborted connection attempt.
553+ // If pending options are available another connection will be triggered.
554+ const checkConnection = async ( ) : Promise < void > => {
532555 if ( this . pendingConnectionOptions ) {
533- return this . connectInternal ( ) . then ( chain ) ;
556+ // Pending options have been placed while connecting.
557+ // Need to reconnect.
558+ this . connectingPromise = this . connectInternal ( ) . finally ( checkConnection ) ;
559+ return this . connectingPromise ;
534560 } else {
561+ // Clear the connecting promise, done.
535562 this . connectingPromise = null ;
536- return result ;
563+ return ;
537564 }
538565 } ;
539566
540- return this . connectingPromise ?? this . connectInternal ( ) . then ( chain ) ;
567+ this . connectingPromise ??= this . connectInternal ( ) . finally ( checkConnection ) ;
568+ return this . connectingPromise ;
541569 }
542570
543571 /**
@@ -548,10 +576,11 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver<PowerSyncDB
548576 protected async disconnectInternal ( ) {
549577 if ( this . disconnectingPromise ) {
550578 // A disconnect is already in progress
551- return await this . disconnectingPromise ;
579+ return this . disconnectingPromise ;
552580 }
581+
553582 // Wait if a sync stream implementation is being created before closing it
554- // (it must be assigned before we can properly dispose it)
583+ // (syncStreamImplementation must be assigned before we can properly dispose it)
555584 await this . syncStreamInitPromise ;
556585
557586 this . disconnectingPromise = ( async ( ) => {
0 commit comments