@adobe/acc-js-sdk 1.1.1 → 1.1.4
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 +198 -22
- 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 +156 -71
- 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 +467 -4
- package/test/soap.test.js +76 -28
- package/.vscode/launch.json +0 -22
package/src/client.js
CHANGED
|
@@ -96,65 +96,110 @@ const xtkObjectHandler = {
|
|
|
96
96
|
* <code>
|
|
97
97
|
* result = await client.NLWS.xtkSession.getServerTime();
|
|
98
98
|
* </code>
|
|
99
|
+
*
|
|
100
|
+
* To get a handler, call the `clientHandler` function and optionally pass a representation.
|
|
101
|
+
* If no representation is passed (undefined), the representation set at the client level
|
|
102
|
+
* will be used, which is the default behavior.
|
|
103
|
+
* To get a proxy with a specific representation, use NLWS.xml or NMWS.json
|
|
99
104
|
*
|
|
100
105
|
* @private
|
|
101
106
|
* @memberof Campaign
|
|
102
107
|
*/
|
|
103
|
-
const clientHandler = {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
108
|
+
const clientHandler = (representation, headers, pushDownOptions) => {
|
|
109
|
+
return {
|
|
110
|
+
get: function(client, namespace) {
|
|
111
|
+
|
|
112
|
+
// Force XML or JSON representation (NLWS.xml or NLWS.json)
|
|
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
|
+
};
|
|
138
|
+
|
|
139
|
+
return new Proxy({ client:client, namespace:namespace}, {
|
|
140
|
+
get: function(callContext, methodName) {
|
|
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];
|
|
116
146
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return promise.then(function(optionAndValue) {
|
|
133
|
-
const optionName = argumentsList[0];
|
|
134
|
-
client._optionCache.put(optionName, optionAndValue);
|
|
135
|
-
return optionAndValue;
|
|
136
|
-
});
|
|
147
|
+
if (pushDownOptions) {
|
|
148
|
+
for (let h in pushDownOptions) callContext.pushDownOptions[h] = pushDownOptions[h];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (methodName == ".") return callContext;
|
|
152
|
+
|
|
153
|
+
// get Schema id from namespace (find first upper case letter)
|
|
154
|
+
var schemaId = "";
|
|
155
|
+
for (var i=0; i<namespace.length; i++) {
|
|
156
|
+
const c = namespace[i];
|
|
157
|
+
if (c >='A' && c<='Z') {
|
|
158
|
+
schemaId = schemaId + ":" + c.toLowerCase() + namespace.substr(i+1);
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
schemaId = schemaId + c;
|
|
137
162
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
163
|
+
callContext.schemaId = schemaId;
|
|
164
|
+
|
|
165
|
+
const caller = function(thisArg, argumentsList) {
|
|
166
|
+
const callContext = thisArg["."];
|
|
167
|
+
const namespace = callContext.namespace;
|
|
168
|
+
const methodNameLC = methodName.toLowerCase();
|
|
169
|
+
methodName = methodName.substr(0, 1).toUpperCase() + methodName.substr(1);
|
|
170
|
+
if (namespace == "xtkSession" && methodNameLC == "logon")
|
|
171
|
+
return callContext.client.logon(argumentsList[0]);
|
|
172
|
+
else if (namespace == "xtkSession" && methodNameLC == "logoff")
|
|
173
|
+
return callContext.client.logoff();
|
|
174
|
+
else if (namespace == "xtkSession" && methodNameLC == "getoption") {
|
|
175
|
+
var promise = callContext.client._callMethod(methodName, callContext, argumentsList);
|
|
176
|
+
return promise.then(function(optionAndValue) {
|
|
177
|
+
const optionName = argumentsList[0];
|
|
178
|
+
client._optionCache.put(optionName, optionAndValue);
|
|
179
|
+
return optionAndValue;
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
// static method
|
|
183
|
+
var result = callContext.client._callMethod(methodName, callContext, argumentsList);
|
|
184
|
+
return result;
|
|
147
185
|
};
|
|
148
|
-
}
|
|
149
186
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
187
|
+
if (methodName == "create") {
|
|
188
|
+
return function(body) {
|
|
189
|
+
callContext.object = body;
|
|
190
|
+
return new Proxy(callContext, xtkObjectHandler);
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return new Proxy(caller, {
|
|
195
|
+
apply: function(target, thisArg, argumentsList) {
|
|
196
|
+
return target(thisArg, argumentsList);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
};
|
|
158
203
|
};
|
|
159
204
|
|
|
160
205
|
// ========================================================================================
|
|
@@ -236,6 +281,11 @@ class Credentials {
|
|
|
236
281
|
* @property {Storage} storage - Overrides the storage interface (i.e. LocalStorage)
|
|
237
282
|
* @property {function} refreshClient - An async callback function with the SDK client as parameter, which will be called when the ACC session is expired
|
|
238
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.
|
|
239
289
|
* @memberOf Campaign
|
|
240
290
|
*/
|
|
241
291
|
|
|
@@ -257,7 +307,7 @@ class ConnectionParameters {
|
|
|
257
307
|
constructor(endpoint, credentials, options) {
|
|
258
308
|
// this._options will be populated with the data from "options" and with
|
|
259
309
|
// default values. But the "options" parameter will not be modified
|
|
260
|
-
this._options = {};
|
|
310
|
+
this._options = Object.assign({}, options);
|
|
261
311
|
|
|
262
312
|
// Default value
|
|
263
313
|
if (options === undefined || options === null)
|
|
@@ -300,6 +350,13 @@ class ConnectionParameters {
|
|
|
300
350
|
this._options._storage = storage;
|
|
301
351
|
this._options.refreshClient = options.refreshClient;
|
|
302
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;
|
|
303
360
|
}
|
|
304
361
|
|
|
305
362
|
/**
|
|
@@ -477,7 +534,7 @@ class Client {
|
|
|
477
534
|
this._entityCache = new XtkEntityCache(this._storage, `${rootKey}.XtkEntityCache`, connectionParameters._options.entityCacheTTL);
|
|
478
535
|
this._methodCache = new MethodCache(this._storage, `${rootKey}.MethodCache`, connectionParameters._options.methodCacheTTL);
|
|
479
536
|
this._optionCache = new OptionCache(this._storage, `${rootKey}.OptionCache`, connectionParameters._options.optionCacheTTL);
|
|
480
|
-
this.NLWS = new Proxy(this, clientHandler);
|
|
537
|
+
this.NLWS = new Proxy(this, clientHandler());
|
|
481
538
|
|
|
482
539
|
this._transport = connectionParameters._options.transport;
|
|
483
540
|
this._traceAPICalls = connectionParameters._options.traceAPICalls;
|
|
@@ -672,13 +729,16 @@ class Client {
|
|
|
672
729
|
* @private
|
|
673
730
|
* @param {string} urn is the API name space, usually the schema. For instance xtk:session
|
|
674
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
|
|
675
733
|
* @return {SOAP.SoapMethodCall} a SoapMethodCall which have been initialized with security tokens... and to which the method
|
|
676
734
|
* parameters should be set
|
|
677
735
|
*/
|
|
678
|
-
_prepareSoapCall(urn, method, internal) {
|
|
736
|
+
_prepareSoapCall(urn, method, internal, extraHttpHeaders, pushDownOptions) {
|
|
679
737
|
const soapCall = new SoapMethodCall(this._transport, urn, method,
|
|
680
738
|
this._sessionToken, this._securityToken,
|
|
681
|
-
this._getUserAgentString(),
|
|
739
|
+
this._getUserAgentString(),
|
|
740
|
+
Object.assign({}, this._connectionParameters._options, pushDownOptions),
|
|
741
|
+
extraHttpHeaders);
|
|
682
742
|
soapCall.internal = !!internal;
|
|
683
743
|
return soapCall;
|
|
684
744
|
}
|
|
@@ -692,6 +752,7 @@ class Client {
|
|
|
692
752
|
*/
|
|
693
753
|
async _retrySoapCall(soapCall) {
|
|
694
754
|
soapCall.retry = false;
|
|
755
|
+
soapCall._retryCount = soapCall._retryCount + 1;
|
|
695
756
|
var newClient = await this._refreshClient(this);
|
|
696
757
|
soapCall.finalize(newClient._soapEndPoint(), newClient);
|
|
697
758
|
if (this._traceAPICalls) {
|
|
@@ -766,6 +827,18 @@ class Client {
|
|
|
766
827
|
this._securityToken = "";
|
|
767
828
|
const credentials = this._connectionParameters._credentials;
|
|
768
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
|
+
|
|
769
842
|
// Clear session token cookie to ensure we're not inheriting an expired cookie. See NEO-26589
|
|
770
843
|
if (credentials._type != "SecurityToken" && typeof document != "undefined") {
|
|
771
844
|
document.cookie = '__sessiontoken=;path=/;';
|
|
@@ -778,8 +851,8 @@ class Client {
|
|
|
778
851
|
that.application = new Application(that);
|
|
779
852
|
return Promise.resolve();
|
|
780
853
|
}
|
|
781
|
-
else if (credentials._type == "SecurityToken") {
|
|
782
|
-
|
|
854
|
+
else if (credentials._type == "SecurityToken") {
|
|
855
|
+
that._sessionInfo = undefined;
|
|
783
856
|
that._installedPackages = {};
|
|
784
857
|
that._sessionToken = "";
|
|
785
858
|
that._securityToken = credentials._securityToken;
|
|
@@ -787,12 +860,14 @@ class Client {
|
|
|
787
860
|
return Promise.resolve();
|
|
788
861
|
}
|
|
789
862
|
else if (credentials._type == "UserPassword" || credentials._type == "BearerToken") {
|
|
790
|
-
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);
|
|
791
864
|
// No retry for logon SOAP methods
|
|
792
865
|
soapCall.retry = false;
|
|
793
866
|
if (credentials._type == "UserPassword") {
|
|
794
867
|
const user = credentials._getUser();
|
|
795
868
|
const password = credentials._getPassword();
|
|
869
|
+
if (!this._connectionParameters._options.noSDKHeaders)
|
|
870
|
+
this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Auth"] = `${credentials._type} ${user}`;
|
|
796
871
|
soapCall.writeString("login", user);
|
|
797
872
|
soapCall.writeString("password", password);
|
|
798
873
|
var parameters = null;
|
|
@@ -860,7 +935,7 @@ class Client {
|
|
|
860
935
|
if (!that.isLogged()) return;
|
|
861
936
|
const credentials = this._connectionParameters._credentials;
|
|
862
937
|
if (credentials._type != "SessionToken" && credentials._type != "AnonymousUser") {
|
|
863
|
-
var soapCall = that._prepareSoapCall("xtk:session", "Logoff");
|
|
938
|
+
var soapCall = that._prepareSoapCall("xtk:session", "Logoff", false, this._connectionParameters._options.extraHttpHeaders);
|
|
864
939
|
return this._makeSoapCall(soapCall).then(function() {
|
|
865
940
|
that._sessionToken = "";
|
|
866
941
|
that._securityToken = "";
|
|
@@ -965,7 +1040,7 @@ class Client {
|
|
|
965
1040
|
* @returns {boolean} a boolean indicating if the package is installed or not
|
|
966
1041
|
*/
|
|
967
1042
|
hasPackage(packageId, optionalName) {
|
|
968
|
-
if (optionalName
|
|
1043
|
+
if (optionalName !== undefined)
|
|
969
1044
|
packageId = `${packageId}:${optionalName}`;
|
|
970
1045
|
if (!this.isLogged())
|
|
971
1046
|
throw CampaignException.NOT_LOGGED_IN(undefined, `Cannot call hasPackage: session not connected`);
|
|
@@ -979,7 +1054,7 @@ class Client {
|
|
|
979
1054
|
* @private
|
|
980
1055
|
* @deprecated since version 1.0.0
|
|
981
1056
|
*/
|
|
982
|
-
|
|
1057
|
+
async _getSecretKeyCipher() {
|
|
983
1058
|
var that = this;
|
|
984
1059
|
if (this._secretKeyCipher) return this._secretKeyCipher;
|
|
985
1060
|
return that.getOption("XtkSecretKey").then(function(secretKey) {
|
|
@@ -1002,7 +1077,7 @@ class Client {
|
|
|
1002
1077
|
*/
|
|
1003
1078
|
async getEntityIfMoreRecent(entityType, fullName, representation, internal) {
|
|
1004
1079
|
const that = this;
|
|
1005
|
-
const soapCall = this._prepareSoapCall("xtk:persist", "GetEntityIfMoreRecent", internal);
|
|
1080
|
+
const soapCall = this._prepareSoapCall("xtk:persist", "GetEntityIfMoreRecent", internal, this._connectionParameters._options.extraHttpHeaders);
|
|
1006
1081
|
soapCall.writeString("pk", entityType + "|" + fullName);
|
|
1007
1082
|
soapCall.writeString("md5", "");
|
|
1008
1083
|
soapCall.writeBoolean("mustExist", false);
|
|
@@ -1105,7 +1180,7 @@ class Client {
|
|
|
1105
1180
|
// console.log(method.toXMLString());
|
|
1106
1181
|
|
|
1107
1182
|
var urn = that._methodCache.getSoapUrn(schemaId, methodName);
|
|
1108
|
-
var soapCall = that._prepareSoapCall(urn, methodName);
|
|
1183
|
+
var soapCall = that._prepareSoapCall(urn, methodName, false, callContext.headers, callContext.pushDownOptions);
|
|
1109
1184
|
|
|
1110
1185
|
// If method is called with one parameter which is a function, then we assume it's a hook: the function will return
|
|
1111
1186
|
// the actual list of parameters
|
|
@@ -1122,7 +1197,7 @@ class Client {
|
|
|
1122
1197
|
throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Cannot call non-static method '${methodName}' of schema '${schemaId}' : no object was specified`);
|
|
1123
1198
|
|
|
1124
1199
|
const rootName = schemaId.substr(schemaId.indexOf(':') + 1);
|
|
1125
|
-
object = that._fromRepresentation(rootName, object);
|
|
1200
|
+
object = that._fromRepresentation(rootName, object, callContext.representation);
|
|
1126
1201
|
soapCall.writeDocument("document", object);
|
|
1127
1202
|
}
|
|
1128
1203
|
|
|
@@ -1146,6 +1221,8 @@ class Client {
|
|
|
1146
1221
|
soapCall.writeByte(paramName, XtkCaster.asByte(paramValue));
|
|
1147
1222
|
else if (type == "short")
|
|
1148
1223
|
soapCall.writeShort(paramName, XtkCaster.asShort(paramValue));
|
|
1224
|
+
else if (type == "int")
|
|
1225
|
+
soapCall.writeLong(paramName, XtkCaster.asLong(paramValue));
|
|
1149
1226
|
else if (type == "long")
|
|
1150
1227
|
soapCall.writeLong(paramName, XtkCaster.asLong(paramValue));
|
|
1151
1228
|
else if (type == "int64")
|
|
@@ -1170,11 +1247,12 @@ class Client {
|
|
|
1170
1247
|
const index = xtkschema.indexOf(":");
|
|
1171
1248
|
docName = xtkschema.substr(index+1);
|
|
1172
1249
|
}
|
|
1173
|
-
|
|
1250
|
+
if (!docName) docName = paramName; // Use te parameter name as the XML root element
|
|
1251
|
+
var xmlValue = that._fromRepresentation(docName, paramValue, callContext.representation);
|
|
1174
1252
|
if (type == "DOMDocument")
|
|
1175
1253
|
soapCall.writeDocument(paramName, xmlValue);
|
|
1176
1254
|
else
|
|
1177
|
-
soapCall.writeElement(paramName, xmlValue
|
|
1255
|
+
soapCall.writeElement(paramName, xmlValue);
|
|
1178
1256
|
}
|
|
1179
1257
|
else
|
|
1180
1258
|
throw CampaignException.BAD_SOAP_PARAMETER(soapCall, paramName, paramValue, `Unsupported parameter type '${type}' for parameter '${paramName}' of method '${methodName}' of schema '${schemaId}`);
|
|
@@ -1189,7 +1267,7 @@ class Client {
|
|
|
1189
1267
|
// the method is called. This is the new version of the object (in XML form)
|
|
1190
1268
|
const entity = soapCall.getEntity();
|
|
1191
1269
|
if (entity) {
|
|
1192
|
-
callContext.object = that._toRepresentation(entity);
|
|
1270
|
+
callContext.object = that._toRepresentation(entity, callContext.representation);
|
|
1193
1271
|
}
|
|
1194
1272
|
}
|
|
1195
1273
|
|
|
@@ -1220,7 +1298,7 @@ class Client {
|
|
|
1220
1298
|
returnValue = soapCall.getNextDate();
|
|
1221
1299
|
else if (type == "DOMDocument") {
|
|
1222
1300
|
returnValue = soapCall.getNextDocument();
|
|
1223
|
-
returnValue = that._toRepresentation(returnValue);
|
|
1301
|
+
returnValue = that._toRepresentation(returnValue, callContext.representation);
|
|
1224
1302
|
if (schemaId === "xtk:queryDef" && methodName === "ExecuteQuery" && paramName === "output") {
|
|
1225
1303
|
// https://github.com/adobe/acc-js-sdk/issues/3
|
|
1226
1304
|
// Check if query operation is "getIfExists". The "object" variable at this point
|
|
@@ -1240,7 +1318,7 @@ class Client {
|
|
|
1240
1318
|
}
|
|
1241
1319
|
else if (type == "DOMElement") {
|
|
1242
1320
|
returnValue = soapCall.getNextElement();
|
|
1243
|
-
returnValue = that._toRepresentation(returnValue);
|
|
1321
|
+
returnValue = that._toRepresentation(returnValue, callContext.representation);
|
|
1244
1322
|
}
|
|
1245
1323
|
else {
|
|
1246
1324
|
// type can reference a schema element. The naming convension is that the type name
|
|
@@ -1254,7 +1332,7 @@ class Client {
|
|
|
1254
1332
|
if (element.getAttribute("name") == shortTypeName) {
|
|
1255
1333
|
// Type found in schema: Process as a DOM element
|
|
1256
1334
|
returnValue = soapCall.getNextElement();
|
|
1257
|
-
returnValue = that._toRepresentation(returnValue);
|
|
1335
|
+
returnValue = that._toRepresentation(returnValue, callContext.representation);
|
|
1258
1336
|
break;
|
|
1259
1337
|
}
|
|
1260
1338
|
element = DomUtil.getNextSiblingElement(element, "element");
|
|
@@ -1309,8 +1387,11 @@ class Client {
|
|
|
1309
1387
|
*/
|
|
1310
1388
|
async test() {
|
|
1311
1389
|
const request = {
|
|
1312
|
-
url: `${this._connectionParameters._endpoint}/r/test
|
|
1390
|
+
url: `${this._connectionParameters._endpoint}/r/test`,
|
|
1391
|
+
headers: {}
|
|
1313
1392
|
};
|
|
1393
|
+
for (let h in this._connectionParameters._options.extraHttpHeaders)
|
|
1394
|
+
request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
|
|
1314
1395
|
const body = await this._makeHttpCall(request);
|
|
1315
1396
|
const xml = DomUtil.parse(body);
|
|
1316
1397
|
const result = this._toRepresentation(xml);
|
|
@@ -1330,6 +1411,8 @@ class Client {
|
|
|
1330
1411
|
'Cookie': '__sessiontoken=' + this._sessionToken
|
|
1331
1412
|
}
|
|
1332
1413
|
};
|
|
1414
|
+
for (let h in this._connectionParameters._options.extraHttpHeaders)
|
|
1415
|
+
request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
|
|
1333
1416
|
const body = await this._makeHttpCall(request);
|
|
1334
1417
|
const lines = body.split('\n');
|
|
1335
1418
|
const doc = DomUtil.newDocument("ping");
|
|
@@ -1359,6 +1442,8 @@ class Client {
|
|
|
1359
1442
|
'Cookie': '__sessiontoken=' + this._sessionToken
|
|
1360
1443
|
}
|
|
1361
1444
|
};
|
|
1445
|
+
for (let h in this._connectionParameters._options.extraHttpHeaders)
|
|
1446
|
+
request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
|
|
1362
1447
|
const body = await this._makeHttpCall(request);
|
|
1363
1448
|
const lines = body.split('\n');
|
|
1364
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
|
});
|