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