1- import { once } from "node:events" ;
2- import type { IncomingMessage , ServerResponse } from "node:http" ;
3- import { TLSSocket } from "node:tls" ;
4- import { Readable } from "node:stream" ;
5- import { splitCookiesString } from "set-cookie-parser" ;
6- import { createReadableStreamFromReadable } from "@react-router/node" ;
1+ import type { ServerResponse } from "node:http" ;
2+
3+ import { createRequest } from "@remix-run/node-fetch-server" ;
74import type * as Vite from "vite" ;
85
96import invariant from "../invariant" ;
@@ -13,110 +10,16 @@ export type NodeRequestHandler = (
1310 res : ServerResponse ,
1411) => Promise < void > ;
1512
16- function fromNodeHeaders ( nodeReq : IncomingMessage ) : Headers {
17- let nodeHeaders = nodeReq . headers ;
18-
19- if ( nodeReq . httpVersionMajor >= 2 ) {
20- nodeHeaders = { ...nodeHeaders } ;
21- if ( nodeHeaders [ ":authority" ] ) {
22- nodeHeaders . host = nodeHeaders [ ":authority" ] as string ;
23- }
24- delete nodeHeaders [ ":authority" ] ;
25- delete nodeHeaders [ ":method" ] ;
26- delete nodeHeaders [ ":path" ] ;
27- delete nodeHeaders [ ":scheme" ] ;
28- }
29-
30- let headers = new Headers ( ) ;
31-
32- for ( let [ key , values ] of Object . entries ( nodeHeaders ) ) {
33- if ( values ) {
34- if ( Array . isArray ( values ) ) {
35- for ( let value of values ) {
36- headers . append ( key , value ) ;
37- }
38- } else {
39- headers . set ( key , values ) ;
40- }
41- }
42- }
43-
44- return headers ;
45- }
46-
47- // Based on `createRemixRequest` in packages/react-router-express/server.ts
4813export function fromNodeRequest (
4914 nodeReq : Vite . Connect . IncomingMessage ,
5015 nodeRes : ServerResponse < Vite . Connect . IncomingMessage > ,
5116) : Request {
52- let protocol =
53- nodeReq . socket instanceof TLSSocket && nodeReq . socket . encrypted
54- ? "https"
55- : "http" ;
56- let origin =
57- nodeReq . headers . origin && "null" !== nodeReq . headers . origin
58- ? nodeReq . headers . origin
59- : `${ protocol } ://${ nodeReq . headers . host } ` ;
6017 // Use `req.originalUrl` so React Router is aware of the full path
6118 invariant (
6219 nodeReq . originalUrl ,
6320 "Expected `nodeReq.originalUrl` to be defined" ,
6421 ) ;
65- let url = new URL ( nodeReq . originalUrl , origin ) ;
66-
67- // Abort action/loaders once we can no longer write a response
68- let controller : AbortController | null = new AbortController ( ) ;
69- let init : RequestInit = {
70- method : nodeReq . method ,
71- headers : fromNodeHeaders ( nodeReq ) ,
72- signal : controller . signal ,
73- } ;
74-
75- // Abort action/loaders once we can no longer write a response iff we have
76- // not yet sent a response (i.e., `close` without `finish`)
77- // `finish` -> done rendering the response
78- // `close` -> response can no longer be written to
79- nodeRes . on ( "finish" , ( ) => ( controller = null ) ) ;
80- nodeRes . on ( "close" , ( ) => controller ?. abort ( ) ) ;
81-
82- if ( nodeReq . method !== "GET" && nodeReq . method !== "HEAD" ) {
83- init . body = createReadableStreamFromReadable ( nodeReq ) ;
84- ( init as { duplex : "half" } ) . duplex = "half" ;
85- }
86-
87- return new Request ( url . href , init ) ;
88- }
89-
90- // Adapted from solid-start's `handleNodeResponse`:
91- // https://github.com/solidjs/solid-start/blob/7398163869b489cce503c167e284891cf51a6613/packages/start/node/fetch.js#L162-L185
92- export async function toNodeRequest ( res : Response , nodeRes : ServerResponse ) {
93- nodeRes . statusCode = res . status ;
94-
95- // HTTP/2 doesn't support status messages
96- // https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.4
97- if ( ! nodeRes . req || nodeRes . req . httpVersionMajor < 2 ) {
98- nodeRes . statusMessage = res . statusText ;
99- }
100-
101- let cookiesStrings = [ ] ;
102-
103- for ( let [ name , value ] of res . headers ) {
104- if ( name === "set-cookie" ) {
105- cookiesStrings . push ( ...splitCookiesString ( value ) ) ;
106- } else nodeRes . setHeader ( name , value ) ;
107- }
108-
109- if ( cookiesStrings . length ) {
110- nodeRes . setHeader ( "set-cookie" , cookiesStrings ) ;
111- }
22+ nodeReq . url = nodeReq . originalUrl ;
11223
113- if ( res . body ) {
114- // https://github.com/microsoft/TypeScript/issues/29867
115- let responseBody = res . body as unknown as AsyncIterable < Uint8Array > ;
116- let readable = Readable . from ( responseBody ) ;
117- readable . pipe ( nodeRes ) ;
118- await once ( readable , "end" ) ;
119- } else {
120- nodeRes . end ( ) ;
121- }
24+ return createRequest ( nodeReq , nodeRes ) ;
12225}
0 commit comments