1
1
import { readFileSync } from 'node:fs'
2
2
import path from 'node:path'
3
3
import process from 'node:process'
4
- import { Readable , type Stream } from 'node:stream'
4
+ import type { Readable } from 'node:stream'
5
5
6
6
import {
7
7
createFake as createFakeDevicedb ,
@@ -10,8 +10,6 @@ import {
10
10
} from '@seamapi/fake-devicedb'
11
11
import { createFake } from '@seamapi/fake-seam-connect'
12
12
import type { VercelRequest , VercelResponse } from '@vercel/node'
13
- import axios from 'axios'
14
- import getRawBody from 'raw-body'
15
13
16
14
// eslint-disable-next-line import/no-relative-parent-imports
17
15
import { seedFake } from '../.storybook/seed-fake.js'
@@ -40,7 +38,8 @@ export default async (
40
38
req : VercelRequest ,
41
39
res : VercelResponse
42
40
) : Promise < void > => {
43
- const { apipath, ...getParams } = req . query
41
+ const { method } = req
42
+ const { apipath, ...query } = req . query
44
43
45
44
const fake = await createFake ( )
46
45
seedFake ( fake . database )
@@ -58,28 +57,47 @@ export default async (
58
57
if ( host == null ) throw new Error ( 'Missing Host header' )
59
58
await fake . startServer ( { baseUrl : `https://${ host } /api` } )
60
59
61
- const requestBuffer = await getRawBody ( req )
60
+ const body = await buffer ( req )
62
61
63
62
if ( typeof apipath !== 'string' ) {
64
63
throw new Error ( 'Expected apipath to be a string' )
65
64
}
66
65
67
- const { status, data, headers } = await axios . request ( {
68
- url : `${ fake . serverUrl } /${ apipath } ` ,
69
- params : getParams ,
70
- method : req . method ,
71
- headers : { ...req . headers } ,
72
- data : getRequestStreamFromBuffer ( requestBuffer ) ,
73
- timeout : 10_000 ,
74
- validateStatus : ( ) => true ,
75
- maxRedirects : 0 ,
76
- responseType : 'arraybuffer' ,
66
+ const serverUrl = fake . serverUrl
67
+ if ( serverUrl == null ) {
68
+ throw new Error ( 'Fake serverUrl was null' )
69
+ }
70
+
71
+ if ( method == null ) {
72
+ throw new Error ( 'Request method undefined' )
73
+ }
74
+
75
+ const url = new URL ( apipath , serverUrl )
76
+ for ( const [ k , v ] of Object . entries ( query ) ) {
77
+ if ( typeof v === 'string' ) url . searchParams . append ( k , v )
78
+ }
79
+
80
+ const reqHeaders : Record < string , string > = { }
81
+ for ( const [ k , v ] of Object . entries ( req . headers ) ) {
82
+ if ( k === 'content-length' ) continue
83
+ if ( typeof v === 'string' ) reqHeaders [ k ] = v
84
+ }
85
+ const proxyRes = await fetch ( url , {
86
+ redirect : 'follow' ,
87
+ mode : 'cors' ,
88
+ credentials : 'include' ,
89
+ method,
90
+ headers : reqHeaders ,
91
+ ...( [ 'GET' , 'HEAD' , 'OPTIONS' ] . includes ( method ) ? { } : { body } ) ,
77
92
} )
78
93
94
+ const { status, headers } = proxyRes
95
+ const data = await proxyRes . arrayBuffer ( )
96
+
79
97
res . status ( status )
80
98
81
- for ( const [ key , value ] of Object . entries ( headers ) ) {
82
- if ( ! unproxiedHeaders . has ( key ) ) res . setHeader ( key , value as string )
99
+ for ( const [ key , value ] of headers ) {
100
+ if ( ! unproxiedHeaders . has ( key ) ) res . setHeader ( key , value )
83
101
}
84
102
85
103
res . end ( Buffer . from ( data as Buffer ) )
@@ -95,12 +113,11 @@ const getFakeDevicedb = async (): Promise<FakeDevicedb> => {
95
113
return fake
96
114
}
97
115
98
- // https://stackoverflow.com/a/44091532/559475
99
- const getRequestStreamFromBuffer = ( requestBuffer : Buffer ) : Stream => {
100
- const requestStream = new Readable ( )
101
- // eslint-disable-next-line @typescript-eslint/no-empty-function
102
- requestStream . _read = ( ) => { }
103
- requestStream . push ( requestBuffer )
104
- requestStream . push ( null )
105
- return requestStream
116
+ const buffer = async ( readable : Readable ) : Promise < ArrayBuffer > => {
117
+ const chunks = [ ]
118
+ for await ( const chunk of readable ) {
119
+ chunks . push ( typeof chunk === 'string' ? Buffer . from ( chunk ) : chunk )
120
+ }
121
+ const buf = Buffer . concat ( chunks )
122
+ return new Uint8Array ( buf ) . buffer
106
123
}
0 commit comments