@zap-studio/fetch 0.5.4 → 0.5.6

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 (64) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/LICENSE +1 -1
  3. package/README.md +19 -5
  4. package/dist/constants.d.ts +17 -0
  5. package/dist/constants.d.ts.map +1 -0
  6. package/dist/{constants.mjs → constants.js} +1 -1
  7. package/dist/constants.js.map +1 -0
  8. package/dist/errors.d.ts +41 -0
  9. package/dist/errors.d.ts.map +1 -0
  10. package/dist/{errors.mjs → errors.js} +1 -1
  11. package/dist/errors.js.map +1 -0
  12. package/dist/fetch-D0IXjsUD.js +222 -0
  13. package/dist/fetch-D0IXjsUD.js.map +1 -0
  14. package/dist/fetch.d.ts +114 -0
  15. package/dist/fetch.d.ts.map +1 -0
  16. package/dist/fetch.js +3 -0
  17. package/dist/headers.d.ts +26 -0
  18. package/dist/headers.d.ts.map +1 -0
  19. package/dist/{headers.mjs → headers.js} +6 -6
  20. package/dist/headers.js.map +1 -0
  21. package/dist/index.d.ts +8 -0
  22. package/dist/index.js +7 -0
  23. package/dist/request.d.ts +30 -0
  24. package/dist/request.d.ts.map +1 -0
  25. package/dist/{request.mjs → request.js} +15 -12
  26. package/dist/request.js.map +1 -0
  27. package/dist/types.d.ts +168 -0
  28. package/dist/types.d.ts.map +1 -0
  29. package/dist/types.js +0 -0
  30. package/dist/url.d.ts +26 -0
  31. package/dist/url.d.ts.map +1 -0
  32. package/dist/{url.mjs → url.js} +36 -37
  33. package/dist/url.js.map +1 -0
  34. package/package.json +19 -28
  35. package/dist/constants.d.mts +0 -18
  36. package/dist/constants.d.mts.map +0 -1
  37. package/dist/constants.mjs.map +0 -1
  38. package/dist/errors.d.mts +0 -41
  39. package/dist/errors.d.mts.map +0 -1
  40. package/dist/errors.mjs.map +0 -1
  41. package/dist/headers.d.mts +0 -26
  42. package/dist/headers.d.mts.map +0 -1
  43. package/dist/headers.mjs.map +0 -1
  44. package/dist/index.d.mts +0 -115
  45. package/dist/index.d.mts.map +0 -1
  46. package/dist/index.mjs +0 -103
  47. package/dist/index.mjs.map +0 -1
  48. package/dist/internal.d.mts +0 -33
  49. package/dist/internal.d.mts.map +0 -1
  50. package/dist/internal.mjs +0 -76
  51. package/dist/internal.mjs.map +0 -1
  52. package/dist/methods.d.mts +0 -23
  53. package/dist/methods.d.mts.map +0 -1
  54. package/dist/methods.mjs +0 -58
  55. package/dist/methods.mjs.map +0 -1
  56. package/dist/request.d.mts +0 -31
  57. package/dist/request.d.mts.map +0 -1
  58. package/dist/request.mjs.map +0 -1
  59. package/dist/types.d.mts +0 -169
  60. package/dist/types.d.mts.map +0 -1
  61. package/dist/types.mjs +0 -1
  62. package/dist/url.d.mts +0 -27
  63. package/dist/url.d.mts.map +0 -1
  64. package/dist/url.mjs.map +0 -1
@@ -0,0 +1,30 @@
1
+ import { ExtendedRequestInit, FetchInput } from "./types.js";
2
+ //#region src/request.d.ts
3
+ /**
4
+ * Normalized representation used by internal request execution.
5
+ *
6
+ * - `url`: resolved string URL from the input (string or `URL`; `Request` uses `request.url`)
7
+ * - `request`: original Request clone when input is a Request
8
+ * - `options`: normalized request options merged with Request headers
9
+ */
10
+ interface NormalizedRequest {
11
+ url: string;
12
+ request?: Request;
13
+ options: ExtendedRequestInit;
14
+ }
15
+ /**
16
+ * Normalizes fetch `input` and request-level options into a consistent internal shape.
17
+ *
18
+ * @param input - Request URL/path or Request instance.
19
+ * @param options - Optional request options.
20
+ * @returns A normalized request structure for internal processing.
21
+ * @throws {TypeError} When cloning a `Request` fails or the merged headers are invalid.
22
+ *
23
+ * @example
24
+ * const normalized = normalizeRequest("/users", { method: "GET" });
25
+ * console.log(normalized.url); // "/users"
26
+ */
27
+ declare const normalizeRequest: (input: FetchInput, options?: ExtendedRequestInit) => NormalizedRequest;
28
+ //#endregion
29
+ export { NormalizedRequest, normalizeRequest };
30
+ //# sourceMappingURL=request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.d.ts","names":[],"sources":["../src/request.ts"],"mappings":";;;;;;;;;UAkBiB;EACf;EACA,UAAU;EACV,SAAS;;;;;;;;;;;;;;cAeE,mBACX,OAAO,YACP,UAAU,wBACT"}
@@ -1,4 +1,4 @@
1
- import { mergeHeaders } from "./headers.mjs";
1
+ import { mergeHeaders } from "./headers.js";
2
2
  //#region src/request.ts
