@adobe/acc-js-sdk 1.1.10 → 1.1.12

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 (78) hide show
  1. package/README.md +8 -2170
  2. package/docs/404.html +11 -0
  3. package/docs/Gemfile +35 -0
  4. package/docs/Gemfile.lock +270 -0
  5. package/docs/_config.yml +55 -0
  6. package/docs/_data/navigation.yml +119 -0
  7. package/docs/_includes/navigation.html +33 -0
  8. package/docs/_layouts/default.html +21 -0
  9. package/docs/_layouts/home.html +4 -0
  10. package/docs/_layouts/page.html +5 -0
  11. package/docs/_layouts/post.html +7 -0
  12. package/docs/_posts/2022-10-14-welcome.html +149 -0
  13. package/docs/application.html +367 -0
  14. package/docs/architecture.html +24 -0
  15. package/docs/assets/css/styles.css +362 -0
  16. package/docs/assets/images/adobe-campaign-256.png +0 -0
  17. package/docs/assets/images/architecture.png +0 -0
  18. package/docs/assets/images/ref.svg +6 -0
  19. package/docs/badgerFish.html +14 -0
  20. package/docs/bestPractices.html +189 -0
  21. package/docs/blog.html +18 -0
  22. package/docs/buildAndRun.html +96 -0
  23. package/docs/caches.html +68 -0
  24. package/docs/changeLog.html +263 -0
  25. package/docs/checkList.html +168 -0
  26. package/docs/concepts.html +130 -0
  27. package/docs/connecting.html +210 -0
  28. package/docs/connectionParameters.html +109 -0
  29. package/docs/contribute.html +54 -0
  30. package/docs/dataTypes.html +124 -0
  31. package/docs/differences.html +4 -0
  32. package/docs/documentation.html +21 -0
  33. package/docs/domHelper.html +88 -0
  34. package/docs/dynamicInvoke.html +36 -0
  35. package/docs/entityAccessor.html +22 -0
  36. package/docs/errors.html +47 -0
  37. package/docs/escaping.html +76 -0
  38. package/docs/favicon.png +0 -0
  39. package/docs/healthCheck.html +66 -0
  40. package/docs/httpHeaders.html +78 -0
  41. package/docs/index.html +64 -0
  42. package/docs/installation.html +34 -0
  43. package/docs/license.html +208 -0
  44. package/docs/messageCenter.html +80 -0
  45. package/docs/methodLevelRepresentation.html +12 -0
  46. package/docs/midSourcing.html +19 -0
  47. package/docs/observability.html +169 -0
  48. package/docs/passwords.html +27 -0
  49. package/docs/profiles.html +103 -0
  50. package/docs/pushDown.html +13 -0
  51. package/docs/quickstart.html +69 -0
  52. package/docs/release.html +52 -0
  53. package/docs/samples.html +82 -0
  54. package/docs/simpleJson.html +88 -0
  55. package/docs/soapAPIs.html +234 -0
  56. package/docs/timeouts.html +23 -0
  57. package/docs/transport.html +45 -0
  58. package/docs/troubleshooting.html +17 -0
  59. package/docs/writeDoc.html +208 -0
  60. package/docs/xml2json.html +96 -0
  61. package/docs/xtkCaster.html +67 -0
  62. package/docs/xtkInterface.html +20 -0
  63. package/docs/xtkOption.html +54 -0
  64. package/docs/xtkPackage.html +16 -0
  65. package/docs/xtkPersist.html +213 -0
  66. package/docs/xtkQueryDef.html +245 -0
  67. package/docs/xtkSchema.html +39 -0
  68. package/docs/xtkSession.html +29 -0
  69. package/docs/xtkWorkflow.html +28 -0
  70. package/docs/xtkWrite.html +51 -0
  71. package/package-lock.json +1 -1
  72. package/package.json +1 -1
  73. package/src/application.js +15 -5
  74. package/src/campaign.js +1 -1
  75. package/src/soap.js +6 -6
  76. package/test/application.test.js +21 -6
  77. package/test/soap.test.js +13 -0
  78. package/CHANGELOG.md +0 -252
package/README.md CHANGED
@@ -1,25 +1,23 @@
1
- # Adobe Campaign Classic (ACC) SDK in JavaScript (node.js and browser)
2
-
3
- This is a node.js SDK for Campaign API. It exposes the Campaign API exactly like it is used inside Campaign using the NLWS notation.
1
+ # Adobe Campaign Classic (ACC) SDK in JavaScript
4
2
 
3
+ The ACC JavaScript SDK is a JavaScript SDK which allows you to call Campaign APIs in a simple, expressive and JavaScript idiomatic way. It hides away the Campaign complexities associated with having to make SOAP calls, XML to JSON conversion, type formatting, etc.
5
4
 
5
+ The API is fully asynchronous using promises and works as well on the server side than on the client side in the browser.
6
6
 
7
- # Change log
8
7
 
9
- See the [Change log](./CHANGELOG.md) for more information about the different versions, changes, etc.
10
8
 
9
+ > **Extensive documentation is available**: https://opensource.adobe.com/acc-js-sdk/
11
10
 
12
- # Overview
13
11
 
14
- The ACC JavaScript SDK is a JavaScript SDK which allows you to call Campaign APIs in a simple, expressive and JavaScript idiomatic way. It hides away the Campaign complexities associated with having to make SOAP calls, XML to JSON conversion, type formatting, etc.
12
+ # QuickStart
15
13
 
16
- The API is fully asynchronous using promises and works as well on the server side than on the client side in the browser.
17
14
 
18
- Install
15
+ To install the SDK, use your favorite node command
19
16
  ```js
20
17
  npm install --save @adobe/acc-js-sdk
21
18
  ```
22
19
 
20
+
23
21
  The SDK entrypoint is the `sdk` object from which everything else can be created.
24
22
 
25
23
  ```js
@@ -41,7 +39,7 @@ which will return the SDK name and version (the actual name and version number w
41
39
  ```
42
40
 
43
41
 
44
- # QuickStart
42
+ # An example
45
43
  Here's a small node.js application which displays all the target mappings in Campaign.
46
44
 
47
45
  Create a new node.js application
