Runnables
Scripts and Jobs share overlapping functionalities, datastructures and concepts. The term runnable
refers to this. The name runnable_id
used in shared datastructures refers to either a Script or Job. A runnable_call_id
refers to an a call or execution of a Script or Job. A runnable_version_id
refers to a specific verion of a Script or Job. This is explained in detail below.
See also Scripts and Jobs in web sockets for realtime updates. Runnable Authoring goes into authoring details.
Scripts
A script is node.js code called in a response to an event in SAGA. See Concepts. The path
of a script declares what kind of event it responds to and implicitly defines the context of the execution and what variables are available to the script.
NOTE: There can be many script bound to the same path, except for custom http script since they are bound to a URL path.
Property Path
/(bots|users|globals)/properties/PROPERTY_NAME
- responds to a property with the given name for either bots,users,globals
Available Variables in the script context:
parent
- either the bot, user or the globals objectproperty
- the property object that caused the event
Message Path
/users/messages/sent (user, message)
- triggered when a user sends a message, even if that message has no recipients/users/messages/incoming (sender, sender_type, user, message)
- triggered when a user receives a message/users/messages/outgoing (user, recipient, recipient_type, message)
- triggered when a user sends a message, once for each user -> recipient pair- For example, if user A sends a message to user B and bot B, this script will be triggered twice, for user A -> user B, and user A -> bot B
/bots/messages/sent (bot, message)
- triggered when a bot sends a message, even if that message has no recipients/bots/messages/incoming (sender, sender_type, bot, message)
- triggered when a bot receives a message/bots/messages/outgoing (bot, recipient, recipient_type, message)
- triggered when a bot sends a message, once for each bot -> recipient pair- For example, if bot A sends a message to user B and bot B, this script will be triggered twice, for bot A -> user B, and bot A -> bot B
Available variables in the script context (changes depending on the path):
sender
- either a user or a bot, depending onsender_type
sender_type
- either 'User' or 'Bot'recipient
- either a user or a bot, depending onrecipient_type
recipient_type
- either 'User' or 'Bot'user
- the given userbot
- the given botmessage
- the message object
User Lifecycle Event Path
/users/events/create
- user was created/users/events/verify
- user has been verified/users/events/login"
- user logged in/users/events/change_password_request
- user wants to change password/users/events/change_password_verified
- users password has been changed/users/events/change_email_request
- user wants to change email/users/events/change_email_verified
- users email has been changed
Available Variables in the script context:
user
- the given user
Custom HTTP Path
/requests/post/PATH
- A HTTPpost
custom script call with the givenpath
/requests/get/PATH
- A HTTPget
custom script call with the givenpath
/requests/delete/PATH
- A HTTPdelete
custom script call with the givenpath
The path is mounted at API_ROOT/requests/
, the HTTP method is post
, get
or delete
depending on the path.
Available Variables in the script context:
request
- the Node HTTP Request Objectresponse
- the Node HTTP Response Objectuser
- if the script requires an authenticated user
The actual URL for the given HTTP method is
https://API_DOMAIN/requests/PATH
Filters
The field parent_properties_criteria
let's you specify a list of properties the parent has to have for the script to apply. The parent properties becomes a positive or a negative dependency. This does not apply for custom HTTP Scripts.
["home"]
- the script applies only if the parent user or bot has ahome
property["!exit"]
- the script applies only if the parent user or bot doesn"t have aexit
property["!exit","home"]
- the script applies only if the parent user or bot doesn"t have aexit
property and must have ahome
property
The field parent_name_criteria
lets you specify the names of the bot or user to match or not, you can't mix in this case.
["rob","hans"]
- script only applies to users ar bots with the namerob
orhans
["!dominik"]
- script is excluded from the user with the namedominik
The field boolean requires_user
is applicable for custom HTTP Scripts only, if true the script requires
GET /scripts
List all scripts. Each script has
- title - a title
- notes - notes to explain the object etc
- path - the path
- enabled - whether the script is enabled
- logging - whether the scripts logging is captured
- javascript - the javascript code that is executed when the trigger matches.
- debug - if true all console.log statements are stored in the database.
- parent_name_criteria - the parent_name_criteria
- parent_properties_criteria - the parent_properties_criteria
Query Parameters
- fields (optional):
- command separated list of names of fields to be returned
- title
- title,path
- command separated list of names of fields to be returned
[
{
"_id": "55999d97bb067fcf2c06ff57",
"title": "room count",
"path": "/users/properties/room",
"enabled": "true",
"javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()",
"logging": true,
"parent_properties_criteria": ["criteria"]
},
{
"_id": "55999d97bb067fcf2c06ff57",
"title": "weather reflector",
"path": "/globals/properties/weather",
"enabled": "false",
"javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()",
"logging": false,
"parent_properties_criteria": []
}
]
POST /scripts
Create a script.
- title - a title
- path - see above
- logging - whether the scripts logging is captured
- javascript - the javascript code that is executed when the trigger matches.
- parent_name_criteria - the parent_name_criteria
- parent_properties_criteria - the parent_properties_criteria
{
"title": "room count",
"path": "/users/properties/room",
"javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()",
"parent_properties_criteria": ["criteria"],
"parent_name_criteria": ["leo"]
}
GET /scripts/:id
Get the script with the given :id.
- title - human-readable title
- notes - notes to explain the object etc
- path - see above
- enabled - whether the script is enabled
- javascript - the javascript code that is executed when the trigger matches.
- parent_name_criteria - the parent_name_criteria
- parent_properties_criteria - the parent_properties_criteria
Query Parameters
- fields (optional):
- command separated list of names of fields to be returned
- title
- title,path
- command separated list of names of fields to be returned
{
"_id": "55999d97bb067fcf2c06ff57",
"title": "weather reflector",
"enabled": "true",
"path": "/properties/weather",
"javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()"
}
UPDATE /scripts/:id
Update the script with the given :id. 'errorMessages', 'errorInvocationCount' and 'invocationCount' are not reset.
- title - title
- path - see above
- enabled - whether the script is enabled
- javascript - the javascript code that is executed when the trigger matches.
- notes - notes to explain the object etc
- parent_name_criteria - the parent_name_criteria
- parent_properties_criteria - the parent_properties_criteria
{
"title": "room count",
"path": "/users/properties/room",
"verb": "put",
"javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()"
}
DELETE /scripts/:id
Update the script with the given :id
Jobs
A job is node.js that is called on a given schedule. A schedules is declared using the [later.js text syntax](http://bunkat.github.io/later/parsers.html#text. The overall structure is very similar to scripts, but instead of path
a job has a text_schedule
that defines how frequent it will be invoked. There are no implicit variables passed to the job since there is no other context then time.
GET /jobs
Returns all jobs.
- title - a title
- text_schedule - a text description of the schedule using later.js text syntax.
- enabled - whether the job is enabled
- logging - whether the scripts logging is captured
- javascript - the javascript code that is executed when the trigger matches. NOTE: More to come about restrictions and context.
Query Parameters
- fields (optional):
- command separated list of names of fields to be returned
- title
- title,path
- command separated list of names of fields to be returned
[
{
"_id": "55999d97bb067fcf2c06ff57",
"title": "room count",
"enabled": "true",
"text_schedule": "every 5 minutes",
"javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()",
},
{
"_id": "55999d97bb067fcf2c06ff57",
"title": "weather reflector",
"false": "true",
"path": "every 2 days",
"javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()"
}
]
POST /jobs
Create a job.
Required fields:
- title - a title
- enabled - whether the job is enabled
- text_schedule - a text description of the schedule using later.js text syntax.
- javascript - the javascript code that is executed when the trigger matches.
- notes - notes to explain the object etc
{
"_id": "55999d97bb067fcf2c06ff57",
"title": "room count",
"text_schedule": "every 5 minutes",
"javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()"
}
GET /jobs/:id
Get the jobs with the given :id.
title - a title
text_schedule - a text description of the schedule using later.js text syntax.
enabled - whether the job is enabled
javascript - the javascript code that is executed when the trigger matches.
notes - notes to explain the object etc
Query Parameters
- fields (optional):
- command separated list of names of fields to be returned
- title
- title,path
- command separated list of names of fields to be returned
{
"_id": "55999d97bb067fcf2c06ff57",
"title": "room count",
"text_schedule": "every 5 minutes",
"javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()",
}
PUT /jobs/:id
Update the jobs with the given :id.
Possible fields:
- title - a title
- enabled - whether the job is enabled
- text_schedule - a text description of the schedule using later.js text syntax.
- javascript - the javascript code that is executed when the trigger matches.
- notes - notes to explain the object etc
{
"_id": "55999d97bb067fcf2c06ff57",
"title": "room count",
"text_schedule": "every 2 minutes",
"javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()",
}
DELETE /jobs/:id
Delete the jobs with the given :id.
{
"_id": "55999d97bb067fcf2c06ff57",
"title": "room count",
"text_schedule": "every 2 minutes",
"javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()"
}
Versions
Each post or update of the javascript code of a Script or Job automatically creates a version entry.
GET /jobs/:id/versions
GET /scripts/:id/versions
Returns a list of all versions for the given script or job. Each entry contains the following.
- _id - the version id
- runnable_id the script or job id
- user_id the id of the user that authored the change
- javascript the actual code of the version
Example
[
{
"_id": "60c41b37b3dca300384aad59",
"runnable_id": "574c9ac8e1e8d2030017c96d",
"user_id": "60b68ee8a4150d0020c1eede",
"javascript": "console.log("hello world);,
"createdAt": "2021-06-12T02:25:59.586Z",
}
]
Activity
Each script or job invocation is stored as a RunnableCall object. A runnable is the internal base object for bot Scripts and Jobss, hence the name RunnableCall.
- _id - the id of the call
- has_error_message - true if the call resulted in an error
- duration the execution duration in milliseconds
- queue_duration the queue duration in milliseconds
- runnable_id the id of either the script or job
- runnable_version_id the version of the script or used in the call, see [Versions]
- runnable_type 0=job, 1=script
- createdAt the time stamp
- runnable_logs array containing the values logged during the call
Script calls contain additional information depending on the type.
parent_id "60bf52a2dbd52e0069edcb35",
property_id "60de2461a94d9608f8160c15",
parent_object {
_id "60bf52a2dbd52e0069edcb35",
name "solarboy" },
}
GET /jobs/:id/logs
GET /scripts/:id/logs
Returns a pageable list of logging statements created by the given script or job via console.log. 'runnable_call_id' refers to the runnable call object that stores information about the job execution. Logs are only stored if the script or job is set to debug:true
.
Important fields:
- createdAt - timestamp
- runnable_id - the id of the job or scripts
- runnable_call_id - the id of the specific call that triggered the script or job that created the log
- messages - the logging message.
console.log(1,2,3)
will create [1,2,3]. multiple console.log calls will create multiple object - level - the log level, info, error or log
[
{
"_id": "5a53ff5cfdc0196880dc8cb4",
"createdAt": "2018-01-08T23:31:40.612Z",
"updatedAt": "2018-01-08T23:31:40.612Z",
"runnable_id": "5706caaebb6fba08718e2e9c",
"runnable_call_id": "5a53ff5cfdc0196880dc8cb2",
"level": "log",
"messages": ["object",{"name":"me"}],
"__v": 0,
"id": "5a53ff5cfdc0196880dc8cb4"
}, {
"_id": "5a53ff3efdc0196880dc8c7c",
"createdAt": "2018-01-08T23:31:10.552Z",
"updatedAt": "2018-01-08T23:31:10.552Z",
"runnable_id": "5706caaebb6fba08718e2e9c",
"runnable_call_id": "5a53ff3efdc0196880dc8c7a",
"level": "log",
"messages": ["here 1"],
"__v": 0,
"id": "5a53ff3efdc0196880dc8c7c"
}
]
GET /jobs/:id/calls
GET /scripts/:id/calls
Returns a pageable list of meta data associated with a script or job execution.
Important fields:
- createdAt - timestamp
- duration - time in milliseconds it to for the script execution
- runnable_id - the actual runnable that object here is describing
- tpye - scripts or jobs
- parent - the owner of the property that invoked the runnable, only applicable to bots and users
- property_id - the property that caused the script invocation, , only applicable to scripts
[
{
"_id": "5a5e52fedb9ebb774b998415",
"createdAt": "2018-01-16T19:31:10.353Z",
"updatedAt": "2018-01-16T19:31:10.673Z",
"duration": 322,
"runnable_id": "5706caaebb6fba08718e2e9c",
"type": "scripts",
"parent_id": "588a380faaaaaec3f4e65d2b",
"property_id": "5a5e52fec6e312774a4d1ad7",
"__v": 0,
"id": "5a5e52fedb9ebb774b998415"
}, {
"_id": "5a5e52a5db9ebb774b9983ea",
"createdAt": "2018-01-16T19:29:41.270Z",
"updatedAt": "2018-01-16T19:29:41.479Z",
"duration": 209,
"runnable_id": "5706caaebb6fba08718e2e9c",
"type": "scripts",
"parent_id": "588a380faaaaaec3f4e65d2b",
"property_id": "5a5e52a5c6e312774a4d1abb",
"__v": 0,
"id": "5a5e52a5db9ebb774b9983ea"
}
]
GET /jobs/:id/version
GET /scripts/:id/version
Every time a script or job is updated the old version is saved in history for basic version management.
Important fields:
- createdAt - timestamp
- runnable_id - the actual runnable that object here is describing
- javascript - the actual code of this version
- old_javascript - the code of the prior version, allows for easy code diffs.
[{
"_id": "5a5d78878c7b559d56c58be0",
"createdAt": "2018-01-16T03:59:03.750Z",
"updatedAt": "2018-01-16T03:59:03.750Z",
"runnable_id": "56129b834f0d7cce5e098fbe",
"javascript": "...",
"old_javascript": "...",
"__v": 0,
"id": "5a5d78878c7b559d56c58be0"
}, {
"_id": "5a5d787b8c7b559d56c58bde",
"createdAt": "2018-01-16T03:58:51.939Z",
"updatedAt": "2018-01-16T03:58:51.939Z",
"runnable_id": "56129b834f0d7cce5e098fbe",
"javascript": "",
"old_javascript": "...",
"__v": 0,
"id": "5a5d787b8c7b559d56c58bde"
}]
GET /scripts/:id/reset
Resets the runtime statistics of the script, the values are 'errorMessages','errorInvocationCount' and 'invocationCount'
Next: WebSockets