UNPKG

@uni-use/request

Version:

An easy to use axios based http client combinatorial api with support for return sequentially

898 lines (882 loc) 30.7 kB
/*! * @uni-use/request v1.6.0-beta.1 * An easy to use axios based http client combinatorial api with support for return sequentially * (c) 2022-2023 saqqdy<https://github.com/saqqdy> * Released under the MIT License. */ this.useRequest = (function (axios, vueDemi) { 'use strict'; /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol */ var _extendStatics = function extendStatics(d, b) { _extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; } || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return _extendStatics(d, b); }; function __extends(d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); _extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var _assign = function __assign() { _assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return _assign.apply(this, arguments); }; function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function sent() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } function __values(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function next() { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; var Serializer = /** @class */function () { function Serializer(instance, options) { this.waiting = {}; this.unique = false; this.orderly = true; this.onCancel = null; var defaultOptions = { unique: false, orderly: true }; options = Object.assign(defaultOptions, options || {}); this.axiosInstance = instance; this.unique = options.unique; this.orderly = options.orderly; options.onCancel && (this.onCancel = options.onCancel); } /** * Do request * * @param config - axios request config * @returns - Promise<unknown> */ // public async request<T = any, R = AxiosResponse<T>, D = any>( // config: SerializerRequestOptions<D> // ): Promise<R> // public async request<T = any, R = AxiosResponse<T>, D = any>( // url: string, // config?: SerializerRequestOptions<D> // ): Promise<R> Serializer.prototype.request = function ( // url: string | SerializerRequestOptions<D>, config) { return __awaiter(this, void 0, void 0, function () { var _a, unique, _b, orderly, _c, url, promiseKey, source, abortController, promise; var _this = this; return __generator(this, function (_d) { _a = config.unique, unique = _a === void 0 ? this.unique : _a, _b = config.orderly, orderly = _b === void 0 ? this.orderly : _b, _c = config.url, url = _c === void 0 ? '' : _c; promiseKey = Symbol('promiseKey'); source = axios.CancelToken.source(); // config.requestOptions = extend(true, {}, options) config.cancelToken = source.token; if (typeof AbortController === 'function') { abortController = new AbortController(); config.signal = abortController.signal; } unique && this.clear(url); promise = new Promise(function (resolve, reject) { _this.axiosInstance(config).then(function (res) { if (!orderly) resolve(res);else _this.wait(url, promiseKey).then(function () { resolve(res); }); }).catch(function (err) { // Request cancelled if (axios.isCancel(err)) _this.onCancel && _this.onCancel(err, config); // Request error else reject(err); }).finally(function () { var index = _this.waiting[url].findIndex(function (el) { return el.promiseKey === promiseKey; }); index > -1 && _this.waiting[url].splice(index, 1); }); }); this.add(url, { promiseKey: promiseKey, promise: promise, source: source, abortController: abortController }); return [2 /*return*/, promise]; }); }); }; /** * Drop all un-need requests * * @param key - the key of waiting line, usually to be the request url */ Serializer.prototype.clear = function (key) { var e_1, _a; for (var url in this.waiting) { // no key => clean all if (!key || url === key) { var seriesList = this.waiting[url] || []; try { for (var seriesList_1 = (e_1 = void 0, __values(seriesList)), seriesList_1_1 = seriesList_1.next(); !seriesList_1_1.done; seriesList_1_1 = seriesList_1.next()) { var series = seriesList_1_1.value; series.source.cancel('request canceled'); series.abortController && series.abortController.abort(); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (seriesList_1_1 && !seriesList_1_1.done && (_a = seriesList_1.return)) _a.call(seriesList_1); } finally { if (e_1) throw e_1.error; } } this.waiting[url] = []; } } }; /** * Waiting to resolve the series before this request * * @param key - the key of waiting line, usually to be the request url * @param promiseKey - the unique promise key * @returns - Promise<void> */ Serializer.prototype.wait = function (key, promiseKey) { return __awaiter(this, void 0, void 0, function () { var seriesList, index; return __generator(this, function (_b) { switch (_b.label) { case 0: if (!this.orderly) return [2 /*return*/, Promise.resolve()]; seriesList = this.waiting[key] || []; index = seriesList.findIndex(function (item) { return item.promiseKey === promiseKey; }); _b.label = 1; case 1: if (!(index > 0)) return [3 /*break*/, 7]; index--; if (!(seriesList[index] && seriesList[index].promiseKey !== promiseKey)) return [3 /*break*/, 6]; _b.label = 2; case 2: _b.trys.push([2, 4,, 5]); return [4 /*yield*/, seriesList[index].promise // await seriesList.splice(index, 1)[0].promise ]; case 3: _b.sent(); return [3 /*break*/, 5]; case 4: _b.sent(); console.info('The task has been dropped'); return [3 /*break*/, 5]; case 5: seriesList.splice(index, 1); _b.label = 6; case 6: return [3 /*break*/, 1]; case 7: return [2 /*return*/]; } }); }); }; /** * set series to waiting list * * @param key - the key of waiting line, usually to be the request url * @param series - waiting object */ Serializer.prototype.add = function (key, series) { if (!(key in this.waiting)) this.waiting[key] = []; this.waiting[key].push(series); }; return Serializer; }(); /** * axios serializer wrapper function * * @param instance - axios or axios instance * @param options - serializer options * @return - axios instance with serializer feature */ function axiosSeries$1(instance, options) { var serializer = new Serializer(instance, options); function axiosWithSeries(url, config) { var _a; if (typeof url !== 'string') { config = url; } else { config !== null && config !== void 0 ? config : config = {}; (_a = config.url) !== null && _a !== void 0 ? _a : config.url = url; } return serializer.request(config); } // axiosWithSeries.defaults = instance.defaults // axiosWithSeries.interceptors = instance.interceptors // axiosWithSeries.getUri = instance.getUri // axiosWithSeries.request = instance.request // axiosWithSeries.get = instance.get // axiosWithSeries.delete = instance.delete // axiosWithSeries.head = instance.head // axiosWithSeries.options = instance.options // axiosWithSeries.post = instance.post // axiosWithSeries.put = instance.put // axiosWithSeries.patch = instance.patch // axiosWithSeries.postForm = instance.postForm // axiosWithSeries.putForm = instance.putForm // axiosWithSeries.patchForm = instance.patchForm // axiosWithSeries.create = instance.create // not in axios instance // axiosWithSeries.Cancel = instance.Cancel // axiosWithSeries.CancelToken = instance.CancelToken // axiosWithSeries.Axios = instance.Axios // axiosWithSeries.VERSION = instance.VERSION // axiosWithSeries.isCancel = instance.isCancel // axiosWithSeries.all = instance.all // axiosWithSeries.spread = instance.spread // axiosWithSeries.isAxiosError = instance.isAxiosError /** * all waiting series */ axiosWithSeries.series = serializer.waiting; /** * clear all series */ axiosWithSeries.clear = function () { // clear all serializer.clear(); }; return axiosWithSeries; } /** * Get the value of value/ref/getter. */ function toValue(r) { return typeof r === 'function' ? r() : vueDemi.unref(r); } /** * waiting for a while * * @param milliseconds - waiting time (milliseconds) * @param throwOnTimeout - throw on timeout */ var waiting = function waiting(milliseconds, throwOnTimeout) { if (throwOnTimeout === void 0) { throwOnTimeout = false; } return new Promise(function (resolve, reject) { return setTimeout(throwOnTimeout ? reject : resolve, milliseconds); }); }; var UntilBase = /** @class */function () { function UntilBase(r, isNot) { if (isNot === void 0) { isNot = false; } this.isNot = false; this.r = r; this.isNot = isNot !== null && isNot !== void 0 ? isNot : false; } // toMatch<U extends T = T>( // condition: (v: T) => v is U, // options?: UntilToMatchOptions // ): Not extends true ? Promise<Exclude<T, U>> : Promise<U> // toMatch<U extends T = T>( // condition: (v: T) => boolean, // options?: UntilToMatchOptions // ): Promise<T> UntilBase.prototype.toMatch = function ( // condition: ((v: T) => v is U) | ((v: T) => boolean), condition, _a) { var _this = this; var _b = _a === void 0 ? {} : _a, _c = _b.flush, flush = _c === void 0 ? 'sync' : _c, _d = _b.deep, deep = _d === void 0 ? false : _d, timeout = _b.timeout, throwOnTimeout = _b.throwOnTimeout; var stop = null; var watcher = new Promise(function (resolve) { stop = vueDemi.watch(_this.r, function (v) { if (condition(v) !== _this.isNot) { stop === null || stop === void 0 ? void 0 : stop(); resolve(v); } }, { flush: flush, deep: deep, immediate: true }); }); var promises = [watcher]; if (timeout != null) { promises.push(waiting(timeout, throwOnTimeout).then(function () { return toValue(_this.r); }).finally(function () { return stop === null || stop === void 0 ? void 0 : stop(); })); } return Promise.race(promises); }; UntilBase.prototype.changed = function (options) { return this.changedTimes(1, options); }; UntilBase.prototype.changedTimes = function (n, options) { if (n === void 0) { n = 1; } var count = -1; // skip the immediate check return this.toMatch(function () { count += 1; return count >= n; }, options); }; Object.defineProperty(UntilBase.prototype, "not", { get: function get() { this.isNot = !this.isNot; return this; }, enumerable: false, configurable: true }); return UntilBase; }(); var UntilArray = /** @class */function (_super) { __extends(UntilArray, _super); function UntilArray(r) { return _super.call(this, r) || this; } UntilArray.prototype.toContains = function (value, options) { return _super.prototype.toMatch.call(this, function (v) { var array = Array.from(v); return array.includes(value) || array.includes(toValue(value)); }, options); }; return UntilArray; }(UntilBase); var UntilValue = /** @class */function (_super) { __extends(UntilValue, _super); function UntilValue(r, isNot) { return _super.call(this, r, isNot) || this; } UntilValue.prototype.toBe = function (value, options) { var _this = this; if (!vueDemi.isRef(value)) return _super.prototype.toMatch.call(this, function (v) { return v === value; }, options); var _a = options !== null && options !== void 0 ? options : {}, _b = _a.flush, flush = _b === void 0 ? 'sync' : _b, _c = _a.deep, deep = _c === void 0 ? false : _c, timeout = _a.timeout, throwOnTimeout = _a.throwOnTimeout; var stop = null; var watcher = new Promise(function (resolve) { stop = vueDemi.watch([_this.r, value], function (_a) { var _b = __read(_a, 2), v1 = _b[0], v2 = _b[1]; if (_this.isNot !== (v1 === v2)) { stop === null || stop === void 0 ? void 0 : stop(); resolve(v1); } }, { flush: flush, deep: deep, immediate: true }); }); var promises = [watcher]; if (timeout != null) { promises.push(waiting(timeout, throwOnTimeout).then(function () { return toValue(_this.r); }).finally(function () { stop === null || stop === void 0 ? void 0 : stop(); return toValue(_this.r); })); } return Promise.race(promises); }; UntilValue.prototype.toBeTruthy = function (options) { return _super.prototype.toMatch.call(this, function (v) { return Boolean(v); }, options); }; UntilValue.prototype.toBeNull = function (options) { return this.toBe(null, options); }; UntilValue.prototype.toBeUndefined = function (options) { return this.toBe(undefined, options); }; UntilValue.prototype.toBeNaN = function (options) { return _super.prototype.toMatch.call(this, Number.isNaN, options); }; return UntilValue; }(UntilBase); function util(r, isNot) { if (Array.isArray(toValue(r))) return new UntilArray(r); return new UntilValue(r, isNot); } /** * Determine if it is an array * * @example * ```js * isArray([]) // true * ``` * @since 1.0.2 * @param target - any target * @returns - target is Array */ function isArray(target) { return Object.prototype.toString.call(target).includes('Array'); } function awaitToDone(promise) { var promises = []; for (var _i = 1; _i < arguments.length; _i++) { promises[_i - 1] = arguments[_i]; } if (!isArray(promise) && promises.length === 0) { return promise.then(function (data) { return [null, data]; }).catch(function (err) { return [err, undefined]; }); } return Promise.all([].concat(promise).concat(promises)).then(function (data) { return [null, data]; }).catch(function (err) { return [err, undefined]; }); } var instance, axiosSeries; var defaultOptions = { unique: true, orderly: true, refetch: false, immediate: true }; // function useRequest<T = any>( // config: InternalAxiosRequestConfig<T> & UseRequestConfig // ): UseRequestReturn<T> & PromiseLike<UseRequestReturn<T>> // function useRequest<T = any>( // config: InternalAxiosRequestConfig<T>, // options: UseRequestConfig // ): UseRequestReturn<T> & PromiseLike<UseRequestReturn<T>> function useRequest(url, config, options) { config = Object.assign({}, defaultOptions, config); var _a = options || config || {}, unique = _a.unique, orderly = _a.orderly, immediate = _a.immediate, // setHeaders, beforeRequest = _a.beforeRequest, afterRequest = _a.afterRequest, // updateDataOnError = false, // onRequestError, onResponseError = _a.onResponseError, onError = _a.onError // onCancel ; // const { refetch } = config // console.log(afterRequest) var data = vueDemi.shallowRef(null); var error = vueDemi.shallowRef(null); var isFetching = vueDemi.ref(false); var isFinished = vueDemi.ref(false); var statusCode = vueDemi.ref(null); var statusText = vueDemi.ref(''); var response = vueDemi.shallowRef(); // const execute = ref(null) if (!instance) { instance = axios.create({ timeout: 10000 }); // instance.interceptors.response.use( // res => { // response.value = res // statusCode.value = res.status // statusText.value = res.statusText // return res // }, // (err: any) => Promise.reject(err) // ) } // if (beforeRequest || onRequestError) { // instance.interceptors.request.clear() // instance.interceptors.request.use( // config => { // // isFetching.value = true // // console.log(6000, isFetching.value, isFinished.value) // return beforeRequest ? beforeRequest(config) : config // // return config // }, // (err: any) => { // // error.value = err // onRequestError && onRequestError(err) // return Promise.reject(err) // } // ) // } // if (onResponseError) { // instance.interceptors.response.clear() // instance.interceptors.response.use( // res => { // // response.value = res // // statusCode.value = res.status // // statusText.value = res.statusText // // isFinished.value = true // // isFetching.value = false // // data.value = res.data // // console.log(4000, isFetching.value, isFinished.value, Object.keys(res || {})) // // return afterRequest ? afterRequest(res) : res // return res // }, // (err: any) => { // // error.value = err // onResponseError && onResponseError(err) // return Promise.reject(err) // } // ) // } if (!axiosSeries) axiosSeries = axiosSeries$1(instance, { unique: unique, orderly: orderly, onCancel: function onCancel(err) { console.info('onCancel => ', err.message, err.config); } }); // if (setHeaders) setHeaders(instance) // if ( // // !instance.interceptors.request.handlers.some( // // ({ fulfilled }) => fulfilled === beforeRequest // // ) && // beforeRequest // ) { // instance.interceptors.request.use(beforeRequest, (err: any) => { // onRequestError && onRequestError(err) // return Promise.reject(err) // }) // } // if ( // // !instance.interceptors.response.handlers.some( // // ({ fulfilled }) => fulfilled === afterRequest // // ) && // afterRequest // ) { // instance.interceptors.response.use(afterRequest, (err: any) => { // onResponseError && onResponseError(err) // return Promise.reject(err) // }) // } // console.log( // 7000, // // options, // // config, // instance.interceptors.response.handlers // // instance.interceptors.response.handlers.includes(afterRequest) // ) /** * request */ function request(config // InternalAxiosRequestConfig<T> & UseRequestConfig // options?: UseRequestConfig ) { return __awaiter(this, void 0, void 0, function () { var _a, err, res, _b, _err_1; return __generator(this, function (_c) { switch (_c.label) { case 0: if (!beforeRequest) return [3 /*break*/, 2]; return [4 /*yield*/, beforeRequest(config)]; case 1: config = _c.sent(); _c.label = 2; case 2: isFinished.value = false; isFetching.value = true; return [4 /*yield*/, awaitToDone(axiosSeries(config))]; case 3: _a = __read.apply(void 0, [_c.sent(), 2]), err = _a[0], res = _a[1]; if (!res) return [3 /*break*/, 10]; response.value = res; statusCode.value = res.status; statusText.value = res.statusText; if (!afterRequest) return [3 /*break*/, 8]; _c.label = 4; case 4: _c.trys.push([4, 6,, 7]); _b = data; return [4 /*yield*/, afterRequest(res)]; case 5: _b.value = _c.sent(); return [3 /*break*/, 7]; case 6: _err_1 = _c.sent(); err = _err_1; onResponseError && onResponseError(err); return [3 /*break*/, 7]; case 7: return [3 /*break*/, 9]; case 8: data.value = res.data; _c.label = 9; case 9: return [3 /*break*/, 11]; case 10: if (err === null || err === void 0 ? void 0 : err.response) { response.value = err.response; statusCode.value = err.response.status; statusText.value = err.response.statusText; onResponseError && onResponseError(response.value); } else { onError && onError(err); } _c.label = 11; case 11: error.value = err; isFinished.value = true; isFetching.value = false; return [2 /*return*/, data.value]; } }); }); } /** * create request */ // function createRequest() { // return '' // } var shell = { isFinished: isFinished, statusCode: statusCode, statusText: statusText, response: response, error: error, data: data, isFetching: isFetching, // canAbort, // aborted, // abort, // execute, // json: setType('json'), // request: request // createRequest, // onResponse: responseEvent.on, // onError: errorEvent.on, // onFinally: finallyEvent.on }; // function setType(type: DataType) { // return () => { // if (!isFetching.value) { // config.type = type // return { // ...shell, // then(onFulfilled: any, onRejected: any) { // return waitUntilFinished().then(onFulfilled, onRejected) // } // } as any // } // return undefined // } // } function waitUntilFinished() { return new Promise(function (resolve, reject) { util(isFinished).toBe(true).then(function () { return resolve(shell); }).catch(function (error) { return reject(error); }); }); } if (immediate) Promise.resolve().then(function () { return request(config); }); return _assign(_assign({}, shell), { then: function then(onFulfilled, onRejected) { return waitUntilFinished().then(onFulfilled, onRejected); } }); } return useRequest; })(axios, VueDemi);