@zap-studio/fetch 0.3.1 → 0.4.0

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @zap-studio/fetch
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 69057cd: Expose fetch defaults constants and utility helpers as public exports.
8
+
3
9
  ## 0.3.1
4
10
 
5
11
  ### Patch Changes
@@ -0,0 +1,14 @@
1
+ //#region src/constants.ts
2
+ /**
3
+ * Default options for the global $fetch
4
+ */
5
+ const GLOBAL_DEFAULTS = {
6
+ baseURL: "",
7
+ headers: void 0,
8
+ throwOnFetchError: true,
9
+ throwOnValidationError: true
10
+ };
11
+
12
+ //#endregion
13
+ export { GLOBAL_DEFAULTS as t };
14
+ //# sourceMappingURL=constants-Dqiih1SQ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants-Dqiih1SQ.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"}
@@ -0,0 +1,11 @@
1
+ import { a as FetchDefaults } from "./types-DjDYV3FA.mjs";
2
+
3
+ //#region src/constants.d.ts
4
+
5
+ /**
6
+ * Default options for the global $fetch
7
+ */
8
+ declare const GLOBAL_DEFAULTS: FetchDefaults;
9
+ //#endregion
10
+ export { GLOBAL_DEFAULTS };
11
+ //# sourceMappingURL=constants.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.mts","names":["GLOBAL_DEFAULTS: FetchDefaults"],"sources":["../src/constants.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;cAAaA,iBAAiB"}
@@ -0,0 +1,3 @@
1
+ import { t as GLOBAL_DEFAULTS } from "./constants-Dqiih1SQ.mjs";
2
+
3
+ export { GLOBAL_DEFAULTS };
@@ -26,4 +26,4 @@ var ValidationError = class extends Error {
26
26
 
27
27
  //#endregion
28
28
  export { ValidationError as n, FetchError as t };
29
- //# sourceMappingURL=errors-DKxnbFHZ.mjs.map
29
+ //# sourceMappingURL=errors-DgqwzMpH.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors-DKxnbFHZ.mjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Error thrown for HTTP errors (non-2xx responses)\n */\nexport class FetchError extends Error {\n status: Response[\"status\"];\n response: 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\n/**\n * Error thrown for validation errors\n */\nexport class ValidationError extends Error {\n issues: StandardSchemaV1.Issue[];\n\n constructor(issues: StandardSchemaV1.Issue[]) {\n super(JSON.stringify(issues, null, 2));\n this.name = \"ValidationError\";\n this.issues = issues;\n }\n}\n"],"mappings":";;;;AAKA,IAAa,aAAb,cAAgC,MAAM;CACpC;CACA;CAEA,YAAY,SAAiB,UAAoB;AAC/C,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,SAAS,SAAS;AACvB,OAAK,WAAW;;;;;;AAOpB,IAAa,kBAAb,cAAqC,MAAM;CACzC;CAEA,YAAY,QAAkC;AAC5C,QAAM,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC;AACtC,OAAK,OAAO;AACZ,OAAK,SAAS"}
1
+ {"version":3,"file":"errors-DgqwzMpH.mjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Error thrown for HTTP errors (non-2xx responses)\n */\nexport class FetchError extends Error {\n status: Response[\"status\"];\n response: 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\n/**\n * Error thrown for validation errors\n */\nexport class ValidationError extends Error {\n issues: StandardSchemaV1.Issue[];\n\n constructor(issues: StandardSchemaV1.Issue[]) {\n super(JSON.stringify(issues, null, 2));\n this.name = \"ValidationError\";\n this.issues = issues;\n }\n}\n"],"mappings":";;;;AAKA,IAAa,aAAb,cAAgC,MAAM;CACpC;CACA;CAEA,YAAY,SAAiB,UAAoB;AAC/C,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,SAAS,SAAS;AACvB,OAAK,WAAW;;;;;;AAOpB,IAAa,kBAAb,cAAqC,MAAM;CACzC;CAEA,YAAY,QAAkC;AAC5C,QAAM,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC;AACtC,OAAK,OAAO;AACZ,OAAK,SAAS"}
package/dist/errors.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { n as ValidationError, t as FetchError } from "./errors-DKxnbFHZ.mjs";
1
+ import { n as ValidationError, t as FetchError } from "./errors-DgqwzMpH.mjs";
2
2
 
3
3
  export { FetchError, ValidationError };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { i as ExtendedRequestInit, n as ApiMethods, r as CreateFetchOptions, t as $Fetch } from "./types-CvCrPMIR.mjs";
1
+ import { i as ExtendedRequestInit, n as ApiMethods, r as CreateFetchOptions, t as $Fetch } from "./types-DjDYV3FA.mjs";
2
2
  import { StandardSchemaV1 } from "@standard-schema/spec";
3
3
 
4
4
  //#region src/index.d.ts
package/dist/index.mjs CHANGED
@@ -1,188 +1,7 @@
1
- import { t as FetchError } from "./errors-DKxnbFHZ.mjs";
2
- import { n as standardValidate, t as isStandardSchema } from "./validator-BGjWrM4d.mjs";
1
+ import { t as GLOBAL_DEFAULTS } from "./constants-Dqiih1SQ.mjs";
2
+ import { t as isStandardSchema } from "./validator-Cd9NivYJ.mjs";
3
+ import { n as fetchInternal, t as createMethod } from "./utils-Cslywt8D.mjs";
3
4
 
