@nullpay/node 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.
@@ -0,0 +1,52 @@
1
+ export interface NullPayConfig {
2
+ secretKey: string;
3
+ baseURL?: string;
4
+ }
5
+ export interface CreateCheckoutSessionParams {
6
+ amount: number;
7
+ currency?: 'CREDITS' | 'USDCX' | 'USAD';
8
+ success_url?: string;
9
+ cancel_url?: string;
10
+ invoice_hash?: string;
11
+ salt?: string;
12
+ }
13
+ export interface CheckoutSession {
14
+ id: string;
15
+ checkout_url: string;
16
+ status: string;
17
+ invoice_hash?: string;
18
+ salt?: string;
19
+ }
20
+ export interface WebhookEvent {
21
+ id: string;
22
+ amount: number;
23
+ token_type: string;
24
+ status: 'SETTLED' | 'FAILED' | 'PROCESSING' | 'PENDING';
25
+ tx_id: string | null;
26
+ timestamp: string;
27
+ }
28
+ export declare class NullPay {
29
+ private secretKey;
30
+ private baseURL;
31
+ constructor(config: NullPayConfig);
32
+ checkout: {
33
+ sessions: {
34
+ create: (params: CreateCheckoutSessionParams) => Promise<CheckoutSession>;
35
+ retrieve: (sessionId: string) => Promise<CheckoutSession>;
36
+ };
37
+ };
38
+ webhooks: {
39
+ /**
40
+ * Verifies the HMAC-SHA256 signature attached to a NullPay webhook payload.
41
+ * @param payload The raw stringified JSON body of the webhook request.
42
+ * @param signature The hex signature from the `x-nullpay-signature` header.
43
+ * @returns true if the signature is valid and securely originates from NullPay.
44
+ */
45
+ verifySignature: (payload: string, signature: string) => boolean;
46
+ /**
47
+ * Helper method to immediately verify and parse the webhook event.
48
+ * Throws an error if the signature is invalid.
49
+ */
50
+ constructEvent: (payload: string, signature: string) => WebhookEvent;
51
+ };
52
+ }
package/dist/index.js ADDED
@@ -0,0 +1,86 @@
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.NullPay = void 0;
7
+ const node_fetch_1 = __importDefault(require("node-fetch"));
8
+ const crypto_1 = __importDefault(require("crypto"));
9
+ class NullPay {
10
+ constructor(config) {
11
+ this.checkout = {
12
+ sessions: {
13
+ create: async (params) => {
14
+ const response = await (0, node_fetch_1.default)(`${this.baseURL}/checkout/sessions`, {
15
+ method: 'POST',
16
+ headers: {
17
+ 'Content-Type': 'application/json',
18
+ 'Authorization': `Bearer ${this.secretKey}`
19
+ },
20
+ body: JSON.stringify(params)
21
+ });
22
+ if (!response.ok) {
23
+ const errorData = await response.json().catch(() => ({}));
24
+ throw new Error(`NullPay API Error: ${response.status} - ${errorData.error || response.statusText}`);
25
+ }
26
+ return await response.json();
27
+ },
28
+ retrieve: async (sessionId) => {
29
+ const response = await (0, node_fetch_1.default)(`${this.baseURL}/checkout/sessions/${sessionId}`, {
30
+ method: 'GET',
31
+ headers: {
32
+ 'Authorization': `Bearer ${this.secretKey}`
33
+ }
34
+ });
35
+ if (!response.ok) {
36
+ const errorData = await response.json().catch(() => ({}));
37
+ throw new Error(`NullPay API Error: ${response.status} - ${errorData.error || response.statusText}`);
38
+ }
39
+ return await response.json();
40
+ }
41
+ }
42
+ };
43
+ this.webhooks = {
44
+ /**
45
+ * Verifies the HMAC-SHA256 signature attached to a NullPay webhook payload.
46
+ * @param payload The raw stringified JSON body of the webhook request.
47
+ * @param signature The hex signature from the `x-nullpay-signature` header.
48
+ * @returns true if the signature is valid and securely originates from NullPay.
49
+ */
50
+ verifySignature: (payload, signature) => {
51
+ if (!payload || !signature)
52
+ return false;
53
+ try {
54
+ const expectedSignature = crypto_1.default
55
+ .createHmac('sha256', this.secretKey)
56
+ .update(payload)
57
+ .digest('hex');
58
+ // Constant-time string comparison to prevent timing attacks
59
+ if (expectedSignature.length !== signature.length)
60
+ return false;
61
+ return crypto_1.default.timingSafeEqual(Buffer.from(signature, 'utf8'), Buffer.from(expectedSignature, 'utf8'));
62
+ }
63
+ catch (err) {
64
+ console.error("NullPay Signature Verification Error:", err);
65
+ return false;
66
+ }
67
+ },
68
+ /**
69
+ * Helper method to immediately verify and parse the webhook event.
70
+ * Throws an error if the signature is invalid.
71
+ */
72
+ constructEvent: (payload, signature) => {
73
+ if (!this.webhooks.verifySignature(payload, signature)) {
74
+ throw new Error("Invalid NullPay Webhook Signature. This request might be spoofed.");
75
+ }
76
+ return JSON.parse(payload);
77
+ }
78
+ };
79
+ if (!config.secretKey) {
80
+ throw new Error("NullPay API Key is required.");
81
+ }
82
+ this.secretKey = config.secretKey;
83
+ this.baseURL = config.baseURL || 'https://null-pay-rs8i.vercel.app/api/v1';
84
+ }
85
+ }
86
+ exports.NullPay = NullPay;
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@nullpay/node",
3
+ "version": "1.0.0",
4
+ "description": "NullPay SDK for Node.js",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc"
12
+ },
13
+ "dependencies": {
14
+ "axios": "^1.6.0",
15
+ "node-fetch": "^2.7.0"
16
+ },
17
+ "devDependencies": {
18
+ "@types/node": "^25.4.0",
19
+ "@types/node-fetch": "^2.6.13",
20
+ "typescript": "^5.9.3"
21
+ }
22
+ }