@zayne-labs/callapi 1.8.20 → 1.8.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/{common-Vd9i_nPc.d.ts → common-C-kIzPcz.d.ts} +991 -84
- package/dist/esm/index.d.ts +15 -15
- package/dist/esm/index.js +57 -26
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/utils/index.d.ts +1 -1
- package/dist/esm/utils/index.js +1 -1
- package/dist/esm/{utils-C4H57FX_.js → utils-DZe23qYR.js} +3 -3
- package/dist/esm/utils-DZe23qYR.js.map +1 -0
- package/package.json +2 -2
- package/dist/esm/utils-C4H57FX_.js.map +0 -1
@@ -215,32 +215,107 @@ declare class ValidationError extends Error {
|
|
215
215
|
type AllowedQueryParamValues = UnmaskType<boolean | number | string>;
|
216
216
|
type Params = UnmaskType<Record<string, AllowedQueryParamValues> | AllowedQueryParamValues[]>;
|
217
217
|
type Query = UnmaskType<Record<string, AllowedQueryParamValues>>;
|
218
|
-
type InitURLOrURLObject = AnyString | URL;
|
218
|
+
type InitURLOrURLObject = AnyString | RouteKeyMethodsURLUnion | URL;
|
219
219
|
interface URLOptions {
|
220
220
|
/**
|
221
|
-
* Base URL to be prepended to all request URLs
|
221
|
+
* Base URL to be prepended to all request URLs.
|
222
|
+
*
|
223
|
+
* When provided, this will be prepended to relative URLs. Absolute URLs (starting with http/https) will not be prepended by the baseURL.
|
224
|
+
*
|
222
225
|
*/
|
223
226
|
baseURL?: string;
|
224
227
|
/**
|
225
|
-
* Resolved request URL
|
228
|
+
* Resolved request URL after processing baseURL, parameters, and query strings.
|
229
|
+
*
|
230
|
+
* This is the final URL that will be used for the HTTP request, computed from
|
231
|
+
* baseURL, initURL, params, and query parameters.
|
232
|
+
*
|
233
|
+
* @readonly
|
226
234
|
*/
|
227
235
|
readonly fullURL?: string;
|
228
236
|
/**
|
229
|
-
* The
|
237
|
+
* The original URL string passed to the callApi instance.
|
238
|
+
*
|
239
|
+
* This preserves the original URL as provided, including any method modifiers like "@get/" or "@post/".
|
240
|
+
*
|
241
|
+
* @readonly
|
230
242
|
*/
|
231
243
|
readonly initURL?: string;
|
232
244
|
/**
|
233
|
-
* The URL string
|
245
|
+
* The URL string after normalization, with method modifiers removed.
|
246
|
+
*
|
247
|
+
* Method modifiers like "@get/", "@post/" are stripped to create a clean URL
|
248
|
+
* for parameter substitution and final URL construction.
|
249
|
+
*
|
250
|
+
* @readonly
|
251
|
+
*
|
252
|
+
*
|
234
253
|
*/
|
235
254
|
readonly initURLNormalized?: string;
|
236
255
|
/**
|
237
|
-
* Parameters to be
|
256
|
+
* Parameters to be substituted into URL path segments.
|
257
|
+
*
|
258
|
+
* Supports both object-style (named parameters) and array-style (positional parameters)
|
259
|
+
* for flexible URL parameter substitution.
|
260
|
+
*
|
261
|
+
* @example
|
262
|
+
* ```typescript
|
263
|
+
* // Object-style parameters (recommended)
|
264
|
+
* const namedParams: URLOptions = {
|
265
|
+
* initURL: "/users/:userId/posts/:postId",
|
266
|
+
* params: { userId: "123", postId: "456" }
|
267
|
+
* };
|
268
|
+
* // Results in: /users/123/posts/456
|
238
269
|
*
|
239
|
-
*
|
270
|
+
* // Array-style parameters (positional)
|
271
|
+
* const positionalParams: URLOptions = {
|
272
|
+
* initURL: "/users/:userId/posts/:postId",
|
273
|
+
* params: ["123", "456"] // Maps in order: userId=123, postId=456
|
274
|
+
* };
|
275
|
+
* // Results in: /users/123/posts/456
|
276
|
+
*
|
277
|
+
* // Single parameter
|
278
|
+
* const singleParam: URLOptions = {
|
279
|
+
* initURL: "/users/:id",
|
280
|
+
* params: { id: "user-123" }
|
281
|
+
* };
|
282
|
+
* // Results in: /users/user-123
|
283
|
+
* ```
|
240
284
|
*/
|
241
285
|
params?: Params;
|
242
286
|
/**
|
243
|
-
* Query parameters to append to the URL.
|
287
|
+
* Query parameters to append to the URL as search parameters.
|
288
|
+
*
|
289
|
+
* These will be serialized into the URL query string using standard
|
290
|
+
* URL encoding practices.
|
291
|
+
*
|
292
|
+
* @example
|
293
|
+
* ```typescript
|
294
|
+
* // Basic query parameters
|
295
|
+
* const queryOptions: URLOptions = {
|
296
|
+
* initURL: "/users",
|
297
|
+
* query: {
|
298
|
+
* page: 1,
|
299
|
+
* limit: 10,
|
300
|
+
* search: "john doe",
|
301
|
+
* active: true
|
302
|
+
* }
|
303
|
+
* };
|
304
|
+
* // Results in: /users?page=1&limit=10&search=john%20doe&active=true
|
305
|
+
*
|
306
|
+
* // Filtering and sorting
|
307
|
+
* const filterOptions: URLOptions = {
|
308
|
+
* initURL: "/products",
|
309
|
+
* query: {
|
310
|
+
* category: "electronics",
|
311
|
+
* minPrice: 100,
|
312
|
+
* maxPrice: 500,
|
313
|
+
* sortBy: "price",
|
314
|
+
* order: "asc"
|
315
|
+
* }
|
316
|
+
* };
|
317
|
+
* // Results in: /products?category=electronics&minPrice=100&maxPrice=500&sortBy=price&order=asc
|
318
|
+
* ```
|
244
319
|
*/
|
245
320
|
query?: Query;
|
246
321
|
}
|
@@ -327,9 +402,8 @@ interface CallApiSchema {
|
|
327
402
|
}
|
328
403
|
declare const routeKeyMethods: ["delete", "get", "patch", "post", "put"];
|
329
404
|
type RouteKeyMethods = (typeof routeKeyMethods)[number];
|
330
|
-
type RouteKeyMethodsURLUnion =
|
331
|
-
type
|
332
|
-
type BaseCallApiSchemaRoutes = Partial<Record<PossibleRouteKey, CallApiSchema>>;
|
405
|
+
type RouteKeyMethodsURLUnion = `@${RouteKeyMethods}/`;
|
406
|
+
type BaseCallApiSchemaRoutes = Partial<Record<AnyString | RouteKeyMethodsURLUnion, CallApiSchema>>;
|
333
407
|
type BaseCallApiSchemaAndConfig = {
|
334
408
|
config?: CallApiSchemaConfig;
|
335
409
|
routes: BaseCallApiSchemaRoutes;
|
@@ -468,134 +542,566 @@ declare global {
|
|
468
542
|
//#endregion
|
469
543
|
//#region src/hooks.d.ts
|
470
544
|
type PluginExtraOptions<TPluginOptions = unknown> = {
|
545
|
+
/** Plugin-specific options passed to the plugin configuration */
|
471
546
|
options: Partial<TPluginOptions>;
|
472
547
|
};
|
473
548
|
interface Hooks<TData = DefaultDataType, TErrorData = DefaultDataType, TPluginOptions = unknown> {
|
474
549
|
/**
|
475
|
-
* Hook
|
476
|
-
*
|
550
|
+
* Hook called when any error occurs within the request/response lifecycle.
|
551
|
+
*
|
552
|
+
* This is a unified error handler that catches both request errors (network failures,
|
553
|
+
* timeouts, etc.) and response errors (HTTP error status codes). It's essentially
|
554
|
+
* a combination of `onRequestError` and `onResponseError` hooks.
|
555
|
+
*
|
556
|
+
* @param context - Error context containing error details, request info, and response (if available)
|
557
|
+
* @returns Promise or void - Hook can be async or sync
|
477
558
|
*/
|
478
559
|
onError?: (context: ErrorContext<TErrorData> & PluginExtraOptions<TPluginOptions>) => Awaitable<unknown>;
|
479
560
|
/**
|
480
|
-
* Hook
|
561
|
+
* Hook called just before the HTTP request is sent.
|
562
|
+
*
|
563
|
+
* This is the ideal place to modify request headers, add authentication,
|
564
|
+
* implement request logging, or perform any setup before the network call.
|
565
|
+
*
|
566
|
+
* @param context - Request context with mutable request object and configuration
|
567
|
+
* @returns Promise or void - Hook can be async or sync
|
568
|
+
*
|
481
569
|
*/
|
482
570
|
onRequest?: (context: RequestContext & PluginExtraOptions<TPluginOptions>) => Awaitable<unknown>;
|
483
571
|
/**
|
484
|
-
*
|
572
|
+
* Hook called when an error occurs during the fetch request itself.
|
573
|
+
*
|
574
|
+
* This handles network-level errors like connection failures, timeouts,
|
575
|
+
* DNS resolution errors, or other issues that prevent getting an HTTP response.
|
576
|
+
* Note that HTTP error status codes (4xx, 5xx) are handled by `onResponseError`.
|
577
|
+
*
|
578
|
+
* @param context - Request error context with error details and null response
|
579
|
+
* @returns Promise or void - Hook can be async or sync
|
485
580
|
*/
|
486
581
|
onRequestError?: (context: RequestErrorContext & PluginExtraOptions<TPluginOptions>) => Awaitable<unknown>;
|
487
582
|
/**
|
488
|
-
* Hook
|
583
|
+
* Hook called during upload stream progress tracking.
|
584
|
+
*
|
585
|
+
* This hook is triggered when uploading data (like file uploads) and provides
|
586
|
+
* progress information about the upload. Useful for implementing progress bars
|
587
|
+
* or upload status indicators.
|
588
|
+
*
|
589
|
+
* @param context - Request stream context with progress event and request instance
|
590
|
+
* @returns Promise or void - Hook can be async or sync
|
591
|
+
*
|
489
592
|
*/
|
490
593
|
onRequestStream?: (context: RequestStreamContext & PluginExtraOptions<TPluginOptions>) => Awaitable<unknown>;
|
491
594
|
/**
|
492
|
-
* Hook
|
595
|
+
* Hook called when any HTTP response is received from the API.
|
596
|
+
*
|
597
|
+
* This hook is triggered for both successful (2xx) and error (4xx, 5xx) responses.
|
598
|
+
* It's useful for response logging, metrics collection, or any processing that
|
599
|
+
* should happen regardless of response status.
|
600
|
+
*
|
601
|
+
* @param context - Response context with either success data or error information
|
602
|
+
* @returns Promise or void - Hook can be async or sync
|
603
|
+
*
|
493
604
|
*/
|
494
605
|
onResponse?: (context: ResponseContext<TData, TErrorData> & PluginExtraOptions<TPluginOptions>) => Awaitable<unknown>;
|
495
606
|
/**
|
496
|
-
*
|
607
|
+
* Hook called when an HTTP error response (4xx, 5xx) is received from the API.
|
608
|
+
*
|
609
|
+
* This handles server-side errors where an HTTP response was successfully received
|
610
|
+
* but indicates an error condition. Different from `onRequestError` which handles
|
611
|
+
* network-level failures.
|
612
|
+
*
|
613
|
+
* @param context - Response error context with HTTP error details and response
|
614
|
+
* @returns Promise or void - Hook can be async or sync
|
497
615
|
*/
|
498
616
|
onResponseError?: (context: ResponseErrorContext<TErrorData> & PluginExtraOptions<TPluginOptions>) => Awaitable<unknown>;
|
499
617
|
/**
|
500
|
-
* Hook
|
618
|
+
* Hook called during download stream progress tracking.
|
619
|
+
*
|
620
|
+
* This hook is triggered when downloading data (like file downloads) and provides
|
621
|
+
* progress information about the download. Useful for implementing progress bars
|
622
|
+
* or download status indicators.
|
623
|
+
*
|
624
|
+
* @param context - Response stream context with progress event and response
|
625
|
+
* @returns Promise or void - Hook can be async or sync
|
626
|
+
*
|
501
627
|
*/
|
502
628
|
onResponseStream?: (context: ResponseStreamContext & PluginExtraOptions<TPluginOptions>) => Awaitable<unknown>;
|
503
629
|
/**
|
504
|
-
* Hook
|
630
|
+
* Hook called when a request is being retried.
|
631
|
+
*
|
632
|
+
* This hook is triggered before each retry attempt, providing information about
|
633
|
+
* the previous failure and the current retry attempt number. Useful for implementing
|
634
|
+
* custom retry logic, exponential backoff, or retry logging.
|
635
|
+
*
|
636
|
+
* @param context - Retry context with error details and retry attempt count
|
637
|
+
* @returns Promise or void - Hook can be async or sync
|
638
|
+
*
|
505
639
|
*/
|
506
640
|
onRetry?: (response: RetryContext<TErrorData> & PluginExtraOptions<TPluginOptions>) => Awaitable<unknown>;
|
507
641
|
/**
|
508
|
-
* Hook
|
642
|
+
* Hook called when a successful response (2xx status) is received from the API.
|
643
|
+
*
|
644
|
+
* This hook is triggered only for successful responses and provides access to
|
645
|
+
* the parsed response data. Ideal for success logging, caching, or post-processing
|
646
|
+
* of successful API responses.
|
647
|
+
*
|
648
|
+
* @param context - Success context with parsed response data and response object
|
649
|
+
* @returns Promise or void - Hook can be async or sync
|
650
|
+
*
|
509
651
|
*/
|
510
652
|
onSuccess?: (context: SuccessContext<TData> & PluginExtraOptions<TPluginOptions>) => Awaitable<unknown>;
|
511
653
|
/**
|
512
|
-
* Hook
|
654
|
+
* Hook called when a validation error occurs.
|
655
|
+
*
|
656
|
+
* This hook is triggered when request or response data fails validation against
|
657
|
+
* a defined schema. It provides access to the validation error details and can
|
658
|
+
* be used for custom error handling, logging, or fallback behavior.
|
659
|
+
*
|
660
|
+
* @param context - Validation error context with error details and response (if available)
|
661
|
+
* @returns Promise or void - Hook can be async or sync
|
662
|
+
*
|
513
663
|
*/
|
514
664
|
onValidationError?: (context: ValidationErrorContext & PluginExtraOptions<TPluginOptions>) => Awaitable<unknown>;
|
515
665
|
}
|
516
666
|
type HooksOrHooksArray<TData = DefaultDataType, TErrorData = DefaultDataType, TMoreOptions = unknown> = { [Key in keyof Hooks<TData, TErrorData, TMoreOptions>]: Hooks<TData, TErrorData, TMoreOptions>[Key] | Array<Hooks<TData, TErrorData, TMoreOptions>[Key]> };
|
667
|
+
interface HookConfigOptions {
|
668
|
+
/**
|
669
|
+
* Controls the execution mode of all composed hooks (main + plugin hooks).
|
670
|
+
*
|
671
|
+
* - **"parallel"**: All hooks execute simultaneously via Promise.all() for better performance
|
672
|
+
* - **"sequential"**: All hooks execute one by one in registration order via await in a loop
|
673
|
+
*
|
674
|
+
* This affects how ALL hooks execute together, regardless of their source (main or plugin).
|
675
|
+
*
|
676
|
+
* Use `hookRegistrationOrder` to control the registration order of main vs plugin hooks.
|
677
|
+
*
|
678
|
+
* @default "parallel"
|
679
|
+
*
|
680
|
+
* @example
|
681
|
+
* ```ts
|
682
|
+
* // Parallel execution (default) - all hooks run simultaneously
|
683
|
+
* hooksExecutionMode: "parallel"
|
684
|
+
*
|
685
|
+
* // Sequential execution - hooks run one after another
|
686
|
+
* hooksExecutionMode: "sequential"
|
687
|
+
*
|
688
|
+
* // Use case: Hooks have dependencies and must run in order
|
689
|
+
* const client = callApi.create({
|
690
|
+
* hooksExecutionMode: "sequential",
|
691
|
+
* hookRegistrationOrder: "mainFirst",
|
692
|
+
* plugins: [transformPlugin],
|
693
|
+
* onRequest: (ctx) => {
|
694
|
+
* // This runs first, then transform plugin runs
|
695
|
+
* ctx.request.headers["x-request-id"] = generateId();
|
696
|
+
* }
|
697
|
+
* });
|
698
|
+
*
|
699
|
+
* // Use case: Independent operations can run in parallel for speed
|
700
|
+
* const client = callApi.create({
|
701
|
+
* hooksExecutionMode: "parallel", // Default
|
702
|
+
* plugins: [metricsPlugin, cachePlugin, loggingPlugin],
|
703
|
+
* onRequest: (ctx) => {
|
704
|
+
* // All hooks (main + plugins) run simultaneously
|
705
|
+
* addRequestTimestamp(ctx.request);
|
706
|
+
* }
|
707
|
+
* });
|
708
|
+
*
|
709
|
+
* // Use case: Error handling hooks that need sequential processing
|
710
|
+
* const client = callApi.create({
|
711
|
+
* hooksExecutionMode: "sequential",
|
712
|
+
* onError: [
|
713
|
+
* (ctx) => logError(ctx.error), // Log first
|
714
|
+
* (ctx) => reportError(ctx.error), // Then report
|
715
|
+
* (ctx) => cleanupResources(ctx) // Finally cleanup
|
716
|
+
* ]
|
717
|
+
* });
|
718
|
+
* ```
|
719
|
+
*/
|
720
|
+
hooksExecutionMode?: "parallel" | "sequential";
|
721
|
+
/**
|
722
|
+
* Controls the registration order of main hooks relative to plugin hooks.
|
723
|
+
*
|
724
|
+
* - **"pluginsFirst"**: Plugin hooks register first, then main hooks (default)
|
725
|
+
* - **"mainFirst"**: Main hooks register first, then plugin hooks
|
726
|
+
*
|
727
|
+
* This determines the order hooks are added to the registry, which affects
|
728
|
+
* their execution sequence when using sequential execution mode.
|
729
|
+
*
|
730
|
+
* @default "pluginsFirst"
|
731
|
+
*
|
732
|
+
* @example
|
733
|
+
* ```ts
|
734
|
+
* // Plugin hooks register first (default behavior)
|
735
|
+
* hookRegistrationOrder: "pluginsFirst"
|
736
|
+
*
|
737
|
+
* // Main hooks register first
|
738
|
+
* hookRegistrationOrder: "mainFirst"
|
739
|
+
*
|
740
|
+
* // Use case: Main validation before plugin processing
|
741
|
+
* const client = callApi.create({
|
742
|
+
* hookRegistrationOrder: "mainFirst",
|
743
|
+
* hooksExecutionMode: "sequential",
|
744
|
+
* plugins: [transformPlugin],
|
745
|
+
* onRequest: (ctx) => {
|
746
|
+
* // This main hook runs first in sequential mode
|
747
|
+
* if (!ctx.request.headers.authorization) {
|
748
|
+
* throw new Error("Authorization required");
|
749
|
+
* }
|
750
|
+
* }
|
751
|
+
* });
|
752
|
+
*
|
753
|
+
* // Use case: Plugin setup before main logic (default)
|
754
|
+
* const client = callApi.create({
|
755
|
+
* hookRegistrationOrder: "pluginsFirst", // Default
|
756
|
+
* hooksExecutionMode: "sequential",
|
757
|
+
* plugins: [setupPlugin],
|
758
|
+
* onRequest: (ctx) => {
|
759
|
+
* // Plugin runs first, then this main hook
|
760
|
+
* console.log("Request prepared:", ctx.request.url);
|
761
|
+
* }
|
762
|
+
* });
|
763
|
+
*
|
764
|
+
* // Use case: Parallel mode (registration order less important)
|
765
|
+
* const client = callApi.create({
|
766
|
+
* hookRegistrationOrder: "pluginsFirst",
|
767
|
+
* hooksExecutionMode: "parallel", // All run simultaneously
|
768
|
+
* plugins: [metricsPlugin, cachePlugin],
|
769
|
+
* onRequest: (ctx) => {
|
770
|
+
* // All hooks run in parallel regardless of registration order
|
771
|
+
* addRequestId(ctx.request);
|
772
|
+
* }
|
773
|
+
* });
|
774
|
+
* ```
|
775
|
+
*/
|
776
|
+
hooksRegistrationOrder?: "mainFirst" | "pluginsFirst";
|
777
|
+
}
|
517
778
|
type RequestContext = {
|
518
779
|
/**
|
519
|
-
*
|
780
|
+
* Base configuration object passed to createFetchClient.
|
781
|
+
*
|
782
|
+
* Contains the foundational configuration that applies to all requests
|
783
|
+
* made by this client instance, such as baseURL, default headers, and
|
784
|
+
* global options.
|
520
785
|
*/
|
521
786
|
baseConfig: BaseCallApiExtraOptions & CallApiRequestOptions;
|
522
787
|
/**
|
523
|
-
*
|
788
|
+
* Instance-specific configuration object passed to the callApi instance.
|
789
|
+
*
|
790
|
+
* Contains configuration specific to this particular API call, which
|
791
|
+
* can override or extend the base configuration.
|
524
792
|
*/
|
525
793
|
config: CallApiExtraOptions & CallApiRequestOptions;
|
526
794
|
/**
|
527
|
-
* Merged options
|
795
|
+
* Merged options combining base config, instance config, and default options.
|
528
796
|
*
|
797
|
+
* This is the final resolved configuration that will be used for the request,
|
798
|
+
* with proper precedence applied (instance > base > defaults).
|
529
799
|
*/
|
530
800
|
options: CallApiExtraOptionsForHooks;
|
531
801
|
/**
|
532
|
-
* Merged request
|
802
|
+
* Merged request object ready to be sent.
|
803
|
+
*
|
804
|
+
* Contains the final request configuration including URL, method, headers,
|
805
|
+
* body, and other fetch options. This object can be modified in onRequest
|
806
|
+
* hooks to customize the outgoing request.
|
533
807
|
*/
|
534
808
|
request: CallApiRequestOptionsForHooks;
|
535
809
|
};
|
536
810
|
type ValidationErrorContext = UnmaskType<RequestContext & {
|
811
|
+
/** Validation error containing details about what failed validation */
|
537
812
|
error: ValidationError;
|
813
|
+
/** HTTP response object if validation failed on response, null if on request */
|
538
814
|
response: Response | null;
|
539
815
|
}>;
|
540
816
|
type SuccessContext<TData> = UnmaskType<RequestContext & {
|
817
|
+
/** Parsed response data with the expected success type */
|
541
818
|
data: TData;
|
819
|
+
/** HTTP response object for the successful request */
|
542
820
|
response: Response;
|
543
821
|
}>;
|
544
822
|
type ResponseContext<TData, TErrorData> = UnmaskType<RequestContext & (Prettify<CallApiResultSuccessVariant<TData>> | Prettify<Extract<CallApiResultErrorVariant<TErrorData>, {
|
545
823
|
error: PossibleHTTPError<TErrorData>;
|
546
824
|
}>>)>;
|
547
825
|
type RequestErrorContext = RequestContext & {
|
826
|
+
/** Error that occurred during the request (network, timeout, etc.) */
|
548
827
|
error: PossibleJavaScriptOrValidationError;
|
828
|
+
/** Always null for request errors since no response was received */
|
549
829
|
response: null;
|
550
830
|
};
|
551
831
|
type ErrorContext<TErrorData> = UnmaskType<RequestContext & ({
|
832
|
+
/** HTTP error with response data */
|
552
833
|
error: PossibleHTTPError<TErrorData>;
|
834
|
+
/** HTTP response object containing error status */
|
553
835
|
response: Response;
|
554
836
|
} | {
|
837
|
+
/** Request-level error (network, timeout, validation, etc.) */
|
555
838
|
error: PossibleJavaScriptOrValidationError;
|
839
|
+
/** Response object if available, null for request errors */
|
556
840
|
response: Response | null;
|
557
841
|
})>;
|
558
842
|
type ResponseErrorContext<TErrorData> = UnmaskType<Extract<ErrorContext<TErrorData>, {
|
559
843
|
error: PossibleHTTPError<TErrorData>;
|
560
844
|
}> & RequestContext>;
|
561
845
|
type RetryContext<TErrorData> = UnmaskType<ErrorContext<TErrorData> & {
|
846
|
+
/** Current retry attempt number (1-based, so 1 = first retry) */
|
562
847
|
retryAttemptCount: number;
|
563
848
|
}>;
|
564
849
|
type RequestStreamContext = UnmaskType<RequestContext & {
|
850
|
+
/** Progress event containing loaded/total bytes information */
|
565
851
|
event: StreamProgressEvent;
|
852
|
+
/** The actual Request instance being uploaded */
|
566
853
|
requestInstance: Request;
|
567
854
|
}>;
|
568
855
|
type ResponseStreamContext = UnmaskType<RequestContext & {
|
856
|
+
/** Progress event containing loaded/total bytes information */
|
569
857
|
event: StreamProgressEvent;
|
858
|
+
/** HTTP response object being downloaded */
|
570
859
|
response: Response;
|
571
860
|
}>;
|
572
861
|
//#endregion
|
573
862
|
//#region src/dedupe.d.ts
|
574
863
|
type DedupeOptions = {
|
575
864
|
/**
|
576
|
-
*
|
577
|
-
*
|
578
|
-
* -
|
865
|
+
* Controls the scope of request deduplication caching.
|
866
|
+
*
|
867
|
+
* - `"global"`: Shares deduplication cache across all `createFetchClient` instances with the same `dedupeCacheScopeKey`.
|
868
|
+
* Useful for applications with multiple API clients that should share deduplication state.
|
869
|
+
* - `"local"`: Limits deduplication to requests within the same `createFetchClient` instance.
|
870
|
+
* Provides better isolation and is recommended for most use cases.
|
871
|
+
*
|
872
|
+
*
|
873
|
+
* **Real-world Scenarios:**
|
874
|
+
* - Use `"global"` when you have multiple API clients (user service, auth service, etc.) that might make overlapping requests
|
875
|
+
* - Use `"local"` (default) for single-purpose clients or when you want strict isolation between different parts of your app
|
876
|
+
*
|
877
|
+
* @example
|
878
|
+
* ```ts
|
879
|
+
* // Local scope - each client has its own deduplication cache
|
880
|
+
* const userClient = createFetchClient({ baseURL: "/api/users" });
|
881
|
+
* const postClient = createFetchClient({ baseURL: "/api/posts" });
|
882
|
+
* // These clients won't share deduplication state
|
883
|
+
*
|
884
|
+
* // Global scope - share cache across related clients
|
885
|
+
* const userClient = createFetchClient({
|
886
|
+
* baseURL: "/api/users",
|
887
|
+
* dedupeCacheScope: "global",
|
888
|
+
* });
|
889
|
+
* const postClient = createFetchClient({
|
890
|
+
* baseURL: "/api/posts",
|
891
|
+
* dedupeCacheScope: "global",
|
892
|
+
* });
|
893
|
+
* // These clients will share deduplication state
|
894
|
+
* ```
|
895
|
+
*
|
579
896
|
* @default "local"
|
580
897
|
*/
|
581
898
|
dedupeCacheScope?: "global" | "local";
|
582
899
|
/**
|
583
|
-
* Unique
|
900
|
+
* Unique namespace for the global deduplication cache when using `dedupeCacheScope: "global"`.
|
901
|
+
*
|
902
|
+
* This creates logical groupings of deduplication caches. All instances with the same key
|
903
|
+
* will share the same cache namespace, allowing fine-grained control over which clients
|
904
|
+
* share deduplication state.
|
905
|
+
*
|
906
|
+
* **Best Practices:**
|
907
|
+
* - Use descriptive names that reflect the logical grouping (e.g., "user-service", "analytics-api")
|
908
|
+
* - Keep scope keys consistent across related API clients
|
909
|
+
* - Consider using different scope keys for different environments (dev, staging, prod)
|
910
|
+
* - Avoid overly broad scope keys that might cause unintended cache sharing
|
911
|
+
*
|
912
|
+
* **Cache Management:**
|
913
|
+
* - Each scope key maintains its own independent cache
|
914
|
+
* - Caches are automatically cleaned up when no references remain
|
915
|
+
* - Consider the memory implications of multiple global scopes
|
916
|
+
*
|
917
|
+
* @example
|
918
|
+
* ```ts
|
919
|
+
* // Group related API clients together
|
920
|
+
* const userClient = createFetchClient({
|
921
|
+
* baseURL: "/api/users",
|
922
|
+
* dedupeCacheScope: "global",
|
923
|
+
* dedupeCacheScopeKey: "user-service"
|
924
|
+
* });
|
925
|
+
* const profileClient = createFetchClient({
|
926
|
+
* baseURL: "/api/profiles",
|
927
|
+
* dedupeCacheScope: "global",
|
928
|
+
* dedupeCacheScopeKey: "user-service" // Same scope - will share cache
|
929
|
+
* });
|
930
|
+
*
|
931
|
+
* // Separate analytics client with its own cache
|
932
|
+
* const analyticsClient = createFetchClient({
|
933
|
+
* baseURL: "/api/analytics",
|
934
|
+
* dedupeCacheScope: "global",
|
935
|
+
* dedupeCacheScopeKey: "analytics-service" // Different scope
|
936
|
+
* });
|
937
|
+
*
|
938
|
+
* // Environment-specific scoping
|
939
|
+
* const apiClient = createFetchClient({
|
940
|
+
* dedupeCacheScope: "global",
|
941
|
+
* dedupeCacheScopeKey: `api-${process.env.NODE_ENV}` // "api-development", "api-production", etc.
|
942
|
+
* });
|
943
|
+
* ```
|
584
944
|
*
|
585
|
-
* CallApi instances sharing this key will use the same cache for deduplication.
|
586
945
|
* @default "default"
|
587
946
|
*/
|
588
947
|
dedupeCacheScopeKey?: "default" | AnyString;
|
589
948
|
/**
|
590
|
-
* Custom
|
591
|
-
*
|
949
|
+
* Custom key generator for request deduplication.
|
950
|
+
*
|
951
|
+
* Override the default key generation strategy to control exactly which requests
|
952
|
+
* are considered duplicates. The default key combines URL, method, body, and
|
953
|
+
* relevant headers (excluding volatile ones like 'Date', 'Authorization', etc.).
|
954
|
+
*
|
955
|
+
* **Default Key Generation:**
|
956
|
+
* The auto-generated key includes:
|
957
|
+
* - Full request URL (including query parameters)
|
958
|
+
* - HTTP method (GET, POST, etc.)
|
959
|
+
* - Request body (for POST/PUT/PATCH requests)
|
960
|
+
* - Stable headers (excludes Date, Authorization, User-Agent, etc.)
|
961
|
+
*
|
962
|
+
* **Custom Key Best Practices:**
|
963
|
+
* - Include only the parts of the request that should affect deduplication
|
964
|
+
* - Avoid including volatile data (timestamps, random IDs, etc.)
|
965
|
+
* - Consider performance - simpler keys are faster to compute and compare
|
966
|
+
* - Ensure keys are deterministic for the same logical request
|
967
|
+
* - Use consistent key formats across your application
|
968
|
+
*
|
969
|
+
* **Performance Considerations:**
|
970
|
+
* - Function-based keys are computed on every request - keep them lightweight
|
971
|
+
* - String keys are fastest but least flexible
|
972
|
+
* - Consider caching expensive key computations if needed
|
973
|
+
*
|
974
|
+
* @example
|
975
|
+
* ```ts
|
976
|
+
* import { callApi } from "@zayne-labs/callapi";
|
977
|
+
*
|
978
|
+
* // Simple static key - useful for singleton requests
|
979
|
+
* const config = callApi("/api/config", {
|
980
|
+
* dedupeKey: "app-config",
|
981
|
+
* dedupeStrategy: "defer" // Share the same config across all requests
|
982
|
+
* });
|
983
|
+
*
|
984
|
+
* // URL and method only - ignore headers and body
|
985
|
+
* const userData = callApi("/api/user/123", {
|
986
|
+
* dedupeKey: (context) => `${context.options.method}:${context.options.fullURL}`
|
987
|
+
* });
|
988
|
+
*
|
989
|
+
* // Include specific headers in deduplication
|
990
|
+
* const apiCall = callApi("/api/data", {
|
991
|
+
* dedupeKey: (context) => {
|
992
|
+
* const authHeader = context.request.headers.get("Authorization");
|
993
|
+
* return `${context.options.fullURL}-${authHeader}`;
|
994
|
+
* }
|
995
|
+
* });
|
996
|
+
*
|
997
|
+
* // User-specific deduplication
|
998
|
+
* const userSpecificCall = callApi("/api/dashboard", {
|
999
|
+
* dedupeKey: (context) => {
|
1000
|
+
* const userId = context.options.fullURL.match(/user\/(\d+)/)?.[1];
|
1001
|
+
* return `dashboard-${userId}`;
|
1002
|
+
* }
|
1003
|
+
* });
|
1004
|
+
*
|
1005
|
+
* // Ignore certain query parameters
|
1006
|
+
* const searchCall = callApi("/api/search?q=test×tamp=123456", {
|
1007
|
+
* dedupeKey: (context) => {
|
1008
|
+
* const url = new URL(context.options.fullURL);
|
1009
|
+
* url.searchParams.delete("timestamp"); // Remove volatile param
|
1010
|
+
* return `search:${url.toString()}`;
|
1011
|
+
* }
|
1012
|
+
* });
|
1013
|
+
* ```
|
1014
|
+
*
|
1015
|
+
* @default Auto-generated from request details
|
592
1016
|
*/
|
593
|
-
dedupeKey?: string;
|
1017
|
+
dedupeKey?: string | ((context: RequestContext) => string);
|
594
1018
|
/**
|
595
|
-
*
|
596
|
-
*
|
597
|
-
*
|
598
|
-
* -
|
1019
|
+
* Strategy for handling duplicate requests.
|
1020
|
+
*
|
1021
|
+
* **Strategy Details:**
|
1022
|
+
* - `"cancel"`: Aborts any in-flight request with the same key when a new request starts.
|
1023
|
+
* The previous request will throw an AbortError, and the new request proceeds normally.
|
1024
|
+
* Best for scenarios where only the latest request matters.
|
1025
|
+
*
|
1026
|
+
* - `"defer"`: Returns the existing promise for duplicate requests, effectively sharing
|
1027
|
+
* the same response across multiple callers. All callers receive the same result.
|
1028
|
+
* Ideal for expensive operations that shouldn't be repeated.
|
1029
|
+
*
|
1030
|
+
* - `"none"`: Disables request deduplication entirely. Every request executes independently
|
1031
|
+
* regardless of similarity. Use when you need guaranteed request execution.
|
1032
|
+
*
|
1033
|
+
* **Real-world Use Cases:**
|
1034
|
+
*
|
1035
|
+
* **Cancel Strategy:**
|
1036
|
+
* - Search-as-you-type functionality (cancel previous searches)
|
1037
|
+
* - Real-time data updates (only latest request matters)
|
1038
|
+
* - User navigation (cancel previous page loads)
|
1039
|
+
* - Form submissions where rapid clicks should cancel previous attempts
|
1040
|
+
*
|
1041
|
+
* **Defer Strategy:**
|
1042
|
+
* - Configuration/settings loading (share across components)
|
1043
|
+
* - User profile data (multiple components need same data)
|
1044
|
+
* - Expensive computations or reports
|
1045
|
+
* - Authentication token refresh (prevent multiple refresh attempts)
|
1046
|
+
*
|
1047
|
+
* **None Strategy:**
|
1048
|
+
* - Analytics events (every event should be sent)
|
1049
|
+
* - Logging requests (each log entry is unique)
|
1050
|
+
* - File uploads (each upload is independent)
|
1051
|
+
* - Critical business operations that must not be deduplicated
|
1052
|
+
*
|
1053
|
+
*
|
1054
|
+
* @example
|
1055
|
+
* ```ts
|
1056
|
+
* // Cancel strategy - search functionality
|
1057
|
+
* const searchClient = createFetchClient({
|
1058
|
+
* baseURL: "/api/search",
|
1059
|
+
* dedupeStrategy: "cancel" // Cancel previous searches
|
1060
|
+
* });
|
1061
|
+
*
|
1062
|
+
* // Defer strategy - shared configuration
|
1063
|
+
* const configClient = createFetchClient({
|
1064
|
+
* dedupeStrategy: "defer" // Share config across components
|
1065
|
+
* });
|
1066
|
+
*
|
1067
|
+
* // Multiple components requesting config simultaneously
|
1068
|
+
* const config1 = configClient("/api/config"); // Makes actual request
|
1069
|
+
* const config2 = configClient("/api/config"); // Returns same promise as config1
|
1070
|
+
* const config3 = configClient("/api/config"); // Returns same promise as config1
|
1071
|
+
* // All three will resolve with the same response
|
1072
|
+
*
|
1073
|
+
* // None strategy - analytics
|
1074
|
+
* const analyticsClient = createFetchClient({
|
1075
|
+
* baseURL: "/api/analytics",
|
1076
|
+
* dedupeStrategy: "none" // Every event must be sent
|
1077
|
+
* });
|
1078
|
+
*
|
1079
|
+
* // Real-world search example with cancel
|
1080
|
+
* const handleSearch = async (query: string) => {
|
1081
|
+
* try {
|
1082
|
+
* const results = await callApi("/api/search", {
|
1083
|
+
* method: "POST",
|
1084
|
+
* body: { query },
|
1085
|
+
* dedupeStrategy: "cancel",
|
1086
|
+
* dedupeKey: "search" // All searches share the same key
|
1087
|
+
* });
|
1088
|
+
* updateUI(results);
|
1089
|
+
* } catch (error) {
|
1090
|
+
* if (error.name === "AbortError") {
|
1091
|
+
* // Previous search was cancelled - this is expected
|
1092
|
+
* return;
|
1093
|
+
* }
|
1094
|
+
* handleError(error);
|
1095
|
+
* }
|
1096
|
+
* };
|
1097
|
+
*
|
1098
|
+
* // Authentication token refresh with defer
|
1099
|
+
* const refreshToken = () => callApi("/api/auth/refresh", {
|
1100
|
+
* dedupeStrategy: "defer",
|
1101
|
+
* dedupeKey: "token-refresh" // Ensure only one refresh happens
|
1102
|
+
* });
|
1103
|
+
* ```
|
1104
|
+
*
|
599
1105
|
* @default "cancel"
|
600
1106
|
*/
|
601
1107
|
dedupeStrategy?: "cancel" | "defer" | "none";
|
@@ -659,7 +1165,9 @@ interface RetryOptions<TErrorData> {
|
|
659
1165
|
*/
|
660
1166
|
type MakeSchemaOptionRequiredIfDefined<TSchemaOption extends CallApiSchema[keyof CallApiSchema], TObject> = undefined extends InferSchemaResult<TSchemaOption, undefined> ? TObject : Required<TObject>;
|
661
1167
|
type ApplyURLBasedConfig<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = TSchemaConfig["prefix"] extends string ? `${TSchemaConfig["prefix"]}${TSchemaRouteKeys}` : TSchemaConfig["baseURL"] extends string ? `${TSchemaConfig["baseURL"]}${TSchemaRouteKeys}` : TSchemaRouteKeys;
|
662
|
-
type ApplyStrictConfig<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = TSchemaConfig["strict"] extends true ? TSchemaRouteKeys :
|
1168
|
+
type ApplyStrictConfig<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = TSchemaConfig["strict"] extends true ? TSchemaRouteKeys :
|
1169
|
+
// eslint-disable-next-line perfectionist/sort-union-types -- Don't sort union types
|
1170
|
+
TSchemaRouteKeys | Exclude<InitURLOrURLObject, RouteKeyMethodsURLUnion>;
|
663
1171
|
type ApplySchemaConfiguration<TSchemaConfig extends CallApiSchemaConfig, TSchemaRouteKeys extends string> = ApplyStrictConfig<TSchemaConfig, ApplyURLBasedConfig<TSchemaConfig, TSchemaRouteKeys>>;
|
664
1172
|
type InferAllRouteKeys<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TSchemaConfig extends CallApiSchemaConfig> = ApplySchemaConfiguration<TSchemaConfig, Extract<keyof TBaseSchemaRoutes, string>>;
|
665
1173
|
type InferInitURL<TBaseSchemaRoutes extends BaseCallApiSchemaRoutes, TSchemaConfig extends CallApiSchemaConfig> = keyof TBaseSchemaRoutes extends never ? InitURLOrURLObject : InferAllRouteKeys<TBaseSchemaRoutes, TSchemaConfig>;
|
@@ -785,59 +1293,183 @@ type CallApiRequestOptionsForHooks = Omit<CallApiRequestOptions, "headers"> & {
|
|
785
1293
|
headers: Record<string, string | undefined>;
|
786
1294
|
};
|
787
1295
|
type FetchImpl = UnmaskType<(input: string | Request | URL, init?: RequestInit) => Promise<Response>>;
|
788
|
-
type SharedExtraOptions<TData = DefaultDataType, TErrorData = DefaultDataType, TResultMode extends ResultModeUnion = ResultModeUnion, TThrowOnError extends ThrowOnErrorUnion = DefaultThrowOnError, TResponseType extends ResponseTypeUnion = ResponseTypeUnion, TPluginArray extends CallApiPlugin[] = DefaultPluginArray> = DedupeOptions & HooksOrHooksArray<TData, TErrorData, Partial<InferPluginOptions<TPluginArray>>> & Partial<InferPluginOptions<TPluginArray>> & ResultModeOption<TErrorData, TResultMode> & RetryOptions<TErrorData> & ThrowOnErrorOption<TErrorData, TThrowOnError> & URLOptions & {
|
1296
|
+
type SharedExtraOptions<TData = DefaultDataType, TErrorData = DefaultDataType, TResultMode extends ResultModeUnion = ResultModeUnion, TThrowOnError extends ThrowOnErrorUnion = DefaultThrowOnError, TResponseType extends ResponseTypeUnion = ResponseTypeUnion, TPluginArray extends CallApiPlugin[] = DefaultPluginArray> = DedupeOptions & HookConfigOptions & HooksOrHooksArray<TData, TErrorData, Partial<InferPluginOptions<TPluginArray>>> & Partial<InferPluginOptions<TPluginArray>> & ResultModeOption<TErrorData, TResultMode> & RetryOptions<TErrorData> & ThrowOnErrorOption<TErrorData, TThrowOnError> & URLOptions & {
|
789
1297
|
/**
|
790
|
-
* Authorization header value.
|
1298
|
+
* Automatically add an Authorization header value.
|
1299
|
+
*
|
1300
|
+
* Supports multiple authentication patterns:
|
1301
|
+
* - String: Direct authorization header value
|
1302
|
+
* - Auth object: Structured authentication configuration
|
1303
|
+
* - null: Explicitly removes authorization
|
1304
|
+
*
|
1305
|
+
* @example
|
1306
|
+
* ```ts
|
1307
|
+
* // Bearer token authentication
|
1308
|
+
* auth: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
1309
|
+
*
|
1310
|
+
* // Basic authentication
|
1311
|
+
* auth: "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
|
1312
|
+
*
|
1313
|
+
* // Using Auth object for dynamic authentication
|
1314
|
+
* auth: {
|
1315
|
+
* type: "bearer",
|
1316
|
+
* token: () => getAccessToken()
|
1317
|
+
* }
|
1318
|
+
*
|
1319
|
+
* // Remove inherited auth from base config
|
1320
|
+
* auth: null
|
1321
|
+
* ```
|
791
1322
|
*/
|
792
1323
|
auth?: string | Auth | null;
|
793
1324
|
/**
|
794
|
-
* Base URL for
|
1325
|
+
* Base URL for all API requests. Will be prepended to relative URLs.
|
1326
|
+
*
|
1327
|
+
* @example
|
1328
|
+
* ```ts
|
1329
|
+
* // Set base URL for all requests
|
1330
|
+
* baseURL: "https://api.example.com/v1"
|
1331
|
+
*
|
1332
|
+
* // Then use relative URLs in requests
|
1333
|
+
* callApi("/users") // → https://api.example.com/v1/users
|
1334
|
+
* callApi("/posts/123") // → https://api.example.com/v1/posts/123
|
1335
|
+
*
|
1336
|
+
* // Environment-specific base URLs
|
1337
|
+
* baseURL: process.env.NODE_ENV === "production"
|
1338
|
+
* ? "https://api.example.com"
|
1339
|
+
* : "http://localhost:3000/api"
|
1340
|
+
* ```
|
795
1341
|
*/
|
796
1342
|
baseURL?: string;
|
797
1343
|
/**
|
798
|
-
* Custom function to serialize
|
1344
|
+
* Custom function to serialize request body objects into strings.
|
1345
|
+
*
|
1346
|
+
* Useful for custom serialization formats or when the default JSON
|
1347
|
+
* serialization doesn't meet your needs.
|
1348
|
+
*
|
1349
|
+
* @example
|
1350
|
+
* ```ts
|
1351
|
+
* // Custom form data serialization
|
1352
|
+
* bodySerializer: (data) => {
|
1353
|
+
* const formData = new URLSearchParams();
|
1354
|
+
* Object.entries(data).forEach(([key, value]) => {
|
1355
|
+
* formData.append(key, String(value));
|
1356
|
+
* });
|
1357
|
+
* return formData.toString();
|
1358
|
+
* }
|
1359
|
+
*
|
1360
|
+
* // XML serialization
|
1361
|
+
* bodySerializer: (data) => {
|
1362
|
+
* return `<request>${Object.entries(data)
|
1363
|
+
* .map(([key, value]) => `<${key}>${value}</${key}>`)
|
1364
|
+
* .join('')}</request>`;
|
1365
|
+
* }
|
1366
|
+
*
|
1367
|
+
* // Custom JSON with specific formatting
|
1368
|
+
* bodySerializer: (data) => JSON.stringify(data, null, 2)
|
1369
|
+
* ```
|
799
1370
|
*/
|
800
1371
|
bodySerializer?: (bodyData: Record<string, unknown>) => string;
|
801
1372
|
/**
|
802
|
-
* Whether
|
1373
|
+
* Whether to clone the response so it can be read multiple times.
|
1374
|
+
*
|
1375
|
+
* By default, response streams can only be consumed once. Enable this when you need
|
1376
|
+
* to read the response in multiple places (e.g., in hooks and main code).
|
1377
|
+
*
|
803
1378
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/Response/clone
|
804
1379
|
* @default false
|
805
1380
|
*/
|
806
1381
|
cloneResponse?: boolean;
|
807
1382
|
/**
|
808
|
-
* Custom fetch implementation
|
1383
|
+
* Custom fetch implementation to replace the default fetch function.
|
1384
|
+
*
|
1385
|
+
* Useful for testing, adding custom behavior, or using alternative HTTP clients
|
1386
|
+
* that implement the fetch API interface.
|
1387
|
+
*
|
1388
|
+
* @example
|
1389
|
+
* ```ts
|
1390
|
+
* // Use node-fetch in Node.js environments
|
1391
|
+
* import fetch from 'node-fetch';
|
1392
|
+
*
|
1393
|
+
* // Mock fetch for testing
|
1394
|
+
* customFetchImpl: async (url, init) => {
|
1395
|
+
* return new Response(JSON.stringify({ mocked: true }), {
|
1396
|
+
* status: 200,
|
1397
|
+
* headers: { 'Content-Type': 'application/json' }
|
1398
|
+
* });
|
1399
|
+
* }
|
1400
|
+
*
|
1401
|
+
* // Add custom logging to all requests
|
1402
|
+
* customFetchImpl: async (url, init) => {
|
1403
|
+
* console.log(`Fetching: ${url}`);
|
1404
|
+
* const response = await fetch(url, init);
|
1405
|
+
* console.log(`Response: ${response.status}`);
|
1406
|
+
* return response;
|
1407
|
+
* }
|
1408
|
+
*
|
1409
|
+
* // Use with custom HTTP client
|
1410
|
+
* customFetchImpl: async (url, init) => {
|
1411
|
+
* // Convert to your preferred HTTP client format
|
1412
|
+
* return await customHttpClient.request({
|
1413
|
+
* url: url.toString(),
|
1414
|
+
* method: init?.method || 'GET',
|
1415
|
+
* headers: init?.headers,
|
1416
|
+
* body: init?.body
|
1417
|
+
* });
|
1418
|
+
* }
|
1419
|
+
* ```
|
809
1420
|
*/
|
810
1421
|
customFetchImpl?: FetchImpl;
|
811
1422
|
/**
|
812
|
-
* Default HTTP error message
|
1423
|
+
* Default HTTP error message when server doesn't provide one.
|
1424
|
+
*
|
1425
|
+
* Can be a static string or a function that receives error context
|
1426
|
+
* to generate dynamic error messages based on the response.
|
1427
|
+
*
|
813
1428
|
* @default "Failed to fetch data from server!"
|
1429
|
+
*
|
1430
|
+
* @example
|
1431
|
+
* ```ts
|
1432
|
+
* // Static error message
|
1433
|
+
* defaultHTTPErrorMessage: "API request failed. Please try again."
|
1434
|
+
*
|
1435
|
+
* // Dynamic error message based on status code
|
1436
|
+
* defaultHTTPErrorMessage: ({ response }) => {
|
1437
|
+
* switch (response.status) {
|
1438
|
+
* case 401: return "Authentication required. Please log in.";
|
1439
|
+
* case 403: return "Access denied. Insufficient permissions.";
|
1440
|
+
* case 404: return "Resource not found.";
|
1441
|
+
* case 429: return "Too many requests. Please wait and try again.";
|
1442
|
+
* case 500: return "Server error. Please contact support.";
|
1443
|
+
* default: return `Request failed with status ${response.status}`;
|
1444
|
+
* }
|
1445
|
+
* }
|
1446
|
+
*
|
1447
|
+
* // Include error data in message
|
1448
|
+
* defaultHTTPErrorMessage: ({ errorData, response }) => {
|
1449
|
+
* const userMessage = errorData?.message || "Unknown error occurred";
|
1450
|
+
* return `${userMessage} (Status: ${response.status})`;
|
1451
|
+
* }
|
1452
|
+
* ```
|
814
1453
|
*/
|
815
1454
|
defaultHTTPErrorMessage?: string | ((context: Pick<HTTPError<TErrorData>, "errorData" | "response">) => string);
|
816
1455
|
/**
|
817
|
-
*
|
1456
|
+
* Forces calculation of total byte size from request/response body streams.
|
1457
|
+
*
|
1458
|
+
* Useful when the Content-Length header is missing or incorrect, and you need
|
1459
|
+
* accurate size information for progress tracking or bandwidth monitoring.
|
1460
|
+
*
|
818
1461
|
* @default false
|
1462
|
+
*
|
819
1463
|
*/
|
820
1464
|
forcefullyCalculateStreamSize?: boolean | {
|
821
1465
|
request?: boolean;
|
822
1466
|
response?: boolean;
|
823
1467
|
};
|
824
1468
|
/**
|
825
|
-
*
|
826
|
-
* - If set to "parallel", main and plugin hooks will be executed in parallel.
|
827
|
-
* - If set to "sequential", the plugin hooks will be executed first, followed by the main hook.
|
828
|
-
* @default "parallel"
|
829
|
-
*/
|
830
|
-
mergedHooksExecutionMode?: "parallel" | "sequential";
|
831
|
-
/**
|
832
|
-
* - Controls what order in which the composed hooks execute
|
833
|
-
* @default "mainHooksAfterPlugins"
|
834
|
-
*/
|
835
|
-
mergedHooksExecutionOrder?: "mainHooksAfterPlugins" | "mainHooksBeforePlugins";
|
836
|
-
/**
|
837
|
-
* - An optional field you can fill with additional information,
|
838
|
-
* to associate with the request, typically used for logging or tracing.
|
1469
|
+
* Optional metadata field for associating additional information with requests.
|
839
1470
|
*
|
840
|
-
*
|
1471
|
+
* Useful for logging, tracing, or handling specific cases in shared interceptors.
|
1472
|
+
* The meta object is passed through to all hooks and can be accessed in error handlers.
|
841
1473
|
*
|
842
1474
|
* @example
|
843
1475
|
* ```ts
|
@@ -854,61 +1486,321 @@ type SharedExtraOptions<TData = DefaultDataType, TErrorData = DefaultDataType, T
|
|
854
1486
|
* url: "https://example.com/api/data",
|
855
1487
|
* meta: { userId: "123" },
|
856
1488
|
* });
|
1489
|
+
*
|
1490
|
+
* // Use case: Request tracking
|
1491
|
+
* const result = await callMainApi({
|
1492
|
+
* url: "https://example.com/api/data",
|
1493
|
+
* meta: {
|
1494
|
+
* requestId: generateId(),
|
1495
|
+
* source: "user-dashboard",
|
1496
|
+
* priority: "high"
|
1497
|
+
* }
|
1498
|
+
* });
|
1499
|
+
*
|
1500
|
+
* // Use case: Feature flags
|
1501
|
+
* const client = callApi.create({
|
1502
|
+
* baseURL: "https://api.example.com",
|
1503
|
+
* meta: {
|
1504
|
+
* features: ["newUI", "betaFeature"],
|
1505
|
+
* experiment: "variantA"
|
1506
|
+
* }
|
1507
|
+
* });
|
857
1508
|
* ```
|
858
1509
|
*/
|
859
1510
|
meta?: GlobalMeta;
|
860
1511
|
/**
|
861
|
-
* Custom function to parse
|
1512
|
+
* Custom function to parse response strings into objects.
|
1513
|
+
*
|
1514
|
+
* Useful when the API returns non-JSON responses or when you need
|
1515
|
+
* custom parsing logic for specific response formats.
|
1516
|
+
*
|
1517
|
+
* @example
|
1518
|
+
* ```ts
|
1519
|
+
* // Parse XML responses
|
1520
|
+
* responseParser: (responseString) => {
|
1521
|
+
* const parser = new DOMParser();
|
1522
|
+
* const doc = parser.parseFromString(responseString, "text/xml");
|
1523
|
+
* return xmlToObject(doc);
|
1524
|
+
* }
|
1525
|
+
*
|
1526
|
+
* // Parse CSV responses
|
1527
|
+
* responseParser: (responseString) => {
|
1528
|
+
* const lines = responseString.split('\n');
|
1529
|
+
* const headers = lines[0].split(',');
|
1530
|
+
* const data = lines.slice(1).map(line => {
|
1531
|
+
* const values = line.split(',');
|
1532
|
+
* return headers.reduce((obj, header, index) => {
|
1533
|
+
* obj[header] = values[index];
|
1534
|
+
* return obj;
|
1535
|
+
* }, {});
|
1536
|
+
* });
|
1537
|
+
* return { data };
|
1538
|
+
* }
|
1539
|
+
*
|
1540
|
+
* // Parse custom format with error handling
|
1541
|
+
* responseParser: async (responseString) => {
|
1542
|
+
* try {
|
1543
|
+
* // Custom parsing logic
|
1544
|
+
* const parsed = customFormat.parse(responseString);
|
1545
|
+
* return { success: true, data: parsed };
|
1546
|
+
* } catch (error) {
|
1547
|
+
* return { success: false, error: error.message };
|
1548
|
+
* }
|
1549
|
+
* }
|
1550
|
+
* ```
|
862
1551
|
*/
|
863
1552
|
responseParser?: (responseString: string) => Awaitable<Record<string, unknown>>;
|
864
1553
|
/**
|
865
|
-
* Expected response type,
|
1554
|
+
* Expected response type, determines how the response body is parsed.
|
1555
|
+
*
|
1556
|
+
* Different response types trigger different parsing methods:
|
1557
|
+
* - **"json"**: Parses as JSON using response.json()
|
1558
|
+
* - **"text"**: Returns as plain text using response.text()
|
1559
|
+
* - **"blob"**: Returns as Blob using response.blob()
|
1560
|
+
* - **"arrayBuffer"**: Returns as ArrayBuffer using response.arrayBuffer()
|
1561
|
+
* - **"stream"**: Returns the response body stream directly
|
1562
|
+
*
|
866
1563
|
* @default "json"
|
1564
|
+
*
|
1565
|
+
* @example
|
1566
|
+
* ```ts
|
1567
|
+
* // JSON API responses (default)
|
1568
|
+
* responseType: "json"
|
1569
|
+
*
|
1570
|
+
* // Plain text responses
|
1571
|
+
* responseType: "text"
|
1572
|
+
* // Usage: const csvData = await callApi("/export.csv", { responseType: "text" });
|
1573
|
+
*
|
1574
|
+
* // File downloads
|
1575
|
+
* responseType: "blob"
|
1576
|
+
* // Usage: const file = await callApi("/download/file.pdf", { responseType: "blob" });
|
1577
|
+
*
|
1578
|
+
* // Binary data
|
1579
|
+
* responseType: "arrayBuffer"
|
1580
|
+
* // Usage: const buffer = await callApi("/binary-data", { responseType: "arrayBuffer" });
|
1581
|
+
*
|
1582
|
+
* // Streaming responses
|
1583
|
+
* responseType: "stream"
|
1584
|
+
* // Usage: const stream = await callApi("/large-dataset", { responseType: "stream" });
|
1585
|
+
* ```
|
867
1586
|
*/
|
868
1587
|
responseType?: TResponseType;
|
869
1588
|
/**
|
870
|
-
*
|
871
|
-
*
|
1589
|
+
* Controls what data is included in the returned result object.
|
1590
|
+
*
|
1591
|
+
* Different modes return different combinations of data, error, and response:
|
1592
|
+
* - **"all"**: Returns { data, error, response } - complete result information
|
1593
|
+
* - **"allWithException"**: Returns { data, error, response } but throws on errors
|
1594
|
+
* - **"onlySuccess"**: Returns only data (null for errors), never throws
|
1595
|
+
* - **"onlySuccessWithException"**: Returns only data but throws on errors
|
1596
|
+
*
|
872
1597
|
* @default "all"
|
1598
|
+
*
|
1599
|
+
* @example
|
1600
|
+
* ```ts
|
1601
|
+
* // Complete result with all information (default)
|
1602
|
+
* resultMode: "all"
|
1603
|
+
* const { data, error, response } = await callApi("/users");
|
1604
|
+
* if (error) {
|
1605
|
+
* console.error("Request failed:", error);
|
1606
|
+
* } else {
|
1607
|
+
* console.log("Users:", data);
|
1608
|
+
* }
|
1609
|
+
*
|
1610
|
+
* // Complete result but throws on errors
|
1611
|
+
* resultMode: "allWithException"
|
1612
|
+
* try {
|
1613
|
+
* const { data, response } = await callApi("/users", { resultMode: "allWithException" });
|
1614
|
+
* console.log("Users:", data);
|
1615
|
+
* } catch (error) {
|
1616
|
+
* console.error("Request failed:", error);
|
1617
|
+
* }
|
1618
|
+
*
|
1619
|
+
* // Only data, returns null on errors
|
1620
|
+
* resultMode: "onlySuccess"
|
1621
|
+
* const users = await callApi("/users", { resultMode: "onlySuccess" });
|
1622
|
+
* if (users) {
|
1623
|
+
* console.log("Users:", users);
|
1624
|
+
* } else {
|
1625
|
+
* console.log("Request failed");
|
1626
|
+
* }
|
1627
|
+
*
|
1628
|
+
* // Only data with null, throws on errors
|
1629
|
+
* resultMode: "onlySuccessWithException"
|
1630
|
+
* try {
|
1631
|
+
* const users = await callApi("/users", { resultMode: "onlySuccessWithException" });
|
1632
|
+
* console.log("Users:", users);
|
1633
|
+
* } catch (error) {
|
1634
|
+
* console.error("Request failed:", error);
|
1635
|
+
* }
|
1636
|
+
* ```
|
873
1637
|
*/
|
874
1638
|
resultMode?: TResultMode;
|
875
1639
|
/**
|
876
|
-
*
|
877
|
-
*
|
1640
|
+
* Controls whether errors are thrown as exceptions or returned in the result.
|
1641
|
+
*
|
1642
|
+
* Can be a boolean or a function that receives the error and decides whether to throw.
|
1643
|
+
* When true, errors are thrown as exceptions instead of being returned in the result object.
|
1644
|
+
*
|
878
1645
|
* @default false
|
1646
|
+
*
|
1647
|
+
* @example
|
1648
|
+
* ```ts
|
1649
|
+
* // Always throw errors
|
1650
|
+
* throwOnError: true
|
1651
|
+
* try {
|
1652
|
+
* const data = await callApi("/users");
|
1653
|
+
* console.log("Users:", data);
|
1654
|
+
* } catch (error) {
|
1655
|
+
* console.error("Request failed:", error);
|
1656
|
+
* }
|
1657
|
+
*
|
1658
|
+
* // Never throw errors (default)
|
1659
|
+
* throwOnError: false
|
1660
|
+
* const { data, error } = await callApi("/users");
|
1661
|
+
* if (error) {
|
1662
|
+
* console.error("Request failed:", error);
|
1663
|
+
* }
|
1664
|
+
*
|
1665
|
+
* // Conditionally throw based on error type
|
1666
|
+
* throwOnError: (error) => {
|
1667
|
+
* // Throw on client errors (4xx) but not server errors (5xx)
|
1668
|
+
* return error.response?.status >= 400 && error.response?.status < 500;
|
1669
|
+
* }
|
1670
|
+
*
|
1671
|
+
* // Throw only on specific status codes
|
1672
|
+
* throwOnError: (error) => {
|
1673
|
+
* const criticalErrors = [401, 403, 404];
|
1674
|
+
* return criticalErrors.includes(error.response?.status);
|
1675
|
+
* }
|
1676
|
+
*
|
1677
|
+
* // Throw on validation errors but not network errors
|
1678
|
+
* throwOnError: (error) => {
|
1679
|
+
* return error.type === "validation";
|
1680
|
+
* }
|
1681
|
+
* ```
|
879
1682
|
*/
|
880
1683
|
throwOnError?: TThrowOnError;
|
881
1684
|
/**
|
882
|
-
* Request timeout in milliseconds
|
1685
|
+
* Request timeout in milliseconds. Request will be aborted if it takes longer.
|
1686
|
+
*
|
1687
|
+
* Useful for preventing requests from hanging indefinitely and providing
|
1688
|
+
* better user experience with predictable response times.
|
1689
|
+
*
|
1690
|
+
* @example
|
1691
|
+
* ```ts
|
1692
|
+
* // 5 second timeout
|
1693
|
+
* timeout: 5000
|
1694
|
+
*
|
1695
|
+
* // Different timeouts for different endpoints
|
1696
|
+
* const quickApi = createFetchClient({ timeout: 3000 }); // 3s for fast endpoints
|
1697
|
+
* const slowApi = createFetchClient({ timeout: 30000 }); // 30s for slow operations
|
1698
|
+
*
|
1699
|
+
* // Per-request timeout override
|
1700
|
+
* await callApi("/quick-data", { timeout: 1000 });
|
1701
|
+
* await callApi("/slow-report", { timeout: 60000 });
|
1702
|
+
*
|
1703
|
+
* // No timeout (use with caution)
|
1704
|
+
* timeout: 0
|
1705
|
+
* ```
|
883
1706
|
*/
|
884
1707
|
timeout?: number;
|
885
1708
|
};
|
886
1709
|
type BaseCallApiExtraOptions<TBaseData = DefaultDataType, TBaseErrorData = DefaultDataType, TBaseResultMode extends ResultModeUnion = ResultModeUnion, TBaseThrowOnError extends ThrowOnErrorUnion = DefaultThrowOnError, TBaseResponseType extends ResponseTypeUnion = ResponseTypeUnion, TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TBaseSchemaAndConfig extends BaseCallApiSchemaAndConfig = BaseCallApiSchemaAndConfig> = SharedExtraOptions<TBaseData, TBaseErrorData, TBaseResultMode, TBaseThrowOnError, TBaseResponseType, TBasePluginArray> & {
|
887
1710
|
/**
|
888
|
-
*
|
1711
|
+
* Array of base CallApi plugins to extend library functionality.
|
1712
|
+
*
|
1713
|
+
* Base plugins are applied to all instances created from this base configuration
|
1714
|
+
* and provide foundational functionality like authentication, logging, or caching.
|
1715
|
+
*
|
1716
|
+
* @example
|
1717
|
+
* ```ts
|
1718
|
+
* // Add logging plugin
|
1719
|
+
*
|
1720
|
+
* // Create base client with common plugins
|
1721
|
+
* const callApi = createFetchClient({
|
1722
|
+
* baseURL: "https://api.example.com",
|
1723
|
+
* plugins: [loggerPlugin({ enabled: true })]
|
1724
|
+
* });
|
1725
|
+
*
|
1726
|
+
* // All requests inherit base plugins
|
1727
|
+
* await callApi("/users");
|
1728
|
+
* await callApi("/posts");
|
1729
|
+
*
|
1730
|
+
* ```
|
889
1731
|
*/
|
890
1732
|
plugins?: TBasePluginArray;
|
891
1733
|
/**
|
892
|
-
* Base schemas for the client.
|
1734
|
+
* Base validation schemas for the client configuration.
|
1735
|
+
*
|
1736
|
+
* Defines validation rules for requests and responses that apply to all
|
1737
|
+
* instances created from this base configuration. Provides type safety
|
1738
|
+
* and runtime validation for API interactions.
|
893
1739
|
*/
|
894
1740
|
schema?: TBaseSchemaAndConfig;
|
895
1741
|
/**
|
896
|
-
*
|
897
|
-
* Use this when you need manual control over how configs are combined.
|
1742
|
+
* Controls which configuration parts skip automatic merging between base and instance configs.
|
898
1743
|
*
|
899
|
-
*
|
900
|
-
*
|
901
|
-
*
|
902
|
-
* - `"request"` - Disables automatic merging of request only
|
1744
|
+
* By default, CallApi automatically merges base configuration with instance configuration.
|
1745
|
+
* This option allows you to disable automatic merging for specific parts when you need
|
1746
|
+
* manual control over how configurations are combined.
|
903
1747
|
*
|
904
|
-
*
|
1748
|
+
* @enum
|
1749
|
+
* - **"all"**: Disables automatic merging for both request options and extra options
|
1750
|
+
* - **"options"**: Disables automatic merging of extra options only (hooks, plugins, etc.)
|
1751
|
+
* - **"request"**: Disables automatic merging of request options only (headers, body, etc.)
|
905
1752
|
*
|
1753
|
+
* @example
|
906
1754
|
* ```ts
|
1755
|
+
* // Skip all automatic merging - full manual control
|
1756
|
+
* const client = callApi.create((ctx) => ({
|
1757
|
+
* skipAutoMergeFor: "all",
|
1758
|
+
*
|
1759
|
+
* // Manually decide what to merge
|
1760
|
+
* baseURL: ctx.options.baseURL, // Keep base URL
|
1761
|
+
* timeout: 5000, // Override timeout
|
1762
|
+
* headers: {
|
1763
|
+
* ...ctx.request.headers, // Merge headers manually
|
1764
|
+
* "X-Custom": "value" // Add custom header
|
1765
|
+
* }
|
1766
|
+
* }));
|
1767
|
+
*
|
1768
|
+
* // Skip options merging - manual plugin/hook control
|
1769
|
+
* const client = callApi.create((ctx) => ({
|
1770
|
+
* skipAutoMergeFor: "options",
|
1771
|
+
*
|
1772
|
+
* // Manually control which plugins to use
|
1773
|
+
* plugins: [
|
1774
|
+
* ...ctx.options.plugins?.filter(p => p.name !== "unwanted") || [],
|
1775
|
+
* customPlugin
|
1776
|
+
* ],
|
1777
|
+
*
|
1778
|
+
* // Request options still auto-merge
|
1779
|
+
* method: "POST"
|
1780
|
+
* }));
|
1781
|
+
*
|
1782
|
+
* // Skip request merging - manual request control
|
1783
|
+
* const client = callApi.create((ctx) => ({
|
1784
|
+
* skipAutoMergeFor: "request",
|
1785
|
+
*
|
1786
|
+
* // Extra options still auto-merge (plugins, hooks, etc.)
|
1787
|
+
*
|
1788
|
+
* // Manually control request options
|
1789
|
+
* headers: {
|
1790
|
+
* "Content-Type": "application/json",
|
1791
|
+
* // Don't merge base headers
|
1792
|
+
* },
|
1793
|
+
* method: ctx.request.method || "GET"
|
1794
|
+
* }));
|
1795
|
+
*
|
1796
|
+
* // Use case: Conditional merging based on request
|
907
1797
|
* const client = createFetchClient((ctx) => ({
|
908
1798
|
* skipAutoMergeFor: "options",
|
909
1799
|
*
|
910
|
-
* //
|
911
|
-
*
|
1800
|
+
* // Only use auth plugin for protected routes
|
1801
|
+
* plugins: ctx.initURL.includes("/protected/")
|
1802
|
+
* ? [...(ctx.options.plugins || []), authPlugin]
|
1803
|
+
* : ctx.options.plugins?.filter(p => p.name !== "auth") || []
|
912
1804
|
* }));
|
913
1805
|
* ```
|
914
1806
|
*/
|
@@ -916,20 +1808,35 @@ type BaseCallApiExtraOptions<TBaseData = DefaultDataType, TBaseErrorData = Defau
|
|
916
1808
|
};
|
917
1809
|
type CallApiExtraOptions<TData = DefaultDataType, TErrorData = DefaultDataType, TResultMode extends ResultModeUnion = ResultModeUnion, TThrowOnError extends ThrowOnErrorUnion = DefaultThrowOnError, TResponseType extends ResponseTypeUnion = ResponseTypeUnion, TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TPluginArray extends CallApiPlugin[] = DefaultPluginArray, TBaseSchemaRoutes extends BaseCallApiSchemaRoutes = BaseCallApiSchemaRoutes, TSchema extends CallApiSchema = CallApiSchema, TBaseSchemaConfig extends CallApiSchemaConfig = CallApiSchemaConfig, TSchemaConfig extends CallApiSchemaConfig = CallApiSchemaConfig, TCurrentRouteSchemaKey extends string = string> = SharedExtraOptions<TData, TErrorData, TResultMode, TThrowOnError, TResponseType, TPluginArray> & {
|
918
1810
|
/**
|
919
|
-
*
|
1811
|
+
* Array of instance-specific CallApi plugins or a function to configure plugins.
|
1812
|
+
*
|
1813
|
+
* Instance plugins are added to the base plugins and provide functionality
|
1814
|
+
* specific to this particular API instance. Can be a static array or a function
|
1815
|
+
* that receives base plugins and returns the instance plugins.
|
1816
|
+
*
|
920
1817
|
*/
|
921
1818
|
plugins?: TPluginArray | ((context: {
|
922
1819
|
basePlugins: Writeable<TBasePluginArray, "deep">;
|
923
1820
|
}) => TPluginArray);
|
924
1821
|
/**
|
925
|
-
*
|
1822
|
+
* Instance-specific validation schemas or a function to configure schemas.
|
1823
|
+
*
|
1824
|
+
* Defines validation rules specific to this API instance, extending or
|
1825
|
+
* overriding base schemas. Can be a static schema object or a function
|
1826
|
+
* that receives base schema context and returns instance schemas.
|
1827
|
+
*
|
926
1828
|
*/
|
927
1829
|
schema?: TSchema | ((context: {
|
928
1830
|
baseSchema: Writeable<TBaseSchemaRoutes, "deep">;
|
929
1831
|
currentRouteSchema: GetCurrentRouteSchema<TBaseSchemaRoutes, TCurrentRouteSchemaKey>;
|
930
1832
|
}) => TSchema);
|
931
1833
|
/**
|
932
|
-
*
|
1834
|
+
* Instance-specific schema configuration or a function to configure schema behavior.
|
1835
|
+
*
|
1836
|
+
* Controls how validation schemas are applied and behave for this specific
|
1837
|
+
* API instance. Can override base schema configuration or extend it with
|
1838
|
+
* instance-specific validation rules.
|
1839
|
+
*
|
933
1840
|
*/
|
934
1841
|
schemaConfig?: TSchemaConfig | ((context: {
|
935
1842
|
baseSchemaConfig: Writeable<TBaseSchemaConfig, "deep">;
|
@@ -946,4 +1853,4 @@ type CallApiParameters<TData = DefaultDataType, TErrorData = DefaultDataType, TR
|
|
946
1853
|
type CallApiResult<TData, TErrorData, TResultMode extends ResultModeUnion, TThrowOnError extends ThrowOnErrorUnion, TResponseType extends ResponseTypeUnion> = Promise<GetCallApiResult<TData, TErrorData, TResultMode, TThrowOnError, TResponseType>>;
|
947
1854
|
//#endregion
|
948
1855
|
export { AnyFunction, AnyString, ApplyStrictConfig, ApplyURLBasedConfig, BaseCallApiConfig, BaseCallApiExtraOptions, BaseCallApiSchemaAndConfig, BaseCallApiSchemaRoutes, CallApiConfig, CallApiExtraOptions, CallApiExtraOptionsForHooks, CallApiParameters, CallApiPlugin, CallApiRequestOptions, CallApiRequestOptionsForHooks, CallApiResult, CallApiResultErrorVariant, CallApiResultSuccessVariant, CallApiSchema, CallApiSchemaConfig, DedupeOptions, DefaultDataType, DefaultPluginArray, DefaultThrowOnError, ErrorContext, GetCurrentRouteSchema, GetCurrentRouteSchemaKey, HTTPError, Hooks, HooksOrHooksArray, InferInitURL, InferParamsFromRoute, InferSchemaResult, PluginExtraOptions, PluginHooks, PluginHooksWithMoreOptions, PluginInitContext, PossibleHTTPError, PossibleJavaScriptError, PossibleJavaScriptOrValidationError, PossibleValidationError, Register, RequestContext, RequestStreamContext, ResponseContext, ResponseErrorContext, ResponseStreamContext, ResponseTypeUnion, ResultModeUnion, RetryOptions, SuccessContext, ThrowOnErrorUnion, URLOptions, ValidationError, Writeable };
|
949
|
-
//# sourceMappingURL=common-
|
1856
|
+
//# sourceMappingURL=common-C-kIzPcz.d.ts.map
|