@@ -11,11 +11,15 @@ import type {
1111 AnyResponse ,
1212 Result ,
1313 ErrorResponse ,
14- PendingResponse ,
1514 RequestHandler ,
1615 NotificationHandler ,
1716} from "./jsonrpc.js" ;
1817
18+ type ConnectionPendingResponse = {
19+ resolve : ( response : unknown ) => void ;
20+ reject : ( error : unknown ) => void ;
21+ } ;
22+
1923/**
2024 * An agent-side connection to a client.
2125 *
@@ -1167,7 +1171,8 @@ export class ClientSideConnection implements Agent {
11671171export type { AnyMessage } from "./jsonrpc.js" ;
11681172
11691173class Connection {
1170- #pendingResponses: Map < string | number | null , PendingResponse > = new Map ( ) ;
1174+ #pendingResponses: Map < string | number | null , ConnectionPendingResponse > =
1175+ new Map ( ) ;
11711176 #nextRequestId: number = 0 ;
11721177 #requestHandler: RequestHandler ;
11731178 #notificationHandler: NotificationHandler ;
@@ -1187,7 +1192,7 @@ class Connection {
11871192 this . #closedPromise = new Promise ( ( resolve ) => {
11881193 this . #abortController. signal . addEventListener ( "abort" , ( ) => resolve ( ) ) ;
11891194 } ) ;
1190- this . #receive( ) ;
1195+ void this . #receive( ) ;
11911196 }
11921197
11931198 /**
@@ -1221,44 +1226,64 @@ class Connection {
12211226 }
12221227
12231228 async #receive( ) {
1224- const reader = this . #stream. readable . getReader ( ) ;
1229+ let closeError : unknown = undefined ;
1230+
12251231 try {
1226- while ( true ) {
1227- const { value : message , done } = await reader . read ( ) ;
1228- if ( done ) {
1229- break ;
1230- }
1231- if ( ! message ) {
1232- continue ;
1233- }
1232+ const reader = this . #stream. readable . getReader ( ) ;
1233+ try {
1234+ while ( ! this . #abortController. signal . aborted ) {
1235+ const { value : message , done } = await reader . read ( ) ;
1236+ if ( done ) {
1237+ break ;
1238+ }
1239+ if ( ! message ) {
1240+ continue ;
1241+ }
12341242
1235- try {
1236- this . #processMessage( message ) ;
1237- } catch ( err ) {
1238- console . error (
1239- "Unexpected error during message processing:" ,
1240- message ,
1241- err ,
1242- ) ;
1243- // Only send error response if the message had an id (was a request)
1244- if ( "id" in message && message . id !== undefined ) {
1245- this . #sendMessage( {
1246- jsonrpc : "2.0" ,
1247- id : message . id ,
1248- error : {
1249- code : - 32700 ,
1250- message : "Parse error" ,
1251- } ,
1252- } ) ;
1243+ try {
1244+ this . #processMessage( message ) ;
1245+ } catch ( err ) {
1246+ console . error (
1247+ "Unexpected error during message processing:" ,
1248+ message ,
1249+ err ,
1250+ ) ;
1251+ // Only send error response if the message had an id (was a request)
1252+ if ( "id" in message && message . id !== undefined ) {
1253+ this . #sendMessage( {
1254+ jsonrpc : "2.0" ,
1255+ id : message . id ,
1256+ error : {
1257+ code : - 32700 ,
1258+ message : "Parse error" ,
1259+ } ,
1260+ } ) ;
1261+ }
12531262 }
12541263 }
1264+ } finally {
1265+ reader . releaseLock ( ) ;
12551266 }
1267+ } catch ( error ) {
1268+ closeError = error ;
12561269 } finally {
1257- reader . releaseLock ( ) ;
1258- this . #abortController. abort ( ) ;
1270+ this . #close( closeError ) ;
12591271 }
12601272 }
12611273
1274+ #close( error ?: unknown ) {
1275+ if ( this . #abortController. signal . aborted ) {
1276+ return ;
1277+ }
1278+
1279+ const closeError : unknown = error ?? new Error ( "ACP connection closed" ) ;
1280+ for ( const pendingResponse of this . #pendingResponses. values ( ) ) {
1281+ pendingResponse . reject ( closeError ) ;
1282+ }
1283+ this . #pendingResponses. clear ( ) ;
1284+ this . #abortController. abort ( closeError ) ;
1285+ }
1286+
12621287 async #processMessage( message : AnyMessage ) {
12631288 if ( "method" in message && "id" in message ) {
12641289 // It's a request
@@ -1376,7 +1401,8 @@ class Connection {
13761401 if ( "result" in response ) {
13771402 pendingResponse . resolve ( response . result ) ;
13781403 } else if ( "error" in response ) {
1379- pendingResponse . reject ( response . error ) ;
1404+ const { code, message, data } = response . error ;
1405+ pendingResponse . reject ( new RequestError ( code , message , data ) ) ;
13801406 }
13811407 this . #pendingResponses. delete ( response . id ) ;
13821408 } else {
@@ -1385,6 +1411,7 @@ class Connection {
13851411 }
13861412
13871413 async sendRequest < Req , Resp > ( method : string , params ?: Req ) : Promise < Resp > {
1414+ this . #throwIfClosed( ) ;
13881415 const id = this . #nextRequestId++ ;
13891416 const responsePromise = new Promise ( ( resolve , reject ) => {
13901417 this . #pendingResponses. set ( id , { resolve, reject } ) ;
@@ -1394,9 +1421,19 @@ class Connection {
13941421 }
13951422
13961423 async sendNotification < N > ( method : string , params ?: N ) : Promise < void > {
1424+ this . #throwIfClosed( ) ;
13971425 await this . #sendMessage( { jsonrpc : "2.0" , method, params } ) ;
13981426 }
13991427
1428+ #throwIfClosed( ) {
1429+ if ( this . #abortController. signal . aborted ) {
1430+ throw (
1431+ this . #abortController. signal . reason ??
1432+ new Error ( "ACP connection closed" )
1433+ ) ;
1434+ }
1435+ }
1436+
14001437 async #sendMessage( message : AnyMessage ) {
14011438 this . #writeQueue = this . #writeQueue
14021439 . then ( async ( ) => {
@@ -1408,8 +1445,7 @@ class Connection {
14081445 }
14091446 } )
14101447 . catch ( ( error ) => {
1411- // Continue processing writes on error
1412- console . error ( "ACP write error:" , error ) ;
1448+ this . #close( error ) ;
14131449 } ) ;
14141450 return this . #writeQueue;
14151451 }
0 commit comments