diff --git a/lib/AvaTaxClient.js b/lib/AvaTaxClient.js index 624af3af..b8f52fdc 100644 --- a/lib/AvaTaxClient.js +++ b/lib/AvaTaxClient.js @@ -13,38 +13,47 @@ * @version 21.3.1 * @link https://github.com/avadev/AvaTax-REST-V2-JS-SDK */ - -import fetch from 'isomorphic-fetch'; +import fetch from 'isomorphic-fetch' import { createBasicAuthHeader } from './utils/basic_auth'; import { withTimeout } from './utils/withTimeout'; +import polly from 'polly-js' +import UserConfiguration from './UserConfiguration' + var JSONbig = require('json-bigint')({ useNativeBigInt: true }); export default class AvaTaxClient { /** - * Construct a new AvaTaxClient - * - * @constructor - * @param string appName Specify the name of your application here. Should not contain any semicolons. - * @param string appVersion Specify the version number of your application here. Should not contain any semicolons. - * @param string machineName Specify the machine name of the machine on which this code is executing here. Should not contain any semicolons. - * @param string environment Indicates which server to use; acceptable values are "sandbox" or "production", or the full URL of your AvaTax instance. - */ - constructor({ appName, appVersion, machineName, environment }) { + * Construct a new AvaTaxClient + * + * @constructor + * @param string appName Specify the name of your application here. Should not contain any semicolons. + * @param string appVersion Specify the version number of your application here. Should not contain any semicolons. + * @param string machineName Specify the machine name of the machine on which this code is executing here. Should not contain any semicolons. + * @param string environment Indicates which server to use; acceptable values are "sandbox" or "production", or the full URL of your AvaTax instance. + */ + constructor({ appName, appVersion, machineName, environment, userConfig = null }) { this.baseUrl = 'https://rest.avatax.com'; + if (userConfig) { + + if (userConfig.maxRetryattempts <= 0) { + userConfig.maxRetryattempts = 0; + } + if (userConfig.TimeoutInMinutes <= 0) { + userConfig.TimeoutInMinutes = 2; + } + this.userConfig = userConfig; + } + else { + this.userConfig = new UserConfiguration(0, 2); + } + if (environment == 'sandbox') { this.baseUrl = 'https://sandbox-rest.avatax.com'; - } else if ( - environment.substring(0, 8) == 'https://' || - environment.substring(0, 7) == 'http://' - ) { + } + else if (environment.substring(0, 8) == 'https://' || environment.substring(0, 7) == 'http://') { this.baseUrl = environment; } - this.clientId = - appName + - '; ' + - appVersion + - '; JavascriptSdk; 21.3.1; ' + - machineName; + this.clientId = appName + '; ' + appVersion + '; JavascriptSdk; 21.3.2; ' + machineName; } /** @@ -76,42 +85,63 @@ export default class AvaTaxClient { * @param string payload The request body, if this is being sent to a POST/PUT API call */ restCall({ url, verb, payload }) { - return withTimeout(1200000, fetch(url, { - method: verb, - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: this.auth, - 'X-Avalara-Client': this.clientId - }, - body: JSON.stringify(payload) - })).then(res => { - var contentType = res.headers._headers['content-type'][0]; - - if (contentType === 'application/vnd.ms-excel' || contentType === 'text/csv') { - return res; - } - return res.text(); - }).then(text => { - var json; - try { - json = JSONbig.parse(text); - } catch (e) { - let ex = new Error('The response is in an unexpected format. See details for the complete response.'); - ex.target = 'Unknown'; - ex.details = text; - throw ex; - } - // handle error - if (json.error) { - let ex = new Error(json.error.message); - ex.code = json.error.code; - ex.target = json.error.target; - ex.details = json.error.details; - throw ex; - } else { - return json; - } + let arr = []; + for (let i = 1; i <= this.userConfig.maxRetryattempts; i++) { + arr.push(2 * i * 1000); + } + return polly(). + waitAndRetry(arr) + .executeForPromise(() => { + return withTimeout(this.userConfig.TimeoutInMinutes * 60 * 1000, fetch(url, { + method: verb, + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: this.auth, + 'X-Avalara-Client': this.clientId + }, + body: JSON.stringify(payload) + })).then(res => { + var contentType = res.headers._headers['content-type'][0]; + if (contentType === 'application/vnd.ms-excel' || contentType === 'text/csv') { + return res; + } + return res.text(); + }).then(text => { + var json; + try { + json = JSONbig.parse(text); + } + catch (e) { + let ex = new Error('The response is in an unexpected format. See details for the complete response.'); + ex.target = 'Unknown'; + ex.details = text; + throw ex; + } + //handle error + if (json.error) { + let ex = new Error(json.error.message); + ex.code = json.error.code; + ex.target = json.error.target; + ex.details = json.error.details; + throw ex; + } else { + return json; + } + }).catch(err => { + if (err.message == 'timeout') { + return Promise.reject(err) + } + else if (err.code && err.code == 'ETIMEDOUT') { + return Promise.reject(err); + } + else if (err.code && err.code == 'InternalServerError') { + return Promise.reject(err) + } + else { + return err; + } + }) }) } @@ -172,6 +202,9 @@ export default class AvaTaxClient { return this.restCall({ url: path, verb: 'post', payload: model }); } + + + /** * Activate an account by accepting terms and conditions * @@ -2270,7 +2303,7 @@ export default class AvaTaxClient { * * @return FetchResult */ - listMrsCompanies({ } = {}) { + listMrsCompanies({ } = {}) { var path = this.buildUrl({ url: `/api/v2/companies/mrs`, parameters: {} @@ -3634,7 +3667,7 @@ export default class AvaTaxClient { * * @return FetchResult */ - listCrossBorderSections({ } = {}) { + listCrossBorderSections({ } = {}) { var path = this.buildUrl({ url: `/api/v2/definitions/crossborder/sections`, parameters: {} @@ -10819,7 +10852,7 @@ export default class AvaTaxClient { * * @return FetchResult */ - listMySubscriptions({ } = {}) { + listMySubscriptions({ } = {}) { var path = this.buildUrl({ url: `/api/v2/utilities/subscriptions`, parameters: {} @@ -10854,7 +10887,7 @@ export default class AvaTaxClient { * * @return object */ - ping({ } = {}) { + ping({ } = {}) { var path = this.buildUrl({ url: `/api/v2/utilities/ping`, parameters: {} diff --git a/lib/UserConfiguration.js b/lib/UserConfiguration.js new file mode 100644 index 00000000..d73370ac --- /dev/null +++ b/lib/UserConfiguration.js @@ -0,0 +1,9 @@ +export default class UserConfiguration { + + constructor(maxRetryattempts, TimeoutInMinutes) { + this.maxRetryattempts = maxRetryattempts; + this.TimeoutInMinutes = TimeoutInMinutes; + } +} + + diff --git a/package.json b/package.json index 37920d93..ba9db5a1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { + "type": "module", "name": "avatax", - "version": "21.3.1", + "version": "21.3.2", "description": "AvaTax v2 SDK for languages using JavaScript", "main": "index.js", "homepage": "https://github.com/avadev/AvaTax-REST-V2-JS-SDK", @@ -24,7 +25,8 @@ "license": "Apache-2.0", "dependencies": { "isomorphic-fetch": "^2.2.1", - "json-bigint": "^1.0.0" + "json-bigint": "^1.0.0", + "polly-js": "^1.8.2" }, "devDependencies": { "babel-cli": "^6.22.2", diff --git a/yarn.lock b/yarn.lock index f1f67f7a..1bea4358 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2472,6 +2472,11 @@ pluralize@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-4.0.0.tgz#59b708c1c0190a2f692f1c7618c446b052fd1762" +polly-js@^1.8.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/polly-js/-/polly-js-1.8.2.tgz#6643376f4ec3feb91300ade628d14f11231b9d49" + integrity sha512-xLP03RU7rnczJgul5YtCbk9SRtuvE/f0hMntAoH4mMmqRoLaHBO9SXPG2UFZRBjqv0ResUCmXhQPwQXkYhBxsg== + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"