takefy-cryptomus
Version:
TypeScript SDK for the Cryptomus payment system API
113 lines (112 loc) • 4.55 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseService = void 0;
const node_crypto_1 = __importDefault(require("node:crypto"));
/**
* Base service class that provides common functionality for all API services.
* Handles authentication, request signing, and HTTP communication with the Cryptomus API.
* This class is extended by PaymentsService, PayoutsService, and OtherService.
*
* @abstract
* @class
*/
class BaseService {
/**
* Creates a new instance of the BaseService.
*
* @param {string} merchantId - Your Cryptomus merchant ID.
* @param {string} paymentKey - Your API key for payment operations.
* @param {string} payoutKey - Your API key for payout operations.
* @param {string} baseUrl - The base URL of the Cryptomus API.
*/
constructor(merchantId, paymentKey, payoutKey, baseUrl) {
this.merchantId = merchantId;
this.paymentKey = paymentKey;
this.payoutKey = payoutKey;
this.baseUrl = baseUrl;
}
/**
* Generates a signature for API request authentication.
* The signature is created by encoding the request payload to base64,
* concatenating it with the appropriate API key, and creating an MD5 hash.
*
* @protected
* @param {Record<string, any>} payload - The request payload to sign.
* @param {boolean} [isPayment=true] - Whether to use payment key (true) or payout key (false).
* @param {boolean} [jsonUnescape=false] - Whether to unescape JSON slashes.
* @returns {string} The generated signature in hexadecimal format.
*
* @example
* ```typescript
* const payload = { amount: "100", currency: "USD" };
* const signature = this.generateSign(payload, true);
* ```
*/
generateSign(payload, isPayment = true, jsonUnescape = false) {
const encodedBody = Buffer.from(jsonUnescape
? JSON.stringify(payload).replace(/\\/g, "/")
: JSON.stringify(payload)).toString("base64");
const key = isPayment ? this.paymentKey : this.payoutKey;
return node_crypto_1.default
.createHash("md5")
.update(encodedBody + key)
.digest("hex");
}
/**
* Makes an HTTP request to the Cryptomus API.
* Handles request signing, error handling, and response parsing.
*
* @protected
* @template T - The expected response type.
* @param {string} endpoint - The API endpoint to call (e.g., "/payment/create").
* @param {"GET" | "POST"} method - The HTTP method to use.
* @param {Record<string, any>} [payload] - Optional request payload for POST requests.
* @param {boolean} [isPayment=true] - Whether this is a payment request (true) or payout request (false).
* @returns {Promise<T>} A promise that resolves with the API response data.
* @throws {Error} If the request fails, returns an error response, or encounters validation errors.
*
* @example
* ```typescript
* const response = await this.request<CreatePaymentResponse>(
* "/payment",
* "POST",
* { amount: "100", currency: "USD" }
* );
* ```
*/
async request(endpoint, method, payload, isPayment = true) {
const body = payload ? JSON.stringify(payload) : '{}';
const headers = {
"Content-Type": "application/json",
merchant: this.merchantId,
sign: this.generateSign(payload || {}, isPayment),
};
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method,
headers,
body,
});
if (!response.ok) {
if (response.status === 422) {
const data = (await response.json());
throw new Error(JSON.stringify(data));
}
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = (await response.json());
if (data.state === 1) {
if ("errors" in data) {
const errorMessages = Object.entries(data.errors)
.map(([field, msgs]) => `${field}: ${msgs.join(", ")}`)
.join("; ");
throw new Error(errorMessages);
}
throw new Error(data.message);
}
return data.result;
}
}
exports.BaseService = BaseService;