Skip to content

Commit 18f9eee

Browse files
committed
refactor: use undici for HTTPS requests
1 parent b67efd7 commit 18f9eee

5 files changed

Lines changed: 76 additions & 43 deletions

File tree

.changeset/new-sloths-tie.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@badrap/libapp": patch
3+
---
4+
5+
Use `undici` for HTTPS requests

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@
3434
"tag": "changeset tag"
3535
},
3636
"dependencies": {
37-
"@badrap/valita": "^0.5.0"
37+
"@badrap/valita": "^0.5.0",
38+
"undici": "^8.2.0"
3839
},
3940
"devDependencies": {
4041
"@changesets/changelog-github": "^0.6.0",
4142
"@changesets/cli": "^2.31.0",
43+
"@types/node": "^25.6.0",
4244
"oxfmt": "^0.47.0",
4345
"oxlint": "^1.62.0",
4446
"oxlint-tsgolint": "^0.22.1",

pnpm-lock.yaml

Lines changed: 30 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/api/client.ts

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as v from "@badrap/valita";
2+
import { fetch, Headers } from "undici";
23

34
const json = JSON.stringify;
45

@@ -69,14 +70,6 @@ function joinPath(path: string[]): string {
6970
.join("/");
7071
}
7172

72-
async function dump(stream: ReadableStream | null) {
73-
if (stream) {
74-
for await (const _ of stream) {
75-
// pass
76-
}
77-
}
78-
}
79-
8073
export interface ClientConfig {
8174
url: string;
8275
token: string;
@@ -123,40 +116,47 @@ export class Client {
123116
headers,
124117
body,
125118
});
126-
const contentType = response.headers.get("content-type");
127-
const isJSON = /^application\/json\s*(;|$)/.test(contentType ?? "");
128-
129-
if (response.status >= 400 && response.status < 600) {
130-
if (isJSON) {
131-
const rawBody: unknown = await response.json();
132-
133-
const body = APIErrorBody.try(rawBody, { mode: "strip" });
134-
if (body.ok) {
135-
throw new APIError(
136-
response.status,
137-
response.statusText,
138-
body.value.error.code,
139-
body.value.error.reason,
140-
);
119+
try {
120+
const contentType = response.headers.get("content-type");
121+
const isJSON = /^application\/json\s*(;|$)/.test(contentType ?? "");
122+
123+
if (response.status >= 400 && response.status < 600) {
124+
if (isJSON) {
125+
const rawBody: unknown = await response.json();
126+
127+
const body = APIErrorBody.try(rawBody, { mode: "strip" });
128+
if (body.ok) {
129+
throw new APIError(
130+
response.status,
131+
response.statusText,
132+
body.value.error.code,
133+
body.value.error.reason,
134+
);
135+
}
141136
}
142-
} else {
143-
await dump(response.body);
137+
throw new HTTPError(response.status, response.statusText);
144138
}
145-
throw new HTTPError(response.status, response.statusText);
146-
}
147139

148-
let json: unknown = undefined;
149-
if (isJSON) {
150-
json = await response.json();
151-
} else {
152-
await dump(response.body);
153-
}
140+
let json: unknown = undefined;
141+
if (isJSON) {
142+
json = await response.json();
143+
}
154144

155-
const etag = response.headers.get("etag") ?? undefined;
156-
if (!options.responseType) {
157-
return { body: json as v.Infer<T>, etag };
145+
const etag = response.headers.get("etag") ?? undefined;
146+
if (!options.responseType) {
147+
return { body: json as v.Infer<T>, etag };
148+
}
149+
return {
150+
body: options.responseType.parse(json, { mode: "strip" }),
151+
etag,
152+
};
153+
} finally {
154+
if (!response.bodyUsed && response.body) {
155+
for await (const _ of response.body) {
156+
// Dump the response data.
157+
}
158+
}
158159
}
159-
return { body: options.responseType.parse(json, { mode: "strip" }), etag };
160160
}
161161

162162
async request<T extends v.Type>(

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"compilerOptions": {
33
"target": "es2022",
44
"module": "node20",
5-
"types": [],
5+
"types": ["node"],
66
"libReplacement": false,
77
"declaration": true,
88
"sourceMap": true,

0 commit comments

Comments
 (0)