@adobe/acc-js-sdk 1.1.2 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/client.js CHANGED
@@ -105,16 +105,49 @@ const xtkObjectHandler = {
105
105
  * @private
106
106
  * @memberof Campaign
107
107
  */
108
- const clientHandler = (representation) => {
108
+ const clientHandler = (representation, headers, pushDownOptions) => {
109
109
  return {
110
110
  get: function(client, namespace) {
111
+
111
112
  // Force XML or JSON representation (NLWS.xml or NLWS.json)
112
- if (namespace == "xml") return new Proxy(client, clientHandler("xml"));
113
- if (namespace == "json") return new Proxy(client, clientHandler("SimpleJson"));
113
+ if (namespace == "xml") return new Proxy(client, clientHandler("xml", headers, pushDownOptions));
114
+ if (namespace == "json") return new Proxy(client, clientHandler("SimpleJson", headers, pushDownOptions));
115
+
116
+ // Override HTTP headers (NLWS.headers({...}))
117
+ // Unlike NLWS.xml or NLWS.json, NLWS.headers returns a function. This function takes key/value
118
+ // pairs of headers, and, when called, returns a proxy object which will remember the headers
119
+ // and be able to pass them to subsequent SOAP call context
120
+ if (namespace == "headers") return (methodHeaders) => {
121
+ // Build of copy of the http headers and append new headers in order to accomodate
122
+ // chained calls, such as NLWS.headers(...).headers(...)
123
+ const newHeaders = {};
124
+ if (headers) for (let h in headers) newHeaders[h] = headers[h];
125
+ if (methodHeaders) for (let h in methodHeaders) newHeaders[h] = methodHeaders[h];
126
+ return new Proxy(client, clientHandler(representation, newHeaders, pushDownOptions));
127
+ };
128
+
129
+ // Pushes down addition options to the SOAP and transport layers
130
+ if (namespace == "pushDown") return (methodPushDownOptions) => {
131
+ // Build of copy of the pushDownOptions in order to accomodate
132
+ // chained calls, such as NLWS.pushDown(...).pushDown(...)
133
+ const newPushDownOptions = {};
134
+ if (pushDownOptions) for (let h in pushDownOptions) newPushDownOptions[h] = pushDownOptions[h];
135
+ if (methodPushDownOptions) for (let h in methodPushDownOptions) newPushDownOptions[h] = methodPushDownOptions[h];
136
+ return new Proxy(client, clientHandler(representation, headers, newPushDownOptions));
137
+ };
114
138
 
115
139
  return new Proxy({ client:client, namespace:namespace}, {
116
140
  get: function(callContext, methodName) {
117
141
  callContext.representation = representation;
142
+ callContext.headers = callContext.headers || client._connectionParameters._options.extraHttpHeaders;
143
+ callContext.pushDownOptions = {};
144
+ if (headers) {
145
+ for (let h in headers) callContext.headers[h] = headers[h];
146
+ }
147
+ if (pushDownOptions) {
148
+ for (let h in pushDownOptions) callContext.pushDownOptions[h] = pushDownOptions[h];
149
+ }
150
+
118
151
  if (methodName == ".") return callContext;
119
152
 
120
153
  // get Schema id from namespace (find first upper case letter)
@@ -248,6 +281,11 @@ class Credentials {
248
281
  * @property {Storage} storage - Overrides the storage interface (i.e. LocalStorage)
249
282
  * @property {function} refreshClient - An async callback function with the SDK client as parameter, which will be called when the ACC session is expired
250
283
  * @property {string} charset - The charset encoding used for http requests. Defaults to UTF-8 since SDK version 1.1.1
284
+ * @property {{ name:string, value:string}} extraHttpHeaders - optional key/value pair of HTTP header (will override any other headers)
285
+ * @property {string} clientApp - optional name/version of the application client of the SDK. This will be passed in HTTP headers for troubleshooting
286
+ * @property {boolean} noSDKHeaders - set to disable "ACC-SDK" HTTP headers
287
+ * @property {boolean} noMethodInURL - Can be set to true to remove the method name from the URL
288
+ * @property {number} timeout - Can be set to change the HTTP call timeout. Value is passed in ms.
251
289
  * @memberOf Campaign
252
290
  */
253
291
 
@@ -269,7 +307,7 @@ class ConnectionParameters {
269
307
  constructor(endpoint, credentials, options) {
270
308
  // this._options will be populated with the data from "options" and with
271
309
  // default values. But the "options" parameter will not be modified
272
- this._options = {};
310
+ this._options = Object.assign({}, options);
273
311
 
274
312
  // Default value
275
313
  if (options === undefined || options === null)
@@ -312,6 +350,13 @@ class ConnectionParameters {
312
350
  this._options._storage = storage;
313
351
  this._options.refreshClient = options.refreshClient;
314
352
  this._options.charset = options.charset === undefined ? "UTF-8": options.charset;
353
+ this._options.extraHttpHeaders = {};
354
+ if (options.extraHttpHeaders) {
355
+ for (let h in options.extraHttpHeaders) this._options.extraHttpHeaders[h] = options.extraHttpHeaders[h];
356
+ }
357
+ this._options.clientApp = options.clientApp;
358
+ this._options.noSDKHeaders = !!options.noSDKHeaders;
359
+ this._options.noMethodInURL = !!options.noMethodInURL;
315
360
  }
316
361
 
317
362
  /**
@@ -684,13 +729,16 @@ class Client {
684
729
  * @private
685
730
  * @param {string} urn is the API name space, usually the schema. For instance xtk:session
686
731
  * @param {string} method is the method to call, for instance Logon
732
+ * @param {boolean} internal is a boolean indicating whether the SOAP call is performed by the SDK (internal = true) or on behalf of a user
687
733
  * @return {SOAP.SoapMethodCall} a SoapMethodCall which have been initialized with security tokens... and to which the method
688
734
  * parameters should be set
689
735
  */
690
- _prepareSoapCall(urn, method, internal) {
736
+ _prepareSoapCall(urn, method, internal, extraHttpHeaders, pushDownOptions) {
691
737
  const soapCall = new SoapMethodCall(this._transport, urn, method,
692
738
  this._sessionToken, this._securityToken,
693
- this._getUserAgentString(), this._connectionParameters._options.charset);
739
+ this._getUserAgentString(),
740
+ Object.assign({}, this._connectionParameters._options, pushDownOptions),
741
+ extraHttpHeaders);
694
742
  soapCall.internal = !!internal;
695
743
  return soapCall;
696
744
  }
@@ -704,6 +752,7 @@ class Client {
704
752
  */
705
753
  async _retrySoapCall(soapCall) {
706
754
  soapCall.retry = false;
755
+ soapCall._retryCount = soapCall._retryCount + 1;
707
756
  var newClient = await this._refreshClient(this);
708
757
  soapCall.finalize(newClient._soapEndPoint(), newClient);
709
758
  if (this._traceAPICalls) {
@@ -778,6 +827,18 @@ class Client {
778
827
  this._securityToken = "";
779
828
  const credentials = this._connectionParameters._credentials;
780
829
 
830
+ const sdkVersion = this.sdk.getSDKVersion();
831
+ const version = `${sdkVersion.name} ${sdkVersion.version}`;
832
+ const clientApp = this._connectionParameters._options.clientApp;
833
+ if (!this._connectionParameters._options.noSDKHeaders) {
834
+ this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Version"] = version;
835
+ this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Auth"] = `${credentials._type}`;
836
+ if (clientApp)
837
+ this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Client-App"] = clientApp;
838
+ }
839
+ // See NEO-35259
840
+ this._connectionParameters._options.extraHttpHeaders['X-Query-Source'] = `${version}${clientApp? "," + clientApp : ""}`;
841
+
781
842
  // Clear session token cookie to ensure we're not inheriting an expired cookie. See NEO-26589
782
843
  if (credentials._type != "SecurityToken" && typeof document != "undefined") {
783
844
  document.cookie = '__sessiontoken=;path=/;';
@@ -790,8 +851,8 @@ class Client {
790
851
  that.application = new Application(that);
791
852
  return Promise.resolve();
792
853
  }
793
- else if (credentials._type == "SecurityToken") {
794
- that._sessionInfo = undefined;
854
+ else if (credentials._type == "SecurityToken") {
855
+ that._sessionInfo = undefined;
795
856
  that._installedPackages = {};
796
857
  that._sessionToken = "";
797
858
  that._securityToken = credentials._securityToken;
@@ -799,12 +860,14 @@ class Client {
799
860
  return Promise.resolve();
800
861
  }
801
862
  else if (credentials._type == "UserPassword" || credentials._type == "BearerToken") {
802
- const soapCall = that._prepareSoapCall("xtk:session", credentials._type === "UserPassword" ? "Logon" : "BearerTokenLogon");
863
+ const soapCall = that._prepareSoapCall("xtk:session", credentials._type === "UserPassword" ? "Logon" : "BearerTokenLogon", false, this._connectionParameters._options.extraHttpHeaders);
803
864
  // No retry for logon SOAP methods
804
865
  soapCall.retry = false;
805
866
  if (credentials._type == "UserPassword") {
806
867
  const user = credentials._getUser();
807
868
  const password = credentials._getPassword();
869
+ if (!this._connectionParameters._options.noSDKHeaders)
870
+ this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Auth"] = `${credentials._type} ${user}`;
808
871
  soapCall.writeString("login", user);
809
872
  soapCall.writeString("password", password);
810
873
  var parameters = null;
@@ -872,7 +935,7 @@ class Client {
872
935
  if (!that.isLogged()) return;
873
936
  const credentials = this._connectionParameters._credentials;
874
937
  if (credentials._type != "SessionToken" && credentials._type != "AnonymousUser") {
875
- var soapCall = that._prepareSoapCall("xtk:session", "Logoff");
938
+ var soapCall = that._prepareSoapCall("xtk:session", "Logoff", false, this._connectionParameters._options.extraHttpHeaders);
876
939
  return this._makeSoapCall(soapCall).then(function() {
877
940
  that._sessionToken = "";
878
941
  that._securityToken = "";
@@ -977,7 +1040,7 @@ class Client {
977
1040
  * @returns {boolean} a boolean indicating if the package is installed or not
978
1041
  */
979
1042
  hasPackage(packageId, optionalName) {
980
- if (optionalName === undefined)
1043
+ if (optionalName !== undefined)
981
1044
  packageId = `${packageId}:${optionalName}`;
982
1045
  if (!this.isLogged())
983
1046
  throw CampaignException.NOT_LOGGED_IN(undefined, `Cannot call hasPackage: session not connected`);
@@ -991,7 +1054,7 @@ class Client {
991
1054
  * @private
992
1055
  * @deprecated since version 1.0.0
993
1056
  */
994
- async _getSecretKeyCipher() {
1057
+ async _getSecretKeyCipher() {
995
1058
  var that = this;
996
1059
  if (this._secretKeyCipher) return this._secretKeyCipher;
997
1060
  return that.getOption("XtkSecretKey").then(function(secretKey) {
@@ -1014,7 +1077,7 @@ class Client {
1014
1077
  */
1015
1078
  async getEntityIfMoreRecent(entityType, fullName, representation, internal) {
1016
1079
  const that = this;
1017
- const soapCall = this._prepareSoapCall("xtk:persist", "GetEntityIfMoreRecent", internal);
1080
+ const soapCall = this._prepareSoapCall("xtk:persist", "GetEntityIfMoreRecent", internal, this._connectionParameters._options.extraHttpHeaders);
1018
1081
  soapCall.writeString("pk", entityType + "|" + fullName);
1019
1082
  soapCall.writeString("md5", "");
1020
1083
  soapCall.writeBoolean("mustExist", false);
@@ -1117,7 +1180,7 @@ class Client {
1117
1180
  // console.log(method.toXMLString());
1118
1181
 
1119
1182
  var urn = that._methodCache.getSoapUrn(schemaId, methodName);
1120
- var soapCall = that._prepareSoapCall(urn, methodName);
1183
+ var soapCall = that._prepareSoapCall(urn, methodName, false, callContext.headers, callContext.pushDownOptions);
1121
1184
 
1122
1185
  // If method is called with one parameter which is a function, then we assume it's a hook: the function will return
1123
1186
  // the actual list of parameters
@@ -1158,6 +1221,8 @@ class Client {
1158
1221
  soapCall.writeByte(paramName, XtkCaster.asByte(paramValue));
1159
1222
  else if (type == "short")
1160
1223
  soapCall.writeShort(paramName, XtkCaster.asShort(paramValue));
1224
+ else if (type == "int")
1225
+ soapCall.writeLong(paramName, XtkCaster.asLong(paramValue));
1161
1226
  else if (type == "long")
1162
1227
  soapCall.writeLong(paramName, XtkCaster.asLong(paramValue));
1163
1228
  else if (type == "int64")
@@ -1182,11 +1247,12 @@ class Client {
1182
1247
  const index = xtkschema.indexOf(":");
1183
1248
  docName = xtkschema.substr(index+1);
1184
1249
  }
1250
+ if (!docName) docName = paramName; // Use te parameter name as the XML root element
1185
1251
  var xmlValue = that._fromRepresentation(docName, paramValue, callContext.representation);
1186
1252
  if (type == "DOMDocument")
1187
1253
  soapCall.writeDocument(paramName, xmlValue);
1188
1254
  else
1189
- soapCall.writeElement(paramName, xmlValue.documentElement);
1255
+ soapCall.writeElement(paramName, xmlValue);
1190
1256
  }
1191
1257
  else
1192
1258
  throw CampaignException.BAD_SOAP_PARAMETER(soapCall, paramName, paramValue, `Unsupported parameter type '${type}' for parameter '${paramName}' of method '${methodName}' of schema '${schemaId}`);
@@ -1321,8 +1387,11 @@ class Client {
1321
1387
  */
1322
1388
  async test() {
1323
1389
  const request = {
1324
- url: `${this._connectionParameters._endpoint}/r/test`
1390
+ url: `${this._connectionParameters._endpoint}/r/test`,
1391
+ headers: {}
1325
1392
  };
1393
+ for (let h in this._connectionParameters._options.extraHttpHeaders)
1394
+ request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
1326
1395
  const body = await this._makeHttpCall(request);
1327
1396
  const xml = DomUtil.parse(body);
1328
1397
  const result = this._toRepresentation(xml);
@@ -1342,6 +1411,8 @@ class Client {
1342
1411
  'Cookie': '__sessiontoken=' + this._sessionToken
1343
1412
  }
1344
1413
  };
1414
+ for (let h in this._connectionParameters._options.extraHttpHeaders)
1415
+ request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
1345
1416
  const body = await this._makeHttpCall(request);
1346
1417
  const lines = body.split('\n');
1347
1418
  const doc = DomUtil.newDocument("ping");
@@ -1371,6 +1442,8 @@ class Client {
1371
1442
  'Cookie': '__sessiontoken=' + this._sessionToken
1372
1443
  }
1373
1444
  };
1445
+ for (let h in this._connectionParameters._options.extraHttpHeaders)
1446
+ request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
1374
1447
  const body = await this._makeHttpCall(request);
1375
1448
  const lines = body.split('\n');
1376
1449
  const doc = DomUtil.newDocument("ping");
package/src/index.js CHANGED
@@ -23,7 +23,8 @@ const DomUtil = require('./domUtil.js').DomUtil;
23
23
  const XtkCaster = require('./xtkCaster.js').XtkCaster;
24
24
  const { Client, Credentials, ConnectionParameters } = require('./client.js');
25
25
  const request = require('./transport.js').request;
26
- const { TestUtil } = require('./testUtil');
26
+ const { TestUtil } = require('./testUtil.js');
27
+ const { HttpError } = require('./transport.js');
27
28
 
28
29
  /**
29
30
  * Get/Set the transport function (defaults to Axios). This function is used for testing / mocking the transport layer.
@@ -210,6 +211,7 @@ sdk.XtkCaster = XtkCaster;
210
211
  sdk.Credentials = Credentials;
211
212
  sdk.DomUtil = DomUtil;
212
213
  sdk.ConnectionParameters = ConnectionParameters;
214
+ sdk.HttpError = HttpError;
213
215
 
214
216
  // Public exports
215
217
  module.exports = sdk;
package/src/soap.js CHANGED
@@ -78,13 +78,15 @@ const NS_XSD = "http://www.w3.org/2001/XMLSchema";
78
78
  * @param {string} sessionToken Campaign session token
79
79
  * @param {string} securityToken Campaign security token
80
80
  * @param {string} userAgentString The user agent string to use for HTTP requests
81
- * @param {string} charset The charset encoding used for http requests, usually UTF-8
81
+ * @param {string} pushDownOptions Options to push down to the request (comes from connectionParameters._options)
82
+ * @param {{ name:string, value:string}} extraHttpHeaders key/value pair of HTTP header (will override any other headers)
82
83
  * @memberof SOAP
83
84
  */
84
85
  class SoapMethodCall {
85
86
 
86
- constructor(transport, urn, methodName, sessionToken, securityToken, userAgentString, charset) {
87
+ constructor(transport, urn, methodName, sessionToken, securityToken, userAgentString, pushDownOptions, extraHttpHeaders) {
87
88
  this.request = undefined; // The HTTP request (object litteral passed to the transport layer)
89
+ this.requestOptions = undefined;
88
90
  this.response = undefined; // The HTTP response object (in case of success)
89
91
 
90
92
  // Current URN and method (for error reporting)
@@ -96,11 +98,14 @@ class SoapMethodCall {
96
98
  this.internal = false;
97
99
  // Enable soap retry
98
100
  this.retry = true;
101
+ this._retryCount = 0;
99
102
 
100
103
  this._sessionToken = sessionToken || "";
101
104
  this._securityToken = securityToken || "";
102
105
  this._userAgentString = userAgentString;
103
- this._charset = charset || "";
106
+ this._pushDownOptions = pushDownOptions || {};
107
+ this._charset = this._pushDownOptions.charset || '';
108
+ this._extraHttpHeaders = extraHttpHeaders || {};
104
109
 
105
110
  // THe SOAP call being built
106
111
  this._doc = undefined; // XML document for SOAP call
@@ -213,7 +218,7 @@ class SoapMethodCall {
213
218
  * @param {string} tag the parameter name
214
219
  * @param {*} value the parameter value, which will be casted to a int32 according to xtk rules
215
220
  */
216
- writeLong(tag, value) {
221
+ writeLong(tag, value) {
217
222
  value = XtkCaster.asLong(value);
218
223
  this._addNode(tag, "xsd:int", XtkCaster.asString(value), SOAP_ENCODING_NATIVE);
219
224
  }
@@ -286,6 +291,7 @@ class SoapMethodCall {
286
291
  writeElement(tag, element) {
287
292
  const node = this._addNode(tag, "ns:Element", null, SOAP_ENCODING_XML);
288
293
  if (element !== null && element !== undefined) {
294
+ if (element.nodeType === 9) element = element.documentElement;
289
295
  const child = this._doc.importNode(element, true);
290
296
  node.appendChild(child);
291
297
  }
@@ -299,7 +305,8 @@ class SoapMethodCall {
299
305
  writeDocument(tag, document) {
300
306
  const node = this._addNode(tag, "", null, SOAP_ENCODING_XML);
301
307
  if (document !== null && document !== undefined) {
302
- const child = this._doc.importNode(document.documentElement, true);
308
+ const element = document.nodeType === 1 ? document : document.documentElement;
309
+ const child = this._doc.importNode(element, true);
303
310
  node.appendChild(child);
304
311
  }
305
312
  }
@@ -513,23 +520,40 @@ class SoapMethodCall {
513
520
  * @param {string} url is the Campaign SOAP endpoint (soaprouter.jsp)
514
521
  * @returns {Object} an options object describing the HTTP request, with cookies, headers and body
515
522
  */
516
- _createHTTPRequest(url) {
523
+ _createHTTPRequest(url, requestOptions) {
524
+
525
+ const headers = {
526
+ 'Content-type': `application/soap+xml${this._charset ? ";charset=" + this._charset : ""}`,
527
+ 'SoapAction': `${this.urn}#${this.methodName}`,
528
+ 'X-Security-Token': this._securityToken
529
+ };
530
+
531
+ // Add HTTP headers specific to the SOAP call for better tracing/troubleshooting
532
+ if (this._extraHttpHeaders && this._extraHttpHeaders['ACC-SDK-Version']) {
533
+ // "this.retry" means that the call can be retried, not that it is being retried. The HTTP header howerver, indicates that this
534
+ // is actually a retry of a previously failed call (expired token)
535
+ if (this._retryCount > 0) headers["ACC-SDK-Call-RetryCount"] = `${this._retryCount}`;
536
+ if (this.internal) headers["ACC-SDK-Call-Internal"] = "1";
537
+ }
517
538
 
518
- const options = {
539
+ const request = {
519
540
  url: url,
520
541
  method: 'POST',
521
- headers: {
522
- 'Content-type': `application/soap+xml${this._charset ? ";charset=" + this._charset : ""}`,
523
- 'SoapAction': `${this.urn}#${this.methodName}`,
524
- 'X-Security-Token': this._securityToken
525
- },
542
+ headers: headers,
526
543
  data: DomUtil.toXMLString(this._doc)
527
544
  };
528
545
  if (this._sessionToken)
529
- options.headers.Cookie = '__sessiontoken=' + this._sessionToken;
546
+ request.headers.Cookie = '__sessiontoken=' + this._sessionToken;
530
547
  if (this._userAgentString)
531
- options.headers['User-Agent'] = this._userAgentString;
532
- return options;
548
+ request.headers['User-Agent'] = this._userAgentString;
549
+
550
+ // Override http headers with custom headers
551
+ for (let h in this._extraHttpHeaders) {
552
+ request.headers[h] = this._extraHttpHeaders[h];
553
+ }
554
+
555
+ const extraOptions = Object.assign({}, this._pushDownOptions, requestOptions);
556
+ return [ request, extraOptions ];
533
557
  }
534
558
 
535
559
  /**
@@ -575,9 +599,11 @@ class SoapMethodCall {
575
599
  sessionTokenElem.textContent = this._sessionToken;
576
600
  this._method.prepend(sessionTokenElem);
577
601
  }
578
- const options = this._createHTTPRequest(url);
602
+ const noMethodInURL = !!this._pushDownOptions.noMethodInURL;
603
+ const actualUrl = noMethodInURL ? url : `${url}?${this.urn}:${this.methodName}`;
604
+
579
605
  // Prepare request and empty response objects
580
- this.request = options;
606
+ [this.request, this.requestOptions] = this._createHTTPRequest(actualUrl);
581
607
  this.response = undefined;
582
608
  }
583
609
 
@@ -590,7 +616,7 @@ class SoapMethodCall {
590
616
  */
591
617
  async execute() {
592
618
  const that = this;
593
- const promise = this._transport(this.request);
619
+ const promise = this._transport(this.request, this.requestOptions);
594
620
  return promise.then(function(body) {
595
621
  if (body.indexOf(`XSV-350008`) != -1)
596
622
  throw CampaignException.SESSION_EXPIRED();
package/src/testUtil.js CHANGED
@@ -1,4 +1,4 @@
1
- const { DomUtil } = require("./domUtil");
1
+ const { DomUtil } = require("./domUtil.js");
2
2
 
3
3
  /*
4
4
  Copyright 2022 Adobe. All rights reserved.
@@ -14,7 +14,7 @@ governing permissions and limitations under the License.
14
14
  (function() {
15
15
  "use strict";
16
16
 
17
- const { newSchema } = require("./application");
17
+ const { newSchema } = require("./application.js");
18
18
 
19
19
  /**********************************************************************************
20
20
  *
package/src/transport.js CHANGED
@@ -14,13 +14,27 @@ governing permissions and limitations under the License.
14
14
 
15
15
  const { Util } = require('./util.js');
16
16
 
17
+ /**
18
+ * @memberof Utils
19
+ * @class
20
+ * @constructor
21
+ */
17
22
  class HttpError {
23
+ /* Encapsulates an error from an HTTP call
24
+ * @param {string|number} statusCode - The Http status code
25
+ * @param {string?} statusText - The Http status text corresponding to the error code
26
+ * @param {any?} data - The payload of the HTTP response, which usually contains details about the error
27
+ */
18
28
  constructor(statusCode, statusText, data) {
19
29
  this.statusCode = statusCode;
20
30
  this.statusText = statusText || "";
21
31
  this.data = data;
22
32
  }
23
33
 
34
+ /**
35
+ * Returns a short description of the error
36
+ * @returns {string} a short descrption of the error
37
+ */
24
38
  toString() {
25
39
  return `${this.statusCode}${this.statusText ? " " + this.statusText : ""}`;
26
40
  }
@@ -52,13 +66,14 @@ if (!Util.isBrowser()) {
52
66
  * - request
53
67
  */
54
68
 
55
- const request = (options) => {
69
+ const request = (options, requestOptions) => {
70
+ requestOptions = requestOptions || {};
56
71
  const request = {
57
72
  method: options.method || "GET",
58
73
  url: options.url,
59
74
  headers: options.headers,
60
75
  data: options.data,
61
- timeout: 5000,
76
+ timeout: requestOptions.timeout || 5000,
62
77
  };
63
78
  return axios(request)
64
79
  .then((response) => {
@@ -2108,6 +2108,7 @@ describe('Application', () => {
2108
2108
  const application = client.application;
2109
2109
  expect(application).not.toBeNull();
2110
2110
  expect(application.buildNumber).toBeUndefined();
2111
+ expect(application.version).toBeUndefined();
2111
2112
  expect(application.instanceName).toBeUndefined();
2112
2113
  expect(application.operator).toBeUndefined();
2113
2114
  expect(application.package).toBeUndefined();
@@ -2145,4 +2146,14 @@ describe('Application', () => {
2145
2146
  expect(schema2).toBeNull();
2146
2147
  });
2147
2148
  });
2149
+
2150
+ describe("Version", () => {
2151
+ it("Should get proper version information", async () => {
2152
+ const client = await Mock.makeClient();
2153
+ client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
2154
+ await client.NLWS.xtkSession.logon();
2155
+ expect(client.application.buildNumber).toBe('9219');
2156
+ expect(client.application.version).toBe('6.7.0');
2157
+ })
2158
+ })
2148
2159
  });
@@ -56,12 +56,12 @@ describe('ACC Client (has package)', () => {
56
56
  client._transport.mockReturnValueOnce(LOGON_RESPONSE);
57
57
  await client.NLWS.xtkSession.logon();
58
58
 
59
- expect(client.hasPackage("nms:campaign"));
60
- expect(client.hasPackage("nms", "campaign"));
61
- expect(!client.hasPackage("nms:mrm"));
62
- expect(!client.hasPackage("nms", "mrm"));
63
- expect(client.hasPackage("nms:core"));
64
- expect(client.hasPackage("nms", "core"));
59
+ expect(client.hasPackage("nms:campaign")).toBeTruthy();
60
+ expect(client.hasPackage("nms", "campaign")).toBeTruthy();
61
+ expect(client.hasPackage("nms:mrm")).toBeFalsy();
62
+ expect(client.hasPackage("nms", "mrm")).toBeFalsy();
63
+ expect(client.hasPackage("nms:core")).toBeTruthy();
64
+ expect(client.hasPackage("nms", "core")).toBeTruthy();
65
65
  });
66
66
 
67
67
  it('should fail when unlogged', async () => {