Overview¶
To fully focus on our award winning Web and Mobile Messaging, Analytics and Deferred Deep Linking solutions, Backend-as-a-Service will be retired on 1st July 2023. Please see here for more details.
KScript allows you to use Kumulos to encapsulate business logic in custom server-side jobs, written in JavaScript. KScripts can be deployed and accessed in the same way as your existing API methods but offer much greater flexibility and control over what happens on the server-side of Kumulos.
KScript methods can also be triggered by Automations, which allows you to use events as a trigger to fire actions. For example, to send an email when a user completes the checkout process.
Enabling KScript¶
KScript is not enabled by default as the majority of use cases can be satisfied via API Methods. If you wish to add server-side jobs, please contact technical support who will be happy to enable KScripts for you.
Once you receive an email confirming that KScript has been enabled for your app, you can then create KScript methods from the API tab of your application in Kumulos. Underneath the "Create API" button, there will now be a "Create Some KScript" button once its enabled on your app.
Although used by numerous apps in production, our KScript feature is still under ongoing development and as such may change in future. However, we will contact you in advance of any significant changes.
Working with KScripts¶
KScript methods are listed in the 'API' section of 'Build'. KScript methods will appear above API methods created with the drag-and-drop editor.
Kumulos provides two ways to add and edit KScript methods. For quick, simple changes, you can use the inline code editor. Alternatively, for prolonged development work or non-trivial changes, we suggest using the KScript IDE (Integrated Development Environment). Both utilize the Monaco Editor from Microsoft.
Inline code editor¶
To view an existing KScript method in the inline code editor, click the edit/pencil icon under 'Actions' next to that method in the list. To use the inline code editor to add a new KScript method, click the KSCRIPT <>
button next to 'Create some KScript' in the right hand pane.
For prolonged development work or non-trivial changes, we recommend using the full-screen KScript IDE instead of the inline code editor.
KScript IDE¶
To open the KScript Integrated Development Environment (IDE), click on the IDE ^
icon next to 'Open the IDE' in the right hand pane.
Toggle theme¶
In both the inline code editor and the KScript IDE, you can switch between light and dark theme by clicking the Toggle Theme icon at the bottom right of the code window.
Testing a KScript Method¶
You can test a KScript Method by clicking the play icon under 'Actions' next to that method in the list, or by clicking Save and Run
within the KScript IDE. Both will bring up a 'Run API' screen, prompting you to enter any input parameters. Click Run It!
to run the KScript Method and see Execution Time, Results (e.g. number of rows updated in a query) and any debug logs.
Once you are happy that your KScript methods are working as intended, don't forget to hit
DEPLOY
either in the right hand pane or the KScript IDE, to deploy your methods to the Kumulos API servers so they can be called from your mobile app.
Creating and Editing KScripts¶
Adding a KScript Method¶
To add a new KScript method, click the KSCRIPT <>
button next to 'Create some KScript' in the right hand pane or, click on the IDE ^
icon next to 'Open the IDE' in the right hand pane to open the KScript IDE and click on the orange add primary action button.
Title and Return Type¶
Give the method a title and decide whether you'll be returning objects (for example database records), or a number.
The method will be listed under 'New Unsaved KScript Methods' until you hit SAVE
.
Input Parameters¶
Next you can add typed input parameters to the method. Each parameter should have a name and a type set for it. These parameters will be available to use from your KScript code from K.params
.
Writing Code¶
Now, you are all set to start writing your KScript method in the code editor. The INSERT
button can be used to insert the alias (unique identifier) of any of your tables or other API methods for use with functions in your method. Press Ctrl + Space
to see the auto-complete for any function.
There are also buttons to SAVE
, SAVE & RUN
and DEPLOY
your method.
Editing a KScript Method¶
To edit an existing KScript method in the inline code editor, click the edit/pencil icon under 'Actions' next to that method in the list. Alternatively, click on the IDE ^
icon next to 'Open the IDE' in the right hand pane to open the KScript IDE and click on the method.
Whenever you make any changes to a method, a black dot icon will appear next to that method in the IDE to indicate there are unsaved changes. The status bar will also show that the method has unsaved changes along with a button to 'Discard' these changes. If you do not wish to 'Discard' these changes, click SAVE
.
All edits to KScript Methods are written to your browser's local storage. If your network connection should be interrupted prior to saving, then the next time you edit that method, any unsaved changes will be retrieved from local storage so that they may be saved (or discarded) as appropriate.
Viewing Revision History¶
At the bottom of both the inline editor and the KScript IDE, you will see the current revision, identified by a version number that is increased each time you save the method.
If you click on the revision, you can view the revision history for this method showing the time and date that previous versions were saved. Clicking on each version will show that version of the method allowing you to retrieve any previous code as required.
If a revision (for example revision 2) of the same KScript method is open in two browser tabs at the same time and edits made in the first browser tab are saved (thus creating revision 3), then should the second browser tab attempt to save any edits made there, a warning will prompt that a newer version of the script has been saved after you started editing, giving you the option to proceed and overwrite the newer version or to return and discard edits. This will avoid the situation where the same script is open in two different tabs/windows and a set of edits on an older revision overwrite edits made to a newer revision.
Don't forget to copy any code you have edited to add to the newer revision and the
discard
the older revision.
Deleting a KScript Method¶
To delete a KScript Method, simply click the minus icon under 'Actions' next to that method in the list and click 'OK' when prompted to confirm.
Function Reference¶
KScript has access to the parameters posted to the script, and a library of useful functions which can be used whilst writing your scripts. These methods are all exposed through the global variable K
.
K.params
¶
K.params
will give you access to the parameters posted to your script. For example, a parameter called userID
would be referenced as: K.params.userID
.
K.params.has(key)
will tell you if there is a non-empty value passed for the given key.
K.log(...)
¶
It is possible to log information to the console during development of your KScripts. This can be useful for seeing what's going on at runtime. To log information to the console, call K.log
with any value you want to log out. It will accept a variable number of arguments and will show them as an array in the log output on screen.
K.error(...)
¶
This function is designed to log any arguments passed to it and also log a stack trace. It will also print the function that called the .error()
method.This can be useful for tracing errors in KScripts.
K.JSON
¶
This class replaces the standard Javascript JSON parser and is recommended for use in KScript methods. All of the usual methods included in the standard Javascript JSON parser are incuded such as K.JSON.parse(...)
and K.JSON.stringify(...)
etc.
K.stackTrace()
¶
Calling this method will output a stack trace of function names and line numbers called up to this point.
K.callAPIMethod(title, paramsObject)
¶
This method allows you to call existing API methods from inside the KScript, and then operate on the results. For example:
var results = K.callAPIMethod('getUserByID', {userID, K.params.userID});
// Do stuff with the results
K.setResponse(result)
¶
This is how a KScript returns data to the API endpoint. You can pass objects, arrays of objects, or numbers to this method. For example:
var users = K.select('users').run();
K.setResponse(users);
This method does not halt execution of the script, so you should plan to generate a result object and set it as the response at the end of execution.
If you plan to return binary data (for example: from base64 encoded data fields), then you must use the K.setResponseTypeMap() method to tell the API servers which fields in the result set contain binary data.
failed(result)
¶
This function can be used to check for failure of any database operations. It returns true
or false
depending on if the call failed or not.
include(alias)
¶
You can include other KScript files at runtime with the include function. Any functions or global variables inside the included KScript file will be loaded into the current scope. For example:
// In _init_ KScript method
function init() {
K.log('Initialising');
}
// In doSomething KScript method
include('_init_');
init();
K.setResponse(0);
throw
¶
If you want to halt execution on an error, you can throw an exception:
var results = false;
if (failed(results)) {
throw "Results failed!";
}
Database Functions¶
Note that when querying tables using any of the following methods, you must use the table alias rather than the table name.
K.query(sql, parameters)
¶
This function allows you to run custom queries on your database. Queries should be written in the MySQL syntax and should use placeholders where you wish to use a value passed as a parameter. For example, if you wanted to retrieve a digest of all new or edited posts (using the timeCreated
and timeUpdated
magic fields) after a given UNIX timestamp:
// Check we have an integer for our timestamp...
var timeUpdated=parseInt(K.params.timeUpdated, 10);
if ( isNaN(timeUpdated) ) {
throw("Invalid timeUpdated argument");
}
// Execute the query...
var results = K.query(
"SELECT * \
FROM 1234_1234_posts \
WHERE ((timeCreated >= FROM_UNIXTIME(?)) OR (timeUpdated >= FROM_UNIXTIME(?)))",
[timeUpdated, timeUpdated]
);
if (failed(results)) {
// See what the SQL error was
K.log(results.error);
}
// Return the results...
K.setResponse(results);
Parameters will be bound in order, and the second argument must be an array. If you don't use any placeholders in your query then you should pass an empty array, like so: []
.
Any records created via
K.query(INSERT INTO...)
will not populate thetimeCreated
field automatically - you must set this field toNOW()
manually in your query.
Date/Time fields¶
In the above example, you can see that when querying the timeCreated
and timeUpdated
magic fields you must to use the FROM_UNIXTIME()
function in your SQL query (as these fields are timestamps).
Date/Time fields on the other hand are signed integers that are intended to store dates and times as seconds relative to (i.e. before or after) the Unix epoch. You do not need to use FROM_UNIXTIME() when querying these fields.
However, please note that the getTime()
method of the Javascript Date
object will return timestamps in milliseconds and so you will need to divide this by 1000 before using in a query. For example, to get all events that have not yet started:
var seconds = Math.round(new Date().getTime() / 1000);
var results = K.query(
"SELECT * \
FROM 1234_1234_events \
WHERE start >= ?",
[seconds]
);
K.setResponse(results);
K.select(table_alias)
¶
K.select
will return a select action object that can be used to query tables in the database. For example:
var select = K.select('1234_1234_users').filter('userID', K.params.userID);
var results = select.run();
Alternatively you can chain the .run()
call:
var results = K.select('1234_1234_users').filter('userID', K.params.userID).run();
Filtering¶
It is possible to use the .filter()
method on select, update and delete action objects to filter the data each action will operate on.
Multiple filters can be chained together (in logical AND) by chaining calls, like: .filter('userID', K.params.userID).filter(...)
The filter method returns the original select object so you can chain on a call to run()
if you want.
Sorting¶
With the select action, it's possible to sort the records with a call to .sort(field, direction)
. field
must be the lowerCamelCase
name of a field in the table, and direction
must be one of 'ASC'
for ascending or 'DESC'
for descending.
Limiting¶
With the select action, it is also possible to limit the records returned with a call to limit(n, offset)
where n
is the number of rows you want returned and offset
is the starting row. For example:
// Get the total number of rows we want to iterate over
var rows=K.query( 'SELECT COUNT(*) AS total FROM 1_1_customers');
// Specify how many rows we want in each iteration
var limit=5;
var offset=0;
// Select rows in blocks of 5 until all rows have been selected
while ( offset < rows.first().total ) {
// Select (at most) 5 rows
var customers = K.select( '1_1_customers' ).limit(limit, offset).run();
var customer;
// Iterate over rows selected
while(customers.hasNext()) {
customer=customers.next();
K.log( customer.customerID );
}
// IMPORTANT update offset (to avoid infinite loop)
offset += limit;
}
Keep reading for more details and examples of result handling...
Result Handling¶
The K.query
and K.select
methods return array-like objects that can be iterated over and/or looped through and returned as responses. The following properties and methods are supported:
.length
.itemAtIndex(i)
.first()
.last()
.next()
.hasNext()
.push(object)
You can iterate through the returned rows like so:
var users = K.select('1234_1234_users').run();
var user;
while(users.hasNext()) {
user=users.next();
// Do something with user object e.g. set an additional property?
user.expireCache = Date.now() + 3600;
}
// All user objects in users returned to the client now have an expiry time of one hour from now appended (i.e. we have advised the client they can cache the results of this query locally for one hour)
K.setResponse(users);
The
.next()
method returns the current item and then increments the iteration pointer (so the result set can only be iterated through once).
If you wish to loop through the result set multiple times within the same Kscript method, without re-running the query, then you can use the .length
property and .itemAtIndex()
as follows:
var users = K.select('1234_1234_users').run();
for (var i=0; i < users.length; i++) {
K.log( users.itemAtIndex(i).name );
}
Data fields¶
If the table you are selecting from contains data fields (for example base64 encoded images), then we need to tell our API servers to treat these fields as binary and base64 encode them rather than JSON encode them. This is done with the K.setResponseTypeMap()
method, which is used to set strict types for fields in a result set.
The available constants that you can use to set strict types are:
K.Types.BOOL
K.Types.DATA
K.Types.DATE_TIME
K.Types.FLOAT
K.Types.INT
K.Types.POSITIVE_FLOAT
K.Types.POSITIVE_INT
K.Types.STRING
K.Types.TEXT
In theory you could set the strict type for every field in the result set. However, it is only necessary to do this for data fields to tell the API servers to treat these fields as binary and base64 encode rather than JSON encode). This is explicitly done for drag and drop API methods, but you have to manually do this for KScript methods, for example:
var users = K.select('1234_1234_users').run();
K.setResponseTypeMap({backdrop:K.Types.DATA,profilePhoto:K.Types.DATA});
K.setResponse(users);
K.insert(table_alias, object)
¶
This method creates a record in the database and returns the ID of the newly created record. For example:
var userID = K.insert('1234_1234_users', {username: K.params.username});
K.update(table_alias, object)
¶
To update records, use this method. It can have filters chained on to it just as K.select
. If you're updating, do remember to define filters. An example to update a user:
var result = K.update('1234_1234_users',
{username: K.params.username}).filter('userID', K.params.userID).run();
The result is the number of updated records, not the number of matching records. So if you call an update and there's nothing to change, it will return 0.
K.delete(table_aias)
¶
This method allows you to delete records from a table. If you call it with no filters, it will not run unless you also call .forceDeleteAll()
. For example:
// Will run...
var deleteUser =
K.delete('1234_1234_users').filter('userID', K.params.userID).run();
// Will throw an exception to the log...
var deleteAllUsers = K.delete('1234_1234_users').run();
// Will also run...
var deleteAllUsers = K.delete('1234_1234_users').forceDeleteAll().run();
This method returns the number of records deleted.
Security Functions¶
Hashing¶
KScript has md5()
and sha1()
available as global functions. These should be faster than JavaScript implementations of these functions.
Passwords¶
For storing passwords, bcrypt hashing functions are available. To store a password, use the K.sec.passwordHash()
function:
var hashedPassword = K.sec.passwordHash(K.params.password);
var userID = K.insert('1234_1234_users', {name: K.params.name, email: K.params.email, password: hashedPassword});
K.setResponse(userID);
To verify a password, use the K.sec.passwordVerify()
function as follows:
K.setResponse(null);
var users = K.select('1234_1234_users').filter('email', K.params.email).run();
if ( users.length === 0) {
K.log( "Unknown email address!");
}
else {
if ( K.sec.passwordVerify(K.params.password, users.first().password) ){
K.setResponse(users.first());
}
else {
K.log("Incorrect password!");
}
}
While providing different error messages for unknown email address and incorrect password is a good user experience for your users, it does mean that a potential hacker could mine your users' email addresses. Therefore, you may wish to just provide a generic 'login failed' error.
Encryption¶
Kumulos offers symmetric encryption using AES. These functions are suitable for protecting secrets.
The following example shows how to encrypt some plaintext, and then decrypt it again.
var PASSWORD = 'secret';
var ciphertext = K.sec.aesEncrypt('Plans to take over the world!', PASSWORD);
K.log(ciphertext);
var plaintext = K.sec.aesDecrypt(ciphertext, PASSWORD);
if (failed(plaintext)) {
// Decryption wasn't possible for some reason (wrong password/corrupted ciphertext)
}
K.log(plaintext);
Due to the increased length of ciphertext versus plaintext, we recommend storing encrypted strings in a Text field rather than a String field to avoid any possible truncation.
JSON Web Tokens (JWT)¶
Parsing a JWT¶
In order to integrate with a 3rd party user authentication service, such as Auth0, it is possible to verify JSON Web Tokens with KScript.
The following example will show how to create a reusable include to authenticate your KScript APIs.
First, create a script to parse & verify the JWT (_Jwt_Auth_
):
// Create a parser using the given signature algorithm & secret
var parser = K.jwt.createParser(K.jwt.Signature.HS256, 'secret');
// Assume the JWT string is passed in a parameter called 'jwt'
var token = parser.parseAndVerify(K.params.jwt);
if (failed(token)) {
throw 'Unauthorized!';
}
// Unpack any global variables you want from the token
var CURRENT_USER_ID = token.getClaim('uid', null);
Next, in any KScript you want to authenticate with a JWT, you can do:
include('_Jwt_Auth_');
if (CURRENT_USER_ID !== K.params.userId) {
throw 'Unauthorized';
}
// Continue to use the passed parameters knowing they belong to the authenticated user
It is also possible to validate the issuer, subject, audience, or id claims in the token as they are being parsed:
...
var token = parser.parseAndVerify(K.params.jwt, {
issuer: 'your-issuer',
subject: 'user-123',
audience: 'kumulos-app',
id: 'your-expected-id'
});
All tokens are checked for expiry at time of parsing. All additional validation claims are optional.
Generating a JWT¶
To hand out authentication tokens for your app, it is possible to generate signed JSON Web Tokens with Kumulos.
The following example shows how to use the JWT builder interface to create a token for your app.
// Create a token builder using the given signing algorithm & secret
var builder = K.jwt.createBuilder(K.jwt.Signature.HS256, 'secret');
// Set some common claims
builder
.setIssuedAt(Date.now() / 1000)
.setExpiry((Date.now() / 1000) + 3600) // Expire in 1hr
.setIssuer('https://your-app.com')
.setSubject('1337-user');
// Add some custom claims
builder.addClaim('roleIds', [1,2,3]);
// Get the signed token as a string
var tokenStr = builder.getToken();
CSV File Handling¶
KScript makes it possible to work with CSV files. You can read & write CSV files from a temporary filesystem available to your script context.
Reading CSV Files¶
The following example shows retrieving a CSV file from an API and parsing records from it in a loop:
var httpClient = K.http.createClient('https://your.api');
var response = httpClient.get('/game-scores.csv');
if (failed(response) || response.isError()) {
throw 'Failed to fetch file';
}
var file = K.fs.createTmpFile(response.getBody());
if (failed(file)) {
throw 'Failed to create temp file with content';
}
var reader = K.csv.createReader(file, {
// Assumes the CSV has 3 columns in the order specified
// These fields will then be used to map objects from the columns in each row of the CSV file
recordFieldNames: ['homeTeamName', 'awayTeamName', 'score']
});
if (failed(reader)) {
throw 'Failed to create a CSV reader';
}
var row;
while ((row = reader.readRecord())) {
if (failed(row)) {
K.log(row);
// row.details will contain the KScriptArray with the data that was read from the CSV row
break; // Stop processing (or use continue to skip the broken row)
}
// Process the row object which will have the shape {homeTeamName, awayTeamName, score}
}
Options¶
The K.csv.createReader(file, options)
method takes an optional configuration object:
{
delimiter: ',',
enclosure: '"',
escape: '\\',
// Array of columns in CSV file, will be used as object keys by the reader.readRecord() method
recordFieldNames: []
}
Writing CSV Files¶
The following example shows writing lines to a temporary CSV file. This file can then be passed to other routines such as the FTP functions.
var file = K.fs.createTmpFile();
if (failed(file)) {
throw 'Failed to create temp file';
}
var writer = K.csv.createWriter(file);
if (failed(writer)) {
throw 'Failed to create CSV writer';
}
// Write a header row
writer.writeRow(['date', 'weather', 'rainfallMm']);
// Write a data row
writer.writeRow(['2017-01-01', 'Sunny', 0]);
// Upload the file somewhere?
Options¶
The K.csv.createWriter(file, options)
method takes an optional configuration object:
{
delimiter: ',',
enclosure: '"',
escape: '\\'
}
FTP Functions¶
KScript offers the ability to work with text files stored on remote FTP servers. The FTP functions can interoperate with the file handling functions already defined in KScript.
The following example shows the available FTP operations.
var client = K.ftp.createFtpClient('ftp.yourhost.com', 'yourUsername', 'yourPassword');
if (failed(client)) {
throw 'Failed to connect to the FTP server';
}
// List the files on the remote
K.log(client.listFiles('.'));
// Download a file from the remote and open as a temporary file
var file = client.getFile('orders.csv');
if (failed(file)) {
throw 'Failed to download & open the file';
}
// Maybe process the file
// Upload the file back with a different name
var uploaded = client.putFile(file, 'orders-new.csv');
if (failed(uploaded)) {
throw 'Failed to upload the file';
}
// Delete the original file
var deleted = client.deleteFile('orders.csv');
if (failed(deleted)) {
throw 'Failed to delete remote file';
}
Session Support¶
KScript introduces persistent sessions to Kumulos and allows you to use them in your apps. KScript sessions are in-memory key-value stores which are designed to be fast and simple to use.
K.session.has(key)
¶
This method returns true if the session has a non-empty value for the given key.
K.session.remove(key)
¶
If you need to unset a session variable, you can use this method. Subsequent accesses to the session key after removing it will return null
.
K.session.destroy()
¶
All session values stored for the user's session will be deleted.
By default, session values will persist for one hour after the session was last accessed.
K.session
¶
To access and set values in the session, you can use this object. It behaves like the K.params
object, but it allows setting values too. For example:
var response = 0;
if (!K.session.has('userID')) {
var results = K.select('1234_1234_users').filter({
username: K.params.username,
passwordHash: K.params.hashedPassword
}).run();
if (!failed(results) && results.length == 1) {
K.session.userID = results.itemAtIndex(0).userID;
response = 1;
}
else {
response = 0;
}
}
else {
// Already logged in
response = 1;
}
K.setResponse(response);
Push Notifications¶
You can use the Kumulos Push service from KScript to trigger targeted push notifications programmatically.
K.push.newMessage()
¶
The push notification builder allows you to construct a notification, add content and target installs, audience segments or channels. For example:
K.push.newMessage().broadcast().withContent('the title', 'the message').send();
Targeting¶
To send a broadcast notification or to target specific installs, segments or channels, use one of the following methods.
.toInstallIds(installIds)
.toUserIds(userIds)
.broadcast(broadcast = true)
.toSegmentId(segmentId)
.toSegmentUuid(segmentUuid)
.toChannelIds(channelIds)
.toChannelUuids(channelUuids)
See the relevant integration guide for your chosen platforms to see how to access the unique installation ID
Content¶
To add content to the push notification, you can use one of the following methods.
.inBackground(inBackground = true)
.withData(data)
.withContent(title, message)
Notification sound¶
To set notification sound, you can use the following method. Each parameter is the sound file to play instead of the default device notification sound. In order to disable vibration and sound for the notification, pass 'none'.
.withSound(iosSound : string): this;
Collapsing notifications¶
Collapse Id corresponds to the apns-collapse-id and the collapse_key options for APNS/FCM respectively. Setting a collapse Id allows the device operating system to group and flatten related messages, it can be set with the following method.
.withCollapseId(collapseId : string): this;
iOS Options¶
Badges¶
To increment the badge count, or to set it to a specific value, you can use the following method.
.withBadge(badgeType, badgeCount)
Category¶
To set the iOS category field, use the following method.
.withIosCategory(categoryString)
Android Options¶
High Priority¶
To set the priority flag and wake up Android devices, use this method.
.withAndroidHighPriority()
Sending on a schedule¶
To send the notification at a time in the future, set a schedule with the following method.
.withSchedule(sendAt, strategy, pastTimes)
Send¶
Finally, to send the notification, use the send()
method, for example:
K.push.newMessage().broadcast().withContent('the title', 'the message').send();
Facebook SDK¶
It is possible to use the Facebook SDK through KScript if you want to add Facebook Login to your apps for example. In order to use the SDK in KScript you need to initialize it.
K.initFB(appID, appSecret, userAccessToken, graphVersion)
¶
This initialization method sets up the Facebook SDK for use in your KScript. You need to pass in your facebook app details along with a valid user access token. This access token can be retrieved from a logged in user by using one of Facebook's various SDKs. With those items, you can initialize KScript's Facebook SDK like so:
var FB_APP_ID = '';
var FB_APP_SECRET = '';
K.initFB(FB_APP_ID, FB_APP_SECRET, K.params.fbAccessToken);
We recommend storing the access token in the KScript session after a successful login action.
It also makes sense to store this initialization in a KScript you can include whenever you need access to the Facebook SDK.
K.FB.api(path, method, data)
¶
After initialization, the api()
method can be used to query the Facebook graph API as the currently logged in user, in accordance with the permissions the user has granted your app. The results it returns are dependent on the query you issue.
This method can return an error which can be checked with the failed()
function.
You can learn more about the Graph API in the Graph API Reference.
An example that retrieves the user's profile information is shown:
// In setFacebookAccessToken
K.session.fbAccessToken = K.params.fbAccessToken;
// In _facebook_
var FB_APP_ID = '';
var FB_APP_SECRET = '';
// Assume session storage of access token set by setFacebookAccessToken
K.initFB(FB_APP_ID, FB_APP_SECRET, K.session.fbAccessToken);
// In getFacebookProfile
include('_facebook_');
var userProfile = K.FB.api('/me?fields=id,name,gender');
if (failed(userProfile)) {
K.log('Failed...');
// Handle as needed
}
K.log(userProfile);
K.setResponse(userProfile);
Convenience functions are also provided for each HTTP method:
K.FB.get(path)
K.FB.post(path, data)
K.FB.put(path, data)
K.FB.delete(path)
K.FB.getUserId()
¶
This method returns the currently logged in user's FBUID. The logged in user is determined by the currently initialized access token passed to K.initFB()
.
AWS SDK¶
It is possible to use the Amazon SDK through KScript if you want to, for example, upload files to S3 service or sign Amazon CloudFront URLs.
Amazon S3¶
You can upload/download files to/from S3 buckets.
Upload files to S3¶
To upload a file to S3 you need to, first, create an S3 Client passing region
in which your bucket is located and Access Key ID and Secret Access Key. The complete example is shown below.
//get S3 Client
var s3client = K.aws.createS3Client(region, accessKey, secretKey);
//upload file
var data = 'hello world';
var params = {
bucket: 'my-bucket',
body : K.fs.createTmpFile(data),
key : 'text.txt',
contentType: 'application/json'
};
var result = s3client.putObject(params);
if (failed(result)) {
K.log('Failed...');
}
Note that the only accepted parameters are
bucket
(name of the S3 bucket. Required.)body
(contents of the file being uploaded, must be a KFilePointer. Required.)key
(name of the file created on S3, i.e. AWS object key. Required.).contentType
(A standard MIME type describing the format of the object data. Defaults to 'application/octet-stream')
As usual you can check success of the operation with failed
function.
Download files from S3¶
//get S3 Client
var s3client = K.aws.createS3Client(accessKey, secretKey, region);
//download file
var params = {
bucket: 'my-bucket',
key : 'text.txt'
};
var result = s3client.getObject(params);
if (failed(result)) {
K.log('Failed...');
}
else{
var contents = K.fs.read(result);
}
Note that you cannot download files larger than 10 MB.
Amazon CloudFront¶
You can sign CloudFront URLs using canned policy.
Sign CloudFront URLs¶
First, create a CloudFront client passing region
to connect to. Next, sign it using getSignedUrl
method. Complete example is shown below.
//create CloudFront client
var cloudFrontClient = K.aws.createCloudFrontClient(region);
//sign url
var signedUrl = cloudFrontClient.getSignedUrl(url, expires, privateKey, keyPairId);
if (failed(signedUrl)) {
K.log('Failed...');
}
getSignedUrl
method accepts 4 parameters.
url
is the link you wish to sign.expires
is a unix timestamp indicating expiration time of the link.
In order to sign URLs you need to obtain a CloudFront key pair.
privateKey
is the contents of your private key file. To deal with linebreaks, you may encode the private key to base64, paste it to the KScript editor and decode it before using. KScript exposesbase64_decode
function.keyPairId
is the Access Key ID of your key pair.
HTTP Client¶
Kumulos includes an HTTP client so you can make web requests to any web accessible API (such as Mailgun or Mandrill).
Creating an instance of a HTTP Client¶
You can create an instance of a blocking HTTP client by calling the K.http.createClient()
method and passing in the baseURI (and optional timeout configuration object).
var client = K.http.createClient('https://api.external-service.com', {timeout: 10});
Similarly, you can create a streaming HTTP client by calling K.http.createStreamingClient()
and passing in the baseURI (and optional timeout configuration object).
Making a request¶
The HTTP client has methods for head
, get
, post
, patch
, put
and delete
requests to a URI relative to the baseURI with given headers and parameters. For example, to perform a post request to an API using BASIC authentication.
Remember you can press
Ctrl + space
to see the auto-complete for any function.
var client = K.http.createClient('https://api.external-service.com', {timeout: 10});
var username = 'username for external API service';
var password = 'password for external API service';
var auth = base64_encode(username + ':' + password);
var headers =
{
'Authorization': 'Basic ' + auth,
};
var params =
{
'param1': 'Hello',
'param2': 'World'
};
var response = client.post('api/v1/endpoint', params, headers);
If the API expects JSON then use
K.JSON.stringify(params)
to encode the parameters.
Parsing Results¶
The HTTP client will return a response object with the following methods:
isSuccess()
isError()
getStatusCode()
getHeader(header)
getHeaders()
getBody()
The isSuccess()
method will return true if the response had a status code in the range 200 - 299. The isError()
method will return true if the status code is outside of this range.
If the API you are calling returns JSON, you can parse the results of the getBody()
method using JSON.parse()
. For example, if you want to allow users to login using their Google Identity, you could do something like:
var client = K.http.createClient('https://www.googleapis.com', {timeout: 10});
var response = client.get('oauth2/v1/userinfo?alt=json&access_token=' + K.params.userAccessToken);
// Handle errors
if (failed(response)) {
K.log(response);
}
else {
var data = JSON.parse(response.getBody());
K.log(data);
}
Overriding default timeout¶
The default timeout for the HTTP Client is 2 minutes (120 seconds). You can pass in an optional configuration object to override the timeout as follows:
var httpClient = K.http.createClient('https://httpbin.org/', {timeout: 5});
var response = httpClient.get('delay/10');
K.log('start');
if (failed((response))) {
K.log(response);
}
else {
K.log(response.getBody());
}
K.log('end');
Analytics¶
You can access analytics events from KScript.
Event stream¶
The following example shows how to iterate over the analytics event stream, reading 10 events for an app. Events are ordered by the time (UTC) that they happened.
var options = {
eventTypes: ['k.*'],
happenedBetween: {
'$gte': new Date("01 01 2001,14:52:39").toISOString(),
'$lte': '2025-08-01T14:00:00.000Z'
},
include: ['data', 'user', 'userAttributes'],
filter: {
'data.proximity': {'$eq': 2}
}
};
var iterator = K.analytics.createEventStreamIterator(options);
if (failed(iter)){
throw iterator.error;
}
var max = 10;
var count = 0;
while (iterator.hasNext() && count < max){
K.log(iterator.next());
count++;
}
As can be seen in the example above, the iterator exposes the hasNext()
and next()
methods.
Options¶
K.analytics.createEventStreamIterator(options)
takes an optional configuration object:
{
// Filter events by event type
// '*' denotes a wildcard and on its own resolves to no filtering
eventTypes: ['product.viewed', 'k.core.*'],
// Filter events by limiting date range
// You can specify lower and/or upper bounds (inclusive)
happenedBetween: {
// Include events that happened after the specified ISO8601 date
'$gte': new Date("01 01 2014,14:52:39").toISOString(),
// Include events that happened before the specified ISO8601 date
'$lte': '2018-08-01T14:00:00.000Z'
},
// Include additional data with events. Possible values are:
// 'data'(event data)
// 'user'(the uuid string of the user which was logged in when the event happened)
// 'userAttributes'(attributes of the respective user)
include: ['data', 'user', 'userAttributes'],
// Filters events by event data and/or user attributes.
// Available comparison operators are:
// '$eq'(=), '$lt'(<), '$gt'(>), '$lte'(<=) and '$gte'(>=)
// Right operand must be a string, a number or a boolean.
// Filter keys must start with 'data.' or 'user.'
filter: {
'data.location.state': {'$eq': 'NY'},
'user.age': {'$lt': 30},
'user.gender': {'$eq': 'M'}
}
}
User attributes¶
You can access user attributes via K.users.getAttributes
. This can be useful when running a KScript method as an action in an Automation where the userId
will be passed in as a parameter. For example: to get the users email address and name...
var attributes = K.users.getAttributes(K.params.userId);
if (!attributes.has("email")) {
throw ("User does not have an email address.");
}
var greeting = "Hi";
if (attributes.has("name")) {
greeting = "Hi " + attributes.get("name");
}
Automation¶
Automations allow you to use events as a trigger to fire actions. For example, send a confirmation email when a user completes checkout process. An automation is comprised of an availability period (for time-limited promotions) and one or more rules. Each rule is then in turn comprised of a trigger (audience and event) and one or more actions. An action can be to run a Kscript method. Please see the Automation docs for more details).
Scheduled KScripts¶
Kumulos includes a robust scheduling engine that can be used to run KScript methods every minute or every hour. If you wish to schedule a recurring KScript, then please contact technical support who will be happy to schedule it for you.
Known Issues¶
- Unterminated strings in a KScript may result in "Built undefined API methods" and break the deployment process (look for unterminated strings in your code to fix this issue)
include(alias)
currently has no guards on cyclic includes and as such, methods may crash if the same script is included twice- Calling an API method with
K.callAPIMethod(alias, paramsObject)
may impact the integrity of theK.params
object. If encountered, refactor the logic into a helper function and use theinclude(alias)
method to include and call the function. - Using a
?
placeholder for integer parameters (such as those passed toLIMIT
SQL statements) doesn't work because it adds quotes to the integer value. As a workaround, you can use string concatenation in your query andparseInt
on the input parameter to check it is sensible. - Renaming KScript methods doesn't check that the name is available first, so you can have two methods with the same name
Reporting Bugs¶
If you experience any issues using KScript other than those listed above, please contact technical support and include as much information as possible about how to reproduce the error.