simplepay-js-sdk 0.6.0 → 0.7.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/src/index.ts CHANGED
@@ -1,161 +1,11 @@
1
- import crypto from 'crypto'
2
- import { PaymentData, SimplePayRequestBody, SimplePayResponse, SimplepayResult, Currency, CURRENCIES } from './types'
3
-
4
- // Existing interfaces remain the same
5
-
6
- const simplepayLogger = (...args: any[]) => {
7
- if (process.env.SIMPLEPAY_LOGGER !== 'true') {
8
- return
9
- }
10
- console.log(...args)
11
- }
12
-
13
- const generateSignature = (body: string, merchantKey: string) => {
14
- const hmac = crypto.createHmac('sha384', merchantKey.trim())
15
- hmac.update(body, 'utf8')
16
- return hmac.digest('base64')
17
- }
18
-
19
- const checkSignature = (responseText: string, signature: string, merchantKey: string) =>
20
- signature === generateSignature(responseText, merchantKey)
21
-
22
- // escaping slashes for the request body to prevent strange SimplePay API errors (eg Missing Signature)
23
- const prepareRequestBody = (body: SimplePayRequestBody) =>
24
- JSON.stringify(body).replace(/\//g, '\\/')
25
-
26
-
27
- const getSimplePayConfig = (currency: Currency) => {
28
- if (!CURRENCIES.includes(currency)) {
29
- throw new Error(`Unsupported currency: ${currency}`)
30
- }
31
-
32
- const SIMPLEPAY_API_URL = 'https://secure.simplepay.hu/payment/v2'
33
- const SIMPLEPAY_SANDBOX_URL = 'https://sandbox.simplepay.hu/payment/v2/start'
34
- const SDK_VERSION = 'SimplePayV2.1_Rrd_0.6.0'
35
- const MERCHANT_KEY = process.env[`SIMPLEPAY_MERCHANT_KEY_${currency}`]
36
- const MERCHANT_ID = process.env[`SIMPLEPAY_MERCHANT_ID_${currency}`]
37
- const API_URL = process.env.SIMPLEPAY_PRODUCTION === 'true' ? SIMPLEPAY_API_URL : SIMPLEPAY_SANDBOX_URL
38
-
39
- return {
40
- MERCHANT_KEY,
41
- MERCHANT_ID,
42
- API_URL,
43
- SDK_VERSION
44
- }
45
- }
46
-
47
- const startPayment = async (paymentData: PaymentData) => {
48
- const currency = paymentData.currency || 'HUF'
49
- const { MERCHANT_KEY, MERCHANT_ID, API_URL, SDK_VERSION } = getSimplePayConfig(currency)
50
- simplepayLogger({ MERCHANT_KEY, MERCHANT_ID, API_URL })
51
-
52
- if (!MERCHANT_KEY || !MERCHANT_ID) {
53
- throw new Error('Missing SimplePay configuration')
54
- }
55
-
56
- const requestBody: SimplePayRequestBody = {
57
- salt: crypto.randomBytes(16).toString('hex'),
58
- merchant: MERCHANT_ID,
59
- orderRef: paymentData.orderRef,
60
- currency,
61
- customerEmail: paymentData.customerEmail,
62
- language: paymentData.language || 'HU',
63
- sdkVersion: SDK_VERSION,
64
- methods: [paymentData.method || 'CARD'],
65
- total: String(paymentData.total),
66
- timeout: new Date(Date.now() + 30 * 60 * 1000)
67
- .toISOString()
68
- .replace(/\.\d{3}Z$/, '+00:00'),
69
- url: process.env.SIMPLEPAY_REDIRECT_URL || 'http://url.to.redirect',
70
- invoice: paymentData.invoice,
71
- }
72
-
73
- const bodyString = prepareRequestBody(requestBody)
74
- const signature = generateSignature(bodyString, MERCHANT_KEY)
75
- simplepayLogger({ bodyString, signature })
76
-
77
- try {
78
- const response = await fetch(API_URL, {
79
- method: 'POST',
80
- headers: {
81
- 'Content-Type': 'application/json',
82
- 'Signature': signature,
83
- },
84
- body: bodyString,
85
- })
86
-
87
- simplepayLogger({ response })
88
-
89
- if (!response.ok) {
90
- throw new Error(`SimplePay API error: ${response.status}`)
91
- }
92
-
93
- const responseSignature = response.headers.get('Signature')
94
- simplepayLogger({ responseSignature })
95
- if (!responseSignature) {
96
- throw new Error('Missing response signature')
97
- }
98
-
99
- const responseText = await response.text()
100
- const responseJSON = JSON.parse(responseText) as SimplePayResponse
101
- simplepayLogger({ responseText, responseJSON })
102
-
103
- if (responseJSON.errorCodes) {
104
- throw new Error(`SimplePay API error: ${responseJSON.errorCodes}`)
105
- }
106
-
107
- if (!checkSignature(responseText, responseSignature, MERCHANT_KEY)) {
108
- throw new Error('Invalid response signature')
109
- }
110
-
111
- return responseJSON
112
-
113
- } catch (error) {
114
- throw error
115
- }
116
- }
117
-
118
- const getCurrencyFromMerchantId = (merchantId: string) => {
119
- const currency = Object.entries(process.env)
120
- .find(([key, value]) =>
121
- key.startsWith('SIMPLEPAY_MERCHANT_ID_') && value === merchantId
122
- )?.[0]?.replace('SIMPLEPAY_MERCHANT_ID_', '') as Currency
123
- if (!currency) {
124
- throw new Error(`Merchant id not found in the environment: ${merchantId}`)
125
- }
126
- return currency
127
- }
128
-
129
- const getPaymentResponse = (r: string, signature: string) => {
130
- signature = decodeURIComponent(signature)
131
- signature = Buffer.from(signature, 'base64').toString('utf-8')
132
- const rDecoded = Buffer.from(r, 'base64').toString('utf-8')
133
- const rDecodedJSON = JSON.parse(rDecoded)
134
- const currency = getCurrencyFromMerchantId(rDecodedJSON.m)
135
- const { MERCHANT_KEY } = getSimplePayConfig(currency as Currency)
136
-
137
- if (!checkSignature(rDecoded, signature, MERCHANT_KEY || '')) {
138
- simplepayLogger({ rDecoded, signature })
139
- throw new Error('Invalid response signature')
140
- }
141
-
142
- const responseJson: SimplepayResult = JSON.parse(rDecoded)
143
- const response = {
144
- responseCode: responseJson.r,
145
- transactionId: responseJson.t,
146
- event: responseJson.e,
147
- merchantId: responseJson.m,
148
- orderRef: responseJson.o,
149
- }
150
-
151
- return response
152
- }
1
+ import { startPayment } from './oneTime'
2
+ import { startRecurringPayment, startTokenPayment} from './recurring'
3
+ import type { Currency, Language, PaymentMethod } from './types'
4
+ import { checkSignature, generateSignature, getPaymentResponse, toISO8601DateString } from './utils'
153
5
 
154
6
  export {
155
- startPayment,
156
- getPaymentResponse,
157
- getSimplePayConfig,
158
- generateSignature,
159
- checkSignature,
160
- getCurrencyFromMerchantId
7
+ Currency, Language, PaymentMethod,
8
+ checkSignature, generateSignature, toISO8601DateString, getPaymentResponse,
9
+ startPayment,
10
+ startRecurringPayment, startTokenPayment,
161
11
  }
@@ -0,0 +1,97 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest'
2
+ import { getPaymentResponse, startPayment } from './index'
3
+
4
+ const setEnv = () => {
5
+ process.env.SIMPLEPAY_MERCHANT_ID_HUF = 'testId'
6
+ process.env.SIMPLEPAY_MERCHANT_KEY_HUF = 'testKey'
7
+ process.env.SIMPLEPAY_MERCHANT_ID_EUR = 'merchantEuroId'
8
+ process.env.SIMPLEPAY_MERCHANT_KEY_EUR = 'secretEuroKey'
9
+ }
10
+
11
+ const paymentData = {
12
+ orderRef: 'TEST123',
13
+ customerEmail: 'test@example.com',
14
+ total: 1212
15
+ }
16
+ describe('SimplePay SDK Tests', () => {
17
+ beforeEach(() => {
18
+ // Clear all environment variables before each test
19
+ delete process.env.SIMPLEPAY_MERCHANT_ID_HUF
20
+ delete process.env.SIMPLEPAY_MERCHANT_KEY_HUF
21
+ delete process.env.SIMPLEPAY_MERCHANT_ID_EUR
22
+ delete process.env.SIMPLEPAY_MERCHANT_KEY_EUR
23
+ })
24
+
25
+ describe('startPayment', () => {
26
+ it('should throw error when merchant configuration is missing', async () => {
27
+ await expect(startPayment(paymentData)).rejects.toThrow('Missing SimplePay configuration')
28
+ })
29
+
30
+ it('should handle API errors correctly', async () => {
31
+ setEnv()
32
+
33
+ global.fetch = vi.fn().mockResolvedValue({
34
+ ok: true,
35
+ headers: {
36
+ get: vi.fn().mockReturnValue('mockSignature')
37
+ },
38
+ text: vi.fn().mockResolvedValue(JSON.stringify({
39
+ transactionId: '123456',
40
+ total: '1212',
41
+ merchant: 'testId'
42
+ }))
43
+ }) as unknown as typeof fetch
44
+ await expect(startPayment(paymentData)).rejects.toThrow('Invalid response signature')
45
+ })
46
+
47
+ it('should successfully start CARD, HUF, HU payment when API returns valid response', async () => {
48
+ setEnv()
49
+ global.fetch = vi.fn().mockResolvedValue({
50
+ ok: true,
51
+ headers: {
52
+ get: vi.fn().mockReturnValue('bxSwUc0qn0oABSRcq9uawF6zncFBhRk/AbO4HznYR9Pt5SjocyxAD+9Q4bE44h0J')
53
+ },
54
+ text: vi.fn().mockResolvedValue(JSON.stringify({
55
+ transactionId: '123456',
56
+ total: '1212',
57
+ merchant: 'testId'
58
+ }))
59
+ }) as unknown as typeof fetch
60
+
61
+ await expect(startPayment(paymentData)).resolves.toBeDefined()
62
+ })
63
+ })
64
+
65
+ describe('getPaymentResponse', () => {
66
+ it('should correctly decode and parse valid response', () => {
67
+ setEnv()
68
+ const r = 'eyJyIjowLCJ0Ijo1MDQyMzM4ODEsImUiOiJTVUNDRVNTIiwibSI6Im1lcmNoYW50RXVyb0lkIiwibyI6ImMtMS1ldXIifQ=='
69
+ // { r: 0, t: 504233881, e: 'SUCCESS', m: 'merchantEuroId', o: 'c-1-eur' }
70
+ const s = 'YlxrpDa8jF/xVB/rNsEJoFxOoHQ+CiziBmWSMIhYWHSCJmvLoc6kzAiZPmYDU8z6'
71
+ const result = getPaymentResponse(r, s)
72
+ expect(result).toEqual({
73
+ responseCode: 0,
74
+ transactionId: 504233881,
75
+ event: 'SUCCESS',
76
+ merchantId: 'merchantEuroId',
77
+ orderRef: 'c-1-eur'
78
+ })
79
+ })
80
+
81
+ it('should throw error for invalid signature', () => {
82
+ setEnv()
83
+ const mockResponse = {
84
+ r: 'SUCCESS',
85
+ t: '123456789',
86
+ e: 'PAYMENT',
87
+ m: 'testId',
88
+ o: 'ORDER123'
89
+ }
90
+ const encodedResponse = Buffer.from(JSON.stringify(mockResponse)).toString('base64')
91
+
92
+ expect(() =>
93
+ getPaymentResponse(encodedResponse, 'invalid-signature')
94
+ ).toThrow('Invalid response signature')
95
+ })
96
+ })
97
+ })
package/src/oneTime.ts ADDED
@@ -0,0 +1,33 @@
1
+ import crypto from 'crypto'
2
+ import { PaymentData, SimplePayRequestBody } from './types'
3
+ import { simplepayLogger, getSimplePayConfig, toISO8601DateString, makeSimplePayRequest } from './utils'
4
+
5
+ const startPayment = async (paymentData: PaymentData) => {
6
+ simplepayLogger({ function: 'SimplePay/startPayment', paymentData })
7
+ const currency = paymentData.currency || 'HUF'
8
+ const { MERCHANT_KEY, MERCHANT_ID, API_URL, SDK_VERSION } = getSimplePayConfig(currency)
9
+ simplepayLogger({ function: 'SimplePay/startPayment', MERCHANT_KEY, MERCHANT_ID, API_URL })
10
+
11
+ if (!MERCHANT_KEY || !MERCHANT_ID) {
12
+ throw new Error(`Missing SimplePay configuration for ${currency}`)
13
+ }
14
+
15
+ const requestBody: SimplePayRequestBody = {
16
+ salt: crypto.randomBytes(16).toString('hex'),
17
+ merchant: MERCHANT_ID,
18
+ orderRef: paymentData.orderRef,
19
+ currency,
20
+ customerEmail: paymentData.customerEmail,
21
+ language: paymentData.language || 'HU',
22
+ sdkVersion: SDK_VERSION,
23
+ methods: [paymentData.method || 'CARD'],
24
+ total: String(paymentData.total),
25
+ timeout: toISO8601DateString(new Date(Date.now() + 30 * 60 * 1000)),
26
+ url: process.env.SIMPLEPAY_REDIRECT_URL || 'http://url.to.redirect',
27
+ invoice: paymentData.invoice,
28
+ }
29
+
30
+ return makeSimplePayRequest(API_URL, requestBody, MERCHANT_KEY)
31
+ }
32
+
33
+ export { startPayment }
@@ -0,0 +1,71 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest'
2
+ import { startRecurringPayment } from './recurring'
3
+ import { toISO8601DateString } from './utils'
4
+
5
+ const setEnv = () => {
6
+ process.env.SIMPLEPAY_MERCHANT_ID_HUF = 'testId'
7
+ process.env.SIMPLEPAY_MERCHANT_KEY_HUF = 'testKey'
8
+ process.env.SIMPLEPAY_MERCHANT_ID_EUR = 'merchantEuroId'
9
+ process.env.SIMPLEPAY_MERCHANT_KEY_EUR = 'secretEuroKey'
10
+ }
11
+
12
+ const paymentData = {
13
+ orderRef: 'TEST123',
14
+ customer: 'Radharadhya Dasa',
15
+ customerEmail: 'test@example.com',
16
+ total: 1212,
17
+ recurring: {
18
+ times: 3,
19
+ until: toISO8601DateString(new Date(Date.now() + 6 * 30 * 24 * 60 * 60 * 1000)),
20
+ maxAmount: 12000
21
+ }
22
+ }
23
+ describe('SimplePay Recurring Tests', () => {
24
+ beforeEach(() => {
25
+ // Clear all environment variables before each test
26
+ delete process.env.SIMPLEPAY_MERCHANT_ID_HUF
27
+ delete process.env.SIMPLEPAY_MERCHANT_KEY_HUF
28
+ delete process.env.SIMPLEPAY_MERCHANT_ID_EUR
29
+ delete process.env.SIMPLEPAY_MERCHANT_KEY_EUR
30
+ })
31
+
32
+ describe('startRecurringPayment', () => {
33
+ it('should throw error when merchant configuration is missing', async () => {
34
+ await expect(startRecurringPayment(paymentData)).rejects.toThrow('Missing SimplePay configuration')
35
+ })
36
+
37
+ it('should handle API errors correctly', async () => {
38
+ setEnv()
39
+ global.fetch = vi.fn().mockResolvedValue({
40
+ ok: true,
41
+ headers: {
42
+ get: vi.fn().mockReturnValue('mockSignature')
43
+ },
44
+ text: vi.fn().mockResolvedValue(JSON.stringify({
45
+ transactionId: '123456',
46
+ total: '1212',
47
+ merchant: 'testId'
48
+ }))
49
+ }) as unknown as typeof fetch
50
+ await expect(startRecurringPayment(paymentData)).rejects.toThrow('Invalid response signature')
51
+ })
52
+
53
+ it('should successfully start recurring payment and card registration when API returns valid response', async () => {
54
+ setEnv()
55
+ global.fetch = vi.fn().mockResolvedValue({
56
+ ok: true,
57
+ headers: {
58
+ get: vi.fn().mockReturnValue('bxSwUc0qn0oABSRcq9uawF6zncFBhRk/AbO4HznYR9Pt5SjocyxAD+9Q4bE44h0J')
59
+ },
60
+ text: vi.fn().mockResolvedValue(JSON.stringify({
61
+ transactionId: '123456',
62
+ total: '1212',
63
+ merchant: 'testId'
64
+ }))
65
+ }) as unknown as typeof fetch
66
+
67
+ await expect(startRecurringPayment(paymentData)).resolves.toBeDefined()
68
+ })
69
+ })
70
+
71
+ })
@@ -0,0 +1,77 @@
1
+ import crypto from 'crypto'
2
+ import { SimplePayRecurringRequestBody, RecurringPaymentData, TokenPaymentData, SimplePayTokenRequestBody} from './types'
3
+ import { getSimplePayConfig, simplepayLogger, toISO8601DateString, makeSimplePayTokenRequest, makeSimplePayRecurringRequest} from './utils'
4
+
5
+ const INTERVAL_IN_MONTHS = 6
6
+ const DEFAULT_UNTIL = new Date(Date.now() + INTERVAL_IN_MONTHS * 30 * 24 * 60 * 60 * 1000)
7
+ const DEFAULT_MAX_AMOUNT = 12000
8
+ const DEFAULT_TIMES = 3
9
+
10
+ const startRecurringPayment = async (paymentData: RecurringPaymentData) => {
11
+ simplepayLogger({ function: 'SimplePay/startRecurringPayment', paymentData })
12
+ const currency = paymentData.currency || 'HUF'
13
+ const { MERCHANT_KEY, MERCHANT_ID, API_URL, SDK_VERSION } = getSimplePayConfig(currency)
14
+ simplepayLogger({ function: 'SimplePay/startRecurringPayment', MERCHANT_KEY, MERCHANT_ID, API_URL })
15
+
16
+ if (!MERCHANT_KEY || !MERCHANT_ID) {
17
+ throw new Error(`Missing SimplePay configuration for ${currency}`)
18
+ }
19
+
20
+ const requestBody: SimplePayRecurringRequestBody = {
21
+ salt: crypto.randomBytes(16).toString('hex'),
22
+ merchant: MERCHANT_ID,
23
+ orderRef: paymentData.orderRef,
24
+ currency,
25
+ customer: paymentData.customer,
26
+ customerEmail: paymentData.customerEmail,
27
+ language: paymentData.language || 'HU',
28
+ sdkVersion: SDK_VERSION,
29
+ methods: ['CARD'],
30
+ recurring: {
31
+ times: paymentData.recurring.times || DEFAULT_TIMES,
32
+ until: paymentData.recurring.until || toISO8601DateString(DEFAULT_UNTIL),
33
+ maxAmount: paymentData.recurring.maxAmount || DEFAULT_MAX_AMOUNT
34
+ },
35
+ threeDSReqAuthMethod: '02',
36
+ total: String(paymentData.total),
37
+ timeout: toISO8601DateString(new Date(Date.now() + 30 * 60 * 1000)),
38
+ url: process.env.SIMPLEPAY_REDIRECT_URL || 'http://url.to.redirect',
39
+ invoice: paymentData.invoice,
40
+ }
41
+
42
+ return makeSimplePayRecurringRequest(API_URL, requestBody, MERCHANT_KEY)
43
+ }
44
+
45
+ const startTokenPayment = async (paymentData: TokenPaymentData) => {
46
+ simplepayLogger({ function: 'SimplePay/startTokenPayment', paymentData })
47
+ const currency = paymentData.currency || 'HUF'
48
+ const { MERCHANT_KEY, MERCHANT_ID, API_URL_RECURRING, SDK_VERSION } = getSimplePayConfig(currency)
49
+ simplepayLogger({ function: 'SimplePay/startTokenPayment', MERCHANT_KEY, MERCHANT_ID, API_URL_RECURRING })
50
+
51
+ if (!MERCHANT_KEY || !MERCHANT_ID) {
52
+ throw new Error(`Missing SimplePay configuration for ${currency}`)
53
+ }
54
+
55
+ const requestBody: SimplePayTokenRequestBody = {
56
+ salt: crypto.randomBytes(16).toString('hex'),
57
+ merchant: MERCHANT_ID,
58
+ orderRef: paymentData.orderRef,
59
+ currency,
60
+ customer: paymentData.customer,
61
+ customerEmail: paymentData.customerEmail,
62
+ language: paymentData.language || 'HU',
63
+ sdkVersion: SDK_VERSION,
64
+ methods: ['CARD'],
65
+ token: paymentData.token,
66
+ type: 'MIT',
67
+ threeDSReqAuthMethod: '02',
68
+ total: String(paymentData.total),
69
+ timeout: toISO8601DateString(new Date(Date.now() + 30 * 60 * 1000)),
70
+ url: process.env.SIMPLEPAY_REDIRECT_URL || 'http://recurring.url.to.redirect',
71
+ invoice: paymentData.invoice,
72
+ }
73
+
74
+ return makeSimplePayTokenRequest(API_URL_RECURRING, requestBody, MERCHANT_KEY)
75
+ }
76
+
77
+ export { startRecurringPayment, startTokenPayment }
package/src/types.ts CHANGED
@@ -1,9 +1,9 @@
1
- type PaymentMethod = 'CARD' | 'WIRE'
1
+ export type PaymentMethod = 'CARD' | 'WIRE'
2
2
 
3
- const CURRENCIES = ['HUF', 'EUR', 'USD'] as const
4
- type Currency = typeof CURRENCIES[number]
3
+ export const CURRENCIES = ['HUF', 'EUR', 'USD'] as const
4
+ export type Currency = typeof CURRENCIES[number]
5
5
 
6
- const LANGUAGES = [
6
+ export const LANGUAGES = [
7
7
  'AR', // Arabic
8
8
  'BG', // Bulgarian
9
9
  'CS', // Czech
@@ -21,9 +21,9 @@ const LANGUAGES = [
21
21
  'TR', // Turkish
22
22
  'ZH', // Chinese
23
23
  ] as const
24
- type Language = typeof LANGUAGES[number]
24
+ export type Language = typeof LANGUAGES[number]
25
25
 
26
- interface PaymentData {
26
+ export interface PaymentData {
27
27
  orderRef: string
28
28
  total: number | string
29
29
  customerEmail: string
@@ -42,7 +42,24 @@ interface PaymentData {
42
42
  }
43
43
  }
44
44
 
45
- interface SimplePayRequestBody extends Omit<PaymentData, 'total'> {
45
+ export type ISO8601DateString = string
46
+ export interface Recurring {
47
+ times: number,
48
+ until: ISO8601DateString,
49
+ maxAmount: number
50
+ }
51
+ export interface RecurringPaymentData extends PaymentData {
52
+ customer: string,
53
+ recurring: Recurring
54
+ }
55
+
56
+ export interface TokenPaymentData extends Omit<PaymentData, 'method'> {
57
+ method: 'CARD',
58
+ customer: string,
59
+ token: string
60
+ }
61
+
62
+ export interface SimplePayRequestBody extends Omit<PaymentData, 'total'> {
46
63
  total: string
47
64
  salt: string
48
65
  merchant: string
@@ -52,24 +69,52 @@ interface SimplePayRequestBody extends Omit<PaymentData, 'total'> {
52
69
  url: string
53
70
  }
54
71
 
55
- interface SimplePayResponse {
72
+ export interface SimplePayRecurringRequestBody extends SimplePayRequestBody {
73
+ customer: string
74
+ recurring: Recurring
75
+ threeDSReqAuthMethod: '02' // only registered users can use this
76
+ }
77
+
78
+ export interface SimplePayTokenRequestBody extends SimplePayRequestBody {
79
+ customer: string
80
+ token: string
81
+ threeDSReqAuthMethod: '02' // only registered users can use this
82
+ type: 'MIT' // Merchant Initiated Transaction
83
+ }
84
+
85
+ export interface SimplePayResponse {
56
86
  salt: string
57
87
  merchant: string
58
88
  orderRef: string
59
89
  currency: Currency
60
90
  transactionId: string
61
- timeout: string
91
+ timeout: ISO8601DateString
62
92
  total: string
63
93
  paymentUrl: string
64
94
  errorCodes?: string[]
65
95
  }
66
96
 
67
- interface SimplepayResult {
97
+ export interface SimplePayRecurringResponse extends SimplePayResponse {
98
+ tokens: string[]
99
+ }
100
+
101
+ export interface SimplePayTokenResponse extends Omit<SimplePayResponse, 'paymentUrl' | 'timeout'> { }
102
+
103
+ export type SimplePayEvents = 'SUCCESS' | 'FAIL' | 'TIMEOUT' | 'CANCEL'
104
+
105
+ export interface SimplePayAPIResult {
68
106
  r: number // response code
69
107
  t: string // transaction id
70
- e: 'success' | 'fail' | 'timeout' | 'cancel' // event
108
+ e: SimplePayEvents // event
71
109
  m: string // merchant id
72
110
  o: string // order id
73
111
  }
74
112
 
75
- export { PaymentData, SimplePayRequestBody, SimplePayResponse, SimplepayResult, CURRENCIES, Currency, PaymentMethod, LANGUAGES, Language }
113
+ export interface SimplePayResult {
114
+ responseCode: number,
115
+ transactionId: string,
116
+ event: SimplePayEvents,
117
+ merchantId: string,
118
+ orderRef: string,
119
+ tokens?: string[],
120
+ }
@@ -1,6 +1,6 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest'
2
- import { checkSignature, generateSignature, getPaymentResponse, getSimplePayConfig, startPayment, getCurrencyFromMerchantId } from './index'
1
+ import { describe, it, expect, beforeEach } from 'vitest'
3
2
  import { Currency } from './types'
3
+ import { checkSignature, generateSignature, getCurrencyFromMerchantId, getSimplePayConfig } from './utils'
4
4
 
5
5
  const setEnv = () => {
6
6
  process.env.SIMPLEPAY_MERCHANT_ID_HUF = 'testId'
@@ -14,11 +14,13 @@ const paymentData = {
14
14
  customerEmail: 'test@example.com',
15
15
  total: 1212
16
16
  }
17
- describe('SimplePay SDK Tests', () => {
17
+ describe('SimplePay Utils Tests', () => {
18
18
  beforeEach(() => {
19
19
  // Clear all environment variables before each test
20
- delete process.env.SIMPLEPAY_MERCHANT_KEY_HUF
21
20
  delete process.env.SIMPLEPAY_MERCHANT_ID_HUF
21
+ delete process.env.SIMPLEPAY_MERCHANT_KEY_HUF
22
+ delete process.env.SIMPLEPAY_MERCHANT_ID_EUR
23
+ delete process.env.SIMPLEPAY_MERCHANT_KEY_EUR
22
24
  })
23
25
  describe('generateSignature', () => {
24
26
  it('should generate correct signature for sample payload from documentation', () => {
@@ -101,7 +103,6 @@ describe('SimplePay SDK Tests', () => {
101
103
  m: 'testId',
102
104
  o: 'ORDER123'
103
105
  }
104
- const encodedResponse = Buffer.from(JSON.stringify(mockResponse)).toString('base64')
105
106
 
106
107
  describe('getCurrencyFromMerchantId', () => {
107
108
  it('should return correct currency for merchantId', () => {
@@ -110,69 +111,4 @@ describe('SimplePay SDK Tests', () => {
110
111
  expect(currency).toBe('HUF')
111
112
  })
112
113
  })
113
-
114
- describe('getPaymentResponse', () => {
115
- it('should correctly decode and parse valid response', () => {
116
- setEnv()
117
- const r = 'eyJyIjowLCJ0Ijo1MDQyMzM4ODEsImUiOiJTVUNDRVNTIiwibSI6Im1lcmNoYW50RXVyb0lkIiwibyI6ImMtMS1ldXIifQ=='
118
- // { r: 0, t: 504233881, e: 'SUCCESS', m: 'merchantEuroId', o: 'c-1-eur' }
119
- const s = 'WWx4cnBEYThqRi94VkIvck5zRUpvRnhPb0hRK0NpemlCbVdTTUloWVdIU0NKbXZMb2M2a3pBaVpQbVlEVTh6Ng=='
120
- const result = getPaymentResponse(r, s)
121
- expect(result).toEqual({
122
- responseCode: 0,
123
- transactionId: 504233881,
124
- event: 'SUCCESS',
125
- merchantId: 'merchantEuroId',
126
- orderRef: 'c-1-eur'
127
- })
128
- })
129
-
130
- it('should throw error for invalid signature', () => {
131
- setEnv()
132
- expect(() =>
133
- getPaymentResponse(encodedResponse, 'invalid-signature')
134
- ).toThrow('Invalid response signature')
135
- })
136
- })
137
-
138
- describe('startPayment', () => {
139
- it('should throw error when merchant configuration is missing', async () => {
140
- await expect(startPayment(paymentData)).rejects.toThrow('Missing SimplePay configuration')
141
- })
142
-
143
- it('should handle API errors correctly', async () => {
144
- setEnv()
145
-
146
- global.fetch = vi.fn().mockResolvedValue({
147
- ok: true,
148
- headers: {
149
- get: vi.fn().mockReturnValue('mockSignature')
150
- },
151
- text: vi.fn().mockResolvedValue(JSON.stringify({
152
- transactionId: '123456',
153
- total: '1212',
154
- merchant: 'testId'
155
- }))
156
- }) as unknown as typeof fetch
157
- await expect(startPayment(paymentData)).rejects.toThrow('Invalid response signature')
158
- })
159
-
160
- it('should successfully start CARD, HUF, HU payment when API returns valid response', async () => {
161
- setEnv()
162
- global.fetch = vi.fn().mockResolvedValue({
163
- ok: true,
164
- headers: {
165
- get: vi.fn().mockReturnValue('bxSwUc0qn0oABSRcq9uawF6zncFBhRk/AbO4HznYR9Pt5SjocyxAD+9Q4bE44h0J')
166
- },
167
- text: vi.fn().mockResolvedValue(JSON.stringify({
168
- transactionId: '123456',
169
- total: '1212',
170
- merchant: 'testId'
171
- }))
172
- }) as unknown as typeof fetch
173
-
174
- await expect(startPayment(paymentData)).resolves.toBeDefined()
175
- })
176
- })
177
-
178
114
  })