@zayne-labs/callapi 1.11.28 → 1.11.30

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