3
3
  /**
4
4
  * Request normalization helpers for fetch `input` values.
@@ -18,23 +18,26 @@ const EMPTY_OPTIONS = {};
18
18
  * const normalized = normalizeRequest("/users", { method: "GET" });
19
19
  * console.log(normalized.url); // "/users"
20
20
  */
21
- function normalizeRequest(input, options) {
22
- if (!(input instanceof Request)) return {
23
- url: input instanceof URL ? input.href : input,
24
- options: options ?? EMPTY_OPTIONS
25
- };
21
+ const normalizeRequest = (input, options) => {
22
+ if (!(input instanceof Request)) {
23
+ const url = input instanceof URL ? input.href : input;
24
+ return {
25
+ options: options ?? EMPTY_OPTIONS,
26
+ url
27
+ };
28
+ }
26
29
  const request = new Request(input);
27
- const { headers, ...rest } = options || {};
30
+ const { headers, ...rest } = options ?? {};
28
31
  const mergedHeaders = mergeHeaders(request.headers, headers);
29
32
  const normalizedOptions = { ...rest };
30
- if (mergedHeaders) normalizedOptions.headers = mergedHeaders;
33
+ if (mergedHeaders !== void 0) normalizedOptions.headers = mergedHeaders;
31
34
  return {
32
- url: request.url,
35
+ options: normalizedOptions,
33
36
  request,
34
- options: normalizedOptions
37
+ url: request.url
35
38
  };
36
- }
39
+ };
37
40
  //#endregion
38
41
  export { normalizeRequest };
39
42
 
