@zap-studio/fetch 0.4.7 → 0.5.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +1 -1
  3. package/README.md +276 -32
  4. package/dist/constants.d.mts +8 -1
  5. package/dist/constants.d.mts.map +1 -1
  6. package/dist/constants.mjs +9 -2
  7. package/dist/constants.mjs.map +1 -1
  8. package/dist/errors.d.mts +29 -0
  9. package/dist/errors.d.mts.map +1 -1
  10. package/dist/errors.mjs +46 -2
  11. package/dist/errors.mjs.map +1 -0
  12. package/dist/headers.d.mts +26 -0
  13. package/dist/headers.d.mts.map +1 -0
  14. package/dist/headers.mjs +35 -0
  15. package/dist/headers.mjs.map +1 -0
  16. package/dist/index.d.mts +28 -10
  17. package/dist/index.d.mts.map +1 -1
  18. package/dist/index.mjs +25 -10
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/internal.d.mts +33 -0
  21. package/dist/internal.d.mts.map +1 -0
  22. package/dist/internal.mjs +73 -0
  23. package/dist/internal.mjs.map +1 -0
  24. package/dist/methods.d.mts +23 -0
  25. package/dist/methods.d.mts.map +1 -0
  26. package/dist/methods.mjs +58 -0
  27. package/dist/methods.mjs.map +1 -0
  28. package/dist/request.d.mts +31 -0
  29. package/dist/request.d.mts.map +1 -0
  30. package/dist/request.mjs +39 -0
  31. package/dist/request.mjs.map +1 -0
  32. package/dist/types.d.mts +71 -45
  33. package/dist/types.d.mts.map +1 -1
  34. package/dist/types.mjs +1 -1
  35. package/dist/url.d.mts +27 -0
  36. package/dist/url.d.mts.map +1 -0
  37. package/dist/url.mjs +56 -0
  38. package/dist/url.mjs.map +1 -0
  39. package/package.json +46 -53
  40. package/bin/intent.js +0 -4
  41. package/dist/errors-DQfwnwmz.mjs +0 -18
  42. package/dist/errors-DQfwnwmz.mjs.map +0 -1
  43. package/dist/utils.d.mts +0 -33
  44. package/dist/utils.d.mts.map +0 -1
  45. package/dist/utils.mjs +0 -180
  46. package/dist/utils.mjs.map +0 -1
  47. package/skills/zap-fetch-typed-http/SKILL.md +0 -152
package/CHANGELOG.md CHANGED
@@ -1,5 +1,57 @@
1
1
  # @zap-studio/fetch
2
2
 
3
+ ## 0.5.1
4
+
5
+ ### Fixed
6
+
7
+ - d92f2c2: Preserve explicit `throwOnValidationError: true` overrides in `$fetch` method helpers and factory-created fetch clients.
8
+
9
+ ### Changed
10
+
11
+ - 2ea1a70: Cleaned up public option typings by removing redundant `| undefined` unions from fetch configuration types and overloads.
12
+
13
+ ### Dependencies
14
+
15
+ - Updated dependency `@zap-studio/validation` to `0.3.3`.
16
+
17
+ ## 0.5.0
18
+
19
+ ### Breaking
20
+
21
+ - Request bodies are no longer auto-serialized from plain objects; use the explicit `json` option (or set `body` yourself). `body` and `json` are mutually exclusive at the type level and enforced at runtime.
22
+
23
+ ### Changed
24
+
25
+ - Simplified the request API around web platform types.
26
+ - The first argument is named `input` and typed as `FetchInput` (`Parameters<typeof fetch>[0]` from `lib.dom`), exported from `@zap-studio/fetch/types`, so allowed inputs track global `fetch` when DOM typings change.
27
+ - Non-`Request` values (including `URL`) are normalized to a string URL before query merge.
28
+ - `ExtendedRequestInit` now extends native `RequestInit` directly instead of redefining request options.
29
+ - `searchParams` now accepts the same input shape as `new URLSearchParams(...)`.
30
+ - Replaced automatic object body serialization with an explicit `json` option.
31
+ - Use `json: value` when you want JSON stringification and `Content-Type: application/json`.
32
+ - Use native `body` when you want standard `fetch` behavior.
33
+ - `body` and `json` are mutually exclusive in TypeScript and guarded at runtime.
34
+ - Reworked URL handling to use the platform `URL` and `URLSearchParams` APIs while preserving relative URL output when no `baseURL` is configured.
35
+ - Simplified the internal module structure and removed the old `utils` module.
36
+
37
+ ### Fixed
38
+
39
+ - Fixed absolute URL handling when no `baseURL` is configured.
40
+ - `resolveSearchParams` keeps a trailing `#` when the input URL had an empty fragment (for example `.../path#`), matching typical `URL` serialization instead of dropping the delimiter.
41
+
42
+ ### Tests
43
+
44
+ - Reworked tests to mirror the `src` module structure.
45
+ - Added full package coverage across statements, branches, functions, and lines.
46
+
47
+ ### Documentation
48
+
49
+ - Documented the throwable error surface for `$fetch`, `createFetch`, and internal request execution with explicit `@throws` tags (for example `FetchError`, `ValidationError`, `TypeError`, `DOMException`, `SyntaxError`, and validator-thrown errors).
50
+
51
+ ### Dependencies
52
+
53
+ - JSR dependency mapping now pins `@zap-studio/validation` to `0.3.2`.
54
+
3
55
  ## 0.4.7
