simplepay-js-sdk 0.1.0 → 0.3.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/README.md CHANGED
@@ -1,37 +1,96 @@
1
- # SimplePay Node.js Utility
1
+ # SimplePay JS SDK
2
2
 
3
- A lightweight utility for integrating SimplePay payments in Node.js applications.
3
+ A lightweight utility for integrating Hungary's SimplePay payments in Node.js applications.
4
+
5
+ ![SimplePay Logo](simplepay_logo.jpg)
4
6
 
5
7
  ## Installation
6
8
 
7
9
  ```bash
10
+ # npm
8
11
  npm install simplepay-js-sdk
12
+
13
+ # yarn
14
+ yarn add simplepay-js-sdk
15
+
16
+ # pnpm
17
+ pnpm add simplepay-js-sdk
9
18
  ```
10
19
 
20
+ ## Configuration
21
+
22
+ Set the following environment variables in your `.env` file:
23
+
24
+ - `SIMPLEPAY_LOGGER` If it set to `true`, it will log varibles - useful only for debugging.
25
+ - `SIMPLEPAY_MERCHANT_KEY_HUF` Your Simplepay secret merchant key.
26
+ - `SIMPLEPAY_MERCHANT_ID_HUF` Your Simplepay merchant id.
27
+ - `SIMPLEPAY_PRODUCTION` If it set to `true`, it will use production environment, otherwise it will use sandbox environment.
28
+ - `SIMPLEPAY_REDIRECT_URL` The URL of your site, where the customer will be redirected after the payment.
29
+
11
30
  ## Usage
12
31
 
32
+ You should create 3 endpoints, to start the payment, get the payment response and handle the IPN.
33
+
34
+ ### Start Payment Endpoint
35
+
13
36
  ```typescript
14
- import { startPayment, getPaymentResponse } from 'simplepay-nodejs-utility'
37
+ import { startPayment } from 'simplepay-js-sdk'
15
38
 
16
- // Start a payment
17
- const paymentResponse = await startPayment({
18
- orderRef: 'unique-order-reference',
19
- total: 1000,
20
- customerEmail: 'customer@example.com',
21
- })
39
+ try {
40
+ const response = await startPayment({
41
+ orderRef: 'order-12',
42
+ total: 1212,
43
+ currency: 'HUF', // optional, defaults to HUF
44
+ customerEmail: 'rrd@webmania.cc',
45
+ language: 'HU', // optional, defaults to HU
46
+ method: 'CARD', // optional, CARD | WIRE, defaults to CARD
47
+ invoice: {
48
+ name: 'Radharadhya Dasa',
49
+ country: 'HU',
50
+ state: 'Budapest',
51
+ city: 'Budapest',
52
+ zip: '1234',
53
+ address: 'Sehol u. 0',
54
+ },
55
+ })
56
+ return response
57
+ } catch (error) {
58
+ console.error('Payment initiation failed:', error)
59
+ return error
60
+ }
61
+ ```
22
62
 
23
- // Handle payment response
24
- const result = getPaymentResponse(encodedResponse, signature)
63
+ `response.paymentUrl` will contain the Simplepay payment URL, which you can redirect the customer to.
64
+
65
+ ### Get Payment Response Endpoint
66
+
67
+ When the customer returns from the Simplepay payment page, you need to get the payment response at your `SIMPLEPAY_REDIRECT_URL`. The url will contain 2 parameters: `r` and `s`.
68
+
69
+ ```typescript
70
+ import { getPaymentResponse } from 'simplepay-js-sdk'
71
+
72
+ // get "r" and "s" from the url the way you do it on your app and framework
73
+
74
+ const response = getPaymentResponse(r, s)
25
75
  ```
26
76
 
27
- ## Configuration
77
+ `response` will have the following properties:
78
+
79
+ - `responseCode`: `0` on success, or an error code
80
+ - `transactionId`: the transaction id
81
+ - `event`: the event type: `success` | `fail` | `timeout` | `cancel`
82
+ - `merchantId`: the merchant id
83
+ - `orderId`: the order id
84
+
85
+ ### IPN Endpoint
28
86
 
29
- Set the following environment variables:
87
+ Simplepay will send a `POST` request to the IPN url and you should send a response back.
88
+ At this endpoint you should
30
89
 
31
- - `SIMPLEPAY_MERCHANT_KEY`
32
- - `SIMPLEPAY_MERCHANT_ID`
33
- - `SIMPLEPAY_PRODUCTION`
34
- - `SIMPLEPAY_REDIRECT_URL`
90
+ - check if the signature is valid - use `checkSignature(ipnBody, signatureHeader, SIMPLEPAY_MERCHANT_KEY_HUF)`
91
+ - add a `receiveDate` property to the received JSON
92
+ - calculate the new signature - use `generateSignature(responseText, SIMPLEPAY_MERCHANT_KEY_HUF)`
93
+ - send the `response` with the new `signature`
35
94
 
