gamemoney 6.0.0 → 7.0.1

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
@@ -4,17 +4,21 @@
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;
@@ -70,14 +77,14 @@ export type GetInvoiceStatusResponse = {
70
77
  currency_project: string;
71
78
  currency_user: string;
72
79
  date_create: string;
73
- date_pay: string;
74
- rate?: string;
80
+ date_pay?: string;
81
+ rate?: number;
75
82
  recurrent_token?: string;
76
83
  reason?: string;
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,7 +93,14 @@ export type GetInvoiceListResponse = {
86
93
  list: GetInvoiceStatusResponse[];
87
94
  is_limit_exceeded: 'yes' | 'no';
88
95
  };
89
- export type GetCardSessionStatusRequest = Record<string, any> & ({
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> & ({
90
104
  invoice: string;
91
105
  } | {
92
106
  project_invoice: string;
@@ -102,11 +116,11 @@ export type FinishCardSessionStatusResponse = {
102
116
  };
103
117
  export type GetCardSessionStatusResponse = WaitOrDeclineCardSessionStatusResponse | FinishCardSessionStatusResponse;
104
118
  export type CancelCheckoutRequest = {
105
- [key: string]: any;
119
+ [key: string]: unknown;
106
120
  projectId: string;
107
121
  };
108
122
  export type GetCheckoutStatusRequest = {
109
- [key: string]: any;
123
+ [key: string]: unknown;
110
124
  projectId: string;
111
125
  };
112
126
  export type Refund = {
@@ -132,11 +146,11 @@ export type GetCheckoutStatusResponse = {
132
146
  currency_project: string;
133
147
  currency_user: string;
134
148
  date_create: string;
135
- rate?: string;
149
+ rate?: number;
136
150
  txid?: string;
137
151
  };
138
152
  export type GetCheckoutListRequest = {
139
- [key: string]: any;
153
+ [key: string]: unknown;
140
154
  start: string;
141
155
  finish: string;
142
156
  };
@@ -145,7 +159,7 @@ export type GetCheckoutListResponse = {
145
159
  is_limit_exceeded: 'yes' | 'no';
146
160
  };
147
161
  export type CreateCheckoutRequest = {
148
- [key: string]: any;
162
+ [key: string]: unknown;
149
163
  projectId: string;
150
164
  user: string;
151
165
  ip: string;
@@ -157,30 +171,52 @@ export type CreateCheckoutRequest = {
157
171
  userCurrency?: string;
158
172
  prepareToken?: string;
159
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
+ };
160
194
  export type AddCardRequest = {
161
- [key: string]: any;
195
+ [key: string]: unknown;
162
196
  user: string;
163
197
  redirect: string;
198
+ language?: string;
199
+ theme?: 'dark' | 'light';
164
200
  };
165
201
  export type AddCardResponse = {
166
202
  url: string;
167
203
  };
168
204
  export type AddTokenCardRequest = {
169
- [key: string]: any;
205
+ [key: string]: unknown;
170
206
  user: string;
171
207
  };
172
208
  export type AddTokenCardResponse = {
173
209
  token: string;
174
210
  };
175
211
  export type GetCardListRequest = {
176
- [key: string]: any;
212
+ [key: string]: unknown;
177
213
  user: string;
178
214
  };
179
215
  export type GetCardListResponse = {
180
216
  pans: string[];
181
217
  };
182
218
  export type GetCardFullListRequest = {
183
- [key: string]: any;
219
+ [key: string]: unknown;
184
220
  user: string;
185
221
  };
186
222
  export type GetCardFullListResponse = {
@@ -189,16 +225,17 @@ export type GetCardFullListResponse = {
189
225
  expire_month: string;
190
226
  expire_year: string;
191
227
  cardholder: string;
228
+ country?: string;
192
229
  }>;
193
230
  };
194
231
  export type DeleteCardRequest = {
195
- [key: string]: any;
232
+ [key: string]: unknown;
196
233
  user: string;
197
234
  pan: string;
198
235
  };
199
236
  export type PrepareExchangeRequest = {
200
- [key: string]: any;
201
- externalId: string;
237
+ [key: string]: unknown;
238
+ externalId?: string;
202
239
  minAmount: number;
203
240
  maxAmount: number;
204
241
  from: string;
@@ -212,12 +249,12 @@ export type PrepareExchangeResponse = {
212
249
  exchanged_amount_to: number;
213
250
  };
214
251
  export type ConvertExchangeRequest = {
215
- [key: string]: any;
252
+ [key: string]: unknown;
216
253
  id: number;
217
254
  amount: number;
218
255
  };
219
256
  export type FastConvertExchangeRequest = {
220
- [key: string]: any;
257
+ [key: string]: unknown;
221
258
  amount: number;
222
259
  from: string;
223
260
  to: string;
@@ -227,7 +264,7 @@ export type FastConvertExchangeResponse = {
227
264
  rate: number;
228
265
  };
229
266
  export type GetExchangeRateRequest = {
230
- [key: string]: any;
267
+ [key: string]: unknown;
231
268
  from: string;
232
269
  to: string;
233
270
  };
@@ -236,7 +273,7 @@ export type GetExchangeRateResponse = {
236
273
  sell: number;
237
274
  };
238
275
  export type GetExchangeInfoRequest = {
239
- [key: string]: any;
276
+ [key: string]: unknown;
240
277
  minAmount: number;
241
278
  maxAmount: number;
242
279
  from: string;
@@ -250,7 +287,7 @@ export type GetExchangeInfoResponse = {
250
287
  exchanged_amount_to: number;
251
288
  };
252
289
  export type GetExchangeStatusRequest = {
253
- [key: string]: any;
290
+ [key: string]: unknown;
254
291
  id?: number;
255
292
  externalId?: string;
256
293
  };
@@ -264,7 +301,7 @@ export type GetExchangeStatusResponse = {
264
301
  status: string;
265
302
  };
266
303
  export type GetBalanceStatisticsRequest = {
267
- [key: string]: any;
304
+ [key: string]: unknown;
268
305
  currency: string;
269
306
  };
270
307
  export type GetBalanceStatisticsResponse = {
@@ -278,7 +315,7 @@ export type GetBalanceStatisticsResponse = {
278
315
  contract_balance: number;
279
316
  };
280
317
  export type GetDaysBalanceStatisticsRequest = {
281
- [key: string]: any;
318
+ [key: string]: unknown;
282
319
  currency: string;
283
320
  start: string;
284
321
  finish: string;
@@ -309,7 +346,7 @@ export type GetPayTypesStatisticsResponse = {
309
346
  checkout: PaySystem[];
310
347
  };
311
348
  export type CreateTerminalRequest = {
312
- [key: string]: any;
349
+ [key: string]: unknown;
313
350
  user: string;
314
351
  amount?: number;
315
352
  comment?: string;
@@ -319,8 +356,13 @@ export type CreateTerminalRequest = {
319
356
  currency?: string;
320
357
  use_user_select_currency?: 'yes' | 'no';
321
358
  language?: string;
359
+ return_mode?: 'skip';
360
+ recurring?: 'yes';
322
361
  terminal_allow_methods?: string[];
323
362
  terminal_disable_methods?: string[];
363
+ terminal_livetime?: number;
364
+ terminal_country?: string;
365
+ terminal_theme?: 'dark' | 'light';
324
366
  };
325
367
  export type CreateTerminalResponse = {
326
368
  url: string;
@@ -375,6 +417,7 @@ export type TransferNotification = {
375
417
  currency: string;
376
418
  user: string;
377
419
  type: string;
420
+ project: number;
378
421
  ip: string;
379
422
  time: number;
380
423
  comment: string;
@@ -384,23 +427,32 @@ type Payload = Record<string, unknown>;
384
427
  export declare class GameMoneyError extends Error {
385
428
  constructor(message: string);
386
429
  }
387
- 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 {
388
435
  private readonly config;
389
- private readonly got;
390
436
  constructor(config: Config);
391
437
  request<T extends GenericResponse>(url: string, payload?: Payload, signType?: SignType): Promise<T>;
392
- generateHmacSignature(body: any): string;
393
- verifyRsaSignature(body: any): boolean;
438
+ generateHmacSignature(body: Record<string, unknown>): string;
439
+ verifyRsaSignature(body: unknown): boolean;
394
440
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_insert_api) */
395
441
  createInvoice(body: CreateInvoiceRequest): Promise<CreateInvoiceResponse & GenericResponse>;
396
442
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_status) */
397
443
  getInvoiceStatus(body: GetInvoiceStatusRequest): Promise<GetInvoiceStatusResponse & GenericResponse>;
398
444
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_list) */
399
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>;
400
448
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_session_status) */
401
449
  getCardSessionStatus(body: GetCardSessionStatusRequest): Promise<GetCardSessionStatusResponse & GenericResponse>;
402
450
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_insert) */
403
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>;
404
456
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_cancel) */
405
457
  cancelCheckout(body: CancelCheckoutRequest): Promise<GenericResponse>;
406
458
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_status) */
@@ -415,7 +467,7 @@ export default class GameMoney {
415
467
  getCardList(body: GetCardListRequest): Promise<GetCardListResponse & GenericResponse>;
416
468
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_fulllist) */
417
469
  getCardFullList(body: GetCardFullListRequest): Promise<GetCardFullListResponse & GenericResponse>;
418
- /** 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) */
419
471
  deleteCard(body: DeleteCardRequest): Promise<GenericResponse>;
420
472
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#exchange_prepare) */
421
473
  prepareExchange(body: PrepareExchangeRequest): Promise<PrepareExchangeResponse & GenericResponse>;
@@ -438,4 +490,4 @@ export default class GameMoney {
438
490
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_api_terminal) */
439
491
  createTerminal(body: CreateTerminalRequest): Promise<CreateTerminalResponse & GenericResponse>;
440
492
  }
441
- 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,6 +82,10 @@ 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
+ }
73
89
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_session_status) */
74
90
  async getCardSessionStatus(body) {
75
91
  return this.request('invoice/cardsession/status', body);
@@ -78,6 +94,14 @@ export default class GameMoney {
78
94
  async createCheckout(body) {
79
95
  return this.request('checkout/insert', body, SignType.RSA);
80
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
+ }
81
105
  /** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_cancel) */
82
106
  async cancelCheckout(body) {
83
107
  return this.request('checkout/cancel', body);
@@ -106,7 +130,7 @@ export default class GameMoney {
106
130
  async getCardFullList(body) {
107
131
  return this.request('card/fulllist', body);
108
132
  }
109
- /** 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) */
110
134
  async deleteCard(body) {
111
135
  return this.request('card/delete', body);
112
136
  }
@@ -151,3 +175,4 @@ export default class GameMoney {
151
175
  return this.request('terminal/create', body);
152
176
  }
153
177
  }
178
+ export default GameMoney;
@@ -1,16 +1,17 @@
1
- /// <reference types="node" resolution-mode="require"/>
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,6 +1,6 @@
1
1
  {
2
2
  "name": "gamemoney",
3
- "version": "6.0.0",
3
+ "version": "7.0.1",
4
4
  "description": "GameMoney API wrapper for Node.js",
5
5
  "keywords": [
6
6
  "gamemoney",
@@ -11,75 +11,66 @@
11
11
  "homepage": "https://github.com/gamemoney-ps/gamemoney-node-sdk#readme",
12
12
  "bugs": {
13
13
  "url": "https://github.com/gamemoney-ps/gamemoney-node-sdk/issues",
14
- "email": "maxpain177@gmail.com"
14
+ "email": "maxpain@linux.com"
15
15
  },
16
16
  "author": {
17
- "name": "Maxim Makarov",
18
- "email": "maxpain177@gmail.com",
19
- "url": "https://maxpain.pro"
17
+ "name": "Max Makarov",
18
+ "email": "maxpain@linux.com"
20
19
  },
21
20
  "license": "MIT",
22
21
  "repository": {
23
22
  "type": "git",
24
- "url": "https://github.com/gamemoney-ps/gamemoney-node-sdk"
23
+ "url": "git+https://github.com/gamemoney-ps/gamemoney-node-sdk.git"
25
24
  },
26
25
  "type": "module",
27
26
  "exports": {
28
27
  ".": {
29
- "import": "./index.js",
30
- "types": "./index.d.ts"
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"
31
47
  }
32
48
  },
33
49
  "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"
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"
40
58
  },
41
59
  "lint-staged": {
42
- "*.ts": "xo"
60
+ "*.ts": "oxlint",
61
+ "*": "oxfmt --check --no-error-on-unmatched-pattern"
43
62
  },
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
63
  "devDependencies": {
65
- "@onmoon/eslint-config": "^1.0.12",
66
- "@onmoon/prettier-config": "^1.0.2",
67
- "@onmoon/tsconfigs": "^3.0.0",
68
- "@types/body-parser": "^1.19.2",
69
- "@types/express": "^4.17.17",
70
- "@types/jest": "^29.5.2",
71
- "@types/node": "^20.4.0",
72
- "@types/uuid": "^9.0.2",
73
- "body-parser": "^1.20.2",
74
- "express": "^4.18.2",
75
- "husky": "^8.0.3",
76
- "lint-staged": "^13.2.3",
77
- "ts-jest": "^29.1.1",
78
- "typescript": "^5.1.6",
79
- "uuid": "^9.0.0",
80
- "xo": "^0.54.2"
81
- },
82
- "dependencies": {
83
- "got": "^12.6.1"
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"
84
75
  }
85
- }
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
- }