@zayne-labs/callapi 1.8.20 → 1.8.21
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 +12 -12
- package/dist/esm/index.js +95 -22
- 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
package/dist/esm/index.d.ts
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
import { 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 } from "./common-
|
1
|
+
import { 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 } from "./common-C-kIzPcz.js";
|
2
2
|
|
3
3
|
//#region src/createFetchClient.d.ts
|
4
4
|
|
5
5
|
declare const createFetchClient: <TBaseData = DefaultDataType, TBaseErrorData = DefaultDataType, TBaseResultMode extends ResultModeUnion = ResultModeUnion, TBaseThrowOnError extends ThrowOnErrorUnion = DefaultThrowOnError, TBaseResponseType extends ResponseTypeUnion = ResponseTypeUnion, const TBaseSchemaAndConfig extends BaseCallApiSchemaAndConfig = BaseCallApiSchemaAndConfig, const TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TComputedBaseSchemaConfig extends CallApiSchemaConfig = NonNullable<Writeable<TBaseSchemaAndConfig["config"], "deep">>, TComputedBaseSchemaRoutes extends BaseCallApiSchemaRoutes = Writeable<TBaseSchemaAndConfig["routes"], "deep">>(initBaseConfig?: BaseCallApiConfig<TBaseData, TBaseErrorData, TBaseResultMode, TBaseThrowOnError, TBaseResponseType, TBaseSchemaAndConfig, TBasePluginArray>) => <TData = TBaseData, TErrorData = TBaseErrorData, TResultMode extends ResultModeUnion = TBaseResultMode, TThrowOnError extends ThrowOnErrorUnion = TBaseThrowOnError, TResponseType extends ResponseTypeUnion = 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>(initURL: TInitURL, config?: CallApiConfig<InferSchemaResult<TSchema["data"], TData>, InferSchemaResult<TSchema["errorData"], TErrorData>, TResultMode, TThrowOnError, TResponseType, TComputedBaseSchemaRoutes, TSchema, TComputedBaseSchemaConfig, TSchemaConfig, TInitURL, TCurrentRouteSchemaKey, TBasePluginArray, TPluginArray> | undefined) => CallApiResult<InferSchemaResult<TSchema["data"], TData>, InferSchemaResult<TSchema["errorData"], TErrorData>, TResultMode, TThrowOnError, TResponseType>;
|
6
|
-
declare const callApi: <TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = ResultModeUnion, TThrowOnError extends ThrowOnErrorUnion = boolean, TResponseType extends ResponseTypeUnion = ResponseTypeUnion, 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<{
|
6
|
+
declare const callApi: <TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = ResultModeUnion, TThrowOnError extends ThrowOnErrorUnion = boolean, TResponseType extends ResponseTypeUnion = ResponseTypeUnion, 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<{
|
7
7
|
[x: AnyString]: CallApiSchema | undefined;
|
8
|
-
"delete/"?: CallApiSchema | undefined;
|
9
|
-
"get/"?: CallApiSchema | undefined;
|
10
|
-
"patch/"?: CallApiSchema | undefined;
|
11
|
-
"post/"?: CallApiSchema | undefined;
|
12
|
-
"put/"?: CallApiSchema | undefined;
|
8
|
+
"@delete/"?: CallApiSchema | undefined;
|
9
|
+
"@get/"?: CallApiSchema | undefined;
|
10
|
+
"@patch/"?: CallApiSchema | undefined;
|
11
|
+
"@post/"?: CallApiSchema | undefined;
|
12
|
+
"@put/"?: CallApiSchema | undefined;
|
13
13
|
}, TCurrentRouteSchemaKey>, const TPluginArray extends CallApiPlugin[] = DefaultPluginArray>(initURL: TInitURL, config?: CallApiConfig<InferSchemaResult<TSchema["data"], TData>, InferSchemaResult<TSchema["errorData"], TErrorData>, TResultMode, TThrowOnError, TResponseType, {
|
14
14
|
[x: AnyString]: CallApiSchema | undefined;
|
15
|
-
"delete/"?: CallApiSchema | undefined;
|
16
|
-
"get/"?: CallApiSchema | undefined;
|
17
|
-
"patch/"?: CallApiSchema | undefined;
|
18
|
-
"post/"?: CallApiSchema | undefined;
|
19
|
-
"put/"?: CallApiSchema | undefined;
|
15
|
+
"@delete/"?: CallApiSchema | undefined;
|
16
|
+
"@get/"?: CallApiSchema | undefined;
|
17
|
+
"@patch/"?: CallApiSchema | undefined;
|
18
|
+
"@post/"?: CallApiSchema | undefined;
|
19
|
+
"@put/"?: CallApiSchema | undefined;
|
20
20
|
}, TSchema, CallApiSchemaConfig, TSchemaConfig, TInitURL, TCurrentRouteSchemaKey, DefaultPluginArray, TPluginArray> | undefined) => CallApiResult<InferSchemaResult<TSchema["data"], TData>, InferSchemaResult<TSchema["errorData"], TErrorData>, TResultMode, TThrowOnError, TResponseType>;
|
21
21
|
//#endregion
|
22
22
|
//#region src/defineHelpers.d.ts
|
package/dist/esm/index.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { HTTPError, ValidationError, createCombinedSignal, createTimeoutSignal, dedupeDefaults, defineEnum, deterministicHashFn, getBody, getFetchImpl, getHeaders, hookDefaults, isArray, isFunction, isHTTPErrorInstance, isObject, isPlainObject, isReadableStream, isString, isValidationErrorInstance, requestOptionDefaults, responseDefaults, retryDefaults, splitBaseConfig, splitConfig, toQueryString, waitFor } from "./utils-
|
1
|
+
import { HTTPError, ValidationError, createCombinedSignal, createTimeoutSignal, dedupeDefaults, defineEnum, deterministicHashFn, getBody, getFetchImpl, getHeaders, hookDefaults, isArray, isFunction, isHTTPErrorInstance, isObject, isPlainObject, isReadableStream, isString, isValidationErrorInstance, requestOptionDefaults, responseDefaults, retryDefaults, splitBaseConfig, splitConfig, toQueryString, waitFor } from "./utils-DZe23qYR.js";
|
2
2
|
|
3
3
|
//#region src/result.ts
|
4
4
|
const getResponseType = (response, parser) => ({
|
@@ -107,13 +107,13 @@ const hookRegistries = {
|
|
107
107
|
onSuccess: /* @__PURE__ */ new Set(),
|
108
108
|
onValidationError: /* @__PURE__ */ new Set()
|
109
109
|
};
|
110
|
-
const composeAllHooks = (hooksArray,
|
110
|
+
const composeAllHooks = (hooksArray, hooksExecutionMode) => {
|
111
111
|
const mergedHook = async (ctx) => {
|
112
|
-
if (
|
112
|
+
if (hooksExecutionMode === "sequential") {
|
113
113
|
for (const hook of hooksArray) await hook?.(ctx);
|
114
114
|
return;
|
115
115
|
}
|
116
|
-
if (
|
116
|
+
if (hooksExecutionMode === "parallel") await Promise.all(hooksArray.map((uniqueHook) => uniqueHook?.(ctx)));
|
117
117
|
};
|
118
118
|
return mergedHook;
|
119
119
|
};
|
@@ -241,21 +241,69 @@ const toStreamableResponse = async (context) => {
|
|
241
241
|
|
242
242
|
//#endregion
|
243
243
|
//#region src/dedupe.ts
|
244
|
-
const
|
245
|
-
|
244
|
+
const resolveDedupeKey = (dedupeKey, context) => {
|
245
|
+
if (isFunction(dedupeKey)) return dedupeKey(context);
|
246
|
+
return dedupeKey ?? null;
|
246
247
|
};
|
248
|
+
const getAbortErrorMessage = (dedupeKey, context) => {
|
249
|
+
if (dedupeKey) return `Duplicate request detected - Aborted previous request with key '${resolveDedupeKey(dedupeKey, context)}' as a new request was initiated`;
|
250
|
+
return `Duplicate request detected - Aborted previous request to '${context.options.fullURL}' as a new request with identical options was initiated`;
|
251
|
+
};
|
252
|
+
/**
|
253
|
+
* @description Creates and manages the deduplication strategy for a request.
|
254
|
+
*
|
255
|
+
* This is the core function that implements request deduplication logic. It handles
|
256
|
+
* cache management, key generation, and provides strategy-specific handlers for
|
257
|
+
* cancel and defer operations.
|
258
|
+
*
|
259
|
+
* **Key Responsibilities:**
|
260
|
+
* - Generates or resolves deduplication keys
|
261
|
+
* - Manages cache scope (local vs global)
|
262
|
+
* - Provides strategy handlers (cancel, defer)
|
263
|
+
* - Handles cache cleanup operations
|
264
|
+
*
|
265
|
+
* **Performance Optimizations:**
|
266
|
+
* - Includes a small delay (0.1ms) for simultaneous request handling
|
267
|
+
* - Lazy cache creation for global scopes
|
268
|
+
* - Efficient cache key resolution
|
269
|
+
*
|
270
|
+
* **Internal Usage:**
|
271
|
+
* This function is used internally by the CallApi system and is not intended
|
272
|
+
* for direct use in application code. It's called automatically during request
|
273
|
+
* processing when deduplication is enabled.
|
274
|
+
*
|
275
|
+
* @param context - Extended request context with deduplication-specific properties
|
276
|
+
* @returns Promise resolving to deduplication strategy handlers and metadata
|
277
|
+
*
|
278
|
+
* @example
|
279
|
+
* ```ts
|
280
|
+
* // This is used internally, but conceptually:
|
281
|
+
* const strategy = await createDedupeStrategy({
|
282
|
+
* ...requestContext,
|
283
|
+
* $GlobalRequestInfoCache: globalCache,
|
284
|
+
* $LocalRequestInfoCache: localCache,
|
285
|
+
* newFetchController: new AbortController()
|
286
|
+
* });
|
287
|
+
*
|
288
|
+
* // Use the returned strategy
|
289
|
+
* await strategy.handleRequestCancelStrategy();
|
290
|
+
* const response = await strategy.handleRequestDeferStrategy({ options, request });
|
291
|
+
* strategy.removeDedupeKeyFromCache();
|
292
|
+
* ```
|
293
|
+
*/
|
247
294
|
const createDedupeStrategy = async (context) => {
|
248
295
|
const { $GlobalRequestInfoCache: $GlobalRequestInfoCache$1, $LocalRequestInfoCache, baseConfig, config, newFetchController, options: globalOptions, request: globalRequest } = context;
|
249
296
|
const dedupeStrategy = globalOptions.dedupeStrategy ?? dedupeDefaults.dedupeStrategy;
|
250
|
-
const
|
297
|
+
const getDedupeKey = () => {
|
251
298
|
const shouldHaveDedupeKey = dedupeStrategy === "cancel" || dedupeStrategy === "defer";
|
252
299
|
if (!shouldHaveDedupeKey) return null;
|
300
|
+
if (globalOptions.dedupeKey) return resolveDedupeKey(globalOptions.dedupeKey, context);
|
253
301
|
return `${globalOptions.fullURL}-${deterministicHashFn({
|
254
302
|
options: globalOptions,
|
255
303
|
request: globalRequest
|
256
304
|
})}`;
|
257
305
|
};
|
258
|
-
const dedupeKey =
|
306
|
+
const dedupeKey = getDedupeKey();
|
259
307
|
const dedupeCacheScope = globalOptions.dedupeCacheScope ?? dedupeDefaults.dedupeCacheScope;
|
260
308
|
const dedupeCacheScopeKey = globalOptions.dedupeCacheScopeKey ?? dedupeDefaults.dedupeCacheScopeKey;
|
261
309
|
if (dedupeCacheScope === "global" && !$GlobalRequestInfoCache$1.has(dedupeCacheScopeKey)) $GlobalRequestInfoCache$1.set(dedupeCacheScopeKey, /* @__PURE__ */ new Map());
|
@@ -270,7 +318,7 @@ const createDedupeStrategy = async (context) => {
|
|
270
318
|
const handleRequestCancelStrategy = () => {
|
271
319
|
const shouldCancelRequest = prevRequestInfo && dedupeStrategy === "cancel";
|
272
320
|
if (!shouldCancelRequest) return;
|
273
|
-
const message = getAbortErrorMessage(globalOptions.dedupeKey,
|
321
|
+
const message = getAbortErrorMessage(globalOptions.dedupeKey, context);
|
274
322
|
const reason = new DOMException(message, "AbortError");
|
275
323
|
prevRequestInfo.controller.abort(reason);
|
276
324
|
return Promise.resolve();
|
@@ -486,8 +534,8 @@ const initializePlugins = async (context) => {
|
|
486
534
|
clonedHookRegistries[key].add(pluginHook);
|
487
535
|
}
|
488
536
|
};
|
489
|
-
const
|
490
|
-
if (
|
537
|
+
const hookRegistrationOrder = options.hooksRegistrationOrder ?? hookDefaults.hooksRegistrationOrder;
|
538
|
+
if (hookRegistrationOrder === "mainFirst") addMainHooks();
|
491
539
|
const { currentRouteSchemaKey, mainInitURL } = getCurrentRouteSchemaKeyAndMainInitURL({
|
492
540
|
baseExtraOptions: baseConfig,
|
493
541
|
extraOptions: config,
|
@@ -529,14 +577,14 @@ const initializePlugins = async (context) => {
|
|
529
577
|
if (!plugin.hooks) continue;
|
530
578
|
addPluginHooks(plugin.hooks);
|
531
579
|
}
|
532
|
-
if (
|
580
|
+
if (hookRegistrationOrder === "pluginsFirst") addMainHooks();
|
533
581
|
const resolvedHooks = {};
|
534
582
|
for (const [key, hookRegistry] of Object.entries(clonedHookRegistries)) {
|
535
583
|
if (hookRegistry.size === 0) continue;
|
536
584
|
const flattenedHookArray = [...hookRegistry].flat();
|
537
585
|
if (flattenedHookArray.length === 0) continue;
|
538
|
-
const
|
539
|
-
const composedHook = composeAllHooks(flattenedHookArray,
|
586
|
+
const hooksExecutionMode = options.hooksExecutionMode ?? hookDefaults.hooksExecutionMode;
|
587
|
+
const composedHook = composeAllHooks(flattenedHookArray, hooksExecutionMode);
|
540
588
|
resolvedHooks[key] = composedHook;
|
541
589
|
}
|
542
590
|
return {
|
@@ -623,14 +671,39 @@ const mergeUrlWithQuery = (url, query) => {
|
|
623
671
|
return `${url}${questionMark}${queryString}`;
|
624
672
|
};
|
625
673
|
/**
|
626
|
-
* @description
|
627
|
-
*
|
674
|
+
* @description Extracts the HTTP method from method-prefixed route patterns.
|
675
|
+
*
|
676
|
+
* Analyzes URLs that start with method modifiers (e.g., "@get/", "@post/") and extracts
|
677
|
+
* the HTTP method for use in API requests. This enables method specification directly
|
678
|
+
* in route definitions.
|
679
|
+
*
|
680
|
+
* @param initURL - The URL string to analyze for method modifiers
|
681
|
+
* @returns The extracted HTTP method (lowercase) if found, otherwise undefined
|
682
|
+
*
|
683
|
+
* @example
|
684
|
+
* ```typescript
|
685
|
+
* // Method extraction from prefixed routes
|
686
|
+
* extractMethodFromURL("@get/users"); // Returns: "get"
|
687
|
+
* extractMethodFromURL("@post/users"); // Returns: "post"
|
688
|
+
* extractMethodFromURL("@put/users/:id"); // Returns: "put"
|
689
|
+
* extractMethodFromURL("@delete/users/:id"); // Returns: "delete"
|
690
|
+
* extractMethodFromURL("@patch/users/:id"); // Returns: "patch"
|
691
|
+
*
|
692
|
+
* // No method modifier
|
693
|
+
* extractMethodFromURL("/users"); // Returns: undefined
|
694
|
+
* extractMethodFromURL("users"); // Returns: undefined
|
695
|
+
*
|
696
|
+
* // Invalid or unsupported methods
|
697
|
+
* extractMethodFromURL("@invalid/users"); // Returns: undefined
|
698
|
+
* extractMethodFromURL("@/users"); // Returns: undefined
|
628
699
|
*
|
629
|
-
*
|
630
|
-
*
|
700
|
+
* // Edge cases
|
701
|
+
* extractMethodFromURL(undefined); // Returns: undefined
|
702
|
+
* extractMethodFromURL(""); // Returns: undefined
|
703
|
+
* ```
|
631
704
|
*/
|
632
705
|
const extractMethodFromURL = (initURL) => {
|
633
|
-
if (!initURL
|
706
|
+
if (!initURL || initURL.startsWith("@")) return;
|
634
707
|
const method = initURL.split("@")[1]?.split("/")[0];
|
635
708
|
if (!method || !routeKeyMethods.includes(method)) return;
|
636
709
|
return method;
|
@@ -646,7 +719,7 @@ const normalizeURL = (initURL) => {
|
|
646
719
|
const normalizedURL = initURL.replace(`@${methodFromURL}/`, "/");
|
647
720
|
return normalizedURL;
|
648
721
|
};
|
649
|
-
const
|
722
|
+
const getFullAndNormalizedURL = (options) => {
|
650
723
|
const { baseURL, initURL, params, query } = options;
|
651
724
|
const normalizedInitURL = normalizeURL(initURL);
|
652
725
|
const urlWithMergedParams = mergeUrlWithParams(normalizedInitURL, params);
|
@@ -693,7 +766,7 @@ const createFetchClient = (initBaseConfig = {}) => {
|
|
693
766
|
options: mergedExtraOptions,
|
694
767
|
request: mergedRequestOptions
|
695
768
|
});
|
696
|
-
const { fullURL, normalizedInitURL } =
|
769
|
+
const { fullURL, normalizedInitURL } = getFullAndNormalizedURL({
|
697
770
|
baseURL: resolvedOptions.baseURL,
|
698
771
|
initURL: resolvedInitURL,
|
699
772
|
params: resolvedOptions.params,
|
@@ -864,7 +937,7 @@ const createFetchClient = (initBaseConfig = {}) => {
|
|
864
937
|
}
|
865
938
|
let message = error?.message;
|
866
939
|
if (error instanceof DOMException && error.name === "AbortError") {
|
867
|
-
message = getAbortErrorMessage(options.dedupeKey,
|
940
|
+
message = getAbortErrorMessage(options.dedupeKey, errorContext);
|
868
941
|
!shouldThrowOnError && console.error(`${error.name}:`, message);
|
869
942
|
}
|
870
943
|
if (error instanceof DOMException && error.name === "TimeoutError") {
|