Skip to content

Commit 8fafba5

Browse files
committed
refact(helpers): add request helper
but I don't think we need it. The fetch api should be sufficient nowadays.
1 parent e16752d commit 8fafba5

1 file changed

Lines changed: 98 additions & 0 deletions

File tree

src/helpers/request.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { Buffer } from 'node:buffer'
2+
import process from 'node:process'
3+
4+
import pkg from '../../package.json' with { type: 'json' }
5+
const convertReadableStream = async (readable: any) => {
6+
// create output details
7+
let string = ''
8+
const chunks = []
9+
10+
// handle each chunk
11+
for await (const chunk of readable) {
12+
string += chunk
13+
chunks.push(chunk)
14+
}
15+
16+
// reformat buffer
17+
const buffer = Buffer.concat(chunks)
18+
19+
// return data
20+
return { string, buffer }
21+
}
22+
const { name, version } = pkg
23+
24+
const userAgent = `${name.replace('@', '')}/${version}`
25+
26+
const defaultOptions: RequestInit = {
27+
method: 'GET',
28+
// keepAliveTimeout: 30e3,
29+
// headersTimeout: 0,
30+
// bodyTimeout: 0,
31+
headers: {
32+
'user-agent': process.env.USER_AGENT || userAgent,
33+
},
34+
}
35+
36+
/** 7 seconds (as milliseconds) */
37+
const DEFAULT_TIMEOUT = 7e3
38+
39+
type OptionsTimeout = { timeout: number }
40+
type OptionsReject = { reject: boolean }
41+
42+
export const request = async (
43+
url: string,
44+
options: RequestInit & OptionsTimeout & OptionsReject
45+
): Promise<Record<any, any>> => {
46+
const requestOptions: RequestInit = {
47+
...defaultOptions,
48+
method: options?.method || 'GET',
49+
body: options?.body || undefined,
50+
signal: AbortSignal.timeout(options?.timeout || DEFAULT_TIMEOUT),
51+
}
52+
if (options?.headers)
53+
requestOptions.headers = {
54+
...requestOptions.headers,
55+
...options.headers,
56+
}
57+
58+
// make actual request
59+
const { status, headers, body, ok, redirected } = await fetch(url, requestOptions)
60+
const statusCode = status
61+
62+
// const ok = statusCode >= 200 && statusCode < 300
63+
if (!ok && (!options || options?.reject !== false)) return Promise.reject({ statusCode, ok, headers, url })
64+
65+
// turn stream into string
66+
const { string, buffer } = await convertReadableStream(body)
67+
68+
// detect/ set redirect
69+
70+
const redirect = statusCode >= 300 && statusCode < 400 && headers.location ? new URL(headers.location, url) : null
71+
72+
// fetch header vars
73+
const contentType = headers.get('content-type')
74+
75+
// parse json if set
76+
let json
77+
try {
78+
json = contentType?.includes('application/json') ? JSON.parse(string) : null
79+
} catch {
80+
json = null
81+
}
82+
83+
// return data
84+
return Promise.resolve({
85+
statusCode,
86+
ok,
87+
redirect,
88+
headers,
89+
contentType,
90+
/** @deprecated */
91+
trailers: new Error('not supported any longer'),
92+
body,
93+
status,
94+
string,
95+
buffer,
96+
json,
97+
})
98+
}

0 commit comments

Comments
 (0)