@adobe/acc-js-sdk 1.0.5 → 1.0.8

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.
@@ -20,7 +20,7 @@ governing permissions and limitations under the License.
20
20
  *********************************************************************************/
21
21
 
22
22
  const DomUtil = require('./domUtil.js').DomUtil;
23
- const { Cache } = require('./util.js');
23
+ const { Cache } = require('./cache.js');
24
24
 
25
25
  /**
26
26
  * @namespace Campaign
@@ -41,12 +41,31 @@ class MethodCache extends Cache {
41
41
  * A in-memory cache for SOAP call method definitions. Not intended to be used directly,
42
42
  * but an internal cache for the Campaign.Client object
43
43
  *
44
+ * Cached object are made of
45
+ * - the key is a string in the form <schemaId>#<methodName>, such as "xtk:session#GetServerTime"
46
+ * - the value is a JSON object made of two attributes:
47
+ * - the "urn" attribute, such as "xtk:persist", which is the URN to use to make the SOAP call
48
+ * - the "method" attribute, a DOM element corresponding to the method XML element
49
+ *
44
50
  * @param {Storage} storage is an optional Storage object, such as localStorage or sessionStorage
45
51
  * @param {string} rootKey is an optional root key to use for the storage object
46
52
  * @param {number} ttl is the TTL for objects in ms. Defaults to 5 mins
47
53
  */
48
54
  constructor(storage, rootKey, ttl) {
49
- super(storage, rootKey, ttl, ((schemaId, methodName) => schemaId + "#" + methodName ));
55
+ super(storage, rootKey, ttl, ((schemaId, methodName) => schemaId + "#" + methodName ), (item, serDeser) => {
56
+ if (serDeser) {
57
+ if (!item || !item.value || !item.value.method) throw Error(`Cannot serialize falsy cached item`);
58
+ const value = Object.assign({}, item); // shallow copy
59
+ value.value = Object.assign({}, value.value); // dummy deep copy
60
+ value.value.method = DomUtil.toXMLString(item.value.method);
61
+ return JSON.stringify(value);
62
+ }
63
+ else {
64
+ const json = JSON.parse(item);
65
+ json.value.method = DomUtil.parse(json.value.method).documentElement;
66
+ return json;
67
+ }
68
+ });
50
69
  }
51
70
 
52
71
  /**
@@ -18,7 +18,7 @@ governing permissions and limitations under the License.
18
18
  *
19
19
  *********************************************************************************/
20
20
  const XtkCaster = require('./xtkCaster.js').XtkCaster;
21
- const { Cache } = require('./util.js');
21
+ const { Cache } = require('./cache.js');
22
22
 
23
23
 
24
24
  /**
@@ -44,6 +44,10 @@ class OptionCache extends Cache {
44
44
  * A in-memory cache for xtk option values. Not intended to be used directly,
45
45
  * but an internal cache for the Campaign.Client object
46
46
  *
47
+ * Cached object are made of
48
+ * - the key is the option name
49
+ * - the value is the option, a JSON object made of value, type, and rawValue properties
50
+ *
47
51
  * @param {Storage} storage is an optional Storage object, such as localStorage or sessionStorage
48
52
  * @param {string} rootKey is an optional root key to use for the storage object
49
53
  * @param {number} ttl is the TTL for objects in ms. Defaults to 5 mins
package/src/soap.js CHANGED
@@ -93,6 +93,8 @@ class SoapMethodCall {
93
93
  // Soap calls marked as internal are calls performed by the framework internally
94
94
  // (such as GetEntityIfMoreRecent calls needed to lookup schemas)
95
95
  this.internal = false;
96
+ // Enable soap retry
97
+ this.retry = true;
96
98
 
97
99
  this._sessionToken = sessionToken || "";
98
100
  this._securityToken = securityToken || "";
@@ -119,7 +121,8 @@ class SoapMethodCall {
119
121
  * @returns {boolean} indicates if the call requires a Logon first
120
122
  */
