@zayne-labs/callapi 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,267 +1,16 @@
1
- type AnyString = string & {
2
- placeholder?: never;
3
- };
4
- type AnyNumber = number & {
5
- placeholder?: never;
6
- };
7
- type Prettify<TObject> = {
8
- [Key in keyof TObject]: TObject[Key];
9
- } & NonNullable<unknown>;
10
-
11
- type ToQueryStringFn = {
12
- (params: ExtraOptions["query"]): string | null;
13
- (params: Required<ExtraOptions>["query"]): string;
14
- };
15
- declare const toQueryString: ToQueryStringFn;
16
- declare const fetchSpecificKeys: ("body" | "method" | "headers" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "priority" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window")[];
17
- declare const handleResponseType: <TResponse>(response: Response, parser?: Required<ExtraOptions>["responseParser"]) => {
18
- json: () => Promise<Record<string, unknown> | TResponse>;
19
- arrayBuffer: () => Promise<TResponse>;
20
- blob: () => Promise<TResponse>;
21
- formData: () => Promise<TResponse>;
22
- text: () => Promise<TResponse>;
23
- };
24
- declare const isHTTPError: <TErrorData>(error: ApiErrorVariant<TErrorData>["error"] | null) => error is {
25
- name: "HTTPError";
26
- errorData: TErrorData;
27
- message: string;
28
- };
29
- type ErrorDetails<TErrorResponse> = {
30
- errorData: TErrorResponse;
31
- response: Response;
32
- defaultErrorMessage: string;
33
- };
34
- type ErrorOptions = {
35
- cause?: unknown;
36
- };
37
- declare class HTTPError<TErrorResponse = Record<string, unknown>> extends Error {
38
- response: ErrorDetails<TErrorResponse>["response"];
39
- errorData: ErrorDetails<TErrorResponse>["errorData"];
40
- name: "HTTPError";
41
- isHTTPError: boolean;
42
- constructor(errorDetails: ErrorDetails<TErrorResponse>, errorOptions?: ErrorOptions);
43
- }
44
- declare const isHTTPErrorInstance: <TErrorResponse>(error: unknown) => error is HTTPError<TErrorResponse>;
45
-
46
- interface $RequestOptions extends Pick<FetchConfig, (typeof fetchSpecificKeys)[number]> {
47
- }
48
- interface ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = ResultModeUnion> {
49
- /** Optional body of the request, can be a object or any other supported body type. */
50
- body?: Record<string, unknown> | RequestInit["body"];
51
- /**
52
- * @description HTTP method for the request.
53
- * @default "GET"
54
- */
55
- method?: "GET" | "POST" | "PATCH" | "PUT" | "DELETE" | AnyString;
56
- /**
57
- * @description Query parameters to append to the URL.
58
- */
59
- query?: Record<string, string | number | boolean>;
60
- /**
61
- * @description Authorization header value.
62
- */
63
- auth?: string | {
64
- bearer: string;
65
- token?: never;
66
- } | {
67
- token: string;
68
- bearer?: never;
69
- };
70
- /**
71
- * @description Custom function to validate the response data.
72
- */
73
- responseValidator?: (data: unknown) => TData;
74
- /**
75
- * @description Custom function to serialize the body object into a string.
76
- */
77
- bodySerializer?: (bodyData: Record<string, unknown>) => string;
78
- /**
79
- * @description Custom function to parse the response string into a object.
80
- */
81
- responseParser?: (responseString: string) => Record<string, unknown>;
82
- /**
83
- * @description Mode of the result, can influence how results are handled or returned.
84
- * Can be set to "all" | "onlySuccess" | "onlyError" | "onlyResponse".
85
- * @default "all"
86
- */
87
- resultMode?: TResultMode;
88
- /**
89
- * @description If true, cancels previous unfinished requests to the same URL.
90
- * @default true
91
- */
92
- cancelRedundantRequests?: boolean;
93
- /**
94
- * @description Base URL to be prepended to all request URLs
95
- */
96
- baseURL?: string;
97
- /**
98
- * @description Request timeout in milliseconds
99
- */
100
- timeout?: number;
101
- /**
102
- * @description Default error message to use if none is provided from a response.
103
- * @default "Failed to fetch data from server!"
104
- */
105
- defaultErrorMessage?: string;
106
- /**
107
- * @description Whether to clone the response, so response.json and the like can used in the interceptors.
108
- * @default false
109
- */
110
- cloneResponse?: boolean;
111
- /**
112
- * If true or the function returns true, throws errors instead of returning them
113
- * The function is passed the error object and can be used to conditionally throw the error
114
- * @default false
115
- */
116
- throwOnError?: boolean | ((error?: Error | HTTPError<TErrorData>) => boolean);
117
- /**
118
- * @description Expected response type, affects how response is parsed
119
- * @default "json"
120
- */
121
- responseType?: keyof ReturnType<typeof handleResponseType>;
122
- /**
123
- * @description Number of retry attempts for failed requests
124
- * @default 0
125
- */
126
- retries?: number;
127
- /**
128
- * @description Delay between retries in milliseconds
129
- * @default 500
130
- */
131
- retryDelay?: number;
132
- /**
133
- * @description HTTP status codes that trigger a retry
134
- * @default [409, 425, 429, 500, 502, 503, 504]
135
- */
136
- retryCodes?: Array<409 | 425 | 429 | 500 | 502 | 503 | 504 | AnyNumber>;
137
- /**
138
- * HTTP methods that are allowed to retry
139
- * @default ["GET", "POST"]
140
- */
141
- retryMethods?: Array<"GET" | "POST" | AnyString>;
142
- /**
143
- * @description an optional field you can fill with additional information,
144
- * to associate with the request, typically used for logging or tracing.
145
- *
146
- * A good use case for this, would be to use the info to handle specific cases in any of the shared interceptors.
147
- * @example
148
- * ```ts
149
- * const callMainApi = callApi.create({
150
- * baseURL: "https://main-api.com",
151
- * onResponseError: ({ response, options }) => {
152
- * if (options.meta?.userId) {
153
- * console.error(`User ${options.meta.userId} made an error`);
154
- * }
155
- * },
156
- * });
157
- *
158
- * const response = await callMainApi({
159
- * url: "https://example.com/api/data",
160
- * meta: { userId: "123" },
161
- * });
162
- * ```
163
- */
164
- meta?: Record<string, unknown>;
165
- /** @description Interceptor to be called just before the request is made, allowing for modifications or additional operations. */
166
- onRequest?: (requestContext: {
167
- request: $RequestOptions;
168
- options: ExtraOptions;
169
- }) => void | Promise<void>;
170
- /** @description Interceptor to be called when an error occurs during the fetch request. */
171
- onRequestError?: (requestErrorContext: {
172
- error: Error;
173
- request: $RequestOptions;
174
- options: ExtraOptions;
175
- }) => void | Promise<void>;
176
- /** @description Interceptor to be called when a successful response is received from the api. */
177
- onResponse?: (responseContext: ResponseContext<TData>) => void | Promise<void>;
178
- /** @description Interceptor to be called when an error response is received from the api. */
179
- onResponseError?: (responseErrorContext: ResponseErrorContext<TErrorData>) => void | Promise<void>;
180
- /**
181
- * @description Interceptor to be called when an error occurs during the fetch request OR when an error response is received from the api
182
- * It is basically a combination of `onRequestError` and `onResponseError` interceptors
183
- */
184
- onError?: (anyErrorContext: ErrorContext<TErrorData>) => void | Promise<void>;
185
- }
186
- type ResponseContext<TData> = Prettify<{
187
- data: TData;
188
- response: Response;
189
- request: $RequestOptions;
190
- options: ExtraOptions;
191
- }>;
192
- type ResponseErrorContext<TErrorData> = Prettify<{
193
- errorData: TErrorData;
194
- response: Response;
195
- request: $RequestOptions;
196
- options: ExtraOptions;
197
- }>;
198
- type ErrorContext<TErrorData> = Prettify<{
199
- errorData?: TErrorData;
200
- error: null;
201
- response: Response;
202
- request: $RequestOptions;
203
- options: ExtraOptions;
204
- } | {
205
- error: Error;
206
- errorData?: null;
207
- response: null;
208
- request: $RequestOptions;
209
- options: ExtraOptions;
210
- }>;
211
- interface FetchConfig<TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = "all"> extends Omit<RequestInit, "method" | "body">, ExtraOptions<TData, TErrorData, TResultMode> {
212
- }
213
- type BaseConfig<TBaseData = unknown, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = "all"> = FetchConfig<TBaseData, TBaseErrorData, TBaseResultMode>;
214
- type ApiSuccessVariant<TData> = {
215
- data: TData;
216
- error: null;
217
- response: Response;
218
- };
219
- type PossibleErrorNames = {
220
- _: "AbortError" | "TimeoutError" | "SyntaxError" | "TypeError" | "Error" | "UnknownError";
221
- }["_"];
222
- type ApiErrorVariant<TErrorData> = {
223
- data: null;
224
- error: {
225
- name: "HTTPError";
226
- errorData: TErrorData;
227
- message: string;
228
- };
229
- response: Response;
230
- } | {
231
- data: null;
232
- error: {
233
- name: PossibleErrorNames;
234
- errorData: Error;
235
- message: string;
236
- };
237
- response: null;
238
- };
239
- type ResultModeMap<TData = unknown, TErrorData = unknown> = {
240
- all: ApiSuccessVariant<TData> | ApiErrorVariant<TErrorData>;
241
- onlySuccess: ApiSuccessVariant<TData>["data"];
242
- onlyError: ApiErrorVariant<TErrorData>["error"];
243
- onlyResponse: Response;
244
- };
245
- type ResultModeUnion = {
246
- _: {
247
- [Key in keyof ResultModeMap]: Key;
248
- }[keyof ResultModeMap];
249
- }["_"];
250
- type GetCallApiResult<TData, TErrorData, TResultMode extends ResultModeUnion> = ResultModeMap<TData, TErrorData>[TResultMode];
1
+ import { R as ResultModeUnion, B as BaseConfig, F as FetchConfig, G as GetCallApiResult } from './index-DDD_c4ys.cjs';
2
+ export { $ as $RequestOptions, c as ErrorContext, E as ExtraOptions, a as ResponseContext, b as ResponseErrorContext } from './index-DDD_c4ys.cjs';
251
3
 
252
- declare const createFetchClient: <TBaseData, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = "all">(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
4
+ declare const createFetchClient: <TBaseData, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = undefined>(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
253
5
  <TData = TBaseData, TErrorData = TBaseErrorData, TResultMode extends ResultModeUnion = TBaseResultMode>(url: string, config?: FetchConfig<TData, TErrorData, TResultMode>): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
254
6
  create: any;
255
- cancel(url: string, reason?: unknown): void;
256
7
  };
257
8
  declare const callApi: {
258
- <TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = "all">(url: string, config?: FetchConfig<TData, TErrorData, TResultMode> | undefined): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
259
- create: <TBaseData, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = "all">(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
9
+ <TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = undefined>(url: string, config?: FetchConfig<TData, TErrorData, TResultMode> | undefined): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
10
+ create: <TBaseData, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = undefined>(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
260
11
  <TData = TBaseData, TErrorData = TBaseErrorData, TResultMode extends ResultModeUnion = TBaseResultMode>(url: string, config?: FetchConfig<TData, TErrorData, TResultMode>): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
261
12
  create: any;
262
- cancel(url: string, reason?: unknown): void;
263
13
  };
264
- cancel(url: string, reason?: unknown): void;
265
14
  };
266
15
 
267
- export { type $RequestOptions, type ErrorContext, type ExtraOptions, type FetchConfig, HTTPError, type ResponseContext, type ResponseErrorContext, callApi, createFetchClient, isHTTPError, isHTTPErrorInstance, toQueryString };
16
+ export { FetchConfig, callApi, createFetchClient };
@@ -0,0 +1 @@
1
+ "use strict";var r,e=Object.defineProperty,o=Object.getOwnPropertyDescriptor,t=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,s={};((r,o)=>{for(var t in o)e(r,t,{get:o[t],enumerable:!0})})(s,{HTTPError:()=>u,isHTTPError:()=>c,isHTTPErrorInstance:()=>l,toQueryString:()=>i}),module.exports=(r=s,((r,s,n,i)=>{if(s&&"object"==typeof s||"function"==typeof s)for(let c of t(s))a.call(r,c)||c===n||e(r,c,{get:()=>s[c],enumerable:!(i=o(s,c))||i.enumerable});return r})(e({},"__esModule",{value:!0}),r));var n=r=>!("object"!=typeof r||null===r||r instanceof FormData||Array.isArray(r)),i=r=>r?new URLSearchParams(r).toString():(console.error("toQueryString:","No query params provided!"),null),c=(Object.keys({408:"Request Timeout",409:"Conflict",425:"Too Early",429:"Too Many Requests",500:"Internal Server Error",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout"}).map(Number),r=>n(r)&&"HTTPError"===r.name),u=class extends Error{errorData;isHTTPError=!0;name="HTTPError";response;constructor(r,e){const{defaultErrorMessage:o,errorData:t,response:a}=r;super(t.message??o,e),this.errorData=t,this.response=a}},l=r=>r instanceof u||n(r)&&"HTTPError"===r.name&&!0===r.isHTTPError;//# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/utils/index.ts","../../../src/typeof.ts","../../../src/utils/utils.ts"],"sourcesContent":["export { HTTPError, isHTTPError, isHTTPErrorInstance, toQueryString } from \"./utils\";\n","import type { AnyFunction } from \"./type-helpers\";\n\nexport const isArray = <TArray>(value: unknown): value is TArray[] => Array.isArray(value);\n\nexport const isObject = <TObject extends Record<string, unknown>>(value: unknown): value is TObject => {\n\treturn (\n\t\ttypeof value === \"object\" && value !== null && !(value instanceof FormData) && !Array.isArray(value)\n\t);\n};\n\nexport const isFunction = <TFunction extends AnyFunction>(value: unknown): value is TFunction =>\n\ttypeof value === \"function\";\n\nexport const isString = (value: unknown) => typeof value === \"string\";\n\nexport const isQueryString = (value: unknown): value is string =>\n\ttypeof value === \"string\" && value.includes(\"=\");\n","import { isArray, isFunction, isObject } from \"../typeof\";\nimport type {\n\t$BaseRequestOptions,\n\t$RequestOptions,\n\tApiErrorVariant,\n\tBaseConfig,\n\tExtraOptions,\n\tFetchConfig,\n\tPossibleErrorObject,\n} from \"../types\";\n\n// prettier-ignore\nexport const getRequestKey = <TConfig extends Record<string, unknown>>(url: string, config?: TConfig) => `${url} | ${JSON.stringify(config ?? {})}`;\n\ntype ToQueryStringFn = {\n\t(params: ExtraOptions[\"query\"]): null | string;\n\t(params: Required<ExtraOptions>[\"query\"]): string;\n};\n\nexport const toQueryString: ToQueryStringFn = (params) => {\n\tif (!params) {\n\t\tconsole.error(\"toQueryString:\", \"No query params provided!\");\n\n\t\treturn null as never;\n\t}\n\n\treturn new URLSearchParams(params as Record<string, string>).toString();\n};\n\nexport const mergeUrlWithParams = (url: string, params: ExtraOptions[\"query\"]): string => {\n\tif (!params) {\n\t\treturn url;\n\t}\n\n\tconst paramsString = toQueryString(params);\n\n\tif (url.endsWith(\"?\")) {\n\t\treturn `${url}${paramsString}`;\n\t}\n\n\tif (url.includes(\"?\")) {\n\t\treturn `${url}&${paramsString}`;\n\t}\n\n\treturn `${url}?${paramsString}`;\n};\n\nexport const objectifyHeaders = (headers: RequestInit[\"headers\"]): Record<string, string> | undefined => {\n\tif (!headers || isObject(headers)) {\n\t\treturn headers;\n\t}\n\n\treturn Object.fromEntries(isArray(headers) ? headers : headers.entries());\n};\n\nconst retryCodesLookup = {\n\t408: \"Request Timeout\",\n\t409: \"Conflict\",\n\t425: \"Too Early\",\n\t429: \"Too Many Requests\",\n\t500: \"Internal Server Error\",\n\t502: \"Bad Gateway\",\n\t503: \"Service Unavailable\",\n\t504: \"Gateway Timeout\",\n};\n\nexport const defaultRetryCodes: Required<BaseConfig>[\"retryCodes\"] =\n\tObject.keys(retryCodesLookup).map(Number);\n\nexport const defaultRetryMethods: Required<BaseConfig>[\"retryMethods\"] = [\"GET\"];\n\nexport const fetchSpecificKeys = [\n\t\"body\",\n\t\"integrity\",\n\t\"method\",\n\t\"headers\",\n\t\"signal\",\n\t\"cache\",\n\t\"redirect\",\n\t\"window\",\n\t\"credentials\",\n\t\"keepalive\",\n\t\"referrer\",\n\t\"priority\",\n\t\"mode\",\n\t\"referrerPolicy\",\n] satisfies Array<keyof FetchConfig>;\n\nexport const omitKeys = <\n\tTObject extends Record<string, unknown>,\n\tconst TOmitArray extends Array<keyof TObject>,\n>(\n\tinitialObject: TObject,\n\tkeysToOmit: TOmitArray\n) => {\n\tconst arrayFromFilteredObject = Object.entries(initialObject).filter(\n\t\t([key]) => !keysToOmit.includes(key)\n\t);\n\n\tconst updatedObject = Object.fromEntries(arrayFromFilteredObject);\n\n\treturn updatedObject as Omit<TObject, keyof TOmitArray>;\n};\n\nconst pickKeys = <TObject extends Record<string, unknown>, const TPickArray extends Array<keyof TObject>>(\n\tinitialObject: TObject,\n\tkeysToPick: TPickArray\n) => {\n\tconst keysToPickSet = new Set(keysToPick);\n\n\tconst arrayFromInitObject = Object.entries(initialObject);\n\n\tconst filteredArray = arrayFromInitObject.filter(([objectKey]) => keysToPickSet.has(objectKey));\n\n\tconst updatedObject = Object.fromEntries(filteredArray);\n\n\treturn updatedObject as Pick<TObject, TPickArray[number]>;\n};\n\nexport const splitConfig = <TObject extends object>(\n\tconfig: TObject\n): [\"body\" extends keyof TObject ? $RequestOptions : $BaseRequestOptions, ExtraOptions] => [\n\tpickKeys(config as Record<string, unknown>, fetchSpecificKeys) as never,\n\tomitKeys(config as Record<string, unknown>, fetchSpecificKeys) as never,\n];\n\nexport const handleResponseType = <TResponse>(\n\tresponse: Response,\n\tparser?: Required<ExtraOptions>[\"responseParser\"]\n) => ({\n\tarrayBuffer: () => response.arrayBuffer() as Promise<TResponse>,\n\tblob: () => response.blob() as Promise<TResponse>,\n\tformData: () => response.formData() as Promise<TResponse>,\n\tjson: async () => {\n\t\tif (parser) {\n\t\t\treturn parser(await response.text());\n\t\t}\n\n\t\treturn response.json() as Promise<TResponse>;\n\t},\n\ttext: () => response.text() as Promise<TResponse>,\n});\n\nexport const getResponseData = <TResponse>(\n\tresponse: Response,\n\tresponseType: keyof ReturnType<typeof handleResponseType>,\n\tparser: ExtraOptions[\"responseParser\"]\n) => {\n\tconst RESPONSE_TYPE_LOOKUP = handleResponseType<TResponse>(response, parser);\n\n\tif (!Object.hasOwn(RESPONSE_TYPE_LOOKUP, responseType)) {\n\t\tthrow new Error(`Invalid response type: ${responseType}`);\n\t}\n\n\treturn RESPONSE_TYPE_LOOKUP[responseType]();\n};\n\ntype data = {\n\toptions: ExtraOptions;\n\tresponse: Response;\n\tsuccessData: unknown;\n};\n\n// == The CallApiResult type is used to cast all return statements due to a design limitation in ts.\n// LINK - See https://www.zhenghao.io/posts/type-functions for more info\nexport const resolveSuccessResult = <CallApiResult>(info: data): CallApiResult => {\n\tconst { options, response, successData } = info;\n\n\tconst apiDetails = {\n\t\tdata: successData,\n\t\terror: null,\n\t\tresponse,\n\t};\n\n\tif (!options.resultMode || options.resultMode === \"all\") {\n\t\treturn apiDetails as CallApiResult;\n\t}\n\n\treturn {\n\t\tonlyError: apiDetails.error,\n\t\tonlyResponse: apiDetails.response,\n\t\tonlySuccess: apiDetails.data,\n\t}[options.resultMode] as CallApiResult;\n};\n\n// == Using curring here so error and options are not required to be passed every time, instead to be captured once by way of closure\nexport const getResolveErrorResultFn = <CallApiResult>($info: {\n\terror?: unknown;\n\toptions: ExtraOptions;\n}) => {\n\tconst { error, options } = $info;\n\n\ttype ErrorInfo = {\n\t\terrorData?: unknown;\n\t\tmessage?: string;\n\t\tresponse?: Response;\n\t};\n\n\tconst resolveErrorResult = (info: ErrorInfo = {}): CallApiResult => {\n\t\tconst { errorData, message, response } = info;\n\n\t\tconst shouldThrowOnError = isFunction(options.throwOnError)\n\t\t\t? options.throwOnError(error as Error)\n\t\t\t: options.throwOnError;\n\n\t\tif (shouldThrowOnError) {\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn {\n\t\t\tdata: null,\n\t\t\terror: {\n\t\t\t\terrorData: errorData ?? error,\n\t\t\t\tmessage: message ?? (error as PossibleErrorObject)?.message ?? options.defaultErrorMessage,\n\t\t\t\tname: (error as PossibleErrorObject)?.name ?? \"UnknownError\",\n\t\t\t},\n\t\t\tresponse: response ?? null,\n\t\t} as CallApiResult;\n\t};\n\n\treturn resolveErrorResult;\n};\n\nexport const isHTTPError = <TErrorData>(error: ApiErrorVariant<TErrorData>[\"error\"] | null) => {\n\treturn isObject(error) && error.name === \"HTTPError\";\n};\n\ntype ErrorDetails<TErrorResponse> = {\n\tdefaultErrorMessage: string;\n\terrorData: TErrorResponse;\n\tresponse: Response;\n};\n\ntype ErrorOptions = {\n\tcause?: unknown;\n};\n\nexport class HTTPError<TErrorResponse = Record<string, unknown>> extends Error {\n\terrorData: ErrorDetails<TErrorResponse>[\"errorData\"];\n\tisHTTPError = true;\n\n\toverride name = \"HTTPError\" as const;\n\n\tresponse: ErrorDetails<TErrorResponse>[\"response\"];\n\n\tconstructor(errorDetails: ErrorDetails<TErrorResponse>, errorOptions?: ErrorOptions) {\n\t\tconst { defaultErrorMessage, errorData, response } = errorDetails;\n\n\t\tsuper((errorData as { message?: string }).message ?? defaultErrorMessage, errorOptions);\n\n\t\tthis.errorData = errorData;\n\t\tthis.response = response;\n\t}\n}\n\n// prettier-ignore\nexport const isHTTPErrorInstance = <TErrorResponse>(\n\terror: unknown\n): error is HTTPError<TErrorResponse> => {\n\treturn (\n\t\terror instanceof HTTPError || (isObject(error) && error.name === \"HTTPError\" && error.isHTTPError === true)\n\t);\n};\n\nexport const waitUntil = (delay: number) => {\n\tif (delay === 0) return;\n\n\tconst { promise, resolve } = Promise.withResolvers();\n\n\tsetTimeout(resolve, delay);\n\n\treturn promise;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACIO,IAAM,WAAW,CAA0C,UAAqC;AACtG,SACC,OAAO,UAAU,YAAY,UAAU,QAAQ,EAAE,iBAAiB,aAAa,CAAC,MAAM,QAAQ,KAAK;AAErG;;;ACWO,IAAM,gBAAiC,CAAC,WAAW;AACzD,MAAI,CAAC,QAAQ;AACZ,YAAQ,MAAM,kBAAkB,2BAA2B;AAE3D,WAAO;AAAA,EACR;AAEA,SAAO,IAAI,gBAAgB,MAAgC,EAAE,SAAS;AACvE;AA4BA,IAAM,mBAAmB;AAAA,EACxB,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACN;AAEO,IAAM,oBACZ,OAAO,KAAK,gBAAgB,EAAE,IAAI,MAAM;AA4JlC,IAAM,cAAc,CAAa,UAAuD;AAC9F,SAAO,SAAS,KAAK,KAAK,MAAM,SAAS;AAC1C;AAYO,IAAM,YAAN,cAAkE,MAAM;AAAA,EAC9E;AAAA,EACA,cAAc;AAAA,EAEL,OAAO;AAAA,EAEhB;AAAA,EAEA,YAAY,cAA4C,cAA6B;AACpF,UAAM,EAAE,qBAAqB,WAAW,SAAS,IAAI;AAErD,UAAO,UAAmC,WAAW,qBAAqB,YAAY;AAEtF,SAAK,YAAY;AACjB,SAAK,WAAW;AAAA,EACjB;AACD;AAGO,IAAM,sBAAsB,CAClC,UACwC;AACxC,SACC,iBAAiB,aAAc,SAAS,KAAK,KAAK,MAAM,SAAS,eAAe,MAAM,gBAAgB;AAExG;","names":[]}
@@ -0,0 +1 @@
1
+ export { H as HTTPError, i as isHTTPError, d as isHTTPErrorInstance, t as toQueryString } from '../index-DDD_c4ys.cjs';
@@ -0,0 +1 @@
1
+ var r=r=>!("object"!=typeof r||null===r||r instanceof FormData||Array.isArray(r)),e=r=>"string"==typeof r,t=r=>"string"==typeof r&&r.includes("="),o=(r,e)=>`${r} | ${JSON.stringify(e??{})}`,s=r=>r?new URLSearchParams(r).toString():(console.error("toQueryString:","No query params provided!"),null),n=(r,e)=>{if(!e)return r;const t=s(e);return r.endsWith("?")?`${r}${t}`:r.includes("?")?`${r}&${t}`:`${r}?${t}`},a=e=>{return!e||r(e)?e:Object.fromEntries((t=e,Array.isArray(t)?e:e.entries()));var t},i=Object.keys({408:"Request Timeout",409:"Conflict",425:"Too Early",429:"Too Many Requests",500:"Internal Server Error",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout"}).map(Number),l=["GET"],c=["body","integrity","method","headers","signal","cache","redirect","window","credentials","keepalive","referrer","priority","mode","referrerPolicy"],u=(r,e)=>{const t=Object.entries(r).filter((([r])=>!e.includes(r)));return Object.fromEntries(t)},f=(r,e)=>{const t=new Set(e),o=Object.entries(r).filter((([r])=>t.has(r)));return Object.fromEntries(o)},y=r=>[f(r,c),u(r,c)],m=(r,e,t)=>{const o=((r,e)=>({arrayBuffer:()=>r.arrayBuffer(),blob:()=>r.blob(),formData:()=>r.formData(),json:async()=>e?e(await r.text()):r.json(),text:()=>r.text()}))(r,t);if(!Object.hasOwn(o,e))throw new Error(`Invalid response type: ${e}`);return o[e]()},p=r=>{const{options:e,response:t,successData:o}=r,s={data:o,error:null,response:t};return e.resultMode&&"all"!==e.resultMode?{onlyError:s.error,onlyResponse:s.response,onlySuccess:s.data}[e.resultMode]:s},d=r=>{const{error:e,options:t}=r;return(r={})=>{const{errorData:o,message:s,response:n}=r;if("function"==typeof t.throwOnError?t.throwOnError(e):t.throwOnError)throw e;return{data:null,error:{errorData:o??e,message:s??e?.message??t.defaultErrorMessage,name:e?.name??"UnknownError"},response:n??null}}},E=e=>r(e)&&"HTTPError"===e.name,w=class extends Error{errorData;isHTTPError=!0;name="HTTPError";response;constructor(r,e){const{defaultErrorMessage:t,errorData:o,response:s}=r;super(o.message??t,e),this.errorData=o,this.response=s}},T=e=>e instanceof w||r(e)&&"HTTPError"===e.name&&!0===e.isHTTPError,b=r=>{if(0===r)return;const{promise:e,resolve:t}=Promise.withResolvers();return setTimeout(t,r),e};export{w as HTTPError,i as defaultRetryCodes,l as defaultRetryMethods,o as getRequestKey,d as getResolveErrorResultFn,m as getResponseData,E as isHTTPError,T as isHTTPErrorInstance,r as isObject,t as isQueryString,e as isString,n as mergeUrlWithParams,a as objectifyHeaders,u as omitKeys,p as resolveSuccessResult,y as splitConfig,s as toQueryString,b as waitUntil};//# sourceMappingURL=chunk-YYBXXYTQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/typeof.ts","../../src/utils/utils.ts"],"names":[],"mappings":"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","file":"chunk-YYBXXYTQ.js","sourcesContent":["import type { AnyFunction } from \"./type-helpers\";\n\nexport const isArray = <TArray>(value: unknown): value is TArray[] => Array.isArray(value);\n\nexport const isObject = <TObject extends Record<string, unknown>>(value: unknown): value is TObject => {\n\treturn (\n\t\ttypeof value === \"object\" && value !== null && !(value instanceof FormData) && !Array.isArray(value)\n\t);\n};\n\nexport const isFunction = <TFunction extends AnyFunction>(value: unknown): value is TFunction =>\n\ttypeof value === \"function\";\n\nexport const isString = (value: unknown) => typeof value === \"string\";\n\nexport const isQueryString = (value: unknown): value is string =>\n\ttypeof value === \"string\" && value.includes(\"=\");\n","import { isArray, isFunction, isObject } from \"../typeof\";\nimport type {\n\t$BaseRequestOptions,\n\t$RequestOptions,\n\tApiErrorVariant,\n\tBaseConfig,\n\tExtraOptions,\n\tFetchConfig,\n\tPossibleErrorObject,\n} from \"../types\";\n\n// prettier-ignore\nexport const getRequestKey = <TConfig extends Record<string, unknown>>(url: string, config?: TConfig) => `${url} | ${JSON.stringify(config ?? {})}`;\n\ntype ToQueryStringFn = {\n\t(params: ExtraOptions[\"query\"]): null | string;\n\t(params: Required<ExtraOptions>[\"query\"]): string;\n};\n\nexport const toQueryString: ToQueryStringFn = (params) => {\n\tif (!params) {\n\t\tconsole.error(\"toQueryString:\", \"No query params provided!\");\n\n\t\treturn null as never;\n\t}\n\n\treturn new URLSearchParams(params as Record<string, string>).toString();\n};\n\nexport const mergeUrlWithParams = (url: string, params: ExtraOptions[\"query\"]): string => {\n\tif (!params) {\n\t\treturn url;\n\t}\n\n\tconst paramsString = toQueryString(params);\n\n\tif (url.endsWith(\"?\")) {\n\t\treturn `${url}${paramsString}`;\n\t}\n\n\tif (url.includes(\"?\")) {\n\t\treturn `${url}&${paramsString}`;\n\t}\n\n\treturn `${url}?${paramsString}`;\n};\n\nexport const objectifyHeaders = (headers: RequestInit[\"headers\"]): Record<string, string> | undefined => {\n\tif (!headers || isObject(headers)) {\n\t\treturn headers;\n\t}\n\n\treturn Object.fromEntries(isArray(headers) ? headers : headers.entries());\n};\n\nconst retryCodesLookup = {\n\t408: \"Request Timeout\",\n\t409: \"Conflict\",\n\t425: \"Too Early\",\n\t429: \"Too Many Requests\",\n\t500: \"Internal Server Error\",\n\t502: \"Bad Gateway\",\n\t503: \"Service Unavailable\",\n\t504: \"Gateway Timeout\",\n};\n\nexport const defaultRetryCodes: Required<BaseConfig>[\"retryCodes\"] =\n\tObject.keys(retryCodesLookup).map(Number);\n\nexport const defaultRetryMethods: Required<BaseConfig>[\"retryMethods\"] = [\"GET\"];\n\nexport const fetchSpecificKeys = [\n\t\"body\",\n\t\"integrity\",\n\t\"method\",\n\t\"headers\",\n\t\"signal\",\n\t\"cache\",\n\t\"redirect\",\n\t\"window\",\n\t\"credentials\",\n\t\"keepalive\",\n\t\"referrer\",\n\t\"priority\",\n\t\"mode\",\n\t\"referrerPolicy\",\n] satisfies Array<keyof FetchConfig>;\n\nexport const omitKeys = <\n\tTObject extends Record<string, unknown>,\n\tconst TOmitArray extends Array<keyof TObject>,\n>(\n\tinitialObject: TObject,\n\tkeysToOmit: TOmitArray\n) => {\n\tconst arrayFromFilteredObject = Object.entries(initialObject).filter(\n\t\t([key]) => !keysToOmit.includes(key)\n\t);\n\n\tconst updatedObject = Object.fromEntries(arrayFromFilteredObject);\n\n\treturn updatedObject as Omit<TObject, keyof TOmitArray>;\n};\n\nconst pickKeys = <TObject extends Record<string, unknown>, const TPickArray extends Array<keyof TObject>>(\n\tinitialObject: TObject,\n\tkeysToPick: TPickArray\n) => {\n\tconst keysToPickSet = new Set(keysToPick);\n\n\tconst arrayFromInitObject = Object.entries(initialObject);\n\n\tconst filteredArray = arrayFromInitObject.filter(([objectKey]) => keysToPickSet.has(objectKey));\n\n\tconst updatedObject = Object.fromEntries(filteredArray);\n\n\treturn updatedObject as Pick<TObject, TPickArray[number]>;\n};\n\nexport const splitConfig = <TObject extends object>(\n\tconfig: TObject\n): [\"body\" extends keyof TObject ? $RequestOptions : $BaseRequestOptions, ExtraOptions] => [\n\tpickKeys(config as Record<string, unknown>, fetchSpecificKeys) as never,\n\tomitKeys(config as Record<string, unknown>, fetchSpecificKeys) as never,\n];\n\nexport const handleResponseType = <TResponse>(\n\tresponse: Response,\n\tparser?: Required<ExtraOptions>[\"responseParser\"]\n) => ({\n\tarrayBuffer: () => response.arrayBuffer() as Promise<TResponse>,\n\tblob: () => response.blob() as Promise<TResponse>,\n\tformData: () => response.formData() as Promise<TResponse>,\n\tjson: async () => {\n\t\tif (parser) {\n\t\t\treturn parser(await response.text());\n\t\t}\n\n\t\treturn response.json() as Promise<TResponse>;\n\t},\n\ttext: () => response.text() as Promise<TResponse>,\n});\n\nexport const getResponseData = <TResponse>(\n\tresponse: Response,\n\tresponseType: keyof ReturnType<typeof handleResponseType>,\n\tparser: ExtraOptions[\"responseParser\"]\n) => {\n\tconst RESPONSE_TYPE_LOOKUP = handleResponseType<TResponse>(response, parser);\n\n\tif (!Object.hasOwn(RESPONSE_TYPE_LOOKUP, responseType)) {\n\t\tthrow new Error(`Invalid response type: ${responseType}`);\n\t}\n\n\treturn RESPONSE_TYPE_LOOKUP[responseType]();\n};\n\ntype data = {\n\toptions: ExtraOptions;\n\tresponse: Response;\n\tsuccessData: unknown;\n};\n\n// == The CallApiResult type is used to cast all return statements due to a design limitation in ts.\n// LINK - See https://www.zhenghao.io/posts/type-functions for more info\nexport const resolveSuccessResult = <CallApiResult>(info: data): CallApiResult => {\n\tconst { options, response, successData } = info;\n\n\tconst apiDetails = {\n\t\tdata: successData,\n\t\terror: null,\n\t\tresponse,\n\t};\n\n\tif (!options.resultMode || options.resultMode === \"all\") {\n\t\treturn apiDetails as CallApiResult;\n\t}\n\n\treturn {\n\t\tonlyError: apiDetails.error,\n\t\tonlyResponse: apiDetails.response,\n\t\tonlySuccess: apiDetails.data,\n\t}[options.resultMode] as CallApiResult;\n};\n\n// == Using curring here so error and options are not required to be passed every time, instead to be captured once by way of closure\nexport const getResolveErrorResultFn = <CallApiResult>($info: {\n\terror?: unknown;\n\toptions: ExtraOptions;\n}) => {\n\tconst { error, options } = $info;\n\n\ttype ErrorInfo = {\n\t\terrorData?: unknown;\n\t\tmessage?: string;\n\t\tresponse?: Response;\n\t};\n\n\tconst resolveErrorResult = (info: ErrorInfo = {}): CallApiResult => {\n\t\tconst { errorData, message, response } = info;\n\n\t\tconst shouldThrowOnError = isFunction(options.throwOnError)\n\t\t\t? options.throwOnError(error as Error)\n\t\t\t: options.throwOnError;\n\n\t\tif (shouldThrowOnError) {\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn {\n\t\t\tdata: null,\n\t\t\terror: {\n\t\t\t\terrorData: errorData ?? error,\n\t\t\t\tmessage: message ?? (error as PossibleErrorObject)?.message ?? options.defaultErrorMessage,\n\t\t\t\tname: (error as PossibleErrorObject)?.name ?? \"UnknownError\",\n\t\t\t},\n\t\t\tresponse: response ?? null,\n\t\t} as CallApiResult;\n\t};\n\n\treturn resolveErrorResult;\n};\n\nexport const isHTTPError = <TErrorData>(error: ApiErrorVariant<TErrorData>[\"error\"] | null) => {\n\treturn isObject(error) && error.name === \"HTTPError\";\n};\n\ntype ErrorDetails<TErrorResponse> = {\n\tdefaultErrorMessage: string;\n\terrorData: TErrorResponse;\n\tresponse: Response;\n};\n\ntype ErrorOptions = {\n\tcause?: unknown;\n};\n\nexport class HTTPError<TErrorResponse = Record<string, unknown>> extends Error {\n\terrorData: ErrorDetails<TErrorResponse>[\"errorData\"];\n\tisHTTPError = true;\n\n\toverride name = \"HTTPError\" as const;\n\n\tresponse: ErrorDetails<TErrorResponse>[\"response\"];\n\n\tconstructor(errorDetails: ErrorDetails<TErrorResponse>, errorOptions?: ErrorOptions) {\n\t\tconst { defaultErrorMessage, errorData, response } = errorDetails;\n\n\t\tsuper((errorData as { message?: string }).message ?? defaultErrorMessage, errorOptions);\n\n\t\tthis.errorData = errorData;\n\t\tthis.response = response;\n\t}\n}\n\n// prettier-ignore\nexport const isHTTPErrorInstance = <TErrorResponse>(\n\terror: unknown\n): error is HTTPError<TErrorResponse> => {\n\treturn (\n\t\terror instanceof HTTPError || (isObject(error) && error.name === \"HTTPError\" && error.isHTTPError === true)\n\t);\n};\n\nexport const waitUntil = (delay: number) => {\n\tif (delay === 0) return;\n\n\tconst { promise, resolve } = Promise.withResolvers();\n\n\tsetTimeout(resolve, delay);\n\n\treturn promise;\n};\n"]}
@@ -0,0 +1,252 @@
1
+ type AnyString = string & {
2
+ placeholder?: never;
3
+ };
4
+ type AnyNumber = number & {
5
+ placeholder?: never;
6
+ };
7
+ type Prettify<TObject> = {
8
+ [Key in keyof TObject]: TObject[Key];
9
+ } & NonNullable<unknown>;
10
+
11
+ type ToQueryStringFn = {
12
+ (params: ExtraOptions["query"]): null | string;
13
+ (params: Required<ExtraOptions>["query"]): string;
14
+ };
15
+ declare const toQueryString: ToQueryStringFn;
16
+ declare const fetchSpecificKeys: ("body" | "method" | "headers" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "priority" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window")[];
17
+ declare const handleResponseType: <TResponse>(response: Response, parser?: Required<ExtraOptions>["responseParser"]) => {
18
+ arrayBuffer: () => Promise<TResponse>;
19
+ blob: () => Promise<TResponse>;
20
+ formData: () => Promise<TResponse>;
21
+ json: () => Promise<Record<string, unknown> | TResponse>;
22
+ text: () => Promise<TResponse>;
23
+ };
24
+ declare const isHTTPError: <TErrorData>(error: ApiErrorVariant<TErrorData>["error"] | null) => error is {
25
+ errorData: TErrorData;
26
+ message: string;
27
+ name: "HTTPError";
28
+ };
29
+ type ErrorDetails<TErrorResponse> = {
30
+ defaultErrorMessage: string;
31
+ errorData: TErrorResponse;
32
+ response: Response;
33
+ };
34
+ type ErrorOptions = {
35
+ cause?: unknown;
36
+ };
37
+ declare class HTTPError<TErrorResponse = Record<string, unknown>> extends Error {
38
+ errorData: ErrorDetails<TErrorResponse>["errorData"];
39
+ isHTTPError: boolean;
40
+ name: "HTTPError";
41
+ response: ErrorDetails<TErrorResponse>["response"];
42
+ constructor(errorDetails: ErrorDetails<TErrorResponse>, errorOptions?: ErrorOptions);
43
+ }
44
+ declare const isHTTPErrorInstance: <TErrorResponse>(error: unknown) => error is HTTPError<TErrorResponse>;
45
+
46
+ interface $RequestOptions extends Pick<FetchConfig, (typeof fetchSpecificKeys)[number]> {
47
+ }
48
+ interface ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = ResultModeUnion> {
49
+ /**
50
+ * @description Authorization header value.
51
+ */
52
+ auth?: {
53
+ bearer: string;
54
+ token?: never;
55
+ } | {
56
+ bearer?: never;
57
+ token: string;
58
+ } | string;
59
+ /**
60
+ * @description Base URL to be prepended to all request URLs
61
+ */
62
+ baseURL?: string;
63
+ /** Optional body of the request, can be a object or any other supported body type. */
64
+ body?: Record<string, unknown> | RequestInit["body"];
65
+ /**
66
+ * @description Custom function to serialize the body object into a string.
67
+ */
68
+ bodySerializer?: (bodyData: Record<string, unknown>) => string;
69
+ /**
70
+ * @description If true, cancels previous unfinished requests to the same URL.
71
+ * @default true
72
+ */
73
+ cancelRedundantRequests?: boolean;
74
+ /**
75
+ * @description Whether to clone the response, so response.json and the like can used in the interceptors.
76
+ * @default false
77
+ */
78
+ cloneResponse?: boolean;
79
+ /**
80
+ * @description Default error message to use if none is provided from a response.
81
+ * @default "Failed to fetch data from server!"
82
+ */
83
+ defaultErrorMessage?: string;
84
+ /**
85
+ * @description an optional field you can fill with additional information,
86
+ * to associate with the request, typically used for logging or tracing.
87
+ *
88
+ * A good use case for this, would be to use the info to handle specific cases in any of the shared interceptors.
89
+ * @example
90
+ * ```ts
91
+ * const callMainApi = callApi.create({
92
+ * baseURL: "https://main-api.com",
93
+ * onResponseError: ({ response, options }) => {
94
+ * if (options.meta?.userId) {
95
+ * console.error(`User ${options.meta.userId} made an error`);
96
+ * }
97
+ * },
98
+ * });
99
+ *
100
+ * const response = await callMainApi({
101
+ * url: "https://example.com/api/data",
102
+ * meta: { userId: "123" },
103
+ * });
104
+ * ```
105
+ */
106
+ meta?: Record<string, unknown>;
107
+ /**
108
+ * @description HTTP method for the request.
109
+ * @default "GET"
110
+ */
111
+ method?: "DELETE" | "GET" | "PATCH" | "POST" | "PUT" | AnyString;
112
+ /**
113
+ * @description Interceptor to be called when an error occurs during the fetch request OR when an error response is received from the api
114
+ * It is basically a combination of `onRequestError` and `onResponseError` interceptors
115
+ */
116
+ onError?: (anyErrorContext: ErrorContext<TErrorData>) => Promise<void> | void;
117
+ /** @description Interceptor to be called just before the request is made, allowing for modifications or additional operations. */
118
+ onRequest?: (requestContext: {
119
+ options: ExtraOptions;
120
+ request: $RequestOptions;
121
+ }) => Promise<void> | void;
122
+ /** @description Interceptor to be called when an error occurs during the fetch request. */
123
+ onRequestError?: (requestErrorContext: {
124
+ error: Error;
125
+ options: ExtraOptions;
126
+ request: $RequestOptions;
127
+ }) => Promise<void> | void;
128
+ /** @description Interceptor to be called when a successful response is received from the api. */
129
+ onResponse?: (responseContext: ResponseContext<TData>) => Promise<void> | void;
130
+ /** @description Interceptor to be called when an error response is received from the api. */
131
+ onResponseError?: (responseErrorContext: ResponseErrorContext<TErrorData>) => Promise<void> | void;
132
+ /**
133
+ * @description Query parameters to append to the URL.
134
+ */
135
+ query?: Record<string, boolean | number | string>;
136
+ /**
137
+ * @description Custom function to parse the response string into a object.
138
+ */
139
+ responseParser?: (responseString: string) => Record<string, unknown>;
140
+ /**
141
+ * @description Expected response type, affects how response is parsed
142
+ * @default "json"
143
+ */
144
+ responseType?: keyof ReturnType<typeof handleResponseType>;
145
+ /**
146
+ * @description Custom function to validate the response data.
147
+ */
148
+ responseValidator?: (data: unknown) => TData;
149
+ /**
150
+ * @description Mode of the result, can influence how results are handled or returned.
151
+ * Can be set to "all" | "onlySuccess" | "onlyError" | "onlyResponse".
152
+ * @default "all"
153
+ */
154
+ resultMode?: TResultMode;
155
+ /**
156
+ * @description Number of retry attempts for failed requests
157
+ * @default 0
158
+ */
159
+ retries?: number;
160
+ /**
161
+ * @description HTTP status codes that trigger a retry
162
+ * @default [409, 425, 429, 500, 502, 503, 504]
163
+ */
164
+ retryCodes?: Array<409 | 425 | 429 | 500 | 502 | 503 | 504 | AnyNumber>;
165
+ /**
166
+ * @description Delay between retries in milliseconds
167
+ * @default 500
168
+ */
169
+ retryDelay?: number;
170
+ /**
171
+ * HTTP methods that are allowed to retry
172
+ * @default ["GET", "POST"]
173
+ */
174
+ retryMethods?: Array<"GET" | "POST" | AnyString>;
175
+ /**
176
+ * If true or the function returns true, throws errors instead of returning them
177
+ * The function is passed the error object and can be used to conditionally throw the error
178
+ * @default false
179
+ */
180
+ throwOnError?: ((error?: Error | HTTPError<TErrorData>) => boolean) | boolean;
181
+ /**
182
+ * @description Request timeout in milliseconds
183
+ */
184
+ timeout?: number;
185
+ }
186
+ type ResponseContext<TData> = Prettify<{
187
+ data: TData;
188
+ options: ExtraOptions;
189
+ request: $RequestOptions;
190
+ response: Response;
191
+ }>;
192
+ type ResponseErrorContext<TErrorData> = Prettify<{
193
+ errorData: TErrorData;
194
+ options: ExtraOptions;
195
+ request: $RequestOptions;
196
+ response: Response;
197
+ }>;
198
+ type ErrorContext<TErrorData> = Prettify<{
199
+ error: Error;
200
+ errorData?: null;
201
+ options: ExtraOptions;
202
+ request: $RequestOptions;
203
+ response: null;
204
+ } | {
205
+ error: null;
206
+ errorData?: TErrorData;
207
+ options: ExtraOptions;
208
+ request: $RequestOptions;
209
+ response: Response;
210
+ }>;
211
+ interface FetchConfig<TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = "all"> extends Omit<RequestInit, "body" | "method">, ExtraOptions<TData, TErrorData, TResultMode> {
212
+ }
213
+ type BaseConfig<TBaseData = unknown, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = "all"> = FetchConfig<TBaseData, TBaseErrorData, TBaseResultMode>;
214
+ type ApiSuccessVariant<TData> = {
215
+ data: TData;
216
+ error: null;
217
+ response: Response;
218
+ };
219
+ type PossibleErrorNames = {
220
+ _: "AbortError" | "Error" | "SyntaxError" | "TimeoutError" | "TypeError" | "UnknownError";
221
+ }["_"];
222
+ type ApiErrorVariant<TErrorData> = {
223
+ data: null;
224
+ error: {
225
+ errorData: Error;
226
+ message: string;
227
+ name: PossibleErrorNames;
228
+ };
229
+ response: null;
230
+ } | {
231
+ data: null;
232
+ error: {
233
+ errorData: TErrorData;
234
+ message: string;
235
+ name: "HTTPError";
236
+ };
237
+ response: Response;
238
+ };
239
+ type ResultModeMap<TData = unknown, TErrorData = unknown> = {
240
+ all: ApiErrorVariant<TErrorData> | ApiSuccessVariant<TData>;
241
+ onlyError: ApiErrorVariant<TErrorData>["error"];
242
+ onlyResponse: Response;
243
+ onlySuccess: ApiSuccessVariant<TData>["data"];
244
+ };
245
+ type ResultModeUnion = {
246
+ _: {
247
+ [Key in keyof ResultModeMap]: Key;
248
+ }[keyof ResultModeMap] | undefined;
249
+ }["_"];
250
+ type GetCallApiResult<TData, TErrorData, TResultMode> = TResultMode extends NonNullable<ResultModeUnion> ? ResultModeMap<TData, TErrorData>[TResultMode] : ResultModeMap<TData, TErrorData>["all"];
251
+
252
+ export { type $RequestOptions as $, type BaseConfig as B, type ExtraOptions as E, type FetchConfig as F, type GetCallApiResult as G, HTTPError as H, type ResultModeUnion as R, type ResponseContext as a, type ResponseErrorContext as b, type ErrorContext as c, isHTTPErrorInstance as d, isHTTPError as i, toQueryString as t };
@@ -1,3 +1,16 @@
1
- export { callApi, createFetchClient } from './createFetchClient.js';
2
- export { $ as $RequestOptions, c as ErrorContext, E as ExtraOptions, F as FetchConfig, H as HTTPError, a as ResponseContext, b as ResponseErrorContext, i as isHTTPError, d as isHTTPErrorInstance, t as toQueryString } from './types-B8FDdcFK.js';
3
- import './type-helpers-DpDJiTqb.js';
1
+ import { R as ResultModeUnion, B as BaseConfig, F as FetchConfig, G as GetCallApiResult } from './index-DDD_c4ys.js';
2
+ export { $ as $RequestOptions, c as ErrorContext, E as ExtraOptions, a as ResponseContext, b as ResponseErrorContext } from './index-DDD_c4ys.js';
3
+
4
+ declare const createFetchClient: <TBaseData, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = undefined>(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
5
+ <TData = TBaseData, TErrorData = TBaseErrorData, TResultMode extends ResultModeUnion = TBaseResultMode>(url: string, config?: FetchConfig<TData, TErrorData, TResultMode>): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
6
+ create: any;
7
+ };
8
+ declare const callApi: {
9
+ <TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = undefined>(url: string, config?: FetchConfig<TData, TErrorData, TResultMode> | undefined): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
10
+ create: <TBaseData, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = undefined>(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
11
+ <TData = TBaseData, TErrorData = TBaseErrorData, TResultMode extends ResultModeUnion = TBaseResultMode>(url: string, config?: FetchConfig<TData, TErrorData, TResultMode>): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
12
+ create: any;
13
+ };
14
+ };
15
+
16
+ export { FetchConfig, callApi, createFetchClient };
package/dist/esm/index.js CHANGED
@@ -1 +1 @@
1
- export{callApi,createFetchClient}from"./chunk-5TFO467R.js";export{HTTPError,isHTTPError,isHTTPErrorInstance,toQueryString}from"./chunk-DWIZQKLW.js";import"./chunk-AKFUJ4JG.js";//# sourceMappingURL=index.js.map
1
+ import{splitConfig as e,defaultRetryCodes as r,defaultRetryMethods as o,isObject as t,isQueryString as s,isString as n,objectifyHeaders as a,getRequestKey as i,omitKeys as u,mergeUrlWithParams as l,waitUntil as c,getResponseData as p,HTTPError as d,resolveSuccessResult as h,getResolveErrorResultFn as m,isHTTPErrorInstance as y}from"./chunk-YYBXXYTQ.js";var f=R=>{const w=new Map,[b,E]=e(R??{}),{body:g,headers:q,signal:D,...$}=b,A=async(f,R)=>{const[b,M]=e(R??{}),{body:T=g,headers:S,signal:k=D,...x}=b,C={baseURL:"",bodySerializer:JSON.stringify,cancelRedundantRequests:!0,defaultErrorMessage:"Failed to fetch data from server!",responseType:"json",retries:0,retryCodes:r,retryDelay:0,retryMethods:o,...E,...M},j={body:t(T)?C.bodySerializer(T):T,headers:q||S||C.auth||t(T)?{...t(T)&&{Accept:"application/json","Content-Type":"application/json"},...s(T)&&{"Content-Type":"application/x-www-form-urlencoded"},...n(C.auth)&&{Authorization:`Bearer ${C.auth}`},...t(C.auth)&&{Authorization:"bearer"in C.auth?`Bearer ${C.auth.bearer}`:`Token ${C.auth.token}`},...a(q),...a(S)}:void 0,method:"GET",...$,...x},v=i(f,u({...j,...C},["onRequest","onResponse","onResponseError","onError","onRequestError"])),z=w.get(v);if(z&&C.cancelRedundantRequests){const e=new DOMException(`Automatic cancelation of the previous unfinished request to the same url, with the same fetch options: ${f}`,"AbortError");z.abort(e)}const O=new AbortController;w.set(v,O);const P=C.timeout?AbortSignal.timeout(C.timeout):null,B=AbortSignal.any([O.signal,...P?[P]:[],...k?[k]:[]]),Y={signal:B,...j};try{await(C.onRequest?.({options:C,request:Y}));const e=await fetch(`${C.baseURL}${l(f,C.query)}`,Y);if(!e.ok&&!B.aborted&&C.retries>0&&C.retryCodes.includes(e.status)&&C.retryMethods.includes(Y.method))return await c(C.retryDelay),await A(f,{...R,retries:C.retries-1});if(!e.ok){const r=await p(C.cloneResponse?e.clone():e,C.responseType,C.responseParser);throw new d({defaultErrorMessage:C.defaultErrorMessage,errorData:r,response:e})}const r=await p(C.cloneResponse?e.clone():e,C.responseType,C.responseParser),o=C.responseValidator?C.responseValidator(r):r;return await(C.onResponse?.({data:o,options:C,request:Y,response:C.cloneResponse?e.clone():e})),h({options:C,response:e,successData:o})}catch(e){const r=m({error:e,options:C});if(e instanceof DOMException&&"TimeoutError"===e.name){const o=`Request timed out after ${C.timeout}ms`;return console.error(`${e.name}:`,o),r({message:o})}if(e instanceof DOMException&&"AbortError"===e.name){const o=`Request aborted due to ${e.message}`;return console.error(`${e.name}:`,o),r({message:o})}if(y(e)){const{errorData:o,response:t}=e;return await Promise.allSettled([C.onResponseError?.({errorData:o,options:C,request:Y,response:C.cloneResponse?t.clone():t}),C.onError?.({error:null,errorData:o,options:C,request:Y,response:t})]),r({errorData:o,message:o?.message,response:t})}return await Promise.allSettled([C.onRequestError?.({error:e,options:C,request:Y}),C.onError?.({error:e,errorData:null,options:C,request:Y,response:null})]),r()}finally{w.delete(v)}};return A.create=f,A},R=f();export{R as callApi,f as createFetchClient};//# sourceMappingURL=index.js.map