UNPKG

@zed-io/wam-payment-sdk

Version:

Official WAM Payment SDK for creating and signing payment links

217 lines (209 loc) 7.5 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var crypto = require('crypto'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var crypto__namespace = /*#__PURE__*/_interopNamespaceDefault(crypto); class WamPaymentError extends Error { constructor(message, code, validationErrors) { super(message); this.code = code; this.validationErrors = validationErrors; this.name = 'WamPaymentError'; } } exports.WamPaymentErrorCode = void 0; (function (WamPaymentErrorCode) { WamPaymentErrorCode["INVALID_CONFIG"] = "INVALID_CONFIG"; WamPaymentErrorCode["INVALID_AMOUNT"] = "INVALID_AMOUNT"; WamPaymentErrorCode["INVALID_CURRENCY"] = "INVALID_CURRENCY"; WamPaymentErrorCode["INVALID_REFERENCE"] = "INVALID_REFERENCE"; WamPaymentErrorCode["INVALID_RETURN_URL"] = "INVALID_RETURN_URL"; WamPaymentErrorCode["SIGNING_ERROR"] = "SIGNING_ERROR"; WamPaymentErrorCode["VALIDATION_ERROR"] = "VALIDATION_ERROR"; })(exports.WamPaymentErrorCode || (exports.WamPaymentErrorCode = {})); class WamPaymentSDK { constructor(config) { this.validateConfig(config); this.config = config; this.baseUrl = this.getBaseUrl(); } /** * Generates a signed payment link for WAM payment processing * @param params Payment parameters including amount, currency, reference, and optional return URL * @returns Payment link response with URL, signature, and metadata */ generatePaymentLink(params) { // Validate input parameters this.validatePaymentParams(params); // Create the payload to sign (must match the format expected by WAM) const payload = `${params.amount}|TTD|${params.reference}`; // Generate HMAC-SHA256 signature const signature = this.generateSignature(payload); // Build the payment URL const paymentUrl = this.buildPaymentUrl(params, signature); return { url: paymentUrl, signature, payload, }; } /** * Validates payment parameters * @param params Payment parameters to validate * @throws WamPaymentError if validation fails */ validatePaymentParams(params) { const errors = []; // Validate amount if (typeof params.amount !== "number" || params.amount <= 0) { errors.push({ field: "amount", message: "Amount must be a positive number", }); } // Validate reference if (!params.reference || typeof params.reference !== "string" || params.reference.trim().length === 0) { errors.push({ field: "reference", message: "Reference must be a non-empty string", }); } // Validate return URL if provided if (params.returnUrl && typeof params.returnUrl !== "string") { errors.push({ field: "returnUrl", message: "Return URL must be a string", }); } if (params.returnUrl && !this.isValidUrl(params.returnUrl)) { errors.push({ field: "returnUrl", message: "Return URL must be a valid URL", }); } if (errors.length > 0) { throw new WamPaymentError("Validation failed", exports.WamPaymentErrorCode.VALIDATION_ERROR, errors); } } /** * Validates the SDK configuration * @param config Configuration to validate * @throws WamPaymentError if configuration is invalid */ validateConfig(config) { const errors = []; if (!config.businessId || typeof config.businessId !== "string") { errors.push({ field: "businessId", message: "Business ID is required and must be a string", }); } if (!config.privateKey || typeof config.privateKey !== "string") { errors.push({ field: "privateKey", message: "Private key is required and must be a string", }); } if (errors.length > 0) { throw new WamPaymentError("Invalid configuration", exports.WamPaymentErrorCode.INVALID_CONFIG, errors); } } /** * Generates HMAC-SHA256 signature * @param payload The payload to sign * @returns Hex-encoded signature */ generateSignature(payload) { try { return crypto__namespace .createHmac("sha256", this.config.privateKey) .update(payload) .digest("hex"); } catch (error) { throw new WamPaymentError("Failed to generate signature", exports.WamPaymentErrorCode.SIGNING_ERROR); } } /** * Gets the base URL based on environment configuration * @returns Base URL for WAM payment gateway */ getBaseUrl() { // Determine environment from config, default to production const environment = this.config.environment || 'production'; // Return appropriate URL based on environment switch (environment) { case 'staging': case 'development': return "https://staging.billing.wam.money"; case 'production': default: return "https://billing.wam.money"; } } /** * Builds the complete payment URL with all parameters * @param params Payment parameters * @param signature Generated signature * @returns Complete payment URL */ buildPaymentUrl(params, signature) { const paymentUrl = new URL(`${this.baseUrl}/pay/external/generic/${this.config.businessId}`); // Add required parameters paymentUrl.searchParams.set("amount", params.amount.toString()); paymentUrl.searchParams.set("currency", "TTD"); paymentUrl.searchParams.set("reference", params.reference); paymentUrl.searchParams.set("signature", signature); // Add optional return URL if (params.returnUrl) { paymentUrl.searchParams.set("returnUrl", params.returnUrl); } return paymentUrl.toString(); } /** * Validates if a string is a valid URL * @param url String to validate * @returns true if valid URL, false otherwise */ isValidUrl(url) { try { new URL(url); return true; } catch { return false; } } /** * Gets the current configuration (without sensitive data) * @returns Configuration object without private key */ getConfig() { return { businessId: this.config.businessId, environment: this.config.environment || 'production', baseUrl: this.baseUrl, }; } } exports.WamPaymentError = WamPaymentError; exports.WamPaymentSDK = WamPaymentSDK; exports.default = WamPaymentSDK; //# sourceMappingURL=index.js.map