diff --git a/CHANGES.md b/CHANGES.md index 0d6e7c6..3293286 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,10 @@ +### Version 2.3.0 - March 2023 +* Introducing new v2 Reporting APIs. Reports allow you to retieve consolidated data about Amazon Pay transactions and settlements. In addition to managing and downloading reports using Seller Central, Amazon Pay offers APIs to manage and retrieve your reports. +* Introducing new signature generation algorithm AMZN-PAY-RSASSA-PSS-V2 and increasing salt length from 20 to 32. +* Added support for handling new parameter 'shippingAddressList' in Checkout Session response. Change is fully backwards compatible. +* Added Error code 408 to API retry logic +* Note : To use new algorithm AMZN-PAY-RSASSA-PSS-V2, "algorithm" needs to be provided as an additional field in "config" and also while rendering Amazon Pay button in "createCheckoutSessionConfig". The changes are backwards-compatible, SDK will use AMZN-PAY-RSASSA-PSS by default. + #### Version 2.2.2 - June 2022 * Fixed security vulnerabilities in dependencies. diff --git a/README.md b/README.md index 08688eb..17a13d3 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,8 @@ To associate the key with your account, follow the instructions here to 'publicKeyId': 'ABC123DEF456XYZ', // RSA Public Key ID (this is not the Merchant or Seller ID) 'privateKey': fs.readFileSync('tst/private.pem'), // Path to RSA Private Key (or a string representation) 'region': 'us', // Must be one of: 'us', 'eu', 'jp' - 'sandbox': true // true (Sandbox) or false (Production) boolean + 'sandbox': true, // true (Sandbox) or false (Production) boolean + 'algorithm': 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified }; ``` @@ -61,6 +62,7 @@ If you have created environment specific keys (i.e Public Key Starts with LIVE o 'publicKeyId': 'PUBLIC_KEY_ID', // LIVE-XXXXX or SANDBOX-XXXXX 'privateKey': fs.readFileSync('tst/private.pem'), // Path to RSA Private Key (or a string representation) 'region': 'us', // Must be one of: 'us', 'eu', 'jp' + 'algorithm': 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified }; ``` @@ -196,7 +198,8 @@ If you are a Solution Provider and need to make an API call on behalf of a diffe publicKeyId: 'ABC123DEF456XYZ', privateKey: fs.readFileSync('tst/private.pem'), region: 'us', - sandbox: true + sandbox: true, + algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified }; const payload = { @@ -224,7 +227,8 @@ If you are a Solution Provider and need to make an API call on behalf of a diffe publicKeyId: 'ABC123DEF456XYZ', privateKey: fs.readFileSync('tst/private.pem'), region: 'us', - sandbox: true + sandbox: true, + algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified }; const payload = { @@ -255,7 +259,8 @@ If you are a Solution Provider and need to make an API call on behalf of a diffe publicKeyId: 'ABC123DEF456XYZ', privateKey: fs.readFileSync('tst/private.pem'), region: 'us', - sandbox: true + sandbox: true, + algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified }; const headers = { @@ -280,7 +285,8 @@ If you are a Solution Provider and need to make an API call on behalf of a diffe publicKeyId: 'ABC123DEF456XYZ', privateKey: fs.readFileSync('tst/private.pem'), region: 'us', - sandbox: true + sandbox: true, + algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified }; const payload = { @@ -321,7 +327,8 @@ If you are a Solution Provider and need to make an API call on behalf of a diffe publicKeyId: 'ABC123DEF456XYZ', privateKey: fs.readFileSync('tst/private.pem'), region: 'us', - sandbox: true + sandbox: true, + algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified }; const payload = { @@ -371,7 +378,8 @@ Example call to generateButtonSignature function: publicKeyId: 'ABC123DEF456XYZ', privateKey: fs.readFileSync('tst/private.pem'), region: 'us', - sandbox: true + sandbox: true, + algorithm: 'AMZN-PAY-RSASSA-PSS-V2' // Amazon Signing Algorithm, Optional: uses AMZN-PAY-RSASSA-PSS if not specified }; const testPayClient = new Client.AmazonPayClient(config); @@ -453,7 +461,7 @@ Example request method: const options = { method: 'POST', urlFragment: '${version}/in-store/merchantScan', - payload = { + payload: { scanData: 'UKhrmatMeKdlfY6b', scanReferenceId: '0b8fb271-2ae2-49a5-b35d4', merchantCOE: 'US', @@ -484,3 +492,208 @@ Example request method: const client = new Client.AmazonPayClient(config); const signedHeaders = client.getSignedHeaders(options); ``` + +# Reporting APIs code samples + +## Amazon Checkout v2 Reporting APIs - GetReport API +```js + const fs = require('fs'); + const uuidv4 = require('uuid/v4'); + const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); + + const config = { + publicKeyId: 'YOUR_PUBLIC_KEY_ID', + privateKey: fs.readFileSync('tst/private.pem'), + region: 'us', + sandbox: false, + }; + + const testPayClient = new Client.WebStoreClient(config); + const requestPayload = { + reportTypes: "_GET_FLAT_FILE_OFFAMAZONPAYMENTS_SETTLEMENT_DATA_", + }; + const response = testPayClient.getReports(requestPayload); + + response.then(function (result) { + console.log(result.data); + }).catch(err => { + console.log(err); + }); +``` + +## Amazon Checkout v2 Reporting APIs - GetReportById API +```js + const fs = require('fs'); + const uuidv4 = require('uuid/v4'); + const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); + + const config = { + publicKeyId: 'YOUR_PUBLIC_KEY_ID', + privateKey: fs.readFileSync('tst/private.pem'), + region: 'us', + sandbox: false, + }; + + const reportId = '1234567890'; + const testPayClient = new Client.WebStoreClient(config); + const response = testPayClient.getReportById(reportId); + + response.then(function (result) { + console.log(result.data); + }).catch(err => { + console.log(err); + }); +``` + +## Amazon Checkout v2 Reporting APIs - GetReportDocument API +```js + const fs = require('fs'); + const uuidv4 = require('uuid/v4'); + const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); + + const config = { + publicKeyId: 'YOUR_PUBLIC_KEY_ID', + privateKey: fs.readFileSync('tst/private.pem'), + region: 'us', + sandbox: false, + }; + + const reportDocumentId = '1234567890'; + const testPayClient = new Client.WebStoreClient(config); + const response = testPayClient.getReportDocument(reportDocumentId); + + response.then(function (result) { + console.log(result.data); + }).catch(err => { + console.log(err); + }); +``` + +## Amazon Checkout v2 Reporting APIs - GetReportSchedules API +```js + const fs = require('fs'); + const uuidv4 = require('uuid/v4'); + const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); + + const config = { + publicKeyId: 'YOUR_PUBLIC_KEY_ID', + privateKey: fs.readFileSync('tst/private.pem'), + region: 'us', + sandbox: false, + }; + + const reportTypes = '_GET_FLAT_FILE_OFFAMAZONPAYMENTS_ORDER_REFERENCE_DATA_,_GET_FLAT_FILE_OFFAMAZONPAYMENTS_BILLING_AGREEMENT_DATA_'; + const testPayClient = new Client.WebStoreClient(config); + const response = testPayClient.getReportSchedules(reportTypes); + + response.then(function (result) { + console.log(result.data); + }).catch(err => { + console.log(err); + }); +``` + +## Amazon Checkout v2 Reporting APIs - GetReportScheduleById API +```js + const fs = require('fs'); + const uuidv4 = require('uuid/v4'); + const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); + + const config = { + publicKeyId: 'YOUR_PUBLIC_KEY_ID', + privateKey: fs.readFileSync('tst/private.pem'), + region: 'us', + sandbox: false, + }; + + const reportScheduleId = '1234567890'; + const testPayClient = new Client.WebStoreClient(config); + const response = testPayClient.getReportScheduleById(reportScheduleId); + + response.then(function (result) { + console.log(result.data); + }).catch(err => { + console.log(err); + }); +``` + +## Amazon Checkout v2 Reporting APIs - CreateReport API +```js + const fs = require('fs'); + const uuidv4 = require('uuid/v4'); + const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); + + const config = { + publicKeyId: 'YOUR_PUBLIC_KEY_ID', + privateKey: fs.readFileSync('tst/private.pem'), + region: 'us', + sandbox: false, + }; + + const requestPayload = { + reportType: '_GET_FLAT_FILE_OFFAMAZONPAYMENTS_AUTHORIZATION_DATA_', + startTime: '20221114T074550Z', + endTime: '20221114T074550Z' + } + const testPayClient = new Client.WebStoreClient(config); + const response = testPayClient.createReport(requestPayload); + + response.then(function (result) { + console.log(result.data); + }).catch(err => { + console.log(err); + }); +``` + +## Amazon Checkout v2 Reporting APIs - CreateReportSchedule API +```js + const fs = require('fs'); + const uuidv4 = require('uuid/v4'); + const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); + + const config = { + publicKeyId: 'YOUR_PUBLIC_KEY_ID', + privateKey: fs.readFileSync('tst/private.pem'), + region: 'us', + sandbox: false, + }; + + const requestPayload = { + reportType: "_GET_FLAT_FILE_OFFAMAZONPAYMENTS_ORDER_REFERENCE_DATA_", + scheduleFrequency: "P1D", + nextReportCreationTime: "20230317T074550Z", + deleteExistingSchedule: false + } + const testPayClient = new Client.WebStoreClient(config); + const response = testPayClient.createReportSchedule(requestPayload); + + response.then(function (result) { + console.log(result.data); + }).catch(err => { + console.log(err); + }); +``` + +## Amazon Checkout v2 Reporting APIs - CancelReportSchedule API +```js + const fs = require('fs'); + const uuidv4 = require('uuid/v4'); + const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs'); + + const config = { + publicKeyId: 'YOUR_PUBLIC_KEY_ID', + privateKey: fs.readFileSync('tst/private.pem'), + region: 'us', + sandbox: false, + }; + + const reportScheduleId = "1234567890"; + const testPayClient = new Client.WebStoreClient(config); + const response = testPayClient.cancelReportSchedule(reportScheduleId); + + response.then(function (result) { + console.log(result.data); + }).catch(err => { + console.log(err); + }); +``` \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index efc8f74..f2186ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,1034 @@ { "name": "@amazonpay/amazon-pay-api-sdk-nodejs", - "version": "2.2.2", - "lockfileVersion": 1, + "version": "2.3.0", + "lockfileVersion": 2, "requires": true, - "dependencies": { - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "packages": { + "": { + "name": "@amazonpay/amazon-pay-api-sdk-nodejs", + "version": "2.3.0", + "license": "Apache-2.0", + "dependencies": { + "axios": "^0.21.2", + "uuid": "^3.3.3" + }, + "devDependencies": { + "chai": "^4.2.0", + "mocha": "^10.0.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz", + "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", "dev": true }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { "ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -463,12 +1482,11 @@ } }, "mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz", + "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==", "dev": true, "requires": { - "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", "chokidar": "3.5.3", diff --git a/package.json b/package.json index 2000a10..2be9342 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@amazonpay/amazon-pay-api-sdk-nodejs", - "version": "2.2.2", + "version": "2.3.0", "description": "Amazon Pay Checkout V2 Integration", "main": "src/client.js", "directories": {}, diff --git a/src/client.js b/src/client.js index 0aece3e..3cffc6b 100644 --- a/src/client.js +++ b/src/client.js @@ -171,12 +171,14 @@ class WebStoreClient extends AmazonPayClient { * @param {String} checkoutSessionId - The checkout session Id * @param {Object} [headers=null] - The headers for the request **/ - getCheckoutSession(checkoutSessionId, headers = null) { - return this.apiCall({ + async getCheckoutSession(checkoutSessionId, headers = null) { + const response = await this.apiCall({ method: 'GET', urlFragment: `checkoutSessions/${checkoutSessionId}`, headers: headers }); + + return helper.enhanceResponseWithShippingAddressList(response); } /** API to update the CheckoutSession object @@ -186,13 +188,15 @@ class WebStoreClient extends AmazonPayClient { * @param {Object} payload - The payload for the request * @param {Object} [headers=null] - The headers for the request **/ - updateCheckoutSession(checkoutSessionId, payload, headers = null) { - return this.apiCall({ + async updateCheckoutSession(checkoutSessionId, payload, headers = null) { + const response = await this.apiCall({ method: 'PATCH', urlFragment: `checkoutSessions/${checkoutSessionId}`, payload: payload, headers: headers }); + + return helper.enhanceResponseWithShippingAddressList(response); } /** API to complete a Checkout Session @@ -202,13 +206,15 @@ class WebStoreClient extends AmazonPayClient { * @param {Object} payload - The payload for the request * @param {Object} [headers=null] - The headers for the request **/ - completeCheckoutSession(checkoutSessionId, payload, headers = null) { - return this.apiCall({ + async completeCheckoutSession(checkoutSessionId, payload, headers = null) { + const response = await this.apiCall({ method: 'POST', urlFragment: `checkoutSessions/${checkoutSessionId}/complete`, payload: payload, headers: headers }); + + return helper.enhanceResponseWithShippingAddressList(response); } /** API to get a ChargePermission object @@ -309,7 +315,7 @@ class WebStoreClient extends AmazonPayClient { * @param {Object} payload - The payload for the request * @param {Object} [headers=null] - The headers for the request **/ - cancelCharge(chargeId, payload, headers = null) { + cancelCharge(chargeId, payload, headers = null) { return this.apiCall({ method: 'DELETE', urlFragment: `charges/${chargeId}/cancel`, @@ -346,6 +352,145 @@ class WebStoreClient extends AmazonPayClient { headers: headers }); } + + + // ----------------------------------- CV2 REPORTING APIS ----------------------------------- + + + /** API to get Reports + * - retrieves details for the reports that match the filters that you specify. + * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#get-reports + * @param {Object} [queryParameters=null] - The queryParameters for the request + * @param {Object} [headers=null] - The headers for the request + **/ + getReports(queryParameters = null, headers = null) { + const {reportTypes, processingStatuses } = queryParameters; + if(Array.isArray(reportTypes)){ + queryParameters.reportTypes = reportTypes.toString(); + } + if(Array.isArray(processingStatuses)){ + queryParameters.processingStatuses = processingStatuses.toString(); + } + return this.apiCall({ + method: 'GET', + urlFragment: `reports`, + headers: headers, + queryParams: queryParameters + }); + } + + + /** API to get Report by Id + * - retrieves report details for the given reportId. + * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#get-report-by-id + * @param {String} reportId - The Report Id + * @param {Object} [headers=null] - The headers for the request + **/ + getReportById(reportId, headers = null) { + return this.apiCall({ + method: 'GET', + urlFragment: `reports/${reportId}`, + headers: headers + }); + } + + + /** API to get Report Document + * - returns the pre-signed S3 URL for the report. The report can be downloaded using this URL. + * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#get-report-document + * @param {String} reportDocumentId - The Report Id + * @param {Object} [headers=null] - The headers for the request + **/ + getReportDocument(reportDocumentId, headers = null) { + return this.apiCall({ + method: 'GET', + urlFragment: `report-documents/${reportDocumentId}`, + headers: headers + }); + } + + + /** API to get Report Schedules + * - returns report schedule details that match the filters criteria specified. + * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#get-report-schedules + * @param {String} [reportTypes=null] - The Report Id + * @param {Object} [headers=null] - The headers for the request + **/ + getReportSchedules(reportTypes = null, headers = null) { + const queryParameters = { + 'reportTypes': Array.isArray(reportTypes) ? reportTypes.toString() : reportTypes + }; + return this.apiCall({ + method: 'GET', + urlFragment: `report-schedules`, + headers: headers, + queryParams: reportTypes ? queryParameters : reportTypes + }); + } + + + /** API to get Report Schedule by Id + * - returns the report schedule details that match the given ID. + * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#get-report-schedule-by-id + * @param {String} reportScheduleId - The Report Schedule Id + * @param {Object} [headers=null] - The headers for the request + **/ + getReportScheduleById(reportScheduleId, headers = null) { + return this.apiCall({ + method: 'GET', + urlFragment: `report-schedules/${reportScheduleId}`, + headers: headers + }); + } + + + /** API to create Report + * - submits a request to generate a report based on the reportType and date range specified. + * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#create-report + * @param {Object} requestPayload - The payload for the request + * @param {Object} headers - The headers for the request + **/ + createReport(requestPayload, headers) { + return this.apiCall({ + method: 'POST', + urlFragment: `reports`, + payload: requestPayload, + headers: headers + }); + } + + + /** API to create Report Schedule + * - creates a report schedule for the given reportType. Only one schedule per report type allowed. + * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#create-report-schedules + * @param {Object} requestPayload - The payload for the request + * @param {Object} headers - The headers for the request + **/ + createReportSchedule(requestPayload, headers) { + return this.apiCall({ + method: 'POST', + urlFragment: `report-schedules`, + payload: requestPayload, + headers: headers + }); + } + + + /** API to cancel Report Schedule + * - cancels the report schedule with the given reportScheduleId. + * @see https://developer.amazon.com/docs/amazon-pay-api-v2/reports.html#cancel-report-schedule + * @param {String} reportScheduleId - The Report Schedule Id + * @param {Object} [headers=null] - The headers for the request + **/ + cancelReportSchedule(reportScheduleId, headers = null) { + return this.apiCall({ + method: 'DELETE', + urlFragment: `report-schedules/${reportScheduleId}`, + headers: headers + }); + } + + } module.exports = { diff --git a/src/clientHelper.js b/src/clientHelper.js index 1b170b1..df22a98 100644 --- a/src/clientHelper.js +++ b/src/clientHelper.js @@ -10,7 +10,8 @@ module.exports = { retryLogic: retryLogic, sendRequest: sendRequest, invokeApi: invokeApi, - prepareOptions: prepareOptions + prepareOptions: prepareOptions, + enhanceResponseWithShippingAddressList: enhanceResponseWithShippingAddressList } function getTimestamp() { @@ -18,7 +19,7 @@ function getTimestamp() { return date.toISOString().split('.')[0] + 'Z'; } -function getAPIEndpointBaseURL (configArgs) { +function getAPIEndpointBaseURL(configArgs) { if ((configArgs.overrideServiceUrl) && (configArgs.overrideServiceUrl.length > 0)) { process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0; // devo environment using self-signed certificate return configArgs.overrideServiceUrl; @@ -43,14 +44,14 @@ function invokeApi(configArgs, apiOptions) { function getQueryString(requestParams) { if (requestParams) return `?${getParametersAsString(requestParams)}`; - return ''; + return ''; } function getParametersAsString(requestParams) { if (!requestParams) return ''; let queryParams = []; - Object.keys(requestParams).forEach(function (param) { + Object.keys(requestParams).sort().forEach(function (param) { queryParams.push(`${param}=${encodeURIComponent(requestParams[param])}`); }); return queryParams.join('&'); @@ -81,15 +82,26 @@ function isEnvSpecificPublicKeyId(publicKeyId) { return publicKeyId.toUpperCase().startsWith('LIVE') || publicKeyId.toUpperCase().startsWith('SANDBOX') } -function sign(privateKey, stringToSign) { +function sign(privateKey, stringToSign, algorithm) { const sign = crypto.createSign('RSA-SHA256').update(stringToSign); return sign.sign({ key: privateKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING, - saltLength: 20 + saltLength: algorithm.saltLength, }, 'base64'); } +function getAlgorithm(algorithm) { + if (!algorithm) return constants.AMAZON_SIGNATURE_ALGORITHM.DEFAULT; + + for (const [key, value] of Object.entries(constants.AMAZON_SIGNATURE_ALGORITHM)) { + if (value.name === algorithm) { + return constants.AMAZON_SIGNATURE_ALGORITHM[key]; + } + } + throw "Not a valid algorithm"; +} + function retryLogic(options, count) { const response = this.sendRequest(options, count); @@ -104,7 +116,7 @@ function retryLogic(options, count) { return response.then(function (result) { return result; }).catch(err => { - if (response.statusCode == 429 || response.statusCode >= 500) { + if (response.statusCode === 408 || response.statusCode === 429 || response.statusCode >= 500) { return this.retryLogic(options, count += 1); } else { return Promise.reject(err); @@ -142,9 +154,9 @@ function signHeaders(configArgs, options) { Object.assign(headers, options.headers); headers['x-amz-pay-region'] = constants.REGION_MAP[configArgs.region.toLowerCase()]; - headers['x-amz-pay-host'] = getAPIEndpointBaseURL(configArgs); + headers['x-amz-pay-host'] = getAPIEndpointBaseURL(configArgs); headers['x-amz-pay-date'] = getTimestamp(); - headers['content-type'] = 'application/json'; + headers['content-type'] = 'application/json'; headers['accept'] = 'application/json'; headers['user-agent'] = `amazon-pay-api-sdk-nodejs/${constants.SDK_VERSION} (JS/${process.versions.node}; ${process.platform})`; @@ -155,7 +167,7 @@ function signHeaders(configArgs, options) { let payload = options.payload; if (payload === null || payload === undefined) { - payload = ''; + payload = ''; } let canonicalRequest = options.method + '\n/' @@ -164,17 +176,18 @@ function signHeaders(configArgs, options) { lowercaseSortedHeaderKeys.forEach(item => canonicalRequest += item.toLowerCase() + ':' + headers[item] + '\n'); canonicalRequest += '\n' + signedHeaders + '\n' + crypto.createHash('SHA256').update(payload).digest('hex'); - const stringToSign = constants.AMAZON_SIGNATURE_ALGORITHM + '\n' + + const algorithm = getAlgorithm(configArgs.algorithm); + const stringToSign = algorithm.name + '\n' + crypto.createHash('SHA256').update(canonicalRequest).digest('hex'); - const signature = sign(configArgs.privateKey, stringToSign); + const signature = sign(configArgs.privateKey, stringToSign, algorithm); - headers['authorization'] = constants.AMAZON_SIGNATURE_ALGORITHM + headers['authorization'] = algorithm.name + ' PublicKeyId=' + configArgs['publicKeyId'] + ', SignedHeaders=' + signedHeaders + ', Signature=' + signature; - return headers; + return headers; } function signPayload(configArgs, payload) { @@ -182,8 +195,16 @@ function signPayload(configArgs, payload) { if (!(typeof payload === 'string' || payload instanceof String)) { payload = JSON.stringify(payload); } - const stringToSign = constants.AMAZON_SIGNATURE_ALGORITHM + '\n' + + const algorithm = getAlgorithm(configArgs.algorithm); + const stringToSign = algorithm.name + '\n' + crypto.createHash('SHA256').update(payload).digest('hex'); - return sign(configArgs.privateKey, stringToSign); + return sign(configArgs.privateKey, stringToSign, algorithm); +} + +function enhanceResponseWithShippingAddressList(response) { + if (response.data.shippingAddressList != null) { + response.data.shippingAddressList = response.data.shippingAddressList.map(shippingAddress => JSON.parse(shippingAddress)); + } + return response; } diff --git a/src/constants.js b/src/constants.js index 0d4be78..6ea130d 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,7 +1,7 @@ 'use strict'; module.exports = { - SDK_VERSION: '2.2.2', + SDK_VERSION: '2.3.0', API_VERSION: 'v2', RETRIES: 3, API_ENDPOINTS: { @@ -17,5 +17,8 @@ module.exports = { eu: 'eu', jp: 'jp' }, - AMAZON_SIGNATURE_ALGORITHM: 'AMZN-PAY-RSASSA-PSS' + AMAZON_SIGNATURE_ALGORITHM: { + DEFAULT: { name: 'AMZN-PAY-RSASSA-PSS', saltLength: 20 }, + V2: { name: 'AMZN-PAY-RSASSA-PSS-V2', saltLength: 32 } + } }; diff --git a/tst/amazonPayClientTest.js b/tst/amazonPayClientTest.js index 2e3b465..b60de0e 100644 --- a/tst/amazonPayClientTest.js +++ b/tst/amazonPayClientTest.js @@ -3,11 +3,13 @@ // Including Required Modules const Client = require('../src/client'); const config = require('./config'); +const configWithAlgorithm = require('./configWithAlgorithm'); const assert = require('assert'); const crypto = require('crypto'); const fs = require('fs'); const publicKey = ``; // Provide public key here to run the tests + const generateButtonSignaturePayloadObject = { storeId: 'amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', webCheckoutDetails: { @@ -19,12 +21,20 @@ const generateButtonSignaturePayloadString = '{"storeId":"amzn1.application-oa2- const generateButtonSignaturePayloadEscapedString = '{"storeId\":\"amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\"webCheckoutDetails\":{\"checkoutReviewReturnUrl\":\"https:\/\/localhost\/test\/CheckoutReview.php\",\"checkoutResultReturnUrl\":\"https:\/\/localhost\/test\/CheckoutResult.php\"}}'; const expectedStringToSign = `AMZN-PAY-RSASSA-PSS 8dec52d799607be40f82d5c8e7ecb6c171e6591c41b1111a576b16076c89381c`; +const expectedStringToSignWithV2Algorithm = `AMZN-PAY-RSASSA-PSS-V2 +8dec52d799607be40f82d5c8e7ecb6c171e6591c41b1111a576b16076c89381c`; const mwsAuthToken = ''; // Provide public key here to run the tests const merchantId = ''; // Provide merchantId -function verify (signature) { - var verifier = crypto.createVerify('RSA-SHA256').update(expectedStringToSign); +function verify(signature, algorithm = null) { + var stringToSign = ''; + if (algorithm) { + stringToSign = expectedStringToSignWithV2Algorithm; + } else { + stringToSign = expectedStringToSign; + } + var verifier = crypto.createVerify('RSA-SHA256').update(stringToSign); return verifier.verify({ key: publicKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING, @@ -38,7 +48,6 @@ describe('AmazonPay Client Test Cases - Generate Button Signature', () => { this.skip(); } }); - it('Validating Generate Button Signature Method', (done) => { const amazonPayCLient = new Client.AmazonPayClient(config); const signatureOne = amazonPayCLient.generateButtonSignature(generateButtonSignaturePayloadObject); @@ -47,6 +56,15 @@ describe('AmazonPay Client Test Cases - Generate Button Signature', () => { assert.ok(verify(signatureOne), 'Failed for JS object payload'); assert.ok(verify(signatureTwo), 'Failed for string payload'); assert.ok(verify(signatureThree), 'Failed for escaped string payload'); + + //Test with V2 Algorithm passed in config + const amazonPayCLientWithAlgorithm = new Client.AmazonPayClient(configWithAlgorithm); + const signatureOneWithAlgorithm = amazonPayCLientWithAlgorithm.generateButtonSignature(generateButtonSignaturePayloadObject); + const signatureTwoWithAlgorithm = amazonPayCLientWithAlgorithm.generateButtonSignature(generateButtonSignaturePayloadString); + const signatureThreeWithAlgorithm = amazonPayCLientWithAlgorithm.generateButtonSignature(generateButtonSignaturePayloadEscapedString); + assert.ok(verify(signatureOneWithAlgorithm, configWithAlgorithm['algorithm']), 'Failed for JS object payload'); + assert.ok(verify(signatureTwoWithAlgorithm, configWithAlgorithm['algorithm']), 'Failed for string payload'); + assert.ok(verify(signatureThreeWithAlgorithm, configWithAlgorithm['algorithm']), 'Failed for escaped string payload'); done(); }); }); @@ -59,17 +77,33 @@ describe('AmazonPay Client Test Cases - Get Authorization Token', () => { } }); it('Validating Get Authorization Token API', (done) => { - const configCopy = {...config}; + const configCopy = { ...config }; configCopy.sandbox = false; const amazonPayCLient = new Client.AmazonPayClient(configCopy); amazonPayCLient.getAuthorizationToken(mwsAuthToken, merchantId) - .then(function (result) { - var actualResponse = result.data; - assert.ok(actualResponse.authorizationToken); - done(); - }) - .catch(function (err) { - done(err); - }); + .then(function (result) { + var actualResponse = result.data; + assert.ok(actualResponse.authorizationToken); + done(); + }) + .catch(function (err) { + done(err); + }); }) -}); \ No newline at end of file + + it('Validating Get Authorization Token API with V2 Algorithm', (done) => { + const configCopy = { ...configWithAlgorithm }; + configCopy.sandbox = false; + const amazonPayCLientWithAlgorithm = new Client.AmazonPayClient(configCopy); + amazonPayCLientWithAlgorithm.getAuthorizationToken(mwsAuthToken, merchantId) + .then(function (result) { + var actualResponse = result.data; + assert.ok(actualResponse.authorizationToken); + done(); + }) + .catch(function (err) { + done(err); + }); + }) +}); + diff --git a/tst/configWithAlgorithm.js b/tst/configWithAlgorithm.js new file mode 100644 index 0000000..795f138 --- /dev/null +++ b/tst/configWithAlgorithm.js @@ -0,0 +1,17 @@ +'use strict'; + +const fs = require('fs'); +// Please Update the below mentioned values before running test cases + +const configArgs = { + 'publicKeyId': '', // Enter your Public Key ID + 'privateKey': fs.readFileSync('AmazonPay_publicKeyId.pem'), // Path to your private key file + 'region': 'eu', + 'sandbox': true, + 'currencyCode': 'EUR', + 'countryCode': 'DE', + 'storeId': 'amzn1.application-oa2-client.xxxxxxxxx', + 'algorithm': 'AMZN-PAY-RSASSA-PSS-V2' +}; + +module.exports = configArgs; diff --git a/tst/unit/clientHelperTest.js b/tst/unit/clientHelperTest.js index 9b4817d..62f1835 100644 --- a/tst/unit/clientHelperTest.js +++ b/tst/unit/clientHelperTest.js @@ -2,6 +2,7 @@ // Including Required Modules const helper = require('../../src/clientHelper'); +const constants = require('../../src/constants'); const assert = require('assert'); // Constants @@ -14,26 +15,40 @@ describe('Test Environment specific URI Test cases', () => { // Test to validate URI for Live specific URI it('Testing Live specific URI', (done) => { - const response = helper.prepareOptions(getPayConfig(false), {urlFragment: 'serviceName'}); + const response = helper.prepareOptions(getPayConfig(false), { urlFragment: 'serviceName' }); assert.strictEqual(response.urlFragment, expectedLiveURI); + + //Test with V2 Algorithm passed in config + const responseWithAlgorithm = helper.prepareOptions(getPayConfig(false, constants.AMAZON_SIGNATURE_ALGORITHM.V2), { urlFragment: 'serviceName' }); + assert.strictEqual(responseWithAlgorithm.urlFragment, expectedLiveURI); + done(); }); // Test to validate URI for Sandbox specific URI it('Testing Sandbox specific URI', (done) => { - const response = helper.prepareOptions(getPayConfig(true), {urlFragment: 'serviceName'}); + const response = helper.prepareOptions(getPayConfig(true), { urlFragment: 'serviceName' }); assert.strictEqual(response.urlFragment, expectedSandboxURI); + + //Test with V2 Algorithm passed in config + const responseWithAlgorithm = helper.prepareOptions(getPayConfig(true, constants.AMAZON_SIGNATURE_ALGORITHM.V2), { urlFragment: 'serviceName' }); + assert.strictEqual(responseWithAlgorithm.urlFragment, expectedSandboxURI); + done(); }); // Generic method used to create Pay Configuration - function getPayConfig(sandboxFlag){ + function getPayConfig(sandboxFlag, algorithmPassed = null) { let payConfig = { 'publicKeyId': 'XXXXXXXXXXXXXXXXXXXXXXXX', - 'privateKey':'keys/private.pem', + 'privateKey': 'keys/private.pem', 'sandbox': sandboxFlag, 'region': 'us', }; + + if (algorithmPassed) { + payConfig['algorithm'] = algorithmPassed; + } return payConfig; } }); @@ -43,27 +58,40 @@ describe('Test Environment specific URI Test cases', () => { // Testing Unified endpoint URI by passing Live specific PublicKeyId it('Testing Unified endpoint URI for Live PublicKeyId', (done) => { - const options = {urlFragment: 'serviceName'}; - const response = helper.prepareOptions(getPayConfig('LIVE-XXXXXXXXXXXXXXXXXXXXXXXX'), {urlFragment: 'serviceName'}); + const options = { urlFragment: 'serviceName' }; + const response = helper.prepareOptions(getPayConfig('LIVE-XXXXXXXXXXXXXXXXXXXXXXXX'), { urlFragment: 'serviceName' }); assert.strictEqual(response.urlFragment, expectedUnfiedURI); + + //Test with V2 Algorithm passed in config + const responseWithAlgorithm = helper.prepareOptions(getPayConfig('LIVE-XXXXXXXXXXXXXXXXXXXXXXXX', constants.AMAZON_SIGNATURE_ALGORITHM.V2), { urlFragment: 'serviceName' }); + assert.strictEqual(responseWithAlgorithm.urlFragment, expectedUnfiedURI); done(); }); // Testing Unified endpoint URI by passing Sandbox specific PublicKeyId it('Testing Unified endpoint URI for Sandbox PublicKeyId', (done) => { - const options = {urlFragment: 'serviceName'}; - const response = helper.prepareOptions(getPayConfig('SANDBOX-XXXXXXXXXXXXXXXXXXXXXXXX'), {urlFragment: 'serviceName'}); + const options = { urlFragment: 'serviceName' }; + const response = helper.prepareOptions(getPayConfig('SANDBOX-XXXXXXXXXXXXXXXXXXXXXXXX'), { urlFragment: 'serviceName' }); assert.strictEqual(response.urlFragment, expectedUnfiedURI); + + //Test with V2 Algorithm passed in config + const responseWithAlgorithm = helper.prepareOptions(getPayConfig('SANDBOX-XXXXXXXXXXXXXXXXXXXXXXXX', constants.AMAZON_SIGNATURE_ALGORITHM.V2), { urlFragment: 'serviceName' }); + assert.strictEqual(responseWithAlgorithm.urlFragment, expectedUnfiedURI); + done(); }); // Generic method used to create Pay Configuration - function getPayConfig(publicKeyId){ + function getPayConfig(publicKeyId, algorithmPassed = null) { let payConfig = { 'publicKeyId': publicKeyId, - 'privateKey':'keys/private.pem', + 'privateKey': 'keys/private.pem', 'region': 'us', }; + + if (algorithmPassed) { + payConfig['algorithm'] = algorithmPassed; + } return payConfig; } }); \ No newline at end of file diff --git a/tst/webStoreClientTest.js b/tst/webStoreClientTest.js index f4a685a..d4bd22e 100644 --- a/tst/webStoreClientTest.js +++ b/tst/webStoreClientTest.js @@ -3,21 +3,29 @@ // Including Required Modules const Client = require('../src/client'); const config = require('./config'); +const configWithAlgorithm = require('./configWithAlgorithm'); const assert = require('assert'); const uuidv4 = require('uuid/v4'); const headers = { 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') }; +const headersWithV2Algorithm = { + 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') +}; const chargePermissionId = ''; // Enter Charge Permission ID +const chargePermissionIdWithV2Algorithm = ''; // Enter Charge Permission ID const buyerToken = ''; // Enter Buyer Token +const buyerTokenWithV2Algorithm = ''; // Enter Buyer Token // Intiating WebStoreClient Class const webStoreClient = new Client.WebStoreClient(config); +const webStoreClientWithAlgorithm = new Client.WebStoreClient(configWithAlgorithm); // Constants required to execute Unit Test cases var checkoutSessionId; var chargeId; +var chargeIdWithV2Algorithm; var refundId; const createCheckoutSessionPayload = { @@ -68,6 +76,16 @@ const createChargePayload = { captureNow: false, canHandlePendingAuthorization: false }; +const createChargePayloadWithV2Algorithm = { + chargePermissionId: chargePermissionIdWithV2Algorithm, + chargeAmount: { + amount: '0.01', + currencyCode: config.currencyCode + }, + captureNow: false, + canHandlePendingAuthorization: false +}; + const captureChargePayload = { captureAmount: { amount: '0.01', @@ -94,7 +112,9 @@ describe('WebStore Client Test Cases - Checkout Session APIs', () => { productType: '', paymentDetails: '', chargePermissionType: '', + orderType: '', recurringMetadata: '', + paymentMethodOnFileMetadata: '', merchantMetadata: '', supplementaryData: '', buyer: '', @@ -125,6 +145,17 @@ describe('WebStore Client Test Cases - Checkout Session APIs', () => { }); }); + it('Validating Get Buyer API with V2 Algorithm', (done) => { + webStoreClientWithAlgorithm.getBuyer(buyerTokenWithV2Algorithm, headersWithV2Algorithm).then(function (result) { + assert.strictEqual(result.status, 200); + var actualResponse = result.data; + assert.deepStrictEqual(actualResponse.buyerId.startsWith('amzn1.account.'), true); + done(); + }).catch(err => { + done(err); + }); + }); + it('Validating Create Checkout Session API', (done) => { webStoreClient.createCheckoutSession(createCheckoutSessionPayload, headers).then(function (result) { assert.strictEqual(result.status, 201); @@ -132,6 +163,18 @@ describe('WebStore Client Test Cases - Checkout Session APIs', () => { checkoutSessionId = actualResponse.checkoutSessionId; assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); done(); + }).catch(err => { + done.error(err); + }); + }); + + it('Validating Create Checkout Session API with V2 Algorithm', (done) => { + webStoreClientWithAlgorithm.createCheckoutSession(createCheckoutSessionPayload, headersWithV2Algorithm).then(function (result) { + assert.strictEqual(result.status, 201); + var actualResponse = result.data; + checkoutSessionId = actualResponse.checkoutSessionId; + assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); + done(); }).catch(err => { done(err); }); @@ -148,6 +191,17 @@ describe('WebStore Client Test Cases - Checkout Session APIs', () => { }); }); + it('Validating Get Checkout Session API with V2 Algorithm', (done) => { + webStoreClientWithAlgorithm.getCheckoutSession(checkoutSessionId, headersWithV2Algorithm).then(function (result) { + assert.strictEqual(result.status, 200); + var actualResponse = result.data; + assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); + done(); + }).catch(err => { + done(err); + }); + }); + it('Validating Update Checkout Session API', (done) => { webStoreClient.updateCheckoutSession(checkoutSessionId, updateCheckoutSessionPayload).then(function (result) { assert.strictEqual(result.status, 200); @@ -159,6 +213,17 @@ describe('WebStore Client Test Cases - Checkout Session APIs', () => { }); }); + it('Validating Update Checkout Session API with V2 Algorithm', (done) => { + webStoreClientWithAlgorithm.updateCheckoutSession(checkoutSessionId, updateCheckoutSessionPayload).then(function (result) { + assert.strictEqual(result.status, 200); + var actualResponse = result.data; + assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); + done(); + }).catch(err => { + done(err); + }); + }); + // Can only run this after visiting amazonPayRedirectUrl it.skip('Validating Complete Checkout Session API', (done) => { webStoreClient.completeCheckoutSession(checkoutSessionId, completeCheckoutSessionPayload).then(function (result) { @@ -170,12 +235,24 @@ describe('WebStore Client Test Cases - Checkout Session APIs', () => { done(err); }); }); + + // Can only run this after visiting amazonPayRedirectUrl + it.skip('Validating Complete Checkout Session API With V2 Algorithm', (done) => { + webStoreClient.completeCheckoutSession(checkoutSessionId, completeCheckoutSessionPayload).then(function (result) { + assert.strictEqual(result.status, 200); + var actualResponse = result.data; + assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); + done(); + }).catch(err => { + done(err); + }); + }); }); describe('', () => { // Skip the tests if chargePermissionId is not provided before(function () { - if (!chargePermissionId) { + if (!chargePermissionId && !chargePermissionIdWithV2Algorithm) { console.error('Please provide chargePermissionId before executing these test cases'); this.skip(); } @@ -213,6 +290,17 @@ describe('', () => { }); }); + it('Validating Get Charge Permission API with V2 Algorithm', (done) => { + webStoreClientWithAlgorithm.getChargePermission(chargePermissionIdWithV2Algorithm, headersWithV2Algorithm).then(function (result) { + assert.strictEqual(result.status, 200); + var actualResponse = result.data; + assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); + done(); + }).catch(err => { + done(err); + }); + }); + it('Validating Update Charge Permission API', (done) => { webStoreClient.updateChargePermission(chargePermissionId, updateChargePermissionPayload, headers).then(function (result) { assert.strictEqual(result.status, 200); @@ -224,6 +312,17 @@ describe('', () => { }); }); + it('Validating Update Charge Permission API with V2 Algorithm', (done) => { + webStoreClientWithAlgorithm.updateChargePermission(chargePermissionIdWithV2Algorithm, updateChargePermissionPayload, headersWithV2Algorithm).then(function (result) { + assert.strictEqual(result.status, 200); + var actualResponse = result.data; + assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); + done(); + }).catch(err => { + done(err); + }); + }); + // Cannot Create Charge if Close Charge Permission is executed, unskip this test case and skip Charge API Tests to validate this API it.skip('Validating Close Charge Permission API', (done) => { webStoreClient.closeChargePermission(chargePermissionId, closeChargePermissionPayload, headers).then(function (result) { @@ -235,6 +334,17 @@ describe('', () => { done(err); }); }); + + it.skip('Validating Close Charge Permission API with V2 Algorithm', (done) => { + webStoreClient.closeChargePermission(chargePermissionIdWithV2Algorithm, closeChargePermissionPayload, headersWithV2Algorithm).then(function (result) { + assert.strictEqual(result.status, 200); + var actualResponse = result.data; + assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); + done(); + }).catch(err => { + done(err); + }); + }); }); // Validating Create Charge API Call @@ -249,15 +359,18 @@ describe('', () => { providerMetadata: '', convertedAmount: '', conversionRate: '', + channel: '', + chargeInitiator: '', statusDetails: '', creationTimestamp: '', expirationTimestamp: '', releaseEnvironment: '', - merchantMetadata: '' + merchantMetadata: '', + platformId: '' }; before(function () { - if (!chargePermissionId) { + if (!chargePermissionId && !chargePermissionIdWithV2Algorithm) { console.error('Please Enter chargePermissionId and execute test cases'); this.skip(); } @@ -275,6 +388,18 @@ describe('', () => { }); }); + it('Validating Create Charge API with V2 Algorithm', (done) => { + webStoreClientWithAlgorithm.createCharge(createChargePayloadWithV2Algorithm, headersWithV2Algorithm).then(function (result) { + assert.strictEqual(result.status, 201); + var actualResponse = result.data; + chargeIdWithV2Algorithm = actualResponse.chargeId; + assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); + done(); + }).catch(err => { + done(err); + }); + }); + it('Validating Get Charge API', (done) => { webStoreClient.getCharge(chargeId, headers).then(function (result) { assert.strictEqual(result.status, 200); @@ -286,6 +411,17 @@ describe('', () => { }); }); + it('Validating Get Charge API with V2 Algorithm', (done) => { + webStoreClientWithAlgorithm.getCharge(chargeIdWithV2Algorithm, headersWithV2Algorithm).then(function (result) { + assert.strictEqual(result.status, 200); + var actualResponse = result.data; + assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); + done(); + }).catch(err => { + done(err); + }); + }); + it('Validating Capture Charge API', (done) => { webStoreClient.captureCharge(chargeId, captureChargePayload, { 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') @@ -299,6 +435,19 @@ describe('', () => { }); }); + it('Validating Capture Charge API with V2 Algorithm', (done) => { + webStoreClientWithAlgorithm.captureCharge(chargeIdWithV2Algorithm, captureChargePayload, { + 'x-amz-pay-idempotency-key': uuidv4().toString().replace(/-/g, '') + }).then(function (result) { + assert.strictEqual(result.status, 200); + var actualResponse = result.data; + assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); + done(); + }).catch(err => { + done(err); + }); + }); + // Cannot Run both Capture charge and Cancel charge at same time, Run either Capture Capture or Cancel Charge it.skip('Validating Cancel Charge API', (done) => { webStoreClient.cancelCharge(chargeId, cancelChargePayload, headers).then(function (result) { @@ -310,9 +459,21 @@ describe('', () => { done(err); }); }); + + // Cannot Run both Capture charge and Cancel charge at same time, Run either Capture Capture or Cancel Charge + it.skip('Validating Cancel Charge API with V2 Algorithm', (done) => { + webStoreClientWithAlgorithm.cancelCharge(chargeIdWithV2Algorithm, cancelChargePayload, headersWithV2Algorithm).then(function (result) { + assert.strictEqual(result.status, 200); + var actualResponse = result.data; + assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); + done(); + }).catch(err => { + done(err); + }); + }); }); - // Validating Refund API Call's + //Validating Refund API Call's describe('WebStore Client Test Cases - Refund APIs', (done) => { // Refund API should have different idempotency key, Hence creating new headers const headers = { @@ -329,7 +490,7 @@ describe('', () => { }; before(function () { - if (!chargePermissionId) { + if (!chargePermissionId && !chargePermissionIdWithV2Algorithm) { console.error('Please Enter chargePermissionId and execute test cases'); this.skip(); } @@ -355,6 +516,26 @@ describe('', () => { }); }); + it('Validating Create Refund API with V2 Algorithm', (done) => { + const refundpaylod = { + chargeId: chargeId, + refundAmount: { + amount: '0.01', + currencyCode: config.currencyCode + }, + softDescriptor: 'SOFT_DESCRIPTOR' + }; + webStoreClientWithAlgorithm.createRefund(refundpaylod, headers).then(function (result) { + assert.strictEqual(result.status, 201); + var actualResponse = result.data; + refundId = actualResponse.refundId; + assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); + done(); + }).catch(err => { + done(err); + }); + }); + it('Validating Get Refund API', (done) => { webStoreClient.getRefund(refundId, headers).then(function (result) { assert.strictEqual(result.status, 200); @@ -365,6 +546,160 @@ describe('', () => { done(err); }); }); + + it('Validating Get Refund API with V2 Algorithm', (done) => { + webStoreClientWithAlgorithm.getRefund(refundId, headers).then(function (result) { + assert.strictEqual(result.status, 200); + var actualResponse = result.data; + assert.deepStrictEqual(Object.keys(expectedResponse), Object.keys(actualResponse)); + done(); + }).catch(err => { + done(err); + }); + }); }); -}); + + // ------------ Testing the CV2 Reporting APIs --------------- + describe('WebStore Client Test Cases - CV2 Reporting APIs', (done) => { + const startTime = '20221118T150630Z'; + const endTime = '20221202T150350Z'; + + const expectGetReportResponse = { + createdTime: '', + endTime: '', + processingEndTime: '', + processingStartTime: '', + processingStatus: '', + reportId: '', + reportType: '', + startTime: '' + } + + const expectGetReportSchedulesReponse = { + nextReportCreationTime: '', + reportScheduleId: '', + reportType: '', + scheduleFrequency: '', + } + + // Tests the GetReports API + it('Validating Get Report API', (done) => { + const requestPayload = { + 'reportType': '', + 'processingStatus': '', + 'createdSince': startTime, + 'createdUntil': endTime, + 'pageSize': '10' + } + webStoreClient.getReports().then(function (result) { + assert.strictEqual(result.status, 200); + var response = result.data; + var reports = response['reports']; + assert.deepStrictEqual(Object.keys(expectGetReportResponse), Object.keys(reports[0])); + done(); + }).catch(err => { + done(err); + }); + }); + + // Tests the GetReportById API + it('Validating Get Report By Id API', (done) => { + const reportId = '60079019360'; + webStoreClient.getReportById(reportId, headers).then(function (result) { + assert.strictEqual(result.status, 200); + var response = result.data; + assert.deepStrictEqual(Object.keys(expectGetReportResponse), Object.keys(response)); + done(); + }).catch(err => { + done(err); + }); + }); + + // Cannot test GerReportDocument right now, as it deals with Settlement reports which are not supported in our accounts + // Tests Get Report Document API + // it('Validating Get Report Document API', (done) => { + // const reportDocumentId = '61516019327'; + // webStoreClient.getReportDocument(reportDocumentId, headers).then(function (result) { + // assert.strictEqual(result.status, 200); + // var response = result.data; + // assert.deepStrictEqual(Object.keys(expectGetReportResponse), Object.keys(response)); + // done(); + // }).catch(err => { + // done(err); + // }); + // }); + + // Tests Get Report Schedules API + it('Validating Get Report Schedules API', (done) => { + const reportTypes = '_GET_FLAT_FILE_OFFAMAZONPAYMENTS_ORDER_REFERENCE_DATA_,_GET_FLAT_FILE_OFFAMAZONPAYMENTS_BILLING_AGREEMENT_DATA_'; + webStoreClient.getReportSchedules(reportTypes, headers).then(function (result) { + assert.strictEqual(result.status, 200); + var response = result.data; + var reportSchedules = response['reportSchedules']; + assert.deepStrictEqual(Object.keys(expectGetReportSchedulesReponse), Object.keys(reportSchedules[0])); + done(); + }).catch(err => { + done(err); + }); + }); + + // Tests Get Report Schedule by Id API + it('Validating Get Report Schedule by Id API', (done) => { + const reportScheduleId = '50011019347'; + webStoreClient.getReportScheduleById(reportScheduleId, headers).then(function (result) { + assert.strictEqual(result.status, 200); + var response = result.data; + assert.deepStrictEqual(Object.keys(expectGetReportSchedulesReponse), Object.keys(response)); + done(); + }).catch(err => { + done(err); + }); + }); + + // Tests Create Report API + it('Validating Create Report API', (done) => { + const requestPayload = { + 'reportType': '_GET_FLAT_FILE_OFFAMAZONPAYMENTS_AUTHORIZATION_DATA_', + 'startTime': startTime, + 'endTime': endTime + } + webStoreClient.createReport(requestPayload, headers).then(function (result) { + assert.strictEqual(result.status, 201); + var response = result.data; + var reportId = response['reportId']; + assert.ok(reportId !== null); + done(); + }).catch(err => { + done(err); + }); + }); + + // Tests Create and Cancel ReportSchedule API + it('Validating Create Report Schedule API and Cancel Report Schedule API', (done) => { + const requestPayload = { + 'reportType': '_GET_FLAT_FILE_OFFAMAZONPAYMENTS_AUTHORIZATION_DATA_', + 'scheduleFrequency': 'PT84H', + 'nextReportCreationTime': startTime, + 'deleteExistingSchedule': true + } + webStoreClient.createReportSchedule(requestPayload, headers).then(function (result) { + assert.strictEqual(result.status, 201); + var response = result.data; + var reportScheduleId = response['reportScheduleId']; + assert.ok(reportScheduleId !== null); + + webStoreClient.cancelReportSchedule(reportScheduleId).then(function (resuLt) { + assert.strictEqual(resuLt.status, 200); + }).catch(err => { + done(err); + }); + + done(); + }).catch(err => { + done(err); + }); + }); + }); +}) +