voko-sdk
Version:
Process payments with ease
129 lines (128 loc) • 4.55 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseAdapter = void 0;
const types_1 = require("../../core/types");
const errors_1 = require("../../core/errors");
const http_client_1 = require("../../utils/http-client");
const logger_1 = require("../../utils/logger");
class BaseAdapter {
config;
provider;
httpClient;
logger;
baseUrl;
constructor(config) {
this.config = config;
this.provider = config.provider;
this.httpClient = new http_client_1.HttpClient({
timeout: config.timeout || 30000,
retries: config.retries || 3,
});
this.logger = new logger_1.Logger(`${this.provider.toUpperCase()}Adapter`);
this.baseUrl = this.getBaseUrl(config.environment);
}
getContentHeaders() {
return { 'Content-Type': 'application/json' };
}
getStatusHttpMethod() {
return 'GET';
}
async initiatePayment(request) {
try {
const transformedRequest = this.transformRequest(request);
const response = await this.makeApiCall(this.getPaymentEndpoint(), transformedRequest, 'POST');
const paymentResponse = this.transformResponse(response, request);
return paymentResponse;
}
catch (error) {
this.logger.error('Payment initiation failed', error);
throw this.handleError(error);
}
}
async checkPaymentStatus(request) {
try {
const requestData = this.getStatusRequestData(request);
const httpMethod = this.getStatusHttpMethod();
const response = await this.makeApiCall(this.getStatusEndpoint(), requestData, httpMethod);
const statusResponse = this.transformStatusResponse(response);
return statusResponse;
}
catch (error) {
this.logger.error('Payment status check failed', error);
throw this.handleError(error);
}
}
async verifyWebhook(payload, signature) {
try {
const isValid = this.verifyWebhookSignature(payload, signature);
if (!isValid) {
return { valid: false, error: 'Invalid webhook signature' };
}
const webhookPayload = this.parseWebhookPayload(payload);
return { valid: true, payload: webhookPayload };
}
catch (error) {
this.logger.error('Webhook verification failed', error);
return { valid: false, error: 'Webhook verification error' };
}
}
async makeApiCall(endpoint, data, method = 'POST') {
const url = this.buildUrl(endpoint);
const headers = this.buildRequestHeaders();
try {
const response = await this.httpClient.request({
url,
method,
headers,
data: method === 'POST' ? data : undefined,
params: method === 'GET' ? data : undefined,
});
return response.data;
}
catch (error) {
throw error;
}
}
buildUrl(endpoint) {
const cleanEndpoint = endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
return `${this.baseUrl}${cleanEndpoint}`;
}
buildRequestHeaders() {
return {
...this.getContentHeaders(),
...this.getAuthHeaders(),
};
}
handleError(error) {
if (error instanceof errors_1.VokoError) {
return error;
}
const errorCode = this.mapErrorCode(error);
return errors_1.VokoError.fromProvider(error, errorCode);
}
generateTransactionId() {
const timestamp = Date.now();
const random = Math.random().toString(36).substring(2, 9);
return `voko_${timestamp}_${random}`;
}
parseWebhookPayload(payload) {
try {
return JSON.parse(payload);
}
catch (error) {
throw new errors_1.VokoError('Invalid webhook payload format', types_1.VokoErrorCode.PROVIDER_ERROR, undefined, 'Unable to parse webhook payload as JSON');
}
}
getSupportedPaymentMethods() {
return [types_1.PaymentMethod.MOBILE_MONEY];
}
getSupportedOperators() {
return [
types_1.MobileOperator.VODACOM_MPESA,
types_1.MobileOperator.AIRTEL_MONEY,
types_1.MobileOperator.TIGO_PESA,
types_1.MobileOperator.HALO_PESA,
];
}
}
exports.BaseAdapter = BaseAdapter;