@adobe/acc-js-sdk 1.1.62 → 1.2.0

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.
Files changed (61) hide show
  1. package/.cursor/commands/opsx-apply.md +152 -0
  2. package/.cursor/commands/opsx-archive.md +157 -0
  3. package/.cursor/commands/opsx-explore.md +173 -0
  4. package/.cursor/commands/opsx-propose.md +106 -0
  5. package/.cursor/skills/openspec-apply-change/SKILL.md +156 -0
  6. package/.cursor/skills/openspec-archive-change/SKILL.md +114 -0
  7. package/.cursor/skills/openspec-explore/SKILL.md +288 -0
  8. package/.cursor/skills/openspec-propose/SKILL.md +110 -0
  9. package/.eslintrc.js +2 -2
  10. package/.github/prompts/opsx-apply.prompt.md +149 -0
  11. package/.github/prompts/opsx-archive.prompt.md +154 -0
  12. package/.github/prompts/opsx-explore.prompt.md +170 -0
  13. package/.github/prompts/opsx-propose.prompt.md +103 -0
  14. package/.github/skills/openspec-apply-change/SKILL.md +156 -0
  15. package/.github/skills/openspec-archive-change/SKILL.md +114 -0
  16. package/.github/skills/openspec-explore/SKILL.md +288 -0
  17. package/.github/skills/openspec-propose/SKILL.md +110 -0
  18. package/.github/workflows/codeql-analysis.yml +5 -4
  19. package/.github/workflows/npm-publish.yml +3 -3
  20. package/AGENTS.md +117 -0
  21. package/CLAUDE.md +2 -0
  22. package/MIGRATION.md +10 -0
  23. package/README.md +6 -2
  24. package/ai-docs/coding-rules.md +95 -0
  25. package/ai-docs/tech-stack.md +43 -0
  26. package/babel.config.js +5 -0
  27. package/docs/changeLog.html +28 -2
  28. package/docs/checkList.html +2 -2
  29. package/docs/quickstart.html +2 -1
  30. package/docs/release.html +1 -1
  31. package/openspec/config.yaml +20 -0
  32. package/package-lock.json +6055 -4036
  33. package/package.json +9 -7
  34. package/src/AGENTS.md +98 -0
  35. package/src/CLAUDE.md +2 -0
  36. package/src/application.js +637 -637
  37. package/src/cache.js +133 -133
  38. package/src/cacheRefresher.js +190 -190
  39. package/src/campaign.js +532 -532
  40. package/src/client.js +1539 -1537
  41. package/src/crypto.js +52 -52
  42. package/src/domUtil.js +346 -346
  43. package/src/entityAccessor.js +61 -61
  44. package/src/index.js +83 -83
  45. package/src/methodCache.js +69 -69
  46. package/src/optionCache.js +26 -26
  47. package/src/soap.js +321 -322
  48. package/src/testUtil.js +13 -13
  49. package/src/transport.js +70 -70
  50. package/src/util.js +147 -147
  51. package/src/web/bundler.js +5 -5
  52. package/src/xtkCaster.js +258 -258
  53. package/src/xtkEntityCache.js +34 -34
  54. package/src/xtkJob.js +185 -185
  55. package/test/AGENTS.md +37 -0
  56. package/test/CLAUDE.md +2 -0
  57. package/test/cacheRefresher.test.js +7 -0
  58. package/test/client.test.js +90 -78
  59. package/test/jest.config.js +6 -0
  60. package/test/observability.test.js +6 -1
  61. package/test/xtkJob.test.js +2 -2
package/src/client.js CHANGED
@@ -10,36 +10,35 @@ OF ANY KIND, either express or implied. See the License for the specific languag
10
10
  governing permissions and limitations under the License.
11
11
  */