4
- //#region src/internal/constants.ts
5
- /**
6
- * Default options for the global $fetch
7
- */
8
- const GLOBAL_DEFAULTS = {
9
- baseURL: "",
10
- headers: void 0,
11
- throwOnFetchError: true,
12
- throwOnValidationError: true
13
- };
14
-
15
- //#endregion
16
- //#region src/internal/utils.ts
17
- /**
18
- * Merges two HeadersInit objects, with the second one taking precedence
19
- *
20
- * @example
21
- * const baseHeaders = { "Authorization": "Bearer token", "Content-Type": "application/json" };
22
- * const overrideHeaders = { "Content-Type": "application/xml", "X-Custom-Header": "value" };
23
- *
24
- * const merged = mergeHeaders(baseHeaders, overrideHeaders);
25
- *
26
- * // Resulting headers:
27
- * // {
28
- * // "Authorization": "Bearer token",
29
- * // "Content-Type": "application/xml",
30
- * // "X-Custom-Header": "value"
31
- * // }
32
- */
33
- function mergeHeaders(base, override) {
34
- if (!(base || override)) return;
35
- const merged = new Headers(base);
36
- if (override) {
37
- const overrideHeaders = new Headers(override);
38
- for (const [key, value] of overrideHeaders.entries()) merged.set(key, value);
39
- }
40
- return merged;
41
- }
42
- /**
43
- * Removes trailing slashes from a string
44
- */
45
- function trimTrailingSlashes(str) {
46
- let end = str.length;
47
- while (end > 0 && str[end - 1] === "/") end -= 1;
48
- return str.slice(0, end);
49
- }
50
- /**
51
- * Removes leading slashes from a string
52
- */
53
- function trimLeadingSlashes(str) {
54
- let start = 0;
55
- while (start < str.length && str[start] === "/") start += 1;
56
- return str.slice(start);
57
- }
58
- const ABSOLUTE_URL_PATTERN = /^(?:https?:)?\/\//i;
59
- /**
60
- * Checks if a URL is absolute (starts with http://, https://, or //)
61
- */
62
- function isAbsoluteURL(url) {
63
- return ABSOLUTE_URL_PATTERN.test(url);
64
- }
65
- /**
66
- * Normalizes search parameters into a URLSearchParams object.
67
- */
68
- function normalizeSearchParams(input) {
69
- if (input === void 0 || input === null) return new URLSearchParams();
70
- if (input instanceof URLSearchParams) return new URLSearchParams(input);
71
- if (typeof input === "string") return new URLSearchParams(input);
72
- if (Array.isArray(input)) return new URLSearchParams(input);
73
- const params = new URLSearchParams();
74
- for (const [k, v] of Object.entries(input)) params.set(k, v);
75
- return params;
76
- }
77
- /**
78
- * Parses a URL string into its path, query, and hash components.
79
- * Handles both absolute URLs (using URL constructor) and relative paths.
80
- */
81
- function parseUrlComponents(url) {
82
- if (isAbsoluteURL(url)) try {
83
- const parsed = new URL(url);
84
- const pathOnly = `${parsed.origin}${parsed.pathname}`;
85
- const existingQuery = parsed.search.startsWith("?") ? parsed.search.slice(1) : parsed.search;
86
- let hash$1 = parsed.hash;
87
- if (hash$1 === "" && url.endsWith("#")) hash$1 = "#";
88
- return {
89
- pathOnly,
90
- existingQuery,
91
- hash: hash$1
92
- };
93
- } catch {}
94
- let hash = "";
95
- let urlWithoutHash = url;
96
- const hashIndex = url.indexOf("#");
97
- if (hashIndex !== -1) {
98
- hash = url.slice(hashIndex);
99
- urlWithoutHash = url.slice(0, hashIndex);
100
- }
101
- const queryIndex = urlWithoutHash.indexOf("?");
102
- if (queryIndex === -1) return {
103
- pathOnly: urlWithoutHash,
104
- existingQuery: "",
105
- hash
106
- };
107
- return {
108
- pathOnly: urlWithoutHash.slice(0, queryIndex),
109
- existingQuery: urlWithoutHash.slice(queryIndex + 1),
110
- hash
111
- };
112
- }
113
- /**
114
- * Builds a URL with merged search parameters from factory defaults,
115
- * request options, and existing query parameters.
116
- *
117
- * This function takes a base URL, factory search parameters,
118
- * and request search parameters, and combines them into a single URL.
119
- *
120
- * Priority (highest to lowest):
121
- * 1. Request search parameters (highest priority, overwrites all others)
122
- * 2. Existing query parameters from the URL (overwrites factory defaults)
123
- * 3. Factory search parameters (lowest priority, overwritten by all others)
124
- *
125
- * If no search parameters are provided, the URL will not have a query string.
126
- * Any trailing hash/fragment is preserved.
127
- */
128
- function buildUrlWithMergedSearchParams(url, factorySearch, requestSearch) {
129
- const { pathOnly, existingQuery, hash } = parseUrlComponents(url);
130
- if (!(factorySearch ?? requestSearch ?? existingQuery)) return url;
131
- const mergedParams = new URLSearchParams();
132
- const resourceParams = new URLSearchParams(existingQuery);
133
- const factoryParams = normalizeSearchParams(factorySearch);
134
- const reqParams = normalizeSearchParams(requestSearch);
135
- for (const [k, v] of factoryParams.entries()) mergedParams.set(k, v);
136
- for (const [k, v] of resourceParams.entries()) mergedParams.set(k, v);
137
- for (const [k, v] of reqParams.entries()) mergedParams.set(k, v);
138
- const queryString = mergedParams.toString();
139
- if (queryString) return `${pathOnly}?${queryString}${hash}`;
140
- return `${pathOnly}${hash}`;
141
- }
142
- /**
143
- * Internal fetch implementation used by both $fetch and createFetch
144
- */
145
- async function fetchInternal(resource, schema, options, defaults) {
146
- const { throwOnValidationError = defaults.throwOnValidationError, throwOnFetchError = defaults.throwOnFetchError, headers: requestHeaders, searchParams: requestSearchParams, ...rest } = options || {};
147
- const mergedHeaders = mergeHeaders(defaults.headers, requestHeaders);
148
- const init = {
149
- ...rest,
150
- headers: mergedHeaders
151
- };
152
- if (schema && init.body) {
153
- init.body = JSON.stringify(init.body);
154
- const existingHeaders = new Headers(init.headers);
155
- if (!existingHeaders.has("Content-Type")) existingHeaders.set("Content-Type", "application/json");
156
- init.headers = existingHeaders;
157
- }
158
- let url;
159
- if (isAbsoluteURL(resource)) url = resource;
160
- else {
161
- const base = trimTrailingSlashes(defaults.baseURL);
162
- const path = trimLeadingSlashes(resource);
163
- url = base ? `${base}/${path}` : resource;
164
- }
165
- url = buildUrlWithMergedSearchParams(url, defaults.searchParams, requestSearchParams);
166
- const response = await fetch(url, init);
167
- if (throwOnFetchError && !response.ok) throw new FetchError(`HTTP ${response.status}: ${response.statusText}`, response);
168
- if (schema) return standardValidate(schema, await response.json(), throwOnValidationError);
169
- return response;
170
- }
171
- /**
172
- * Creates an HTTP method helper bound to a fetch function
173
- */
174
- function createMethod(fetchFn, method) {
175
- function methodFetch(resource, schemaOrOptions, optionsOrUndefined) {
176
- const [schema, options] = isStandardSchema(schemaOrOptions) ? [schemaOrOptions, optionsOrUndefined] : [void 0, schemaOrOptions];
177
- return fetchFn(resource, schema, {
178
- ...options,
179
- method
180
- });
181
- }
182
- return methodFetch;
183
- }
184
-
185
- //#endregion
186
5
  //#region src/index.ts