40
- //# sourceMappingURL=request.mjs.map
43
+ //# sourceMappingURL=request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.js","names":[],"sources":["../src/request.ts"],"sourcesContent":["/**\n * Request normalization helpers for fetch `input` values.\n *\n * @module @zap-studio/fetch/request\n */\n\nimport { mergeHeaders } from \"./headers.js\";\nimport type { ExtendedRequestInit, FetchInput } from \"./types.js\";\n\nconst EMPTY_OPTIONS = {} as ExtendedRequestInit;\n\n/**\n * Normalized representation used by internal request execution.\n *\n * - `url`: resolved string URL from the input (string or `URL`; `Request` uses `request.url`)\n * - `request`: original Request clone when input is a Request\n * - `options`: normalized request options merged with Request headers\n */\nexport interface NormalizedRequest {\n url: string;\n request?: Request;\n options: ExtendedRequestInit;\n}\n\n/**\n * Normalizes fetch `input` and request-level options into a consistent internal shape.\n *\n * @param input - Request URL/path or Request instance.\n * @param options - Optional request options.\n * @returns A normalized request structure for internal processing.\n * @throws {TypeError} When cloning a `Request` fails or the merged headers are invalid.\n *\n * @example\n * const normalized = normalizeRequest(\"/users\", { method: \"GET\" });\n * console.log(normalized.url); // \"/users\"\n */\nexport const normalizeRequest = (\n input: FetchInput,\n options?: ExtendedRequestInit\n): NormalizedRequest => {\n if (!(input instanceof Request)) {\n const url = input instanceof URL ? input.href : input;\n return {\n options: options ?? EMPTY_OPTIONS,\n url,\n };\n }\n\n const request = new Request(input);\n const { headers, ...rest } = options ?? {};\n const mergedHeaders = mergeHeaders(request.headers, headers);\n const normalizedOptions = { ...rest } as ExtendedRequestInit;\n\n if (mergedHeaders !== undefined) {\n normalizedOptions.headers = mergedHeaders;\n }\n\n return {\n options: normalizedOptions,\n request,\n url: request.url,\n };\n};\n"],"mappings":";;;;;;;AASA,MAAM,gBAAgB,CAAC;;;;;;;;;;;;;AA2BvB,MAAa,oBACX,OACA,YACsB;CACtB,IAAI,EAAE,iBAAiB,UAAU;EAC/B,MAAM,MAAM,iBAAiB,MAAM,MAAM,OAAO;EAChD,OAAO;GACL,SAAS,WAAW;GACpB;EACF;CACF;CAEA,MAAM,UAAU,IAAI,QAAQ,KAAK;CACjC,MAAM,EAAE,SAAS,GAAG,SAAS,WAAW,CAAC;CACzC,MAAM,gBAAgB,aAAa,QAAQ,SAAS,OAAO;CAC3D,MAAM,oBAAoB,EAAE,GAAG,KAAK;CAEpC,IAAI,kBAAkB,KAAA,GACpB,kBAAkB,UAAU;CAG9B,OAAO;EACL,SAAS;EACT;EACA,KAAK,QAAQ;CACf;AACF"}
@@ -0,0 +1,168 @@
1
+ import { StandardSchemaV1 } from "@zap-studio/validation";
2
+ //#region src/types.d.ts
3
+ /**
4
+ * Accepted `fetch` input type (`string`, `URL`, or `Request`).
5
+ */
6
+ type FetchInput = Parameters<typeof fetch>[0];
7
+ type URLSearchParamsInput = ConstructorParameters<typeof URLSearchParams>[0];
8
+ type RequestBodyInit = RequestInit & {
9
+ json?: never;
10
+ };
11
+ type JsonBodyInit = Omit<RequestInit, "body"> & {
12
+ /**
13
+ * JSON body convenience. When provided, this is JSON-stringified into `body`.
14
+ * @default undefined
15
+ */
16
+ json: unknown;
17
+ body?: never;
18
+ };
19
+ interface CustomRequestInit {
20
+ /**
21
+ * Per-request query/search params
22
+ * @default undefined
23
+ */
24
+ searchParams?: URLSearchParamsInput;
25
+ /**
26
+ * Whether to throw a FetchError on HTTP errors (non-2xx responses)
27
+ * @default true
28
+ */
29
+ throwOnFetchError?: boolean;
30
+ /**
31
+ * Whether to throw a ValidationError on validation errors
32
+ * @default true
33
+ */
34
+ throwOnValidationError?: boolean;
35
+ }
36
+ /**
37
+ * Extended RequestInit type to include custom fetch options
38
+ *
39
+ * @example
40
+ * const options: ExtendedRequestInit = {
41
+ * method: "POST",
42
+ * json: { name: "Ada" },
43
+ * throwOnFetchError: true,
44
+ * };
45
+ */
46
+ type ExtendedRequestInit = (RequestBodyInit | JsonBodyInit) & CustomRequestInit;
47
+ /**
48
+ * Internal defaults used by fetchInternal
49
+ *
50
+ * @example
51
+ * const defaults: FetchDefaults = {
52
+ * baseURL: "https://api.example.com",
53
+ * throwOnFetchError: true,
54
+ * throwOnValidationError: true,
55
+ * };
56
+ */
57
+ interface FetchDefaults {
58
+ /**
59
+ * Base URL to prepend to all requests
60
+ * @default ""
61
+ */
62
+ baseURL: string;
63
+ /**
64
+ * Default headers to include in all requests (can be overridden per request)
65
+ * @default undefined
66
+ */
67
+ headers?: HeadersInit;
68
+ /**
69
+ * Default query/search params applied to every request (can be overridden per request)
70
+ * @default undefined
71
+ */
72
+ searchParams?: URLSearchParamsInput;
73
+ /**
74
+ * Whether to throw a `FetchError` on HTTP errors (non-2xx responses)
75
+ * @default true
76
+ */
77
+ throwOnFetchError: boolean;
78
+ /**
79
+ * Whether to throw a `ValidationError` on validation errors
80
+ * @default true
81
+ */
82
+ throwOnValidationError: boolean;
83
+ }
84
+ /**
85
+ * Type-safe fetch function with Standard Schema validation support
86
+ */
87
+ interface $Fetch {
88
+ /**
89
+ * Fetch with schema validation and throwOnValidationError: false
90
+ * @param input - URL or path to fetch
91
+ * @param schema - Standard Schema for response validation
92
+ * @param options - Extended request options with throwOnValidationError: false
93
+ * @returns Standard Schema Result object with value or issues
94
+ * @throws {FetchError} When `throwOnFetchError` is `true` and the response is not ok.
95
+ * @throws {TypeError} When request construction, JSON request serialization, headers,
96
+ * search params, native `fetch`, or `response.json()` body reading fail with a
97
+ * `TypeError`.
98
+ * @throws {DOMException} When native `fetch` or `response.json()` rejects an aborted
99
+ * request/body read as an `AbortError` DOMException.
100
+ * @throws {SyntaxError} When `response.json()` cannot parse the response body.
101
+ * @throws {unknown} Any error thrown or rejected by the provided Standard Schema validator.
102
+ */
103
+ <TSchema extends StandardSchemaV1>(input: FetchInput, schema: TSchema, options: ExtendedRequestInit & {
104
+ throwOnValidationError: false;
105
+ }): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;
106
+ /**
107
+ * Fetch with schema validation and throwOnValidationError: true or undefined (default)
108
+ * @param input - URL or path to fetch
109
+ * @param schema - Standard Schema for response validation
110
+ * @param options - Extended request options
111
+ * @returns Validated data of type TSchema
112
+ * @throws {FetchError} When `throwOnFetchError` is `true` and the response is not ok.
113
+ * @throws {ValidationError} When validation returns issues.
114
+ * @throws {TypeError} When request construction, JSON request serialization, headers,
115
+ * search params, native `fetch`, or `response.json()` body reading fail with a
116
+ * `TypeError`.
117
+ * @throws {DOMException} When native `fetch` or `response.json()` rejects an aborted
118
+ * request/body read as an `AbortError` DOMException.
119
+ * @throws {SyntaxError} When `response.json()` cannot parse the response body.
120
+ * @throws {unknown} Any error thrown or rejected by the provided Standard Schema validator.
121
+ */
122
+ <TSchema extends StandardSchemaV1>(input: FetchInput, schema: TSchema, options?: ExtendedRequestInit & {
123
+ throwOnValidationError?: true;
124
+ }): Promise<StandardSchemaV1.InferOutput<TSchema>>;
125
+ /**
126
+ * Fetch without schema validation
127
+ * @param input - URL or path to fetch
128
+ * @param options - Extended request options
129
+ * @returns Raw Response object
130
+ * @throws {FetchError} When `throwOnFetchError` is `true` and the response is not ok.
131
+ * @throws {TypeError} When request construction, JSON request serialization, headers,
132
+ * search params, or native `fetch` fail with a `TypeError`.
133
+ * @throws {DOMException} When native `fetch` rejects an aborted request as an
134
+ * `AbortError` DOMException.
135
+ */
136
+ (input: FetchInput, options?: ExtendedRequestInit): Promise<Response>;
137
+ }
138
+ /**
139
+ * API HTTP method-specific fetch functions
140
+ *
141
+ * @example
142
+ * const user = await api.get("/users/1", UserSchema);
143
+ */
144
+ interface ApiMethods {
145
+ /**
146
+ * DELETE method fetch function
147
+ */
148
+ delete: $Fetch;
149
+ /**
150
+ * GET method fetch function
151
+ */
152
+ get: $Fetch;
153
+ /**
154
+ * PATCH method fetch function
155
+ */
156
+ patch: $Fetch;
157
+ /**
158
+ * POST method fetch function
159
+ */
160
+ post: $Fetch;
161
+ /**
162
+ * PUT method fetch function
163
+ */
164
+ put: $Fetch;
165
+ }
166
+ //#endregion
167
+ export { $Fetch, ApiMethods, ExtendedRequestInit, FetchDefaults, FetchInput };
168
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;KAWY,aAAa,kBAAkB;KAEtC,uBAAuB,6BAA6B;KAEpD,kBAAkB;EACrB;;KAGG,eAAe,KAAK;;;;;EAKvB;EACA;;UAGQ;;;;;EAKR,eAAe;;;;;EAKf;;;;;EAKA;;;;;;;;;;;;KAaU,uBAAuB,kBAAkB,gBACnD;;;;;;;;;;;UAYe;;;;;EAKf;;;;;EAKA,UAAU;;;;;EAKV,eAAe;;;;;EAKf;;;;;EAKA;;;;;UAMe;;;;;;;;;;;;;;;;GAgBd,gBAAgB,kBACf,OAAO,YACP,QAAQ,SACR,SAAS;IAAwB;MAChC,QAAQ,iBAAiB,OAAO,iBAAiB,YAAY;;;;;;;;;;;;;;;;;GAkB/D,gBAAgB,kBACf,OAAO,YACP,QAAQ,SACR,UAAU;IACR;MAED,QAAQ,iBAAiB,YAAY;;;;;;;;;;;;GAavC,OAAO,YAAY,UAAU,sBAAsB,QAAQ;;;;;;;;UAS7C;;;;EAIf,QAAQ;;;;EAIR,KAAK;;;;EAIL,OAAO;;;;EAIP,MAAM;;;;EAIN,KAAK"}
package/dist/types.js ADDED
File without changes
package/dist/url.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ import { ExtendedRequestInit, FetchDefaults } from "./types.js";
2
+ //#region src/url.d.ts
3
+ /**
4
+ * Resolves final request URL by applying baseURL and layered search params.
5
+ *
6
+ * Search param precedence:
7
+ * 1. `defaults.searchParams`
8
+ * 2. search params already present in `resourceUrl`
9
+ * 3. per-request `searchParams`
10
+ *
11
+ * @example
12
+ * const finalUrl = resolveRequestUrl(
13
+ * "/users?page=2",
14
+ * { ...defaults, baseURL: "https://api.example.com", searchParams: { locale: "en" } },
15
+ * { page: "3" },
16
+ * );
17
+ * // https://api.example.com/users?locale=en&page=3
18
+ *
19
+ * @throws {TypeError} When `baseURL` and `resourceUrl` cannot be resolved by
20
+ * `URL`, or when default/per-request search params cannot be converted by
21
+ * `URLSearchParams`.
22
+ */
23
+ declare const resolveRequestUrl: (resourceUrl: string, defaults: FetchDefaults, searchParams?: ExtendedRequestInit["searchParams"]) => string;
24
+ //#endregion
25
+ export { resolveRequestUrl };
26
+ //# sourceMappingURL=url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.d.ts","names":[],"sources":["../src/url.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;cAmFa,oBACX,qBACA,UAAU,eACV,eAAe"}
@@ -1,5 +1,36 @@
1
1
  //#region src/url.ts
