@@ -81,7 +81,7 @@ function installRuntime(): MockRuntime {
8181}
8282
8383function createMockFetch ( entries : Array < { match : RegExp ; response : Response } > ) : typeof fetch {
84- return ( async ( input : RequestInfo | URL ) => {
84+ return vi . fn ( async ( input : RequestInfo | URL ) => {
8585 const url =
8686 typeof input === "string" ? input : input instanceof URL ? input . toString ( ) : input . url ;
8787 const entry = entries . find ( ( e ) => e . match . test ( url ) ) ;
@@ -175,6 +175,7 @@ describe("downloadMSTeamsBotFrameworkAttachment", () => {
175175 tokenProvider : buildTokenProvider ( ) ,
176176 maxBytes : 10_000_000 ,
177177 fetchFn,
178+ fetchFnSupportsDispatcher : true ,
178179 resolveFn : resolvePublicHost ,
179180 } ) ;
180181
@@ -198,6 +199,7 @@ describe("downloadMSTeamsBotFrameworkAttachment", () => {
198199 tokenProvider : buildTokenProvider ( ) ,
199200 maxBytes : 10_000_000 ,
200201 fetchFn,
202+ fetchFnSupportsDispatcher : true ,
201203 resolveFn : resolvePublicHost ,
202204 } ) ;
203205
@@ -218,6 +220,7 @@ describe("downloadMSTeamsBotFrameworkAttachment", () => {
218220 tokenProvider : buildTokenProvider ( ) ,
219221 maxBytes : 10_000_000 ,
220222 fetchFn,
223+ fetchFnSupportsDispatcher : true ,
221224 resolveFn : resolvePublicHost ,
222225 } ) ;
223226
@@ -258,6 +261,7 @@ describe("downloadMSTeamsBotFrameworkAttachment", () => {
258261 tokenProvider : buildTokenProvider ( ) ,
259262 maxBytes : 10_000_000 ,
260263 fetchFn,
264+ fetchFnSupportsDispatcher : true ,
261265 resolveFn : resolvePublicHost ,
262266 } ) ;
263267
@@ -325,15 +329,8 @@ describe("downloadMSTeamsBotFrameworkAttachment", () => {
325329 expect ( fetchFn ) . not . toHaveBeenCalled ( ) ;
326330 } ) ;
327331
328- describe ( "Node 24+ dispatcher bypass (issue #63396)" , ( ) => {
329- it ( "drives the caller's fetchFn directly without the pinned undici dispatcher" , async ( ) => {
330- // Regression: before the fix, fetchBotFrameworkAttachment* routed
331- // through `fetchWithSsrFGuard`, which installs a `createPinnedDispatcher`
332- // incompatible with Node 24+'s built-in undici v7. Downloads failed with
333- // "invalid onRequestStart method". The fix switches to
334- // `safeFetchWithPolicy`, which calls the supplied `fetchFn` directly
335- // and never attaches a pinned dispatcher. Verify the caller's `fetchFn`
336- // is invoked (no dispatcher in init).
332+ describe ( "guarded attachment fetches" , ( ) => {
333+ it ( "drives dispatcher-aware caller fetchFn hooks through a pinned dispatcher" , async ( ) => {
337334 const fileBytes = Buffer . from ( "BFBYTES" , "utf-8" ) ;
338335 const fetchCalls : Array < { url : string ; init ?: RequestInit } > = [ ] ;
339336 const fetchFn : typeof fetch = ( async ( input : RequestInfo | URL , init ?: RequestInit ) => {
@@ -365,20 +362,20 @@ describe("downloadMSTeamsBotFrameworkAttachment", () => {
365362 tokenProvider : buildTokenProvider ( ) ,
366363 maxBytes : 10_000_000 ,
367364 fetchFn,
365+ fetchFnSupportsDispatcher : true ,
368366 resolveFn : resolvePublicHost ,
369367 } ) ;
370368
371369 expect ( media ?. path ) . toBe ( runtime . savePath ) ;
372370 expect ( media ?. contentType ) . toBe ( runtime . savedContentType ) ;
373371 // Both the attachment info call and the view call should be observed,
374- // confirming the direct fetch path was taken (no dispatcher interception) .
372+ // confirming the guarded fetch path still preserves caller fetch hooks .
375373 expect ( fetchCalls ) . toHaveLength ( 2 ) ;
376374 expect ( fetchCalls [ 0 ] . url . endsWith ( "/v3/attachments/att-1" ) ) . toBe ( true ) ;
377375 expect ( fetchCalls [ 1 ] . url . endsWith ( "/v3/attachments/att-1/views/original" ) ) . toBe ( true ) ;
378- // Verify no pinned undici dispatcher is attached on either request.
379376 for ( const call of fetchCalls ) {
380377 const init = call . init as RequestInit & { dispatcher ?: unknown } ;
381- expect ( init ?. dispatcher ) . toBeUndefined ( ) ;
378+ expect ( init ?. dispatcher ) . toBeDefined ( ) ;
382379 }
383380 } ) ;
384381
@@ -396,6 +393,7 @@ describe("downloadMSTeamsBotFrameworkAttachment", () => {
396393 tokenProvider : buildTokenProvider ( ) ,
397394 maxBytes : 10_000_000 ,
398395 fetchFn,
396+ fetchFnSupportsDispatcher : true ,
399397 resolveFn : resolvePublicHost ,
400398 logger,
401399 } ) ;
@@ -433,6 +431,7 @@ describe("downloadMSTeamsBotFrameworkAttachment", () => {
433431 tokenProvider : buildTokenProvider ( ) ,
434432 maxBytes : 10_000_000 ,
435433 fetchFn,
434+ fetchFnSupportsDispatcher : true ,
436435 resolveFn : resolvePublicHost ,
437436 logger,
438437 } ) ;
0 commit comments