@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/.github/workflows/npm-publish.yml +1 -1
- package/CHANGELOG.md +29 -0
- package/README.md +188 -21
- package/compile.js +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/samples/011 - basics - packages.js +60 -0
- package/samples/utils.js +3 -1
- package/src/application.js +11 -4
- package/src/client.js +89 -16
- package/src/index.js +3 -1
- package/src/soap.js +44 -18
- package/src/testUtil.js +2 -2
- package/src/transport.js +17 -2
- package/test/application.test.js +11 -0
- package/test/client.hasPackage.test.js +6 -6
- package/test/client.test.js +415 -4
- package/test/soap.test.js +76 -28
- package/.vscode/launch.json +0 -22
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(),
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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}
|
|
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,
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
546
|
+
request.headers.Cookie = '__sessiontoken=' + this._sessionToken;
|
|
530
547
|
if (this._userAgentString)
|
|
531
|
-
|
|
532
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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) => {
|
package/test/application.test.js
CHANGED
|
@@ -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(
|
|
62
|
-
expect(
|
|
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 () => {
|