• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

paypay / paypayopa-sdk-node / 3889352965

pending completion
3889352965

push

github

GitHub
Merge pull request #654 from paypay/dependabot/npm_and_yarn/json5-2.2.3

41 of 45 branches covered (91.11%)

Branch coverage included in aggregate %.

177 of 188 relevant lines covered (94.15%)

20.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.2
/src/lib/paypay-rest-sdk.ts
1
/*
2
 * Main file, methods that are exposed to end-user
3
 */
4
import { Auth } from "./auth";
25✔
5
import { Conf } from "./conf";
25✔
6
import { HttpsClient, HttpsClientError, HttpsClientMessage, HttpsClientSuccess } from "./httpsClient";
25✔
7
import { HmacSHA256, enc, algo } from "crypto-js";
25✔
8
import { v4 as uuidv4 } from "uuid";
25✔
9
import * as jwt from "jsonwebtoken";
25✔
10

11
interface Endpoint {
12
  method: string,
13
  path: string,
14
  apiKey: string | undefined,
15
}
16

17
class PayPayRestSDK {
18
  private readonly auth: Auth;
19
  private config: Conf;
20
  private httpsClient: HttpsClient = new HttpsClient();
33✔
21

22
  constructor() {
23
    this.config = Conf.forEnvironment('STAGING');
33✔
24
    this.auth = new Auth();
33✔
25
  }
26

27
  /**
28
   * Replace the HttpsClient that this SDK client instance uses for API calls.
29
   */
30
  setHttpsClient(httpsClient: HttpsClient) {
31
    this.httpsClient = httpsClient;
30✔
32
  }
33

34
  /**
35
   * Set authentication passed by end-user
36
   * @param clientConfig
37
   */
38
  public configure = (clientConfig: {
33✔
39
    clientId: string;
40
    clientSecret: string;
41
    merchantId?: string;
42
    /**
43
     * @deprecated since version 2.1. Use {@code env} or {@code conf} instead.
44
     */
45
    productionMode?: boolean;
46
    /**
47
     * @deprecated since version 2.1. Use {@code env} or {@code conf} instead.
48
     */
49
    perfMode?: boolean;
50
    /**
51
     * Use one of the standard environments. {@code "STAGING"} can be used for testing, and is the default.
52
     */
53
    env?: 'PROD' | 'STAGING' | 'PERF_MODE';
54
    /**
55
     * Specify a custom host name and port. For common environments, use {@code env}.
56
     */
57
    conf?: Conf;
58
  }) => {
59
    this.auth.setAuth(clientConfig.clientId, clientConfig.clientSecret, clientConfig.merchantId);
32✔
60
    if (clientConfig.conf !== undefined) {
32!
61
      this.config = clientConfig.conf;
×
62
    } else if (clientConfig.env !== undefined) {
32✔
63
      this.config = Conf.forEnvironment(clientConfig.env);
3✔
64
    } else if (clientConfig.perfMode) {
29✔
65
      this.config = Conf.forEnvironment('PERF_MODE');
1✔
66
    } else if (clientConfig.productionMode) {
28✔
67
      this.config = Conf.forEnvironment('PROD');
2✔
68
    } else {
69
      this.config = Conf.forEnvironment('STAGING');
26✔
70
    }
71
  }
72

73
  private createAuthHeader = (method: string, resourceUrl: string, body: unknown) => {
33✔
74
    const epoch = Math.floor(Date.now() / 1000);
34✔
75
    const nonce = uuidv4();
34✔
76

77
    const jsonified = JSON.stringify(body);
34✔
78
    const isempty = [undefined, null, "", "undefined", "null"];
34✔
79

80
    let contentType;
81
    let payloadDigest;
82
    if (isempty.includes(jsonified)) {
34✔
83
      contentType = "empty";
11✔
84
      payloadDigest = "empty";
11✔
85
    } else {
86
      contentType = "application/json";
23✔
87
      payloadDigest = algo.MD5.create()
23✔
88
        .update(contentType)
89
        .update(jsonified)
90
        .finalize()
91
        .toString(enc.Base64);
92
    }
93
    const signatureRawList = [resourceUrl, method, nonce, epoch, contentType, payloadDigest];
34✔
94
    const signatureRawData = signatureRawList.join("\n");
34✔
95
    const hashed = HmacSHA256(signatureRawData, this.auth.clientSecret);
34✔
96
    const hashed64 = enc.Base64.stringify(hashed);
34✔
97
    const headList = [this.auth.clientId, hashed64, nonce, epoch, payloadDigest];
34✔
98
    const header = headList.join(":");
34✔
99
    return `hmac OPA-Auth:${header}`;
34✔
100
  }
101

102
  private fillPathTemplate(template: string, input: any[]) {
103
    const queryParams = template.match(/{\w+}/g);
11✔
104
    if (queryParams) {
11✔
105
      queryParams.forEach((q, n) => {
11✔
106
        template = template.replace(q, input[n]);
12✔
107
      });
108
    }
109
    return template;
11✔
110
  }
111

112
  private paypaySetupOptions = (endpoint: Endpoint, input: any) => {
33✔
113
    const method = endpoint.method;
34✔
114
    const path = (method === "GET" || method === "DELETE")
34✔
115
      ? this.fillPathTemplate(endpoint.path, input)
34✔
116
      : endpoint.path;
117

118
    const headers: Record<string, string | number> = {};
34✔
119

120
    const isempty = ["undefined", "null"];
34✔
121
    if (this.auth.merchantId && !isempty.includes(this.auth.merchantId)) {
34✔
122
      headers["X-ASSUME-MERCHANT"] = this.auth.merchantId;
27✔
123
    }
124

125
    if (method === "POST") {
34✔
126
      input.requestedAt = Math.round(new Date().getTime() / 1000);
23✔
127
      headers["Content-Type"] = "application/json";
23✔
128
      headers["Content-Length"] = Buffer.byteLength(JSON.stringify(input));
23✔
129
    }
130

131
    const cleanPath = path.split("?")[0];
34✔
132
    const authHeader = this.createAuthHeader(method,
34✔
133
      cleanPath,
134
      method === "GET" || method === "DELETE" ? null : input);
95✔
135
    headers["Authorization"] = authHeader;
34✔
136

137
    return {
34✔
138
      apiKey: endpoint.apiKey,
139
      hostname: this.config.getHostname(),
140
      port: this.config.getPortNumber(),
141
      headers,
142
      path,
143
      method,
144
    };
145
  }
146

147
  private getEndpoint = (nameApi: string, nameMethod: string, pathSuffix = ""): Endpoint => {
33✔
148
    return {
34✔
149
      method: this.config.getHttpsMethod(nameApi, nameMethod),
150
      path: this.config.getHttpsPath(nameApi, nameMethod) + pathSuffix,
151
      apiKey: this.config.getApiKey(nameApi, nameMethod),
152
    };
153
  }
154

155
  private invokeMethod = (
33✔
156
    endpoint: Endpoint,
157
    payload: unknown,
158
    callback?: HttpsClientMessage): Promise<HttpsClientSuccess | HttpsClientError> => {
159
    const options = this.paypaySetupOptions(endpoint, payload);
34✔
160
    return new Promise((resolve) => {
34✔
161
      this.httpsClient.httpsCall(options, payload, (result) => {
34✔
162
        resolve(result);
28✔
163
        if (callback !== undefined) {
28✔
164
          callback(result);
28✔
165
        }
166
      });
167
    });
168
  }
169

170
  /**
171
   * Create a dynamic QR Code to receive payments
172
   * @callback                Callback function to handle result
173
   * @returns {Promise}       Promise resolving to object containing STATUS and BODY
174
   * @param {Object} payload  JSON object payload
175
   * @param {boolean} [agreeSimilarTransaction] (Optional) If set to "true", the payment duplication check will be bypassed.
176
   * @param {Callback} [callback] (Optional) The callback to invoke when a response is received.
177
   */
178
  public createPayment = (
33✔
179
    payload: any,
180
    ...args: [callback?: HttpsClientMessage] | [agreeSimilarTransaction: boolean, callback?: HttpsClientMessage]
181
  ) => {
182
    const agreeSimilarTransaction = args[0] === true;
9✔
183
    const callback = typeof args[0] === "boolean" ? args[1] : args[0];
9✔
184
    const endpoint = this.getEndpoint("API_PAYMENT", "CREATE_PAYMENT", `?agreeSimilarTransaction=${agreeSimilarTransaction}`);
9✔
185
    return this.invokeMethod(endpoint, payload, callback);
9✔
186
  }
187

188
  /**
189
   * Create a dynamic QR Code to receive payments
190
   * @callback                Callback function to handle result
191
   * @returns {Promise}       Promise resolving to object containing STATUS and BODY
192
   * @param {Object} payload  JSON object payload
193
   */
194
  public qrCodeCreate = (payload: any, callback?: HttpsClientMessage) => {
33✔
195
    return this.invokeMethod(this.getEndpoint("API_PAYMENT", "QRCODE_CREATE"), payload, callback);
2✔
196
  }
197

198
  /**
199
   * Delete a created dynamic QR Code
200
   * @callback                    Callback function to handle result
201
   * @returns {Object}            Returns result containing STATUS and BODY
202
   * @param {string} inputParams  Array of codeId : QR Code that is to be deleted
203
   */
204
  public qrCodeDelete = (inputParams: Array<string | number>, callback?: HttpsClientMessage) => {
33✔
205
    return this.invokeMethod(this.getEndpoint("API_PAYMENT", "QRCODE_DELETE"), inputParams, callback);
1✔
206
  }
207

208
  /**
209
   * Get payment details for web cashier and Dynamic QR
210
   *
211
   * @callback                    Callback function to handle result
212
   * @returns {Promise}           Promise resolving to object containing STATUS and BODY
213
   * @param {string} inputParams  Array of merchantPaymentId : The unique payment transaction id provided by merchant
214
   */
215
  public getCodePaymentDetails = (inputParams: Array<string | number>, callback?: HttpsClientMessage) => {
33✔
216
    return this.invokeMethod(this.getEndpoint("API_PAYMENT", "GET_CODE_PAYMENT_DETAILS"), inputParams, callback);
1✔
217
  }
218

219
  /**
220
   * Get payment details
221
   *
222
   * @callback                    Callback function to handle result
223
   * @returns {Promise}           Promise resolving to object containing STATUS and BODY
224
   * @param {string} inputParams  Array of merchantPaymentId : The unique payment transaction id provided by merchant
225
   */
226
  public getPaymentDetails = (inputParams: Array<string | number>, callback?: HttpsClientMessage) => {
33✔
227
    return this.invokeMethod(this.getEndpoint("API_PAYMENT", "GET_PAYMENT_DETAILS"), inputParams, callback);
1✔
228
  }
229

230
  /**
231
   * Cancel a payment
232
   * This api is used in case, while creating a payment, the client can not determine the status of the payment
233
   *
234
   * @callback                    Callback function to handle result
235
   * @returns {Promise}           Promise resolving to object containing STATUS and BODY
236
   * @param {string} inputParams  Array of merchantPaymentId : The unique payment transaction id provided by merchant
237
   */
238
  public paymentCancel = (inputParams: Array<string | number>, callback?: HttpsClientMessage) => {
33✔
239
    return this.invokeMethod(this.getEndpoint("API_PAYMENT", "CANCEL_PAYMENT"), inputParams, callback);
1✔
240
  }
241

242
  /**
243
   * Capture a payment authorization
244
   * This api is used to capture the payment authorization for a payment
245
   *
246
   * @callback                Callback function to handle result
247
   * @returns {Promise}       Promise resolving to object containing STATUS and BODY
248
   * @param {Object} payload  JSON object payload
249
   */
250
  public paymentAuthCapture = (payload: any, callback?: HttpsClientMessage) => {
33✔
251
    return this.invokeMethod(this.getEndpoint("API_PAYMENT", "PAYMENT_AUTH_CAPTURE"), payload, callback);
1✔
252
  }
253

254
  /**
255
   * Revert a payment authorization
256
   * The following api is used when a payment needs to be cancelled. For example, when the user cancels the order
257
   *
258
   * @callback                Callback function to handle result
259
   * @returns {Promise}       Promise resolving to object containing STATUS and BODY
260
   * @param {Object} payload  JSON object payload
261
   */
262
  public paymentAuthRevert = (payload: any, callback?: HttpsClientMessage) => {
33✔
263
    return this.invokeMethod(this.getEndpoint("API_PAYMENT", "PAYMENT_AUTH_REVERT"), payload, callback);
1✔
264
  }
265

266
  /**
267
   * Refund a payment
268
   *
269
   * @callback                Callback function to handle result
270
   * @returns {Promise}       Promise resolving to object containing STATUS and BODY
271
   * @param {Object} payload  JSON object payload
272
   */
273
  public paymentRefund = (payload: any, callback?: HttpsClientMessage) => {
33✔
274
    return this.invokeMethod(this.getEndpoint("API_PAYMENT", "REFUND_PAYMENT"), payload, callback);
1✔
275
  }
276

277
  /**
278
   * Get refund details
279
   *
280
   * @callback                    Callback function to handle result
281
   * @returns {Promise}           Promise resolving to object containing STATUS and BODY
282
   * @param {string} inputParams  Array of merchantPaymentId : The unique payment transaction id provided by merchant
283
   */
284
  public getRefundDetails = (inputParams: Array<string | number>, callback?: HttpsClientMessage) => {
33✔
285
    return this.invokeMethod(this.getEndpoint("API_PAYMENT", "GET_REFUND_DETAILS"), inputParams, callback);
1✔
286
  }
287

288
  /**
289
   * Check user wallet balance
290
   * Check if user has enough balance to make a payment
291
   *
292
   * @callback                   Callback function to handle result
293
   * @returns {Promise}          Promise resolving to object containing STATUS and BODY
294
   * @param {Array} inputParams  Array of userAuthorizationId, amount, currency, productType
295
   */
296
  public checkUserWalletBalance = (inputParams: Array<string | number>, callback?: HttpsClientMessage) => {
33✔
297
    return this.invokeMethod(this.getEndpoint("API_WALLET", "CHECK_BALANCE"), inputParams, callback);
×
298
  }
299

300
  /**
301
   * Direct user to the authorization web page
302
   *
303
   * @callback                   Callback function to handle result
304
   * @returns {Object}           Returns result containing STATUS and BODY
305
   * @param {Array} inputParams  Array of apiKey, jwtToken
306
   */
307
  public authorization = (inputParams: Array<string | number>, callback?: HttpsClientMessage) => {
33✔
308
    return this.invokeMethod(this.getEndpoint("API_DIRECT_DEBIT", "AUTHORIZATION"), inputParams, callback);
×
309
  }
310

311
  /**
312
   * Receive the user authorization result
313
   *
314
   * @callback                   Callback function to handle result
315
   * @returns {Promise}          Promise resolving to object containing STATUS and BODY
316
   * @param {Array} inputParams  Array of apiKey, jwtToken
317
   */
318
  public authorizationResult = (inputParams: Array<string | number>, callback?: HttpsClientMessage) => {
33✔
319
    return this.invokeMethod(this.getEndpoint("API_DIRECT_DEBIT", "AUTHORIZATION_RESULT"), inputParams, callback);
×
320
  }
321

322
  /**
323
   * Create an account link QR Code to authorise OPA client
324
   * @callback                Callback function to handle result
325
   * @returns {Promise}       Promise resolving to object containing STATUS and BODY
326
   * @param {Object} payload  JSON object payload
327
   */
328
  public accountLinkQRCodeCreate = (payload: any, callback?: HttpsClientMessage) => {
33✔
329
    return this.invokeMethod(this.getEndpoint("API_ACCOUNT_LINK", "QRCODE_CREATE"), payload, callback);
1✔
330
  }
331

332
  /**
333
   * Verify the validity of a JWT token
334
   * @returns {Object}               Returns the decoded token
335
   * @param {Object} token           The token to be verified
336
   * @param {Object} clientSecret    The client secret to be used for verification
337
   */
338
  public validateJWT = (token: string, clientSecret: string): string | object => {
33✔
339
    return jwt.verify(token, Buffer.from(clientSecret, "base64"));
×
340
  }
341

342
  public paymentPreauthorize = (
33✔
343
    payload: any,
344
    ...args: [callback?: HttpsClientMessage] | [agreeSimilarTransaction: boolean, callback?: HttpsClientMessage]
345
  ) => {
346
    const agreeSimilarTransaction = args[0] === true;
3✔
347
    const callback = typeof args[0] === "boolean" ? args[1] : args[0];
3✔
348
    const endpoint = this.getEndpoint("API_PAYMENT", "PREAUTHORIZE", `?agreeSimilarTransaction=${agreeSimilarTransaction}`);
3✔
349
    return this.invokeMethod(endpoint, payload, callback);
3✔
350
  }
351

352
  public paymentSubscription = (payload: any, callback?: HttpsClientMessage) => {
33✔
353
    return this.invokeMethod(this.getEndpoint("API_SUBSCRIPTION", "PAYMENTS"), payload, callback);
1✔
354
  }
355

356
  /**
357
   * Create pending payment
358
   *
359
   * @callback                Callback function to handle result
360
   * @returns {Promise}       Promise resolving to object containing STATUS and BODY
361
   * @param {Object} payload  JSON object payload
362
   */
363
  public createPendingPayment = (payload: any, callback?: HttpsClientMessage) => {
33✔
364
    return this.invokeMethod(this.getEndpoint("API_REQUEST_ORDER", "PENDING_PAYMENT_CREATE"), payload, callback);
1✔
365
  }
366

367
  /**
368
   * Get pending order details
369
   *
370
   * @callback                    Callback function to handle result
371
   * @returns {Promise}           Promise resolving to object containing STATUS and BODY
372
   * @param {string} inputParams  Array of merchantPaymentId : The unique payment transaction id provided by merchant
373
   */
374
  public getPendingPaymentDetails = (inputParams: Array<string | number>, callback?: HttpsClientMessage) => {
33✔
375
    return this.invokeMethod(this.getEndpoint("API_REQUEST_ORDER", "GET_ORDER_DETAILS"), inputParams, callback);
1✔
376
  }
377

378
  /**
379
   * Cancel pending order
380
   *
381
   * @callback                    Callback function to handle result
382
   * @returns {Promise}           Promise resolving to object containing STATUS and BODY
383
   * @param {string} inputParams  Array of merchantPaymentId : The unique payment transaction id provided by merchant
384
   */
385
  public cancelPendingOrder = (inputParams: Array<string | number>, callback?: HttpsClientMessage) => {
33✔
386
    return this.invokeMethod(this.getEndpoint("API_REQUEST_ORDER", "PENDING_ORDER_CANCEL"), inputParams, callback);
1✔
387
  }
388

389
  /**
390
   * Refund pending payment
391
   *
392
   * @callback                Callback function to handle result
393
   * @returns {Promise}       Promise resolving to object containing STATUS and BODY
394
   * @param {Object} payload  JSON object payload
395
   */
396
  public refundPendingPayment = (payload: any, callback?: HttpsClientMessage) => {
33✔
397
    return this.invokeMethod(this.getEndpoint("API_PAYMENT", "REFUND_PAYMENT"), payload, callback);
1✔
398
  }
399

400
  /**
401
   * Get user authorization status
402
   *
403
   * @callback                    Callback function to handle result
404
   * @returns {Promise}           Promise resolving to object containing STATUS and BODY
405
   * @param {string} inputParams  Array of UserAuthorizationId : The unique UserAuthorizationId id 
406
   */
407
  public getUserAuthorizationStatus = (inputParams: Array<string | number>, callback?: HttpsClientMessage) => {
33✔
408
    return this.invokeMethod(this.getEndpoint("USER_AUTHORIZATION", "GET_USER_AUTHORIZATION_STATUS"), inputParams, callback);
1✔
409
  }
410

411
  /**
412
   * Unlink user
413
   *
414
   * @callback                    Callback function to handle result
415
   * @returns {Promise}           Promise resolving to object containing STATUS and BODY
416
   * @param {string} inputParams  Array of UserAuthorizationId : The unique UserAuthorizationId id 
417
   */
418
  public unlinkUser = (inputParams: Array<string | number>, callback?: HttpsClientMessage) => {
33✔
419
    return this.invokeMethod(this.getEndpoint("USER_AUTHORIZATION", "UNLINK_USER"), inputParams, callback);
1✔
420
  }
421

422
  /**
423
    * Cash back
424
    * 
425
    * @callback                    Callback function to handle result
426
    * @returns {Object}            Returns result containing STATUS and BODY
427
    * @param {string} inputParams  Array of UserAuthorizationId : The unique UserAuthorizationId id 
428
    * @param inputParams 
429
    * @param callback 
430
    */
431
  public cashBack = (payload: any, callback?: HttpsClientMessage) => {
33✔
432
    return this.invokeMethod(this.getEndpoint("API_PAYMENT", "GIVE_CASH_BACK"), payload, callback);
1✔
433
  }
434

435
  /**
436
   * Get Cash back details
437
   * 
438
   * @callback                    Callback function to handle result
439
   * @returns {Promise}           Promise resolving to object containing STATUS and BODY
440
   * @param {string} inputParams  Array of UserAuthorizationId : The unique UserAuthorizationId id 
441
   * @param inputParams 
442
   * @param callback 
443
   */
444
  public getCashBackDetails = (inputParams: Array<string | number>, callback?: HttpsClientMessage) => {
33✔
445
    return this.invokeMethod(this.getEndpoint("API_PAYMENT", "CHECK_CASHBACK_DETAILS"), inputParams, callback);
1✔
446
  }
447

448
  /**
449
   * Reverse Cash back
450
   * 
451
   * @callback                    Callback function to handle result
452
   * @returns {Promise}           Promise resolving to object containing STATUS and BODY
453
   * @param {string} inputParams  Array of UserAuthorizationId : The unique UserAuthorizationId id 
454
   * @param inputParams 
455
   * @param callback 
456
   */
457
  public reverseCashBack = (payload: any, callback?: HttpsClientMessage) => {
33✔
458
    return this.invokeMethod(this.getEndpoint("API_PAYMENT", "REVERSAL_CASHBACK"), payload, callback);
1✔
459
  }
460

461
  /**
462
   * Get Reverse Cash back details
463
   * 
464
   * @callback                    Callback function to handle result
465
   * @returns {Promise}           Promise resolving to object containing STATUS and BODY
466
   * @param {string} inputParams  Array of UserAuthorizationId : The unique UserAuthorizationId id 
467
   * @param inputParams 
468
   * @param callback 
469
   */
470
  public getReverseCashBackDetails = (inputParams: Array<string | number>, callback?: HttpsClientMessage) => {
33✔
471
    return this.invokeMethod(this.getEndpoint("API_PAYMENT", "CHECK_CASHBACK_REVERSE_DETAILS"), inputParams, callback);
1✔
472
  }
473
}
474

475
/**
476
 * These are methods and variables that are exposed to end-user
477
 */
478
export let payPayRestSDK = new PayPayRestSDK();
25✔
479
export { PayPayRestSDK };
25✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc