@adobe/acc-js-sdk 1.1.4 → 1.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +3 -1
- package/CHANGELOG.md +18 -1
- package/README.md +54 -4
- package/compile.js +1 -0
- package/package-lock.json +22 -14
- package/package.json +1 -1
- package/src/application.js +35 -2
- package/src/cache.js +30 -1
- package/src/cacheRefresher.js +267 -0
- package/src/campaign.js +29 -28
- package/src/client.js +403 -110
- package/src/soap.js +1 -1
- package/src/transport.js +11 -10
- package/test/application.test.js +2 -2
- package/test/cacheRefresher.test.js +338 -0
- package/test/caches.test.js +22 -1
- package/test/client.test.js +501 -34
- package/test/mock.js +225 -46
- package/test/observability.test.js +267 -0
- package/test/soap.test.js +1 -1
package/src/client.js
CHANGED
|
@@ -10,14 +10,14 @@ 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
|
-
|
|
13
|
+
"use strict";
|
|
14
|
+
|
|
15
15
|
|
|
16
16
|
/**********************************************************************************
|
|
17
|
-
*
|
|
17
|
+
*
|
|
18
18
|
* ACC JavaScript SDK
|
|
19
19
|
* See README.md for usage
|
|
20
|
-
*
|
|
20
|
+
*
|
|
21
21
|
*********************************************************************************/
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -31,6 +31,7 @@ const Cipher = require('./crypto.js').Cipher;
|
|
|
31
31
|
const DomUtil = require('./domUtil.js').DomUtil;
|
|
32
32
|
const MethodCache = require('./methodCache.js').MethodCache;
|
|
33
33
|
const OptionCache = require('./optionCache.js').OptionCache;
|
|
34
|
+
const CacheRefresher = require('./cacheRefresher.js').CacheRefresher;
|
|
34
35
|
const request = require('./transport.js').request;
|
|
35
36
|
const Application = require('./application.js').Application;
|
|
36
37
|
const EntityAccessor = require('./entityAccessor.js').EntityAccessor;
|
|
@@ -38,16 +39,16 @@ const { Util } = require('./util.js');
|
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
41
|
* @namespace Campaign
|
|
41
|
-
*
|
|
42
|
+
*
|
|
42
43
|
* @typedef {Object} SessionInfo
|
|
43
44
|
* @memberOf Campaign
|
|
44
|
-
*
|
|
45
|
+
*
|
|
45
46
|
* @typedef {Object} RedirStatus
|
|
46
47
|
* @memberOf Campaign
|
|
47
|
-
*
|
|
48
|
+
*
|
|
48
49
|
* @typedef {Object} PingStatus
|
|
49
50
|
* @memberOf Campaign
|
|
50
|
-
*
|
|
51
|
+
*
|
|
51
52
|
* @typedef {Object} McPingStatus
|
|
52
53
|
* @memberOf Campaign
|
|
53
54
|
*
|
|
@@ -58,14 +59,14 @@ const { Util } = require('./util.js');
|
|
|
58
59
|
|
|
59
60
|
/**
|
|
60
61
|
* Java Script Proxy handler for an XTK object. An XTK object is one constructed with the following syntax:
|
|
61
|
-
*
|
|
62
|
+
*
|
|
62
63
|
* <code>
|
|
63
64
|
* NLWS.xtkQueryDef.create(...)
|
|
64
65
|
* </code>
|
|
65
|
-
*
|
|
66
|
+
*
|
|
66
67
|
* Any Xtk methods can be called directly on such an object using this proxy handler which will lookup
|
|
67
68
|
* the method definition and manage parameters marshalling and SOAP call
|
|
68
|
-
*
|
|
69
|
+
*
|
|
69
70
|
* @private
|
|
70
71
|
* @memberof Campaign
|
|
71
72
|
*/
|
|
@@ -83,20 +84,20 @@ const xtkObjectHandler = {
|
|
|
83
84
|
return new Proxy(caller, {
|
|
84
85
|
apply: function(target, thisArg, argumentsList) {
|
|
85
86
|
return target(thisArg, argumentsList);
|
|
86
|
-
}
|
|
87
|
+
}
|
|
87
88
|
});
|
|
88
89
|
|
|
89
90
|
}
|
|
90
91
|
};
|
|
91
92
|
|
|
92
93
|
/**
|
|
93
|
-
* Java Script Proxy handler for NLWS.
|
|
94
|
+
* Java Script Proxy handler for NLWS.
|
|
94
95
|
* The proxy resolves constructs such as
|
|
95
|
-
*
|
|
96
|
+
*
|
|
96
97
|
* <code>
|
|
97
98
|
* result = await client.NLWS.xtkSession.getServerTime();
|
|
98
99
|
* </code>
|
|
99
|
-
*
|
|
100
|
+
*
|
|
100
101
|
* To get a handler, call the `clientHandler` function and optionally pass a representation.
|
|
101
102
|
* If no representation is passed (undefined), the representation set at the client level
|
|
102
103
|
* will be used, which is the default behavior.
|
|
@@ -194,7 +195,7 @@ const clientHandler = (representation, headers, pushDownOptions) => {
|
|
|
194
195
|
return new Proxy(caller, {
|
|
195
196
|
apply: function(target, thisArg, argumentsList) {
|
|
196
197
|
return target(thisArg, argumentsList);
|
|
197
|
-
}
|
|
198
|
+
}
|
|
198
199
|
});
|
|
199
200
|
}
|
|
200
201
|
});
|
|
@@ -206,7 +207,7 @@ const clientHandler = (representation, headers, pushDownOptions) => {
|
|
|
206
207
|
// Campaign credentials
|
|
207
208
|
// ========================================================================================
|
|
208
209
|
|
|
209
|
-
/**
|
|
210
|
+
/**
|
|
210
211
|
* @class
|
|
211
212
|
* @constructor
|
|
212
213
|
* @private
|
|
@@ -222,7 +223,7 @@ class Credentials {
|
|
|
222
223
|
* @param {string} securityToken the security token. Will use an empty token if not specified
|
|
223
224
|
*/
|
|
224
225
|
constructor(type, sessionToken, securityToken) {
|
|
225
|
-
if (type != "UserPassword" && type != "ImsServiceToken" && type != "SessionToken" &&
|
|
226
|
+
if (type != "UserPassword" && type != "ImsServiceToken" && type != "SessionToken" &&
|
|
226
227
|
type != "AnonymousUser" && type != "SecurityToken" && type != "BearerToken")
|
|
227
228
|
throw CampaignException.INVALID_CREDENTIALS_TYPE(type);
|
|
228
229
|
this._type = type;
|
|
@@ -236,7 +237,7 @@ class Credentials {
|
|
|
236
237
|
|
|
237
238
|
/**
|
|
238
239
|
* For "UserPassword" type credentials, return the user name
|
|
239
|
-
*
|
|
240
|
+
*
|
|
240
241
|
* @private
|
|
241
242
|
* @returns {string} the user name
|
|
242
243
|
*/
|
|
@@ -250,7 +251,7 @@ class Credentials {
|
|
|
250
251
|
|
|
251
252
|
/**
|
|
252
253
|
* For "UserPassword" type credentials, return the user password
|
|
253
|
-
*
|
|
254
|
+
*
|
|
254
255
|
* @private
|
|
255
256
|
* @returns {string} the user password
|
|
256
257
|
*/
|
|
@@ -288,7 +289,7 @@ class Credentials {
|
|
|
288
289
|
* @property {number} timeout - Can be set to change the HTTP call timeout. Value is passed in ms.
|
|
289
290
|
* @memberOf Campaign
|
|
290
291
|
*/
|
|
291
|
-
|
|
292
|
+
|
|
292
293
|
|
|
293
294
|
/**
|
|
294
295
|
* @class
|
|
@@ -330,7 +331,7 @@ class ConnectionParameters {
|
|
|
330
331
|
|
|
331
332
|
this._options.entityCacheTTL = options.entityCacheTTL || 1000*300; // 5 mins
|
|
332
333
|
this._options.methodCacheTTL = options.methodCacheTTL || 1000*300; // 5 mins
|
|
333
|
-
this._options.optionCacheTTL = options.optionCacheTTL || 1000*300; // 5 mins
|
|
334
|
+
this._options.optionCacheTTL = options.optionCacheTTL || 1000*300; // 5 mins
|
|
334
335
|
this._options.traceAPICalls = options.traceAPICalls === null || options.traceAPICalls ? !!options.traceAPICalls : false;
|
|
335
336
|
this._options.transport = options.transport || request;
|
|
336
337
|
|
|
@@ -342,10 +343,10 @@ class ConnectionParameters {
|
|
|
342
343
|
storage = options.storage;
|
|
343
344
|
try {
|
|
344
345
|
if (!storage)
|
|
345
|
-
storage = localStorage;
|
|
346
|
+
storage = localStorage;
|
|
346
347
|
} catch (ex) {
|
|
347
348
|
/* ignore error if localStorage not found */
|
|
348
|
-
}
|
|
349
|
+
}
|
|
349
350
|
}
|
|
350
351
|
this._options._storage = storage;
|
|
351
352
|
this._options.refreshClient = options.refreshClient;
|
|
@@ -361,7 +362,7 @@ class ConnectionParameters {
|
|
|
361
362
|
|
|
362
363
|
/**
|
|
363
364
|
* Creates connection parameters for a Campaign instance, using a user name and password
|
|
364
|
-
*
|
|
365
|
+
*
|
|
365
366
|
* @param {string} endpoint The campaign endpoint (URL)
|
|
366
367
|
* @param {string} user The user name
|
|
367
368
|
* @param {string} password The user password
|
|
@@ -375,7 +376,7 @@ class ConnectionParameters {
|
|
|
375
376
|
|
|
376
377
|
/**
|
|
377
378
|
* Creates connection parameters for a Campaign instance from bearer token
|
|
378
|
-
*
|
|
379
|
+
*
|
|
379
380
|
* @param {string} endpoint The campaign endpoint (URL)
|
|
380
381
|
* @param {string} bearerToken IMS bearer token
|
|
381
382
|
* @param {*} options connection options
|
|
@@ -387,7 +388,7 @@ class ConnectionParameters {
|
|
|
387
388
|
}
|
|
388
389
|
/**
|
|
389
390
|
* Creates connection parameters for a Campaign instance, using an IMS service token and a user name (the user to impersonate)
|
|
390
|
-
*
|
|
391
|
+
*
|
|
391
392
|
* @param {string} endpoint The campaign endpoint (URL)
|
|
392
393
|
* @param {string} user The user name
|
|
393
394
|
* @param {string} serviceToken The IMS service token
|
|
@@ -401,7 +402,7 @@ class ConnectionParameters {
|
|
|
401
402
|
|
|
402
403
|
/**
|
|
403
404
|
* Creates connection parameters for a Campaign instance, using a session token
|
|
404
|
-
*
|
|
405
|
+
*
|
|
405
406
|
* @static
|
|
406
407
|
* @param {string} endpoint The campaign endpoint (URL)
|
|
407
408
|
* @param {string} sessionToken The session token
|
|
@@ -418,7 +419,7 @@ class ConnectionParameters {
|
|
|
418
419
|
* Typically, called when embedding the SDK in Campaign: the session token will be
|
|
419
420
|
* passed automatically as a cookie, so only the security token is actually needed
|
|
420
421
|
* to logon
|
|
421
|
-
*
|
|
422
|
+
*
|
|
422
423
|
* @static
|
|
423
424
|
* @param {string} endpoint The campaign endpoint (URL)
|
|
424
425
|
* @param {string} securityToken The session token
|
|
@@ -432,7 +433,7 @@ class ConnectionParameters {
|
|
|
432
433
|
|
|
433
434
|
/**
|
|
434
435
|
* Creates connection parameters for a Campaign instance for an anonymous user
|
|
435
|
-
*
|
|
436
|
+
*
|
|
436
437
|
* @param {string} endpoint The campaign endpoint (URL)
|
|
437
438
|
* @param {Campaign.ConnectionOptions} options connection options
|
|
438
439
|
* @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
|
|
@@ -447,7 +448,7 @@ class ConnectionParameters {
|
|
|
447
448
|
* Creates connection parameters for a Campaign instance, using an external account. This can be used to connect
|
|
448
449
|
* to a mid-sourcing instance, or to a message center instance. This function will lookup the external account,
|
|
449
450
|
* and use its credentials to get connection parameters to the corresponding Campaign instance
|
|
450
|
-
*
|
|
451
|
+
*
|
|
451
452
|
* @param {Client} client The Campaign Client from which to lookup the external account (normally, a connected client to the marketing instance)
|
|
452
453
|
* @param {string} extAccountName The name of the external account. Only mid-sourcing accounts (type 3) are supported
|
|
453
454
|
* @returns {ConnectionParameters} a ConnectionParameters object which can be used to create a Client
|
|
@@ -493,6 +494,102 @@ class ConnectionParameters {
|
|
|
493
494
|
|
|
494
495
|
}
|
|
495
496
|
|
|
497
|
+
// ========================================================================================
|
|
498
|
+
// File Uploader
|
|
499
|
+
// ========================================================================================
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* File Uploader API for JS SDK(Currently available only in browsers)
|
|
503
|
+
* @private
|
|
504
|
+
* @ignore
|
|
505
|
+
* @memberof Campaign
|
|
506
|
+
* @param client
|
|
507
|
+
* @returns {{upload: (function(*=): Promise<{name: string, md5: string, type: string, size: string, url: string}>)}}
|
|
508
|
+
*/
|
|
509
|
+
const fileUploader = (client) => {
|
|
510
|
+
|
|
511
|
+
return {
|
|
512
|
+
/**
|
|
513
|
+
* 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.
|
|
514
|
+
* @ignore
|
|
515
|
+
* @param file, where file is an instance of [File](https://developer.mozilla.org/en-US/docs/Web/API/File)
|
|
516
|
+
* @returns {Promise<{name: string, md5: string, type: string, size: string, url: string}>}
|
|
517
|
+
*/
|
|
518
|
+
upload: (file) => {
|
|
519
|
+
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.`);
|
|
520
|
+
return new Promise((resolve, reject) => {
|
|
521
|
+
try {
|
|
522
|
+
if (!Util.isBrowser()) {
|
|
523
|
+
throw 'File uploading is only supported in browser based calls.';
|
|
524
|
+
}
|
|
525
|
+
const data = new FormData();
|
|
526
|
+
data.append('file_noMd5', file);
|
|
527
|
+
//TODO: Needs to be refactored after cookie issue get resolved.
|
|
528
|
+
client._makeHttpCall({
|
|
529
|
+
url: `${client._connectionParameters._endpoint}/nl/jsp/uploadFile.jsp`,
|
|
530
|
+
processData: false,
|
|
531
|
+
credentials: 'include',
|
|
532
|
+
method: 'POST',
|
|
533
|
+
body: data,
|
|
534
|
+
headers: {
|
|
535
|
+
'x-security-token': client._securityToken,
|
|
536
|
+
'Cookie': '__sessiontoken=' + client._sessionToken,
|
|
537
|
+
}
|
|
538
|
+
}).then((okay) => {
|
|
539
|
+
if (!okay.startsWith('Ok')) {
|
|
540
|
+
throw okay;
|
|
541
|
+
}
|
|
542
|
+
const iframe = document.createElement('iframe');
|
|
543
|
+
iframe.style.height = 0;
|
|
544
|
+
iframe.style.width = 0;
|
|
545
|
+
document.controller = { // Written to support https://git.corp.adobe.com/Campaign/ac/blob/v6-master/nl/datakit/nl/jsp/uploadFile.jsp
|
|
546
|
+
uploadFileCallBack: async (data) => {
|
|
547
|
+
if (!data || data.length !== 1) {
|
|
548
|
+
// Tried to replicate the logic for file upload functionality written here:
|
|
549
|
+
// https://git.corp.adobe.com/Campaign/ac/blob/v6-master/wpp/xtk/web/dce/uploader.js
|
|
550
|
+
return reject(CampaignException.FILE_UPLOAD_FAILED(file.name, 'Malformed data:' + data.toString()));
|
|
551
|
+
}
|
|
552
|
+
const counter = await client.NLWS.xtkCounter.increaseValue({name: 'xtkResource'});
|
|
553
|
+
const fileRes= {
|
|
554
|
+
internalName: 'RES' + counter,
|
|
555
|
+
md5: data[0].md5,
|
|
556
|
+
label: data[0].fileName,
|
|
557
|
+
fileName: data[0].fileName,
|
|
558
|
+
originalName: data[0].fileName,
|
|
559
|
+
useMd5AsFilename: '1',
|
|
560
|
+
storageType: 5,
|
|
561
|
+
xtkschema: 'xtk:fileRes'
|
|
562
|
+
|
|
563
|
+
};
|
|
564
|
+
await client.NLWS.xtkSession.write(fileRes);
|
|
565
|
+
await client.NLWS.xtkFileRes.create(fileRes).publishIfNeeded();
|
|
566
|
+
const url = await client.NLWS.xtkFileRes.create(fileRes).getURL();
|
|
567
|
+
resolve({
|
|
568
|
+
name: data[0].fileName,
|
|
569
|
+
md5: data[0].md5,
|
|
570
|
+
type: file.type,
|
|
571
|
+
size: file.size,
|
|
572
|
+
url: url
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
const html = `<body>${okay}</body>`;
|
|
577
|
+
document.body.appendChild(iframe);
|
|
578
|
+
iframe.contentWindow.document.open();
|
|
579
|
+
iframe.contentWindow.document.write(html);
|
|
580
|
+
iframe.contentWindow.document.close();
|
|
581
|
+
}).catch((ex) => {
|
|
582
|
+
reject(CampaignException.FILE_UPLOAD_FAILED(file.name, ex));
|
|
583
|
+
});
|
|
584
|
+
} catch (ex) {
|
|
585
|
+
reject(CampaignException.FILE_UPLOAD_FAILED(file.name, ex));
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
|
|
496
593
|
// ========================================================================================
|
|
497
594
|
// ACC Client
|
|
498
595
|
// ========================================================================================
|
|
@@ -508,7 +605,7 @@ class Client {
|
|
|
508
605
|
/**
|
|
509
606
|
* ACC API Client.
|
|
510
607
|
* Do not create directly, use SDK.init instead
|
|
511
|
-
*
|
|
608
|
+
*
|
|
512
609
|
* @param {Campaign.SDK} sdk is the global sdk object used to create the client
|
|
513
610
|
* @param {Campaign.ConnectionParameters} user user name, for instance admin
|
|
514
611
|
*/
|
|
@@ -521,9 +618,9 @@ class Client {
|
|
|
521
618
|
this._sessionToken = undefined;
|
|
522
619
|
this._securityToken = undefined;
|
|
523
620
|
this._installedPackages = {}; // package set (key and value = package id, ex: "nms:amp")
|
|
524
|
-
|
|
621
|
+
|
|
525
622
|
this._secretKeyCipher = undefined;
|
|
526
|
-
|
|
623
|
+
|
|
527
624
|
this._storage = connectionParameters._options._storage;
|
|
528
625
|
// TODO late cache initiallzation because need XtkDatabaseId / instance name
|
|
529
626
|
var instanceKey = connectionParameters._endpoint || "";
|
|
@@ -532,23 +629,31 @@ class Client {
|
|
|
532
629
|
const rootKey = `acc.js.sdk.${sdk.getSDKVersion().version}.${instanceKey}.cache`;
|
|
533
630
|
|
|
534
631
|
this._entityCache = new XtkEntityCache(this._storage, `${rootKey}.XtkEntityCache`, connectionParameters._options.entityCacheTTL);
|
|
632
|
+
this._entityCacheRefresher = new CacheRefresher(this._entityCache, this, "xtk:schema", `${rootKey}.XtkEntityCache`);
|
|
535
633
|
this._methodCache = new MethodCache(this._storage, `${rootKey}.MethodCache`, connectionParameters._options.methodCacheTTL);
|
|
536
634
|
this._optionCache = new OptionCache(this._storage, `${rootKey}.OptionCache`, connectionParameters._options.optionCacheTTL);
|
|
635
|
+
this._optionCacheRefresher = new CacheRefresher(this._optionCache, this, "xtk:option", `${rootKey}.OptionCache`);
|
|
537
636
|
this.NLWS = new Proxy(this, clientHandler());
|
|
538
637
|
|
|
539
638
|
this._transport = connectionParameters._options.transport;
|
|
540
639
|
this._traceAPICalls = connectionParameters._options.traceAPICalls;
|
|
541
640
|
this._observers = [];
|
|
641
|
+
this._cacheChangeListeners = [];
|
|
542
642
|
this._refreshClient = connectionParameters._options.refreshClient;
|
|
543
643
|
|
|
544
644
|
// expose utilities
|
|
645
|
+
/**
|
|
646
|
+
* File Uploader API
|
|
647
|
+
* @type {{upload: (function(*=): Promise<{name: string, md5: string, type: string, size: string, url: string}>)}}
|
|
648
|
+
*/
|
|
649
|
+
this.fileUploader = fileUploader(this);
|
|
545
650
|
|
|
546
|
-
/**
|
|
651
|
+
/**
|
|
547
652
|
* Accessor to DOM helpers
|
|
548
653
|
* @type {XML.DomUtil}
|
|
549
654
|
*/
|
|
550
655
|
this.DomUtil = DomUtil;
|
|
551
|
-
/**
|
|
656
|
+
/**
|
|
552
657
|
* Accessor to a XtkCaster
|
|
553
658
|
* @type {XtkCaster}
|
|
554
659
|
*/
|
|
@@ -558,12 +663,27 @@ class Client {
|
|
|
558
663
|
* @type {Campaign.Application}
|
|
559
664
|
*/
|
|
560
665
|
this.application = null;
|
|
666
|
+
|
|
667
|
+
// Context for observability. See logon() function which will fill this context
|
|
668
|
+
this._lastStatsReport = Date.now();
|
|
669
|
+
this._observabilityContext = {
|
|
670
|
+
eventId: 0,
|
|
671
|
+
client: {
|
|
672
|
+
sdkVersion: this.sdk.getSDKVersion().version,
|
|
673
|
+
endpoint: this._connectionParameters._endpoint,
|
|
674
|
+
createdAt: Date.now(),
|
|
675
|
+
clientApp: this._connectionParameters._options.clientApp,
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
if (this._connectionParameters._credentials) {
|
|
679
|
+
this._observabilityContext.client.type = this._connectionParameters._credentials.type;
|
|
680
|
+
}
|
|
561
681
|
}
|
|
562
682
|
|
|
563
683
|
/**
|
|
564
684
|
* Override the transport. By default, we are using axios, but this can be customised.
|
|
565
685
|
* See transport.js and documentation in the README for more details
|
|
566
|
-
* @param {*} transport
|
|
686
|
+
* @param {*} transport
|
|
567
687
|
*/
|
|
568
688
|
setTransport(transport) {
|
|
569
689
|
this._transport = transport;
|
|
@@ -571,7 +691,7 @@ class Client {
|
|
|
571
691
|
|
|
572
692
|
/**
|
|
573
693
|
* Get the user agent string to use in all HTTP requests
|
|
574
|
-
*
|
|
694
|
+
*
|
|
575
695
|
* @returns {string} the user agent string
|
|
576
696
|
*/
|
|
577
697
|
_getUserAgentString() {
|
|
@@ -581,7 +701,7 @@ class Client {
|
|
|
581
701
|
|
|
582
702
|
/**
|
|
583
703
|
* Convert an XML object into a representation
|
|
584
|
-
*
|
|
704
|
+
*
|
|
585
705
|
* @private
|
|
586
706
|
* @param {DOMElement} xml the XML DOM element to convert
|
|
587
707
|
* @param {string} representation the expected representation ('xml', 'BadgerFish', or 'SimpleJson'). If not set, will use the current representation
|
|
@@ -598,7 +718,7 @@ class Client {
|
|
|
598
718
|
|
|
599
719
|
/**
|
|
600
720
|
* Convert to an XML object from a representation
|
|
601
|
-
*
|
|
721
|
+
*
|
|
602
722
|
* @private
|
|
603
723
|
* @param {string} rootName the name of the root XML element
|
|
604
724
|
* @param {XML.XtkObject} entity the object to convert
|
|
@@ -618,7 +738,7 @@ class Client {
|
|
|
618
738
|
|
|
619
739
|
/**
|
|
620
740
|
* Convert between 2 representations
|
|
621
|
-
*
|
|
741
|
+
*
|
|
622
742
|
* @private
|
|
623
743
|
* @param {XML.XtkObject} entity the object to convert
|
|
624
744
|
* @param {string} fromRepresentation the source representation ('xml', 'BadgerFish', or 'SimpleJson').
|
|
@@ -636,7 +756,7 @@ class Client {
|
|
|
636
756
|
|
|
637
757
|
/**
|
|
638
758
|
* Compare two representations
|
|
639
|
-
*
|
|
759
|
+
*
|
|
640
760
|
* @private
|
|
641
761
|
* @param {string} rep1 the first representation ('xml', 'BadgerFish', or 'SimpleJson')
|
|
642
762
|
* @param {string} rep2 the second representation ('xml', 'BadgerFish', or 'SimpleJson')
|
|
@@ -652,7 +772,7 @@ class Client {
|
|
|
652
772
|
|
|
653
773
|
/**
|
|
654
774
|
* Activate / deactivate tracing of API calls
|
|
655
|
-
*
|
|
775
|
+
*
|
|
656
776
|
* @param {boolean} trace indicates whether to activate tracing or not
|
|
657
777
|
*/
|
|
658
778
|
traceAPICalls(trace) {
|
|
@@ -688,9 +808,67 @@ class Client {
|
|
|
688
808
|
this._observers.map((observer) => callback(observer));
|
|
689
809
|
}
|
|
690
810
|
|
|
811
|
+
_trackEvent(eventName, parentEvent, payload) {
|
|
812
|
+
try {
|
|
813
|
+
if (payload && payload.name === 'CampaignException') {
|
|
814
|
+
payload = {
|
|
815
|
+
detail: payload.detail,
|
|
816
|
+
errorCode: payload.errorCode,
|
|
817
|
+
faultCode: payload.faultCode,
|
|
818
|
+
faultString: payload.faultString,
|
|
819
|
+
message: payload.message,
|
|
820
|
+
statusCode: payload.statusCode,
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
this._observabilityContext.eventId = this._observabilityContext.eventId + 1;
|
|
824
|
+
const now = Date.now();
|
|
825
|
+
const event = {
|
|
826
|
+
client: this._observabilityContext.client,
|
|
827
|
+
session: this._observabilityContext.session,
|
|
828
|
+
eventId: this._observabilityContext.eventId,
|
|
829
|
+
eventName: eventName,
|
|
830
|
+
payload: payload,
|
|
831
|
+
timestamp: now,
|
|
832
|
+
};
|
|
833
|
+
if (parentEvent) event.parentEventId = parentEvent.eventId;
|
|
834
|
+
this._notifyObservers((observer) => observer.event && observer.event(event, parentEvent));
|
|
835
|
+
|
|
836
|
+
// Regularly report internal stats every 5 mins
|
|
837
|
+
if ((now - this._lastStatsReport) >= 300000) {
|
|
838
|
+
this._lastStatsReport = now;
|
|
839
|
+
this._trackInternalStats();
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
return event;
|
|
843
|
+
} catch (error) {
|
|
844
|
+
console.info(`Failed to track observability event`, error);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
_trackInternalStats() {
|
|
849
|
+
this._trackCacheStats('entityCache', this._entityCache);
|
|
850
|
+
this._trackCacheStats('optionCache', this._optionCache);
|
|
851
|
+
this._trackCacheStats('methodCache', this._methodCache);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
_trackCacheStats(name, cache) {
|
|
855
|
+
if (!cache || !cache._stats) return;
|
|
856
|
+
this._trackEvent('CACHE//stats', undefined, {
|
|
857
|
+
name: name,
|
|
858
|
+
reads: cache._stats.reads,
|
|
859
|
+
writes: cache._stats.writes,
|
|
860
|
+
removals: cache._stats.removals,
|
|
861
|
+
clears: cache._stats.clears,
|
|
862
|
+
memoryHits: cache._stats.memoryHits,
|
|
863
|
+
storageHits: cache._stats.storageHits,
|
|
864
|
+
loads: cache._stats.loads,
|
|
865
|
+
saves: cache._stats.saves,
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
|
|
691
869
|
/**
|
|
692
870
|
* Is the client logged?
|
|
693
|
-
*
|
|
871
|
+
*
|
|
694
872
|
* @returns {boolean} a boolean indicating if the client is logged or not
|
|
695
873
|
*/
|
|
696
874
|
isLogged() {
|
|
@@ -725,7 +903,7 @@ class Client {
|
|
|
725
903
|
|
|
726
904
|
/**
|
|
727
905
|
* Prepares a SOAP call, including authentication, headers...
|
|
728
|
-
*
|
|
906
|
+
*
|
|
729
907
|
* @private
|
|
730
908
|
* @param {string} urn is the API name space, usually the schema. For instance xtk:session
|
|
731
909
|
* @param {string} method is the method to call, for instance Logon
|
|
@@ -734,8 +912,8 @@ class Client {
|
|
|
734
912
|
* parameters should be set
|
|
735
913
|
*/
|
|
736
914
|
_prepareSoapCall(urn, method, internal, extraHttpHeaders, pushDownOptions) {
|
|
737
|
-
const soapCall = new SoapMethodCall(this._transport, urn, method,
|
|
738
|
-
this._sessionToken, this._securityToken,
|
|
915
|
+
const soapCall = new SoapMethodCall(this._transport, urn, method,
|
|
916
|
+
this._sessionToken, this._securityToken,
|
|
739
917
|
this._getUserAgentString(),
|
|
740
918
|
Object.assign({}, this._connectionParameters._options, pushDownOptions),
|
|
741
919
|
extraHttpHeaders);
|
|
@@ -753,16 +931,30 @@ class Client {
|
|
|
753
931
|
async _retrySoapCall(soapCall) {
|
|
754
932
|
soapCall.retry = false;
|
|
755
933
|
soapCall._retryCount = soapCall._retryCount + 1;
|
|
756
|
-
var newClient = await this._refreshClient(this);
|
|
934
|
+
var newClient = await this._refreshClient(this);
|
|
757
935
|
soapCall.finalize(newClient._soapEndPoint(), newClient);
|
|
936
|
+
const safeCallData = Util.trim(soapCall.request.data);
|
|
758
937
|
if (this._traceAPICalls) {
|
|
759
|
-
const safeCallData = Util.trim(soapCall.request.data);
|
|
760
938
|
console.log(`RETRY SOAP//request ${safeCallData}`);
|
|
761
939
|
}
|
|
762
|
-
|
|
763
|
-
|
|
940
|
+
const event = this._trackEvent('SOAP//request', undefined, {
|
|
941
|
+
urn: soapCall.urn,
|
|
942
|
+
methodName: soapCall.methodName,
|
|
943
|
+
internal: soapCall.internal,
|
|
944
|
+
retry: true,
|
|
945
|
+
retryCount: soapCall._retryCount,
|
|
946
|
+
safeCallData: safeCallData,
|
|
947
|
+
});
|
|
948
|
+
try {
|
|
949
|
+
await soapCall.execute();
|
|
764
950
|
const safeCallResponse = Util.trim(soapCall.response);
|
|
765
|
-
|
|
951
|
+
if (this._traceAPICalls) {
|
|
952
|
+
console.log(`SOAP//response ${safeCallResponse}`);
|
|
953
|
+
}
|
|
954
|
+
this._trackEvent('SOAP//response', event, { safeCallResponse: safeCallResponse });
|
|
955
|
+
} catch(error) {
|
|
956
|
+
this._trackEvent('SOAP//failure', event, error);
|
|
957
|
+
throw error;
|
|
766
958
|
}
|
|
767
959
|
return;
|
|
768
960
|
}
|
|
@@ -779,7 +971,7 @@ class Client {
|
|
|
779
971
|
/**
|
|
780
972
|
* After a SOAP method call has been prepared with '_prepareSoapCall', and parameters have been added,
|
|
781
973
|
* this function actually executes the SOAP call
|
|
782
|
-
*
|
|
974
|
+
*
|
|
783
975
|
* @private
|
|
784
976
|
* @param {SOAP.SoapMethodCall} soapCall the SOAP method to call
|
|
785
977
|
*/
|
|
@@ -788,24 +980,34 @@ class Client {
|
|
|
788
980
|
if (soapCall.requiresLogon() && !that.isLogged())
|
|
789
981
|
throw CampaignException.NOT_LOGGED_IN(soapCall, `Cannot execute SOAP call ${soapCall.urn}#${soapCall.methodName}: you are not logged in. Use the Logon function first`);
|
|
790
982
|
soapCall.finalize(this._soapEndPoint());
|
|
791
|
-
|
|
983
|
+
|
|
792
984
|
const safeCallData = Util.trim(soapCall.request.data);
|
|
793
985
|
if (that._traceAPICalls)
|
|
794
986
|
console.log(`SOAP//request ${safeCallData}`);
|
|
795
987
|
that._notifyObservers((observer) => observer.onSOAPCall && observer.onSOAPCall(soapCall, safeCallData) );
|
|
796
|
-
|
|
988
|
+
|
|
989
|
+
const event = this._trackEvent('SOAP//request', undefined, {
|
|
990
|
+
urn: soapCall.urn,
|
|
991
|
+
methodName: soapCall.methodName,
|
|
992
|
+
internal: soapCall.internal,
|
|
993
|
+
retry: false,
|
|
994
|
+
retryCount: soapCall._retryCount,
|
|
995
|
+
safeCallData: safeCallData,
|
|
996
|
+
});
|
|
797
997
|
return soapCall.execute()
|
|
798
998
|
.then(() => {
|
|
799
999
|
const safeCallResponse = Util.trim(soapCall.response);
|
|
800
1000
|
if (that._traceAPICalls)
|
|
801
1001
|
console.log(`SOAP//response ${safeCallResponse}`);
|
|
802
1002
|
that._notifyObservers((observer) => observer.onSOAPCallSuccess && observer.onSOAPCallSuccess(soapCall, safeCallResponse) );
|
|
1003
|
+
this._trackEvent('SOAP//response', event, { safeCallResponse: safeCallResponse });
|
|
803
1004
|
return Promise.resolve();
|
|
804
1005
|
})
|
|
805
1006
|
.catch((ex) => {
|
|
806
1007
|
if (that._traceAPICalls)
|
|
807
1008
|
console.log(`SOAP//failure ${ex.toString()}`);
|
|
808
1009
|
that._notifyObservers((observer) => observer.onSOAPCallFailure && observer.onSOAPCallFailure(soapCall, ex) );
|
|
1010
|
+
this._trackEvent('SOAP//failure', event, ex);
|
|
809
1011
|
// Call session expiration callback in case of 401
|
|
810
1012
|
if (ex.statusCode == 401 && that._refreshClient && soapCall.retry) {
|
|
811
1013
|
return this._retrySoapCall(soapCall);
|
|
@@ -815,6 +1017,32 @@ class Client {
|
|
|
815
1017
|
});
|
|
816
1018
|
}
|
|
817
1019
|
|
|
1020
|
+
_onLogon() {
|
|
1021
|
+
this.application = new Application(this);
|
|
1022
|
+
this.application._registerCacheChangeListener();
|
|
1023
|
+
this._observabilityContext.instance = {
|
|
1024
|
+
buildNumber: this.application.buildNumber,
|
|
1025
|
+
version: this.application.version,
|
|
1026
|
+
instanceName: this.application.instanceName,
|
|
1027
|
+
};
|
|
1028
|
+
if (this.application.operator) {
|
|
1029
|
+
this._observabilityContext.instance.operator = {
|
|
1030
|
+
login: this.application.operator.login,
|
|
1031
|
+
id: this.application.operator.id,
|
|
1032
|
+
timezone: this.application.operator.timezone,
|
|
1033
|
+
rights: this.application.operator.rights,
|
|
1034
|
+
packages: this.application.operator.packages,
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
this._observabilityContext.session = {
|
|
1038
|
+
logonAt: Date.now(),
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
_onLogoff() {
|
|
1043
|
+
delete this._observabilityContext.instance;
|
|
1044
|
+
delete this._observabilityContext.session;
|
|
1045
|
+
}
|
|
818
1046
|
|
|
819
1047
|
/**
|
|
820
1048
|
* Login to an instance
|
|
@@ -839,6 +1067,8 @@ class Client {
|
|
|
839
1067
|
// See NEO-35259
|
|
840
1068
|
this._connectionParameters._options.extraHttpHeaders['X-Query-Source'] = `${version}${clientApp? "," + clientApp : ""}`;
|
|
841
1069
|
|
|
1070
|
+
this._trackEvent('SDK//logon', undefined, {});
|
|
1071
|
+
|
|
842
1072
|
// Clear session token cookie to ensure we're not inheriting an expired cookie. See NEO-26589
|
|
843
1073
|
if (credentials._type != "SecurityToken" && typeof document != "undefined") {
|
|
844
1074
|
document.cookie = '__sessiontoken=;path=/;';
|
|
@@ -848,7 +1078,7 @@ class Client {
|
|
|
848
1078
|
that._installedPackages = {};
|
|
849
1079
|
that._sessionToken = credentials._sessionToken;
|
|
850
1080
|
that._securityToken = "";
|
|
851
|
-
that.
|
|
1081
|
+
that._onLogon();
|
|
852
1082
|
return Promise.resolve();
|
|
853
1083
|
}
|
|
854
1084
|
else if (credentials._type == "SecurityToken") {
|
|
@@ -856,7 +1086,7 @@ class Client {
|
|
|
856
1086
|
that._installedPackages = {};
|
|
857
1087
|
that._sessionToken = "";
|
|
858
1088
|
that._securityToken = credentials._securityToken;
|
|
859
|
-
that.
|
|
1089
|
+
that._onLogon();
|
|
860
1090
|
return Promise.resolve();
|
|
861
1091
|
}
|
|
862
1092
|
else if (credentials._type == "UserPassword" || credentials._type == "BearerToken") {
|
|
@@ -880,10 +1110,10 @@ class Client {
|
|
|
880
1110
|
else {
|
|
881
1111
|
const bearerToken = credentials._bearerToken;
|
|
882
1112
|
soapCall.writeString("bearerToken", bearerToken);
|
|
883
|
-
}
|
|
1113
|
+
}
|
|
884
1114
|
return this._makeSoapCall(soapCall).then(function() {
|
|
885
1115
|
const sessionToken = soapCall.getNextString();
|
|
886
|
-
|
|
1116
|
+
|
|
887
1117
|
that._sessionInfo = soapCall.getNextDocument();
|
|
888
1118
|
that._installedPackages = {};
|
|
889
1119
|
const userInfo = DomUtil.findElement(that._sessionInfo, "userInfo");
|
|
@@ -895,7 +1125,7 @@ class Client {
|
|
|
895
1125
|
that._installedPackages[name] = name;
|
|
896
1126
|
pack = DomUtil.getNextSiblingElement(pack);
|
|
897
1127
|
}
|
|
898
|
-
|
|
1128
|
+
|
|
899
1129
|
const securityToken = soapCall.getNextString();
|
|
900
1130
|
soapCall.checkNoMoreArgs();
|
|
901
1131
|
// Sanity check: we should have both a session token and a security token.
|
|
@@ -907,7 +1137,7 @@ class Client {
|
|
|
907
1137
|
that._sessionToken = sessionToken;
|
|
908
1138
|
that._securityToken = securityToken;
|
|
909
1139
|
|
|
910
|
-
that.
|
|
1140
|
+
that._onLogon();
|
|
911
1141
|
});
|
|
912
1142
|
}
|
|
913
1143
|
else {
|
|
@@ -918,7 +1148,7 @@ class Client {
|
|
|
918
1148
|
|
|
919
1149
|
/**
|
|
920
1150
|
* Get details about the session (assumes client is logged)
|
|
921
|
-
*
|
|
1151
|
+
*
|
|
922
1152
|
* @param {string} representation the expected representation. If not set, will use the default client representation
|
|
923
1153
|
* @returns {Campaign.SessionInfo} details about the session
|
|
924
1154
|
*/
|
|
@@ -932,47 +1162,55 @@ class Client {
|
|
|
932
1162
|
*/
|
|
933
1163
|
logoff() {
|
|
934
1164
|
var that = this;
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1165
|
+
try {
|
|
1166
|
+
if (!that.isLogged()) return;
|
|
1167
|
+
that.application._unregisterCacheChangeListener();
|
|
1168
|
+
that._unregisterAllCacheChangeListeners();
|
|
1169
|
+
this.stopRefreshCaches();
|
|
1170
|
+
const credentials = this._connectionParameters._credentials;
|
|
1171
|
+
if (credentials._type != "SessionToken" && credentials._type != "AnonymousUser") {
|
|
1172
|
+
var soapCall = that._prepareSoapCall("xtk:session", "Logoff", false, this._connectionParameters._options.extraHttpHeaders);
|
|
939
1173
|
return this._makeSoapCall(soapCall).then(function() {
|
|
1174
|
+
that._sessionToken = "";
|
|
1175
|
+
that._securityToken = "";
|
|
1176
|
+
that.application = null;
|
|
1177
|
+
soapCall.checkNoMoreArgs();
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
else {
|
|
940
1181
|
that._sessionToken = "";
|
|
941
1182
|
that._securityToken = "";
|
|
942
1183
|
that.application = null;
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
that._sessionToken = "";
|
|
948
|
-
that._securityToken = "";
|
|
949
|
-
that.application = null;
|
|
1184
|
+
}
|
|
1185
|
+
} finally {
|
|
1186
|
+
this._trackEvent('SDK//logoff', undefined, {});
|
|
1187
|
+
this._onLogoff();
|
|
950
1188
|
}
|
|
951
1189
|
}
|
|
952
1190
|
|
|
953
1191
|
/**
|
|
954
1192
|
* Get the value of an option
|
|
955
|
-
*
|
|
1193
|
+
*
|
|
956
1194
|
* @param {string} name is the option name, for instance XtkDatabaseId
|
|
957
1195
|
* @param {boolean} useCache indicates whether to use the cache or not. Default is true
|
|
958
1196
|
* @return the option value, casted in the expected data type. If the option does not exist, it will return null.
|
|
959
1197
|
*/
|
|
960
1198
|
async getOption(name, useCache = true) {
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1199
|
+
var value;
|
|
1200
|
+
if (useCache) {
|
|
1201
|
+
value = this._optionCache.get(name);
|
|
1202
|
+
}
|
|
1203
|
+
if (value === undefined) {
|
|
1204
|
+
const option = await this.NLWS.xtkSession.getOption(name);
|
|
1205
|
+
value = this._optionCache.put(name, option);
|
|
1206
|
+
}
|
|
1207
|
+
return value;
|
|
970
1208
|
}
|
|
971
1209
|
|
|
972
1210
|
/**
|
|
973
1211
|
* Set an option value. Creates the option if it does not exists. Update the option
|
|
974
1212
|
* if it exists already
|
|
975
|
-
*
|
|
1213
|
+
*
|
|
976
1214
|
* @param {string} name the option name
|
|
977
1215
|
* @param {*} rawValue the value to set
|
|
978
1216
|
* @param {string} description the optional description of the option
|
|
@@ -989,7 +1227,7 @@ class Client {
|
|
|
989
1227
|
var attName = XtkCaster._variantStorageAttribute(type);
|
|
990
1228
|
if (!attName) {
|
|
991
1229
|
// could not infer the storage type of the attribute to use to store the value (when option did not exist before) => assume string
|
|
992
|
-
type = 6;
|
|
1230
|
+
type = 6;
|
|
993
1231
|
attName = "stringValue";
|
|
994
1232
|
}
|
|
995
1233
|
var doc = { xtkschema: "xtk:option", _operation: "insertOrUpdate", _key: "@name", name: name, dataType: type };
|
|
@@ -1032,9 +1270,53 @@ class Client {
|
|
|
1032
1270
|
this.clearOptionCache();
|
|
1033
1271
|
}
|
|
1034
1272
|
|
|
1273
|
+
/**
|
|
1274
|
+
* Start auto refresh of all caches
|
|
1275
|
+
* @param {integer} refreshFrequency refresh frequency in ms. 10000 ms by default.
|
|
1276
|
+
*/
|
|
1277
|
+
startRefreshCaches(refreshFrequency) {
|
|
1278
|
+
if (refreshFrequency === undefined || refreshFrequency === null)
|
|
1279
|
+
refreshFrequency = 10000;
|
|
1280
|
+
this._optionCacheRefresher.startAutoRefresh(refreshFrequency);
|
|
1281
|
+
// Start auto refresh for entityCache a little later
|
|
1282
|
+
setTimeout(() => { this._entityCacheRefresher.startAutoRefresh(refreshFrequency); }, refreshFrequency/2);
|
|
1283
|
+
}
|
|
1284
|
+
/**
|
|
1285
|
+
* Stop auto refresh of all caches
|
|
1286
|
+
*/
|
|
1287
|
+
stopRefreshCaches() {
|
|
1288
|
+
this._optionCacheRefresher.stopAutoRefresh();
|
|
1289
|
+
this._entityCacheRefresher.stopAutoRefresh();
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
// Register a callback to be called when a schema has been modified and should be removed
|
|
1293
|
+
// from the caches
|
|
1294
|
+
_registerCacheChangeListener(listener) {
|
|
1295
|
+
this._cacheChangeListeners.push(listener);
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// Unregister a cache change listener
|
|
1299
|
+
_unregisterCacheChangeListener(listener) {
|
|
1300
|
+
for (var i = 0; i < this._cacheChangeListeners.length; i++) {
|
|
1301
|
+
if (this._cacheChangeListeners[i] == listener) {
|
|
1302
|
+
this._cacheChangeListeners.splice(i, 1);
|
|
1303
|
+
break;
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
// Unregister all cache change listener
|
|
1309
|
+
_unregisterAllCacheChangeListeners() {
|
|
1310
|
+
this._cacheChangeListeners = [];
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
_notifyCacheChangeListeners(schemaId) {
|
|
1314
|
+
this._cacheChangeListeners.map((listener) => listener.invalidateCacheItem(schemaId));
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1035
1317
|
/**
|
|
1036
1318
|
* Tests if a package is installed
|
|
1037
|
-
*
|
|
1319
|
+
*
|
|
1038
1320
|
* @param {string} packageId the package identifier, for instance: "nms:amp"
|
|
1039
1321
|
* @param {string} optionalName if set, the first parameter will be interpreted as the namespace (ex: "nms") and the second as the name, ex: "amp"
|
|
1040
1322
|
* @returns {boolean} a boolean indicating if the package is installed or not
|
|
@@ -1049,8 +1331,8 @@ class Client {
|
|
|
1049
1331
|
|
|
1050
1332
|
/**
|
|
1051
1333
|
* Obtains a cipher that can be used to encrypt/decrypt passwords, using the database secret key.
|
|
1052
|
-
* This is used for example for mid-sourcing account.
|
|
1053
|
-
*
|
|
1334
|
+
* This is used for example for mid-sourcing account.
|
|
1335
|
+
*
|
|
1054
1336
|
* @private
|
|
1055
1337
|
* @deprecated since version 1.0.0
|
|
1056
1338
|
*/
|
|
@@ -1065,10 +1347,10 @@ class Client {
|
|
|
1065
1347
|
|
|
1066
1348
|
/**
|
|
1067
1349
|
* Gets an entity, such as a schema, a source schema, a form, a navtree, etc. Each Campaign entity has a MD5 which is used to determine
|
|
1068
|
-
* if an entity has changed or not. The GetEntityIfMoreRecent SOAP call can use this MD5 to avoid returning entities that did not
|
|
1350
|
+
* if an entity has changed or not. The GetEntityIfMoreRecent SOAP call can use this MD5 to avoid returning entities that did not
|
|
1069
1351
|
* actually changed. Currently, the SDK, however is not able to use the MD5 and will perform a SOAP call every time the function is
|
|
1070
1352
|
* called and return the whole entity
|
|
1071
|
-
*
|
|
1353
|
+
*
|
|
1072
1354
|
* @param {string} entityType is the type of entity requested, such as "xtk:schema", "xtk:srcSchema", "xtk:navtree", "xtk:form", etc.
|
|
1073
1355
|
* @param {string} fullName is the fully qualified name of the entity (i.e. <namespace>:<name>)
|
|
1074
1356
|
* @param {string} representation the expected representation, or undefined to set the default
|
|
@@ -1091,7 +1373,7 @@ class Client {
|
|
|
1091
1373
|
|
|
1092
1374
|
/**
|
|
1093
1375
|
* Get a compiled schema (not a source schema) definition as a DOM or JSON object depending on hte current representation
|
|
1094
|
-
*
|
|
1376
|
+
*
|
|
1095
1377
|
* @param {string} schemaId the schema id, such as "xtk:session", or "nms:recipient"
|
|
1096
1378
|
* @param {string} representation an optional representation of the schema: "BadgerFish", "SimpleJson" or "xml". If not set, we'll use the client default representation
|
|
1097
1379
|
* @param {boolean} internal indicates an "internal" call, i.e. a call performed by the SDK itself rather than the user of the SDK. For instance, the SDK will dynamically load schemas to find method definitions
|
|
@@ -1101,18 +1383,19 @@ class Client {
|
|
|
1101
1383
|
var that = this;
|
|
1102
1384
|
var entity = that._entityCache.get("xtk:schema", schemaId);
|
|
1103
1385
|
if (!entity) {
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
if (entity)
|
|
1386
|
+
entity = await that.getEntityIfMoreRecent("xtk:schema", schemaId, "xml", internal);
|
|
1387
|
+
if (entity) {
|
|
1107
1388
|
that._entityCache.put("xtk:schema", schemaId, entity);
|
|
1108
|
-
|
|
1389
|
+
that._methodCache.put(entity);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1109
1392
|
entity = that._toRepresentation(entity, representation);
|
|
1110
1393
|
return entity;
|
|
1111
1394
|
}
|
|
1112
1395
|
|
|
1113
1396
|
/**
|
|
1114
1397
|
* Get the definition of a system enumeration (SysEnum). Will be returned as JSON or XML depending on the client 'representation' attribute
|
|
1115
|
-
*
|
|
1398
|
+
*
|
|
1116
1399
|
* @param {string} enumName
|
|
1117
1400
|
* @param {string} optionalStartSchemaOrSchemaName
|
|
1118
1401
|
* @returns {XML.XtkObject} the enumeration definition in the current representation
|
|
@@ -1138,13 +1421,13 @@ class Client {
|
|
|
1138
1421
|
if (index == -1)
|
|
1139
1422
|
throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `getEnum expects a valid schema name. '${optionalStartSchemaOrSchemaName}' is not a valid name.`);
|
|
1140
1423
|
optionalStartSchemaOrSchemaName = await this.getSchema(optionalStartSchemaOrSchemaName, undefined, true);
|
|
1141
|
-
if (!optionalStartSchemaOrSchemaName)
|
|
1424
|
+
if (!optionalStartSchemaOrSchemaName)
|
|
1142
1425
|
throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `Schema '${optionalStartSchemaOrSchemaName}' not found.`);
|
|
1143
1426
|
}
|
|
1144
|
-
else
|
|
1427
|
+
else
|
|
1145
1428
|
throw CampaignException.BAD_PARAMETER("optionalStartSchemaOrSchemaName", optionalStartSchemaOrSchemaName, `getEnum expects a valid schema name wich is a string. Given ${typeof optionalStartSchemaOrSchemaName} instead`);
|
|
1146
1429
|
|
|
1147
|
-
const schema = optionalStartSchemaOrSchemaName;
|
|
1430
|
+
const schema = optionalStartSchemaOrSchemaName;
|
|
1148
1431
|
for (const e of EntityAccessor.getChildElements(schema, "enumeration")) {
|
|
1149
1432
|
const n = EntityAccessor.getAttributeAsString(e, "name");
|
|
1150
1433
|
if (n == enumName)
|
|
@@ -1154,7 +1437,7 @@ class Client {
|
|
|
1154
1437
|
|
|
1155
1438
|
/**
|
|
1156
1439
|
* Call Campaign SOAP method
|
|
1157
|
-
*
|
|
1440
|
+
*
|
|
1158
1441
|
* @private
|
|
1159
1442
|
* @param {string} methodName is the method to call. In order to be more JavaScript friendly, the first char can be lower-cased
|
|
1160
1443
|
* @param {*} callContext the call context)
|
|
@@ -1165,7 +1448,7 @@ class Client {
|
|
|
1165
1448
|
const that = this;
|
|
1166
1449
|
const result = [];
|
|
1167
1450
|
const schemaId = callContext.schemaId;
|
|
1168
|
-
|
|
1451
|
+
|
|
1169
1452
|
var schema = await that.getSchema(schemaId, "xml", true);
|
|
1170
1453
|
if (!schema)
|
|
1171
1454
|
throw CampaignException.SOAP_UNKNOWN_METHOD(schemaId, methodName, `Schema '${schemaId}' not found`);
|
|
@@ -1260,7 +1543,7 @@ class Client {
|
|
|
1260
1543
|
param = DomUtil.getNextSiblingElement(param, "param");
|
|
1261
1544
|
}
|
|
1262
1545
|
}
|
|
1263
|
-
|
|
1546
|
+
|
|
1264
1547
|
return that._makeSoapCall(soapCall).then(function() {
|
|
1265
1548
|
if (!isStatic) {
|
|
1266
1549
|
// Non static methods, such as xtk:query#SelectAll return a element named "entity" which is the object itself on which
|
|
@@ -1359,30 +1642,40 @@ class Client {
|
|
|
1359
1642
|
request.headers = request.headers || [];
|
|
1360
1643
|
if (!request.headers['User-Agent'])
|
|
1361
1644
|
request.headers['User-Agent'] = this._getUserAgentString();
|
|
1645
|
+
let event;
|
|
1362
1646
|
try {
|
|
1363
1647
|
const safeCallData = Util.trim(request.data);
|
|
1364
1648
|
if (this._traceAPICalls)
|
|
1365
1649
|
console.log(`HTTP//request ${request.method} ${request.url}${safeCallData ? " " + safeCallData : ""}`);
|
|
1366
1650
|
this._notifyObservers((observer) => observer.onHTTPCall && observer.onHTTPCall(request, safeCallData) );
|
|
1651
|
+
event = this._trackEvent('HTTP//request', undefined, {
|
|
1652
|
+
url: request.url,
|
|
1653
|
+
method: request.method,
|
|
1654
|
+
headers: request.request,
|
|
1655
|
+
safeCallData: safeCallData,
|
|
1656
|
+
});
|
|
1367
1657
|
const body = await this._transport(request);
|
|
1368
1658
|
|
|
1369
1659
|
const safeCallResponse = Util.trim(body);
|
|
1370
1660
|
if (this._traceAPICalls)
|
|
1371
1661
|
console.log(`HTTP//response${safeCallResponse ? " " + safeCallResponse : ""}`);
|
|
1372
1662
|
this._notifyObservers((observer) => observer.onHTTPCallSuccess && observer.onHTTPCallSuccess(request, safeCallResponse) );
|
|
1663
|
+
this._trackEvent('HTTP//response', event, { safeCallResponse: safeCallResponse });
|
|
1373
1664
|
return body;
|
|
1374
1665
|
} catch(err) {
|
|
1375
1666
|
if (this._traceAPICalls)
|
|
1376
1667
|
console.log("HTTP//failure", err);
|
|
1377
1668
|
this._notifyObservers((observer) => observer.onHTTPCallFailure && observer.onHTTPCallFailure(request, err) );
|
|
1378
|
-
|
|
1669
|
+
const ex = makeCampaignException({ request:request, reqponse:err.response }, err);
|
|
1670
|
+
this._trackEvent('HTTP//failure', event, { }, ex);
|
|
1671
|
+
throw ex;
|
|
1379
1672
|
}
|
|
1380
1673
|
}
|
|
1381
1674
|
|
|
1382
1675
|
/**
|
|
1383
1676
|
* Tests if the Campaign redirection server is up (/r/test).
|
|
1384
1677
|
* Does not require a logged client
|
|
1385
|
-
*
|
|
1678
|
+
*
|
|
1386
1679
|
* @returns {Campaign.RedirStatus} an object describing the status of the redirection server
|
|
1387
1680
|
*/
|
|
1388
1681
|
async test() {
|
|
@@ -1400,12 +1693,12 @@ class Client {
|
|
|
1400
1693
|
|
|
1401
1694
|
/**
|
|
1402
1695
|
* Ping the Campaign server (/nl/jsp/ping.jsp)
|
|
1403
|
-
*
|
|
1696
|
+
*
|
|
1404
1697
|
* @returns {Campaign.PingStatus} an object describing the server status
|
|
1405
1698
|
*/
|
|
1406
1699
|
async ping() {
|
|
1407
1700
|
const request = {
|
|
1408
|
-
url: `${this._connectionParameters._endpoint}/nl/jsp/ping.jsp`,
|
|
1701
|
+
url: `${this._connectionParameters._endpoint}/nl/jsp/ping.jsp`,
|
|
1409
1702
|
headers: {
|
|
1410
1703
|
'X-Security-Token': this._securityToken,
|
|
1411
1704
|
'Cookie': '__sessiontoken=' + this._sessionToken
|
|
@@ -1431,12 +1724,12 @@ class Client {
|
|
|
1431
1724
|
/**
|
|
1432
1725
|
* Ping a Message Center Campaign server (/nl/jsp/mcPing.jsp).
|
|
1433
1726
|
* Assumes Message Center is installed
|
|
1434
|
-
*
|
|
1727
|
+
*
|
|
1435
1728
|
* @returns {Campaign.McPingStatus} an object describing Message Center server status
|
|
1436
1729
|
*/
|
|
1437
1730
|
async mcPing() {
|
|
1438
1731
|
const request = {
|
|
1439
|
-
url: `${this._connectionParameters._endpoint}/nl/jsp/mcPing.jsp`,
|
|
1732
|
+
url: `${this._connectionParameters._endpoint}/nl/jsp/mcPing.jsp`,
|
|
1440
1733
|
headers: {
|
|
1441
1734
|
'X-Security-Token': this._securityToken,
|
|
1442
1735
|
'Cookie': '__sessiontoken=' + this._sessionToken
|
|
@@ -1450,7 +1743,7 @@ class Client {
|
|
|
1450
1743
|
const root = doc.documentElement;
|
|
1451
1744
|
var status = lines[0].trim();
|
|
1452
1745
|
if (status != "") root.setAttribute("status", status);
|
|
1453
|
-
|
|
1746
|
+
|
|
1454
1747
|
var rtCount;
|
|
1455
1748
|
var threshold;
|
|
1456
1749
|
if (status == "Error") {
|
|
@@ -1493,4 +1786,4 @@ exports.Client = Client;
|
|
|
1493
1786
|
exports.Credentials = Credentials;
|
|
1494
1787
|
exports.ConnectionParameters = ConnectionParameters;
|
|
1495
1788
|
|
|
1496
|
-
})();
|
|
1789
|
+
})();
|