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.
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
}