UNPKG

signicat-client-ts

Version:

Community TypeScript client for Signicat Authentication REST API with automatic token management

272 lines (271 loc) 12 kB
"use strict"; 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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AxiosHttpRequest = void 0; const axios_1 = __importDefault(require("axios")); const form_data_1 = __importDefault(require("form-data")); const ApiError_1 = require("./ApiError"); const BaseHttpRequest_1 = require("./BaseHttpRequest"); const CancelablePromise_1 = require("./CancelablePromise"); const OpenAPI_1 = require("./OpenAPI"); const TokenManager_1 = require("./TokenManager"); let tokenManager = null; const createTokenManager = () => { if (OpenAPI_1.SignicatAuth) { return new TokenManager_1.TokenManager(OpenAPI_1.SignicatAuth); } return null; }; const getTokenManager = () => { if (!tokenManager && OpenAPI_1.SignicatAuth) { tokenManager = createTokenManager(); } return tokenManager; }; class AxiosHttpRequest extends BaseHttpRequest_1.BaseHttpRequest { constructor(config) { super(config); } request(options) { return new CancelablePromise_1.CancelablePromise((resolve, reject, onCancel) => __awaiter(this, void 0, void 0, function* () { var _a; try { const tm = getTokenManager(); // 자동 토큰 관리가 설정되어 있고 토큰이 명시적으로 제공되지 않은 경우 if (tm && !this.config.TOKEN) { // 요청 전에 토큰을 가져옴 const token = yield tm.getToken(); const mutableOptions = Object.assign({}, options); mutableOptions.headers = Object.assign(Object.assign({}, mutableOptions.headers), { Authorization: `Bearer ${token}` }); options = mutableOptions; } const response = yield this.sendRequest(options, onCancel); resolve(response.data); } catch (error) { const axiosError = error; // 토큰 관련 오류(401)인 경우 토큰을 갱신하고 재시도 if (((_a = axiosError.response) === null || _a === void 0 ? void 0 : _a.status) === 401 && getTokenManager()) { try { // 토큰 강제 갱신 yield getTokenManager().refreshToken(); // 새 토큰으로 요청 재시도 const token = yield getTokenManager().getToken(); const mutableOptions = Object.assign({}, options); mutableOptions.headers = Object.assign(Object.assign({}, mutableOptions.headers), { Authorization: `Bearer ${token}` }); const response = yield this.sendRequest(mutableOptions, onCancel); resolve(response.data); } catch (retryError) { reject(this.handleError(retryError, options)); } } else { reject(this.handleError(error, options)); } } })); } sendRequest(options, onCancel) { return __awaiter(this, void 0, void 0, function* () { const url = `${this.config.BASE}${options.url}`; const formData = this.getFormData(options); const body = this.getRequestBody(options); const headers = yield this.getHeaders(options); const cancelToken = options.cancelToken; const config = Object.assign({ url, data: body !== null && body !== void 0 ? body : formData, method: options.method, headers, params: options.query, timeout: options.timeout, withCredentials: this.config.WITH_CREDENTIALS, cancelToken }, (options.responseType && { responseType: options.responseType })); if (options.mediaType === "application/json") { config.data = JSON.stringify(config.data); } // Cancel handler 등록 if (onCancel && cancelToken) { onCancel(() => { if (cancelToken.cancel) { cancelToken.cancel("Request cancelled"); } }); } return axios_1.default.request(config); }); } handleError(error, options) { var _a; if (axios_1.default.isCancel(error)) { return new CancelablePromise_1.CancelError(error.message || "Request was cancelled"); } const axiosError = error; if (axiosError.response) { return new ApiError_1.ApiError(options, { url: ((_a = axiosError.response.config) === null || _a === void 0 ? void 0 : _a.url) || "", ok: false, status: axiosError.response.status, statusText: axiosError.response.statusText, body: axiosError.response.data, }, axiosError.message); } return new ApiError_1.ApiError(options, { url: "", ok: false, status: 0, statusText: axiosError.message, body: null, }, axiosError.message); } getFormData(options) { if (options.formData) { const formData = new form_data_1.default(); for (const key in options.formData) { if (options.formData[key] !== undefined && options.formData[key] !== null) { const value = options.formData[key]; if (value instanceof Array) { for (const item of value) { formData.append(key, item); } } else { formData.append(key, value); } } } return formData; } return undefined; } getRequestBody(options) { if (options.mediaType === "application/x-www-form-urlencoded" && options.body) { return new URLSearchParams(options.body).toString(); } return options.body; } getHeaders(options) { return __awaiter(this, void 0, void 0, function* () { var _a; const token = yield this.getToken(); const username = yield this.getUsername(); const password = yield this.getPassword(); const additionalHeaders = yield this.getAdditionalHeaders(); const headers = Object.assign(Object.assign({ Accept: (_a = options.mediaType) !== null && _a !== void 0 ? _a : "application/json" }, additionalHeaders), options.headers); if (options.mediaType) { headers["Content-Type"] = options.mediaType; } if (token) { headers.Authorization = `Bearer ${token}`; } if (username && password) { const credentials = btoa(`${username}:${password}`); headers.Authorization = `Basic ${credentials}`; } return headers; }); } getToken() { return __awaiter(this, void 0, void 0, function* () { const token = this.config.TOKEN; if (!token) { return undefined; } if (typeof token === "function") { return yield token({}); } return token; }); } getUsername() { return __awaiter(this, void 0, void 0, function* () { const username = this.config.USERNAME; if (!username) { return undefined; } if (typeof username === "function") { return yield username({}); } return username; }); } getPassword() { return __awaiter(this, void 0, void 0, function* () { const password = this.config.PASSWORD; if (!password) { return undefined; } if (typeof password === "function") { return yield password({}); } return password; }); } getAdditionalHeaders() { return __awaiter(this, void 0, void 0, function* () { const headers = this.config.HEADERS; if (!headers) { return {}; } if (typeof headers === "function") { return yield headers({}); } return headers; }); } request_(options) { return __awaiter(this, void 0, void 0, function* () { var _a; try { const tm = getTokenManager(); // 자동 토큰 관리가 설정되어 있고 토큰이 명시적으로 제공되지 않은 경우 if (tm && !this.config.TOKEN) { const token = yield tm.getToken(); const mutableOptions = Object.assign({}, options); mutableOptions.headers = Object.assign(Object.assign({}, mutableOptions.headers), { Authorization: `Bearer ${token}` }); options = mutableOptions; } const cancelToken = options.cancelToken; const config = Object.assign({ url: `${this.config.BASE}${options.url}`, method: options.method, headers: yield this.getHeaders(options), params: options.query, timeout: options.timeout, withCredentials: this.config.WITH_CREDENTIALS, cancelToken }, (options.responseType && { responseType: options.responseType })); const response = yield axios_1.default.request(config); const result = { url: response.config.url || "", ok: response.status >= 200 && response.status < 300, status: response.status, statusText: response.statusText, body: response.data, }; return result; } catch (error) { if (axios_1.default.isCancel(error)) { const cancelError = error; throw new CancelablePromise_1.CancelError(cancelError.message); } const axiosError = error; if (axiosError.response) { const result = { url: ((_a = axiosError.response.config) === null || _a === void 0 ? void 0 : _a.url) || "", ok: false, status: axiosError.response.status, statusText: axiosError.response.statusText, body: axiosError.response.data, }; throw new ApiError_1.ApiError(options, result, axiosError.message); } throw new ApiError_1.ApiError(options, { url: "", ok: false, status: 0, statusText: error.message, body: null, }, error.message); } }); } } exports.AxiosHttpRequest = AxiosHttpRequest;