@@ -70,6 +70,23 @@ export function consumeSSEChunk(buffer: string, chunk: string): { events: Parsed
7070 return { events, buffer : rest } ;
7171}
7272
73+ function abortError ( ) : DOMException {
74+ return new DOMException ( 'Aborted' , 'AbortError' ) ;
75+ }
76+
77+ function waitForCaller < T > ( operation : PromiseLike < T > , signal ?: AbortSignal ) : Promise < T > {
78+ if ( ! signal ) return Promise . resolve ( operation ) ;
79+ if ( signal . aborted ) return Promise . reject ( abortError ( ) ) ;
80+
81+ return new Promise < T > ( ( resolve , reject ) => {
82+ const onAbort = ( ) => reject ( abortError ( ) ) ;
83+ signal . addEventListener ( 'abort' , onAbort , { once : true } ) ;
84+ Promise . resolve ( operation )
85+ . then ( resolve , reject )
86+ . finally ( ( ) => signal . removeEventListener ( 'abort' , onAbort ) ) ;
87+ } ) ;
88+ }
89+
7390function captureStreamFailure (
7491 error : unknown ,
7592 provider : string ,
@@ -115,14 +132,14 @@ export async function streamAskChat(
115132 } ) ;
116133
117134 if ( handlers . signal ?. aborted ) {
118- const error = new DOMException ( 'Aborted' , 'AbortError' ) ;
135+ const error = abortError ( ) ;
119136 captureStreamFailure ( error , provider , config . model , startTime , true ) ;
120137 throw error ;
121138 }
122139
123140 let sessionData : Awaited < ReturnType < typeof supabase . auth . getSession > > [ 'data' ] ;
124141 try {
125- ( { data : sessionData } = await supabase . auth . getSession ( ) ) ;
142+ ( { data : sessionData } = await waitForCaller ( supabase . auth . getSession ( ) , handlers . signal ) ) ;
126143 } catch ( error ) {
127144 captureStreamFailure ( error , provider , config . model , startTime , Boolean ( handlers . signal ?. aborted ) ) ;
128145 throw error ;
@@ -135,9 +152,9 @@ export async function streamAskChat(
135152 throw error ;
136153 }
137154 if ( handlers . signal ?. aborted ) {
138- const error = new DOMException ( 'Aborted' , 'AbortError' ) ;
155+ const error = abortError ( ) ;
139156 captureStreamFailure ( error , provider , config . model , startTime , true ) ;
140- throw new DOMException ( 'Aborted' , 'AbortError' ) ;
157+ throw error ;
141158 }
142159
143160 const controller = new AbortController ( ) ;
@@ -236,6 +253,7 @@ export async function streamAskChat(
236253 throw new DOMException ( 'Aborted' , 'AbortError' ) ;
237254 }
238255 const { done, value } = await reader . read ( ) ;
256+ if ( handlers . signal ?. aborted ) throw abortError ( ) ;
239257 if ( done ) break ;
240258
241259 const parsed = consumeSSEChunk ( buffer , decoder . decode ( value , { stream : true } ) ) ;
@@ -261,9 +279,13 @@ export async function streamAskChat(
261279 return finalOutput ;
262280 } catch ( error ) {
263281 const callerAborted = Boolean ( handlers . signal ?. aborted ) ;
264- const reportedError = ! callerAborted && controller . signal . aborted ? new TimeoutError ( ) : error ;
282+ const reportedError = callerAborted
283+ ? abortError ( )
284+ : controller . signal . aborted
285+ ? new TimeoutError ( )
286+ : error ;
265287 captureStreamFailure ( reportedError , provider , config . model , startTime , callerAborted ) ;
266- if ( handlers . signal ?. aborted ) throw error ;
288+ if ( callerAborted ) throw reportedError ;
267289 if ( controller . signal . aborted ) throw reportedError ;
268290 throw error ;
269291 } finally {
0 commit comments