@@ -102,2166 +100,6 @@ Target mappings: {"deliveryMapping":[{"id":"1747","label":"Recipients","name":"m
102
100
 
103
101
 
104
102
 
105
- # API Basics
106
-
107
- In order to call any Campaign API, you need to create a `Client` object first. You pass it the Campaign URL, as well as your credentials.
108
-
109
- ```js
110
- const sdk = require('@adobe/acc-js-sdk');
111
- const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
112
- "https://myInstance.campaign.adobe.com",
113
- "admin", "admin");
114
- const client = await sdk.init(connectionParameters);
115
- ```
116
-
117
- ## Connection options
118
-
119
- Connection parameters can also be passed an option object with the following attributes
120
- Attribute|Default|Description
121
- ---|---|---
122
- representation|"SimpleJson"| See below. Will determine if the SDK works with xml of json object. Default is JSON
123
- rememberMe|false| The Campaign `rememberMe` attribute which can be used to extend the lifetime of session tokens
124
- entityCacheTTL|300000| The TTL (in milliseconds) for the xtk entity cache
125
- methodCacheTTL|300000| The TTL (in milliseconds) for the xtk method cache
126
- optionCacheTTL|300000| The TTL (in milliseconds) for the xtk option cache
127
- traceAPICalls|false| Activates tracing of API calls or not
128
- transport|axios|Overrides the transport layer
129
- noStorage|false|De-activate using of local storage
130
- storage|localStorage|Overrides the local storage for caches
131
- refreshClient|undefined|Async callback to run when the session token is expired
132
- charset|UTF-8|The charset encoding used for http requests. In version 1.1.1 and above, the default will be UTF-8. It's possible to override (including setting an empty character set) with this option.
133
- extraHttpHeaders|[string]:string|An optional dictionary (key/value pairs) of extra HTTP headers to pass to all API calls.
134
- clientApp|string|An optional string describing the name and version of the SDK client application. It will be passed to the server in the ACC-SDK-Client-App HTTP header
135
- noSDKHeaders|boolean|Can be set to disable passing ACC-SDK-* HTTP headers to the server
136
- noMethodInURL|boolean|Can be set to true to remove the method name from the URL
137
- timeout|number|Can be used to set the APIs call timeout (in ms)
138
- ```js
139
- const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
140
- "https://myInstance.campaign.adobe.com",
141
- "admin", "admin",
142
- { representation: "xml", rememberMe: true });
143
- ```
144
-
145
- ## Login with IMS
146
-
147
- The SDK also supports IMS service token with the `ofUserAndServiceToken` function. Pass it a user to impersonate and the IMS service token.
148
-
149
- In that context, the IMS service token grants admin-level privileges, and the user indicates which Campaign user to impersonate.
150
- ```js
151
- const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
152
- "https://myInstance.campaign.adobe.com",
153
- "admin", "==ims_service_token_here");
154
- ```
155
- ## Login with IMS access token
156
- The SDK supports IMS access token of an IMS user with the `ofBearerToken` function. Pass it a bearer token.
157
- ```js
158
- const connectionParameters = sdk.ConnectionParameters.ofBearerToken(
159
- "https://myInstance.campaign.adobe.com",
160
- "ims_bearer_token");
161
- ````
162
-
163
- ## Login with Session token
164
-
165
- Campaign supports authenticating with a session token in some contexts. This is usually used for Message Center API calls (see the "Message Center" section below).
166
-
167
- In this example, the session token is a string composed of the user name, a slash sign, and the password (often empty)
168
-
169
- ```js
170
- const connectionParameters = sdk.ConnectionParameters.ofSessionToken(url, "mc/mc");
171
- ```
172
-
173
- Note that this authentication mode is very specific and does not actually performs a Logon: the session token will be passed to each API calls as-is (with an empty security token) and requires proper setup of the security zones for access to be granted.
174
-
175
- Another consequence is that the Application object will not be available (client.application will be undefined) when using this authentication mode. The reason is that the application object requires an actual login call to be made to be populated.
176
-
177
-
178
- ## Anonymous logon
179
-
180
- Several Campaign APIs are anonymous, i.e. do not require to actually logon to be used. For instance the "/r/test" API is anonymous. The SDK supports anonymous APIs but still need to be initialized with anonymous credentials as follows. Of course, anonymous APIs also work if you are logged on with a different method.
181
-
182
- ```js
183
- const connectionParameters = sdk.ConnectionParameters.ofAnonymousUser(url);
184
- const client = await sdk.init(connectionParameters);
185
- ```
186
-
187
- ## Logon with Security token
188
-
189
- If you want to use the SDK client-side in a web page returned by Campaign, you cannot use the previous authentication functions because you do not know the user and password, and because you cannot read the session token cookie.
190
-
191
- For this scenario, the `ofSecurityToken` function can be used. Pass it a security token (usually available as document.__securitytoken), and the SDK will let the browser handle the session token (cookie) for you.
192
-
193
- ```html
194
- <script src="acc-sdk.js"></script>
195
- <script>
196
- (async () => {
197
- try {
198
- const sdk = document.accSDK;
199
- var securityToken = "@UyAN...";
200
- const connectionParameters = sdk.ConnectionParameters.ofSecurityToken(url, securityToken);
201
- const client = await sdk.init(connectionParameters);
202
- await client.logon();
203
- const option = await client.getOption("XtkDatabaseId");
204
- console.log(option);
205
- } catch(ex) {
206
- console.error(ex);
207
- }
208
- })();
209
- </script>
210
- </body>
211
- </html>
212
- ```
213
-
214
- Note: if the HTML page is served by the Campaign server (which is normally the case in this situation), you can pass an empty url to the `ofSecurityToken` API call.
215
-
216
-
217
- ## LogOn / LogOff
218
-
219
- The `sdk.init` call will not actually connect to Campaign, you can call the `logon` method for this. Logon does not need to be called when using session-token authentication or anonymous authentication.
220
-
221
- ```js
222
- await client.logon();
223
- ```
224
-
225
- ```js
226
- await client.logoff();
227
- ```
228
-
229
- ## refreshClient callback
230
- The refreshClient is an async callback function with the SDK client as parameter, it is called when the ACC session is expired.
231
- The callback must refresh the client session and return it. if a SOAP query fails with session expiration error then it will be retried when the callback is defined.
232
-
233
- ```js
234
- const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
235
- url, "admin", "admin",
236
- { refreshClient: async (client) => {
237
- await client.logon();
238
- return client;
239
- }});
240
- ```
241
-
242
- ## IP Whitelisting
243
-
244
- Campaign includes an IP whitelisting component which prevents connections from unauthorized IP addresses. This is a common source of authentication errors.
245
-
246
- A node application using the SDK must be whitelisted to be able to access Campaign. The SDK `ip` function is a helper function that can help you find the IP or IPs which need to be whitelisted.
247
-
248
- This API is only meant for troubleshooting purposes and uses the `https://api.db-ip.com/v2/free/self` service.
249
-
250
- ```js
251
- const ip = await sdk.ip();
252
- ```
253
-
254
- Will return something like
255
-
256
- ```json
257
- { "ipAddress":"AAA.BBB.CCC.DDD","continentCode":"EU","continentName":"Europe","countryCode":"FR","countryName":"France","stateProv":"Centre-Val de Loire","city":"Bourges" }
258
- ```
259
-
260
- ## Calling static SOAP methods
261
-
262
- The NLWS object allows to dynamically perform SOAP calls on the targetted Campaign instance.
263
- ```js
264
- const NLWS = client.NLWS;
265
- ```
266
-
267
- Static SOAP methods are the easiest to call. Once you have a `NLWS` object and have logged on to the server, call a static mathod as followed. This example will use the `xtk:session#GetServerTime` method to displayt the current timestamp on the server.
268
-
269
-
270
- ```js
271
- const NLWS = client.NLWS;
272
- result = await NLWS.xtkSession.getServerTime();
273
- console.log(result);
274
- ```
275
-
276
- where
277
- * `xtkSession` is made of the namespace and entity to which the API applies. For instance `xtk:session` -> `xtkSession`
278
- * `getServerTime` is the method name. In ACC, method names start with an upper case letter, but in JS SDK you can put it in lower case too (which is preferred for JavaScript code).
279
-
280
-
281
- ## Parameter types
282
-
283
- In Campaign, many method attributes are XML elements or documents, as well as many return types. It's not very easy to use in JavaScript, so the SDK supports automatic XML<=> JSON conversion. Of yourse, you can still use XML if you want.
284
-
285
- We're supporting 2 flavors of JSON in addition to XML.
286
- * `SimpleJson` which is the recommeded and default representation
287
- * `BadgerFish` which was the only and default before 1.0.0, and is now a legacy flavor of JSON. It's a little bit complex and was deprecated in favor of `SimpleJson` (http://www.sklar.com/badgerfish/)
288
- * `xml` which can be use to perform no transformation: Campaign XML is returned directly without any transformations.
289
-
290
-
291
- The representation can set when creating a client. It's recommended to keep it to `SimpleJson`.
292
- ```js
293
- const client = await sdk.init("https://myInstance.campaign.adobe.com", "admin", "admin", { representation: "SimpleJson" });
294
- ```
295
-
296
- Here's an example of a queryDef in SimpleJson). This query will return an array containing one item for each external account in the Campaign database. Each item will contain the account id and name.
297
-
298
- ```
299
- const queryDef = {
300
- schema: "nms:extAccount",
301
- operation: "select",
302
- select: {
303
- node: [
304
- { expr: "@id" },
305
- { expr: "@name" }
306
- ]
307
- }
308
- };
309
- ```
310
-
311
- ## Method-level representation
312
-
313
- The client object is created with a default representation which is used for all API calls in the context of this client. Since version 1.1.2, it is also possible to set the representation at the method level, i.e. use a particular representation for a particular API call.
314
-
315
- * `client.NLWS`: use the default representation set at the client level
316
- * `client.NLWS.xml`: use the XML reresentation
317
- * `client.NLWS.json`: use the SimpleJson representation
318
-
319
-
320
- ## SimpleJson format
321
- The Simple JSON format works like this:
322
-
323
- The XML root element tag is determined by the SDK as it's generating the XML, usually from the current schema name.
324
-
325
- * XML: `<root/>
326
- `
327
- * JSON: `{}`
328
-
329
- XML attributes are mapped to JSON attributes with the same name, whose litteral value can be a string, number, or boolean. There's no "@" sign in the JSON attribute name.
330
- Values in JSON attributes can be indifferently typed (ex: number, boolean), or strings (ex: "3" instead of just 3) depending if the conversion could determine the attribute type or not.
331
- API users should expect and handle both value and use the `XtkCaster` object to ensure proper conversion when using.
332
-
333
- * XML: `<root hello="world" count=3 ok=true/>`
334
- * JSON: `{ hello:"world", count:3, ok:true }`
335
-
336
- XML elements are mapped to JSON objects
337
-
338
- * XML: `<root><item id=1/></root>`
339
- * JSON: `{ item: { id:1 } }`
340
-
341
- If the parent element tag ends with `-collection` children are always an array, even if there are no children, or if there is just one child. The rationale is that XML/JSON conversion is ambigous : XML can have multiple elements with the same tag and when there's only one such element, it's not possible to determine if it should be represented as a JSON object or JSON array unless we have additional metadata.
342
-
343
- * XML: `<root-collection><item id=1/></root>`
344
- * JSON: `{ item: [ { id:1 } ] }`
345
-
346
- When an XML element is repeated, an JSON array is used
347
-
348
- * XML: `<root><item id=1/><item id=2/></root>`
349
- * JSON: `{ item: [ { id:1 }, { id:2 } ] }`
350
-
351
- Text of XML element is handle with the `$` sign in the JSON attribute name, or with a child JSON object name `$`
352
-
353
- Text of the root element
354
- * XML: `<root>Hello</root>`
355
- * JSON: `{ $: "Hello" }`
356
-
357
- Text of a child element
358
- * XML: `<root><item>Hello</item></root>`
359
- * JSON: `{ $item: "Hello" }`
360
- * Alternative JSON: `{ item: { $: "Hello" } }`
361
-
362
- If an element contains both text, and children, you need to use the alternative `$` syntax
363
- * XML: `<root><item>Hello<child id="1"/>
364
- </item>
365
- </root>`
366
- * JSON: `{ item: { $: "Hello", child: { id:1 } }`
367
-
368
-
369
- ## BadgerFish format
370
-
371
- To distinguish between BadgerFish and SimpleJson format, all BadgerFish objects will have the BadgerFishObject class, that includes the top-level object, but also all children objects. A badgerfish object can be created as follows. It will automatically convert all the object literals into BadgerFishObjet class.
372
-
373
- ```
374
- const obj = new DomuUtil.BadgerFishObject({ "@att":"value });
375
- ```
376
-
377
-
378
- ## Returning multiple values
379
- Campaign APIs can return one or multiple values. The SDK uses the following convention:
380
- * no return value -> returns `null`
381
- * one return value -> returns the value directly
382
- * more that one return value -> returns an array of values
383
-
384
-
385
- ## Calling non-static APIs
386
-
387
- To call a non-static API, you need an object to call the API on. You create an object with the `create` method.
388
- For instance, here's how one creates a QueryDef object.
389
-
390
- ```js
391
- const queryDef = {
392
- schema: "nms:extAccount",
393
- operation: "select",
394
- select: {
395
- node: [
396
- { expr: "@id" },
397
- { expr: "@name" }
398
- ]
399
- }
400
- };
401
- const query = NLWS.xtkQueryDef.create(queryDef);
402
- ```
403
-
404
- Note: the returned object is opaque and private, it should not be directly manipulated.
405
-
406
- The method can then be called directly on the object
407
- ```js
408
- const extAccounts = await query.executeQuery();
409
- ```
410
-
411
- In this example, the result is as follows
412
-
413
- ```js
414
- { extAccount:[
415
- { id: "2523379", name: "cda_snowflake_extaccount" },
416
- { id: "1782", name: "defaultPopAccount" },
417
- { id: "3643548", name: "v8" }
418
- ]}
419
- ```
420
-
421
- Some methods can mutate the object on which they apply. This is for instance the case of the xtk:queryDef#SelectAll method. You call it on a queryDef, and it internally returns a new query definition which contain select nodes for all the nodes of the schema. When such a method is called, the SDK will know how to "mutate" the corresponding object.
422
-
423
- ```js
424
- const queryDef = {
425
- schema: "xtk:option",
426
- operation: "get",
427
- where: { condition: [ { expr:`@name='XtkDatabaseId'` } ] }
428
- };
429
- const query = client.NLWS.xtkQueryDef.create(queryDef);
430
- await query.selectAll(false);
431
- var result = await query.executeQuery();
432
- ```
433
-
434
- In the previous example, a queryDef is created without any select nodes. Then the selectAll method is called. After the call, the JavaScript queryDef object will contain a select elements with all the nodes corresponding to attributes of the xtk:option schema.
435
-
436
-
437
- ## XTK interfaces
438
-
439
- Campaign schemas are following an object model. An interface is a set of methods. For instance, the "xtk:persist" interface, defined in the "xtk:session" schema, has a NewInstance method.
440
- Schemas can implement interface, which means they inherit and implement the methods of the interface. Such methods are internally called using a particular SOAP call URN, which is formed of the interface name, followed by a pipe character, followed by the implementation schema id. For instance "xtk:persist|nms:delivery" is used to indicate that we're calling a method of the xtk:persist on a nms:delivery object which implements the xtk:persist interface.
441
-
442
- The version 1.1.9 of the SDK properly implement this type of calls and will deal with this complexity for you. For instance, you can simply call the NewInstance method as follows:
443
-
444
- ```js
445
- // Create a proxy delivery object
446
- const delivery = client.NLWS.nmsDelivery.create({ label: "Hello" });
447
- // Call the xtk:persist|nms:delivery#NewInstance method to retreive the default
448
- // values of a delivery object before actually saving the delivery
449
- await delivery.newInstance();
450
- ```
451
- There are 2 common interfaces: xtk:persist and xtk:jobInterface which are documented below.
452
-
453
-
454
- ## Campaign data types
455
-
456
- Campaign uses a typed system with some specificities:
457
- * for strings, "", null, or undefined are equivalent
458
- * numerical values cannot be null or undefined (0 is used instead)
459
- * boolean values cannot be null or undefined (false is used instead)
460
- * conversion between types is automatic based on their ISO representation
461
-
462
-
463
- | Xtk type | | JS type | Comment |
464
- | ------------ |----|-------- | --- |
465
- | string | 6 | string | never null, defaults to "" |
466
- | memo | 12 | string |
467
- | CDATA | 13 | string |
468
- | byte | 1 | number | signed integer in the [-128, 128[ range. Never null, defaults to 0 |
469
- | short | 2 | number | signed 16 bits integer in the [-32768, 32768[ range. Never null, defaults to 0 |
470
- | long | 3 | number | signed 32 bits integer. Never null, defaults to 0 |
471
- | 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.
472
- | float | 4 | number | single-percision numeric value. Never null, defaults to 0 |
473
- | double | 5 | number | single-percision numeric value. Never null, defaults to 0 |
474
- | datetime | 7 | Date | UTC timestamp with second precision. Can be null |
475
- | datetimetz | | | |
476
- | datetimenotz | | | |
477
- | date | 10 | Date | UTC timestamp with day precision. Can be null |
478
- | boolean | 15 | boolean | boolean value, defaultint to false. Cannot be null |
479
- | timespan | | | |
480
- | primarykey | | string | A primary key is serialized with format <schemaId>|<keyField>[|<keyField>[...]]
481
-
482
-
483
- The SDK user does not have to handle this, but outside of the Campaign ecosystem, those rules may not apply and you probably do not want to use a number for a string, etc. The `XtkCaster` class is here to help.
484
-
485
- You get a static `XtkCaster` object like this
486
- ```js
487
- const XtkCaster = sdk.XtkCaster;
488
- ```
489
-
490
- or directly from the client for convenience
491
- ```js
492
- const XtkCaster = client.XtkCaster;
493
- ```
494
-
495
- To convert a Campaign value into a given type, use one of the following.
496
- ```js
497
- stringValue = XtkCaster.asString(anyValue);
498
- booleanValue = XtkCaster.asBoolean(anyValue);
499
- byteValue = XtkCaster.asByte(anyValue);
500
- shortValue = XtkCaster.asShort(anyValue);
501
- int32Value = XtkCaster.asLong(anyValue);
502
- numberValue = XtkCaster.asNumber(anyValue);
503
- timestampValue = XtkCaster.asTimestamp(anyValue);
504
- dateValue = XtkCaster.asDate(anyValue);
505
- ```
506
-
507
- More dynamic conversions can be achieved using the `as` function. See the types table above for details.
508
-
509
- ```js
510
- stringValue = XtkCaster.as(anyValue, 6);
511
- ```
512
-
513
- In addition, the following helpers are available
514
- * `XtkCaster.isTimeType` to test if a data type is a date, time or timestamp
515
- * `XtkCaster.isStringType` to test if a data type is a string type (string, memo, etc.)
516
- * `XtkCaster.isNumericType` to test if a data type is a numeric type
517
-
518
-
519
- ## DOM helpers
520
-
521
-
522
- DOM manipulation is sometimes a bit painful. The `DomUtil` helper provides a few convenience functions
523
-
524
- ```js
525
- const DomUtil = sdk.DomUtil;
526
- ```
527
-
528
- or
529
-
530
- ```js
531
- const DomUtil = client.DomUtil;
532
- ```
533
-
534
-
535
- Create DOM from XML string:
536
- ```js
537
- const doc = DomUtil.parse(`<root>
538
- <one/>
539
- </root>`);
540
- ```
541
-
542
- Writes a DOM document or element as a string:
543
- ```js
544
- const s = DomUtil.toXMLString(docOrElement);
545
- ```
546
-
547
- Creates a new document
548
- ```js
549
- const queryDoc = DomUtil.newDocument("queryDef");
550
- ```
551
-
552
- Escape text value
553
- ```js
554
- const escaped = DomUtil.escapeXmlString(value);
555
- ```
556
-
557
- Find element by name (finds the first element with given tag). This is a very common operation when manipulating Campaign XML documents
558
- ```js
559
- const el = DomUtil.findElement(parentElement, elementName, shouldThrow);
560
- ```
561
-
562
- Get the text value of an elemennt. This will accomodate text elements, cdata elements, as well has having multiple text child element (which is ususally not the case in Campaign)
563
- ```js
564
- const text = DomUtil.elementValue(element);
565
- ```
566
-
567
- Iterates over child elements
568
- ```js
569
- var child = DomUtil.getFirstChildElement(parentElement);
570
- while (child) {
571
- ...
572
- child = DomUtil.getNextSiblingElement(child);
573
- }
574
- ```
575
-
576
- Iterates over child elements of a given type
577
- ```js
578
- var methodChild = DomUtil.getFirstChildElement(parentElement, "method");
579
- while (methodChild) {
580
- ...
581
- methodChild = DomUtil.getNextSiblingElement(methodChild, "method");
582
- }
583
- ```
584
-
585
- Get typed attribute values, with automatic conversion to the corresponding xtk type, and handling default values
586
- ```js
587
- const stringValue = DomUtil.getAttributeAsString(element, attributeName)
588
- const byteValue = DomUtil.getAttributeAsByte(element, attributeName)
589
- const booleanValue = DomUtil.getAttributeAsBoolean(element, attributeName)
590
- const shortValue = DomUtil.getAttributeAsShort(element, attributeName)
591
- const longValue = DomUtil.getAttributeAsLong(element, attributeName)
592
- ```
593
-
594
- JSON to XML conversion (SimpleJson by default)
595
- ```js
596
- const document = DomUtil.fromJSON(json);
597
- const json = DomUtil.toJSON(documentOrElement);
598
- ```
599
-
600
- BadgerFish can be forced as well
601
- ```js
602
- const document = DomUtil.fromJSON(json, "BadgerFish");
603
- const json = DomUtil.toJSON(documentOrElement, "BadgerFish");
604
- ```
605
-
606
- ## Passing XML parameters
607
- Many Campaign APIs take arguments which are DOM documents or DOM elements. For example, the nms:delivery#DeployTriggerMessages first argument is a DOMElement which is supposed to be a `<where>` clause used as a condition to select Message Center deliveries to publish.
608
-
609
- ```xml
610
- <method name="DeployTriggerMessages" static="true">
611
- <parameters>
612
- <param inout="in" name="deliveries" type="DOMElement"/>
613
- <param inout="in" name="localPublish" type="boolean"/>
614
- </parameters>
615
- </method>
616
- ```
617
-
618
- For example, one would want to use the following condition to republish a particular delivery
619
-
620
- ```js
621
- await client.NLWS.nmsDelivery.DeployTriggerMessages({
622
- condition: [ {
623
- expr: "@internalName='DM23'"
624
- }]
625
- }, false);
626
- ```
627
-
628
- The JSON object corresponds to the following XML
629
- ```xml
630
- <where>
631
- <condition expr="@internalName='DM23'"/>
632
- </where>
633
- ```
634
-
635
- Note that in XML, unlike JSON, the root element `<where>` is explicitely named "where". When converting JSON to XML, there is no way for the SDK to know which tag name to used for the root XML element. The SDK contains some code to set it for the most common situation, but will rely on the user to specify, when necessary, the name of the root elment. This can be done using the `xtkschema` (all case insensitive) attribute as follows:
636
- ```js
637
- await client.NLWS.nmsDelivery.DeployTriggerMessages({
638
- xtkschema: 'xtk:where',
639
- condition: [ {
640
- expr: "@internalName='DM23'"
641
- }]
642
- }, false);
643
- ```
644
-
645
- When the `xtkschema` attribute is set, the part after the colon (i.e. "where" in this example) will be used as the root element, effectively generating the right XML.
646
-
647
- In our example, the `DeployTriggerMessages` will work properly regardless of the XML root of its `deliveries` parameter, so it's not needed to actually set the `xtkschema` attribute, but it's a best practice to do so, because some APIs will actually depend on receiving the right tag name.
648
-
649
- ## Error Management
650
-
651
- If an API call fails (SOAP fault or HTTP error), a `CampaignException` object is thrown. This object contains the following attributes
652
-
653
- * `message` a message describing the error
654
- * `statusCode` a HTTP status code. In case of a SOAP fault, the status code will be 500
655
- * `errorCode` the Campaign error code if one is available (ex: XSV-350013)
656
- * `methodCall` the SOAP call which caused the error. It will contain the following attributes
657
- * `type` the type of the API call ("SOAP" or "HTTP")
658
- * `urn` the SOAP call URN, i.e. the schema id. Will be empty for HTTP methods
659
- * `url` the HTTP URL
660
- * `methodName` the name of the SOAP method. For HTTP methods, the query path
661
- * `request` the raw SOAP request, as text. For HTTP requests, this is an option object containing details about the request
662
- * `response` the raw SOAP/HTTP response, as text
663
- * `faultCode` for SOAP faults, the Campaign error code
664
- * `faultString` the error message
665
- * `detail` optional additional details about the error
666
-
667
- In general all errors are mapped to a CampaignException and we try to keep the semantic of errors: for instance a call with an incorrect parameter will return an HTTP stauts of 400 even if it's not actually a, HTTP call. SDK specific errors will have an errorCode with the "SDK-######" format, using "SDK" as a prefix.
668
-
669
- ```js
670
- try {
671
- await client.logon();
672
- result = await NLWS.xtkSession.getServerTime();
673
- } catch (ex) {
674
- console.log(ex.message);
675
- }
676
- ```
677
-
678
- It's also noteworthy that all the data returned in a CampaignException is trimmed, i.e. session and security token values are hidden, so that the exception object can be safely logged.
679
-
680
- ## Caches
681
-
682
- The following caches are managed by the SDK and active by default. They are in-memory caches.
683
-
684
- * Options cache. Stores typed option values, by option name.
685
- * Entity cache. Caches schemas and other entities
686
- * Method cache. Cahces SOAP method definitions.
687
-
688
- Caches can be cleared at any time
689
- ```js
690
- client.clearOptionCache();
691
- client.clearMethodCache();
692
- client.clearEntityCache();
693
- ```
694
-
695
- or
696
- ```js
697
- client.clearAllCaches();
698
- ```
699
-
700
- Caches have a TTL of 5 minutes by default. The TTL can be changed at connection time using connection options `entityCacheTTL`, `methodCacheTTL`, and `optionCacheTTL`.
701
-
702
- Caches can be de-activated by setting a TTL of -1 which will have the effect of making all cached data always invalid.
703
-
704
-
705
-
706
- ## Persistent caches
707
- In addition to memory caches, it is possible to use persistent caches as well. This was introduced in version 1.0.5 and is active by default as well when using the SDK in a browser. The browser local storage is used (if allowed).
708
-
709
- Cached data is stored in local storage with keys prefixed with `acc.js.sdk.{{version}}.{{server}}.cache.` where `version` is the SDK version and `server` is the Campaign server name. This means that the cached data is lost when upgrading the SDK.
710
-
711
- It's possible to disable persistent caches using the `noStorage` connection option.
712
-
713
- It is also possible to setup one's own persistent cache, by passing a `storage` object as a connection option. This object should implement 3 methods: `getItem`, `setItem`, and `removeItem` (synchronous)
714
-
715
-
716
- ## Auto-refresh caches
717
-
718
- The SDK includes a mechnism to maintain the schemas and options caches up-to-date by polling the Campaign server on a regular basis (10 seconds by default). The server returns the list of entities (schemas or options) which have changed since they were cached, and the client removes them from the cache. When a schema changes, the corresponding methods are also removed from the method cache.
719
-
720
- This mechanism is not activate by default but can be activated or deactivated by the following functions
721
-
722
- ```js
723
- client.startRefreshCaches(30000); // activate cache auto-refresh mechanism every 30s
724
- client.stopRefreshCaches(); // de-activate cache auto-refresh
725
- ```
726
-
727
- This mechanism is based on the `xtk:session#GetModifiedEntities` SOAP method which is only available in Campaign 8.4 and above only. For other builds of Campaign, the auto-refresh mechanism will not do anything.
728
-
729
- The following changes are handled:
730
- * If the build number has changed, the whole cache is cleared
731
- * If more than 10 schemas or options have changed, the whole cache is cleared
732
- * if less than 10 schemas or options have changed, only those entities are removed from the cache
733
-
734
-
735
- The refresh mechanism includes the following guardrails
736
- * Both xtk:option and xtk:schema caches are refreshed every n seconds. To avoid issuing two API calls at the same time to the server, the schema cache refresh call is delayed by a few seconds. In the future this delay may change.
737
- * If the xtk:session#GetModifiedEntities API is not available, the auto refresh mechanism will silently stop automatically
738
- * If an error occurs while trying to refresh, a warning will be logged to the JavaScript console but the auto refresh will not be stopped.
739
-
740
- ## Passwords
741
-
742
- External account passwords can be decrypted using a Cipher. This function is deprecated since version 1.0.0 since it's not guaranteed to work in future versions of Campaign (V8 and above)
743
-
744
- ```js
745
- const cipher = await client.getSecretKeyCipher();
746
- const password = cipher.decryptPassword(encryptedPassword);
747
- ````
748
-
749
- > **warning** This function is deprecated in version 1.0.0 of the SDK because it may break as we deploy Vault.
750
-
751
- In order to set the password of an external account, you can use the `encryptPassword` API as follow
752
-
753
- ```js
754
- const password = await this._client.NLWS.xtkSession.encryptPassword('password');
755
- const account = {
756
- xtkschema: "nms:extAccount",
757
- name: name,
758
- account: 'admin',
759
- server: server,
760
- password: password,
761
- };
762
- await this._client.NLWS.xtkSession.Write(account);
763
- ```
764
-
765
-
766
- ## HTTP Headers
767
-
768
- ### Out-of-the-box headers
769
- In version 1.1.3 and above, the SDK will pass additional HTTP headers automatically
770
-
771
- Header | Description
772
- -------|------------
773
- SOAPAction| name of the schema and SOAP method (ex: xtk:query#ExecuteQuery)
774
- ACC-SDK-Version| Version of the SDK making the scores
775
- ACC-SDK-Auth| Authentification type and ACC user
776
- ACC-SDK-Client-App| Name of the application calling the client SDK
777
- ACC-SDK-Call-RetryCount| In case an API call is retried, indicates the number of retries
778
- ACC-SDK-Call-Internal| Indicates that an API call is performed byt the SDK for its own purpose
779
-
780
- The `ACC-SDK` headers can be removed using the connection parameter `noSDKHeaders`.
781
-
782
- ### Custom HTTP headers
783
- In version 1.1.3 and above, it is possible to pass additional HTTP headers or override HTTP headers set by the SDK. This can be done globally (i.e. for all API calls), or locally, i.e. just for a particular call, or both.
784
-
785
- Http headers are passed through an object whose keys represent the header name and values the corresponding header value. Nothing particular is done in term of case sensitivity, headers will be passed as passed.
786
-
787
- To set global HTTP headers for all API calls of a client, pass an http headers array in the connection parameters
788
- ```js
789
- const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
790
- "https://myInstance.campaign.adobe.com",
791
- "admin", "admin",
792
- { extraHttpHeaders: {
793
- "X-ACC-JS-SDK-LBSAFE": "1",
794
- "X-ACC-WEBUI-VERSION: "1.2"
795
- } });
796
- ```
797
-
798
- Subsequent API calls will have the corresponding headers set.
799
-
800
- To set more HTTP headers for a particular API call, use the "headers" method of the NLWS object.
801
-
802
- ```js
803
- const query = client.NLWS
804
- .headers({'X-Test': 'hello'})
805
- .xtkQueryDef.create(queryDef);
806
- await query.executeQuery();
807
- ```
808
-
809
- ## Timeouts
810
-
811
- By default, the SDK has a timeout of 5s when running in a node.js environment, and uses the browser defaults when run inside a browser (using the fetch API).
812
-
813
- It is possible to overwrite the transport layer (see `The Transport Protocol` and use your own code to make and configure HTTP requests) to tune the timeout value. It is a bit cumbersome though.
814
-
815
- Instead, you can use the `timeout` parameter, and set it either globally, as a connection parameter, or even at the API call level but using the `PushDown` mechanism described below.
816
-
817
- Sets a timeout of 10s gloally
818
- ```js
819
- const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
820
- "https://myInstance.campaign.adobe.com",
821
- "admin", "admin",
822
- { timeout: 10000 });
823
- ```
824
-
825
- Override the timeout to 1 min for a particular API call
826
- ```js
827
- NLWS.xml.pushDown({ timeout: 60000 }).xtkBuilder.installPackage(dom);
828
- ```
829
-
830
- ## Pushdown mechanism
831
- The Pushdown mechanism can be used to push down variables to the transport layer. A common use case it to pass a custom timeout value down to the transport layer.
832
-
833
- The pushed down parameters are passed as a second parameter to the transport function. This parameter will contain all the connection parameters as well as any parameter that you can push down at the API call level. API call pushdowns can override default pushdowns.
834
-
835
- Any key/value pairs can be pushed down. This example pushes down the timeout and foo variables to the transport layer.
836
- ```js
837
- NLWS.xml.pushDown({ timeout: 60000, foo: 'bar' }).xtkBuilder.installPackage(dom);
838
- ```
839
-
840
- ## Troubleshooting
841
- In the version 1.1.5 of the SDK, we are automatically adding the SOAP method name in the URL in order to simplify troubleshooting. Normally, all SOAP method calls are make to the soaprouter.jsp endpoint, which makes it difficult to understand which actual API call is being made.
842
- In fact the SOAP call name is available via the SOAPAction HTTP header, but it's usually not immediatelly visible.
843
-
844
- The SOAP calls URLs are now formed like this: `http://acc-sdk:8080/nl/jsp/soaprouter.jsp?xtk:queryDef:ExecuteQuery` where the SOAP method name is added as a query parameter. Campaign server ignores this parameter.
845
-
846
- This can be disabled using the `noMethodInURL` connection parameter
847
-
848
- const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
849
- "https://myInstance.campaign.adobe.com",
850
- "admin", "admin",
851
- { noMethodInURL: true });
852
-
853
-
854
- # Samples
855
-
856
- The `samples` folder contains several samples illustrating how to use the various Campaing APIs.
857
-
858
- A sample file looks like this
859
- * It includes the `utils` library which contains a few helper functions.s
860
- * It starts with an asynchronous auto-execute function that is used to run the sample from the command line
861
- * This function contains one or more calls to the `utils.sample` function. Each such call describes and execute a sample.
862
- * A sample file should not do anything else or have any side effect: all the actual sample code should be inside calls to `utils.sample`
863
-
864
- | Note the use of `await` when calling `utils.sample`
865
-
866
- ```js
867
- const utils = require("./utils.js");
868
- ( async () => {
869
- await utils.sample({
870
- title: "The Sample title",
871
- labels: [ "xtk:queryDef", "Basics", "Query", "QueryDef", "Get" ],
872
- description: `A description of the sample`,
873
- code: async() => {
874
- //... Sample code goes there
875
- }
876
- });
877
-
878
- await utils.sample({
879
- title: "A Second sample",
880
- labels: [ "xtk:queryDef", "Basics", "Query", "QueryDef", "Get" ],
881
- description: `A description of the sample`,
882
- code: async() => {
883
- //... Sample code goes there
884
- }
885
- });
886
- })();
887
- ```
888
-
889
- The `utils.sample` function takes 1 parameters describing the sample:
890
- * `title` is the sample title, a short, human friendly name for the sample
891
- * `labels` is a list of keywords that can be used to retreive the samples in a large list
892
- * `description` is a longer, multi-line description of the sample
893
- * `code` is an async function, the code of the sample
894
-
895
- Most of the samples - actually all of them except some specific samples needing specific logon - will also use the `utils.logon` function. This is a helper function which will perform the Campaign Logon and Logoff for you, and call your callback function with pre-initialized `client` and `NLWS` objects
896
-
897
- | Note the use of `await` when calling `utils.logon`
898
-
899
- ```js
900
- await utils.sample({
901
- title: "The Sample title",
902
- labels: [ "xtk:queryDef", "Basics", "Query", "QueryDef", "Get" ],
903
- description: `A description of the sample`,
904
- code: async() => {
905
- return await utils.logon(async (client, NLWS) => {
906
- //... Sample code goes there
907
- });
908
- }
909
- });
910
- ```
911
-
912
- ### Running samples
913
- Samples can be run from the command line. First, set 3 environment variables with your instance credentials:
914
- ```sh
915
- export ACC_URL=https://myInstance.campaign.adobe.com
916
- export ACC_USERadmin
917
- export ACC_PASSWORD=...
918
- ```
919
-
920
- and then run the samples
921
- ```sh
922
- node samples/000\ -\ basics\ -\ logon.js
923
- ````
924
-
925
-
926
-
927
-
928
- # Core API
929
-
930
- ## Get option value
931
-
932
- A convenience function is provided, which returns a typed option value.
933
- ```js
934
- var value = await client.getOption("XtkDatabaseId");
935
- ```
936
-
937
- Options are cached because they are often used. It's possible to force the reload of an option:
938
- ```js
939
- var value = await client.getOption("XtkDatabaseId", false);
940
- ```
941
-
942
- It's also possible to call the API directly.
943
- Use the `xtk:session:GetOption` method to return an option value and it's type. This call will not use the option cache for returning the option value, but will still cache the result.
944
-
945
- ```js
946
- const optionValueAndType = await NLWS.xtkSession.getOption("XtkDatabaseId");
947
- console.log("Marketing datbaseId: " + optionValueAndType);
948
-
949
- Marketing datbaseId: u7F00010100B52BDE,6
950
- ```
951
-
952
- If the option does not exist, it will return [ "", 0 ]
953
-
954
- ```js
955
- var datbaseId = await client.getOption("XtkDatabaseId");
956
- console.log(datbaseId);
957
- ```
958
-
959
- The cache can be cleared
960
- ```js
961
- client.clearOptionCache();
962
- ```
963
-
964
-
965
- ## Setting options
966
-
967
- It's also possible to set options with the `setOption` function.
968
- * It will create the option if necessary
969
- * If the option already exists, it will use the existing value to infer the data type of the option
970
-
971
- ```js
972
- await client.setOption("MyOption", "My value");
973
- ```
974
-
975
- This is really a convenience function. You can always force an option type by using a writer on the xtk:option table, and using getOption to read back and cache the result.
976
-
977
-
978
- ## Test if a package exists
979
- * Since: 0.1.20
980
- * Test if a package is installed. Expects to be connected to an instance
981
-
982
- ```js
983
- var hasAmp = client.hasPackage("nms:amp");
984
- ```
985
-
986
- or
987
- ```js
988
- var hasAmp = client.hasPackage("nms", "amp");
989
- ```
990
-
991
- ## Creating and updating entities in Campaign
992
-
993
- There are several possibillities to create objects in Campaign.
994
-
995
- ### Create from scratch
996
-
997
- This first method is to create an object from scratch. It's a multi-step operation which contains the following steps
998
-
999
- * Create an object with the "create" function. This function takes an optional parameter with the attributes you know you're going to set
1000
- * Call the xtk:persist#NewInstance API which will generate a unique id, and complete your object with default values (such as default folder, etc.) depending on your role
1001
- * Optionally set more attributes to override any defaults
1002
- * Call save() or xtk:session#Write to create the object in the database
1003
-
1004
- ```js
1005
- const delivery = client.NLWS.nmsDelivery.create({ label: "Test #1", messageType: "0" });
1006
- await delivery.newInstance();
1007
- delivery.$desc = "My description";
1008
- await client.NLWS.xtkSession.write(delivery); // or await delivery.save();
1009
- ```
1010
-
1011
- You'll notice that this method does not return anything. You may have expected this method to return the created object or some id of this object,
1012
- but Campaign does not. Campaign works the other way round. You first get call NewInstance which will give the id before the object is actually saved
1013
- in the database.
1014
-
1015
- ```js
1016
- const delivery = client.NLWS.nmsDelivery.create({ label: "Test #1", messageType: "0" });
1017
- await delivery.newInstance();
1018
- // delivery.entity.id is the future id of the object in the database
1019
- ```
1020
-
1021
- If you need to modify the object again after it's been created, you can use xtk:session#Write or save again, but you must tell Campaign to perform an update operation instead of an insert, or the call will probably fail or create a duplicate in the database.
1022
- Make sure to read the section about the "xtk:session#Write" method below to understand how exactly objects are updated
1023
-
1024
- ```js
1025
- delivery._operation = "update";
1026
- delivery.$desc = "My updated description";
1027
- await delivery.save();
1028
- ```
1029
-
1030
- Finally, to delete the object, use xtk:session#Write or save again, this time passing it the "_operation=delete" attribute
1031
- ```js
1032
- delivery._operation = "delete";
1033
- await delivery.save();
1034
- ```
1035
-
1036
- ### Create by duplicating an existing object
1037
-
1038
- Sometimes, you do not want to create objects from scratch. Instead you can copy an existing object. Campaign has a sophisticated mechanism to duplicate object and ensures that only the relevant attributes are actually set. For instance, when you dupliate a delivery which is finished, you probably want the new delivery to be in the edition state rather than in the finished state. Schema attributes having the "defOnDuplicate" property will be reset to their defaults in the duplicated object.
1039
-
1040
- Just like the "NewInstance" API, the "xtk:persist#Duplicate" will automatically set the primary key for you. And again, it is a multi-step process.
1041
-
1042
- * Create an object with the "create" function. This time, do no pass any parameters
1043
- * Call the duplicate method, passing it the primary key of the entity you want to duplicate
1044
- * Optionally set more attributes to override any defaults
1045
- * Call save() or xtk:session#Write to create the object in the database
1046
-
1047
- ```js
1048
- const operator = client.NLWS.xtkOperator.create();
1049
- await operator.duplicate("xtk:operator|1610");
1050
- operator.name = "Alex";
1051
- await operator.save();
1052
- ```
1053
-
1054
- The primary key format is described in the data types section of this document.
1055
-
1056
-
1057
- ### Updating entities
1058
-
1059
- Entities can be updated using the `xtk:session#Write` API. This API is very flexible and also can be used to create or delete entities or to modify multiple entites at once.
1060
-
1061
- This method takes an unique argument which is a patch to apply. A patch has the same structure as an entity, but only contains the attributes or elements that need to be modified, created, or deleted. In addition to the value, the patch can also use the _operation property to indicate if a particular set of data needs to be inserted, updated or deleted.
1062
- The patch object also must have the `xtkschema` property set to the schema id of the entity to modify.
1063
-
1064
- For instance, one can update the email of a recipient with the following code which clearly shows the xtkschema property, the id and _operation properties to indicate that it is an update and which entity to update, and finally, the email attribute which is the only modified attribute.
1065
-
1066
- ```js
1067
- client.NLWS.xtkSession.write({ xtkschema: "nms:recipient",
1068
- id: "1234", _operation:"update",
1069
- email: "amorin@adobe.com"
1070
- });
1071
- ```
1072
-
1073
- It's of course possible to pass the whole entity to an update, but this is strongly discouraged as it can have unwanted side effects in complex scenario when passed nested documents with linked objects. It's also less performant, and may overwrite data.
1074
- Passing a patch (sometimes called a diff) containing only the actually modified attributes is the best practice. It also has the benefit to allow some sort of concurrent modifications as each update will onlly update the attributes actually changed.
1075
-
1076
-
1077
- ### Setting foreign keys
1078
-
1079
- It's pretty common to have to set foreign keys. For instance one want to set the folder in which a recipient is stored. The first possibility is to set the folder-id attribute directly. It's also the most efficient, but it assumes you know the foreign key in the first place.
1080
-
1081
- ```js
1082
- client.NLWS.xtkSession.write({ xtkschema: "nms:recipient",
1083
- xtkschema:"nms:recipient",
1084
- id: 2020, _operation:"update",
1085
- "folder-id": 6040
1086
- });
1087
- ```
1088
-
1089
- If you do not know the primary key of the folder but know its name, you can use the following syntax. It works for all collections, where items can be identified with their keys (as defined in the schemas).
1090
- ```js
1091
- client.NLWS.xtkSession.write({ xtkschema: "nms:recipient",
1092
- xtkschema:"nms:recipient",
1093
- id: 1990, _operation:"update",
1094
- folder: {
1095
- _operation: "none",
1096
- name: "test"
1097
- }
1098
- });
1099
- ```
1100
-
1101
- Note the `operation="none"` attribute on the folder element which tells Campaign that we should not actually update the folder object itself, but to set the recipient folder instead. If you omit the _operation: "none" property, Campaign will modify both the recipient, but also the folder. It is useful in some cases, but does not make sense in this scenario.
1102
-
1103
-
1104
- ### Identifying entities
1105
-
1106
- We've had a glimpse of it but the xtk:session#Write API has several strategies to identify entities, both the top level entity but also linked entities as we've seen with the recipient folder example above.
1107
-
1108
- * If the entity is an "autopk" entity, i.e. has autopk=true set defined in its schema, then it will have an internal primary key using the @id attribute. If the corresponding id is set in the patch document, it will be used to identify the object.
1109
- * Otherwise, it will use the entity keys, as defined in the schema.
1110
-
1111
- For instance, folders are an autopk entity and have the id attribute. They also have 2 keys: name and fullName. All 3 can be used as identifiers to update a folder label as the 3 examples below show
1112
-
1113
-
1114
- ```js
1115
- // Update folder by id
1116
- await client.NLWS.xtkSession.write({
1117
- xtkschema: "xtk:folder",
1118
- _operation: "update", id: 1234,
1119
- label: "Hello World",
1120
- });
1121
- });
1122
-
1123
- // Update folder by name
1124
- await client.NLWS.xtkSession.write({
1125
- xtkschema: "xtk:folder",
1126
- _operation: "update", name: "test",
1127
- label: "Hello World",
1128
- });
1129
- });
1130
-
1131
- // Update folder by full name
1132
- // This is just for example, do not use this method as the folder full name is the concatenation
1133
- // of the folder label and it's parent folders labels. Changing the label will create an
1134
- // inconsistency between the folder full name and its label. You can update other attributes though.
1135
- await client.NLWS.xtkSession.write({
1136
- xtkschema: "xtk:folder",
1137
- _operation: "update", fullName: "/Profiles and Targets/Recipients/Hello/",
1138
- label: "Hello World",
1139
- });
1140
- });
1141
- ```
1142
-
1143
-
1144
- ### Deleting data
1145
-
1146
- The `xtkSession#write` API can also be used to delete data using the "_operation=delete" attribute. For a delete operation, the patch should contain the xtkschema attribute, the _operation=delete attribute and an identifier of the entity.
1147
-
1148
- For insance, a folder can be delete with
1149
-
1150
- ```js
1151
- await client.NLWS.xtkSession.write({
1152
- xtkschema: "xtk:folder",
1153
- _operation: "delete", name: "test",
1154
- });
1155
- });
1156
- ```
1157
-
1158
- Owned entities which are also autopk will also be deleted
1159
-
1160
-
1161
- ### Setting ids
1162
-
1163
- In the previous examples we showed how to create or update object and let Campaign generate the ids. In some cases, you'll want to explictiely set the ids upfront. To ensure uniqueness of the ids, Campaign provides an API to "reserve" ids in advane that you can use afterwards: xtk:session#GetNewIdsEx.
1164
-
1165
- In this example, we're getting an id and creating a recipient. The id can be re-used in subsequent calls as a foreign key
1166
- ```js
1167
- const idList = XtkCaster.asArray(await client.NLWS.xtkSession.GetNewIdsEx(1, "XtkNewId"));
1168
- await client.NLWS.xtkSession.write({ xtkschema:"nms:recipient", id: idList[0], email: 'amorin@adobe.com' });
1169
- ```
1170
-
1171
- Note that:
1172
- * Calling GetNewIdsEx for individual ids is not efficient. It's usually better to reserve a large range of ids and insert multiple rows using those ids
1173
- * Inserting data in unitary fashion with API calls is not efficient. Use data management workflows for large imports
1174
- * Make sure that the NLWS.xtkSession.GetNewIdsEx returns an array by using XtkCaster.asArray(...)
1175
-
1176
-
1177
-
1178
-
1179
- ## The xtk:jobInterface interface
1180
-
1181
- ## Connect to mid-sourcing
1182
- From a marketing client connection, one can get a client to a mid server
1183
-
1184
- ```js
1185
- console.log("Connecting to mid server...");
1186
- const credentials = await sdk.Credentials.ofExternalAccount(client, "defaultEmailMid");
1187
- const midClient = await sdk.init(credentials);
1188
-
1189
- await midClient.client.logon();
1190
- const datbaseId = await midClient.getOption("XtkDatabaseId");
1191
- console.log("Mid datbaseId: " + datbaseId);
1192
- await midClient.NLWS.xtkSession.testCnx();
1193
- console.log("Disconnecting from mid");
1194
- await midClient.client.logoff();
1195
- ```
1196
-
1197
- ## Health check
1198
- Campaign proposes several APIs for health check. Just like all APIs in the SDK, it's been wrapped into a function and will return a XML or JSON object depending on the current representation
1199
-
1200
- ### /r/test
1201
- This API is anonymous and run directly on the Apache front server. Note that this API will failed if called on a tomcat endpoint (port 8080)
1202
- ```js
1203
- const test = await client.test();
1204
- ```
1205
-
1206
- will return
1207
- ```json
1208
- {
1209
- "status":"OK",
1210
- "date":"2021-08-27 03:06:02.941-07",
1211
- "build":"9236",
1212
- "sha1":"cc45440",
1213
- "instance":"xxx_mkt_prod1",
1214
- "sourceIP":"193.104.215.11",
1215
- "host":"xxx.campaign.adobe.com",
1216
- "localHost":"xxx-mkt-prod1-1"
1217
- }
1218
- ```
1219
-
1220
- Note: as this API is anonymous, one does not need to actually log on to Campaign to call it. Here's a full example. See the authentication section for more details about anonymous logon.
1221
- ```js
1222
- const connectionParameters = sdk.ConnectionParameters.ofAnonymousUser("https://...");
1223
- const client = await sdk.init(connectionParameters);
1224
- const test = await client.test();
1225
- ```
1226
-
1227
-
1228
- ### ping
1229
- The ping API is authenticated and will return a simple status code indicating the the Campaign server is running. It will also return the current database timestamp. The API itself will return plain text, but for convenience this has been wrapped into JSON / XML in the SDK
1230
- ```js
1231
- const ping = await client.ping();
1232
- ```
1233
-
1234
- will return
1235
- ```json
1236
- {
1237
- "status":"Ok",
1238
- "timestamp":"2021-08-27 12:51:56.088Z"
1239
- }
1240
- ```
1241
-
1242
- ### mcPing
1243
- Message Center instances have a dedicated ping API which also returns the Message Center queue size and the maximum expected size (threshold). The API itself will return plain text, but for convenience this has been wrapped into JSON / XML in the SDK
1244
- ```js
1245
- const ping = await client.mcPing();
1246
- ```
1247
-
1248
- will return
1249
- ```json
1250
- {
1251
- "status":"Ok",
1252
- "timestamp":"2021-08-27 12:51:56.088Z",
1253
- "eventQueueSize":"7",
1254
- "eventQueueMaxSize":"400"
1255
- }
1256
- ```
1257
-
1258
- ## The Transport Protocol
1259
-
1260
- The SDK uses `axios` library internally to perform HTTP calls. This can be customized and one can use any other (async) protocol, which is implemented in the `transport.js` file.
1261
- The transport protocol defines
1262
- - What is an HTTP request
1263
- - What is the corresponding response
1264
- - How errors are handled
1265
-
1266
- The transport protocol exports a single asynchronous function `request` which takes two parameters.
1267
-
1268
- The first parameter is the request object with the following attributes. Note that it matches axios requests.
1269
- * `method` is the HTTP verb
1270
- * `url` is the URL to call
1271
- * `headers` is an object containing key value pairs with http headers and their values
1272
- * `data` is the request payload
1273
-
1274
- The second parameter is an set of additional parameters that have been pushed down to the transport layer (see the `Pushdown` paragraph for more details). In particular, the `timeout` parameter should be honored by the transport layer.
1275
-
1276
- If the request is successful, a promise is returned with the result payload, as a string.
1277
-
1278
- If the request fails, the promise is rejected with an error object with class `HttpError`, a litteral with the following attributes:
1279
- * `statusCode` is the HTTP status code, such as 404, 500, etc.
1280
- * `statusText` is the HTTP status text coming with the error
1281
- * `data` is the response data, if any
1282
-
1283
- For proper error handling by the ACC SDK, it's important that the actual class of returned objects is named "HttpError"
1284
-
1285
- The transport can be overriden by using the `client.setTransport` call and passing it a transport function, i.e. an async function which
1286
- * Takes a `Request` object litteral as a parameter
1287
- * Returns a the request result in a promise
1288
- * Returns a rejected promise containing an `HttpError` in case of failure
1289
-
1290
-
1291
- ## Observers
1292
-
1293
- The Campaign client implements an observer mechanism that you can use to hook into what's hapenning internally.
1294
-
1295
- An `Observer` is an object having any of the following methods:
1296
-
1297
- For SOAP calls
1298
- * onSOAPCall(soapCall, safeCallData)
1299
- * onSOAPCallSuccess(soapCall, safeCallResponse) {}
1300
- * onSOAPCallFailure(soapCall, exception) {}
1301
-
1302
- For HTTP calls (such as JSP, JSSP...). Note that despite SOAP calls are also HTTP calls, the following callbacks will not be called for SOAP calls.
1303
- * onHTTPCall(request, safeCallData)
1304
- * onHTTPCallSuccess(request, safeCallResponse) {}
1305
- * onHTTPCallFailure(request, exception) {}
1306
-
1307
- The `soapCall` parameter is the SOAP call which is being observed. In the `onSOAPCall` callback, the SOAP call has not been executed yet.
1308
-
1309
- The `request` parameter is the HTTP request (as defined in the transport protocol above)
1310
-
1311
- The `safeCallData` and `safeCallResponse` represent the text XML of the SOAP request and response, but in which all session and security tokens have been replaced with "***" string. Hence the name "safe". You should use those parameters for any logging purpose to avoid leaking credentials.
1312
-
1313
-
1314
- The `soapCall` parameter is a `SoapMethodCall` object which describes the SOAP call. It has the following public attributes.
1315
-
1316
- * `urn` is the SOAP URN which corresponds to the Campaign schema id. For instance "xtk:session"
1317
- * `methodName` is the name of the method to call. For instance "Logon"
1318
- * `internal` is true or false, depending if the SOAP call is an internal SOAP call performed by the framework itself, or if it's a SOAP call issued by a SDK user
1319
- * `request` is a literal corresponding to the HTTP request. It's compatible with the `transport` protocol. It may be undefined if the SOAP call has need been completely built
1320
- * `response` is a string containing the XML result of the SOAP call if the call was successful. It may be undefined if the call was not executed yet or if the call failed
1321
-
1322
-
1323
- In version 1.1.7, the observer interface is extended to listen for internal events of the SDK. The `event` function of the observer, if it exist will be call for each SDK event with 2 parameters: the event itself, and for some events, a parent event. For instance a SOAP response event will have the SOAP request for a parent event.
1324
- ```js
1325
- client.registerObserver({
1326
- event: (event, parentEvent) => { ... },
1327
- });
1328
- ```
1329
-
1330
- The following events are available
1331
-
1332
- | event name | comment / description |
1333
- |----|----|
1334
- | SDK//logon | A client logs on |
1335
- | SDK//logoff | A client logs off |
1336
- | CACHE//stats | Regularly sends stats about internal caches |
1337
- | SOAP//request | The SDK executes a SOAP request |
1338
- | SOAP//response | The SDK processes the successful response of a SOAP request |
1339
- | SOAP//failure | A SOAP request failed |
1340
- | HTTP//request | The SDK executes an HTTP request |
1341
- | HTTP//response | The SDK processes the successful response of an HTTP request |
1342
- | HTTP//failure | An HTTP request failed |
1343
- | CACHE_REFRESHER//start | A cache auto-refresher starts |
1344
- | CACHE_REFRESHER//stop | A cache auto-refresher stops |
1345
- | CACHE_REFRESHER//tick | A cache auto-refresh occurs |
1346
- | CACHE_REFRESHER//loggedOff | The cache auto-refresh was triggered whereas the client was logged off |
1347
- | CACHE_REFRESHER//error | The cache auto-refresh failed. Auto-refresh will continue. |
1348
- | CACHE_REFRESHER//abort | The cache auto-refresh failed because the server does not support it. Auto-refresh will stop. |
1349
- | CACHE_REFRESHER//response | The server responded to an auto-refresh request |
1350
-
1351
- # Configuration
1352
-
1353
- ## Tracking all SOAP calls
1354
-
1355
- SOAP calls can be logged by setting the `traceAPICalls` attribute on the client at any time. For security reasons, the security and session tokens values will be replaced by "***" to avoid leaking them
1356
-
1357
- ```js
1358
- client.traceAPICalls(true);
1359
- ```
1360
-
1361
- This is an example of the logs
1362
- ````
1363
- SOAP//request xtk:session#GetOption <SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
1364
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
1365
- xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
1366
- xmlns:ns="http://xml.apache.org/xml-soap">
1367
- <SOAP-ENV:Header>
1368
- <Cookie>__sessiontoken=***</Cookie>
1369
- <X-Security-Token>***</X-Security-Token>
1370
- </SOAP-ENV:Header>
1371
- <SOAP-ENV:Body>
1372
- <m:GetOption xmlns:m="urn:xtk:session" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
1373
- <sessiontoken xsi:type="xsd:string">***</sessiontoken>
1374
- <name xsi:type="xsd:string">XtkDatabaseId</name>
1375
- </m:GetOption>
1376
- </SOAP-ENV:Body>
1377
- </SOAP-ENV:Envelope>
1378
-
1379
- SOAP//response xtk:session#GetOption <?xml version='1.0'?>
1380
- <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema'
1381
- xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
1382
- xmlns:ns='urn:xtk:session'
1383
- xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
1384
- <SOAP-ENV:Body>
1385
- <GetOptionResponse xmlns='urn:xtk:session' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
1386
- <pstrValue xsi:type='xsd:string'>uFE80000000000000F1FA913DD7CC7C4804BA419F</pstrValue>
1387
- <pbtType xsi:type='xsd:byte'>6</pbtType>
1388
- </GetOptionResponse>
1389
- </SOAP-ENV:Body>
1390
- </SOAP-ENV:Envelope>
1391
- `````
1392
-
1393
-
1394
- # Query API
1395
-
1396
- List all accounts
1397
- ````
1398
- const queryDef = {
1399
- schema: "nms:extAccount",
1400
- operation: "select",
1401
- select: {
1402
- node: [
1403
- { expr: "@id" },
1404
- { expr: "@name" }
1405
- ]
1406
- }
1407
- };
1408
- const query = NLWS.xtkQueryDef.create(queryDef);
1409
-
1410
- console.log(query);
1411
- const extAccounts = await query.executeQuery();
1412
- console.log(JSON.stringify(extAccounts));
1413
- ````
1414
-
1415
- Get a single record
1416
- ```js
1417
- var queryDef = {
1418
- schema: "nms:extAccount",
1419
- operation: "get",
1420
- select: {
1421
- node: [
1422
- { expr: "@id" },
1423
- { expr: "@name" },
1424
- { expr: "@label" },
1425
- { expr: "@type" },
1426
- { expr: "@account" },
1427
- { expr: "@password" },
1428
- { expr: "@server" },
1429
- { expr: "@provider" },
1430
- ]
1431
- },
1432
- where: {
1433
- condition: [
1434
- { expr: "@name='ffda'" }
1435
- ]
1436
- }
1437
- }
1438
- const query = NLWS.xtkQueryDef.create(queryDef);
1439
- const extAccount = await query.executeQuery();
1440
- ```
1441
-
1442
- ## Escaping
1443
- It's common to use variables in query conditions. For instance, in the above example, you'll want to query an account by name instead of using the hardcoded "ffda" name. The `expr` attribute takes an XTK expression as a parameter, and 'ffda' is a string litteral in an xtk expression.
1444
-
1445
- To prevent xtk ingestions vulnerabilities, you should not concatenate strings and write code such as expr: "@name = '" + name + "'": if the value of the name
1446
- parameter contains single quotes, your code will not work, but could also cause vulnerabilities.
1447
-
1448
- ### sdk.escapeXtk
1449
-
1450
- The `sdk.escapeXtk` can be used to properly escape string litterals in xtk expressions. The function will also surround the escaped value with single quotes.
1451
-
1452
- You can use string concatenation like this. Note the lack of single quotes around the value.
1453
- ```
1454
- { expr: "@name=" + sdk.escapeXtk(name) }
1455
- ```
1456
-
1457
- or a template litteral
1458
- ```
1459
- `{ expr: "@name=${sdk.escapeXtk(name)}" }`
1460
- ```
1461
-
1462
- The `escapeXtk` function can also be used to create tagged string litterals. This leads to a much shorter syntax. Note that with this syntax, only the parameter values of the template litteral are escaped
1463
- ```
1464
- sdk.escapeXtk`{ expr: "@name=${name}" }`
1465
- ```
1466
-
1467
- This can also be used to escape other data types such as timestamps
1468
-
1469
- ```
1470
- sdk.escapeXtk`{ expr: "@lastModified > = ${yesterday}" }`
1471
- ```
1472
-
1473
- will return `{ expr: "@lastModified > = #2021-07-07T10:03:33.332Z# }`
1474
-
1475
-
1476
- ### sdk.escapeForLike
1477
-
1478
- This function escapes values so that they can be used in SQL or XTK like conditions. For example a search term "term" can be escaped as follows to implement a search conditions
1479
-
1480
- ```
1481
- expr: `Lower([${xpath}]) LIKE '%${sdk.escapeForLike(term)}%'`,
1482
- ```
1483
-
1484
- ### sdk.expandXPath & sdk.unexpandXPath
1485
-
1486
- In Campaign, xpaths are used to access attributes of entities. When XPaths are used in XTK expressions, there can be ambiguities, for instance, in the expression "country/@name", is "country/@name" a xpath or are we dividing the variable country by the value of the attribute @name?
1487
-
1488
- Amibiguity can be resolved by "expanding" the xpath from "country/@name" to "[country/@name]". The square brackets indicate an xpath.
1489
-
1490
- ```
1491
- const expandedXPath = sdk.expandXPath(xpath);
1492
- const unexpandedXPath = sdk.unexpandXPath(expandedXPath);
1493
- ```
1494
-
1495
- ### xtkConstText
1496
-
1497
- This function allows to convert literal values to xtk text constants, providing correct serialization. For instance, text constants will be quoted with single quotes, timestamps with the "#" character, etc.
1498
-
1499
- ```
1500
- expect(sdk.xtkConstText("Hello", "string")).toBe("'Hello'");
1501
- expect(sdk.xtkConstText(-42.3, "double")).toBe("-42.3");
1502
- expect(sdk.xtkConstText("2022-02-15T09:49:04.000Z", "datetime")).toBe("#2022-02-15T09:49:04.000Z#");
1503
- ```
1504
-
1505
-
1506
- ## Pagination
1507
- Results can be retrieved in different pages, using the `@lineCount` and `@startLine` attributes. For instance, retrieves profiles 3 and 4 (skip 1 and 2)
1508
-
1509
- ```js
1510
- var queryDef = {
1511
- schema: "nms:recipient",
1512
- operation: "select",
1513
- lineCount: 2,
1514
- startLine: 2,
1515
- select: {
1516
- node: [
1517
- { expr: "@id" },
1518
- { expr: "@email" }
1519
- ]
1520
- }
1521
- }
1522
- var query = NLWS.xtkQueryDef.create(queryDef);
1523
- var recipients = await query.executeQuery();
1524
- console.log(JSON.stringify(recipients));
1525
- ```
1526
-
1527
-
1528
-
1529
- # Writer API
1530
-
1531
- Creates an image (data is base64 encoded)
1532
- ```js
1533
- var data = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA9ElEQVQ4jaXTIUsFQRSG4eeKiBjEIBeDYDGoSUwGm81s8SdYtIhFhPMDbEaz/SIIZkGbWg1Gg0GwiIgYZPZuWBxn8bJvWXb2O+/scM70lAhjuMO1sF9IVaES61jFnjBbyLQKjurnJz6yr62CsI2t+m0gRhGERZw1Vk6zTFEQ+rjETOP3b7OqBr1G8SRusPYrc4I3LGCeapN37AqP443g8R/FiYNsZcgGSRCmq1ZxmEXa6Yt0hKh6/dAaLbOcd+H/XOGpi2AFU10EqWsTXQQ7wmsSPNdzP8DXCII0D41BSgxvXboHm1jCXDpnPbHfeME9znEh+AFoTyfEnWJgLQAAAABJRU5ErkJggg==";
1534
- var doc = {
1535
- xtkschema: "xtk:image",
1536
- _operation: "insert",
1537
- namespace: "cus",
1538
- name: "test.png",
1539
- label: "Self test",
1540
- type: "png",
1541
- $data: data
1542
- };
1543
- await NLWS.xtkSession.write(doc);
1544
- ````
1545
-
1546
- Creates a folder (with image previously created)
1547
- ```js
1548
- const folder = {
1549
- xtkschema: "xtk:folder",
1550
- _operation: "insert",
1551
- parent-id: 1167,
1552
- name: "testSDK",
1553
- label: "Test SDK",
1554
- entity: "xtk:folder",
1555
- schema: "xtk:folder",
1556
- model: "xtkFolder",
1557
- "image-namespace": "cus",
1558
- "image-name": "test.png"
1559
- };
1560
- await NLWS.xtkSession.write(folder);
1561
- ````
1562
-
1563
- Some objects, such as deliveries are created from templates. The `createFromModel` API is preferred in this case. Given a template name, and a patch object, it will return an object created from the template and the patch, applying all sort of business rules and default values. This object can be inserted using a writer.
1564
-
1565
- In this example, an email delivery is created from the "mail" delivery template and it's label is set to "Hello".
1566
-
1567
- Note the xtkschema attribute in the second parameter of the `createFromModel` API call which is needed for the SDK to perform the proper JSON to XML transformation.
1568
-
1569
- ```js
1570
- const mail = await client.NLWS.nmsDelivery.createFromModel('mail', { xtkschema:'nms:delivery', label:'Hello'});
1571
- await client.NLWS.xtkSession.write(mail);
1572
- ````
1573
-
1574
- # Workflow API
1575
-
1576
- Start and stop wotkflows, passing either an id or workflow internal name
1577
- ```js
1578
- await NLWS.xtkWorkflow.stop(4900);
1579
- await NLWS.xtkWorkflow.start(4900);
1580
- ```
1581
-
1582
- A workflow can be started with parameters. Variables, are passed as attributes of the parameters document.
1583
- ```js
1584
- await NLWS.xtkWorkflow.startWithParameters(4900, { hello: "world" });
1585
- ```
1586
-
1587
- The variables can be used in the workflow as attributes of the `instance.vars` variable.
1588
-
1589
- ```js
1590
- logInfo(instance.vars.hello);
1591
- ```
1592
-
1593
-
1594
-
1595
- # Profiles and subscriptions
1596
-
1597
- Create a recipient
1598
- ```js
1599
- var recipient = {
1600
- xtkschema: "nms:recipient",
1601
- _operation: "insert",
1602
- firstName: "Thomas",
1603
- lastName: "Jordy",
1604
- email: "jordy@adobe.com"
1605
- };
1606
- await NLWS.xtkSession.write(recipient);
1607
- ```
1608
-
1609
- Create multiple recipients
1610
- ```js
1611
- var recipients = {
1612
- xtkschema: "nms:recipient",
1613
- recipient: [
1614
- {
1615
- _operation: "insert",
1616
- firstName: "Christophe",
1617
- lastName: "Protat",
1618
- email: "protat@adobe.com"
1619
- },
1620
- {
1621
- _operation: "insert",
1622
- firstName: "Eric",
1623
- lastName: "Perrin",
1624
- email: "perrin@adobe.com"
1625
- }
1626
- ]
1627
- };
1628
- await NLWS.xtkSession.writeCollection(recipients);
1629
- ```
1630
-
1631
- List all recipients in Adobe
1632
- ```js
1633
- var queryDef = {
1634
- schema: "nms:recipient",
1635
- operation: "select",
1636
- select: {
1637
- node: [
1638
- { expr: "@id" },
1639
- { expr: "@firstName" },
1640
- { expr: "@lastName" },
1641
- { expr: "@email" }
1642
- ]
1643
- },
1644
- where: {
1645
- condition: [
1646
- { expr: "GetEmailDomain(@email)='adobe.com'" }
1647
- ]
1648
- }
1649
- }
1650
- const query = NLWS.xtkQueryDef.create(queryDef);
1651
- var recipients = await query.executeQuery();
1652
- console.log(JSON.stringify(recipients));
1653
- ```
1654
-
1655
- Count total number of profiles
1656
- ```js
1657
- var queryDef = {
1658
- schema: "nms:recipient",
1659
- operation: "count"
1660
- }
1661
- var query = NLWS.xtkQueryDef.create(queryDef);
1662
- var count = await query.executeQuery();
1663
- count = XtkCaster.asLong(count.count);
1664
- console.log(count);
1665
- ```
1666
-
1667
- Update a profile. In this case, use the "@email" attribute as a key. If the `@_key` attribute is not specified, the primary key will be used.
1668
- ```js
1669
- var recipient = {
1670
- xtkschema: "nms:recipient",
1671
- _key: "@email",
1672
- _operation: "update",
1673
- firstName: "Alexandre",
1674
- email: "amorin@adobe.com"
1675
- };
1676
- await NLWS.xtkSession.write(recipient);
1677
- ```
1678
-
1679
- Deletes a profile
1680
- ```js
1681
- var recipient = {
1682
- xtkschema: "nms:recipient",
1683
- _key: "@email",
1684
- _operation: "delete",
1685
- email: "amorin@adobe.com"
1686
- };
1687
- await NLWS.xtkSession.write(recipient);
1688
- ```
1689
-
1690
- Deletes a set of profiles, based on condition. For instance delete everyone having an email address in adobe.com domain
1691
- ```js
1692
- await NLWS.xtkSession.deleteCollection("nms:recipient", { condition: { expr: "GetEmailDomain(@email)='adobe.com'"} });
1693
- ```
1694
-
1695
-
1696
- # Message Center
1697
-
1698
- The Message Center API (`nms:rtEvent#PushEvent`) can be used to send transactional messages. It should be called on the Message Center execution instances, not on the marketing instances.
1699
-
1700
- ## Authentication
1701
- Two authentication mechanism are possible for Message Center. It is possible to use a user/password authentication and call the Logon method to get a session and security token, as all other APIs. When using this authentication mechanism, the caller is responsible to handle token expiration and must explicitely handle the case when the Message Center API call fails because of an expired token.
1702
-
1703
- Another common authentication strategy is to define a trusted Security Zone for message center clients and setup this security zone to use the "user/password" as a session token.
1704
-
1705
- Here's an example of authentication with this method
1706
- ```js
1707
- const connectionParameters = sdk.ConnectionParameters.ofSessionToken(url, "mc/mc");
1708
- const client = await sdk.init(connectionParameters);
1709
- ```
1710
-
1711
- ## Pushing events
1712
-
1713
- Events can be pushed using the `nms:rtEvent#PushEvent` API call. For instance
1714
- ```js
1715
- var result = await NLWS.nmsRtEvent.pushEvent({
1716
- wishedChannel: 0,
1717
- type: "welcome",
1718
- email: "aggmorin@gmail.com",
1719
- ctx: {
1720
- $title: "Alex"
1721
- }
1722
- });
1723
- console.log(`>> Result: ${result}`);
1724
- ```
1725
-
1726
- There are a couple of noteworthy things to say about this API when using SimpleJson serialization.
1727
-
1728
- * The payload passed to the pushEvent API call is actuall a nms:rtEvent entity. Hence the wishedChannel, etc. are actually XML attributes. The default SimpleJson conversion works fine here, no need to prefix the attributes with the "@" sign.
1729
- * However, the `ctx` section is not structured. We do not have a schema to validate or guide the conversion. It is common to use XML elements instead of attributes in the ctx context. In the message center template, you'll find things like `<%= rtEvent.ctx.title %>`. The fact that "title" is used (in stead of "@title") implied that the ctx node will contain a title element, not a title attribute. For the SimpleJson conversion to work, it's therefore important to indicate "$title" as the JSON attribute name. This will guide the SimpleJson converted to use an XML element instead of an XML attribute
1730
-
1731
-
1732
- ## Getting event status
1733
-
1734
- There's no scalable API to get the status of a message center event. One can use the QueryDef API to query the nms:rtEvent table for testing purpose though.
1735
-
1736
- To do so, the first step is to decode the event id returned by PushEvent. It is a 64 bit number, whose high byte is the message center cell (instance) id which handled the event. It's a number between 0 and 255. The lower bytes represent the primary key of the event. Note that this is subject to change in future versions of Campaign and should not be considered stable.
1737
-
1738
- Clear high byte
1739
- ```js
1740
- eventId = Number(BigInt(eventId) & BigInt("0xFFFFFFFFFFFFFF"));
1741
- ```
1742
-
1743
- Get event status
1744
- ```js
1745
- var queryDef = {
1746
- schema: "nms:rtEvent",
1747
- operation: "get",
1748
- select: {
1749
- node: [
1750
- { expr: "@id" },
1751
- { expr: "@status" },
1752
- { expr: "@created" },
1753
- { expr: "@processing" },
1754
- { expr: "@processed" }
1755
- ]
1756
- },
1757
- where: {
1758
- condition: [
1759
- { expr:`@id=${eventId}` }
1760
- ]
1761
- }
1762
- }
1763
- query = NLWS.xtkQueryDef.create(queryDef);
1764
- var event = await query.executeQuery();
1765
- console.log(`>> Event: ${JSON.stringify(event)}`);
1766
- ```
1767
-
1768
- # Application
1769
-
1770
- The `application` object can be obtained from a client, and will mimmic the Campaing `application` object (https://docs.adobe.com/content/help/en/campaign-classic/technicalresources/api/c-Application.html)
1771
-
1772
- | Attribute/Method | Description |
1773
- |---|---|
1774
- | **buildNumber** | The server build number
1775
- | **version** | In SDK version 1.1.4 and above, returns the server version formatted as major.minor.servicePack (ex: 8.2.10)
1776
- | **instanceName** | The name of the Campaign instance
1777
- | **operator** | Information about the current operator (i.e. logged user), of class `CurrentLogin`
1778
- | **packages** | List of installed packages, as an array of strings
1779
- | async **getSchema**(schemaId) | Get a schema by id (see the Schemas section below)
1780
- | async **getEnumeration**(enumerationName, schemaOrSchemaId) | Get an enumeration
1781
- | **hasPackage**(name) | Tests if a package is installed or not
1782
-
1783
-
1784
- The `CurrentLogin` object has the following attributes / functions
1785
-
1786
- | Attribute/Method | Description |
1787
- |---|---|
1788
- | **id** | the internal id (int32) of the operator
1789
- | **login** | the login name of the operator
1790
- | **computeString** | A human readable name for the operator
1791
- | **timezone** | The timezone of the operator
1792
- | **rights** | An array of strings describing the rights of the operators
1793
-
1794
- # Schemas
1795
-
1796
- Reading schemas is a common operation in Campaign. The SDK provides a convenient functions as well as caching for efficient use of schemas.
1797
-
1798
- ```js
1799
- const schema = await client.getSchema("nms:recipient");
1800
- console.log(JSON.stringify(schema));
1801
- ```
1802
-
1803
- A given representation can be forced
1804
- ```js
1805
- const xmlSchema = await client.getSchema("nms:recipient", "xml");
1806
- const jsonSchema = await client.getSchema("nms:recipient", "SimpleJson");
1807
- ```
1808
-
1809
- System enumerations can also be retreived with the fully qualified enumeration name
1810
- ```js
1811
- const sysEnum = await client.getSysEnum("nms:extAccount:encryptionType");
1812
- ```
1813
-
1814
- or from a schema
1815
- ```js
1816
- const schema = await client.getSchema("nms:extAccount");
1817
- const sysEnum = await client.getSysEnum("encryptionType", schema);
1818
- ```
1819
-
1820
- Get a source schema
1821
- ```js
1822
- var srcSchema = await NLWS.xtkPersist.getEntityIfMoreRecent("xtk:srcSchema|nms:recipient", "", false);
1823
- console.log(JSON.stringify(srcSchema));
1824
- ```
1825
-
1826
- ## Schema API (aka XtkNodeDef)
1827
- The Schema API is the Campaign API which allows to access schemas and the corresponding node hierarchy in a programmatic way. It's simpler to use this API than to manipulate XML or JSON. The name XtkNodeDef comes from "Xtk Node Definition", where an XtkNode is a generic node in a schema definition.
1828
-
1829
- The Schema API closely mimmics the Campaign server side API : https://docs.adobe.com/content/help/en/campaign-classic/technicalresources/api/c-Schema.html with the following differences:
1830
-
1831
- * The `XtkSchema` and associated classes (`XtkSchemaNode`, `XtkSchemaKey`, `XtkEnumeration` and `XtkEnumerationValue`) are all immutable. There are currently no API to create schemas dynamically
1832
- * Not all methods and functions are implemented
1833
- * Several methods are asynchronous because they may require a server round trip to fetch schemas, etc.
1834
- * There could be slight differences in usage due to Campaign server side JavaScript using some E4X specific constructs to iterate over collections (ex: for each(...)) which are not available in standard JavaScript environments
1835
-
1836
- The entry point is the application object. Obtain a schema from its id:
1837
-
1838
- ```js
1839
- const application = client.application;
1840
- const schema = await application.getSchema("nms:recipient");
1841
- ```
1842
-
1843
- This return a schema object of class `XtkSchema`
1844
-
1845
-
1846
- ### Iterating over collections
1847
- The metadata SDK closely mimmics the Campaign API, but provides convenience functions to access collections of objects, such as the children of a node, the values of an enumeration, etc. using an `ArrayMap` structure which allows access as both an array and a map.
1848
-
1849
- Access as a map. Child elements can be accessed with their names, as if it was a JavaScript map. For instance, accessing the gender of a recipient. This method is kept as a compatibility layer with the legacy API and older versions of the SDK but is deprecated / discouraged. The reason is that there are schemas which have attribut names such as "length", or element names such as "forEach" which collide with JavaScript objects.
1850
- ```js
1851
- const schema = await client.application.getSchema("nms:recipient");
1852
- const enumerations = schema.enumerations;
1853
- // deprecated, discouraged
1854
- expect(enumerations.gender.label).toBe("Gender");
1855
- ```
1856
-
1857
- Instead, prefer the `get` function which can retreive any enumeration value
1858
- ```js
1859
- const schema = await client.application.getSchema("nms:recipient");
1860
- const enumerations = schema.enumerations;
1861
- expect(enumerations.get("gender").label).toBe("Gender");
1862
- ```
1863
-
1864
- Elements can also be accessed as an array. In this example, we are iterating over the enumerations of a schema
1865
- ```js
1866
- const schema = await client.application.getSchema("nms:recipient");
1867
- const enumerations = schema.enumerations;
1868
- for (let i=0; i<enumerations.length; i++) {
1869
- const enumeration = enumerations[i];
1870
- }
1871
- ```
1872
-
1873
- Note that this assumes that there is no enumeration called "length" which will override the "length" attribute. Schemas, schema elements, and sql schemas have attributes named "length", but they are attributes, and will therefore be named "@length" in the metadata API. There is no element named "length" in out-of-the-box schemas.
1874
-
1875
- The ArrayMap also behaves like an iterator and works fine with the `for...of` syntax
1876
- ```js
1877
- const schema = await client.application.getSchema("nms:recipient");
1878
- const enumerations = schema.enumerations;
1879
- for (const enumeration of enumerations) {
1880
- ...
1881
- }
1882
- ```
1883
-
1884
- For convenience, the `map` and `forEach`, `find`, `filter`, `get`, and `flatMap` methods are also available and behave as expected:
1885
-
1886
- ```js
1887
- const schema = await client.application.getSchema("nms:recipient");
1888
- // comma separated list of enumerations
1889
- const enumerations = schema.enumerations.map(e => e.name).join(',');
1890
- ```
1891
-
1892
- ```js
1893
- const schema = await client.application.getSchema("nms:recipient");
1894
- schema.enumerations.forEach(e => { ... });
1895
- ```
1896
-
1897
- The `for...in` loop is also supported but deprecated/discouraged as it may return incorrect results for collections having items whose key collide with javaScript properties (such as length, map, forEach, etc.). Use a `for...of` construcr instead, or the `map` or `forEach` functions.
1898
- ```js
1899
- const schema = await client.application.getSchema("nms:recipient");
1900
- // deprecated, discouraged
1901
- for (const key in schema.enumerations) {
1902
- ...
1903
- }
1904
- ```
1905
-
1906
- ## Navigating schemas
1907
- The schema API is useful to quickly navigate in the schema hierarchy. Here are a few examples
1908
-
1909
- Get the label of the email attribute of the nms:recipient schema
1910
- ```js
1911
- const schema = await application.getSchema("nms:recipient");
1912
- const email = await schema.root.findNode("@email");
1913
- console.log(email.label);
1914
- ```
1915
-
1916
- The `findNode` function follows links and references
1917
- * The function now supports `ref` nodes. Ref nodes are schema nodes having a `ref` property which is a reference to another node, possibly in a different schema.
1918
- * If the xpath passed to the function ends with a ref node, the ref node itself will be returned. We're not following the reference. You can use the `refTarget` method to explicitely follow the reference
1919
- * If the xpath traverse intermediate nodes which are ref nodes, the `findNode` method will follow the reference. For instance, the start activity in a workflow is a reference. Finding the xpath "start/@img" will follow the start reference and find the @img attribute from there
1920
-
1921
- * Support for links. If the xpath parameter contains links, `findNode` will follow the link
1922
- target with the same rules as for reference nodes. To get the target of a link, use the `linkTarget` method instead of `refTarget`.
1923
-
1924
-
1925
- For insance, you can get the country of a recipient who clicked in an email. This call follows the link from nms:broadLogRcp to nms:recipient and then from nms:recipient to nms:country, returning the country isoA3 attribute.
1926
- ```js
1927
- const schema = await application.getSchema("nms:broadLogRcp");
1928
- const node = await schema.root.findNode("recipient/country/@isoA3");
1929
- ```
1930
-
1931
- The same syntax can be used for reference nodes. For instance, getting the attributes of the start activity of a workflow:
1932
- ```js
1933
- const schema = await application.getSchema("xtk:workflow");
1934
- const node = await schema.root.findNode("start/@name");
1935
- ```
1936
-
1937
- In order to actually iterate over the children, things are a little bit more complicated
1938
- ```js
1939
- const schema = await application.getSchema("xtk:workflow");
1940
- const start = await schema.root.findNode("start");
1941
- // start is the ref node, not the target of the ref. One need to explicitely
1942
- // follow the ref in order to get the list of children
1943
- const target = await start.refTarget();
1944
- target.children.forEach(child => ... );
1945
- ```
1946
-
1947
- To get the root node of the target of a link, use the `linkTarget` function
1948
- ```js
1949
- const schema = await application.getSchema("nms:broadLogRcp");
1950
- const node = await schema.root.findNode("recipient/country");
1951
- // node is the country link, not the root node of the nms:country schema
1952
- const root = await node.linkTarget();
1953
- // root is the root node of the nms:country schema
1954
- ```
1955
-
1956
-
1957
- ### XtkSchema
1958
-
1959
- | Attribute | Description |
1960
- |---|---|
1961
- | **id** | The id of the schema. For instance "nms:recipient"
1962
- | **namespace** | The namespace of the schema. For instance "nms"
1963
- | **name** | The name of the schema (internal name)
1964
- | **label** | The label (i.e. human readable, localised) name of the node.
1965
- | **labelLocalizationId** | The translation id of the label of the node.
1966
- | **labelSingular** | The singular label (i.e. human readable, localised) name of the schema. The label of a schema is typically a plural.
1967
- | **labelSingularTranslationId** | The translation id of the label of the node of the singular label.
1968
- | **isLibrary** | For schemas, indicates if the schema is a library
1969
- | **mappingType** |Schema mapping type. Usually "sql"
1970
- | **md5** | The MD5 code of the schema in the form of a hexadecimal string
1971
- | **xml** | The XML (DOM) corresponding to this schema.<br>Note: this attribute is not available in the JS SDK.
1972
- | **root** | The schema root node, if there is one. A reference to a `XtkSchemaNode`
1973
- | **enumerations** | Map of enumerations in this schema, indexed by enumeration name. Values are of type `XtkEnumeration`
1974
- | **userDescription** | The description of the schema in the form of a string.
1975
-
1976
- A schema is also a `XtkSchemaNode` and the corresponding properties/methods are also availale.
1977
-
1978
- ### XtkSchemaNode
1979
-
1980
- | Attribute | Description |
1981
- |---|---|
1982
- | **children** | A array/map of children of the node. See note on the ArrayMap structure below
1983
- | **dataPolicy** | Returns a string of characters which provides the data policy of the current node.
1984
- | **description** | A long, human readable, description of the node
1985
- | **descriptionLocalizationId** | The translation id of the description of the node.
1986
- | **editType** |Returns a string of characters which specifies the editing type of the current node.
1987
- | **enum** | The name of the enumeration for the node, or an empty string if the node does node have an enumeration. See `enumeration()` method to get the corresponding `XtkSchemaNode`
1988
- | **enumerationImage** | Returns the name of the image of the current node in the form of a string of characters.
1989
- | **folderModel** |Only on the root node, returns a string which contains the folder template(s). On the other nodes, it returns undefined.
1990
- | **image** | Returns the name of the image in the form of a string of characters.
1991
- | **img** | Returns the name of the image in the form of a string of characters. (alias to `image` property)
1992
- | **integrity** | Returns the link integrity type.
1993
- | **keys** | A array/map of keys in this node, indexed by key name. Map values are of type `XtkSchemaKey`
1994
- | **hasEnumeration** | Returns a boolean which indicates whether the value of the current node is linked to an enumeration.
1995
- | **childrenCount** | Number of children nodes
1996
- | **hasSQLTable** | Returns a boolean which indicates whether the current node is linked to an SQL table.
1997
- | **hasUserEnumeration** | Returns a boolean which indicates whether the value of the current node is linked to a user enumeration.
1998
- | **schema** | The schema (`XtkSchema`) to which this node belongs
1999
- | **isAdvanced** | Returns a boolean which indicates whether the current node is advanced or not.
2000
- | **isAnyType** | Returns a boolean which indicates whether the current node is ordinary.
2001
- | **isAttribute** | Indicates if the node is an attribute (true) or an element (false)
2002
- | **isAutoIncrement** | Returns a boolean which indicates whether the value of the current node is incremented automatically.
2003
- | **isAutoPK** | Returns a boolean which indicates whether the current node is a primary key.
2004
- | **isAutoUUID** | Yes | No | Returns a boolean which indicates whether the current node is an automatic UUID
2005
- | **isAutoStg** | Yes | No | Returns a boolean which indicates whether the schema is a staging schema
2006
- | **isBlob** | Returns a boolean which indicates whether the current node is a BLOB.
2007
- | **isCalculated** | Returns a boolean which indicates whether the value of the current node is the result of a calculation. Note that compute strings are not considered as calculated attributes.
2008
- | **isCDATA** | Returns a boolean which indicates whether the current node is mapped from CDATA type XML.
2009
- | **isCollection** | Returns a boolean which indicates whether the current node is a collection of sub-elements and/or attributes. This is an alias to `unbound` and `isUnbound` properties.
2010
- | **isDefaultOnDuplicate** | Returns a boolean. If the value added is vrai, during record deduplication, the default value (defined in defaultValue) is automatically reapplied during recording.
2011
- | **isElementOnly** | Returns a boolean which indicates whether the current node is a logical sub-division of the schema.
2012
- | **isExternalJoin** | True if the node is a link and if the join is external.
2013
- | **isLink** | Returns a boolean which indicates whether the node is a link.
2014
- | **isMappedAsXML** | Returns a boolean which indicates whether the node is an XML mapping.
2015
- | **isMemo** | Returns a boolean which indicates whether the current node is mapped by a Memo.
2016
- | **isMemoData** | Returns a boolean which indicates whether the current node is mapped by a MemoData.
2017
- | **isNotNull** | Returns a boolean which indicates whether or not the current node can take the null value into account.
2018
- | **isRequired** | Returns a boolean which indicates whether or not the value of the current node is mandatory.
2019
- | **isRoot** | Indicates if the node is the root node of a schema, i.e. the first child of the schema node, whose name matches the schema name
2020
- | **isSQL** | Returns a boolean which indicates whether the current node is mapped in SQL.
2021
- | **isTemporaryTable** | Returns a boolean indicating whether the table is a temporary table. The table will not be created during database creation.
2022
- | **unbound** | Returns a boolean which indicates whether the current node has an unlimited number of children of the same type.
2023
- | **joins** | Element of type "link" has an array of XtkJoin. See `joinNodes` method.
2024
- | **label** | The label (i.e. human readable, localised) name of the node.
2025
- | **labelLocalizationId** | The translation id of the label of the node.
2026
- | **name** | The name of the node (internal name)
2027
- | **nodePath** | The xpath of the node
2028
- | **parent** | The parent node (a `XtkSchemaNode` object). Will be null for schema nodes
2029
- | **PKSequence** | Returns a character string that provides the name of the sequence to use for the primary key.
2030
- | **packageStatus** | Returns a number that gives the package status.
2031
- | **packageStatusString** | Returns a string that gives the package status ("never", "always", "default", or "preCreate").
2032
- | **revLink** | Returns the name of the reverse link in the link target schema. See `reverseLink` method to get the actual reverse link object
2033
- | **SQLName** | The SQL name of the field. The property is an empty string if the object isn't an SQL type field.
2034
- | **SQLTable** | The SQL name of the table. The property is an empty string if the object isn't the main element or if schema mapping isn't of SQL type.
2035
- | **size** | For string nodes, the maximum length of the node value. Alias to `length`.
2036
- | **length** | For string nodes, the maximum length of the node value. Alias to `size`.
2037
- | **target** | A string corresponding to the target of a link. Note that in the SDK, this is a string, whereas in the JS API, this is the actual target node. Because the SDK is async. Use `linkTarget` to get the target node of a link.
2038
- | **type** | The data type of the node, for instance "string", "long", etc.
2039
- | **userEnumeration** | Returns a string of characters which is the name of the user enumeration used by the current node.
2040
- | **ref** | Some nodes are only references to other nodes. There are 2 kind of references. Local references are simply a xpath in the current schema (starting from the schema itself, and not the schema root). Fully qualified references are prefixed with a schema id. The target node can be accessed with the `refTarget` funtion.
2041
- | **isMappedAsXml** | Is the field mapped as XML?
2042
- | **visibleIf** | The visibility expression of the node (if any) since version 1.1.9 of the SDK
2043
- | **belongsTo** | For attribute and elements, indicates the schema id in which they were defined. Since version 1.1.10 of the SDK
2044
-
2045
-
2046
- | Method | Description |
2047
- |---|---|
2048
- | async **findNode** | Find a child node using a xpath. This function follows links and references if necessary and will dynamically fetch/cache necessary schemas.
2049
- | async **refTarget** | Get the target node of a reference
2050
- | async **linkTarget** | Get the target node of a link. See `target`
2051
- | async **joinNodes** | Get the schema nodes corresponding to link. The function returns nodes for both the source and the destination of the link. See `joins`.
2052
- | async **reverseLink** | Returns the node corresponding to the reverse link of a link. See `revLink` to get the reverse link name rather than the actual node
2053
- | async **computeString** | Returns the compute string of a node, following references if necessary
2054
- | async **enumeration** | For nodes whose value is an enumeration, return the `XtkEnumeration` object corresponding to the enumeration definition. See `enum` property to get the enumeration name instead of the object
2055
- | **firstInternalKeyDef** |
2056
- | **firstExternalKeyDef** |
2057
- | **firstKeyDef** |
2058
-
2059
-
2060
-
2061
- ### XtkSchemaKey
2062
-
2063
- | Attribute/Method | Description |
2064
- |---|---|
2065
- | **schema** | The schema to which this key belongs
2066
- | **name** | The name of the key (internal name)
2067
- | **label** | The label (i.e. human readable, localised) name of the key
2068
- | **description** | A long, human readable, description of the key
2069
- | **isInternal** | Indicates if the key is an internal key (as opposed to an external key)
2070
- | **allowEmptyPart** |
2071
- | **fields** | A ArrayMap of key fields making up the key. Each value is a reference to a `XtkSchemaNode`
2072
-
2073
- ### XtkEnumeration
2074
-
2075
- | Attribute/Method | Description |
2076
- |---|---|
2077
- | **name** | The name of the enumeration, fully qualified, i.e. prefixed with the schema id
2078
- | **label** | The label (i.e. human readable, localised) name of the key
2079
- | **labelLocalizationId** | The translation id of the label of the key.
2080
- | **description** | A long, human readable, description of the key
2081
- | **descriptionLocalizationId** | The translation id of the description of the key.
2082
- | **baseType** | The base type of the enumeration, usually "string" or "byte"
2083
- | **default** | The default value of the enumeration, casted to the enumeration type
2084
- | **hasImage** | If the enumeration has an image
2085
- | **values** | A ArrayMap of enumeration values, of type `XtkEnumerationValue`
2086
-
2087
- ### XtkEnumerationValue
2088
-
2089
- | Attribute/Method | Description |
2090
- |---|---|
2091
- | **name** | The name of the key (internal name)
2092
- | **label** | The label (i.e. human readable, localised) name of the key
2093
- | **labelLocalizationId** | The translation id of the label of the key.
2094
- | **description** | A long, human readable, description of the key
2095
- | **descriptionLocalizationId** | The translation id of the description of the key.
2096
- | **image** |
2097
- | **enabledIf** |
2098
- | **applicableIf** |
2099
- | **value** | The value of the enumeration (casted to the proper Javascript type)
2100
-
2101
- # Advanced Topics
2102
-
2103
- ## The EntityAccessor
2104
-
2105
- An `EntityAccessor` provides a simple interface to access entity objects regardless of their representation. For instance, a query result may be a DOM Element, or a object literal, or a BadgerFish objet. Accessing attribute values and sub elements requires to know which representation is used and which representation specific API to call. For instance, to get the "name" attribute of an entity, you'll write:
2106
-
2107
- * for Simple Json representation, access as JavaScript properties: entity.name or entity["name"]
2108
- * for the XML representation, use the DOM API: entity.DomUtil.getAttribute("name)"
2109
- * for Badget fish, access as JavaScript properties, but do not forget the "@" sign; entity["@name"]
2110
-
2111
- Once done, you'll probably want to cast the value to an XTK type using the XtkCaster.
2112
-
2113
- If you need to access entity attributes (or child elements) in a generic way, you can use the `EntityAccessor`. It has the following static methods:
2114
-
2115
- * `getAttributeAsString`, `getAttributeAsLong`, `getAttributeAsBoolean` to get typed attribute values
2116
- * `getChildElements` to get the child elements. The result can be iterated on with a `for...of...` loop
2117
- * `getElement` to get a child element whose attributes and child elements can also be accessed by the EntityAccessor API
2118
-
2119
- ## Invoking SOAP calls dynamically
2120
- Soap calls can be invoked dynamically as follows
2121
-
2122
- ```js
2123
- const namespace = client.NLWS["xtkSession"];
2124
- const method = namespace["getOption"];
2125
- const result = await method.call(namespace, parameters);
2126
- ```
2127
-
2128
- where parameters is the list of parameters to the SOAP call.
2129
- Parameters can be a function which can compute and return the list of parameters as the function is being called:
2130
-
2131
- ```js
2132
- const result = await method.call(namespace, (method, callContext) => {
2133
- return parameters;
2134
- });
2135
- ```
2136
- The `method` parameter is the XML definition of the SOAP method call. The `callContext` is an object which contains the following attributes:
2137
- * `schemaId` is the id of the schema containing the SOAP method
2138
- * `namespace` is the call namespace
2139
- * `object` is only used for non-static call and contains the "this" of the call.
2140
-
2141
-
2142
-
2143
- # Build & Run
2144
-
2145
- To build this project, you need node and npm
2146
-
2147
- ```sh
2148
- npm install
2149
- ```
2150
-
2151
- ## Check and resolve any security issues
2152
- ```sh
2153
- npm audit
2154
- npm audit fix --force
2155
- ```
2156
-
2157
- ## Check if there are any code warnings
2158
- ```sh
2159
- node_modules/jshint/bin/jshint src/
2160
- ```
2161
-
2162
- ## Run tests
2163
- ```sh
2164
- npm run unit-tests
2165
- ```
2166
-
2167
- ## Build JavaScript documentation
2168
- ```sh
2169
- npm run jsdoc
2170
- open ./docs/jsdoc/index.html
2171
- ```
2172
-
2173
- The HTML doc will be generated in the docs/ folder
2174
-
2175
- ## Deploy to npm
2176
-
2177
- To deploy to npm
2178
- * Build and run tests locally
2179
- * Increase version in `package.json`
2180
- * Push a commit with message `Release 1.2.3` in master
2181
-
2182
- | There's a publication action that will publish released automatically when there's a commit named "Release ..." in master AND the version matches the one in package.json
2183
- | Do not create a git tag for this version, the publication hook will take care of it. If you have created a tag with the release name, the publication will fail
2184
-
2185
-
2186
- # Client-side SDK
2187
- The SDK can also be used client side.
2188
-
2189
- ## Compile the client-side SDK
2190
- Go to the root folder of the SDK and compile the SDK
2191
- ````sh
2192
- node ./compile.js
2193
- ````
2194
-
2195
- It generates a file named `dist/bundle.js`
2196
- ````
2197
- ACC client-side SDK compiler version 0.1.0
2198
- Bundling ../package.json
2199
- Bundling ./web/jsdom.js
2200
- Bundling ./web/crypto.js
2201
- Bundling ./web/request.js
2202
- Bundling ./xtkCaster.js
2203
- Bundling ./domUtil.js
2204
- Bundling ./xtkEntityCache.js
2205
- Bundling ./methodCache.js
2206
- Bundling ./optionCache.js
2207
- Bundling ./soap.js
2208
- Bundling ./crypto.js
2209
- Bundling ./client.js
2210
- Bundling ./index.js
2211
- Client-side SDK generated in ./dist/bundle.js
2212
- ````
2213
-
2214
- ## Use a proxy
2215
- Using the client side SDK cannot be done directly because the Campaign server has CORS configured to reject HTTP requests from resources not served by Campaign.
2216
- Therefore a server-side proxy is need to relay the calls to Campaign, or you need to serve the SDK and corresponding web pages from Campaign itself
2217
-
2218
- ## Deploy the SDK to a Campaign server
2219
- Once compiled, copy it to the Campaign server (here on a dev environment).
2220
- ````sh
2221
- cd /c/cygwin64/home/neolane/ac
2222
- cp "Z:\amorin On My Mac\Documents\dev\git\ac7\acc-js-sdk\dist/bundle.js" nl/web/accSDK.js
2223
- ````
2224
-
2225
- This makes them available on the following endpoint
2226
- ````
2227
- /nl/accSDK.js
2228
- ````
2229
-
2230
-
2231
-
2232
-
2233
- ## Usage
2234
-
2235
- Include the SDK
2236
- ```
2237
- <script src="accSDK.js"></script>
2238
- ````
2239
-
2240
- Use the SDK. Note that the SDK variable is now called `document.accSDK` to avoid potential name collision with the common name "sdk".
2241
- ````
2242
- <script>
2243
-
2244
- (async () => {
2245
- const sdk = document.accSDK;
2246
-
2247
- const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
2248
- "http://ffdamid:8080", "admin", "admin");
2249
- const client = await sdk.init(connectionParameters);
2250
-
2251
- console.log(sdk.getSDKVersion());
2252
- await client.logon();
2253
-
2254
- var databaseId = await client.getOption("XtkDatabaseId");
2255
- console.log(databaseId);
2256
- document.getElementById("hello").textContent = databaseId;
2257
-
2258
- await client.logoff();
2259
- })();
2260
-
2261
- </script>
2262
- ````
2263
-
2264
-
2265
103
 
2266
104
  # Contributing
2267
105