@@ -190,8 +190,12 @@ export class SandboxClient {
190190 }
191191 this . keepAliveInterval = null ;
192192
193- // Only attempt auto-reconnect on DISCONNECTED, not HIBERNATED
194- if ( state === "DISCONNECTED" && ! this . isExplicitlyDisconnected ) {
193+ // Only attempt auto-reconnect on DISCONNECTED, not HIBERNATED, and not if disposed
194+ if (
195+ state === "DISCONNECTED" &&
196+ ! this . isExplicitlyDisconnected &&
197+ ! this . disposable . isDisposed
198+ ) {
195199 this . attemptAutoReconnect ( ) ;
196200 }
197201 } else if ( state === "CONNECTED" ) {
@@ -332,6 +336,10 @@ export class SandboxClient {
332336 "sandboxClient.disconnect" ,
333337 { "sandbox.id" : this . id } ,
334338 async ( ) => {
339+ if ( this . disposable . isDisposed ) {
340+ throw new Error ( "Cannot disconnect: SandboxClient has been disposed" ) ;
341+ }
342+
335343 this . isExplicitlyDisconnected = true ;
336344 if ( this . keepAliveInterval ) {
337345 clearInterval ( this . keepAliveInterval ) ;
@@ -351,6 +359,10 @@ export class SandboxClient {
351359 "sandboxClient.reconnect" ,
352360 { "sandbox.id" : this . id } ,
353361 async ( ) => {
362+ if ( this . disposable . isDisposed ) {
363+ throw new Error ( "Cannot reconnect: SandboxClient has been disposed" ) ;
364+ }
365+
354366 this . isExplicitlyDisconnected = false ;
355367 return this . agentClient . reconnect ( ) ;
356368 }
@@ -368,6 +380,9 @@ export class SandboxClient {
368380 try {
369381 await retryWithDelay (
370382 async ( ) => {
383+ if ( this . disposable . isDisposed ) {
384+ throw new Error ( "Client disposed - stopping auto-reconnect" ) ;
385+ }
371386 if ( this . isExplicitlyDisconnected ) {
372387 throw new Error (
373388 "Explicit disconnect - stopping auto-reconnect"
@@ -397,31 +412,53 @@ export class SandboxClient {
397412 * If enabled, we will keep the sandbox from hibernating as long as the SDK is connected to it.
398413 */
399414 public keepActiveWhileConnected ( enabled : boolean ) {
415+ if ( this . disposable . isDisposed ) {
416+ throw new Error ( "Client disposed" ) ;
417+ }
418+
400419 // Used to manage the interval when disconnects happen
401420 this . shouldKeepAlive = enabled ;
402421
403422 if ( enabled ) {
404423 if ( ! this . keepAliveInterval ) {
405424 this . keepAliveInterval = setInterval ( ( ) => {
406- this . agentClient . system . update ( )
425+ if ( this . disposable . isDisposed ) {
426+ if ( this . keepAliveInterval ) {
427+ clearInterval ( this . keepAliveInterval ) ;
428+ this . keepAliveInterval = null ;
429+ }
430+ return ;
431+ }
432+
433+ this . agentClient . system
434+ . update ( )
407435 . then ( ( ) => {
408436 // Reset failure count on success
409437 this . keepAliveFailures = 0 ;
410438 } )
411439 . catch ( ( error ) => {
412440 this . keepAliveFailures ++ ;
413- console . warn ( `Keep-alive failed (${ this . keepAliveFailures } /${ this . maxKeepAliveFailures } ):` , error ) ;
414-
441+ console . warn (
442+ `Keep-alive failed (${ this . keepAliveFailures } /${ this . maxKeepAliveFailures } ):` ,
443+ error
444+ ) ;
445+
415446 // If we've hit max failures, stop aggressive keep-alive to prevent connection thrashing
416447 if ( this . keepAliveFailures >= this . maxKeepAliveFailures ) {
417- console . warn ( "Max keep-alive failures reached, reducing frequency to prevent connection issues" ) ;
448+ console . warn (
449+ "Max keep-alive failures reached, reducing frequency to prevent connection issues"
450+ ) ;
418451 if ( this . keepAliveInterval ) {
419452 clearInterval ( this . keepAliveInterval ) ;
420453 this . keepAliveInterval = null ;
421454 }
422- // Restart with longer interval after failures
455+ // Restart with longer interval after failures, but only if not disposed
423456 setTimeout ( ( ) => {
424- if ( this . shouldKeepAlive && ! this . keepAliveInterval ) {
457+ if (
458+ this . shouldKeepAlive &&
459+ ! this . keepAliveInterval &&
460+ ! this . disposable . isDisposed
461+ ) {
425462 this . keepActiveWhileConnected ( true ) ;
426463 this . keepAliveFailures = 0 ; // Reset for retry
427464 }
@@ -441,6 +478,17 @@ export class SandboxClient {
441478 * Dispose the session, this will disconnect from the sandbox and dispose all resources. If you want to do a clean disconnect, await "disconnect" method first.
442479 */
443480 dispose ( ) {
481+ // Prevent any future reconnection attempts
482+ this . isExplicitlyDisconnected = true ;
483+
484+ // Clear keep-alive settings to prevent restart
485+ this . shouldKeepAlive = false ;
486+
487+ if ( this . keepAliveInterval ) {
488+ clearInterval ( this . keepAliveInterval ) ;
489+ this . keepAliveInterval = null ;
490+ }
491+
444492 this . disposable . dispose ( ) ;
445493 }
446494}
0 commit comments