@zap-studio/fetch 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +169 -0
- package/dist/errors/index.d.ts +10 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +3 -0
- package/dist/errors-DrfSty0J.js +14 -0
- package/dist/errors-DrfSty0J.js.map +1 -0
- package/dist/index-BkzLFXkF.d.ts +9 -0
- package/dist/index-BkzLFXkF.d.ts.map +1 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +79 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +1 -0
- package/package.json +8 -3
- package/src/errors/index.ts +0 -11
- package/src/index.ts +0 -126
- package/src/types/index.ts +0 -23
- package/src/utils/index.ts +0 -104
- package/tests/index.test.ts +0 -974
- package/tests/utils/index.test.ts +0 -355
- package/tsconfig.json +0 -5
- package/tsdown.config.ts +0 -3
- package/vitest.config.ts +0 -6
|
@@ -1,355 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { FetchError } from "../../src/errors";
|
|
3
|
-
import { parseResponse, prepareHeadersAndBody } from "../../src/utils";
|
|
4
|
-
|
|
5
|
-
describe("prepareHeadersAndBody", () => {
|
|
6
|
-
describe("null and undefined handling", () => {
|
|
7
|
-
it("should return null body for undefined", () => {
|
|
8
|
-
const result = prepareHeadersAndBody(undefined, undefined);
|
|
9
|
-
expect(result.body).toBeNull();
|
|
10
|
-
expect(result.headers).toBeUndefined();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it("should return null body for null", () => {
|
|
14
|
-
const result = prepareHeadersAndBody(null, undefined);
|
|
15
|
-
expect(result.body).toBeNull();
|
|
16
|
-
expect(result.headers).toBeUndefined();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it("should preserve headers when body is null", () => {
|
|
20
|
-
const headers = { Authorization: "Bearer token" };
|
|
21
|
-
const result = prepareHeadersAndBody(null, headers);
|
|
22
|
-
expect(result.body).toBeNull();
|
|
23
|
-
expect(result.headers).toEqual(headers);
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe("BodyInit types", () => {
|
|
28
|
-
it("should pass FormData through unchanged", () => {
|
|
29
|
-
const formData = new FormData();
|
|
30
|
-
formData.append("key", "value");
|
|
31
|
-
const result = prepareHeadersAndBody(formData, undefined);
|
|
32
|
-
expect(result.body).toBe(formData);
|
|
33
|
-
expect(result.headers).toBeUndefined();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it("should pass URLSearchParams through unchanged", () => {
|
|
37
|
-
const params = new URLSearchParams({ key: "value" });
|
|
38
|
-
const result = prepareHeadersAndBody(params, undefined);
|
|
39
|
-
expect(result.body).toBe(params);
|
|
40
|
-
expect(result.headers).toBeUndefined();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("should pass Blob through unchanged", () => {
|
|
44
|
-
const blob = new Blob(["test"], { type: "text/plain" });
|
|
45
|
-
const result = prepareHeadersAndBody(blob, undefined);
|
|
46
|
-
expect(result.body).toBe(blob);
|
|
47
|
-
expect(result.headers).toBeUndefined();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it("should pass ArrayBuffer through unchanged", () => {
|
|
51
|
-
const buffer = new ArrayBuffer(8);
|
|
52
|
-
const result = prepareHeadersAndBody(buffer, undefined);
|
|
53
|
-
expect(result.body).toBe(buffer);
|
|
54
|
-
expect(result.headers).toBeUndefined();
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it("should pass ReadableStream through unchanged", () => {
|
|
58
|
-
const stream = new ReadableStream();
|
|
59
|
-
const result = prepareHeadersAndBody(stream, undefined);
|
|
60
|
-
expect(result.body).toBe(stream);
|
|
61
|
-
expect(result.headers).toBeUndefined();
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it("should pass string through unchanged", () => {
|
|
65
|
-
const text = "plain text";
|
|
66
|
-
const result = prepareHeadersAndBody(text, undefined);
|
|
67
|
-
expect(result.body).toBe(text);
|
|
68
|
-
expect(result.headers).toBeUndefined();
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
describe("object serialization", () => {
|
|
73
|
-
it("should stringify plain objects and set Content-Type", () => {
|
|
74
|
-
const obj = { name: "test", value: 123 };
|
|
75
|
-
const result = prepareHeadersAndBody(obj, undefined);
|
|
76
|
-
expect(result.body).toBe(JSON.stringify(obj));
|
|
77
|
-
expect(result.headers).toEqual({
|
|
78
|
-
"Content-Type": "application/json",
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it("should merge Content-Type with existing headers for objects", () => {
|
|
83
|
-
const obj = { data: "test" };
|
|
84
|
-
const existingHeaders = { Authorization: "Bearer token" };
|
|
85
|
-
const result = prepareHeadersAndBody(obj, existingHeaders);
|
|
86
|
-
expect(result.body).toBe(JSON.stringify(obj));
|
|
87
|
-
expect(result.headers).toEqual({
|
|
88
|
-
"Content-Type": "application/json",
|
|
89
|
-
Authorization: "Bearer token",
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it("should preserve custom Content-Type when provided", () => {
|
|
94
|
-
const obj = { data: "test" };
|
|
95
|
-
const headers = { "Content-Type": "application/xml" };
|
|
96
|
-
const result = prepareHeadersAndBody(obj, headers);
|
|
97
|
-
expect(result.body).toBe(JSON.stringify(obj));
|
|
98
|
-
expect(result.headers).toEqual({
|
|
99
|
-
"Content-Type": "application/xml",
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
describe("primitive types", () => {
|
|
105
|
-
it("should convert number to string", () => {
|
|
106
|
-
const result = prepareHeadersAndBody(123, undefined);
|
|
107
|
-
expect(result.body).toBe("123");
|
|
108
|
-
expect(result.headers).toBeUndefined();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it("should convert boolean to string", () => {
|
|
112
|
-
const result = prepareHeadersAndBody(true, undefined);
|
|
113
|
-
expect(result.body).toBe("true");
|
|
114
|
-
expect(result.headers).toBeUndefined();
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
describe("parseResponse", () => {
|
|
120
|
-
describe("json response type", () => {
|
|
121
|
-
it("should parse JSON response with correct content-type", async () => {
|
|
122
|
-
const mockData = { id: 1, name: "test" };
|
|
123
|
-
const response = new Response(JSON.stringify(mockData), {
|
|
124
|
-
headers: { "content-type": "application/json" },
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
const result = await parseResponse(response, "json");
|
|
128
|
-
expect(result).toEqual(mockData);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it("should parse JSON with charset in content-type", async () => {
|
|
132
|
-
const mockData = { value: "test" };
|
|
133
|
-
const response = new Response(JSON.stringify(mockData), {
|
|
134
|
-
headers: { "content-type": "application/json; charset=utf-8" },
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
const result = await parseResponse(response, "json");
|
|
138
|
-
expect(result).toEqual(mockData);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it("should throw FetchError when JSON expected but content-type missing", async () => {
|
|
142
|
-
const response = new Response(JSON.stringify({ data: "test" }), {
|
|
143
|
-
status: 200,
|
|
144
|
-
statusText: "OK",
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
await expect(parseResponse(response, "json")).rejects.toThrow(FetchError);
|
|
148
|
-
await expect(parseResponse(response, "json")).rejects.toThrow(
|
|
149
|
-
"Expected JSON response but received no content type",
|
|
150
|
-
);
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it("should throw FetchError when JSON expected but content-type is wrong", async () => {
|
|
154
|
-
const response = new Response("<html></html>", {
|
|
155
|
-
status: 200,
|
|
156
|
-
statusText: "OK",
|
|
157
|
-
headers: { "content-type": "text/html" },
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
await expect(parseResponse(response, "json")).rejects.toThrow(FetchError);
|
|
161
|
-
await expect(parseResponse(response, "json")).rejects.toThrow(
|
|
162
|
-
"Expected JSON response but received no content type",
|
|
163
|
-
);
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
describe("text response type", () => {
|
|
168
|
-
it("should parse text response with text/plain content-type", async () => {
|
|
169
|
-
const mockText = "plain text content";
|
|
170
|
-
const response = new Response(mockText, {
|
|
171
|
-
headers: { "content-type": "text/plain" },
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
const result = await parseResponse(response, "text");
|
|
175
|
-
expect(result).toBe(mockText);
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it("should parse text response with text/html content-type", async () => {
|
|
179
|
-
const mockHtml = "<html><body>test</body></html>";
|
|
180
|
-
const response = new Response(mockHtml, {
|
|
181
|
-
headers: { "content-type": "text/html" },
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
const result = await parseResponse(response, "text");
|
|
185
|
-
expect(result).toBe(mockHtml);
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it("should throw FetchError when text expected but content-type is wrong", async () => {
|
|
189
|
-
const response = new Response("test", {
|
|
190
|
-
status: 200,
|
|
191
|
-
statusText: "OK",
|
|
192
|
-
headers: { "content-type": "application/json" },
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
await expect(parseResponse(response, "text")).rejects.toThrow(FetchError);
|
|
196
|
-
await expect(parseResponse(response, "text")).rejects.toThrow(
|
|
197
|
-
"Expected text response but received different content type",
|
|
198
|
-
);
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
describe("blob response type", () => {
|
|
203
|
-
it("should parse blob response", async () => {
|
|
204
|
-
const mockData = new Blob(["test data"], { type: "text/plain" });
|
|
205
|
-
const response = new Response(mockData);
|
|
206
|
-
|
|
207
|
-
const result = await parseResponse(response, "blob");
|
|
208
|
-
expect(result).toBeDefined();
|
|
209
|
-
expect(result.constructor.name).toBe("Blob");
|
|
210
|
-
expect(result.type).toContain("text/plain");
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
it("should handle binary blob data", async () => {
|
|
214
|
-
const buffer = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]); // "Hello"
|
|
215
|
-
const blob = new Blob([buffer]);
|
|
216
|
-
const response = new Response(blob);
|
|
217
|
-
|
|
218
|
-
const result = await parseResponse(response, "blob");
|
|
219
|
-
expect(result).toBeDefined();
|
|
220
|
-
expect(result.constructor.name).toBe("Blob");
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
describe("arrayBuffer response type", () => {
|
|
225
|
-
it("should parse arrayBuffer response", async () => {
|
|
226
|
-
const buffer = new Uint8Array([1, 2, 3, 4]).buffer;
|
|
227
|
-
const response = new Response(buffer);
|
|
228
|
-
|
|
229
|
-
const result = await parseResponse(response, "arrayBuffer");
|
|
230
|
-
expect(result).toBeInstanceOf(ArrayBuffer);
|
|
231
|
-
expect(result.byteLength).toBe(4);
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
it("should handle empty arrayBuffer", async () => {
|
|
235
|
-
const response = new Response(new ArrayBuffer(0));
|
|
236
|
-
|
|
237
|
-
const result = await parseResponse(response, "arrayBuffer");
|
|
238
|
-
expect(result).toBeInstanceOf(ArrayBuffer);
|
|
239
|
-
expect(result.byteLength).toBe(0);
|
|
240
|
-
});
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
describe("bytes response type", () => {
|
|
244
|
-
it("should parse bytes as Uint8Array", async () => {
|
|
245
|
-
const buffer = new Uint8Array([1, 2, 3, 4]);
|
|
246
|
-
const response = new Response(buffer);
|
|
247
|
-
|
|
248
|
-
const result = await parseResponse(response, "bytes");
|
|
249
|
-
expect(result).toBeInstanceOf(Uint8Array);
|
|
250
|
-
expect(result.length).toBe(4);
|
|
251
|
-
expect(Array.from(result)).toEqual([1, 2, 3, 4]);
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
it("should convert ArrayBuffer to Uint8Array", async () => {
|
|
255
|
-
const buffer = new ArrayBuffer(8);
|
|
256
|
-
const view = new Uint8Array(buffer);
|
|
257
|
-
view.set([10, 20, 30, 40, 50, 60, 70, 80]);
|
|
258
|
-
const response = new Response(buffer);
|
|
259
|
-
|
|
260
|
-
const result = await parseResponse(response, "bytes");
|
|
261
|
-
expect(result).toBeInstanceOf(Uint8Array);
|
|
262
|
-
expect(result.length).toBe(8);
|
|
263
|
-
expect(Array.from(result)).toEqual([10, 20, 30, 40, 50, 60, 70, 80]);
|
|
264
|
-
});
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
describe("formData response type", () => {
|
|
268
|
-
it("should parse formData response with correct content-type", async () => {
|
|
269
|
-
const formData = new FormData();
|
|
270
|
-
formData.append("key", "value");
|
|
271
|
-
formData.append("number", "123");
|
|
272
|
-
|
|
273
|
-
// Create a proper multipart/form-data body
|
|
274
|
-
const boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW";
|
|
275
|
-
const body = `------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name="key"\r\n\r\nvalue\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name="number"\r\n\r\n123\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--`;
|
|
276
|
-
|
|
277
|
-
const response = new Response(body, {
|
|
278
|
-
headers: {
|
|
279
|
-
"content-type": `multipart/form-data; boundary=${boundary}`,
|
|
280
|
-
},
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
const result = await parseResponse(response, "formData");
|
|
284
|
-
expect(result).toBeDefined();
|
|
285
|
-
expect(result.constructor.name).toBe("FormData");
|
|
286
|
-
expect(result.get("key")).toBe("value");
|
|
287
|
-
expect(result.get("number")).toBe("123");
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
it("should throw FetchError when formData expected but content-type is wrong", async () => {
|
|
291
|
-
const response = new Response("test", {
|
|
292
|
-
status: 200,
|
|
293
|
-
statusText: "OK",
|
|
294
|
-
headers: { "content-type": "application/json" },
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
await expect(parseResponse(response, "formData")).rejects.toThrow(
|
|
298
|
-
FetchError,
|
|
299
|
-
);
|
|
300
|
-
await expect(parseResponse(response, "formData")).rejects.toThrow(
|
|
301
|
-
"Expected FormData response but received different content type",
|
|
302
|
-
);
|
|
303
|
-
});
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
describe("clone response type", () => {
|
|
307
|
-
it("should clone the response", async () => {
|
|
308
|
-
const mockData = { id: 1, name: "test" };
|
|
309
|
-
const response = new Response(JSON.stringify(mockData), {
|
|
310
|
-
headers: { "content-type": "application/json" },
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
const result = await parseResponse(response, "clone");
|
|
314
|
-
expect(result).toBeInstanceOf(Response);
|
|
315
|
-
expect(result).not.toBe(response);
|
|
316
|
-
|
|
317
|
-
const data = await result.json();
|
|
318
|
-
expect(data).toEqual(mockData);
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
it("should allow reading cloned response multiple times", async () => {
|
|
322
|
-
const mockData = "test data";
|
|
323
|
-
const response = new Response(mockData, {
|
|
324
|
-
headers: { "content-type": "text/plain" },
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
const cloned = await parseResponse(response, "clone");
|
|
328
|
-
const text1 = await cloned.text();
|
|
329
|
-
|
|
330
|
-
// Original response should still be readable after clone
|
|
331
|
-
const text2 = await response.text();
|
|
332
|
-
|
|
333
|
-
expect(text1).toBe(mockData);
|
|
334
|
-
expect(text2).toBe(mockData);
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
describe("unsupported response type", () => {
|
|
339
|
-
it("should throw FetchError for unsupported response type", async () => {
|
|
340
|
-
const response = new Response("test", {
|
|
341
|
-
status: 200,
|
|
342
|
-
statusText: "OK",
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
// @ts-expect-error - testing invalid response type
|
|
346
|
-
await expect(parseResponse(response, "invalid")).rejects.toThrow(
|
|
347
|
-
FetchError,
|
|
348
|
-
);
|
|
349
|
-
// @ts-expect-error - testing invalid response type
|
|
350
|
-
await expect(parseResponse(response, "invalid")).rejects.toThrow(
|
|
351
|
-
"Unsupported response type: invalid",
|
|
352
|
-
);
|
|
353
|
-
});
|
|
354
|
-
});
|
|
355
|
-
});
|
package/tsconfig.json
DELETED
package/tsdown.config.ts
DELETED