mpesalib
Version:
A robust Node.js library for Safaricom's Daraja API with complete TypeScript support and modern async/await patterns
149 lines • 5.13 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HttpClient = void 0;
const axios_1 = __importDefault(require("axios"));
const utils_1 = require("../utils");
class HttpClient {
constructor(config) {
this.accessToken = null;
this.tokenExpiry = null;
this.config = config;
const baseURL = utils_1.MpesaUtils.getBaseUrl(config.environment);
this.client = axios_1.default.create({
baseURL,
timeout: 30000,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
});
// Add request interceptor for authentication
this.client.interceptors.request.use(async (config) => {
if (config.url !== '/oauth/v1/generate' && !config.headers.Authorization) {
const token = await this.getAccessToken();
config.headers.Authorization = `Bearer ${token}`;
}
return config;
}, (error) => Promise.reject(error));
// Add response interceptor for error handling
this.client.interceptors.response.use((response) => response, (error) => {
if (error.response?.status === 401) {
// Token expired, clear it
this.accessToken = null;
this.tokenExpiry = null;
}
return Promise.reject(this.formatError(error));
});
}
/**
* Get access token from Safaricom OAuth API
*/
async getAccessToken() {
// Check if we have a valid token
if (this.accessToken && this.tokenExpiry && new Date() < this.tokenExpiry) {
return this.accessToken;
}
try {
const credentials = Buffer.from(`${this.config.consumerKey}:${this.config.consumerSecret}`).toString('base64');
const response = await this.client.get('/oauth/v1/generate?grant_type=client_credentials', {
headers: {
Authorization: `Basic ${credentials}`,
},
});
this.accessToken = response.data.access_token;
// Set expiry to 5 minutes before actual expiry (default is 1 hour)
const expiryInMs = (parseInt(response.data.expires_in) - 300) * 1000;
this.tokenExpiry = new Date(Date.now() + expiryInMs);
return this.accessToken;
}
catch (error) {
throw new Error(`Failed to get access token: ${this.getErrorMessage(error)}`);
}
}
/**
* Make GET request
*/
async get(url, config) {
const response = await this.client.get(url, config);
return response.data;
}
/**
* Make POST request
*/
async post(url, data, config) {
const response = await this.client.post(url, data, config);
return response.data;
}
/**
* Make PUT request
*/
async put(url, data, config) {
const response = await this.client.put(url, data, config);
return response.data;
}
/**
* Make DELETE request
*/
async delete(url, config) {
const response = await this.client.delete(url, config);
return response.data;
}
/**
* Format error response
*/
formatError(error) {
if (error.response) {
// Server responded with error status
const { status, data } = error.response;
const message = data?.errorMessage || data?.ResponseDescription || error.message;
const formattedError = new Error(`HTTP ${status}: ${message}`);
formattedError.status = status;
formattedError.data = data;
return formattedError;
}
else if (error.request) {
// Request was made but no response received
return new Error('Network error: No response received from server');
}
else {
// Something else happened
return new Error(`Request error: ${error.message}`);
}
}
/**
* Get error message from various error formats
*/
getErrorMessage(error) {
if (error.response?.data?.errorMessage) {
return error.response.data.errorMessage;
}
if (error.response?.data?.ResponseDescription) {
return error.response.data.ResponseDescription;
}
if (error.message) {
return error.message;
}
return 'Unknown error occurred';
}
/**
* Clear access token (useful for testing or manual token refresh)
*/
clearToken() {
this.accessToken = null;
this.tokenExpiry = null;
}
/**
* Get current token info (for debugging)
*/
getTokenInfo() {
return {
token: this.accessToken,
expiry: this.tokenExpiry,
};
}
}
exports.HttpClient = HttpClient;
//# sourceMappingURL=httpClient.js.map