@@ -50,6 +50,7 @@ const DEFAULT_CLOSE_TIMEOUT_MS = 5_000;
5050const DEFAULT_MAX_RECONNECT_ATTEMPTS = 5 ;
5151const DEFAULT_RECONNECT_DELAY_MS = 1000 ;
5252const DEFAULT_MAX_QUEUED_BYTES = 2 * 1024 * 1024 ;
53+ const RECONNECT_STABLE_RESET_MS = 30_000 ;
5354
5455function rawWsDataToBuffer ( data : RawData ) : Buffer {
5556 if ( Buffer . isBuffer ( data ) ) {
@@ -78,6 +79,7 @@ class WebSocketRealtimeTranscriptionSession<Event> implements RealtimeTranscript
7879 private queuedBytes = 0 ;
7980 private ready = false ;
8081 private reconnectAttempts = 0 ;
82+ private reconnectStableTimer : ReturnType < typeof setTimeout > | undefined ;
8183 private reconnecting = false ;
8284 private suppressReconnect = false ;
8385 private ws : WebSocket | null = null ;
@@ -108,6 +110,7 @@ class WebSocketRealtimeTranscriptionSession<Event> implements RealtimeTranscript
108110 this . closed = false ;
109111 this . suppressReconnect = false ;
110112 this . reconnectAttempts = 0 ;
113+ this . clearReconnectStableReset ( ) ;
111114 await this . doConnect ( ) ;
112115 }
113116
@@ -128,6 +131,7 @@ class WebSocketRealtimeTranscriptionSession<Event> implements RealtimeTranscript
128131 this . closed = true ;
129132 this . connected = false ;
130133 this . ready = false ;
134+ this . clearReconnectStableReset ( ) ;
131135 this . queuedAudio = [ ] ;
132136 this . queuedBytes = 0 ;
133137 if ( ! this . ws || this . ws . readyState !== WebSocket . OPEN ) {
@@ -201,6 +205,7 @@ class WebSocketRealtimeTranscriptionSession<Event> implements RealtimeTranscript
201205 settled = true ;
202206 clearConnectTimeout ( ) ;
203207 this . ready = true ;
208+ this . scheduleReconnectStableReset ( ) ;
204209 this . flushQueuedAudio ( ) ;
205210 resolve ( ) ;
206211 } ;
@@ -259,7 +264,6 @@ class WebSocketRealtimeTranscriptionSession<Event> implements RealtimeTranscript
259264 this . ws . on ( "open" , ( ) => {
260265 opened = true ;
261266 this . connected = true ;
262- this . reconnectAttempts = 0 ;
263267 this . captureLocalOpen ( ) ;
264268 try {
265269 this . options . onOpen ?.( this . transport ) ;
@@ -300,6 +304,7 @@ class WebSocketRealtimeTranscriptionSession<Event> implements RealtimeTranscript
300304 this . captureClose ( code , reasonBuffer ) ;
301305 this . connected = false ;
302306 this . ready = false ;
307+ this . clearReconnectStableReset ( ) ;
303308 if ( this . closeTimer ) {
304309 clearTimeout ( this . closeTimer ) ;
305310 this . closeTimer = undefined ;
@@ -415,6 +420,7 @@ class WebSocketRealtimeTranscriptionSession<Event> implements RealtimeTranscript
415420 clearTimeout ( this . closeTimer ) ;
416421 this . closeTimer = undefined ;
417422 }
423+ this . clearReconnectStableReset ( ) ;
418424 this . connected = false ;
419425 this . ready = false ;
420426 if ( this . ws ) {
@@ -423,6 +429,27 @@ class WebSocketRealtimeTranscriptionSession<Event> implements RealtimeTranscript
423429 }
424430 }
425431
432+ private scheduleReconnectStableReset ( ) : void {
433+ this . clearReconnectStableReset ( ) ;
434+ if ( this . reconnectAttempts <= 0 ) {
435+ return ;
436+ }
437+ this . reconnectStableTimer = setTimeout ( ( ) => {
438+ this . reconnectStableTimer = undefined ;
439+ if ( this . connected && this . ready ) {
440+ this . reconnectAttempts = 0 ;
441+ }
442+ } , RECONNECT_STABLE_RESET_MS ) ;
443+ }
444+
445+ private clearReconnectStableReset ( ) : void {
446+ if ( ! this . reconnectStableTimer ) {
447+ return ;
448+ }
449+ clearTimeout ( this . reconnectStableTimer ) ;
450+ this . reconnectStableTimer = undefined ;
451+ }
452+
426453 private emitError ( error : unknown ) : void {
427454 const normalized = error instanceof Error ? error : new Error ( String ( error ) ) ;
428455 try {
0 commit comments