187
6
  async function $fetch(resource, schemaOrOptions, optionsOrUndefined) {
188
7
  const [schema, options] = isStandardSchema(schemaOrOptions) ? [schemaOrOptions, optionsOrUndefined] : [void 0, schemaOrOptions];
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["GLOBAL_DEFAULTS: FetchDefaults","hash","url: string","api: ApiMethods","defaults: FetchDefaults"],"sources":["../src/internal/constants.ts","../src/internal/utils.ts","../src/index.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","import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { FetchError } from \"../errors\";\nimport type {\n $Fetch,\n ExtendedRequestInit,\n FetchDefaults,\n SearchParams,\n} from \"../types\";\nimport { isStandardSchema, standardValidate } from \"../validator\";\n\n/**\n * Merges two HeadersInit objects, with the second one taking precedence\n *\n * @example\n * const baseHeaders = { \"Authorization\": \"Bearer token\", \"Content-Type\": \"application/json\" };\n * const overrideHeaders = { \"Content-Type\": \"application/xml\", \"X-Custom-Header\": \"value\" };\n *\n * const merged = mergeHeaders(baseHeaders, overrideHeaders);\n *\n * // Resulting headers:\n * // {\n * // \"Authorization\": \"Bearer token\",\n * // \"Content-Type\": \"application/xml\",\n * // \"X-Custom-Header\": \"value\"\n * // }\n */\nexport function mergeHeaders(\n base: HeadersInit | undefined,\n override: HeadersInit | undefined\n): 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\n/**\n * Removes trailing slashes from a string\n */\nfunction trimTrailingSlashes(str: string): string {\n let end = str.length;\n while (end > 0 && str[end - 1] === \"/\") {\n end -= 1;\n }\n return str.slice(0, end);\n}\n\n/**\n * Removes leading slashes from a string\n */\nfunction trimLeadingSlashes(str: string): string {\n let start = 0;\n while (start < str.length && str[start] === \"/\") {\n start += 1;\n }\n return str.slice(start);\n}\n\nconst ABSOLUTE_URL_PATTERN = /^(?:https?:)?\\/\\//i;\n\n/**\n * Checks if a URL is absolute (starts with http://, https://, or //)\n */\nfunction isAbsoluteURL(url: string): boolean {\n return ABSOLUTE_URL_PATTERN.test(url);\n}\n\n/**\n * Normalizes search parameters into a URLSearchParams object.\n */\nfunction normalizeSearchParams(\n input: SearchParams | undefined\n): URLSearchParams {\n if (input === undefined || input === null) {\n return new URLSearchParams();\n }\n\n if (input instanceof URLSearchParams) {\n return new URLSearchParams(input);\n }\n\n if (typeof input === \"string\") {\n return new URLSearchParams(input);\n }\n\n if (Array.isArray(input)) {\n return new URLSearchParams(input);\n }\n\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(input)) {\n params.set(k, v);\n }\n\n return params;\n}\n\n/**\n * Parses a URL string into its path, query, and hash components.\n * Handles both absolute URLs (using URL constructor) and relative paths.\n */\nfunction parseUrlComponents(url: string): {\n pathOnly: string;\n existingQuery: string;\n hash: string;\n} {\n // Try parsing as absolute URL first\n if (isAbsoluteURL(url)) {\n try {\n const parsed = new URL(url);\n const pathOnly = `${parsed.origin}${parsed.pathname}`;\n // parsed.search includes the leading \"?\", so strip it\n const existingQuery = parsed.search.startsWith(\"?\")\n ? parsed.search.slice(1)\n : parsed.search;\n // URL constructor normalizes away empty hash, if original URL had # at end, preserve it\n let hash = parsed.hash;\n if (hash === \"\" && url.endsWith(\"#\")) {\n hash = \"#\";\n }\n return { pathOnly, existingQuery, hash };\n } catch {\n // Fall through to manual parsing if URL constructor fails\n }\n }\n\n // Manual parsing for relative URLs or if URL constructor failed\n let hash = \"\";\n let urlWithoutHash = url;\n const hashIndex = url.indexOf(\"#\");\n if (hashIndex !== -1) {\n hash = url.slice(hashIndex);\n urlWithoutHash = url.slice(0, hashIndex);\n }\n\n // Find the first \"?\" to split path and query\n const queryIndex = urlWithoutHash.indexOf(\"?\");\n if (queryIndex === -1) {\n return { pathOnly: urlWithoutHash, existingQuery: \"\", hash };\n }\n\n const pathOnly = urlWithoutHash.slice(0, queryIndex);\n const existingQuery = urlWithoutHash.slice(queryIndex + 1);\n return { pathOnly, existingQuery, hash };\n}\n\n/**\n * Builds a URL with merged search parameters from factory defaults,\n * request options, and existing query parameters.\n *\n * This function takes a base URL, factory search parameters,\n * and request search parameters, and combines them into a single URL.\n *\n * Priority (highest to lowest):\n * 1. Request search parameters (highest priority, overwrites all others)\n * 2. Existing query parameters from the URL (overwrites factory defaults)\n * 3. Factory search parameters (lowest priority, overwritten by all others)\n *\n * If no search parameters are provided, the URL will not have a query string.\n * Any trailing hash/fragment is preserved.\n */\nfunction buildUrlWithMergedSearchParams(\n url: string,\n factorySearch: FetchDefaults[\"searchParams\"] | undefined,\n requestSearch: ExtendedRequestInit[\"searchParams\"] | undefined\n): string {\n const { pathOnly, existingQuery, hash } = parseUrlComponents(url);\n\n // Early return if no search params to merge\n const hasSearchParams = factorySearch ?? requestSearch ?? existingQuery;\n if (!hasSearchParams) {\n return url;\n }\n\n const mergedParams = new URLSearchParams();\n\n const resourceParams = new URLSearchParams(existingQuery);\n const factoryParams = normalizeSearchParams(factorySearch);\n const reqParams = normalizeSearchParams(requestSearch);\n\n for (const [k, v] of factoryParams.entries()) {\n mergedParams.set(k, v);\n }\n\n for (const [k, v] of resourceParams.entries()) {\n mergedParams.set(k, v);\n }\n\n for (const [k, v] of reqParams.entries()) {\n mergedParams.set(k, v);\n }\n\n const queryString = mergedParams.toString();\n if (queryString) {\n return `${pathOnly}?${queryString}${hash}`;\n }\n\n return `${pathOnly}${hash}`;\n}\n\n/**\n * Internal fetch implementation used by both $fetch and createFetch\n */\nexport async function fetchInternal(\n resource: string,\n schema: StandardSchemaV1 | undefined,\n options: ExtendedRequestInit | undefined,\n defaults: FetchDefaults\n): Promise<unknown> {\n const {\n throwOnValidationError = defaults.throwOnValidationError,\n throwOnFetchError = defaults.throwOnFetchError,\n headers: requestHeaders,\n searchParams: requestSearchParams,\n ...rest\n } = options || {};\n\n const mergedHeaders = mergeHeaders(defaults.headers, requestHeaders);\n const init = { ...rest, headers: mergedHeaders } as RequestInit;\n\n // Auto-stringify body and set default Content-Type if we have a schema\n if (schema && init.body) {\n init.body = JSON.stringify(init.body);\n\n const existingHeaders = new Headers(init.headers);\n if (!existingHeaders.has(\"Content-Type\")) {\n existingHeaders.set(\"Content-Type\", \"application/json\");\n }\n\n init.headers = existingHeaders;\n }\n\n // For absolute URLs, ignore baseURL entirely\n let url: string;\n if (isAbsoluteURL(resource)) {\n url = resource;\n } else {\n // Normalize URL by avoiding double slashes between baseURL and resource\n const base = trimTrailingSlashes(defaults.baseURL);\n const path = trimLeadingSlashes(resource);\n url = base ? `${base}/${path}` : resource;\n }\n\n // Merge query/search params\n url = buildUrlWithMergedSearchParams(\n url,\n defaults.searchParams,\n requestSearchParams\n );\n\n const response = await fetch(url, init);\n\n if (throwOnFetchError && !response.ok) {\n throw new FetchError(\n `HTTP ${response.status}: ${response.statusText}`,\n response\n );\n }\n\n // For json with schema, validate\n if (schema) {\n const raw = await response.json();\n return standardValidate(schema, raw, throwOnValidationError);\n }\n\n // No validation, return raw response data\n return response;\n}\n\n/**\n * Creates an HTTP method helper bound to a fetch function\n */\nexport function createMethod<TFetch extends $Fetch>(\n fetchFn: TFetch,\n method: string\n): $Fetch {\n function methodFetch<TSchema extends StandardSchemaV1>(\n resource: string,\n schema: TSchema,\n options: Omit<ExtendedRequestInit<false>, \"method\">\n ): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;\n\n function methodFetch<TSchema extends StandardSchemaV1>(\n resource: string,\n schema: TSchema,\n options?: Omit<ExtendedRequestInit<true | undefined>, \"method\">\n ): Promise<StandardSchemaV1.InferOutput<TSchema>>;\n\n function methodFetch(\n resource: string,\n options?: Omit<ExtendedRequestInit, \"method\">\n ): Promise<Response>;\n\n function methodFetch(\n resource: string,\n schemaOrOptions?: StandardSchemaV1 | Omit<ExtendedRequestInit, \"method\">,\n optionsOrUndefined?: Omit<ExtendedRequestInit, \"method\">\n ): Promise<unknown> {\n const [schema, options] = isStandardSchema(schemaOrOptions)\n ? [schemaOrOptions, optionsOrUndefined]\n : [undefined, schemaOrOptions];\n\n return (fetchFn as (...args: unknown[]) => Promise<unknown>)(\n resource,\n schema,\n { ...options, method }\n );\n }\n\n return methodFetch;\n}\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { GLOBAL_DEFAULTS } from \"./internal/constants\";\nimport { createMethod, fetchInternal } from \"./internal/utils\";\nimport type {\n $Fetch,\n ApiMethods,\n CreateFetchOptions,\n ExtendedRequestInit,\n FetchDefaults,\n} from \"./types\";\nimport { isStandardSchema } from \"./validator\";\n\n/**\n * Type-safe fetch wrapper with Standard Schema validation.\n *\n * - When `throwOnValidationError: true`: validated data of type `TSchema`\n * - When `throwOnValidationError: false`: Standard Schema Result object `{ value?, issues? }`\n * - When `throwOnFetchError: true`: throws `FetchError` on non-ok responses\n *\n * If no schema is provided, returns the raw `Response` object.\n *\n * @throws {FetchError} When `throwOnFetchError: true` and response is not ok\n * @throws {ValidationError} When `throwOnValidationError: true` and validation fails\n *\n * @example\n * import { z } from \"zod\";\n * import { $fetch } from \"@zap-studio/fetch\";\n *\n * const UserSchema = z.object({ id: z.number(), name: z.string() });\n *\n * // Basic usage (schema validation)\n * const user = await $fetch(\"/api/users/1\", UserSchema, { headers: { \"Authorization\": \"Bearer token\" } });\n * console.log(\"Validated user:\", user);\n *\n * // Raw usage (no schema validation and typed Response object)\n * const result = await $fetch(\"/api/data\", { method: \"POST\", body: JSON.stringify({ key: \"value\" }) });\n * const json = await result.json() as ResultType;\n * console.log(\"Raw response data:\", json);\n *\n * // Usage with validation errors returned instead of thrown\n * const result = await $fetch(\"/api/users/1\", UserSchema, { throwOnValidationError: false });\n *\n * if (result.issues) {\n * console.error(\"Validation errors:\", result.issues);\n * } else {\n * console.log(\"Validated user:\", result.value);\n * }\n */\nexport async function $fetch<TSchema extends StandardSchemaV1>(\n resource: string,\n schema: TSchema,\n options: ExtendedRequestInit<false>\n): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;\n\nexport async function $fetch<TSchema extends StandardSchemaV1>(\n resource: string,\n schema: TSchema,\n options?: ExtendedRequestInit<true | undefined>\n): Promise<StandardSchemaV1.InferOutput<TSchema>>;\n\nexport async function $fetch(\n resource: string,\n options?: ExtendedRequestInit\n): Promise<Response>;\n\nexport async function $fetch(\n resource: string,\n schemaOrOptions?: StandardSchemaV1 | ExtendedRequestInit,\n optionsOrUndefined?: ExtendedRequestInit\n): Promise<unknown> {\n const [schema, options] = isStandardSchema(schemaOrOptions)\n ? [schemaOrOptions, optionsOrUndefined]\n : [undefined, schemaOrOptions];\n\n return await fetchInternal(resource, schema, options, GLOBAL_DEFAULTS);\n}\n\n/**\n * Convenience methods for common HTTP verbs.\n *\n * These methods always require a schema for validation.\n * For raw responses without validation, use `$fetch` directly.\n *\n * @example\n * import { z } from \"zod\";\n * import { api } from \"@zap-studio/fetch\";\n *\n * const PostSchema = z.object({\n * id: z.number(),\n * title: z.string(),\n * content: z.string(),\n * });\n *\n * async function fetchPost(postId: number) {\n * const post = await api.get(`https://api.example.com/posts/${postId}`, PostSchema);\n * return post; // post is typed as { id: number; title: string; content: string; }\n * }\n */\nexport const api: ApiMethods = {\n get: createMethod($fetch, \"GET\"),\n post: createMethod($fetch, \"POST\"),\n put: createMethod($fetch, \"PUT\"),\n patch: createMethod($fetch, \"PATCH\"),\n delete: createMethod($fetch, \"DELETE\"),\n};\n\n/**\n * Creates a custom fetch instance with pre-configured defaults.\n *\n * Use this factory to create API clients with a base URL, default headers,\n * and other shared configuration. Each instance is independent.\n *\n * @example\n * import { z } from \"zod\";\n * import { createFetch } from \"@zap-studio/fetch\";\n *\n * // Create a configured instance\n * const { $fetch, api } = createFetch({\n * baseURL: \"https://api.example.com\",\n * headers: { \"Authorization\": \"Bearer token\" },\n * });\n *\n * const UserSchema = z.object({ id: z.number(), name: z.string() });\n *\n * // Now use relative paths - baseURL is prepended automatically\n * const user = await api.get(\"/users/1\", UserSchema);\n *\n * // Or use $fetch directly\n * const response = await $fetch(\"/users\", UserSchema, { method: \"POST\", body: { name: \"John\" } });\n */\nexport function createFetch(factoryOptions: CreateFetchOptions = {}): {\n $fetch: $Fetch;\n api: ApiMethods;\n} {\n const defaults: FetchDefaults = {\n baseURL: factoryOptions.baseURL ?? \"\",\n headers: factoryOptions.headers,\n searchParams: factoryOptions.searchParams,\n throwOnFetchError: factoryOptions.throwOnFetchError ?? true,\n throwOnValidationError: factoryOptions.throwOnValidationError ?? true,\n };\n\n async function customFetch<TSchema extends StandardSchemaV1>(\n resource: string,\n schema: TSchema,\n options: ExtendedRequestInit<false>\n ): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;\n\n async function customFetch<TSchema extends StandardSchemaV1>(\n resource: string,\n schema: TSchema,\n options?: ExtendedRequestInit<true | undefined>\n ): Promise<StandardSchemaV1.InferOutput<TSchema>>;\n\n async function customFetch(\n resource: string,\n options?: ExtendedRequestInit\n ): Promise<Response>;\n\n async function customFetch(\n resource: string,\n schemaOrOptions?: StandardSchemaV1 | ExtendedRequestInit,\n optionsOrUndefined?: ExtendedRequestInit\n ): Promise<unknown> {\n const [schema, options] = isStandardSchema(schemaOrOptions)\n ? [schemaOrOptions, optionsOrUndefined]\n : [undefined, schemaOrOptions];\n\n return await fetchInternal(resource, schema, options, defaults);\n }\n\n const customApi = {\n get: createMethod(customFetch, \"GET\"),\n post: createMethod(customFetch, \"POST\"),\n put: createMethod(customFetch, \"PUT\"),\n patch: createMethod(customFetch, \"PATCH\"),\n delete: createMethod(customFetch, \"DELETE\"),\n };\n\n return {\n $fetch: customFetch,\n api: customApi,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["api: ApiMethods","defaults: FetchDefaults"],"sources":["../src/index.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { GLOBAL_DEFAULTS } from \"./constants\";\nimport type {\n $Fetch,\n ApiMethods,\n CreateFetchOptions,\n ExtendedRequestInit,\n FetchDefaults,\n} from \"./types\";\nimport { createMethod, fetchInternal } from \"./utils\";\nimport { isStandardSchema } from \"./validator\";\n\n/**\n * Type-safe fetch wrapper with Standard Schema validation.\n *\n * - When `throwOnValidationError: true`: validated data of type `TSchema`\n * - When `throwOnValidationError: false`: Standard Schema Result object `{ value?, issues? }`\n * - When `throwOnFetchError: true`: throws `FetchError` on non-ok responses\n *\n * If no schema is provided, returns the raw `Response` object.\n *\n * @throws {FetchError} When `throwOnFetchError: true` and response is not ok\n * @throws {ValidationError} When `throwOnValidationError: true` and validation fails\n *\n * @example\n * import { z } from \"zod\";\n * import { $fetch } from \"@zap-studio/fetch\";\n *\n * const UserSchema = z.object({ id: z.number(), name: z.string() });\n *\n * // Basic usage (schema validation)\n * const user = await $fetch(\"/api/users/1\", UserSchema, { headers: { \"Authorization\": \"Bearer token\" } });\n * console.log(\"Validated user:\", user);\n *\n * // Raw usage (no schema validation and typed Response object)\n * const result = await $fetch(\"/api/data\", { method: \"POST\", body: JSON.stringify({ key: \"value\" }) });\n * const json = await result.json() as ResultType;\n * console.log(\"Raw response data:\", json);\n *\n * // Usage with validation errors returned instead of thrown\n * const result = await $fetch(\"/api/users/1\", UserSchema, { throwOnValidationError: false });\n *\n * if (result.issues) {\n * console.error(\"Validation errors:\", result.issues);\n * } else {\n * console.log(\"Validated user:\", result.value);\n * }\n */\nexport async function $fetch<TSchema extends StandardSchemaV1>(\n resource: string,\n schema: TSchema,\n options: ExtendedRequestInit<false>\n): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;\n\nexport async function $fetch<TSchema extends StandardSchemaV1>(\n resource: string,\n schema: TSchema,\n options?: ExtendedRequestInit<true | undefined>\n): Promise<StandardSchemaV1.InferOutput<TSchema>>;\n\nexport async function $fetch(\n resource: string,\n options?: ExtendedRequestInit\n): Promise<Response>;\n\nexport async function $fetch(\n resource: string,\n schemaOrOptions?: StandardSchemaV1 | ExtendedRequestInit,\n optionsOrUndefined?: ExtendedRequestInit\n): Promise<unknown> {\n const [schema, options] = isStandardSchema(schemaOrOptions)\n ? [schemaOrOptions, optionsOrUndefined]\n : [undefined, schemaOrOptions];\n\n return await fetchInternal(resource, schema, options, GLOBAL_DEFAULTS);\n}\n\n/**\n * Convenience methods for common HTTP verbs.\n *\n * These methods always require a schema for validation.\n * For raw responses without validation, use `$fetch` directly.\n *\n * @example\n * import { z } from \"zod\";\n * import { api } from \"@zap-studio/fetch\";\n *\n * const PostSchema = z.object({\n * id: z.number(),\n * title: z.string(),\n * content: z.string(),\n * });\n *\n * async function fetchPost(postId: number) {\n * const post = await api.get(`https://api.example.com/posts/${postId}`, PostSchema);\n * return post; // post is typed as { id: number; title: string; content: string; }\n * }\n */\nexport const api: ApiMethods = {\n get: createMethod($fetch, \"GET\"),\n post: createMethod($fetch, \"POST\"),\n put: createMethod($fetch, \"PUT\"),\n patch: createMethod($fetch, \"PATCH\"),\n delete: createMethod($fetch, \"DELETE\"),\n};\n\n/**\n * Creates a custom fetch instance with pre-configured defaults.\n *\n * Use this factory to create API clients with a base URL, default headers,\n * and other shared configuration. Each instance is independent.\n *\n * @example\n * import { z } from \"zod\";\n * import { createFetch } from \"@zap-studio/fetch\";\n *\n * // Create a configured instance\n * const { $fetch, api } = createFetch({\n * baseURL: \"https://api.example.com\",\n * headers: { \"Authorization\": \"Bearer token\" },\n * });\n *\n * const UserSchema = z.object({ id: z.number(), name: z.string() });\n *\n * // Now use relative paths - baseURL is prepended automatically\n * const user = await api.get(\"/users/1\", UserSchema);\n *\n * // Or use $fetch directly\n * const response = await $fetch(\"/users\", UserSchema, { method: \"POST\", body: { name: \"John\" } });\n */\nexport function createFetch(factoryOptions: CreateFetchOptions = {}): {\n $fetch: $Fetch;\n api: ApiMethods;\n} {\n const defaults: FetchDefaults = {\n baseURL: factoryOptions.baseURL ?? \"\",\n headers: factoryOptions.headers,\n searchParams: factoryOptions.searchParams,\n throwOnFetchError: factoryOptions.throwOnFetchError ?? true,\n throwOnValidationError: factoryOptions.throwOnValidationError ?? true,\n };\n\n async function customFetch<TSchema extends StandardSchemaV1>(\n resource: string,\n schema: TSchema,\n options: ExtendedRequestInit<false>\n ): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;\n\n async function customFetch<TSchema extends StandardSchemaV1>(\n resource: string,\n schema: TSchema,\n options?: ExtendedRequestInit<true | undefined>\n ): Promise<StandardSchemaV1.InferOutput<TSchema>>;\n\n async function customFetch(\n resource: string,\n options?: ExtendedRequestInit\n ): Promise<Response>;\n\n async function customFetch(\n resource: string,\n schemaOrOptions?: StandardSchemaV1 | ExtendedRequestInit,\n optionsOrUndefined?: ExtendedRequestInit\n ): Promise<unknown> {\n const [schema, options] = isStandardSchema(schemaOrOptions)\n ? [schemaOrOptions, optionsOrUndefined]\n : [undefined, schemaOrOptions];\n\n return await fetchInternal(resource, schema, options, defaults);\n }\n\n const customApi = {\n get: createMethod(customFetch, \"GET\"),\n post: createMethod(customFetch, \"POST\"),\n put: createMethod(customFetch, \"PUT\"),\n patch: createMethod(customFetch, \"PATCH\"),\n delete: createMethod(customFetch, \"DELETE\"),\n };\n\n return {\n $fetch: customFetch,\n api: customApi,\n };\n}\n"],"mappings":";;;;;AAiEA,eAAsB,OACpB,UACA,iBACA,oBACkB;CAClB,MAAM,CAAC,QAAQ,WAAW,iBAAiB,gBAAgB,GACvD,CAAC,iBAAiB,mBAAmB,GACrC,CAAC,QAAW,gBAAgB;AAEhC,QAAO,MAAM,cAAc,UAAU,QAAQ,SAAS,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;AAwBxE,MAAaA,MAAkB;CAC7B,KAAK,aAAa,QAAQ,MAAM;CAChC,MAAM,aAAa,QAAQ,OAAO;CAClC,KAAK,aAAa,QAAQ,MAAM;CAChC,OAAO,aAAa,QAAQ,QAAQ;CACpC,QAAQ,aAAa,QAAQ,SAAS;CACvC;;;;;;;;;;;;;;;;;;;;;;;;;AA0BD,SAAgB,YAAY,iBAAqC,EAAE,EAGjE;CACA,MAAMC,WAA0B;EAC9B,SAAS,eAAe,WAAW;EACnC,SAAS,eAAe;EACxB,cAAc,eAAe;EAC7B,mBAAmB,eAAe,qBAAqB;EACvD,wBAAwB,eAAe,0BAA0B;EAClE;CAmBD,eAAe,YACb,UACA,iBACA,oBACkB;EAClB,MAAM,CAAC,QAAQ,WAAW,iBAAiB,gBAAgB,GACvD,CAAC,iBAAiB,mBAAmB,GACrC,CAAC,QAAW,gBAAgB;AAEhC,SAAO,MAAM,cAAc,UAAU,QAAQ,SAAS,SAAS;;AAWjE,QAAO;EACL,QAAQ;EACR,KAVgB;GAChB,KAAK,aAAa,aAAa,MAAM;GACrC,MAAM,aAAa,aAAa,OAAO;GACvC,KAAK,aAAa,aAAa,MAAM;GACrC,OAAO,aAAa,aAAa,QAAQ;GACzC,QAAQ,aAAa,aAAa,SAAS;GAC5C;EAKA"}
@@ -127,4 +127,4 @@ type ApiMethods = {
127
127
  };
