Security News
Research
Supply Chain Attack on Rspack npm Packages Injects Cryptojacking Malware
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
@adobe/acc-js-sdk
Advanced tools
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.
Another attempt to publish to npm from github action
Bug fixes
Bug fixes
Initial version
In order to call the API, you need to create a Client
object
const sdk = require('./src/index.js');
const client = await sdk.init("https://myInstance.campaign.adobe.com", "admin", "admin");
const NLWS = client.NLWS;
The NLWS object allows to dynamically perform SOAP calls on the targetted Campaign instance.
You can get version information about the SDK
console.log(sdk.getSDKVersion());
await client.logon();
await client.logoff();
Static APIs are the easiest to call. Once you have a NLWS
object and logon to the server, call a static API as followed
result = await NLWS.xtkSession.getServerTime();
console.log(result);
where
xtkSession
is made of the namespace and entity to which the API applies. For instance xtk:session
-> xtkSession
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.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. We're using Badgerfish convention (http://www.sklar.com/badgerfish/) for the translation.
By default, JSON is used, but the representation can be changed as follow:
client.representation = "xml";
client.representation = "json";
Here's an example of a queryDef in JSON
const queryDef = {
"@schema": "nms:extAccount",
"@operation": "select",
"select": {
"node": [
{ "@expr": "@id" },
{ "@expr": "@name" }
]
}
};
Campaign API can return one or multiple values. The SDK uses the following convention:
To call a non-static API, you need an object to call the API on. You create an object with the create
method.
For instance, here's how one creates a QueryDef object.
const queryDef = {
"@schema": "nms:extAccount",
"@operation": "select",
"select": {
"node": [
{ "@expr": "@id" },
{ "@expr": "@name" }
]
}
};
const query = NLWS.xtkQueryDef.create(queryDef);
The method can then be called directly on the object
const extAccounts = await query.executeQuery();
In this example, the result is as follows
{"extAccount":[
{"@id":"2523379","@name":"cda_snowflake_extaccount"},
{"@id":"1782","@name":"defaultPopAccount"},
{"@id":"3643548","@name":"v8"}
]}
Campaign uses a typed system with some specificities:
Xtk type | JS type | Comment | |
---|---|---|---|
string | 6 | string | never null, defaults to "" |
memo | 12 | string | |
CDATA | 13 | string | |
byte | 1 | number | signed integer in the [-128, 128[ range. Never null, defaults to 0 |
short | 2 | number | signed 16 bits integer in the [-32768, 32768[ range. Never null, defaults to 0 |
long | 3 | number | signed 32 bits integer. Never null, defaults to 0 |
float | 4 | number | single-percision numeric value. Never null, defaults to 0 |
double | 5 | number | single-percision numeric value. Never null, defaults to 0 |
datetime | 7 | Date | UTC timestamp with second precision. Can be null |
datetimetz | |||
datetimenotz | |||
date | 10 | Date | UTC timestamp with day precision. Can be null |
boolean | 15 | boolean | boolean value, defaultint to false. Cannot be null |
timespan |
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.
You get a static XtkCaster
object like this
const XtkCaster = sdk.XtkCaster;
To convert a Campaign value into a given type, use one of the following.
stringValue = XtkCaster.asString(anyValue);
booleanValue = XtkCaster.asBoolean(anyValue);
byteValue = XtkCaster.asByte(anyValue);
shortValue = XtkCaster.asShort(anyValue);
int32Value = XtkCaster.asLong(anyValue);
numberValue = XtkCaster.asNumber(anyValue);
timestampValue = XtkCaster.asTimestamp(anyValue);
dateValue = XtkCaster.asDate(anyValue);
More dynamic conversions can be achieved using the as
function. See the types table above for details.
stringValue = XtkCaster.as(anyValue, 6);
DOM manipulation is sometimes a bit painful. The DomUtil
helper provides a few convenience functions
const DomUtil = sdk.DomUtil;
Create DOM from XML string:
const doc = DomUtil.parse("<root><one/></root>");
Writes a DOM document or element as a string:
const s = DomUtil.toXMLString(docOrElement);
Creates a new document
const queryDoc = DomUtil.newDocument("queryDef");
Escape text value
const escaped = DomUtil.escapeXmlString(value);
Find element by name (finds the first)
const el = DomUtil.findElement(parentElement, elementName, shouldThrow);
Get the text value of an elemenbt
const text = DomUtil.elementValue(element);
Iterates over child elements
var child = DomUtil.getFirstChildElement(parentElement);
while (child) {
...
child = DomUtil.getNextSiblingElement(child);
}
Iterates over child elements of a given type
var methodChild = DomUtil.getFirstChildElement(parentElement, "method");
while (methodChild) {
...
methodChild = DomUtil.getNextSiblingElement(methodChild, "method");
}
Get typed attribute values
const stringValue = DomUtil.getAttributeAsString(element, attributeName)
const byteValue = DomUtil.getAttributeAsByte(element, attributeName)
const booleanValue = DomUtil.getAttributeAsBoolean(element, attributeName)
const shortValue = DomUtil.getAttributeAsShort(element, attributeName)
const longValue = DomUtil.getAttributeAsLong(element, attributeName)
JSON to XML conversion (badger fish)
const document = DomUtil.fromJSON(json);
const json = DomUtil.toJSON(documentOrElement);
The following caches are manage by the SDK
Caches can be cleared at any time
client.clearOptionCache();
client.clearMethodCache();
client.clearEntityCache();
or
client.clearAllCaches();
External account passwords can be decrypted using a Cipher.
const cipher = await client.getSecretKeyCipher();
const password = cipher.decryptPassword(encryptedPassword);
A convenience function is provided, which returns a typed option value.
var value = await client.getOption("XtkDatabaseId");
Options are cached because they are often used. It's possible to force the reload of an option:
var value = await client.getOption("XtkDatabaseId", false);
It's also possible to call the API directly.
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.
const optionValueAndType = await NLWS.xtkSession.getOption("XtkDatabaseId");
console.log("Marketing datbaseId: " + optionValueAndType);
Marketing datbaseId: u7F00010100B52BDE,6
If the option does not exist, it will return [ "", 0 ]
var datbaseId = await client.getOption("XtkDatabaseId");
console.log(datbaseId);
The cache can be cleared
client.clearOptionCache();
From a marketing client connection, one can get a client to a mid server
console.log("Connecting to mid server...");
const midClient = await client.getMidClient();
await midClient.client.logon();
const datbaseId = await midClient.getOption("XtkDatabaseId");
console.log("Mid datbaseId: " + datbaseId);
await midClient.NLWS.xtkSession.testCnx();
console.log("Disconnecting from mid");
await midClient.client.logoff();
SOAP calls can be logged by setting the traceSOAPCalls
attribute on the client at any time.
client.traceSOAPCalls = true;
This is an example of the logs
SOAP//request xtk:session#GetOption <SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://xml.apache.org/xml-soap"><SOAP-ENV:Header><Cookie>__sessiontoken=___3033D619-6710-450D-9194-CEB718D9F57B</Cookie><X-Security-Token>@p4IgqV7etc_liq15zAq59iYRLcCh6_tQkRC5WHbhIA8RTHkFt6VIc9R9RYA4NPwFcqtGh9-LmvrdplXgiiLWNA==</X-Security-Token></SOAP-ENV:Header><SOAP-ENV:Body><m:GetOption xmlns:m="urn:xtk:session" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><sessiontoken xsi:type="xsd:string">___3033D619-6710-450D-9194-CEB718D9F57B</sessiontoken><name xsi:type="xsd:string">XtkDatabaseId</name></m:GetOption></SOAP-ENV:Body></SOAP-ENV:Envelope>
SOAP//response xtk:session#GetOption <?xml version='1.0'?><SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:session' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'><SOAP-ENV:Body><GetOptionResponse xmlns='urn:xtk:session' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'><pstrValue xsi:type='xsd:string'>uFE80000000000000F1FA913DD7CC7C4804BA419F</pstrValue><pbtType xsi:type='xsd:byte'>6</pbtType></GetOptionResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
List all accounts
const queryDef = {
"@schema": "nms:extAccount",
"@operation": "select",
"select": {
"node": [
{ "@expr": "@id" },
{ "@expr": "@name" }
]
}
};
const query = NLWS.xtkQueryDef.create(queryDef);
console.log(query);
const extAccounts = await query.executeQuery();
console.log(JSON.stringify(extAccounts));
Get a single record
var queryDef = {
"@schema": "nms:extAccount",
"@operation": "get",
"select": {
"node": [
{ "@expr": "@id" },
{ "@expr": "@name" },
{ "@expr": "@label" },
{ "@expr": "@type" },
{ "@expr": "@account" },
{ "@expr": "@password" },
{ "@expr": "@server" },
{ "@expr": "@provider" },
]
},
"where": {
"condition": [
{ "@expr": "@name='ffda'" }
]
}
}
const query = NLWS.xtkQueryDef.create(queryDef);
const extAccount = await query.executeQuery();
Results can be retrieved in different pages, using the @lineCount
and @startLine
attributes. For instance, retrieves profiles 3 and 4 (skip 1 and 2)
var queryDef = {
"@schema": "nms:recipient",
"@operation": "select",
"@lineCount": 2,
"@startLine": 2,
"select": {
"node": [
{ "@expr": "@id" },
{ "@expr": "@email" }
]
}
}
var query = NLWS.xtkQueryDef.create(queryDef);
var recipients = await query.executeQuery();
console.log(JSON.stringify(recipients));
Creates an image (data is base64 encoded)
var data = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA9ElEQVQ4jaXTIUsFQRSG4eeKiBjEIBeDYDGoSUwGm81s8SdYtIhFhPMDbEaz/SIIZkGbWg1Gg0GwiIgYZPZuWBxn8bJvWXb2O+/scM70lAhjuMO1sF9IVaES61jFnjBbyLQKjurnJz6yr62CsI2t+m0gRhGERZw1Vk6zTFEQ+rjETOP3b7OqBr1G8SRusPYrc4I3LGCeapN37AqP443g8R/FiYNsZcgGSRCmq1ZxmEXa6Yt0hKh6/dAaLbOcd+H/XOGpi2AFU10EqWsTXQQ7wmsSPNdzP8DXCII0D41BSgxvXboHm1jCXDpnPbHfeME9znEh+AFoTyfEnWJgLQAAAABJRU5ErkJggg==";
var doc = {
"@xtkschema": "xtk:image",
"@_operation": "insert",
"@namespace": "cus",
"@name": "test.png",
"@label": "Self test",
"@type": "png",
"data": { "$": data }
};
await NLWS.xtkPersist.write(doc);
Creates a folder (with image previously created)
const folder = {
"@xtkschema": "xtk:folder",
"@_operation": "insert",
"@parent-id": 1167,
"@name": "testSDK",
"@label": "Test SDK",
"@entity": "xtk:folder",
"@schema": "xtk:folder",
"@model": "xtkFolder",
"@image-namespace": "cus",
"@image-name": "test.png"
};
await NLWS.xtkPersist.write(folder);
Start and stop wotkflows, passing either an id or workflow internal name
await NLWS.xtkWorkflow.stop(4900);
await NLWS.xtkWorkflow.start(4900);
A workflow can be started with parameters. Variables, are passed as attributes of the parameters document.
await NLWS.xtkWorkflow.startWithParameters(4900, { "@hello": "world" });
The variables can be used in the workflow as attributes of the instance.vars
variable.
logInfo(instance.vars.hello);
Create a recipient
var recipient = {
"@xtkschema": "nms:recipient",
"@_operation": "insert",
"@firstName": "Thomas",
"@lastName": "Jordy",
"@email": "jordy@adobe.com"
};
await NLWS.xtkPersist.write(recipient);
Create multiple recipients
var recipients = {
"@xtkschema": "nms:recipient",
"recipient": [
{
"@_operation": "insert",
"@firstName": "Christophe",
"@lastName": "Protat",
"@email": "protat@adobe.com"
},
{
"@_operation": "insert",
"@firstName": "Eric",
"@lastName": "Perrin",
"@email": "perrin@adobe.com"
}
]
};
await NLWS.xtkPersist.writeCollection(recipients);
List all recipients in Adobe
var queryDef = {
"@schema": "nms:recipient",
"@operation": "select",
"select": {
"node": [
{ "@expr": "@id" },
{ "@expr": "@firstName" },
{ "@expr": "@lastName" },
{ "@expr": "@email" }
]
},
"where": {
"condition": [
{ "@expr": "GetEmailDomain(@email)='adobe.com'" }
]
}
}
const query = NLWS.xtkQueryDef.create(queryDef);
var recipients = await query.executeQuery();
console.log(JSON.stringify(recipients));
Count total number of profiles
var queryDef = {
"@schema": "nms:recipient",
"@operation": "count"
}
var query = NLWS.xtkQueryDef.create(queryDef);
var count = await query.executeQuery();
count = XtkCaster.asLong(count["@count"]);
console.log(count);
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.
var recipient = {
"@xtkschema": "nms:recipient",
"@_key": "@email",
"@_operation": "update",
"@firstName": "Alexandre",
"@email": "amorin@adobe.com"
};
await NLWS.xtkPersist.write(recipient);
Deletes a profile
var recipient = {
"@xtkschema": "nms:recipient",
"@_key": "@email",
"@_operation": "delete",
"@email": "amorin@adobe.com"
};
await NLWS.xtkPersist.write(recipient);
Deletes a set of profiles, based on condition. For instance delete everyone having an email address in adobe.com domain
await NLWS.xtkPersist.deleteCollection("nms:recipient", { condition: { "@expr": "GetEmailDomain(@email)='adobe.com'"} });
One can register a recipient to a service
Reading schemas is a common operation in Campaign. The SDK provides a convenient function as well as caching for efficient use of schemas.
const schema = await client.getSchema("nms:recipient");
console.log(JSON.stringify(schema));
A given representation can be forced
const xmlSchema = await client.getSchema("nms:recipient", "xml");
const jsonSchema = await client.getSchema("nms:recipient", "json");
System enumerations can also be retreived with the fully qualified enumeration name
const sysEnum = await client.getSysEnum("nms:extAccount:encryptionType");
or from a schema
const schema = await client.getSchema("nms:extAccount");
const sysEnum = await client.getSysEnum("encryptionType", schema);
Get a source schema
var srcSchema = await NLWS.xtkPersist.getEntityIfMoreRecent("xtk:srcSchema|nms:recipient", "", false);
console.log(JSON.stringify(srcSchema));
To build this project, you need node and npm
npm install
To deploy to npm
package.json
Release 1.2.3
The SDK can also be used client side.
Go to the root folder of the SDK and compile the SDK
node compile.js
It generates a file named bundle.js
ACC client-side SDK compiler version 0.1.0
Bundling ../package.json
Bundling ./web/jsdom.js
Bundling ./web/crypto.js
Bundling ./web/request.js
Bundling ./xtkCaster.js
Bundling ./dom.js
Bundling ./xtkEntityCache.js
Bundling ./methodCache.js
Bundling ./optionCache.js
Bundling ./soap.js
Bundling ./crypto.js
Bundling ./client.js
Bundling ./index.js
Client-side SDK generated in ./bundle.js
Once compiled, copy it to the Campaign server (here on a dev environment).
cd /c/cygwin64/home/neolane/ac
cp "Z:\amorin On My Mac\Documents\dev\git\ac7\acc-js-sdk\bundle.js" nl/web/accSDK.js
cp "Z:\amorin On My Mac\Documents\dev\git\ac7\acc-js-sdk\index.html" nl/web/index.html
This makes them available on
/nl/accSDK.js
Include the SDK
<script src="accSDK.js"></script>
Use the SDK
<script>
(async () => {
const client = await accSDK.init("http://ffdamid:8080", "admin", "admin");
console.log(accSDK.getSDKVersion());
await client.logon();
var databaseId = await client.getOption("XtkDatabaseId");
console.log(databaseId);
document.getElementById("hello").textContent = databaseId;
await client.logoff();
})();
</script>
Contributions are welcomed! Read the Contributing Guide for more information.
This project is licensed under the Apache V2 License. See LICENSE for more information.
FAQs
ACC Javascript SDK
The npm package @adobe/acc-js-sdk receives a total of 172 weekly downloads. As such, @adobe/acc-js-sdk popularity was classified as not popular.
We found that @adobe/acc-js-sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.
Security News
Sonar’s acquisition of Tidelift highlights a growing industry shift toward sustainable open source funding, addressing maintainer burnout and critical software dependencies.