11import { Readable } from "node:stream" ;
2- import type { ReadableStream as WebReadableStream } from "node:stream/web" ;
32import type { Federation } from "@fedify/fedify" ;
43import type {
54 Request as ERequest ,
@@ -25,15 +24,18 @@ export function integrateFederation<TContextData>(
2524 ? contextData
2625 : Promise . resolve ( contextData ) ;
2726 contextDataPromise . then ( async ( contextData ) => {
27+ let notFound = false ;
28+ let notAcceptable = false ;
2829 const response = await federation . fetch ( request , {
2930 contextData,
3031 onNotFound : ( ) => {
3132 // If the `federation` object finds a request not responsible for it
3233 // (i.e., not a federation-related request), it will call the `next`
3334 // function provided by the Express framework to continue the request
3435 // handling by the Express:
36+ notFound = true ;
3537 next ( ) ;
36- return new Response ( "" , { status : 404 } ) ; // unused
38+ return new Response ( "Not found " , { status : 404 } ) ; // unused
3739 } ,
3840 onNotAcceptable : ( ) => {
3941 // Similar to `onNotFound`, but slightly more tricky.
@@ -42,11 +44,27 @@ export function integrateFederation<TContextData>(
4244 // the `next` function provided by the Express framework to continue
4345 // if any route is matched, and otherwise, it will return a 406 Not
4446 // Acceptable response:
45- if ( req . route != null ) next ( ) ;
46- return new Response ( "" , { status : 406 } ) ;
47+ notAcceptable = true ;
48+ next ( ) ;
49+ return new Response ( "Not acceptable" , {
50+ status : 406 ,
51+ headers : {
52+ "Content-Type" : "text/plain" ,
53+ Vary : "Accept" ,
54+ } ,
55+ } ) ;
4756 } ,
4857 } ) ;
49- setEResponse ( res , response ) ;
58+ if ( notFound || ( notAcceptable && req . route != null ) ) return ;
59+ await setEResponse ( res , response ) ;
60+ // Prevent the Express framework from sending the response again:
61+ res . end ( ) ;
62+ res . status = ( ) => res ;
63+ res . send = ( ) => res ;
64+ res . end = ( ) => res ;
65+ res . json = ( ) => res ;
66+ res . removeHeader = ( ) => res ;
67+ res . setHeader = ( ) => res ;
5068 } ) ;
5169 } ;
5270}
@@ -64,14 +82,28 @@ function fromERequest(req: ERequest): Request {
6482 return new Request ( url , {
6583 method : req . method ,
6684 headers,
67- body : Readable . toWeb ( req ) as ReadableStream < Uint8Array > ,
85+ body :
86+ req . method === "GET" || req . method === "HEAD"
87+ ? undefined
88+ : ( Readable . toWeb ( req ) as ReadableStream < Uint8Array > ) ,
6889 } ) ;
6990}
7091
71- function setEResponse ( res : EResponse , response : Response ) : void {
92+ function setEResponse ( res : EResponse , response : Response ) : Promise < void > {
7293 res . status ( response . status ) ;
7394 response . headers . forEach ( ( value , key ) => res . setHeader ( key , value ) ) ;
74- if ( response . body == null ) return ;
75- // biome-ignore lint/suspicious/noExplicitAny: Readable.fromWeb is untyped
76- Readable . fromWeb ( response . body as WebReadableStream < any > ) . pipe ( res ) ;
95+ if ( response . body == null ) return Promise . resolve ( ) ;
96+ const body = response . body ;
97+ return new Promise ( ( resolve ) => {
98+ const reader = body . getReader ( ) ;
99+ reader . read ( ) . then ( function read ( { done, value } ) {
100+ if ( done ) {
101+ reader . releaseLock ( ) ;
102+ resolve ( ) ;
103+ return ;
104+ }
105+ res . write ( Buffer . from ( value ) ) ;
106+ reader . read ( ) . then ( read ) ;
107+ } ) ;
108+ } ) ;
77109}
0 commit comments