import type { Readable } from "stream" ; import { PassThrough } from "stream" ; import type AbortController from "abort-controller" ; import FormStream from "form-data" ; import type { RequestInfo , RequestInit , Response } from "node-fetch" ; import nodeFetch , { Request as BaseNodeRequest } from "node-fetch" ; import { FormData as NodeFormData , isFile } from "./formData" ; import type { UploadHandler } from "./formData" ; import { internalParseFormData } from "./parseMultipartFormData" ; export type { HeadersInit , RequestInfo , ResponseInit } from "node-fetch" ; export { Headers , Response } from "node-fetch" ; function formDataToStream ( formData ) { let formStream = new FormStream ( ) ; function toNodeStream ( input ) { if ( typeof input ?. on === "function" ) { return input ; } let passthrough = new PassThrough ( ) ; let stream = input as ReadableStream < any > ; let reader = stream . getReader ( ) ; reader . read ( ) . then ( async ( { done , value } ) => { while ( ! done ) { passthrough . push ( value ) ; ( { done , value } = await reader . read ( ) ) ; } passthrough . push ( null ) ; } ) . catch ( error => { passthrough . emit ( "error" , error ) ; } ) ; return passthrough ; } for ( let [ key , value ] of formData . entries ( ) ) { if ( typeof value === "string" ) { formStream . append ( key , value ) ; } else if ( isFile ( value ) ) { let stream = toNodeStream ( value . stream ( ) ) ; formStream . append ( key , stream , { filename : value . name , contentType : value . type , knownLength : value . size } ) ; } else { let file = value as File ; let stream = toNodeStream ( file . stream ( ) ) ; formStream . append ( key , stream , { filename : "unknown" } ) ; } } return formStream ; } interface NodeRequestInit extends RequestInit { abortController ? : AbortController ; } class NodeRequest extends BaseNodeRequest { private abortController ? : AbortController ; constructor ( input , init ? ) { if ( init ?. body instanceof NodeFormData ) { init = { ... init , body : formDataToStream ( init . body ) } ; } super ( input , init ) ; let anyInput = input as any ; let anyInit = init as any ; this . abortController = anyInput ?. abortController || anyInit ?. abortController ; } async formData ( uploadHandler ? ) { let contentType = this . headers . get ( "Content-Type" ) ; if ( contentType ) { return await internalParseFormData ( contentType , this . body as Readable , this . abortController , uploadHandler ) ; } throw new Error ( "Invalid MIME type" ) ; } clone ( ) { return new NodeRequest ( this ) ; } } export { NodeRequest as Request , NodeRequestInit as RequestInit } ; see https see https export function fetch ( input , init ? ) { init = { compress : false , ... init } ; if ( init ?. body instanceof NodeFormData ) { init = { ... init , body : formDataToStream ( init . body ) } ; } return nodeFetch ( input , init ) ; }