@zayne-labs/callapi 1.11.46 → 1.12.1

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.
@@ -75,991 +75,1041 @@ type CustomAuth = {
75
75
  };
76
76
  type AuthOption = PossibleAuthValueOrGetter | BearerAuth | TokenAuth | BasicAuth | CustomAuth;
77
77
  //#endregion
78
- //#region src/stream.d.ts
79
- type StreamProgressEvent = {
80
- /**
81
- * Current chunk of data being streamed
82
- */
83
- chunk: Uint8Array;
84
- /**
85
- * Progress in percentage
86
- */
87
- progress: number;
78
+ //#region src/constants/validation.d.ts
79
+ declare const fallBackRouteSchemaKey = "@default";
80
+ type FallBackRouteSchemaKey = typeof fallBackRouteSchemaKey;
81
+ //#endregion
82
+ //#region src/types/standard-schema.d.ts
83
+ /**
84
+ * The Standard Schema interface.
85
+ * @see https://github.com/standard-schema/standard-schema
86
+ */
87
+ /** The Standard Typed interface. This is a base type extended by other specs. */
88
+ interface StandardTypedV1<Input = unknown, Output = Input> {
89
+ /** The Standard properties. */
90
+ readonly "~standard": StandardTypedV1.Props<Input, Output>;
91
+ }
92
+ declare namespace StandardTypedV1 {
93
+ /** The Standard Typed properties interface. */
94
+ interface Props<Input = unknown, Output = Input> {
95
+ /** Inferred types associated with the schema. */
96
+ readonly types?: Types<Input, Output> | undefined;
97
+ /** The vendor name of the schema library. */
98
+ readonly vendor: string;
99
+ /** The version number of the standard. */
100
+ readonly version: 1;
101
+ }
102
+ /** The Standard Typed types interface. */
103
+ interface Types<Input = unknown, Output = Input> {
104
+ /** The input type of the schema. */
105
+ readonly input: Input;
106
+ /** The output type of the schema. */
107
+ readonly output: Output;
108
+ }
109
+ /** Infers the input type of a Standard Typed. */
110
+ type InferInput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["input"];
111
+ /** Infers the output type of a Standard Typed. */
112
+ type InferOutput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["output"];
113
+ }
114
+ /** The Standard Schema interface. */
115
+ interface StandardSchemaV1<Input = unknown, Output = Input> {
116
+ /** The Standard Schema properties. */
117
+ readonly "~standard": StandardSchemaV1.Props<Input, Output>;
118
+ }
119
+ declare namespace StandardSchemaV1 {
120
+ /** The Standard Schema properties interface. */
121
+ interface Props<Input = unknown, Output = Input> extends StandardTypedV1.Props<Input, Output> {
122
+ /** Validates unknown input values. */
123
+ readonly validate: (value: unknown, options?: StandardSchemaV1.Options) => Promise<Result<Output>> | Result<Output>;
124
+ }
125
+ /** The result interface of the validate function. */
126
+ type Result<Output> = FailureResult | SuccessResult<Output>;
127
+ /** The result interface if validation succeeds. */
128
+ interface SuccessResult<Output> {
129
+ /** A falsy value for `issues` indicates success. */
130
+ readonly issues?: undefined;
131
+ /** The typed output value. */
132
+ readonly value: Output;
133
+ }
134
+ interface Options {
135
+ /** Explicit support for additional vendor-specific parameters, if needed. */
136
+ readonly libraryOptions?: Record<string, unknown> | undefined;
137
+ }
138
+ /** The result interface if validation fails. */
139
+ interface FailureResult {
140
+ /** The issues of failed validation. */
141
+ readonly issues: readonly Issue[];
142
+ }
143
+ /** The issue interface of the failure output. */
144
+ interface Issue {
145
+ /** The error message of the issue. */
146
+ readonly message: string;
147
+ /** The path of the issue, if any. */
148
+ readonly path?: ReadonlyArray<PathSegment | PropertyKey> | undefined;
149
+ }
150
+ /** The path segment interface of the issue. */
151
+ interface PathSegment {
152
+ /** The key representing a path segment. */
153
+ readonly key: PropertyKey;
154
+ }
155
+ /** The Standard types interface. */
156
+ type Types<Input = unknown, Output = Input> = StandardTypedV1.Types<Input, Output>;
157
+ /** Infers the input type of a Standard. */
158
+ type InferInput<Schema extends StandardTypedV1> = StandardTypedV1.InferInput<Schema>;
159
+ /** Infers the output type of a Standard. */
160
+ type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
161
+ }
162
+ //#endregion
163
+ //#region src/validation.d.ts
164
+ type ResultVariant = "infer-input" | "infer-output";
165
+ 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;
166
+ type InferSchemaOutput<TSchema, TFallbackResult = unknown> = InferSchemaResult<TSchema, TFallbackResult, "infer-output">;
167
+ type InferSchemaInput<TSchema, TFallbackResult = unknown> = InferSchemaResult<TSchema, TFallbackResult, "infer-input">;
168
+ type BooleanObject = { [Key in keyof CallApiSchema]: boolean };
169
+ interface CallApiSchemaConfig {
88
170
  /**
89
- * Total size of data in bytes
171
+ * The base url of the schema. By default it's the baseURL of the callApi instance.
90
172
  */
91
- totalBytes: number;
173
+ baseURL?: "" | AnyString;
92
174
  /**
93
- * Amount of data transferred so far
175
+ * Disables runtime validation for the schema.
94
176
  */
95
- transferredBytes: number;
96
- };
97
- //#endregion
98
- //#region src/hooks.d.ts
99
- interface Hooks<TCallApiContext extends CallApiContext = DefaultCallApiContext> {
177
+ disableRuntimeValidation?: boolean | BooleanObject;
100
178
  /**
101
- * Hook called when any error occurs within the request/response lifecycle.
102
- *
103
- * This is a unified error handler that catches both request errors (network failures,
104
- * timeouts, etc.) and response errors (HTTP error status codes). It's essentially
105
- * a combination of `onRequestError` and `onResponseError` hooks.
179
+ * If `true`, the original input value will be used instead of the transformed/validated output.
106
180
  *
107
- * @param context - Error context containing error details, request info, and response (if available)
108
- * @returns Promise or void - Hook can be async or sync
181
+ * When true, the original input is returned unchanged after validation, ignoring any schema-level
182
+ * transformations such as type coercion, default values, or field mapping. Only the validation
183
+ * step is executed; the resulting value is discarded in favor of the raw input.
109
184
  */
110
- onError?: (context: ErrorContext<TCallApiContext>) => Awaitable<unknown>;
185
+ disableRuntimeValidationTransform?: boolean | BooleanObject;
111
186
  /**
112
- * Hook called before the HTTP request is sent and before any internal processing of the request object begins.
113
- *
114
- * This is the ideal place to modify request headers, add authentication,
115
- * implement request logging, or perform any setup before the network call.
116
- *
117
- * @param context - Request context with mutable request object and configuration
118
- * @returns Promise or void - Hook can be async or sync
187
+ * Optional url prefix that will be substituted for the `baseURL` of the schemaConfig at runtime.
119
188
  *
189
+ * Enables a short, stable prefix for routes while keeping the full `baseURL` centralized in config.
190
+ * Keeps route definitions concise and shields them from changes to the underlying base URL.
120
191
  */
121
- onRequest?: (context: RequestContext<TCallApiContext>) => Awaitable<unknown>;
192
+ prefix?: "" | AnyString;
122
193
  /**
123
- * Hook called when an error occurs during the fetch request itself.
194
+ * Controls the strictness of API route validation.
124
195
  *
125
- * This handles network-level errors like connection failures, timeouts,
126
- * DNS resolution errors, or other issues that prevent getting an HTTP response.
127
- * Note that HTTP error status codes (4xx, 5xx) are handled by `onResponseError`.
196
+ * When true:
197
+ * - Only routes explicitly defined in the schema will be considered valid to typescript and the runtime.
198
+ * - Attempting to call routes not defined in the schema will result in both type errors and runtime validation errors.
199
+ * - Useful for ensuring API calls conform exactly to your schema definition
128
200
  *
129
- * @param context - Request error context with error details and null response
130
- * @returns Promise or void - Hook can be async or sync
201
+ * When false or undefined (default):
202
+ * - All routes will be allowed, whether they are defined in the schema or not
131
203
  */
132
- onRequestError?: (context: RequestErrorContext<TCallApiContext>) => Awaitable<unknown>;
204
+ strict?: boolean;
205
+ }
206
+ type CallApiSchemaType<TInput> = StandardSchemaV1<TInput | undefined> | ((value: TInput) => Awaitable<TInput | undefined>);
207
+ interface CallApiSchema {
208
+ auth?: CallApiSchemaType<AuthOption>;
133
209
  /**
134
- * Hook called just before the HTTP request is sent and after the request has been processed.
135
- *
136
- * @param context - Request context with mutable request object and configuration
210
+ * The schema to use for validating the request body.
137
211
  */
138
- onRequestReady?: (context: RequestContext<TCallApiContext>) => Awaitable<unknown>;
212
+ body?: CallApiSchemaType<Body>;
139
213
  /**
140
- * Hook called during upload stream progress tracking.
141
- *
142
- * This hook is triggered when uploading data (like file uploads) and provides
143
- * progress information about the upload. Useful for implementing progress bars
144
- * or upload status indicators.
145
- *
146
- * @param context - Request stream context with progress event and request instance
147
- * @returns Promise or void - Hook can be async or sync
148
- *
214
+ * The schema to use for validating the response data.
149
215
  */
150
- onRequestStream?: (context: RequestStreamContext<TCallApiContext>) => Awaitable<unknown>;
216
+ data?: CallApiSchemaType<unknown>;
151
217
  /**
152
- * Hook called when any HTTP response is received from the API.
153
- *
154
- * This hook is triggered for both successful (2xx) and error (4xx, 5xx) responses.
155
- * It's useful for response logging, metrics collection, or any processing that
156
- * should happen regardless of response status.
157
- *
158
- * @param context - Response context with either success data or error information
159
- * @returns Promise or void - Hook can be async or sync
160
- *
218
+ * The schema to use for validating the response error data.
161
219
  */
162
- onResponse?: (context: ResponseContext<TCallApiContext>) => Awaitable<unknown>;
220
+ errorData?: CallApiSchemaType<unknown>;
163
221
  /**
164
- * Hook called when an HTTP error response (4xx, 5xx) is received from the API.
165
- *
166
- * This handles server-side errors where an HTTP response was successfully received
167
- * but indicates an error condition. Different from `onRequestError` which handles
168
- * network-level failures.
169
- *
170
- * @param context - Response error context with HTTP error details and response
171
- * @returns Promise or void - Hook can be async or sync
222
+ * The schema to use for validating the request headers.
172
223
  */
173
- onResponseError?: (context: ResponseErrorContext<TCallApiContext>) => Awaitable<unknown>;
224
+ headers?: CallApiSchemaType<HeadersOption>;
174
225
  /**
175
- * Hook called during download stream progress tracking.
176
- *
177
- * This hook is triggered when downloading data (like file downloads) and provides
178
- * progress information about the download. Useful for implementing progress bars
179
- * or download status indicators.
180
- *
181
- * @param context - Response stream context with progress event and response
182
- * @returns Promise or void - Hook can be async or sync
183
- *
226
+ * The schema to use for validating the meta option.
184
227
  */
185
- onResponseStream?: (context: ResponseStreamContext<TCallApiContext>) => Awaitable<unknown>;
228
+ meta?: CallApiSchemaType<GlobalMeta>;
186
229
  /**
187
- * Hook called when a request is being retried.
188
- *
189
- * This hook is triggered before each retry attempt, providing information about
190
- * the previous failure and the current retry attempt number. Useful for implementing
191
- * custom retry logic, exponential backoff, or retry logging.
192
- *
193
- * @param context - Retry context with error details and retry attempt count
194
- * @returns Promise or void - Hook can be async or sync
195
- *
230
+ * The schema to use for validating the request method.
196
231
  */
197
- onRetry?: (response: RetryContext<TCallApiContext>) => Awaitable<unknown>;
232
+ method?: CallApiSchemaType<MethodUnion>;
198
233
  /**
199
- * Hook called when a successful response (2xx status) is received from the API.
200
- *
201
- * This hook is triggered only for successful responses and provides access to
202
- * the parsed response data. Ideal for success logging, caching, or post-processing
203
- * of successful API responses.
204
- *
205
- * @param context - Success context with parsed response data and response object
206
- * @returns Promise or void - Hook can be async or sync
207
- *
234
+ * The schema to use for validating the request url parameters.
208
235
  */
209
- onSuccess?: (context: SuccessContext<TCallApiContext>) => Awaitable<unknown>;
236
+ params?: CallApiSchemaType<Params>;
210
237
  /**
211
- * Hook called when a validation error occurs.
212
- *
213
- * This hook is triggered when request or response data fails validation against
214
- * a defined schema. It provides access to the validation error details and can
215
- * be used for custom error handling, logging, or fallback behavior.
216
- *
217
- * @param context - Validation error context with error details and response (if available)
218
- * @returns Promise or void - Hook can be async or sync
219
- *
238
+ * The schema to use for validating the request url queries.
220
239
  */
221
- onValidationError?: (context: ValidationErrorContext<TCallApiContext>) => Awaitable<unknown>;
240
+ query?: CallApiSchemaType<Query>;
222
241
  }
223
- type HooksOrHooksArray<TCallApiContext extends NoInfer<CallApiContext> = DefaultCallApiContext> = { [Key in keyof Hooks<TCallApiContext>]: Hooks<TCallApiContext>[Key] | Array<Hooks<TCallApiContext>[Key]> };
224
- interface HookConfigOptions {
225
- /**
226
- * Controls the execution mode of all composed hooks (main + plugin hooks).
227
- *
228
- * - **"parallel"**: All hooks execute simultaneously via Promise.all() for better performance
229
- * - **"sequential"**: All hooks execute one by one in registration order via await in a loop
230
- *
231
- * This affects how ALL hooks execute together, regardless of their source (main or plugin).
232
- *
233
- * @default "parallel"
234
- */
235
- hooksExecutionMode?: "parallel" | "sequential";
236
- }
237
- type RequestContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = {
238
- /**
239
- * Base configuration object passed to createFetchClient.
240
- *
241
- * Contains the foundational configuration that applies to all requests
242
- * made by this client instance, such as baseURL, default headers, and
243
- * global options.
244
- */
245
- baseConfig: Exclude<BaseCallApiConfig, AnyFunction>;
246
- /**
247
- * Instance-specific configuration object passed to the callApi instance.
248
- *
249
- * Contains configuration specific to this particular API call, which
250
- * can override or extend the base configuration.
251
- */
252
- config: CallApiConfig;
253
- /**
254
- * Merged options combining base config, instance config, and default options.
255
- *
256
- * This is the final resolved configuration that will be used for the request,
257
- * with proper precedence applied (instance > base > defaults).
258
- */
259
- options: CallApiExtraOptionsForHooks<TCallApiContext>;
260
- /**
261
- * Merged request object ready to be sent.
262
- *
263
- * Contains the final request configuration including URL, method, headers,
264
- * body, and other fetch options. This object can be modified in onRequest
265
- * hooks to customize the outgoing request.
266
- */
267
- request: CallApiRequestOptionsForHooks;
268
- };
269
- type ValidationErrorContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = DistributiveOmit<Extract<CallApiResultErrorVariant<unknown>, {
270
- error: PossibleValidationError;
271
- }>, "data"> & RequestContext<TCallApiContext>;
272
- type SuccessContext<TCallApiContext extends Pick<CallApiContext, "Data" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = DistributiveOmit<CallApiResultSuccessVariant<TCallApiContext["Data"]>, "error"> & RequestContext<TCallApiContext>;
273
- type ResponseContext<TCallApiContext extends Pick<CallApiContext, "Data" | "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = RequestContext<TCallApiContext> & (Prettify<CallApiResultSuccessVariant<TCallApiContext["Data"]>> | Prettify<Extract<CallApiResultErrorVariant<TCallApiContext["ErrorData"]>, {
274
- error: PossibleHTTPError<TCallApiContext["ErrorData"]>;
275
- }>>);
276
- type RequestErrorContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = DistributiveOmit<Extract<CallApiResultErrorVariant<unknown>, {
277
- error: PossibleJavaScriptError;
278
- }>, "data"> & RequestContext<TCallApiContext>;
279
- type ErrorContext<TCallApiContext extends Pick<CallApiContext, "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = DistributiveOmit<CallApiResultErrorVariant<TCallApiContext["ErrorData"]>, "data"> & RequestContext<TCallApiContext>;
280
- type ResponseErrorContext<TCallApiContext extends Pick<CallApiContext, "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = Extract<ErrorContext<TCallApiContext>, {
281
- error: PossibleHTTPError<TCallApiContext["ErrorData"]>;
282
- }> & RequestContext<TCallApiContext>;
283
- type RetryContext<TCallApiContext extends Pick<CallApiContext, "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = ErrorContext<TCallApiContext> & {
284
- retryAttemptCount: number;
242
+ declare const routeKeyMethods: readonly ["delete", "get", "patch", "post", "put"];
243
+ type RouteKeyMethods = (typeof routeKeyMethods)[number];
244
+ type RouteKeyMethodsURLUnion = `${AtSymbol}${RouteKeyMethods}/`;
245
+ type BaseSchemaRouteKeyPrefixes = FallBackRouteSchemaKey | RouteKeyMethodsURLUnion;
246
+ type BaseCallApiSchemaRoutes = Partial<Record<AnyString | BaseSchemaRouteKeyPrefixes, CallApiSchema>>;
247
+ type BaseCallApiSchemaAndConfig = {
248
+ config?: CallApiSchemaConfig;
249
+ routes: BaseCallApiSchemaRoutes;
285
250
  };