2
2
  /**
3
+ * Copies search params into target, overriding duplicate keys.
4
+ */
5
+ const mergeSearchParams = (target, source) => {
6
+ for (const [key, value] of new URLSearchParams(source)) target.set(key, value);
7
+ };
8
+ /**
9
+ * Ensures a URL has a trailing slash for relative URL resolution.
10
+ */
11
+ const ensureTrailingSlash = (url) => url.endsWith("/") ? url : `${url}/`;
12
+ /**
13
+ * Resolves search params by applying default params, URL params, then request params.
14
+ */
15
+ const resolveSearchParams = (url, defaultSearchParams, searchParams) => {
16
+ if (defaultSearchParams === void 0 && searchParams === void 0) return url;
17
+ const hashIndex = url.indexOf("#");
18
+ const hasFragment = hashIndex !== -1;
19
+ const urlWithoutHash = hasFragment ? url.slice(0, hashIndex) : url;
20
+ const hash = hasFragment ? url.slice(hashIndex + 1) : "";
21
+ const queryIndex = urlWithoutHash.indexOf("?");
22
+ const pathname = queryIndex === -1 ? urlWithoutHash : urlWithoutHash.slice(0, queryIndex);
23
+ const urlSearchParams = queryIndex === -1 ? void 0 : urlWithoutHash.slice(queryIndex + 1);
24
+ const resolvedSearchParams = new URLSearchParams();
25
+ mergeSearchParams(resolvedSearchParams, defaultSearchParams);
26
+ mergeSearchParams(resolvedSearchParams, urlSearchParams);
27
+ mergeSearchParams(resolvedSearchParams, searchParams);
28
+ const resolvedSearch = resolvedSearchParams.toString();
29
+ const fragmentSuffix = hasFragment ? `#${hash}` : "";
30
+ if (resolvedSearch.length === 0) return `${pathname}${fragmentSuffix}`;
31
+ return `${pathname}?${resolvedSearch}${fragmentSuffix}`;
32
+ };
33
+ /**
3
34
  * Resolves final request URL by applying baseURL and layered search params.
4
35
  *
5
36
  * Search param precedence:
@@ -19,43 +50,11 @@
19
50
  * `URL`, or when default/per-request search params cannot be converted by
20
51
  * `URLSearchParams`.
21
52
  */
