Skip to main content

Functions Runtime

Functions execute within a sandboxed Node.js environment, supporting all language features, including async/await syntax. See details below:

Fetch API

The Fetch function is provided as a property of the context object. It implements the standard Fetch API interface.

export default async function(event, { log, fetch, store }) {
const response = await fetch("https://example.com");
if (response.ok) {
const json = await response.json();
}
}

Persistent Storage

Persistent data storage between function calls is achievable using a key-value storage system, which is accessible through the store property of the context object.

The store object is defined by the following interface (in TypeScript notation):

interface Store {
get(key: string): Promise<any>;

del(key: string): Promise<void>;

// set value for 'key' with default or provided TTL (in number of seconds or string like '7d', '12h', '1m')
set(key: string, value: any, opts?: number | string): Promise<void>;

// returns remaining TTL for 'key' in seconds or -2 if key doesn't exist
ttl(key: string): Promise<number>;
}

Data isolation

Data in key-value storage is isolated on Workspace level. If you want to keep similar set of keys for multiple sites or destinations isolated form each other, you need to use that entity id (source, destination, connection) as a prefix for the key.

export default async function(event, context) {
await store.set(`${context.destination.id}:myKey`, "myValue")
}

Time to live (TTL)

Default TTL: 31 days

It means that if you don't update data for a particular key for 31 days, that key will be deleted.

You can change TTL for a particular key by passing third argument to set method as number in seconds or as short human-readable string, e.g.: 14, "14d"

// set TTL to 7 days for 'myKey'
await store.set("myKey", "myValue", "7d")

Disable TTL: to disable TTL and keep value forever pass "inf" or -1 as third argument to set method:

// disable TTL for 'myKey' to keep it forever
await store.set("myKey", "myValue", "inf")

Data for a particular key can be updated to refresh TTL. See the example.

Check TTL

You can check remaining TTL for specific key:

// returns remaining TTL for 'myKey' in seconds or -2 if key doesn't exist
const remainingSec = await store.ttl("myKey")
if (remainingSec < 60 * 60 * 24) {
// less than 1 day left. refresh TTL
await store.set("myKey", "myValue", "7d")
}

Example

"User sign up webhook" example:

const webHookURL = "https://hooks.slack.com/services/.../.../..."

export default async function(event, { log, fetch, store }) {
if (event.type === "identify") {
// check if user already signed up
if (await store.get(`signup/${event.traits.email}`)) {
log.info(`User ${event.traits.email} already signed up`);
// store to refresh ttl to the next 30 days
await store.set(`signup/${event.traits.email}`, true, "30d");
} else {
// store signup flag for user with 30 days TTL
await store.set(`signup/${event.traits.email}`, true, "30d");
await fetch(webHookURL, {
method: "POST",
body: JSON.stringify({
text: `Horray! We have new user ${event.traits.email}`
})
});
}
}
}

Warehouse API

Warehouse API is provided as a the getWarehouse property of the context object. It allows you to query your data warehouses.

Pass destination ID or connection ID to getWarehouse method to get a Warehouse instance.

note

Only ClickHouse destination currently supports the Warehouse API.
HTTPS port ( 8443 by default ) should be open in your ClickHouse server.

Warehouse type:

interface Warehouse {
query: (sql: string, params?: Record<string, any>) => Promise<any[]>;
}

where:

  • query - method to execute SQL query. It returns an array of rows.
    • sql - SQL query with optional placeholders for named parameters. Placeholders should be in the form of @paramName or :paramName.
    • params - object with named parameters.

Example:

export default async function(event, { log, getWarehouse }) {

const warehouse = getWarehouse("destinationId");

const row = await warehouse.query("SELECT value FROM table WHERE id = @id LIMIT 1", { id: event.properties.id });

event.properties.value = row[0]?.value

return event
}

Logging

Logging may be helpful for debugging functions and also for monitoring. To log something, use log property of the context object.

log object has the following interface (in TypeScript notation):

interface Log {
info(message: string, ...args: any[]);

warn(message: string, ...args: any[]);

debug(message: string, ...args: any[]);

error(message: string, ...args: any[]);
}

Examples with logging: Enrich, User sign up webhook

In Function editor to see logs from the last Run press Show logs button.

Logs of Functions that are already attached to Connections can be seen in the Live Events section of the main menu.

Environment variables

You can use environment variables in your functions. They are accessible via process.env object.

export default async function(event, { log }) {
const apiKey = process.env.API_KEY;
log.info("API key: " +apiKey)
// function logic
}

Environment variable values are set at the Connection level, allowing a single function to operate with different configurations seamlessly.

Crypto

Jitsu offers shortened version of node crypto module which supports following methods:

hash, randomUUID, randomBytes, randomInt


import { hash } from 'crypto';


export default async function(event, { log, geo }) {

const h = hash("sha256", JSON.stringify(event))

log.info("Event hash: " + h)

}

Using external libraries

If you need to use any external libraries, besides core libraries, you must create a Jitsu project with SDK and bundle your function with all dependencies.

GEO Location

Jitsu Cloud provides IP geolocation information for each event. It's available in geo property of the context.

export default async function(event, { log, geo }) {
log.info(JSON.stringify(geo))
}

geo object structure

{
"country": {
"code": "US",
"isEU": false
},
"city": {
"name": "New York"
},
"region": {
"code": "NY"
},
"location": {
"latitude": 40.6808,
"longitude": -73.9701
},
"postalCode": {
"code": "11238"
}
}

User Agent

Jitsu parses User-Agent header and provides its data. It's available in ua property of the context.:

export default async function(event, { log, ua }) {
console.log(JSON.stringify(ua, null, 2))
}

ua object structure

{
"browser": {
"name": "Firefox",
"version": "111.0",
"major": "111"
},
"engine": {
"name": "Gecko",
"version": "109.0"
},
"os": {
"name": "Mac OS",
"version": "10.15"
},
"device": {
"vendor": "Apple",
"model": "Macintosh",
"type": "desktop"
},
"cpu": {},
"bot": false
}