bc-checkout-sdk
Version:
BetterCommerce's Checkout NodeJS SDK enables BC client applications to integrate with Checkout merchant API system. It publishes an interface to interact with [Checkout API](https://api-reference.checkout.com/#operation/getPaymentDetails/) endpoints.
197 lines (196 loc) • 9.52 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const api_1 = __importDefault(require("../../base/api"));
const CheckoutEnvironment_1 = require("../../base/config/CheckoutEnvironment");
const entity_1 = require("../../base/entity");
const RequestMethod_1 = require("../../constants/enums/RequestMethod");
const SingletonFactory = (function () {
let accessToken = '';
const axiosInstance = api_1.default.create({
baseURL: CheckoutEnvironment_1.CheckoutEnvironment.baseUrl,
withCredentials: true,
});
const getToken = () => accessToken;
const setToken = (token) => (accessToken = token);
const clearToken = () => (accessToken = '');
axiosInstance.interceptors.request.use((config) => {
const token = getToken();
//this is to be changed when we implement currency / language switcher
if (token) {
config.headers['Authorization'] = 'Bearer ' + token;
}
return config;
}, (err) => Promise.reject(err));
/**
* This function creates an Axios response interceptor that handles 401 responses and
* refreshes the token by calling the /connect/token endpoint. It also logs the
* activity of the request and response.
*
* @private
* @returns {void}
*/
function createAxiosResponseInterceptor() {
const interceptor = axiosInstance.interceptors.response.use((response) => response, (error) => {
var _a, _b, _c;
const extras = CheckoutEnvironment_1.CheckoutEnvironment.getExtras();
const logActivity = extras === null || extras === void 0 ? void 0 : extras.logActivity;
//console.log(error)
// Reject promise if usual error
if (((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.status) !== 400 && ((_b = error === null || error === void 0 ? void 0 : error.response) === null || _b === void 0 ? void 0 : _b.status) !== 401 && ((_c = error === null || error === void 0 ? void 0 : error.response) === null || _c === void 0 ? void 0 : _c.status) !== 404) {
return Promise.reject(error);
}
if (logActivity) {
logActivity({
data: { error: error },
message: "Checkout.com OAuth Cached Token Expired",
});
}
/*
* When response code is 401, try to refresh the token.
* Eject the interceptor so it doesn't loop in case
* token refresh causes the 401 response
*/
axiosInstance.interceptors.response.eject(interceptor);
// return getAuthToken().finally(createAxiosResponseInterceptor)
const url = new URL('connect/token', CheckoutEnvironment_1.CheckoutEnvironment.getAuthUrl());
const auth = Buffer.from(`${CheckoutEnvironment_1.CheckoutEnvironment.getAccessId()}:${CheckoutEnvironment_1.CheckoutEnvironment.getAccessSecret()}`).toString("base64");
const requestConfig = {
url: url.href,
method: RequestMethod_1.RequestMethod.POST,
data: `grant_type=client_credentials&client_id=${CheckoutEnvironment_1.CheckoutEnvironment.getAccessId()}&client_secret=${CheckoutEnvironment_1.CheckoutEnvironment.getAccessSecret()}&scope=gateway`,
headers: {
Authorization: `Basic ${auth}`,
},
};
if (logActivity) {
logActivity({
data: requestConfig,
message: "Checkout.com OAuth Request",
});
}
return axiosInstance(requestConfig).then((res) => {
var _a, _b, _c;
//console.log("token", res.data.access_token)
setToken((_a = res === null || res === void 0 ? void 0 : res.data) === null || _a === void 0 ? void 0 : _a.access_token);
if (logActivity) {
logActivity({
data: { data: (_b = res === null || res === void 0 ? void 0 : res.data) === null || _b === void 0 ? void 0 : _b.access_token },
message: "Checkout.com OAuth Response",
});
}
error.response.config.headers['Authorization'] = `Bearer ${(_c = res === null || res === void 0 ? void 0 : res.data) === null || _c === void 0 ? void 0 : _c.access_token}`;
//console.log(error.response.config)
return axiosInstance(error.response.config);
}).catch((error) => {
if (logActivity) {
logActivity({
data: { error: error },
message: "Checkout.com OAuth Error",
});
}
console.log(error);
return Promise.reject(error);
}).finally(createAxiosResponseInterceptor);
});
}
createAxiosResponseInterceptor();
return { axiosInstance };
})();
const axiosInstance = SingletonFactory.axiosInstance;
Object.freeze(axiosInstance);
/**
* This function makes a request to the Checkout.com API and handles the response.
*
* @param {string} url - The URL of the API endpoint.
* @param {string} method - The HTTP method to use. Defaults to 'post'.
* @param {object} data - The data to send in the request body.
* @param {object} params - The URL parameters to send with the request.
* @param {object} headers - The headers to send with the request.
* @param {object} cookies - The cookies to send with the request.
* @param {string} baseUrl - The base URL of the API. Defaults to the value of `CheckoutEnvironment.getBaseUrl()`.
*
* @returns {Promise<object | { hasError: true, error: any }>} - A promise that resolves to the response data or an object with an error property.
*/
const fetcher = async ({ url = '', method = 'post', data = {}, params = {}, headers = {}, cookies = {}, baseUrl = "", }) => {
const computedUrl = new URL(url, baseUrl || CheckoutEnvironment_1.CheckoutEnvironment.getBaseUrl());
const config = {
method: method,
url: computedUrl.href,
headers,
};
if (Object.keys(params).length) {
config.params = params;
}
if (Object.keys(data).length) {
config.data = data;
}
//console.log(JSON.stringify(config))
try {
const response = await axiosInstance(config);
let responseCode = response.status;
let responseBody = response.data;
if (responseCode >= 200 && responseCode < 300) {
return responseBody;
}
else {
let status = undefined;
let errorCode = undefined;
let errorMessage = undefined;
if (responseBody != undefined) {
if ("status" in responseBody != undefined) {
status = responseBody.status;
}
if ("error_code" in responseBody != undefined) {
errorCode = responseBody.error_code;
}
if ("error_message" in responseBody != undefined) {
errorMessage = responseBody.error_message;
}
}
switch (responseCode) {
case 400:
case 404:
throw new entity_1.InvalidRequestException(responseCode, status, errorCode, errorMessage);
case 401:
throw new entity_1.AuthenticationException(responseCode, status, errorCode, errorMessage);
default:
throw new entity_1.APIException(responseCode, "internal_error", "internal_error", "Something went wrong.");
}
}
}
catch (error) {
let errorData = {};
if (error.response) {
//errorData = error.response;
errorData = {
//headers: error.response.headers,
status: error.response.status,
data: error.response.data,
};
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
}
else if (error.request) {
errorData = error.request;
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
}
else {
errorData = error.message;
// Something happened in setting up the request that triggered an Error
console.log('Error: ' + error.message);
}
return { hasError: true, error: errorData };
//console.log(error, 'error inside fetcher');
//throw new Error(error.response.data.message);
}
};
exports.default = fetcher;