286
- type RequestStreamContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = RequestContext<TCallApiContext> & {
287
- event: StreamProgressEvent;
288
- requestInstance: Request;
251
+ type GetResolvedSchemaContext = {
252
+ baseExtraOptions: BaseCallApiExtraOptions;
253
+ currentRouteSchemaKey: string;
254
+ extraOptions: CallApiExtraOptions;
289
255
  };
290
- type ResponseStreamContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = RequestContext<TCallApiContext> & {
291
- event: StreamProgressEvent;
292
- response: Response;
256
+ declare const getCurrentRouteSchemaKeyAndMainInitURL: (context: Pick<GetResolvedSchemaContext, "baseExtraOptions" | "extraOptions"> & {
257
+ initURL: string;
258
+ }) => {
259
+ currentRouteSchemaKey: string;
260
+ initURL: string;
261
+ mainInitURL: string;
293
262
  };
294
263
  //#endregion
295
- //#region src/dedupe.d.ts
296
- type DedupeStrategyUnion = UnmaskType<"cancel" | "defer" | "none">;
297
- type DedupeOptions = {
264
+ //#region src/url.d.ts
265
+ declare const atSymbol = "@";
266
+ type AtSymbol = typeof atSymbol;
267
+ type AllowedQueryParamValues = UnmaskType<boolean | number | string>;
268
+ type RecordStyleParams = UnmaskType<Record<string, AllowedQueryParamValues>>;
269
+ type TupleStyleParams = UnmaskType<AllowedQueryParamValues[]>;
270
+ type Params = UnmaskType<RecordStyleParams | TupleStyleParams>;
271
+ type Query = UnmaskType<Record<string, AllowedQueryParamValues> | URLSearchParams>;
272
+ type InitURLOrURLObject = AnyString | RouteKeyMethodsURLUnion | URL;
273
+ interface URLOptions {
298
274
  /**
299
- * Controls the scope of request deduplication caching.
300
- *
301
- * - `"global"`: Shares deduplication cache across all `createFetchClient` instances with the same `dedupeCacheScopeKey`.
302
- * Useful for applications with multiple API clients that should share deduplication state.
303
- * - `"local"`: Limits deduplication to requests within the same `createFetchClient` instance.
304
- * Provides better isolation and is recommended for most use cases.
305
- *
275
+ * Base URL for all API requests. Will only be prepended to relative URLs.
306
276
  *
307
- * **Real-world Scenarios:**
308
- * - Use `"global"` when you have multiple API clients (user service, auth service, etc.) that might make overlapping requests
309
- * - Use `"local"` (default) for single-purpose clients or when you want strict isolation between different parts of your app
277
+ * Absolute URLs (starting with http/https) will not be prepended by the baseURL.
310
278
  *
311
279
  * @example
312
280
  * ```ts
313
- * // Local scope - each client has its own deduplication cache
314
- * const userClient = createFetchClient({ baseURL: "/api/users" });
315
- * const postClient = createFetchClient({ baseURL: "/api/posts" });
316
- * // These clients won't share deduplication state
281
+ * // Set base URL for all requests
282
+ * baseURL: "https://api.example.com/v1"
317
283
  *
318
- * // Global scope - share cache across related clients
319
- * const userClient = createFetchClient({
320
- * baseURL: "/api/users",
321
- * dedupeCacheScope: "global",
322
- * });
323
- * const postClient = createFetchClient({
324
- * baseURL: "/api/posts",
325
- * dedupeCacheScope: "global",
326
- * });
327
- * // These clients will share deduplication state
328
- * ```
284
+ * // Then use relative URLs in requests
285
+ * callApi("/users") // https://api.example.com/v1/users
286
+ * callApi("/posts/123") // → https://api.example.com/v1/posts/123
329
287
  *
330
- * @default "local"
288
+ * // Environment-specific base URLs
289
+ * baseURL: process.env.NODE_ENV === "production"
290
+ * ? "https://api.example.com"
291
+ * : "http://localhost:3000/api"
292
+ * ```
331
293
  */
332
- dedupeCacheScope?: "global" | "local";
294
+ baseURL?: string;
333
295
  /**
334
- * Unique namespace for the global deduplication cache when using `dedupeCacheScope: "global"`.
335
- *
336
- * This creates logical groupings of deduplication caches. All instances with the same key
337
- * will share the same cache namespace, allowing fine-grained control over which clients
338
- * share deduplication state.
339
- *
340
- * **Best Practices:**
341
- * - Use descriptive names that reflect the logical grouping (e.g., "user-service", "analytics-api")
342
- * - Keep scope keys consistent across related API clients
343
- * - Consider using different scope keys for different environments (dev, staging, prod)
344
- * - Avoid overly broad scope keys that might cause unintended cache sharing
345
- *
346
- * **Cache Management:**
347
- * - Each scope key maintains its own independent cache
348
- * - Caches are automatically cleaned up when no references remain
349
- * - Consider the memory implications of multiple global scopes
296
+ * Resolved request URL after processing baseURL, parameters, and query strings (readonly)
350
297
  *
351
- * @example
352
- * ```ts
353
- * // Group related API clients together
354
- * const userClient = createFetchClient({
355
- * baseURL: "/api/users",
356
- * dedupeCacheScope: "global",
357
- * dedupeCacheScopeKey: "user-service"
358
- * });
359
- * const profileClient = createFetchClient({
360
- * baseURL: "/api/profiles",
361
- * dedupeCacheScope: "global",
362
- * dedupeCacheScopeKey: "user-service" // Same scope - will share cache
363
- * });
298
+ * This is the final URL that will be used for the HTTP request, computed from
299
+ * baseURL, initURL, params, and query parameters.
364
300
  *
365
- * // Separate analytics client with its own cache
366
- * const analyticsClient = createFetchClient({
367
- * baseURL: "/api/analytics",
368
- * dedupeCacheScope: "global",
369
- * dedupeCacheScopeKey: "analytics-service" // Different scope
370
- * });
301
+ */
302
+ readonly fullURL?: string;
303
+ /**
304
+ * The original URL string passed to the callApi instance (readonly)
371
305
  *
372
- * // Environment-specific scoping
373
- * const apiClient = createFetchClient({
374
- * dedupeCacheScope: "global",
375
- * dedupeCacheScopeKey: `api-${process.env.NODE_ENV}` // "api-development", "api-production", etc.
376
- * });
377
- * ```
306
+ * This preserves the original URL as provided, including any method modifiers like "@get/" or "@post/".
378
307
  *
379
- * @default "default"
380
308
  */
381
- dedupeCacheScopeKey?: "default" | AnyString | ((context: RequestContext) => string | undefined);
309
+ readonly initURL?: string;
382
310
  /**
383
- * Custom key generator for request deduplication.
384
- *
385
- * Override the default key generation strategy to control exactly which requests
386
- * are considered duplicates. The default key combines URL, method, body, and
387
- * relevant headers (excluding volatile ones like 'Date', 'Authorization', etc.).
311
+ * The URL string after normalization, with method modifiers removed(readonly)
388
312
  *
389
- * **Default Key Generation:**
390
- * The auto-generated key includes:
391
- * - Full request URL (including query parameters)
392
- * - HTTP method (GET, POST, etc.)
393
- * - Request body (for POST/PUT/PATCH requests)
394
- * - Stable headers (excludes Date, Authorization, User-Agent, etc.)
313
+ * Method modifiers like "@get/", "@post/" are stripped to create a clean URL
314
+ * for parameter substitution and final URL construction.
395
315
  *
396
- * **Custom Key Best Practices:**
397
- * - Include only the parts of the request that should affect deduplication
398
- * - Avoid including volatile data (timestamps, random IDs, etc.)
399
- * - Consider performance - simpler keys are faster to compute and compare
400
- * - Ensure keys are deterministic for the same logical request
401
- * - Use consistent key formats across your application
316
+ */
317
+ readonly initURLNormalized?: string;
318
+ /**
319
+ * Parameters to be substituted into URL path segments.
402
320
  *
403
- * **Performance Considerations:**
404
- * - Function-based keys are computed on every request - keep them lightweight
405
- * - String keys are fastest but least flexible
406
- * - Consider caching expensive key computations if needed
321
+ * Supports both object-style (named parameters) and array-style (positional parameters)
322
+ * for flexible URL parameter substitution.
407
323
  *
408
324
  * @example
409
- * ```ts
410
- * import { callApi } from "@zayne-labs/callapi";
325
+ * ```typescript
326
+ * // Object-style parameters (recommended)
327
+ * const namedParams: URLOptions = {
328
+ * initURL: "/users/:userId/posts/:postId",
329
+ * params: { userId: "123", postId: "456" }
330
+ * };
331
+ * // Results in: /users/123/posts/456
411
332
  *
412
- * // Simple static key - useful for singleton requests
413
- * const config = callApi("/api/config", {
414
- * dedupeKey: "app-config",
415
- * dedupeStrategy: "defer" // Share the same config across all requests
416
- * });
333
+ * // Array-style parameters (positional)
334
+ * const positionalParams: URLOptions = {
335
+ * initURL: "/users/:userId/posts/:postId",
336
+ * params: ["123", "456"] // Maps in order: userId=123, postId=456
337
+ * };
338
+ * // Results in: /users/123/posts/456
417
339
  *
418
- * // URL and method only - ignore headers and body
419
- * const userData = callApi("/api/user/123", {
420
- * dedupeKey: (context) => `${context.options.method}:${context.options.fullURL}`
421
- * });
340
+ * // Single parameter
341
+ * const singleParam: URLOptions = {
342
+ * initURL: "/users/:id",
343
+ * params: { id: "user-123" }
344
+ * };
345
+ * // Results in: /users/user-123
346
+ * ```
347
+ */
348
+ params?: Params;
349
+ /**
350
+ * Query parameters to append to the URL as search parameters.
422
351
  *
423
- * // Include specific headers in deduplication
424
- * const apiCall = callApi("/api/data", {
425
- * dedupeKey: (context) => {
426
- * const authHeader = context.request.headers.get("Authorization");
427
- * return `${context.options.fullURL}-${authHeader}`;
352
+ * These will be serialized into the URL query string using standard
353
+ * URL encoding practices.
354
+ *
355
+ * @example
356
+ * ```typescript
357
+ * // Basic query parameters
358
+ * const queryOptions: URLOptions = {
359
+ * initURL: "/users",
360
+ * query: {
361
+ * page: 1,
362
+ * limit: 10,
363
+ * search: "john doe",
364
+ * active: true
428
365
  * }
429
- * });
366
+ * };
367
+ * // Results in: /users?page=1&limit=10&search=john%20doe&active=true
430
368
  *
431
- * // User-specific deduplication
432
- * const userSpecificCall = callApi("/api/dashboard", {
433
- * dedupeKey: (context) => {
434
- * const userId = context.options.fullURL.match(/user\/(\d+)/)?.[1];
435
- * return `dashboard-${userId}`;
436
- * }
437
- * });
438
- *
439
- * // Ignore certain query parameters
440
- * const searchCall = callApi("/api/search?q=test&timestamp=123456", {
441
- * dedupeKey: (context) => {
442
- * const url = new URL(context.options.fullURL);
443
- * url.searchParams.delete("timestamp"); // Remove volatile param
444
- * return `search:${url.toString()}`;
369
+ * // Filtering and sorting
370
+ * const filterOptions: URLOptions = {
371
+ * initURL: "/products",
372
+ * query: {
373
+ * category: "electronics",
374
+ * minPrice: 100,
375
+ * maxPrice: 500,
376
+ * sortBy: "price",
377
+ * order: "asc"
445
378
  * }
446
- * });
379
+ * };
380
+ * // Results in: /products?category=electronics&minPrice=100&maxPrice=500&sortBy=price&order=asc
447
381
  * ```
448
- *
449
- * @default Auto-generated from request details
450
382
  */
451
- dedupeKey?: string | ((context: RequestContext) => string | undefined);
383
+ query?: Query;
384
+ }
385
+ //#endregion
386
+ //#region src/types/conditional-types.d.ts
387
+ /**
388
+ * @description Makes a type partial if the output type of TSchema is not provided or has undefined in the union, otherwise makes it required
389
+ */
390
+ type MakeSchemaOptionRequiredIfDefined<TSchemaOption extends CallApiSchema[keyof CallApiSchema], TObject> = undefined extends InferSchemaOutput<TSchemaOption, undefined> ? TObject : Required<TObject>;
391
+ type MergeBaseWithRouteKey<TBaseURLOrPrefix extends string | undefined, TRouteKey extends string> = TBaseURLOrPrefix extends string ? TRouteKey extends `${AtSymbol}${infer TMethod extends RouteKeyMethods}/${infer TRestOfRoutKey}` ? `${AtSymbol}${TMethod}/${RemoveLeadingSlash<RemoveTrailingSlash<TBaseURLOrPrefix>>}/${RemoveLeadingSlash<TRestOfRoutKey>}` : `${TBaseURLOrPrefix}${TRouteKey}` : TRouteKey;
392
+ type ApplyURLBasedConfig<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = TSchemaConfig["prefix"] extends string ? MergeBaseWithRouteKey<TSchemaConfig["prefix"], TSchemaRouteKeys> : TSchemaConfig["baseURL"] extends string ? MergeBaseWithRouteKey<TSchemaConfig["baseURL"], TSchemaRouteKeys> : TSchemaRouteKeys;
393
+ type ApplyStrictConfig<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = TSchemaConfig["strict"] extends true ? TSchemaRouteKeys : // eslint-disable-next-line perfectionist/sort-union-types -- Don't sort union types
394
+ TSchemaRouteKeys | Exclude<InitURLOrURLObject, RouteKeyMethodsURLUnion>;
395
+ type ApplySchemaConfiguration<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = ApplyStrictConfig<TSchemaConfig, ApplyURLBasedConfig<TSchemaConfig, TSchemaRouteKeys>>;
396
+ type InferAllMainRoutes<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes> = Omit<TBaseSchemaRoutes, FallBackRouteSchemaKey>;
397
+ type InferAllMainRouteKeys<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TSchemaConfig extends CallApiSchemaConfig> = ApplySchemaConfiguration<TSchemaConfig, Extract<keyof InferAllMainRoutes<TBaseSchemaRoutes>, string>>;
398
+ type InferInitURL<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TSchemaConfig extends CallApiSchemaConfig> = keyof TBaseSchemaRoutes extends never ? InitURLOrURLObject : InferAllMainRouteKeys<TBaseSchemaRoutes, TSchemaConfig>;
399
+ type GetCurrentRouteSchemaKey<TSchemaConfig extends CallApiSchemaConfig, TPath> = TPath extends URL ? string : TSchemaConfig["prefix"] extends string ? TPath extends (`${AtSymbol}${infer TMethod extends RouteKeyMethods}/${RemoveLeadingSlash<TSchemaConfig["prefix"]>}${infer TCurrentRoute}`) ? `${AtSymbol}${TMethod}/${RemoveLeadingSlash<TCurrentRoute>}` : TPath extends `${TSchemaConfig["prefix"]}${infer TCurrentRoute}` ? TCurrentRoute : string : TSchemaConfig["baseURL"] extends string ? TPath extends (`${AtSymbol}${infer TMethod extends RouteKeyMethods}/${TSchemaConfig["baseURL"]}${infer TCurrentRoute}`) ? `${AtSymbol}${TMethod}/${RemoveLeadingSlash<TCurrentRoute>}` : TPath extends `${TSchemaConfig["baseURL"]}${infer TCurrentRoute}` ? TCurrentRoute : string : TPath;
400
+ 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;
401
+ type JsonPrimitive = boolean | number | string | null | undefined;
402
+ type SerializableObject = Record<PropertyKey, unknown>;
403
+ type SerializableArray = Array<JsonPrimitive | SerializableObject> | ReadonlyArray<JsonPrimitive | SerializableObject>;
404
+ type Body = UnmaskType<Exclude<RequestInit["body"], undefined> | SerializableArray | SerializableObject>;
405
+ type InferBodyOption<TSchema extends CallApiSchema> = MakeSchemaOptionRequiredIfDefined<TSchema["body"], {
452
406
  /**
453
- * Strategy for handling duplicate requests. Can be a static string or callback function.
407
+ * Body of the request, can be a object or any other supported body type.
408
+ */
409
+ body?: InferSchemaOutput<TSchema["body"], Body>;
410
+ }>;
411
+ type MethodUnion = UnmaskType<"CONNECT" | "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT" | "TRACE" | AnyString>;
412
+ type ExtractMethodFromURL<TInitURL> = string extends TInitURL ? MethodUnion : TInitURL extends `${AtSymbol}${infer TMethod extends RouteKeyMethods}/${string}` ? Uppercase<TMethod> : MethodUnion;
413
+ type InferMethodOption<TSchema extends CallApiSchema, TInitURL extends InitURLOrURLObject> = MakeSchemaOptionRequiredIfDefined<TSchema["method"], {
414
+ /**
415
+ * HTTP method for the request.
416
+ * @default "GET"
417
+ */
418
+ method?: InferSchemaOutput<TSchema["method"], ExtractMethodFromURL<TInitURL>>;
419
+ }>;
420
+ type HeadersOption = UnmaskType<Headers | Record<"Authorization", CommonAuthorizationHeaders | undefined> | Record<"Content-Type", CommonContentTypes | undefined> | Record<CommonRequestHeaders, string | undefined> | Record<string, string | undefined> | Array<[string, string]>>;
421
+ type InferHeadersOption<TSchema extends CallApiSchema> = MakeSchemaOptionRequiredIfDefined<TSchema["headers"], {
422
+ /**
423
+ * Headers to be used in the request.
424
+ */
425
+ headers?: InferSchemaOutput<TSchema["headers"], HeadersOption> | ((context: {
426
+ baseHeaders: Extract<HeadersOption, Record<string, unknown>>;
427
+ }) => InferSchemaOutput<TSchema["headers"], HeadersOption>);
428
+ }>;
429
+ type InferRequestOptions<TSchema extends CallApiSchema, TInitURL extends InferInitURL<BaseCallApiSchemaRoutes, CallApiSchemaConfig>> = InferBodyOption<TSchema> & InferHeadersOption<TSchema> & InferMethodOption<TSchema, TInitURL>;
430
+ type InferMetaOption<TSchema extends CallApiSchema, TCallApiContext extends CallApiContext> = MakeSchemaOptionRequiredIfDefined<TSchema["meta"], {
431
+ /**
432
+ * - An optional field you can fill with additional information,
433
+ * to associate with the request, typically used for logging or tracing.
454
434
  *
455
- * **Available Strategies:**
456
- * - `"cancel"`: Cancel previous request when new one starts (good for search)
457
- * - `"defer"`: Share response between duplicate requests (good for config loading)
458
- * - `"none"`: No deduplication, all requests execute independently
435
+ * - A good use case for this, would be to use the info to handle specific cases in any of the shared interceptors.
459
436
  *
460
437
  * @example
461
438
  * ```ts
462
- * // Static strategies
463
- * const searchClient = createFetchClient({
464
- * dedupeStrategy: "cancel" // Cancel previous searches
465
- * });
466
- *
467
- * const configClient = createFetchClient({
468
- * dedupeStrategy: "defer" // Share config across components
439
+ * const callMainApi = callApi.create({
440
+ * baseURL: "https://main-api.com",
441
+ * onResponseError: ({ response, options }) => {
442
+ * if (options.meta?.userId) {
443
+ * console.error(`User ${options.meta.userId} made an error`);
444
+ * }
445
+ * },
469
446
  * });
470
447
  *
471
- * // Dynamic strategy based on request
472
- * const smartClient = createFetchClient({
473
- * dedupeStrategy: (context) => {
474
- * return context.options.method === "GET" ? "defer" : "cancel";
475
- * }
448
+ * const response = await callMainApi({
449
+ * url: "https://example.com/api/data",
450
+ * meta: { userId: "123" },
476
451
  * });
477
- *
478
- * // Search-as-you-type with cancel strategy
479
- * const handleSearch = async (query: string) => {
480
- * try {
481
- * const { data } = await callApi("/api/search", {
482
- * method: "POST",
483
- * body: { query },
484
- * dedupeStrategy: "cancel",
485
- * dedupeKey: "search" // Cancel previous searches, only latest one goes through
486
- * });
487
- *
488
- * updateSearchResults(data);
489
- * } catch (error) {
490
- * if (error.name === "AbortError") {
491
- * // Previous search cancelled - (expected behavior)
492
- * return;
493
- * }
494
- * console.error("Search failed:", error);
495
- * }
496
- * };
497
- *
498
452
  * ```
499
- *
500
- * @default "cancel"
501
453
  */
502
- dedupeStrategy?: DedupeStrategyUnion | ((context: RequestContext) => DedupeStrategyUnion);
503
- };
504
- //#endregion
505
- //#region src/middlewares.d.ts
506
- type FetchImpl = UnmaskType<(input: string | Request | URL, init?: RequestInit) => Promise<Response>>;
507
- type FetchMiddlewareContext<TCallApiContext extends CallApiContext> = RequestContext<TCallApiContext> & {
508
- fetchImpl: FetchImpl;
509
- };
510
- interface Middlewares<TCallApiContext extends NoInfer<CallApiContext> = DefaultCallApiContext> {
454
+ meta?: InferSchemaOutput<TSchema["meta"], TCallApiContext["Meta"]>;
455
+ }>;
456
+ type InferAuthOption<TSchema extends CallApiSchema> = MakeSchemaOptionRequiredIfDefined<TSchema["auth"], {
511
457
  /**
512
- * Wraps the fetch implementation to intercept requests at the network layer.
513
- *
514
- * Takes a context object containing the current fetch function and returns a new fetch function.
515
- * Use it to cache responses, add logging, handle offline mode, or short-circuit requests etc.
516
- * Multiple middleware compose in order: plugins → base config → per-request.
458
+ * Automatically add an Authorization header value.
517
459
  *
518
- * Unlike `customFetchImpl`, middleware can call through to the original fetch.
460
+ * Supports multiple authentication patterns:
461
+ * - String: Direct authorization header value
462
+ * - Auth object: Structured authentication configuration
519
463
  *
520
464
  * @example
521
465
  * ```ts
522
- * // Cache responses
523
- * const cache = new Map();
524
- *
525
- * fetchMiddleware: (ctx) => async (input, init) => {
526
- * const key = input.toString();
527
- *
528
- * const cachedResponse = cache.get(key);
529
- *
530
- * if (cachedResponse) {
531
- * return cachedResponse.clone();
532
- * }
466
+ * // Bearer auth
467
+ * const response = await callMainApi({
468
+ * url: "https://example.com/api/data",
469
+ * auth: "123456",
470
+ * });
533
471
  *
534
- * const response = await ctx.fetchImpl(input, init);
535
- * cache.set(key, response.clone());
472
+ * // Bearer auth
473
+ * const response = await callMainApi({
474
+ * url: "https://example.com/api/data",
475
+ * auth: {
476
+ * type: "Bearer",
477
+ * value: "123456",
478
+ * },
479
+ })
536
480
  *
537
- * return response;
538
- * }
481
+ * // Token auth
482
+ * const response = await callMainApi({
483
+ * url: "https://example.com/api/data",
484
+ * auth: {
485
+ * type: "Token",
486
+ * value: "123456",
487
+ * },
488
+ * });
539
489
  *
540
- * // Handle offline
541
- * fetchMiddleware: (ctx) => async (...parameters) => {
542
- * if (!navigator.onLine) {
543
- * return new Response('{"error": "offline"}', { status: 503 });
544
- * }
490
+ * // Basic auth
491
+ * const response = await callMainApi({
492
+ * url: "https://example.com/api/data",
493
+ * auth: {
494
+ * type: "Basic",
495
+ * username: "username",
496
+ * password: "password",
497
+ * },
498
+ * });
545
499
  *
546
- * return ctx.fetchImpl(...parameters);
547
- * }
548
500
  * ```
549
501
  */
550
- fetchMiddleware?: (context: FetchMiddlewareContext<TCallApiContext>) => FetchImpl;
551
- }
552
- //#endregion
553
- //#region src/constants/validation.d.ts
554
- declare const fallBackRouteSchemaKey = "@default";
555
- type FallBackRouteSchemaKey = typeof fallBackRouteSchemaKey;
502
+ auth?: InferSchemaOutput<TSchema["auth"], AuthOption>;
503
+ }>;
504
+ type InferQueryOption<TSchema extends CallApiSchema> = MakeSchemaOptionRequiredIfDefined<TSchema["query"], {
505
+ /**
506
+ * Parameters to be appended to the URL (i.e: /:id)
507
+ */
508
+ query?: InferSchemaOutput<TSchema["query"], Query>;
509
+ }>;
510
+ type EmptyString = "";
511
+ type EmptyTuple = readonly [];
512
+ type StringTuple = readonly string[];
513
+ type PossibleParamNamePatterns = `${string}:${string}` | `${string}{${string}}${"" | AnyString}`;
514
+ type ExtractRouteParamNames<TCurrentRoute, TParamNamesAccumulator extends StringTuple = EmptyTuple> = TCurrentRoute extends PossibleParamNamePatterns ? TCurrentRoute extends `${infer TRoutePrefix}:${infer TParamAndRemainingRoute}` ? TParamAndRemainingRoute extends `${infer TCurrentParam}/${infer TRemainingRoute}` ? TCurrentParam extends EmptyString ? ExtractRouteParamNames<`${TRoutePrefix}/${TRemainingRoute}`, TParamNamesAccumulator> : ExtractRouteParamNames<`${TRoutePrefix}/${TRemainingRoute}`, [...TParamNamesAccumulator, TCurrentParam]> : TParamAndRemainingRoute extends `${infer TCurrentParam}` ? TCurrentParam extends EmptyString ? ExtractRouteParamNames<TRoutePrefix, TParamNamesAccumulator> : ExtractRouteParamNames<TRoutePrefix, [...TParamNamesAccumulator, TCurrentParam]> : ExtractRouteParamNames<TRoutePrefix, TParamNamesAccumulator> : TCurrentRoute extends `${infer TRoutePrefix}{${infer TCurrentParam}}${infer TRemainingRoute}` ? TCurrentParam extends EmptyString ? ExtractRouteParamNames<`${TRoutePrefix}${TRemainingRoute}`, TParamNamesAccumulator> : ExtractRouteParamNames<`${TRoutePrefix}${TRemainingRoute}`, [...TParamNamesAccumulator, TCurrentParam]> : TParamNamesAccumulator : TParamNamesAccumulator;
515
+ type ConvertParamNamesToRecord<TParamNames extends StringTuple> = Prettify<TParamNames extends (readonly [infer TFirstParamName extends string, ...infer TRemainingParamNames extends StringTuple]) ? Record<TFirstParamName, AllowedQueryParamValues> & ConvertParamNamesToRecord<TRemainingParamNames> : NonNullable<unknown>>;
516
+ type ConvertParamNamesToTuple<TParamNames extends StringTuple> = TParamNames extends readonly [string, ...infer TRemainingParamNames extends StringTuple] ? [AllowedQueryParamValues, ...ConvertParamNamesToTuple<TRemainingParamNames>] : [];
517
+ type InferParamsFromRoute<TCurrentRoute> = ExtractRouteParamNames<TCurrentRoute> extends StringTuple ? ExtractRouteParamNames<TCurrentRoute> extends EmptyTuple ? Params : ConvertParamNamesToRecord<ExtractRouteParamNames<TCurrentRoute>> | ConvertParamNamesToTuple<ExtractRouteParamNames<TCurrentRoute>> : Params;
518
+ 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>;
519
+ type InferParamsOption<TSchema extends CallApiSchema, TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TCurrentRouteSchemaKey extends string> = MakeParamsOptionRequired<TSchema["params"], TBaseSchemaRoutes, TCurrentRouteSchemaKey, {
520
+ /**
521
+ * Parameters to be appended to the URL (i.e: /:id)
522
+ */
523
+ params?: InferSchemaOutput<TSchema["params"], InferParamsFromRoute<TCurrentRouteSchemaKey>>;
524
+ }>;
525
+ type InferExtraOptions<TSchema extends CallApiSchema, TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TCurrentRouteSchemaKey extends string, TCallApiContext extends CallApiContext> = InferAuthOption<TSchema> & InferMetaOption<TSchema, TCallApiContext> & InferParamsOption<TSchema, TBaseSchemaRoutes, TCurrentRouteSchemaKey> & InferQueryOption<TSchema>;
526
+ type ResultModeOption<TErrorData, TResultMode extends ResultModeType> = TErrorData extends false ? {
527
+ resultMode: "onlyData";
528
+ } : TErrorData extends false | undefined ? {
529
+ resultMode?: "onlyData";
530
+ } : {
531
+ resultMode?: TResultMode;
532
+ };
533
+ type ThrowOnErrorBoolean = boolean;
534
+ type ThrowOnErrorType<TErrorData, TThrowOnError extends ThrowOnErrorBoolean> = TThrowOnError | ((context: ErrorContext<{
535
+ ErrorData: TErrorData;
536
+ }>) => TThrowOnError);
537
+ type ThrowOnErrorOption<TErrorData, TThrowOnError extends ThrowOnErrorBoolean> = TErrorData extends false ? {
538
+ throwOnError: true;
539
+ } : TErrorData extends false | undefined ? {
540
+ throwOnError?: true;
541
+ } : {
542
+ throwOnError?: ThrowOnErrorType<TErrorData, TThrowOnError>;
543
+ };
556
544
  //#endregion
557
- //#region src/types/standard-schema.d.ts
558
- /**
559
- * The Standard Schema interface.
560
- * @see https://github.com/standard-schema/standard-schema
561
- */
562
- /** The Standard Typed interface. This is a base type extended by other specs. */
563
- interface StandardTypedV1<Input = unknown, Output = Input> {
564
- /** The Standard properties. */
565
- readonly "~standard": StandardTypedV1.Props<Input, Output>;
566
- }
567
- declare namespace StandardTypedV1 {
568
- /** The Standard Typed properties interface. */
569
- interface Props<Input = unknown, Output = Input> {
570
- /** Inferred types associated with the schema. */
571
- readonly types?: Types<Input, Output> | undefined;
572
- /** The vendor name of the schema library. */
573
- readonly vendor: string;
574
- /** The version number of the standard. */
575
- readonly version: 1;
576
- }
577
- /** The Standard Typed types interface. */
578
- interface Types<Input = unknown, Output = Input> {
579
- /** The input type of the schema. */
580
- readonly input: Input;
581
- /** The output type of the schema. */
582
- readonly output: Output;
583
- }
584
- /** Infers the input type of a Standard Typed. */
585
- type InferInput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["input"];
586
- /** Infers the output type of a Standard Typed. */
587
- type InferOutput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["output"];
588
- }
589
- /** The Standard Schema interface. */
590
- interface StandardSchemaV1<Input = unknown, Output = Input> {
591
- /** The Standard Schema properties. */
592
- readonly "~standard": StandardSchemaV1.Props<Input, Output>;
593
- }
594
- declare namespace StandardSchemaV1 {
595
- /** The Standard Schema properties interface. */
596
- interface Props<Input = unknown, Output = Input> extends StandardTypedV1.Props<Input, Output> {
597
- /** Validates unknown input values. */
598
- readonly validate: (value: unknown, options?: StandardSchemaV1.Options) => Promise<Result<Output>> | Result<Output>;
599
- }
600
- /** The result interface of the validate function. */
601
- type Result<Output> = FailureResult | SuccessResult<Output>;
602
- /** The result interface if validation succeeds. */
603
- interface SuccessResult<Output> {
604
- /** A falsy value for `issues` indicates success. */
605
- readonly issues?: undefined;
606
- /** The typed output value. */
607
- readonly value: Output;
608
- }
609
- interface Options {
610
- /** Explicit support for additional vendor-specific parameters, if needed. */
611
- readonly libraryOptions?: Record<string, unknown> | undefined;
612
- }
613
- /** The result interface if validation fails. */
614
- interface FailureResult {
615
- /** The issues of failed validation. */
616
- readonly issues: readonly Issue[];
617
- }
618
- /** The issue interface of the failure output. */
619
- interface Issue {
620
- /** The error message of the issue. */
621
- readonly message: string;
622
- /** The path of the issue, if any. */
623
- readonly path?: ReadonlyArray<PathSegment | PropertyKey> | undefined;
624
- }
625
- /** The path segment interface of the issue. */
626
- interface PathSegment {
627
- /** The key representing a path segment. */
628
- readonly key: PropertyKey;
629
- }
630
- /** The Standard types interface. */
631
- type Types<Input = unknown, Output = Input> = StandardTypedV1.Types<Input, Output>;
632
- /** Infers the input type of a Standard. */
633
- type InferInput<Schema extends StandardTypedV1> = StandardTypedV1.InferInput<Schema>;
634
- /** Infers the output type of a Standard. */
635
- type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
545
+ //#region src/retry.d.ts
546
+ declare const defaultRetryStatusCodesLookup: () => Readonly<{
547
+ 408: "Request Timeout";
548
+ 409: "Conflict";
549
+ 425: "Too Early";
550
+ 429: "Too Many Requests";
551
+ 500: "Internal Server Error";
552
+ 502: "Bad Gateway";
553
+ 503: "Service Unavailable";
554
+ 504: "Gateway Timeout";
555
+ }>;
556
+ type RetryStatusCodes = UnmaskType<AnyNumber | keyof ReturnType<typeof defaultRetryStatusCodesLookup>>;
557
+ type RetryCondition<TErrorData> = (context: ErrorContext<{
558
+ ErrorData: TErrorData;
559
+ }>) => Awaitable<boolean>;
560
+ interface RetryOptions<TErrorData> {
561
+ /**
562
+ * Keeps track of the number of times the request has already been retried
563
+ * @internal
564
+ * @deprecated **NOTE**: This property is used internally to track retries. Please abstain from modifying it.
565
+ */
566
+ readonly ["~retryAttemptCount"]?: number;
567
+ /**
568
+ * Number of allowed retry attempts on HTTP errors
569
+ * @default 0
570
+ */
571
+ retryAttempts?: number;
572
+ /**
573
+ * Callback whose return value determines if a request should be retried or not
574
+ */
575
+ retryCondition?: RetryCondition<TErrorData>;
576
+ /**
577
+ * Delay between retries in milliseconds
578
+ * @default 1000
579
+ */
580
+ retryDelay?: number | ((currentAttemptCount: number) => number);
581
+ /**
582
+ * Maximum delay in milliseconds. Only applies to exponential strategy
583
+ * @default 10000
584
+ */
585
+ retryMaxDelay?: number;
586
+ /**
587
+ * HTTP methods that are allowed to retry
588
+ * @default ["GET", "POST"]
589
+ */
590
+ retryMethods?: MethodUnion[];
591
+ /**
592
+ * HTTP status codes that trigger a retry
593
+ */
594
+ retryStatusCodes?: RetryStatusCodes[];
595
+ /**
596
+ * Strategy to use when retrying
597
+ * @default "linear"
598
+ */
599
+ retryStrategy?: "exponential" | "linear";
636
600
  }
637
601
  //#endregion
638
- //#region src/validation.d.ts
639
- type ResultVariant = "infer-input" | "infer-output";
640
- 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;
641
- type InferSchemaOutput<TSchema, TFallbackResult = unknown> = InferSchemaResult<TSchema, TFallbackResult, "infer-output">;
642
- type InferSchemaInput<TSchema, TFallbackResult = unknown> = InferSchemaResult<TSchema, TFallbackResult, "infer-input">;
643
- type BooleanObject = { [Key in keyof CallApiSchema]: boolean };
644
- interface CallApiSchemaConfig {
602
+ //#region src/refetch.d.ts
603
+ interface RefetchOptions {
645
604
  /**
646
- * The base url of the schema. By default it's the baseURL of the callApi instance.
605
+ * Tracks the number of times refetch has been called
606
+ * @internal
607
+ * @deprecated **NOTE**: This property is used internally to track refetch calls. Please abstain from modifying it.
647
608
  */
648
- baseURL?: "" | AnyString;
609
+ readonly ["~refetchCount"]?: number;
649
610
  /**
650
- * Disables runtime validation for the schema.
611
+ * Maximum number of times refetch can be called from error hooks.
612
+ *
613
+ * Prevents infinite loops when refetch is called repeatedly in error hooks.
614
+ * When the limit is reached, refetch will throw an error instead of retrying.
615
+ *
616
+ * @default 1
617
+ *
618
+ * @example
619
+ * ```ts
620
+ * // Allow up to 5 refetch attempts
621
+ * refetchAttempts: 5
622
+ *
623
+ * // Disable refetch limit
624
+ * refetchAttempts: Infinity
625
+ *
626
+ * // Strict limit of 1 refetch
627
+ * refetchAttempts: 1
628
+ * ```
651
629
  */
652
- disableRuntimeValidation?: boolean | BooleanObject;
630
+ refetchAttempts?: number;
631
+ }
632
+ type RefetchFn = (overrides?: Pick<RefetchOptions, "refetchAttempts">) => Promise<CallApiResultLoose<unknown, unknown> | null>;
633
+ //#endregion
634
+ //#region src/stream.d.ts
635
+ type StreamProgressEvent = {
653
636
  /**
654
- * If `true`, the original input value will be used instead of the transformed/validated output.
637
+ * Current chunk of data being streamed
638
+ */
639
+ chunk: Uint8Array;
640
+ /**
641
+ * Progress in percentage
642
+ */
643
+ progress: number;
644
+ /**
645
+ * Total size of data in bytes
646
+ */
647
+ totalBytes: number;
648
+ /**
649
+ * Amount of data transferred so far
650
+ */
651
+ transferredBytes: number;
652
+ };
653
+ //#endregion
654
+ //#region src/hooks.d.ts
655
+ type CallApiRequestOptionsForHooks = Omit<CallApiRequestOptions, "headers"> & {
656
+ headers: Partial<Record<"Authorization" | "Content-Type" | CommonRequestHeaders, string>>;
657
+ };
658
+ type CallApiExtraOptionsForHooks<TCallApiContext extends CallApiContext = DefaultCallApiContext> = Hooks & Omit<CallApiExtraOptions<TCallApiContext>, keyof Hooks> & {
659
+ refetch: RefetchFn;
660
+ };
661
+ interface Hooks<TCallApiContext extends CallApiContext = DefaultCallApiContext> {
662
+ /**
663
+ * Hook called when any error occurs within the request/response lifecycle.
655
664
  *
656
- * When true, the original input is returned unchanged after validation, ignoring any schema-level
657
- * transformations such as type coercion, default values, or field mapping. Only the validation
658
- * step is executed; the resulting value is discarded in favor of the raw input.
665
+ * This is a unified error handler that catches both request errors (network failures,
666
+ * timeouts, etc.) and response errors (HTTP error status codes). It's essentially
667
+ * a combination of `onRequestError` and `onResponseError` hooks.
668
+ *
669
+ * @param context - Error context containing error details, request info, and response (if available)
670
+ * @returns Promise or void - Hook can be async or sync
659
671
  */
660
- disableRuntimeValidationTransform?: boolean | BooleanObject;
672
+ onError?: (context: ErrorContext<TCallApiContext>) => Awaitable<unknown>;
661
673
  /**
662
- * Optional url prefix that will be substituted for the `baseURL` of the schemaConfig at runtime.
674
+ * Hook called before the HTTP request is sent and before any internal processing of the request object begins.
675
+ *
676
+ * This is the ideal place to modify request headers, add authentication,
677
+ * implement request logging, or perform any setup before the network call.
678
+ *
679
+ * @param context - Request context with mutable request object and configuration
680
+ * @returns Promise or void - Hook can be async or sync
663
681
  *
664
- * Enables a short, stable prefix for routes while keeping the full `baseURL` centralized in config.
665
- * Keeps route definitions concise and shields them from changes to the underlying base URL.
666
682
  */
667
- prefix?: "" | AnyString;
683
+ onRequest?: (context: RequestContext<TCallApiContext>) => Awaitable<unknown>;
668
684
  /**
669
- * Controls the strictness of API route validation.
685
+ * Hook called when an error occurs during the fetch request itself.
670
686
  *
671
- * When true:
672
- * - Only routes explicitly defined in the schema will be considered valid to typescript and the runtime.
673
- * - Attempting to call routes not defined in the schema will result in both type errors and runtime validation errors.
674
- * - Useful for ensuring API calls conform exactly to your schema definition
687
+ * This handles network-level errors like connection failures, timeouts,
688
+ * DNS resolution errors, or other issues that prevent getting an HTTP response.
689
+ * Note that HTTP error status codes (4xx, 5xx) are handled by `onResponseError`.
675
690
  *
676
- * When false or undefined (default):
677
- * - All routes will be allowed, whether they are defined in the schema or not
691
+ * @param context - Request error context with error details and null response
692
+ * @returns Promise or void - Hook can be async or sync
678
693
  */
679
- strict?: boolean;
680
- }
681
- type CallApiSchemaType<TInput> = StandardSchemaV1<TInput | undefined> | ((value: TInput) => Awaitable<TInput | undefined>);
682
- interface CallApiSchema {
683
- auth?: CallApiSchemaType<AuthOption>;
694
+ onRequestError?: (context: RequestErrorContext<TCallApiContext>) => Awaitable<unknown>;
684
695
  /**
685
- * The schema to use for validating the request body.
696
+ * Hook called just before the HTTP request is sent and after the request has been processed.
697
+ *
698
+ * @param context - Request context with mutable request object and configuration
686
699
  */
687
- body?: CallApiSchemaType<Body>;
700
+ onRequestReady?: (context: RequestContext<TCallApiContext>) => Awaitable<unknown>;
688
701
  /**
689
- * The schema to use for validating the response data.
702
+ * Hook called during upload stream progress tracking.
703
+ *
704
+ * This hook is triggered when uploading data (like file uploads) and provides
705
+ * progress information about the upload. Useful for implementing progress bars
706
+ * or upload status indicators.
707
+ *
708
+ * @param context - Request stream context with progress event and request instance
709
+ * @returns Promise or void - Hook can be async or sync
710
+ *
690
711
  */
691
- data?: CallApiSchemaType<unknown>;
712
+ onRequestStream?: (context: RequestStreamContext<TCallApiContext>) => Awaitable<unknown>;
692
713
  /**
693
- * The schema to use for validating the response error data.
714
+ * Hook called when any HTTP response is received from the API.
715
+ *
716
+ * This hook is triggered for both successful (2xx) and error (4xx, 5xx) responses.
717
+ * It's useful for response logging, metrics collection, or any processing that
718
+ * should happen regardless of response status.
719
+ *
720
+ * @param context - Response context with either success data or error information
721
+ * @returns Promise or void - Hook can be async or sync
722
+ *
694
723
  */
695
- errorData?: CallApiSchemaType<unknown>;
724
+ onResponse?: (context: ResponseContext<TCallApiContext>) => Awaitable<unknown>;
696
725
  /**
697
- * The schema to use for validating the request headers.
726
+ * Hook called when an HTTP error response (4xx, 5xx) is received from the API.
727
+ *
728
+ * This handles server-side errors where an HTTP response was successfully received
729
+ * but indicates an error condition. Different from `onRequestError` which handles
730
+ * network-level failures.
731
+ *
732
+ * @param context - Response error context with HTTP error details and response
733
+ * @returns Promise or void - Hook can be async or sync
698
734
  */
699
- headers?: CallApiSchemaType<HeadersOption>;
735
+ onResponseError?: (context: ResponseErrorContext<TCallApiContext>) => Awaitable<unknown>;
700
736
  /**
701
- * The schema to use for validating the meta option.
737
+ * Hook called during download stream progress tracking.
738
+ *
739
+ * This hook is triggered when downloading data (like file downloads) and provides
740
+ * progress information about the download. Useful for implementing progress bars
741
+ * or download status indicators.
742
+ *
743
+ * @param context - Response stream context with progress event and response
744
+ * @returns Promise or void - Hook can be async or sync
745
+ *
702
746
  */
703
- meta?: CallApiSchemaType<GlobalMeta>;
747
+ onResponseStream?: (context: ResponseStreamContext<TCallApiContext>) => Awaitable<unknown>;
704
748
  /**
705
- * The schema to use for validating the request method.
749
+ * Hook called when a request is being retried.
750
+ *
751
+ * This hook is triggered before each retry attempt, providing information about
752
+ * the previous failure and the current retry attempt number. Useful for implementing
753
+ * custom retry logic, exponential backoff, or retry logging.
754
+ *
755
+ * @param context - Retry context with error details and retry attempt count
756
+ * @returns Promise or void - Hook can be async or sync
757
+ *
706
758
  */
707
- method?: CallApiSchemaType<MethodUnion>;
759
+ onRetry?: (context: RetryContext<TCallApiContext>) => Awaitable<unknown>;
708
760
  /**
709
- * The schema to use for validating the request url parameters.
761
+ * Hook called when a successful response (2xx status) is received from the API.
762
+ *
763
+ * This hook is triggered only for successful responses and provides access to
764
+ * the parsed response data. Ideal for success logging, caching, or post-processing
765
+ * of successful API responses.
766
+ *
767
+ * @param context - Success context with parsed response data and response object
768
+ * @returns Promise or void - Hook can be async or sync
769
+ *
710
770
  */
711
- params?: CallApiSchemaType<Params>;
771
+ onSuccess?: (context: SuccessContext<TCallApiContext>) => Awaitable<unknown>;
712
772
  /**
713
- * The schema to use for validating the request url queries.
773
+ * Hook called when a validation error occurs.
774
+ *
775
+ * This hook is triggered when request or response data fails validation against
776
+ * a defined schema. It provides access to the validation error details and can
777
+ * be used for custom error handling, logging, or fallback behavior.
778
+ *
779
+ * @param context - Validation error context with error details and response (if available)
780
+ * @returns Promise or void - Hook can be async or sync
781
+ *
714
782
  */
715
- query?: CallApiSchemaType<Query>;
783
+ onValidationError?: (context: ValidationErrorContext<TCallApiContext>) => Awaitable<unknown>;
716
784
  }
717
- declare const routeKeyMethods: readonly ["delete", "get", "patch", "post", "put"];
718
- type RouteKeyMethods = (typeof routeKeyMethods)[number];
719
- type RouteKeyMethodsURLUnion = `${AtSymbol}${RouteKeyMethods}/`;
720
- type BaseSchemaRouteKeyPrefixes = FallBackRouteSchemaKey | RouteKeyMethodsURLUnion;
721
- type BaseCallApiSchemaRoutes = Partial<Record<AnyString | BaseSchemaRouteKeyPrefixes, CallApiSchema>>;
722
- type BaseCallApiSchemaAndConfig = {
723
- config?: CallApiSchemaConfig;
724
- routes: BaseCallApiSchemaRoutes;
785
+ type HooksOrHooksArray<TCallApiContext extends NoInfer<CallApiContext> = DefaultCallApiContext> = { [Key in keyof Hooks<TCallApiContext>]: Hooks<TCallApiContext>[Key] | Array<Hooks<TCallApiContext>[Key]> };
786
+ interface HookConfigOptions {
787
+ /**
788
+ * Controls the execution mode of all composed hooks (main + plugin hooks).
789
+ *
790
+ * - **"parallel"**: All hooks execute simultaneously via Promise.all() for better performance
791
+ * - **"sequential"**: All hooks execute one by one in registration order via await in a loop
792
+ *
793
+ * This affects how ALL hooks execute together, regardless of their source (main or plugin).
794
+ *
795
+ * @default "parallel"
796
+ */
797
+ hooksExecutionMode?: "parallel" | "sequential";
798
+ }
799
+ type RequestContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = {
800
+ /**
801
+ * Base configuration object passed to createFetchClient.
802
+ *
803
+ * Contains the foundational configuration that applies to all requests
804
+ * made by this client instance, such as baseURL, default headers, and
805
+ * global options.
806
+ */
807
+ baseConfig: Exclude<BaseCallApiConfig, AnyFunction>;
808
+ /**
809
+ * Instance-specific configuration object passed to the callApi instance.
810
+ *
811
+ * Contains configuration specific to this particular API call, which
812
+ * can override or extend the base configuration.
813
+ */
814
+ config: CallApiConfig;
815
+ /**
816
+ * Merged options combining base config, instance config, and default options.
817
+ *
818
+ * This is the final resolved configuration that will be used for the request,
819
+ * with proper precedence applied (instance > base > defaults).
820
+ */
821
+ options: CallApiExtraOptionsForHooks<TCallApiContext>;
822
+ /**
823
+ * Merged request object ready to be sent.
824
+ *
825
+ * Contains the final request configuration including URL, method, headers,
826
+ * body, and other fetch options. This object can be modified in onRequest
827
+ * hooks to customize the outgoing request.
828
+ */
829
+ request: CallApiRequestOptionsForHooks;
830
+ };
831
+ type SuccessContext<TCallApiContext extends Pick<CallApiContext, "Data" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = DistributiveOmit<CallApiResultSuccessVariant<TCallApiContext["Data"]>, "error"> & RequestContext<TCallApiContext>;
832
+ type ResponseContext<TCallApiContext extends Pick<CallApiContext, "Data" | "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = RequestContext<TCallApiContext> & (Prettify<CallApiResultSuccessVariant<TCallApiContext["Data"]>> | Prettify<Extract<CallApiResultErrorVariant<TCallApiContext["ErrorData"]>, {
833
+ error: PossibleHTTPError<TCallApiContext["ErrorData"]>;
834
+ }>>);
835
+ type RequestStreamContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = RequestContext<TCallApiContext> & {
836
+ event: StreamProgressEvent;
837
+ requestInstance: Request;
838
+ };
839
+ type ResponseStreamContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = RequestContext<TCallApiContext> & {
840
+ event: StreamProgressEvent;
841
+ response: Response;
842
+ };
843
+ type ErrorContext<TCallApiContext extends Pick<CallApiContext, "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = DistributiveOmit<CallApiResultErrorVariant<TCallApiContext["ErrorData"]>, "data"> & RequestContext<TCallApiContext>;
844
+ type ValidationErrorContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = Extract<ErrorContext<TCallApiContext>, {
845
+ error: PossibleValidationError;
846
+ }> & RequestContext<TCallApiContext>;
847
+ type RequestErrorContext<TCallApiContext extends Pick<CallApiContext, "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = Extract<ErrorContext<TCallApiContext>, {
848
+ error: PossibleJavaScriptError;
849
+ }> & RequestContext<TCallApiContext>;
850
+ type ResponseErrorContext<TCallApiContext extends Pick<CallApiContext, "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = Extract<ErrorContext<TCallApiContext>, {
851
+ error: PossibleHTTPError<TCallApiContext["ErrorData"]>;
852
+ }> & RequestContext<TCallApiContext>;
853
+ type RetryContext<TCallApiContext extends Pick<CallApiContext, "ErrorData" | "InferredExtraOptions" | "Meta"> = DefaultCallApiContext> = ErrorContext<TCallApiContext> & {
854
+ retryAttemptCount: number;
725
855
  };
726
856
  //#endregion
727
- //#region src/url.d.ts
728
- declare const atSymbol = "@";
729
- type AtSymbol = typeof atSymbol;
730
- type AllowedQueryParamValues = UnmaskType<boolean | number | string>;
731
- type RecordStyleParams = UnmaskType<Record<string, AllowedQueryParamValues>>;
732
- type TupleStyleParams = UnmaskType<AllowedQueryParamValues[]>;
733
- type Params = UnmaskType<RecordStyleParams | TupleStyleParams>;
734
- type Query = UnmaskType<Record<string, AllowedQueryParamValues> | URLSearchParams>;
735
- type InitURLOrURLObject = AnyString | RouteKeyMethodsURLUnion | URL;
736
- interface URLOptions {
857
+ //#region src/dedupe.d.ts
858
+ type DedupeStrategyUnion = UnmaskType<"cancel" | "defer" | "none">;
859
+ type DedupeOptions = {
737
860
  /**
738
- * Base URL for all API requests. Will only be prepended to relative URLs.
861
+ * Controls the scope of request deduplication caching.
739
862
  *
740
- * Absolute URLs (starting with http/https) will not be prepended by the baseURL.
863
+ * - `"global"`: Shares deduplication cache across all `createFetchClient` instances with the same `dedupeCacheScopeKey`.
864
+ * Useful for applications with multiple API clients that should share deduplication state.
865
+ * - `"local"`: Limits deduplication to requests within the same `createFetchClient` instance.
866
+ * Provides better isolation and is recommended for most use cases.
867
+ *
868
+ *
869
+ * **Real-world Scenarios:**
870
+ * - Use `"global"` when you have multiple API clients (user service, auth service, etc.) that might make overlapping requests
871
+ * - Use `"local"` (default) for single-purpose clients or when you want strict isolation between different parts of your app
741
872
  *
742
873
  * @example
743
874
  * ```ts
744
- * // Set base URL for all requests
745
- * baseURL: "https://api.example.com/v1"
746
- *
747
- * // Then use relative URLs in requests
748
- * callApi("/users") // → https://api.example.com/v1/users
749
- * callApi("/posts/123") // → https://api.example.com/v1/posts/123
875
+ * // Local scope - each client has its own deduplication cache
876
+ * const userClient = createFetchClient({ baseURL: "/api/users" });
877
+ * const postClient = createFetchClient({ baseURL: "/api/posts" });
878
+ * // These clients won't share deduplication state
750
879
  *
751
- * // Environment-specific base URLs
752
- * baseURL: process.env.NODE_ENV === "production"
753
- * ? "https://api.example.com"
754
- * : "http://localhost:3000/api"
880
+ * // Global scope - share cache across related clients
881
+ * const userClient = createFetchClient({
882
+ * baseURL: "/api/users",
883
+ * dedupeCacheScope: "global",
884
+ * });
885
+ * const postClient = createFetchClient({
886
+ * baseURL: "/api/posts",
887
+ * dedupeCacheScope: "global",
888
+ * });
889
+ * // These clients will share deduplication state
755
890
  * ```
756
- */
757
- baseURL?: string;
758
- /**
759
- * Resolved request URL after processing baseURL, parameters, and query strings (readonly)
760
- *
761
- * This is the final URL that will be used for the HTTP request, computed from
762
- * baseURL, initURL, params, and query parameters.
763
- *
764
- */
765
- readonly fullURL?: string;
766
- /**
767
- * The original URL string passed to the callApi instance (readonly)
768
- *
769
- * This preserves the original URL as provided, including any method modifiers like "@get/" or "@post/".
770
891
  *
892
+ * @default "local"
771
893
  */
772
- readonly initURL?: string;
894
+ dedupeCacheScope?: "global" | "local";
773
895
  /**
774
- * The URL string after normalization, with method modifiers removed(readonly)
896
+ * Unique namespace for the global deduplication cache when using `dedupeCacheScope: "global"`.
775
897
  *
776
- * Method modifiers like "@get/", "@post/" are stripped to create a clean URL
777
- * for parameter substitution and final URL construction.
898
+ * This creates logical groupings of deduplication caches. All instances with the same key
899
+ * will share the same cache namespace, allowing fine-grained control over which clients
900
+ * share deduplication state.
778
901
  *
779
- */
780
- readonly initURLNormalized?: string;
781
- /**
782
- * Parameters to be substituted into URL path segments.
902
+ * **Best Practices:**
903
+ * - Use descriptive names that reflect the logical grouping (e.g., "user-service", "analytics-api")
904
+ * - Keep scope keys consistent across related API clients
905
+ * - Consider using different scope keys for different environments (dev, staging, prod)
906
+ * - Avoid overly broad scope keys that might cause unintended cache sharing
783
907
  *
784
- * Supports both object-style (named parameters) and array-style (positional parameters)
785
- * for flexible URL parameter substitution.
908
+ * **Cache Management:**
909
+ * - Each scope key maintains its own independent cache
910
+ * - Caches are automatically cleaned up when no references remain
911
+ * - Consider the memory implications of multiple global scopes
786
912
  *
787
913
  * @example
788
- * ```typescript
789
- * // Object-style parameters (recommended)
790
- * const namedParams: URLOptions = {
791
- * initURL: "/users/:userId/posts/:postId",
792
- * params: { userId: "123", postId: "456" }
793
- * };
794
- * // Results in: /users/123/posts/456
914
+ * ```ts
915
+ * // Group related API clients together
916
+ * const userClient = createFetchClient({
917
+ * baseURL: "/api/users",
918
+ * dedupeCacheScope: "global",
919
+ * dedupeCacheScopeKey: "user-service"
920
+ * });
921
+ * const profileClient = createFetchClient({
922
+ * baseURL: "/api/profiles",
923
+ * dedupeCacheScope: "global",
924
+ * dedupeCacheScopeKey: "user-service" // Same scope - will share cache
925
+ * });
795
926
  *
796
- * // Array-style parameters (positional)
797
- * const positionalParams: URLOptions = {
798
- * initURL: "/users/:userId/posts/:postId",
799
- * params: ["123", "456"] // Maps in order: userId=123, postId=456
800
- * };
801
- * // Results in: /users/123/posts/456
927
+ * // Separate analytics client with its own cache
928
+ * const analyticsClient = createFetchClient({
929
+ * baseURL: "/api/analytics",
930
+ * dedupeCacheScope: "global",
931
+ * dedupeCacheScopeKey: "analytics-service" // Different scope
932
+ * });
802
933
  *
803
- * // Single parameter
804
- * const singleParam: URLOptions = {
805
- * initURL: "/users/:id",
806
- * params: { id: "user-123" }
807
- * };
808
- * // Results in: /users/user-123
934
+ * // Environment-specific scoping
935
+ * const apiClient = createFetchClient({
936
+ * dedupeCacheScope: "global",
937
+ * dedupeCacheScopeKey: `api-${process.env.NODE_ENV}` // "api-development", "api-production", etc.
938
+ * });
809
939
  * ```
940
+ *
941
+ * @default "default"
810
942
  */
811
- params?: Params;
943
+ dedupeCacheScopeKey?: "default" | AnyString | ((context: RequestContext) => string | undefined);
812
944
  /**
813
- * Query parameters to append to the URL as search parameters.
945
+ * Custom key generator for request deduplication.
814
946
  *
815
- * These will be serialized into the URL query string using standard
816
- * URL encoding practices.
947
+ * Override the default key generation strategy to control exactly which requests
948
+ * are considered duplicates. The default key combines URL, method, body, and
949
+ * relevant headers (excluding volatile ones like 'Date', 'Authorization', etc.).
950
+ *
951
+ * **Default Key Generation:**
952
+ * The auto-generated key includes:
953
+ * - Full request URL (including query parameters)
954
+ * - HTTP method (GET, POST, etc.)
955
+ * - Request body (for POST/PUT/PATCH requests)
956
+ * - Stable headers (excludes Date, Authorization, User-Agent, etc.)
957
+ *
958
+ * **Custom Key Best Practices:**
959
+ * - Include only the parts of the request that should affect deduplication
960
+ * - Avoid including volatile data (timestamps, random IDs, etc.)
961
+ * - Consider performance - simpler keys are faster to compute and compare
962
+ * - Ensure keys are deterministic for the same logical request
963
+ * - Use consistent key formats across your application
964
+ *
965
+ * **Performance Considerations:**
966
+ * - Function-based keys are computed on every request - keep them lightweight
967
+ * - String keys are fastest but least flexible
968
+ * - Consider caching expensive key computations if needed
817
969
  *
818
970
  * @example
819
- * ```typescript
820
- * // Basic query parameters
821
- * const queryOptions: URLOptions = {
822
- * initURL: "/users",
823
- * query: {
824
- * page: 1,
825
- * limit: 10,
826
- * search: "john doe",
827
- * active: true
828
- * }
829
- * };
830
- * // Results in: /users?page=1&limit=10&search=john%20doe&active=true
971
+ * ```ts
972
+ * import { callApi } from "@zayne-labs/callapi";
831
973
  *
832
- * // Filtering and sorting
833
- * const filterOptions: URLOptions = {
834
- * initURL: "/products",
835
- * query: {
836
- * category: "electronics",
837
- * minPrice: 100,
838
- * maxPrice: 500,
839
- * sortBy: "price",
840
- * order: "asc"
841
- * }
842
- * };
843
- * // Results in: /products?category=electronics&minPrice=100&maxPrice=500&sortBy=price&order=asc
844
- * ```
845
- */
846
- query?: Query;
847
- }
848
- //#endregion
849
- //#region src/types/conditional-types.d.ts
850
- /**
851
- * @description Makes a type partial if the output type of TSchema is not provided or has undefined in the union, otherwise makes it required
852
- */
853
- type MakeSchemaOptionRequiredIfDefined<TSchemaOption extends CallApiSchema[keyof CallApiSchema], TObject> = undefined extends InferSchemaOutput<TSchemaOption, undefined> ? TObject : Required<TObject>;
854
- type MergeBaseWithRouteKey<TBaseURLOrPrefix extends string | undefined, TRouteKey extends string> = TBaseURLOrPrefix extends string ? TRouteKey extends `${AtSymbol}${infer TMethod extends RouteKeyMethods}/${infer TRestOfRoutKey}` ? `${AtSymbol}${TMethod}/${RemoveLeadingSlash<RemoveTrailingSlash<TBaseURLOrPrefix>>}/${RemoveLeadingSlash<TRestOfRoutKey>}` : `${TBaseURLOrPrefix}${TRouteKey}` : TRouteKey;
855
- type ApplyURLBasedConfig<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = TSchemaConfig["prefix"] extends string ? MergeBaseWithRouteKey<TSchemaConfig["prefix"], TSchemaRouteKeys> : TSchemaConfig["baseURL"] extends string ? MergeBaseWithRouteKey<TSchemaConfig["baseURL"], TSchemaRouteKeys> : TSchemaRouteKeys;
856
- type ApplyStrictConfig<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = TSchemaConfig["strict"] extends true ? TSchemaRouteKeys : // eslint-disable-next-line perfectionist/sort-union-types -- Don't sort union types
857
- TSchemaRouteKeys | Exclude<InitURLOrURLObject, RouteKeyMethodsURLUnion>;
858
- type ApplySchemaConfiguration<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = ApplyStrictConfig<TSchemaConfig, ApplyURLBasedConfig<TSchemaConfig, TSchemaRouteKeys>>;
859
- type InferAllMainRoutes<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes> = Omit<TBaseSchemaRoutes, FallBackRouteSchemaKey>;
860
- type InferAllMainRouteKeys<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TSchemaConfig extends CallApiSchemaConfig> = ApplySchemaConfiguration<TSchemaConfig, Extract<keyof InferAllMainRoutes<TBaseSchemaRoutes>, string>>;
861
- type InferInitURL<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TSchemaConfig extends CallApiSchemaConfig> = keyof TBaseSchemaRoutes extends never ? InitURLOrURLObject : InferAllMainRouteKeys<TBaseSchemaRoutes, TSchemaConfig>;
862
- type GetCurrentRouteSchemaKey<TSchemaConfig extends CallApiSchemaConfig, TPath> = TPath extends URL ? string : TSchemaConfig["prefix"] extends string ? TPath extends (`${AtSymbol}${infer TMethod extends RouteKeyMethods}/${RemoveLeadingSlash<TSchemaConfig["prefix"]>}${infer TCurrentRoute}`) ? `${AtSymbol}${TMethod}/${RemoveLeadingSlash<TCurrentRoute>}` : TPath extends `${TSchemaConfig["prefix"]}${infer TCurrentRoute}` ? TCurrentRoute : string : TSchemaConfig["baseURL"] extends string ? TPath extends (`${AtSymbol}${infer TMethod extends RouteKeyMethods}/${TSchemaConfig["baseURL"]}${infer TCurrentRoute}`) ? `${AtSymbol}${TMethod}/${RemoveLeadingSlash<TCurrentRoute>}` : TPath extends `${TSchemaConfig["baseURL"]}${infer TCurrentRoute}` ? TCurrentRoute : string : TPath;
863
- 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;
864
- type JsonPrimitive = boolean | number | string | null | undefined;
865
- type SerializableObject = Record<PropertyKey, unknown>;
866
- type SerializableArray = Array<JsonPrimitive | SerializableObject> | ReadonlyArray<JsonPrimitive | SerializableObject>;
867
- type Body = UnmaskType<Exclude<RequestInit["body"], undefined> | SerializableArray | SerializableObject>;
868
- type InferBodyOption<TSchema extends CallApiSchema> = MakeSchemaOptionRequiredIfDefined<TSchema["body"], {
869
- /**
870
- * Body of the request, can be a object or any other supported body type.
871
- */
872
- body?: InferSchemaOutput<TSchema["body"], Body>;
873
- }>;
874
- type MethodUnion = UnmaskType<"CONNECT" | "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT" | "TRACE" | AnyString>;
875
- type ExtractMethodFromURL<TInitURL> = string extends TInitURL ? MethodUnion : TInitURL extends `${AtSymbol}${infer TMethod extends RouteKeyMethods}/${string}` ? Uppercase<TMethod> : MethodUnion;
876
- type InferMethodOption<TSchema extends CallApiSchema, TInitURL extends InitURLOrURLObject> = MakeSchemaOptionRequiredIfDefined<TSchema["method"], {
877
- /**
878
- * HTTP method for the request.
879
- * @default "GET"
880
- */
881
- method?: InferSchemaOutput<TSchema["method"], ExtractMethodFromURL<TInitURL>>;
882
- }>;
883
- type HeadersOption = UnmaskType<Headers | Record<"Authorization", CommonAuthorizationHeaders | undefined> | Record<"Content-Type", CommonContentTypes | undefined> | Record<CommonRequestHeaders, string | undefined> | Record<string, string | undefined> | Array<[string, string]>>;
884
- type InferHeadersOption<TSchema extends CallApiSchema> = MakeSchemaOptionRequiredIfDefined<TSchema["headers"], {
885
- /**
886
- * Headers to be used in the request.
887
- */
888
- headers?: InferSchemaOutput<TSchema["headers"], HeadersOption> | ((context: {
889
- baseHeaders: Extract<HeadersOption, Record<string, unknown>>;
890
- }) => InferSchemaOutput<TSchema["headers"], HeadersOption>);
891
- }>;
892
- type InferRequestOptions<TSchema extends CallApiSchema, TInitURL extends InferInitURL<BaseCallApiSchemaRoutes, CallApiSchemaConfig>> = InferBodyOption<TSchema> & InferHeadersOption<TSchema> & InferMethodOption<TSchema, TInitURL>;
893
- type InferMetaOption<TSchema extends CallApiSchema, TCallApiContext extends CallApiContext> = MakeSchemaOptionRequiredIfDefined<TSchema["meta"], {
894
- /**
895
- * - An optional field you can fill with additional information,
896
- * to associate with the request, typically used for logging or tracing.
974
+ * // Simple static key - useful for singleton requests
975
+ * const config = callApi("/api/config", {
976
+ * dedupeKey: "app-config",
977
+ * dedupeStrategy: "defer" // Share the same config across all requests
978
+ * });
979
+ *
980
+ * // URL and method only - ignore headers and body
981
+ * const userData = callApi("/api/user/123", {
982
+ * dedupeKey: (context) => `${context.options.method}:${context.options.fullURL}`
983
+ * });
897
984
  *
898
- * - A good use case for this, would be to use the info to handle specific cases in any of the shared interceptors.
985
+ * // Include specific headers in deduplication
986
+ * const apiCall = callApi("/api/data", {
987
+ * dedupeKey: (context) => {
988
+ * const authHeader = context.request.headers.get("Authorization");
989
+ * return `${context.options.fullURL}-${authHeader}`;
990
+ * }
991
+ * });
899
992
  *
900
- * @example
901
- * ```ts
902
- * const callMainApi = callApi.create({
903
- * baseURL: "https://main-api.com",
904
- * onResponseError: ({ response, options }) => {
905
- * if (options.meta?.userId) {
906
- * console.error(`User ${options.meta.userId} made an error`);
907
- * }
908
- * },
993
+ * // User-specific deduplication
994
+ * const userSpecificCall = callApi("/api/dashboard", {
995
+ * dedupeKey: (context) => {
996
+ * const userId = context.options.fullURL.match(/user\/(\d+)/)?.[1];
997
+ * return `dashboard-${userId}`;
998
+ * }
909
999
  * });
910
1000
  *
911
- * const response = await callMainApi({
912
- * url: "https://example.com/api/data",
913
- * meta: { userId: "123" },
1001
+ * // Ignore certain query parameters
1002
+ * const searchCall = callApi("/api/search?q=test&timestamp=123456", {
1003
+ * dedupeKey: (context) => {
1004
+ * const url = new URL(context.options.fullURL);
1005
+ * url.searchParams.delete("timestamp"); // Remove volatile param
1006
+ * return `search:${url.toString()}`;
1007
+ * }
914
1008
  * });
915
1009
  * ```
1010
+ *
1011
+ * @default Auto-generated from request details
916
1012
  */
917
- meta?: InferSchemaOutput<TSchema["meta"], TCallApiContext["Meta"]>;
918
- }>;
919
- type InferAuthOption<TSchema extends CallApiSchema> = MakeSchemaOptionRequiredIfDefined<TSchema["auth"], {
1013
+ dedupeKey?: string | ((context: RequestContext) => string | undefined);
920
1014
  /**
921
- * Automatically add an Authorization header value.
1015
+ * Strategy for handling duplicate requests. Can be a static string or callback function.
922
1016
  *
923
- * Supports multiple authentication patterns:
924
- * - String: Direct authorization header value
925
- * - Auth object: Structured authentication configuration
1017
+ * **Available Strategies:**
1018
+ * - `"cancel"`: Cancel previous request when new one starts (good for search)
1019
+ * - `"defer"`: Share response between duplicate requests (good for config loading)
1020
+ * - `"none"`: No deduplication, all requests execute independently
926
1021
  *
927
1022
  * @example
928
1023
  * ```ts
929
- * // Bearer auth
930
- * const response = await callMainApi({
931
- * url: "https://example.com/api/data",
932
- * auth: "123456",
1024
+ * // Static strategies
1025
+ * const searchClient = createFetchClient({
1026
+ * dedupeStrategy: "cancel" // Cancel previous searches
933
1027
  * });
934
1028
  *
935
- * // Bearer auth
936
- * const response = await callMainApi({
937
- * url: "https://example.com/api/data",
938
- * auth: {
939
- * type: "Bearer",
940
- * value: "123456",
941
- * },
942
- })
943
- *
944
- * // Token auth
945
- * const response = await callMainApi({
946
- * url: "https://example.com/api/data",
947
- * auth: {
948
- * type: "Token",
949
- * value: "123456",
950
- * },
1029
+ * const configClient = createFetchClient({
1030
+ * dedupeStrategy: "defer" // Share config across components
951
1031
  * });
952
1032
  *
953
- * // Basic auth
954
- * const response = await callMainApi({
955
- * url: "https://example.com/api/data",
956
- * auth: {
957
- * type: "Basic",
958
- * username: "username",
959
- * password: "password",
960
- * },
1033
+ * // Dynamic strategy based on request
1034
+ * const smartClient = createFetchClient({
1035
+ * dedupeStrategy: (context) => {
1036
+ * return context.options.method === "GET" ? "defer" : "cancel";
1037
+ * }
961
1038
  * });
962
1039
  *
1040
+ * // Search-as-you-type with cancel strategy
1041
+ * const handleSearch = async (query: string) => {
1042
+ * try {
1043
+ * const { data } = await callApi("/api/search", {
1044
+ * method: "POST",
1045
+ * body: { query },
1046
+ * dedupeStrategy: "cancel",
1047
+ * dedupeKey: "search" // Cancel previous searches, only latest one goes through
1048
+ * });
1049
+ *
1050
+ * updateSearchResults(data);
1051
+ * } catch (error) {
1052
+ * if (error.name === "AbortError") {
1053
+ * // Previous search cancelled - (expected behavior)
1054
+ * return;
1055
+ * }
1056
+ * console.error("Search failed:", error);
1057
+ * }
1058
+ * };
1059
+ *
963
1060
  * ```
1061
+ *
1062
+ * @default "cancel"
964
1063
  */
965
- auth?: InferSchemaOutput<TSchema["auth"], AuthOption>;
966
- }>;
967
- type InferQueryOption<TSchema extends CallApiSchema> = MakeSchemaOptionRequiredIfDefined<TSchema["query"], {
968
- /**
969
- * Parameters to be appended to the URL (i.e: /:id)
970
- */
971
- query?: InferSchemaOutput<TSchema["query"], Query>;
972
- }>;
973
- type EmptyString = "";
974
- type EmptyTuple = readonly [];
975
- type StringTuple = readonly string[];
976
- type PossibleParamNamePatterns = `${string}:${string}` | `${string}{${string}}${"" | AnyString}`;
977
- type ExtractRouteParamNames<TCurrentRoute, TParamNamesAccumulator extends StringTuple = EmptyTuple> = TCurrentRoute extends PossibleParamNamePatterns ? TCurrentRoute extends `${infer TRoutePrefix}:${infer TParamAndRemainingRoute}` ? TParamAndRemainingRoute extends `${infer TCurrentParam}/${infer TRemainingRoute}` ? TCurrentParam extends EmptyString ? ExtractRouteParamNames<`${TRoutePrefix}/${TRemainingRoute}`, TParamNamesAccumulator> : ExtractRouteParamNames<`${TRoutePrefix}/${TRemainingRoute}`, [...TParamNamesAccumulator, TCurrentParam]> : TParamAndRemainingRoute extends `${infer TCurrentParam}` ? TCurrentParam extends EmptyString ? ExtractRouteParamNames<TRoutePrefix, TParamNamesAccumulator> : ExtractRouteParamNames<TRoutePrefix, [...TParamNamesAccumulator, TCurrentParam]> : ExtractRouteParamNames<TRoutePrefix, TParamNamesAccumulator> : TCurrentRoute extends `${infer TRoutePrefix}{${infer TCurrentParam}}${infer TRemainingRoute}` ? TCurrentParam extends EmptyString ? ExtractRouteParamNames<`${TRoutePrefix}${TRemainingRoute}`, TParamNamesAccumulator> : ExtractRouteParamNames<`${TRoutePrefix}${TRemainingRoute}`, [...TParamNamesAccumulator, TCurrentParam]> : TParamNamesAccumulator : TParamNamesAccumulator;
978
- type ConvertParamNamesToRecord<TParamNames extends StringTuple> = Prettify<TParamNames extends (readonly [infer TFirstParamName extends string, ...infer TRemainingParamNames extends StringTuple]) ? Record<TFirstParamName, AllowedQueryParamValues> & ConvertParamNamesToRecord<TRemainingParamNames> : NonNullable<unknown>>;
979
- type ConvertParamNamesToTuple<TParamNames extends StringTuple> = TParamNames extends readonly [string, ...infer TRemainingParamNames extends StringTuple] ? [AllowedQueryParamValues, ...ConvertParamNamesToTuple<TRemainingParamNames>] : [];
980
- type InferParamsFromRoute<TCurrentRoute> = ExtractRouteParamNames<TCurrentRoute> extends StringTuple ? ExtractRouteParamNames<TCurrentRoute> extends EmptyTuple ? Params : ConvertParamNamesToRecord<ExtractRouteParamNames<TCurrentRoute>> | ConvertParamNamesToTuple<ExtractRouteParamNames<TCurrentRoute>> : Params;
981
- 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>;
982
- type InferParamsOption<TSchema extends CallApiSchema, TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TCurrentRouteSchemaKey extends string> = MakeParamsOptionRequired<TSchema["params"], TBaseSchemaRoutes, TCurrentRouteSchemaKey, {
983
- /**
984
- * Parameters to be appended to the URL (i.e: /:id)
985
- */
986
- params?: InferSchemaOutput<TSchema["params"], InferParamsFromRoute<TCurrentRouteSchemaKey>>;
987
- }>;
988
- type InferExtraOptions<TSchema extends CallApiSchema, TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TCurrentRouteSchemaKey extends string, TCallApiContext extends CallApiContext> = InferAuthOption<TSchema> & InferMetaOption<TSchema, TCallApiContext> & InferParamsOption<TSchema, TBaseSchemaRoutes, TCurrentRouteSchemaKey> & InferQueryOption<TSchema>;
989
- type ResultModeOption<TErrorData, TResultMode extends ResultModeType> = TErrorData extends false ? {
990
- resultMode: "onlyData";
991
- } : TErrorData extends false | undefined ? {
992
- resultMode?: "onlyData";
993
- } : {
994
- resultMode?: TResultMode;
995
- };
996
- type ThrowOnErrorBoolean = boolean;
997
- type ThrowOnErrorType<TErrorData, TThrowOnError extends ThrowOnErrorBoolean> = TThrowOnError | ((context: ErrorContext<{
998
- ErrorData: TErrorData;
999
- }>) => TThrowOnError);
1000
- type ThrowOnErrorOption<TErrorData, TThrowOnError extends ThrowOnErrorBoolean> = TErrorData extends false ? {
1001
- throwOnError: true;
1002
- } : TErrorData extends false | undefined ? {
1003
- throwOnError?: true;
1004
- } : {
1005
- throwOnError?: ThrowOnErrorType<TErrorData, TThrowOnError>;
1064
+ dedupeStrategy?: DedupeStrategyUnion | ((context: RequestContext) => DedupeStrategyUnion);
1006
1065
  };
1007
1066
  //#endregion
1008
- //#region src/retry.d.ts
1009
- declare const defaultRetryStatusCodesLookup: () => Readonly<{
1010
- 408: "Request Timeout";
1011
- 409: "Conflict";
1012
- 425: "Too Early";
1013
- 429: "Too Many Requests";
1014
- 500: "Internal Server Error";
1015
- 502: "Bad Gateway";
1016
- 503: "Service Unavailable";
1017
- 504: "Gateway Timeout";
1018
- }>;
1019
- type RetryStatusCodes = UnmaskType<AnyNumber | keyof ReturnType<typeof defaultRetryStatusCodesLookup>>;
1020
- type RetryCondition<TErrorData> = (context: ErrorContext<{
1021
- ErrorData: TErrorData;
1022
- }>) => Awaitable<boolean>;
1023
- interface RetryOptions<TErrorData> {
1024
- /**
1025
- * Keeps track of the number of times the request has already been retried
1026
- * @internal
1027
- * @deprecated **NOTE**: This property is used internally to track retries. Please abstain from modifying it.
1028
- */
1029
- readonly ["~retryAttemptCount"]?: number;
1030
- /**
1031
- * Number of allowed retry attempts on HTTP errors
1032
- * @default 0
1033
- */
1034
- retryAttempts?: number;
1035
- /**
1036
- * Callback whose return value determines if a request should be retried or not
1037
- */
1038
- retryCondition?: RetryCondition<TErrorData>;
1039
- /**
1040
- * Delay between retries in milliseconds
1041
- * @default 1000
1042
- */
1043
- retryDelay?: number | ((currentAttemptCount: number) => number);
1044
- /**
1045
- * Maximum delay in milliseconds. Only applies to exponential strategy
1046
- * @default 10000
1047
- */
1048
- retryMaxDelay?: number;
1049
- /**
1050
- * HTTP methods that are allowed to retry
1051
- * @default ["GET", "POST"]
1052
- */
1053
- retryMethods?: MethodUnion[];
1054
- /**
1055
- * HTTP status codes that trigger a retry
1056
- */
1057
- retryStatusCodes?: RetryStatusCodes[];
1067
+ //#region src/middlewares.d.ts
1068
+ type FetchImpl = UnmaskType<(input: string | Request | URL, init?: RequestInit) => Awaitable<Response>>;
1069
+ type FetchMiddlewareContext<TCallApiContext extends CallApiContext> = RequestContext<TCallApiContext> & {
1070
+ fetchImpl: FetchImpl;
1071
+ };
1072
+ interface Middlewares<TCallApiContext extends NoInfer<CallApiContext> = DefaultCallApiContext> {
1058
1073
  /**
1059
- * Strategy to use when retrying
1060
- * @default "linear"
1074
+ * Wraps the fetch implementation to intercept requests at the network layer.
1075
+ *
1076
+ * Takes a context object containing the current fetch function and returns a new fetch function.
1077
+ * Use it to cache responses, add logging, handle offline mode, or short-circuit requests etc.
1078
+ * Multiple middleware compose in order: plugins → base config → per-request.
1079
+ *
1080
+ * Unlike `customFetchImpl`, middleware can call through to the original fetch.
1081
+ *
1082
+ * @example
1083
+ * ```ts
1084
+ * // Cache responses
1085
+ * const cache = new Map();
1086
+ *
1087
+ * fetchMiddleware: (ctx) => async (input, init) => {
1088
+ * const key = input.toString();
1089
+ *
1090
+ * const cachedResponse = cache.get(key);
1091
+ *
1092
+ * if (cachedResponse) {
1093
+ * return cachedResponse.clone();
1094
+ * }
1095
+ *
1096
+ * const response = await ctx.fetchImpl(input, init);
1097
+ * cache.set(key, response.clone());
1098
+ *
1099
+ * return response;
1100
+ * }
1101
+ *
1102
+ * // Handle offline
1103
+ * fetchMiddleware: (ctx) => async (...parameters) => {
1104
+ * if (!navigator.onLine) {
1105
+ * return new Response('{"error": "offline"}', { status: 503 });
1106
+ * }
1107
+ *
1108
+ * return ctx.fetchImpl(...parameters);
1109
+ * }
1110
+ * ```
1061
1111
  */
1062
- retryStrategy?: "exponential" | "linear";
1112
+ fetchMiddleware?: (context: FetchMiddlewareContext<TCallApiContext>) => FetchImpl;
1063
1113
  }
1064
1114
  //#endregion
1065
1115
  //#region src/utils/external/error.d.ts
@@ -1146,15 +1196,12 @@ type CallApiRequestOptions = {
1146
1196
  */
1147
1197
  method?: MethodUnion;
1148
1198
  } & Pick<ModifiedRequestInit, FetchSpecificKeysUnion>;
1149
- type CallApiRequestOptionsForHooks = Omit<CallApiRequestOptions, "headers"> & {
1150
- headers: Record<"Authorization" | "Content-Type" | CommonRequestHeaders, string | undefined>;
1151
- };
1152
1199
  type SharedExtraOptions<TCallApiContext extends CallApiContext = DefaultCallApiContext, TData = DefaultDataType, TErrorData = DefaultDataType, TResultMode extends ResultModeType = ResultModeType, TThrowOnError extends ThrowOnErrorBoolean = DefaultThrowOnError, TResponseType extends ResponseTypeType = ResponseTypeType, TPluginArray extends CallApiPlugin[] = DefaultPluginArray, TComputedMergedPluginExtraOptions = Partial<InferPluginExtraOptions<TPluginArray> & InferSchemaOutput<TCallApiContext["InferredExtraOptions"], TCallApiContext["InferredExtraOptions"]>>, TComputedCallApiContext extends CallApiContext = OverrideCallApiContext<TCallApiContext, {
1153
1200
  Data: TData;
1154
1201
  ErrorData: TErrorData;
1155
1202
  InferredExtraOptions: TComputedMergedPluginExtraOptions;
1156
1203
  ResultMode: TResultMode;
1157
- }>> = DedupeOptions & HookConfigOptions & HooksOrHooksArray<NoInferUnMasked<TComputedCallApiContext>> & Middlewares<NoInferUnMasked<TComputedCallApiContext>> & ResultModeOption<TErrorData, TResultMode> & RetryOptions<TErrorData> & TComputedMergedPluginExtraOptions & ThrowOnErrorOption<TErrorData, TThrowOnError> & URLOptions & {
1204
+ }>> = DedupeOptions & HookConfigOptions & HooksOrHooksArray<NoInferUnMasked<TComputedCallApiContext>> & Middlewares<NoInferUnMasked<TComputedCallApiContext>> & RefetchOptions & ResultModeOption<TErrorData, TResultMode> & RetryOptions<TErrorData> & TComputedMergedPluginExtraOptions & ThrowOnErrorOption<TErrorData, TThrowOnError> & URLOptions & {
1158
1205
  /**
1159
1206
  * Automatically add an Authorization header value.
1160
1207
  *
@@ -1193,7 +1240,7 @@ type SharedExtraOptions<TCallApiContext extends CallApiContext = DefaultCallApiC
1193
1240
  * bodySerializer: (data) => JSON.stringify(data, null, 2)
1194
1241
  * ```
1195
1242
  */
1196
- bodySerializer?: (bodyData: Record<string, unknown>) => string;
1243
+ bodySerializer?: (bodyData: SerializableObject) => string;
1197
1244
  /**
1198
1245
  * Whether to clone the response so it can be read multiple times.
1199
1246
  *
@@ -1631,7 +1678,6 @@ type CallApiExtraOptions<TCallApiContext extends CallApiContext = DefaultCallApi
1631
1678
  */
1632
1679
  schemaConfig?: TSchemaConfig | ((context: GetExtendSchemaConfigContext<TBaseSchemaConfig>) => TSchemaConfig);
1633
1680
  };
1634
- type CallApiExtraOptionsForHooks<TCallApiContext extends CallApiContext = DefaultCallApiContext> = Hooks & Omit<CallApiExtraOptions<TCallApiContext>, keyof Hooks>;
1635
1681
  type InstanceContext = {
1636
1682
  initURL: string;
1637
1683
  options: CallApiExtraOptions;
@@ -1711,9 +1757,7 @@ type ResultModeType = ResultModePlaceholder | ResultModeUnion;
1711
1757
  type InferCallApiResult<TData, TErrorData, TResultMode extends ResultModeType, TThrowOnError extends ThrowOnErrorBoolean, TComputedResultModeMapWithException extends ResultModeMap<TData, TErrorData, true> = ResultModeMap<TData, TErrorData, true>, TComputedResultModeMapWithoutException extends ResultModeMap<TData, TErrorData, TThrowOnError> = ResultModeMap<TData, TErrorData, TThrowOnError>> = TErrorData extends false ? TComputedResultModeMapWithException["onlyData"] : TErrorData extends false | undefined ? TComputedResultModeMapWithException["onlyData"] : ResultModePlaceholder extends TResultMode ? TComputedResultModeMapWithoutException["all"] : TResultMode extends ResultModeUnion ? TComputedResultModeMapWithoutException[TResultMode] : never;
1712
1758
  //#endregion
1713
1759
  //#region src/plugins.d.ts
1714
- type PluginSetupContext<TCallApiContext extends CallApiContext = DefaultCallApiContext> = RequestContext<TCallApiContext> & {
1715
- initURL: string;
1716
- };
1760
+ type PluginSetupContext<TCallApiContext extends CallApiContext = DefaultCallApiContext> = RequestContext<TCallApiContext> & ReturnType<typeof getCurrentRouteSchemaKeyAndMainInitURL>;
1717
1761
  type PluginInitResult<TCallApiContext extends CallApiContext = DefaultCallApiContext> = Partial<Omit<PluginSetupContext<TCallApiContext>, "initURL" | "request"> & {
1718
1762
  initURL: InitURLOrURLObject;
1719
1763
  request: CallApiRequestOptions;
@@ -1776,92 +1820,5 @@ type DefaultCallApiContext = Prettify<OverrideCallApiContext<Required<CallApiCon
1776
1820
  Meta: GlobalMeta;
1777
1821
  }>>;
1778
1822
  //#endregion
1779
- //#region src/createFetchClient.d.ts
1780
- 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 ThrowOnErrorBoolean = 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 ThrowOnErrorBoolean = 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>;
1781
- declare const createFetchClient: <TBaseCallApiContext extends CallApiContext = {
1782
- InferredExtraOptions: unknown;
1783
- Data: DefaultDataType;
1784
- ErrorData: DefaultDataType;
1785
- ResultMode: ResultModeType;
1786
- Meta: GlobalMeta;
1787
- }, TBaseData = TBaseCallApiContext["Data"], TBaseErrorData = TBaseCallApiContext["ErrorData"], TBaseResultMode extends ResultModeType = (TBaseCallApiContext["ResultMode"] extends ResultModeType ? TBaseCallApiContext["ResultMode"] : ResultModeType), TBaseThrowOnError extends ThrowOnErrorBoolean = 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 ThrowOnErrorBoolean = 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, {
1788
- all: CallApiResultSuccessVariant<TComputedData>;
1789
- fetchApi: Response;
1790
- onlyData: NoInferUnMasked<TComputedData>;
1791
- onlyResponse: Response;
1792
- withoutResponse: {
1793
- data: NoInferUnMasked<TComputedData>;
1794
- error: null;
1795
- };
1796
- }, {
1797
- all: TThrowOnError extends true ? CallApiResultSuccessVariant<TComputedData> : CallApiResultSuccessOrErrorVariant<TComputedData, TComputedErrorData>;
1798
- fetchApi: (TThrowOnError extends true ? CallApiResultSuccessVariant<TComputedData> : CallApiResultSuccessOrErrorVariant<TComputedData, TComputedErrorData>)["response"];
1799
- onlyData: (TThrowOnError extends true ? CallApiResultSuccessVariant<TComputedData> : CallApiResultSuccessOrErrorVariant<TComputedData, TComputedErrorData>)["data"];
1800
- onlyResponse: (TThrowOnError extends true ? CallApiResultSuccessVariant<TComputedData> : CallApiResultSuccessOrErrorVariant<TComputedData, TComputedErrorData>)["response"];
1801
- withoutResponse: DistributiveOmit<TThrowOnError extends true ? CallApiResultSuccessVariant<TComputedData> : CallApiResultSuccessOrErrorVariant<TComputedData, TComputedErrorData>, "response"> extends infer T ? { [Key in keyof T]: T[Key] } : never;
1802
- }>>(initURL: TInitURL, initConfig?: CallApiConfig<TCallApiContext, TComputedData, TComputedErrorData, TResultMode, TThrowOnError, TResponseType, TComputedBaseSchemaRoutes, TSchema, TComputedBaseSchemaConfig, TSchemaConfig, TInitURL, TCurrentRouteSchemaKey, TBasePluginArray, TPluginArray>) => Promise<TComputedResult>;
1803
- declare const callApi: <TData = unknown, TErrorData = unknown, TResultMode extends ResultModeType = ResultModeType, TCallApiContext extends CallApiContext = {
1804
- InferredExtraOptions: unknown;
1805
- Data: DefaultDataType;
1806
- ErrorData: DefaultDataType;
1807
- ResultMode: ResultModeType;
1808
- Meta: GlobalMeta;
1809
- }, TThrowOnError extends ThrowOnErrorBoolean = 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<{
1810
- [x: AnyString]: CallApiSchema | undefined;
1811
- "@default"?: CallApiSchema | undefined;
1812
- "@delete/"?: CallApiSchema | undefined;
1813
- "@get/"?: CallApiSchema | undefined;
1814
- "@patch/"?: CallApiSchema | undefined;
1815
- "@post/"?: CallApiSchema | undefined;
1816
- "@put/"?: CallApiSchema | undefined;
1817
- }, TCurrentRouteSchemaKey, CallApiSchema | undefined, {
1818
- [x: AnyString]: CallApiSchema | undefined;
1819
- "@default"?: CallApiSchema | undefined;
1820
- "@delete/"?: CallApiSchema | undefined;
1821
- "@get/"?: CallApiSchema | undefined;
1822
- "@patch/"?: CallApiSchema | undefined;
1823
- "@post/"?: CallApiSchema | undefined;
1824
- "@put/"?: CallApiSchema | undefined;
1825
- }[TCurrentRouteSchemaKey], NonNullable<Omit<CallApiSchema | undefined, keyof {
1826
- [x: AnyString]: CallApiSchema | undefined;
1827
- "@default"?: CallApiSchema | undefined;
1828
- "@delete/"?: CallApiSchema | undefined;
1829
- "@get/"?: CallApiSchema | undefined;
1830
- "@patch/"?: CallApiSchema | undefined;
1831
- "@post/"?: CallApiSchema | undefined;
1832
- "@put/"?: CallApiSchema | undefined;
1833
- }[TCurrentRouteSchemaKey]> & {
1834
- [x: AnyString]: CallApiSchema | undefined;
1835
- "@default"?: CallApiSchema | undefined;
1836
- "@delete/"?: CallApiSchema | undefined;
1837
- "@get/"?: CallApiSchema | undefined;
1838
- "@patch/"?: CallApiSchema | undefined;
1839
- "@post/"?: CallApiSchema | undefined;
1840
- "@put/"?: CallApiSchema | undefined;
1841
- }[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, {
1842
- all: CallApiResultSuccessVariant<TComputedData>;
1843
- fetchApi: Response;
1844
- onlyData: NoInferUnMasked<TComputedData>;
1845
- onlyResponse: Response;
1846
- withoutResponse: {
1847
- data: NoInferUnMasked<TComputedData>;
1848
- error: null;
1849
- };
1850
- }, {
1851
- all: TThrowOnError extends true ? CallApiResultSuccessVariant<TComputedData> : CallApiResultSuccessOrErrorVariant<TComputedData, TComputedErrorData>;
1852
- fetchApi: (TThrowOnError extends true ? CallApiResultSuccessVariant<TComputedData> : CallApiResultSuccessOrErrorVariant<TComputedData, TComputedErrorData>)["response"];
1853
- onlyData: (TThrowOnError extends true ? CallApiResultSuccessVariant<TComputedData> : CallApiResultSuccessOrErrorVariant<TComputedData, TComputedErrorData>)["data"];
1854
- onlyResponse: (TThrowOnError extends true ? CallApiResultSuccessVariant<TComputedData> : CallApiResultSuccessOrErrorVariant<TComputedData, TComputedErrorData>)["response"];
1855
- withoutResponse: DistributiveOmit<TThrowOnError extends true ? CallApiResultSuccessVariant<TComputedData> : CallApiResultSuccessOrErrorVariant<TComputedData, TComputedErrorData>, "response"> extends infer T ? { [Key in keyof T]: T[Key] } : never;
1856
- }>>(initURL: TInitURL, initConfig?: CallApiConfig<TCallApiContext, TComputedData, TComputedErrorData, TResultMode, TThrowOnError, TResponseType, {
1857
- [x: AnyString]: CallApiSchema | undefined;
1858
- "@default"?: CallApiSchema | undefined;
1859
- "@delete/"?: CallApiSchema | undefined;
1860
- "@get/"?: CallApiSchema | undefined;
1861
- "@patch/"?: CallApiSchema | undefined;
1862
- "@post/"?: CallApiSchema | undefined;
1863
- "@put/"?: CallApiSchema | undefined;
1864
- }, TSchema, CallApiSchemaConfig, TSchemaConfig, TInitURL, TCurrentRouteSchemaKey, DefaultPluginArray, TPluginArray>) => Promise<TComputedResult>;
1865
- //#endregion
1866
- export { Hooks as $, HTTPError as A, BaseSchemaRouteKeyPrefixes as B, CallApiRequestOptions as C, GetCallApiContextRequired as D, GetCallApiContext as E, InferAllMainRoutes as F, InferSchemaOutput as G, CallApiSchemaConfig as H, InferInitURL as I, FetchImpl as J, FallBackRouteSchemaKey as K, InferParamsFromRoute as L, RetryOptions as M, GetCurrentRouteSchemaKey as N, InstanceContext as O, InferAllMainRouteKeys as P, ErrorContext as Q, URLOptions as R, CallApiParameters as S, CallApiResultLoose as T, CallApiSchemaType as U, CallApiSchema as V, InferSchemaInput as W, Middlewares as X, FetchMiddlewareContext as Y, DedupeOptions as Z, BaseCallApiConfig as _, CallApiPlugin as a, ResponseStreamContext as at, CallApiExtraOptions as b, PluginSetupContext as c, Satisfies as ct, CallApiResultSuccessVariant as d, HooksOrHooksArray as et, PossibleHTTPError as f, ResultModeType as g, ResponseTypeType as h, DefaultCallApiContext as i, ResponseErrorContext as it, ValidationError as j, Register as k, CallApiResultErrorVariant as l, Writeable as lt, PossibleValidationError as m, createFetchClient as n, RequestStreamContext as nt, PluginHooks as o, SuccessContext as ot, PossibleJavaScriptError as p, fallBackRouteSchemaKey as q, createFetchClientWithContext as r, ResponseContext as rt, PluginMiddlewares as s, AnyFunction as st, callApi as t, RequestContext as tt, CallApiResultSuccessOrErrorVariant as u, fetchSpecificKeys as ut, BaseCallApiExtraOptions as v, CallApiRequestOptionsForHooks as w, CallApiExtraOptionsForHooks as x, CallApiConfig as y, BaseCallApiSchemaRoutes as z };
1867
- //# sourceMappingURL=index-JYbaY_l-.d.ts.map
1823
+ export { RetryOptions as $, GetCallApiContext as A, DedupeOptions as B, CallApiExtraOptions as C, DistributiveOmit as Ct, CallApiResultLoose as D, fetchSpecificKeys as Dt, CallApiResult as E, Writeable as Et, HTTPError as F, HooksOrHooksArray as G, CallApiRequestOptionsForHooks as H, ValidationError as I, ResponseContext as J, RequestContext as K, FetchImpl as L, GlobalMeta as M, InstanceContext as N, GetBaseSchemaConfig as O, Register as P, RefetchOptions as Q, FetchMiddlewareContext as R, CallApiContext as S, AnyString as St, CallApiRequestOptions as T, Satisfies as Tt, ErrorContext as U, CallApiExtraOptionsForHooks as V, Hooks as W, ResponseStreamContext as X, ResponseErrorContext as Y, SuccessContext as Z, ResponseTypeType as _, InferSchemaOutput as _t, PluginHooks as a, InferAllMainRoutes as at, BaseCallApiExtraOptions as b, fallBackRouteSchemaKey as bt, CallApiResultErrorVariant as c, ThrowOnErrorBoolean as ct, GetResponseType as d, BaseCallApiSchemaRoutes as dt, ApplyStrictConfig as et, InferCallApiResult as f, BaseSchemaRouteKeyPrefixes as ft, ResponseTypeMap as g, InferSchemaInput as gt, PossibleValidationError as h, CallApiSchemaType as ht, CallApiPlugin as i, InferAllMainRouteKeys as it, GetCallApiContextRequired as j, GetBaseSchemaRoutes as k, CallApiResultSuccessOrErrorVariant as l, URLOptions as lt, PossibleJavaScriptError as m, CallApiSchemaConfig as mt, DefaultDataType as n, GetCurrentRouteSchema as nt, PluginMiddlewares as o, InferInitURL as ot, PossibleHTTPError as p, CallApiSchema as pt, RequestStreamContext as q, DefaultPluginArray as r, GetCurrentRouteSchemaKey as rt, PluginSetupContext as s, InferParamsFromRoute as st, DefaultCallApiContext as t, ApplyURLBasedConfig as tt, CallApiResultSuccessVariant as u, BaseCallApiSchemaAndConfig as ut, ResultModeType as v, InferSchemaResult as vt, CallApiParameters as w, NoInferUnMasked as wt, CallApiConfig as x, AnyFunction as xt, BaseCallApiConfig as y, FallBackRouteSchemaKey as yt, Middlewares as z };
1824
+ //# sourceMappingURL=default-types-BvfiXmWZ.d.ts.map