@payunit/nodejs-sdk
Version:
PayUnit Payment Processor SDK
173 lines • 9.23 kB
JavaScript
;
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.PayunitClient = void 0;
const axios_1 = __importDefault(require("axios"));
const index_1 = require("./validators/index");
const config_1 = require("./types/config");
class PayunitClient {
constructor(config) {
try {
// Validate configuration
const { error, value } = config_1.configSchema.validate(config, {
abortEarly: true,
allowUnknown: false,
stripUnknown: true,
});
if (error) {
const errorMessages = error.details.map((detail) => detail.message).join('; ');
throw new Error(`Invalid configuration: ${errorMessages}`);
}
this.config = value;
// Store sensitive data in a separate object that won't be serialized
this.credentials = {
auth: Buffer.from(`${this.config.apiUsername}:${this.config.apiPassword}`).toString('base64'),
apiKey: this.config.apiKey,
};
this.axiosInstance = axios_1.default.create({
baseURL: `${this.config.baseURL.replace(/\/+$/, '')}/api`,
headers: {
'Content-Type': 'application/json',
'User-Agent': 'PayUnit-Node-SDK/1.0',
},
timeout: this.config.timeout,
maxRedirects: 0,
validateStatus: (status) => status >= 200 && status < 400,
});
// Add request interceptor for auth headers
this.axiosInstance.interceptors.request.use((config) => {
const headers = new axios_1.default.AxiosHeaders(Object.assign(Object.assign({}, config.headers), { 'Content-Type': 'application/json', 'User-Agent': 'PayUnit-Node-SDK/1.0', Authorization: `Basic ${this.credentials.auth}`, 'x-api-key': this.credentials.apiKey, mode: this.config.mode }));
return Object.assign(Object.assign({}, config), { headers });
});
// Add response interceptor for error handling
this.axiosInstance.interceptors.response.use((response) => response, (error) => {
var _a, _b;
if (axios_1.default.isAxiosError(error)) {
const status = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status;
const data = (_b = error.response) === null || _b === void 0 ? void 0 : _b.data;
console.log({
status,
data,
message: error === null || error === void 0 ? void 0 : error.message,
});
if (status === 401) {
return Promise.reject(new Error(`Authentication failed. Please check your credentials or authorisations needed. ${data === null || data === void 0 ? void 0 : data.message}`));
}
if (status === 403) {
return Promise.reject(new Error(`Access denied. Please check your API key and permissions needed'. ${data === null || data === void 0 ? void 0 : data.message}`));
}
const message = (data === null || data === void 0 ? void 0 : data.message) || error.message || 'An unknown error occurred';
return Promise.reject(new Error(`API request failed: ${message}`));
}
return Promise.reject(error);
});
}
catch (error) {
const safeError = new Error('Failed to initialize PayUnit client');
safeError.originalError = error instanceof Error ? error.message : 'Unknown error';
throw safeError;
}
// Import the actual implementations
const { Collections } = require('./Collections');
const { Checkout } = require('./Checkout');
const { Invoice } = require('./Invoice');
const { Disbursement } = require('./Disbursement');
// Initialize services with the current client instance
this.collections = new Collections(this);
this.checkout = new Checkout(this);
this.invoice = new Invoice(this);
this.disbursement = new Disbursement(this);
}
request(method_1, endpoint_1) {
return __awaiter(this, arguments, void 0, function* (method, endpoint, data = null, params) {
if (!endpoint || typeof endpoint !== 'string') {
throw new Error('Endpoint must be a non-empty string');
}
// Sanitize endpoint to prevent path traversal
const sanitizedEndpoint = endpoint.replace(/\.{2,}/g, '').replace(/^\/+/g, '');
const response = yield this.axiosInstance.request({
method,
url: sanitizedEndpoint,
data: data !== null ? data : undefined,
params,
});
return response.data;
});
}
makeRequest(method, endpoint, requestSchema, data, errorMessage, params) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f, _g;
try {
// For GET requests, validate the data but don't send it as request body
if (method === 'GET') {
// Validate the data (usually URL parameters) against schema
const { error } = requestSchema.validate(data, {
abortEarly: false,
allowUnknown: true,
stripUnknown: true,
});
if (error) {
throw index_1.ValidationError.fromJoiError(error);
}
// Make the GET request without body data
const response = yield this.axiosInstance.request({
method,
url: endpoint,
params,
});
// Check for API-level errors
if (response.data && response.data.status === 'FAILED') {
throw index_1.ValidationError.fromApiError(response.data);
}
// Return the data if it exists, otherwise the full response
return (_b = (_a = response.data) === null || _a === void 0 ? void 0 : _a.data) !== null && _b !== void 0 ? _b : response.data;
}
// For POST requests, validate and send data as request body
const { error, value } = requestSchema.validate(data, {
abortEarly: false,
allowUnknown: true,
stripUnknown: true,
});
if (error) {
throw index_1.ValidationError.fromJoiError(error);
}
// Make the request with validated data
const response = yield this.axiosInstance.request({
method,
url: endpoint,
data: value,
params,
});
// Check for API-level errors
if (response.data && response.data.status === 'FAILED') {
throw index_1.ValidationError.fromApiError(response.data);
}
// Return the data if it exists, otherwise the full response
return (_d = (_c = response.data) === null || _c === void 0 ? void 0 : _c.data) !== null && _d !== void 0 ? _d : response.data;
}
catch (error) {
if (error instanceof index_1.ValidationError) {
throw error;
}
if (axios_1.default.isAxiosError(error)) {
// Error is already processed by the interceptor
throw new Error((_g = (_f = (_e = error.response) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.message) !== null && _g !== void 0 ? _g : `${errorMessage} ${error.message}`);
}
throw new Error(error instanceof Error ? error.message : 'An unknown error occurred');
}
});
}
}
exports.PayunitClient = PayunitClient;
//# sourceMappingURL=PayunitClient.js.map