121
123
  requiresLogon() {
122
- const requiresLogon = !(this.urn === "xtk:session" && this.methodName === "Logon");
124
+ const requiresLogon = !(this.urn === "xtk:session" &&
125
+ (this.methodName === "Logon" || this.methodName === "BearerTokenLogon") ) ;
123
126
  return requiresLogon;
124
127
  }
125
128
 
@@ -150,22 +153,6 @@ class SoapMethodCall {
150
153
  this._method.setAttribute(`xmlns:m`, urnPath);
151
154
  this._method.setAttribute(`SOAP-ENV:encodingStyle`, encoding);
152
155
  this._data.appendChild(this._method);
153
-
154
- if (this._sessionToken) {
155
- const cookieHeader = this._doc.createElement("Cookie");
156
- cookieHeader.textContent = `__sessiontoken=${this._sessionToken}`;
157
- this._header.appendChild(cookieHeader);
158
- }
159
-
160
- const securityTokenHeader = this._doc.createElement("X-Security-Token");
161
- securityTokenHeader.textContent = this._securityToken;
162
- this._header.appendChild(securityTokenHeader);
163
-
164
- // Always write a sessiontoken element as the first parameter. Even when using SecurityToken authentication
165
- // and when the session token is actually passed implicitely as a cookie, one must write a sessiontoken
166
- // element. If not, authentication will fail because the first parameter is interpreted as the "authentication mode"
167
- // and eventually passed as the first parameter of CXtkLocalSessionPart::GetXtkSecurity
168
- this.writeString("sessiontoken", this._sessionToken);
169
156
  }
170
157
 
171
158
  /**
@@ -541,12 +528,50 @@ class SoapMethodCall {
541
528
  options.headers['User-Agent'] = this._userAgentString;
542
529
  return options;
543
530
  }
544
-
531
+
545
532
  /**
546
533
  * Finalize a SOAP call just before sending
547
534
  * @param {string} url the endpoint (/nl/jsp/soaprouter.jsp)
535
+ * @param {client.Client} sdk client (optional)
548
536
  */