12
12
  (function() {
13
- "use strict";
14
- /*jshint sub:true*/
13
+ "use strict";
15
14
 
16
- /**********************************************************************************
15
+ /**********************************************************************************
17
16
  *
18
17
  * ACC JavaScript SDK
19
18
  * See README.md for usage
20
19
  *
21
20
  *********************************************************************************/
22
21
 
23
- /**
22
+ /**
24
23
  * Client to ACC instance
25
24
  */
26
- const { SoapMethodCall } = require('./soap.js');
27
- const { CampaignException, makeCampaignException } = require('./campaign.js');
28
- const XtkCaster = require('./xtkCaster.js').XtkCaster;
29
- const XtkEntityCache = require('./xtkEntityCache.js').XtkEntityCache;
30
- const Cipher = require('./crypto.js').Cipher;
31
- const DomUtil = require('./domUtil.js').DomUtil;
32
- const MethodCache = require('./methodCache.js').MethodCache;
33
- const OptionCache = require('./optionCache.js').OptionCache;
34
- const CacheRefresher = require('./cacheRefresher.js').CacheRefresher;
35
- const request = require('./transport.js').request;
36
- const { Application, newSchema } = require('./application.js');
37
- const EntityAccessor = require('./entityAccessor.js').EntityAccessor;
38
- const { Util } = require('./util.js');
39
- const { XtkJobInterface } = require('./xtkJob.js');
40
- const qsStringify = require('qs-stringify');
41
-
42
- /**
25
+ const { SoapMethodCall } = require('./soap.js');
26
+ const { CampaignException, makeCampaignException } = require('./campaign.js');
27
+ const XtkCaster = require('./xtkCaster.js').XtkCaster;
28
+ const XtkEntityCache = require('./xtkEntityCache.js').XtkEntityCache;
29
+ const Cipher = require('./crypto.js').Cipher;
30
+ const DomUtil = require('./domUtil.js').DomUtil;
31
+ const MethodCache = require('./methodCache.js').MethodCache;
32
+ const OptionCache = require('./optionCache.js').OptionCache;
33
+ const CacheRefresher = require('./cacheRefresher.js').CacheRefresher;
34
+ const request = require('./transport.js').request;
35
+ const { Application, newSchema } = require('./application.js');
36
+ const EntityAccessor = require('./entityAccessor.js').EntityAccessor;
37
+ const { Util } = require('./util.js');
38
+ const { XtkJobInterface } = require('./xtkJob.js');
39
+ const qsStringify = require('qs-stringify');
40
+
41
+ /**
43
42
  * @namespace Campaign
44
43
  *
45
44
  * @typedef {Object} SessionInfo
@@ -61,7 +60,7 @@ const qsStringify = require('qs-stringify');
61
60
  * @memberOf Campaign
62
61
  */
63
62
 
64
- /**
63
+ /**
65
64
  * @typedef {Object} XtkMethodParam
66
65
  * @property {string} name - the name of the parameter
67
66
  * @property {string} type - the type of the parameter
@@ -69,7 +68,7 @@ const qsStringify = require('qs-stringify');
69
68
  * @memberOf Campaign
70
69
  */
71
70
 
72
- /**
71
+ /**
73
72
  * Java Script Proxy handler for an XTK object. An XTK object is one constructed with the following syntax:
74
73
  *
75
74
  * <code>
@@ -82,43 +81,44 @@ const qsStringify = require('qs-stringify');
82
81
  * @private
83
82
  * @memberof Campaign
84
83
  */
85
- const xtkObjectHandler = {
84
+ const xtkObjectHandler = {
86
85
  set: function(callContext, prop, value) {
87
- const object = callContext.object;
88
- object[prop] = value;
86
+ const object = callContext.object;
87
+ object[prop] = value;
88
+ return true;
89
89
  },
90
90
 
91
91
  get: function(callContext, methodName) {
92
- if (methodName == ".")
93
- return callContext;
94
- if (methodName === "__xtkProxy")
95
- return true;
96
- if (methodName === "save") {
97
- return async () => {
98
- return callContext.client.NLWS.xtkSession.write(callContext.object);
99
- };
100
- }
101
- if (methodName === "entity") {
102
- return callContext.object;
103
- }
104
-
105
- const caller = function(thisArg, argumentsList) {
106
- const callContext = thisArg["."];
107
- if (methodName == "inspect") return callContext.object;
108
- methodName = methodName.substr(0, 1).toUpperCase() + methodName.substr(1);
109
- return callContext.client._callMethod(methodName, callContext, argumentsList);
92
+ if (methodName == ".")
93
+ return callContext;
94
+ if (methodName === "__xtkProxy")
95
+ return true;
96
+ if (methodName === "save") {
97
+ return async () => {
98
+ return callContext.client.NLWS.xtkSession.write(callContext.object);
110
99
  };
100
+ }
101
+ if (methodName === "entity") {
102
+ return callContext.object;
103
+ }
111
104
 
112
- return new Proxy(caller, {
113
- apply: function(target, thisArg, argumentsList) {
114
- return target(thisArg, argumentsList);
115
- }
116
- });
105
+ const caller = function(thisArg, argumentsList) {
106
+ const callContext = thisArg["."];
107
+ if (methodName == "inspect") return callContext.object;
108
+ methodName = methodName.substr(0, 1).toUpperCase() + methodName.substr(1);
109
+ return callContext.client._callMethod(methodName, callContext, argumentsList);
110
+ };
111
+
112
+ return new Proxy(caller, {
113
+ apply: function(target, thisArg, argumentsList) {
114
+ return target(thisArg, argumentsList);
115
+ }
116
+ });
117
117
 
118
118
  }
119
- };
119
+ };
120
120
 
121
- /**
121
+ /**
122
122
  * Java Script Proxy handler for NLWS.
123
123
  * The proxy resolves constructs such as
124
124
  *
@@ -134,106 +134,106 @@ const xtkObjectHandler = {
134
134
  * @private
135
135
  * @memberof Campaign
136
136
  */
137
- const clientHandler = (representation, headers, pushDownOptions) => {
137
+ const clientHandler = (representation, headers, pushDownOptions) => {
138
138
  return {
139
- get: function(client, namespace) {
140
-
141
- // Force XML or JSON representation (NLWS.xml or NLWS.json)
142
- if (namespace == "xml") return new Proxy(client, clientHandler("xml", headers, pushDownOptions));
143
- if (namespace == "json") return new Proxy(client, clientHandler("SimpleJson", headers, pushDownOptions));
144
-
145
- // Override HTTP headers (NLWS.headers({...}))
146
- // Unlike NLWS.xml or NLWS.json, NLWS.headers returns a function. This function takes key/value
147
- // pairs of headers, and, when called, returns a proxy object which will remember the headers
148
- // and be able to pass them to subsequent SOAP call context
149
- if (namespace == "headers") return (methodHeaders) => {
150
- // Build of copy of the http headers and append new headers in order to accomodate
151
- // chained calls, such as NLWS.headers(...).headers(...)
152
- const newHeaders = {};
153
- if (headers) for (let h in headers) newHeaders[h] = headers[h];
154
- if (methodHeaders) for (let h in methodHeaders) newHeaders[h] = methodHeaders[h];
155
- return new Proxy(client, clientHandler(representation, newHeaders, pushDownOptions));
156
- };
139
+ get: function(client, namespace) {
140
+
141
+ // Force XML or JSON representation (NLWS.xml or NLWS.json)
142
+ if (namespace == "xml") return new Proxy(client, clientHandler("xml", headers, pushDownOptions));
143
+ if (namespace == "json") return new Proxy(client, clientHandler("SimpleJson", headers, pushDownOptions));
144
+
145
+ // Override HTTP headers (NLWS.headers({...}))
146
+ // Unlike NLWS.xml or NLWS.json, NLWS.headers returns a function. This function takes key/value
147
+ // pairs of headers, and, when called, returns a proxy object which will remember the headers
148
+ // and be able to pass them to subsequent SOAP call context
149
+ if (namespace == "headers") return (methodHeaders) => {
150
+ // Build of copy of the http headers and append new headers in order to accomodate
151
+ // chained calls, such as NLWS.headers(...).headers(...)
152
+ const newHeaders = {};
153
+ if (headers) for (let h in headers) newHeaders[h] = headers[h];
154
+ if (methodHeaders) for (let h in methodHeaders) newHeaders[h] = methodHeaders[h];
155
+ return new Proxy(client, clientHandler(representation, newHeaders, pushDownOptions));
156
+ };
157
157
 
158
- // Pushes down addition options to the SOAP and transport layers
159
- if (namespace == "pushDown") return (methodPushDownOptions) => {
160
- // Build of copy of the pushDownOptions in order to accomodate
161
- // chained calls, such as NLWS.pushDown(...).pushDown(...)
162
- const newPushDownOptions = {};
163
- if (pushDownOptions) for (let h in pushDownOptions) newPushDownOptions[h] = pushDownOptions[h];
164
- if (methodPushDownOptions) for (let h in methodPushDownOptions) newPushDownOptions[h] = methodPushDownOptions[h];
165
- return new Proxy(client, clientHandler(representation, headers, newPushDownOptions));
166
- };
158
+ // Pushes down addition options to the SOAP and transport layers
159
+ if (namespace == "pushDown") return (methodPushDownOptions) => {
160
+ // Build of copy of the pushDownOptions in order to accomodate
161
+ // chained calls, such as NLWS.pushDown(...).pushDown(...)
162
+ const newPushDownOptions = {};
163
+ if (pushDownOptions) for (let h in pushDownOptions) newPushDownOptions[h] = pushDownOptions[h];
164
+ if (methodPushDownOptions) for (let h in methodPushDownOptions) newPushDownOptions[h] = methodPushDownOptions[h];
165
+ return new Proxy(client, clientHandler(representation, headers, newPushDownOptions));
166
+ };
167
167
 
168
- return new Proxy({ client:client, namespace:namespace}, {
169
- get: function(callContext, methodName) {
170
- callContext.representation = representation;
171
- callContext.headers = callContext.headers || client._connectionParameters._options.extraHttpHeaders;
172
- callContext.pushDownOptions = {};
173
- if (headers) {
174
- for (let h in headers) callContext.headers[h] = headers[h];
175
- }
176
- if (pushDownOptions) {
177
- for (let h in pushDownOptions) callContext.pushDownOptions[h] = pushDownOptions[h];
178
- }
168
+ return new Proxy({ client:client, namespace:namespace}, {
169
+ get: function(callContext, methodName) {
170
+ callContext.representation = representation;
171
+ callContext.headers = callContext.headers || client._connectionParameters._options.extraHttpHeaders;
172
+ callContext.pushDownOptions = {};
173
+ if (headers) {
174
+ for (let h in headers) callContext.headers[h] = headers[h];
175
+ }
176
+ if (pushDownOptions) {
177
+ for (let h in pushDownOptions) callContext.pushDownOptions[h] = pushDownOptions[h];
178
+ }
179
179
 
180
- if (methodName == ".")
181
- return callContext;
182
-
183
- // get Schema id from namespace (find first upper case letter)
184
- callContext.schemaId = Util.schemaIdFromNamespace(namespace);
185
-
186
- const caller = function(thisArg, argumentsList) {
187
- const callContext = thisArg["."];
188
- const namespace = callContext.namespace;
189
- const methodNameLC = methodName.toLowerCase();
190
- methodName = methodName.substr(0, 1).toUpperCase() + methodName.substr(1);
191
- if (namespace == "xtkSession" && methodNameLC == "logon")
192
- return callContext.client.logon(argumentsList[0]);
193
- else if (namespace == "xtkSession" && methodNameLC == "logoff")
194
- return callContext.client.logoff();
195
- else if (namespace == "xtkSession" && methodNameLC == "getoption") {
196
- var promise = callContext.client._callMethod(methodName, callContext, argumentsList);
197
- return promise.then(function(optionAndValue) {
198
- const optionName = argumentsList[0];
199
- return client._optionCache.put(optionName, optionAndValue).then(() => optionAndValue);
200
- });
201
- }
202
- // static method
203
- var result = callContext.client._callMethod(methodName, callContext, argumentsList);
204
- return result;
205
- };
206
-
207
- if (methodName == "create") {
208
- return function(body) {
209
- callContext.object = body || {}; // supports empty bodies
210
- if (!callContext.object.xtkschema) callContext.object.xtkschema = callContext.schemaId;
211
- return new Proxy(callContext, xtkObjectHandler);
212
- };
213
- }
180
+ if (methodName == ".")
181
+ return callContext;
182
+
183
+ // get Schema id from namespace (find first upper case letter)
184
+ callContext.schemaId = Util.schemaIdFromNamespace(namespace);
185
+
186
+ const caller = function(thisArg, argumentsList) {
187
+ const callContext = thisArg["."];
188
+ const namespace = callContext.namespace;
189
+ const methodNameLC = methodName.toLowerCase();
190
+ methodName = methodName.substr(0, 1).toUpperCase() + methodName.substr(1);
191
+ if (namespace == "xtkSession" && methodNameLC == "logon")
192
+ return callContext.client.logon(argumentsList[0]);
193
+ else if (namespace == "xtkSession" && methodNameLC == "logoff")
194
+ return callContext.client.logoff();
195
+ else if (namespace == "xtkSession" && methodNameLC == "getoption") {
196
+ var promise = callContext.client._callMethod(methodName, callContext, argumentsList);
197
+ return promise.then(function(optionAndValue) {
198
+ const optionName = argumentsList[0];
199
+ return client._optionCache.put(optionName, optionAndValue).then(() => optionAndValue);
200
+ });
201
+ }
202
+ // static method
203
+ var result = callContext.client._callMethod(methodName, callContext, argumentsList);
204
+ return result;
205
+ };
214
206
 
215
- return new Proxy(caller, {
216
- apply: function(target, thisArg, argumentsList) {
217
- return target(thisArg, argumentsList);
218
- }
219
- });
220
- }
207
+ if (methodName == "create") {
208
+ return function(body) {
209
+ callContext.object = body || {}; // supports empty bodies
210
+ if (!callContext.object.xtkschema) callContext.object.xtkschema = callContext.schemaId;
211
+ return new Proxy(callContext, xtkObjectHandler);
212
+ };
213
+ }
214
+
215
+ return new Proxy(caller, {
216
+ apply: function(target, thisArg, argumentsList) {
217
+ return target(thisArg, argumentsList);
218
+ }
221
219
  });
222
- }
220
+ }
221
+ });
222
+ }
223
223
  };
224
- };
224
+ };
225
225
 
226
- // ========================================================================================
227
- // Campaign credentials
228
- // ========================================================================================
226
+ // ========================================================================================
227
+ // Campaign credentials
228
+ // ========================================================================================
229
229
 
230
- /**
230
+ /**
231
231
  * @class
232
232
  * @constructor
233
233
  * @private
234
234
  * @memberof Campaign
235
235
  */
236
- class Credentials {
236
+ class Credentials {
237
237
 
238
238
  /**
239
239
  * Credentials to a Campaign instance. Encapsulates the various types of credentials.
@@ -243,16 +243,16 @@ class Credentials {
243
243
  * @param {string} securityToken the security token. Will use an empty token if not specified
244
244
  */
245
245
  constructor(type, sessionToken, securityToken) {
246
- if (type != "UserPassword" && type != "ImsServiceToken" && type != "SessionToken" && type != "SessionAndSecurityToken" &&
246
+ if (type != "UserPassword" && type != "ImsServiceToken" && type != "SessionToken" && type != "SessionAndSecurityToken" &&
247
247
  type != "AnonymousUser" && type != "SecurityToken" && type != "BearerToken" && type != "ImsBearerToken")
248
- throw CampaignException.INVALID_CREDENTIALS_TYPE(type);
249
- this._type = type;
250
- this._sessionToken = sessionToken || "";
251
- this._securityToken = securityToken || "";
252
- if (type == "BearerToken" || type === "ImsBearerToken") {
253
- this._bearerToken = sessionToken || "";
254
- this._sessionToken = "";
255
- }
248
+ throw CampaignException.INVALID_CREDENTIALS_TYPE(type);
249
+ this._type = type;
250
+ this._sessionToken = sessionToken || "";
251
+ this._securityToken = securityToken || "";
252
+ if (type == "BearerToken" || type === "ImsBearerToken") {
253
+ this._bearerToken = sessionToken || "";
254
+ this._sessionToken = "";
255
+ }
256
256
  }
257
257
 
258
258
  /**
@@ -262,11 +262,11 @@ class Credentials {
262
262
  * @returns {string} the user name
263
263
  */
264
264
  _getUser() {
265
- if (this._type != "UserPassword")
266
- throw CampaignException.CANNOT_GET_CREDENTIALS_USER(this._type);
267
- const tokens = this._sessionToken.split("/");
268
- const user = tokens[0];
269
- return user;
265
+ if (this._type != "UserPassword")
266
+ throw CampaignException.CANNOT_GET_CREDENTIALS_USER(this._type);
267
+ const tokens = this._sessionToken.split("/");
268
+ const user = tokens[0];
269
+ return user;
270
270
  }
271
271
 
272
272
  /**
@@ -276,20 +276,20 @@ class Credentials {
276
276
  * @returns {string} the user password
277
277
  */
278
278
  _getPassword() {
279
- if (this._type != "UserPassword")
280
- throw CampaignException.CANNOT_GET_CREDENTIALS_PASSWORD(this._type);
281
- const tokens = this._sessionToken.split("/");
282
- const password = tokens.length > 1 ? tokens[1] : "";
283
- return password;
279
+ if (this._type != "UserPassword")
280
+ throw CampaignException.CANNOT_GET_CREDENTIALS_PASSWORD(this._type);
281
+ const tokens = this._sessionToken.split("/");
282
+ const password = tokens.length > 1 ? tokens[1] : "";
283
+ return password;
284
284
  }
285
- }
285
+ }
286
286
 
287
287
 
288
- // ========================================================================================
289
- // Campaign connection parameters
290
- // ========================================================================================
288
+ // ========================================================================================
289
+ // Campaign connection parameters
290
+ // ========================================================================================
291
291
 
292
- /**
292
+ /**
293
293
  * @typedef {Object} ConnectionOptions
294
294
  * @property {string} representation - the representation to use, i.e. "SimpleJson" (the default), "BadgerFish", or "xml"
295
295
  * @property {boolean} rememberMe - The Campaign `rememberMe` attribute which can be used to extend the lifetime of session tokens
@@ -314,12 +314,12 @@ class Credentials {
314
314
  */
315
315
 
316
316
 
317
- /**
317
+ /**
318
318
  * @class
319
319
  * @constructor
320
320
  * @memberof Campaign
321
321
  */
322
- class ConnectionParameters {
322
+ class ConnectionParameters {
323
323
 
324
324
  /**
325
325
  * Creates a connection parameters object which can be used to create a Client object
@@ -329,59 +329,59 @@ class ConnectionParameters {
329
329
  * @param {Campaign.ConnectionOptions} options connection options
330
330
  */
331
331
  constructor(endpoint, credentials, options) {
332
- // this._options will be populated with the data from "options" and with
333
- // default values. But the "options" parameter will not be modified
334
- this._options = Object.assign({}, options);
332
+ // this._options will be populated with the data from "options" and with
333
+ // default values. But the "options" parameter will not be modified
334
+ this._options = Object.assign({}, options);
335
335
 
336
- // Default value
337
- if (options === undefined || options === null)
338
- options = { };
336
+ // Default value
337
+ if (options === undefined || options === null)
338
+ options = { };
339
339
  // Before version 1.0.0, the 4th parameter could be a boolean for the 'rememberMe' option.
340
340
  // Passing a boolean is not supported any more in 1.0.0. The Client constructor takes an
341
341
  // option object. The rememberMe parameter can be passed directly to the logon function
342
- if (typeof options != "object")
343
- throw CampaignException.INVALID_CONNECTION_OPTIONS(options);
344
-
345
- this._options.representation = options.representation;
346
- if (this._options.representation === undefined || this._options.representation === null)
347
- this._options.representation = "SimpleJson";
348
-
349
- if (this._options.representation != "xml" && this._options.representation != "BadgerFish" && this._options.representation != "SimpleJson")
350
- throw CampaignException.INVALID_REPRESENTATION(this._options.representation, "Cannot create Campaign client");
351
-
352
- // Defaults for rememberMe
353
- this._options.rememberMe = !!options.rememberMe;
354
-
355
- this._options.entityCacheTTL = options.entityCacheTTL || 1000*300; // 5 mins
356
- this._options.methodCacheTTL = options.methodCacheTTL || 1000*300; // 5 mins
357
- this._options.optionCacheTTL = options.optionCacheTTL || 1000*300; // 5 mins
358
- this._options.traceAPICalls = options.traceAPICalls === null || options.traceAPICalls ? !!options.traceAPICalls : false;
359
- this._options.transport = options.transport || request;
360
-
361
- this._endpoint = endpoint;
362
- this._credentials = credentials;
363
-
364
- var storage;
365
- if (!options.noStorage) {
366
- storage = options.storage;
367
- try {
368
- if (!storage)
369
- storage = localStorage;
370
- } catch (ex) {
371
- /* ignore error if localStorage not found */
372
- }
373
- }
374
- this._options._storage = storage;
375
- this._options.refreshClient = options.refreshClient;
376
- this._options.charset = options.charset === undefined ? "UTF-8": options.charset;
377
- this._options.extraHttpHeaders = {};
378
- if (options.extraHttpHeaders) {
379
- for (let h in options.extraHttpHeaders) this._options.extraHttpHeaders[h] = options.extraHttpHeaders[h];
342
+ if (typeof options != "object")
343
+ throw CampaignException.INVALID_CONNECTION_OPTIONS(options);
344
+
345
+ this._options.representation = options.representation;
346
+ if (this._options.representation === undefined || this._options.representation === null)
347
+ this._options.representation = "SimpleJson";
348
+
349
+ if (this._options.representation != "xml" && this._options.representation != "BadgerFish" && this._options.representation != "SimpleJson")
350
+ throw CampaignException.INVALID_REPRESENTATION(this._options.representation, "Cannot create Campaign client");
351
+
352
+ // Defaults for rememberMe
353
+ this._options.rememberMe = !!options.rememberMe;
354
+
355
+ this._options.entityCacheTTL = options.entityCacheTTL || 1000*300; // 5 mins
356
+ this._options.methodCacheTTL = options.methodCacheTTL || 1000*300; // 5 mins
357
+ this._options.optionCacheTTL = options.optionCacheTTL || 1000*300; // 5 mins
358
+ this._options.traceAPICalls = options.traceAPICalls === null || options.traceAPICalls ? !!options.traceAPICalls : false;
359
+ this._options.transport = options.transport || request;
360
+
361
+ this._endpoint = endpoint;
362
+ this._credentials = credentials;
363
+
364
+ var storage;
365
+ if (!options.noStorage) {
366
+ storage = options.storage;
367
+ try {
368
+ if (!storage)
369
+ storage = localStorage;
370
+ } catch (ex) {
371
+ /* ignore error if localStorage not found */
380
372
  }
381
- this._options.clientApp = options.clientApp;
382
- this._options.noSDKHeaders = !!options.noSDKHeaders;
383
- this._options.noMethodInURL = !!options.noMethodInURL;
384
- this._options.cacheRootKey = options.cacheRootKey === undefined ? "default": options.cacheRootKey;
373
+ }
374
+ this._options._storage = storage;
375
+ this._options.refreshClient = options.refreshClient;
376
+ this._options.charset = options.charset === undefined ? "UTF-8": options.charset;
377
+ this._options.extraHttpHeaders = {};
378
+ if (options.extraHttpHeaders) {
379
+ for (let h in options.extraHttpHeaders) this._options.extraHttpHeaders[h] = options.extraHttpHeaders[h];
380
+ }
381
+ this._options.clientApp = options.clientApp;
382
+ this._options.noSDKHeaders = !!options.noSDKHeaders;
383
+ this._options.noMethodInURL = !!options.noMethodInURL;
384
+ this._options.cacheRootKey = options.cacheRootKey === undefined ? "default": options.cacheRootKey;
385
385
  }
386
386
 
387
387
  /**
@@ -394,8 +394,8 @@ class ConnectionParameters {
394
394
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
395
395
  */
396
396
  static ofUserAndPassword(endpoint, user, password, options) {
397
- const credentials = new Credentials("UserPassword", `${user}/${password}`, "");
398
- return new ConnectionParameters(endpoint, credentials, options);
397
+ const credentials = new Credentials("UserPassword", `${user}/${password}`, "");
398
+ return new ConnectionParameters(endpoint, credentials, options);
399
399
  }
400
400
 
401
401
  /**
@@ -412,8 +412,8 @@ class ConnectionParameters {
412
412
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
413
413
  */
414
414
  static ofBearerToken(endpoint, bearerToken, options) {
415
- const credentials = new Credentials("BearerToken", bearerToken);
416
- return new ConnectionParameters(endpoint, credentials, options);
415
+ const credentials = new Credentials("BearerToken", bearerToken);
416
+ return new ConnectionParameters(endpoint, credentials, options);
417
417
  }
418
418
 
419
419
  /**
@@ -428,8 +428,8 @@ class ConnectionParameters {
428
428
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
429
429
  */
430
430
  static ofImsBearerToken(endpoint, bearerToken, options) {
431
- const credentials = new Credentials("ImsBearerToken", bearerToken);
432
- return new ConnectionParameters(endpoint, credentials, options);
431
+ const credentials = new Credentials("ImsBearerToken", bearerToken);
432
+ return new ConnectionParameters(endpoint, credentials, options);
433
433
  }
434
434
 
435
435
  /**
@@ -442,8 +442,8 @@ class ConnectionParameters {
442
442
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
443
443
  */
444
444
  static ofUserAndServiceToken(endpoint, user, serviceToken, options) {
445
- const credentials = new Credentials("ImsServiceToken", `_ims_/${user}/${serviceToken}`, "");
446
- return new ConnectionParameters(endpoint, credentials, options);
445
+ const credentials = new Credentials("ImsServiceToken", `_ims_/${user}/${serviceToken}`, "");
446
+ return new ConnectionParameters(endpoint, credentials, options);
447
447
  }
448
448
 
449
449
  /**
@@ -456,8 +456,8 @@ class ConnectionParameters {
456
456
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
457
457
  */
458
458
  static ofSessionToken(endpoint, sessionToken, options) {
459
- const credentials = new Credentials("SessionToken", sessionToken, "");
460
- return new ConnectionParameters(endpoint, credentials, options);
459
+ const credentials = new Credentials("SessionToken", sessionToken, "");
460
+ return new ConnectionParameters(endpoint, credentials, options);
461
461
  }
462
462
 
463
463
  /**
@@ -471,8 +471,8 @@ class ConnectionParameters {
471
471
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
472
472
  */
473
473
  static ofSessionAndSecurityToken(endpoint, sessionToken, securityToken, options) {
474
- const credentials = new Credentials("SessionAndSecurityToken", sessionToken, securityToken);
475
- return new ConnectionParameters(endpoint, credentials, options);
474
+ const credentials = new Credentials("SessionAndSecurityToken", sessionToken, securityToken);
475
+ return new ConnectionParameters(endpoint, credentials, options);
476
476
  }
477
477
 
478
478
  /**
@@ -488,8 +488,8 @@ class ConnectionParameters {
488
488
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
489
489
  */
490
490
  static ofSecurityToken(endpoint, securityToken, options) {
491
- const credentials = new Credentials("SecurityToken", "", securityToken);
492
- return new ConnectionParameters(endpoint, credentials, options);
491
+ const credentials = new Credentials("SecurityToken", "", securityToken);
492
+ return new ConnectionParameters(endpoint, credentials, options);
493
493
  }
494
494
 
495
495
  /**
@@ -500,8 +500,8 @@ class ConnectionParameters {
500
500
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
501
501
  */
502
502
  static ofAnonymousUser(endpoint, options) {
503
- const credentials = new Credentials("AnonymousUser", "", "");
504
- return new ConnectionParameters(endpoint, credentials, options);
503
+ const credentials = new Credentials("AnonymousUser", "", "");
504
+ return new ConnectionParameters(endpoint, credentials, options);
505
505
  }
506
506
 
507
507
 
@@ -515,58 +515,58 @@ class ConnectionParameters {
515
515
  * @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
516
516
  */
517
517
  static async ofExternalAccount(client, extAccountName) {
518
- var queryDef = {
519
- "schema": "nms:extAccount",
520
- "operation": "get",
521
- "select": {
522
- "node": [
523
- { "expr": "@id" },
524
- { "expr": "@name" },
525
- { "expr": "@label" },
526
- { "expr": "@type" },
527
- { "expr": "@account" },
528
- { "expr": "@password" },
529
- { "expr": "@server" }
530
- ]
531
- },
532
- "where": {
533
- "condition": [
534
- { "expr": client.sdk.escapeXtk`@name=${extAccountName}` },
535
- { "expr": "@type=3" }
536
- ]
537
- }
538
- };
539
- // Convert to current representation
540
- queryDef = client._convertToRepresentation(queryDef, "SimpleJson");
541
- const query = client.NLWS.xtkQueryDef.create(queryDef);
542
- const extAccount = await query.executeQuery();
543
-
544
- const cipher = await client._getSecretKeyCipher();
545
- const type = EntityAccessor.getAttributeAsLong(extAccount, "type");
546
- if (type == 3) {
547
- // Mid-souring
548
- const endpoint = EntityAccessor.getAttributeAsString(extAccount, "server");
549
- const user = EntityAccessor.getAttributeAsString(extAccount, "account");
550
- const password = cipher.decryptPassword(EntityAccessor.getAttributeAsString(extAccount, "password"));
551
- return ConnectionParameters.ofUserAndPassword(endpoint, user, password, client._connectionParameters._options);
518
+ var queryDef = {
519
+ "schema": "nms:extAccount",
520
+ "operation": "get",
521
+ "select": {
522
+ "node": [
523
+ { "expr": "@id" },
524
+ { "expr": "@name" },
525
+ { "expr": "@label" },
526
+ { "expr": "@type" },
527
+ { "expr": "@account" },
528
+ { "expr": "@password" },
529
+ { "expr": "@server" }
530
+ ]
531
+ },
532
+ "where": {
533
+ "condition": [
534
+ { "expr": client.sdk.escapeXtk`@name=${extAccountName}` },
535
+ { "expr": "@type=3" }
536
+ ]
552
537
  }
553
- throw CampaignException.CREDENTIALS_FOR_INVALID_EXT_ACCOUNT(extAccountName, type);
538
+ };
539
+ // Convert to current representation
540
+ queryDef = client._convertToRepresentation(queryDef, "SimpleJson");
541
+ const query = client.NLWS.xtkQueryDef.create(queryDef);
542
+ const extAccount = await query.executeQuery();
543
+
544
+ const cipher = await client._getSecretKeyCipher();
545
+ const type = EntityAccessor.getAttributeAsLong(extAccount, "type");
546
+ if (type == 3) {
547
+ // Mid-souring
548
+ const endpoint = EntityAccessor.getAttributeAsString(extAccount, "server");
549
+ const user = EntityAccessor.getAttributeAsString(extAccount, "account");
550
+ const password = cipher.decryptPassword(EntityAccessor.getAttributeAsString(extAccount, "password"));
551
+ return ConnectionParameters.ofUserAndPassword(endpoint, user, password, client._connectionParameters._options);
552
+ }
553
+ throw CampaignException.CREDENTIALS_FOR_INVALID_EXT_ACCOUNT(extAccountName, type);
554
554
  }
555
555
 
556
- }
556
+ }
557
557
 
558
- // ========================================================================================
559
- // File Uploader
560
- // ========================================================================================
558
+ // ========================================================================================
559
+ // File Uploader
560
+ // ========================================================================================
561
561
 
562
- /**
562
+ /**
563
563
  * @typedef {Object} FileUploadOptions
564
564
  * @property {"publishIfNeeded"|"none"|undefined} the post-processing action to execute. Defaults to "publishIfNeeded"
565
565
  * @memberOf Campaign
566
566
  */
567
567
 
568
568
 
569
- /**
569
+ /**
570
570
  * File Uploader API for JS SDK(Currently available only in browsers)
571
571
  * @private
572
572
  * @ignore
@@ -574,172 +574,174 @@ class ConnectionParameters {
574
574
  * @param client
575
575
  * @returns {{upload: (function(*=): Promise<{name: string, md5: string, type: string, size: string, url: string}>)}}
576
576
  */
577
- const fileUploader = (client) => {
577
+ const fileUploader = (client) => {
578
578
 
579
579
  return {
580
- /**
580
+ /**
581
581
  * This is the exposed/public method for fileUploader instance which will do all the processing related to the upload process internally and returns the promise containing all the required data.
582
582
  * @ignore
583
583
  * @param file, where file is an instance of [File](https://developer.mozilla.org/en-US/docs/Web/API/File)
584
584
  * @param {FileUploadOptions|undefined} options
585
585
  * @returns {Promise<{name: string, md5: string, type: string, size: string, url: string}>}
586
586
  */
587
- upload: (file, options, fileResPrefix) => {
588
- console.log(`fileuploader.upload is an experimental feature and is not currently fully functional. It is work in progress and will change in the future.`);
589
- return new Promise((resolve, reject) => {
590
- const action = (options && options.action) ? options.action : "publishIfNeeded";
591
- if (action !== "publishIfNeeded" && action !== "none")
592
- reject(CampaignException.BAD_PARAMETER("action", action, "The 'action' parameter of the upload API should be 'publishIfNeeded' or 'none'"));
593
- try {
594
- if (!Util.isBrowser()) {
595
- throw 'File uploading is only supported in browser based calls.';
596
- }
597
- const data = new FormData();
598
- data.append('file_noMd5', file);
599
- const headers = client._getAuthHeaders(false);
600
- for (let h in client._connectionParameters._options.extraHttpHeaders)
601
- headers[h] = client._connectionParameters._options.extraHttpHeaders[h];
602
- client._makeHttpCall({
603
- url: `${client._connectionParameters._endpoint}/nl/jsp/uploadFile.jsp`,
604
- processData: false,
605
- method: 'POST',
606
- data: data,
607
- headers: headers
608
- }).then((okay) => {
609
- if (!okay.startsWith('Ok')) {
610
- throw okay;
611
- }
612
- const iframe = document.createElement('iframe');
613
- iframe.style.display = 'block';
614
- iframe.style.border = 'none';
615
- iframe.style.height = 0;
616
- iframe.style.width = 0;
617
- if(options && options.className) {
618
- iframe.className = options.className;
587
+ upload: (file, options, fileResPrefix) => {
588
+ if (client._traceAPICalls) {
589
+ console.warn(`fileuploader.upload is an experimental feature and is not currently fully functional. It is work in progress and will change in the future.`);
590
+ }
591
+ return new Promise((resolve, reject) => {
592
+ const action = (options && options.action) ? options.action : "publishIfNeeded";
593
+ if (action !== "publishIfNeeded" && action !== "none")
594
+ reject(CampaignException.BAD_PARAMETER("action", action, "The 'action' parameter of the upload API should be 'publishIfNeeded' or 'none'"));
595
+ try {
596
+ if (!Util.isBrowser()) {
597
+ throw 'File uploading is only supported in browser based calls.';
598
+ }
599
+ const data = new FormData();
600
+ data.append('file_noMd5', file);
601
+ const headers = client._getAuthHeaders(false);
602
+ for (let h in client._connectionParameters._options.extraHttpHeaders)
603
+ headers[h] = client._connectionParameters._options.extraHttpHeaders[h];
604
+ client._makeHttpCall({
605
+ url: `${client._connectionParameters._endpoint}/nl/jsp/uploadFile.jsp`,
606
+ processData: false,
607
+ method: 'POST',
608
+ data: data,
609
+ headers: headers
610
+ }).then((okay) => {
611
+ if (!okay.startsWith('Ok')) {
612
+ throw okay;
613
+ }
614
+ const iframe = document.createElement('iframe');
615
+ iframe.style.display = 'block';
616
+ iframe.style.border = 'none';
617
+ iframe.style.height = 0;
618
+ iframe.style.width = 0;
619
+ if(options && options.className) {
620
+ iframe.className = options.className;
621
+ }
622
+ document.controller = { // Written to support https://git.corp.adobe.com/Campaign/ac/blob/v6-master/nl/datakit/nl/jsp/uploadFile.jsp
623
+ uploadFileCallBack: async (data) => {
624
+ if (!data || data.length !== 1) {
625
+ // Tried to replicate the logic for file upload functionality written here:
626
+ // https://git.corp.adobe.com/Campaign/ac/blob/v6-master/wpp/xtk/web/dce/uploader.js
627
+ return reject(CampaignException.FILE_UPLOAD_FAILED(file.name, 'Malformed data:' + data.toString()));
628
+ }
629
+ const result = {
630
+ name: data[0].fileName,
631
+ md5: data[0].md5,
632
+ type: file.type,
633
+ size: file.size,
634
+ };
635
+ if (action === "publishIfNeeded") {
636
+ try {
637
+ // Following https://jira.corp.adobe.com/browse/NEO-88828 the fileRes internal name is defined as is:
638
+ // If a prefix is not provided, we keep the old behavior which is to use the prefix 'RES' and the xtkResource counter (i.e.'RES1'...)
639
+ // If a prefix is provided, we use it with a UUID (i.e. 'customPrefix-123e4567-e89b-12d3-a456-426614174000')
640
+ const oldBehaviorPrefix = 'RES';
641
+ const prefix = Util.validateFileResPrefix(fileResPrefix, oldBehaviorPrefix);
642
+ const getUUIDOrFallback = async() => {
643
+ try {
644
+ return Util.getUUID();
645
+ } catch (error) {
646
+ // In case getUUID throws, fall back to increasing the counter
647
+ return await client.NLWS.xtkCounter.increaseValue({ name: 'xtkResource' });
619
648
  }
620
- document.controller = { // Written to support https://git.corp.adobe.com/Campaign/ac/blob/v6-master/nl/datakit/nl/jsp/uploadFile.jsp
621
- uploadFileCallBack: async (data) => {
622
- if (!data || data.length !== 1) {
623
- // Tried to replicate the logic for file upload functionality written here:
624
- // https://git.corp.adobe.com/Campaign/ac/blob/v6-master/wpp/xtk/web/dce/uploader.js
625
- return reject(CampaignException.FILE_UPLOAD_FAILED(file.name, 'Malformed data:' + data.toString()));
626
- }
627
- const result = {
628
- name: data[0].fileName,
629
- md5: data[0].md5,
630
- type: file.type,
631
- size: file.size,
632
- };
633
- if (action === "publishIfNeeded") {
634
- try {
635
- // Following https://jira.corp.adobe.com/browse/NEO-88828 the fileRes internal name is defined as is:
636
- // If a prefix is not provided, we keep the old behavior which is to use the prefix 'RES' and the xtkResource counter (i.e.'RES1'...)
637
- // If a prefix is provided, we use it with a UUID (i.e. 'customPrefix-123e4567-e89b-12d3-a456-426614174000')
638
- const oldBehaviorPrefix = 'RES';
639
- const prefix = Util.validateFileResPrefix(fileResPrefix, oldBehaviorPrefix);
640
- const getUUIDOrFallback = async() => {
641
- try {
642
- return Util.getUUID();
643
- } catch (error) {
644
- // In case getUUID throws, fall back to increasing the counter
645
- return await client.NLWS.xtkCounter.increaseValue({ name: 'xtkResource' });
646
- }
647
- };
648
- const suffix = (prefix === oldBehaviorPrefix) ?
649
- await client.NLWS.xtkCounter.increaseValue({ name: 'xtkResource' }) : await getUUIDOrFallback();
650
-
651
- const internalName = (prefix === oldBehaviorPrefix) ? `${prefix}${suffix}` : `${prefix}_${suffix}`;
652
-
653
- const fileRes = {
654
- internalName,
655
- md5: data[0].md5,
656
- label: data[0].fileName,
657
- fileName: data[0].fileName,
658
- originalName: data[0].fileName,
659
- useMd5AsFilename: '1',
660
- storageType: 5,
661
- xtkschema: 'xtk:fileRes',
662
- };
663
- await client.NLWS.xtkSession.write(fileRes);
664
- await client.NLWS.xtkFileRes
665
- .create(fileRes)
666
- .publishIfNeeded();
667
- const url = await client.NLWS.xtkFileRes
668
- .create(fileRes)
669
- .getURL();
670
- result.url = url;
671
- } catch (ex) {
672
- reject(
673
- CampaignException.FILE_UPLOAD_FAILED(
674
- file.name,
675
- ex
676
- )
677
- );
678
- }
679
- }
680
- resolve(result);
681
- }
682
- };
683
- const html = `<body>${okay}</body>`;
684
- document.body.appendChild(iframe);
685
- iframe.contentWindow.document.open();
686
- iframe.contentWindow.document.write(html);
687
- iframe.contentWindow.document.close();
688
- }).catch((ex) => {
689
- reject(CampaignException.FILE_UPLOAD_FAILED(file.name, ex));
690
- });
691
- } catch (ex) {
692
- reject(CampaignException.FILE_UPLOAD_FAILED(file.name, ex));
649
+ };
650
+ const suffix = (prefix === oldBehaviorPrefix) ?
651
+ await client.NLWS.xtkCounter.increaseValue({ name: 'xtkResource' }) : await getUUIDOrFallback();
652
+
653
+ const internalName = (prefix === oldBehaviorPrefix) ? `${prefix}${suffix}` : `${prefix}_${suffix}`;
654
+
655
+ const fileRes = {
656
+ internalName,
657
+ md5: data[0].md5,
658
+ label: data[0].fileName,
659
+ fileName: data[0].fileName,
660
+ originalName: data[0].fileName,
661
+ useMd5AsFilename: '1',
662
+ storageType: 5,
663
+ xtkschema: 'xtk:fileRes',
664
+ };
665
+ await client.NLWS.xtkSession.write(fileRes);
666
+ await client.NLWS.xtkFileRes
667
+ .create(fileRes)
668
+ .publishIfNeeded();
669
+ const url = await client.NLWS.xtkFileRes
670
+ .create(fileRes)
671
+ .getURL();
672
+ result.url = url;
673
+ } catch (ex) {
674
+ reject(
675
+ CampaignException.FILE_UPLOAD_FAILED(
676
+ file.name,
677
+ ex
678
+ )
679
+ );
680
+ }
681
+ }
682
+ resolve(result);
693
683
  }
684
+ };
685
+ const html = `<body>${okay}</body>`;
686
+ document.body.appendChild(iframe);
687
+ iframe.contentWindow.document.open();
688
+ iframe.contentWindow.document.write(html);
689
+ iframe.contentWindow.document.close();
690
+ }).catch((ex) => {
691
+ reject(CampaignException.FILE_UPLOAD_FAILED(file.name, ex));
694
692
  });
695
- },
693
+ } catch (ex) {
694
+ reject(CampaignException.FILE_UPLOAD_FAILED(file.name, ex));
695
+ }
696
+ });
697
+ },
696
698
 
697
- /**
699
+ /**
698
700
  * Exposed method to call aemAssetDownload.jssp which will
699
701
  * download the asset from AEM and upload it to Campaign.
700
702
  */
701
- uploadAemAsset: async (assetDownloadUrl) => {
702
- const url = `${client._connectionParameters._endpoint}/nms/aemAssetDownload.jssp`;
703
- const headers = client._getAuthHeaders(false);
704
- headers['Content-Type'] = 'application/json';
705
-
706
- try {
707
- // We need to pass the Authorization header to AEM to download the asset from AEM
708
- // as well as authenticating campaign server.
709
- // A user token having access to campaign as well as AEM is required
710
- if(headers['Authorization'] === undefined || headers['Authorization'] === '' || headers['Authorization'] === 'null') {
711
- throw 'Bearer token is missing';
712
- }
713
- // Serialize json data (required for fetch)
714
- const jsonData = JSON.stringify({
715
- 'assetDownloadUrl': assetDownloadUrl
716
- });
717
- for (let h in client._connectionParameters._options.extraHttpHeaders)
718
- headers[h] = client._connectionParameters._options.extraHttpHeaders[h];
719
- var response = await client._makeHttpCall({
720
- url: url,
721
- method: 'POST',
722
- data: jsonData,
723
- headers: headers
724
- });
703
+ uploadAemAsset: async (assetDownloadUrl) => {
704
+ const url = `${client._connectionParameters._endpoint}/nms/aemAssetDownload.jssp`;
705
+ const headers = client._getAuthHeaders(false);
706
+ headers['Content-Type'] = 'application/json';
725
707
 
726
- // response is returned as string when using fetch(in browser)
727
- // & returned as json using axios(nodejs).
728
- if(typeof response === 'string')
729
- response = JSON.parse(response);
730
- if(response.publishedURL)
731
- return response;
732
- else
733
- throw 'Publishing failed';
734
- } catch (ex) {
735
- if(ex instanceof CampaignException)
736
- throw CampaignException.AEM_ASSET_UPLOAD_FAILED(ex.faultString, ex.statusCode);
737
- else
738
- throw CampaignException.AEM_ASSET_UPLOAD_FAILED(ex, ex.statusCode);
739
- }
740
- },
708
+ try {
709
+ // We need to pass the Authorization header to AEM to download the asset from AEM
710
+ // as well as authenticating campaign server.
711
+ // A user token having access to campaign as well as AEM is required
712
+ if(headers['Authorization'] === undefined || headers['Authorization'] === '' || headers['Authorization'] === 'null') {
713
+ throw 'Bearer token is missing';
714
+ }
715
+ // Serialize json data (required for fetch)
716
+ const jsonData = JSON.stringify({
717
+ 'assetDownloadUrl': assetDownloadUrl
718
+ });
719
+ for (let h in client._connectionParameters._options.extraHttpHeaders)
720
+ headers[h] = client._connectionParameters._options.extraHttpHeaders[h];
721
+ var response = await client._makeHttpCall({
722
+ url: url,
723
+ method: 'POST',
724
+ data: jsonData,
725
+ headers: headers
726
+ });
727
+
728
+ // response is returned as string when using fetch(in browser)
729
+ // & returned as json using axios(nodejs).
730
+ if(typeof response === 'string')
731
+ response = JSON.parse(response);
732
+ if(response.publishedURL)
733
+ return response;
734
+ else
735
+ throw 'Publishing failed';
736
+ } catch (ex) {
737
+ if(ex instanceof CampaignException)
738
+ throw CampaignException.AEM_ASSET_UPLOAD_FAILED(ex.faultString, ex.statusCode);
739
+ else
740
+ throw CampaignException.AEM_ASSET_UPLOAD_FAILED(ex, ex.statusCode);
741
+ }
742
+ },
741
743
 
742
- /**
744
+ /**
743
745
  * Exposed public method of the fileUploader api,
744
746
  * specifically designed to download files from the 'upload' folder of the Campaign instance
745
747
  * @param {string} md5 md5 of the file content
@@ -751,64 +753,64 @@ const fileUploader = (client) => {
751
753
  * handle this file) expl : image/png, text/plain;charset=ISO-8859-1
752
754
  * @returns {Promise<File(string)>}
753
755
  */
754
- download: async (md5, ext, options) => {
755
- if (!md5 || typeof md5 !== 'string') {
756
- throw CampaignException.BAD_PARAMETER(
757
- "md5",
758
- md5,
759
- "'md5' is mandatory parameter with type as 'string' for download file."
760
- );
761
- }
756
+ download: async (md5, ext, options) => {
757
+ if (!md5 || typeof md5 !== 'string') {
758
+ throw CampaignException.BAD_PARAMETER(
759
+ "md5",
760
+ md5,
761
+ "'md5' is mandatory parameter with type as 'string' for download file."
762
+ );
763
+ }
762
764
 
763
- if (!ext || typeof ext !== "string") {
764
- throw CampaignException.BAD_PARAMETER(
765
- "ext",
766
- ext,
767
- "'ext' is mandatory parameter with type as 'string' for download file."
768
- );
769
- }
765
+ if (!ext || typeof ext !== "string") {
766
+ throw CampaignException.BAD_PARAMETER(
767
+ "ext",
768
+ ext,
769
+ "'ext' is mandatory parameter with type as 'string' for download file."
770
+ );
771
+ }
770
772
 
771
- try {
772
- const fileName =
773
+ try {
774
+ const fileName =
773
775
  options && options.fileName ? options.fileName : md5;
774
- const contentType =
776
+ const contentType =
775
777
  options && options.contentType ? options.contentType : "";
776
778
 
777
- let queryString = `md5=${encodeURIComponent(md5)}&ext=${encodeURIComponent(ext)}&fileName=${encodeURIComponent(fileName)}`;
779
+ let queryString = `md5=${encodeURIComponent(md5)}&ext=${encodeURIComponent(ext)}&fileName=${encodeURIComponent(fileName)}`;
778
780
 
779
- if (contentType) {
780
- queryString += `&contentType=${encodeURIComponent(contentType)}`;
781
- }
781
+ if (contentType) {
782
+ queryString += `&contentType=${encodeURIComponent(contentType)}`;
783
+ }
782
784
 
783
- const headers = client._getAuthHeaders(false);
784
- for (let h in client._connectionParameters._options.extraHttpHeaders)
785
- headers[h] = client._connectionParameters._options.extraHttpHeaders[h];
786
- const rawFileResponse = await client._makeHttpCall({
787
- url: `${client._connectionParameters._endpoint}/nl/jsp/downloadFile.jsp?${queryString}`,
788
- headers: headers,
789
- });
785
+ const headers = client._getAuthHeaders(false);
786
+ for (let h in client._connectionParameters._options.extraHttpHeaders)
787
+ headers[h] = client._connectionParameters._options.extraHttpHeaders[h];
788
+ const rawFileResponse = await client._makeHttpCall({
789
+ url: `${client._connectionParameters._endpoint}/nl/jsp/downloadFile.jsp?${queryString}`,
790
+ headers: headers,
791
+ });
790
792
 
791
- return rawFileResponse;
792
- } catch (ex) {
793
- throw CampaignException.FILE_DOWNLOAD_FAILED(md5, ex);
794
- }
793
+ return rawFileResponse;
794
+ } catch (ex) {
795
+ throw CampaignException.FILE_DOWNLOAD_FAILED(md5, ex);
795
796
  }
797
+ }
796
798
 
797
799
  };
798
- };
800
+ };
799
801
 
800
802
 
801
- // ========================================================================================
802
- // ACC Client
803
- // ========================================================================================
803
+ // ========================================================================================
804
+ // ACC Client
805
+ // ========================================================================================
804
806
 
805
- /**
807
+ /**
806
808
  * @private
807
809
  * @class
808
810
  * @constructor
809
811
  * @memberof Campaign
810
812
  */
811
- class Client {
813
+ class Client {
812
814
 
813
815
  /**
814
816
  * ACC API Client.
@@ -818,11 +820,11 @@ class Client {
818
820
  * @param {Campaign.ConnectionParameters} user user name, for instance admin
819
821
  */
820
822
  constructor(sdk, connectionParameters) {
821
- this.sdk = sdk;
822
- this.reinit(connectionParameters);
823
+ this.sdk = sdk;
824
+ this.reinit(connectionParameters);
823
825
 
824
- this._observers = [];
825
- this._cacheChangeListeners = [];
826
+ this._observers = [];
827
+ this._cacheChangeListeners = [];
826
828
  }
827
829
 
828
830
  /**
@@ -833,91 +835,91 @@ class Client {
833
835
  * @param {Campaign.ConnectionParameters} user user name, for instance admin
834
836
  */
835
837
  reinit(connectionParameters) {
836
- this._connectionParameters = connectionParameters; // ## TODO security concern (password kept in memory)
837
- this._representation = connectionParameters._options.representation;
838
-
839
- this._sessionInfo = undefined;
840
- this._sessionToken = undefined;
841
- this._securityToken = undefined;
842
- this._bearerToken = undefined; // set when using Bearer authentication and "ImsBearer" credential type
843
- this._installedPackages = {}; // package set (key and value = package id, ex: "nms:amp")
844
-
845
- this._secretKeyCipher = undefined;
846
-
847
- this._storage = connectionParameters._options._storage;
848
-
849
- var instanceKey = connectionParameters._options.instanceKey;
850
- if (!instanceKey)
851
- instanceKey = connectionParameters._endpoint || "";
852
- if (instanceKey.startsWith("http://")) instanceKey = instanceKey.substr(7);
853
- if (instanceKey.startsWith("https://")) instanceKey = instanceKey.substr(8);
854
-
855
- // Determine the cache root key. There are 3 possible values:
856
- // * no value or "default" is the default behavior, i.e. all cache keys are prefixed with "acc.js.sdk.${sdk.getSDKVersion().version}.${instanceKey}.cache."
857
- // * "none" (or actually anything else for now), where cache keys are not prefixed by anything
858
- const rootKeyType = connectionParameters._options.cacheRootKey;
859
- let rootKey = "";
860
- if (!rootKeyType || rootKeyType === "default")
861
- rootKey = `acc.js.sdk.${this.sdk.getSDKVersion().version}.${instanceKey}.cache.`;
862
-
863
- // Clear storage cache if the sdk versions or the instances are different
864
- if (this._storage && typeof this._storage.removeItem === 'function') {
865
- for (let key in this._storage) {
866
- if (key.startsWith("acc.js.sdk.") && !key.startsWith(rootKey)) {
867
- this._storage.removeItem(key);
868
- }
838
+ this._connectionParameters = connectionParameters; // ## TODO security concern (password kept in memory)
839
+ this._representation = connectionParameters._options.representation;
840
+
841
+ this._sessionInfo = undefined;
842
+ this._sessionToken = undefined;
843
+ this._securityToken = undefined;
844
+ this._bearerToken = undefined; // set when using Bearer authentication and "ImsBearer" credential type
845
+ this._installedPackages = {}; // package set (key and value = package id, ex: "nms:amp")
846
+
847
+ this._secretKeyCipher = undefined;
848
+
849
+ this._storage = connectionParameters._options._storage;
850
+
851
+ var instanceKey = connectionParameters._options.instanceKey;
852
+ if (!instanceKey)
853
+ instanceKey = connectionParameters._endpoint || "";
854
+ if (instanceKey.startsWith("http://")) instanceKey = instanceKey.substr(7);
855
+ if (instanceKey.startsWith("https://")) instanceKey = instanceKey.substr(8);
856
+
857
+ // Determine the cache root key. There are 3 possible values:
858
+ // * no value or "default" is the default behavior, i.e. all cache keys are prefixed with "acc.js.sdk.${sdk.getSDKVersion().version}.${instanceKey}.cache."
859
+ // * "none" (or actually anything else for now), where cache keys are not prefixed by anything
860
+ const rootKeyType = connectionParameters._options.cacheRootKey;
861
+ let rootKey = "";
862
+ if (!rootKeyType || rootKeyType === "default")
863
+ rootKey = `acc.js.sdk.${this.sdk.getSDKVersion().version}.${instanceKey}.cache.`;
864
+
865
+ // Clear storage cache if the sdk versions or the instances are different
866
+ if (this._storage && typeof this._storage.removeItem === 'function') {
867
+ for (let key in this._storage) {
868
+ if (key.startsWith("acc.js.sdk.") && !key.startsWith(rootKey)) {
869
+ this._storage.removeItem(key);
869
870
  }
870
871
  }
872
+ }
871
873
 
872
- this._entityCache = new XtkEntityCache(this._storage, `${rootKey}XtkEntityCache`, connectionParameters._options.entityCacheTTL);
873
- this._entityCacheRefresher = new CacheRefresher(this._entityCache, this, "xtk:schema", `${rootKey}XtkEntityCache`);
874
- this._methodCache = new MethodCache(this._storage, `${rootKey}MethodCache`, connectionParameters._options.methodCacheTTL);
875
- this._optionCache = new OptionCache(this._storage, `${rootKey}OptionCache`, connectionParameters._options.optionCacheTTL);
876
- this._optionCacheRefresher = new CacheRefresher(this._optionCache, this, "xtk:option", `${rootKey}OptionCache`);
877
- this.NLWS = new Proxy(this, clientHandler());
874
+ this._entityCache = new XtkEntityCache(this._storage, `${rootKey}XtkEntityCache`, connectionParameters._options.entityCacheTTL);
875
+ this._entityCacheRefresher = new CacheRefresher(this._entityCache, this, "xtk:schema", `${rootKey}XtkEntityCache`);
876
+ this._methodCache = new MethodCache(this._storage, `${rootKey}MethodCache`, connectionParameters._options.methodCacheTTL);
877
+ this._optionCache = new OptionCache(this._storage, `${rootKey}OptionCache`, connectionParameters._options.optionCacheTTL);
878
+ this._optionCacheRefresher = new CacheRefresher(this._optionCache, this, "xtk:option", `${rootKey}OptionCache`);
879
+ this.NLWS = new Proxy(this, clientHandler());
878
880
 
879
- this._transport = connectionParameters._options.transport;
880
- this._traceAPICalls = connectionParameters._options.traceAPICalls;
881
- this._refreshClient = connectionParameters._options.refreshClient;
881
+ this._transport = connectionParameters._options.transport;
882
+ this._traceAPICalls = connectionParameters._options.traceAPICalls;
883
+ this._refreshClient = connectionParameters._options.refreshClient;
882
884
 
883
- // expose utilities
884
- /**
885
+ // expose utilities
886
+ /**
885
887
  * File Uploader API
886
888
  * @type {{upload: (function(*=): Promise<{name: string, md5: string, type: string, size: string, url: string}>)}}
887
889
  */
888
- this.fileUploader = fileUploader(this);
890
+ this.fileUploader = fileUploader(this);
889
891
 
890
- /**
892
+ /**
891
893
  * Accessor to DOM helpers
892
894
  * @type {XML.DomUtil}
893
895
  */
894
- this.DomUtil = DomUtil;
895
- /**
896
+ this.DomUtil = DomUtil;
897
+ /**
896
898
  * Accessor to a XtkCaster
897
899
  * @type {XtkCaster}
898
900
  */
899
- this.XtkCaster = XtkCaster;
900
- /**
901
+ this.XtkCaster = XtkCaster;
902
+ /**
901
903
  * The application object. Only valid when logged
902
904
  * @type {Campaign.Application}
903
905
  */
904
- this.application = null;
905
-
906
- // Context for observability. See logon() function which will fill this context
907
- this._lastStatsReport = Date.now();
908
- this._observabilityContext = {
909
- eventId: 0,
910
- client: {
911
- sdkVersion: this.sdk.getSDKVersion().version,
912
- endpoint: this._connectionParameters._endpoint,
913
- createdAt: Date.now(),
914
- clientApp: this._connectionParameters._options.clientApp,
915
- instanceKey: instanceKey
916
- }
917
- };
918
- if (this._connectionParameters._credentials) {
919
- this._observabilityContext.client.type = this._connectionParameters._credentials.type;
906
+ this.application = null;
907
+
908
+ // Context for observability. See logon() function which will fill this context
909
+ this._lastStatsReport = Date.now();
910
+ this._observabilityContext = {
911
+ eventId: 0,
912
+ client: {
913
+ sdkVersion: this.sdk.getSDKVersion().version,
914
+ endpoint: this._connectionParameters._endpoint,
915
+ createdAt: Date.now(),
916
+ clientApp: this._connectionParameters._options.clientApp,
917
+ instanceKey: instanceKey
920
918
  }
919
+ };
920
+ if (this._connectionParameters._credentials) {
921
+ this._observabilityContext.client.type = this._connectionParameters._credentials.type;
922
+ }
921
923
  }
922
924
 
923
925
  /**
@@ -926,7 +928,7 @@ class Client {
926
928
  * @param {*} transport
927
929
  */
928
930
  setTransport(transport) {
929
- this._transport = transport;
931
+ this._transport = transport;
930
932
  }
931
933
 
932
934
  /**
@@ -935,8 +937,8 @@ class Client {
935
937
  * @returns {string} the user agent string
936
938
  */
937
939
  _getUserAgentString() {
938
- const version = this.sdk.getSDKVersion();
939
- return `${version.name}/${version.version} ${version.description}`;
940
+ const version = this.sdk.getSDKVersion();
941
+ return `${version.name}/${version.version} ${version.description}`;
940
942
  }
941
943
 
942
944
  /**
@@ -945,18 +947,18 @@ class Client {
945
947
  * @returns {Object} the headers
946
948
  */
947
949
  _getAuthHeaders(setCookie) {
948
- const headers = {};
949
- if (this._bearerToken) {
950
- headers['Authorization'] = `Bearer ${this._bearerToken}`;
951
- }
952
- else {
953
- headers['X-Security-Token'] = this._securityToken;
954
- headers['X-Session-Token'] = this._sessionToken;
955
- if (setCookie) {
956
- headers['Cookie'] = '__sessiontoken=' + this._sessionToken;
957
- }
950
+ const headers = {};
951
+ if (this._bearerToken) {
952
+ headers['Authorization'] = `Bearer ${this._bearerToken}`;
953
+ }
954
+ else {
955
+ headers['X-Security-Token'] = this._securityToken;
956
+ headers['X-Session-Token'] = this._sessionToken;
957
+ if (setCookie) {
958
+ headers['Cookie'] = '__sessiontoken=' + this._sessionToken;
958
959
  }
959
- return headers;
960
+ }
961
+ return headers;
960
962
  }
961
963
 
962
964
  /**
@@ -968,12 +970,12 @@ class Client {
968
970
  * @returns {XML.XtkObject} the object converted in the requested representation
969
971
  */
970
972
  _toRepresentation(xml, representation) {
971
- representation = representation || this._representation;
972
- if (representation == "xml")
973
- return xml;
974
- if (representation == "BadgerFish" || representation == "SimpleJson")
975
- return DomUtil.toJSON(xml, representation);
976
- throw CampaignException.INVALID_REPRESENTATION(this._representation, "Cannot convert XML document to this representation");
973
+ representation = representation || this._representation;
974
+ if (representation == "xml")
975
+ return xml;
976
+ if (representation == "BadgerFish" || representation == "SimpleJson")
977
+ return DomUtil.toJSON(xml, representation);
978
+ throw CampaignException.INVALID_REPRESENTATION(this._representation, "Cannot convert XML document to this representation");
977
979
  }
978
980
 
979
981
  /**
@@ -986,14 +988,14 @@ class Client {
986
988
  * @returns {DOMElement} the object converted to XML
987
989
  */
988
990
  _fromRepresentation(rootName, entity, representation) {
989
- representation = representation || this._representation;
990
- if (representation == "xml")
991
- return entity;
992
- if (representation == "BadgerFish" || representation == "SimpleJson") {
993
- var xml = DomUtil.fromJSON(rootName, entity, representation);
994
- return xml;
995
- }
996
- throw CampaignException.INVALID_REPRESENTATION(this._representation, "Cannot convert to XML from this representation");
991
+ representation = representation || this._representation;
992
+ if (representation == "xml")
993
+ return entity;
994
+ if (representation == "BadgerFish" || representation == "SimpleJson") {
995
+ var xml = DomUtil.fromJSON(rootName, entity, representation);
996
+ return xml;
997
+ }
998
+ throw CampaignException.INVALID_REPRESENTATION(this._representation, "Cannot convert to XML from this representation");
997
999
  }
998
1000
 
999
1001
  /**
@@ -1006,12 +1008,12 @@ class Client {
1006
1008
  * @returns {DOMElement} the converted object
1007
1009
  */
1008
1010
  _convertToRepresentation(entity, fromRepresentation, toRepresentation) {
1009
- toRepresentation = toRepresentation || this._representation;
1010
- if (this._isSameRepresentation(fromRepresentation, toRepresentation))
1011
- return entity;
1012
- var xml = this._fromRepresentation("root", entity, fromRepresentation);
1013
- entity = this._toRepresentation(xml, toRepresentation);
1011
+ toRepresentation = toRepresentation || this._representation;
1012
+ if (this._isSameRepresentation(fromRepresentation, toRepresentation))
1014
1013
  return entity;
1014
+ var xml = this._fromRepresentation("root", entity, fromRepresentation);
1015
+ entity = this._toRepresentation(xml, toRepresentation);
1016
+ return entity;
1015
1017
  }
1016
1018
 
1017
1019
  /**
@@ -1023,11 +1025,11 @@ class Client {
1023
1025
  * @returns a boolean indicating if the 2 representations are the same or not
1024
1026
  */
1025
1027
  _isSameRepresentation(rep1, rep2) {
1026
- if (!rep1 || !rep2) throw CampaignException.INVALID_REPRESENTATION(undefined, "Cannot compare to undefined representation");
1027
- if (rep1 != "xml" && rep1 != "SimpleJson" && rep1 != "BadgerFish") throw CampaignException.INVALID_REPRESENTATION(rep1, "Cannot compare to invalid representation");
1028
- if (rep2 != "xml" && rep2 != "SimpleJson" && rep2 != "BadgerFish") throw CampaignException.INVALID_REPRESENTATION(rep2, "Cannot compare to invalid representation");
1029
- if (rep1 == rep2) return true;
1030
- return rep1 == rep2;
1028
+ if (!rep1 || !rep2) throw CampaignException.INVALID_REPRESENTATION(undefined, "Cannot compare to undefined representation");
1029
+ if (rep1 != "xml" && rep1 != "SimpleJson" && rep1 != "BadgerFish") throw CampaignException.INVALID_REPRESENTATION(rep1, "Cannot compare to invalid representation");
1030
+ if (rep2 != "xml" && rep2 != "SimpleJson" && rep2 != "BadgerFish") throw CampaignException.INVALID_REPRESENTATION(rep2, "Cannot compare to invalid representation");
1031
+ if (rep1 == rep2) return true;
1032
+ return rep1 == rep2;
1031
1033
  }
1032
1034
 
1033
1035
  /**
@@ -1036,7 +1038,7 @@ class Client {
1036
1038
  * @param {boolean} trace indicates whether to activate tracing or not
1037
1039
  */
1038
1040
  traceAPICalls(trace) {
1039
- this._traceAPICalls = !!trace;
1041
+ this._traceAPICalls = !!trace;
1040
1042
  }
1041
1043
 
1042
1044
  /**
@@ -1044,7 +1046,7 @@ class Client {
1044
1046
  * @param {Campaign.Observer} observer
1045
1047
  */
1046
1048
  registerObserver(observer) {
1047
- this._observers.push(observer);
1049
+ this._observers.push(observer);
1048
1050
  }
1049
1051
 
1050
1052
  /**
@@ -1052,81 +1054,81 @@ class Client {
1052
1054
  * @param {Campaign.Observer} observer
1053
1055
  */
1054
1056
  unregisterObserver(observer) {
1055
- for (var i=0; i<this._observers.length; i++) {
1056
- if (this._observers[i] == observer) {
1057
- this._observers.splice(i, 1);
1058
- break;
1059
- }
1057
+ for (var i=0; i<this._observers.length; i++) {
1058
+ if (this._observers[i] == observer) {
1059
+ this._observers.splice(i, 1);
1060
+ break;
1060
1061
  }
1062
+ }
1061
1063
  }
1062
1064
 
1063
1065
  unregisterAllObservers() {
1064
- this._observers = [];
1066
+ this._observers = [];
1065
1067
  }
1066
1068
 
1067
1069
  _notifyObservers(callback) {
1068
- this._observers.map((observer) => callback(observer));
1070
+ this._observers.map((observer) => callback(observer));
1069
1071
  }
1070
1072
 
1071
1073
  _trackEvent(eventName, parentEvent, payload, pushDownOptions) {
1072
- try {
1073
- if (payload && payload.name === 'CampaignException') {
1074
- payload = {
1075
- detail: payload.detail,
1076
- errorCode: payload.errorCode,
1077
- faultCode: payload.faultCode,
1078
- faultString: payload.faultString,
1079
- message: payload.message,
1080
- statusCode: payload.statusCode,
1081
- };
1082
- }
1083
- this._observabilityContext.eventId = this._observabilityContext.eventId + 1;
1084
- const now = Date.now();
1085
- const event = {
1086
- client: this._observabilityContext.client,
1087
- session: this._observabilityContext.session,
1088
- eventId: this._observabilityContext.eventId,
1089
- eventName: eventName,
1090
- payload: payload,
1091
- timestamp: now,
1092
- };
1093
- if (pushDownOptions) {
1094
- event.pushDownOptions = pushDownOptions;
1095
- }
1096
- if (parentEvent) event.parentEventId = parentEvent.eventId;
1097
- this._notifyObservers((observer) => observer.event && observer.event(event, parentEvent));
1098
-
1099
- // Regularly report internal stats every 5 mins
1100
- if ((now - this._lastStatsReport) >= 300000) {
1101
- this._lastStatsReport = now;
1102
- this._trackInternalStats();
1103
- }
1074
+ try {
1075
+ if (payload && payload.name === 'CampaignException') {
1076
+ payload = {
1077
+ detail: payload.detail,
1078
+ errorCode: payload.errorCode,
1079
+ faultCode: payload.faultCode,
1080
+ faultString: payload.faultString,
1081
+ message: payload.message,
1082
+ statusCode: payload.statusCode,
1083
+ };
1084
+ }
1085
+ this._observabilityContext.eventId = this._observabilityContext.eventId + 1;
1086
+ const now = Date.now();
1087
+ const event = {
1088
+ client: this._observabilityContext.client,
1089
+ session: this._observabilityContext.session,
1090
+ eventId: this._observabilityContext.eventId,
1091
+ eventName: eventName,
1092
+ payload: payload,
1093
+ timestamp: now,
1094
+ };
1095
+ if (pushDownOptions) {
1096
+ event.pushDownOptions = pushDownOptions;
1097
+ }
1098
+ if (parentEvent) event.parentEventId = parentEvent.eventId;
1099
+ this._notifyObservers((observer) => observer.event && observer.event(event, parentEvent));
1104
1100
 
1105
- return event;
1106
- } catch (error) {
1107
- console.info(`Failed to track observability event`, error);
1101
+ // Regularly report internal stats every 5 mins
1102
+ if ((now - this._lastStatsReport) >= 300000) {
1103
+ this._lastStatsReport = now;
1104
+ this._trackInternalStats();
1108
1105
  }
1106
+
1107
+ return event;
1108
+ } catch (error) {
1109
+ console.info(`Failed to track observability event`, error);
1110
+ }
1109
1111
  }
1110
1112
 
1111
1113
  _trackInternalStats() {
1112
- this._trackCacheStats('entityCache', this._entityCache);
1113
- this._trackCacheStats('optionCache', this._optionCache);
1114
- this._trackCacheStats('methodCache', this._methodCache);
1114
+ this._trackCacheStats('entityCache', this._entityCache);
1115
+ this._trackCacheStats('optionCache', this._optionCache);
1116
+ this._trackCacheStats('methodCache', this._methodCache);
1115
1117
  }
1116
1118
 
1117
1119
  _trackCacheStats(name, cache) {
1118
- if (!cache || !cache._stats) return;
1119
- this._trackEvent('CACHE//stats', undefined, {
1120
- name: name,
1121
- reads: cache._stats.reads,
1122
- writes: cache._stats.writes,
1123
- removals: cache._stats.removals,
1124
- clears: cache._stats.clears,
1125
- memoryHits: cache._stats.memoryHits,
1126
- storageHits: cache._stats.storageHits,
1127
- loads: cache._stats.loads,
1128
- saves: cache._stats.saves,
1129
- });
1120
+ if (!cache || !cache._stats) return;
1121
+ this._trackEvent('CACHE//stats', undefined, {
1122
+ name: name,
1123
+ reads: cache._stats.reads,
1124
+ writes: cache._stats.writes,
1125
+ removals: cache._stats.removals,
1126
+ clears: cache._stats.clears,
1127
+ memoryHits: cache._stats.memoryHits,
1128
+ storageHits: cache._stats.storageHits,
1129
+ loads: cache._stats.loads,
1130
+ saves: cache._stats.saves,
1131
+ });
1130
1132
  }
1131
1133
 
1132
1134
  /**
@@ -1135,36 +1137,36 @@ class Client {
1135
1137
  * @returns {boolean} a boolean indicating if the client is logged or not
1136
1138
  */
1137
1139
  isLogged() {
1138
- if (!this._connectionParameters._credentials)
1139
- return false;
1140
-
1141
- // If using anonymous credentials => always logged
1142
- const credentialsType = this._connectionParameters._credentials._type;
1143
- if (credentialsType == "AnonymousUser")
1144
- return true;
1145
- else if (credentialsType == "ImsBearerToken") {
1146
- return !!this._bearerToken;
1147
- }
1140
+ if (!this._connectionParameters._credentials)
1141
+ return false;
1142
+
1143
+ // If using anonymous credentials => always logged
1144
+ const credentialsType = this._connectionParameters._credentials._type;
1145
+ if (credentialsType == "AnonymousUser")
1146
+ return true;
1147
+ else if (credentialsType == "ImsBearerToken") {
1148
+ return !!this._bearerToken;
1149
+ }
1148
1150
 
1149
- // When using bearer token authentication we are considered logged only after
1150
- // the bearer token has been converted into session token and security token
1151
- // by method xtk:session#BearerTokenLogon
1152
- if( credentialsType == "BearerToken")
1153
- return this._sessionToken != undefined &&
1151
+ // When using bearer token authentication we are considered logged only after
1152
+ // the bearer token has been converted into session token and security token
1153
+ // by method xtk:session#BearerTokenLogon
1154
+ if( credentialsType == "BearerToken")
1155
+ return this._sessionToken != undefined &&
1154
1156
  this._sessionToken != null &&
1155
1157
  this._sessionToken != "" &&
1156
1158
  this._securityToken != undefined &&
1157
1159
  this._securityToken != null &&
1158
1160
  this._securityToken != "";
1159
1161
 
1160
- // with session token authentication, we do not expect a security token
1161
- // with security token authentication, we do not expect a session token
1162
- const needsSecurityToken = credentialsType != "SessionToken";
1163
- const hasSecurityToken = this._securityToken !== null && this._securityToken !== undefined && this._securityToken !== "";
1164
- const needsSessionToken = credentialsType != "SecurityToken";
1165
- const hasSessionToken = this._sessionToken !== null && this._sessionToken !== undefined && this._sessionToken !== "";
1162
+ // with session token authentication, we do not expect a security token
1163
+ // with security token authentication, we do not expect a session token
1164
+ const needsSecurityToken = credentialsType != "SessionToken";
1165
+ const hasSecurityToken = this._securityToken !== null && this._securityToken !== undefined && this._securityToken !== "";
1166
+ const needsSessionToken = credentialsType != "SecurityToken";
1167
+ const hasSessionToken = this._sessionToken !== null && this._sessionToken !== undefined && this._sessionToken !== "";
1166
1168
 
1167
- return (!needsSecurityToken || hasSecurityToken) && (!needsSessionToken || hasSessionToken);
1169
+ return (!needsSecurityToken || hasSecurityToken) && (!needsSessionToken || hasSessionToken);
1168
1170
  }
1169
1171
 
1170
1172
  /**
@@ -1180,29 +1182,29 @@ class Client {
1180
1182
  */
1181
1183
  _prepareSoapCall(urn, method, isStatic, internal, extraHttpHeaders, pushDownOptions) {
1182
1184
 
1183
- // Send request ID header if enableRequestIdHeader flag is set to true
1184
- const enableRequestIdHeader = this._connectionParameters._options &&
1185
+ // Send request ID header if enableRequestIdHeader flag is set to true
1186
+ const enableRequestIdHeader = this._connectionParameters._options &&
1185
1187
  this._connectionParameters._options.enableRequestIdHeader;
1186
- let updatedExtraHttpHeaders = extraHttpHeaders;
1187
- if (enableRequestIdHeader) {
1188
- try {
1189
- const requestId = Util.getUUID();
1190
- updatedExtraHttpHeaders = Object.assign({}, extraHttpHeaders, {
1191
- "x-request-id": requestId,
1192
- });
1193
- } catch (error) {
1194
- console.error("Failed to generate request ID", error);
1195
- }
1188
+ let updatedExtraHttpHeaders = extraHttpHeaders;
1189
+ if (enableRequestIdHeader) {
1190
+ try {
1191
+ const requestId = Util.getUUID();
1192
+ updatedExtraHttpHeaders = Object.assign({}, extraHttpHeaders, {
1193
+ "x-request-id": requestId,
1194
+ });
1195
+ } catch (error) {
1196
+ console.error("Failed to generate request ID", error);
1196
1197
  }
1197
- const soapCall = new SoapMethodCall(this._transport, urn, method,
1198
- this._sessionToken, this._securityToken,
1199
- this._getUserAgentString(),
1200
- Object.assign({}, this._connectionParameters._options, pushDownOptions),
1201
- updatedExtraHttpHeaders,
1202
- this._bearerToken);
1203
- soapCall.internal = !!internal;
1204
- soapCall.isStatic = isStatic;
1205
- return soapCall;
1198
+ }
1199
+ const soapCall = new SoapMethodCall(this._transport, urn, method,
1200
+ this._sessionToken, this._securityToken,
1201
+ this._getUserAgentString(),
1202
+ Object.assign({}, this._connectionParameters._options, pushDownOptions),
1203
+ updatedExtraHttpHeaders,
1204
+ this._bearerToken);
1205
+ soapCall.internal = !!internal;
1206
+ soapCall.isStatic = isStatic;
1207
+ return soapCall;
1206
1208
  }
1207
1209
 
1208
1210
  /**
@@ -1213,35 +1215,35 @@ class Client {
1213
1215
  * parameters should be set
1214
1216
  */
1215
1217
  async _retrySoapCall(soapCall) {
1216
- soapCall.retry = false;
1217
- soapCall._retryCount = soapCall._retryCount + 1;
1218
- var newClient = await this._refreshClient(this);
1219
- soapCall.finalize(newClient._soapEndPoint(), newClient);
1220
- const safeCallData = Util.trim(soapCall.request.data);
1218
+ soapCall.retry = false;
1219
+ soapCall._retryCount = soapCall._retryCount + 1;
1220
+ var newClient = await this._refreshClient(this);
1221
+ soapCall.finalize(newClient._soapEndPoint(), newClient);
1222
+ const safeCallData = Util.trim(soapCall.request.data);
1223
+ if (this._traceAPICalls) {
1224
+ console.log(`RETRY SOAP//request ${safeCallData}`);
1225
+ }
1226
+ const pushDownOptions = soapCall._pushDownOptions;
1227
+ const event = this._trackEvent('SOAP//request', undefined, {
1228
+ urn: soapCall.urn,
1229
+ methodName: soapCall.methodName,
1230
+ internal: soapCall.internal,
1231
+ retry: true,
1232
+ retryCount: soapCall._retryCount,
1233
+ safeCallData: safeCallData,
1234
+ }, pushDownOptions);
1235
+ try {
1236
+ await soapCall.execute();
1237
+ const safeCallResponse = Util.trim(soapCall.response);
1221
1238
  if (this._traceAPICalls) {
1222
- console.log(`RETRY SOAP//request ${safeCallData}`);
1239
+ console.log(`SOAP//response ${safeCallResponse}`);
1223
1240
  }
1224
- const pushDownOptions = soapCall._pushDownOptions;
1225
- const event = this._trackEvent('SOAP//request', undefined, {
1226
- urn: soapCall.urn,
1227
- methodName: soapCall.methodName,
1228
- internal: soapCall.internal,
1229
- retry: true,
1230
- retryCount: soapCall._retryCount,
1231
- safeCallData: safeCallData,
1232
- }, pushDownOptions);
1233
- try {
1234
- await soapCall.execute();
1235
- const safeCallResponse = Util.trim(soapCall.response);
1236
- if (this._traceAPICalls) {
1237
- console.log(`SOAP//response ${safeCallResponse}`);
1238
- }
1239
- this._trackEvent('SOAP//response', event, { safeCallResponse: safeCallResponse }, pushDownOptions);
1240
- } catch(error) {
1241
- this._trackEvent('SOAP//failure', event, error, pushDownOptions);
1242
- throw error;
1243
- }
1244
- return;
1241
+ this._trackEvent('SOAP//response', event, { safeCallResponse: safeCallResponse }, pushDownOptions);
1242
+ } catch(error) {
1243
+ this._trackEvent('SOAP//failure', event, error, pushDownOptions);
1244
+ throw error;
1245
+ }
1246
+ return;
1245
1247
  }
1246
1248
 
1247
1249
  /**
@@ -1251,7 +1253,7 @@ class Client {
1251
1253
  * @return {string} soap call End point
1252
1254
  */
1253
1255
  _soapEndPoint() {
1254
- return this._connectionParameters._endpoint + "/nl/jsp/soaprouter.jsp";
1256
+ return this._connectionParameters._endpoint + "/nl/jsp/soaprouter.jsp";
1255
1257
  }
1256
1258
 
1257
1259
  // Serializes parameters for a SOAP call
@@ -1259,88 +1261,88 @@ class Client {
1259
1261
  // @param {DOMDocument} schema is the XML schema of the method call
1260
1262
  // @param {SOAP.SoapMethodCall} soapCall is the SOAP call being performed
1261
1263
  // @param {Campaign.XtkMethodParam[]} inputParameters is the list of input parameters. The first paramater in the array is the "this" parameter for non-static method calls
1262
- // @param {string} representation is the representation to use to interpret the input parameters
1264
+ // @param {string} representation is the representation to use to interpret the input parameters
1263
1265
  async _writeSoapCallParameters(entitySchemaId, schema, soapCall, inputParameters, representation) {
1264
- const methodName = soapCall.methodName;
1265
- var isThisParam = !soapCall.isStatic;
1266
-
1267
- for (const ip of inputParameters) {
1268
- const type = ip.type;
1269
- const paramName = ip.name;
1270
- var paramValue = ip.value;
1271
-
1272
- if (type == "string")
1273
- soapCall.writeString(ip.name, XtkCaster.asString(ip.value));
1274
- else if (type == "primarykey")
1275
- soapCall.writeString(ip.name, XtkCaster.asString(ip.value));
1276
- else if (type == "boolean")
1277
- soapCall.writeBoolean(ip.name, XtkCaster.asBoolean(ip.value));
1278
- else if (type == "byte")
1279
- soapCall.writeByte(ip.name, XtkCaster.asByte(ip.value));
1280
- else if (type == "short")
1281
- soapCall.writeShort(ip.name, XtkCaster.asShort(ip.value));
1282
- else if (type == "int")
1283
- soapCall.writeLong(ip.name, XtkCaster.asLong(ip.value));
1284
- else if (type == "long")
1285
- soapCall.writeLong(ip.name, XtkCaster.asLong(ip.value));
1286
- else if (type == "int64")
1287
- soapCall.writeInt64(ip.name, XtkCaster.asInt64(ip.value));
1288
- else if (type == "datetime")
1289
- soapCall.writeTimestamp(ip.name, XtkCaster.asTimestamp(ip.value));
1290
- else if (type == "date")
1291
- soapCall.writeDate(ip.name, XtkCaster.asDate(ip.value));
1292
- else if (type == "DOMDocument" || type == "DOMElement") {
1293
- var docName = undefined;
1294
- let paramRepresentation = representation;
1295
- if (paramValue.__xtkProxy) {
1296
- // A xtk proxy object is passed as a parameter. The call context contains the schema so we
1297
- // can use it to determine the XML document root (docName)
1298
- const paramValueContext = paramValue["."];
1299
- paramValue = paramValueContext.object;
1300
- const xtkschema = paramValueContext.schemaId;
1301
- const index = xtkschema.indexOf(":");
1302
- docName = xtkschema.substring(index+1);
1303
- paramRepresentation = paramValueContext.representation; // xtk proxy may have it's own representation
1304
- }
1305
- else {
1306
- // Hack for workflow API. The C++ code checks that the name of the XML element is <variables>. When
1307
- // using xml representation at the SDK level, it's ok since the SDK caller will set that. But this does
1308
- // not work when using "BadgerFish" representation where we do not know the root element name.
1309
- if (entitySchemaId == "xtk:workflow" && paramName == "parameters" && (
1310
- methodName == "StartWithParameters" || methodName == "PostEvent" || methodName == "SimulateWithParameters" ||
1266
+ const methodName = soapCall.methodName;
1267
+ var isThisParam = !soapCall.isStatic;
1268
+
1269
+ for (const ip of inputParameters) {
1270
+ const type = ip.type;
1271
+ const paramName = ip.name;
1272
+ var paramValue = ip.value;
1273
+
1274
+ if (type == "string")
1275
+ soapCall.writeString(ip.name, XtkCaster.asString(ip.value));
1276
+ else if (type == "primarykey")
1277
+ soapCall.writeString(ip.name, XtkCaster.asString(ip.value));
1278
+ else if (type == "boolean")
1279
+ soapCall.writeBoolean(ip.name, XtkCaster.asBoolean(ip.value));
1280
+ else if (type == "byte")
1281
+ soapCall.writeByte(ip.name, XtkCaster.asByte(ip.value));
1282
+ else if (type == "short")
1283
+ soapCall.writeShort(ip.name, XtkCaster.asShort(ip.value));
1284
+ else if (type == "int")
1285
+ soapCall.writeLong(ip.name, XtkCaster.asLong(ip.value));
1286
+ else if (type == "long")
1287
+ soapCall.writeLong(ip.name, XtkCaster.asLong(ip.value));
1288
+ else if (type == "int64")
1289
+ soapCall.writeInt64(ip.name, XtkCaster.asInt64(ip.value));
1290
+ else if (type == "datetime")
1291
+ soapCall.writeTimestamp(ip.name, XtkCaster.asTimestamp(ip.value));
1292
+ else if (type == "date")
1293
+ soapCall.writeDate(ip.name, XtkCaster.asDate(ip.value));
1294
+ else if (type == "DOMDocument" || type == "DOMElement") {
1295
+ var docName = undefined;
1296
+ let paramRepresentation = representation;
1297
+ if (paramValue.__xtkProxy) {
1298
+ // A xtk proxy object is passed as a parameter. The call context contains the schema so we
1299
+ // can use it to determine the XML document root (docName)
1300
+ const paramValueContext = paramValue["."];
1301
+ paramValue = paramValueContext.object;
1302
+ const xtkschema = paramValueContext.schemaId;
1303
+ const index = xtkschema.indexOf(":");
1304
+ docName = xtkschema.substring(index+1);
1305
+ paramRepresentation = paramValueContext.representation; // xtk proxy may have it's own representation
1306
+ }
1307
+ else {
1308
+ // Hack for workflow API. The C++ code checks that the name of the XML element is <variables>. When
1309
+ // using xml representation at the SDK level, it's ok since the SDK caller will set that. But this does
1310
+ // not work when using "BadgerFish" representation where we do not know the root element name.
1311
+ if (entitySchemaId == "xtk:workflow" && paramName == "parameters" && (
1312
+ methodName == "StartWithParameters" || methodName == "PostEvent" || methodName == "SimulateWithParameters" ||
1311
1313
  methodName == "SpawnWithParameters" || methodName == "SpawnWithParametersEx") )
1312
- docName = "variables";
1313
- if (entitySchemaId == "nms:rtEvent" && methodName == "PushEvent")
1314
- docName = "rtEvent";
1315
- // Try to guess the document name. This is usually available in the xtkschema attribute
1316
- var xtkschema = EntityAccessor.getAttributeAsString(paramValue, "xtkschema");
1317
- if (!xtkschema) xtkschema = paramValue["@xtkschema"];
1318
- if (xtkschema) {
1319
- const index = xtkschema.indexOf(":");
1320
- docName = xtkschema.substring(index+1);
1321
- }
1322
- if (!docName) docName = paramName; // Use te parameter name as the XML root element
1323
- }
1324
- var xmlValue = this._fromRepresentation(docName, paramValue, paramRepresentation || representation);
1325
- if (type == "DOMDocument") {
1326
- if (isThisParam) {
1327
- isThisParam = false;
1328
- // The xtk:persist#NewInstance requires a xtkschema attribute which we can compute here
1329
- // Actually, we're always adding it, for all non-static methods
1330
- const xmlRoot = xmlValue.nodeType === 9 ? xmlValue.documentElement : xmlValue;
1331
- if (!xmlRoot.hasAttribute("xtkschema"))
1332
- xmlRoot.setAttribute("xtkschema", entitySchemaId);
1333
- soapCall.writeDocument("document", xmlValue);
1334
- }
1335
- else
1336
- soapCall.writeDocument(paramName, xmlValue);
1337
- }
1338
- else
1339
- soapCall.writeElement(paramName, xmlValue);
1314
+ docName = "variables";
1315
+ if (entitySchemaId == "nms:rtEvent" && methodName == "PushEvent")
1316
+ docName = "rtEvent";
1317
+ // Try to guess the document name. This is usually available in the xtkschema attribute
1318
+ var xtkschema = EntityAccessor.getAttributeAsString(paramValue, "xtkschema");
1319
+ if (!xtkschema) xtkschema = paramValue["@xtkschema"];
1320
+ if (xtkschema) {
1321
+ const index = xtkschema.indexOf(":");
1322
+ docName = xtkschema.substring(index+1);
1323
+ }
1324
+ if (!docName) docName = paramName; // Use te parameter name as the XML root element
1325
+ }
1326
+ var xmlValue = this._fromRepresentation(docName, paramValue, paramRepresentation || representation);
1327
+ if (type == "DOMDocument") {
1328
+ if (isThisParam) {
1329
+ isThisParam = false;
1330
+ // The xtk:persist#NewInstance requires a xtkschema attribute which we can compute here
1331
+ // Actually, we're always adding it, for all non-static methods
1332
+ const xmlRoot = xmlValue.nodeType === 9 ? xmlValue.documentElement : xmlValue;
1333
+ if (!xmlRoot.hasAttribute("xtkschema"))
1334
+ xmlRoot.setAttribute("xtkschema", entitySchemaId);
1335
+ soapCall.writeDocument("document", xmlValue);
1340
1336
  }
1341
1337
  else
1342
- throw CampaignException.BAD_SOAP_PARAMETER(soapCall, paramName, paramValue, `Unsupported parameter type '${type}' for parameter '${paramName}' of method '${methodName}' of schema '${entitySchemaId}`);
1338
+ soapCall.writeDocument(paramName, xmlValue);
1339
+ }
1340
+ else
1341
+ soapCall.writeElement(paramName, xmlValue);
1343
1342
  }
1343
+ else
1344
+ throw CampaignException.BAD_SOAP_PARAMETER(soapCall, paramName, paramValue, `Unsupported parameter type '${type}' for parameter '${paramName}' of method '${methodName}' of schema '${entitySchemaId}`);
1345
+ }
1344
1346
  }
1345
1347
 
1346
1348
  // Deserializes results for a SOAP call
@@ -1348,76 +1350,76 @@ class Client {
1348
1350
  // @param {DOMDocument} schema is the XML schema of the method call
1349
1351
  // @param {SOAP.SoapMethodCall} soapCall is the SOAP call being performed
1350
1352
  // @param {Campaign.XtkMethodParam[]} outputParameters is the list of output parameters. The first paramater in the array is the "this" parameter for non-static method calls
1351
- // @param {string} representation is the representation to use to interpret the parameters
1353
+ // @param {string} representation is the representation to use to interpret the parameters
1352
1354
  async _readSoapCallResult(entitySchemaId, schema, soapCall, outputParameters, representation) {
1353
- const methodName = soapCall.methodName;
1354
- var isThisParam = !soapCall.isStatic;
1355
- for (const op of outputParameters) {
1356
- const type = op.type;
1357
- const paramName = op.name;
1358
- var returnValue = op.value;
1359
-
1360
- if (isThisParam) {
1361
- isThisParam = false;
1362
- // Non static methods, such as xtk:query#SelectAll return a element named "entity" which is the object itself on which
1363
- // the method is called. This is the new version of the object (in XML form)
1364
- const entity = soapCall.getEntity();
1365
- if (entity)
1366
- returnValue = this._toRepresentation(entity, representation);
1367
- }
1368
- else if (type == "string")
1369
- returnValue = soapCall.getNextString();
1370
- else if (type == "primarykey")
1371
- returnValue = soapCall.getNextPrimaryKey();
1372
- else if (type == "boolean")
1373
- returnValue = soapCall.getNextBoolean();
1374
- else if (type == "byte")
1375
- returnValue = soapCall.getNextByte();
1376
- else if (type == "short")
1377
- returnValue = soapCall.getNextShort();
1378
- else if (type == "long")
1379
- returnValue = soapCall.getNextLong();
1380
- else if (type == "int64")
1381
- // int64 are represented as strings to make sure no precision is lost
1382
- returnValue = soapCall.getNextInt64();
1383
- else if (type == "datetime")
1384
- returnValue = soapCall.getNextDateTime();
1385
- else if (type == "date")
1386
- returnValue = soapCall.getNextDate();
1387
- else if (type == "DOMDocument") {
1388
- returnValue = soapCall.getNextDocument();
1389
- returnValue = this._toRepresentation(returnValue, representation);
1390
- }
1391
- else if (type == "DOMElement") {
1355
+ const methodName = soapCall.methodName;
1356
+ var isThisParam = !soapCall.isStatic;
1357
+ for (const op of outputParameters) {
1358
+ const type = op.type;
1359
+ const paramName = op.name;
1360
+ var returnValue = op.value;
1361
+
1362
+ if (isThisParam) {
1363
+ isThisParam = false;
1364
+ // Non static methods, such as xtk:query#SelectAll return a element named "entity" which is the object itself on which
1365
+ // the method is called. This is the new version of the object (in XML form)
1366
+ const entity = soapCall.getEntity();
1367
+ if (entity)
1368
+ returnValue = this._toRepresentation(entity, representation);
1369
+ }
1370
+ else if (type == "string")
1371
+ returnValue = soapCall.getNextString();
1372
+ else if (type == "primarykey")
1373
+ returnValue = soapCall.getNextPrimaryKey();
1374
+ else if (type == "boolean")
1375
+ returnValue = soapCall.getNextBoolean();
1376
+ else if (type == "byte")
1377
+ returnValue = soapCall.getNextByte();
1378
+ else if (type == "short")
1379
+ returnValue = soapCall.getNextShort();
1380
+ else if (type == "long")
1381
+ returnValue = soapCall.getNextLong();
1382
+ else if (type == "int64")
1383
+ // int64 are represented as strings to make sure no precision is lost
1384
+ returnValue = soapCall.getNextInt64();
1385
+ else if (type == "datetime")
1386
+ returnValue = soapCall.getNextDateTime();
1387
+ else if (type == "date")
1388
+ returnValue = soapCall.getNextDate();
1389
+ else if (type == "DOMDocument") {
1390
+ returnValue = soapCall.getNextDocument();
1391
+ returnValue = this._toRepresentation(returnValue, representation);
1392
+ }
1393
+ else if (type == "DOMElement") {
1394
+ returnValue = soapCall.getNextElement();
1395
+ returnValue = this._toRepresentation(returnValue, representation);
1396
+ }
1397
+ else {
1398
+ const schemaName = entitySchemaId.substring(entitySchemaId.indexOf(':') + 1);
1399
+ // type can reference a schema element. The naming convension is that the type name
1400
+ // is {schemaName}{elementNameCamelCase}. For instance, the type "sessionUserInfo"
1401
+ // matches the "userInfo" element of the "xtkSession" schema
1402
+ let element;
1403
+ if (type.substr(0, schemaName.length) == schemaName) {
1404
+ const shortTypeName = type.substr(schemaName.length, 1).toLowerCase() + type.substr(schemaName.length + 1);
1405
+ element = DomUtil.getFirstChildElement(schema, "element");
1406
+ while (element) {
1407
+ if (element.getAttribute("name") == shortTypeName) {
1408
+ // Type found in schema: Process as a DOM element
1392
1409
  returnValue = soapCall.getNextElement();
1393
1410
  returnValue = this._toRepresentation(returnValue, representation);
1411
+ break;
1412
+ }
1413
+ element = DomUtil.getNextSiblingElement(element, "element");
1394
1414
  }
1395
- else {
1396
- const schemaName = entitySchemaId.substring(entitySchemaId.indexOf(':') + 1);
1397
- // type can reference a schema element. The naming convension is that the type name
1398
- // is {schemaName}{elementNameCamelCase}. For instance, the type "sessionUserInfo"
1399
- // matches the "userInfo" element of the "xtkSession" schema
1400
- let element;
1401
- if (type.substr(0, schemaName.length) == schemaName) {
1402
- const shortTypeName = type.substr(schemaName.length, 1).toLowerCase() + type.substr(schemaName.length + 1);
1403
- element = DomUtil.getFirstChildElement(schema, "element");
1404
- while (element) {
1405
- if (element.getAttribute("name") == shortTypeName) {
1406
- // Type found in schema: Process as a DOM element
1407
- returnValue = soapCall.getNextElement();
1408
- returnValue = this._toRepresentation(returnValue, representation);
1409
- break;
1410
- }
1411
- element = DomUtil.getNextSiblingElement(element, "element");
1412
- }
1413
1415
 
1414
- }
1415
- if (!element)
1416
- throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `Unsupported return type '${type}' for parameter '${paramName}' of method '${methodName}' of schema '${entitySchemaId}'`);
1417
- }
1418
- op.value = returnValue;
1416
+ }
1417
+ if (!element)
1418
+ throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `Unsupported return type '${type}' for parameter '${paramName}' of method '${methodName}' of schema '${entitySchemaId}'`);
1419
1419
  }
1420
- soapCall.checkNoMoreArgs();
1420
+ op.value = returnValue;
1421
+ }
1422
+ soapCall.checkNoMoreArgs();
1421
1423
  }
1422
1424
 
1423
1425
  /**
@@ -1432,46 +1434,46 @@ class Client {
1432
1434
  * @param {SOAP.SoapMethodCall} soapCall is the SOAP call being performed
1433
1435
  * @param {Campaign.XtkMethodParam[]} inputParams is the list of input parameters. The first paramater in the array is the "this" parameter for non-static method calls
1434
1436
  * @param {Campaign.XtkMethodParam[]} outputParams is the list of output parameters. The first paramater in the array is the "this" parameter for non-static method calls
1435
- * @param {string} representation is the representation to use to interpret the parameters
1437
+ * @param {string} representation is the representation to use to interpret the parameters
1436
1438
  */
1437
1439
  async _makeInterceptableSoapCall(entitySchemaId, schema, soapCall, inputParams, outputParams, representation) {
1438
- // Call observers and give them a chance to modify the parameters before the call is actually made
1439
- if (!soapCall.internal) {
1440
- await this._beforeSoapCall({
1441
- urn: soapCall.urn,
1442
- name: soapCall.methodName,
1443
- }, inputParams, representation);
1444
- }
1440
+ // Call observers and give them a chance to modify the parameters before the call is actually made
1441
+ if (!soapCall.internal) {
1442
+ await this._beforeSoapCall({
1443
+ urn: soapCall.urn,
1444
+ name: soapCall.methodName,
1445
+ }, inputParams, representation);
1446
+ }
1445
1447
 
1446
- // Make SOAP call
1447
- await this._writeSoapCallParameters(entitySchemaId, schema, soapCall, inputParams, representation);
1448
- await this._makeSoapCall(soapCall);
1449
- await this._readSoapCallResult(entitySchemaId, schema, soapCall, outputParams, representation);
1448
+ // Make SOAP call
1449
+ await this._writeSoapCallParameters(entitySchemaId, schema, soapCall, inputParams, representation);
1450
+ await this._makeSoapCall(soapCall);
1451
+ await this._readSoapCallResult(entitySchemaId, schema, soapCall, outputParams, representation);
1450
1452
 
1451
- // Specific handling of query results
1452
- // https://github.com/adobe/acc-js-sdk/issues/3
1453
- if (entitySchemaId === "xtk:queryDef" && soapCall.methodName === "ExecuteQuery") {
1454
- const returnValue = outputParams[1].value; // first parameter is the "this", second one (index 1) is the query result
1455
- const emptyResult = Object.keys(returnValue).length == 0;
1456
- const object = inputParams[0].value; // first parmater is the "this"
1457
- const operation = EntityAccessor.getAttributeAsString(object, "operation");
1458
- if (operation == "getIfExists" && emptyResult)
1459
- outputParams[1].value = null;
1460
- else if (operation == "select" && emptyResult) {
1461
- const querySchemaId = EntityAccessor.getAttributeAsString(object, "schema");
1462
- const index = querySchemaId.indexOf(':');
1463
- const querySchemaName = querySchemaId.substr(index + 1).replace(':', '_');
1464
- outputParams[1].value[querySchemaName] = [];
1465
- }
1453
+ // Specific handling of query results
1454
+ // https://github.com/adobe/acc-js-sdk/issues/3
1455
+ if (entitySchemaId === "xtk:queryDef" && soapCall.methodName === "ExecuteQuery") {
1456
+ const returnValue = outputParams[1].value; // first parameter is the "this", second one (index 1) is the query result
1457
+ const emptyResult = Object.keys(returnValue).length == 0;
1458
+ const object = inputParams[0].value; // first parmater is the "this"
1459
+ const operation = EntityAccessor.getAttributeAsString(object, "operation");
1460
+ if (operation == "getIfExists" && emptyResult)
1461
+ outputParams[1].value = null;
1462
+ else if (operation == "select" && emptyResult) {
1463
+ const querySchemaId = EntityAccessor.getAttributeAsString(object, "schema");
1464
+ const index = querySchemaId.indexOf(':');
1465
+ const querySchemaName = querySchemaId.substr(index + 1).replace(':', '_');
1466
+ outputParams[1].value[querySchemaName] = [];
1466
1467
  }
1468
+ }
1467
1469
 
1468
- // Call observers and give them a chance to modify the results
1469
- if (!soapCall.internal) {
1470
- await this._afterSoapCall({
1471
- urn: soapCall.urn,
1472
- name: soapCall.methodName
1473
- }, inputParams, representation, outputParams);
1474
- }
1470
+ // Call observers and give them a chance to modify the results
1471
+ if (!soapCall.internal) {
1472
+ await this._afterSoapCall({
1473
+ urn: soapCall.urn,
1474
+ name: soapCall.methodName
1475
+ }, inputParams, representation, outputParams);
1476
+ }
1475
1477
  }
1476
1478
 
1477
1479
  /**
@@ -1482,233 +1484,233 @@ class Client {
1482
1484
  * @param {SOAP.SoapMethodCall} soapCall the SOAP method to call
1483
1485
  */
1484
1486
  _makeSoapCall(soapCall) {
1485
- const that = this;
1486
- if (soapCall.requiresLogon() && !that.isLogged())
1487
- throw CampaignException.NOT_LOGGED_IN(soapCall, `Cannot execute SOAP call ${soapCall.urn}#${soapCall.methodName}: you are not logged in. Use the Logon function first`);
1488
- soapCall.finalize(this._soapEndPoint());
1489
-
1490
- const safeCallData = Util.trim(soapCall.request.data);
1491
- if (that._traceAPICalls)
1492
- console.log(`SOAP//request ${safeCallData}`);
1493
- that._notifyObservers((observer) => observer.onSOAPCall && observer.onSOAPCall(soapCall, safeCallData) );
1494
-
1495
- const pushDownOptions = soapCall._pushDownOptions;
1496
- const event = this._trackEvent('SOAP//request', undefined, {
1497
- urn: soapCall.urn,
1498
- methodName: soapCall.methodName,
1499
- internal: soapCall.internal,
1500
- retry: false,
1501
- retryCount: soapCall._retryCount,
1502
- safeCallData: safeCallData,
1503
- }, pushDownOptions);
1504
- return soapCall.execute()
1505
- .then(() => {
1506
- const safeCallResponse = Util.trim(soapCall.response);
1507
- if (that._traceAPICalls)
1508
- console.log(`SOAP//response ${safeCallResponse}`);
1509
- that._notifyObservers((observer) => observer.onSOAPCallSuccess && observer.onSOAPCallSuccess(soapCall, safeCallResponse) );
1510
- this._trackEvent('SOAP//response', event, { safeCallResponse: safeCallResponse }, pushDownOptions);
1511
- return Promise.resolve();
1512
- })
1513
- .catch((ex) => {
1514
- if (that._traceAPICalls)
1515
- console.log(`SOAP//failure ${ex.toString()}`);
1516
- that._notifyObservers((observer) => observer.onSOAPCallFailure && observer.onSOAPCallFailure(soapCall, ex) );
1517
- this._trackEvent('SOAP//failure', event, ex, pushDownOptions);
1518
- // Call session expiration callback in case of 401
1519
- if (ex.statusCode == 401 && that._refreshClient && soapCall.retry) {
1520
- return this._retrySoapCall(soapCall);
1521
- }
1522
- else
1523
- return Promise.reject(ex);
1524
- });
1487
+ const that = this;
1488
+ if (soapCall.requiresLogon() && !that.isLogged())
1489
+ throw CampaignException.NOT_LOGGED_IN(soapCall, `Cannot execute SOAP call ${soapCall.urn}#${soapCall.methodName}: you are not logged in. Use the Logon function first`);
1490
+ soapCall.finalize(this._soapEndPoint());
1491
+
1492
+ const safeCallData = Util.trim(soapCall.request.data);
1493
+ if (that._traceAPICalls)
1494
+ console.log(`SOAP//request ${safeCallData}`);
1495
+ that._notifyObservers((observer) => observer.onSOAPCall && observer.onSOAPCall(soapCall, safeCallData) );
1496
+
1497
+ const pushDownOptions = soapCall._pushDownOptions;
1498
+ const event = this._trackEvent('SOAP//request', undefined, {
1499
+ urn: soapCall.urn,
1500
+ methodName: soapCall.methodName,
1501
+ internal: soapCall.internal,
1502
+ retry: false,
1503
+ retryCount: soapCall._retryCount,
1504
+ safeCallData: safeCallData,
1505
+ }, pushDownOptions);
1506
+ return soapCall.execute()
1507
+ .then(() => {
1508
+ const safeCallResponse = Util.trim(soapCall.response);
1509
+ if (that._traceAPICalls)
1510
+ console.log(`SOAP//response ${safeCallResponse}`);
1511
+ that._notifyObservers((observer) => observer.onSOAPCallSuccess && observer.onSOAPCallSuccess(soapCall, safeCallResponse) );
1512
+ this._trackEvent('SOAP//response', event, { safeCallResponse: safeCallResponse }, pushDownOptions);
1513
+ return Promise.resolve();
1514
+ })
1515
+ .catch((ex) => {
1516
+ if (that._traceAPICalls)
1517
+ console.log(`SOAP//failure ${ex.toString()}`);
1518
+ that._notifyObservers((observer) => observer.onSOAPCallFailure && observer.onSOAPCallFailure(soapCall, ex) );
1519
+ this._trackEvent('SOAP//failure', event, ex, pushDownOptions);
1520
+ // Call session expiration callback in case of 401
1521
+ if (ex.statusCode == 401 && that._refreshClient && soapCall.retry) {
1522
+ return this._retrySoapCall(soapCall);
1523
+ }
1524
+ else
1525
+ return Promise.reject(ex);
1526
+ });
1525
1527
  }
1526
1528
 
1527
1529
  _onLogon() {
1528
- this.application = new Application(this);
1529
- this.application._registerCacheChangeListener();
1530
- this._observabilityContext.instance = {
1531
- buildNumber: this.application.buildNumber,
1532
- version: this.application.version,
1533
- instanceName: this.application.instanceName,
1534
- };
1535
- if (this.application.operator) {
1536
- this._observabilityContext.instance.operator = {
1537
- login: this.application.operator.login,
1538
- id: this.application.operator.id,
1539
- timezone: this.application.operator.timezone,
1540
- rights: this.application.operator.rights,
1541
- packages: this.application.operator.packages,
1542
- };
1543
- }
1544
- this._observabilityContext.session = {
1545
- logonAt: Date.now(),
1530
+ this.application = new Application(this);
1531
+ this.application._registerCacheChangeListener();
1532
+ this._observabilityContext.instance = {
1533
+ buildNumber: this.application.buildNumber,
1534
+ version: this.application.version,
1535
+ instanceName: this.application.instanceName,
1536
+ };
1537
+ if (this.application.operator) {
1538
+ this._observabilityContext.instance.operator = {
1539
+ login: this.application.operator.login,
1540
+ id: this.application.operator.id,
1541
+ timezone: this.application.operator.timezone,
1542
+ rights: this.application.operator.rights,
1543
+ packages: this.application.operator.packages,
1546
1544
  };
1545
+ }
1546
+ this._observabilityContext.session = {
1547
+ logonAt: Date.now(),
1548
+ };
1547
1549
  }
1548
1550
 
1549
1551
  _onLogoff() {
1550
- delete this._observabilityContext.instance;
1551
- delete this._observabilityContext.session;
1552
+ delete this._observabilityContext.instance;
1553
+ delete this._observabilityContext.session;
1552
1554
  }
1553
1555
 
1554
1556
  _updateSessionInfo(sessionInfo, soapCall) {
1555
- this._sessionInfo = sessionInfo;
1556
- this._installedPackages = {};
1557
- const userInfo = DomUtil.findElement(sessionInfo, "userInfo");
1558
- if (!userInfo)
1559
- throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `userInfo structure missing`);
1560
- let pack = DomUtil.getFirstChildElement(userInfo, "installed-package");
1561
- while (pack) {
1562
- const name = `${DomUtil.getAttributeAsString(pack, "namespace")}:${DomUtil.getAttributeAsString(pack, "name")}`;
1563
- this._installedPackages[name] = name;
1564
- pack = DomUtil.getNextSiblingElement(pack);
1565
- }
1557
+ this._sessionInfo = sessionInfo;
1558
+ this._installedPackages = {};
1559
+ const userInfo = DomUtil.findElement(sessionInfo, "userInfo");
1560
+ if (!userInfo)
1561
+ throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `userInfo structure missing`);
1562
+ let pack = DomUtil.getFirstChildElement(userInfo, "installed-package");
1563
+ while (pack) {
1564
+ const name = `${DomUtil.getAttributeAsString(pack, "namespace")}:${DomUtil.getAttributeAsString(pack, "name")}`;
1565
+ this._installedPackages[name] = name;
1566
+ pack = DomUtil.getNextSiblingElement(pack);
1567
+ }
1566
1568
  }
1567
1569
 
1568
1570
  async _fetchSessionInfo() {
1569
- const userInfoPromise = this.NLWS.xml.xtkSession.getUserInfo();
1570
- const testPromise = this.test();
1571
- const all = Promise.all([userInfoPromise, testPromise]);
1572
- const values = await all;
1573
-
1574
- const sessionInfo = DomUtil.newDocument("sessionInfo");
1575
- const sessionInfoRoot = sessionInfo.documentElement;
1576
- const userInfo = sessionInfo.importNode(values[0], true);
1577
- sessionInfoRoot.appendChild(userInfo);
1578
- const serverInfo = sessionInfo.createElement('serverInfo');
1579
- sessionInfoRoot.appendChild(serverInfo);
1580
- const test = values[1];
1581
- if (test["date"])
1582
- serverInfo.setAttribute("serverDate", new Date(Date.parse(test["date"])).toISOString());
1583
- serverInfo.setAttribute("instanceName", test["instance"]);
1584
- if (test["version"]) {
1585
- const versionParts = test["version"].split(".");
1586
- serverInfo.setAttribute("majNumber", versionParts[0]);
1587
- serverInfo.setAttribute("minNumber", versionParts[1]);
1588
- serverInfo.setAttribute("servicePack", versionParts[2]);
1589
- }
1590
- let buildNumber = test["build"];
1591
- // Alternative method to get the build number (not available unless server has been upgraded at least once)
1592
- if (!buildNumber)
1593
- buildNumber = await this.getOption("NmsServer_LastPostUpgrade", false);
1594
- if (!buildNumber)
1595
- throw CampaignException.UNEXPECTED_SOAP_RESPONSE(undefined, `buildNumber structure missing for both /r/test and NmsServer_LastPostUpgrade option`);
1596
- serverInfo.setAttribute("buildNumber", buildNumber);
1597
- return sessionInfoRoot;
1571
+ const userInfoPromise = this.NLWS.xml.xtkSession.getUserInfo();
1572
+ const testPromise = this.test();
1573
+ const all = Promise.all([userInfoPromise, testPromise]);
1574
+ const values = await all;
1575
+
1576
+ const sessionInfo = DomUtil.newDocument("sessionInfo");
1577
+ const sessionInfoRoot = sessionInfo.documentElement;
1578
+ const userInfo = sessionInfo.importNode(values[0], true);
1579
+ sessionInfoRoot.appendChild(userInfo);
1580
+ const serverInfo = sessionInfo.createElement('serverInfo');
1581
+ sessionInfoRoot.appendChild(serverInfo);
1582
+ const test = values[1];
1583
+ if (test["date"])
1584
+ serverInfo.setAttribute("serverDate", new Date(Date.parse(test["date"])).toISOString());
1585
+ serverInfo.setAttribute("instanceName", test["instance"]);
1586
+ if (test["version"]) {
1587
+ const versionParts = test["version"].split(".");
1588
+ serverInfo.setAttribute("majNumber", versionParts[0]);
1589
+ serverInfo.setAttribute("minNumber", versionParts[1]);
1590
+ serverInfo.setAttribute("servicePack", versionParts[2]);
1591
+ }
1592
+ let buildNumber = test["build"];
1593
+ // Alternative method to get the build number (not available unless server has been upgraded at least once)
1594
+ if (!buildNumber)
1595
+ buildNumber = await this.getOption("NmsServer_LastPostUpgrade", false);
1596
+ if (!buildNumber)
1597
+ throw CampaignException.UNEXPECTED_SOAP_RESPONSE(undefined, `buildNumber structure missing for both /r/test and NmsServer_LastPostUpgrade option`);
1598
+ serverInfo.setAttribute("buildNumber", buildNumber);
1599
+ return sessionInfoRoot;
1598
1600
  }
1599
1601
 
1600
1602
  /**
1601
1603
  * Login to an instance
1602
1604
  */
1603
1605
  logon() {
1604
- const that = this;
1605
-
1606
- this.application = null;
1607
- this._sessionToken = "";
1608
- this._securityToken = "";
1609
- this._bearerToken = undefined;
1610
- const credentials = this._connectionParameters._credentials;
1611
-
1612
- const sdkVersion = this.sdk.getSDKVersion();
1613
- const version = `${sdkVersion.name} ${sdkVersion.version}`;
1614
- const clientApp = this._connectionParameters._options.clientApp;
1615
- if (!this._connectionParameters._options.noSDKHeaders) {
1616
- this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Version"] = version;
1617
- this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Auth"] = `${credentials._type}`;
1618
- if (clientApp)
1619
- this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Client-App"] = clientApp;
1620
- }
1621
- // See NEO-35259
1622
- this._connectionParameters._options.extraHttpHeaders['X-Query-Source'] = `${version}${clientApp? "," + clientApp : ""}`;
1606
+ const that = this;
1607
+
1608
+ this.application = null;
1609
+ this._sessionToken = "";
1610
+ this._securityToken = "";
1611
+ this._bearerToken = undefined;
1612
+ const credentials = this._connectionParameters._credentials;
1613
+
1614
+ const sdkVersion = this.sdk.getSDKVersion();
1615
+ const version = `${sdkVersion.name} ${sdkVersion.version}`;
1616
+ const clientApp = this._connectionParameters._options.clientApp;
1617
+ if (!this._connectionParameters._options.noSDKHeaders) {
1618
+ this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Version"] = version;
1619
+ this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Auth"] = `${credentials._type}`;
1620
+ if (clientApp)
1621
+ this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Client-App"] = clientApp;
1622
+ }
1623
+ // See NEO-35259
1624
+ this._connectionParameters._options.extraHttpHeaders['X-Query-Source'] = `${version}${clientApp? "," + clientApp : ""}`;
1623
1625
 
1624
- this._trackEvent('SDK//logon', undefined, {});
1626
+ this._trackEvent('SDK//logon', undefined, {});
1625
1627
 
1626
- // Clear session token cookie to ensure we're not inheriting an expired cookie. See NEO-26589
1627
- if (credentials._type != "SecurityToken" && typeof document != "undefined") {
1628
- document.cookie = '__sessiontoken=;path=/;';
1629
- }
1630
- if (credentials._type == "SessionToken" || credentials._type == "AnonymousUser" || credentials._type == "SessionAndSecurityToken") {
1631
- that._sessionInfo = undefined;
1632
- that._installedPackages = {};
1633
- that._sessionToken = credentials._sessionToken;
1634
- that._securityToken = credentials._type == "SessionAndSecurityToken" ? credentials._securityToken : "";
1635
- that._bearerToken = undefined;
1636
- that._onLogon();
1637
- return Promise.resolve();
1638
- }
1639
- else if (credentials._type == "SecurityToken") {
1640
- that._sessionInfo = undefined;
1641
- that._installedPackages = {};
1642
- that._sessionToken = "";
1643
- that._securityToken = credentials._securityToken;
1644
- that._bearerToken = undefined;
1645
- that._onLogon();
1646
- return Promise.resolve();
1647
- }
1648
- else if (credentials._type == "ImsBearerToken") {
1649
- that._sessionInfo = undefined;
1650
- that._installedPackages = {};
1651
- that._sessionToken = "";
1652
- that._securityToken = "";
1653
- that._bearerToken = credentials._bearerToken;
1654
-
1655
- // With IMS Bearer token, we do not call the Logon or BearerTokenLogon method any more. As a consequence,
1656
- // we do not have the user and server information returned by those methods, so we need to get the corresponding
1657
- // information by other means
1658
- if (!this._connectionParameters._options.sessionInfo) {
1659
- that._onLogon();
1660
- return Promise.resolve();
1661
- }
1662
- return that._fetchSessionInfo().then((sessionInfo) => {
1663
- that._updateSessionInfo(sessionInfo, undefined);
1664
- that._onLogon();
1665
- });
1628
+ // Clear session token cookie to ensure we're not inheriting an expired cookie. See NEO-26589
1629
+ if (credentials._type != "SecurityToken" && typeof document != "undefined") {
1630
+ document.cookie = '__sessiontoken=;path=/;';
1631
+ }
1632
+ if (credentials._type == "SessionToken" || credentials._type == "AnonymousUser" || credentials._type == "SessionAndSecurityToken") {
1633
+ that._sessionInfo = undefined;
1634
+ that._installedPackages = {};
1635
+ that._sessionToken = credentials._sessionToken;
1636
+ that._securityToken = credentials._type == "SessionAndSecurityToken" ? credentials._securityToken : "";
1637
+ that._bearerToken = undefined;
1638
+ that._onLogon();
1639
+ return Promise.resolve();
1640
+ }
1641
+ else if (credentials._type == "SecurityToken") {
1642
+ that._sessionInfo = undefined;
1643
+ that._installedPackages = {};
1644
+ that._sessionToken = "";
1645
+ that._securityToken = credentials._securityToken;
1646
+ that._bearerToken = undefined;
1647
+ that._onLogon();
1648
+ return Promise.resolve();
1649
+ }
1650
+ else if (credentials._type == "ImsBearerToken") {
1651
+ that._sessionInfo = undefined;
1652
+ that._installedPackages = {};
1653
+ that._sessionToken = "";
1654
+ that._securityToken = "";
1655
+ that._bearerToken = credentials._bearerToken;
1656
+
1657
+ // With IMS Bearer token, we do not call the Logon or BearerTokenLogon method any more. As a consequence,
1658
+ // we do not have the user and server information returned by those methods, so we need to get the corresponding
1659
+ // information by other means
1660
+ if (!this._connectionParameters._options.sessionInfo) {
1661
+ that._onLogon();
1662
+ return Promise.resolve();
1666
1663
  }
1667
- else if (credentials._type == "UserPassword" || credentials._type == "BearerToken") {
1668
- const soapCall = that._prepareSoapCall("xtk:session", credentials._type === "UserPassword" ? "Logon" : "BearerTokenLogon", true, false, this._connectionParameters._options.extraHttpHeaders);
1669
- // No retry for logon SOAP methods
1670
- soapCall.retry = false;
1671
- if (credentials._type == "UserPassword") {
1672
- const user = credentials._getUser();
1673
- const password = credentials._getPassword();
1674
- if (!this._connectionParameters._options.noSDKHeaders)
1675
- this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Auth"] = `${credentials._type} ${user}`;
1676
- soapCall.writeString("login", user);
1677
- soapCall.writeString("password", password);
1678
- var parameters = null;
1679
- if (this._connectionParameters._options.rememberMe) {
1680
- parameters = soapCall.createElement("parameters");
1681
- parameters.setAttribute("rememberMe", "true");
1682
- }
1683
- soapCall.writeElement("parameters", parameters);
1684
- }
1685
- else {
1686
- const bearerToken = credentials._bearerToken;
1687
- soapCall.writeString("bearerToken", bearerToken);
1688
- }
1689
- return this._makeSoapCall(soapCall).then(function() {
1690
- const sessionToken = soapCall.getNextString();
1691
- const sessionInfo = soapCall.getNextDocument();
1692
- that._updateSessionInfo(sessionInfo, soapCall);
1693
- const securityToken = soapCall.getNextString();
1694
- soapCall.checkNoMoreArgs();
1695
- // Sanity check: we should have both a session token and a security token.
1696
- if (!sessionToken)
1697
- throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `Logon method succeeded, but no session token was returned`);
1698
- if (!securityToken)
1699
- throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `Logon method succeeded, but no security token was returned`);
1700
- // store member variables after all parameters are decode the ensure atomicity
1701
- that._sessionToken = sessionToken;
1702
- that._securityToken = securityToken;
1703
- that._bearerToken = undefined;
1704
-
1705
- that._onLogon();
1706
- });
1664
+ return that._fetchSessionInfo().then((sessionInfo) => {
1665
+ that._updateSessionInfo(sessionInfo, undefined);
1666
+ that._onLogon();
1667
+ });
1668
+ }
1669
+ else if (credentials._type == "UserPassword" || credentials._type == "BearerToken") {
1670
+ const soapCall = that._prepareSoapCall("xtk:session", credentials._type === "UserPassword" ? "Logon" : "BearerTokenLogon", true, false, this._connectionParameters._options.extraHttpHeaders);
1671
+ // No retry for logon SOAP methods
1672
+ soapCall.retry = false;
1673
+ if (credentials._type == "UserPassword") {
1674
+ const user = credentials._getUser();
1675
+ const password = credentials._getPassword();
1676
+ if (!this._connectionParameters._options.noSDKHeaders)
1677
+ this._connectionParameters._options.extraHttpHeaders["ACC-SDK-Auth"] = `${credentials._type} ${user}`;
1678
+ soapCall.writeString("login", user);
1679
+ soapCall.writeString("password", password);
1680
+ var parameters = null;
1681
+ if (this._connectionParameters._options.rememberMe) {
1682
+ parameters = soapCall.createElement("parameters");
1683
+ parameters.setAttribute("rememberMe", "true");
1684
+ }
1685
+ soapCall.writeElement("parameters", parameters);
1707
1686
  }
1708
1687
  else {
1709
- //throw CampaignException.INVALID_CREDENTIALS_TYPE(credentials._type, "Cannot logon");
1710
- return Promise.reject(CampaignException.INVALID_CREDENTIALS_TYPE(credentials._type, "Cannot logon"));
1688
+ const bearerToken = credentials._bearerToken;
1689
+ soapCall.writeString("bearerToken", bearerToken);
1711
1690
  }
1691
+ return this._makeSoapCall(soapCall).then(function() {
1692
+ const sessionToken = soapCall.getNextString();
1693
+ const sessionInfo = soapCall.getNextDocument();
1694
+ that._updateSessionInfo(sessionInfo, soapCall);
1695
+ const securityToken = soapCall.getNextString();
1696
+ soapCall.checkNoMoreArgs();
1697
+ // Sanity check: we should have both a session token and a security token.
1698
+ if (!sessionToken)
1699
+ throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `Logon method succeeded, but no session token was returned`);
1700
+ if (!securityToken)
1701
+ throw CampaignException.UNEXPECTED_SOAP_RESPONSE(soapCall, `Logon method succeeded, but no security token was returned`);
1702
+ // store member variables after all parameters are decode the ensure atomicity
1703
+ that._sessionToken = sessionToken;
1704
+ that._securityToken = securityToken;
1705
+ that._bearerToken = undefined;
1706
+
1707
+ that._onLogon();
1708
+ });
1709
+ }
1710
+ else {
1711
+ //throw CampaignException.INVALID_CREDENTIALS_TYPE(credentials._type, "Cannot logon");
1712
+ return Promise.reject(CampaignException.INVALID_CREDENTIALS_TYPE(credentials._type, "Cannot logon"));
1713
+ }
1712
1714
  }
1713
1715
 
1714
1716
  /**
@@ -1718,41 +1720,41 @@ class Client {
1718
1720
  * @returns {Campaign.SessionInfo} details about the session
1719
1721
  */
1720
1722
  getSessionInfo(representation) {
1721
- representation = representation || this._representation;
1722
- return this._toRepresentation(this._sessionInfo, representation);
1723
+ representation = representation || this._representation;
1724
+ return this._toRepresentation(this._sessionInfo, representation);
1723
1725
  }
1724
1726
 
1725
1727
  /**
1726
1728
  * Logs off from an instance to which one previous logged on using the "logon" call
1727
1729
  */
1728
1730
  logoff() {
1729
- var that = this;
1730
- try {
1731
- if (!that.isLogged()) return;
1732
- that.application._unregisterCacheChangeListener();
1733
- that._unregisterAllCacheChangeListeners();
1734
- this.stopRefreshCaches();
1735
- const credentials = this._connectionParameters._credentials;
1736
- if (credentials._type != "SessionToken" && credentials._type != "AnonymousUser") {
1737
- var soapCall = that._prepareSoapCall("xtk:session", "Logoff", true, false, this._connectionParameters._options.extraHttpHeaders);
1738
- return this._makeSoapCall(soapCall).then(function() {
1739
- that._sessionToken = "";
1740
- that._securityToken = "";
1741
- that._bearerToken = undefined;
1742
- that.application = null;
1743
- soapCall.checkNoMoreArgs();
1744
- });
1745
- }
1746
- else {
1747
- that._sessionToken = "";
1748
- that._securityToken = "";
1749
- that._bearerToken = undefined;
1750
- that.application = null;
1751
- }
1752
- } finally {
1753
- this._trackEvent('SDK//logoff', undefined, {});
1754
- this._onLogoff();
1731
+ var that = this;
1732
+ try {
1733
+ if (!that.isLogged()) return;
1734
+ that.application._unregisterCacheChangeListener();
1735
+ that._unregisterAllCacheChangeListeners();
1736
+ this.stopRefreshCaches();
1737
+ const credentials = this._connectionParameters._credentials;
1738
+ if (credentials._type != "SessionToken" && credentials._type != "AnonymousUser") {
1739
+ var soapCall = that._prepareSoapCall("xtk:session", "Logoff", true, false, this._connectionParameters._options.extraHttpHeaders);
1740
+ return this._makeSoapCall(soapCall).then(function() {
1741
+ that._sessionToken = "";
1742
+ that._securityToken = "";
1743
+ that._bearerToken = undefined;
1744
+ that.application = null;
1745
+ soapCall.checkNoMoreArgs();
1746
+ });
1755
1747
  }
1748
+ else {
1749
+ that._sessionToken = "";
1750
+ that._securityToken = "";
1751
+ that._bearerToken = undefined;
1752
+ that.application = null;
1753
+ }
1754
+ } finally {
1755
+ this._trackEvent('SDK//logoff', undefined, {});
1756
+ this._onLogoff();
1757
+ }
1756
1758
  }
1757
1759
 
1758
1760
  /**
@@ -1783,59 +1785,59 @@ class Client {
1783
1785
  * @param {string} description the optional description of the option
1784
1786
  */
1785
1787
  async setOption(name, rawValue, description) {
1786
- // First, read the current option value to make sure we have the right type
1787
- await this.getOption(name, true);
1788
- const option = await this._optionCache.getOption(name);
1789
- // Note: option is never null or undefined there: Campaign will return a value of type 0 and value ""
1790
- var type = option.type;
1791
- var value = XtkCaster.as(rawValue, type);
1792
-
1793
- // Document attribute for value depends on value type
1794
- var attName = XtkCaster._variantStorageAttribute(type);
1795
- if (!attName) {
1796
- // could not infer the storage type of the attribute to use to store the value (when option did not exist before) => assume string
1797
- type = 6;
1798
- attName = "stringValue";
1799
- }
1800
- var doc = { xtkschema: "xtk:option", _operation: "insertOrUpdate", _key: "@name", name: name, dataType: type };
1801
- if (description != null && description != undefined)
1802
- doc.description = description;
1803
- doc[attName] = value;
1804
- await this.NLWS.xtkSession.write(doc);
1805
- // Once set, cache the value
1806
- await this._optionCache.put(name, [value, type]);
1788
+ // First, read the current option value to make sure we have the right type
1789
+ await this.getOption(name, true);
1790
+ const option = await this._optionCache.getOption(name);
1791
+ // Note: option is never null or undefined there: Campaign will return a value of type 0 and value ""
1792
+ var type = option.type;
1793
+ var value = XtkCaster.as(rawValue, type);
1794
+
1795
+ // Document attribute for value depends on value type
1796
+ var attName = XtkCaster._variantStorageAttribute(type);
1797
+ if (!attName) {
1798
+ // could not infer the storage type of the attribute to use to store the value (when option did not exist before) => assume string
1799
+ type = 6;
1800
+ attName = "stringValue";
1801
+ }
1802
+ var doc = { xtkschema: "xtk:option", _operation: "insertOrUpdate", _key: "@name", name: name, dataType: type };
1803
+ if (description != null && description != undefined)
1804
+ doc.description = description;
1805
+ doc[attName] = value;
1806
+ await this.NLWS.xtkSession.write(doc);
1807
+ // Once set, cache the value
1808
+ await this._optionCache.put(name, [value, type]);
1807
1809
  }
1808
1810
 
1809
1811
  /**
1810
1812
  * Clears the options cache
1811
1813
  */
1812
1814
  async clearOptionCache() {
1813
- await this._optionCache.clear();
1815
+ await this._optionCache.clear();
1814
1816
  }
1815
1817
 
1816
1818
  /**
1817
1819
  * Clears the method cache
1818
1820
  */
1819
1821
  async clearMethodCache() {
1820
- await this._methodCache.clear();
1822
+ await this._methodCache.clear();
1821
1823
  }
1822
1824
 
1823
1825
  /**
1824
1826
  * Clears the entity cache
1825
1827
  */
1826
1828
  async clearEntityCache() {
1827
- await this._entityCache.clear();
1829
+ await this._entityCache.clear();
1828
1830
  }
1829
1831
 
1830
1832
  /**
1831
1833
  * Clears all caches (options, methods, entities)
1832
1834
  */
1833
1835
  async clearAllCaches() {
1834
- return Promise.all([
1835
- this.clearEntityCache(),
1836
- this.clearMethodCache(),
1837
- this.clearOptionCache(),
1838
- ]);
1836
+ return Promise.all([
1837
+ this.clearEntityCache(),
1838
+ this.clearMethodCache(),
1839
+ this.clearOptionCache(),
1840
+ ]);
1839
1841
  }
1840
1842
 
1841
1843
  /**
@@ -1843,43 +1845,43 @@ class Client {
1843
1845
  * @param {integer} refreshFrequency refresh frequency in ms. 10000 ms by default.
1844
1846
  */
1845
1847
  startRefreshCaches(refreshFrequency) {
1846
- if (refreshFrequency === undefined || refreshFrequency === null)
1847
- refreshFrequency = 10000;
1848
- this._optionCacheRefresher.startAutoRefresh(refreshFrequency);
1849
- // Start auto refresh for entityCache a little later
1850
- setTimeout(() => { this._entityCacheRefresher.startAutoRefresh(refreshFrequency); }, refreshFrequency/2);
1848
+ if (refreshFrequency === undefined || refreshFrequency === null)
1849
+ refreshFrequency = 10000;
1850
+ this._optionCacheRefresher.startAutoRefresh(refreshFrequency);
1851
+ // Start auto refresh for entityCache a little later
1852
+ setTimeout(() => { this._entityCacheRefresher.startAutoRefresh(refreshFrequency); }, refreshFrequency/2);
1851
1853
  }
1852
1854
  /**
1853
1855
  * Stop auto refresh of all caches
1854
1856
  */
1855
1857
  stopRefreshCaches() {
1856
- this._optionCacheRefresher.stopAutoRefresh();
1857
- this._entityCacheRefresher.stopAutoRefresh();
1858
+ this._optionCacheRefresher.stopAutoRefresh();
1859
+ this._entityCacheRefresher.stopAutoRefresh();
1858
1860
  }
1859
1861
 
1860
1862
  // Register a callback to be called when a schema has been modified and should be removed
1861
1863
  // from the caches
1862
1864
  _registerCacheChangeListener(listener) {
1863
- this._cacheChangeListeners.push(listener);
1865
+ this._cacheChangeListeners.push(listener);
1864
1866
  }
1865
1867
 
1866
1868
  // Unregister a cache change listener
1867
1869
  _unregisterCacheChangeListener(listener) {
1868
- for (var i = 0; i < this._cacheChangeListeners.length; i++) {
1869
- if (this._cacheChangeListeners[i] == listener) {
1870
- this._cacheChangeListeners.splice(i, 1);
1871
- break;
1872
- }
1870
+ for (var i = 0; i < this._cacheChangeListeners.length; i++) {
1871
+ if (this._cacheChangeListeners[i] == listener) {
1872
+ this._cacheChangeListeners.splice(i, 1);
1873
+ break;
1873
1874
  }
1875
+ }
1874
1876
  }
1875
1877
 
1876
1878
  // Unregister all cache change listener
1877
1879
  _unregisterAllCacheChangeListeners() {
1878
- this._cacheChangeListeners = [];
1880
+ this._cacheChangeListeners = [];
1879
1881
  }
1880
1882
 
1881
1883
  _notifyCacheChangeListeners(schemaId) {
1882
- this._cacheChangeListeners.map((listener) => listener.invalidateCacheItem(schemaId));
1884
+ this._cacheChangeListeners.map((listener) => listener.invalidateCacheItem(schemaId));
1883
1885
  }
1884
1886
 
1885
1887
  /**
@@ -1890,11 +1892,11 @@ class Client {
1890
1892
  * @returns {boolean} a boolean indicating if the package is installed or not
1891
1893
  */
1892
1894
  hasPackage(packageId, optionalName) {
1893
- if (optionalName !== undefined)
1895
+ if (optionalName !== undefined)
1894
1896
  packageId = `${packageId}:${optionalName}`;
1895
- if (!this.isLogged())
1897
+ if (!this.isLogged())
1896
1898
  throw CampaignException.NOT_LOGGED_IN(undefined, `Cannot call hasPackage: session not connected`);
1897
- return this._installedPackages[packageId] !== undefined;
1899
+ return this._installedPackages[packageId] !== undefined;
1898
1900
  }
1899
1901
 
1900
1902
  /**
@@ -1905,12 +1907,12 @@ class Client {
1905
1907
  * @deprecated since version 1.0.0
1906
1908
  */
1907
1909
  async _getSecretKeyCipher() {
1908
- var that = this;
1909
- if (this._secretKeyCipher) return this._secretKeyCipher;
1910
- return that.getOption("XtkSecretKey").then(function(secretKey) {
1911
- that._secretKeyCipher = new Cipher(secretKey);
1912
- return that._secretKeyCipher;
1913
- });
1910
+ var that = this;
1911
+ if (this._secretKeyCipher) return this._secretKeyCipher;
1912
+ return that.getOption("XtkSecretKey").then(function(secretKey) {
1913
+ that._secretKeyCipher = new Cipher(secretKey);
1914
+ return that._secretKeyCipher;
1915
+ });
1914
1916
  }
1915
1917
 
1916
1918
  /**
@@ -1926,17 +1928,17 @@ class Client {
1926
1928
  * @return {XML.XtkObject} A DOM or JSON representation of the entity, or null if the entity is not found
1927
1929
  */
1928
1930
  async getEntityIfMoreRecent(entityType, fullName, representation, internal) {
1929
- const soapCall = this._prepareSoapCall("xtk:persist", "GetEntityIfMoreRecent", true, internal, this._connectionParameters._options.extraHttpHeaders);
1930
- const inputParams = [
1931
- { name: "pk", type: "string", value: entityType + "|" + fullName },
1932
- { name: "md5", type: "string", value: "" },
1933
- { name: "mustExist", type: "boolean", value: false },
1934
- ];
1935
- const outputParams = [
1936
- { name: "doc", type: "DOMDocument" },
1937
- ];
1938
- await this._makeInterceptableSoapCall("xtk:session", undefined, soapCall, inputParams, outputParams, representation);
1939
- return outputParams[0].value;
1931
+ const soapCall = this._prepareSoapCall("xtk:persist", "GetEntityIfMoreRecent", true, internal, this._connectionParameters._options.extraHttpHeaders);
1932
+ const inputParams = [
1933
+ { name: "pk", type: "string", value: entityType + "|" + fullName },
1934
+ { name: "md5", type: "string", value: "" },
1935
+ { name: "mustExist", type: "boolean", value: false },
1936
+ ];
1937
+ const outputParams = [
1938
+ { name: "doc", type: "DOMDocument" },
1939
+ ];
1940
+ await this._makeInterceptableSoapCall("xtk:session", undefined, soapCall, inputParams, outputParams, representation);
1941
+ return outputParams[0].value;
1940
1942
  }
1941
1943
 
1942
1944
  /**
@@ -1950,7 +1952,7 @@ class Client {
1950
1952
  * @see {@link Campaign.XtkSchema}
1951
1953
  */
1952
1954
  newSchema(xml) {
1953
- return newSchema(xml, this.application);
1955
+ return newSchema(xml, this.application);
1954
1956
  }
1955
1957
 
1956
1958
  /**
@@ -1963,71 +1965,71 @@ class Client {
1963
1965
  * @returns {XML.XtkObject} the schema definition, as either a DOM document or a JSON object
1964
1966
  */
1965
1967
  async getSchema(schemaId, representation, internal, withoutCache = false) {
1966
- // Support for Orchestrated Campaign XDM schemas (do not use cache)
1967
- const pipeIndex = schemaId.indexOf("|");
1968
- if( pipeIndex != -1 && schemaId.startsWith("xdm:") ) {
1969
- const entityType = schemaId.substring(0, pipeIndex);
1970
- schemaId = schemaId.substring(pipeIndex + 1);
1971
- const entity = await this.getEntityIfMoreRecent(entityType, schemaId, representation, internal);
1972
- return entity;
1973
- }
1974
- var entity = await this._entityCache.get("xtk:schema", schemaId);
1975
- if (!entity || withoutCache) {
1976
- // special case of "temp:group:*" schemas for nms:group
1977
- // Schema "temp:group:*" is not cached because life cycle of this kind of schema is not the same as the others schemas
1978
- if (schemaId.startsWith("temp:group:")) {
1979
- const parts = schemaId.split(":");
1980
- let queryDef = {
1981
- "schema": "nms:group",
1982
- "operation": "get",
1983
- "select": {
1984
- "node": [
1985
- { "expr": "@id" },
1986
- { "expr": "extension" }
1987
- ]
1988
- },
1989
- "where": {
1990
- "condition": [
1991
- { "expr": "@id=" + XtkCaster.asLong(parts[2]) }
1992
- ]
1993
- }
1994
- };
1995
- // Convert to current representation
1996
- queryDef = this._convertToRepresentation(queryDef, "SimpleJson", "xml");
1997
- const query = this.NLWS.xml.xtkQueryDef.create(queryDef);
1998
- try {
1999
- const groupSchema = await query.executeQuery();
2000
- const extension = DomUtil.findElement(groupSchema, "extension");
2001
- if (extension) {
2002
- entity = extension;
2003
- } else {
2004
- entity = null;
2005
- }
2006
- } catch (ex) {
2007
- if (ex.name == 'CampaignException' && ex.errorCode == 'SOP-330011') {
2008
- entity = null;
2009
- } else {
2010
- throw ex;
2011
- }
2012
- }
2013
- } else {
2014
- entity = await this.getEntityIfMoreRecent("xtk:schema", schemaId, "xml", internal);
2015
- if (entity) {
2016
- const impls = DomUtil.getAttributeAsString(entity, "implements");
2017
- if (impls === "xtk:persist" && schemaId !== "xtk:session" && schemaId !== "xtk:persist") {
2018
- // Ensure xtk:persist is present by loading the xtk:session schema
2019
- const xtkSession = await this.getSchema("xtk:session", "xml", true);
2020
- // it is possible that methodCache content has not be loaded in memory
2021
- // so we re-put the methods
2022
- await this._methodCache.put(xtkSession);
2023
- }
2024
- await this._entityCache.put("xtk:schema", schemaId, entity);
2025
- await this._methodCache.put(entity);
2026
- }
1968
+ // Support for Orchestrated Campaign XDM schemas (do not use cache)
1969
+ const pipeIndex = schemaId.indexOf("|");
1970
+ if( pipeIndex != -1 && schemaId.startsWith("xdm:") ) {
1971
+ const entityType = schemaId.substring(0, pipeIndex);
1972
+ schemaId = schemaId.substring(pipeIndex + 1);
1973
+ const entity = await this.getEntityIfMoreRecent(entityType, schemaId, representation, internal);
1974
+ return entity;
1975
+ }
1976
+ var entity = await this._entityCache.get("xtk:schema", schemaId);
1977
+ if (!entity || withoutCache) {
1978
+ // special case of "temp:group:*" schemas for nms:group
1979
+ // Schema "temp:group:*" is not cached because life cycle of this kind of schema is not the same as the others schemas
1980
+ if (schemaId.startsWith("temp:group:")) {
1981
+ const parts = schemaId.split(":");
1982
+ let queryDef = {
1983
+ "schema": "nms:group",
1984
+ "operation": "get",
1985
+ "select": {
1986
+ "node": [
1987
+ { "expr": "@id" },
1988
+ { "expr": "extension" }
1989
+ ]
1990
+ },
1991
+ "where": {
1992
+ "condition": [
1993
+ { "expr": "@id=" + XtkCaster.asLong(parts[2]) }
1994
+ ]
1995
+ }
1996
+ };
1997
+ // Convert to current representation
1998
+ queryDef = this._convertToRepresentation(queryDef, "SimpleJson", "xml");
1999
+ const query = this.NLWS.xml.xtkQueryDef.create(queryDef);
2000
+ try {
2001
+ const groupSchema = await query.executeQuery();
2002
+ const extension = DomUtil.findElement(groupSchema, "extension");
2003
+ if (extension) {
2004
+ entity = extension;
2005
+ } else {
2006
+ entity = null;
2027
2007
  }
2008
+ } catch (ex) {
2009
+ if (ex.name == 'CampaignException' && ex.errorCode == 'SOP-330011') {
2010
+ entity = null;
2011
+ } else {
2012
+ throw ex;
2013
+ }
2014
+ }
2015
+ } else {
2016
+ entity = await this.getEntityIfMoreRecent("xtk:schema", schemaId, "xml", internal);
2017
+ if (entity) {
2018
+ const impls = DomUtil.getAttributeAsString(entity, "implements");
2019
+ if (impls === "xtk:persist" && schemaId !== "xtk:session" && schemaId !== "xtk:persist") {
2020
+ // Ensure xtk:persist is present by loading the xtk:session schema
2021
+ const xtkSession = await this.getSchema("xtk:session", "xml", true);
2022
+ // it is possible that methodCache content has not be loaded in memory
2023
+ // so we re-put the methods
2024
+ await this._methodCache.put(xtkSession);
2025
+ }
2026
+ await this._entityCache.put("xtk:schema", schemaId, entity);
2027
+ await this._methodCache.put(entity);
2028
+ }
2028
2029
  }
2029
- entity = this._toRepresentation(entity, representation);
2030
- return entity;
2030
+ }
2031
+ entity = this._toRepresentation(entity, representation);
2032
+ return entity;
2031
2033
  }
2032
2034
 
2033
2035
  /**
@@ -2039,37 +2041,37 @@ class Client {
2039
2041
  */
2040
2042
  async getSysEnum(enumName, optionalStartSchemaOrSchemaName) {
2041
2043
 
2042
- // Called with one parameter: enumName must be the fully qualified enumeration name
2043
- // as <namespace>:<schema>:<enum>, for instance "nms:extAccount:encryptionType"
2044
- if (!optionalStartSchemaOrSchemaName) {
2045
- const index = enumName.lastIndexOf(':');
2046
- if (index == -1)
2047
- throw CampaignException.BAD_PARAMETER("enumName", enumName, `getEnum expects a fully qualified enumeration name. '${enumName}' is not a valid name.`);
2048
- optionalStartSchemaOrSchemaName = enumName.substring(0, index);
2049
- enumName = enumName.substring(index + 1);
2050
- }
2051
-
2052
- if (!optionalStartSchemaOrSchemaName || optionalStartSchemaOrSchemaName == "")
2053
- throw CampaignException.BAD_PARAMETER("enumName", enumName, `getEnum needs a schema id.`);
2054
-
2055
- // If we have a schema name (and not a schema), then lookup the schema by name
2056
- if (typeof optionalStartSchemaOrSchemaName == "string") {
2057
- const index = optionalStartSchemaOrSchemaName.lastIndexOf(':');
2058
- if (index == -1)
2059
- throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `getEnum expects a valid schema name. '${optionalStartSchemaOrSchemaName}' is not a valid name.`);
2060
- optionalStartSchemaOrSchemaName = await this.getSchema(optionalStartSchemaOrSchemaName, undefined, true);
2061
- if (!optionalStartSchemaOrSchemaName)
2062
- throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `Schema '${optionalStartSchemaOrSchemaName}' not found.`);
2063
- }
2064
- else
2065
- throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `getEnum expects a valid schema name wich is a string. Given ${typeof optionalStartSchemaOrSchemaName} instead`);
2044
+ // Called with one parameter: enumName must be the fully qualified enumeration name
2045
+ // as <namespace>:<schema>:<enum>, for instance "nms:extAccount:encryptionType"
2046
+ if (!optionalStartSchemaOrSchemaName) {
2047
+ const index = enumName.lastIndexOf(':');
2048
+ if (index == -1)
2049
+ throw CampaignException.BAD_PARAMETER("enumName", enumName, `getEnum expects a fully qualified enumeration name. '${enumName}' is not a valid name.`);
2050
+ optionalStartSchemaOrSchemaName = enumName.substring(0, index);
2051
+ enumName = enumName.substring(index + 1);
2052
+ }
2066
2053
 
2067
- const schema = optionalStartSchemaOrSchemaName;
2068
- for (const e of EntityAccessor.getChildElements(schema, "enumeration")) {
2069
- const n = EntityAccessor.getAttributeAsString(e, "name");
2070
- if (n == enumName)
2071
- return e;
2072
- }
2054
+ if (!optionalStartSchemaOrSchemaName || optionalStartSchemaOrSchemaName == "")
2055
+ throw CampaignException.BAD_PARAMETER("enumName", enumName, `getEnum needs a schema id.`);
2056
+
2057
+ // If we have a schema name (and not a schema), then lookup the schema by name
2058
+ if (typeof optionalStartSchemaOrSchemaName == "string") {
2059
+ const index = optionalStartSchemaOrSchemaName.lastIndexOf(':');
2060
+ if (index == -1)
2061
+ throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `getEnum expects a valid schema name. '${optionalStartSchemaOrSchemaName}' is not a valid name.`);
2062
+ optionalStartSchemaOrSchemaName = await this.getSchema(optionalStartSchemaOrSchemaName, undefined, true);
2063
+ if (!optionalStartSchemaOrSchemaName)
2064
+ throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `Schema '${optionalStartSchemaOrSchemaName}' not found.`);
2065
+ }
2066
+ else
2067
+ throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `getEnum expects a valid schema name wich is a string. Given ${typeof optionalStartSchemaOrSchemaName} instead`);
2068
+
2069
+ const schema = optionalStartSchemaOrSchemaName;
2070
+ for (const e of EntityAccessor.getChildElements(schema, "enumeration")) {
2071
+ const n = EntityAccessor.getAttributeAsString(e, "name");
2072
+ if (n == enumName)
2073
+ return e;
2074
+ }
2073
2075
  }
2074
2076
 
2075
2077
  /**
@@ -2082,127 +2084,127 @@ class Client {
2082
2084
  * @returns {*} the SOAP call result. If there's just one output parameter, the value itself will be returned. If not, an array will be returned
2083
2085
  */
2084
2086
  async _callMethod(methodName, callContext, parameters) {
2085
- const that = this;
2086
- const schemaId = callContext.schemaId;
2087
-
2088
- var entitySchemaId = schemaId;
2089
- if (schemaId === 'xtk:jobInterface')
2090
- entitySchemaId = callContext.entitySchemaId;
2091
-
2092
- // Get the schema which contains the method call. Methods of the xtk:jobInterface interface are handled specificaaly
2093
- // because xtk:jobInterface is not actually a schema, but just an interface. In practice, it's used as an xtk template
2094
- // rather that an xtk inheritance mechanism
2095
- const methodSchemaId = schemaId === 'xtk:jobInterface' ? 'xtk:job' : schemaId;
2096
- var schema = await that.getSchema(methodSchemaId, "xml", true);
2097
- if (!schema)
2098
- throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Schema '${schemaId}' not found`);
2099
-
2100
- // Lookup the method to call
2101
- var method = await that._methodCache.get(methodSchemaId, methodName);
2102
- if (!method) {
2103
- // first char of the method name may be lower case (ex: nms:seedMember.getAsModel) but the methodName
2104
- // variable has been capitalized. Make an attempt to lookup method name without capitalisation
2105
- const methodNameLC = methodName.substring(0, 1).toLowerCase() + methodName.substring(1);
2106
- method = await that._methodCache.get(schemaId, methodNameLC);
2107
- if (method) methodName = methodNameLC;
2108
- }
2109
- if (!method) {
2110
- await this._methodCache.put(schema);
2111
- method = await that._methodCache.get(methodSchemaId, methodName);
2112
- }
2113
- if (!method)
2114
- throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Method '${methodName}' of schema '${schemaId}' not found`);
2115
-
2116
- // Compute the SOAP URN. Again, specically handle xtk:jobInterface as it's not a real schema. The actual entity schema
2117
- // would be available as the entitySchemaId property of the callContext
2118
- var urn = schemaId !== 'xtk:jobInterface' ? await that._methodCache.getSoapUrn(schemaId, methodName)
2119
- : `xtk:jobInterface|${entitySchemaId}`;
2120
-
2121
- const isStatic = DomUtil.getAttributeAsBoolean(method, "static");
2122
- var soapCall = that._prepareSoapCall(urn, methodName, isStatic, false, callContext.headers, callContext.pushDownOptions);
2123
-
2124
- // If method is called with one parameter which is a function, then we assume it's a hook: the function will return
2125
- // the actual list of parameters
2126
- let isfunc = parameters && typeof parameters === "function";
2127
- if (!isfunc && parameters && parameters.length >= 1 && typeof parameters[0] === "function")
2128
- isfunc = true;
2129
- if (isfunc)
2130
- parameters = parameters[0](method, callContext);
2131
-
2132
- // Create input and output parameters arrays. Each array will contain elements for the corresponding parameter name, type and value
2133
- const inputParams = [];
2134
- const outputParams = [];
2135
-
2136
- // For non static methods
2137
- // in case of persistent job: object represents the entity instance
2138
- // in case of non-persistent job: object represents job description
2139
- // the first output parameters represent the entity itself. The name of the corresponding
2140
- // parameter is set the the entity schema name.
2141
- if (!isStatic) {
2142
- var schemaName = entitySchemaId.substring(entitySchemaId.indexOf(':') + 1);
2143
- if (!callContext.object)
2144
- throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Cannot call non-static method '${methodName}' of schema '${schemaId}' : no object was specified`);
2145
- inputParams.push({
2146
- name: schemaName,
2147
- type: "DOMDocument",
2148
- value: callContext.object
2149
- });
2087
+ const that = this;
2088
+ const schemaId = callContext.schemaId;
2089
+
2090
+ var entitySchemaId = schemaId;
2091
+ if (schemaId === 'xtk:jobInterface')
2092
+ entitySchemaId = callContext.entitySchemaId;
2093
+
2094
+ // Get the schema which contains the method call. Methods of the xtk:jobInterface interface are handled specificaaly
2095
+ // because xtk:jobInterface is not actually a schema, but just an interface. In practice, it's used as an xtk template
2096
+ // rather that an xtk inheritance mechanism
2097
+ const methodSchemaId = schemaId === 'xtk:jobInterface' ? 'xtk:job' : schemaId;
2098
+ var schema = await that.getSchema(methodSchemaId, "xml", true);
2099
+ if (!schema)
2100
+ throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Schema '${schemaId}' not found`);
2101
+
2102
+ // Lookup the method to call
2103
+ var method = await that._methodCache.get(methodSchemaId, methodName);
2104
+ if (!method) {
2105
+ // first char of the method name may be lower case (ex: nms:seedMember.getAsModel) but the methodName
2106
+ // variable has been capitalized. Make an attempt to lookup method name without capitalisation
2107
+ const methodNameLC = methodName.substring(0, 1).toLowerCase() + methodName.substring(1);
2108
+ method = await that._methodCache.get(schemaId, methodNameLC);
2109
+ if (method) methodName = methodNameLC;
2110
+ }
2111
+ if (!method) {
2112
+ await this._methodCache.put(schema);
2113
+ method = await that._methodCache.get(methodSchemaId, methodName);
2114
+ }
2115
+ if (!method)
2116
+ throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Method '${methodName}' of schema '${schemaId}' not found`);
2117
+
2118
+ // Compute the SOAP URN. Again, specically handle xtk:jobInterface as it's not a real schema. The actual entity schema
2119
+ // would be available as the entitySchemaId property of the callContext
2120
+ var urn = schemaId !== 'xtk:jobInterface' ? await that._methodCache.getSoapUrn(schemaId, methodName)
2121
+ : `xtk:jobInterface|${entitySchemaId}`;
2122
+
2123
+ const isStatic = DomUtil.getAttributeAsBoolean(method, "static");
2124
+ var soapCall = that._prepareSoapCall(urn, methodName, isStatic, false, callContext.headers, callContext.pushDownOptions);
2125
+
2126
+ // If method is called with one parameter which is a function, then we assume it's a hook: the function will return
2127
+ // the actual list of parameters
2128
+ let isfunc = parameters && typeof parameters === "function";
2129
+ if (!isfunc && parameters && parameters.length >= 1 && typeof parameters[0] === "function")
2130
+ isfunc = true;
2131
+ if (isfunc)
2132
+ parameters = parameters[0](method, callContext);
2133
+
2134
+ // Create input and output parameters arrays. Each array will contain elements for the corresponding parameter name, type and value
2135
+ const inputParams = [];
2136
+ const outputParams = [];
2137
+
2138
+ // For non static methods
2139
+ // in case of persistent job: object represents the entity instance
2140
+ // in case of non-persistent job: object represents job description
2141
+ // the first output parameters represent the entity itself. The name of the corresponding
2142
+ // parameter is set the the entity schema name.
2143
+ if (!isStatic) {
2144
+ var schemaName = entitySchemaId.substring(entitySchemaId.indexOf(':') + 1);
2145
+ if (!callContext.object)
2146
+ throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Cannot call non-static method '${methodName}' of schema '${schemaId}' : no object was specified`);
2147
+ inputParams.push({
2148
+ name: schemaName,
2149
+ type: "DOMDocument",
2150
+ value: callContext.object
2151
+ });
2152
+ outputParams.push({
2153
+ name: schemaName,
2154
+ type: "DOMDocument"
2155
+ });
2156
+ }
2157
+
2158
+ // Traverse the <parameters> object and create the corresponding parameter objects
2159
+ const parametersIsArray = (typeof parameters == "object") && parameters.length;
2160
+ const params = DomUtil.getFirstChildElement(method, "parameters");
2161
+ if (params) {
2162
+ var param = DomUtil.getFirstChildElement(params, "param");
2163
+ var paramIndex = 0;
2164
+ while (param) {
2165
+ const inout = DomUtil.getAttributeAsString(param, "inout");
2166
+ const type = DomUtil.getAttributeAsString(param, "type");
2167
+ const paramName = DomUtil.getAttributeAsString(param, "name");
2168
+ const isIn = !inout || inout=="in" || inout=="inout";
2169
+ const isOut = inout=="out" || inout=="inout";
2170
+ if (isIn) {
2171
+ let paramValue = parametersIsArray ? parameters[paramIndex] : parameters;
2172
+ const inputParam = {
2173
+ name: paramName,
2174
+ type: type,
2175
+ value: paramValue
2176
+ };
2177
+ inputParams.push(inputParam);
2178
+ paramIndex = paramIndex + 1;
2179
+ }
2180
+ if (isOut) {
2150
2181
  outputParams.push({
2151
- name: schemaName,
2152
- type: "DOMDocument"
2182
+ name: paramName,
2183
+ type: type,
2153
2184
  });
2185
+ }
2186
+ if( !isIn && !isOut) {
2187
+ throw CampaignException.BAD_PARAMETER("inout", inout, `Parameter '${paramName}' of schema '${entitySchemaId}' is not correctly defined as an input or output parameter`);
2188
+ }
2189
+ param = DomUtil.getNextSiblingElement(param, "param");
2154
2190
  }
2191
+ }
2155
2192
 
2156
- // Traverse the <parameters> object and create the corresponding parameter objects
2157
- const parametersIsArray = (typeof parameters == "object") && parameters.length;
2158
- const params = DomUtil.getFirstChildElement(method, "parameters");
2159
- if (params) {
2160
- var param = DomUtil.getFirstChildElement(params, "param");
2161
- var paramIndex = 0;
2162
- while (param) {
2163
- const inout = DomUtil.getAttributeAsString(param, "inout");
2164
- const type = DomUtil.getAttributeAsString(param, "type");
2165
- const paramName = DomUtil.getAttributeAsString(param, "name");
2166
- const isIn = !inout || inout=="in" || inout=="inout";
2167
- const isOut = inout=="out" || inout=="inout";
2168
- if (isIn) {
2169
- let paramValue = parametersIsArray ? parameters[paramIndex] : parameters;
2170
- const inputParam = {
2171
- name: paramName,
2172
- type: type,
2173
- value: paramValue
2174
- };
2175
- inputParams.push(inputParam);
2176
- paramIndex = paramIndex + 1;
2177
- }
2178
- if (isOut) {
2179
- outputParams.push({
2180
- name: paramName,
2181
- type: type,
2182
- });
2183
- }
2184
- if( !isIn && !isOut) {
2185
- throw CampaignException.BAD_PARAMETER("inout", inout, `Parameter '${paramName}' of schema '${entitySchemaId}' is not correctly defined as an input or output parameter`);
2186
- }
2187
- param = DomUtil.getNextSiblingElement(param, "param");
2188
- }
2189
- }
2190
-
2191
- // Make the SOAP call
2192
- await this._makeInterceptableSoapCall(entitySchemaId, schema, soapCall, inputParams, outputParams, callContext.representation);
2193
+ // Make the SOAP call
2194
+ await this._makeInterceptableSoapCall(entitySchemaId, schema, soapCall, inputParams, outputParams, callContext.representation);
2193
2195
 
2194
- // Simplify the result when there's 0 or 1 return value
2195
- if (!isStatic) {
2196
- const newObject = outputParams.shift().value;
2197
- if (newObject) callContext.object = newObject;
2198
- }
2199
- if (outputParams.length == 0) return null;
2200
- if (outputParams.length == 1) return outputParams[0].value;
2201
- const result = [];
2202
- for (var i=0; i<outputParams.length; i++) {
2203
- result.push(outputParams[i].value);
2204
- }
2205
- return result;
2196
+ // Simplify the result when there's 0 or 1 return value
2197
+ if (!isStatic) {
2198
+ const newObject = outputParams.shift().value;
2199
+ if (newObject) callContext.object = newObject;
2200
+ }
2201
+ if (outputParams.length == 0) return null;
2202
+ if (outputParams.length == 1) return outputParams[0].value;
2203
+ const result = [];
2204
+ for (var i=0; i<outputParams.length; i++) {
2205
+ result.push(outputParams[i].value);
2206
+ }
2207
+ return result;
2206
2208
  }
2207
2209
 
2208
2210
  /**
@@ -2220,48 +2222,48 @@ class Client {
2220
2222
  * In addition, the outputParams array will be modified, and the "value" property of each output param will be set
2221
2223
  */
2222
2224
  async makeSoapCall(urn, methodName, isStatic, inputParams, outputParams, representation) {
2223
- const soapCall = this._prepareSoapCall(urn, methodName, isStatic, false,
2224
- this._connectionParameters._options.extraHttpHeaders);
2225
+ const soapCall = this._prepareSoapCall(urn, methodName, isStatic, false,
2226
+ this._connectionParameters._options.extraHttpHeaders);
2225
2227
  // To support anonymous SOAP calls, we need to disable the logon check
2226
- soapCall.requiresLogon = () => false;
2227
- await this._makeInterceptableSoapCall(urn, null, soapCall, inputParams, outputParams, representation);
2228
- const results = outputParams.map((o)=> o.value);
2229
- return results;
2228
+ soapCall.requiresLogon = () => false;
2229
+ await this._makeInterceptableSoapCall(urn, null, soapCall, inputParams, outputParams, representation);
2230
+ const results = outputParams.map((o)=> o.value);
2231
+ return results;
2230
2232
  }
2231
2233
 
2232
2234
  async _makeHttpCall(request) {
2233
- request.method = request.method || "GET";
2234
- request.headers = request.headers || [];
2235
- if (!request.headers['User-Agent'])
2236
- request.headers['User-Agent'] = this._getUserAgentString();
2237
- let event;
2238
- try {
2239
- const safeCallData = Util.trim(request.data);
2240
- if (this._traceAPICalls)
2241
- console.log(`HTTP//request ${request.method} ${request.url}${safeCallData ? " " + safeCallData : ""}`);
2242
- this._notifyObservers((observer) => observer.onHTTPCall && observer.onHTTPCall(request, safeCallData) );
2243
- event = this._trackEvent('HTTP//request', undefined, {
2244
- url: request.url,
2245
- method: request.method,
2246
- headers: request.request,
2247
- safeCallData: safeCallData,
2248
- });
2249
- const body = await this._transport(request);
2250
-
2251
- const safeCallResponse = Util.trim(body);
2252
- if (this._traceAPICalls)
2253
- console.log(`HTTP//response${safeCallResponse ? " " + safeCallResponse : ""}`);
2254
- this._notifyObservers((observer) => observer.onHTTPCallSuccess && observer.onHTTPCallSuccess(request, safeCallResponse) );
2255
- this._trackEvent('HTTP//response', event, { safeCallResponse: safeCallResponse });
2256
- return body;
2257
- } catch(err) {
2258
- if (this._traceAPICalls)
2259
- console.log("HTTP//failure", err);
2260
- this._notifyObservers((observer) => observer.onHTTPCallFailure && observer.onHTTPCallFailure(request, err) );
2261
- const ex = makeCampaignException({ request:request, response:err.response }, err);
2262
- this._trackEvent('HTTP//failure', event, { }, ex);
2263
- throw ex;
2264
- }
2235
+ request.method = request.method || "GET";
2236
+ request.headers = request.headers || [];
2237
+ if (!request.headers['User-Agent'])
2238
+ request.headers['User-Agent'] = this._getUserAgentString();
2239
+ let event;
2240
+ try {
2241
+ const safeCallData = Util.trim(request.data);
2242
+ if (this._traceAPICalls)
2243
+ console.log(`HTTP//request ${request.method} ${request.url}${safeCallData ? " " + safeCallData : ""}`);
2244
+ this._notifyObservers((observer) => observer.onHTTPCall && observer.onHTTPCall(request, safeCallData) );
2245
+ event = this._trackEvent('HTTP//request', undefined, {
2246
+ url: request.url,
2247
+ method: request.method,
2248
+ headers: request.request,
2249
+ safeCallData: safeCallData,
2250
+ });
2251
+ const body = await this._transport(request);
2252
+
2253
+ const safeCallResponse = Util.trim(body);
2254
+ if (this._traceAPICalls)
2255
+ console.log(`HTTP//response${safeCallResponse ? " " + safeCallResponse : ""}`);
2256
+ this._notifyObservers((observer) => observer.onHTTPCallSuccess && observer.onHTTPCallSuccess(request, safeCallResponse) );
2257
+ this._trackEvent('HTTP//response', event, { safeCallResponse: safeCallResponse });
2258
+ return body;
2259
+ } catch(err) {
2260
+ if (this._traceAPICalls)
2261
+ console.log("HTTP//failure", err);
2262
+ this._notifyObservers((observer) => observer.onHTTPCallFailure && observer.onHTTPCallFailure(request, err) );
2263
+ const ex = makeCampaignException({ request:request, response:err.response }, err);
2264
+ this._trackEvent('HTTP//failure', event, { }, ex);
2265
+ throw ex;
2266
+ }
2265
2267
  }
2266
2268
 
2267
2269
  /**
@@ -2271,16 +2273,16 @@ class Client {
2271
2273
  * @returns {Campaign.RedirStatus} an object describing the status of the redirection server
2272
2274
  */
2273
2275
  async test() {
2274
- const request = {
2275
- url: `${this._connectionParameters._endpoint}/r/test`,
2276
- headers: {}
2277
- };
2278
- for (let h in this._connectionParameters._options.extraHttpHeaders)
2279
- request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2280
- const body = await this._makeHttpCall(request);
2281
- const xml = DomUtil.parse(body);
2282
- const result = this._toRepresentation(xml);
2283
- return result;
2276
+ const request = {
2277
+ url: `${this._connectionParameters._endpoint}/r/test`,
2278
+ headers: {}
2279
+ };
2280
+ for (let h in this._connectionParameters._options.extraHttpHeaders)
2281
+ request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2282
+ const body = await this._makeHttpCall(request);
2283
+ const xml = DomUtil.parse(body);
2284
+ const result = this._toRepresentation(xml);
2285
+ return result;
2284
2286
  }
2285
2287
 
2286
2288
  /**
@@ -2289,26 +2291,26 @@ class Client {
2289
2291
  * @returns {Campaign.PingStatus} an object describing the server status
2290
2292
  */
2291
2293
  async ping() {
2292
- const headers = this._getAuthHeaders(true);
2293
- const request = {
2294
- url: `${this._connectionParameters._endpoint}/nl/jsp/ping.jsp`,
2295
- headers: headers,
2296
- };
2297
- for (let h in this._connectionParameters._options.extraHttpHeaders)
2298
- request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2299
- const body = await this._makeHttpCall(request);
2300
- const lines = body.split('\n');
2301
- const doc = DomUtil.newDocument("ping");
2302
- const root = doc.documentElement;
2303
- const status = lines[0].trim();
2304
- if (status != "") root.setAttribute("status", status);
2305
-
2306
- if (lines.length > 1) {
2307
- const timestamp = lines[1].trim();
2308
- if (timestamp != "") root.setAttribute("timestamp", timestamp);
2309
- }
2310
- const result = this._toRepresentation(doc);
2311
- return result;
2294
+ const headers = this._getAuthHeaders(true);
2295
+ const request = {
2296
+ url: `${this._connectionParameters._endpoint}/nl/jsp/ping.jsp`,
2297
+ headers: headers,
2298
+ };
2299
+ for (let h in this._connectionParameters._options.extraHttpHeaders)
2300
+ request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2301
+ const body = await this._makeHttpCall(request);
2302
+ const lines = body.split('\n');
2303
+ const doc = DomUtil.newDocument("ping");
2304
+ const root = doc.documentElement;
2305
+ const status = lines[0].trim();
2306
+ if (status != "") root.setAttribute("status", status);
2307
+
2308
+ if (lines.length > 1) {
2309
+ const timestamp = lines[1].trim();
2310
+ if (timestamp != "") root.setAttribute("timestamp", timestamp);
2311
+ }
2312
+ const result = this._toRepresentation(doc);
2313
+ return result;
2312
2314
  }
2313
2315
 
2314
2316
  /**
@@ -2319,33 +2321,33 @@ class Client {
2319
2321
  * @returns {Campaign.ReportContext} an object containing the context data for a specific report
2320
2322
  */
2321
2323
  async getReportData(callContext, representation) {
2322
- try {
2323
- if(callContext.formData && callContext.formData.ctx) {
2324
- var xmlCtx = this._fromRepresentation('ctx', callContext.formData.ctx);
2325
- callContext.formData.ctx = DomUtil.toXMLString(xmlCtx);
2326
- }
2327
- const selectionCount = callContext.selection.split(',').length;
2324
+ try {
2325
+ if(callContext.formData && callContext.formData.ctx) {
2326
+ var xmlCtx = this._fromRepresentation('ctx', callContext.formData.ctx);
2327
+ callContext.formData.ctx = DomUtil.toXMLString(xmlCtx);
2328
+ }
2329
+ const selectionCount = callContext.selection.split(',').length;
2328
2330
 
2329
- const headers = this._getAuthHeaders(false);
2330
- headers['Content-Type'] = 'application/x-www-form-urlencoded';
2331
- const request = {
2332
- url: `${this._connectionParameters._endpoint}/report/${callContext.reportName}?${encodeURI(`_noRender=true&_schema=${callContext.schema}&_context=${callContext.context}&_selection=${callContext.selection}`)}&_selectionCount=${selectionCount}`,
2333
- headers: headers,
2334
- method: 'POST',
2335
- data : qsStringify(callContext.formData)
2336
- };
2331
+ const headers = this._getAuthHeaders(false);
2332
+ headers['Content-Type'] = 'application/x-www-form-urlencoded';
2333
+ const request = {
2334
+ url: `${this._connectionParameters._endpoint}/report/${callContext.reportName}?${encodeURI(`_noRender=true&_schema=${callContext.schema}&_context=${callContext.context}&_selection=${callContext.selection}`)}&_selectionCount=${selectionCount}`,
2335
+ headers: headers,
2336
+ method: 'POST',
2337
+ data : qsStringify(callContext.formData)
2338
+ };
2337
2339
 
2338
- for (let h in this._connectionParameters._options.extraHttpHeaders)
2339
- request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2340
- const body = await this._makeHttpCall(request);
2341
- if(!body.startsWith("<ctx"))
2342
- throw CampaignException.FEATURE_NOT_SUPPORTED("Reports Data");
2343
- const xml = DomUtil.parse(body);
2344
- const result = this._toRepresentation(xml, representation);
2345
- return result;
2346
- } catch(ex) {
2347
- throw CampaignException.REPORT_FETCH_FAILED(callContext.reportName, ex);
2348
- }
2340
+ for (let h in this._connectionParameters._options.extraHttpHeaders)
2341
+ request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2342
+ const body = await this._makeHttpCall(request);
2343
+ if(!body.startsWith("<ctx"))
2344
+ throw CampaignException.FEATURE_NOT_SUPPORTED("Reports Data");
2345
+ const xml = DomUtil.parse(body);
2346
+ const result = this._toRepresentation(xml, representation);
2347
+ return result;
2348
+ } catch(ex) {
2349
+ throw CampaignException.REPORT_FETCH_FAILED(callContext.reportName, ex);
2350
+ }
2349
2351
  }
2350
2352
 
2351
2353
  /**
@@ -2355,52 +2357,52 @@ class Client {
2355
2357
  * @returns {Campaign.McPingStatus} an object describing Message Center server status
2356
2358
  */
2357
2359
  async mcPing() {
2358
- const headers = this._getAuthHeaders(true);
2359
- const request = {
2360
- url: `${this._connectionParameters._endpoint}/nl/jsp/mcPing.jsp`,
2361
- headers: headers
2362
- };
2363
- for (let h in this._connectionParameters._options.extraHttpHeaders)
2364
- request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2365
- const body = await this._makeHttpCall(request);
2366
- const lines = body.split('\n');
2367
- const doc = DomUtil.newDocument("ping");
2368
- const root = doc.documentElement;
2369
- var status = lines[0].trim();
2370
- if (status != "") root.setAttribute("status", status);
2371
-
2372
- var rtCount;
2373
- var threshold;
2374
- if (status == "Error") {
2375
- const error = lines.length > 1 ? lines[1] : "";
2376
- root.setAttribute("error", error);
2377
- const index1 = error.indexOf('(');
2378
- const index2 = error.indexOf('/');
2379
- const index3 = error.indexOf(')');
2380
- if (index1 != -1 && index2 != -1 && index3 != -1) {
2381
- rtCount = error.substring(index1+1, index2);
2382
- threshold = error.substring(index2+1, index3);
2383
- }
2360
+ const headers = this._getAuthHeaders(true);
2361
+ const request = {
2362
+ url: `${this._connectionParameters._endpoint}/nl/jsp/mcPing.jsp`,
2363
+ headers: headers
2364
+ };
2365
+ for (let h in this._connectionParameters._options.extraHttpHeaders)
2366
+ request.headers[h] = this._connectionParameters._options.extraHttpHeaders[h];
2367
+ const body = await this._makeHttpCall(request);
2368
+ const lines = body.split('\n');
2369
+ const doc = DomUtil.newDocument("ping");
2370
+ const root = doc.documentElement;
2371
+ var status = lines[0].trim();
2372
+ if (status != "") root.setAttribute("status", status);
2373
+
2374
+ var rtCount;
2375
+ var threshold;
2376
+ if (status == "Error") {
2377
+ const error = lines.length > 1 ? lines[1] : "";
2378
+ root.setAttribute("error", error);
2379
+ const index1 = error.indexOf('(');
2380
+ const index2 = error.indexOf('/');
2381
+ const index3 = error.indexOf(')');
2382
+ if (index1 != -1 && index2 != -1 && index3 != -1) {
2383
+ rtCount = error.substring(index1+1, index2);
2384
+ threshold = error.substring(index2+1, index3);
2384
2385
  }
2385
- else {
2386
- if (lines.length > 1) {
2387
- const timestamp = lines[1].trim();
2388
- if (timestamp != "") root.setAttribute("timestamp", timestamp);
2389
- }
2390
- if (lines.length > 2) {
2391
- const queue = lines[2];
2392
- const index2 = queue.indexOf('/');
2393
- const index3 = queue.indexOf(' pending events');
2394
- if (index2 != -1 && index3 != -1) {
2395
- rtCount = queue.substring(0, index2);
2396
- threshold = queue.substring(index2+1, index3);
2397
- }
2398
- }
2386
+ }
2387
+ else {
2388
+ if (lines.length > 1) {
2389
+ const timestamp = lines[1].trim();
2390
+ if (timestamp != "") root.setAttribute("timestamp", timestamp);
2399
2391
  }
2400
- if (rtCount !== undefined && rtCount.trim() != "") root.setAttribute("eventQueueSize", rtCount);
2401
- if (threshold !== undefined && rtCount.trim() != "") root.setAttribute("eventQueueMaxSize", threshold);
2402
- const result = this._toRepresentation(doc);
2403
- return result;
2392
+ if (lines.length > 2) {
2393
+ const queue = lines[2];
2394
+ const index2 = queue.indexOf('/');
2395
+ const index3 = queue.indexOf(' pending events');
2396
+ if (index2 != -1 && index3 != -1) {
2397
+ rtCount = queue.substring(0, index2);
2398
+ threshold = queue.substring(index2+1, index3);
2399
+ }
2400
+ }
2401
+ }
2402
+ if (rtCount !== undefined && rtCount.trim() != "") root.setAttribute("eventQueueSize", rtCount);
2403
+ if (threshold !== undefined && rtCount.trim() != "") root.setAttribute("eventQueueMaxSize", threshold);
2404
+ const result = this._toRepresentation(doc);
2405
+ return result;
2404
2406
  }
2405
2407
 
2406
2408
  /**
@@ -2409,7 +2411,7 @@ class Client {
2409
2411
  * @returns {Campaign.XtkJobInterface} a job
2410
2412
  */
2411
2413
  jobInterface(soapCallSpec) {
2412
- return new XtkJobInterface(this, soapCallSpec);
2414
+ return new XtkJobInterface(this, soapCallSpec);
2413
2415
  }
2414
2416
 
2415
2417
  // Calls the beforeSoapCall method on all observers which have this method. Ignore any exception
@@ -2419,17 +2421,17 @@ class Client {
2419
2421
  // @param {Array<*>} inputParameters is an array containing the method parameters
2420
2422
  // @param {string} representation is the representation (SimpleJson, xml, etc.) used for this method and in which the object and parameters are set
2421
2423
  async _beforeSoapCall(method, inputParameters, representation) {
2422
- if (!representation) representation = this._representation;
2423
- for (const observer of this._observers) {
2424
- if (observer.beforeSoapCall) {
2425
- try {
2426
- await observer.beforeSoapCall(method, inputParameters, representation);
2427
- }
2428
- catch (any) {
2429
- // Ignore errors occuring in observers
2430
- }
2431
- }
2424
+ if (!representation) representation = this._representation;
2425
+ for (const observer of this._observers) {
2426
+ if (observer.beforeSoapCall) {
2427
+ try {
2428
+ await observer.beforeSoapCall(method, inputParameters, representation);
2429
+ }
2430
+ catch (any) {
2431
+ // Ignore errors occuring in observers
2432
+ }
2432
2433
  }
2434
+ }
2433
2435
  }
2434
2436
 
2435
2437
  // Calls the afterSoapCall method on all observers which have this method. Ignore any exception
@@ -2440,25 +2442,25 @@ class Client {
2440
2442
  // @param {string} representation is the representation (SimpleJson, xml, etc.) used for this method and in which the object and parameters are set
2441
2443
  // @param {Array<*>} outputParameters an array (possibly) empty of the values returned by the SOAP call
2442
2444
  async _afterSoapCall(method, inputParameters, representation, outputParameters) {
2443
- if (!representation) representation = this._representation;
2444
- for (const observer of this._observers) {
2445
- if (observer.afterSoapCall) {
2446
- try {
2447
- await observer.afterSoapCall(method, inputParameters, representation, outputParameters);
2448
- }
2449
- catch (any) {
2450
- // Ignore errors occuring in observers
2451
- }
2452
- }
2445
+ if (!representation) representation = this._representation;
2446
+ for (const observer of this._observers) {
2447
+ if (observer.afterSoapCall) {
2448
+ try {
2449
+ await observer.afterSoapCall(method, inputParameters, representation, outputParameters);
2450
+ }
2451
+ catch (any) {
2452
+ // Ignore errors occuring in observers
2453
+ }
2453
2454
  }
2455
+ }
2454
2456
  }
2455
- }
2457
+ }
2456
2458
 
2457
2459
 
2458
- // Public exports
2459
- Client.CampaignException = CampaignException;
2460
- exports.Client = Client;
2461
- exports.Credentials = Credentials;
2462
- exports.ConnectionParameters = ConnectionParameters;
2460
+ // Public exports
2461
+ Client.CampaignException = CampaignException;
2462
+ exports.Client = Client;
2463
+ exports.Credentials = Credentials;
2464
+ exports.ConnectionParameters = ConnectionParameters;
2463
2465
 
2464
2466
  })();