@spixter/ez-upi-flow 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +65 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +51 -6
- package/readme.md +27 -0
- package/README.md +0 -3
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { UPIPaymentConfig, IntentUrls } from './types.js';
|
|
2
|
+
export declare class UPIServerEngine {
|
|
3
|
+
private defaultUpi?;
|
|
4
|
+
private defaultName?;
|
|
5
|
+
constructor(defaults?: {
|
|
6
|
+
merchantUpi?: string;
|
|
7
|
+
merchantName?: string;
|
|
8
|
+
});
|
|
9
|
+
createSession(config: UPIPaymentConfig, ttlSeconds?: number): Promise<IntentUrls>;
|
|
10
|
+
isSessionActive(expiresAt: number): boolean;
|
|
11
|
+
validateUTRFormat(utr: string): boolean;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE1D,qBAAa,eAAe;IAC1B,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAC,CAAS;gBAEjB,QAAQ,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE;IAKzD,aAAa,CAAC,MAAM,EAAE,gBAAgB,EAAE,UAAU,GAAE,MAAY,GAAG,OAAO,CAAC,UAAU,CAAC;IAmD5F,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI3C,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAG/C"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.UPIServerEngine = void 0;
|
|
7
|
+
const qrcode_1 = __importDefault(require("qrcode"));
|
|
8
|
+
const node_crypto_1 = require("node:crypto");
|
|
9
|
+
class UPIServerEngine {
|
|
10
|
+
defaultUpi;
|
|
11
|
+
defaultName;
|
|
12
|
+
constructor(defaults) {
|
|
13
|
+
this.defaultUpi = defaults?.merchantUpi;
|
|
14
|
+
this.defaultName = defaults?.merchantName;
|
|
15
|
+
}
|
|
16
|
+
async createSession(config, ttlSeconds = 180) {
|
|
17
|
+
const upiId = config.merchantUpi || this.defaultUpi;
|
|
18
|
+
const name = config.merchantName || this.defaultName;
|
|
19
|
+
if (!upiId || !name) {
|
|
20
|
+
throw new Error('[upi-intent-flow] Merchant UPI ID aur Name mandatory hain.');
|
|
21
|
+
}
|
|
22
|
+
if (config.amount <= 0) {
|
|
23
|
+
throw new Error('[upi-intent-flow] Amount 0 se zyada hona chahiye.');
|
|
24
|
+
}
|
|
25
|
+
const formattedAmount = config.amount.toFixed(2);
|
|
26
|
+
const encodedName = encodeURIComponent(name);
|
|
27
|
+
const transactionNote = encodeURIComponent(config.note || `Order #${config.orderId}`);
|
|
28
|
+
const baseParams = `pa=${upiId}&pn=${encodedName}&am=${formattedAmount}&cu=INR&tr=${config.orderId}&tn=${transactionNote}`;
|
|
29
|
+
const rawIntent = `upi://pay?${baseParams}`;
|
|
30
|
+
const gpayIntent = `gpay://upi/pay?${baseParams}`;
|
|
31
|
+
const phonepeIntent = `phonepe://pay?${baseParams}`;
|
|
32
|
+
const paytmIntent = `paytmmp://pay?${baseParams}`;
|
|
33
|
+
const qrBase64 = await qrcode_1.default.toDataURL(rawIntent, {
|
|
34
|
+
errorCorrectionLevel: 'M',
|
|
35
|
+
margin: 1,
|
|
36
|
+
width: 260,
|
|
37
|
+
});
|
|
38
|
+
const now = Date.now();
|
|
39
|
+
const expiresAt = now + ttlSeconds * 1000;
|
|
40
|
+
const ip = config.clientIp || '0.0.0.0';
|
|
41
|
+
const ua = config.userAgent || 'unknown';
|
|
42
|
+
const sessionToken = (0, node_crypto_1.createHash)('sha256')
|
|
43
|
+
.update(`${config.orderId}|${ip}|${ua}|${(0, node_crypto_1.randomBytes)(8).toString('hex')}`)
|
|
44
|
+
.digest('hex');
|
|
45
|
+
return {
|
|
46
|
+
rawIntent,
|
|
47
|
+
gpayIntent,
|
|
48
|
+
phonepeIntent,
|
|
49
|
+
paytmIntent,
|
|
50
|
+
qrBase64,
|
|
51
|
+
orderId: config.orderId,
|
|
52
|
+
amount: config.amount,
|
|
53
|
+
sessionToken,
|
|
54
|
+
expiresAt,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
isSessionActive(expiresAt) {
|
|
58
|
+
return Date.now() <= expiresAt;
|
|
59
|
+
}
|
|
60
|
+
validateUTRFormat(utr) {
|
|
61
|
+
return /^\d{12}$/.test(utr.trim());
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.UPIServerEngine = UPIServerEngine;
|
|
65
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;AAC5B,6CAAsD;AAGtD,MAAa,eAAe;IAClB,UAAU,CAAU;IACpB,WAAW,CAAU;IAE7B,YAAY,QAA0D;QACpE,IAAI,CAAC,UAAU,GAAG,QAAQ,EAAE,WAAW,CAAC;QACxC,IAAI,CAAC,WAAW,GAAG,QAAQ,EAAE,YAAY,CAAC;IAC5C,CAAC;IAEM,KAAK,CAAC,aAAa,CAAC,MAAwB,EAAE,aAAqB,GAAG;QAC3E,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC,UAAU,CAAC;QACpD,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC,WAAW,CAAC;QAErD,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAChF,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,eAAe,GAAG,kBAAkB,CAAC,MAAM,CAAC,IAAI,IAAI,UAAU,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAEtF,MAAM,UAAU,GAAG,MAAM,KAAK,OAAO,WAAW,OAAO,eAAe,cAAc,MAAM,CAAC,OAAO,OAAO,eAAe,EAAE,CAAC;QAE3H,MAAM,SAAS,GAAG,aAAa,UAAU,EAAE,CAAC;QAC5C,MAAM,UAAU,GAAG,kBAAkB,UAAU,EAAE,CAAC;QAClD,MAAM,aAAa,GAAG,iBAAiB,UAAU,EAAE,CAAC;QACpD,MAAM,WAAW,GAAG,iBAAiB,UAAU,EAAE,CAAC;QAElD,MAAM,QAAQ,GAAG,MAAM,gBAAM,CAAC,SAAS,CAAC,SAAS,EAAE;YACjD,oBAAoB,EAAE,GAAG;YACzB,MAAM,EAAE,CAAC;YACT,KAAK,EAAE,GAAG;SACX,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,SAAS,GAAG,GAAG,GAAG,UAAU,GAAG,IAAI,CAAC;QAE1C,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,IAAI,SAAS,CAAC;QACxC,MAAM,EAAE,GAAG,MAAM,CAAC,SAAS,IAAI,SAAS,CAAC;QACzC,MAAM,YAAY,GAAG,IAAA,wBAAU,EAAC,QAAQ,CAAC;aACtC,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,IAAI,EAAE,IAAI,IAAA,yBAAW,EAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;aACzE,MAAM,CAAC,KAAK,CAAC,CAAC;QAEjB,OAAO;YACL,SAAS;YACT,UAAU;YACV,aAAa;YACb,WAAW;YACX,QAAQ;YACR,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,YAAY;YACZ,SAAS;SACV,CAAC;IACJ,CAAC;IAEM,eAAe,CAAC,SAAiB;QACtC,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,SAAS,CAAC;IACjC,CAAC;IAEM,iBAAiB,CAAC,GAAW;QAClC,OAAO,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;CACF;AAnED,0CAmEC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface UPIPaymentConfig {
|
|
2
|
+
merchantUpi: string;
|
|
3
|
+
merchantName: string;
|
|
4
|
+
amount: number;
|
|
5
|
+
orderId: string;
|
|
6
|
+
note?: string;
|
|
7
|
+
clientIp?: string;
|
|
8
|
+
userAgent?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface IntentUrls {
|
|
11
|
+
rawIntent: string;
|
|
12
|
+
gpayIntent: string;
|
|
13
|
+
phonepeIntent: string;
|
|
14
|
+
paytmIntent: string;
|
|
15
|
+
qrBase64: string;
|
|
16
|
+
orderId: string;
|
|
17
|
+
amount: number;
|
|
18
|
+
sessionToken: string;
|
|
19
|
+
expiresAt: number;
|
|
20
|
+
}
|
|
21
|
+
export interface ClientModalOptions {
|
|
22
|
+
packet: IntentUrls;
|
|
23
|
+
merchantName: string;
|
|
24
|
+
onSuccessClaim: (data: {
|
|
25
|
+
orderId: string;
|
|
26
|
+
utr: string;
|
|
27
|
+
sessionToken: string;
|
|
28
|
+
}) => void;
|
|
29
|
+
onCancel: (data: {
|
|
30
|
+
orderId: string;
|
|
31
|
+
reason: string;
|
|
32
|
+
}) => void;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,UAAU,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACvF,QAAQ,EAAE,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CAC/D"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,51 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@spixter/ez-upi-flow",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Zero-KYC direct UPI intent & dynamic QR payment flow with 3-minute strict TTL and back-trap protection.",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./server": {
|
|
13
|
+
"types": "./dist/server.d.ts",
|
|
14
|
+
"import": "./dist/server.js"
|
|
15
|
+
},
|
|
16
|
+
"./client": {
|
|
17
|
+
"types": "./dist/client.d.ts",
|
|
18
|
+
"import": "./dist/client.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "rimraf dist && tsc",
|
|
28
|
+
"prepublishOnly": "npm run build"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"upi",
|
|
32
|
+
"payments",
|
|
33
|
+
"gpay",
|
|
34
|
+
"phonepe",
|
|
35
|
+
"paytm",
|
|
36
|
+
"zero-kyc",
|
|
37
|
+
"qr-code",
|
|
38
|
+
"intent-flow"
|
|
39
|
+
],
|
|
40
|
+
"author": "Shubh Gupta",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"qrcode": "^1.5.4"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/node": "^22.0.0",
|
|
47
|
+
"@types/qrcode": "^1.5.5",
|
|
48
|
+
"rimraf": "^6.0.0",
|
|
49
|
+
"typescript": "^5.6.0"
|
|
50
|
+
}
|
|
51
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# ⚡ ez-upi-flow
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/ez-upi-flow)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](#)
|
|
6
|
+
[](#)
|
|
7
|
+
|
|
8
|
+
> **Zero-KYC direct UPI intent & dynamic QR payment flow for indie builders and small businesses.**
|
|
9
|
+
|
|
10
|
+
Accept UPI payments straight into your personal or merchant VPA (`GPay`, `PhonePe`, `Paytm`, `FamPay`) without paying a **2% gateway fee** or waiting days for merchant paperwork approval.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
### ✨ Features
|
|
15
|
+
|
|
16
|
+
- 🚀 **Zero KYC Onboarding:** No merchant portal registration. Plug in your UPI ID and start taking payments.
|
|
17
|
+
- 📱 **Native Mobile Intent:** Automatically summons GPay, PhonePe, and Paytm app sheets directly on mobile browsers.
|
|
18
|
+
- 🖥️ **Dynamic Desktop QR:** Renders high-contrast, locked-amount Base64 QR code for desktop browsers.
|
|
19
|
+
- ⏱️ **Strict 3-Minute TTL:** Hard countdown timer releases stuck inventory if payment isn't completed.
|
|
20
|
+
- 🛡️ **Anti-Back Navigation Trap:** Intercepts browser back clicks and tab closes to auto-cancel abandoned checkouts.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
### 📦 Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install ez-upi-flow
|
package/README.md
DELETED