@onepay-payment-sdk/server
Version:
server payment sdk for onepay payment gateway
247 lines (240 loc) • 7.42 kB
JavaScript
import https from 'https';
import crypto from 'crypto';
// src/constants/environment.ts
var ENVIRONMENT_API = {
LIVE: "https://merchant-api-live-v2.onepay.lk/api/ipg/gateway"
};
// src/exceptions/PaymentException.ts
var PaymentException = class extends Error {
constructor(message) {
super(message);
this.name = "PaymentError";
this.message = message;
}
};
// src/validation/inputValidators.ts
function isValidUrl(url) {
try {
new URL(url);
return true;
} catch {
return false;
}
}
function isValidEmail(email) {
const atIndex = email.indexOf("@");
const dotIndex = email.lastIndexOf(".");
if (atIndex < 1 || atIndex === email.length - 1) {
return false;
}
if (dotIndex < atIndex + 2 || dotIndex === email.length - 1) {
return false;
}
if (email.includes(" ")) {
return false;
}
return true;
}
function validatePayLink(url) {
let urlObj;
try {
urlObj = new URL(url);
if (!urlObj.protocol.startsWith("https")) {
throw new Error("URL must use HTTPS Protocol");
}
if (urlObj.searchParams.get("hash") === null) {
throw new Error("Missing salt query parameter");
}
return urlObj;
} catch (error) {
if (error instanceof PaymentException) {
throw new PaymentException(error.message);
} else {
throw new Error("Failed to parse URL");
}
}
}
function validatePaymentParams(basicParams) {
if (typeof basicParams.firstName !== "string" || basicParams.firstName.length < 1) {
throw new Error("First name must be a non-empty string");
}
if (typeof basicParams.lastName !== "string" || basicParams.lastName.length < 1) {
throw new Error("Last name must be a non-empty string");
}
if (typeof basicParams.email !== "string" || !isValidEmail(basicParams.email)) {
throw new Error("Email must be a valid email address");
}
if (typeof basicParams.phone !== "string") {
throw new Error("Phone number must be a string");
}
if (typeof basicParams.amount !== "number" || basicParams.amount < 100) {
throw new Error("Amount must be a number greater than or equal to 100");
}
if (typeof basicParams.reference !== "string" || basicParams.reference.length < 10 || basicParams.reference.length > 20) {
throw new Error(
"Reference must be a string with a length between 10 and 20 characters"
);
}
if (typeof basicParams.transactionRedirectUrl !== "string" || !isValidUrl(basicParams.transactionRedirectUrl)) {
throw new Error("Transaction redirect URL is not valid");
}
return basicParams;
}
// src/constants/currency.ts
var Currency = {
USD: "USD",
LKR: "LKR"
};
async function paymentRequest(url, token, body) {
if (!url && !token && !body) {
throw new Error("Missing required parameters");
}
const urlObj = validatePayLink(url);
const hashParam = urlObj.searchParams.get("hash");
const TIMEOUT_MS = 3e4;
const options = {
hostname: urlObj.hostname,
path: urlObj.pathname + `?hash=${hashParam}`,
method: "POST",
headers: {
"Content-Type": "application/json",
authorization: token
},
timeout: TIMEOUT_MS
};
return new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
const chunks = [];
res.setTimeout(TIMEOUT_MS, () => {
req.destroy(new Error("Response timeout"));
});
res.on("data", (chunk) => {
chunks.push(Buffer.from(chunk));
});
res.on("end", () => {
try {
const data = Buffer.concat(chunks).toString("utf8");
const response = JSON.parse(data);
if (res.statusCode === 200 && response.status === 1e3) {
resolve({
status: response.status,
message: response.message,
data: response.data
});
} else {
const error = new Error(data);
reject(error);
}
} catch (err) {
const error = new Error("Failed to Process response" + err);
reject(error);
}
});
});
req.on("error", (error) => {
reject(error);
});
req.write(JSON.stringify(body));
req.end();
});
}
function generatePaymentLink(paymentLinkParams) {
const { baseURL, salt, paymentParams } = paymentLinkParams;
if (!baseURL) {
throw new Error("Missing required parameter : BaseURL");
}
if (!salt) {
throw new Error("Missing required parameter : Salt");
}
if (!paymentParams || typeof paymentParams !== "object") {
throw new Error("Invalid or missing paymentParams. It must be an object.");
}
try {
const paymentParamsString = JSON.stringify(paymentParams);
const hash = crypto.createHash("sha256").update(paymentParamsString + salt).digest("hex");
const normalizeBaseURL = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL;
const paymentLink = new URL(`${normalizeBaseURL}/request-payment-link/`);
paymentLink.searchParams.append("hash", hash);
return paymentLink.toString();
} catch (error) {
throw new Error(
`Failed to generate payment link : ${error instanceof Error ? error.message : String(error)}`,
{
cause: error
}
);
}
}
// src/onepay.ts
var Onepay = class {
appId;
token;
salt;
baseUrl;
paymentParams;
constructor(onepayConfig) {
this.appId = onepayConfig.appId;
this.token = onepayConfig.token;
this.salt = onepayConfig.salt;
this.baseUrl = ENVIRONMENT_API.LIVE;
this.paymentParams = null;
}
generatePaymentParams(basicParams) {
if (!this.appId) {
throw new Error("App ID not initialized");
}
const validatedParams = validatePaymentParams(basicParams);
const paymentDetailsWithAppId = {
amount: validatedParams.amount,
reference: validatedParams.reference,
customer_email: validatedParams.email,
customer_first_name: validatedParams.firstName,
customer_last_name: validatedParams.lastName,
customer_phone_number: validatedParams.phone,
transaction_redirect_url: validatedParams.transactionRedirectUrl,
...validatedParams.additionalData && {
additional_data: validatedParams.additionalData
},
currency: validatedParams.currency || Currency.LKR,
app_id: this.appId
};
this.paymentParams = paymentDetailsWithAppId;
try {
return this.paymentParams;
} catch (err) {
if (err instanceof Error) {
throw new Error(`Failed to serialize payment: ${err.message}`);
} else {
throw new Error("Failed to serialize payment:");
}
}
}
async createPaymentRequest(onepayPaymentParams) {
if (!this.token) {
throw new Error("Token not initialized");
}
if (!this.salt) {
throw new Error("Salt not initialized");
}
try {
const paymentRequestUrl = generatePaymentLink({
baseURL: this.baseUrl,
paymentParams: onepayPaymentParams,
salt: this.salt
});
const response = await paymentRequest(
paymentRequestUrl,
this.token,
onepayPaymentParams
);
return response;
} catch (err) {
throw new Error("Failed to create payment request" + err);
}
}
};
// src/index.ts
var src_default = Onepay;
export { Currency, ENVIRONMENT_API, Onepay, src_default as default };
//# sourceMappingURL=index.mjs.map
//# sourceMappingURL=index.mjs.map