@zayne-labs/callapi 1.11.35 → 1.11.37

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