128
128
  //#endregion
129
129
  export { FetchDefaults as a, ExtendedRequestInit as i, ApiMethods as n, SearchParams as o, CreateFetchOptions as r, $Fetch as t };
130
- //# sourceMappingURL=types-CvCrPMIR.d.mts.map
130
+ //# sourceMappingURL=types-DjDYV3FA.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types-CvCrPMIR.d.mts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;;AAQA;AAEI;;;AAWK,KAbG,YAAA,GACR,eAYK,GAXL,MAWK,CAAA,MAAA,EAAA,MAAA,CAAA,GAAA,MAAA,GAAA,CAAA,MAAA,EAAA,MAAA,CAAA,EAAA;;;;AAgBT,KApBK,uBAAA,GAA0B,IAoBnB,CApBwB,WAoBxB,EAAA,MAAA,CAAA,GAAA;EAaZ;AA+BA;AAKA;EAQmB,IAAA,CAAA,EAzEV,QAyEU,GAzEC,MAyED,CAAA,MAAA,EAAA,OAAA,CAAA;EAEP;;;;EAEC,YAAA,CAAA,EAxEI,YAwEa;EAAzB;;;;EAaqC,iBAAA,CAAA,EAAA,OAAA;CAA7B;;;;AAQwC,KAlFzC,mBAkFyC,CAAA,gCAAA,OAAA,GAAA,SAAA,GAAA,OAAA,GAAA,SAAA,CAAA,GAhFjD,uBAgFiD,GAAA;EAAA;AAMrD;;;EAYO,sBAAA,CAAA,EA7FoB,uBA6FpB;CAIG;;;;KA3FE,aAAA;;;;;;;;;;YAUA;;;;;iBAKK;;;;;;;;;;;;;;;KAgBL,kBAAA,GAAqB,QAAQ;;;;KAK7B,MAAA;;;;;;;;mBAQO,4CAEP,kBACC,6BACR,QAAQ,gBAAA,CAAiB,OAAO,gBAAA,CAAiB,YAAY;;;;;;;;mBAS/C,4CAEP,mBACE,wCACT,QAAQ,gBAAA,CAAiB,YAAY;;;;;;;+BAQX,sBAAsB,QAAQ;;;;;KAMjD,UAAA;;;;OAIL;;;;QAIC;;;;OAID;;;;UAIG;;;;SAID"}
1
+ {"version":3,"file":"types-DjDYV3FA.d.mts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;;AAQA;AAEI;;;AAWK,KAbG,YAAA,GACR,eAYK,GAXL,MAWK,CAAA,MAAA,EAAA,MAAA,CAAA,GAAA,MAAA,GAAA,CAAA,MAAA,EAAA,MAAA,CAAA,EAAA;;;;AAgBT,KApBK,uBAAA,GAA0B,IAoBnB,CApBwB,WAoBxB,EAAA,MAAA,CAAA,GAAA;EAaZ;AA+BA;AAKA;EAQmB,IAAA,CAAA,EAzEV,QAyEU,GAzEC,MAyED,CAAA,MAAA,EAAA,OAAA,CAAA;EAEP;;;;EAEC,YAAA,CAAA,EAxEI,YAwEa;EAAzB;;;;EAaqC,iBAAA,CAAA,EAAA,OAAA;CAA7B;;;;AAQwC,KAlFzC,mBAkFyC,CAAA,gCAAA,OAAA,GAAA,SAAA,GAAA,OAAA,GAAA,SAAA,CAAA,GAhFjD,uBAgFiD,GAAA;EAAA;AAMrD;;;EAYO,sBAAA,CAAA,EA7FoB,uBA6FpB;CAIG;;;;KA3FE,aAAA;;;;;;;;;;YAUA;;;;;iBAKK;;;;;;;;;;;;;;;KAgBL,kBAAA,GAAqB,QAAQ;;;;KAK7B,MAAA;;;;;;;;mBAQO,4CAEP,kBACC,6BACR,QAAQ,gBAAA,CAAiB,OAAO,gBAAA,CAAiB,YAAY;;;;;;;;mBAS/C,4CAEP,mBACE,wCACT,QAAQ,gBAAA,CAAiB,YAAY;;;;;;;+BAQX,sBAAsB,QAAQ;;;;;KAMjD,UAAA;;;;OAIL;;;;QAIC;;;;OAID;;;;UAIG;;;;SAID"}
package/dist/types.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as FetchDefaults, i as ExtendedRequestInit, n as ApiMethods, o as SearchParams, r as CreateFetchOptions, t as $Fetch } from "./types-CvCrPMIR.mjs";
1
+ import { a as FetchDefaults, i as ExtendedRequestInit, n as ApiMethods, o as SearchParams, r as CreateFetchOptions, t as $Fetch } from "./types-DjDYV3FA.mjs";
2
2
  export { $Fetch, ApiMethods, CreateFetchOptions, ExtendedRequestInit, FetchDefaults, SearchParams };
