@nanawan/axle 1.0.2 → 1.0.4

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/api.d.mts ADDED
@@ -0,0 +1,27 @@
1
+ import { c as AxleRequestConfig, s as AxleInstance, y as RunnerMethod } from "./instance-9YUALwMk.mjs";
2
+ import { UseAxle, UseAxleInstance, UseAxleOptions, UseAxleOptionsWithRunnable, WatchOptions } from "./use.mjs";
3
+
4
+ //#region src/api.d.ts
5
+ type ApiPathParams = Record<string, any> | (() => Record<string, any>);
6
+ type ApiWatchOptions = WatchOptions & {
7
+ pathParams?: boolean;
8
+ };
9
+ type ApiUseOptions<V, R, P, D> = Partial<UseAxleOptions<V, R, P, D>> & {
10
+ pathParams?: ApiPathParams;
11
+ watch?: ApiWatchOptions;
12
+ };
13
+ type ApiUseOptionsWithRunnable<V, R, P, D> = Partial<Omit<UseAxleOptionsWithRunnable<V, R, P, D>, 'runnable'>> & Pick<UseAxleOptionsWithRunnable<V, R, P, D>, 'runnable'> & {
14
+ pathParams?: ApiPathParams;
15
+ watch?: ApiWatchOptions;
16
+ };
17
+ declare function createApi(axle: AxleInstance, useAxle: UseAxle): <R = any, P = Record<string, any>, D = Record<string, any>>(url: string, method: RunnerMethod) => {
18
+ url: string;
19
+ load: (params?: P | undefined, pathParams?: ApiPathParams, config?: AxleRequestConfig<D, Record<string, any>> | undefined) => Promise<R>;
20
+ use: {
21
+ <V = R>(options?: ApiUseOptionsWithRunnable<V, R, P, D> | undefined): UseAxleInstance<V, R | undefined, P, D>;
22
+ <V_1 = R>(options?: ApiUseOptions<V_1, R, P, D> | undefined): UseAxleInstance<V_1, R, P, D>;
23
+ };
24
+ patchUrl: (url: string, pathParams: ApiPathParams) => string;
25
+ };
26
+ //#endregion
27
+ export { ApiPathParams, ApiUseOptions, ApiUseOptionsWithRunnable, ApiWatchOptions, createApi };
package/dist/api.mjs ADDED
@@ -0,0 +1,46 @@
1
+ import { isFunction } from "parattail";
2
+ //#region src/api.ts
3
+ function createApi(axle, useAxle) {
4
+ return function api(url, method) {
5
+ function load(params, pathParams, config) {
6
+ return axle[method](patchUrl(url, pathParams ?? {}), params, config);
7
+ }
8
+ function use(options = {}) {
9
+ const { pathParams = {}, watch: watchOptions, ...rest } = options;
10
+ const enableWatchPathParams = isFunction(pathParams) && (watchOptions?.pathParams || watchOptions === true);
11
+ return useAxle({
12
+ url: () => patchUrl(url, pathParams),
13
+ method,
14
+ watch: watchOptions === true ? {
15
+ params: true,
16
+ config: true,
17
+ _custom: enableWatchPathParams ? pathParams : void 0
18
+ } : watchOptions === false ? {
19
+ params: false,
20
+ config: false
21
+ } : {
22
+ params: false,
23
+ config: false,
24
+ ...watchOptions,
25
+ _custom: enableWatchPathParams ? pathParams : void 0
26
+ },
27
+ ...rest
28
+ });
29
+ }
30
+ function patchUrl(url, pathParams) {
31
+ const params = isFunction(pathParams) ? pathParams() : pathParams;
32
+ Object.entries(params).forEach(([key, value]) => {
33
+ url = url.replace(`:${key}`, value);
34
+ });
35
+ return url;
36
+ }
37
+ return {
38
+ url,
39
+ load,
40
+ use,
41
+ patchUrl
42
+ };
43
+ };
44
+ }
45
+ //#endregion
46
+ export { createApi };
@@ -0,0 +1,91 @@
1
+ import { C as isAxiosError, S as createModifyRunner, _ as ResponseInterceptor, a as AxiosRequestHeaders, b as createAxle, c as AxleRequestConfig, d as HeadersDefaults, f as Interceptor, g as RequestInterceptor, h as ModifyRunner, i as AxiosRequestConfig, l as FetchMethod, m as ModifyMethod, n as AxiosInstance, o as AxiosResponse, p as InternalAxiosRequestConfig, r as AxiosInterceptorOptions, s as AxleInstance, t as AxiosError, u as FetchRunner, v as ResponseType, x as createFetchRunner, y as RunnerMethod } from "./instance-9YUALwMk.mjs";
2
+ import { AxiosInterceptorOptions as AxiosInterceptorOptions$1, AxiosRequestConfig as AxiosRequestConfig$1, AxiosResponse as AxiosResponse$1 } from "axios";
3
+
4
+ //#region src/matcher.d.ts
5
+ type MatchPattern = string | ((options: {
6
+ url: string;
7
+ method: string;
8
+ status?: number;
9
+ }) => boolean);
10
+ declare function matchPattern(pattern: MatchPattern, method: string, url: string, status?: number): boolean;
11
+ declare function createMatcher(include?: MatchPattern[], exclude?: MatchPattern[]): (method: string, url: string, status?: number) => boolean;
12
+ //#endregion
13
+ //#region src/helper.d.ts
14
+ interface WithResponseReturn<R> {
15
+ response: R | undefined;
16
+ errorResponse: AxiosResponse$1 | undefined;
17
+ }
18
+ declare function withResponse<R>(promise: Promise<R>): Promise<WithResponseReturn<R>>;
19
+ declare function download(url: string | Blob, filename: string): void;
20
+ //#endregion
21
+ //#region src/interceptors/requestHeadersInterceptor.d.ts
22
+ interface RequestHeadersInterceptorOptions {
23
+ headers?: Record<string, string> | (() => Record<string, string>);
24
+ include?: MatchPattern[];
25
+ exclude?: MatchPattern[];
26
+ axiosInterceptorOptions?: AxiosInterceptorOptions$1;
27
+ }
28
+ declare function requestHeadersInterceptor(options?: RequestHeadersInterceptorOptions): RequestInterceptor;
29
+ //#endregion
30
+ //#region src/interceptors/requestMockInterceptor.d.ts
31
+ type RequestMockInterceptorMapping = {
32
+ url: string | ((url: string) => boolean);
33
+ handler: (config: AxiosRequestConfig$1) => {
34
+ data: any;
35
+ status?: number;
36
+ statusText?: string;
37
+ };
38
+ method?: string;
39
+ delay?: number;
40
+ };
41
+ interface RequestMockInterceptorOptions {
42
+ mappings?: RequestMockInterceptorMapping[];
43
+ include?: MatchPattern[];
44
+ exclude?: MatchPattern[];
45
+ axiosInterceptorOptions?: AxiosInterceptorOptions$1;
46
+ }
47
+ declare function requestMockInterceptor(options?: RequestMockInterceptorOptions): RequestInterceptor;
48
+ //#endregion
49
+ //#region src/interceptors/responseBlobInterceptor.d.ts
50
+ interface ResponseBlobInterceptorOptions {
51
+ onResponse?: (response: AxiosResponse$1<any, any>) => any;
52
+ include?: MatchPattern[];
53
+ exclude?: MatchPattern[];
54
+ axiosInterceptorOptions?: AxiosInterceptorOptions$1;
55
+ }
56
+ declare function responseBlobInterceptor(options?: ResponseBlobInterceptorOptions): ResponseInterceptor;
57
+ //#endregion
58
+ //#region src/interceptors/responseRetryInterceptor.d.ts
59
+ interface ResponseRetryInterceptorOptions {
60
+ count?: number;
61
+ include?: MatchPattern[];
62
+ exclude?: MatchPattern[];
63
+ axiosInterceptorOptions?: AxiosInterceptorOptions$1;
64
+ }
65
+ declare function responseRetryInterceptor(options: ResponseRetryInterceptorOptions): ResponseInterceptor;
66
+ //#endregion
67
+ //#region src/interceptors/responseStatusInterceptor.d.ts
68
+ interface ResponseStatusInterceptorOptions {
69
+ validStatusHandler?: Record<number | string, (response: AxiosResponse$1<any, any>) => any>;
70
+ invalidStatusHandler?: Record<number | string, (error: any) => any>;
71
+ include?: MatchPattern[];
72
+ exclude?: MatchPattern[];
73
+ axiosInterceptorOptions?: AxiosInterceptorOptions$1;
74
+ }
75
+ declare function responseStatusInterceptor(options: ResponseStatusInterceptorOptions): ResponseInterceptor;
76
+ //#endregion
77
+ //#region src/interceptors/requestMd5Interceptor.d.ts
78
+ type RequestMd5InterceptorMapping = {
79
+ url: string | ((url: string) => boolean);
80
+ path: string[];
81
+ method?: string;
82
+ };
83
+ interface RequestMd5InterceptorOptions {
84
+ mappings?: RequestMd5InterceptorMapping[];
85
+ include?: MatchPattern[];
86
+ exclude?: MatchPattern[];
87
+ axiosInterceptorOptions?: AxiosInterceptorOptions$1;
88
+ }
89
+ declare function requestMd5Interceptor(options?: RequestMd5InterceptorOptions): RequestInterceptor;
90
+ //#endregion
91
+ export { AxiosError, AxiosInstance, AxiosInterceptorOptions, AxiosRequestConfig, AxiosRequestHeaders, AxiosResponse, AxleInstance, AxleRequestConfig, FetchMethod, FetchRunner, HeadersDefaults, Interceptor, InternalAxiosRequestConfig, MatchPattern, ModifyMethod, ModifyRunner, RequestHeadersInterceptorOptions, RequestInterceptor, RequestMd5InterceptorMapping, RequestMd5InterceptorOptions, RequestMockInterceptorMapping, RequestMockInterceptorOptions, ResponseBlobInterceptorOptions, ResponseInterceptor, ResponseRetryInterceptorOptions, ResponseStatusInterceptorOptions, ResponseType, RunnerMethod, WithResponseReturn, createAxle, createFetchRunner, createMatcher, createModifyRunner, download, isAxiosError, matchPattern, requestHeadersInterceptor, requestMd5Interceptor, requestMockInterceptor, responseBlobInterceptor, responseRetryInterceptor, responseStatusInterceptor, withResponse };
package/dist/index.mjs ADDED
@@ -0,0 +1,324 @@
1
+ import axios, { AxiosError, AxiosError as AxiosError$1, isAxiosError, isAxiosError as isAxiosError$1, isCancel } from "axios";
2
+ import qs from "qs";
3
+ import { inBrowser, isFunction, isString } from "parattail";
4
+ import md5 from "crypto-js/md5.js";
5
+ import get from "lodash/get.js";
6
+ import set from "lodash/set.js";
7
+ //#region src/utils/index.ts
8
+ function isFormData(value) {
9
+ return typeof FormData !== "undefined" && value instanceof FormData;
10
+ }
11
+ function formDataToObject(formData) {
12
+ const normalizedData = {};
13
+ formData.forEach((value, key) => {
14
+ normalizedData[key] = value;
15
+ });
16
+ return normalizedData;
17
+ }
18
+ function objectToFormData(object) {
19
+ const formData = new FormData();
20
+ Object.keys(object).forEach((key) => formData.append(key, object[key]));
21
+ return formData;
22
+ }
23
+ //#endregion
24
+ //#region src/instance.ts
25
+ function createFetchRunner(service, method, responseType) {
26
+ return function(url, params, config) {
27
+ return service[method](url, {
28
+ params,
29
+ responseType,
30
+ ...config
31
+ });
32
+ };
33
+ }
34
+ function createModifyRunner(service, method, contentType) {
35
+ return function(url, params, config) {
36
+ let normalizedParams = params ?? {};
37
+ if (contentType === "application/x-www-form-urlencoded") normalizedParams = qs.stringify(normalizedParams);
38
+ if (contentType === "multipart/form-data") normalizedParams = objectToFormData(normalizedParams);
39
+ return service[method](url, normalizedParams, {
40
+ headers: { "Content-Type": contentType },
41
+ ...config
42
+ });
43
+ };
44
+ }
45
+ function createAxle(config = {}) {
46
+ const service = axios.create(config);
47
+ function getHeaders() {
48
+ return service.defaults.headers.common;
49
+ }
50
+ function setHeader(key, value) {
51
+ service.defaults.headers.common[key] = value;
52
+ }
53
+ function removeHeader(key) {
54
+ if (typeof key === "string") {
55
+ Reflect.deleteProperty(service.defaults.headers.common, key);
56
+ return;
57
+ }
58
+ key.forEach((k) => Reflect.deleteProperty(service.defaults.headers.common, k));
59
+ }
60
+ function useRequestInterceptor(...interceptors) {
61
+ interceptors.forEach((interceptor) => {
62
+ service.interceptors.request.use(interceptor.onFulfilled, interceptor.onRejected, interceptor.options);
63
+ });
64
+ }
65
+ function useResponseInterceptor(...interceptors) {
66
+ interceptors.forEach((interceptor) => {
67
+ service.interceptors.response.use(interceptor.onFulfilled, interceptor.onRejected, interceptor.options);
68
+ });
69
+ }
70
+ return {
71
+ get: createFetchRunner(service, "get", "json"),
72
+ getBlob: createFetchRunner(service, "get", "blob"),
73
+ getDocument: createFetchRunner(service, "get", "document"),
74
+ getArrayBuffer: createFetchRunner(service, "get", "arraybuffer"),
75
+ getText: createFetchRunner(service, "get", "text"),
76
+ getStream: createFetchRunner(service, "get", "stream"),
77
+ head: createFetchRunner(service, "head", "json"),
78
+ headBlob: createFetchRunner(service, "head", "blob"),
79
+ headDocument: createFetchRunner(service, "head", "document"),
80
+ headArrayBuffer: createFetchRunner(service, "head", "arraybuffer"),
81
+ headText: createFetchRunner(service, "head", "text"),
82
+ headStream: createFetchRunner(service, "head", "stream"),
83
+ options: createFetchRunner(service, "options", "json"),
84
+ optionsBlob: createFetchRunner(service, "options", "blob"),
85
+ optionsDocument: createFetchRunner(service, "options", "document"),
86
+ optionsArrayBuffer: createFetchRunner(service, "options", "arraybuffer"),
87
+ optionsText: createFetchRunner(service, "options", "text"),
88
+ optionsStream: createFetchRunner(service, "options", "stream"),
89
+ delete: createFetchRunner(service, "delete", "json"),
90
+ deleteBlob: createFetchRunner(service, "delete", "blob"),
91
+ deleteDocument: createFetchRunner(service, "delete", "document"),
92
+ deleteArrayBuffer: createFetchRunner(service, "delete", "arraybuffer"),
93
+ deleteText: createFetchRunner(service, "delete", "text"),
94
+ deleteStream: createFetchRunner(service, "delete", "stream"),
95
+ post: createModifyRunner(service, "post", "application/json"),
96
+ postUrlEncode: createModifyRunner(service, "post", "application/x-www-form-urlencoded"),
97
+ postMultipart: createModifyRunner(service, "post", "multipart/form-data"),
98
+ put: createModifyRunner(service, "put", "application/json"),
99
+ putUrlEncode: createModifyRunner(service, "put", "application/x-www-form-urlencoded"),
100
+ putMultipart: createModifyRunner(service, "put", "multipart/form-data"),
101
+ patch: createModifyRunner(service, "patch", "application/json"),
102
+ patchUrlEncode: createModifyRunner(service, "patch", "application/x-www-form-urlencoded"),
103
+ patchMultipart: createModifyRunner(service, "patch", "multipart/form-data"),
104
+ getHeaders,
105
+ setHeader,
106
+ removeHeader,
107
+ useRequestInterceptor,
108
+ useResponseInterceptor,
109
+ axios: service
110
+ };
111
+ }
112
+ //#endregion
113
+ //#region src/matcher.ts
114
+ function matchPattern(pattern, method, url, status) {
115
+ if (isFunction(pattern)) return pattern({
116
+ url,
117
+ method,
118
+ status
119
+ });
120
+ if (pattern.startsWith("status:")) return pattern.replace("status:", "").trim() === String(status);
121
+ return pattern.startsWith("method:") ? pattern.replace("method:", "").trim() === method : url === pattern;
122
+ }
123
+ function createMatcher(include, exclude) {
124
+ function matcher(method, url, status) {
125
+ if (!include && !exclude) return true;
126
+ if ((exclude ?? []).some((pattern) => matchPattern(pattern, method, url, status))) return false;
127
+ if (!include) return true;
128
+ return (include ?? []).some((pattern) => matchPattern(pattern, method, url, status));
129
+ }
130
+ return matcher;
131
+ }
132
+ //#endregion
133
+ //#region src/helper.ts
134
+ function withResponse(promise) {
135
+ return new Promise((resolve, reject) => {
136
+ promise.then((response) => {
137
+ resolve({
138
+ response,
139
+ errorResponse: void 0
140
+ });
141
+ }).catch((error) => {
142
+ if (isAxiosError$1(error)) resolve({
143
+ response: void 0,
144
+ errorResponse: error.response
145
+ });
146
+ else reject(error);
147
+ });
148
+ });
149
+ }
150
+ function download(url, filename) {
151
+ if (!inBrowser()) return;
152
+ const a = document.createElement("a");
153
+ a.download = filename;
154
+ a.style.display = "none";
155
+ a.href = typeof url === "string" ? url : URL.createObjectURL(url);
156
+ document.body.appendChild(a);
157
+ a.click();
158
+ URL.revokeObjectURL(a.href);
159
+ document.body.removeChild(a);
160
+ }
161
+ //#endregion
162
+ //#region src/interceptors/requestHeadersInterceptor.ts
163
+ function requestHeadersInterceptor(options = {}) {
164
+ const { headers: headersOrGetter } = options;
165
+ return {
166
+ onFulfilled(config) {
167
+ if (!createMatcher(options.include, options.exclude)(config.method ?? "", config.url ?? "")) return config;
168
+ const headers = (isFunction(headersOrGetter) ? headersOrGetter() : headersOrGetter) ?? {};
169
+ Object.entries(headers).forEach(([key, value]) => {
170
+ config.headers[key] = value;
171
+ });
172
+ return config;
173
+ },
174
+ onRejected: (error) => Promise.reject(error),
175
+ options: options.axiosInterceptorOptions
176
+ };
177
+ }
178
+ //#endregion
179
+ //#region src/interceptors/requestMockInterceptor.ts
180
+ function settle(response, resolve, reject, delay = 0) {
181
+ if (delay > 0) {
182
+ setTimeout(() => {
183
+ settle(response, resolve, reject);
184
+ }, delay);
185
+ return;
186
+ }
187
+ if (!response.config.validateStatus || response.config.validateStatus(response.status)) resolve(response);
188
+ else reject(new AxiosError$1(`Request failed with status code ${response.status}`, void 0, response.config, response));
189
+ }
190
+ function requestMockInterceptor(options = {}) {
191
+ return {
192
+ onFulfilled(config) {
193
+ if (!createMatcher(options.include, options.exclude)(config.method ?? "", config.url ?? "")) return config;
194
+ const findMapping = () => (options.mappings ?? []).find((mapping) => {
195
+ const isMatchUrl = isFunction(mapping.url) ? mapping.url(config.url ?? "") : mapping.url === (config.url ?? "");
196
+ const isMatchMethod = mapping.method != null ? config.method === mapping.method : true;
197
+ return isMatchUrl && isMatchMethod;
198
+ });
199
+ const mapping = findMapping();
200
+ if (!mapping) return config;
201
+ config.adapter = () => {
202
+ const partialResponse = mapping.handler(config);
203
+ const response = {
204
+ ...partialResponse,
205
+ headers: config.headers,
206
+ config,
207
+ request: {},
208
+ data: partialResponse.data,
209
+ status: partialResponse.status ?? 200,
210
+ statusText: partialResponse.statusText ?? "OK"
211
+ };
212
+ return new Promise((resolve, reject) => {
213
+ settle(response, resolve, reject, mapping.delay);
214
+ });
215
+ };
216
+ return config;
217
+ },
218
+ onRejected: (error) => Promise.reject(error),
219
+ options: options.axiosInterceptorOptions
220
+ };
221
+ }
222
+ //#endregion
223
+ //#region src/interceptors/responseBlobInterceptor.ts
224
+ function responseBlobInterceptor(options = {}) {
225
+ return {
226
+ onFulfilled(response) {
227
+ if (!createMatcher(options.include, options.exclude)(response.config.method ?? "", response.config.url ?? "", response.status)) return response;
228
+ if (response.request.responseType === "blob") return options.onResponse?.(response) ?? response;
229
+ return response;
230
+ },
231
+ onRejected: (error) => Promise.reject(error),
232
+ options: options.axiosInterceptorOptions
233
+ };
234
+ }
235
+ //#endregion
236
+ //#region src/interceptors/responseRetryInterceptor.ts
237
+ function responseRetryInterceptor(options) {
238
+ return {
239
+ onFulfilled: (response) => response,
240
+ onRejected(error) {
241
+ if (!createMatcher(options.include, options.exclude)(error.config.method ?? "", error.config.url ?? "", error?.response?.status) || isCancel(error)) return Promise.reject(error);
242
+ const { count = 1 } = options;
243
+ let retryCount = 0;
244
+ async function retry() {
245
+ try {
246
+ retryCount++;
247
+ return await axios.create()(error.config);
248
+ } catch (error) {
249
+ if (retryCount === count) return Promise.reject(error);
250
+ return retry();
251
+ }
252
+ }
253
+ return retry();
254
+ },
255
+ options: options.axiosInterceptorOptions
256
+ };
257
+ }
258
+ //#endregion
259
+ //#region src/interceptors/responseStatusInterceptor.ts
260
+ function responseStatusInterceptor(options) {
261
+ return {
262
+ onFulfilled: (response) => {
263
+ if (!createMatcher(options.include, options.exclude)(response.config.method ?? "", response.config.url ?? "", response.status)) return response;
264
+ const handler = (options.validStatusHandler ?? {})[response.status];
265
+ if (!handler) return response;
266
+ return handler(response) ?? response;
267
+ },
268
+ onRejected: (error) => {
269
+ if (!createMatcher(options.include, options.exclude)(error.config.method ?? "", error.config.url ?? "", error?.response?.status)) return Promise.reject(error);
270
+ const handler = (options.invalidStatusHandler ?? {})[error.response.status];
271
+ if (!handler) return Promise.reject(error);
272
+ return handler(error) ?? Promise.reject(error);
273
+ },
274
+ options: options.axiosInterceptorOptions
275
+ };
276
+ }
277
+ //#endregion
278
+ //#region src/interceptors/requestMd5Interceptor.ts
279
+ function withCtxMd5(ctx, mapping) {
280
+ mapping.path.forEach((path) => {
281
+ const targetValue = get(ctx, path);
282
+ if (targetValue != null) set(ctx, path, md5(String(targetValue)).toString());
283
+ });
284
+ }
285
+ function withMd5(config, mapping) {
286
+ const { data = {}, params = {}, headers = {} } = config;
287
+ const ctx = {
288
+ data: isFormData(data) ? data : JSON.parse(JSON.stringify(data)),
289
+ params: JSON.parse(JSON.stringify(params)),
290
+ headers: JSON.parse(JSON.stringify(headers))
291
+ };
292
+ if (isString(ctx.data) && ctx.data.length > 0 && ctx.headers["Content-Type"] === "application/x-www-form-urlencoded") {
293
+ ctx.data = qs.parse(ctx.data);
294
+ withCtxMd5(ctx, mapping);
295
+ ctx.data = qs.stringify(ctx.data);
296
+ } else if (isFormData(ctx.data)) {
297
+ ctx.data = formDataToObject(ctx.data);
298
+ withCtxMd5(ctx, mapping);
299
+ ctx.data = objectToFormData(ctx.data);
300
+ } else withCtxMd5(ctx, mapping);
301
+ return {
302
+ ...config,
303
+ ...ctx
304
+ };
305
+ }
306
+ function requestMd5Interceptor(options = {}) {
307
+ return {
308
+ onFulfilled(config) {
309
+ if (!createMatcher(options.include, options.exclude)(config.method ?? "", config.url ?? "")) return config;
310
+ const findMapping = () => (options.mappings ?? []).find((mapping) => {
311
+ const isMatchUrl = isFunction(mapping.url) ? mapping.url(config.url ?? "") : mapping.url === (config.url ?? "");
312
+ const isMatchMethod = mapping.method != null ? config.method === mapping.method : true;
313
+ return isMatchUrl && isMatchMethod;
314
+ });
315
+ const mapping = findMapping();
316
+ if (!mapping) return config;
317
+ return withMd5(config, mapping);
318
+ },
319
+ onRejected: (error) => Promise.reject(error),
320
+ options: options.axiosInterceptorOptions
321
+ };
322
+ }
323
+ //#endregion
324
+ export { AxiosError, createAxle, createFetchRunner, createMatcher, createModifyRunner, download, isAxiosError, matchPattern, requestHeadersInterceptor, requestMd5Interceptor, requestMockInterceptor, responseBlobInterceptor, responseRetryInterceptor, responseStatusInterceptor, withResponse };
@@ -0,0 +1,64 @@
1
+ import { AxiosError as AxiosError$1, AxiosInstance, AxiosInterceptorOptions as AxiosInterceptorOptions$1, AxiosRequestConfig as AxiosRequestConfig$1, AxiosRequestHeaders, AxiosResponse as AxiosResponse$1, HeadersDefaults, InternalAxiosRequestConfig, ResponseType, isAxiosError as isAxiosError$1 } from "axios";
2
+
3
+ //#region src/instance.d.ts
4
+ interface AxleRequestConfig<D = any, E = Record<string, any>> extends AxiosRequestConfig$1<D> {
5
+ extra?: E;
6
+ }
7
+ type FetchRunner = <R = AxiosResponse$1, P = Record<string, any>, D = Record<string, any>>(url: string, params?: P, config?: AxleRequestConfig<D>) => Promise<R>;
8
+ type ModifyRunner = <R = AxiosResponse$1, P = Record<string, any>, D = Record<string, any>>(url: string, params?: P, config?: AxleRequestConfig<D>) => Promise<R>;
9
+ type FetchMethod = 'get' | 'delete' | 'options' | 'head';
10
+ type ModifyMethod = 'post' | 'put' | 'patch';
11
+ type RunnerMethod = keyof Omit<AxleInstance, 'axios' | 'getHeaders' | 'setHeader' | 'removeHeader' | 'useRequestInterceptor' | 'useResponseInterceptor'>;
12
+ interface Interceptor<V> {
13
+ onFulfilled?: ((value: V) => any) | null;
14
+ onRejected?: ((error: any) => any) | null;
15
+ options?: AxiosInterceptorOptions$1;
16
+ }
17
+ type RequestInterceptor = Interceptor<InternalAxiosRequestConfig>;
18
+ type ResponseInterceptor<V = AxiosResponse$1<any, any>> = Interceptor<V>;
19
+ type AxleInstance = {
20
+ get: FetchRunner;
21
+ getBlob: FetchRunner;
22
+ getDocument: FetchRunner;
23
+ getText: FetchRunner;
24
+ getArrayBuffer: FetchRunner;
25
+ getStream: FetchRunner;
26
+ head: FetchRunner;
27
+ headBlob: FetchRunner;
28
+ headDocument: FetchRunner;
29
+ headText: FetchRunner;
30
+ headArrayBuffer: FetchRunner;
31
+ headStream: FetchRunner;
32
+ options: FetchRunner;
33
+ optionsBlob: FetchRunner;
34
+ optionsDocument: FetchRunner;
35
+ optionsText: FetchRunner;
36
+ optionsArrayBuffer: FetchRunner;
37
+ optionsStream: FetchRunner;
38
+ delete: FetchRunner;
39
+ deleteBlob: FetchRunner;
40
+ deleteDocument: FetchRunner;
41
+ deleteText: FetchRunner;
42
+ deleteArrayBuffer: FetchRunner;
43
+ deleteStream: FetchRunner;
44
+ post: ModifyRunner;
45
+ postUrlEncode: ModifyRunner;
46
+ postMultipart: ModifyRunner;
47
+ put: ModifyRunner;
48
+ putUrlEncode: ModifyRunner;
49
+ putMultipart: ModifyRunner;
50
+ patch: ModifyRunner;
51
+ patchUrlEncode: ModifyRunner;
52
+ patchMultipart: ModifyRunner;
53
+ getHeaders(): HeadersDefaults['common'];
54
+ setHeader(key: string, value: string): void;
55
+ removeHeader(key: string | string[]): void;
56
+ useRequestInterceptor(...interceptors: RequestInterceptor[]): void;
57
+ useResponseInterceptor(...interceptors: ResponseInterceptor[]): void;
58
+ axios: AxiosInstance;
59
+ };
60
+ declare function createFetchRunner(service: AxiosInstance, method: FetchMethod, responseType: ResponseType): <R = AxiosResponse$1<any, any, {}>, P = Record<string, any>, D = Record<string, any>>(url: string, params?: P | undefined, config?: AxleRequestConfig<D, Record<string, any>> | undefined) => Promise<R>;
61
+ declare function createModifyRunner(service: AxiosInstance, method: ModifyMethod, contentType: 'application/json' | 'multipart/form-data' | 'application/x-www-form-urlencoded'): <R = AxiosResponse$1<any, any, {}>, P = Record<string, any>, D = Record<string, any>>(url: string, params?: P | undefined, config?: AxleRequestConfig<D, Record<string, any>> | undefined) => Promise<R>;
62
+ declare function createAxle(config?: AxleRequestConfig): AxleInstance;
63
+ //#endregion
64
+ export { isAxiosError$1 as C, createModifyRunner as S, ResponseInterceptor as _, AxiosRequestHeaders as a, createAxle as b, AxleRequestConfig as c, HeadersDefaults as d, Interceptor as f, RequestInterceptor as g, ModifyRunner as h, AxiosRequestConfig$1 as i, FetchMethod as l, ModifyMethod as m, AxiosInstance as n, AxiosResponse$1 as o, InternalAxiosRequestConfig as p, AxiosInterceptorOptions$1 as r, AxleInstance as s, AxiosError$1 as t, FetchRunner as u, ResponseType as v, createFetchRunner as x, RunnerMethod as y };
package/dist/use.d.mts ADDED
@@ -0,0 +1,85 @@
1
+ import { c as AxleRequestConfig, s as AxleInstance, y as RunnerMethod } from "./instance-9YUALwMk.mjs";
2
+ import { Ref } from "vue";
3
+
4
+ //#region src/use.d.ts
5
+ type Runnable = () => boolean;
6
+ interface RunOptions<V, P, D> {
7
+ url?: string;
8
+ params?: P;
9
+ config?: AxleRequestConfig<D>;
10
+ resetValue?: boolean;
11
+ cloneResetValue?: boolean | ((value: V) => V);
12
+ }
13
+ type UseAxleExtra<V> = {
14
+ loading: Ref<boolean>;
15
+ error: Ref<Error | undefined>;
16
+ uploadProgress: Ref<number>;
17
+ downloadProgress: Ref<number>;
18
+ pollingCanceled: Ref<boolean>;
19
+ abort(): void;
20
+ resetValue(options?: ResetValueOptions<V>): void;
21
+ invalidateCache(): void;
22
+ cancelPolling(): void;
23
+ };
24
+ interface UseAxleRefs<V> {
25
+ value: Ref<V>;
26
+ loading: Ref<boolean>;
27
+ error: Ref<Error | undefined>;
28
+ uploadProgress: Ref<number>;
29
+ downloadProgress: Ref<number>;
30
+ pollingCanceled: Ref<boolean>;
31
+ }
32
+ type Run<V, R, P, D> = {
33
+ (options?: RunOptions<V, P, D>): Promise<R>;
34
+ } & UseAxleExtra<V>;
35
+ type WatchOptions = boolean | {
36
+ params?: boolean;
37
+ config?: boolean;
38
+ _custom?: () => any;
39
+ };
40
+ interface UseAxleOptions<V = any, R = any, P = Record<string, any>, D = Record<string, any>> {
41
+ url: string | (() => string);
42
+ method: RunnerMethod;
43
+ value?: V;
44
+ immediate?: boolean;
45
+ resetValue?: boolean;
46
+ cloneResetValue?: boolean | ((value: V) => V);
47
+ abortOnUnmount?: boolean;
48
+ cacheKey?: string | (() => string);
49
+ cacheTime?: number;
50
+ config?: AxleRequestConfig<D> | (() => AxleRequestConfig<D>);
51
+ watch?: WatchOptions;
52
+ pollingInterval?: number;
53
+ pollingOnHidden?: boolean;
54
+ pollingOnDeactivated?: boolean;
55
+ refreshOnWindowFocus?: boolean;
56
+ params?: P | (() => P);
57
+ onBefore?(refs: UseAxleRefs<V>): void;
58
+ onAfter?(refs: UseAxleRefs<V>): void;
59
+ onTransform?(response: R, refs: UseAxleRefs<V>): V | Promise<V>;
60
+ onSuccess?(response: R, refs: UseAxleRefs<V>): void;
61
+ onError?(error: Error, refs: UseAxleRefs<V>): void;
62
+ }
63
+ interface ResetValueOptions<V> {
64
+ cloneResetValue?: boolean | ((value: V) => V);
65
+ }
66
+ type UseAxleInstance<V, R, P, D> = [value: Ref<V>, run: Run<V, R, P, D>, extra: UseAxleExtra<V>];
67
+ interface CreateUseAxleOptions {
68
+ axle: AxleInstance;
69
+ immediate?: boolean;
70
+ abortOnUnmount?: boolean;
71
+ cacheTime?: number;
72
+ onTransform?(response: any, refs: any): any;
73
+ }
74
+ type UseAxleOptionsWithRunnable<V = any, R = any, P = Record<string, any>, D = Record<string, any>> = UseAxleOptions<V, R, P, D> & {
75
+ runnable: Runnable;
76
+ };
77
+ interface UseAxle {
78
+ <V = any, R = any, P = Record<string, any>, D = Record<string, any>>(options: UseAxleOptionsWithRunnable<V, R, P, D>): UseAxleInstance<V, R | undefined, P, D>;
79
+ <V = any, R = any, P = Record<string, any>, D = Record<string, any>>(options: UseAxleOptions<V, R, P, D>): UseAxleInstance<V, R, P, D>;
80
+ }
81
+ declare function normalizeValueGetter<T>(valueGetter: T | (() => T)): T;
82
+ declare function cleanupCacheBuffer(): void;
83
+ declare function createUseAxle(options: CreateUseAxleOptions): UseAxle;
84
+ //#endregion
85
+ export { CreateUseAxleOptions, ResetValueOptions, Run, RunOptions, Runnable, UseAxle, UseAxleExtra, UseAxleInstance, UseAxleOptions, UseAxleOptionsWithRunnable, UseAxleRefs, WatchOptions, cleanupCacheBuffer, createUseAxle, normalizeValueGetter };
package/dist/use.mjs ADDED
@@ -0,0 +1,229 @@
1
+ import { isFunction } from "parattail";
2
+ import { getCurrentInstance, onActivated, onDeactivated, onMounted, onUnmounted, ref, watch } from "vue";
3
+ //#region src/use.ts
4
+ function normalizeValueGetter(valueGetter) {
5
+ return isFunction(valueGetter) ? valueGetter() : valueGetter;
6
+ }
7
+ const cacheBuffer = /* @__PURE__ */ new Map();
8
+ function cleanupCacheBuffer() {
9
+ cacheBuffer.forEach((value, key) => {
10
+ if (value.expiredTime && Date.now() >= value.expiredTime) cacheBuffer.delete(key);
11
+ });
12
+ }
13
+ function createUseAxle(options) {
14
+ const { axle, onTransform: defaultOnTransform, immediate: defaultImmediate = true, abortOnUnmount: defaultAbortOnUnmount = true, cacheTime: defaultCacheTime = Infinity } = options;
15
+ const useAxle = (options) => {
16
+ const { url: initialUrlOrGetter, method, immediate = defaultImmediate, abortOnUnmount = defaultAbortOnUnmount, cacheTime = defaultCacheTime, cacheKey, pollingInterval, pollingOnHidden = true, pollingOnDeactivated = false, refreshOnWindowFocus = false, value: initialValue, resetValue: initialResetValue, cloneResetValue: initialCloneResetValue, params: initialParamsOrGetter, config: initialConfigOrGetter, watch: watchOptions, runnable = () => true, onBefore = () => {}, onAfter = () => {}, onTransform = defaultOnTransform ?? ((response) => response), onSuccess = () => {}, onError = () => {} } = options;
17
+ const value = ref(initialValue);
18
+ const loading = ref(false);
19
+ const error = ref();
20
+ const downloadProgress = ref(0);
21
+ const uploadProgress = ref(0);
22
+ const pollingCanceled = ref(false);
23
+ const refs = {
24
+ value,
25
+ loading,
26
+ error,
27
+ downloadProgress,
28
+ uploadProgress,
29
+ pollingCanceled
30
+ };
31
+ const extra = {
32
+ uploadProgress,
33
+ downloadProgress,
34
+ loading,
35
+ error,
36
+ pollingCanceled,
37
+ abort,
38
+ resetValue,
39
+ invalidateCache,
40
+ cancelPolling
41
+ };
42
+ let controller = new AbortController();
43
+ let pollingTimer = null;
44
+ let deactivated = false;
45
+ let hidden = false;
46
+ let unmounted = false;
47
+ const run = Object.assign(async (options = {}) => {
48
+ if (!runnable() || abortOnUnmount && unmounted) return;
49
+ pollingCanceled.value = false;
50
+ if (controller.signal.aborted) controller = new AbortController();
51
+ if ((options.resetValue ?? initialResetValue ?? false) === true) resetValue(options);
52
+ uploadProgress.value = 0;
53
+ downloadProgress.value = 0;
54
+ const url = options.url ?? normalizeValueGetter(initialUrlOrGetter);
55
+ const params = options.params ?? normalizeValueGetter(initialParamsOrGetter);
56
+ const config = options.config ?? normalizeValueGetter(initialConfigOrGetter);
57
+ const normalizedCacheKey = cacheKey ? normalizeValueGetter(cacheKey) : void 0;
58
+ onBefore(refs);
59
+ loading.value = true;
60
+ try {
61
+ cleanupCacheBuffer();
62
+ const response = await getResponse();
63
+ if (shouldSetCacheResponse(normalizedCacheKey)) {
64
+ const cache = cacheBuffer.get(normalizedCacheKey);
65
+ cache.response = response;
66
+ cache.expiredTime = Date.now() + cacheTime;
67
+ }
68
+ value.value = await onTransform(response, refs);
69
+ error.value = void 0;
70
+ onSuccess(response, refs);
71
+ loading.value = false;
72
+ onAfter(refs);
73
+ return response;
74
+ } catch (responseError) {
75
+ error.value = responseError;
76
+ onError(responseError, refs);
77
+ loading.value = false;
78
+ onAfter(refs);
79
+ throw responseError;
80
+ } finally {
81
+ clearPolling();
82
+ startPolling();
83
+ }
84
+ function getResponse() {
85
+ if (shouldUseCache(normalizedCacheKey)) return JSON.parse(JSON.stringify(cacheBuffer.get(normalizedCacheKey).response));
86
+ if (shouldAwaitCachePromise(normalizedCacheKey)) return cacheBuffer.get(normalizedCacheKey).promise;
87
+ const promise = fetchResponse();
88
+ if (shouldSetCachePromise(normalizedCacheKey)) cacheBuffer.set(normalizedCacheKey, { promise });
89
+ return promise;
90
+ }
91
+ function fetchResponse() {
92
+ return axle[method](url, params, {
93
+ signal: controller.signal,
94
+ onUploadProgress(event) {
95
+ uploadProgress.value = event.progress ?? 0;
96
+ },
97
+ onDownloadProgress(event) {
98
+ downloadProgress.value = event.progress ?? 0;
99
+ },
100
+ ...config
101
+ });
102
+ }
103
+ function shouldUseCache(key) {
104
+ if (!key || !cacheBuffer.has(key)) return false;
105
+ return cacheBuffer.get(key).response != null;
106
+ }
107
+ function shouldAwaitCachePromise(key) {
108
+ if (!key || !cacheBuffer.has(key)) return false;
109
+ return cacheBuffer.get(key).promise;
110
+ }
111
+ function shouldSetCachePromise(key) {
112
+ if (!key || cacheBuffer.has(key)) return false;
113
+ return true;
114
+ }
115
+ function shouldSetCacheResponse(key) {
116
+ if (!key || !cacheBuffer.has(key)) return false;
117
+ return cacheBuffer.get(key).response == null;
118
+ }
119
+ }, extra);
120
+ if (immediate) runWithInitialConfig();
121
+ if (getCurrentInstance()) {
122
+ onActivated(() => {
123
+ deactivated = false;
124
+ addVisibilityChangeListener();
125
+ addWindowFocusListener();
126
+ startPolling();
127
+ });
128
+ onMounted(() => {
129
+ addVisibilityChangeListener();
130
+ addWindowFocusListener();
131
+ });
132
+ onDeactivated(() => {
133
+ deactivated = true;
134
+ removeVisibilityChangeListener();
135
+ removeWindowFocusListener();
136
+ clearPolling();
137
+ });
138
+ onUnmounted(() => {
139
+ removeVisibilityChangeListener();
140
+ removeWindowFocusListener();
141
+ cancelPolling();
142
+ });
143
+ onUnmounted(() => {
144
+ unmounted = true;
145
+ if (abortOnUnmount) abort();
146
+ });
147
+ if (watchOptions) {
148
+ const normalizedWatchOptions = watchOptions === true ? {
149
+ params: true,
150
+ config: true
151
+ } : {
152
+ params: false,
153
+ config: false,
154
+ ...watchOptions
155
+ };
156
+ const enableWatchParams = isFunction(initialParamsOrGetter) && normalizedWatchOptions.params;
157
+ const enableWatchConfig = isFunction(initialConfigOrGetter) && normalizedWatchOptions.config;
158
+ watch(() => [
159
+ enableWatchParams ? normalizeValueGetter(initialParamsOrGetter) : void 0,
160
+ enableWatchConfig ? normalizeValueGetter(initialConfigOrGetter) : void 0,
161
+ normalizedWatchOptions._custom ? normalizedWatchOptions._custom() : void 0
162
+ ], () => {
163
+ runWithInitialConfig();
164
+ });
165
+ }
166
+ }
167
+ function runWithInitialConfig() {
168
+ return run({
169
+ url: normalizeValueGetter(initialUrlOrGetter),
170
+ params: normalizeValueGetter(initialParamsOrGetter),
171
+ config: normalizeValueGetter(initialConfigOrGetter)
172
+ });
173
+ }
174
+ function resetValue(options = {}) {
175
+ value.value = ((options.cloneResetValue ?? initialCloneResetValue ?? false) === true ? (v) => v == null ? null : JSON.parse(JSON.stringify(v)) : isFunction(initialCloneResetValue) ? initialCloneResetValue : (v) => v)(initialValue);
176
+ }
177
+ function abort() {
178
+ controller.abort();
179
+ }
180
+ function addWindowFocusListener() {
181
+ if (typeof window !== "undefined") window.addEventListener("focus", handleWindowFocus);
182
+ }
183
+ function removeWindowFocusListener() {
184
+ if (typeof window !== "undefined") window.removeEventListener("focus", handleWindowFocus);
185
+ }
186
+ function handleWindowFocus() {
187
+ if (refreshOnWindowFocus) runWithInitialConfig();
188
+ }
189
+ function addVisibilityChangeListener() {
190
+ if (typeof document !== "undefined") document.addEventListener("visibilitychange", handleVisibilityChange);
191
+ }
192
+ function removeVisibilityChangeListener() {
193
+ if (typeof document !== "undefined") document.removeEventListener("visibilitychange", handleVisibilityChange);
194
+ }
195
+ function handleVisibilityChange() {
196
+ hidden = document.visibilityState === "hidden";
197
+ if (pollingOnHidden) return;
198
+ hidden ? clearPolling() : startPolling();
199
+ }
200
+ function startPolling() {
201
+ if (pollingInterval == null || pollingCanceled.value || pollingTimer != null || deactivated && !pollingOnDeactivated || hidden && !pollingOnHidden) return;
202
+ pollingTimer = setTimeout(() => {
203
+ runWithInitialConfig();
204
+ }, pollingInterval);
205
+ }
206
+ function clearPolling() {
207
+ if (pollingTimer == null) return;
208
+ clearTimeout(pollingTimer);
209
+ pollingTimer = null;
210
+ }
211
+ function cancelPolling() {
212
+ clearPolling();
213
+ pollingCanceled.value = true;
214
+ }
215
+ function invalidateCache() {
216
+ const normalizedCacheKey = cacheKey ? normalizeValueGetter(cacheKey) : void 0;
217
+ if (!normalizedCacheKey || !cacheBuffer.has(normalizedCacheKey)) return;
218
+ cacheBuffer.delete(normalizedCacheKey);
219
+ }
220
+ return [
221
+ value,
222
+ run,
223
+ extra
224
+ ];
225
+ };
226
+ return useAxle;
227
+ }
228
+ //#endregion
229
+ export { cleanupCacheBuffer, createUseAxle, normalizeValueGetter };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanawan/axle",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Progressive request tool based on axios",
5
5
  "keywords": [
6
6
  "axios",
@@ -67,7 +67,7 @@
67
67
  "crypto-js": "^4.2.0",
68
68
  "lodash": "4.17.21",
69
69
  "qs": "^6.11.0",
70
- "@nanawan/rattail": "^2.0.3"
70
+ "parattail": "^2.0.10"
71
71
  },
72
72
  "devDependencies": {
73
73
  "@types/crypto-js": "^4.2.1",