@adyen/api-library
Version:
The Adyen API Library for NodeJS enables you to work with Adyen APIs.
232 lines • 11.8 kB
JavaScript
;
/*
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
* Adyen NodeJS API Library
* Copyright (c) 2020 Adyen B.V.
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const https_1 = require("https");
const https_proxy_agent_1 = require("https-proxy-agent");
const fs = __importStar(require("fs"));
const url_1 = require("url");
const libraryConstants_1 = __importDefault(require("../constants/libraryConstants"));
const httpClientException_1 = __importDefault(require("./httpClientException"));
const apiException_1 = __importDefault(require("../services/exception/apiException"));
const apiConstants_1 = require("../constants/apiConstants");
const checkServerIdentity_1 = __importDefault(require("../helpers/checkServerIdentity"));
class HttpURLConnectionClient {
/**
* Sends an HTTP request to the specified endpoint with the provided JSON payload and configuration.
*
* This method sets up request headers, including authentication (API key or basic auth), content type,
* and timeout. If a certificate path is provided in the config, it installs a certificate verifier.
* Throws an ApiException when an error occurs (invalid API key, API error response, etc.).
*
* @param endpoint - The URL to which the request will be sent.
* @param json - The JSON string to be sent as the request body.
* @param config - The configuration object containing authentication, timeout, and certificate details.
* @param isApiRequired - Indicates whether an API key is required for this request.
* @param requestOptions - Additional options for the HTTP request, such as headers and timeout.
* @returns A promise that resolves with the response body as a string.
* @throws {ApiException} when an error occurs
*/
request(endpoint, json, config, isApiRequired, requestOptions) {
var _a;
(_a = requestOptions.headers) !== null && _a !== void 0 ? _a : (requestOptions.headers = {});
requestOptions.timeout = config.connectionTimeoutMillis;
if (config.certificatePath) {
this.installCertificateVerifier(config.certificatePath);
}
const apiKey = config.apiKey;
if (isApiRequired && !apiKey) {
return Promise.reject(new apiException_1.default("Invalid X-API-Key was used", 401));
}
if (apiKey) {
requestOptions.headers[apiConstants_1.ApiConstants.API_KEY] = apiKey;
}
else {
const authString = `${config.username}:${config.password}`;
const authStringEnc = Buffer.from(authString, "utf8").toString("base64");
requestOptions.headers.Authorization = `Basic ${authStringEnc}`;
}
requestOptions.headers[apiConstants_1.ApiConstants.CONTENT_TYPE] = apiConstants_1.ApiConstants.APPLICATION_JSON_TYPE;
const httpConnection = this.createRequest(endpoint, requestOptions, config.applicationName);
return this.doRequest(httpConnection, json);
}
createRequest(endpoint, requestOptions, applicationName) {
if (!requestOptions.headers) {
requestOptions.headers = {};
}
const url = new url_1.URL(endpoint);
requestOptions.hostname = url.hostname;
requestOptions.protocol = url.protocol;
requestOptions.port = url.port;
requestOptions.path = url.pathname;
if (requestOptions.params) {
requestOptions.path += "?" + new url_1.URLSearchParams(requestOptions.params).toString();
}
if (requestOptions && requestOptions.idempotencyKey) {
requestOptions.headers[apiConstants_1.ApiConstants.IDEMPOTENCY_KEY] = requestOptions.idempotencyKey;
delete requestOptions.idempotencyKey;
}
if (this.proxy && this.proxy.host) {
const { host, port, ...options } = this.proxy;
requestOptions.agent = new https_proxy_agent_1.HttpsProxyAgent({ host, port: port || 443, ...options });
}
else {
requestOptions.agent = new https_1.Agent(this.agentOptions);
}
requestOptions.headers["Cache-Control"] = "no-cache";
if (!requestOptions.method) {
requestOptions.method = apiConstants_1.ApiConstants.METHOD_POST;
}
requestOptions.headers[apiConstants_1.ApiConstants.ACCEPT_CHARSET] = HttpURLConnectionClient.CHARSET;
// user-agent header
const libInfo = `${libraryConstants_1.default.LIB_NAME}/${libraryConstants_1.default.LIB_VERSION}`;
requestOptions.headers[apiConstants_1.ApiConstants.USER_AGENT] = applicationName ? `${applicationName} ${libInfo}` : libInfo;
// custom headers
requestOptions.headers[apiConstants_1.ApiConstants.ADYEN_LIBRARY_NAME] = libraryConstants_1.default.LIB_NAME;
requestOptions.headers[apiConstants_1.ApiConstants.ADYEN_LIBRARY_VERSION] = libraryConstants_1.default.LIB_VERSION;
// create a new ClientRequest object
const req = (0, https_1.request)(requestOptions);
// set the timeout on the ClientRequest instance
if (requestOptions.timeout) {
req.setTimeout(requestOptions.timeout);
}
return req;
}
doRequest(connectionRequest, json) {
return new Promise((resolve, reject) => {
connectionRequest.flushHeaders();
connectionRequest.on("response", (res) => {
const response = {
statusCode: res.statusCode,
headers: res.headers,
body: ""
};
// define default exception (in case of error during the handling of the response)
const getException = (responseBody) => new httpClientException_1.default({
message: `HTTP Exception: ${response.statusCode}. ${res.statusMessage}`,
statusCode: response.statusCode,
errorCode: undefined,
responseHeaders: response.headers,
responseBody,
});
let exception = getException(response.body);
res.on("data", (chunk) => {
response.body += chunk;
});
res.on("end", () => {
if (!res.complete) {
reject(new Error("The connection was terminated while the message was still being sent"));
}
if (res.statusCode && (res.statusCode < 200 || res.statusCode >= 300)) {
// API error handling
try {
const formattedData = JSON.parse(response.body);
const isApiError = "status" in formattedData;
const isRequestError = "errors" in formattedData;
if (isApiError) {
// Adyen API has returned an error
exception = new httpClientException_1.default({
message: `HTTP Exception: ${formattedData.status}. ${res.statusMessage}: ${formattedData.message}`,
statusCode: formattedData.status,
errorCode: formattedData.errorCode,
responseHeaders: res.headers,
responseBody: response.body,
apiError: formattedData,
});
}
else if (isRequestError) {
exception = new Error(response.body);
}
else {
exception = getException(response.body);
}
}
catch (e) {
// parsing error
exception = new httpClientException_1.default({
message: `HTTP Exception: ${response.statusCode}. Error parsing response: ${e.message}`,
statusCode: response.statusCode,
responseHeaders: response.headers,
responseBody: response.body,
});
}
return reject(exception);
}
resolve(response.body);
});
res.on("error", reject);
});
connectionRequest.on("timeout", () => {
connectionRequest.abort();
});
connectionRequest.on("error", (e) => reject(new apiException_1.default(e.message)));
connectionRequest.write(Buffer.from(json));
connectionRequest.end();
});
}
installCertificateVerifier(terminalCertificatePath) {
try {
if (terminalCertificatePath == "unencrypted") {
this.agentOptions = {
rejectUnauthorized: false
};
}
else {
const certificateInput = fs.readFileSync(terminalCertificatePath);
this.agentOptions = {
ca: certificateInput,
checkServerIdentity: checkServerIdentity_1.default,
};
}
}
catch (e) {
const message = e instanceof Error ? e.message : "undefined";
return Promise.reject(new httpClientException_1.default({ message: `Error loading certificate from path: ${message}` }));
}
}
}
HttpURLConnectionClient.CHARSET = "utf-8";
exports.default = HttpURLConnectionClient;
//# sourceMappingURL=httpURLConnectionClient.js.map