@@ -0,0 +1,175 @@
1
+ import { t as FetchError } from "./errors-DgqwzMpH.mjs";
2
+ import { n as standardValidate, t as isStandardSchema } from "./validator-Cd9NivYJ.mjs";
3
+
4
+ //#region src/utils.ts
5
+ /**
6
+ * Merges two HeadersInit objects, with the second one taking precedence
7
+ *
8
+ * @example
9
+ * const baseHeaders = { "Authorization": "Bearer token", "Content-Type": "application/json" };
10
+ * const overrideHeaders = { "Content-Type": "application/xml", "X-Custom-Header": "value" };
11
+ *
12
+ * const merged = mergeHeaders(baseHeaders, overrideHeaders);
13
+ *
14
+ * // Resulting headers:
15
+ * // {
16
+ * // "Authorization": "Bearer token",
17
+ * // "Content-Type": "application/xml",
18
+ * // "X-Custom-Header": "value"
19
+ * // }
20
+ */
21
+ function mergeHeaders(base, override) {
22
+ if (!(base || override)) return;
23
+ const merged = new Headers(base);
24
+ if (override) {
25
+ const overrideHeaders = new Headers(override);
26
+ for (const [key, value] of overrideHeaders.entries()) merged.set(key, value);
27
+ }
28
+ return merged;
29
+ }
30
+ /**
31
+ * Removes trailing slashes from a string
32
+ */
33
+ function trimTrailingSlashes(str) {
34
+ let end = str.length;
35
+ while (end > 0 && str[end - 1] === "/") end -= 1;
36
+ return str.slice(0, end);
37
+ }
38
+ /**
39
+ * Removes leading slashes from a string
40
+ */
41
+ function trimLeadingSlashes(str) {
42
+ let start = 0;
43
+ while (start < str.length && str[start] === "/") start += 1;
44
+ return str.slice(start);
45
+ }
46
+ const ABSOLUTE_URL_PATTERN = /^(?:https?:)?\/\//i;
47
+ /**
48
+ * Checks if a URL is absolute (starts with http://, https://, or //)
49
+ */
50
+ function isAbsoluteURL(url) {
51
+ return ABSOLUTE_URL_PATTERN.test(url);
52
+ }
53
+ /**
54
+ * Normalizes search parameters into a URLSearchParams object.
55
+ */
56
+ function normalizeSearchParams(input) {
57
+ if (input === void 0 || input === null) return new URLSearchParams();
58
+ if (input instanceof URLSearchParams) return new URLSearchParams(input);
59
+ if (typeof input === "string") return new URLSearchParams(input);
60
+ if (Array.isArray(input)) return new URLSearchParams(input);
61
+ const params = new URLSearchParams();
62
+ for (const [k, v] of Object.entries(input)) params.set(k, v);
63
+ return params;
64
+ }
65
+ /**
66
+ * Parses a URL string into its path, query, and hash components.
67
+ * Handles both absolute URLs (using URL constructor) and relative paths.
68
+ */
69
+ function parseUrlComponents(url) {
70
+ if (isAbsoluteURL(url)) try {
71
+ const parsed = new URL(url);
72
+ const pathOnly = `${parsed.origin}${parsed.pathname}`;
73
+ const existingQuery = parsed.search.startsWith("?") ? parsed.search.slice(1) : parsed.search;
74
+ let hash$1 = parsed.hash;
75
+ if (hash$1 === "" && url.endsWith("#")) hash$1 = "#";
76
+ return {
77
+ pathOnly,
78
+ existingQuery,
79
+ hash: hash$1
80
+ };
81
+ } catch {}
82
+ let hash = "";
83
+ let urlWithoutHash = url;
84
+ const hashIndex = url.indexOf("#");
85
+ if (hashIndex !== -1) {
86
+ hash = url.slice(hashIndex);
87
+ urlWithoutHash = url.slice(0, hashIndex);
88
+ }
89
+ const queryIndex = urlWithoutHash.indexOf("?");
90
+ if (queryIndex === -1) return {
91
+ pathOnly: urlWithoutHash,
92
+ existingQuery: "",
93
+ hash
94
+ };
95
+ return {
96
+ pathOnly: urlWithoutHash.slice(0, queryIndex),
97
+ existingQuery: urlWithoutHash.slice(queryIndex + 1),
98
+ hash
99
+ };
100
+ }
101
+ /**
102
+ * Builds a URL with merged search parameters from factory defaults,
103
+ * request options, and existing query parameters.
104
+ *
105
+ * This function takes a base URL, factory search parameters,
106
+ * and request search parameters, and combines them into a single URL.
107
+ *
108
+ * Priority (highest to lowest):
109
+ * 1. Request search parameters (highest priority, overwrites all others)
110
+ * 2. Existing query parameters from the URL (overwrites factory defaults)
111
+ * 3. Factory search parameters (lowest priority, overwritten by all others)
112
+ *
113
+ * If no search parameters are provided, the URL will not have a query string.
114
+ * Any trailing hash/fragment is preserved.
115
+ */
116
+ function buildUrlWithMergedSearchParams(url, factorySearch, requestSearch) {
117
+ const { pathOnly, existingQuery, hash } = parseUrlComponents(url);
118
+ if (!(factorySearch ?? requestSearch ?? existingQuery)) return url;
119
+ const mergedParams = new URLSearchParams();
120
+ const resourceParams = new URLSearchParams(existingQuery);
121
+ const factoryParams = normalizeSearchParams(factorySearch);
122
+ const reqParams = normalizeSearchParams(requestSearch);
123
+ for (const [k, v] of factoryParams.entries()) mergedParams.set(k, v);
124
+ for (const [k, v] of resourceParams.entries()) mergedParams.set(k, v);
125
+ for (const [k, v] of reqParams.entries()) mergedParams.set(k, v);
126
+ const queryString = mergedParams.toString();
127
+ if (queryString) return `${pathOnly}?${queryString}${hash}`;
128
+ return `${pathOnly}${hash}`;
129
+ }
130
+ /**
131
+ * Internal fetch implementation used by both $fetch and createFetch
132
+ */
133
+ async function fetchInternal(resource, schema, options, defaults) {
134
+ const { throwOnValidationError = defaults.throwOnValidationError, throwOnFetchError = defaults.throwOnFetchError, headers: requestHeaders, searchParams: requestSearchParams, ...rest } = options || {};
135
+ const mergedHeaders = mergeHeaders(defaults.headers, requestHeaders);
136
+ const init = {
137
+ ...rest,
138
+ headers: mergedHeaders
139
+ };
140
+ if (schema && init.body) {
141
+ init.body = JSON.stringify(init.body);
142
+ const existingHeaders = new Headers(init.headers);
143
+ if (!existingHeaders.has("Content-Type")) existingHeaders.set("Content-Type", "application/json");
144
+ init.headers = existingHeaders;
145
+ }
146
+ let url;
147
+ if (isAbsoluteURL(resource)) url = resource;
148
+ else {
149
+ const base = trimTrailingSlashes(defaults.baseURL);
150
+ const path = trimLeadingSlashes(resource);
151
+ url = base ? `${base}/${path}` : resource;
152
+ }
153
+ url = buildUrlWithMergedSearchParams(url, defaults.searchParams, requestSearchParams);
154
+ const response = await fetch(url, init);
155
+ if (throwOnFetchError && !response.ok) throw new FetchError(`HTTP ${response.status}: ${response.statusText}`, response);
156
+ if (schema) return standardValidate(schema, await response.json(), throwOnValidationError);
157
+ return response;
158
+ }
159
+ /**
160
+ * Creates an HTTP method helper bound to a fetch function
161
+ */
162
+ function createMethod(fetchFn, method) {
163
+ function methodFetch(resource, schemaOrOptions, optionsOrUndefined) {
164
+ const [schema, options] = isStandardSchema(schemaOrOptions) ? [schemaOrOptions, optionsOrUndefined] : [void 0, schemaOrOptions];
165
+ return fetchFn(resource, schema, {
166
+ ...options,
167
+ method
168
+ });
169
+ }
170
+ return methodFetch;
171
+ }
172
+
173
+ //#endregion
174
+ export { fetchInternal as n, mergeHeaders as r, createMethod as t };
175
+ //# sourceMappingURL=utils-Cslywt8D.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils-Cslywt8D.mjs","names":["hash","url: string"],"sources":["../src/utils.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { FetchError } from \"./errors\";\nimport type {\n $Fetch,\n ExtendedRequestInit,\n FetchDefaults,\n SearchParams,\n} from \"./types\";\nimport { isStandardSchema, standardValidate } from \"./validator\";\n\n/**\n * Merges two HeadersInit objects, with the second one taking precedence\n *\n * @example\n * const baseHeaders = { \"Authorization\": \"Bearer token\", \"Content-Type\": \"application/json\" };\n * const overrideHeaders = { \"Content-Type\": \"application/xml\", \"X-Custom-Header\": \"value\" };\n *\n * const merged = mergeHeaders(baseHeaders, overrideHeaders);\n *\n * // Resulting headers:\n * // {\n * // \"Authorization\": \"Bearer token\",\n * // \"Content-Type\": \"application/xml\",\n * // \"X-Custom-Header\": \"value\"\n * // }\n */\nexport function mergeHeaders(\n base: HeadersInit | undefined,\n override: HeadersInit | undefined\n): 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\n/**\n * Removes trailing slashes from a string\n */\nfunction trimTrailingSlashes(str: string): string {\n let end = str.length;\n while (end > 0 && str[end - 1] === \"/\") {\n end -= 1;\n }\n return str.slice(0, end);\n}\n\n/**\n * Removes leading slashes from a string\n */\nfunction trimLeadingSlashes(str: string): string {\n let start = 0;\n while (start < str.length && str[start] === \"/\") {\n start += 1;\n }\n return str.slice(start);\n}\n\nconst ABSOLUTE_URL_PATTERN = /^(?:https?:)?\\/\\//i;\n\n/**\n * Checks if a URL is absolute (starts with http://, https://, or //)\n */\nfunction isAbsoluteURL(url: string): boolean {\n return ABSOLUTE_URL_PATTERN.test(url);\n}\n\n/**\n * Normalizes search parameters into a URLSearchParams object.\n */\nfunction normalizeSearchParams(\n input: SearchParams | undefined\n): URLSearchParams {\n if (input === undefined || input === null) {\n return new URLSearchParams();\n }\n\n if (input instanceof URLSearchParams) {\n return new URLSearchParams(input);\n }\n\n if (typeof input === \"string\") {\n return new URLSearchParams(input);\n }\n\n if (Array.isArray(input)) {\n return new URLSearchParams(input);\n }\n\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(input)) {\n params.set(k, v);\n }\n\n return params;\n}\n\n/**\n * Parses a URL string into its path, query, and hash components.\n * Handles both absolute URLs (using URL constructor) and relative paths.\n */\nfunction parseUrlComponents(url: string): {\n pathOnly: string;\n existingQuery: string;\n hash: string;\n} {\n // Try parsing as absolute URL first\n if (isAbsoluteURL(url)) {\n try {\n const parsed = new URL(url);\n const pathOnly = `${parsed.origin}${parsed.pathname}`;\n // parsed.search includes the leading \"?\", so strip it\n const existingQuery = parsed.search.startsWith(\"?\")\n ? parsed.search.slice(1)\n : parsed.search;\n // URL constructor normalizes away empty hash, if original URL had # at end, preserve it\n let hash = parsed.hash;\n if (hash === \"\" && url.endsWith(\"#\")) {\n hash = \"#\";\n }\n return { pathOnly, existingQuery, hash };\n } catch {\n // Fall through to manual parsing if URL constructor fails\n }\n }\n\n // Manual parsing for relative URLs or if URL constructor failed\n let hash = \"\";\n let urlWithoutHash = url;\n const hashIndex = url.indexOf(\"#\");\n if (hashIndex !== -1) {\n hash = url.slice(hashIndex);\n urlWithoutHash = url.slice(0, hashIndex);\n }\n\n // Find the first \"?\" to split path and query\n const queryIndex = urlWithoutHash.indexOf(\"?\");\n if (queryIndex === -1) {\n return { pathOnly: urlWithoutHash, existingQuery: \"\", hash };\n }\n\n const pathOnly = urlWithoutHash.slice(0, queryIndex);\n const existingQuery = urlWithoutHash.slice(queryIndex + 1);\n return { pathOnly, existingQuery, hash };\n}\n\n/**\n * Builds a URL with merged search parameters from factory defaults,\n * request options, and existing query parameters.\n *\n * This function takes a base URL, factory search parameters,\n * and request search parameters, and combines them into a single URL.\n *\n * Priority (highest to lowest):\n * 1. Request search parameters (highest priority, overwrites all others)\n * 2. Existing query parameters from the URL (overwrites factory defaults)\n * 3. Factory search parameters (lowest priority, overwritten by all others)\n *\n * If no search parameters are provided, the URL will not have a query string.\n * Any trailing hash/fragment is preserved.\n */\nfunction buildUrlWithMergedSearchParams(\n url: string,\n factorySearch: FetchDefaults[\"searchParams\"] | undefined,\n requestSearch: ExtendedRequestInit[\"searchParams\"] | undefined\n): string {\n const { pathOnly, existingQuery, hash } = parseUrlComponents(url);\n\n // Early return if no search params to merge\n const hasSearchParams = factorySearch ?? requestSearch ?? existingQuery;\n if (!hasSearchParams) {\n return url;\n }\n\n const mergedParams = new URLSearchParams();\n\n const resourceParams = new URLSearchParams(existingQuery);\n const factoryParams = normalizeSearchParams(factorySearch);\n const reqParams = normalizeSearchParams(requestSearch);\n\n for (const [k, v] of factoryParams.entries()) {\n mergedParams.set(k, v);\n }\n\n for (const [k, v] of resourceParams.entries()) {\n mergedParams.set(k, v);\n }\n\n for (const [k, v] of reqParams.entries()) {\n mergedParams.set(k, v);\n }\n\n const queryString = mergedParams.toString();\n if (queryString) {\n return `${pathOnly}?${queryString}${hash}`;\n }\n\n return `${pathOnly}${hash}`;\n}\n\n/**\n * Internal fetch implementation used by both $fetch and createFetch\n */\nexport async function fetchInternal(\n resource: string,\n schema: StandardSchemaV1 | undefined,\n options: ExtendedRequestInit | undefined,\n defaults: FetchDefaults\n): Promise<unknown> {\n const {\n throwOnValidationError = defaults.throwOnValidationError,\n throwOnFetchError = defaults.throwOnFetchError,\n headers: requestHeaders,\n searchParams: requestSearchParams,\n ...rest\n } = options || {};\n\n const mergedHeaders = mergeHeaders(defaults.headers, requestHeaders);\n const init = { ...rest, headers: mergedHeaders } as RequestInit;\n\n // Auto-stringify body and set default Content-Type if we have a schema\n if (schema && init.body) {\n init.body = JSON.stringify(init.body);\n\n const existingHeaders = new Headers(init.headers);\n if (!existingHeaders.has(\"Content-Type\")) {\n existingHeaders.set(\"Content-Type\", \"application/json\");\n }\n\n init.headers = existingHeaders;\n }\n\n // For absolute URLs, ignore baseURL entirely\n let url: string;\n if (isAbsoluteURL(resource)) {\n url = resource;\n } else {\n // Normalize URL by avoiding double slashes between baseURL and resource\n const base = trimTrailingSlashes(defaults.baseURL);\n const path = trimLeadingSlashes(resource);\n url = base ? `${base}/${path}` : resource;\n }\n\n // Merge query/search params\n url = buildUrlWithMergedSearchParams(\n url,\n defaults.searchParams,\n requestSearchParams\n );\n\n const response = await fetch(url, init);\n\n if (throwOnFetchError && !response.ok) {\n throw new FetchError(\n `HTTP ${response.status}: ${response.statusText}`,\n response\n );\n }\n\n // For json with schema, validate\n if (schema) {\n const raw = await response.json();\n return standardValidate(schema, raw, throwOnValidationError);\n }\n\n // No validation, return raw response data\n return response;\n}\n\n/**\n * Creates an HTTP method helper bound to a fetch function\n */\nexport function createMethod<TFetch extends $Fetch>(\n fetchFn: TFetch,\n method: string\n): $Fetch {\n function methodFetch<TSchema extends StandardSchemaV1>(\n resource: string,\n schema: TSchema,\n options: Omit<ExtendedRequestInit<false>, \"method\">\n ): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;\n\n function methodFetch<TSchema extends StandardSchemaV1>(\n resource: string,\n schema: TSchema,\n options?: Omit<ExtendedRequestInit<true | undefined>, \"method\">\n ): Promise<StandardSchemaV1.InferOutput<TSchema>>;\n\n function methodFetch(\n resource: string,\n options?: Omit<ExtendedRequestInit, \"method\">\n ): Promise<Response>;\n\n function methodFetch(\n resource: string,\n schemaOrOptions?: StandardSchemaV1 | Omit<ExtendedRequestInit, \"method\">,\n optionsOrUndefined?: Omit<ExtendedRequestInit, \"method\">\n ): Promise<unknown> {\n const [schema, options] = isStandardSchema(schemaOrOptions)\n ? [schemaOrOptions, optionsOrUndefined]\n : [undefined, schemaOrOptions];\n\n return (fetchFn as (...args: unknown[]) => Promise<unknown>)(\n resource,\n schema,\n { ...options, method }\n );\n }\n\n return methodFetch;\n}\n"],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { a as FetchDefaults, i as ExtendedRequestInit, t as $Fetch } from "./types-DjDYV3FA.mjs";
2
+ import { StandardSchemaV1 } from "@standard-schema/spec";
3
+
4
+ //#region src/utils.d.ts
5
+
6
+ /**
7
+ * Merges two HeadersInit objects, with the second one taking precedence
8
+ *
9
+ * @example
10
+ * const baseHeaders = { "Authorization": "Bearer token", "Content-Type": "application/json" };
11
+ * const overrideHeaders = { "Content-Type": "application/xml", "X-Custom-Header": "value" };
12
+ *
13
+ * const merged = mergeHeaders(baseHeaders, overrideHeaders);
14
+ *
15
+ * // Resulting headers:
16
+ * // {
17
+ * // "Authorization": "Bearer token",
18
+ * // "Content-Type": "application/xml",
19
+ * // "X-Custom-Header": "value"
20
+ * // }
21
+ */
22
+ declare function mergeHeaders(base: HeadersInit | undefined, override: HeadersInit | undefined): Headers | undefined;
23
+ /**
24
+ * Internal fetch implementation used by both $fetch and createFetch
25
+ */
26
+ declare function fetchInternal(resource: string, schema: StandardSchemaV1 | undefined, options: ExtendedRequestInit | undefined, defaults: FetchDefaults): Promise<unknown>;
27
+ /**
28
+ * Creates an HTTP method helper bound to a fetch function
29
+ */
30
+ declare function createMethod<TFetch extends $Fetch>(fetchFn: TFetch, method: string): $Fetch;
31
+ //#endregion
32
+ export { createMethod, fetchInternal, mergeHeaders };
33
+ //# sourceMappingURL=utils.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.mts","names":[],"sources":["../src/utils.ts"],"sourcesContent":[],"mappings":";;;;;;;AA0BA;;;;;AAyLA;;;;;;AAqEA;;;AAGG,iBAjQa,YAAA,CAiQb,IAAA,EAhQK,WAgQL,GAAA,SAAA,EAAA,QAAA,EA/PS,WA+PT,GAAA,SAAA,CAAA,EA9PA,OA8PA,GAAA,SAAA;;;;iBAxEmB,aAAA,2BAEZ,uCACC,2CACC,gBACT;;;;iBAgEa,4BAA4B,iBACjC,yBAER"}
package/dist/utils.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import { n as fetchInternal, r as mergeHeaders, t as createMethod } from "./utils-Cslywt8D.mjs";
2
+
3
+ export { createMethod, fetchInternal, mergeHeaders };
@@ -1,4 +1,4 @@
1
- import { n as ValidationError } from "./errors-DKxnbFHZ.mjs";
1
+ import { n as ValidationError } from "./errors-DgqwzMpH.mjs";
2
2
 
