@@ -319,6 +319,21 @@ export interface RPCServerTransportOptions {
319319 * ```
320320 */
321321 onsessionclosed ?: ( sessionId : string ) => void | Promise < void > ;
322+
323+ /**
324+ * Timeout in milliseconds for waiting for a response from the onmessage handler.
325+ * If the handler doesn't call send() within this time, the request will fail with a timeout error.
326+ *
327+ * @default 60000 (60 seconds)
328+ *
329+ * @example
330+ * ```typescript
331+ * const transport = new RPCServerTransport({
332+ * timeout: 30000 // 30 seconds
333+ * });
334+ * ```
335+ */
336+ timeout ?: number ;
322337}
323338
324339export class RPCServerTransport implements Transport {
@@ -331,6 +346,7 @@ export class RPCServerTransport implements Transport {
331346 private _initialized = false ;
332347 private _onsessioninitialized ?: ( sessionId : string ) => void | Promise < void > ;
333348 private _onsessionclosed ?: ( sessionId : string ) => void | Promise < void > ;
349+ private _timeout : number ;
334350
335351 sessionId ?: string ;
336352 onclose ?: ( ) => void ;
@@ -341,6 +357,7 @@ export class RPCServerTransport implements Transport {
341357 this . _sessionIdGenerator = options ?. sessionIdGenerator ;
342358 this . _onsessioninitialized = options ?. onsessioninitialized ;
343359 this . _onsessionclosed = options ?. onsessionclosed ;
360+ this . _timeout = options ?. timeout ?? 60000 ; // Default 60 seconds
344361 }
345362
346363 setProtocolVersion ( version : string ) : void {
@@ -516,14 +533,40 @@ export class RPCServerTransport implements Transport {
516533 this . _currentRequestId = ( message as { id : string | number | null } ) . id ;
517534
518535 // Set up the promise before calling onmessage to handle race conditions
519- const responsePromise = new Promise < void > ( ( resolve ) => {
520- this . _responseResolver = resolve ;
536+ let timeoutId : ReturnType < typeof setTimeout > | null = null ;
537+ const responsePromise = new Promise < void > ( ( resolve , reject ) => {
538+ // Set up timeout
539+ timeoutId = setTimeout ( ( ) => {
540+ this . _responseResolver = null ;
541+ reject (
542+ new Error (
543+ `Request timeout: No response received within ${ this . _timeout } ms for request ID ${ this . _currentRequestId } `
544+ )
545+ ) ;
546+ } , this . _timeout ) ;
547+
548+ // Wrap the resolver to clear timeout when response is received
549+ this . _responseResolver = ( ) => {
550+ if ( timeoutId ) {
551+ clearTimeout ( timeoutId ) ;
552+ timeoutId = null ;
553+ }
554+ resolve ( ) ;
555+ } ;
521556 } ) ;
522557
523558 this . onmessage ?.( message ) ;
524559
525560 // Wait for a response using a promise that resolves when send() is called
526- await responsePromise ;
561+ try {
562+ await responsePromise ;
563+ } catch ( error ) {
564+ // Clean up on timeout
565+ this . _pendingResponse = null ;
566+ this . _currentRequestId = null ;
567+ this . _responseResolver = null ;
568+ throw error ;
569+ }
527570
528571 const response = this . _pendingResponse ;
529572 this . _pendingResponse = null ;
0 commit comments