4
56
 
5
57
  ### Patch Changes
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Alexandre Trotel
3
+ Copyright (c) 2026 Alexandre Trotel
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,57 +1,301 @@
1
1
  # @zap-studio/fetch
2
2
 
3
- A type-safe fetch wrapper with Standard Schema validation.
3
+ A small fetch wrapper with [**Standard Schema**](https://standardschema.dev/schema) response validation.
4
4
 
5
- ## Why @zap-studio/fetch?
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @zap-studio/fetch
9
+ ```
10
+
11
+ ## Quick Example
12
+
13
+ ```ts
14
+ import { api } from "@zap-studio/fetch";
15
+ import { z } from "zod";
16
+
17
+ const UserSchema = z.object({
18
+ id: z.number(),
19
+ name: z.string(),
20
+ email: z.string().email(),
21
+ });
22
+
23
+ const user = await api.get("https://api.example.com/users/1", UserSchema);
24
+
25
+ console.log(user.name);
26
+ ```
27
+
28
+ ## Before
6
29
 
7
- **Before:**
30
+ Without response validation, fetch code often needs unchecked assertions:
31
+
32
+ ```ts
33
+ type User = {
34
+ id: number;
35
+ name: string;
36
+ };
8
37
 
9
- ```typescript
10
38
  const response = await fetch("/api/users/1");
11
39
  const data = await response.json();
12
- const user = data as User; // 😱 Unsafe type assertion
40
+
41
+ const user = data as User;
13
42
  ```
14
43
 
15
- **After:**
44
+ ## After
45
+
46
+ With `@zap-studio/fetch`, the response is validated before it is returned:
47
+
48
+ ```ts
49
+ import { api } from "@zap-studio/fetch";
16
50
 
17
- ```typescript
18
51
  const user = await api.get("/api/users/1", UserSchema);
19
- // ✨ Typed, validated, and safe!
20
52
  ```
21
53
 
22
- ## Features
54
+ The returned value is inferred from the schema.
23
55
 
24
- - 🎯 **Type-safe requests** with automatic type inference
25
- - 🛡️ **Runtime validation** using Standard Schema (Zod, Valibot, ArkType, etc.)
26
- - ⚡️ **Convenient API methods** (GET, POST, PUT, PATCH, DELETE)
27
- - 🏭 **Factory pattern** for creating pre-configured instances with base URLs
28
- - 🚨 **Custom error handling** with FetchError and ValidationError classes
29
- - 📘 **Full TypeScript support** with zero configuration
56
+ ## Raw Fetch Usage
30
57
 
31
- ## Installation
58
+ Use `$fetch` without a schema when you want the normal `Response` object.
32
59
 
33
- ```bash
34
- pnpm add @zap-studio/fetch
35
- # or
36
- npm install @zap-studio/fetch
60
+ ```ts
61
+ import { $fetch } from "@zap-studio/fetch";
62
+
63
+ const response = await $fetch("/api/users/1");
64
+ const user = await response.json();
37
65
  ```
38
66
 
39
- ## Quick Start
67
+ Native fetch options are passed through as `RequestInit`.
40
68
 
41
- ```typescript
42
- import { z } from "zod";
69
+ ```ts
70
+ const response = await $fetch("/api/users", {
71
+ method: "POST",
72
+ body: JSON.stringify({ name: "Ada" }),
73
+ headers: {
74
+ "Content-Type": "application/json",
75
+ },
76
+ });
77
+ ```
78
+
79
+ ## Validated Fetch Usage
80
+
81
+ Pass a Standard Schema as the second argument to validate the JSON response.
82
+
83
+ ```ts
84
+ import { $fetch } from "@zap-studio/fetch";
85
+
86
+ const user = await $fetch("/api/users/1", UserSchema);
87
+ ```
88
+
89
+ The schema validates the response body, not the request body.
90
+
91
+ When validation fails, a `ValidationError` is thrown by default.
92
+
93
+ ## API Method Helpers
94
+
95
+ The `api` export provides common HTTP methods.
96
+
97
+ ```ts
43
98
  import { api } from "@zap-studio/fetch";
44
99
 
45
- // Define your schema
46
- const UserSchema = z.object({
47
- id: z.number(),
48
- name: z.string(),
49
- email: z.email(),
100
+ const user = await api.get("/api/users/1", UserSchema);
101
+
102
+ const created = await api.post("/api/users", UserSchema, {
103
+ json: {
104
+ name: "Ada",
105
+ email: "ada@example.com",
106
+ },
50
107
  });
108
+ ```
51
109
 
52
- // Make a type-safe request
53
- const user = await api.get("https://api.example.com/users/1", UserSchema);
110
+ In this example, `UserSchema` validates the response from `/api/users`.
111
+ The `json` value is the outgoing request body and is not validated by `UserSchema`.
112
+
113
+ These helpers set the HTTP method for you. For raw responses without validation, use `$fetch`.
114
+
115
+ ## JSON Request Bodies
116
+
117
+ Use `json` when you want the package to serialize a JSON request body.
118
+
119
+ ```ts
120
+ await api.post("/api/users", UserSchema, {
121
+ json: {
122
+ name: "Ada",
123
+ },
124
+ });
125
+ ```
126
+
127
+ The schema argument still validates the response. Validate request bodies separately before
128
+ passing them to `json` if your application needs outgoing payload validation.
129
+
130
+ This sets:
131
+
132
+ - `body` to `JSON.stringify(json)`
133
+ - `Content-Type` to `application/json` when no content type was already provided
134
+
135
+ Use native `body` for standard fetch behavior.
136
+
137
+ ```ts
138
+ await $fetch("/api/upload", {
139
+ method: "POST",
140
+ body: formData,
141
+ });
142
+ ```
143
+
144
+ `body` and `json` are mutually exclusive.
145
+
146
+ ## Query Params
147
+
148
+ Use `searchParams` for per-request query params.
149
+
150
+ ```ts
151
+ await api.get("/api/users", UserListSchema, {
152
+ searchParams: {
153
+ page: "1",
154
+ limit: "20",
155
+ },
156
+ });
157
+ ```
158
+
159
+ `searchParams` accepts the same input shapes as `new URLSearchParams(...)`.
160
+
161
+ ```ts
162
+ await api.get("/api/users", UserListSchema, {
163
+ searchParams: new URLSearchParams({ q: "ada" }),
164
+ });
165
+
166
+ await api.get("/api/users", UserListSchema, {
167
+ searchParams: "q=ada&page=1",
168
+ });
169
+
170
+ await api.get("/api/users", UserListSchema, {
171
+ searchParams: [["q", "ada"]],
172
+ });
173
+ ```
174
+
175
+ When defaults, URL query params, and request params overlap, later values win:
176
+
177
+ 1. `createFetch({ searchParams })`
178
+ 2. query params already present in the URL
179
+ 3. per-request `searchParams`
180
+
181
+ ## Creating a Client
182
+
183
+ Use `createFetch` to configure shared defaults.
184
+
185
+ ```ts
186
+ import { createFetch } from "@zap-studio/fetch";
187
+
188
+ const { $fetch, api } = createFetch({
189
+ baseURL: "https://api.example.com",
190
+ headers: {
191
+ Authorization: `Bearer ${token}`,
192
+ },
193
+ searchParams: {
194
+ locale: "en",
195
+ },
196
+ });
54
197
 
55
- // user is fully typed and validated! ✨
56
- console.log(user.name); // TypeScript knows this is a string
198
+ const user = await api.get("/users/1", UserSchema);
199
+ const response = await $fetch("/health");
57
200
  ```
201
+
202
+ Supported defaults:
203
+
204
+ | Option | Description |
205
+ | ------------------------ | ----------------------------------------------- |
206
+ | `baseURL` | Base URL for relative request URLs |
207
+ | `headers` | Headers applied to every request |
208
+ | `searchParams` | Query params applied to every request |
209
+ | `throwOnFetchError` | Throw `FetchError` for non-ok responses |
210
+ | `throwOnValidationError` | Throw `ValidationError` for validation failures |
211
+
212
+ ## Non-throwing Validation
213
+
214
+ Set `throwOnValidationError: false` to receive the raw Standard Schema result.
215
+
216
+ ```ts
217
+ const result = await api.get("/api/users/1", UserSchema, {
218
+ throwOnValidationError: false,
219
+ });
220
+
221
+ if (result.issues) {
222
+ console.error("Validation failed:", result.issues);
223
+ } else {
224
+ console.log("Validation passed:", result.value);
225
+ }
226
+ ```
227
+
228
+ ## HTTP Errors
229
+
230
+ By default, non-ok responses throw a `FetchError`.
231
+
232
+ ```ts
233
+ import { FetchError } from "@zap-studio/fetch/errors";
234
+
235
+ try {
236
+ await api.get("/api/users/404", UserSchema);
237
+ } catch (error) {
238
+ if (error instanceof FetchError) {
239
+ console.error(error.status);
240
+ console.error(error.response);
241
+ }
242
+ }
243
+ ```
244
+
245
+ Disable this behavior when you want to handle the raw response yourself.
246
+
247
+ ```ts
248
+ const response = await $fetch("/api/users/404", {
249
+ throwOnFetchError: false,
250
+ });
251
+
252
+ console.log(response.status);
253
+ ```
254
+
255
+ ## Request Objects
256
+
257
+ The first argument (`input`) uses the same type as global `fetch`.
258
+
259
+ ```ts
260
+ const request = new Request("https://api.example.com/users/1", {
261
+ headers: {
262
+ Authorization: `Bearer ${token}`,
263
+ },
264
+ });
265
+
266
+ const user = await $fetch(request, UserSchema);
267
+ ```
268
+
269
+ Per-request options are merged on top of the `Request`.
270
+
271
+ ## Standard Schema
272
+
273
+ `@zap-studio/fetch` validates responses through `@zap-studio/validation`, so it works with any validation library that implements Standard Schema.
274
+
275
+ Examples include:
276
+
277
+ - [Zod](https://zod.dev/)
278
+ - [Valibot](https://valibot.dev/)
279
+ - [ArkType](https://arktype.io/)
280
+
281
+ You can also import Standard Schema types from `@zap-studio/validation` when needed.
282
+
283
+ ```ts
284
+ import type { StandardSchemaV1 } from "@zap-studio/validation";
285
+ ```
286
+
287
+ ## Choosing the Right API
288
+
289
+ | API | Use when |
290
+ | ------------- | ------------------------------------------------- |
291
+ | `$fetch` | You want raw fetch behavior or a custom method |
292
+ | `api.get` | You want a validated GET request |
293
+ | `api.post` | You want a validated POST request |
294
+ | `api.put` | You want a validated PUT request |
295
+ | `api.patch` | You want a validated PATCH request |
296
+ | `api.delete` | You want a validated DELETE request |
297
+ | `createFetch` | You want shared defaults like base URL or headers |
298
+
299
+ ## License
300
+
301
+ MIT
@@ -1,9 +1,16 @@
1
1
  import { FetchDefaults } from "./types.mjs";
2
2
 
3
3
  //#region src/constants.d.ts
4
-
5
4
  /**
6
5
  * Default options for the global $fetch
6
+ *
7
+ * These defaults are used by the top-level `$fetch` export.
8
+ * Use `createFetch(...)` when you need per-client defaults.
9
+ *
10
+ * @example
11
+ * import { GLOBAL_DEFAULTS } from "@zap-studio/fetch/constants";
12
+ *
13
+ * console.log(GLOBAL_DEFAULTS.throwOnFetchError); // true
7
14
  */
8
15
  declare const GLOBAL_DEFAULTS: FetchDefaults;
9
16
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.mts","names":["GLOBAL_DEFAULTS: FetchDefaults"],"sources":["../src/constants.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;cAAaA,iBAAiB"}
1
+ {"version":3,"file":"constants.d.mts","names":[],"sources":["../src/constants.ts"],"mappings":";;;;;;;;;;;;;;cAmBa,eAAA,EAAiB,aAAA"}
@@ -1,14 +1,21 @@
1
1
  //#region src/constants.ts
2
2
  /**
3
3
  * Default options for the global $fetch
4
+ *
5
+ * These defaults are used by the top-level `$fetch` export.
6
+ * Use `createFetch(...)` when you need per-client defaults.
7
+ *
8
+ * @example
9
+ * import { GLOBAL_DEFAULTS } from "@zap-studio/fetch/constants";
10
+ *
11
+ * console.log(GLOBAL_DEFAULTS.throwOnFetchError); // true
4
12
  */
5
13
  const GLOBAL_DEFAULTS = {
6
14
  baseURL: "",
7
- headers: void 0,
8
15
  throwOnFetchError: true,
9
16
  throwOnValidationError: true
10
17
  };
11
-
12
18
  //#endregion
13
19
  export { GLOBAL_DEFAULTS };
20
+
14
21
  //# sourceMappingURL=constants.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.mjs","names":["GLOBAL_DEFAULTS: FetchDefaults"],"sources":["../src/constants.ts"],"sourcesContent":["import type { FetchDefaults } from \"./types\";\n\n/**\n * Default options for the global $fetch\n */\nexport const GLOBAL_DEFAULTS: FetchDefaults = {\n baseURL: \"\",\n headers: undefined,\n throwOnFetchError: true,\n throwOnValidationError: true,\n};\n"],"mappings":";;;;AAKA,MAAaA,kBAAiC;CAC5C,SAAS;CACT,SAAS;CACT,mBAAmB;CACnB,wBAAwB;CACzB"}
1
+ {"version":3,"file":"constants.mjs","names":[],"sources":["../src/constants.ts"],"sourcesContent":["/**\n * Shared defaults and constants for fetch behavior.\n *\n * @module\n */\n\nimport type { FetchDefaults } from \"./types.js\";\n\n/**\n * Default options for the global $fetch\n *\n * These defaults are used by the top-level `$fetch` export.\n * Use `createFetch(...)` when you need per-client defaults.\n *\n * @example\n * import { GLOBAL_DEFAULTS } from \"@zap-studio/fetch/constants\";\n *\n * console.log(GLOBAL_DEFAULTS.throwOnFetchError); // true\n */\nexport const GLOBAL_DEFAULTS: FetchDefaults = {\n baseURL: \"\",\n throwOnFetchError: true,\n throwOnValidationError: true,\n};\n"],"mappings":";;;;;;;;;;;;AAmBA,MAAa,kBAAiC;CAC5C,SAAS;CACT,mBAAmB;CACnB,wBAAwB;CACzB"}
package/dist/errors.d.mts CHANGED
@@ -1,10 +1,39 @@
1
1
  //#region src/errors.d.ts
2
2
  /**
3
+ * Custom error types used by the fetch package.
4
+ *
5
+ * @module
6
+ */
7
+ /**
3
8
  * Error thrown for HTTP errors (non-2xx responses)
9
+ *
10
+ * Includes the failing `Response` object and status code for
11
+ * downstream error handling and response inspection.
12
+ *
13
+ * @example
14
+ * import { FetchError } from "@zap-studio/fetch/errors";
15
+ *
16
+ * try {
17
+ * await $fetch("/users/404");
18
+ * } catch (error) {
19
+ * if (error instanceof FetchError) {
20
+ * console.error(error.status);
21
+ * console.error(await error.response.text());
22
+ * }
23
+ * }
4
24
  */
5
25
  declare class FetchError extends Error {
26
+ /**
27
+ * HTTP status code from the failing response.
28
+ */
6
29
  status: Response["status"];
30
+ /**
31
+ * Full response object for additional inspection.
32
+ */
7
33
  response: Response;
34
+ /**
35
+ * Creates a FetchError from a non-ok response.
36
+ */
8
37
  constructor(message: string, response: Response);
9
38
  }
10
39
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.mts","names":[],"sources":["../src/errors.ts"],"sourcesContent":[],"mappings":";;AAGA;;AAEY,cAFC,UAAA,SAAmB,KAAA,CAEpB;EAE6B,MAAA,EAH/B,QAG+B,CAAA,QAAA,CAAA;EAJT,QAAA,EAEpB,QAFoB;EAAA,WAAA,CAAA,OAAA,EAAA,MAAA,EAAA,QAAA,EAIS,QAJT"}
1
+ {"version":3,"file":"errors.d.mts","names":[],"sources":["../src/errors.ts"],"mappings":";;AAwBA;;;;;;;;;;;;;;;;;;;;;;cAAa,UAAA,SAAmB,KAAA;;;;EAI9B,MAAA,EAAQ,QAAA;;;;EAIR,QAAA,EAAU,QAAA;;;;EAKV,WAAA,CAAY,OAAA,UAAiB,QAAA,EAAU,QAAA;AAAA"}
package/dist/errors.mjs CHANGED
@@ -1,3 +1,47 @@
1
- import { t as FetchError } from "./errors-DQfwnwmz.mjs";
1
+ //#region src/errors.ts
2
+ /**
3
+ * Custom error types used by the fetch package.
4
+ *
5
+ * @module
6
+ */
7
+ /**
8
+ * Error thrown for HTTP errors (non-2xx responses)
9
+ *
10
+ * Includes the failing `Response` object and status code for
11
+ * downstream error handling and response inspection.
12
+ *
13
+ * @example
14
+ * import { FetchError } from "@zap-studio/fetch/errors";
15
+ *
16
+ * try {
17
+ * await $fetch("/users/404");
18
+ * } catch (error) {
19
+ * if (error instanceof FetchError) {
20
+ * console.error(error.status);
21
+ * console.error(await error.response.text());
22
+ * }
23
+ * }
24
+ */
25
+ var FetchError = class extends Error {
26
+ /**
27
+ * HTTP status code from the failing response.
28
+ */
29
+ status;
30
+ /**
31
+ * Full response object for additional inspection.
32
+ */
33
+ response;
34
+ /**
35
+ * Creates a FetchError from a non-ok response.
36
+ */
37
+ constructor(message, response) {
38
+ super(message);
39
+ this.name = "FetchError";
40
+ this.status = response.status;
41
+ this.response = response;
42
+ }
43
+ };
44
+ //#endregion
45
+ export { FetchError };
2
46
 
3
- export { FetchError };
47
+ //# sourceMappingURL=errors.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.mjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Custom error types used by the fetch package.\n *\n * @module\n */\n\n/**\n * Error thrown for HTTP errors (non-2xx responses)\n *\n * Includes the failing `Response` object and status code for\n * downstream error handling and response inspection.\n *\n * @example\n * import { FetchError } from \"@zap-studio/fetch/errors\";\n *\n * try {\n * await $fetch(\"/users/404\");\n * } catch (error) {\n * if (error instanceof FetchError) {\n * console.error(error.status);\n * console.error(await error.response.text());\n * }\n * }\n */\nexport class FetchError extends Error {\n /**\n * HTTP status code from the failing response.\n */\n status: Response[\"status\"];\n /**\n * Full response object for additional inspection.\n */\n response: Response;\n\n /**\n * Creates a FetchError from a non-ok response.\n */\n constructor(message: string, response: Response) {\n super(message);\n this.name = \"FetchError\";\n this.status = response.status;\n this.response = response;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAwBA,IAAa,aAAb,cAAgC,MAAM;;;;CAIpC;;;;CAIA;;;;CAKA,YAAY,SAAiB,UAAoB;AAC/C,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,SAAS,SAAS;AACvB,OAAK,WAAW"}
@@ -0,0 +1,26 @@
1
+ //#region src/headers.d.ts
2
+ /**
3
+ * Header utility helpers for request normalization and merging.
4
+ *
5
+ * @module
6
+ */
7
+ /**
8
+ * Merges two HeadersInit objects, with the second one taking precedence.
9
+ *
10
+ * @param base - Base/default headers.
11
+ * @param override - Request-level override headers.
12
+ * @returns A merged `Headers` object, or `undefined` when both inputs are empty.
13
+ * @throws {TypeError} When either header input contains invalid header names or values.
14
+ *
15
+ * @example
16
+ * const headers = mergeHeaders(
17
+ * { Authorization: "Bearer token" },
18
+ * { "X-Trace-Id": "abc" },
19
+ * );
20
+ *
21
+ * console.log(headers?.get("Authorization")); // Bearer token
22
+ */
23
+ declare function mergeHeaders(base?: HeadersInit, override?: HeadersInit): Headers | undefined;
24
+ //#endregion
25
+ export { mergeHeaders };
26
+ //# sourceMappingURL=headers.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.d.mts","names":[],"sources":["../src/headers.ts"],"mappings":";;AAsBA;;;;;;;;;;;;;;;;;;;;iBAAgB,YAAA,CAAa,IAAA,GAAO,WAAA,EAAa,QAAA,GAAW,WAAA,GAAc,OAAA"}
@@ -0,0 +1,35 @@
1
+ //#region src/headers.ts
2
+ /**
3
+ * Header utility helpers for request normalization and merging.
4
+ *
5
+ * @module
6
+ */
7
+ /**
8
+ * Merges two HeadersInit objects, with the second one taking precedence.
9
+ *
10
+ * @param base - Base/default headers.
11
+ * @param override - Request-level override headers.
12
+ * @returns A merged `Headers` object, or `undefined` when both inputs are empty.
13
+ * @throws {TypeError} When either header input contains invalid header names or values.
14
+ *
15
+ * @example
16
+ * const headers = mergeHeaders(
17
+ * { Authorization: "Bearer token" },
18
+ * { "X-Trace-Id": "abc" },
19
+ * );
20
+ *
21
+ * console.log(headers?.get("Authorization")); // Bearer token
22
+ */
23
+ function mergeHeaders(base, override) {
24
+ if (!(base || override)) return;
25
+ const merged = new Headers(base);
26
+ if (override) {
27
+ const overrideHeaders = new Headers(override);
28
+ for (const [key, value] of overrideHeaders.entries()) merged.set(key, value);
29
+ }
30
+ return merged;
31
+ }
32
+ //#endregion
33
+ export { mergeHeaders };
34
+
35
+ //# sourceMappingURL=headers.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.mjs","names":[],"sources":["../src/headers.ts"],"sourcesContent":["/**\n * Header utility helpers for request normalization and merging.\n *\n * @module\n */\n\n/**\n * Merges two HeadersInit objects, with the second one taking precedence.\n *\n * @param base - Base/default headers.\n * @param override - Request-level override headers.\n * @returns A merged `Headers` object, or `undefined` when both inputs are empty.\n * @throws {TypeError} When either header input contains invalid header names or values.\n *\n * @example\n * const headers = mergeHeaders(\n * { Authorization: \"Bearer token\" },\n * { \"X-Trace-Id\": \"abc\" },\n * );\n *\n * console.log(headers?.get(\"Authorization\")); // Bearer token\n */\nexport function mergeHeaders(base?: HeadersInit, override?: HeadersInit): Headers | undefined {\n if (!(base || override)) {\n return;\n }\n\n const merged = new Headers(base);\n if (override) {\n const overrideHeaders = new Headers(override);\n for (const [key, value] of overrideHeaders.entries()) {\n merged.set(key, value);\n }\n }\n return merged;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,aAAa,MAAoB,UAA6C;AAC5F,KAAI,EAAE,QAAQ,UACZ;CAGF,MAAM,SAAS,IAAI,QAAQ,KAAK;AAChC,KAAI,UAAU;EACZ,MAAM,kBAAkB,IAAI,QAAQ,SAAS;AAC7C,OAAK,MAAM,CAAC,KAAK,UAAU,gBAAgB,SAAS,CAClD,QAAO,IAAI,KAAK,MAAM;;AAG1B,QAAO"}