22
- function resolveRequestUrl(resourceUrl, defaults, searchParams) {
23
- return resolveSearchParams(defaults.baseURL ? new URL(resourceUrl, ensureTrailingSlash(defaults.baseURL)).toString() : resourceUrl, defaults.searchParams, searchParams);
24
- }
25
- /**
26
- * Resolves search params by applying default params, URL params, then request params.
27
- */
28
- function resolveSearchParams(url, defaultSearchParams, searchParams) {
29
- if (!defaultSearchParams && searchParams === void 0) return url;
30
- const hashIndex = url.indexOf("#");
31
- const hasFragment = hashIndex >= 0;
32
- const urlWithoutHash = hasFragment ? url.slice(0, hashIndex) : url;
33
- const hash = hasFragment ? url.slice(hashIndex + 1) : "";
34
- const queryIndex = urlWithoutHash.indexOf("?");
35
- const pathname = queryIndex >= 0 ? urlWithoutHash.slice(0, queryIndex) : urlWithoutHash;
36
- const urlSearchParams = queryIndex >= 0 ? urlWithoutHash.slice(queryIndex + 1) : void 0;
37
- const resolvedSearchParams = new URLSearchParams();
38
- mergeSearchParams(resolvedSearchParams, defaultSearchParams);
39
- mergeSearchParams(resolvedSearchParams, urlSearchParams);
40
- mergeSearchParams(resolvedSearchParams, searchParams);
41
- const resolvedSearch = resolvedSearchParams.toString();
42
- const fragmentSuffix = hasFragment ? `#${hash}` : "";
43
- if (!resolvedSearch) return `${pathname}${fragmentSuffix}`;
44
- return `${pathname}?${resolvedSearch}${fragmentSuffix}`;
45
- }
46
- /**
47
- * Ensures a URL has a trailing slash for relative URL resolution.
48
- */
49
- function ensureTrailingSlash(url) {
50
- return url.endsWith("/") ? url : `${url}/`;
51
- }
52
- /**
53
- * Copies search params into target, overriding duplicate keys.
54
- */
55
- function mergeSearchParams(target, source) {
56
- for (const [key, value] of new URLSearchParams(source)) target.set(key, value);
57
- }
53
+ const resolveRequestUrl = (resourceUrl, defaults, searchParams) => {
54
+ const url = defaults.baseURL ? new URL(resourceUrl, ensureTrailingSlash(defaults.baseURL)).toString() : resourceUrl;
55
+ return resolveSearchParams(url, defaults.searchParams, searchParams);
56
+ };
58
57
  //#endregion
