@@ -443,8 +443,16 @@ export class InMemoryAcpHttpBackend implements AcpHttpBackend {
443443 } ) ;
444444
445445 try {
446- await connection . writeInbound ( message ) ;
447- const response = await connection . recvInitial ( message . id ) ;
446+ const discard = ( ) : void => {
447+ this . registry . discard ( connection . connectionId ) ;
448+ } ;
449+
450+ await raceAbort ( connection . writeInbound ( message ) , signal , discard ) ;
451+ const response = await raceAbort (
452+ connection . recvInitial ( message . id ) ,
453+ signal ,
454+ discard ,
455+ ) ;
448456
449457 if ( signal . aborted ) {
450458 throw new Error ( "Request aborted" ) ;
@@ -677,3 +685,35 @@ function isMatchingResponse(
677685) : msg is AnyResponse {
678686 return "id" in msg && ! ( "method" in msg ) && msg . id === id ;
679687}
688+
689+ async function raceAbort < T > (
690+ promise : Promise < T > ,
691+ signal : AbortSignal ,
692+ onAbort : ( ) => void ,
693+ ) : Promise < T > {
694+ promise . catch ( ( ) => undefined ) ;
695+
696+ if ( signal . aborted ) {
697+ onAbort ( ) ;
698+ throw new Error ( "Request aborted" ) ;
699+ }
700+
701+ let removeAbortListener : ( ) => void = ( ) => { } ;
702+ const abortPromise = new Promise < never > ( ( _resolve , reject ) => {
703+ const abort = ( ) : void => {
704+ onAbort ( ) ;
705+ reject ( new Error ( "Request aborted" ) ) ;
706+ } ;
707+
708+ signal . addEventListener ( "abort" , abort , { once : true } ) ;
709+ removeAbortListener = ( ) => {
710+ signal . removeEventListener ( "abort" , abort ) ;
711+ } ;
712+ } ) ;
713+
714+ try {
715+ return await Promise . race ( [ promise , abortPromise ] ) ;
716+ } finally {
717+ removeAbortListener ( ) ;
718+ }
719+ }
0 commit comments