@zap-studio/fetch 0.2.0 → 0.2.2
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 +12 -0
- package/dist/errors.d.mts +4 -4
- package/dist/errors.d.mts.map +1 -1
- package/dist/index.d.mts +82 -88
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +19 -5
- package/dist/index.mjs.map +1 -1
- package/dist/types-BB4ejGeA.d.mts +100 -0
- package/dist/types-BB4ejGeA.d.mts.map +1 -0
- package/dist/types.d.mts +2 -2
- package/dist/validator.d.mts +23 -23
- package/dist/validator.d.mts.map +1 -1
- package/package.json +4 -3
- package/dist/types-C0Uhh2KM.d.mts +0 -52
- package/dist/types-C0Uhh2KM.d.mts.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @zap-studio/fetch
|
|
2
2
|
|
|
3
|
+
## 0.2.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 5c3abbf: Prepare JSR publish and isolatedDeclarations support with new explicit types for `$Fetch` and `ApiMethods`
|
|
8
|
+
|
|
9
|
+
## 0.2.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 82bac5c: Replace regex-based slash trimming with more efficient string manipulation functions for URL normalization
|
|
14
|
+
|
|
3
15
|
## 0.2.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/dist/errors.d.mts
CHANGED
|
@@ -3,16 +3,16 @@ import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
|
3
3
|
//#region src/errors.d.ts
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
* Error thrown for HTTP errors (non-2xx responses)
|
|
7
|
+
*/
|
|
8
8
|
declare class FetchError extends Error {
|
|
9
9
|
status: Response["status"];
|
|
10
10
|
response: Response;
|
|
11
11
|
constructor(message: string, response: Response);
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
* Error thrown for validation errors
|
|
15
|
+
*/
|
|
16
16
|
declare class ValidationError extends Error {
|
|
17
17
|
issues: StandardSchemaV1.Issue[];
|
|
18
18
|
constructor(issues: StandardSchemaV1.Issue[]);
|
package/dist/errors.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.mts","names":[],"sources":["../src/errors.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;AACU,cADG,UAAA,SAAmB,KAAA,CACtB;EACE,MAAA,EADF,QACE,CAAA,QAAA,CAAA;EAE6B,QAAA,EAF7B,QAE6B;EAJT,WAAA,CAAA,OAAA,EAAA,MAAA,EAAA,QAAA,EAIS,QAJT;;AAehC;;;AAAqC,cAAxB,eAAA,SAAwB,KAAA,CAAA;
|
|
1
|
+
{"version":3,"file":"errors.d.mts","names":[],"sources":["../src/errors.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;AACU,cADG,UAAA,SAAmB,KAAA,CACtB;EACE,MAAA,EADF,QACE,CAAA,QAAA,CAAA;EAE6B,QAAA,EAF7B,QAE6B;EAJT,WAAA,CAAA,OAAA,EAAA,MAAA,EAAA,QAAA,EAIS,QAJT;;AAehC;;;AAAqC,cAAxB,eAAA,SAAwB,KAAA,CAAA;EAAA,MAAA,EAC3B,gBAAA,CAAiB,KADU,EAAA;sBAGf,gBAAA,CAAiB"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,101 +1,95 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as ExtendedRequestInit, n as ApiMethods, r as CreateFetchOptions, t as $Fetch } from "./types-BB4ejGeA.mjs";
|
|
2
2
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
3
|
|
|
4
4
|
//#region src/index.d.ts
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
7
|
+
* Type-safe fetch wrapper with Standard Schema validation.
|
|
8
|
+
*
|
|
9
|
+
* - When `throwOnValidationError: true`: validated data of type `TSchema`
|
|
10
|
+
* - When `throwOnValidationError: false`: Standard Schema Result object `{ value?, issues? }`
|
|
11
|
+
* - When `throwOnFetchError: true`: throws `FetchError` on non-ok responses
|
|
12
|
+
*
|
|
13
|
+
* If no schema is provided, returns the raw `Response` object.
|
|
14
|
+
*
|
|
15
|
+
* @throws {FetchError} When `throwOnFetchError: true` and response is not ok
|
|
16
|
+
* @throws {ValidationError} When `throwOnValidationError: true` and validation fails
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* import { z } from "zod";
|
|
20
|
+
* import { $fetch } from "@zap-studio/fetch";
|
|
21
|
+
*
|
|
22
|
+
* const UserSchema = z.object({ id: z.number(), name: z.string() });
|
|
23
|
+
*
|
|
24
|
+
* // Basic usage (schema validation)
|
|
25
|
+
* const user = await $fetch("/api/users/1", UserSchema, { headers: { "Authorization": "Bearer token" } });
|
|
26
|
+
* console.log("Validated user:", user);
|
|
27
|
+
*
|
|
28
|
+
* // Raw usage (no schema validation and typed Response object)
|
|
29
|
+
* const result = await $fetch("/api/data", { method: "POST", body: JSON.stringify({ key: "value" }) });
|
|
30
|
+
* const json = await result.json() as ResultType;
|
|
31
|
+
* console.log("Raw response data:", json);
|
|
32
|
+
*
|
|
33
|
+
* // Usage with validation errors returned instead of thrown
|
|
34
|
+
* const result = await $fetch("/api/users/1", UserSchema, { throwOnValidationError: false });
|
|
35
|
+
*
|
|
36
|
+
* if (result.issues) {
|
|
37
|
+
* console.error("Validation errors:", result.issues);
|
|
38
|
+
* } else {
|
|
39
|
+
* console.log("Validated user:", result.value);
|
|
40
|
+
* }
|
|
41
|
+
*/
|
|
42
42
|
declare function $fetch<TSchema extends StandardSchemaV1>(resource: string, schema: TSchema, options?: ExtendedRequestInit): Promise<StandardSchemaV1.InferOutput<TSchema> | StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;
|
|
43
43
|
declare function $fetch(resource: string, options?: ExtendedRequestInit): Promise<Response>;
|
|
44
44
|
/**
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
declare const api:
|
|
66
|
-
get: <TSchema extends StandardSchemaV1>(resource: string, schema: TSchema, options?: Omit<ExtendedRequestInit, "method">) => Promise<StandardSchemaV1.InferOutput<TSchema> | StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;
|
|
67
|
-
post: <TSchema extends StandardSchemaV1>(resource: string, schema: TSchema, options?: Omit<ExtendedRequestInit, "method">) => Promise<StandardSchemaV1.InferOutput<TSchema> | StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;
|
|
68
|
-
put: <TSchema extends StandardSchemaV1>(resource: string, schema: TSchema, options?: Omit<ExtendedRequestInit, "method">) => Promise<StandardSchemaV1.InferOutput<TSchema> | StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;
|
|
69
|
-
patch: <TSchema extends StandardSchemaV1>(resource: string, schema: TSchema, options?: Omit<ExtendedRequestInit, "method">) => Promise<StandardSchemaV1.InferOutput<TSchema> | StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;
|
|
70
|
-
delete: <TSchema extends StandardSchemaV1>(resource: string, schema: TSchema, options?: Omit<ExtendedRequestInit, "method">) => Promise<StandardSchemaV1.InferOutput<TSchema> | StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;
|
|
71
|
-
};
|
|
45
|
+
* Convenience methods for common HTTP verbs.
|
|
46
|
+
*
|
|
47
|
+
* These methods always require a schema for validation.
|
|
48
|
+
* For raw responses without validation, use `$fetch` directly.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* import { z } from "zod";
|
|
52
|
+
* import { api } from "@zap-studio/fetch";
|
|
53
|
+
*
|
|
54
|
+
* const PostSchema = z.object({
|
|
55
|
+
* id: z.number(),
|
|
56
|
+
* title: z.string(),
|
|
57
|
+
* content: z.string(),
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* async function fetchPost(postId: number) {
|
|
61
|
+
* const post = await api.get(`https://api.example.com/posts/${postId}`, PostSchema);
|
|
62
|
+
* return post; // post is typed as { id: number; title: string; content: string; }
|
|
63
|
+
* }
|
|
64
|
+
*/
|
|
65
|
+
declare const api: ApiMethods;
|
|
72
66
|
/**
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
67
|
+
* Creates a custom fetch instance with pre-configured defaults.
|
|
68
|
+
*
|
|
69
|
+
* Use this factory to create API clients with a base URL, default headers,
|
|
70
|
+
* and other shared configuration. Each instance is independent.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* import { z } from "zod";
|
|
74
|
+
* import { createFetch } from "@zap-studio/fetch";
|
|
75
|
+
*
|
|
76
|
+
* // Create a configured instance
|
|
77
|
+
* const { $fetch, api } = createFetch({
|
|
78
|
+
* baseURL: "https://api.example.com",
|
|
79
|
+
* headers: { "Authorization": "Bearer token" },
|
|
80
|
+
* });
|
|
81
|
+
*
|
|
82
|
+
* const UserSchema = z.object({ id: z.number(), name: z.string() });
|
|
83
|
+
*
|
|
84
|
+
* // Now use relative paths - baseURL is prepended automatically
|
|
85
|
+
* const user = await api.get("/users/1", UserSchema);
|
|
86
|
+
*
|
|
87
|
+
* // Or use $fetch directly
|
|
88
|
+
* const response = await $fetch("/users", UserSchema, { method: "POST", body: { name: "John" } });
|
|
89
|
+
*/
|
|
96
90
|
declare function createFetch(factoryOptions?: CreateFetchOptions): {
|
|
97
|
-
$fetch:
|
|
98
|
-
api:
|
|
91
|
+
$fetch: $Fetch;
|
|
92
|
+
api: ApiMethods;
|
|
99
93
|
};
|
|
100
94
|
//#endregion
|
|
101
95
|
export { $fetch, api, createFetch };
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":["api: ApiMethods"],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;AAgDA;;;;;;;;;;;AASA;;;;;AAsCA;AAgCA;;;;;;;;;;;;;;;;;iBA/EsB,uBAAuB,4CAEnC,mBACE,sBACT,QACC,gBAAA,CAAiB,YAAY,WAC7B,gBAAA,CAAiB,OAAO,gBAAA,CAAiB,YAAY;iBAGnC,MAAA,6BAEV,sBACT,QAAQ;;;;;;;;;;;;;;;;;;;;;;cAmCEA,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;iBAgCF,WAAA,kBAA4B;UAClC;OACH"}
|
package/dist/index.mjs
CHANGED
|
@@ -39,9 +39,23 @@ function mergeHeaders(base, override) {
|
|
|
39
39
|
}
|
|
40
40
|
return merged;
|
|
41
41
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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;
|
|
45
59
|
/**
|
|
46
60
|
* Checks if a URL is absolute (starts with http://, https://, or //)
|
|
47
61
|
*/
|
|
@@ -67,8 +81,8 @@ async function fetchInternal(resource, schema, options, defaults) {
|
|
|
67
81
|
let url;
|
|
68
82
|
if (isAbsoluteURL(resource)) url = resource;
|
|
69
83
|
else {
|
|
70
|
-
const base = defaults.baseURL
|
|
71
|
-
const path = resource
|
|
84
|
+
const base = trimTrailingSlashes(defaults.baseURL);
|
|
85
|
+
const path = trimLeadingSlashes(resource);
|
|
72
86
|
url = base ? `${base}/${path}` : resource;
|
|
73
87
|
}
|
|
74
88
|
const response = await fetch(url, init);
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["url: string","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 = {\n baseURL: \"\",\n headers: undefined,\n throwOnFetchError: true,\n throwOnValidationError: true,\n} as const satisfies FetchDefaults;\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { $fetch } from \"..\";\nimport { FetchError } from \"../errors\";\nimport type { ExtendedRequestInit, FetchDefaults } from \"../types\";\nimport { 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\nconst TRAILING_SLASHES = /\\/+$/;\nconst LEADING_SLASHES = /^\\/+/;\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 * 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 ...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 = defaults.baseURL.replace(TRAILING_SLASHES, \"\");\n const path = resource.replace(LEADING_SLASHES, \"\");\n url = base ? `${base}/${path}` : resource;\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 typeof $fetch>(\n fetchFn: TFetch,\n method: string\n) {\n return <TSchema extends StandardSchemaV1>(\n resource: string,\n schema: TSchema,\n options?: Omit<ExtendedRequestInit, \"method\">\n ) => fetchFn(resource, schema, { ...options, method });\n}\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { GLOBAL_DEFAULTS } from \"./internal/constants\";\nimport { createMethod, fetchInternal } from \"./internal/utils\";\nimport type {\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\n): Promise<\n | StandardSchemaV1.InferOutput<TSchema>\n | StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>\n>;\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 = {\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: typeof $fetch;\n api: typeof api;\n} {\n const defaults: FetchDefaults = {\n baseURL: factoryOptions.baseURL ?? \"\",\n headers: factoryOptions.headers,\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\n ): Promise<\n | StandardSchemaV1.InferOutput<TSchema>\n | StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>\n >;\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":["GLOBAL_DEFAULTS: FetchDefaults","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 { $Fetch, ExtendedRequestInit, FetchDefaults } from \"../types\";\nimport { 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 * 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 ...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 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 return <TSchema extends StandardSchemaV1>(\n resource: string,\n schema: TSchema,\n options?: Omit<ExtendedRequestInit, \"method\">\n ) => fetchFn(resource, schema, { ...options, method });\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\n): Promise<\n | StandardSchemaV1.InferOutput<TSchema>\n | StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>\n>;\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 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\n ): Promise<\n | StandardSchemaV1.InferOutput<TSchema>\n | StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>\n >;\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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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Extended RequestInit type to include custom fetch options
|
|
7
|
+
*/
|
|
8
|
+
type ExtendedRequestInit = Omit<RequestInit, "body"> & {
|
|
9
|
+
/**
|
|
10
|
+
* Request body - can be a BodyInit value or an object that will be JSON-stringified
|
|
11
|
+
*/
|
|
12
|
+
body?: BodyInit | Record<string, unknown>;
|
|
13
|
+
/**
|
|
14
|
+
* Whether to throw a FetchError on HTTP errors (non-2xx responses)
|
|
15
|
+
* @default true
|
|
16
|
+
*/
|
|
17
|
+
throwOnFetchError?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Whether to throw a ValidationError on validation errors
|
|
20
|
+
* @default true
|
|
21
|
+
*/
|
|
22
|
+
throwOnValidationError?: boolean;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Internal defaults used by fetchInternal
|
|
26
|
+
*/
|
|
27
|
+
type FetchDefaults = {
|
|
28
|
+
/**
|
|
29
|
+
* Base URL to prepend to all requests
|
|
30
|
+
* @default ""
|
|
31
|
+
*/
|
|
32
|
+
baseURL: string;
|
|
33
|
+
/**
|
|
34
|
+
* Default headers to include in all requests
|
|
35
|
+
* @default undefined
|
|
36
|
+
*/
|
|
37
|
+
headers: HeadersInit | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Whether to throw a `FetchError` on HTTP errors (non-2xx responses)
|
|
40
|
+
* @default true
|
|
41
|
+
*/
|
|
42
|
+
throwOnFetchError: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Whether to throw a `ValidationError` on validation errors
|
|
45
|
+
* @default true
|
|
46
|
+
*/
|
|
47
|
+
throwOnValidationError: boolean;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Options for creating a custom fetch instance with `createFetch`
|
|
51
|
+
*/
|
|
52
|
+
type CreateFetchOptions = Partial<FetchDefaults>;
|
|
53
|
+
/**
|
|
54
|
+
* Type-safe fetch function with Standard Schema validation support
|
|
55
|
+
*/
|
|
56
|
+
type $Fetch = {
|
|
57
|
+
/**
|
|
58
|
+
* Fetch with schema validation
|
|
59
|
+
* @param resource - URL or path to fetch
|
|
60
|
+
* @param schema - Standard Schema for response validation
|
|
61
|
+
* @param options - Extended request options
|
|
62
|
+
* @returns Validated data or Standard Schema Result based on throwOnValidationError option
|
|
63
|
+
*/
|
|
64
|
+
<TSchema extends StandardSchemaV1>(resource: string, schema: TSchema, options?: ExtendedRequestInit): Promise<StandardSchemaV1.InferOutput<TSchema> | StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;
|
|
65
|
+
/**
|
|
66
|
+
* Fetch without schema validation
|
|
67
|
+
* @param resource - URL or path to fetch
|
|
68
|
+
* @param options - Extended request options
|
|
69
|
+
* @returns Raw Response object
|
|
70
|
+
*/
|
|
71
|
+
(resource: string, options?: ExtendedRequestInit): Promise<Response>;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* API HTTP method-specific fetch functions
|
|
75
|
+
*/
|
|
76
|
+
type ApiMethods = {
|
|
77
|
+
/**
|
|
78
|
+
* GET method fetch function
|
|
79
|
+
*/
|
|
80
|
+
get: $Fetch;
|
|
81
|
+
/**
|
|
82
|
+
* POST method fetch function
|
|
83
|
+
*/
|
|
84
|
+
post: $Fetch;
|
|
85
|
+
/**
|
|
86
|
+
* PUT method fetch function
|
|
87
|
+
*/
|
|
88
|
+
put: $Fetch;
|
|
89
|
+
/**
|
|
90
|
+
* DELETE method fetch function
|
|
91
|
+
*/
|
|
92
|
+
delete: $Fetch;
|
|
93
|
+
/**
|
|
94
|
+
* PATCH method fetch function
|
|
95
|
+
*/
|
|
96
|
+
patch: $Fetch;
|
|
97
|
+
};
|
|
98
|
+
//#endregion
|
|
99
|
+
export { FetchDefaults as a, ExtendedRequestInit as i, ApiMethods as n, CreateFetchOptions as r, $Fetch as t };
|
|
100
|
+
//# sourceMappingURL=types-BB4ejGeA.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-BB4ejGeA.d.mts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;AAAuC,KAA3B,mBAAA,GAAsB,IAAK,CAAA,WAAA,EAAA,MAAA,CAAA,GAAA;EAAL;;;EAId,IAAA,CAAA,EAAX,QAAW,GAAA,MAAA,CAAA,MAAA,EAAA,OAAA,CAAA;EAgBpB;AA0BA;AAKA;;EAUY,iBAAA,CAAA,EAAA,OAAA;EACE;;;;EAGgB,sBAAiB,CAAA,EAAA,OAAA;CAAzC;;;;AAS+C,KAtDzC,aAAA,GAsDyC;EAAA;AAMrD;;;EAYO,OAAA,EAAA,MAAA;EAIG;;;;WAlEC;;;;;;;;;;;;;;;KAgBC,kBAAA,GAAqB,QAAQ;;;;KAK7B,MAAA;;;;;;;;mBAQO,4CAEP,mBACE,sBACT,QACC,gBAAA,CAAiB,YAAY,WAC7B,gBAAA,CAAiB,OAAO,gBAAA,CAAiB,YAAY;;;;;;;+BAS5B,sBAAsB,QAAQ;;;;;KAMjD,UAAA;;;;OAIL;;;;QAIC;;;;OAID;;;;UAIG;;;;SAID"}
|
package/dist/types.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { CreateFetchOptions, ExtendedRequestInit, FetchDefaults };
|
|
1
|
+
import { a as FetchDefaults, i as ExtendedRequestInit, n as ApiMethods, r as CreateFetchOptions, t as $Fetch } from "./types-BB4ejGeA.mjs";
|
|
2
|
+
export { $Fetch, ApiMethods, CreateFetchOptions, ExtendedRequestInit, FetchDefaults };
|
package/dist/validator.d.mts
CHANGED
|
@@ -3,31 +3,31 @@ import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
|
3
3
|
//#region src/validator.d.ts
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
* Type guard to check if a value is a Standard Schema schema
|
|
7
|
+
*/
|
|
8
8
|
declare function isStandardSchema(value: unknown): value is StandardSchemaV1;
|
|
9
9
|
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
10
|
+
* Helper function to validate data using Standard Schema
|
|
11
|
+
*
|
|
12
|
+
* @throws {ValidationError} When `throwOnError` is true and validation fails
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* import { standardValidate } from "@zap-studio/fetch/validator";
|
|
16
|
+
* import { z } from "zod";
|
|
17
|
+
*
|
|
18
|
+
* const UserSchema = z.object({ id: z.number(), name: z.string() });
|
|
19
|
+
*
|
|
20
|
+
* // Basic usage
|
|
21
|
+
* const user = await standardValidate(UserSchema, data);
|
|
22
|
+
*
|
|
23
|
+
* // Non-throwing usage
|
|
24
|
+
* const result = await standardValidate(UserSchema, data, false);
|
|
25
|
+
* if (result.issues) {
|
|
26
|
+
* console.error("Validation failed:", result.issues);
|
|
27
|
+
* } else {
|
|
28
|
+
* console.log("Success:", result.value);
|
|
29
|
+
* }
|
|
30
|
+
*/
|
|
31
31
|
declare function standardValidate<TSchema extends StandardSchemaV1>(schema: TSchema, input: unknown, throwOnError: boolean): Promise<StandardSchemaV1.InferOutput<TSchema> | StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;
|
|
32
32
|
//#endregion
|
|
33
33
|
export { isStandardSchema, standardValidate };
|
package/dist/validator.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.d.mts","names":[],"sources":["../src/validator.ts"],"sourcesContent":[],"mappings":";;;;;;AAMA;AA8BsB,iBA9BN,gBAAA,
|
|
1
|
+
{"version":3,"file":"validator.d.mts","names":[],"sources":["../src/validator.ts"],"sourcesContent":[],"mappings":";;;;;;AAMA;AA8BsB,iBA9BN,gBAAA,CA8BM,KAAA,EAAA,OAAA,CAAA,EAAA,KAAA,IA9BqC,gBA8BrC;;;;;;;;;;;;;;;;;;;;;;;iBAAA,iCAAiC,0BAC7C,iDAGP,QACC,gBAAA,CAAiB,YAAY,WAC7B,gBAAA,CAAiB,OAAO,gBAAA,CAAiB,YAAY"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zap-studio/fetch",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
5
6
|
"private": false,
|
|
6
7
|
"publishConfig": {
|
|
7
8
|
"access": "public"
|
|
@@ -24,9 +25,9 @@
|
|
|
24
25
|
"valibot": "^1.2.0",
|
|
25
26
|
"vitest": "^4.0.14",
|
|
26
27
|
"zod": "^4.1.13",
|
|
27
|
-
"@zap-studio/vitest-config": "0.0.0",
|
|
28
28
|
"@zap-studio/tsdown-config": "0.0.0",
|
|
29
|
-
"@zap-studio/typescript-config": "0.0.0"
|
|
29
|
+
"@zap-studio/typescript-config": "0.0.0",
|
|
30
|
+
"@zap-studio/vitest-config": "0.0.0"
|
|
30
31
|
},
|
|
31
32
|
"exports": {
|
|
32
33
|
".": "./dist/index.mjs",
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
//#region src/types.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Extended RequestInit type to include custom fetch options
|
|
4
|
-
*/
|
|
5
|
-
type ExtendedRequestInit = Omit<RequestInit, "body"> & {
|
|
6
|
-
/**
|
|
7
|
-
* Request body - can be a BodyInit value or an object that will be JSON-stringified
|
|
8
|
-
*/
|
|
9
|
-
body?: BodyInit | Record<string, unknown>;
|
|
10
|
-
/**
|
|
11
|
-
* Whether to throw a FetchError on HTTP errors (non-2xx responses)
|
|
12
|
-
* @default true
|
|
13
|
-
*/
|
|
14
|
-
throwOnFetchError?: boolean;
|
|
15
|
-
/**
|
|
16
|
-
* Whether to throw a ValidationError on validation errors
|
|
17
|
-
* @default true
|
|
18
|
-
*/
|
|
19
|
-
throwOnValidationError?: boolean;
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* Internal defaults used by fetchInternal
|
|
23
|
-
*/
|
|
24
|
-
type FetchDefaults = {
|
|
25
|
-
/**
|
|
26
|
-
* Base URL to prepend to all requests
|
|
27
|
-
* @default ""
|
|
28
|
-
*/
|
|
29
|
-
baseURL: string;
|
|
30
|
-
/**
|
|
31
|
-
* Default headers to include in all requests
|
|
32
|
-
* @default undefined
|
|
33
|
-
*/
|
|
34
|
-
headers: HeadersInit | undefined;
|
|
35
|
-
/**
|
|
36
|
-
* Whether to throw a `FetchError` on HTTP errors (non-2xx responses)
|
|
37
|
-
* @default true
|
|
38
|
-
*/
|
|
39
|
-
throwOnFetchError: boolean;
|
|
40
|
-
/**
|
|
41
|
-
* Whether to throw a `ValidationError` on validation errors
|
|
42
|
-
* @default true
|
|
43
|
-
*/
|
|
44
|
-
throwOnValidationError: boolean;
|
|
45
|
-
};
|
|
46
|
-
/**
|
|
47
|
-
* Options for creating a custom fetch instance with `createFetch`
|
|
48
|
-
*/
|
|
49
|
-
type CreateFetchOptions = Partial<FetchDefaults>;
|
|
50
|
-
//#endregion
|
|
51
|
-
export { ExtendedRequestInit as n, FetchDefaults as r, CreateFetchOptions as t };
|
|
52
|
-
//# sourceMappingURL=types-C0Uhh2KM.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-C0Uhh2KM.d.mts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;AAGA;;AAAkC,KAAtB,mBAAA,GAAsB,IAAA,CAAK,WAAL,EAAA,MAAA,CAAA,GAAA;EAIzB;;;EAgBG,IAAA,CAAA,EAhBH,QAgBG,GAhBQ,MAgBK,CAAA,MAUd,EAAA,OAAW,CAAA;EAgBV;;;;;;;;;;;;;;KA1BA,aAAA;;;;;;;;;;WAUD;;;;;;;;;;;;;;;KAgBC,kBAAA,GAAqB,QAAQ"}
|