gamemoney 5.0.0 → 7.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Maxim Makarov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,20 +1,24 @@
1
- ![GameMoney](https://auth.gamemoney.com/assets/img/logo_gamemoney_login.png)
1
+ ![GameMoney](https://cp.gmpays.com/assets/img/gm_logo.png)
2
2
 
3
3
  [GameMoney](https://gmpays.com/) API wrapper for Node.js
4
4
 
5
5
  Full API documentation [here](https://cp.gmpays.com/apidoc)
6
6
 
7
- ## Installation
7
+ ## Installation
8
+
8
9
  ```sh
9
10
  $ npm install gamemoney
10
11
  ```
11
12
 
13
+ The package is ESM-only (there is no CommonJS build) and has no runtime dependencies. It requires Node.js `>=22.12.0`, where ES modules can also be loaded with `require()`.
14
+
12
15
  ## Usage
13
16
 
14
17
  ### Initialization
18
+
15
19
  ```typescript
16
- import fs from 'fs'
17
- import GameMoney from 'gamemoney'
20
+ import fs from 'node:fs'
21
+ import { GameMoney } from 'gamemoney'
18
22
 
19
23
  const gm = new GameMoney({
20
24
  project: 42,
@@ -23,7 +27,7 @@ const gm = new GameMoney({
23
27
  // Optional. But to make checkouts must be specified
24
28
  rsaPrivateKey: {
25
29
  key: fs.readFileSync('./private.pem').toString(),
26
- passphrase: '123' // Optional
30
+ passphrase: '123', // Optional
27
31
  },
28
32
 
29
33
  // OR:
@@ -31,8 +35,64 @@ const gm = new GameMoney({
31
35
  // process.env.GM_RSA_PRIVATE_KEY ?? '',
32
36
  // 'base64',
33
37
  // )
38
+
39
+ // Optional. API host from the project settings. Default: https://paygate.gamemoney.com
40
+ apiUrl: 'https://paygate.gamemoney.com',
41
+
42
+ // Optional. GameMoney certificate or public key from the project settings,
43
+ // used to verify signatures of responses and notifications.
44
+ // Default: the certificate bundled with the package
45
+ gameMoneyPublicKey: fs.readFileSync('./gm.crt'),
46
+
47
+ // Optional. Request timeout in milliseconds. Default: no timeout
48
+ timeout: 30_000,
34
49
  })
35
50
  ```
36
51
 
52
+ From CommonJS code, via Node's built-in [`require(esm)`](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require):
53
+
54
+ ```javascript
55
+ const { GameMoney, verifyRsaSignature } = require('gamemoney')
56
+ ```
57
+
58
+ ### Errors
59
+
60
+ - `GameMoneyError`: GameMoney responded with `"state": "error"`, the error text is in `message`.
61
+ - `GameMoneyHttpError`: GameMoney responded with a non-2xx HTTP status, available in `status`.
62
+ - `TimeoutError`: the request did not complete within `timeout`. GameMoney may still process it, so check the operation status (for example, with `getCheckoutStatus`) before retrying.
63
+ - `Error` with `Response signature mismatch` or `Wrong rand parameter`: the response failed verification and must not be trusted.
64
+
65
+ ### Notifications
66
+
67
+ GameMoney resends payment and payout notifications for 24 hours until the project responds with `{"success": "true"}`:
68
+
69
+ ```typescript
70
+ if (!gm.verifyRsaSignature(notification)) {
71
+ response.send({ success: 'error', error: 'signature mismatch' })
72
+ return
73
+ }
74
+
75
+ response.send({ success: 'true' })
76
+ ```
77
+
78
+ Transfer notifications are answered with the created invoice signed with HMAC, see [the example](https://github.com/gamemoney-ps/gamemoney-node-sdk/tree/master/src/examples/transfer/callback.ts).
79
+
80
+ ### Signatures
81
+
82
+ `parametersToString`, `generateHmacSignature`, `generateRsaSignature` and `verifyRsaSignature` implement the [GameMoney signature algorithm](https://cp.gmpays.com/apidoc#sign_general) and are exported for custom integrations and tests, for example to sign responses of a GameMoney mock.
83
+
84
+ ### Other API methods
85
+
86
+ Any API method can be called with a signed request:
87
+
88
+ ```typescript
89
+ const response = await gm.request('exchange/rate', { from: 'USD', to: 'RUB' })
90
+ ```
91
+
37
92
  ### Examples
38
- See examples in [src/examples](https://github.com/gamemoney-ps/gamemoney-node-sdk/tree/master/src/examples) directory
93
+
94
+ See examples in [src/examples](https://github.com/gamemoney-ps/gamemoney-node-sdk/tree/master/src/examples) directory. They read the credentials from `GAMEMONEY_PROJECT_ID`, `GAMEMONEY_HMAC_PRIVATE_KEY` and `GAMEMONEY_RSA_PRIVATE_KEY` (base64) and can be run directly:
95
+
96
+ ```sh
97
+ $ node --env-file=.env src/examples/statistics/balance.ts
98
+ ```
@@ -0,0 +1 @@
1
+ export declare const gameMoneyCertificate = "-----BEGIN CERTIFICATE-----\nMIID3TCCAsWgAwIBAgIJANtAJ3UMiGLZMA0GCSqGSIb3DQEBCwUAMIGEMQswCQYD\nVQQGEwJDUjERMA8GA1UECAwIU2FuIEpvc2UxEjAQBgNVBAcMCVNhbnRhIEFuYTET\nMBEGA1UECgwKSUJTIFMuUi5MLjEeMBwGA1UEAwwVY2hlY2tpbi5nYW1lbW9uZXku\nY29tMRkwFwYJKoZIhvcNAQkBFgpjZW9AaWJzLmNyMB4XDTE2MDkwNDA3MjY0OVoX\nDTI2MDkwNjA3MjY0OVowgYQxCzAJBgNVBAYTAkNSMREwDwYDVQQIDAhTYW4gSm9z\nZTESMBAGA1UEBwwJU2FudGEgQW5hMRMwEQYDVQQKDApJQlMgUy5SLkwuMR4wHAYD\nVQQDDBVjaGVja2luLmdhbWVtb25leS5jb20xGTAXBgkqhkiG9w0BCQEWCmNlb0Bp\nYnMuY3IwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPK9ODW+BcqZ5P\nYlQWziyLzKImuE8EDn7XuE9ZDmpKiJxwDUKZHSQYH4QtHyx0qYAbIqIGrKemfTu1\nnvW9+O8yKLFLLcaXVaSLU7mpp8uSWasGbkLqE7xVLqxQZq1zrBSEPnKR1/dNxD83\n5pNzMLx7ki02t1J01MAj0FvQ3GemIAQU15m+w+9YKX8cUYEBm+h2KuY6uziLhJTM\nBAQRIXO3z4fkZhUi/0wpiy5Zxi2jbh07gab7me5dpxxwOs/Dt10S6J8qu+AAH0DE\n3diqQS4OcaCYJuIo/kJVxrn8TO2WKzSf2CBMWMzKtA2lOIMokC79gsrTFAasRM8j\nBQkvD5/TAgMBAAGjUDBOMB0GA1UdDgQWBBTqyL+faltohjM5faVuKxRUBCG25DAf\nBgNVHSMEGDAWgBTqyL+faltohjM5faVuKxRUBCG25DAMBgNVHRMEBTADAQH/MA0G\nCSqGSIb3DQEBCwUAA4IBAQBpnItyLrXE1RWdGE+xoJ2YEbjNtgEfzaypFPpVuMO0\nhvCV1rJJDS3zs/P1uSF0akqN4weSGOeFuFyGf3v2j40M1T1XdllOA8ucBv7Rfy2W\nl1rR2aU+Hd6rl0E/7lhtx3VUobgPVKZn8k7NMKkSMtF/f2cS9jI4i6gsJfFImMr9\ngWjEZAlmwQcnilZ6ZUhhn+0yHFbCoX8fETH/sZlofZOnN8EkETyqyfThIpTX41XH\ngeivrSfScNQH1mWJuE0DXMobNrhyJpxHRJwXXQyck6TiDM8OETki4PBzjKk/Gsyc\n61gqP9VPE2AVVwKypWOJidMxMZ03n4+MlyTbz3mnBXL9\n-----END CERTIFICATE-----\n";
@@ -1,4 +1,4 @@
1
- -----BEGIN CERTIFICATE-----
1
+ export const gameMoneyCertificate = `-----BEGIN CERTIFICATE-----
2
2
  MIID3TCCAsWgAwIBAgIJANtAJ3UMiGLZMA0GCSqGSIb3DQEBCwUAMIGEMQswCQYD
3
3
  VQQGEwJDUjERMA8GA1UECAwIU2FuIEpvc2UxEjAQBgNVBAcMCVNhbnRhIEFuYTET
4
4
  MBEGA1UECgwKSUJTIFMuUi5MLjEeMBwGA1UEAwwVY2hlY2tpbi5nYW1lbW9uZXku
@@ -21,3 +21,4 @@ gWjEZAlmwQcnilZ6ZUhhn+0yHFbCoX8fETH/sZlofZOnN8EkETyqyfThIpTX41XH
21
21
  geivrSfScNQH1mWJuE0DXMobNrhyJpxHRJwXXQyck6TiDM8OETki4PBzjKk/Gsyc
22
22
  61gqP9VPE2AVVwKypWOJidMxMZ03n4+MlyTbz3mnBXL9
23
23
  -----END CERTIFICATE-----
24
+ `;
@@ -1,8 +1,10 @@
1
- import { type RsaKey, type HmacKey } from './utils.js';
2
- export declare enum SignType {
3
- 'HMAC' = "HMAC",
4
- 'RSA' = "RSA"
5
- }
1
+ import { type RsaKey, type RsaPublicKey, type HmacKey } from './utils.ts';
2
+ export { generateHmacSignature, generateRsaSignature, parametersToString, verifyRsaSignature, } from './utils.ts';
3
+ export declare const SignType: {
4
+ readonly HMAC: 'HMAC';
5
+ readonly RSA: 'RSA';
6
+ };
7
+ export type SignType = (typeof SignType)[keyof typeof SignType];
6
8
  export type GenericRequest = {
7
9
  [key: string]: any;
8
10
  rand?: string;
@@ -21,9 +23,12 @@ export type Config = {
21
23
  rsaPrivateKey?: RsaKey;
22
24
  hmacPrivateKey: HmacKey;
23
25
  project: number;
26
+ apiUrl?: string;
27
+ gameMoneyPublicKey?: RsaPublicKey;
28
+ timeout?: number;
24
29
  };
25
30
  export type CreateInvoiceRequest = {
26
- [key: string]: any;
31
+ [key: string]: unknown;
27
32
  type: string;
28
33
  user: string;
29
34
  ip: string;
@@ -40,6 +45,8 @@ export type CreateInvoiceRequest = {
40
45
  return_mode?: 'skip';
41
46
  recurring?: 'yes';
42
47
  recurrent_token?: string;
48
+ payment_token?: string;
49
+ theme?: 'dark' | 'light';
43
50
  };
44
51
  export type CreateInvoiceResponse = {
45
52
  invoice: number;
@@ -47,11 +54,11 @@ export type CreateInvoiceResponse = {
47
54
  data: string;
48
55
  };
49
56
  export type GetInvoiceStatusRequestWithProjectInvoiceId = {
50
- [key: string]: any;
57
+ [key: string]: unknown;
51
58
  invoice: number;
52
59
  };
53
60
  export type GetInvoiceStatusRequestWithGamemoneyInvoiceId = {
54
- [key: string]: any;
61
+ [key: string]: unknown;
55
62
  project_invoice: string;
56
63
  };
57
64
  export type GetInvoiceStatusRequest = GetInvoiceStatusRequestWithProjectInvoiceId | GetInvoiceStatusRequestWithGamemoneyInvoiceId;
@@ -77,7 +84,7 @@ export type GetInvoiceStatusResponse = {
77
84
  txid?: string;
78
85
  };
79
86
  export type GetInvoiceListRequest = {
80
- [key: string]: any;
87
+ [key: string]: unknown;
81
88
  start: string;
82
89
  finish: string;
83
90
  status?: InvoiceStatus;
@@ -86,12 +93,34 @@ export type GetInvoiceListResponse = {
86
93
  list: GetInvoiceStatusResponse[];
87
94
  is_limit_exceeded: 'yes' | 'no';
88
95
  };
96
+ export type AddTokenInvoiceRequest = {
97
+ [key: string]: unknown;
98
+ user: string;
99
+ };
100
+ export type AddTokenInvoiceResponse = {
101
+ token: string;
102
+ };
103
+ export type GetCardSessionStatusRequest = Record<string, unknown> & ({
104
+ invoice: string;
105
+ } | {
106
+ project_invoice: string;
107
+ });
108
+ export type WaitOrDeclineCardSessionStatusResponse = {
109
+ status: 'wait' | 'decline';
110
+ data: string;
111
+ };
112
+ export type FinishCardSessionStatusResponse = {
113
+ status: 'finish';
114
+ type: 'redirect';
115
+ data: string;
116
+ };
117
+ export type GetCardSessionStatusResponse = WaitOrDeclineCardSessionStatusResponse | FinishCardSessionStatusResponse;
89
118
  export type CancelCheckoutRequest = {
90
- [key: string]: any;
119
+ [key: string]: unknown;
91
120
  projectId: string;
92
121
  };
93
122
  export type GetCheckoutStatusRequest = {
94
- [key: string]: any;
123
+ [key: string]: unknown;
95
124
  projectId: string;
96
125
  };
97
126
  export type Refund = {
@@ -121,7 +150,7 @@ export type GetCheckoutStatusResponse = {
121
150
  txid?: string;
122
151
  };
123
152
  export type GetCheckoutListRequest = {
124
- [key: string]: any;
153
+ [key: string]: unknown;
125
154
  start: string;
126
155
  finish: string;
127
156
  };
@@ -130,7 +159,7 @@ export type GetCheckoutListResponse = {
130
159
  is_limit_exceeded: 'yes' | 'no';
131
160
  };
132
161
  export type CreateCheckoutRequest = {
133
- [key: string]: any;
162
+ [key: string]: unknown;
134
163
  projectId: string;
135
164
  user: string;
136
165
  ip: string;
@@ -142,30 +171,52 @@ export type CreateCheckoutRequest = {
142
171
  userCurrency?: string;
143
172
  prepareToken?: string;
144
173
  };
174
+ export type PrepareCheckoutRequest = Record<string, unknown> & {
175
+ type: string;
176
+ wallet?: string;
177
+ currency?: string;
178
+ userCurrency?: string;
179
+ } & ({
180
+ amount: number;
181
+ } | {
182
+ paid_amount: number;
183
+ });
184
+ export type PrepareCheckoutResponse = {
185
+ amount: number;
186
+ net_amount: number;
187
+ paid_amount: number;
188
+ currency_project: string;
189
+ currency_user: string;
190
+ token?: string;
191
+ rate?: number;
192
+ expire?: number;
193
+ };
145
194
  export type AddCardRequest = {
146
- [key: string]: any;
195
+ [key: string]: unknown;
147
196
  user: string;
148
197
  redirect: string;
198
+ language?: string;
199
+ theme?: 'dark' | 'light';
149
200
  };
150
201
  export type AddCardResponse = {
151
202
  url: string;
152
203
  };
153
204
  export type AddTokenCardRequest = {
154
- [key: string]: any;
205
+ [key: string]: unknown;
155
206
  user: string;
156
207
  };
157
208
  export type AddTokenCardResponse = {
158
209
  token: string;
159
210
  };
160
211
  export type GetCardListRequest = {
161
- [key: string]: any;
212
+ [key: string]: unknown;
162
213
  user: string;
163
214
  };
164
215
  export type GetCardListResponse = {
165
216
  pans: string[];
166
217
  };
167
218
  export type GetCardFullListRequest = {
168
- [key: string]: any;
219
+ [key: string]: unknown;
169
220
  user: string;
170
221
  };
171
222
  export type GetCardFullListResponse = {
@@ -174,16 +225,17 @@ export type GetCardFullListResponse = {
174
225
  expire_month: string;
175
226
  expire_year: string;
176
227
  cardholder: string;
228
+ country?: string;
177
229
  }>;
178
230
  };
179
231
  export type DeleteCardRequest = {
180
- [key: string]: any;
232
+ [key: string]: unknown;
181
233
  user: string;
182
234
  pan: string;
183
235
  };
184
236
  export type PrepareExchangeRequest = {
185
- [key: string]: any;
186
- externalId: string;
237
+ [key: string]: unknown;
238
+ externalId?: string;
187
239
  minAmount: number;
188
240
  maxAmount: number;
189
241
  from: string;
@@ -197,12 +249,12 @@ export type PrepareExchangeResponse = {
197
249
  exchanged_amount_to: number;
198
250
  };
199
251
  export type ConvertExchangeRequest = {
200
- [key: string]: any;
252
+ [key: string]: unknown;
201
253
  id: number;
202
254
  amount: number;
203
255
  };
204
256
  export type FastConvertExchangeRequest = {
205
- [key: string]: any;
257
+ [key: string]: unknown;
206
258
  amount: number;
207
259
  from: string;
208
260
  to: string;
@@ -212,7 +264,7 @@ export type FastConvertExchangeResponse = {
212
264
  rate: number;
213
265
  };
214
266
  export type GetExchangeRateRequest = {
215
- [key: string]: any;
267
+ [key: string]: unknown;
216
268
  from: string;
217
269
  to: string;
218
270
  };
@@ -221,7 +273,7 @@ export type GetExchangeRateResponse = {
221
273
  sell: number;
222
274
  };
223
275
  export type GetExchangeInfoRequest = {
224
- [key: string]: any;
276
+ [key: string]: unknown;
225
277
  minAmount: number;
226
278
  maxAmount: number;
227
279
  from: string;
@@ -235,7 +287,7 @@ export type GetExchangeInfoResponse = {
235
287
  exchanged_amount_to: number;
236
288
  };
237
289
  export type GetExchangeStatusRequest = {
238
- [key: string]: any;
290
+ [key: string]: unknown;
239
291
  id?: number;
240
292
  externalId?: string;
241
293
  };
@@ -249,7 +301,7 @@ export type GetExchangeStatusResponse = {
249
301
  status: string;
250
302
  };
251
303
  export type GetBalanceStatisticsRequest = {
252
- [key: string]: any;
304
+ [key: string]: unknown;
253
305
  currency: string;
254
306
  };
255
307
  export type GetBalanceStatisticsResponse = {
@@ -263,7 +315,7 @@ export type GetBalanceStatisticsResponse = {
263
315
  contract_balance: number;
264
316
  };
265
317
  export type GetDaysBalanceStatisticsRequest = {
266
- [key: string]: any;
318
+ [key: string]: unknown;
267
319
  currency: string;
268
320
  start: string;
269
321
  finish: string;
@@ -294,7 +346,7 @@ export type GetPayTypesStatisticsResponse = {
294
346
  checkout: PaySystem[];
295
347
  };
296
348
  export type CreateTerminalRequest = {
297
- [key: string]: any;
349
+ [key: string]: unknown;
298
350
  user: string;
299
351
  amount?: number;
300
352
  comment?: string;
@@ -304,21 +356,26 @@ export type CreateTerminalRequest = {
304
356
  currency?: string;
305
357
  use_user_select_currency?: 'yes' | 'no';
306
358
  language?: string;
359
+ return_mode?: 'skip';
360
+ recurring?: 'yes';
307
361
  terminal_allow_methods?: string[];
308
362
  terminal_disable_methods?: string[];
363
+ terminal_livetime?: number;
364
+ terminal_country?: string;
365
+ terminal_theme?: 'dark' | 'light';
309
366
  };
310
367
  export type CreateTerminalResponse = {
311
368
  url: string;
312
369
  };
313
370
  export type InvoiceStatus = 'New' | 'Processing' | 'Paid' | 'Chargeback' | 'Refund' | 'Chargeback_cancel' | 'Refused';
314
371
  export type InvoiceNotification = {
315
- project: number;
316
- invoice: number;
372
+ project: string;
373
+ invoice: string;
317
374
  status: InvoiceStatus;
318
- amount: number;
319
- net_amount: number;
320
- recieved_amount: number;
321
- rate?: number;
375
+ amount: string;
376
+ net_amount: string;
377
+ recieved_amount: string;
378
+ rate?: string;
322
379
  user: string;
323
380
  type: string;
324
381
  wallet: string;
@@ -360,6 +417,7 @@ export type TransferNotification = {
360
417
  currency: string;
361
418
  user: string;
362
419
  type: string;
420
+ project: number;
363
421
  ip: string;
364
422
  time: number;
365
423
  comment: string;
@@ -369,21 +427,32 @@ type Payload = Record<string, unknown>;
369
427
  export declare class GameMoneyError extends Error {
370
428
  constructor(message: string);
371
429
  }
372
- export default class GameMoney {
430
+ export declare class GameMoneyHttpError extends Error {
431
+ readonly status: number;
432
+ constructor(status: number, statusText: string);
433
+ }
434
+ export declare class GameMoney {
373
435
  private readonly config;
374
- private readonly got;
375
436
  constructor(config: Config);
376
437
  request<T extends GenericResponse>(url: string, payload?: Payload, signType?: SignType): Promise<T>;
377
- generateHmacSignature(body: any): string;
378
- verifyRsaSignature(body: any): boolean;
438
+ generateHmacSignature(body: Record<string, unknown>): string;
439
+ verifyRsaSignature(body: unknown): boolean;
379
440
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_insert_api) */
380
441
  createInvoice(body: CreateInvoiceRequest): Promise<CreateInvoiceResponse & GenericResponse>;
381
442
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_status) */
382
443
  getInvoiceStatus(body: GetInvoiceStatusRequest): Promise<GetInvoiceStatusResponse & GenericResponse>;
383
444
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_list) */
384
445
  getInvoiceList(body: GetInvoiceListRequest): Promise<GetInvoiceListResponse & GenericResponse>;
446
+ /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_add_token) */
447
+ addTokenInvoice(body: AddTokenInvoiceRequest): Promise<AddTokenInvoiceResponse & GenericResponse>;
448
+ /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_session_status) */
449
+ getCardSessionStatus(body: GetCardSessionStatusRequest): Promise<GetCardSessionStatusResponse & GenericResponse>;
385
450
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_insert) */
386
451
  createCheckout(body: CreateCheckoutRequest): Promise<GenericResponse>;
452
+ /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_prepare) */
453
+ prepareCheckout(body: PrepareCheckoutRequest): Promise<PrepareCheckoutResponse & GenericResponse>;
454
+ /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_check) */
455
+ checkCheckout(body: CreateCheckoutRequest): Promise<GenericResponse>;
387
456
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_cancel) */
388
457
  cancelCheckout(body: CancelCheckoutRequest): Promise<GenericResponse>;
389
458
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_status) */
@@ -398,7 +467,7 @@ export default class GameMoney {
398
467
  getCardList(body: GetCardListRequest): Promise<GetCardListResponse & GenericResponse>;
399
468
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_fulllist) */
400
469
  getCardFullList(body: GetCardFullListRequest): Promise<GetCardFullListResponse & GenericResponse>;
401
- /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_list) */
470
+ /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_delete) */
402
471
  deleteCard(body: DeleteCardRequest): Promise<GenericResponse>;
403
472
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#exchange_prepare) */
404
473
  prepareExchange(body: PrepareExchangeRequest): Promise<PrepareExchangeResponse & GenericResponse>;
@@ -421,4 +490,4 @@ export default class GameMoney {
421
490
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_api_terminal) */
422
491
  createTerminal(body: CreateTerminalRequest): Promise<CreateTerminalResponse & GenericResponse>;
423
492
  }
424
- export {};
493
+ export default GameMoney;
@@ -1,34 +1,36 @@
1
- import got from 'got';
2
- import { generateRsaSignature, generateHmacSignature, getRandomString, verifyRsaSignature, } from './utils.js';
3
- export var SignType;
4
- (function (SignType) {
5
- SignType["HMAC"] = "HMAC";
6
- SignType["RSA"] = "RSA";
7
- })(SignType || (SignType = {}));
1
+ import { generateRsaSignature, generateHmacSignature, getRandomString, stringifyForm, verifyRsaSignature, } from './utils.js';
2
+ export { generateHmacSignature, generateRsaSignature, parametersToString, verifyRsaSignature, } from './utils.js';
3
+ export const SignType = {
4
+ HMAC: 'HMAC',
5
+ RSA: 'RSA',
6
+ };
8
7
  export class GameMoneyError extends Error {
9
8
  constructor(message) {
10
9
  super(message);
11
10
  this.name = 'GameMoneyError';
12
11
  }
13
12
  }
14
- export default class GameMoney {
13
+ export class GameMoneyHttpError extends Error {
14
+ status;
15
+ constructor(status, statusText) {
16
+ super(`Response code ${status} (${statusText})`);
17
+ this.name = 'GameMoneyHttpError';
18
+ this.status = status;
19
+ }
20
+ }
21
+ export class GameMoney {
15
22
  config;
16
- got = got.extend({
17
- prefixUrl: 'https://paygate.gamemoney.com',
18
- responseType: 'json',
19
- });
20
23
  constructor(config) {
21
24
  this.config = config;
22
- this.config = config;
23
25
  }
24
26
  async request(url, payload = {}, signType = SignType.HMAC) {
25
27
  const form = {
26
- rand: getRandomString(20),
27
- project: this.config.project,
28
28
  ...payload,
29
+ project: payload.project ?? this.config.project,
30
+ rand: payload.rand ?? getRandomString(20),
29
31
  };
30
32
  if (signType === SignType.RSA) {
31
- if (!this.config.rsaPrivateKey) {
33
+ if (this.config.rsaPrivateKey === undefined) {
32
34
  throw new Error("To make requests with RSA sign type, 'rsaPrivateKey' must be provided");
33
35
  }
34
36
  form.signature = generateRsaSignature(form, this.config.rsaPrivateKey);
@@ -36,12 +38,22 @@ export default class GameMoney {
36
38
  else {
37
39
  form.signature = generateHmacSignature(form, this.config.hmacPrivateKey);
38
40
  }
39
- const response = await this.got.post({
40
- url,
41
- form,
42
- resolveBodyOnly: true,
41
+ const httpResponse = await fetch(new URL(url, this.config.apiUrl ?? 'https://paygate.gamemoney.com'), {
42
+ method: 'POST',
43
+ headers: {
44
+ accept: 'application/json',
45
+ 'content-type': 'application/x-www-form-urlencoded',
46
+ },
47
+ body: stringifyForm(form),
48
+ signal: this.config.timeout === undefined
49
+ ? null
50
+ : AbortSignal.timeout(this.config.timeout),
43
51
  });
44
- if (!verifyRsaSignature(response)) {
52
+ if (!httpResponse.ok) {
53
+ throw new GameMoneyHttpError(httpResponse.status, httpResponse.statusText);
54
+ }
55
+ const response = (await httpResponse.json());
56
+ if (!verifyRsaSignature(response, this.config.gameMoneyPublicKey)) {
45
57
  throw new Error('Response signature mismatch');
46
58
  }
47
59
  if (form.rand !== response.rand) {
@@ -56,7 +68,7 @@ export default class GameMoney {
56
68
  return generateHmacSignature(body, this.config.hmacPrivateKey);
57
69
  }
58
70
  verifyRsaSignature(body) {
59
- return verifyRsaSignature(body);
71
+ return verifyRsaSignature(body, this.config.gameMoneyPublicKey);
60
72
  }
61
73
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_insert_api) */
62
74
  async createInvoice(body) {
@@ -70,10 +82,26 @@ export default class GameMoney {
70
82
  async getInvoiceList(body) {
71
83
  return this.request('invoice/list', body);
72
84
  }
85
+ /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_add_token) */
86
+ async addTokenInvoice(body) {
87
+ return this.request('invoice/addtoken', body);
88
+ }
89
+ /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_session_status) */
90
+ async getCardSessionStatus(body) {
91
+ return this.request('invoice/cardsession/status', body);
92
+ }
73
93
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_insert) */
74
94
  async createCheckout(body) {
75
95
  return this.request('checkout/insert', body, SignType.RSA);
76
96
  }
97
+ /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_prepare) */
98
+ async prepareCheckout(body) {
99
+ return this.request('checkout/prepare', body);
100
+ }
101
+ /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_check) */
102
+ async checkCheckout(body) {
103
+ return this.request('checkout/check', body, SignType.RSA);
104
+ }
77
105
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_cancel) */
78
106
  async cancelCheckout(body) {
79
107
  return this.request('checkout/cancel', body);
@@ -102,7 +130,7 @@ export default class GameMoney {
102
130
  async getCardFullList(body) {
103
131
  return this.request('card/fulllist', body);
104
132
  }
105
- /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_list) */
133
+ /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_delete) */
106
134
  async deleteCard(body) {
107
135
  return this.request('card/delete', body);
108
136
  }
@@ -147,3 +175,4 @@ export default class GameMoney {
147
175
  return this.request('terminal/create', body);
148
176
  }
149
177
  }
178
+ export default GameMoney;
@@ -1,16 +1,17 @@
1
- /// <reference types="node" />
2
1
  import crypto from 'node:crypto';
3
2
  export type RsaKey = Parameters<crypto.Sign['sign']>[0];
3
+ export type RsaPublicKey = Parameters<crypto.Verify['verify']>[0];
4
4
  export type HmacKey = Parameters<typeof crypto.createHmac>[1];
5
5
  type JsonPrimitive = number | number[] | string | string[] | undefined | null;
6
6
  type Json = {
7
7
  [key: string]: Json | JsonPrimitive;
8
8
  };
9
- type Body = {
10
- signature: string;
11
- } & Json;
9
+ type FormValue = string | number | boolean | bigint | undefined | null | FormValue[] | {
10
+ [key: string]: FormValue;
11
+ };
12
12
  export declare function parametersToString(body: Json): string;
13
- export declare function verifyRsaSignature(body: Body): boolean;
13
+ export declare function stringifyForm(form: Record<string, FormValue>): string;
14
+ export declare function verifyRsaSignature(body: unknown, publicKey?: RsaPublicKey): boolean;
14
15
  export declare function generateRsaSignature(body: Json, key: RsaKey): string;
15
16
  export declare function generateHmacSignature(body: Json, key: HmacKey): string;
16
17
  export declare function getRandomString(length: number): string;
package/dist/utils.js ADDED
@@ -0,0 +1,77 @@
1
+ import crypto from 'node:crypto';
2
+ import { gameMoneyCertificate } from './certificate.js';
3
+ export function parametersToString(body) {
4
+ let parametersString = '';
5
+ const keys = Object.keys(body).sort();
6
+ if (Array.isArray(body)) {
7
+ keys.sort((a, b) => Number(a) - Number(b));
8
+ }
9
+ for (const key of keys) {
10
+ let value = body[key];
11
+ if (key === 'signature') {
12
+ continue;
13
+ }
14
+ if (value === null || value === undefined) {
15
+ value = '';
16
+ }
17
+ if (typeof value === 'object' && value !== null) {
18
+ value = parametersToString(value);
19
+ }
20
+ parametersString += `${key}:${value};`;
21
+ }
22
+ return parametersString;
23
+ }
24
+ // Wire format of gamemoney@3 (request + qs): RFC 3986 escaping, nested values as `key[index]=value`
25
+ function encodeFormComponent(value) {
26
+ return encodeURIComponent(value).replaceAll(/[!'()*]/g, (char) => `%${char.codePointAt(0).toString(16).toUpperCase()}`);
27
+ }
28
+ function appendFormValue(pairs, key, value) {
29
+ if (value === undefined) {
30
+ return;
31
+ }
32
+ if (typeof value === 'object' && value !== null) {
33
+ for (const [nestedKey, nestedValue] of Object.entries(value)) {
34
+ appendFormValue(pairs, `${key}[${nestedKey}]`, nestedValue);
35
+ }
36
+ return;
37
+ }
38
+ pairs.push(`${encodeFormComponent(key)}=${encodeFormComponent(value === null ? '' : String(value))}`);
39
+ }
40
+ export function stringifyForm(form) {
41
+ const pairs = [];
42
+ for (const [key, value] of Object.entries(form)) {
43
+ appendFormValue(pairs, key, value);
44
+ }
45
+ return pairs.join('&');
46
+ }
47
+ export function verifyRsaSignature(body, publicKey = gameMoneyCertificate) {
48
+ if (typeof body !== 'object' ||
49
+ body === null ||
50
+ !('signature' in body) ||
51
+ typeof body.signature !== 'string' ||
52
+ body.signature === '') {
53
+ return false;
54
+ }
55
+ return crypto
56
+ .createVerify('RSA-SHA256')
57
+ .update(parametersToString(body), 'utf8')
58
+ .verify(publicKey, body.signature, 'base64');
59
+ }
60
+ export function generateRsaSignature(body, key) {
61
+ return crypto
62
+ .createSign('RSA-SHA256')
63
+ .update(parametersToString(body), 'utf8')
64
+ .sign(key, 'base64');
65
+ }
66
+ export function generateHmacSignature(body, key) {
67
+ return crypto
68
+ .createHmac('sha256', key)
69
+ .update(parametersToString(body), 'utf8')
70
+ .digest('hex');
71
+ }
72
+ export function getRandomString(length) {
73
+ return crypto
74
+ .randomBytes(Math.ceil(length / 2))
75
+ .toString('hex')
76
+ .slice(0, length);
77
+ }
package/package.json CHANGED
@@ -1,85 +1,76 @@
1
1
  {
2
- "name": "gamemoney",
3
- "version": "5.0.0",
4
- "description": "GameMoney API wrapper for Node.js",
5
- "keywords": [
6
- "gamemoney",
7
- "gmpays",
8
- "gm",
9
- "merchant"
10
- ],
11
- "homepage": "https://github.com/gamemoney-ps/gamemoney-node-sdk#readme",
12
- "bugs": {
13
- "url": "https://github.com/gamemoney-ps/gamemoney-node-sdk/issues",
14
- "email": "maxpain177@gmail.com"
15
- },
16
- "author": {
17
- "name": "Maxim Makarov",
18
- "email": "maxpain177@gmail.com",
19
- "url": "https://maxpain.pro"
20
- },
21
- "license": "MIT",
22
- "repository": {
23
- "type": "git",
24
- "url": "https://github.com/gamemoney-ps/gamemoney-node-sdk"
25
- },
26
- "type": "module",
27
- "exports": {
28
- ".": {
29
- "import": "./index.js",
30
- "types": "./index.d.ts"
31
- }
32
- },
33
- "scripts": {
34
- "prebuild": "rm -rf .build",
35
- "build": "tsc",
36
- "postbuild": "cp -r package*.json .npmignore ./src/certs README.md .build",
37
- "test": "NODE_OPTIONS=--experimental-vm-modules jest",
38
- "lint": "xo",
39
- "lint:fix": "xo --fix"
40
- },
41
- "lint-staged": {
42
- "*.ts": "xo"
43
- },
44
- "jest": {
45
- "testMatch": [
46
- "**/*.test.ts"
47
- ],
48
- "preset": "ts-jest/presets/default-esm",
49
- "globals": {
50
- "ts-jest": {
51
- "useESM": true
52
- }
53
- },
54
- "moduleNameMapper": {
55
- "^(\\.{1,2}/.*)\\.js$": "$1"
56
- },
57
- "maxConcurrency": 50
58
- },
59
- "xo": {
60
- "extends": "@onmoon",
61
- "prettier": true
62
- },
63
- "prettier": "@onmoon/prettier-config",
64
- "devDependencies": {
65
- "@onmoon/eslint-config": "^1.0.12",
66
- "@onmoon/prettier-config": "^1.0.2",
67
- "@onmoon/tsconfigs": "^2.0.2",
68
- "@types/body-parser": "^1.19.2",
69
- "@types/express": "^4.17.17",
70
- "@types/jest": "^29.4.0",
71
- "@types/node": "^18.13.0",
72
- "@types/uuid": "^9.0.0",
73
- "body-parser": "^1.20.1",
74
- "express": "^4.18.2",
75
- "husky": "^8.0.3",
76
- "lint-staged": "^13.1.1",
77
- "ts-jest": "^29.0.5",
78
- "typescript": "^4.9.5",
79
- "uuid": "^9.0.0",
80
- "xo": "^0.53.1"
81
- },
82
- "dependencies": {
83
- "got": "^12.5.3"
84
- }
85
- }
2
+ "name": "gamemoney",
3
+ "version": "7.0.0",
4
+ "description": "GameMoney API wrapper for Node.js",
5
+ "keywords": [
6
+ "gamemoney",
7
+ "gmpays",
8
+ "gm",
9
+ "merchant"
10
+ ],
11
+ "homepage": "https://github.com/gamemoney-ps/gamemoney-node-sdk#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/gamemoney-ps/gamemoney-node-sdk/issues",
14
+ "email": "maxpain@linux.com"
15
+ },
16
+ "author": {
17
+ "name": "Max Makarov",
18
+ "email": "maxpain@linux.com"
19
+ },
20
+ "license": "MIT",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/gamemoney-ps/gamemoney-node-sdk.git"
24
+ },
25
+ "type": "module",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "default": "./dist/index.js"
30
+ },
31
+ "./package.json": "./package.json"
32
+ },
33
+ "main": "./dist/index.js",
34
+ "types": "./dist/index.d.ts",
35
+ "files": [
36
+ "dist"
37
+ ],
38
+ "sideEffects": false,
39
+ "engines": {
40
+ "node": ">=22.12.0"
41
+ },
42
+ "devEngines": {
43
+ "runtime": {
44
+ "name": "node",
45
+ "version": ">=22.22.1",
46
+ "onFail": "error"
47
+ }
48
+ },
49
+ "scripts": {
50
+ "build": "rm -rf dist && tsc -p tsconfig.build.json",
51
+ "typecheck": "tsc",
52
+ "test": "node --test 'src/**/*.test.ts'",
53
+ "lint": "oxlint && oxfmt --check",
54
+ "lint:fix": "oxlint --fix && oxfmt",
55
+ "prepublishOnly": "npm run lint && npm run typecheck && npm test",
56
+ "prepack": "npm run build",
57
+ "prepare": "husky"
58
+ },
59
+ "lint-staged": {
60
+ "*.ts": "oxlint",
61
+ "*": "oxfmt --check --no-error-on-unmatched-pattern"
62
+ },
63
+ "devDependencies": {
64
+ "@types/body-parser": "^1.19.6",
65
+ "@types/express": "^5.0.6",
66
+ "@types/node": "^22.20.5",
67
+ "body-parser": "^2.4.0",
68
+ "express": "^5.3.0",
69
+ "husky": "^9.1.7",
70
+ "lint-staged": "^17.6.0",
71
+ "oxfmt": "^0.74.0",
72
+ "oxlint": "^1.89.0",
73
+ "oxlint-tsgolint": "^7.0.2005",
74
+ "typescript": "^7.0.2"
75
+ }
76
+ }
package/utils.js DELETED
@@ -1,51 +0,0 @@
1
- import { URL } from 'node:url';
2
- import crypto from 'node:crypto';
3
- import fs from 'node:fs';
4
- const publicCert = fs
5
- .readFileSync(new URL('certs/gm.crt', import.meta.url))
6
- .toString();
7
- export function parametersToString(body) {
8
- let parametersString = '';
9
- const keys = Object.keys(body).sort();
10
- if (Array.isArray(body)) {
11
- keys.sort((a, b) => Number(a) - Number(b));
12
- }
13
- for (const key of keys) {
14
- let value = body[key];
15
- if (key === 'signature') {
16
- continue;
17
- }
18
- if (value === null || value === undefined) {
19
- value = '';
20
- }
21
- if (typeof value === 'object' && value !== null) {
22
- value = parametersToString(value);
23
- }
24
- parametersString += `${key}:${value};`;
25
- }
26
- return parametersString;
27
- }
28
- export function verifyRsaSignature(body) {
29
- return crypto
30
- .createVerify('RSA-SHA256')
31
- .update(parametersToString(body), 'utf8')
32
- .verify(publicCert, body.signature, 'base64');
33
- }
34
- export function generateRsaSignature(body, key) {
35
- return crypto
36
- .createSign('RSA-SHA256')
37
- .update(parametersToString(body), 'utf8')
38
- .sign(key, 'base64');
39
- }
40
- export function generateHmacSignature(body, key) {
41
- return crypto
42
- .createHmac('sha256', key)
43
- .update(parametersToString(body), 'utf8')
44
- .digest('hex');
45
- }
46
- export function getRandomString(length) {
47
- return crypto
48
- .randomBytes(Math.ceil(length / 2))
49
- .toString('hex')
50
- .slice(0, length);
51
- }