549
- finalize(url) {
537
+ finalize(url, client) {
538
+ if (client) {
539
+ this._sessionToken = client._sessionToken;
540
+ this._securityToken = client._securityToken;
541
+ }
542
+
543
+ var cookieHeader = DomUtil.findElement(this._header, "Cookie");
544
+ if (this._sessionToken) {
545
+ if (!cookieHeader) {
546
+ cookieHeader = this._doc.createElement("Cookie");
547
+ this._header.appendChild(cookieHeader);
548
+ }
549
+ cookieHeader.textContent = `__sessiontoken=${this._sessionToken}`;
550
+ } else if (cookieHeader) {
551
+ cookieHeader.remove();
552
+ }
553
+
554
+ var securityTokenHeader = DomUtil.findElement(this._header, "X-Security-Token");
555
+ if (!securityTokenHeader) {
556
+ securityTokenHeader = this._doc.createElement("X-Security-Token");
557
+ this._header.appendChild(securityTokenHeader);
558
+ }
559
+ securityTokenHeader.textContent = this._securityToken;
560
+
561
+ // Always write a sessiontoken element as the first parameter. Even when using SecurityToken authentication
562
+ // and when the session token is actually passed implicitely as a cookie, one must write a sessiontoken
563
+ // element. If not, authentication will fail because the first parameter is interpreted as the "authentication mode"
564
+ // and eventually passed as the first parameter of CXtkLocalSessionPart::GetXtkSecurity
565
+ var sessionTokenElem = DomUtil.findElement(this._method, "sessiontoken");
566
+ if (sessionTokenElem) {
567
+ sessionTokenElem.textContent = this._sessionToken;
568
+ } else {
569
+ sessionTokenElem = this._doc.createElement("sessiontoken");
570
+ sessionTokenElem.setAttribute("xsi:type", "xsd:string");
571
+ // sessionTokenElem.setAttribute("SOAP-ENV:encodingStyle", SOAP_ENCODING_NATIVE);
572
+ sessionTokenElem.textContent = this._sessionToken;
573
+ this._method.prepend(sessionTokenElem);
574
+ }
550
575
  const options = this._createHTTPRequest(url);
551
576
  // Prepare request and empty response objects
552
577
  this.request = options;
@@ -564,6 +589,8 @@ class SoapMethodCall {
564
589
  const that = this;
565
590
  const promise = this._transport(this.request);
566
591
  return promise.then(function(body) {
592
+ if (body.indexOf(`XSV-350008`) != -1)
593
+ throw CampaignException.SESSION_EXPIRED();
567
594
  that.response = body;
568
595
  // Response is a serialized XML document with the following structure
569
596
  //
@@ -0,0 +1,47 @@
1
+ const { DomUtil } = require("./domUtil");
2
+
3
+ /*
4
+ Copyright 2022 Adobe. All rights reserved.
5
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License. You may obtain a copy
7
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software distributed under
10
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
11
+ OF ANY KIND, either express or implied. See the License for the specific language
12
+ governing permissions and limitations under the License.
13
+ */
14
+ (function() {
15
+ "use strict";
16
+
17
+ const { newSchema } = require("./application");
18
+
19
+ /**********************************************************************************
20
+ *
21
+ * Utilities for testing
22
+ *
23
+ *********************************************************************************/
24
+
25
+ /**
26
+ * @namespace Utils
27
+ */
28
+
29
+ /**
30
+ * @memberof Utils
31
+ * @class
32
+ * @constructor
33
+ */
34
+ class TestUtil {
35
+
36
+ static newSchema(xml) {
37
+ if (typeof xml === "string")
38
+ xml = DomUtil.parse(xml);
39
+ return newSchema(xml);
40
+ }
41
+ }
42
+
43
+
44
+ // Public expots
45
+ exports.TestUtil = TestUtil;
46
+
47
+ })();
package/src/util.js CHANGED
@@ -135,236 +135,7 @@ class Util {
135
135
  }
136
136
  }
137
137
 
138
-
139
- /**********************************************************************************
140
- *
141
- * A simple cache for XtkEntities, options, etc.
142
- *
143
- *********************************************************************************/
144
-
145
- /**
146
- * @private
147
- * @class
148
- * @constructor
149
- * @memberof Utils
150
- */
151
- class SafeStorage {
152
-
153
- /**
154
- * A wrapper to the Storage interface (LocalStorage, etc.) which is "safe", i.e.
155
- *
156
- * - it will never throw / support local stroage to be undefined or not accessible
157
- * - Handle the notion of "root key", i.e. prefix
158
- * - Set/get values as JSON only and not as strings
159
- * - Silently caches all exceptions
160
- * - Automatically remove from storage cached values which are not valid, expired, or cannot be parsed
161
- *
162
- * SafeStorage objects are created automatically by Caches
163
- *
164
- * @param {Storage} delegate an optional delegate options, confomring to the Storage interface (getItem, setItem, removeItem)
165
- * @param {string} rootKey an optional prefix which will be prepend to all keys
166
- */
167
- constructor(delegate, rootKey) {
168
- this._delegate = delegate;
169
- this._rootKey = rootKey ? `${rootKey}$` : "";
170
- }
171
-
172
- /**
173
- * Get an item from storage
174
- * @param {string} key the item key (relative to the root key)
175
- * @returns {Object} the cached JSON object, or undefined if not found
176
- */
177
- getItem(key) {
178
- if (!this._delegate || this._rootKey === undefined || this._rootKey === null)
179
- return;
180
- const itemKey = `${this._rootKey}${key}`;
181
- const raw = this._delegate.getItem(itemKey);
182
- if (!raw)
183
- return undefined;
184
- try {
185
- return JSON.parse(raw);
186
- } catch(ex) {
187
- this.removeItem(key);
188
- }
189
- }
190
-
191
- /**
192
- * Put an item into storage
193
- * @param {string} key the item key (relative to the root key)
194
- * @param {Object} json the value to cache
195
- */
196
- setItem(key, json) {
197
- if (!this._delegate || this._rootKey === undefined || this._rootKey === null)
198
- return;
199
- try {
200
- if (json && typeof json === "object") {
201
- const raw = JSON.stringify(json);
202
- this._delegate.setItem(`${this._rootKey}${key}`, raw);
203
- return;
204
- }
205
- } catch(ex) { /* Ignore errors in safe class */
206
- }
207
- this.removeItem(key);
208
- }
209
-
210
- /**
211
- * Removes an item from the storage
212
- * @param {string} key the item key (relative to the root key)
213
- */
214
- removeItem(key) {
215
- if (!this._delegate || this._rootKey === undefined || this._rootKey === null)
216
- return;
217
- try {
218
- this._delegate.removeItem(`${this._rootKey}${key}`);
219
- } catch(ex) { /* Ignore errors in safe class */
220
- }
221
- }
222
- }
223
-
224
- /**
225
- * @private
226
- * @class
227
- * @constructor
228
- * @memberof Utils
229
- */
230
- class CachedObject {
231
-
232
- /**
233
- * An object in the cache, i.e. a wrapped to a cached value and additional metadata to manage the cache.
234
- * Do not create such objects directly, they are 100% managed by the Cache object
235
- *
236
- * @param {*} value the cached value
237
- * @param {number} cachedAt the timestamp at which the value was cached
238
- * @param {number} expiresAt the timestamp at which the cached value expires
239
- */
240
- constructor(value, cachedAt, expiresAt) {
241
- this.value = value;
242
- this.cachedAt = cachedAt;
243
- this.expiresAt = expiresAt;
244
- }
245
- }
246
-
247
- /**
248
- * @private
249
- * @class
250
- * @constructor
251
- * @memberof Utils
252
- */
253
- class Cache {
254
-
255
- /**
256
- * A general purpose in-memory cache with TTL. In addition to caching in memory, the cache has the ability to delegate the caching
257
- * to a persistent cache, such as the browser localStorage. The interface is 100% synchronous.
258
- *
259
- * By default, caches take a single parameter for the key. It is possible however to use a more complex scenario by setting a makeKeyFn.
260
- * When set, such a function will take 1 or more arguments and will be responsible to create a primitive key (a string) from the arguments.
261
- * The cache public APIs : get and put therefore can take a variable number of key arguments, which will be combined into the actual primitive key.
262
- *
263
- * @param {Storage} storage is an optional Storage object, such as localStorage or sessionStorage. This object will be wrapped into a SafeStorage object to ensure access is safe and will not throw any exceptions
264
- * @param {string} rootKey is an optional root key to use for the storage object
265
- * @param {number} ttl is the TTL for objects in ms. Defaults to 5 mins
266
- * @param {function} makeKeyFn is an optional function which will generate a key for objects in the cache. It's passed the arguments of the cache 'get' function
267
- */
268
- constructor(storage, rootKey, ttl, makeKeyFn) {
269
- this._storage = new SafeStorage(storage, rootKey);
270
- this._ttl = ttl || 1000*300;
271
- this._makeKeyFn = makeKeyFn || ((x) => x);
272
- this._cache = {};
273
- // timestamp at which the cache was last cleared
274
- this._lastCleared = this._loadLastCleared();
275
- }
276
-
277
- // Load timestamp at which the cache was last cleared
278
- _loadLastCleared() {
279
- const json = this._storage.getItem("lastCleared");
280
- return json ? json.timestamp : undefined;
281
- }
282
-
283
- _saveLastCleared() {
284
- const now = Date.now();
285
- this._lastCleared = now;
286
- this._storage.setItem("lastCleared", { timestamp: now});
287
- }
288
-
289
- // Load from local storage
290
- _load(key) {
291
- const json = this._storage.getItem(key);
292
- if (!json || !json.cachedAt || json.cachedAt <= this._lastCleared) {
293
- this._storage.removeItem(key);
294
- return;
295
- }
296
- return json;
297
- }
298
-
299
- // Save to local storage
300
- _save(key, cached) {
301
- this._storage.setItem(key, cached);
302
- }
303
-
304
- // Remove from local storage
305
- _remove(key) {
306
- this._storage.removeItem(key);
307
- }
308
-
309
- _getIfActive(key) {
310
- // In memory cache?
311
- var cached = this._cache[key];
312
- // Local storage ?
313
- if (!cached) {
314
- cached = this._load(key);
315
- this._cache[key] = cached;
316
- }
317
- if (!cached)
318
- return undefined;
319
- if (cached.expiresAt <= Date.now()) {
320
- delete this._cache[key];
321
- this._remove(key);
322
- return undefined;
323
- }
324
- return cached.value;
325
- }
326
-
327
- /**
328
- * Get a value from the cache
329
- * @param {*} key the key or keys of the value to retreive
330
- * @returns {*} the cached value, or undefined if not found
331
- */
332
- get() {
333
- const key = this._makeKeyFn.apply(this, arguments);
334
- const cached = this._getIfActive(key);
335
- return cached;
336
- }
337
-
338
- /**
339
- * Put a value from the cache
340
- * @param {*} key the key or keys of the value to retreive
341
- * @param {*} value the value to cache
342
- * @returns {CachedObject} a cached object containing the cached value
343
- */
344
- put() {
345
- const value = arguments[arguments.length -1];
346
- const key = this._makeKeyFn.apply(this, arguments);
347
- const now = Date.now();
348
- const expiresAt = now + this._ttl;
349
- const cached = new CachedObject(value, now, expiresAt);
350
- this._cache[key] = cached;
351
- this._save(key, cached);
352
- return cached;
353
- }
354
-
355
- /**
356
- * Removes everything from the cache. It does not directly removes data from persistent storage if there is, but it marks the cache
357
- * as cleared so that subsequent get operation will not actually return any data cached in persistent storage
358
- */
359
- clear() {
360
- this._cache = {};
361
- this._saveLastCleared();
362
- }
363
- }
364
-
365
138
  // Public expots
366
139
  exports.Util = Util;
367
- exports.SafeStorage = SafeStorage;
368
- exports.Cache = Cache;
369
140
 
370
141
  })();
package/src/xtkCaster.js CHANGED
@@ -12,6 +12,8 @@ governing permissions and limitations under the License.
12
12
  (function() {
13
13
  "use strict";
14
14
 
15
+ const { Util } = require('./util.js');
16
+
15
17
  /**********************************************************************************
16
18
  *
17
19
  * Helper class to cast values to and from their Xtk versions
@@ -37,11 +39,15 @@ governing permissions and limitations under the License.
37
39
  | Xtk type | | JS type | Comment |
38
40
  | ------------ |----|-------- | --- |
39
41
  | string | 6 | string | never null, defaults to "" |
40
- | memo | 12 | string |
41
- | CDATA | 13 | string |
42
+ | memo | 12 | string | large strings. Never null, defaults to ""
43
+ | CDATA | 13 | string | string in the CDATA section of an XML document. Never null, defaults to ""
44
+ | uuid | | string |
45
+ | blob | | string |
46
+ | html | | string |
42
47
  | byte | 1 | number | signed integer in the [-128, 128[ range. Never null, defaults to 0 |
43
48
  | short | 2 | number | signed 16 bits integer in the [-32768, 32768[ range. Never null, defaults to 0 |
44
49
  | long | 3 | number | signed 32 bits integer. Never null, defaults to 0 |
50
+ | int | | number | signed 32 bits integer. Never null, defaults to 0 |
45
51
  | int64 | | string | signed 64 bits integer. As JavaScript handles all numbers as doubles, it's not possible to properly represent an int64 as a number, and it's therefore represented as a string.
46
52
  | float | 4 | number | single-percision numeric value. Never null, defaults to 0 |
47
53
  | double | 5 | number | single-percision numeric value. Never null, defaults to 0 |
@@ -49,10 +55,11 @@ governing permissions and limitations under the License.
49
55
  | datetimetz | | | |
50
56
  | datetimenotz | | | |
51
57
  | date | 10 | Date | UTC timestamp with day precision. Can be null |
58
+ | timespan | 14 | number | A timespan, in seconds
52
59
  | boolean | 15 | boolean | boolean value, defaultint to false. Cannot be null |
53
- | timespan | | | |
60
+ | array | | Array | a array or a collection
54
61
 
55
- * @typedef {(0|''|6|'string'|'int64'|12|13|'memo'|'CDATA'|1|'byte'|2|'short'|3|'long'|15|'boolean'|4|5|'float'|'double'|7|'datetime'|'datetimetz'|'datetimenotz'|10|'date')} XtkType
62
+ * @typedef {(0|''|6|'string'|'int64'|12|13|'memo'|'CDATA'|1|'byte'|2|'short'|3|'long'|15|'boolean'|4|5|'float'|'double'|7|'datetime'|'datetimetz'|'datetimenotz'|10|'date'|14|'timespan'|'array')} XtkType
56
63
  * @memberof Campaign
57
64
  */
58
65
 
@@ -85,10 +92,13 @@ class XtkCaster {
85
92
  return null;
86
93
  case 6: // FIELD_SZ
87
94
  case "string":
95
+ case "uuid":
88
96
  case "int64":
89
97
  return "stringValue";
90
98
  case 12: // FIELD_MEMO
91
99
  case 13: // FIELD_MEMOSHORT
100
+ case "blob":
101
+ case "html":
92
102
  case "memo":
93
103
  case "CDATA":
94
104
  return "memoValue";
@@ -97,8 +107,10 @@ class XtkCaster {
97
107
  case 2: // FIELD_SHORT
98
108
  case "short":
99
109
  case 3: // FIELD_LONG
110
+ case "int":
100
111
  case "long":
101
- case 15: // FIELD_BOOLEAN
112
+ case "timespan":
113
+ case 15: // FIELD_BOOLEAN
102
114
  case "boolean":
103
115
  return "longValue";
104
116
  case 4: // FIELD_FLOAT
@@ -137,6 +149,9 @@ class XtkCaster {
137
149
  case 13: // FIELD_MEMOSHORT
138
150
  case "string":
139
151
  case "memo":
152
+ case "uuid":
153
+ case "blob":
154
+ case "html":
140
155
  case "CDATA": {
141
156
  return this.asString(value);
142
157
  }
@@ -149,6 +164,7 @@ class XtkCaster {
149
164
  return this.asShort(value);
150
165
  }
151
166
  case 3: // FIELD_LONG
167
+ case "int":
152
168
  case "long": {
153
169
  return this.asLong(value);
154
170
  }
@@ -175,6 +191,13 @@ class XtkCaster {
175
191
  case "date": {
176
192
  return this.asDate(value);
177
193
  }
194
+ case "array": {
195
+ return this.asArray(value);
196
+ }
197
+ case 14: // FIELD_TIMESPAN
198
+ case "timespan": {
199
+ return this.asTimespan(value);
200
+ }
178
201
  default: {
179
202
  throw CampaignException.BAD_PARAMETER("type", type, `Cannot convert value type='${type}', value='${value}'`);
180
203
  }
@@ -318,6 +341,16 @@ class XtkCaster {
318
341
  return number;
319
342
  }
320
343
 
344
+ /**
345
+ * Convert a raw value into a timestamp (alias to the "asTimestamp" function)
346
+ *
347
+ * @param {*} value is the raw value to convert
348
+ * @return {Date} the timestamp, possibly null
349
+ */
350
+ static asDatetime(value) {
351
+ return this.asTimestamp(value);
352
+ }
353
+
321
354
  /**
322
355
  * Convert a raw value into a timestamp
323
356
  *
@@ -354,7 +387,7 @@ class XtkCaster {
354
387
  }
355
388
 
356
389
  /**
357
- * Convert a raw value into a date. This is a UTC timestamp where time fields are 0
390
+ * Convert a raw value into a date. This is a UTC timestamp where time fields are 0
358
391
  *
359
392
  * @param {*} value is the raw value to convert
360
393
  * @return {Date} a date
@@ -369,8 +402,49 @@ class XtkCaster {
369
402
  }
370
403
  return timestamp;
371
404
  }
405
+
406
+ /**
407
+ * Convert a raw value into an array (if it is not an array yet). Null and undefined will be
408
+ * converted into an empty array
409
+ *
410
+ * @param {*} value is the raw value to convert
411
+ * @return {Array} a array
412
+ */
413
+ static asArray(value) {
414
+ if (value === null || value === undefined) return [];
415
+ if (Util.isArray(value)) return value;
416
+ return [value];
417
+ }
418
+
419
+ /**
420
+ * Convert a raw value into a timespan, in seconds
421
+ * @param {*} value is the raw value to convert
422
+ * @returns is the time span, in seconds
423
+ */
424
+ static asTimespan(value) {
425
+ if (value === null || value === undefined) return 0;
426
+ if ((typeof value) == "string") value = value.trim();
427
+ if (value === "" || value === true || value === false) return 0;
428
+ if (value !== value || value === Number.POSITIVE_INFINITY || value === Number.NEGATIVE_INFINITY) return 0;
429
+ // Number to timespan -> Consider as number of seconds
430
+ var timespan = XtkCaster.asLong(value);
431
+ return timespan;
432
+ }
433
+
434
+ static isTimeType(type) {
435
+ return type === "datetime" || type === "datetimetz" || type === "datetimenotz" || type === "timestamp" || type === "date" || type === "time" || type === "timespan" || type === 7 || type === 10 || type === 14;
436
+ }
437
+
438
+ static isStringType(type) {
439
+ return type === "string" || type === "memo" || type === 6 || type === 12 || type === 13 || type === "blob" || type === "html" || type === "CDATA";
440
+ }
441
+
442
+ static isNumericType(type) {
443
+ return type === "byte" || type === 1 || type === "short" || type === 2 || type === "int" || type === "long" || type === 3 || type === "float" || type === 4 || type === "double" || type === 5 || type === "timespan" || type === 14;
444
+ }
372
445
  }
373
446
 
447
+
374
448
  exports.XtkCaster = XtkCaster;
375
449
 
376
450
  })();
@@ -13,7 +13,7 @@ governing permissions and limitations under the License.
13
13
  "use strict";
14
14
 
15
15
  const DomUtil = require('./domUtil.js').DomUtil;
16
- const { Cache } = require('./util.js');
16
+ const { Cache } = require('./cache.js');
17
17
 
18
18
 
19
19
  /**********************************************************************************
@@ -32,14 +32,30 @@ class XtkEntityCache extends Cache {
32
32
 
33
33
  /**
34
34
  * A in-memory cache for xtk entities. Not intended to be used directly,
35
- * but an internal cache for the Campaign.Client object
35
+ * but an internal cache for the Campaign.Client object.
36
+ *
37
+ * Cached object are made of
38
+ * - the key is a string in the form <entityType>|<entityName>, such as "xtk:schema|nms:recipient"
39
+ * - the value is a DOM element corresponding to the entity. It's always a DOM element, regardless of the client representation
36
40
  *
37
41
  * @param {Storage} storage is an optional Storage object, such as localStorage or sessionStorage
38
42
  * @param {string} rootKey is an optional root key to use for the storage object
39
43
  * @param {number} ttl is the TTL for objects in ms. Defaults to 5 mins
40
44
  */
41
45
  constructor(storage, rootKey, ttl) {
42
- super(storage, rootKey, ttl, (entityType, entityFullName) => entityType + "|" + entityFullName);
46
+ super(storage, rootKey, ttl, (entityType, entityFullName) => entityType + "|" + entityFullName, (item, serDeser) => {
47
+ if (serDeser) {
48
+ if (!item || !item.value) throw Error(`Cannot serialize falsy cached item`);
49
+ const value = Object.assign({}, item);
50
+ value.value = DomUtil.toXMLString(item.value);
51
+ return JSON.stringify(value);
52
+ }
53
+ else {
54
+ const json = JSON.parse(item);
55
+ json.value = DomUtil.parse(json.value).documentElement;
56
+ return json;
57
+ }
58
+ });
43
59
  }
44
60
 
45
61
  /**