@zayne-labs/callapi 1.14.2 → 1.16.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/dist/{conditional-types-C9cMfJMZ.d.ts → callapi-context-NF0HXJwF.d.ts} +1544 -1540
- package/dist/constants/index.d.ts +7 -6
- package/dist/constants/index.js +1 -1
- package/dist/{constants-C8dGbmdY.js → constants-KCmRZnc7.js} +41 -24
- package/dist/constants-KCmRZnc7.js.map +1 -0
- package/dist/{index-Dcg43451.d.ts → index-bRY6RbJu.d.ts} +89 -65
- package/dist/index.d.ts +3 -3
- package/dist/index.js +31 -18
- package/dist/index.js.map +1 -1
- package/dist/utils/external/index.d.ts +2 -2
- package/dist/utils/external/index.js +2 -2
- package/package.json +18 -18
- package/dist/constants-C8dGbmdY.js.map +0 -1
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
//#region src/constants/common.d.ts
|
|
2
2
|
declare const fetchSpecificKeys: readonly (keyof RequestInit | "duplex" | "extraFetchOptions")[];
|
|
3
3
|
//#endregion
|
|
4
|
+
//#region src/types/default-types.d.ts
|
|
5
|
+
type DefaultDataType = unknown;
|
|
6
|
+
type DefaultPluginArray = CallApiPlugin[];
|
|
7
|
+
type DefaultThrowOnError = boolean;
|
|
8
|
+
type DefaultMetaObject = Record<string, unknown>;
|
|
9
|
+
type DefaultInferredExtraOptions = unknown;
|
|
10
|
+
type DefaultCallApiContext = Omit<CallApiContext, "Meta">;
|
|
11
|
+
//#endregion
|
|
4
12
|
//#region src/types/type-helpers.d.ts
|
|
5
|
-
type
|
|
6
|
-
type
|
|
13
|
+
type NonNullableUnknown = NonNullable<unknown>;
|
|
14
|
+
type AnyString = string & NonNullableUnknown;
|
|
15
|
+
type AnyNumber = number & NonNullableUnknown;
|
|
7
16
|
type AnyFunction<TResult = unknown> = (...args: any[]) => TResult;
|
|
8
17
|
type Prettify<TObject> = NonNullable<unknown> & { [Key in keyof TObject]: TObject[Key]; };
|
|
9
18
|
type WriteableLevel = "deep" | "shallow";
|
|
19
|
+
type IsEmptyObject<TObject> = keyof TObject extends never ? true : false;
|
|
10
20
|
/**
|
|
11
21
|
* Makes all properties in an object type writeable (removes readonly modifiers).
|
|
12
22
|
* Supports both shallow and deep modes, and handles special cases like arrays, tuples, and unions.
|
|
@@ -37,208 +47,343 @@ type CommonRequestHeaders = "Access-Control-Allow-Credentials" | "Access-Control
|
|
|
37
47
|
type CommonAuthorizationHeaders = `${"Basic" | "Bearer" | "Token"} ${string}`;
|
|
38
48
|
type CommonContentTypes = "application/epub+zip" | "application/gzip" | "application/json" | "application/ld+json" | "application/octet-stream" | "application/ogg" | "application/pdf" | "application/rtf" | "application/vnd.ms-fontobject" | "application/wasm" | "application/xhtml+xml" | "application/xml" | "application/zip" | "audio/aac" | "audio/mpeg" | "audio/ogg" | "audio/opus" | "audio/webm" | "audio/x-midi" | "font/otf" | "font/ttf" | "font/woff" | "font/woff2" | "image/avif" | "image/bmp" | "image/gif" | "image/jpeg" | "image/png" | "image/svg+xml" | "image/tiff" | "image/webp" | "image/x-icon" | "model/gltf-binary" | "model/gltf+json" | "text/calendar" | "text/css" | "text/csv" | "text/html" | "text/javascript" | "text/plain" | "video/3gpp" | "video/3gpp2" | "video/av1" | "video/mp2t" | "video/mp4" | "video/mpeg" | "video/ogg" | "video/webm" | "video/x-msvideo" | AnyString;
|
|
39
49
|
//#endregion
|
|
40
|
-
//#region src/
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
/** The Standard properties. */
|
|
44
|
-
readonly "~standard": StandardTypedV1.Props<Input, Output>;
|
|
45
|
-
}
|
|
46
|
-
declare namespace StandardTypedV1 {
|
|
47
|
-
/** The Standard Typed properties interface. */
|
|
48
|
-
interface Props<Input = unknown, Output = Input> {
|
|
49
|
-
/** Inferred types associated with the schema. */
|
|
50
|
-
readonly types?: Types<Input, Output> | undefined;
|
|
51
|
-
/** The vendor name of the schema library. */
|
|
52
|
-
readonly vendor: string;
|
|
53
|
-
/** The version number of the standard. */
|
|
54
|
-
readonly version: 1;
|
|
55
|
-
}
|
|
56
|
-
/** The Standard Typed types interface. */
|
|
57
|
-
interface Types<Input = unknown, Output = Input> {
|
|
58
|
-
/** The input type of the schema. */
|
|
59
|
-
readonly input: Input;
|
|
60
|
-
/** The output type of the schema. */
|
|
61
|
-
readonly output: Output;
|
|
62
|
-
}
|
|
63
|
-
/** Infers the input type of a Standard Typed. */
|
|
64
|
-
type InferInput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
65
|
-
/** Infers the output type of a Standard Typed. */
|
|
66
|
-
type InferOutput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
67
|
-
}
|
|
68
|
-
/** The Standard Schema interface. */
|
|
69
|
-
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
70
|
-
/** The Standard Schema properties. */
|
|
71
|
-
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
|
|
72
|
-
}
|
|
73
|
-
declare namespace StandardSchemaV1 {
|
|
74
|
-
/** The Standard Schema properties interface. */
|
|
75
|
-
interface Props<Input = unknown, Output = Input> extends StandardTypedV1.Props<Input, Output> {
|
|
76
|
-
/** Validates unknown input values. */
|
|
77
|
-
readonly validate: (value: unknown, options?: StandardSchemaV1.Options) => Promise<Result<Output>> | Result<Output>;
|
|
78
|
-
}
|
|
79
|
-
/** The result interface of the validate function. */
|
|
80
|
-
type Result<Output> = FailureResult | SuccessResult<Output>;
|
|
81
|
-
/** The result interface if validation succeeds. */
|
|
82
|
-
interface SuccessResult<Output> {
|
|
83
|
-
/** A falsy value for `issues` indicates success. */
|
|
84
|
-
readonly issues?: undefined;
|
|
85
|
-
/** The typed output value. */
|
|
86
|
-
readonly value: Output;
|
|
87
|
-
}
|
|
88
|
-
interface Options {
|
|
89
|
-
/** Explicit support for additional vendor-specific parameters, if needed. */
|
|
90
|
-
readonly libraryOptions?: Record<string, unknown> | undefined;
|
|
91
|
-
}
|
|
92
|
-
/** The result interface if validation fails. */
|
|
93
|
-
interface FailureResult {
|
|
94
|
-
/** The issues of failed validation. */
|
|
95
|
-
readonly issues: readonly Issue[];
|
|
96
|
-
}
|
|
97
|
-
/** The issue interface of the failure output. */
|
|
98
|
-
interface Issue {
|
|
99
|
-
/** The error message of the issue. */
|
|
100
|
-
readonly message: string;
|
|
101
|
-
/** The path of the issue, if any. */
|
|
102
|
-
readonly path?: ReadonlyArray<PathSegment | PropertyKey> | undefined;
|
|
103
|
-
}
|
|
104
|
-
/** The path segment interface of the issue. */
|
|
105
|
-
interface PathSegment {
|
|
106
|
-
/** The key representing a path segment. */
|
|
107
|
-
readonly key: PropertyKey;
|
|
108
|
-
}
|
|
109
|
-
/** The Standard types interface. */
|
|
110
|
-
interface Types<Input = unknown, Output = Input> extends StandardTypedV1.Types<Input, Output> {}
|
|
111
|
-
/** Infers the input type of a Standard. */
|
|
112
|
-
type InferInput<Schema extends StandardTypedV1> = StandardTypedV1.InferInput<Schema>;
|
|
113
|
-
/** Infers the output type of a Standard. */
|
|
114
|
-
type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
|
|
115
|
-
}
|
|
116
|
-
//#endregion
|
|
117
|
-
//#region src/constants/validation.d.ts
|
|
118
|
-
declare const fallBackRouteSchemaKey = "@default";
|
|
119
|
-
type FallBackRouteSchemaKey = typeof fallBackRouteSchemaKey;
|
|
120
|
-
//#endregion
|
|
121
|
-
//#region src/url.d.ts
|
|
122
|
-
declare const atSymbol = "@";
|
|
123
|
-
type AtSymbol = typeof atSymbol;
|
|
124
|
-
type AllowedQueryParamValues = UnmaskType<boolean | number | string>;
|
|
125
|
-
type RecordStyleParams = UnmaskType<Record<string, AllowedQueryParamValues>>;
|
|
126
|
-
type TupleStyleParams = UnmaskType<AllowedQueryParamValues[]>;
|
|
127
|
-
type Params = UnmaskType<RecordStyleParams | TupleStyleParams>;
|
|
128
|
-
type StructuredQueryValues = Record<string, unknown> | unknown[] | null | undefined;
|
|
129
|
-
type Query = UnmaskType<Record<string, AllowedQueryParamValues | StructuredQueryValues> | URLSearchParams>;
|
|
130
|
-
type InitURLOrURLObject = AnyString | RouteKeyMethodsURLUnion | URL;
|
|
131
|
-
interface URLOptions {
|
|
50
|
+
//#region src/dedupe.d.ts
|
|
51
|
+
type DedupeStrategyUnion = UnmaskType<"cancel" | "defer" | "none">;
|
|
52
|
+
type DedupeOptions = {
|
|
132
53
|
/**
|
|
133
|
-
*
|
|
54
|
+
* Controls the scope of request deduplication caching.
|
|
134
55
|
*
|
|
135
|
-
*
|
|
56
|
+
* - `"global"`: Shares deduplication cache across all `createFetchClient` instances with the same `dedupeCacheScopeKey`.
|
|
57
|
+
* Useful for applications with multiple API clients that should share deduplication state.
|
|
58
|
+
* - `"local"`: Limits deduplication to requests within the same `createFetchClient` instance.
|
|
59
|
+
* Provides better isolation and is recommended for most use cases.
|
|
60
|
+
*
|
|
61
|
+
*
|
|
62
|
+
* **Real-world Scenarios:**
|
|
63
|
+
* - Use `"global"` when you have multiple API clients (user service, auth service, etc.) that might make overlapping requests
|
|
64
|
+
* - Use `"local"` (default) for single-purpose clients or when you want strict isolation between different parts of your app
|
|
136
65
|
*
|
|
137
66
|
* @example
|
|
138
67
|
* ```ts
|
|
139
|
-
* //
|
|
140
|
-
* baseURL: "
|
|
141
|
-
*
|
|
142
|
-
* //
|
|
143
|
-
* callApi("/users") // → https://api.example.com/v1/users
|
|
144
|
-
* callApi("/posts/123") // → https://api.example.com/v1/posts/123
|
|
68
|
+
* // Local scope - each client has its own deduplication cache
|
|
69
|
+
* const userClient = createFetchClient({ baseURL: "/api/users" });
|
|
70
|
+
* const postClient = createFetchClient({ baseURL: "/api/posts" });
|
|
71
|
+
* // These clients won't share deduplication state
|
|
145
72
|
*
|
|
146
|
-
* //
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* : "
|
|
73
|
+
* // Global scope - share cache across related clients
|
|
74
|
+
* const userClient = createFetchClient({
|
|
75
|
+
* baseURL: "/api/users",
|
|
76
|
+
* dedupeCacheScope: "global",
|
|
77
|
+
* });
|
|
78
|
+
* const postClient = createFetchClient({
|
|
79
|
+
* baseURL: "/api/posts",
|
|
80
|
+
* dedupeCacheScope: "global",
|
|
81
|
+
* });
|
|
82
|
+
* // These clients will share deduplication state
|
|
150
83
|
* ```
|
|
151
|
-
*/
|
|
152
|
-
baseURL?: string;
|
|
153
|
-
/**
|
|
154
|
-
* Resolved request URL after processing baseURL, parameters, and query strings (readonly)
|
|
155
|
-
*
|
|
156
|
-
* This is the final URL that will be used for the HTTP request, computed from
|
|
157
|
-
* baseURL, initURL, params, and query parameters.
|
|
158
|
-
*
|
|
159
|
-
*/
|
|
160
|
-
readonly fullURL?: string;
|
|
161
|
-
/**
|
|
162
|
-
* The original URL string passed to the callApi instance (readonly)
|
|
163
|
-
*
|
|
164
|
-
* This preserves the original URL as provided, including any method modifiers like "@get/" or "@post/".
|
|
165
84
|
*
|
|
85
|
+
* @default "local"
|
|
166
86
|
*/
|
|
167
|
-
|
|
87
|
+
dedupeCacheScope?: "global" | "local";
|
|
168
88
|
/**
|
|
169
|
-
*
|
|
89
|
+
* Unique namespace for the global deduplication cache when using `dedupeCacheScope: "global"`.
|
|
170
90
|
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
91
|
+
* This creates logical groupings of deduplication caches. All instances with the same key
|
|
92
|
+
* will share the same cache namespace, allowing fine-grained control over which clients
|
|
93
|
+
* share deduplication state.
|
|
173
94
|
*
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
*
|
|
95
|
+
* **Best Practices:**
|
|
96
|
+
* - Use descriptive names that reflect the logical grouping (e.g., "user-service", "analytics-api")
|
|
97
|
+
* - Keep scope keys consistent across related API clients
|
|
98
|
+
* - Consider using different scope keys for different environments (dev, staging, prod)
|
|
99
|
+
* - Avoid overly broad scope keys that might cause unintended cache sharing
|
|
178
100
|
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
101
|
+
* **Cache Management:**
|
|
102
|
+
* - Each scope key maintains its own independent cache
|
|
103
|
+
* - Caches are automatically cleaned up when no references remain
|
|
104
|
+
* - Consider the memory implications of multiple global scopes
|
|
181
105
|
*
|
|
182
106
|
* @example
|
|
183
|
-
* ```
|
|
184
|
-
* //
|
|
185
|
-
* const
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
107
|
+
* ```ts
|
|
108
|
+
* // Group related API clients together
|
|
109
|
+
* const userClient = createFetchClient({
|
|
110
|
+
* baseURL: "/api/users",
|
|
111
|
+
* dedupeCacheScope: "global",
|
|
112
|
+
* dedupeCacheScopeKey: "user-service"
|
|
113
|
+
* });
|
|
114
|
+
* const profileClient = createFetchClient({
|
|
115
|
+
* baseURL: "/api/profiles",
|
|
116
|
+
* dedupeCacheScope: "global",
|
|
117
|
+
* dedupeCacheScopeKey: "user-service" // Same scope - will share cache
|
|
118
|
+
* });
|
|
190
119
|
*
|
|
191
|
-
* //
|
|
192
|
-
* const
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
120
|
+
* // Separate analytics client with its own cache
|
|
121
|
+
* const analyticsClient = createFetchClient({
|
|
122
|
+
* baseURL: "/api/analytics",
|
|
123
|
+
* dedupeCacheScope: "global",
|
|
124
|
+
* dedupeCacheScopeKey: "analytics-service" // Different scope
|
|
125
|
+
* });
|
|
197
126
|
*
|
|
198
|
-
* //
|
|
199
|
-
* const
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
* };
|
|
203
|
-
* // Results in: /users/user-123
|
|
127
|
+
* // Environment-specific scoping
|
|
128
|
+
* const apiClient = createFetchClient({
|
|
129
|
+
* dedupeCacheScope: "global",
|
|
130
|
+
* dedupeCacheScopeKey: `api-${process.env.NODE_ENV}` // "api-development", "api-production", etc.
|
|
131
|
+
* });
|
|
204
132
|
* ```
|
|
133
|
+
*
|
|
134
|
+
* @default "default"
|
|
205
135
|
*/
|
|
206
|
-
|
|
136
|
+
dedupeCacheScopeKey?: "default" | AnyString | ((context: RequestContext) => string | undefined);
|
|
207
137
|
/**
|
|
208
|
-
*
|
|
138
|
+
* Custom key generator for request deduplication.
|
|
209
139
|
*
|
|
210
|
-
*
|
|
211
|
-
* URL
|
|
140
|
+
* Override the default key generation strategy to control exactly which requests
|
|
141
|
+
* are considered duplicates. The default key combines URL, method, body, and
|
|
142
|
+
* relevant headers (excluding volatile ones like 'Date', 'Authorization', etc.).
|
|
212
143
|
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
* page: 1,
|
|
220
|
-
* limit: 10,
|
|
221
|
-
* search: "john doe",
|
|
222
|
-
* active: true
|
|
223
|
-
* }
|
|
224
|
-
* };
|
|
225
|
-
* // Results in: /users?page=1&limit=10&search=john%20doe&active=true
|
|
144
|
+
* **Default Key Generation:**
|
|
145
|
+
* The auto-generated key includes:
|
|
146
|
+
* - Full request URL (including query parameters)
|
|
147
|
+
* - HTTP method (GET, POST, etc.)
|
|
148
|
+
* - Request body (for POST/PUT/PATCH requests)
|
|
149
|
+
* - Stable headers (excludes Date, Authorization, User-Agent, etc.)
|
|
226
150
|
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
151
|
+
* **Custom Key Best Practices:**
|
|
152
|
+
* - Include only the parts of the request that should affect deduplication
|
|
153
|
+
* - Avoid including volatile data (timestamps, random IDs, etc.)
|
|
154
|
+
* - Consider performance - simpler keys are faster to compute and compare
|
|
155
|
+
* - Ensure keys are deterministic for the same logical request
|
|
156
|
+
* - Use consistent key formats across your application
|
|
157
|
+
*
|
|
158
|
+
* **Performance Considerations:**
|
|
159
|
+
* - Function-based keys are computed on every request - keep them lightweight
|
|
160
|
+
* - String keys are fastest but least flexible
|
|
161
|
+
* - Consider caching expensive key computations if needed
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```ts
|
|
165
|
+
* import { callApi } from "@zayne-labs/callapi";
|
|
166
|
+
*
|
|
167
|
+
* // Simple static key - useful for singleton requests
|
|
168
|
+
* const config = callApi("/api/config", {
|
|
169
|
+
* dedupeKey: "app-config",
|
|
170
|
+
* dedupeStrategy: "defer" // Share the same config across all requests
|
|
171
|
+
* });
|
|
172
|
+
*
|
|
173
|
+
* // URL and method only - ignore headers and body
|
|
174
|
+
* const userData = callApi("/api/user/123", {
|
|
175
|
+
* dedupeKey: (context) => `${context.options.method}:${context.options.fullURL}`
|
|
176
|
+
* });
|
|
177
|
+
*
|
|
178
|
+
* // Include specific headers in deduplication
|
|
179
|
+
* const apiCall = callApi("/api/data", {
|
|
180
|
+
* dedupeKey: (context) => {
|
|
181
|
+
* const authHeader = context.request.headers.get("Authorization");
|
|
182
|
+
* return `${context.options.fullURL}-${authHeader}`;
|
|
183
|
+
* }
|
|
184
|
+
* });
|
|
185
|
+
*
|
|
186
|
+
* // User-specific deduplication
|
|
187
|
+
* const userSpecificCall = callApi("/api/dashboard", {
|
|
188
|
+
* dedupeKey: (context) => {
|
|
189
|
+
* const userId = context.options.fullURL.match(/user\/(\d+)/)?.[1];
|
|
190
|
+
* return `dashboard-${userId}`;
|
|
191
|
+
* }
|
|
192
|
+
* });
|
|
193
|
+
*
|
|
194
|
+
* // Ignore certain query parameters
|
|
195
|
+
* const searchCall = callApi("/api/search?q=test×tamp=123456", {
|
|
196
|
+
* dedupeKey: (context) => {
|
|
197
|
+
* const url = new URL(context.options.fullURL);
|
|
198
|
+
* url.searchParams.delete("timestamp"); // Remove volatile param
|
|
199
|
+
* return `search:${url.toString()}`;
|
|
200
|
+
* }
|
|
201
|
+
* });
|
|
202
|
+
* ```
|
|
203
|
+
*
|
|
204
|
+
* @default Auto-generated from request details
|
|
205
|
+
*/
|
|
206
|
+
dedupeKey?: string | ((context: RequestContext) => string | undefined);
|
|
207
|
+
/**
|
|
208
|
+
* Strategy for handling duplicate requests. Can be a static string or callback function.
|
|
209
|
+
*
|
|
210
|
+
* **Available Strategies:**
|
|
211
|
+
* - `"cancel"`: Cancel previous request when new one starts (good for search)
|
|
212
|
+
* - `"defer"`: Share response between duplicate requests (good for config loading)
|
|
213
|
+
* - `"none"`: No deduplication, all requests execute independently
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* // Static strategies
|
|
218
|
+
* const searchClient = createFetchClient({
|
|
219
|
+
* dedupeStrategy: "cancel" // Cancel previous searches
|
|
220
|
+
* });
|
|
221
|
+
*
|
|
222
|
+
* const configClient = createFetchClient({
|
|
223
|
+
* dedupeStrategy: "defer" // Share config across components
|
|
224
|
+
* });
|
|
225
|
+
*
|
|
226
|
+
* // Dynamic strategy based on request
|
|
227
|
+
* const smartClient = createFetchClient({
|
|
228
|
+
* dedupeStrategy: (context) => {
|
|
229
|
+
* return context.options.method === "GET" ? "defer" : "cancel";
|
|
230
|
+
* }
|
|
231
|
+
* });
|
|
232
|
+
*
|
|
233
|
+
* // Search-as-you-type with cancel strategy
|
|
234
|
+
* const handleSearch = async (query: string) => {
|
|
235
|
+
* try {
|
|
236
|
+
* const { data } = await callApi("/api/search", {
|
|
237
|
+
* method: "POST",
|
|
238
|
+
* body: { query },
|
|
239
|
+
* dedupeStrategy: "cancel",
|
|
240
|
+
* dedupeKey: "search" // Cancel previous searches, only latest one goes through
|
|
241
|
+
* });
|
|
242
|
+
*
|
|
243
|
+
* updateSearchResults(data);
|
|
244
|
+
* } catch (error) {
|
|
245
|
+
* if (error.name === "AbortError") {
|
|
246
|
+
* // Previous search cancelled - (expected behavior)
|
|
247
|
+
* return;
|
|
248
|
+
* }
|
|
249
|
+
* console.error("Search failed:", error);
|
|
236
250
|
* }
|
|
237
251
|
* };
|
|
238
|
-
*
|
|
252
|
+
*
|
|
239
253
|
* ```
|
|
254
|
+
*
|
|
255
|
+
* @default "cancel"
|
|
240
256
|
*/
|
|
241
|
-
|
|
257
|
+
dedupeStrategy?: DedupeStrategyUnion | ((context: RequestContext) => DedupeStrategyUnion);
|
|
258
|
+
};
|
|
259
|
+
//#endregion
|
|
260
|
+
//#region src/middlewares.d.ts
|
|
261
|
+
type FetchImpl = UnmaskType<(input: string | Request | URL, init?: RequestInit) => Awaitable<Response>>;
|
|
262
|
+
type FetchMiddlewareContext<TCallApiContext extends CallApiContext> = RequestContext<TCallApiContext> & {
|
|
263
|
+
fetchImpl: FetchImpl;
|
|
264
|
+
};
|
|
265
|
+
interface Middlewares<TCallApiContext extends NoInfer<CallApiContext> = DefaultCallApiContext> {
|
|
266
|
+
/**
|
|
267
|
+
* Wraps the fetch implementation to intercept requests at the network layer.
|
|
268
|
+
*
|
|
269
|
+
* Takes a context object containing the current fetch function and returns a new fetch function.
|
|
270
|
+
* Use it to cache responses, add logging, handle offline mode, or short-circuit requests etc.
|
|
271
|
+
* Multiple middleware compose in order: plugins → base config → per-request.
|
|
272
|
+
*
|
|
273
|
+
* Unlike `customFetchImpl`, middleware can call through to the original fetch.
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```ts
|
|
277
|
+
* // Cache responses
|
|
278
|
+
* const cache = new Map();
|
|
279
|
+
*
|
|
280
|
+
* fetchMiddleware: (ctx) => async (input, init) => {
|
|
281
|
+
* const key = input.toString();
|
|
282
|
+
*
|
|
283
|
+
* const cachedResponse = cache.get(key);
|
|
284
|
+
*
|
|
285
|
+
* if (cachedResponse) {
|
|
286
|
+
* return cachedResponse.clone();
|
|
287
|
+
* }
|
|
288
|
+
*
|
|
289
|
+
* const response = await ctx.fetchImpl(input, init);
|
|
290
|
+
* cache.set(key, response.clone());
|
|
291
|
+
*
|
|
292
|
+
* return response;
|
|
293
|
+
* }
|
|
294
|
+
*
|
|
295
|
+
* // Handle offline
|
|
296
|
+
* fetchMiddleware: (ctx) => async (...parameters) => {
|
|
297
|
+
* if (!navigator.onLine) {
|
|
298
|
+
* return new Response('{"error": "offline"}', { status: 503 });
|
|
299
|
+
* }
|
|
300
|
+
*
|
|
301
|
+
* return ctx.fetchImpl(...parameters);
|
|
302
|
+
* }
|
|
303
|
+
* ```
|
|
304
|
+
*/
|
|
305
|
+
fetchMiddleware?: (context: FetchMiddlewareContext<TCallApiContext>) => FetchImpl;
|
|
306
|
+
}
|
|
307
|
+
//#endregion
|
|
308
|
+
//#region src/constants/validation.d.ts
|
|
309
|
+
declare const fallBackRouteSchemaKey = "@default";
|
|
310
|
+
type FallBackRouteSchemaKey = typeof fallBackRouteSchemaKey;
|
|
311
|
+
//#endregion
|
|
312
|
+
//#region src/types/standard-schema.d.ts
|
|
313
|
+
/** The Standard Typed interface. This is a base type extended by other specs. */
|
|
314
|
+
interface StandardTypedV1<Input = unknown, Output = Input> {
|
|
315
|
+
/** The Standard properties. */
|
|
316
|
+
readonly "~standard": StandardTypedV1.Props<Input, Output>;
|
|
317
|
+
}
|
|
318
|
+
declare namespace StandardTypedV1 {
|
|
319
|
+
/** The Standard Typed properties interface. */
|
|
320
|
+
interface Props<Input = unknown, Output = Input> {
|
|
321
|
+
/** Inferred types associated with the schema. */
|
|
322
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
323
|
+
/** The vendor name of the schema library. */
|
|
324
|
+
readonly vendor: string;
|
|
325
|
+
/** The version number of the standard. */
|
|
326
|
+
readonly version: 1;
|
|
327
|
+
}
|
|
328
|
+
/** The Standard Typed types interface. */
|
|
329
|
+
interface Types<Input = unknown, Output = Input> {
|
|
330
|
+
/** The input type of the schema. */
|
|
331
|
+
readonly input: Input;
|
|
332
|
+
/** The output type of the schema. */
|
|
333
|
+
readonly output: Output;
|
|
334
|
+
}
|
|
335
|
+
/** Infers the input type of a Standard Typed. */
|
|
336
|
+
type InferInput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
337
|
+
/** Infers the output type of a Standard Typed. */
|
|
338
|
+
type InferOutput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
339
|
+
}
|
|
340
|
+
/** The Standard Schema interface. */
|
|
341
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
342
|
+
/** The Standard Schema properties. */
|
|
343
|
+
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
|
|
344
|
+
}
|
|
345
|
+
declare namespace StandardSchemaV1 {
|
|
346
|
+
/** The Standard Schema properties interface. */
|
|
347
|
+
interface Props<Input = unknown, Output = Input> extends StandardTypedV1.Props<Input, Output> {
|
|
348
|
+
/** Validates unknown input values. */
|
|
349
|
+
readonly validate: (value: unknown, options?: StandardSchemaV1.Options) => Promise<Result<Output>> | Result<Output>;
|
|
350
|
+
}
|
|
351
|
+
/** The result interface of the validate function. */
|
|
352
|
+
type Result<Output> = FailureResult | SuccessResult<Output>;
|
|
353
|
+
/** The result interface if validation succeeds. */
|
|
354
|
+
interface SuccessResult<Output> {
|
|
355
|
+
/** A falsy value for `issues` indicates success. */
|
|
356
|
+
readonly issues?: undefined;
|
|
357
|
+
/** The typed output value. */
|
|
358
|
+
readonly value: Output;
|
|
359
|
+
}
|
|
360
|
+
interface Options {
|
|
361
|
+
/** Explicit support for additional vendor-specific parameters, if needed. */
|
|
362
|
+
readonly libraryOptions?: Record<string, unknown> | undefined;
|
|
363
|
+
}
|
|
364
|
+
/** The result interface if validation fails. */
|
|
365
|
+
interface FailureResult {
|
|
366
|
+
/** The issues of failed validation. */
|
|
367
|
+
readonly issues: readonly Issue[];
|
|
368
|
+
}
|
|
369
|
+
/** The issue interface of the failure output. */
|
|
370
|
+
interface Issue {
|
|
371
|
+
/** The error message of the issue. */
|
|
372
|
+
readonly message: string;
|
|
373
|
+
/** The path of the issue, if any. */
|
|
374
|
+
readonly path?: ReadonlyArray<PathSegment | PropertyKey> | undefined;
|
|
375
|
+
}
|
|
376
|
+
/** The path segment interface of the issue. */
|
|
377
|
+
interface PathSegment {
|
|
378
|
+
/** The key representing a path segment. */
|
|
379
|
+
readonly key: PropertyKey;
|
|
380
|
+
}
|
|
381
|
+
/** The Standard types interface. */
|
|
382
|
+
interface Types<Input = unknown, Output = Input> extends StandardTypedV1.Types<Input, Output> {}
|
|
383
|
+
/** Infers the input type of a Standard. */
|
|
384
|
+
type InferInput<Schema extends StandardTypedV1> = StandardTypedV1.InferInput<Schema>;
|
|
385
|
+
/** Infers the output type of a Standard. */
|
|
386
|
+
type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
|
|
242
387
|
}
|
|
243
388
|
//#endregion
|
|
244
389
|
//#region src/validation.d.ts
|
|
@@ -342,27 +487,150 @@ declare const getCurrentRouteSchemaKeyAndMainInitURL: (context: Pick<GetResolved
|
|
|
342
487
|
mainInitURL: string;
|
|
343
488
|
};
|
|
344
489
|
//#endregion
|
|
345
|
-
//#region src/
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
490
|
+
//#region src/url.d.ts
|
|
491
|
+
declare const atSymbol = "@";
|
|
492
|
+
type AtSymbol = typeof atSymbol;
|
|
493
|
+
type AllowedQueryParamValues = UnmaskType<boolean | number | string>;
|
|
494
|
+
type RecordStyleParams = UnmaskType<Record<string, AllowedQueryParamValues>>;
|
|
495
|
+
type TupleStyleParams = UnmaskType<AllowedQueryParamValues[]>;
|
|
496
|
+
type Params = UnmaskType<RecordStyleParams | TupleStyleParams>;
|
|
497
|
+
type StructuredQueryValues = Record<string, unknown> | unknown[] | null | undefined;
|
|
498
|
+
type Query = UnmaskType<Record<string, AllowedQueryParamValues | StructuredQueryValues> | URLSearchParams>;
|
|
499
|
+
type InitURLOrURLObject = AnyString | RouteKeyMethodsURLUnion | URL;
|
|
500
|
+
interface URLOptions {
|
|
501
|
+
/**
|
|
502
|
+
* Base URL for all API requests. Will only be prepended to relative URLs.
|
|
503
|
+
*
|
|
504
|
+
* Absolute URLs (starting with http/https) will not be prepended by the baseURL.
|
|
505
|
+
*
|
|
506
|
+
* @example
|
|
507
|
+
* ```ts
|
|
508
|
+
* // Set base URL for all requests
|
|
509
|
+
* baseURL: "https://api.example.com/v1"
|
|
510
|
+
*
|
|
511
|
+
* // Then use relative URLs in requests
|
|
512
|
+
* callApi("/users") // → https://api.example.com/v1/users
|
|
513
|
+
* callApi("/posts/123") // → https://api.example.com/v1/posts/123
|
|
514
|
+
*
|
|
515
|
+
* // Environment-specific base URLs
|
|
516
|
+
* baseURL: process.env.NODE_ENV === "production"
|
|
517
|
+
* ? "https://api.example.com"
|
|
518
|
+
* : "http://localhost:3000/api"
|
|
519
|
+
* ```
|
|
520
|
+
*/
|
|
521
|
+
baseURL?: string;
|
|
522
|
+
/**
|
|
523
|
+
* Resolved request URL after processing baseURL, parameters, and query strings (readonly)
|
|
524
|
+
*
|
|
525
|
+
* This is the final URL that will be used for the HTTP request, computed from
|
|
526
|
+
* baseURL, initURL, params, and query parameters.
|
|
527
|
+
*
|
|
528
|
+
*/
|
|
529
|
+
readonly fullURL?: string;
|
|
530
|
+
/**
|
|
531
|
+
* The original URL string passed to the callApi instance (readonly)
|
|
532
|
+
*
|
|
533
|
+
* This preserves the original URL as provided, including any method modifiers like "@get/" or "@post/".
|
|
534
|
+
*
|
|
535
|
+
*/
|
|
536
|
+
readonly initURL?: string;
|
|
537
|
+
/**
|
|
538
|
+
* The URL string after normalization, with method modifiers removed(readonly)
|
|
539
|
+
*
|
|
540
|
+
* Method modifiers like "@get/", "@post/" are stripped to create a clean URL
|
|
541
|
+
* for parameter substitution and final URL construction.
|
|
542
|
+
*
|
|
543
|
+
*/
|
|
544
|
+
readonly initURLNormalized?: string;
|
|
545
|
+
/**
|
|
546
|
+
* Parameters to be substituted into URL path segments.
|
|
547
|
+
*
|
|
548
|
+
* Supports both object-style (named parameters) and array-style (positional parameters)
|
|
549
|
+
* for flexible URL parameter substitution.
|
|
550
|
+
*
|
|
551
|
+
* @example
|
|
552
|
+
* ```typescript
|
|
553
|
+
* // Object-style parameters (recommended)
|
|
554
|
+
* const namedParams: URLOptions = {
|
|
555
|
+
* initURL: "/users/:userId/posts/:postId",
|
|
556
|
+
* params: { userId: "123", postId: "456" }
|
|
557
|
+
* };
|
|
558
|
+
* // Results in: /users/123/posts/456
|
|
559
|
+
*
|
|
560
|
+
* // Array-style parameters (positional)
|
|
561
|
+
* const positionalParams: URLOptions = {
|
|
562
|
+
* initURL: "/users/:userId/posts/:postId",
|
|
563
|
+
* params: ["123", "456"] // Maps in order: userId=123, postId=456
|
|
564
|
+
* };
|
|
565
|
+
* // Results in: /users/123/posts/456
|
|
566
|
+
*
|
|
567
|
+
* // Single parameter
|
|
568
|
+
* const singleParam: URLOptions = {
|
|
569
|
+
* initURL: "/users/:id",
|
|
570
|
+
* params: { id: "user-123" }
|
|
571
|
+
* };
|
|
572
|
+
* // Results in: /users/user-123
|
|
573
|
+
* ```
|
|
574
|
+
*/
|
|
575
|
+
params?: Params;
|
|
576
|
+
/**
|
|
577
|
+
* Query parameters to append to the URL as search parameters.
|
|
578
|
+
*
|
|
579
|
+
* These will be serialized into the URL query string using standard
|
|
580
|
+
* URL encoding practices.
|
|
581
|
+
*
|
|
582
|
+
* @example
|
|
583
|
+
* ```typescript
|
|
584
|
+
* // Basic query parameters
|
|
585
|
+
* const queryOptions: URLOptions = {
|
|
586
|
+
* initURL: "/users",
|
|
587
|
+
* query: {
|
|
588
|
+
* page: 1,
|
|
589
|
+
* limit: 10,
|
|
590
|
+
* search: "john doe",
|
|
591
|
+
* active: true
|
|
592
|
+
* }
|
|
593
|
+
* };
|
|
594
|
+
* // Results in: /users?page=1&limit=10&search=john%20doe&active=true
|
|
595
|
+
*
|
|
596
|
+
* // Filtering and sorting
|
|
597
|
+
* const filterOptions: URLOptions = {
|
|
598
|
+
* initURL: "/products",
|
|
599
|
+
* query: {
|
|
600
|
+
* category: "electronics",
|
|
601
|
+
* minPrice: 100,
|
|
602
|
+
* maxPrice: 500,
|
|
603
|
+
* sortBy: "price",
|
|
604
|
+
* order: "asc"
|
|
605
|
+
* }
|
|
606
|
+
* };
|
|
607
|
+
* // Results in: /products?category=electronics&minPrice=100&maxPrice=500&sortBy=price&order=asc
|
|
608
|
+
* ```
|
|
609
|
+
*/
|
|
610
|
+
query?: Query;
|
|
611
|
+
}
|
|
612
|
+
//#endregion
|
|
613
|
+
//#region src/utils/external/error.d.ts
|
|
614
|
+
type HTTPErrorDetails<TErrorData> = Pick<CallApiExtraOptions, "defaultHTTPErrorMessage"> & {
|
|
615
|
+
errorData: TErrorData;
|
|
616
|
+
response: Response;
|
|
617
|
+
};
|
|
618
|
+
declare class HTTPError<TErrorData = Record<string, unknown>> extends Error {
|
|
619
|
+
errorData: HTTPErrorDetails<TErrorData>["errorData"];
|
|
620
|
+
readonly httpErrorSymbol: symbol;
|
|
621
|
+
name: "HTTPError";
|
|
622
|
+
response: HTTPErrorDetails<TErrorData>["response"];
|
|
623
|
+
constructor(errorDetails: HTTPErrorDetails<TErrorData>, errorOptions?: ErrorOptions);
|
|
624
|
+
/**
|
|
625
|
+
* @description Checks if the given error is an instance of HTTPError
|
|
626
|
+
* @param error - The error to check
|
|
627
|
+
* @returns true if the error is an instance of HTTPError, false otherwise
|
|
628
|
+
*/
|
|
629
|
+
static isError<TErrorData>(error: unknown): error is HTTPError<TErrorData>;
|
|
630
|
+
}
|
|
631
|
+
type SafeExtract<TUnion, TKey extends TUnion> = Extract<TUnion, TKey>;
|
|
632
|
+
type ValidationErrorDetails = {
|
|
633
|
+
/**
|
|
366
634
|
* The cause of the validation error.
|
|
367
635
|
*
|
|
368
636
|
* It's either the name the schema for which validation failed, or the name of the schema config option that led to the validation error.
|
|
@@ -392,1525 +660,1261 @@ declare class ValidationError extends Error {
|
|
|
392
660
|
static isError(error: unknown): error is ValidationError;
|
|
393
661
|
}
|
|
394
662
|
//#endregion
|
|
395
|
-
//#region src/
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
type
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
type ResponseTypeMap<TData> = { [Key in keyof InitResponseTypeMap<TData>]: Awaited<ReturnType<InitResponseTypeMap<TData>[Key]>>; };
|
|
410
|
-
type GetResponseType<TData, TResponseType extends ResponseTypeType, TComputedResponseTypeMap extends ResponseTypeMap<TData> = ResponseTypeMap<TData>> = null extends TResponseType ? TComputedResponseTypeMap["json"] : TResponseType extends NonNullable<ResponseTypeType> ? TComputedResponseTypeMap[TResponseType] : never;
|
|
411
|
-
type CallApiResultSuccessVariant<TData> = {
|
|
412
|
-
data: NoInferUnMasked<TData>;
|
|
413
|
-
error: null;
|
|
414
|
-
response: Response;
|
|
415
|
-
};
|
|
416
|
-
type PossibleJavaScriptError = UnmaskType<{
|
|
417
|
-
errorData: false;
|
|
418
|
-
message: string;
|
|
419
|
-
name: "AbortError" | "Error" | "SyntaxError" | "TimeoutError" | "TypeError" | AnyString;
|
|
420
|
-
originalError: DOMException | Error | SyntaxError | TypeError;
|
|
421
|
-
}>;
|
|
422
|
-
type PossibleHTTPError<TErrorData> = UnmaskType<{
|
|
423
|
-
errorData: NoInferUnMasked<TErrorData>;
|
|
424
|
-
message: string;
|
|
425
|
-
name: "HTTPError";
|
|
426
|
-
originalError: HTTPError;
|
|
427
|
-
}>;
|
|
428
|
-
type PossibleValidationError = UnmaskType<{
|
|
429
|
-
errorData: ValidationError["errorData"];
|
|
430
|
-
issueCause: ValidationError["issueCause"];
|
|
431
|
-
message: string;
|
|
432
|
-
name: "ValidationError";
|
|
433
|
-
originalError: ValidationError;
|
|
434
|
-
}>;
|
|
435
|
-
type CallApiResultErrorVariant<TErrorData> = {
|
|
436
|
-
data: null;
|
|
437
|
-
error: PossibleHTTPError<TErrorData>;
|
|
438
|
-
response: Response;
|
|
439
|
-
} | {
|
|
440
|
-
data: null;
|
|
441
|
-
error: PossibleJavaScriptError;
|
|
442
|
-
response: Response | null;
|
|
443
|
-
} | {
|
|
444
|
-
data: null;
|
|
445
|
-
error: PossibleValidationError;
|
|
446
|
-
response: Response | null;
|
|
447
|
-
};
|
|
448
|
-
type CallApiResultSuccessOrErrorVariant<TData, TError> = CallApiResultErrorVariant<TError> | CallApiResultSuccessVariant<TData>;
|
|
449
|
-
type GetCallApiResult<TThrowOnError extends ThrowOnErrorBoolean, TResultWithException extends CallApiResultSuccessVariant<unknown>, TResultWithoutException extends CallApiResultSuccessOrErrorVariant<unknown, unknown>> = TThrowOnError extends true ? TResultWithException : TResultWithoutException;
|
|
450
|
-
type ResultModeMap<TData = DefaultDataType, TErrorData = DefaultDataType, TThrowOnError extends ThrowOnErrorBoolean = DefaultThrowOnError, TComputedResult extends GetCallApiResult<TThrowOnError, CallApiResultSuccessVariant<TData>, CallApiResultSuccessOrErrorVariant<TData, TErrorData>> = GetCallApiResult<TThrowOnError, CallApiResultSuccessVariant<TData>, CallApiResultSuccessOrErrorVariant<TData, TErrorData>>> = UnmaskType<{
|
|
451
|
-
all: TComputedResult;
|
|
452
|
-
fetchApi: TComputedResult["response"];
|
|
453
|
-
onlyData: TComputedResult["data"];
|
|
454
|
-
onlyResponse: TComputedResult["response"];
|
|
455
|
-
withoutResponse: Prettify<DistributiveOmit<TComputedResult, "response">>;
|
|
456
|
-
}>;
|
|
457
|
-
type ResultModePlaceholder = null;
|
|
458
|
-
type ResultModeUnion = keyof ResultModeMap;
|
|
459
|
-
type ResultModeType = ResultModePlaceholder | ResultModeUnion;
|
|
460
|
-
type InferCallApiResult<TData, TErrorData, TResultMode extends ResultModeType, TThrowOnError extends ThrowOnErrorBoolean, TComputedResultModeMapWithException extends ResultModeMap<TData, TErrorData, true> = ResultModeMap<TData, TErrorData, true>, TComputedResultModeMapWithoutException extends ResultModeMap<TData, TErrorData, TThrowOnError> = ResultModeMap<TData, TErrorData, TThrowOnError>> = TErrorData extends false ? TComputedResultModeMapWithException["onlyData"] : TErrorData extends false | undefined ? TComputedResultModeMapWithException["onlyData"] : ResultModePlaceholder extends TResultMode ? TComputedResultModeMapWithoutException["all"] : TResultMode extends ResultModeUnion ? TComputedResultModeMapWithoutException[TResultMode] : never;
|
|
461
|
-
type ErrorInfoOptions = Pick<CallApiExtraOptions, "cloneResponse" | "resultMode"> & {
|
|
462
|
-
message?: string;
|
|
463
|
-
};
|
|
464
|
-
//#endregion
|
|
465
|
-
//#region src/middlewares.d.ts
|
|
466
|
-
type FetchImpl = UnmaskType<(input: string | Request | URL, init?: RequestInit) => Awaitable<Response>>;
|
|
467
|
-
type FetchMiddlewareContext<TCallApiContext extends CallApiContext> = RequestContext<TCallApiContext> & {
|
|
468
|
-
fetchImpl: FetchImpl;
|
|
663
|
+
//#region src/types/options-types.d.ts
|
|
664
|
+
interface Register {}
|
|
665
|
+
type GlobalMeta = Register extends {
|
|
666
|
+
meta?: infer TMeta extends DefaultMetaObject;
|
|
667
|
+
} ? TMeta : DefaultMetaObject;
|
|
668
|
+
type FetchSpecificKeysUnion = Exclude<(typeof fetchSpecificKeys)[number], "body" | "headers" | "method">;
|
|
669
|
+
type ModifiedRequestInit = RequestInit & {
|
|
670
|
+
duplex?: "half";
|
|
671
|
+
/**
|
|
672
|
+
* Custom fetch options that are merged into the final request configuration.
|
|
673
|
+
*
|
|
674
|
+
* This property is intended for environment-specific extensions not included in the standard web `RequestInit` type, such as `dispatcher` for Undici/Node.js or the `next` object for Next.js extended fetch.
|
|
675
|
+
*/
|
|
676
|
+
extraFetchOptions?: RequestInit;
|
|
469
677
|
};
|
|
470
|
-
|
|
678
|
+
type CallApiRequestOptions<TBody = Body> = {
|
|
471
679
|
/**
|
|
472
|
-
*
|
|
680
|
+
* Body of the request, can be a object or any other supported body type.
|
|
681
|
+
*/
|
|
682
|
+
body?: TBody;
|
|
683
|
+
/**
|
|
684
|
+
* Headers to be used in the request.
|
|
685
|
+
*/
|
|
686
|
+
headers?: HeadersOption;
|
|
687
|
+
/**
|
|
688
|
+
* HTTP method for the request.
|
|
689
|
+
* @default "GET"
|
|
690
|
+
*/
|
|
691
|
+
method?: MethodUnion;
|
|
692
|
+
} & Pick<ModifiedRequestInit, FetchSpecificKeysUnion>;
|
|
693
|
+
type SharedExtraOptions<TCallApiContext extends CallApiContext = DefaultCallApiContext, TData = DefaultDataType, TErrorData = DefaultDataType, TResultMode extends ResultModeType = ResultModeType, TThrowOnError extends ThrowOnErrorBoolean = DefaultThrowOnError, TResponseType extends ResponseTypeType = ResponseTypeType, TBody = Body> = DedupeOptions & HookConfigOptions & HooksOrHooksArray<NoInferUnMasked<TCallApiContext>> & Middlewares<NoInferUnMasked<TCallApiContext>> & RefetchOptions & ResultModeOption<TErrorData, TResultMode> & RetryOptions<TErrorData> & Partial<TCallApiContext["InferredExtraOptions"]> & ThrowOnErrorOption<TErrorData, TThrowOnError> & URLOptions & {
|
|
694
|
+
/**
|
|
695
|
+
* Automatically add an Authorization header value.
|
|
473
696
|
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
697
|
+
* Supports multiple authentication patterns:
|
|
698
|
+
* - String: Direct authorization header value
|
|
699
|
+
* - Auth object: Structured authentication configuration
|
|
477
700
|
*
|
|
478
|
-
*
|
|
701
|
+
* ```
|
|
702
|
+
*/
|
|
703
|
+
auth?: AuthOption;
|
|
704
|
+
/**
|
|
705
|
+
* Custom function to serialize request body objects into strings.
|
|
706
|
+
*
|
|
707
|
+
* Useful for custom string serialization formats or when the default JSON
|
|
708
|
+
* serialization doesn't meet your needs.
|
|
479
709
|
*
|
|
480
710
|
* @example
|
|
481
711
|
* ```ts
|
|
482
|
-
* //
|
|
483
|
-
*
|
|
484
|
-
*
|
|
485
|
-
*
|
|
486
|
-
*
|
|
712
|
+
* // XML serialization
|
|
713
|
+
* bodySerializer: (body) => {
|
|
714
|
+
* return `<request>${Object.entries(body)
|
|
715
|
+
* .map(([key, value]) => `<${key}>${value}</${key}>`)
|
|
716
|
+
* .join('')}</request>`;
|
|
717
|
+
* }
|
|
487
718
|
*
|
|
488
|
-
*
|
|
719
|
+
* // Custom JSON with specific formatting
|
|
720
|
+
* bodySerializer: (body) => JSON.stringify(body, null, 2)
|
|
721
|
+
* ```
|
|
722
|
+
*/
|
|
723
|
+
bodySerializer?: (body: TBody extends SerializableObject ? TBody : SerializableObject) => string;
|
|
724
|
+
/**
|
|
725
|
+
* Custom function to transform the request body before it is passed to fetch.
|
|
489
726
|
*
|
|
490
|
-
*
|
|
491
|
-
*
|
|
492
|
-
* }
|
|
727
|
+
* Useful for converting plain objects into formats like `FormData`,
|
|
728
|
+
* `URLSearchParams`, `Blob`, or other Fetch-compatible body values.
|
|
493
729
|
*
|
|
494
|
-
*
|
|
495
|
-
* cache.set(key, response.clone());
|
|
730
|
+
* Takes precedence over `bodySerializer`.
|
|
496
731
|
*
|
|
497
|
-
*
|
|
498
|
-
*
|
|
732
|
+
* @example
|
|
733
|
+
* ```ts
|
|
734
|
+
* bodyTransformer: ({ body }) => {
|
|
735
|
+
* const formData = new FormData();
|
|
499
736
|
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
* return new Response('{"error": "offline"}', { status: 503 });
|
|
504
|
-
* }
|
|
737
|
+
* Object.entries(body).forEach(([key, value]) => {
|
|
738
|
+
* formData.append(key, String(value));
|
|
739
|
+
* });
|
|
505
740
|
*
|
|
506
|
-
* return
|
|
741
|
+
* return formData;
|
|
507
742
|
* }
|
|
508
743
|
* ```
|
|
509
744
|
*/
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
type PluginSetupContext<TCallApiContext extends CallApiContext = DefaultCallApiContext> = RequestContext<TCallApiContext> & ReturnType<typeof getCurrentRouteSchemaKeyAndMainInitURL>;
|
|
515
|
-
type PluginInitResult<TCallApiContext extends CallApiContext = DefaultCallApiContext> = Partial<Omit<PluginSetupContext<TCallApiContext>, "initURL" | "request"> & {
|
|
516
|
-
initURL: InitURLOrURLObject;
|
|
517
|
-
request: CallApiRequestOptions;
|
|
518
|
-
}>;
|
|
519
|
-
type GetDefaultDataTypeForPlugins<TData> = DefaultDataType extends TData ? never : TData;
|
|
520
|
-
type PluginHooks<TCallApiContext extends CallApiContext = DefaultCallApiContext> = HooksOrHooksArray<OverrideCallApiContext<TCallApiContext, {
|
|
521
|
-
Data: GetDefaultDataTypeForPlugins<TCallApiContext["Data"]>;
|
|
522
|
-
ErrorData: GetDefaultDataTypeForPlugins<TCallApiContext["ErrorData"]>;
|
|
523
|
-
}>>;
|
|
524
|
-
type PluginMiddlewares<TCallApiContext extends CallApiContext = DefaultCallApiContext> = Middlewares<OverrideCallApiContext<TCallApiContext, {
|
|
525
|
-
Data: GetDefaultDataTypeForPlugins<TCallApiContext["Data"]>;
|
|
526
|
-
ErrorData: GetDefaultDataTypeForPlugins<TCallApiContext["ErrorData"]>;
|
|
527
|
-
}>>;
|
|
528
|
-
interface CallApiPlugin<TCallApiContext extends CallApiContext = DefaultCallApiContext> {
|
|
745
|
+
bodyTransformer?: (context: {
|
|
746
|
+
body: TBody;
|
|
747
|
+
headers: Headers;
|
|
748
|
+
}) => Body;
|
|
529
749
|
/**
|
|
530
|
-
*
|
|
750
|
+
* Whether to clone the response so it can be read multiple times.
|
|
751
|
+
*
|
|
752
|
+
* By default, response streams can only be consumed once. Enable this when you need
|
|
753
|
+
* to read the response in multiple places (e.g., in hooks and main code).
|
|
754
|
+
*
|
|
755
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Response/clone
|
|
756
|
+
* @default false
|
|
531
757
|
*/
|
|
532
|
-
|
|
758
|
+
cloneResponse?: boolean;
|
|
533
759
|
/**
|
|
534
|
-
*
|
|
760
|
+
* Custom fetch implementation to replace the default fetch function.
|
|
761
|
+
*
|
|
762
|
+
* Useful for testing, adding custom behavior, or using alternative HTTP clients
|
|
763
|
+
* that implement the fetch API interface.
|
|
764
|
+
*
|
|
765
|
+
* @example
|
|
766
|
+
* ```ts
|
|
767
|
+
* // Use node-fetch in Node.js environments
|
|
768
|
+
* import fetch from 'node-fetch';
|
|
769
|
+
*
|
|
770
|
+
* // Mock fetch for testing
|
|
771
|
+
* customFetchImpl: async (url, init) => {
|
|
772
|
+
* return new Response(JSON.stringify({ mocked: true }), {
|
|
773
|
+
* status: 200,
|
|
774
|
+
* headers: { 'Content-Type': 'application/json' }
|
|
775
|
+
* });
|
|
776
|
+
* }
|
|
777
|
+
*
|
|
778
|
+
* // Add custom logging to all requests
|
|
779
|
+
* customFetchImpl: async (url, init) => {
|
|
780
|
+
* console.log(`Fetching: ${url}`);
|
|
781
|
+
* const response = await fetch(url, init);
|
|
782
|
+
* console.log(`Response: ${response.status}`);
|
|
783
|
+
* return response;
|
|
784
|
+
* }
|
|
785
|
+
*
|
|
786
|
+
* // Use with custom HTTP client
|
|
787
|
+
* customFetchImpl: async (url, init) => {
|
|
788
|
+
* // Convert to your preferred HTTP client format
|
|
789
|
+
* return await customHttpClient.request({
|
|
790
|
+
* url: url.toString(),
|
|
791
|
+
* method: init?.method || 'GET',
|
|
792
|
+
* headers: init?.headers,
|
|
793
|
+
* body: init?.body
|
|
794
|
+
* });
|
|
795
|
+
* }
|
|
796
|
+
* ```
|
|
535
797
|
*/
|
|
536
|
-
|
|
798
|
+
customFetchImpl?: FetchImpl;
|
|
537
799
|
/**
|
|
538
|
-
*
|
|
800
|
+
* Enable debug mode for the request.
|
|
801
|
+
*
|
|
802
|
+
* @default true
|
|
539
803
|
*/
|
|
540
|
-
|
|
804
|
+
debugMode?: boolean;
|
|
541
805
|
/**
|
|
542
|
-
*
|
|
806
|
+
* Default HTTP error message when server doesn't provide one.
|
|
807
|
+
*
|
|
808
|
+
* Can be a static string or a function that receives error context
|
|
809
|
+
* to generate dynamic error messages based on the response.
|
|
810
|
+
*
|
|
811
|
+
* @default "Failed to fetch data from server!"
|
|
812
|
+
*
|
|
813
|
+
* @example
|
|
814
|
+
* ```ts
|
|
815
|
+
* // Static error message
|
|
816
|
+
* defaultHTTPErrorMessage: "API request failed. Please try again."
|
|
817
|
+
*
|
|
818
|
+
* // Dynamic error message based on status code
|
|
819
|
+
* defaultHTTPErrorMessage: ({ response }) => {
|
|
820
|
+
* switch (response.status) {
|
|
821
|
+
* case 401: return "Authentication required. Please log in.";
|
|
822
|
+
* case 403: return "Access denied. Insufficient permissions.";
|
|
823
|
+
* case 404: return "Resource not found.";
|
|
824
|
+
* case 429: return "Too many requests. Please wait and try again.";
|
|
825
|
+
* case 500: return "Server error. Please contact support.";
|
|
826
|
+
* default: return `Request failed with status ${response.status}`;
|
|
827
|
+
* }
|
|
828
|
+
* }
|
|
829
|
+
*
|
|
830
|
+
* // Include error data in message
|
|
831
|
+
* defaultHTTPErrorMessage: ({ errorData, response }) => {
|
|
832
|
+
* const userMessage = errorData?.message || "Unknown error occurred";
|
|
833
|
+
* return `${userMessage} (Status: ${response.status})`;
|
|
834
|
+
* }
|
|
835
|
+
* ```
|
|
543
836
|
*/
|
|
544
|
-
|
|
837
|
+
defaultHTTPErrorMessage?: string | ((context: Pick<HTTPError<TErrorData>, "errorData" | "response">) => string);
|
|
545
838
|
/**
|
|
546
|
-
*
|
|
839
|
+
* Custom function to parse response strings into actual value instead of the default response.json().
|
|
840
|
+
*
|
|
841
|
+
* Useful when you need custom parsing logic for specific response formats.
|
|
842
|
+
*
|
|
843
|
+
* @example
|
|
844
|
+
* ```ts
|
|
845
|
+
* responseParser: (text) => {
|
|
846
|
+
* return JSON.parse(text);
|
|
847
|
+
* }
|
|
848
|
+
*
|
|
849
|
+
* // Parse XML responses
|
|
850
|
+
* responseParser: (text) => {
|
|
851
|
+
* const parser = new DOMParser();
|
|
852
|
+
* const doc = parser.parseFromString(text, "text/xml");
|
|
853
|
+
* return xmlToObject(doc);
|
|
854
|
+
* }
|
|
855
|
+
*
|
|
856
|
+
* // Parse CSV responses
|
|
857
|
+
* responseParser: (text) => {
|
|
858
|
+
* const lines = text.split('\n');
|
|
859
|
+
* const headers = lines[0].split(',');
|
|
860
|
+
* const data = lines.slice(1).map(line => {
|
|
861
|
+
* const values = line.split(',');
|
|
862
|
+
* return headers.reduce((obj, header, index) => {
|
|
863
|
+
* obj[header] = values[index];
|
|
864
|
+
* return obj;
|
|
865
|
+
* }, {});
|
|
866
|
+
* });
|
|
867
|
+
* return data;
|
|
868
|
+
* }
|
|
869
|
+
*
|
|
870
|
+
* ```
|
|
547
871
|
*/
|
|
548
|
-
|
|
872
|
+
responseParser?: ResponseParser<TData>;
|
|
549
873
|
/**
|
|
550
|
-
*
|
|
874
|
+
* Expected response type, determines how the response body is parsed.
|
|
875
|
+
*
|
|
876
|
+
* Different response types trigger different parsing methods:
|
|
877
|
+
* - **"json"**: Parses as JSON using response.json()
|
|
878
|
+
* - **"text"**: Returns as plain text using response.text()
|
|
879
|
+
* - **"blob"**: Returns as Blob using response.blob()
|
|
880
|
+
* - **"arrayBuffer"**: Returns as ArrayBuffer using response.arrayBuffer()
|
|
881
|
+
* - **"stream"**: Returns the response body stream directly
|
|
882
|
+
*
|
|
883
|
+
* @default "json"
|
|
884
|
+
*
|
|
885
|
+
* @example
|
|
886
|
+
* ```ts
|
|
887
|
+
* // JSON API responses (default)
|
|
888
|
+
* responseType: "json"
|
|
889
|
+
*
|
|
890
|
+
* // Plain text responses
|
|
891
|
+
* responseType: "text"
|
|
892
|
+
* // Usage: const csvData = await callApi("/export.csv", { responseType: "text" });
|
|
893
|
+
*
|
|
894
|
+
* // File downloads
|
|
895
|
+
* responseType: "blob"
|
|
896
|
+
* // Usage: const file = await callApi("/download/file.pdf", { responseType: "blob" });
|
|
897
|
+
*
|
|
898
|
+
* // Binary data
|
|
899
|
+
* responseType: "arrayBuffer"
|
|
900
|
+
* // Usage: const buffer = await callApi("/binary-data", { responseType: "arrayBuffer" });
|
|
901
|
+
*
|
|
902
|
+
* // Streaming responses
|
|
903
|
+
* responseType: "stream"
|
|
904
|
+
* // Usage: const stream = await callApi("/large-dataset", { responseType: "stream" });
|
|
905
|
+
* ```
|
|
551
906
|
*/
|
|
552
|
-
|
|
907
|
+
responseType?: TResponseType;
|
|
553
908
|
/**
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
909
|
+
* Dictates how CallApi processes and returns the final result
|
|
910
|
+
*
|
|
911
|
+
- **"all"** (default): Returns `{ data, error, response }`. Standard lifecycle.
|
|
912
|
+
- **"onlyData"**: Returns only the data from the response.
|
|
913
|
+
- **"onlyResponse"**: Returns only the `Response` object.
|
|
914
|
+
- **"fetchApi"**: Also returns only the `Response` object, but also skips parsing of the response body internally and data/errorData schema validation.
|
|
915
|
+
- **"withoutResponse"**: Returns `{ data, error }`. Standard lifecycle, but omits the `response` property.
|
|
916
|
+
*
|
|
917
|
+
*
|
|
918
|
+
* **Note:**
|
|
919
|
+
* By default, simplified modes (`"onlyData"`, `"onlyResponse"`, `"fetchApi"`) do not throw errors.
|
|
920
|
+
* Success/failure should be handled via hooks or by checking the return value (e.g., `if (data)` or `if (response?.ok)`).
|
|
921
|
+
* To force an exception instead, set `throwOnError: true`.
|
|
922
|
+
*
|
|
923
|
+
*
|
|
924
|
+
* @default "all"
|
|
925
|
+
*
|
|
926
|
+
*/
|
|
927
|
+
resultMode?: TResultMode;
|
|
557
928
|
/**
|
|
558
|
-
*
|
|
559
|
-
*/
|
|
560
|
-
setup?: (context: PluginSetupContext<TCallApiContext>) => Awaitable<PluginInitResult<TCallApiContext>> | Awaitable<void>;
|
|
561
|
-
/**
|
|
562
|
-
* A version for the plugin
|
|
563
|
-
*/
|
|
564
|
-
version?: string;
|
|
565
|
-
}
|
|
566
|
-
type InferPluginExtraOptions<TPluginArray extends CallApiPlugin[]> = UnionToIntersection<TPluginArray extends Array<infer TPlugin> ? TPlugin extends CallApiPlugin ? TPlugin["defineExtraOptions"] extends AnyFunction<infer TResult> ? InferSchemaOutput<TResult, TResult> : never : never : never>;
|
|
567
|
-
//#endregion
|
|
568
|
-
//#region src/types/default-types.d.ts
|
|
569
|
-
type DefaultDataType = unknown;
|
|
570
|
-
type DefaultPluginArray = CallApiPlugin[];
|
|
571
|
-
type DefaultThrowOnError = boolean;
|
|
572
|
-
type DefaultMetaObject = Record<string, unknown>;
|
|
573
|
-
type DefaultCallApiContext = Prettify<OverrideCallApiContext<Required<CallApiContext>, {
|
|
574
|
-
Meta: GlobalMeta;
|
|
575
|
-
}>>;
|
|
576
|
-
//#endregion
|
|
577
|
-
//#region src/utils/external/body.d.ts
|
|
578
|
-
type BodyType = NonNullable<CallApiRequestOptions["body"]>;
|
|
579
|
-
declare const toSearchParams: <TSchema extends CallApiSchemaType<BodyType>>(data: InferSchemaOutput<TSchema>, schema?: TSchema) => URLSearchParams;
|
|
580
|
-
declare const toQueryString: <TSchema extends CallApiSchemaType<BodyType>>(...parameters: Parameters<typeof toSearchParams<TSchema>>) => string;
|
|
581
|
-
/**
|
|
582
|
-
* @description Converts a plain object to FormData.
|
|
583
|
-
*
|
|
584
|
-
* Handles various data types:
|
|
585
|
-
* - **Primitives** (string, number, boolean): Converted to strings
|
|
586
|
-
* - **Blobs/Files**: Added directly to FormData
|
|
587
|
-
* - **Arrays**: Each item is appended (allows multiple values for same key)
|
|
588
|
-
* - **Objects**: JSON stringified before adding to FormData
|
|
589
|
-
*
|
|
590
|
-
* @example
|
|
591
|
-
* ```ts
|
|
592
|
-
* // Basic usage
|
|
593
|
-
* const formData = toFormData({
|
|
594
|
-
* name: "John",
|
|
595
|
-
* age: 30,
|
|
596
|
-
* active: true
|
|
597
|
-
* });
|
|
598
|
-
*
|
|
599
|
-
* // With arrays
|
|
600
|
-
* const formData = toFormData({
|
|
601
|
-
* tags: ["javascript", "typescript"],
|
|
602
|
-
* name: "John"
|
|
603
|
-
* });
|
|
604
|
-
*
|
|
605
|
-
* // With files
|
|
606
|
-
* const formData = toFormData({
|
|
607
|
-
* avatar: fileBlob,
|
|
608
|
-
* name: "John"
|
|
609
|
-
* });
|
|
610
|
-
*
|
|
611
|
-
* // With nested objects (one level only)
|
|
612
|
-
* const formData = toFormData({
|
|
613
|
-
* user: { name: "John", age: 30 },
|
|
614
|
-
* settings: { theme: "dark" }
|
|
615
|
-
* });
|
|
616
|
-
*/
|
|
617
|
-
declare const toFormData: <TSchema extends CallApiSchemaType<BodyType>>(data: InferSchemaOutput<TSchema>, schema?: TSchema) => FormData;
|
|
618
|
-
//#endregion
|
|
619
|
-
//#region src/utils/external/define.d.ts
|
|
620
|
-
declare const defineSchema: <const TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, const TSchemaConfig extends CallApiSchemaConfig>(routes: TBaseSchemaRoutes, config?: Satisfies<TSchemaConfig, CallApiSchemaConfig>) => {
|
|
621
|
-
config: Writeable<Satisfies<TSchemaConfig, CallApiSchemaConfig>, "deep">;
|
|
622
|
-
routes: Writeable<TBaseSchemaRoutes, "deep">;
|
|
623
|
-
};
|
|
624
|
-
declare const defineSchemaRoutes: <const TSchemaRoutes extends BaseCallApiSchemaRoutes>(routes: TSchemaRoutes) => Writeable<typeof routes, "deep">;
|
|
625
|
-
declare const defineMainSchema: <const TSchema extends CallApiSchema>(mainSchema: Satisfies<TSchema, CallApiSchema>) => Writeable<typeof mainSchema, "deep">;
|
|
626
|
-
declare const defineSchemaConfig: <const TSchemaConfig extends CallApiSchemaConfig>(config: Satisfies<TSchemaConfig, CallApiSchemaConfig>) => Writeable<typeof config, "deep">;
|
|
627
|
-
declare const definePlugin: <const TPlugin extends CallApiPlugin>(plugin: TPlugin) => Writeable<typeof plugin, "deep">;
|
|
628
|
-
type BaseConfigObject = Exclude<BaseCallApiConfig, AnyFunction>;
|
|
629
|
-
type BaseConfigFn = Extract<BaseCallApiConfig, AnyFunction>;
|
|
630
|
-
type DefineBaseConfig = {
|
|
631
|
-
<const TBaseConfig extends BaseConfigObject>(baseConfig: Satisfies<TBaseConfig, BaseConfigObject>): Writeable<typeof baseConfig, "deep">;
|
|
632
|
-
<const TBaseConfig extends BaseConfigObject>(baseConfig: (...parameters: Parameters<BaseConfigFn>) => Writeable<TBaseConfig, "deep">): typeof baseConfig;
|
|
633
|
-
};
|
|
634
|
-
declare const defineBaseConfig: DefineBaseConfig;
|
|
635
|
-
declare const defineInstanceConfig: <const TInstanceConfig extends CallApiConfig>(config: TInstanceConfig) => Writeable<typeof config, "deep">;
|
|
636
|
-
//#endregion
|
|
637
|
-
//#region src/utils/external/guards.d.ts
|
|
638
|
-
declare const isHTTPError: <TErrorData>(error: CallApiResultErrorVariant<TErrorData>["error"] | null) => error is PossibleHTTPError<TErrorData>;
|
|
639
|
-
declare const isHTTPErrorInstance: <TErrorData>(error: unknown) => error is HTTPError<TErrorData>;
|
|
640
|
-
declare const isValidationError: (error: CallApiResultErrorVariant<unknown>["error"] | null) => error is PossibleValidationError;
|
|
641
|
-
declare const isValidationErrorInstance: (error: unknown) => error is ValidationError;
|
|
642
|
-
declare const isJavascriptError: (error: CallApiResultErrorVariant<unknown>["error"] | null) => error is PossibleJavaScriptError;
|
|
643
|
-
//#endregion
|
|
644
|
-
//#region src/utils/external/headers.d.ts
|
|
645
|
-
declare const objectifyHeaders: (headers: CallApiRequestOptions["headers"]) => Record<string, string>;
|
|
646
|
-
//#endregion
|
|
647
|
-
//#region src/retry.d.ts
|
|
648
|
-
declare const defaultRetryStatusCodesLookup: () => Readonly<{
|
|
649
|
-
408: "Request Timeout";
|
|
650
|
-
409: "Conflict";
|
|
651
|
-
425: "Too Early";
|
|
652
|
-
429: "Too Many Requests";
|
|
653
|
-
500: "Internal Server Error";
|
|
654
|
-
502: "Bad Gateway";
|
|
655
|
-
503: "Service Unavailable";
|
|
656
|
-
504: "Gateway Timeout";
|
|
657
|
-
}>;
|
|
658
|
-
type RetryStatusCodes = UnmaskType<AnyNumber | keyof ReturnType<typeof defaultRetryStatusCodesLookup>>;
|
|
659
|
-
type RetryCondition<TErrorData> = (context: ErrorContext<{
|
|
660
|
-
ErrorData: TErrorData;
|
|
661
|
-
}>) => Awaitable<boolean>;
|
|
662
|
-
type CallApiLooseImpl = (initURL: InitURLOrURLObject, init?: CallApiConfig) => Promise<CallApiResultLoose<unknown, unknown>>;
|
|
663
|
-
interface RetryOptions<TErrorData> {
|
|
664
|
-
/**
|
|
665
|
-
* Tracks the number of times the request has already been retried internally
|
|
666
|
-
* @internal
|
|
667
|
-
* @deprecated **WARNING**: This property is used internally to track retries. Please abstain from reading or modifying it.
|
|
668
|
-
*/
|
|
669
|
-
readonly ["~retryAttemptCount"]?: number;
|
|
670
|
-
/**
|
|
671
|
-
* Number of allowed retry attempts on HTTP errors
|
|
672
|
-
* @default 0
|
|
673
|
-
*/
|
|
674
|
-
retryAttempts?: number;
|
|
675
|
-
/**
|
|
676
|
-
* Callback whose return value determines if a request should be retried or not
|
|
677
|
-
*/
|
|
678
|
-
retryCondition?: RetryCondition<TErrorData>;
|
|
679
|
-
/**
|
|
680
|
-
* Delay between retries in milliseconds
|
|
681
|
-
* @default 1000
|
|
682
|
-
*/
|
|
683
|
-
retryDelay?: number | ((currentAttemptCount: number) => number);
|
|
684
|
-
/**
|
|
685
|
-
* Maximum delay in milliseconds. Only applies to exponential strategy
|
|
686
|
-
* @default 10000
|
|
687
|
-
*/
|
|
688
|
-
retryMaxDelay?: number;
|
|
689
|
-
/**
|
|
690
|
-
* HTTP methods that are allowed to retry
|
|
691
|
-
* @default ["GET", "POST"]
|
|
692
|
-
*/
|
|
693
|
-
retryMethods?: MethodUnion[];
|
|
694
|
-
/**
|
|
695
|
-
* HTTP status codes that trigger a retry
|
|
696
|
-
*/
|
|
697
|
-
retryStatusCodes?: RetryStatusCodes[];
|
|
698
|
-
/**
|
|
699
|
-
* Strategy to use when retrying
|
|
700
|
-
* @default "linear"
|
|
701
|
-
*/
|
|
702
|
-
retryStrategy?: "exponential" | "linear";
|
|
703
|
-
}
|
|
704
|
-
type RetryManagerContext = {
|
|
705
|
-
callApi: CallApiLooseImpl;
|
|
706
|
-
callApiArgs: {
|
|
707
|
-
config: CallApiConfig;
|
|
708
|
-
initURL: InitURLOrURLObject;
|
|
709
|
-
};
|
|
710
|
-
error: unknown;
|
|
711
|
-
errorContext: ErrorContext;
|
|
712
|
-
hookInfo: ExecuteHookInfo;
|
|
713
|
-
removeDedupeCacheEntry: () => void;
|
|
714
|
-
};
|
|
715
|
-
//#endregion
|
|
716
|
-
//#region src/refetch.d.ts
|
|
717
|
-
declare const shouldAttemptRefetchSymbol: unique symbol;
|
|
718
|
-
interface RefetchOptions {
|
|
719
|
-
/**
|
|
720
|
-
* Tracks if the refetching of the request should be attempted
|
|
721
|
-
* @internal
|
|
722
|
-
* @deprecated **WARNING**: This property is used internally to track retries. Please abstain from reading or modifying it.
|
|
723
|
-
*/
|
|
724
|
-
[shouldAttemptRefetchSymbol]?: boolean;
|
|
725
|
-
}
|
|
726
|
-
type RefetchFn = () => void;
|
|
727
|
-
type RefetchManagerResult = {
|
|
728
|
-
handleRefetch: () => Promise<CallApiResultLoose<unknown, unknown>> | null;
|
|
729
|
-
refetch: RefetchFn;
|
|
730
|
-
};
|
|
731
|
-
declare const createRefetchManager: (ctx: Pick<RetryManagerContext, "callApi" | "callApiArgs" | "removeDedupeCacheEntry"> & {
|
|
732
|
-
options: CallApiExtraOptions;
|
|
733
|
-
}) => RefetchManagerResult;
|
|
734
|
-
type RefetchFnOption = Pick<ReturnType<typeof createRefetchManager>, "refetch">;
|
|
735
|
-
//#endregion
|
|
736
|
-
//#region src/stream.d.ts
|
|
737
|
-
type StreamProgressEvent = {
|
|
738
|
-
/**
|
|
739
|
-
* Current chunk of data being streamed.
|
|
740
|
-
*
|
|
741
|
-
* Will be `null` on the final completion tick (when progress reaches 100%).
|
|
742
|
-
*/
|
|
743
|
-
chunk: Uint8Array | null;
|
|
744
|
-
/**
|
|
745
|
-
* Progress in percentage
|
|
746
|
-
*/
|
|
747
|
-
progress: number;
|
|
748
|
-
/**
|
|
749
|
-
* Total size of data in bytes
|
|
750
|
-
*/
|
|
751
|
-
totalBytes: number;
|
|
752
|
-
/**
|
|
753
|
-
* Amount of data transferred so far
|
|
754
|
-
*/
|
|
755
|
-
transferredBytes: number;
|
|
756
|
-
};
|
|
757
|
-
//#endregion
|
|
758
|
-
//#region src/hooks.d.ts
|
|
759
|
-
type CallApiRequestOptionsForHooks = Omit<CallApiRequestOptions, "headers"> & {
|
|
760
|
-
headers: Partial<Record<"Authorization" | "Content-Type" | CommonRequestHeaders, string>>;
|
|
761
|
-
};
|
|
762
|
-
type CallApiExtraOptionsForHooks<TCallApiContext extends CallApiContext = DefaultCallApiContext> = Hooks & Omit<CallApiExtraOptions<TCallApiContext>, keyof Hooks> & Pick<RefetchFnOption, "refetch">;
|
|
763
|
-
interface Hooks<TCallApiContext extends CallApiContext = DefaultCallApiContext> {
|
|
764
|
-
/**
|
|
765
|
-
* Hook called when any error occurs within the request/response lifecycle.
|
|
766
|
-
*
|
|
767
|
-
* This is a unified error handler that catches both request errors (network failures,
|
|
768
|
-
* timeouts, etc.) and response errors (HTTP error status codes). It's essentially
|
|
769
|
-
* a combination of `onRequestError` and `onResponseError` hooks.
|
|
770
|
-
*
|
|
771
|
-
* @param context - Error context containing error details, request info, and response (if available)
|
|
772
|
-
* @returns Promise or void - Hook can be async or sync
|
|
773
|
-
*/
|
|
774
|
-
onError?: (context: ErrorContext<TCallApiContext>) => Awaitable<unknown>;
|
|
775
|
-
/**
|
|
776
|
-
* Hook called before the HTTP request is sent and before any internal processing of the request object begins.
|
|
777
|
-
*
|
|
778
|
-
* This is the ideal place to modify request headers, add authentication,
|
|
779
|
-
* implement request logging, or perform any setup before the network call.
|
|
780
|
-
*
|
|
781
|
-
* @param context - Request context with mutable request object and configuration
|
|
782
|
-
* @returns Promise or void - Hook can be async or sync
|
|
783
|
-
*
|
|
784
|
-
*/
|
|
785
|
-
onRequest?: (context: RequestContext<TCallApiContext>) => Awaitable<unknown>;
|
|
786
|
-
/**
|
|
787
|
-
* Hook called when an error occurs during the fetch request itself.
|
|
788
|
-
*
|
|
789
|
-
* This handles network-level errors like connection failures, timeouts,
|
|
790
|
-
* DNS resolution errors, or other issues that prevent getting an HTTP response.
|
|
791
|
-
* Note that HTTP error status codes (4xx, 5xx) are handled by `onResponseError`.
|
|
792
|
-
*
|
|
793
|
-
* @param context - Request error context with error details and null response
|
|
794
|
-
* @returns Promise or void - Hook can be async or sync
|
|
795
|
-
*/
|
|
796
|
-
onRequestError?: (context: RequestErrorContext<TCallApiContext>) => Awaitable<unknown>;
|
|
797
|
-
/**
|
|
798
|
-
* Hook called just before the HTTP request is sent and after the request has been processed.
|
|
799
|
-
*
|
|
800
|
-
* @param context - Request context with mutable request object and configuration
|
|
801
|
-
*/
|
|
802
|
-
onRequestReady?: (context: RequestContext<TCallApiContext>) => Awaitable<unknown>;
|
|
803
|
-
/**
|
|
804
|
-
* Hook called during upload stream progress tracking.
|
|
805
|
-
*
|
|
806
|
-
* This hook is triggered when uploading data (like file uploads) and provides
|
|
807
|
-
* progress information about the upload. Useful for implementing progress bars
|
|
808
|
-
* or upload status indicators.
|
|
809
|
-
*
|
|
810
|
-
* @param context - Request stream context with progress event and request instance
|
|
811
|
-
* @returns Promise or void - Hook can be async or sync
|
|
812
|
-
*
|
|
813
|
-
*/
|
|
814
|
-
onRequestStream?: (context: RequestStreamContext<TCallApiContext>) => Awaitable<unknown>;
|
|
815
|
-
/**
|
|
816
|
-
* Hook called when any HTTP response is received from the API.
|
|
817
|
-
*
|
|
818
|
-
* This hook is triggered for both successful (2xx) and error (4xx, 5xx) responses.
|
|
819
|
-
* It's useful for response logging, metrics collection, or any processing that
|
|
820
|
-
* should happen regardless of response status.
|
|
821
|
-
*
|
|
822
|
-
* @param context - Response context with either success data or error information
|
|
823
|
-
* @returns Promise or void - Hook can be async or sync
|
|
824
|
-
*
|
|
825
|
-
*/
|
|
826
|
-
onResponse?: (context: ResponseContext<TCallApiContext>) => Awaitable<unknown>;
|
|
827
|
-
/**
|
|
828
|
-
* Hook called when an HTTP error response (4xx, 5xx) is received from the API.
|
|
829
|
-
*
|
|
830
|
-
* This handles server-side errors where an HTTP response was successfully received
|
|
831
|
-
* but indicates an error condition. Different from `onRequestError` which handles
|
|
832
|
-
* network-level failures.
|
|
833
|
-
*
|
|
834
|
-
* @param context - Response error context with HTTP error details and response
|
|
835
|
-
* @returns Promise or void - Hook can be async or sync
|
|
836
|
-
*/
|
|
837
|
-
onResponseError?: (context: ResponseErrorContext<TCallApiContext>) => Awaitable<unknown>;
|
|
838
|
-
/**
|
|
839
|
-
* Hook called during download stream progress tracking.
|
|
840
|
-
*
|
|
841
|
-
* This hook is triggered when downloading data (like file downloads) and provides
|
|
842
|
-
* progress information about the download. Useful for implementing progress bars
|
|
843
|
-
* or download status indicators.
|
|
844
|
-
*
|
|
845
|
-
* @param context - Response stream context with progress event and response
|
|
846
|
-
* @returns Promise or void - Hook can be async or sync
|
|
847
|
-
*
|
|
848
|
-
*/
|
|
849
|
-
onResponseStream?: (context: ResponseStreamContext<TCallApiContext>) => Awaitable<unknown>;
|
|
850
|
-
/**
|
|
851
|
-
* Hook called when a request is being retried.
|
|
852
|
-
*
|
|
853
|
-
* This hook is triggered before each retry attempt, providing information about
|
|
854
|
-
* the previous failure and the current retry attempt number. Useful for implementing
|
|
855
|
-
* custom retry logic, exponential backoff, or retry logging.
|
|
856
|
-
*
|
|
857
|
-
* @param context - Retry context with error details and retry attempt count
|
|
858
|
-
* @returns Promise or void - Hook can be async or sync
|
|
929
|
+
* Controls whether errors are thrown as exceptions or returned in the result.
|
|
859
930
|
*
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
/**
|
|
863
|
-
* Hook called when a successful response (2xx status) is received from the API.
|
|
931
|
+
* Can be a boolean or a function that receives the error and decides whether to throw.
|
|
932
|
+
* When true, errors are thrown as exceptions instead of being returned in the result object.
|
|
864
933
|
*
|
|
865
|
-
*
|
|
866
|
-
* the parsed response data. Ideal for success logging, caching, or post-processing
|
|
867
|
-
* of successful API responses.
|
|
934
|
+
* @default false
|
|
868
935
|
*
|
|
869
|
-
* @
|
|
870
|
-
*
|
|
936
|
+
* @example
|
|
937
|
+
* ```ts
|
|
938
|
+
* // Always throw errors
|
|
939
|
+
* throwOnError: true
|
|
940
|
+
* try {
|
|
941
|
+
* const data = await callApi("/users");
|
|
942
|
+
* console.log("Users:", data);
|
|
943
|
+
* } catch (error) {
|
|
944
|
+
* console.error("Request failed:", error);
|
|
945
|
+
* }
|
|
871
946
|
*
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
*
|
|
947
|
+
* // Never throw errors (default)
|
|
948
|
+
* throwOnError: false
|
|
949
|
+
* const { data, error } = await callApi("/users");
|
|
950
|
+
* if (error) {
|
|
951
|
+
* console.error("Request failed:", error);
|
|
952
|
+
* }
|
|
876
953
|
*
|
|
877
|
-
*
|
|
878
|
-
*
|
|
879
|
-
*
|
|
954
|
+
* // Conditionally throw based on error type
|
|
955
|
+
* throwOnError: (error) => {
|
|
956
|
+
* // Throw on client errors (4xx) but not server errors (5xx)
|
|
957
|
+
* return error.response?.status >= 400 && error.response?.status < 500;
|
|
958
|
+
* }
|
|
880
959
|
*
|
|
881
|
-
*
|
|
882
|
-
*
|
|
960
|
+
* // Throw only on specific status codes
|
|
961
|
+
* throwOnError: (error) => {
|
|
962
|
+
* const criticalErrors = [401, 403, 404];
|
|
963
|
+
* return criticalErrors.includes(error.response?.status);
|
|
964
|
+
* }
|
|
883
965
|
*
|
|
966
|
+
* // Throw on validation errors but not network errors
|
|
967
|
+
* throwOnError: (error) => {
|
|
968
|
+
* return error.type === "validation";
|
|
969
|
+
* }
|
|
970
|
+
* ```
|
|
884
971
|
*/
|
|
885
|
-
|
|
886
|
-
}
|
|
887
|
-
type HooksOrHooksArray<TCallApiContext extends NoInfer<CallApiContext> = DefaultCallApiContext> = { [Key in keyof Hooks<TCallApiContext>]: Hooks<TCallApiContext>[Key] | Array<Hooks<TCallApiContext>[Key]>; };
|
|
888
|
-
interface HookConfigOptions {
|
|
972
|
+
throwOnError?: ThrowOnErrorType<TErrorData, TThrowOnError>;
|
|
889
973
|
/**
|
|
890
|
-
*
|
|
891
|
-
*
|
|
892
|
-
* - **"parallel"**: All hooks execute simultaneously via Promise.all() for better performance
|
|
893
|
-
* - **"sequential"**: All hooks execute one by one in registration order via await in a loop
|
|
894
|
-
*
|
|
895
|
-
* This affects how ALL hooks execute together, regardless of their source (main or plugin).
|
|
974
|
+
* Request timeout in milliseconds. Request will be aborted if it takes longer.
|
|
896
975
|
*
|
|
897
|
-
*
|
|
898
|
-
|
|
899
|
-
hooksExecutionMode?: "parallel" | "sequential";
|
|
900
|
-
}
|
|
901
|
-
type RequestContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = {
|
|
902
|
-
/**
|
|
903
|
-
* Base configuration object passed to createFetchClient.
|
|
976
|
+
* Useful for preventing requests from hanging indefinitely and providing
|
|
977
|
+
* better user experience with predictable response times.
|
|
904
978
|
*
|
|
905
|
-
*
|
|
906
|
-
*
|
|
907
|
-
*
|
|
908
|
-
|
|
909
|
-
baseConfig: Exclude<BaseCallApiConfig, AnyFunction>;
|
|
910
|
-
/**
|
|
911
|
-
* Instance-specific configuration object passed to the callApi instance.
|
|
979
|
+
* @example
|
|
980
|
+
* ```ts
|
|
981
|
+
* // 5 second timeout
|
|
982
|
+
* timeout: 5000
|
|
912
983
|
*
|
|
913
|
-
*
|
|
914
|
-
*
|
|
915
|
-
|
|
916
|
-
config: CallApiConfig;
|
|
917
|
-
/**
|
|
918
|
-
* Merged options combining base config, instance config, and default options.
|
|
984
|
+
* // Different timeouts for different endpoints
|
|
985
|
+
* const quickApi = createFetchClient({ timeout: 3000 }); // 3s for fast endpoints
|
|
986
|
+
* const slowApi = createFetchClient({ timeout: 30000 }); // 30s for slow operations
|
|
919
987
|
*
|
|
920
|
-
*
|
|
921
|
-
*
|
|
922
|
-
|
|
923
|
-
options: CallApiExtraOptionsForHooks<TCallApiContext>;
|
|
924
|
-
/**
|
|
925
|
-
* Merged request object ready to be sent.
|
|
988
|
+
* // Per-request timeout override
|
|
989
|
+
* await callApi("/quick-data", { timeout: 1000 });
|
|
990
|
+
* await callApi("/slow-report", { timeout: 60000 });
|
|
926
991
|
*
|
|
927
|
-
*
|
|
928
|
-
*
|
|
929
|
-
*
|
|
992
|
+
* // No timeout (use with caution)
|
|
993
|
+
* timeout: 0
|
|
994
|
+
* ```
|
|
930
995
|
*/
|
|
931
|
-
|
|
932
|
-
};
|
|
933
|
-
type SuccessContext<TCallApiContext extends Pick<CallApiContext, "Data" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = DistributiveOmit<CallApiResultSuccessVariant<TCallApiContext["Data"]>, "error"> & RequestContext<TCallApiContext>;
|
|
934
|
-
type ResponseContext<TCallApiContext extends Pick<CallApiContext, "Data" | "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = RequestContext<TCallApiContext> & (Prettify<CallApiResultSuccessVariant<TCallApiContext["Data"]>> | Prettify<Extract<CallApiResultErrorVariant<TCallApiContext["ErrorData"]>, {
|
|
935
|
-
error: PossibleHTTPError<TCallApiContext["ErrorData"]>;
|
|
936
|
-
}>>);
|
|
937
|
-
type RequestStreamContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = RequestContext<TCallApiContext> & {
|
|
938
|
-
event: StreamProgressEvent;
|
|
939
|
-
requestInstance: Request;
|
|
940
|
-
};
|
|
941
|
-
type ResponseStreamContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = RequestContext<TCallApiContext> & {
|
|
942
|
-
event: StreamProgressEvent;
|
|
943
|
-
response: Response;
|
|
944
|
-
};
|
|
945
|
-
type ErrorContext<TCallApiContext extends Pick<CallApiContext, "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = DistributiveOmit<CallApiResultErrorVariant<TCallApiContext["ErrorData"]>, "data"> & RequestContext<TCallApiContext>;
|
|
946
|
-
type ValidationErrorContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = Extract<ErrorContext<TCallApiContext>, {
|
|
947
|
-
error: PossibleValidationError;
|
|
948
|
-
}> & RequestContext<TCallApiContext>;
|
|
949
|
-
type RequestErrorContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = Extract<ErrorContext<TCallApiContext>, {
|
|
950
|
-
error: PossibleJavaScriptError;
|
|
951
|
-
}> & RequestContext<TCallApiContext>;
|
|
952
|
-
type ResponseErrorContext<TCallApiContext extends Pick<CallApiContext, "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = Extract<ErrorContext<TCallApiContext>, {
|
|
953
|
-
error: PossibleHTTPError<TCallApiContext["ErrorData"]>;
|
|
954
|
-
}> & RequestContext<TCallApiContext>;
|
|
955
|
-
type RetryContext<TCallApiContext extends Pick<CallApiContext, "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = ErrorContext<TCallApiContext> & {
|
|
956
|
-
retryAttemptCount: number;
|
|
957
|
-
};
|
|
958
|
-
type ExecuteHookInfo = {
|
|
959
|
-
errorInfoOptions: ErrorInfoOptions;
|
|
960
|
-
shouldThrowOnError: boolean | undefined;
|
|
996
|
+
timeout?: number;
|
|
961
997
|
};
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
type DedupeStrategyUnion = UnmaskType<"cancel" | "defer" | "none">;
|
|
965
|
-
type DedupeOptions = {
|
|
998
|
+
type BaseCallApiExtraOptions<TBaseCallApiContext extends CallApiContext = DefaultCallApiContext, TBaseData = DefaultDataType, TBaseErrorData = DefaultDataType, TBaseResultMode extends ResultModeType = ResultModeType, TBaseThrowOnError extends ThrowOnErrorBoolean = DefaultThrowOnError, TBaseResponseType extends ResponseTypeType = ResponseTypeType, TBaseMeta extends DefaultMetaObject = DefaultMetaObject, TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TBaseSchemaAndConfig extends BaseCallApiSchemaAndConfig = BaseCallApiSchemaAndConfig> = SharedExtraOptions<TBaseCallApiContext, TBaseData, TBaseErrorData, TBaseResultMode, TBaseThrowOnError, TBaseResponseType> & {
|
|
999
|
+
meta?: TBaseMeta;
|
|
966
1000
|
/**
|
|
967
|
-
*
|
|
968
|
-
*
|
|
969
|
-
* - `"global"`: Shares deduplication cache across all `createFetchClient` instances with the same `dedupeCacheScopeKey`.
|
|
970
|
-
* Useful for applications with multiple API clients that should share deduplication state.
|
|
971
|
-
* - `"local"`: Limits deduplication to requests within the same `createFetchClient` instance.
|
|
972
|
-
* Provides better isolation and is recommended for most use cases.
|
|
973
|
-
*
|
|
1001
|
+
* Array of base CallApi plugins to extend library functionality.
|
|
974
1002
|
*
|
|
975
|
-
*
|
|
976
|
-
*
|
|
977
|
-
* - Use `"local"` (default) for single-purpose clients or when you want strict isolation between different parts of your app
|
|
1003
|
+
* Base plugins are applied to all instances created from this base configuration
|
|
1004
|
+
* and provide foundational functionality like authentication, logging, or caching.
|
|
978
1005
|
*
|
|
979
1006
|
* @example
|
|
980
1007
|
* ```ts
|
|
981
|
-
* //
|
|
982
|
-
* const userClient = createFetchClient({ baseURL: "/api/users" });
|
|
983
|
-
* const postClient = createFetchClient({ baseURL: "/api/posts" });
|
|
984
|
-
* // These clients won't share deduplication state
|
|
1008
|
+
* // Add logging plugin
|
|
985
1009
|
*
|
|
986
|
-
* //
|
|
987
|
-
* const
|
|
988
|
-
* baseURL: "
|
|
989
|
-
*
|
|
990
|
-
* });
|
|
991
|
-
* const postClient = createFetchClient({
|
|
992
|
-
* baseURL: "/api/posts",
|
|
993
|
-
* dedupeCacheScope: "global",
|
|
1010
|
+
* // Create base client with common plugins
|
|
1011
|
+
* const callApi = createFetchClient({
|
|
1012
|
+
* baseURL: "https://api.example.com",
|
|
1013
|
+
* plugins: [loggerPlugin({ enabled: true })]
|
|
994
1014
|
* });
|
|
995
|
-
* // These clients will share deduplication state
|
|
996
|
-
* ```
|
|
997
1015
|
*
|
|
998
|
-
*
|
|
1016
|
+
* // All requests inherit base plugins
|
|
1017
|
+
* await callApi("/users");
|
|
1018
|
+
* await callApi("/posts");
|
|
1019
|
+
*
|
|
1020
|
+
* ```
|
|
999
1021
|
*/
|
|
1000
|
-
|
|
1022
|
+
plugins?: TBasePluginArray;
|
|
1001
1023
|
/**
|
|
1002
|
-
*
|
|
1024
|
+
* Base validation schemas for the client configuration.
|
|
1003
1025
|
*
|
|
1004
|
-
*
|
|
1005
|
-
*
|
|
1006
|
-
*
|
|
1026
|
+
* Defines validation rules for requests and responses that apply to all
|
|
1027
|
+
* instances created from this base configuration. Provides type safety
|
|
1028
|
+
* and runtime validation for API interactions.
|
|
1029
|
+
*/
|
|
1030
|
+
schema?: TBaseSchemaAndConfig;
|
|
1031
|
+
/**
|
|
1032
|
+
* Controls which configuration parts skip automatic merging between base and instance configs.
|
|
1007
1033
|
*
|
|
1008
|
-
*
|
|
1009
|
-
*
|
|
1010
|
-
*
|
|
1011
|
-
* - Consider using different scope keys for different environments (dev, staging, prod)
|
|
1012
|
-
* - Avoid overly broad scope keys that might cause unintended cache sharing
|
|
1034
|
+
* By default, CallApi automatically merges base configuration with instance configuration.
|
|
1035
|
+
* This option allows you to disable automatic merging for specific parts when you need
|
|
1036
|
+
* manual control over how configurations are combined.
|
|
1013
1037
|
*
|
|
1014
|
-
*
|
|
1015
|
-
* -
|
|
1016
|
-
* -
|
|
1017
|
-
* -
|
|
1038
|
+
* @enum
|
|
1039
|
+
* - **"all"**: Disables automatic merging for both request options and extra options
|
|
1040
|
+
* - **"options"**: Disables automatic merging of extra options only (hooks, plugins, etc.)
|
|
1041
|
+
* - **"request"**: Disables automatic merging of request options only (headers, body, etc.)
|
|
1018
1042
|
*
|
|
1019
1043
|
* @example
|
|
1020
1044
|
* ```ts
|
|
1021
|
-
* //
|
|
1022
|
-
* const
|
|
1023
|
-
*
|
|
1024
|
-
* dedupeCacheScope: "global",
|
|
1025
|
-
* dedupeCacheScopeKey: "user-service"
|
|
1026
|
-
* });
|
|
1027
|
-
* const profileClient = createFetchClient({
|
|
1028
|
-
* baseURL: "/api/profiles",
|
|
1029
|
-
* dedupeCacheScope: "global",
|
|
1030
|
-
* dedupeCacheScopeKey: "user-service" // Same scope - will share cache
|
|
1031
|
-
* });
|
|
1045
|
+
* // Skip all automatic merging - full manual control
|
|
1046
|
+
* const client = callApi.create((ctx) => ({
|
|
1047
|
+
* skipAutoMergeFor: "all",
|
|
1032
1048
|
*
|
|
1033
|
-
*
|
|
1034
|
-
*
|
|
1035
|
-
*
|
|
1036
|
-
*
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
1049
|
+
* // Manually decide what to merge
|
|
1050
|
+
* baseURL: ctx.options.baseURL, // Keep base URL
|
|
1051
|
+
* timeout: 5000, // Override timeout
|
|
1052
|
+
* headers: {
|
|
1053
|
+
* ...ctx.request.headers, // Merge headers manually
|
|
1054
|
+
* "X-Custom": "value" // Add custom header
|
|
1055
|
+
* }
|
|
1056
|
+
* }));
|
|
1039
1057
|
*
|
|
1040
|
-
* //
|
|
1041
|
-
* const
|
|
1042
|
-
*
|
|
1043
|
-
*
|
|
1044
|
-
*
|
|
1058
|
+
* // Skip options merging - manual plugin/hook control
|
|
1059
|
+
* const client = callApi.create((ctx) => ({
|
|
1060
|
+
* skipAutoMergeFor: "options",
|
|
1061
|
+
*
|
|
1062
|
+
* // Manually control which plugins to use
|
|
1063
|
+
* plugins: [
|
|
1064
|
+
* ...ctx.options.plugins?.filter(p => p.name !== "unwanted") || [],
|
|
1065
|
+
* customPlugin
|
|
1066
|
+
* ],
|
|
1067
|
+
*
|
|
1068
|
+
* // Request options still auto-merge
|
|
1069
|
+
* method: "POST"
|
|
1070
|
+
* }));
|
|
1071
|
+
*
|
|
1072
|
+
* // Skip request merging - manual request control
|
|
1073
|
+
* const client = callApi.create((ctx) => ({
|
|
1074
|
+
* skipAutoMergeFor: "request",
|
|
1075
|
+
*
|
|
1076
|
+
* // Extra options still auto-merge (plugins, hooks, etc.)
|
|
1077
|
+
*
|
|
1078
|
+
* // Manually control request options
|
|
1079
|
+
* headers: {
|
|
1080
|
+
* "Content-Type": "application/json",
|
|
1081
|
+
* // Don't merge base headers
|
|
1082
|
+
* },
|
|
1083
|
+
* method: ctx.request.method || "GET"
|
|
1084
|
+
* }));
|
|
1085
|
+
*
|
|
1086
|
+
* // Use case: Conditional merging based on request
|
|
1087
|
+
* const client = createFetchClient((ctx) => ({
|
|
1088
|
+
* skipAutoMergeFor: "options",
|
|
1089
|
+
*
|
|
1090
|
+
* // Only use auth plugin for protected routes
|
|
1091
|
+
* plugins: ctx.initURL.includes("/protected/")
|
|
1092
|
+
* ? [...(ctx.options.plugins || []), authPlugin]
|
|
1093
|
+
* : ctx.options.plugins?.filter(p => p.name !== "auth") || []
|
|
1094
|
+
* }));
|
|
1045
1095
|
* ```
|
|
1096
|
+
*/
|
|
1097
|
+
skipAutoMergeFor?: "all" | "options" | "request";
|
|
1098
|
+
};
|
|
1099
|
+
type GetBaseSchemaRoutes<TBaseSchemaAndConfig extends BaseCallApiSchemaAndConfig> = Writeable<TBaseSchemaAndConfig["routes"], "deep">;
|
|
1100
|
+
type GetBaseSchemaConfig<TBaseSchemaAndConfig extends BaseCallApiSchemaAndConfig> = Writeable<NonNullable<TBaseSchemaAndConfig["config"]>, "deep">;
|
|
1101
|
+
type InferExtendSchemaContext<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TCurrentRouteSchemaKey extends string> = {
|
|
1102
|
+
baseSchemaRoutes: TBaseSchemaRoutes;
|
|
1103
|
+
currentRouteSchema: GetCurrentRouteSchema<TBaseSchemaRoutes, TCurrentRouteSchemaKey>;
|
|
1104
|
+
currentRouteSchemaKey: TCurrentRouteSchemaKey;
|
|
1105
|
+
};
|
|
1106
|
+
type GetExtendSchemaConfigContext<TBaseSchemaConfig extends CallApiSchemaConfig> = {
|
|
1107
|
+
baseSchemaConfig: TBaseSchemaConfig;
|
|
1108
|
+
};
|
|
1109
|
+
type InferExtendPluginContext<TBasePluginArray extends CallApiPlugin[]> = {
|
|
1110
|
+
basePlugins: TBasePluginArray;
|
|
1111
|
+
};
|
|
1112
|
+
type CallApiExtraOptions<TCallApiContext extends CallApiContext = DefaultCallApiContext, TData = DefaultDataType, TErrorData = DefaultDataType, TResultMode extends ResultModeType = ResultModeType, TThrowOnError extends ThrowOnErrorBoolean = DefaultThrowOnError, TResponseType extends ResponseTypeType = ResponseTypeType, TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TPluginArray extends CallApiPlugin[] = DefaultPluginArray, TBaseSchemaRoutes extends BaseCallApiSchemaRoutes = BaseCallApiSchemaRoutes, TSchema extends CallApiSchema = CallApiSchema, TBaseSchemaConfig extends CallApiSchemaConfig = CallApiSchemaConfig, TSchemaConfig extends CallApiSchemaConfig = CallApiSchemaConfig, TCurrentRouteSchemaKey extends string = string, TBody extends InferSchemaOutput<TSchema["body"], Body> = InferSchemaOutput<TSchema["body"], Body>> = InferRequiredExtraOptions<TSchema, TBaseSchemaRoutes, TCurrentRouteSchemaKey, TCallApiContext> & Omit<SharedExtraOptions<TCallApiContext, TData, TErrorData, TResultMode, TThrowOnError, TResponseType, TBody>, keyof InferRequiredExtraOptions<CallApiSchema, BaseCallApiSchemaRoutes, string, CallApiContext>> & {
|
|
1113
|
+
/**
|
|
1114
|
+
* Array of instance-specific CallApi plugins or a function to configure plugins.
|
|
1115
|
+
*
|
|
1116
|
+
* Instance plugins are added to the base plugins and provide functionality
|
|
1117
|
+
* specific to this particular API instance. Can be a static array or a function
|
|
1118
|
+
* that receives base plugins and returns the instance plugins.
|
|
1046
1119
|
*
|
|
1047
|
-
* @default "default"
|
|
1048
1120
|
*/
|
|
1049
|
-
|
|
1121
|
+
plugins?: TPluginArray | ((context: InferExtendPluginContext<TBasePluginArray>) => TPluginArray);
|
|
1050
1122
|
/**
|
|
1051
|
-
*
|
|
1123
|
+
* For instance-specific validation schemas
|
|
1052
1124
|
*
|
|
1053
|
-
*
|
|
1054
|
-
* are considered duplicates. The default key combines URL, method, body, and
|
|
1055
|
-
* relevant headers (excluding volatile ones like 'Date', 'Authorization', etc.).
|
|
1125
|
+
* Defines validation rules specific to this API instance, extending or overriding the base schema.
|
|
1056
1126
|
*
|
|
1057
|
-
*
|
|
1058
|
-
* The auto-generated key includes:
|
|
1059
|
-
* - Full request URL (including query parameters)
|
|
1060
|
-
* - HTTP method (GET, POST, etc.)
|
|
1061
|
-
* - Request body (for POST/PUT/PATCH requests)
|
|
1062
|
-
* - Stable headers (excludes Date, Authorization, User-Agent, etc.)
|
|
1127
|
+
* Can be a static schema object or a function that receives base schema context and returns instance schemas.
|
|
1063
1128
|
*
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
* -
|
|
1068
|
-
*
|
|
1069
|
-
*
|
|
1129
|
+
*/
|
|
1130
|
+
schema?: TSchema | ((context: InferExtendSchemaContext<TBaseSchemaRoutes, TCurrentRouteSchemaKey>) => TSchema);
|
|
1131
|
+
/**
|
|
1132
|
+
* Instance-specific schema configuration or a function to configure schema behavior.
|
|
1133
|
+
*
|
|
1134
|
+
* Controls how validation schemas are applied and behave for this specific API instance.
|
|
1135
|
+
* Can override base schema configuration or extend it with instance-specific validation rules.
|
|
1136
|
+
*
|
|
1137
|
+
*/
|
|
1138
|
+
schemaConfig?: TSchemaConfig | ((context: GetExtendSchemaConfigContext<TBaseSchemaConfig>) => TSchemaConfig);
|
|
1139
|
+
};
|
|
1140
|
+
type InstanceContext = {
|
|
1141
|
+
initURL: string;
|
|
1142
|
+
options: CallApiExtraOptions;
|
|
1143
|
+
request: CallApiRequestOptions;
|
|
1144
|
+
};
|
|
1145
|
+
type BaseCallApiConfig<TBaseCallApiContext extends CallApiContext = DefaultCallApiContext, TBaseData = DefaultDataType, TBaseErrorData = DefaultDataType, TBaseResultMode extends ResultModeType = ResultModeType, TBaseThrowOnError extends ThrowOnErrorBoolean = DefaultThrowOnError, TBaseResponseType extends ResponseTypeType = ResponseTypeType, TBaseMeta extends DefaultMetaObject = DefaultMetaObject, TBaseSchemaAndConfig extends BaseCallApiSchemaAndConfig = BaseCallApiSchemaAndConfig, TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TComputedBaseExtraOptions = BaseCallApiExtraOptions<TBaseCallApiContext, TBaseData, TBaseErrorData, TBaseResultMode, TBaseThrowOnError, TBaseResponseType, TBaseMeta, TBasePluginArray, TBaseSchemaAndConfig>> = (CallApiRequestOptions & TComputedBaseExtraOptions) | ((context: InstanceContext) => CallApiRequestOptions & TComputedBaseExtraOptions);
|
|
1146
|
+
type CallApiConfig<TCallApiContext extends CallApiContext = DefaultCallApiContext, TData = DefaultDataType, TErrorData = DefaultDataType, TResultMode extends ResultModeType = ResultModeType, TThrowOnError extends ThrowOnErrorBoolean = DefaultThrowOnError, TResponseType extends ResponseTypeType = ResponseTypeType, TBaseSchemaRoutes extends BaseCallApiSchemaRoutes = BaseCallApiSchemaRoutes, TSchema extends CallApiSchema = CallApiSchema, TBaseSchemaConfig extends CallApiSchemaConfig = CallApiSchemaConfig, TSchemaConfig extends CallApiSchemaConfig = CallApiSchemaConfig, TInitURL extends InitURLOrURLObject = InitURLOrURLObject, TCurrentRouteSchemaKey extends string = string, TBody extends InferSchemaOutput<TSchema["body"], Body> = InferSchemaOutput<TSchema["body"], Body>, TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TPluginArray extends CallApiPlugin[] = DefaultPluginArray> = CallApiExtraOptions<TCallApiContext, TData, TErrorData, TResultMode, TThrowOnError, TResponseType, TBasePluginArray, TPluginArray, TBaseSchemaRoutes, TSchema, TBaseSchemaConfig, TSchemaConfig, TCurrentRouteSchemaKey, TBody> & InferRequestOptions<TSchema, TInitURL, TBody> & Omit<CallApiRequestOptions<TBody>, keyof InferRequestOptions<CallApiSchema, string>>;
|
|
1147
|
+
type CallApiParameters<TData = DefaultDataType, TErrorData = DefaultDataType, TResultMode extends ResultModeType = ResultModeType, TCallApiContext extends CallApiContext = DefaultCallApiContext, TThrowOnError extends ThrowOnErrorBoolean = DefaultThrowOnError, TResponseType extends ResponseTypeType = ResponseTypeType, TBaseSchemaRoutes extends BaseCallApiSchemaRoutes = BaseCallApiSchemaRoutes, TSchema extends CallApiSchema = CallApiSchema, TBaseSchemaConfig extends CallApiSchemaConfig = CallApiSchemaConfig, TSchemaConfig extends CallApiSchemaConfig = CallApiSchemaConfig, TInitURL extends InitURLOrURLObject = InitURLOrURLObject, TCurrentRouteSchemaKey extends string = string, TBody extends InferSchemaOutput<TSchema["body"], Body> = InferSchemaOutput<TSchema["body"], Body>, TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TPluginArray extends CallApiPlugin[] = DefaultPluginArray, TComputedRequiredOptions = InferRequestOptions<TSchema, TInitURL, TBody> & InferRequiredExtraOptions<TSchema, TBaseSchemaRoutes, TCurrentRouteSchemaKey, TCallApiContext>, TComputedConfig = CallApiConfig<TCallApiContext, TData, TErrorData, TResultMode, TThrowOnError, TResponseType, TBaseSchemaRoutes, TSchema, TBaseSchemaConfig, TSchemaConfig, TInitURL, TCurrentRouteSchemaKey, TBody, TBasePluginArray, TPluginArray>> = NonNullableUnknown extends TComputedRequiredOptions ? [initURL: TInitURL, config?: TComputedConfig] : [initURL: TInitURL, config: TComputedConfig];
|
|
1148
|
+
type CallApiResult<TData, TErrorData, TResultMode extends ResultModeType, TThrowOnError extends ThrowOnErrorBoolean> = InferCallApiResult<TData, TErrorData, TResultMode, TThrowOnError>;
|
|
1149
|
+
type CallApiResultLoose<TData, TErrorData, TResultMode extends ResultModeType = ResultModeType, TThrowOnError extends ThrowOnErrorBoolean = ThrowOnErrorBoolean> = InferCallApiResult<TData, TErrorData, TResultMode, TThrowOnError>;
|
|
1150
|
+
//#endregion
|
|
1151
|
+
//#region src/auth.d.ts
|
|
1152
|
+
type PossibleAuthValue = Awaitable<string | null | undefined>;
|
|
1153
|
+
type PossibleAuthValueOrGetter = PossibleAuthValue | (() => PossibleAuthValue);
|
|
1154
|
+
type BearerAuth = {
|
|
1155
|
+
type: "Bearer";
|
|
1156
|
+
value: PossibleAuthValueOrGetter;
|
|
1157
|
+
};
|
|
1158
|
+
type TokenAuth = {
|
|
1159
|
+
type: "Token";
|
|
1160
|
+
value: PossibleAuthValueOrGetter;
|
|
1161
|
+
};
|
|
1162
|
+
type BasicAuth = {
|
|
1163
|
+
type: "Basic";
|
|
1164
|
+
username: PossibleAuthValueOrGetter;
|
|
1165
|
+
password: PossibleAuthValueOrGetter;
|
|
1166
|
+
};
|
|
1167
|
+
/**
|
|
1168
|
+
* Custom auth
|
|
1169
|
+
*
|
|
1170
|
+
* @param prefix - prefix of the header
|
|
1171
|
+
* @param authValue - value of the header
|
|
1172
|
+
*
|
|
1173
|
+
* @example
|
|
1174
|
+
* ```ts
|
|
1175
|
+
* {
|
|
1176
|
+
* type: "Custom",
|
|
1177
|
+
* prefix: "Token",
|
|
1178
|
+
* authValue: "token"
|
|
1179
|
+
* }
|
|
1180
|
+
* ```
|
|
1181
|
+
*/
|
|
1182
|
+
type CustomAuth = {
|
|
1183
|
+
type: "Custom";
|
|
1184
|
+
prefix: PossibleAuthValueOrGetter;
|
|
1185
|
+
value: PossibleAuthValueOrGetter;
|
|
1186
|
+
};
|
|
1187
|
+
type AuthOption = PossibleAuthValueOrGetter | BearerAuth | TokenAuth | BasicAuth | CustomAuth;
|
|
1188
|
+
//#endregion
|
|
1189
|
+
//#region src/types/conditional-types.d.ts
|
|
1190
|
+
/**
|
|
1191
|
+
* @description Makes a type partial if the output type of TSchema is not provided or has undefined in the union, otherwise makes it required
|
|
1192
|
+
*/
|
|
1193
|
+
type MakeSchemaOptionRequiredIfDefined<TSchemaOption extends CallApiSchema[keyof CallApiSchema], TObject> = undefined extends InferSchemaOutput<TSchemaOption, undefined> ? TObject : Required<TObject>;
|
|
1194
|
+
type MergeBaseWithRouteKey<TBaseURLOrPrefix extends string | undefined, TRouteKey extends string> = TBaseURLOrPrefix extends string ? TRouteKey extends `${AtSymbol}${infer TMethod extends RouteKeyMethods}/${infer TRestOfRoutKey}` ? `${AtSymbol}${TMethod}/${RemoveLeadingSlash<RemoveTrailingSlash<TBaseURLOrPrefix>>}/${RemoveLeadingSlash<TRestOfRoutKey>}` : `${TBaseURLOrPrefix}${TRouteKey}` : TRouteKey;
|
|
1195
|
+
type ApplyURLBasedConfig<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = TSchemaConfig["prefix"] extends string ? MergeBaseWithRouteKey<TSchemaConfig["prefix"], TSchemaRouteKeys> : TSchemaConfig["baseURL"] extends string ? MergeBaseWithRouteKey<TSchemaConfig["baseURL"], TSchemaRouteKeys> : TSchemaRouteKeys;
|
|
1196
|
+
type ApplyStrictConfig<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = TSchemaConfig["strict"] extends true ? TSchemaRouteKeys // eslint-disable-next-line perfectionist/sort-union-types -- Don't sort union types
|
|
1197
|
+
: TSchemaRouteKeys | Exclude<InitURLOrURLObject, RouteKeyMethodsURLUnion>;
|
|
1198
|
+
type ApplySchemaConfiguration<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = ApplyStrictConfig<TSchemaConfig, ApplyURLBasedConfig<TSchemaConfig, TSchemaRouteKeys>>;
|
|
1199
|
+
type InferAllMainRoutes<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes> = Omit<TBaseSchemaRoutes, FallBackRouteSchemaKey>;
|
|
1200
|
+
type InferAllMainRouteKeys<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TSchemaConfig extends CallApiSchemaConfig> = ApplySchemaConfiguration<TSchemaConfig, Extract<keyof InferAllMainRoutes<TBaseSchemaRoutes>, string>>;
|
|
1201
|
+
type InferInitURL<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TSchemaConfig extends CallApiSchemaConfig> = keyof TBaseSchemaRoutes extends never ? InitURLOrURLObject : InferAllMainRouteKeys<TBaseSchemaRoutes, TSchemaConfig>;
|
|
1202
|
+
type GetCurrentRouteSchemaKey<TSchemaConfig extends CallApiSchemaConfig, TPath> = TPath extends URL ? string : TSchemaConfig["prefix"] extends string ? TPath extends (`${AtSymbol}${infer TMethod extends RouteKeyMethods}/${RemoveLeadingSlash<TSchemaConfig["prefix"]>}${infer TCurrentRoute}`) ? `${AtSymbol}${TMethod}/${RemoveLeadingSlash<TCurrentRoute>}` : TPath extends `${TSchemaConfig["prefix"]}${infer TCurrentRoute}` ? TCurrentRoute : string : TSchemaConfig["baseURL"] extends string ? TPath extends (`${AtSymbol}${infer TMethod extends RouteKeyMethods}/${TSchemaConfig["baseURL"]}${infer TCurrentRoute}`) ? `${AtSymbol}${TMethod}/${RemoveLeadingSlash<TCurrentRoute>}` : TPath extends `${TSchemaConfig["baseURL"]}${infer TCurrentRoute}` ? TCurrentRoute : string : TPath;
|
|
1203
|
+
type GetCurrentRouteSchema<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TCurrentRouteSchemaKey extends string, TComputedFallBackRouteSchema = TBaseSchemaRoutes[FallBackRouteSchemaKey], TComputedCurrentRouteSchema = TBaseSchemaRoutes[TCurrentRouteSchemaKey], TComputedRouteSchema extends CallApiSchema = NonNullable<Omit<TComputedFallBackRouteSchema, keyof TComputedCurrentRouteSchema> & TComputedCurrentRouteSchema>> = TComputedRouteSchema extends CallApiSchema ? Writeable<TComputedRouteSchema, "deep"> : CallApiSchema;
|
|
1204
|
+
type JsonPrimitive = boolean | number | string | null | undefined;
|
|
1205
|
+
type SerializableObject = Record<PropertyKey, unknown>;
|
|
1206
|
+
type SerializableArray = Array<JsonPrimitive | SerializableObject> | ReadonlyArray<JsonPrimitive | SerializableObject>;
|
|
1207
|
+
type Body = UnmaskType<Exclude<RequestInit["body"], undefined> | SerializableArray | SerializableObject>;
|
|
1208
|
+
type InferBodyOption<TSchema extends CallApiSchema, TBody = InferSchemaOutput<TSchema["body"], Body>> = MakeSchemaOptionRequiredIfDefined<TSchema["body"], {
|
|
1209
|
+
/**
|
|
1210
|
+
* Body of the request, can be a object or any other supported body type.
|
|
1211
|
+
*/
|
|
1212
|
+
body?: TBody;
|
|
1213
|
+
}>;
|
|
1214
|
+
type MethodUnion = UnmaskType<"CONNECT" | "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT" | "TRACE" | AnyString>;
|
|
1215
|
+
type ExtractMethodFromURL<TInitURL> = string extends TInitURL ? MethodUnion : TInitURL extends `${AtSymbol}${infer TMethod extends RouteKeyMethods}/${string}` ? Uppercase<TMethod> : MethodUnion;
|
|
1216
|
+
type InferMethodOption<TSchema extends CallApiSchema, TInitURL extends InitURLOrURLObject> = MakeSchemaOptionRequiredIfDefined<TSchema["method"], {
|
|
1217
|
+
/**
|
|
1218
|
+
* HTTP method for the request.
|
|
1219
|
+
* @default "GET"
|
|
1220
|
+
*/
|
|
1221
|
+
method?: InferSchemaOutput<TSchema["method"], ExtractMethodFromURL<TInitURL>>;
|
|
1222
|
+
}>;
|
|
1223
|
+
type HeadersOption = UnmaskType<Headers | Record<"Authorization", CommonAuthorizationHeaders | undefined> | Record<"Content-Type", CommonContentTypes | undefined> | Record<CommonRequestHeaders, string | undefined> | Record<string, string | undefined> | Array<[string, string]>>;
|
|
1224
|
+
type InferHeadersOption<TSchema extends CallApiSchema> = MakeSchemaOptionRequiredIfDefined<TSchema["headers"], {
|
|
1225
|
+
/**
|
|
1226
|
+
* Headers to be used in the request.
|
|
1227
|
+
*/
|
|
1228
|
+
headers?: InferSchemaOutput<TSchema["headers"], HeadersOption> | ((context: {
|
|
1229
|
+
baseHeaders: Extract<HeadersOption, Record<string, unknown>>;
|
|
1230
|
+
}) => InferSchemaOutput<TSchema["headers"], HeadersOption>);
|
|
1231
|
+
}>;
|
|
1232
|
+
type InferRequestOptions<TSchema extends CallApiSchema, TInitURL extends InferInitURL<BaseCallApiSchemaRoutes, CallApiSchemaConfig>, TBody = InferSchemaOutput<TSchema["body"], Body>> = InferBodyOption<TSchema, TBody> & InferHeadersOption<TSchema> & InferMethodOption<TSchema, TInitURL>;
|
|
1233
|
+
type InferMetaOption<TSchema extends CallApiSchema, TCallApiContext extends CallApiContext> = MakeSchemaOptionRequiredIfDefined<TSchema["meta"], {
|
|
1234
|
+
/**
|
|
1235
|
+
* Optional metadata field for associating additional information with requests.
|
|
1070
1236
|
*
|
|
1071
|
-
*
|
|
1072
|
-
*
|
|
1073
|
-
* - String keys are fastest but least flexible
|
|
1074
|
-
* - Consider caching expensive key computations if needed
|
|
1237
|
+
* Useful for logging, tracing, or handling specific cases in shared interceptors.
|
|
1238
|
+
* The meta object is passed through to all hooks and can be accessed in error handlers.
|
|
1075
1239
|
*
|
|
1076
1240
|
* @example
|
|
1077
1241
|
* ```ts
|
|
1078
|
-
*
|
|
1079
|
-
*
|
|
1080
|
-
*
|
|
1081
|
-
*
|
|
1082
|
-
*
|
|
1083
|
-
*
|
|
1084
|
-
*
|
|
1085
|
-
*
|
|
1086
|
-
* // URL and method only - ignore headers and body
|
|
1087
|
-
* const userData = callApi("/api/user/123", {
|
|
1088
|
-
* dedupeKey: (context) => `${context.options.method}:${context.options.fullURL}`
|
|
1242
|
+
* const callMainApi = callApi.create({
|
|
1243
|
+
* baseURL: "https://main-api.com",
|
|
1244
|
+
* onResponseError: ({ response, options }) => {
|
|
1245
|
+
* if (options.meta?.userId) {
|
|
1246
|
+
* console.error(`User ${options.meta.userId} made an error`);
|
|
1247
|
+
* }
|
|
1248
|
+
* },
|
|
1089
1249
|
* });
|
|
1090
1250
|
*
|
|
1091
|
-
*
|
|
1092
|
-
*
|
|
1093
|
-
*
|
|
1094
|
-
* const authHeader = context.request.headers.get("Authorization");
|
|
1095
|
-
* return `${context.options.fullURL}-${authHeader}`;
|
|
1096
|
-
* }
|
|
1251
|
+
* const response = await callMainApi({
|
|
1252
|
+
* url: "https://example.com/api/data",
|
|
1253
|
+
* meta: { userId: "123" },
|
|
1097
1254
|
* });
|
|
1098
1255
|
*
|
|
1099
|
-
* //
|
|
1100
|
-
* const
|
|
1101
|
-
*
|
|
1102
|
-
*
|
|
1103
|
-
*
|
|
1256
|
+
* // Use case: Request tracking
|
|
1257
|
+
* const result = await callMainApi({
|
|
1258
|
+
* url: "https://example.com/api/data",
|
|
1259
|
+
* meta: {
|
|
1260
|
+
* requestId: generateId(),
|
|
1261
|
+
* source: "user-dashboard",
|
|
1262
|
+
* priority: "high"
|
|
1104
1263
|
* }
|
|
1105
1264
|
* });
|
|
1106
1265
|
*
|
|
1107
|
-
* //
|
|
1108
|
-
* const
|
|
1109
|
-
*
|
|
1110
|
-
*
|
|
1111
|
-
*
|
|
1112
|
-
*
|
|
1266
|
+
* // Use case: Feature flags
|
|
1267
|
+
* const client = callApi.create({
|
|
1268
|
+
* baseURL: "https://api.example.com",
|
|
1269
|
+
* meta: {
|
|
1270
|
+
* features: ["newUI", "betaFeature"],
|
|
1271
|
+
* experiment: "variantA"
|
|
1113
1272
|
* }
|
|
1114
1273
|
* });
|
|
1115
1274
|
* ```
|
|
1116
|
-
*
|
|
1117
|
-
* @default Auto-generated from request details
|
|
1118
1275
|
*/
|
|
1119
|
-
|
|
1276
|
+
meta?: InferSchemaOutput<TSchema["meta"], TCallApiContext["Meta"] extends DefaultMetaObject ? TCallApiContext["Meta"] : GlobalMeta>;
|
|
1277
|
+
}>;
|
|
1278
|
+
type InferAuthOption<TSchema extends CallApiSchema> = MakeSchemaOptionRequiredIfDefined<TSchema["auth"], {
|
|
1120
1279
|
/**
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1280
|
+
* Automatically add an Authorization header value.
|
|
1281
|
+
*
|
|
1282
|
+
* Supports multiple authentication patterns:
|
|
1283
|
+
* - String: Direct authorization header value
|
|
1284
|
+
* - Auth object: Structured authentication configuration
|
|
1285
|
+
*
|
|
1286
|
+
* @example
|
|
1287
|
+
* ```ts
|
|
1288
|
+
* // Bearer auth
|
|
1289
|
+
* const response = await callMainApi({
|
|
1290
|
+
* url: "https://example.com/api/data",
|
|
1291
|
+
* auth: "123456",
|
|
1292
|
+
* });
|
|
1293
|
+
*
|
|
1294
|
+
* // Bearer auth
|
|
1295
|
+
* const response = await callMainApi({
|
|
1296
|
+
* url: "https://example.com/api/data",
|
|
1297
|
+
* auth: {
|
|
1298
|
+
* type: "Bearer",
|
|
1299
|
+
* value: "123456",
|
|
1300
|
+
* },
|
|
1301
|
+
})
|
|
1302
|
+
*
|
|
1303
|
+
* // Token auth
|
|
1304
|
+
* const response = await callMainApi({
|
|
1305
|
+
* url: "https://example.com/api/data",
|
|
1306
|
+
* auth: {
|
|
1307
|
+
* type: "Token",
|
|
1308
|
+
* value: "123456",
|
|
1309
|
+
* },
|
|
1310
|
+
* });
|
|
1311
|
+
*
|
|
1312
|
+
* // Basic auth
|
|
1313
|
+
* const response = await callMainApi({
|
|
1314
|
+
* url: "https://example.com/api/data",
|
|
1315
|
+
* auth: {
|
|
1316
|
+
* type: "Basic",
|
|
1317
|
+
* username: "username",
|
|
1318
|
+
* password: "password",
|
|
1319
|
+
* },
|
|
1320
|
+
* });
|
|
1321
|
+
*
|
|
1322
|
+
* ```
|
|
1323
|
+
*/
|
|
1324
|
+
auth?: InferSchemaOutput<TSchema["auth"], AuthOption>;
|
|
1325
|
+
}>;
|
|
1326
|
+
type InferQueryOption<TSchema extends CallApiSchema> = MakeSchemaOptionRequiredIfDefined<TSchema["query"], {
|
|
1327
|
+
/**
|
|
1328
|
+
* Parameters to be appended to the URL (i.e: /:id)
|
|
1169
1329
|
*/
|
|
1170
|
-
|
|
1330
|
+
query?: InferSchemaOutput<TSchema["query"], Query>;
|
|
1331
|
+
}>;
|
|
1332
|
+
type EmptyString = "";
|
|
1333
|
+
type EmptyTuple = readonly [];
|
|
1334
|
+
type StringTuple = readonly string[];
|
|
1335
|
+
type PossibleParamNamePatterns = `${string}:${string}` | `${string}{${string}}${"" | AnyString}`;
|
|
1336
|
+
type ExtractRouteParamNames<TCurrentRoute, TParamNamesAccumulator extends StringTuple = EmptyTuple> = TCurrentRoute extends PossibleParamNamePatterns ? TCurrentRoute extends `${infer TRoutePrefix}:${infer TParamAndRemainingRoute}` ? TParamAndRemainingRoute extends `${infer TCurrentParam}/${infer TRemainingRoute}` ? TCurrentParam extends EmptyString ? ExtractRouteParamNames<`${TRoutePrefix}/${TRemainingRoute}`, TParamNamesAccumulator> : ExtractRouteParamNames<`${TRoutePrefix}/${TRemainingRoute}`, [...TParamNamesAccumulator, TCurrentParam]> : TParamAndRemainingRoute extends `${infer TCurrentParam}` ? TCurrentParam extends EmptyString ? ExtractRouteParamNames<TRoutePrefix, TParamNamesAccumulator> : ExtractRouteParamNames<TRoutePrefix, [...TParamNamesAccumulator, TCurrentParam]> : ExtractRouteParamNames<TRoutePrefix, TParamNamesAccumulator> : TCurrentRoute extends `${infer TRoutePrefix}{${infer TCurrentParam}}${infer TRemainingRoute}` ? TCurrentParam extends EmptyString ? ExtractRouteParamNames<`${TRoutePrefix}${TRemainingRoute}`, TParamNamesAccumulator> : ExtractRouteParamNames<`${TRoutePrefix}${TRemainingRoute}`, [...TParamNamesAccumulator, TCurrentParam]> : TParamNamesAccumulator : TParamNamesAccumulator;
|
|
1337
|
+
type ConvertParamNamesToRecord<TParamNames extends StringTuple> = Prettify<TParamNames extends (readonly [infer TFirstParamName extends string, ...infer TRemainingParamNames extends StringTuple]) ? Record<TFirstParamName, AllowedQueryParamValues> & ConvertParamNamesToRecord<TRemainingParamNames> : NonNullableUnknown>;
|
|
1338
|
+
type ConvertParamNamesToTuple<TParamNames extends StringTuple> = TParamNames extends readonly [string, ...infer TRemainingParamNames extends StringTuple] ? [AllowedQueryParamValues, ...ConvertParamNamesToTuple<TRemainingParamNames>] : [];
|
|
1339
|
+
type InferParamsFromRoute<TCurrentRoute> = ExtractRouteParamNames<TCurrentRoute> extends StringTuple ? ExtractRouteParamNames<TCurrentRoute> extends EmptyTuple ? Params : ConvertParamNamesToRecord<ExtractRouteParamNames<TCurrentRoute>> | ConvertParamNamesToTuple<ExtractRouteParamNames<TCurrentRoute>> : Params;
|
|
1340
|
+
type MakeParamsOptionRequired<TParamsSchemaOption extends CallApiSchema["params"], TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TCurrentRouteSchemaKey extends string, TObject> = MakeSchemaOptionRequiredIfDefined<TParamsSchemaOption, Params extends InferParamsFromRoute<TCurrentRouteSchemaKey> ? TObject : TCurrentRouteSchemaKey extends Extract<keyof TBaseSchemaRoutes, TCurrentRouteSchemaKey> ? undefined extends InferSchemaOutput<TParamsSchemaOption, null> ? TObject : Required<TObject> : TObject>;
|
|
1341
|
+
type InferParamsOption<TSchema extends CallApiSchema, TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TCurrentRouteSchemaKey extends string> = MakeParamsOptionRequired<TSchema["params"], TBaseSchemaRoutes, TCurrentRouteSchemaKey, {
|
|
1342
|
+
/**
|
|
1343
|
+
* Parameters to be appended to the URL (i.e: /:id)
|
|
1344
|
+
*/
|
|
1345
|
+
params?: InferSchemaOutput<TSchema["params"], InferParamsFromRoute<TCurrentRouteSchemaKey>>;
|
|
1346
|
+
}>;
|
|
1347
|
+
type InferRequiredExtraOptions<TSchema extends CallApiSchema, TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TCurrentRouteSchemaKey extends string, TCallApiContext extends CallApiContext> = InferAuthOption<TSchema> & InferMetaOption<TSchema, TCallApiContext> & InferParamsOption<TSchema, TBaseSchemaRoutes, TCurrentRouteSchemaKey> & InferQueryOption<TSchema>;
|
|
1348
|
+
type ResultModeOption<TErrorData, TResultMode extends ResultModeType> = TErrorData extends false ? {
|
|
1349
|
+
resultMode: "onlyData";
|
|
1350
|
+
} : TErrorData extends false | undefined ? {
|
|
1351
|
+
resultMode?: "onlyData";
|
|
1352
|
+
} : {
|
|
1353
|
+
resultMode?: TResultMode;
|
|
1354
|
+
};
|
|
1355
|
+
type ThrowOnErrorBoolean = boolean;
|
|
1356
|
+
type ThrowOnErrorType<TErrorData, TThrowOnError extends ThrowOnErrorBoolean> = TThrowOnError | ((context: ErrorContext<{
|
|
1357
|
+
ErrorData: TErrorData;
|
|
1358
|
+
}>) => TThrowOnError);
|
|
1359
|
+
type ThrowOnErrorOption<TErrorData, TThrowOnError extends ThrowOnErrorBoolean> = TErrorData extends false ? {
|
|
1360
|
+
throwOnError: true;
|
|
1361
|
+
} : TErrorData extends false | undefined ? {
|
|
1362
|
+
throwOnError?: true;
|
|
1363
|
+
} : {
|
|
1364
|
+
throwOnError?: ThrowOnErrorType<TErrorData, TThrowOnError>;
|
|
1365
|
+
};
|
|
1366
|
+
//#endregion
|
|
1367
|
+
//#region src/result.d.ts
|
|
1368
|
+
type ResponseParser<TData> = (text: string) => Awaitable<TData>;
|
|
1369
|
+
declare const getResponseType: <TData>(response: Response, responseParser: ResponseParser<TData>) => {
|
|
1370
|
+
arrayBuffer: () => Promise<ArrayBuffer>;
|
|
1371
|
+
blob: () => Promise<Blob>;
|
|
1372
|
+
formData: () => Promise<FormData>;
|
|
1373
|
+
json: () => Promise<TData>;
|
|
1374
|
+
stream: () => ReadableStream<Uint8Array<ArrayBuffer>> | null;
|
|
1375
|
+
text: () => Promise<string>;
|
|
1376
|
+
};
|
|
1377
|
+
type InitResponseTypeMap<TData = unknown> = ReturnType<typeof getResponseType<TData>>;
|
|
1378
|
+
type ResponseTypeUnion = keyof InitResponseTypeMap;
|
|
1379
|
+
type ResponseTypePlaceholder = null;
|
|
1380
|
+
type ResponseTypeType = ResponseTypePlaceholder | ResponseTypeUnion;
|
|
1381
|
+
type ResponseTypeMap<TData> = { [Key in keyof InitResponseTypeMap<TData>]: Awaited<ReturnType<InitResponseTypeMap<TData>[Key]>>; };
|
|
1382
|
+
type GetResponseType<TData, TResponseType extends ResponseTypeType, TComputedResponseTypeMap extends ResponseTypeMap<TData> = ResponseTypeMap<TData>> = null extends TResponseType ? TComputedResponseTypeMap["json"] : TResponseType extends NonNullable<ResponseTypeType> ? TComputedResponseTypeMap[TResponseType] : never;
|
|
1383
|
+
type CallApiResultSuccessVariant<TData> = {
|
|
1384
|
+
data: NoInferUnMasked<TData>;
|
|
1385
|
+
error: null;
|
|
1386
|
+
response: Response;
|
|
1387
|
+
};
|
|
1388
|
+
type PossibleJavaScriptError = UnmaskType<{
|
|
1389
|
+
errorData: false;
|
|
1390
|
+
message: string;
|
|
1391
|
+
name: "AbortError" | "Error" | "SyntaxError" | "TimeoutError" | "TypeError" | AnyString;
|
|
1392
|
+
originalError: DOMException | Error | SyntaxError | TypeError;
|
|
1393
|
+
}>;
|
|
1394
|
+
type PossibleHTTPError<TErrorData> = UnmaskType<{
|
|
1395
|
+
errorData: NoInferUnMasked<TErrorData>;
|
|
1396
|
+
message: string;
|
|
1397
|
+
name: "HTTPError";
|
|
1398
|
+
originalError: HTTPError;
|
|
1399
|
+
}>;
|
|
1400
|
+
type PossibleValidationError = UnmaskType<{
|
|
1401
|
+
errorData: ValidationError["errorData"];
|
|
1402
|
+
issueCause: ValidationError["issueCause"];
|
|
1403
|
+
message: string;
|
|
1404
|
+
name: "ValidationError";
|
|
1405
|
+
originalError: ValidationError;
|
|
1406
|
+
}>;
|
|
1407
|
+
type CallApiResultErrorVariant<TErrorData> = {
|
|
1408
|
+
data: null;
|
|
1409
|
+
error: PossibleHTTPError<TErrorData>;
|
|
1410
|
+
response: Response;
|
|
1411
|
+
} | {
|
|
1412
|
+
data: null;
|
|
1413
|
+
error: PossibleJavaScriptError;
|
|
1414
|
+
response: Response | null;
|
|
1415
|
+
} | {
|
|
1416
|
+
data: null;
|
|
1417
|
+
error: PossibleValidationError;
|
|
1418
|
+
response: Response | null;
|
|
1419
|
+
};
|
|
1420
|
+
type CallApiResultSuccessOrErrorVariant<TData, TError> = CallApiResultErrorVariant<TError> | CallApiResultSuccessVariant<TData>;
|
|
1421
|
+
type GetCallApiResult<TThrowOnError extends ThrowOnErrorBoolean, TResultWithException extends CallApiResultSuccessVariant<unknown>, TResultWithoutException extends CallApiResultSuccessOrErrorVariant<unknown, unknown>> = TThrowOnError extends true ? TResultWithException : TResultWithoutException;
|
|
1422
|
+
type ResultModeMap<TData = DefaultDataType, TErrorData = DefaultDataType, TThrowOnError extends ThrowOnErrorBoolean = DefaultThrowOnError, TComputedResult extends GetCallApiResult<TThrowOnError, CallApiResultSuccessVariant<TData>, CallApiResultSuccessOrErrorVariant<TData, TErrorData>> = GetCallApiResult<TThrowOnError, CallApiResultSuccessVariant<TData>, CallApiResultSuccessOrErrorVariant<TData, TErrorData>>> = UnmaskType<{
|
|
1423
|
+
all: TComputedResult;
|
|
1424
|
+
fetchApi: TComputedResult["response"];
|
|
1425
|
+
onlyData: TComputedResult["data"];
|
|
1426
|
+
onlyResponse: TComputedResult["response"];
|
|
1427
|
+
withoutResponse: Prettify<DistributiveOmit<TComputedResult, "response">>;
|
|
1428
|
+
}>;
|
|
1429
|
+
type ResultModePlaceholder = null;
|
|
1430
|
+
type ResultModeUnion = keyof ResultModeMap;
|
|
1431
|
+
type ResultModeType = ResultModePlaceholder | ResultModeUnion;
|
|
1432
|
+
type InferCallApiResult<TData, TErrorData, TResultMode extends ResultModeType, TThrowOnError extends ThrowOnErrorBoolean, TComputedResultModeMapWithException extends ResultModeMap<TData, TErrorData, true> = ResultModeMap<TData, TErrorData, true>, TComputedResultModeMapWithoutException extends ResultModeMap<TData, TErrorData, TThrowOnError> = ResultModeMap<TData, TErrorData, TThrowOnError>> = TErrorData extends false ? TComputedResultModeMapWithException["onlyData"] : TErrorData extends false | undefined ? TComputedResultModeMapWithException["onlyData"] : ResultModePlaceholder extends TResultMode ? TComputedResultModeMapWithoutException["all"] : TResultMode extends ResultModeUnion ? TComputedResultModeMapWithoutException[TResultMode] : never;
|
|
1433
|
+
type ErrorInfoOptions = Pick<CallApiExtraOptions, "cloneResponse" | "resultMode"> & {
|
|
1434
|
+
message?: string;
|
|
1171
1435
|
};
|
|
1172
1436
|
//#endregion
|
|
1173
|
-
//#region src/
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1437
|
+
//#region src/utils/external/body.d.ts
|
|
1438
|
+
type BodyType = NonNullable<CallApiRequestOptions["body"]>;
|
|
1439
|
+
declare const toSearchParams: <TSchema extends CallApiSchemaType<BodyType>>(data: InferSchemaOutput<TSchema>, schema?: TSchema) => URLSearchParams;
|
|
1440
|
+
declare const toQueryString: <TSchema extends CallApiSchemaType<BodyType>>(...parameters: Parameters<typeof toSearchParams<TSchema>>) => string;
|
|
1441
|
+
/**
|
|
1442
|
+
* @description Converts a plain object to FormData.
|
|
1443
|
+
*
|
|
1444
|
+
* Handles various data types:
|
|
1445
|
+
* - **Primitives** (string, number, boolean): Converted to strings
|
|
1446
|
+
* - **Blobs/Files**: Added directly to FormData
|
|
1447
|
+
* - **Arrays**: Each item is appended (allows multiple values for same key)
|
|
1448
|
+
* - **Objects**: JSON stringified before adding to FormData
|
|
1449
|
+
*
|
|
1450
|
+
* @example
|
|
1451
|
+
* ```ts
|
|
1452
|
+
* // Basic usage
|
|
1453
|
+
* const formData = toFormData({
|
|
1454
|
+
* name: "John",
|
|
1455
|
+
* age: 30,
|
|
1456
|
+
* active: true
|
|
1457
|
+
* });
|
|
1458
|
+
*
|
|
1459
|
+
* // With arrays
|
|
1460
|
+
* const formData = toFormData({
|
|
1461
|
+
* tags: ["javascript", "typescript"],
|
|
1462
|
+
* name: "John"
|
|
1463
|
+
* });
|
|
1464
|
+
*
|
|
1465
|
+
* // With files
|
|
1466
|
+
* const formData = toFormData({
|
|
1467
|
+
* avatar: fileBlob,
|
|
1468
|
+
* name: "John"
|
|
1469
|
+
* });
|
|
1470
|
+
*
|
|
1471
|
+
* // With nested objects (one level only)
|
|
1472
|
+
* const formData = toFormData({
|
|
1473
|
+
* user: { name: "John", age: 30 },
|
|
1474
|
+
* settings: { theme: "dark" }
|
|
1475
|
+
* });
|
|
1476
|
+
*/
|
|
1477
|
+
declare const toFormData: <TSchema extends CallApiSchemaType<BodyType>>(data: InferSchemaOutput<TSchema>, schema?: TSchema) => FormData;
|
|
1478
|
+
//#endregion
|
|
1479
|
+
//#region src/utils/external/define.d.ts
|
|
1480
|
+
declare const defineSchema: <const TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, const TSchemaConfig extends CallApiSchemaConfig>(routes: TBaseSchemaRoutes, config?: Satisfies<TSchemaConfig, CallApiSchemaConfig>) => {
|
|
1481
|
+
routes: Writeable<TBaseSchemaRoutes, "deep">;
|
|
1482
|
+
config: Writeable<Satisfies<TSchemaConfig, CallApiSchemaConfig>, "deep">;
|
|
1197
1483
|
};
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1484
|
+
declare const defineSchemaRoutes: <const TSchemaRoutes extends BaseCallApiSchemaRoutes>(routes: TSchemaRoutes) => Writeable<typeof routes, "deep">;
|
|
1485
|
+
declare const defineMainSchema: <const TSchema extends CallApiSchema>(mainSchema: Satisfies<TSchema, CallApiSchema>) => Writeable<typeof mainSchema, "deep">;
|
|
1486
|
+
declare const defineSchemaConfig: <const TSchemaConfig extends CallApiSchemaConfig>(config: Satisfies<TSchemaConfig, CallApiSchemaConfig>) => Writeable<typeof config, "deep">;
|
|
1487
|
+
declare const definePluginWithContext: <const TCallApiContext extends CallApiContext = NonNullableUnknown>() => <const TPlugin extends CallApiPlugin<TCallApiContext>>(plugin: TPlugin) => NonNullableUnknown extends TCallApiContext ? Writeable<TPlugin, "deep"> : ContextTag<Writeable<TPlugin, "deep">, TCallApiContext>;
|
|
1488
|
+
declare const definePlugin: <const TPlugin extends CallApiPlugin<{}>>(plugin: TPlugin) => Writeable<TPlugin, "deep">;
|
|
1489
|
+
type BaseConfigObject = Exclude<BaseCallApiConfig, AnyFunction>;
|
|
1490
|
+
type BaseConfigFn = Extract<BaseCallApiConfig, AnyFunction>;
|
|
1491
|
+
type DefineBaseConfig = {
|
|
1492
|
+
<const TBaseConfig extends BaseConfigObject>(baseConfig: Satisfies<TBaseConfig, BaseConfigObject>): Writeable<typeof baseConfig, "deep">;
|
|
1493
|
+
<const TBaseConfig extends BaseConfigObject>(baseConfig: (...parameters: Parameters<BaseConfigFn>) => Writeable<TBaseConfig, "deep">): typeof baseConfig;
|
|
1494
|
+
};
|
|
1495
|
+
declare const defineBaseConfig: DefineBaseConfig;
|
|
1496
|
+
declare const defineInstanceConfig: <const TInstanceConfig extends CallApiConfig>(config: TInstanceConfig) => Writeable<typeof config, "deep">;
|
|
1497
|
+
declare const defineFallbackRouteSchema: <const TSchema extends CallApiSchema>(schema: TSchema) => {
|
|
1498
|
+
"@default": NonNullable<TSchema> extends Record<string | number | symbol, unknown> | unknown[] | readonly unknown[] ? Writeable<TSchema, "deep"> : TSchema;
|
|
1499
|
+
};
|
|
1500
|
+
//#endregion
|
|
1501
|
+
//#region src/utils/external/guards.d.ts
|
|
1502
|
+
declare const isHTTPError: <TErrorData>(error: CallApiResultErrorVariant<TErrorData>["error"] | null) => error is PossibleHTTPError<TErrorData>;
|
|
1503
|
+
declare const isHTTPErrorInstance: <TErrorData>(error: unknown) => error is HTTPError<TErrorData>;
|
|
1504
|
+
declare const isValidationError: (error: CallApiResultErrorVariant<unknown>["error"] | null) => error is PossibleValidationError;
|
|
1505
|
+
declare const isValidationErrorInstance: (error: unknown) => error is ValidationError;
|
|
1506
|
+
declare const isJavascriptError: (error: CallApiResultErrorVariant<unknown>["error"] | null) => error is PossibleJavaScriptError;
|
|
1507
|
+
//#endregion
|
|
1508
|
+
//#region src/utils/external/headers.d.ts
|
|
1509
|
+
declare const objectifyHeaders: (headers: CallApiRequestOptions["headers"]) => Record<string, string>;
|
|
1510
|
+
//#endregion
|
|
1511
|
+
//#region src/utils/external/helpers.d.ts
|
|
1512
|
+
declare const extraOptionsHelper: <TExtraOptions>() => ExtraOptionsWithContextTag<TExtraOptions>;
|
|
1513
|
+
declare const metaHelper: <TMeta extends DefaultMetaObject>() => MetaWithContextTag<TMeta>;
|
|
1514
|
+
//#endregion
|
|
1515
|
+
//#region src/retry.d.ts
|
|
1516
|
+
declare const defaultRetryStatusCodesLookup: () => Readonly<{
|
|
1517
|
+
408: "Request Timeout";
|
|
1518
|
+
409: "Conflict";
|
|
1519
|
+
425: "Too Early";
|
|
1520
|
+
429: "Too Many Requests";
|
|
1521
|
+
500: "Internal Server Error";
|
|
1522
|
+
502: "Bad Gateway";
|
|
1523
|
+
503: "Service Unavailable";
|
|
1524
|
+
504: "Gateway Timeout";
|
|
1525
|
+
}>;
|
|
1526
|
+
type RetryStatusCodes = UnmaskType<AnyNumber | keyof ReturnType<typeof defaultRetryStatusCodesLookup>>;
|
|
1527
|
+
type RetryCondition<TErrorData> = (context: ErrorContext<{
|
|
1528
|
+
ErrorData: TErrorData;
|
|
1529
|
+
}>) => Awaitable<boolean>;
|
|
1530
|
+
type CallApiLooseImpl = (initURL: InitURLOrURLObject, init?: CallApiConfig) => Promise<CallApiResultLoose<unknown, unknown>>;
|
|
1531
|
+
interface RetryOptions<TErrorData> {
|
|
1207
1532
|
/**
|
|
1208
|
-
*
|
|
1209
|
-
* @
|
|
1533
|
+
* Tracks the number of times the request has already been retried internally
|
|
1534
|
+
* @internal
|
|
1535
|
+
* @deprecated **WARNING**: This property is used internally to track retries. Please abstain from reading or modifying it.
|
|
1210
1536
|
*/
|
|
1211
|
-
|
|
1212
|
-
} & Pick<ModifiedRequestInit, FetchSpecificKeysUnion>;
|
|
1213
|
-
type SharedExtraOptions<TCallApiContext extends CallApiContext = DefaultCallApiContext, TData = DefaultDataType, TErrorData = DefaultDataType, TResultMode extends ResultModeType = ResultModeType, TThrowOnError extends ThrowOnErrorBoolean = DefaultThrowOnError, TResponseType extends ResponseTypeType = ResponseTypeType, TPluginArray extends CallApiPlugin[] = DefaultPluginArray, TBody = Body, TComputedMergedPluginExtraOptions = Partial<InferPluginExtraOptions<TPluginArray> & InferSchemaOutput<TCallApiContext["InferredExtraOptions"], TCallApiContext["InferredExtraOptions"]>>, TComputedCallApiContext extends CallApiContext = OverrideCallApiContext<TCallApiContext, {
|
|
1214
|
-
Data: TData;
|
|
1215
|
-
ErrorData: TErrorData;
|
|
1216
|
-
InferredExtraOptions: TComputedMergedPluginExtraOptions;
|
|
1217
|
-
ResultMode: TResultMode;
|
|
1218
|
-
}>> = DedupeOptions & HookConfigOptions & HooksOrHooksArray<NoInferUnMasked<TComputedCallApiContext>> & Middlewares<NoInferUnMasked<TComputedCallApiContext>> & RefetchOptions & ResultModeOption<TErrorData, TResultMode> & RetryOptions<TErrorData> & TComputedMergedPluginExtraOptions & ThrowOnErrorOption<TErrorData, TThrowOnError> & URLOptions & {
|
|
1537
|
+
readonly ["~retryAttemptCount"]?: number;
|
|
1219
1538
|
/**
|
|
1220
|
-
*
|
|
1221
|
-
*
|
|
1222
|
-
* Supports multiple authentication patterns:
|
|
1223
|
-
* - String: Direct authorization header value
|
|
1224
|
-
* - Auth object: Structured authentication configuration
|
|
1225
|
-
*
|
|
1226
|
-
* ```
|
|
1539
|
+
* Use a valid `Retry-After` response header instead of the configured retry delay
|
|
1540
|
+
* @default false
|
|
1227
1541
|
*/
|
|
1228
|
-
|
|
1542
|
+
respectRetryAfter?: boolean;
|
|
1229
1543
|
/**
|
|
1230
|
-
*
|
|
1231
|
-
*
|
|
1232
|
-
* Useful for custom string serialization formats or when the default JSON
|
|
1233
|
-
* serialization doesn't meet your needs.
|
|
1234
|
-
*
|
|
1235
|
-
* @example
|
|
1236
|
-
* ```ts
|
|
1237
|
-
* // XML serialization
|
|
1238
|
-
* bodySerializer: (body) => {
|
|
1239
|
-
* return `<request>${Object.entries(body)
|
|
1240
|
-
* .map(([key, value]) => `<${key}>${value}</${key}>`)
|
|
1241
|
-
* .join('')}</request>`;
|
|
1242
|
-
* }
|
|
1243
|
-
*
|
|
1244
|
-
* // Custom JSON with specific formatting
|
|
1245
|
-
* bodySerializer: (body) => JSON.stringify(body, null, 2)
|
|
1246
|
-
* ```
|
|
1544
|
+
* Number of allowed retry attempts on HTTP errors
|
|
1545
|
+
* @default 0
|
|
1247
1546
|
*/
|
|
1248
|
-
|
|
1547
|
+
retryAttempts?: number;
|
|
1249
1548
|
/**
|
|
1250
|
-
*
|
|
1251
|
-
*
|
|
1252
|
-
* Useful for converting plain objects into formats like `FormData`,
|
|
1253
|
-
* `URLSearchParams`, `Blob`, or other Fetch-compatible body values.
|
|
1254
|
-
*
|
|
1255
|
-
* Takes precedence over `bodySerializer`.
|
|
1256
|
-
*
|
|
1257
|
-
* @example
|
|
1258
|
-
* ```ts
|
|
1259
|
-
* bodyTransformer: ({ body }) => {
|
|
1260
|
-
* const formData = new FormData();
|
|
1261
|
-
*
|
|
1262
|
-
* Object.entries(body).forEach(([key, value]) => {
|
|
1263
|
-
* formData.append(key, String(value));
|
|
1264
|
-
* });
|
|
1265
|
-
*
|
|
1266
|
-
* return formData;
|
|
1267
|
-
* }
|
|
1268
|
-
* ```
|
|
1549
|
+
* Callback whose return value determines if a request should be retried or not
|
|
1269
1550
|
*/
|
|
1270
|
-
|
|
1271
|
-
body: TBody;
|
|
1272
|
-
headers: Headers;
|
|
1273
|
-
}) => Body;
|
|
1551
|
+
retryCondition?: RetryCondition<TErrorData>;
|
|
1274
1552
|
/**
|
|
1275
|
-
*
|
|
1276
|
-
*
|
|
1277
|
-
* By default, response streams can only be consumed once. Enable this when you need
|
|
1278
|
-
* to read the response in multiple places (e.g., in hooks and main code).
|
|
1279
|
-
*
|
|
1280
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/Response/clone
|
|
1281
|
-
* @default false
|
|
1553
|
+
* Delay between retries in milliseconds
|
|
1554
|
+
* @default 1000
|
|
1282
1555
|
*/
|
|
1283
|
-
|
|
1556
|
+
retryDelay?: number | ((currentAttemptCount: number) => number);
|
|
1284
1557
|
/**
|
|
1285
|
-
*
|
|
1286
|
-
*
|
|
1287
|
-
* Useful for testing, adding custom behavior, or using alternative HTTP clients
|
|
1288
|
-
* that implement the fetch API interface.
|
|
1289
|
-
*
|
|
1290
|
-
* @example
|
|
1291
|
-
* ```ts
|
|
1292
|
-
* // Use node-fetch in Node.js environments
|
|
1293
|
-
* import fetch from 'node-fetch';
|
|
1294
|
-
*
|
|
1295
|
-
* // Mock fetch for testing
|
|
1296
|
-
* customFetchImpl: async (url, init) => {
|
|
1297
|
-
* return new Response(JSON.stringify({ mocked: true }), {
|
|
1298
|
-
* status: 200,
|
|
1299
|
-
* headers: { 'Content-Type': 'application/json' }
|
|
1300
|
-
* });
|
|
1301
|
-
* }
|
|
1302
|
-
*
|
|
1303
|
-
* // Add custom logging to all requests
|
|
1304
|
-
* customFetchImpl: async (url, init) => {
|
|
1305
|
-
* console.log(`Fetching: ${url}`);
|
|
1306
|
-
* const response = await fetch(url, init);
|
|
1307
|
-
* console.log(`Response: ${response.status}`);
|
|
1308
|
-
* return response;
|
|
1309
|
-
* }
|
|
1310
|
-
*
|
|
1311
|
-
* // Use with custom HTTP client
|
|
1312
|
-
* customFetchImpl: async (url, init) => {
|
|
1313
|
-
* // Convert to your preferred HTTP client format
|
|
1314
|
-
* return await customHttpClient.request({
|
|
1315
|
-
* url: url.toString(),
|
|
1316
|
-
* method: init?.method || 'GET',
|
|
1317
|
-
* headers: init?.headers,
|
|
1318
|
-
* body: init?.body
|
|
1319
|
-
* });
|
|
1320
|
-
* }
|
|
1321
|
-
* ```
|
|
1558
|
+
* Maximum delay in milliseconds. Only applies to exponential strategy
|
|
1559
|
+
* @default 10000
|
|
1322
1560
|
*/
|
|
1323
|
-
|
|
1561
|
+
retryMaxDelay?: number;
|
|
1324
1562
|
/**
|
|
1325
|
-
*
|
|
1326
|
-
*
|
|
1327
|
-
* @default true
|
|
1563
|
+
* HTTP methods that are allowed to retry
|
|
1564
|
+
* @default ["GET", "POST"]
|
|
1328
1565
|
*/
|
|
1329
|
-
|
|
1566
|
+
retryMethods?: MethodUnion[];
|
|
1330
1567
|
/**
|
|
1331
|
-
*
|
|
1332
|
-
*
|
|
1333
|
-
* Can be a static string or a function that receives error context
|
|
1334
|
-
* to generate dynamic error messages based on the response.
|
|
1335
|
-
*
|
|
1336
|
-
* @default "Failed to fetch data from server!"
|
|
1337
|
-
*
|
|
1338
|
-
* @example
|
|
1339
|
-
* ```ts
|
|
1340
|
-
* // Static error message
|
|
1341
|
-
* defaultHTTPErrorMessage: "API request failed. Please try again."
|
|
1342
|
-
*
|
|
1343
|
-
* // Dynamic error message based on status code
|
|
1344
|
-
* defaultHTTPErrorMessage: ({ response }) => {
|
|
1345
|
-
* switch (response.status) {
|
|
1346
|
-
* case 401: return "Authentication required. Please log in.";
|
|
1347
|
-
* case 403: return "Access denied. Insufficient permissions.";
|
|
1348
|
-
* case 404: return "Resource not found.";
|
|
1349
|
-
* case 429: return "Too many requests. Please wait and try again.";
|
|
1350
|
-
* case 500: return "Server error. Please contact support.";
|
|
1351
|
-
* default: return `Request failed with status ${response.status}`;
|
|
1352
|
-
* }
|
|
1353
|
-
* }
|
|
1354
|
-
*
|
|
1355
|
-
* // Include error data in message
|
|
1356
|
-
* defaultHTTPErrorMessage: ({ errorData, response }) => {
|
|
1357
|
-
* const userMessage = errorData?.message || "Unknown error occurred";
|
|
1358
|
-
* return `${userMessage} (Status: ${response.status})`;
|
|
1359
|
-
* }
|
|
1360
|
-
* ```
|
|
1568
|
+
* HTTP status codes that trigger a retry
|
|
1361
1569
|
*/
|
|
1362
|
-
|
|
1570
|
+
retryStatusCodes?: RetryStatusCodes[];
|
|
1363
1571
|
/**
|
|
1364
|
-
*
|
|
1365
|
-
*
|
|
1366
|
-
* Useful for logging, tracing, or handling specific cases in shared interceptors.
|
|
1367
|
-
* The meta object is passed through to all hooks and can be accessed in error handlers.
|
|
1368
|
-
*
|
|
1369
|
-
* @example
|
|
1370
|
-
* ```ts
|
|
1371
|
-
* const callMainApi = callApi.create({
|
|
1372
|
-
* baseURL: "https://main-api.com",
|
|
1373
|
-
* onResponseError: ({ response, options }) => {
|
|
1374
|
-
* if (options.meta?.userId) {
|
|
1375
|
-
* console.error(`User ${options.meta.userId} made an error`);
|
|
1376
|
-
* }
|
|
1377
|
-
* },
|
|
1378
|
-
* });
|
|
1379
|
-
*
|
|
1380
|
-
* const response = await callMainApi({
|
|
1381
|
-
* url: "https://example.com/api/data",
|
|
1382
|
-
* meta: { userId: "123" },
|
|
1383
|
-
* });
|
|
1384
|
-
*
|
|
1385
|
-
* // Use case: Request tracking
|
|
1386
|
-
* const result = await callMainApi({
|
|
1387
|
-
* url: "https://example.com/api/data",
|
|
1388
|
-
* meta: {
|
|
1389
|
-
* requestId: generateId(),
|
|
1390
|
-
* source: "user-dashboard",
|
|
1391
|
-
* priority: "high"
|
|
1392
|
-
* }
|
|
1393
|
-
* });
|
|
1394
|
-
*
|
|
1395
|
-
* // Use case: Feature flags
|
|
1396
|
-
* const client = callApi.create({
|
|
1397
|
-
* baseURL: "https://api.example.com",
|
|
1398
|
-
* meta: {
|
|
1399
|
-
* features: ["newUI", "betaFeature"],
|
|
1400
|
-
* experiment: "variantA"
|
|
1401
|
-
* }
|
|
1402
|
-
* });
|
|
1403
|
-
* ```
|
|
1572
|
+
* Strategy to use when retrying
|
|
1573
|
+
* @default "linear"
|
|
1404
1574
|
*/
|
|
1405
|
-
|
|
1575
|
+
retryStrategy?: "exponential" | "linear";
|
|
1576
|
+
}
|
|
1577
|
+
type RetryManagerContext = {
|
|
1578
|
+
callApi: CallApiLooseImpl;
|
|
1579
|
+
callApiArgs: {
|
|
1580
|
+
config: CallApiConfig;
|
|
1581
|
+
initURL: InitURLOrURLObject;
|
|
1582
|
+
};
|
|
1583
|
+
error: unknown;
|
|
1584
|
+
errorContext: ErrorContext;
|
|
1585
|
+
hookInfo: ExecuteHookInfo;
|
|
1586
|
+
removeDedupeCacheEntry: () => void;
|
|
1587
|
+
};
|
|
1588
|
+
//#endregion
|
|
1589
|
+
//#region src/refetch.d.ts
|
|
1590
|
+
declare const refetchAttemptTrackerSymbol: unique symbol;
|
|
1591
|
+
interface RefetchOptions {
|
|
1406
1592
|
/**
|
|
1407
|
-
*
|
|
1408
|
-
*
|
|
1409
|
-
*
|
|
1410
|
-
*
|
|
1411
|
-
* @example
|
|
1412
|
-
* ```ts
|
|
1413
|
-
* responseParser: (text) => {
|
|
1414
|
-
* return JSON.parse(text);
|
|
1415
|
-
* }
|
|
1416
|
-
*
|
|
1417
|
-
* // Parse XML responses
|
|
1418
|
-
* responseParser: (text) => {
|
|
1419
|
-
* const parser = new DOMParser();
|
|
1420
|
-
* const doc = parser.parseFromString(text, "text/xml");
|
|
1421
|
-
* return xmlToObject(doc);
|
|
1422
|
-
* }
|
|
1423
|
-
*
|
|
1424
|
-
* // Parse CSV responses
|
|
1425
|
-
* responseParser: (text) => {
|
|
1426
|
-
* const lines = text.split('\n');
|
|
1427
|
-
* const headers = lines[0].split(',');
|
|
1428
|
-
* const data = lines.slice(1).map(line => {
|
|
1429
|
-
* const values = line.split(',');
|
|
1430
|
-
* return headers.reduce((obj, header, index) => {
|
|
1431
|
-
* obj[header] = values[index];
|
|
1432
|
-
* return obj;
|
|
1433
|
-
* }, {});
|
|
1434
|
-
* });
|
|
1435
|
-
* return data;
|
|
1436
|
-
* }
|
|
1437
|
-
*
|
|
1438
|
-
* ```
|
|
1593
|
+
* Tracks if the refetching of the request should be attempted
|
|
1594
|
+
* @internal
|
|
1595
|
+
* @deprecated **WARNING**: This property is used internally to track retries. Please abstain from reading or modifying it.
|
|
1439
1596
|
*/
|
|
1440
|
-
|
|
1597
|
+
[refetchAttemptTrackerSymbol]?: boolean;
|
|
1598
|
+
}
|
|
1599
|
+
type RefetchFn = () => void;
|
|
1600
|
+
type RefetchManagerResult = {
|
|
1601
|
+
handleRefetch: () => Promise<CallApiResultLoose<unknown, unknown>> | null;
|
|
1602
|
+
refetch: RefetchFn;
|
|
1603
|
+
};
|
|
1604
|
+
declare const createRefetchManager: (ctx: Pick<RetryManagerContext, "callApi" | "callApiArgs" | "removeDedupeCacheEntry"> & {
|
|
1605
|
+
options: CallApiExtraOptions;
|
|
1606
|
+
}) => RefetchManagerResult;
|
|
1607
|
+
type RefetchFnOption = Pick<ReturnType<typeof createRefetchManager>, "refetch">;
|
|
1608
|
+
//#endregion
|
|
1609
|
+
//#region src/stream.d.ts
|
|
1610
|
+
type StreamProgressEvent = {
|
|
1441
1611
|
/**
|
|
1442
|
-
*
|
|
1443
|
-
*
|
|
1444
|
-
* Different response types trigger different parsing methods:
|
|
1445
|
-
* - **"json"**: Parses as JSON using response.json()
|
|
1446
|
-
* - **"text"**: Returns as plain text using response.text()
|
|
1447
|
-
* - **"blob"**: Returns as Blob using response.blob()
|
|
1448
|
-
* - **"arrayBuffer"**: Returns as ArrayBuffer using response.arrayBuffer()
|
|
1449
|
-
* - **"stream"**: Returns the response body stream directly
|
|
1450
|
-
*
|
|
1451
|
-
* @default "json"
|
|
1452
|
-
*
|
|
1453
|
-
* @example
|
|
1454
|
-
* ```ts
|
|
1455
|
-
* // JSON API responses (default)
|
|
1456
|
-
* responseType: "json"
|
|
1457
|
-
*
|
|
1458
|
-
* // Plain text responses
|
|
1459
|
-
* responseType: "text"
|
|
1460
|
-
* // Usage: const csvData = await callApi("/export.csv", { responseType: "text" });
|
|
1461
|
-
*
|
|
1462
|
-
* // File downloads
|
|
1463
|
-
* responseType: "blob"
|
|
1464
|
-
* // Usage: const file = await callApi("/download/file.pdf", { responseType: "blob" });
|
|
1465
|
-
*
|
|
1466
|
-
* // Binary data
|
|
1467
|
-
* responseType: "arrayBuffer"
|
|
1468
|
-
* // Usage: const buffer = await callApi("/binary-data", { responseType: "arrayBuffer" });
|
|
1612
|
+
* Current chunk of data being streamed.
|
|
1469
1613
|
*
|
|
1470
|
-
*
|
|
1471
|
-
* responseType: "stream"
|
|
1472
|
-
* // Usage: const stream = await callApi("/large-dataset", { responseType: "stream" });
|
|
1473
|
-
* ```
|
|
1614
|
+
* Will be `null` on the final completion tick (when progress reaches 100%).
|
|
1474
1615
|
*/
|
|
1475
|
-
|
|
1616
|
+
chunk: Uint8Array | null;
|
|
1476
1617
|
/**
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
- **"onlyData"**: Returns only the data from the response.
|
|
1481
|
-
- **"onlyResponse"**: Returns only the `Response` object.
|
|
1482
|
-
- **"fetchApi"**: Also returns only the `Response` object, but also skips parsing of the response body internally and data/errorData schema validation.
|
|
1483
|
-
- **"withoutResponse"**: Returns `{ data, error }`. Standard lifecycle, but omits the `response` property.
|
|
1484
|
-
*
|
|
1485
|
-
*
|
|
1486
|
-
* **Note:**
|
|
1487
|
-
* By default, simplified modes (`"onlyData"`, `"onlyResponse"`, `"fetchApi"`) do not throw errors.
|
|
1488
|
-
* Success/failure should be handled via hooks or by checking the return value (e.g., `if (data)` or `if (response?.ok)`).
|
|
1489
|
-
* To force an exception instead, set `throwOnError: true`.
|
|
1490
|
-
*
|
|
1491
|
-
*
|
|
1492
|
-
* @default "all"
|
|
1493
|
-
*
|
|
1494
|
-
*/
|
|
1495
|
-
resultMode?: TResultMode;
|
|
1618
|
+
* Progress in percentage
|
|
1619
|
+
*/
|
|
1620
|
+
progress: number;
|
|
1496
1621
|
/**
|
|
1497
|
-
*
|
|
1622
|
+
* Total size of data in bytes
|
|
1623
|
+
*/
|
|
1624
|
+
totalBytes: number;
|
|
1625
|
+
/**
|
|
1626
|
+
* Amount of data transferred so far
|
|
1627
|
+
*/
|
|
1628
|
+
transferredBytes: number;
|
|
1629
|
+
};
|
|
1630
|
+
//#endregion
|
|
1631
|
+
//#region src/hooks.d.ts
|
|
1632
|
+
type CallApiRequestOptionsForHooks = Omit<CallApiRequestOptions, "headers"> & {
|
|
1633
|
+
headers: Partial<Record<"Authorization" | "Content-Type" | CommonRequestHeaders, string>>;
|
|
1634
|
+
};
|
|
1635
|
+
type CallApiExtraOptionsForHooks<TCallApiContext extends CallApiContext = DefaultCallApiContext> = Hooks & Omit<CallApiExtraOptions<TCallApiContext>, keyof Hooks> & Pick<RefetchFnOption, "refetch">;
|
|
1636
|
+
interface Hooks<TCallApiContext extends CallApiContext = DefaultCallApiContext> {
|
|
1637
|
+
/**
|
|
1638
|
+
* Hook called when any error occurs within the request/response lifecycle.
|
|
1498
1639
|
*
|
|
1499
|
-
*
|
|
1500
|
-
*
|
|
1640
|
+
* This is a unified error handler that catches both request errors (network failures,
|
|
1641
|
+
* timeouts, etc.) and response errors (HTTP error status codes). It's essentially
|
|
1642
|
+
* a combination of `onRequestError` and `onResponseError` hooks.
|
|
1501
1643
|
*
|
|
1502
|
-
* @
|
|
1644
|
+
* @param context - Error context containing error details, request info, and response (if available)
|
|
1645
|
+
* @returns Promise or void - Hook can be async or sync
|
|
1646
|
+
*/
|
|
1647
|
+
onError?: (context: ErrorContext<TCallApiContext>) => Awaitable<unknown>;
|
|
1648
|
+
/**
|
|
1649
|
+
* Hook called before the HTTP request is sent and before any internal processing of the request object begins.
|
|
1503
1650
|
*
|
|
1504
|
-
*
|
|
1505
|
-
*
|
|
1506
|
-
* // Always throw errors
|
|
1507
|
-
* throwOnError: true
|
|
1508
|
-
* try {
|
|
1509
|
-
* const data = await callApi("/users");
|
|
1510
|
-
* console.log("Users:", data);
|
|
1511
|
-
* } catch (error) {
|
|
1512
|
-
* console.error("Request failed:", error);
|
|
1513
|
-
* }
|
|
1651
|
+
* This is the ideal place to modify request headers, add authentication,
|
|
1652
|
+
* implement request logging, or perform any setup before the network call.
|
|
1514
1653
|
*
|
|
1515
|
-
*
|
|
1516
|
-
*
|
|
1517
|
-
* const { data, error } = await callApi("/users");
|
|
1518
|
-
* if (error) {
|
|
1519
|
-
* console.error("Request failed:", error);
|
|
1520
|
-
* }
|
|
1654
|
+
* @param context - Request context with mutable request object and configuration
|
|
1655
|
+
* @returns Promise or void - Hook can be async or sync
|
|
1521
1656
|
*
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
*
|
|
1526
|
-
* }
|
|
1657
|
+
*/
|
|
1658
|
+
onRequest?: (context: RequestContext<TCallApiContext>) => Awaitable<unknown>;
|
|
1659
|
+
/**
|
|
1660
|
+
* Hook called when an error occurs during the fetch request itself.
|
|
1527
1661
|
*
|
|
1528
|
-
*
|
|
1529
|
-
*
|
|
1530
|
-
*
|
|
1531
|
-
* return criticalErrors.includes(error.response?.status);
|
|
1532
|
-
* }
|
|
1662
|
+
* This handles network-level errors like connection failures, timeouts,
|
|
1663
|
+
* DNS resolution errors, or other issues that prevent getting an HTTP response.
|
|
1664
|
+
* Note that HTTP error status codes (4xx, 5xx) are handled by `onResponseError`.
|
|
1533
1665
|
*
|
|
1534
|
-
*
|
|
1535
|
-
*
|
|
1536
|
-
* return error.type === "validation";
|
|
1537
|
-
* }
|
|
1538
|
-
* ```
|
|
1666
|
+
* @param context - Request error context with error details and null response
|
|
1667
|
+
* @returns Promise or void - Hook can be async or sync
|
|
1539
1668
|
*/
|
|
1540
|
-
|
|
1669
|
+
onRequestError?: (context: RequestErrorContext<TCallApiContext>) => Awaitable<unknown>;
|
|
1541
1670
|
/**
|
|
1542
|
-
*
|
|
1671
|
+
* Hook called just before the HTTP request is sent and after the request has been processed.
|
|
1543
1672
|
*
|
|
1544
|
-
*
|
|
1545
|
-
|
|
1673
|
+
* @param context - Request context with mutable request object and configuration
|
|
1674
|
+
*/
|
|
1675
|
+
onRequestReady?: (context: RequestContext<TCallApiContext>) => Awaitable<unknown>;
|
|
1676
|
+
/**
|
|
1677
|
+
* Hook called during upload stream progress tracking.
|
|
1546
1678
|
*
|
|
1547
|
-
*
|
|
1548
|
-
*
|
|
1549
|
-
*
|
|
1550
|
-
* timeout: 5000
|
|
1679
|
+
* This hook is triggered when uploading data (like file uploads) and provides
|
|
1680
|
+
* progress information about the upload. Useful for implementing progress bars
|
|
1681
|
+
* or upload status indicators.
|
|
1551
1682
|
*
|
|
1552
|
-
*
|
|
1553
|
-
*
|
|
1554
|
-
* const slowApi = createFetchClient({ timeout: 30000 }); // 30s for slow operations
|
|
1683
|
+
* @param context - Request stream context with progress event and request instance
|
|
1684
|
+
* @returns Promise or void - Hook can be async or sync
|
|
1555
1685
|
*
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1686
|
+
*/
|
|
1687
|
+
onRequestStream?: (context: RequestStreamContext<TCallApiContext>) => Awaitable<unknown>;
|
|
1688
|
+
/**
|
|
1689
|
+
* Hook called when any HTTP response is received from the API.
|
|
1690
|
+
*
|
|
1691
|
+
* This hook is triggered for both successful (2xx) and error (4xx, 5xx) responses.
|
|
1692
|
+
* It's useful for response logging, metrics collection, or any processing that
|
|
1693
|
+
* should happen regardless of response status.
|
|
1694
|
+
*
|
|
1695
|
+
* @param context - Response context with either success data or error information
|
|
1696
|
+
* @returns Promise or void - Hook can be async or sync
|
|
1559
1697
|
*
|
|
1560
|
-
* // No timeout (use with caution)
|
|
1561
|
-
* timeout: 0
|
|
1562
|
-
* ```
|
|
1563
1698
|
*/
|
|
1564
|
-
|
|
1565
|
-
};
|
|
1566
|
-
type BaseCallApiExtraOptions<TBaseCallApiContext extends CallApiContext = DefaultCallApiContext, TBaseData = DefaultDataType, TBaseErrorData = DefaultDataType, TBaseResultMode extends ResultModeType = ResultModeType, TBaseThrowOnError extends ThrowOnErrorBoolean = DefaultThrowOnError, TBaseResponseType extends ResponseTypeType = ResponseTypeType, TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TBaseSchemaAndConfig extends BaseCallApiSchemaAndConfig = BaseCallApiSchemaAndConfig> = SharedExtraOptions<TBaseCallApiContext, TBaseData, TBaseErrorData, TBaseResultMode, TBaseThrowOnError, TBaseResponseType, TBasePluginArray> & {
|
|
1699
|
+
onResponse?: (context: ResponseContext<TCallApiContext>) => Awaitable<unknown>;
|
|
1567
1700
|
/**
|
|
1568
|
-
*
|
|
1701
|
+
* Hook called when an HTTP error response (4xx, 5xx) is received from the API.
|
|
1569
1702
|
*
|
|
1570
|
-
*
|
|
1571
|
-
*
|
|
1703
|
+
* This handles server-side errors where an HTTP response was successfully received
|
|
1704
|
+
* but indicates an error condition. Different from `onRequestError` which handles
|
|
1705
|
+
* network-level failures.
|
|
1572
1706
|
*
|
|
1573
|
-
* @
|
|
1574
|
-
*
|
|
1575
|
-
|
|
1707
|
+
* @param context - Response error context with HTTP error details and response
|
|
1708
|
+
* @returns Promise or void - Hook can be async or sync
|
|
1709
|
+
*/
|
|
1710
|
+
onResponseError?: (context: ResponseErrorContext<TCallApiContext>) => Awaitable<unknown>;
|
|
1711
|
+
/**
|
|
1712
|
+
* Hook called during download stream progress tracking.
|
|
1576
1713
|
*
|
|
1577
|
-
*
|
|
1578
|
-
*
|
|
1579
|
-
*
|
|
1580
|
-
* plugins: [loggerPlugin({ enabled: true })]
|
|
1581
|
-
* });
|
|
1714
|
+
* This hook is triggered when downloading data (like file downloads) and provides
|
|
1715
|
+
* progress information about the download. Useful for implementing progress bars
|
|
1716
|
+
* or download status indicators.
|
|
1582
1717
|
*
|
|
1583
|
-
*
|
|
1584
|
-
*
|
|
1585
|
-
* await callApi("/posts");
|
|
1718
|
+
* @param context - Response stream context with progress event and response
|
|
1719
|
+
* @returns Promise or void - Hook can be async or sync
|
|
1586
1720
|
*
|
|
1587
|
-
* ```
|
|
1588
1721
|
*/
|
|
1589
|
-
|
|
1722
|
+
onResponseStream?: (context: ResponseStreamContext<TCallApiContext>) => Awaitable<unknown>;
|
|
1590
1723
|
/**
|
|
1591
|
-
*
|
|
1724
|
+
* Hook called when a request is being retried.
|
|
1725
|
+
*
|
|
1726
|
+
* This hook is triggered before each retry attempt, providing information about
|
|
1727
|
+
* the previous failure and the current retry attempt number. Useful for implementing
|
|
1728
|
+
* custom retry logic, exponential backoff, or retry logging.
|
|
1729
|
+
*
|
|
1730
|
+
* @param context - Retry context with error details and retry attempt count
|
|
1731
|
+
* @returns Promise or void - Hook can be async or sync
|
|
1592
1732
|
*
|
|
1593
|
-
* Defines validation rules for requests and responses that apply to all
|
|
1594
|
-
* instances created from this base configuration. Provides type safety
|
|
1595
|
-
* and runtime validation for API interactions.
|
|
1596
1733
|
*/
|
|
1597
|
-
|
|
1734
|
+
onRetry?: (context: RetryContext<TCallApiContext>) => Awaitable<unknown>;
|
|
1598
1735
|
/**
|
|
1599
|
-
*
|
|
1736
|
+
* Hook called when a successful response (2xx status) is received from the API.
|
|
1600
1737
|
*
|
|
1601
|
-
*
|
|
1602
|
-
*
|
|
1603
|
-
*
|
|
1738
|
+
* This hook is triggered only for successful responses and provides access to
|
|
1739
|
+
* the parsed response data. Ideal for success logging, caching, or post-processing
|
|
1740
|
+
* of successful API responses.
|
|
1604
1741
|
*
|
|
1605
|
-
* @
|
|
1606
|
-
*
|
|
1607
|
-
* - **"options"**: Disables automatic merging of extra options only (hooks, plugins, etc.)
|
|
1608
|
-
* - **"request"**: Disables automatic merging of request options only (headers, body, etc.)
|
|
1742
|
+
* @param context - Success context with parsed response data and response object
|
|
1743
|
+
* @returns Promise or void - Hook can be async or sync
|
|
1609
1744
|
*
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
*
|
|
1614
|
-
* skipAutoMergeFor: "all",
|
|
1745
|
+
*/
|
|
1746
|
+
onSuccess?: (context: SuccessContext<TCallApiContext>) => Awaitable<unknown>;
|
|
1747
|
+
/**
|
|
1748
|
+
* Hook called when a validation error occurs.
|
|
1615
1749
|
*
|
|
1616
|
-
*
|
|
1617
|
-
*
|
|
1618
|
-
*
|
|
1619
|
-
* headers: {
|
|
1620
|
-
* ...ctx.request.headers, // Merge headers manually
|
|
1621
|
-
* "X-Custom": "value" // Add custom header
|
|
1622
|
-
* }
|
|
1623
|
-
* }));
|
|
1750
|
+
* This hook is triggered when request or response data fails validation against
|
|
1751
|
+
* a defined schema. It provides access to the validation error details and can
|
|
1752
|
+
* be used for custom error handling, logging, or fallback behavior.
|
|
1624
1753
|
*
|
|
1625
|
-
*
|
|
1626
|
-
*
|
|
1627
|
-
* skipAutoMergeFor: "options",
|
|
1754
|
+
* @param context - Validation error context with error details and response (if available)
|
|
1755
|
+
* @returns Promise or void - Hook can be async or sync
|
|
1628
1756
|
*
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1757
|
+
*/
|
|
1758
|
+
onValidationError?: (context: ValidationErrorContext<TCallApiContext>) => Awaitable<unknown>;
|
|
1759
|
+
}
|
|
1760
|
+
type HooksOrHooksArray<TCallApiContext extends NoInfer<CallApiContext> = DefaultCallApiContext> = { [Key in keyof Hooks<TCallApiContext>]: Hooks<TCallApiContext>[Key] | Array<Hooks<TCallApiContext>[Key]>; };
|
|
1761
|
+
interface HookConfigOptions {
|
|
1762
|
+
/**
|
|
1763
|
+
* Controls the execution mode of all composed hooks (main + plugin hooks).
|
|
1634
1764
|
*
|
|
1635
|
-
*
|
|
1636
|
-
*
|
|
1637
|
-
* }));
|
|
1765
|
+
* - **"parallel"**: All hooks execute simultaneously via Promise.all() for better performance
|
|
1766
|
+
* - **"sequential"**: All hooks execute one by one in registration order via await in a loop
|
|
1638
1767
|
*
|
|
1639
|
-
*
|
|
1640
|
-
* const client = callApi.create((ctx) => ({
|
|
1641
|
-
* skipAutoMergeFor: "request",
|
|
1768
|
+
* This affects how ALL hooks execute together, regardless of their source (main or plugin).
|
|
1642
1769
|
*
|
|
1643
|
-
*
|
|
1770
|
+
* @default "parallel"
|
|
1771
|
+
*/
|
|
1772
|
+
hooksExecutionMode?: "parallel" | "sequential";
|
|
1773
|
+
}
|
|
1774
|
+
type RequestContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = {
|
|
1775
|
+
/**
|
|
1776
|
+
* Base configuration object passed to createFetchClient.
|
|
1644
1777
|
*
|
|
1645
|
-
*
|
|
1646
|
-
*
|
|
1647
|
-
*
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
*
|
|
1778
|
+
* Contains the foundational configuration that applies to all requests
|
|
1779
|
+
* made by this client instance, such as baseURL, default headers, and
|
|
1780
|
+
* global options.
|
|
1781
|
+
*/
|
|
1782
|
+
baseConfig: Exclude<BaseCallApiConfig, AnyFunction>;
|
|
1783
|
+
/**
|
|
1784
|
+
* Instance-specific configuration object passed to the callApi instance.
|
|
1652
1785
|
*
|
|
1653
|
-
*
|
|
1654
|
-
*
|
|
1655
|
-
|
|
1786
|
+
* Contains configuration specific to this particular API call, which
|
|
1787
|
+
* can override or extend the base configuration.
|
|
1788
|
+
*/
|
|
1789
|
+
config: CallApiConfig;
|
|
1790
|
+
/**
|
|
1791
|
+
* Merged options combining base config, instance config, and default options.
|
|
1656
1792
|
*
|
|
1657
|
-
*
|
|
1658
|
-
*
|
|
1659
|
-
* ? [...(ctx.options.plugins || []), authPlugin]
|
|
1660
|
-
* : ctx.options.plugins?.filter(p => p.name !== "auth") || []
|
|
1661
|
-
* }));
|
|
1662
|
-
* ```
|
|
1793
|
+
* This is the final resolved configuration that will be used for the request,
|
|
1794
|
+
* with proper precedence applied (instance > base > defaults).
|
|
1663
1795
|
*/
|
|
1664
|
-
|
|
1796
|
+
options: CallApiExtraOptionsForHooks<TCallApiContext>;
|
|
1797
|
+
/**
|
|
1798
|
+
* Merged request object ready to be sent.
|
|
1799
|
+
*
|
|
1800
|
+
* Contains the final request configuration including URL, method, headers,
|
|
1801
|
+
* body, and other fetch options. This object can be modified in onRequest
|
|
1802
|
+
* hooks to customize the outgoing request.
|
|
1803
|
+
*/
|
|
1804
|
+
request: CallApiRequestOptionsForHooks;
|
|
1665
1805
|
};
|
|
1666
|
-
type
|
|
1667
|
-
type
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1806
|
+
type SuccessContext<TCallApiContext extends Pick<CallApiContext, "Data" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = DistributiveOmit<CallApiResultSuccessVariant<TCallApiContext["Data"]>, "error"> & RequestContext<TCallApiContext>;
|
|
1807
|
+
type ResponseContext<TCallApiContext extends Pick<CallApiContext, "Data" | "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = RequestContext<TCallApiContext> & (Prettify<CallApiResultSuccessVariant<TCallApiContext["Data"]>> | Prettify<Extract<CallApiResultErrorVariant<TCallApiContext["ErrorData"]>, {
|
|
1808
|
+
error: PossibleHTTPError<TCallApiContext["ErrorData"]>;
|
|
1809
|
+
}>>);
|
|
1810
|
+
type RequestStreamContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = RequestContext<TCallApiContext> & {
|
|
1811
|
+
event: StreamProgressEvent;
|
|
1812
|
+
requestInstance: Request;
|
|
1672
1813
|
};
|
|
1673
|
-
type
|
|
1674
|
-
|
|
1814
|
+
type ResponseStreamContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = RequestContext<TCallApiContext> & {
|
|
1815
|
+
event: StreamProgressEvent;
|
|
1816
|
+
response: Response;
|
|
1675
1817
|
};
|
|
1676
|
-
type
|
|
1677
|
-
|
|
1818
|
+
type ErrorContext<TCallApiContext extends Pick<CallApiContext, "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = DistributiveOmit<CallApiResultErrorVariant<TCallApiContext["ErrorData"]>, "data"> & RequestContext<TCallApiContext>;
|
|
1819
|
+
type ValidationErrorContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = Extract<ErrorContext<TCallApiContext>, {
|
|
1820
|
+
error: PossibleValidationError;
|
|
1821
|
+
}> & RequestContext<TCallApiContext>;
|
|
1822
|
+
type RequestErrorContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = Extract<ErrorContext<TCallApiContext>, {
|
|
1823
|
+
error: PossibleJavaScriptError;
|
|
1824
|
+
}> & RequestContext<TCallApiContext>;
|
|
1825
|
+
type ResponseErrorContext<TCallApiContext extends Pick<CallApiContext, "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = Extract<ErrorContext<TCallApiContext>, {
|
|
1826
|
+
error: PossibleHTTPError<TCallApiContext["ErrorData"]>;
|
|
1827
|
+
}> & RequestContext<TCallApiContext>;
|
|
1828
|
+
type RetryContext<TCallApiContext extends Pick<CallApiContext, "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = ErrorContext<TCallApiContext> & {
|
|
1829
|
+
retryAttemptCount: number;
|
|
1678
1830
|
};
|
|
1679
|
-
type
|
|
1831
|
+
type ExecuteHookInfo = {
|
|
1832
|
+
errorInfoOptions: ErrorInfoOptions;
|
|
1833
|
+
shouldThrowOnError: boolean | undefined;
|
|
1834
|
+
};
|
|
1835
|
+
//#endregion
|
|
1836
|
+
//#region src/plugins.d.ts
|
|
1837
|
+
type PluginSetupContext<TCallApiContext extends CallApiContext = DefaultCallApiContext> = RequestContext<TCallApiContext> & ReturnType<typeof getCurrentRouteSchemaKeyAndMainInitURL>;
|
|
1838
|
+
type PluginInitResult<TCallApiContext extends CallApiContext = DefaultCallApiContext> = Partial<Omit<PluginSetupContext<TCallApiContext>, "initURL" | "request"> & {
|
|
1839
|
+
initURL: InitURLOrURLObject;
|
|
1840
|
+
request: CallApiRequestOptions;
|
|
1841
|
+
}>;
|
|
1842
|
+
type GetDefaultDataTypeForPlugins<TData> = DefaultDataType extends TData ? never : TData;
|
|
1843
|
+
type PluginHooks<TCallApiContext extends CallApiContext = DefaultCallApiContext> = HooksOrHooksArray<OverrideCallApiContext<TCallApiContext, {
|
|
1844
|
+
Data: GetDefaultDataTypeForPlugins<TCallApiContext["Data"]>;
|
|
1845
|
+
ErrorData: GetDefaultDataTypeForPlugins<TCallApiContext["ErrorData"]>;
|
|
1846
|
+
}>>;
|
|
1847
|
+
type PluginMiddlewares<TCallApiContext extends CallApiContext = DefaultCallApiContext> = Middlewares<OverrideCallApiContext<TCallApiContext, {
|
|
1848
|
+
Data: GetDefaultDataTypeForPlugins<TCallApiContext["Data"]>;
|
|
1849
|
+
ErrorData: GetDefaultDataTypeForPlugins<TCallApiContext["ErrorData"]>;
|
|
1850
|
+
}>>;
|
|
1851
|
+
interface CallApiPlugin<TCallApiContext extends CallApiContext = DefaultCallApiContext> {
|
|
1680
1852
|
/**
|
|
1681
|
-
*
|
|
1682
|
-
*
|
|
1683
|
-
* Instance plugins are added to the base plugins and provide functionality
|
|
1684
|
-
* specific to this particular API instance. Can be a static array or a function
|
|
1685
|
-
* that receives base plugins and returns the instance plugins.
|
|
1686
|
-
*
|
|
1853
|
+
* A description for the plugin
|
|
1687
1854
|
*/
|
|
1688
|
-
|
|
1855
|
+
description?: string;
|
|
1689
1856
|
/**
|
|
1690
|
-
*
|
|
1691
|
-
*
|
|
1692
|
-
* Defines validation rules specific to this API instance, extending or overriding the base schema.
|
|
1693
|
-
*
|
|
1694
|
-
* Can be a static schema object or a function that receives base schema context and returns instance schemas.
|
|
1695
|
-
*
|
|
1857
|
+
* Defines additional options that can be passed to callApi
|
|
1696
1858
|
*/
|
|
1697
|
-
|
|
1859
|
+
extraOptionsDef?: ExtraOptionsWithContextTag<DefaultInferredExtraOptions>;
|
|
1698
1860
|
/**
|
|
1699
|
-
*
|
|
1700
|
-
*
|
|
1701
|
-
* Controls how validation schemas are applied and behave for this specific API instance.
|
|
1702
|
-
* Can override base schema configuration or extend it with instance-specific validation rules.
|
|
1703
|
-
*
|
|
1861
|
+
* Hooks for the plugin
|
|
1704
1862
|
*/
|
|
1705
|
-
|
|
1706
|
-
};
|
|
1707
|
-
type InstanceContext = {
|
|
1708
|
-
initURL: string;
|
|
1709
|
-
options: CallApiExtraOptions;
|
|
1710
|
-
request: CallApiRequestOptions;
|
|
1711
|
-
};
|
|
1712
|
-
type BaseCallApiConfig<TBaseCallApiContext extends CallApiContext = DefaultCallApiContext, TBaseData = DefaultDataType, TBaseErrorData = DefaultDataType, TBaseResultMode extends ResultModeType = ResultModeType, TBaseThrowOnError extends ThrowOnErrorBoolean = DefaultThrowOnError, TBaseResponseType extends ResponseTypeType = ResponseTypeType, TBaseSchemaAndConfig extends BaseCallApiSchemaAndConfig = BaseCallApiSchemaAndConfig, TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TComputedBaseConfig = BaseCallApiExtraOptions<TBaseCallApiContext, TBaseData, TBaseErrorData, TBaseResultMode, TBaseThrowOnError, TBaseResponseType, TBasePluginArray, TBaseSchemaAndConfig>> = (CallApiRequestOptions & TComputedBaseConfig) | ((context: InstanceContext) => CallApiRequestOptions & TComputedBaseConfig);
|
|
1713
|
-
type CallApiConfig<TCallApiContext extends CallApiContext = DefaultCallApiContext, TData = DefaultDataType, TErrorData = DefaultDataType, TResultMode extends ResultModeType = ResultModeType, TThrowOnError extends ThrowOnErrorBoolean = DefaultThrowOnError, TResponseType extends ResponseTypeType = ResponseTypeType, TBaseSchemaRoutes extends BaseCallApiSchemaRoutes = BaseCallApiSchemaRoutes, TSchema extends CallApiSchema = CallApiSchema, TBaseSchemaConfig extends CallApiSchemaConfig = CallApiSchemaConfig, TSchemaConfig extends CallApiSchemaConfig = CallApiSchemaConfig, TInitURL extends InitURLOrURLObject = InitURLOrURLObject, TCurrentRouteSchemaKey extends string = string, TBody extends InferSchemaOutput<TSchema["body"], Body> = InferSchemaOutput<TSchema["body"], Body>, TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TPluginArray extends CallApiPlugin[] = DefaultPluginArray> = InferExtraOptions<TSchema, TBaseSchemaRoutes, TCurrentRouteSchemaKey, TCallApiContext> & InferRequestOptions<TSchema, TInitURL, TBody> & Omit<CallApiExtraOptions<TCallApiContext, TData, TErrorData, TResultMode, TThrowOnError, TResponseType, TBasePluginArray, TPluginArray, TBaseSchemaRoutes, TSchema, TBaseSchemaConfig, TSchemaConfig, TCurrentRouteSchemaKey, TBody>, keyof InferExtraOptions<CallApiSchema, BaseCallApiSchemaRoutes, string, CallApiContext>> & Omit<CallApiRequestOptions<TBody>, keyof InferRequestOptions<CallApiSchema, string, TBody>>;
|
|
1714
|
-
type CallApiParameters<TData = DefaultDataType, TErrorData = DefaultDataType, TResultMode extends ResultModeType = ResultModeType, TCallApiContext extends CallApiContext = DefaultCallApiContext, TThrowOnError extends ThrowOnErrorBoolean = DefaultThrowOnError, TResponseType extends ResponseTypeType = ResponseTypeType, TBaseSchemaRoutes extends BaseCallApiSchemaRoutes = BaseCallApiSchemaRoutes, TSchema extends CallApiSchema = CallApiSchema, TBaseSchemaConfig extends CallApiSchemaConfig = CallApiSchemaConfig, TSchemaConfig extends CallApiSchemaConfig = CallApiSchemaConfig, TInitURL extends InitURLOrURLObject = InitURLOrURLObject, TCurrentRouteSchemaKey extends string = string, TBody extends InferSchemaOutput<TSchema["body"], Body> = InferSchemaOutput<TSchema["body"], Body>, TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TPluginArray extends CallApiPlugin[] = DefaultPluginArray, TComputedConfig = CallApiConfig<TCallApiContext, TData, TErrorData, TResultMode, TThrowOnError, TResponseType, TBaseSchemaRoutes, TSchema, TBaseSchemaConfig, TSchemaConfig, TInitURL, TCurrentRouteSchemaKey, TBody, TBasePluginArray, TPluginArray>, TComputedRequiredOptions = InferExtraOptions<TSchema, TBaseSchemaRoutes, TCurrentRouteSchemaKey, TCallApiContext> & InferRequestOptions<TSchema, TInitURL, TBody>> = NonNullable<unknown> extends TComputedRequiredOptions ? [initURL: TInitURL, config?: TComputedConfig] : [initURL: TInitURL, config: TComputedConfig];
|
|
1715
|
-
type CallApiResult<TData, TErrorData, TResultMode extends ResultModeType, TThrowOnError extends ThrowOnErrorBoolean> = InferCallApiResult<TData, TErrorData, TResultMode, TThrowOnError>;
|
|
1716
|
-
type CallApiResultLoose<TData, TErrorData, TResultMode extends ResultModeType = ResultModeType, TThrowOnError extends ThrowOnErrorBoolean = ThrowOnErrorBoolean> = InferCallApiResult<TData, TErrorData, TResultMode, TThrowOnError>;
|
|
1717
|
-
//#endregion
|
|
1718
|
-
//#region src/auth.d.ts
|
|
1719
|
-
type PossibleAuthValue = Awaitable<string | null | undefined>;
|
|
1720
|
-
type PossibleAuthValueOrGetter = PossibleAuthValue | (() => PossibleAuthValue);
|
|
1721
|
-
type BearerAuth = {
|
|
1722
|
-
type: "Bearer";
|
|
1723
|
-
value: PossibleAuthValueOrGetter;
|
|
1724
|
-
};
|
|
1725
|
-
type TokenAuth = {
|
|
1726
|
-
type: "Token";
|
|
1727
|
-
value: PossibleAuthValueOrGetter;
|
|
1728
|
-
};
|
|
1729
|
-
type BasicAuth = {
|
|
1730
|
-
type: "Basic";
|
|
1731
|
-
username: PossibleAuthValueOrGetter;
|
|
1732
|
-
password: PossibleAuthValueOrGetter;
|
|
1733
|
-
};
|
|
1734
|
-
/**
|
|
1735
|
-
* Custom auth
|
|
1736
|
-
*
|
|
1737
|
-
* @param prefix - prefix of the header
|
|
1738
|
-
* @param authValue - value of the header
|
|
1739
|
-
*
|
|
1740
|
-
* @example
|
|
1741
|
-
* ```ts
|
|
1742
|
-
* {
|
|
1743
|
-
* type: "Custom",
|
|
1744
|
-
* prefix: "Token",
|
|
1745
|
-
* authValue: "token"
|
|
1746
|
-
* }
|
|
1747
|
-
* ```
|
|
1748
|
-
*/
|
|
1749
|
-
type CustomAuth = {
|
|
1750
|
-
type: "Custom";
|
|
1751
|
-
prefix: PossibleAuthValueOrGetter;
|
|
1752
|
-
value: PossibleAuthValueOrGetter;
|
|
1753
|
-
};
|
|
1754
|
-
type AuthOption = PossibleAuthValueOrGetter | BearerAuth | TokenAuth | BasicAuth | CustomAuth;
|
|
1755
|
-
//#endregion
|
|
1756
|
-
//#region src/types/conditional-types.d.ts
|
|
1757
|
-
/**
|
|
1758
|
-
* @description Makes a type partial if the output type of TSchema is not provided or has undefined in the union, otherwise makes it required
|
|
1759
|
-
*/
|
|
1760
|
-
type MakeSchemaOptionRequiredIfDefined<TSchemaOption extends CallApiSchema[keyof CallApiSchema], TObject> = undefined extends InferSchemaOutput<TSchemaOption, undefined> ? TObject : Required<TObject>;
|
|
1761
|
-
type MergeBaseWithRouteKey<TBaseURLOrPrefix extends string | undefined, TRouteKey extends string> = TBaseURLOrPrefix extends string ? TRouteKey extends `${AtSymbol}${infer TMethod extends RouteKeyMethods}/${infer TRestOfRoutKey}` ? `${AtSymbol}${TMethod}/${RemoveLeadingSlash<RemoveTrailingSlash<TBaseURLOrPrefix>>}/${RemoveLeadingSlash<TRestOfRoutKey>}` : `${TBaseURLOrPrefix}${TRouteKey}` : TRouteKey;
|
|
1762
|
-
type ApplyURLBasedConfig<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = TSchemaConfig["prefix"] extends string ? MergeBaseWithRouteKey<TSchemaConfig["prefix"], TSchemaRouteKeys> : TSchemaConfig["baseURL"] extends string ? MergeBaseWithRouteKey<TSchemaConfig["baseURL"], TSchemaRouteKeys> : TSchemaRouteKeys;
|
|
1763
|
-
type ApplyStrictConfig<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = TSchemaConfig["strict"] extends true ? TSchemaRouteKeys // eslint-disable-next-line perfectionist/sort-union-types -- Don't sort union types
|
|
1764
|
-
: TSchemaRouteKeys | Exclude<InitURLOrURLObject, RouteKeyMethodsURLUnion>;
|
|
1765
|
-
type ApplySchemaConfiguration<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = ApplyStrictConfig<TSchemaConfig, ApplyURLBasedConfig<TSchemaConfig, TSchemaRouteKeys>>;
|
|
1766
|
-
type InferAllMainRoutes<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes> = Omit<TBaseSchemaRoutes, FallBackRouteSchemaKey>;
|
|
1767
|
-
type InferAllMainRouteKeys<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TSchemaConfig extends CallApiSchemaConfig> = ApplySchemaConfiguration<TSchemaConfig, Extract<keyof InferAllMainRoutes<TBaseSchemaRoutes>, string>>;
|
|
1768
|
-
type InferInitURL<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TSchemaConfig extends CallApiSchemaConfig> = keyof TBaseSchemaRoutes extends never ? InitURLOrURLObject : InferAllMainRouteKeys<TBaseSchemaRoutes, TSchemaConfig>;
|
|
1769
|
-
type GetCurrentRouteSchemaKey<TSchemaConfig extends CallApiSchemaConfig, TPath> = TPath extends URL ? string : TSchemaConfig["prefix"] extends string ? TPath extends (`${AtSymbol}${infer TMethod extends RouteKeyMethods}/${RemoveLeadingSlash<TSchemaConfig["prefix"]>}${infer TCurrentRoute}`) ? `${AtSymbol}${TMethod}/${RemoveLeadingSlash<TCurrentRoute>}` : TPath extends `${TSchemaConfig["prefix"]}${infer TCurrentRoute}` ? TCurrentRoute : string : TSchemaConfig["baseURL"] extends string ? TPath extends (`${AtSymbol}${infer TMethod extends RouteKeyMethods}/${TSchemaConfig["baseURL"]}${infer TCurrentRoute}`) ? `${AtSymbol}${TMethod}/${RemoveLeadingSlash<TCurrentRoute>}` : TPath extends `${TSchemaConfig["baseURL"]}${infer TCurrentRoute}` ? TCurrentRoute : string : TPath;
|
|
1770
|
-
type GetCurrentRouteSchema<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TCurrentRouteSchemaKey extends string, TComputedFallBackRouteSchema = TBaseSchemaRoutes[FallBackRouteSchemaKey], TComputedCurrentRouteSchema = TBaseSchemaRoutes[TCurrentRouteSchemaKey], TComputedRouteSchema extends CallApiSchema = NonNullable<Omit<TComputedFallBackRouteSchema, keyof TComputedCurrentRouteSchema> & TComputedCurrentRouteSchema>> = TComputedRouteSchema extends CallApiSchema ? Writeable<TComputedRouteSchema, "deep"> : CallApiSchema;
|
|
1771
|
-
type JsonPrimitive = boolean | number | string | null | undefined;
|
|
1772
|
-
type SerializableObject = Record<PropertyKey, unknown>;
|
|
1773
|
-
type SerializableArray = Array<JsonPrimitive | SerializableObject> | ReadonlyArray<JsonPrimitive | SerializableObject>;
|
|
1774
|
-
type Body = UnmaskType<Exclude<RequestInit["body"], undefined> | SerializableArray | SerializableObject>;
|
|
1775
|
-
type InferBodyOption<TSchema extends CallApiSchema, TBody = InferSchemaOutput<TSchema["body"], Body>> = MakeSchemaOptionRequiredIfDefined<TSchema["body"], {
|
|
1863
|
+
hooks?: PluginHooks<TCallApiContext> | ((context: PluginSetupContext<TCallApiContext>) => Awaitable<PluginHooks<TCallApiContext>> | Awaitable<void>);
|
|
1776
1864
|
/**
|
|
1777
|
-
*
|
|
1865
|
+
* A unique id for the plugin
|
|
1778
1866
|
*/
|
|
1779
|
-
|
|
1780
|
-
}>;
|
|
1781
|
-
type MethodUnion = UnmaskType<"CONNECT" | "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT" | "TRACE" | AnyString>;
|
|
1782
|
-
type ExtractMethodFromURL<TInitURL> = string extends TInitURL ? MethodUnion : TInitURL extends `${AtSymbol}${infer TMethod extends RouteKeyMethods}/${string}` ? Uppercase<TMethod> : MethodUnion;
|
|
1783
|
-
type InferMethodOption<TSchema extends CallApiSchema, TInitURL extends InitURLOrURLObject> = MakeSchemaOptionRequiredIfDefined<TSchema["method"], {
|
|
1867
|
+
id: string;
|
|
1784
1868
|
/**
|
|
1785
|
-
*
|
|
1786
|
-
* @default "GET"
|
|
1869
|
+
* Defines metadata that can be passed to callApi
|
|
1787
1870
|
*/
|
|
1788
|
-
|
|
1789
|
-
}>;
|
|
1790
|
-
type HeadersOption = UnmaskType<Headers | Record<"Authorization", CommonAuthorizationHeaders | undefined> | Record<"Content-Type", CommonContentTypes | undefined> | Record<CommonRequestHeaders, string | undefined> | Record<string, string | undefined> | Array<[string, string]>>;
|
|
1791
|
-
type InferHeadersOption<TSchema extends CallApiSchema> = MakeSchemaOptionRequiredIfDefined<TSchema["headers"], {
|
|
1871
|
+
metaDef?: MetaWithContextTag<DefaultMetaObject>;
|
|
1792
1872
|
/**
|
|
1793
|
-
*
|
|
1873
|
+
* Middlewares that for the plugin
|
|
1794
1874
|
*/
|
|
1795
|
-
|
|
1796
|
-
baseHeaders: Extract<HeadersOption, Record<string, unknown>>;
|
|
1797
|
-
}) => InferSchemaOutput<TSchema["headers"], HeadersOption>);
|
|
1798
|
-
}>;
|
|
1799
|
-
type InferRequestOptions<TSchema extends CallApiSchema, TInitURL extends InferInitURL<BaseCallApiSchemaRoutes, CallApiSchemaConfig>, TBody = InferSchemaOutput<TSchema["body"], Body>> = InferBodyOption<TSchema, TBody> & InferHeadersOption<TSchema> & InferMethodOption<TSchema, TInitURL>;
|
|
1800
|
-
type InferMetaOption<TSchema extends CallApiSchema, TCallApiContext extends CallApiContext> = MakeSchemaOptionRequiredIfDefined<TSchema["meta"], {
|
|
1875
|
+
middlewares?: PluginMiddlewares<TCallApiContext> | ((context: PluginSetupContext<TCallApiContext>) => Awaitable<PluginMiddlewares<TCallApiContext>> | Awaitable<void>);
|
|
1801
1876
|
/**
|
|
1802
|
-
*
|
|
1803
|
-
* to associate with the request, typically used for logging or tracing.
|
|
1804
|
-
*
|
|
1805
|
-
* - A good use case for this, would be to use the info to handle specific cases in any of the shared interceptors.
|
|
1806
|
-
*
|
|
1807
|
-
* @example
|
|
1808
|
-
* ```ts
|
|
1809
|
-
* const callMainApi = callApi.create({
|
|
1810
|
-
* baseURL: "https://main-api.com",
|
|
1811
|
-
* onResponseError: ({ response, options }) => {
|
|
1812
|
-
* if (options.meta?.userId) {
|
|
1813
|
-
* console.error(`User ${options.meta.userId} made an error`);
|
|
1814
|
-
* }
|
|
1815
|
-
* },
|
|
1816
|
-
* });
|
|
1817
|
-
*
|
|
1818
|
-
* const response = await callMainApi({
|
|
1819
|
-
* url: "https://example.com/api/data",
|
|
1820
|
-
* meta: { userId: "123" },
|
|
1821
|
-
* });
|
|
1822
|
-
* ```
|
|
1877
|
+
* A name for the plugin
|
|
1823
1878
|
*/
|
|
1824
|
-
|
|
1825
|
-
}>;
|
|
1826
|
-
type InferAuthOption<TSchema extends CallApiSchema> = MakeSchemaOptionRequiredIfDefined<TSchema["auth"], {
|
|
1879
|
+
name: string;
|
|
1827
1880
|
/**
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
* - String: Direct authorization header value
|
|
1832
|
-
* - Auth object: Structured authentication configuration
|
|
1833
|
-
*
|
|
1834
|
-
* @example
|
|
1835
|
-
* ```ts
|
|
1836
|
-
* // Bearer auth
|
|
1837
|
-
* const response = await callMainApi({
|
|
1838
|
-
* url: "https://example.com/api/data",
|
|
1839
|
-
* auth: "123456",
|
|
1840
|
-
* });
|
|
1841
|
-
*
|
|
1842
|
-
* // Bearer auth
|
|
1843
|
-
* const response = await callMainApi({
|
|
1844
|
-
* url: "https://example.com/api/data",
|
|
1845
|
-
* auth: {
|
|
1846
|
-
* type: "Bearer",
|
|
1847
|
-
* value: "123456",
|
|
1848
|
-
* },
|
|
1849
|
-
})
|
|
1850
|
-
*
|
|
1851
|
-
* // Token auth
|
|
1852
|
-
* const response = await callMainApi({
|
|
1853
|
-
* url: "https://example.com/api/data",
|
|
1854
|
-
* auth: {
|
|
1855
|
-
* type: "Token",
|
|
1856
|
-
* value: "123456",
|
|
1857
|
-
* },
|
|
1858
|
-
* });
|
|
1859
|
-
*
|
|
1860
|
-
* // Basic auth
|
|
1861
|
-
* const response = await callMainApi({
|
|
1862
|
-
* url: "https://example.com/api/data",
|
|
1863
|
-
* auth: {
|
|
1864
|
-
* type: "Basic",
|
|
1865
|
-
* username: "username",
|
|
1866
|
-
* password: "password",
|
|
1867
|
-
* },
|
|
1868
|
-
* });
|
|
1869
|
-
*
|
|
1870
|
-
* ```
|
|
1871
|
-
*/
|
|
1872
|
-
auth?: InferSchemaOutput<TSchema["auth"], AuthOption>;
|
|
1873
|
-
}>;
|
|
1874
|
-
type InferQueryOption<TSchema extends CallApiSchema> = MakeSchemaOptionRequiredIfDefined<TSchema["query"], {
|
|
1881
|
+
* Base schema for the client.
|
|
1882
|
+
*/
|
|
1883
|
+
schema?: BaseCallApiSchemaAndConfig;
|
|
1875
1884
|
/**
|
|
1876
|
-
*
|
|
1885
|
+
* A function that will be called when the plugin is initialized. This will be called before the any of the other internal functions.
|
|
1877
1886
|
*/
|
|
1878
|
-
|
|
1879
|
-
}>;
|
|
1880
|
-
type EmptyString = "";
|
|
1881
|
-
type EmptyTuple = readonly [];
|
|
1882
|
-
type StringTuple = readonly string[];
|
|
1883
|
-
type PossibleParamNamePatterns = `${string}:${string}` | `${string}{${string}}${"" | AnyString}`;
|
|
1884
|
-
type ExtractRouteParamNames<TCurrentRoute, TParamNamesAccumulator extends StringTuple = EmptyTuple> = TCurrentRoute extends PossibleParamNamePatterns ? TCurrentRoute extends `${infer TRoutePrefix}:${infer TParamAndRemainingRoute}` ? TParamAndRemainingRoute extends `${infer TCurrentParam}/${infer TRemainingRoute}` ? TCurrentParam extends EmptyString ? ExtractRouteParamNames<`${TRoutePrefix}/${TRemainingRoute}`, TParamNamesAccumulator> : ExtractRouteParamNames<`${TRoutePrefix}/${TRemainingRoute}`, [...TParamNamesAccumulator, TCurrentParam]> : TParamAndRemainingRoute extends `${infer TCurrentParam}` ? TCurrentParam extends EmptyString ? ExtractRouteParamNames<TRoutePrefix, TParamNamesAccumulator> : ExtractRouteParamNames<TRoutePrefix, [...TParamNamesAccumulator, TCurrentParam]> : ExtractRouteParamNames<TRoutePrefix, TParamNamesAccumulator> : TCurrentRoute extends `${infer TRoutePrefix}{${infer TCurrentParam}}${infer TRemainingRoute}` ? TCurrentParam extends EmptyString ? ExtractRouteParamNames<`${TRoutePrefix}${TRemainingRoute}`, TParamNamesAccumulator> : ExtractRouteParamNames<`${TRoutePrefix}${TRemainingRoute}`, [...TParamNamesAccumulator, TCurrentParam]> : TParamNamesAccumulator : TParamNamesAccumulator;
|
|
1885
|
-
type ConvertParamNamesToRecord<TParamNames extends StringTuple> = Prettify<TParamNames extends (readonly [infer TFirstParamName extends string, ...infer TRemainingParamNames extends StringTuple]) ? Record<TFirstParamName, AllowedQueryParamValues> & ConvertParamNamesToRecord<TRemainingParamNames> : NonNullable<unknown>>;
|
|
1886
|
-
type ConvertParamNamesToTuple<TParamNames extends StringTuple> = TParamNames extends readonly [string, ...infer TRemainingParamNames extends StringTuple] ? [AllowedQueryParamValues, ...ConvertParamNamesToTuple<TRemainingParamNames>] : [];
|
|
1887
|
-
type InferParamsFromRoute<TCurrentRoute> = ExtractRouteParamNames<TCurrentRoute> extends StringTuple ? ExtractRouteParamNames<TCurrentRoute> extends EmptyTuple ? Params : ConvertParamNamesToRecord<ExtractRouteParamNames<TCurrentRoute>> | ConvertParamNamesToTuple<ExtractRouteParamNames<TCurrentRoute>> : Params;
|
|
1888
|
-
type MakeParamsOptionRequired<TParamsSchemaOption extends CallApiSchema["params"], TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TCurrentRouteSchemaKey extends string, TObject> = MakeSchemaOptionRequiredIfDefined<TParamsSchemaOption, Params extends InferParamsFromRoute<TCurrentRouteSchemaKey> ? TObject : TCurrentRouteSchemaKey extends Extract<keyof TBaseSchemaRoutes, TCurrentRouteSchemaKey> ? undefined extends InferSchemaOutput<TParamsSchemaOption, null> ? TObject : Required<TObject> : TObject>;
|
|
1889
|
-
type InferParamsOption<TSchema extends CallApiSchema, TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TCurrentRouteSchemaKey extends string> = MakeParamsOptionRequired<TSchema["params"], TBaseSchemaRoutes, TCurrentRouteSchemaKey, {
|
|
1887
|
+
setup?: (context: PluginSetupContext<TCallApiContext>) => Awaitable<PluginInitResult<TCallApiContext>> | Awaitable<void>;
|
|
1890
1888
|
/**
|
|
1891
|
-
*
|
|
1889
|
+
* A version for the plugin
|
|
1892
1890
|
*/
|
|
1893
|
-
|
|
1894
|
-
}
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
type
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
} : {
|
|
1912
|
-
throwOnError?: ThrowOnErrorType<TErrorData, TThrowOnError>;
|
|
1891
|
+
version?: string;
|
|
1892
|
+
}
|
|
1893
|
+
//#endregion
|
|
1894
|
+
//#region src/types/callapi-context.d.ts
|
|
1895
|
+
interface CallApiContext {
|
|
1896
|
+
Data?: DefaultDataType;
|
|
1897
|
+
ErrorData?: DefaultDataType;
|
|
1898
|
+
InferredExtraOptions?: DefaultInferredExtraOptions;
|
|
1899
|
+
Meta?: DefaultMetaObject;
|
|
1900
|
+
ResultMode?: ResultModeType;
|
|
1901
|
+
}
|
|
1902
|
+
type GetCallApiContext<TCallApiContext extends CallApiContext> = TCallApiContext;
|
|
1903
|
+
type GetCallApiContextRequired<TCallApiContext extends Required<CallApiContext>> = TCallApiContext;
|
|
1904
|
+
type OverrideCallApiContext<TFullCallApiContext extends CallApiContext, TOverrideCallApiContext extends CallApiContext> = Prettify<Omit<TFullCallApiContext, keyof TOverrideCallApiContext> & TOverrideCallApiContext>;
|
|
1905
|
+
declare const callApiContextSymbol: unique symbol;
|
|
1906
|
+
type callApiContextSymbol = typeof callApiContextSymbol;
|
|
1907
|
+
type ContextTag<TType, TCallApiContext extends CallApiContext> = TType & {
|
|
1908
|
+
readonly [callApiContextSymbol]: TCallApiContext;
|
|
1913
1909
|
};
|
|
1910
|
+
type MetaWithContextTag<TMeta extends DefaultMetaObject | undefined> = ContextTag<TMeta, {
|
|
1911
|
+
Meta: TMeta;
|
|
1912
|
+
}>;
|
|
1913
|
+
type ExtraOptionsWithContextTag<TExtraOptions extends DefaultInferredExtraOptions> = ContextTag<TExtraOptions, {
|
|
1914
|
+
InferredExtraOptions: TExtraOptions;
|
|
1915
|
+
}>;
|
|
1916
|
+
type InferMetaFromTag<TTaggedType, TFallback = never> = TTaggedType extends ContextTag<unknown, infer TCallApiContext extends CallApiContext> ? IsEmptyObject<TCallApiContext["Meta"]> extends true ? TFallback : TCallApiContext["Meta"] : TFallback;
|
|
1917
|
+
type InferExtraOptionsFromTag<TTaggedType> = TTaggedType extends ContextTag<unknown, infer TCallApiContext extends CallApiContext> ? unknown extends TCallApiContext["InferredExtraOptions"] ? never : TCallApiContext["InferredExtraOptions"] : never;
|
|
1914
1918
|
//#endregion
|
|
1915
|
-
export {
|
|
1916
|
-
//# sourceMappingURL=
|
|
1919
|
+
export { PossibleValidationError as $, DefaultCallApiContext as $t, isHTTPErrorInstance as A, ValidationError as At, defineSchema as B, FallBackRouteSchemaKey as Bt, SuccessContext as C, CallApiResult as Ct, metaHelper as D, InstanceContext as Dt, extraOptionsHelper as E, GetBaseSchemaRoutes as Et, defineFallbackRouteSchema as F, CallApiSchema as Ft, toSearchParams as G, DedupeOptions as Gt, defineSchemaRoutes as H, FetchImpl as Ht, defineInstanceConfig as I, CallApiSchemaConfig as It, CallApiResultSuccessVariant as J, CommonRequestHeaders as Jt, CallApiResultErrorVariant as K, AnyString as Kt, defineMainSchema as L, InferSchemaInput as Lt, isValidationError as M, BaseCallApiSchemaAndConfig as Mt, isValidationErrorInstance as N, BaseCallApiSchemaRoutes as Nt, objectifyHeaders as O, Register as Ot, defineBaseConfig as P, BaseSchemaRouteKeyPrefixes as Pt, PossibleJavaScriptError as Q, Writeable as Qt, definePlugin as R, InferSchemaOutput as Rt, ResponseStreamContext as S, CallApiRequestOptions as St, RetryOptions as T, GetBaseSchemaConfig as Tt, toFormData as U, FetchMiddlewareContext as Ut, defineSchemaConfig as V, fallBackRouteSchemaKey as Vt, toQueryString as W, Middlewares as Wt, InferCallApiResult as X, NoInferUnMasked as Xt, GetResponseType as Y, DistributiveOmit as Yt, PossibleHTTPError as Z, UnionToIntersection as Zt, HooksOrHooksArray as _, BaseCallApiConfig as _t, GetCallApiContextRequired as a, Body as at, ResponseContext as b, CallApiExtraOptions as bt, MetaWithContextTag as c, HeadersOption as ct, PluginMiddlewares as d, InferInitURL as dt, DefaultMetaObject as en, ResponseTypeMap as et, PluginSetupContext as f, InferParamsFromRoute as ft, Hooks as g, AuthOption as gt, ErrorContext as h, ThrowOnErrorBoolean as ht, GetCallApiContext as i, ApplyURLBasedConfig as it, isJavascriptError as j, URLOptions as jt, isHTTPError as k, HTTPError as kt, CallApiPlugin as l, InferAllMainRouteKeys as lt, CallApiRequestOptionsForHooks as m, SerializableObject as mt, ContextTag as n, fetchSpecificKeys as nn, ResultModeType as nt, InferExtraOptionsFromTag as o, GetCurrentRouteSchema as ot, CallApiExtraOptionsForHooks as p, SerializableArray as pt, CallApiResultSuccessOrErrorVariant as q, CommonContentTypes as qt, ExtraOptionsWithContextTag as r, ApplyStrictConfig as rt, InferMetaFromTag as s, GetCurrentRouteSchemaKey as st, CallApiContext as t, DefaultPluginArray as tn, ResponseTypeType as tt, PluginHooks as u, InferAllMainRoutes as ut, RequestContext as v, BaseCallApiExtraOptions as vt, RefetchOptions as w, CallApiResultLoose as wt, ResponseErrorContext as x, CallApiParameters as xt, RequestStreamContext as y, CallApiConfig as yt, definePluginWithContext as z, InferSchemaResult as zt };
|
|
1920
|
+
//# sourceMappingURL=callapi-context-NF0HXJwF.d.ts.map
|