36
95
  ## License
37
96
 
package/dist/index.js CHANGED
@@ -14,13 +14,22 @@ const generateSignature = (body, merchantKey) => {
14
14
  const checkSignature = (responseText, signature, merchantKey) => signature === generateSignature(responseText, merchantKey);
15
15
  // escaping slashes for the request body to prevent strange SimplePay API errors (eg Missing Signature)
16
16
  const prepareRequestBody = (body) => JSON.stringify(body).replace(/\//g, '\\/');
17
- const SIMPLEPAY_API_URL = 'https://secure.simplepay.hu/payment/v2';
18
- const SIMPLEPAY_SANDBOX_URL = 'https://sandbox.simplepay.hu/payment/v2/start';
19
- const SDK_VERSION = 'SimplePayV2.1_Rrd_0.1.0';
20
- const startPayment = async (paymentData) => {
21
- const MERCHANT_KEY = process.env.SIMPLEPAY_MERCHANT_KEY;
22
- const MERCHANT_ID = process.env.SIMPLEPAY_MERCHANT_ID;
17
+ const getSimplePayConfig = () => {
18
+ const SIMPLEPAY_API_URL = 'https://secure.simplepay.hu/payment/v2';
19
+ const SIMPLEPAY_SANDBOX_URL = 'https://sandbox.simplepay.hu/payment/v2/start';
20
+ const SDK_VERSION = '0.3.0';
21
+ const MERCHANT_KEY = process.env.SIMPLEPAY_MERCHANT_KEY_HUF;
22
+ const MERCHANT_ID = process.env.SIMPLEPAY_MERCHANT_ID_HUF;
23
23
  const API_URL = process.env.SIMPLEPAY_PRODUCTION === 'true' ? SIMPLEPAY_API_URL : SIMPLEPAY_SANDBOX_URL;
24
+ return {
25
+ MERCHANT_KEY,
26
+ MERCHANT_ID,
27
+ API_URL,
28
+ SDK_VERSION
29
+ };
30
+ };
31
+ const startPayment = async (paymentData) => {
32
+ const { MERCHANT_KEY, MERCHANT_ID, API_URL, SDK_VERSION } = getSimplePayConfig();
24
33
  simplepayLogger({ MERCHANT_KEY, MERCHANT_ID, API_URL });
25
34
  if (!MERCHANT_KEY || !MERCHANT_ID) {
26
35
  throw new Error('Missing SimplePay configuration');
@@ -33,7 +42,7 @@ const startPayment = async (paymentData) => {
33
42
  customerEmail: paymentData.customerEmail,
34
43
  language: paymentData.language || 'HU',
35
44
  sdkVersion: SDK_VERSION,
36
- methods: ['CARD'],
45
+ methods: [paymentData.method || 'CARD'],
37
46
  total: String(paymentData.total),
38
47
  timeout: new Date(Date.now() + 30 * 60 * 1000)
39
48
  .toISOString()
@@ -79,9 +88,10 @@ const startPayment = async (paymentData) => {
79
88
  }
80
89
  };
81
90
  const getPaymentResponse = (r, signature) => {
91
+ const { MERCHANT_KEY } = getSimplePayConfig();
82
92
  // Note: Replaced atob with Buffer for ESM
83
93
  const rDecoded = Buffer.from(r, 'base64').toString('utf-8');
84
- if (!checkSignature(rDecoded, signature, process.env.SIMPLEPAY_MERCHANT_KEY || '')) {
94
+ if (!checkSignature(rDecoded, signature, MERCHANT_KEY || '')) {
85
95
  simplepayLogger({ rDecoded, signature });
86
96
  throw new Error('Invalid response signature');
87
97
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,9 +1,11 @@
1
+ type PaymentMethod = 'CARD' | 'WIRE';
1
2
  interface PaymentData {
2
3
  orderRef: string;
3
4
  total: number | string;
4
5
  customerEmail: string;
5
6
  currency?: string;
6
7
  language?: string;
8
+ method?: PaymentMethod;
7
9
  invoice?: {
8
10
  name: string;
9
11
  country: string;
@@ -20,7 +22,7 @@ interface SimplePayRequestBody extends Omit<PaymentData, 'total'> {
20
22
  salt: string;
21
23
  merchant: string;
22
24
  sdkVersion: string;
23
- methods: ['CARD'];
25
+ methods: PaymentMethod[];
24
26
  timeout: string;
25
27
  url: string;
26
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "simplepay-js-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "A Node.js utility for SimplePay payment integration",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,7 +20,9 @@
20
20
  "scripts": {
21
21
  "build": "tsc",
22
22
  "prepare": "npm run build",
23
- "test": "vitest"
23
+ "test": "vitest --run",
24
+ "test:watch": "vitest",
25
+ "release": "bash ./release.sh"
24
26
  },
25
27
  "keywords": [
26
28
  "simplepay",
@@ -31,7 +33,7 @@
31
33
  "author": "Radharadhya Dasa",
32
34
  "license": "MIT",
33
35
  "devDependencies": {
34
- "@types/node": "^20.0.0",
36
+ "@types/node": "^22.0.0",
35
37
  "typescript": "^5.0.0",
36
38
  "vitest": "^2.1.6"
37
39
  },
package/src/index.spec.ts CHANGED
@@ -1,5 +1,17 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { checkSignature, generateSignature } from './index'
1
+ import { describe, it, expect, vi } from 'vitest'
2
+ import { checkSignature, generateSignature, getPaymentResponse, startPayment } from './index'
3
+ import { PaymentData } from './types'
4
+
5
+ const setEnv = () => {
6
+ process.env.SIMPLEPAY_MERCHANT_KEY_HUF = 'testKey'
7
+ process.env.SIMPLEPAY_MERCHANT_ID_HUF = 'testId'
8
+ }
9
+
10
+ const paymentData = {
11
+ orderRef: 'TEST123',
12
+ customerEmail: 'test@example.com',
13
+ total: 1212
14
+ }
3
15
 
4
16
  describe('generateSignature', () => {
5
17
  it('should generate correct signature for sample payload from documentation', () => {
@@ -48,4 +60,92 @@ describe('checkSignature', () => {
48
60
  const result = checkSignature(JSON.stringify(response).replace(/\//g, '\\/'), expectedSignature, merchantKey)
49
61
  expect(result).toBeTruthy()
50
62
  })
63
+
64
+ it('should return false for invalid signature', () => {
65
+ const merchantKey = 'testKey'
66
+ const response = { test: 'data' }
67
+ const invalidSignature = 'invalid-signature'
68
+
69
+ const result = checkSignature(
70
+ JSON.stringify(response),
71
+ invalidSignature,
72
+ merchantKey
73
+ )
74
+ expect(result).toBeFalsy()
75
+ })
76
+ })
77
+
78
+ describe('getPaymentResponse', () => {
79
+ it('should correctly decode and parse valid response', () => {
80
+ // Create a base64 encoded response similar to what SimplePay returns
81
+ const mockResponse = {
82
+ r: 'SUCCESS',
83
+ t: '123456789',
84
+ e: 'PAYMENT',
85
+ m: 'MERCHANT123',
86
+ o: 'ORDER123'
87
+ }
88
+ const encodedResponse = Buffer.from(JSON.stringify(mockResponse)).toString('base64')
89
+ const validSignature = generateSignature(JSON.stringify(mockResponse), process.env.SIMPLEPAY_MERCHANT_KEY_HUF || '')
90
+
91
+ const result = getPaymentResponse(encodedResponse, validSignature)
92
+
93
+ expect(result).toEqual({
94
+ responseCode: 'SUCCESS',
95
+ transactionId: '123456789',
96
+ event: 'PAYMENT',
97
+ merchantId: 'MERCHANT123',
98
+ orderId: 'ORDER123'
99
+ })
100
+ })
101
+
102
+ it('should throw error for invalid signature', () => {
103
+ const mockResponse = { test: 'data' }
104
+ const encodedResponse = Buffer.from(JSON.stringify(mockResponse)).toString('base64')
105
+
106
+ expect(() =>
107
+ getPaymentResponse(encodedResponse, 'invalid-signature')
108
+ ).toThrow('Invalid response signature')
109
+ })
110
+ })
111
+
112
+ describe('startPayment', () => {
113
+ it('should throw error when merchant configuration is missing', async () => {
114
+ await expect(startPayment(paymentData)).rejects.toThrow('Missing SimplePay configuration')
115
+ })
116
+
117
+ it('should handle API errors correctly', async () => {
118
+ setEnv()
119
+
120
+ global.fetch = vi.fn().mockResolvedValue({
121
+ ok: true,
122
+ headers: {
123
+ get: vi.fn().mockReturnValue('mockSignature')
124
+ },
125
+ text: vi.fn().mockResolvedValue(JSON.stringify({
126
+ transactionId: '123456',
127
+ total: '1212',
128
+ merchant: 'testId'
129
+ }))
130
+ }) as unknown as typeof fetch
131
+ await expect(startPayment(paymentData)).rejects.toThrow('Invalid response signature')
132
+ })
133
+
134
+ it('should successfully start CARD, HUF, HU payment when API returns valid response', async () => {
135
+ setEnv()
136
+ global.fetch = vi.fn().mockResolvedValue({
137
+ ok: true,
138
+ headers: {
139
+ get: vi.fn().mockReturnValue('bxSwUc0qn0oABSRcq9uawF6zncFBhRk/AbO4HznYR9Pt5SjocyxAD+9Q4bE44h0J')
140
+ },
141
+ text: vi.fn().mockResolvedValue(JSON.stringify({
142
+ transactionId: '123456',
143
+ total: '1212',
144
+ merchant: 'testId'
145
+ }))
146
+ }) as unknown as typeof fetch
147
+
148
+ await expect(startPayment(paymentData)).resolves.toBeDefined()
149
+ })
51
150
  })
151
+
package/src/index.ts CHANGED
@@ -23,14 +23,25 @@ const checkSignature = (responseText: string, signature: string, merchantKey: st
23
23
  const prepareRequestBody = (body: SimplePayRequestBody) =>
24
24
  JSON.stringify(body).replace(/\//g, '\\/')
25
25
 
26
- const SIMPLEPAY_API_URL = 'https://secure.simplepay.hu/payment/v2'
27
- const SIMPLEPAY_SANDBOX_URL = 'https://sandbox.simplepay.hu/payment/v2/start'
28
- const SDK_VERSION = 'SimplePayV2.1_Rrd_0.1.0'
29
26
 
30
- const startPayment = async (paymentData: PaymentData) => {
31
- const MERCHANT_KEY = process.env.SIMPLEPAY_MERCHANT_KEY
32
- const MERCHANT_ID = process.env.SIMPLEPAY_MERCHANT_ID
27
+ const getSimplePayConfig = () => {
28
+ const SIMPLEPAY_API_URL = 'https://secure.simplepay.hu/payment/v2'
29
+ const SIMPLEPAY_SANDBOX_URL = 'https://sandbox.simplepay.hu/payment/v2/start'
30
+ const SDK_VERSION = '0.3.0'
31
+ const MERCHANT_KEY = process.env.SIMPLEPAY_MERCHANT_KEY_HUF
32
+ const MERCHANT_ID = process.env.SIMPLEPAY_MERCHANT_ID_HUF
33
33
  const API_URL = process.env.SIMPLEPAY_PRODUCTION === 'true' ? SIMPLEPAY_API_URL : SIMPLEPAY_SANDBOX_URL
34
+
35
+ return {
36
+ MERCHANT_KEY,
37
+ MERCHANT_ID,
38
+ API_URL,
39
+ SDK_VERSION
40
+ }
41
+ }
42
+
43
+ const startPayment = async (paymentData: PaymentData) => {
44
+ const { MERCHANT_KEY, MERCHANT_ID, API_URL, SDK_VERSION } = getSimplePayConfig()
34
45
  simplepayLogger({ MERCHANT_KEY, MERCHANT_ID, API_URL })
35
46
 
36
47
  if (!MERCHANT_KEY || !MERCHANT_ID) {
@@ -45,7 +56,7 @@ const startPayment = async (paymentData: PaymentData) => {
45
56
  customerEmail: paymentData.customerEmail,
46
57
  language: paymentData.language || 'HU',
47
58
  sdkVersion: SDK_VERSION,
48
- methods: ['CARD'],
59
+ methods: [paymentData.method || 'CARD'],
49
60
  total: String(paymentData.total),
50
61
  timeout: new Date(Date.now() + 30 * 60 * 1000)
51
62
  .toISOString()
@@ -101,10 +112,11 @@ const startPayment = async (paymentData: PaymentData) => {
101
112
  }
102
113
 
103
114
  const getPaymentResponse = (r: string, signature: string) => {
115
+ const { MERCHANT_KEY } = getSimplePayConfig()
104
116
  // Note: Replaced atob with Buffer for ESM
105
117
  const rDecoded = Buffer.from(r, 'base64').toString('utf-8')
106
118
 
107
- if (!checkSignature(rDecoded, signature, process.env.SIMPLEPAY_MERCHANT_KEY || '')) {
119
+ if (!checkSignature(rDecoded, signature, MERCHANT_KEY || '')) {
108
120
  simplepayLogger({ rDecoded, signature })
109
121
  throw new Error('Invalid response signature')
110
122
  }
package/src/types.ts CHANGED
@@ -1,9 +1,12 @@
1
+ type PaymentMethod = 'CARD' | 'WIRE'
2
+
1
3
  interface PaymentData {
2
4
  orderRef: string
3
5
  total: number | string
4
6
  customerEmail: string
5
7
  currency?: string
6
8
  language?: string
9
+ method?: PaymentMethod
7
10
  invoice?: {
8
11
  name: string
9
12
  country: string
@@ -21,7 +24,7 @@ interface SimplePayRequestBody extends Omit<PaymentData, 'total'> {
21
24
  salt: string
22
25
  merchant: string
23
26
  sdkVersion: string
24
- methods: ['CARD']
27
+ methods: PaymentMethod[]
25
28
  timeout: string
26
29
  url: string
27
30
  }