59
58
  export { resolveRequestUrl };
60
59
 
61
- //# sourceMappingURL=url.mjs.map
60
+ //# sourceMappingURL=url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.js","names":[],"sources":["../src/url.ts"],"sourcesContent":["/**\n * URL resolution and query merging utilities.\n *\n * @module @zap-studio/fetch/url\n */\n\nimport type { ExtendedRequestInit, FetchDefaults } from \"./types.js\";\n\n/**\n * Copies search params into target, overriding duplicate keys.\n */\nconst mergeSearchParams = (\n target: URLSearchParams,\n source: ExtendedRequestInit[\"searchParams\"] | undefined\n): void => {\n for (const [key, value] of new URLSearchParams(source)) {\n target.set(key, value);\n }\n};\n\n/**\n * Ensures a URL has a trailing slash for relative URL resolution.\n */\nconst ensureTrailingSlash = (url: string): string =>\n url.endsWith(\"/\") ? url : `${url}/`;\n\n/**\n * Resolves search params by applying default params, URL params, then request params.\n */\nconst resolveSearchParams = (\n url: string,\n defaultSearchParams: FetchDefaults[\"searchParams\"] | undefined,\n searchParams: ExtendedRequestInit[\"searchParams\"] | undefined\n): string => {\n if (defaultSearchParams === undefined && searchParams === undefined) {\n return url;\n }\n\n const hashIndex = url.indexOf(\"#\");\n const hasFragment = hashIndex !== -1;\n const urlWithoutHash = hasFragment ? url.slice(0, hashIndex) : url;\n const hash = hasFragment ? url.slice(hashIndex + 1) : \"\";\n const queryIndex = urlWithoutHash.indexOf(\"?\");\n const pathname =\n queryIndex === -1 ? urlWithoutHash : urlWithoutHash.slice(0, queryIndex);\n const urlSearchParams =\n queryIndex === -1 ? undefined : urlWithoutHash.slice(queryIndex + 1);\n const resolvedSearchParams = new URLSearchParams();\n\n mergeSearchParams(resolvedSearchParams, defaultSearchParams);\n mergeSearchParams(resolvedSearchParams, urlSearchParams);\n mergeSearchParams(resolvedSearchParams, searchParams);\n\n const resolvedSearch = resolvedSearchParams.toString();\n const fragmentSuffix = hasFragment ? `#${hash}` : \"\";\n\n if (resolvedSearch.length === 0) {\n return `${pathname}${fragmentSuffix}`;\n }\n\n return `${pathname}?${resolvedSearch}${fragmentSuffix}`;\n};\n\n/**\n * Resolves final request URL by applying baseURL and layered search params.\n *\n * Search param precedence:\n * 1. `defaults.searchParams`\n * 2. search params already present in `resourceUrl`\n * 3. per-request `searchParams`\n *\n * @example\n * const finalUrl = resolveRequestUrl(\n * \"/users?page=2\",\n * { ...defaults, baseURL: \"https://api.example.com\", searchParams: { locale: \"en\" } },\n * { page: \"3\" },\n * );\n * // https://api.example.com/users?locale=en&page=3\n *\n * @throws {TypeError} When `baseURL` and `resourceUrl` cannot be resolved by\n * `URL`, or when default/per-request search params cannot be converted by\n * `URLSearchParams`.\n */\nexport const resolveRequestUrl = (\n resourceUrl: string,\n defaults: FetchDefaults,\n searchParams?: ExtendedRequestInit[\"searchParams\"]\n): string => {\n const url = defaults.baseURL\n ? new URL(resourceUrl, ensureTrailingSlash(defaults.baseURL)).toString()\n : resourceUrl;\n\n return resolveSearchParams(url, defaults.searchParams, searchParams);\n};\n"],"mappings":";;;;AAWA,MAAM,qBACJ,QACA,WACS;CACT,KAAK,MAAM,CAAC,KAAK,UAAU,IAAI,gBAAgB,MAAM,GACnD,OAAO,IAAI,KAAK,KAAK;AAEzB;;;;AAKA,MAAM,uBAAuB,QAC3B,IAAI,SAAS,GAAG,IAAI,MAAM,GAAG,IAAI;;;;AAKnC,MAAM,uBACJ,KACA,qBACA,iBACW;CACX,IAAI,wBAAwB,KAAA,KAAa,iBAAiB,KAAA,GACxD,OAAO;CAGT,MAAM,YAAY,IAAI,QAAQ,GAAG;CACjC,MAAM,cAAc,cAAc;CAClC,MAAM,iBAAiB,cAAc,IAAI,MAAM,GAAG,SAAS,IAAI;CAC/D,MAAM,OAAO,cAAc,IAAI,MAAM,YAAY,CAAC,IAAI;CACtD,MAAM,aAAa,eAAe,QAAQ,GAAG;CAC7C,MAAM,WACJ,eAAe,KAAK,iBAAiB,eAAe,MAAM,GAAG,UAAU;CACzE,MAAM,kBACJ,eAAe,KAAK,KAAA,IAAY,eAAe,MAAM,aAAa,CAAC;CACrE,MAAM,uBAAuB,IAAI,gBAAgB;CAEjD,kBAAkB,sBAAsB,mBAAmB;CAC3D,kBAAkB,sBAAsB,eAAe;CACvD,kBAAkB,sBAAsB,YAAY;CAEpD,MAAM,iBAAiB,qBAAqB,SAAS;CACrD,MAAM,iBAAiB,cAAc,IAAI,SAAS;CAElD,IAAI,eAAe,WAAW,GAC5B,OAAO,GAAG,WAAW;CAGvB,OAAO,GAAG,SAAS,GAAG,iBAAiB;AACzC;;;;;;;;;;;;;;;;;;;;;AAsBA,MAAa,qBACX,aACA,UACA,iBACW;CACX,MAAM,MAAM,SAAS,UACjB,IAAI,IAAI,aAAa,oBAAoB,SAAS,OAAO,CAAC,CAAC,CAAC,SAAS,IACrE;CAEJ,OAAO,oBAAoB,KAAK,SAAS,cAAc,YAAY;AACrE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zap-studio/fetch",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "private": false,
5
5
  "description": "A type-safe fetch wrapper for HTTP requests with runtime schema validation.",
