smart-upiqr
Version:
Easily generate branded UPI QR codes and payment links with customizable options for JavaScript and Node.js.
194 lines (193 loc) • 8.01 kB
JavaScript
;
// index.ts
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UPILink = UPILink;
exports.UPIQR = UPIQR;
// --- Imports ---
// qrcode is always required
const QRCode = __importStar(require("qrcode"));
// Lazy import for canvas (only used in Node.js)
let nodeCanvas;
function getNodeCanvas() {
if (!nodeCanvas) {
nodeCanvas = require("canvas");
}
return nodeCanvas;
}
// --- Utilities ---
const formatDateIsoWithOffset = (date) => {
const pad = (n) => n.toString().padStart(2, "0");
const tzOffset = -date.getTimezoneOffset();
const sign = tzOffset >= 0 ? "+" : "-";
const tzHours = pad(Math.floor(Math.abs(tzOffset) / 60));
const tzMinutes = pad(Math.abs(tzOffset) % 60);
return (date.getFullYear() +
"-" +
pad(date.getMonth() + 1) +
"-" +
pad(date.getDate()) +
"T" +
pad(date.getHours()) +
":" +
pad(date.getMinutes()) +
":" +
pad(date.getSeconds()) +
sign +
tzHours +
":" +
tzMinutes);
};
// --- UPI Link Generator ---
function UPILink(options) {
const { PayeeUPI, PayeeName, Amount, TransactionNote, MerchantCode, TransactionRef, TransactionId, invoiceNo, invoiceDate, QrExpireDays, QrTimestamp, GSTno, } = options;
if (!PayeeUPI || !PayeeName || !Amount) {
throw new Error(`"PayeeUPI", "PayeeName", "Amount > 0" is required. Received --> PayeeUPI: ${PayeeUPI} | PayeeName: ${PayeeName} | Amount: ${Amount}`);
}
if (isNaN(Amount) || Amount <= 0) {
throw new Error(`"Amount" must be number > 0. Received: ${Amount}`);
}
if (QrExpireDays && (isNaN(QrExpireDays) || QrExpireDays <= 0)) {
throw new Error(`"QrExpireDays" must be number > 0 for Future expiry. Received: ${QrExpireDays}`);
}
const now = new Date();
let upi = `upi://pay?pa=${PayeeUPI}&pn=${PayeeName}&am=${Amount}&cu=INR`;
if (TransactionNote)
upi += `&tn=${TransactionNote}`;
if (MerchantCode)
upi += `&mc=${MerchantCode}`;
if (TransactionRef)
upi += `&tr=${TransactionRef}`;
if (TransactionId)
upi += `&tid=${TransactionId}`;
if (invoiceNo)
upi += `&invoiceNo=${invoiceNo}`;
if (invoiceDate)
upi += `&invoiceDate=${formatDateIsoWithOffset(now)}`;
if (QrTimestamp)
upi += `&QRts=${formatDateIsoWithOffset(now)}`;
if (QrExpireDays) {
const expireDate = new Date(now.getTime() + QrExpireDays * 86400000);
upi += `&QRexpire=${formatDateIsoWithOffset(expireDate)}`;
}
if (GSTno)
upi += `&gstIn=${GSTno}`;
return upi;
}
// --- Browser/Node detection ---
function isBrowser() {
return typeof window !== "undefined" && typeof document !== "undefined";
}
// --- UPI QR Generator ---
function UPIQR(options) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d;
const link = UPILink(options);
if (!link)
return null;
// Browser path
if (isBrowser()) {
const qrDataUrl = yield QRCode.toDataURL(link, {
type: "image/png",
color: {
dark: ((_a = options.color) === null || _a === void 0 ? void 0 : _a.dark) || "#000000",
light: ((_b = options.color) === null || _b === void 0 ? void 0 : _b.light) || "#ffffff",
},
margin: 2,
scale: 8,
});
if (options.logo) {
return new Promise((resolve, reject) => {
const qrImg = new Image();
qrImg.crossOrigin = "anonymous";
qrImg.src = qrDataUrl;
qrImg.onload = () => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = qrImg.width;
canvas.height = qrImg.height;
ctx.drawImage(qrImg, 0, 0);
const logo = new Image();
logo.crossOrigin = "anonymous";
logo.src = options.logo;
logo.onload = () => {
const logoSize = options.logoSize || qrImg.width / 6;
const x = (canvas.width - logoSize) / 2;
const y = (canvas.height - logoSize) / 2;
ctx.drawImage(logo, x, y, logoSize, logoSize);
resolve(canvas.toDataURL("image/png"));
};
logo.onerror = reject;
};
qrImg.onerror = reject;
});
}
return qrDataUrl;
}
// Node.js path
const { createCanvas, loadImage } = getNodeCanvas();
const qrBuffer = yield QRCode.toBuffer(link, {
type: "png",
color: {
dark: ((_c = options.color) === null || _c === void 0 ? void 0 : _c.dark) || "#000000",
light: ((_d = options.color) === null || _d === void 0 ? void 0 : _d.light) || "#ffffff",
},
margin: 2,
scale: 8,
});
if (options.logo) {
const qrImg = yield loadImage(qrBuffer);
const canvas = createCanvas(qrImg.width, qrImg.height);
const ctx = canvas.getContext("2d");
ctx.drawImage(qrImg, 0, 0);
const logo = yield loadImage(options.logo);
const logoSize = options.logoSize || qrImg.width / 6;
const x = (canvas.width - logoSize) / 2;
const y = (canvas.height - logoSize) / 2;
ctx.drawImage(logo, x, y, logoSize, logoSize);
return canvas.toDataURL("image/png");
}
return `data:image/png;base64,${qrBuffer.toString("base64")}`;
});
}