3
3
  //#region src/validator.ts
4
4
  /**
@@ -41,4 +41,4 @@ async function standardValidate(schema, input, throwOnError) {
41
41
 
42
42
  //#endregion
43
43
  export { standardValidate as n, isStandardSchema as t };
44
- //# sourceMappingURL=validator-BGjWrM4d.mjs.map
44
+ //# sourceMappingURL=validator-Cd9NivYJ.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"validator-BGjWrM4d.mjs","names":[],"sources":["../src/validator.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { ValidationError } from \"./errors\";\n\n/**\n * Type guard to check if a value is a Standard Schema schema\n */\nexport function isStandardSchema(value: unknown): value is StandardSchemaV1 {\n return (\n !!value &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n \"~standard\" in value\n );\n}\n\n/**\n * Helper function to validate data using Standard Schema\n *\n * @throws {ValidationError} When `throwOnError` is true and validation fails\n *\n * @example\n * import { standardValidate } from \"@zap-studio/fetch/validator\";\n * import { z } from \"zod\";\n *\n * const UserSchema = z.object({ id: z.number(), name: z.string() });\n *\n * // Basic usage\n * const user = await standardValidate(UserSchema, data);\n *\n * // Non-throwing usage\n * const result = await standardValidate(UserSchema, data, false);\n * if (result.issues) {\n * console.error(\"Validation failed:\", result.issues);\n * } else {\n * console.log(\"Success:\", result.value);\n * }\n */\nexport async function standardValidate<TSchema extends StandardSchemaV1>(\n schema: TSchema,\n input: unknown,\n throwOnError: boolean\n): Promise<\n | StandardSchemaV1.InferOutput<TSchema>\n | StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>\n> {\n let result = schema[\"~standard\"].validate(input);\n if (result instanceof Promise) {\n result = await result;\n }\n\n if (result.issues) {\n if (throwOnError) {\n throw new ValidationError([...result.issues]);\n }\n return result;\n }\n\n return throwOnError ? result.value : result;\n}\n"],"mappings":";;;;;;AAMA,SAAgB,iBAAiB,OAA2C;AAC1E,QACE,CAAC,CAAC,UACD,OAAO,UAAU,YAAY,OAAO,UAAU,eAC/C,eAAe;;;;;;;;;;;;;;;;;;;;;;;;AA0BnB,eAAsB,iBACpB,QACA,OACA,cAIA;CACA,IAAI,SAAS,OAAO,aAAa,SAAS,MAAM;AAChD,KAAI,kBAAkB,QACpB,UAAS,MAAM;AAGjB,KAAI,OAAO,QAAQ;AACjB,MAAI,aACF,OAAM,IAAI,gBAAgB,CAAC,GAAG,OAAO,OAAO,CAAC;AAE/C,SAAO;;AAGT,QAAO,eAAe,OAAO,QAAQ"}
1
+ {"version":3,"file":"validator-Cd9NivYJ.mjs","names":[],"sources":["../src/validator.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { ValidationError } from \"./errors\";\n\n/**\n * Type guard to check if a value is a Standard Schema schema\n */\nexport function isStandardSchema(value: unknown): value is StandardSchemaV1 {\n return (\n !!value &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n \"~standard\" in value\n );\n}\n\n/**\n * Helper function to validate data using Standard Schema\n *\n * @throws {ValidationError} When `throwOnError` is true and validation fails\n *\n * @example\n * import { standardValidate } from \"@zap-studio/fetch/validator\";\n * import { z } from \"zod\";\n *\n * const UserSchema = z.object({ id: z.number(), name: z.string() });\n *\n * // Basic usage\n * const user = await standardValidate(UserSchema, data);\n *\n * // Non-throwing usage\n * const result = await standardValidate(UserSchema, data, false);\n * if (result.issues) {\n * console.error(\"Validation failed:\", result.issues);\n * } else {\n * console.log(\"Success:\", result.value);\n * }\n */\nexport async function standardValidate<TSchema extends StandardSchemaV1>(\n schema: TSchema,\n input: unknown,\n throwOnError: boolean\n): Promise<\n | StandardSchemaV1.InferOutput<TSchema>\n | StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>\n> {\n let result = schema[\"~standard\"].validate(input);\n if (result instanceof Promise) {\n result = await result;\n }\n\n if (result.issues) {\n if (throwOnError) {\n throw new ValidationError([...result.issues]);\n }\n return result;\n }\n\n return throwOnError ? result.value : result;\n}\n"],"mappings":";;;;;;AAMA,SAAgB,iBAAiB,OAA2C;AAC1E,QACE,CAAC,CAAC,UACD,OAAO,UAAU,YAAY,OAAO,UAAU,eAC/C,eAAe;;;;;;;;;;;;;;;;;;;;;;;;AA0BnB,eAAsB,iBACpB,QACA,OACA,cAIA;CACA,IAAI,SAAS,OAAO,aAAa,SAAS,MAAM;AAChD,KAAI,kBAAkB,QACpB,UAAS,MAAM;AAGjB,KAAI,OAAO,QAAQ;AACjB,MAAI,aACF,OAAM,IAAI,gBAAgB,CAAC,GAAG,OAAO,OAAO,CAAC;AAE/C,SAAO;;AAGT,QAAO,eAAe,OAAO,QAAQ"}
@@ -1,3 +1,3 @@
1
- import { n as standardValidate, t as isStandardSchema } from "./validator-BGjWrM4d.mjs";
1
+ import { n as standardValidate, t as isStandardSchema } from "./validator-Cd9NivYJ.mjs";
2
2
 
