UNPKG

fexjs

Version:

A lightweight and powerful Fetch API wrapper with interceptors, cancel tokens, and timeout support.

172 lines 7.41 kB
/* eslint-disable @typescript-eslint/no-unused-vars */ var __awaiter = (this && this.__awaiter) || function (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()); }); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; class FexCancelToken { constructor() { this.cancel = () => { }; this.controller = new AbortController(); this.promise = new Promise((resolve) => { this.cancel = (message) => { this.reason = message || "Request canceled"; this.controller.abort(); resolve(); }; }); } get signal() { return this.controller.signal; } } class FexInstance { constructor(config = {}) { this.interceptors = { request: { use: (onFulfilled, onRejected) => { this.requestInterceptors.push({ onFulfilled, onRejected }); }, }, response: { use: (onFulfilled, onRejected) => { this.responseInterceptors.push({ onFulfilled, onRejected }); }, }, }; this.requestInterceptors = []; this.responseInterceptors = []; this.defaultConfig = Object.assign({ headers: {} }, config); } request(method_1, url_1, data_1) { return __awaiter(this, arguments, void 0, function* (method, url, data, config = {}) { var _a; let mergedConfig = Object.assign(Object.assign(Object.assign({}, this.defaultConfig), config), { method, headers: Object.assign(Object.assign({}, this.defaultConfig.headers), config.headers) }); if (mergedConfig.baseURL && !url.startsWith("http")) { url = mergedConfig.baseURL.replace(/\/$/, "") + "/" + url.replace(/^\//, ""); } mergedConfig.url = url; for (const { onFulfilled, onRejected } of this.requestInterceptors) { try { mergedConfig = onFulfilled(mergedConfig); } catch (error) { if (onRejected) return Promise.reject(onRejected(error)); throw error; } } const headers = new Headers(mergedConfig.headers); const controller = new AbortController(); const timeout = (_a = mergedConfig.timeout) !== null && _a !== void 0 ? _a : 0; if (timeout > 0) { const timeoutSignal = AbortSignal.timeout(timeout); if (timeoutSignal.aborted) { controller.abort(); } timeoutSignal.addEventListener("abort", () => controller.abort()); } if (mergedConfig.cancelToken) { mergedConfig.cancelToken.promise.then(() => controller.abort()); } const { headers: _, timeout: __, cancelToken: ___ } = mergedConfig, restConfig = __rest(mergedConfig, ["headers", "timeout", "cancelToken"]); const fetchConfig = Object.assign({ headers, signal: controller.signal }, restConfig); if (data && method !== "GET" && method !== "HEAD") { if (data instanceof FormData || data instanceof Blob || data instanceof URLSearchParams) { fetchConfig.body = data; } else { fetchConfig.body = JSON.stringify(data); headers.set("Content-Type", "application/json"); } } try { const response = yield fetch(url, fetchConfig); let responseData; const contentType = response.headers.get("Content-Type") || ""; if (contentType.includes("application/json")) { responseData = (yield response.json()); } else if (contentType.includes("text/")) { responseData = (yield response.text()); } else if (contentType.includes("image/") || contentType.includes("application/octet-stream")) { responseData = (yield response.blob()); } else { responseData = (yield response.blob()); } const finalResponse = { data: responseData, status: response.status, statusText: response.statusText, headers: response.headers, config: mergedConfig, request: response, }; for (const { onFulfilled, onRejected } of this.responseInterceptors) { try { return yield onFulfilled(finalResponse); } catch (error) { if (onRejected) { return Promise.reject(onRejected(error)); } throw error; } } return finalResponse; } catch (error) { if (error instanceof Error && error.name === "AbortError") { console.error("⏳ 요청이 타임아웃되었거나 취소되었습니다."); return Promise.reject(new Error("Request aborted")); } for (const { onRejected } of this.responseInterceptors) { if (onRejected) return Promise.reject(onRejected(error)); } throw error; } }); } get(url, config) { return this.request("GET", url, undefined, config); } post(url, data, config) { return this.request("POST", url, data, config); } put(url, data, config) { return this.request("PUT", url, data, config); } delete(url, config) { return this.request("DELETE", url, undefined, config); } options(url, config) { return this.request("OPTIONS", url, undefined, config); } create(config = {}) { return new FexInstance(config); } } const fex = new FexInstance(); export default fex; export { FexCancelToken, FexInstance }; //# sourceMappingURL=fex.js.map