6
6
  "keywords": [
@@ -35,43 +35,34 @@
35
35
  ],
36
36
  "type": "module",
37
37
  "sideEffects": false,
38
- "types": "./dist/index.d.mts",
38
+ "types": "./dist/index.d.ts",
39
39
  "exports": {
40
- ".": "./dist/index.mjs",
41
- "./constants": "./dist/constants.mjs",
42
- "./errors": "./dist/errors.mjs",
43
- "./headers": "./dist/headers.mjs",
44
- "./internal": "./dist/internal.mjs",
45
- "./methods": "./dist/methods.mjs",
46
- "./request": "./dist/request.mjs",
47
- "./types": "./dist/types.mjs",
48
- "./url": "./dist/url.mjs",
40
+ ".": "./dist/index.js",
41
+ "./constants": "./dist/constants.js",
42
+ "./errors": "./dist/errors.js",
43
+ "./fetch": "./dist/fetch.js",
44
+ "./headers": "./dist/headers.js",
45
+ "./request": "./dist/request.js",
46
+ "./types": "./dist/types.js",
47
+ "./url": "./dist/url.js",
49
48
  "./package.json": "./package.json"
50
49
  },
51
50
  "publishConfig": {
52
51
  "access": "public"
53
52
  },
54
53
  "dependencies": {
55
- "@zap-studio/validation": "0.3.4"
54
+ "@zap-studio/validation": "workspace:*"
56
55
  },