3
3
  export { isStandardSchema, standardValidate };
package/package.json CHANGED
@@ -1,38 +1,64 @@
1
1
  {
2
2
  "name": "@zap-studio/fetch",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "private": false,
7
+ "homepage": "https://www.zapstudio.dev/packages/fetch",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/zap-studio/monorepo.git",
11
+ "directory": "packages/fetch"
12
+ },
13
+ "description": "A type-safe fetch wrapper for HTTP requests with runtime schema validation.",
14
+ "keywords": [
15
+ "fetch",
16
+ "type-safe",
17
+ "validation",
18
+ "schema",
19
+ "typescript",
20
+ "http",
21
+ "api",
22
+ "zod",
23
+ "valibot",
24
+ "arktype",
25
+ "runtime validation",
26
+ "error handling",
27
+ "standard schema",
28
+ "request",
29
+ "response"
30
+ ],
7
31
  "publishConfig": {
8
32
  "access": "public"
9
33
  },
10
34
  "files": [
11
35
  "dist",
12
- "README.md",
13
- "CHANGELOG.md"
36
+ "CHANGELOG.md",
37
+ "LICENSE.md",
38
+ "README.md"
14
39
  ],
15
40
  "dependencies": {
16
41
  "@standard-schema/spec": "^1.0.0"
17
42
  },
