import { URL } from "url" ; import { Request , RequestInfo , RequestInit , Response , _headersFromIncomingRequest , fetch , } from "@miniflare/core" ; import { getRequestContext } from "@miniflare/shared" ; import { Headers } from "undici" ; import StandardWebSocket from "ws" ; import { coupleWebSocket } from "./couple" ; import { WebSocketPair } from "./websocket" ; export async function upgradingFetch ( input , init ? ) { const request = new Request ( input , init ) ; if ( request . method === "GET" && request . headers . get ( "upgrade" ) === "websocket" ) { getRequestContext ( ) ?. incrementSubrequests ( ) ; const url = new URL ( request . url ) ; if ( url . protocol !== "http:" && url . protocol !== "https:" ) { throw new TypeError ( `Fetch API cannot load: ${ url . toString ( ) }.\nMake sure you're using http(s):// URLs for WebSocket requests via fetch.` ) ; } url . protocol = url . protocol . replace ( "http" , "ws" ) ; const headers = { } ; let protocols ; for ( const [ key , value ] of request . headers . entries ( ) ) { if ( key . toLowerCase ( ) === "sec-websocket-protocol" ) { protocols = value . split ( "," ) . map ( ( protocol ) => protocol . trim ( ) ) ; } else { headers [ key ] = value ; } } const ws = new StandardWebSocket ( url , protocols , { followRedirects : request . redirect === "follow" , headers , } ) ; let headersResolve ; const headersPromise = new Promise < Headers > ( ( resolve ) => { headersResolve = resolve ; } ) ; ws . once ( "upgrade" , ( req ) => { headersResolve ( _headersFromIncomingRequest ( req ) ) ; } ) ; const [ worker , client ] = Object . values ( new WebSocketPair ( ) ) ; await coupleWebSocket ( ws , client ) ; return new Response ( null , { status : 101 , webSocket : worker , headers : await headersPromise , } ) ; } return fetch ( request ) ; }