57
56
  "devDependencies": {
58
- "@better-fetch/fetch": "^1.1.21",
59
- "arktype": "^2.2.0",
60
- "axios": "^1.15.2",
61
- "ky": "^2.0.2",
62
- "ofetch": "^1.5.1",
63
- "typescript": "^6.0.3",
64
- "valibot": "^1.3.1",
65
- "vite-plus": "^0.1.19",
66
- "zod": "^4.3.6",
67
- "@zap-studio/typescript": "0.0.0"
57
+ "@zap-studio/typescript": "workspace:*",
58
+ "arktype": "catalog:",
59
+ "tsdown": "catalog:",
60
+ "typescript": "catalog:",
61
+ "valibot": "catalog:",
62
+ "vitest": "catalog:",
63
+ "zod": "catalog:"
68
64
  },
69
65
  "engines": {
70
66
  "node": ">=18.0.0"
71
- },
72
- "scripts": {
73
- "build": "vp pack",
74
- "test": "vp test run",
75
- "test:watch": "vp test watch"
76
67
  }
77
- }
68
+ }
@@ -1,18 +0,0 @@
1
- import { FetchDefaults } from "./types.mjs";
2
-
3
- //#region src/constants.d.ts
4
- /**
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
14
- */
15
- declare const GLOBAL_DEFAULTS: FetchDefaults;
16
- //#endregion
17
- export { GLOBAL_DEFAULTS };
18
- //# sourceMappingURL=constants.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.d.mts","names":[],"sources":["../src/constants.ts"],"mappings":";;;;;;;;;;;;;;cAmBa,eAAA,EAAiB,aAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.mjs","names":[],"sources":["../src/constants.ts"],"sourcesContent":["/**\n * Shared defaults and constants for fetch behavior.\n *\n * @module @zap-studio/fetch/constants\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 DELETED
@@ -1,41 +0,0 @@
1
- //#region src/errors.d.ts
2
- /**
3
- * Custom error types used by the fetch package.
4
- *
5
- * @module @zap-studio/fetch/errors
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
- declare class FetchError extends Error {
26
- /**
27
- * HTTP status code from the failing response.
28
- */
29
- status: Response["status"];
30
- /**
31
- * Full response object for additional inspection.
32
- */
33
- response: Response;
34
- /**
35
- * Creates a FetchError from a non-ok response.
36
- */
37
- constructor(message: string, response: Response);
38
- }
39
- //#endregion
40
- export { FetchError };
41
- //# sourceMappingURL=errors.d.mts.map
@@ -1 +0,0 @@
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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"errors.mjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Custom error types used by the fetch package.\n *\n * @module @zap-studio/fetch/errors\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"}
@@ -1,26 +0,0 @@
1
- //#region src/headers.d.ts
2
- /**
3
- * Header utility helpers for request normalization and merging.
4
- *
5
- * @module @zap-studio/fetch/headers
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
@@ -1 +0,0 @@
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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"headers.mjs","names":[],"sources":["../src/headers.ts"],"sourcesContent":["/**\n * Header utility helpers for request normalization and merging.\n *\n * @module @zap-studio/fetch/headers\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 if (!base) {\n return new Headers(override);\n }\n\n if (!override) {\n return new Headers(base);\n }\n\n const merged = new Headers(base);\n for (const [key, value] of new Headers(override).entries()) {\n merged.set(key, value);\n }\n return merged;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,aAAa,MAAoB,UAA6C;AAC5F,KAAI,EAAE,QAAQ,UACZ;AAGF,KAAI,CAAC,KACH,QAAO,IAAI,QAAQ,SAAS;AAG9B,KAAI,CAAC,SACH,QAAO,IAAI,QAAQ,KAAK;CAG1B,MAAM,SAAS,IAAI,QAAQ,KAAK;AAChC,MAAK,MAAM,CAAC,KAAK,UAAU,IAAI,QAAQ,SAAS,CAAC,SAAS,CACxD,QAAO,IAAI,KAAK,MAAM;AAExB,QAAO"}