18
43
  "devDependencies": {
19
- "@types/node": "^24.10.1",
44
+ "@types/node": "^25.0.2",
20
45
  "@vitest/coverage-v8": "^4.0.15",
21
- "arktype": "^2.1.28",
22
- "jsdom": "^27.2.0",
23
- "tsdown": "0.17.0-beta.6",
46
+ "arktype": "^2.1.29",
47
+ "tsdown": "^0.18.0",
24
48
  "typescript": "^5.9.3",
25
49
  "valibot": "^1.2.0",
26
50
  "vitest": "^4.0.15",
27
- "zod": "^4.1.13",
51
+ "zod": "^4.2.0",
28
52
  "@zap-studio/tsdown-config": "0.0.0",
29
53
  "@zap-studio/typescript-config": "0.0.0",
30
54
  "@zap-studio/vitest-config": "0.0.0"
31
55
  },
32
56
  "exports": {
33
57
  ".": "./dist/index.mjs",
58
+ "./constants": "./dist/constants.mjs",
34
59
  "./errors": "./dist/errors.mjs",
35
60
  "./types": "./dist/types.mjs",
61
+ "./utils": "./dist/utils.mjs",
36
62
  "./validator": "./dist/validator.mjs",
37
63
  "./package.json": "./package.json"
38
64
  },
@@ -41,7 +67,7 @@
41
67
  "types": "./dist/index.d.mts",
42
68
  "scripts": {
43
69
  "build": "tsdown --config tsdown.config.ts",
44
- "check-types": "tsc --noEmit",
70
+ "check": "tsc --noEmit",
45
71
  "test": "vitest run",
46
72
  "test:watch": "vitest --watch"
47
73
  }
File without changes