Oglama SDK
Founding principles
Defined by the Roman architect Vitruvius, the principles of Strength, Utility, and Delight (firmitas, utilitas, venustas) form the foundation of good architecture, and they are central to Oglama's philosophy.
Firmitas
Oglama opens the door to automations that are simply not possible with other software. It maintains a good balance between AI flexibility and JavaScript programming determinism, all while protecting your privacy.
Utilitas
Effortlessly install, run, and edit modules directly from the built-in source code editor. The editor supports all the methods and properties listed below, and comes with autocomplete, auto-formatting, and linting.
Venustas
Oglama is designed with simplicity at its core. You don't need to be a programmer to get value from this software. Just search our repository for a module that solves your problem, install it, run it, and modify it to your liking.
Getting started
Oglama is a desktop application built on top of Chromium that allows you to automate web actions.
Create an account and download the latest version to get started. Alternatively, clone oglama/oglama and run npm start to use the latest pre-release version.
1. Agents
Agents are autonomous browser windows, each operating in its own isolated session. For security reasons, agents do not have direct access to the file system or to each other's data. You must manually specify input files as needed.
2. Modules
Agents execute small JavaScript programs called modules. Each module defines inputs, outputs, functions, and a finite-state machine. For security reasons, modules do not have direct access to the browser window. Instead, the dollar sign object ($) is used to interact with the web page, pause execution, chat with a locally running large language model, fetch user input, save results, and more.
2.1. Finite-state machine
Complex browser interactions are best modeled as a finite-state machine.
When a user starts an agent, the state machine begins execution from the entry state.
It then jumps from state to state with
return { next: "state-key" }The state machine stops if an error occurs or if no next state is specified.
2.2. Functions
Functions are used to avoid code duplication within state machine states. Unlike states, a function's return value has no special significance. Functions can be called from either a state or another function using $.fn("function-key")
2.3. Inputs and outputs
Each module can define up to 20 inputs and 20 outputs. This limit is intended to reduce cognitive load.
Supported input and output types are: integer, string, boolean,table and files
Inputs for each run are specified in the Settings tab. Fetch inputs in states and functions with $.ioInput*()
Outputs are collected in the Results tab. Store outputs in states and functions with $.ioOutput*()
3. Collaboration
You can publish your modules to the module repository, allowing others to install and use your work. You can also import and export your automations as .oglama.yaml files, giving you complete privacy and control over your work.
Example
Here is an example of a small Oglama module (search.oglama.yaml) that performs a Google search.
Please note that the module is exported as a YAML file, but each function and finite-state machine state is written in pure JavaScript and relies on the dollar sign object ($) for operations.
srcStateMachine:
- key: start
code: |
await $.fn("visit-google");
await $.fn("search");
srcFunctions:
- key: visit-google
code: |
// Navigate to Google and wait for page to load
await $.navLoad("https://google.com/");
- key: search
code: |
// Find the input field
const inputKey = await $.doQuery("[name='q']");
if ("string" !== typeof inputKey) {
throw new Error("Could not find input field");
}
// Get search term from user settings
const searchTerm = $.ioInputString("search-term");
// Replace previous string and send enter key
await $.doType(inputKey, searchTerm, { replace: true, submit: true });
srcInputs:
- key: search-term
type: string
name: Search term
desc: A search term for Google
max: 1024
options: []
default: oglama
srcOutputs: []
Import this and other modules by following these steps:
- Launch Oglama, select an agent, and click on Options
- Click Source Code, go to Source Control, and select 'Import from YAML'
- Choose the module file (
search.oglama.yaml)
The SDK
All available Oglama SDK methods and properties are described below. The SDK has a flat structure, with every method and property attached to the dollar sign object ($).$.args
{array}
- When used inside a state:
array passed by previous state as { next: 'state-key', args }
- When used inside a function:
array passed as the second argument to $.fn( 'function-key', args )Although you can use $.global*() methods to store and retrieve data from a global store, it is sometimes better to simply pass arguments from one state to another.
srcStateMachine:
- key: start
code: |
// Generate a random number locally (or use $.osRand())
const randomNumber = await $.fn("random", [2, 10]);
// Pass it to the next state
return { next: "surprise", args: [randomNumber] };
- key: surprise
code: |
// Passed with { next: "surprise", args: [randomNumber] };
const randomNumber = $.args[0];
$.log(`The number I was thinking of was ${randomNumber}`);
// Put the LLM to work
const prompt = `Multiply ${randomNumber} by itself.`;
const response = await $.llm(prompt);
srcFunctions:
- key: random
code: |
if (2 !== $.args.length) {
throw new Error("Expecting 2 arguments");
}
// Destructure the function arguments
const [from, to] = $.args;
// Generate a random number
return Math.floor(Math.random() * (to - from + 1)) + from;
srcInputs: []
srcOutputs: []
$.current
{string}
Current state key.At the core of every Oglama module is a finite-state machine where each state is uniquely identified by its key.
You may need to reference the current or the $.previous state key inside functions.
srcStateMachine:
- key: start
code: |
await $.fn("write-haiku");
return { next: "middle" };
- key: middle
code: |
await $.fn("write-haiku");
return { next: "end" };
- key: end
code: |
await $.fn("write-haiku");
srcFunctions:
- key: write-haiku
code: |
// The Old Pond by Matsuo Bashō (1644-1694)
switch ($.current) {
case "start":
$.log("An old silent pond");
break;
case "middle":
$.log("A frog jumps into the pond");
break;
case "end":
$.log("Splash! Silence again.");
break;
}
await $.sleep(1000);
srcInputs: []
srcOutputs: []
$.previous
{string|null}
Previous state key or null if this is the entry state.Following the example for the $.current property, here's how one would use the previous state key.
srcStateMachine:
- key: start
code: |
await $.fn("write-haiku");
return { next: "middle" };
- key: middle
code: |
await $.fn("write-haiku");
return { next: "end" };
- key: end
code: |
await $.fn("write-haiku");
srcFunctions:
- key: write-haiku
code: |
// The Old Pond by Matsuo Bashō (1644-1694)
switch ($.previous) {
case null:
$.log("An old silent pond");
break;
case "start":
$.log("A frog jumps into the pond");
break;
case "middle":
$.log("Splash! Silence again.");
break;
}
await $.sleep(1000);
srcInputs: []
srcOutputs: []
async $.fn( fnKey, fnArgs = [] )
Call a function (see the Functions tab).
@param {string} fnKey Function key
@param {array} fnArgs (optional) Function arguments; accessed with $.args
Functions allow you to organize your module better and prevent code duplication.
Here's a simple example for counting down using functions - recursively.
srcStateMachine:
- key: start
code: |
await $.fn("countdown", [3]);
$.log("That was easy");
srcFunctions:
- key: countdown
code: |
const number = $.args[0];
if (number <= 0) {
return;
}
$.log(number, "success");
await $.sleep(1000);
// Recursion is fun!
await $.fn("countdown", [number - 1]);
srcInputs: []
srcOutputs: []
async $.llm( prompt )
Prompt the locally running large language model.
@param {string} prompt Prompt - up to 4096 characters long
@return {string} LLM response
@throws {Error} If the LLM is not ready
Oglama provides easy access to a locally running large language model for complex tasks such as text summarization and sentiment analysis. Please note that LLMs are neither accurate nor deterministic.
The example below shows when not to use a large language model: mathematical operations are much faster and more accurate in pure JavaScript.
srcStateMachine:
- key: start
code: |
const startTime = performance.now();
// Ask the magic box
const response = await $.llm("Answer with one number: 2 + 3");
// Log the execution time
$.log(`Finished in ${(performance.now() - startTime) / 1000} seconds`);
srcFunctions: []
srcInputs: []
srcOutputs: []
$.log( message, status = "info" )
Append a message to the agent logs.
@param {any} message Message
@param {"info"|"success"|"warning"|"error"} status (optional) Status; default info
A maximum of 250 logs are retained in the logs panel for each agent. Logs are stored in session and are removed when the app is closed. There are four log types, each with their own color:info,success.warning, anderror.
srcStateMachine:
- key: start
code: |
$.log("🍰 A new cake recipe was added.", "info");
$.log("🧁 The cake has baked successfully!", "success");
$.log("🔥 The oven temperature is far too high.", "warning");
$.log("💀 Cake failed to rise, check your ingredients.", "error");
srcFunctions: []
srcInputs: []
srcOutputs: []
async $.sleep( ms )
Pause the execution of the current thread for a specified number of milliseconds.
@param {number} ms Sleep time in milliseconds
Sometimes you may need to slow down your script to prevent overloading a website's resources, and other times you might just want a bit of showmanship.
srcStateMachine:
- key: start
code: |
$.log("It's the final countdown:", "warning");
await $.sleep(1000);
let counter = 5;
while (counter-- > 0) {
$.log(`⌛ ${counter + 1}...`);
// Wait for it...
await $.sleep(1000);
}
$.log("🚀 Liftoff!", "success");
srcFunctions: []
srcInputs: []
srcOutputs: []
$.pause( message = "" )
Pause the execution of the current state indefinitely.
When resumed, the current state will be re-executed from the start, not from the current line!
@param {string} message (optional) Message displayed in dialog when agent is (re-)selected
Oglama modules do not access or store any personal data, such as passwords or cookies.
If a user needs to log into a website or verify they are human, simply pause the script at the current finite-state machine state and kindly request their input.
srcStateMachine:
- key: start
code: |
// Check if we already asked the user to log in
if ($.globalRunGet("asked-user")) {
return;
}
// Mark this so we don't enter an infinite loop
$.globalRunSet("asked-user", true);
// Look for button that is only available after login
const elements = await $.doAwaitPresent(".dashboard-button", { timeout: 1 });
// Ooops! (reCaptcha, login wall etc.)
if (!elements) {
$.pause("'Dubito, ergo cogito; cogito, ergo sum' to continue.");
}
srcFunctions: []
srcInputs: []
srcOutputs: []
$.stop( message = "" )
Stop the execution of the current state.
When resumed, the finite-state machine will start from the first state (the Entry Point 🏁).
@param {string} message (optional) Message displayed in dialog when agent is (re-)selected
Unlike $.pause(), the current run is abandoned so all values stored with $.globalRunSet() are discarded. The next time you start the agent, it will execute normally from the entry state.
srcStateMachine:
- key: start
code: |
// Check if we already asked the user to log in
if (await $.globalEnvGet("asked-user")) {
return;
}
// Mark this so we don't enter an infinite loop
// Use the environment cache instead of the run store
await $.globalEnvSet("asked-user", true);
// Look for button that is only available after login
const elements = await $.doAwaitPresent(".dashboard-button", { timeout: 1 });
// Ooops! (reCaptcha, login wall etc.)
if (!elements) {
// Abandon the current run (and clear values in the run store)
$.stop("State the meaning of life to continue.");
}
srcFunctions: []
srcInputs: []
srcOutputs: []
$.setTimeout( callback, ms )
Delays execution of a function by a specified number of milliseconds.
@param {function} callback JavaScript function
@param {number} ms The number of milliseconds to wait before executing the callback
@return {int} Timeout ID
Setting a timer is useful for a wide range of algorithms, but you will likely find it most valuable when setting up a listener for an event that has not occurred yet.
srcStateMachine:
- key: start
code: |
// Go home
await $.navLoad("about:home/");
await $.doAwaitPresent(".mascot");
// Click on mascot in the future
$.setTimeout(async () => {
const mascotKey = await $.doQuery(".mascot");
await $.doClick(mascotKey);
}, 1000);
// Wait for mascot click to generate new quote
await $.doAwaitPresent(".quote");
// Wait for mouse to move away after click
await $.sleep(500);
srcFunctions: []
srcInputs: []
srcOutputs: []
$.clearTimeout( timeoutId )
Cancels a timeout previously established by $.setTimeout.
@param {function} timeoutId The identifier of the timeout to cancel, as returned by $.setTimeout
srcStateMachine:
- key: start
code: |
// Set the bomb
const timerId = $.setTimeout(async () => {
$.log("💥 Boom!", "error");
}, 500);
// Clear the bomb
$.clearTimeout(timerId);
$.log("All clear", "success");
srcFunctions: []
srcInputs: []
srcOutputs: []
async $.osRequest( url, options = {} )
OS: Make a request directly from the computer.
Useful for bypassing CORS (Cross-Origin Resource Sharing) constraints set by the browser.
If you need to make an authenticated request from the currently loaded page, use $.doRequest instead.
Note that these requests do not have access to your browser session's cookies.
@param {string} url Request URL
@param {Object} options (optional) Request options
@param {string} options.method (optional) Request method; default GET
@param {object} options.data (optional) Request data; default {}
@param {object} options.headers (optional) Request headers; default {}
@param {boolean} options.json (optional) JSON request; default true
@param {int} options.timeout (optional) Request timeout in seconds; default 60
@param {boolean} options.resData (optional) Parse and return the response data; default true
@return {{ ok:boolean, status:number, headers:object, data:mixed}} Response object
@throws {Error} If request failed
This method acts like a proxy, bypassing any CORS restrictions.
If you need to pass along cookies with your request, first nagivate to the target domain using $.navLoad() then issue the request with $.doRequest() or $.ioSaveRequest().
srcStateMachine:
- key: start
code: |
const url = "http://localhost:7199/manifest.json";
// JSON request (CORS is bypassed)
$.log(`Fetching ${url} from OS`, "success");
const response = await $.osRequest(url);
$.log([response?.status, response?.headers, response?.data]);
// Fetch headers only
$.log(`Fetching ${url} without data from OS`, "success");
const responseNoData = await $.osRequest(url, { resData: false });
$.log([responseNoData?.status, responseNoData?.headers, responseNoData?.data]);
srcFunctions: []
srcInputs: []
srcOutputs: []
$.osFileGetUrl( filePath )
OS: Prepare file:/// URL from file path.
@param {string|null} filePath File path generated with $.ioSave* methods or $.ioInputFiles
@return {string|null} URI encoded file:/// URL or null on error
async $.osFileGetSize( filePath )
OS: Fetch file size.
@param {string|null} filePath File path generated with $.ioSave* methods or $.ioInputFiles
@return {{ int:int, string:string}|null} File size in bytes and as a human-readable string expressed in KiB, MiB, GiB, and TiB
async $.osFileShow( filePath )
OS: Show file in folder.
@param {string} filePath File path generated with $.ioSave* methods or $.ioInputFiles
@return {boolean}
srcStateMachine:
- key: start
code: |
const url = "http://localhost:7199/manifest.json";
// Save the file to disk
const filePath = await $.ioSaveUrl("json-files", url);
// Open containing folder (if the user allows it)
if ($.ioInputBoolean("show-file-after-download")) {
await $.osFileShow(filePath);
}
srcFunctions: []
srcInputs:
- key: show-file-after-download
type: boolean
name: Show files
desc: Show downloaded files when the script finishes
srcOutputs:
- key: json-files
type: files
name: JSON files
desc: ""
max: 1024
extensions:
- json
$.osRand( min, max, options = {} )
OS: Generate a random signed integer between the specified minimum and maximum values (inclusive), or a random alphanumeric string with a length between the specified minimum and maximum values.
@param {int} min Minimum signed integer value OR minimum string length
@param {int} max Maximum signed integer value OR maximum string length
@param {Object} options (optional) Random generator options
@param {boolean} options.string (optional) Return a random string instead; default false; if true, min and max define the length of the returned string
@return {int|string} A random signed integer between min and max (inclusive) OR a random string between min and max characters long, but not longer than 512 characters
Introducing randomness into the behavior of modules is so useful that we decided to dedicate a helper function to it.
You could use Math.floor(Math.random() * (max - min + 1)) + min instead, but this is cleaner.
srcStateMachine:
- key: start
code: |
const minTemp = -15;
const maxTemp = 25;
const predictedTemp = $.osRand(minTemp, maxTemp);
$.log(`🌤️ Forecast says: ${predictedTemp}°C`, "success");
switch (true) {
case predictedTemp < 0:
const randomString = $.osRand(3, 4, { string: true });
$.log(`Brrr${randomString}... this is cold! 🥶`);
break;
case predictedTemp < 20:
$.log("Perfect for a walk. 😄");
break;
default:
$.log("Time for some ice cream. 😎");
break;
}
srcFunctions: []
srcInputs: []
srcOutputs: []
async $.globalEnvGet( envKey = null )
Environment globals: Get environment variable(s). Values are JSON serializable.
These values persit between runs but are reset on module install, fork or release.
@param {string|null} envKey (optional) Environment variable key or null for all values as a key-value object; default null
@return {object|any|null}
In this example, we're using the environment cache to perform an action only once per day.
srcStateMachine:
- key: start
code: |
// Prepare date in YYYY-MM-DD format
const dateToday = new Date().toISOString().split("T")[0];
// Fetch the date stored in environment cache (persistent between runs)
const dateStored = await $.globalEnvGet("date");
if (dateToday !== dateStored) {
// Do something new!
$.log("New day, new possibilities ☀️");
// Store today in environment cache
await $.globalEnvSet("date", dateToday);
}
srcFunctions: []
srcInputs: []
srcOutputs: []
async $.globalEnvSet( envKey, envValue )
Environment globals: Set environment variable. Values must be JSON serializable.
These values persit between runs but are reset on module install, fork or release.
The total environment cache size must not exceeded 512kB per agent.
@param {string} envKey Environment variable key
@param {any|null} envValue Environment variable value; if null, the key is removed
@return {boolean}
In this example, we're listing and removing all values from the environment cache.
srcStateMachine:
- key: start
code: |
// Set some random values to environment cache (persistent between runs)
for (let i = 1; i <= 3; i++) {
const randomInt = $.osRand(10, 99);
const randomString = $.osRand(10, 15, { string: true });
await $.globalEnvSet(`key-${randomInt}`, randomString);
}
// Get all values stored in environment cache
const envValues = await $.globalEnvGet();
// Log them as an object
$.log(envValues);
// Log them individually
for (const envKey of Object.keys(envValues)) {
$.log(`✨ ${envKey} = ${envValues[envKey]}`, "success");
}
// Clean the cache
for (const envKey of Object.keys(envValues)) {
// Setting value to null deletes it from the environment cache
await $.globalEnvSet(envKey, null);
$.log(`🗑️ ${envKey} environment value removed`, "warning");
}
srcFunctions: []
srcInputs: []
srcOutputs: []
$.globalRunGet( runKey = null )
Run globals: Get global variable(s) for this run.
These values are reset before each run.
@param {string|null} runKey (optional) Run variable key or null for all values as a key-value object; default null
@return {object|any|null}
$.globalRunSet( runKey, runValue )
Run globals: Set global variable for this run.
These values are reset before each run.
@param {string} runKey Run variable key
@param {any|null} runValue Run variable value; if null, the key is removed
@return {boolean}
$.ioInputInt( ioKey )
IO: Get input integer(s).
This method returns an integer or an array of integers based on the selected input format.
@param {string} ioKey Integer input key
@return {int | int[]} Integer(s) supplied by user
@throws {Error} If ioKey is not a valid input integer key
$.ioInputString( ioKey )
IO: Get input string(s).
This method returns a string or an array of strings based on the selected input format.
@param {string} ioKey String input key
@return {string | string[]} String(s) supplied by user
@throws {Error} If ioKey is not a valid input string key
$.ioInputBoolean( ioKey )
IO: Get input boolean.
@param {string} ioKey Boolean input key
@return {boolean} Boolean supplied by user
@throws {Error} If ioKey is not a valid input boolean key
async $.ioInputRow( ioKey, index = null )
IO: Get the next available table row and increment index internally.
Alternatively, get the row at the specified index.
Row keys are declared in the Inputs tab for this table input.
@param {string} ioKey Table input key
@param {int} index (optional) Table index; default null
@return {Object<string,string> | null} Current row or null if reached the end of the table
@throws {Error} If ioKey is not a valid input table key
$.ioInputFiles( ioKey )
IO: Get input file paths.
@param {string} ioKey Files input key
@return {string[]} Input file paths
@throws {Error} If ioKey is not a valid input files key
async $.ioOutputInt( ioKey, int )
IO: Set output integer.
Subsequent calls override previous values.
@param {string} ioKey Integer output key
@param {int} int Integer
@return {boolean} true on success, false for invalid integer
@throws {Error} If ioKey is not a valid output integer key
async $.ioOutputString( ioKey, string )
IO: Set output string.
Subsequent calls override previous values.
Warning: string will be truncated to 1024 characters.
If you need to store longer strings, use $.ioSaveText instead.
@param {string} ioKey String output key
@param {string} string String
@return {boolean} true on success, false for invalid string
@throws {Error} If ioKey is not a valid output string key
async $.ioOutputBoolean( ioKey, boolean )
IO: Set output boolean.
Subsequent calls override previous values.
@param {string} ioKey Boolean output key
@param {boolean} boolean Boolean value
@return {boolean} true on success, false for invalid boolean
@throws {Error} If ioKey is not a valid output boolean key
async $.ioOutputRow( ioKey, row )
IO: Append a row to output table.
Row keys are declared in the Outputs tab for this table output.
@param {string} ioKey Table output key
@param {Object<string,string>} row Row object
@return {boolean} true on success, false for invalid row object
@throws {Error} If ioKey is not a valid output table key
async $.ioSaveText( ioKey, text, options = {} )
IO: Save text to disk as new file.
Useful for saving arbitrary strings in custom formats like JSON, YAML, INI etc.
For strings that are shorter than or equal to 1024 characters, you can use $.ioOutputString.
@param {string} ioKey Files output key
@param {string} text Text to save
@param {Object} options (optional) Save options
@param {string} options.extension (optional) File extension; default null; must match one of the extensions declared in output; falls back to first file extension declared in output
@return {string | null} File path on success, null if download failed
@throws {Error} If ioKey is not a valid output files key
async $.ioSaveDownload( ioKey, options = {} )
IO: Capture the next downloaded file and save it to disk.
Useful for saving any file download, regardless of how it was trigerred.
Defer the download event with $.setTimeout() before calling $.ioSaveDownload.
@param {string} ioKey Files output key
@param {Object} options (optional) Save options
@param {int} options.timeout (optional) Download timeout in seconds; default 600
@param {string} options.extension (optional) File extension; default null; must match one of the extensions declared in output; falls back to first file extension declared in output
@return {string | null} File path on success, null if download failed
@throws {Error} If ioKey is not a valid output files key
async $.ioSaveScreenshot( ioKey, options = {} )
IO: Take a screenshot of the current page and save it to disk.
@param {string} ioKey Files output key
@param {Object} options (optional) Save options
@param {string} options.extension (optional) File extension; default null; must match one of the extensions declared in output; falls back to first file extension declared in output
@param {boolean} options.dpr (optional) Use Device Pixel Ratio (DPR); default false; output video at true scale, which might be 2:1 instead of 1:1 on MacOS
@return {{ path:(string|null), width:int, height:int, error: (string|null)}} Screenshot details
@throws {Error} If ioKey is not a valid output files key
async $.ioSaveVideo( ioKey, options = {} )
IO: Record a video of the current page and save it to disk.
The video is rendered in real time with no sound.
@param {string} ioKey Files output key
@param {Object} options (optional) Save options
@param {string} options.extension (optional) File extension; default null; must match one of the extensions declared in output; falls back to first file extension declared in output
@param {int} options.fps (optional) Frames per second; default 20; an integer between 1 and 30
@param {"av1"|"h264"} options.codec (optional) Video codec; default "av1"; available codecs:
- "av1": better compression
- "h264": wider support across devices
@param {boolean} options.dpr (optional) Use Device Pixel Ratio (DPR); default false; output video at true scale, which might be 2:1 instead of 1:1 on MacOS
@param {boolean} options.rwp (optional) Record While Paused; default false; continue recording video even when agent is paused
@return {function(): Promise<{ path:(string|null), width:int, height:int, duration:int, error: (string|null)}>}
Returns an async function that stops recording the page.
Calling this function returns an object with recording details.
@throws {Error} If ioKey is not a valid output files key OR if trying to record more than one video at a time
In the following example we're recording smooth scrolling a web page at 150 pixels per second. Note that $.ioSaveVideo returns a callback function that stops the recording.
srcStateMachine:
- key: start
code: |
// Go home
await $.navLoad("about:home/");
// Start recording
const recStop = await $.ioSaveVideo("video");
// Wait, then load the test page
await $.sleep(1000);
await $.navLoad("about:home/test/");
// Smooth-scroll through the entire page
await $.doScroll(750, { speed: 150 });
// Log recorded video file path
const filePath = await recStop();
$.log(filePath);
srcFunctions: []
srcInputs: []
srcOutputs:
- key: video
type: files
name: Recordings
desc: ""
max: 512
extensions:
- mp4
async $.ioSaveUrl( ioKey, url, options = {} )
IO: Capture the file stored at this URL and save it to disk.
Useful for saving files that are not available as links on page.
@param {string} ioKey Files output key
@param {string} url URL to download
@param {Object} options (optional) Save options
@param {int} options.timeout (optional) Download timeout in seconds; default 600
@param {string} options.extension (optional) File extension; default null; must match one of the extensions declared in output; falls back to first file extension declared in output
@return {string | null} File path on success, null if download failed
@throws {Error} If ioKey is not a valid output files key or if url is invalid
async $.ioSaveRequest( ioKey, url, options = {} )
IO: Capture the result of this fetch request and save it to disk.
Useful for saving the result of fetch requests made from the current domain/page.
For direct access to JSON or text responses, use $.doRequest instead.
@param {string} ioKey Files output key
@param {string} url URL to save locally
@param {Object} options (optional) Request options
@param {string} options.method (optional) Request method; default GET
@param {object} options.data (optional) Request data; default {}
@param {object} options.headers (optional) Request headers; default {}
@param {boolean} options.json (optional) JSON request; default true
@param {int} options.timeout (optional) Request timeout in seconds; default 60
@param {string} options.extension (optional) File extension; default null; must match one of the extensions declared in output; falls back to first file extension declared in output
@return {string | null} File path on success, null if download failed
@throws {Error} If ioKey is not a valid output files key or if url is invalid
This example demonstrates how to save a file with a custom extension. Note that the file extension must first be declared in the output configuration. If the specified extension is not included in the declared list, the first listed extension, "json" in this case, will be used instead.
If you don't specify a file extension, the script will attempt to deduce it from the URL.
srcStateMachine:
- key: start
code: |
const url = "http://localhost:7199/manifest.json";
// Navigate to origin so the browser allows the request (CORS)
await $.navLoad(new URL(url).origin);
$.log("Saving JSON as simple text file...");
const jsonPath = await $.ioSaveRequest("manifest", url, { extension: "txt" });
if ("string" !== typeof jsonPath) {
throw new Error("$.ioSaveRequest failed");
}
srcFunctions: []
srcInputs: []
srcOutputs:
- key: manifest
type: files
name: JSON files
desc: ""
max: 1024
extensions:
- json
- txt
async $.handleAlert()
Browser: Prevent the next window.alert() from bubbling.
Unhandled alert dialogs are automatically closed,
and their message is passed as a toast notification.
async $.handleConfirm( accept = true )
Browser: Prevent the next window.confirm() from bubbling, and either accept or reject it.
Unhandled confirmation dialogs are automatically accepted,
and their message is passed as a toast notification.
@param {boolean} accept (optional) Accept or reject the next confirmation message; default true
async $.handlePrompt( response = "" )
Browser: Prevent the next window.prompt() from bubbling, and answer it.
Unhandled prompts automatically return with their default value or an empty string,
and their message is passed as a toast notification.
@param {string} response (optional) Prompt response text
async $.doQuery( selector, options = {} )
Document: Find the first HTML element that matches the CSS selector and return its corresponding Element key.
@param {string} selector Standard CSS selector
@param {Object} options (optional) Query options
@param {string} options.parent (optional) Parent Element key; default null to search the entire Document
@param {string} options.contains (optional) Text contained by Element (case insensitive); default null for no restrictions
@param {boolean} options.scrollable (optional) Restrict results to elements that have active scrollbars; default false
@param {boolean} options.viewportDown (optional) Restrict results to elements placed in the viewport and below it; default false
@return {string|null} Element key or null on error
async $.doQueryAll( selector, options = {} )
Document: Find all HTML elements that match the CSS selector and return their corresponding Element keys.
@param {string} selector Standard CSS selector
@param {Object} options (optional) Query options
@param {string} options.parent (optional) Parent Element key; default null to search the entire Document
@param {string} options.contains (optional) Text contained by Element (case insensitive); default null for no restrictions
@param {boolean} options.scrollable (optional) Restrict results to elements that have active scrollbars; default false
@param {boolean} options.viewportDown (optional) Restrict results to elements placed in the viewport and below it; default false
@return {string[]} Array of Element keys
async $.doQueryParent( elKey, options = {} )
Document: Find the parent of this HTML element that matches the CSS selector and return its corresponding Element key.
@param {string} elKey Element key - obtained with $.doQuery
@param {Object} options (optional) Query options
@param {string} options.selector (optional) CSS selector for parent element; default null to stop at first ancestor
@param {string} options.contains (optional) Text contained by Element (case insensitive); default null for no restrictions
@param {boolean} options.scrollable (optional) Restrict results to elements that have active scrollbars; default false
@return {string|null} Element key or null on error
async $.doQuerySiblings( elKey, options = {} )
Document: Find the siblings of this HTML element that match the CSS selector and return their corresponding Element keys.
@param {string} elKey Element key - obtained with $.doQuery
@param {Object} options (optional) Query options
@param {string} options.selector (optional) CSS selector for parent element; default null to stop at first ancestor
@param {string} options.contains (optional) Text contained by Element (case insensitive); default null for no restrictions
@param {boolean} options.scrollable (optional) Restrict results to elements that have active scrollbars; default false
@return {string[]} Element keys
async $.doQueryAt( left, top, options = {} )
Document: Find the first HTML element that matches the CSS selector at the specified coordinates,
and return its corresponding Element key.
@param {int} left Left coordinate in pixels
@param {int} top Top coordinate in pixels
@param {Object} options (optional) Query options
@param {string} options.selector (optional) CSS selector for parent element; default null to stop at first ancestor
@param {string} options.contains (optional) Text contained by Element (case insensitive); default null for no restrictions
@param {boolean} options.scrollable (optional) Restrict results to elements that have active scrollbars; default false
@return {string|null} Element key or null on error
async $.doRequest( url, options = {} )
Document: Make a request from the current page.
Useful for JSON and simple text responses. For large files or binary data use $.ioSaveRequest instead.
If you need to bypass CORS and send the requests directly from the computer (outside of the browser session) use $.osRequest instead.
@param {string} url Request URL
@param {Object} options (optional) Request options
@param {string} options.method (optional) Request method; default GET
@param {object} options.data (optional) Request data; default {}
@param {object} options.headers (optional) Request headers; default {}
@param {boolean} options.json (optional) JSON request; default true
@param {int} options.timeout (optional) Request timeout in seconds; default 60
@param {boolean} options.resData (optional) Parse and return the response data; default true
@return {{ ok:boolean, status:number, headers:object, data:mixed}} Response object
@throws {Error} If request failed
This example describes how to fetch data in the browser when CORS is an issue.
If you don't care about cookies you can use $.osRequest() to bypass CORS instead.
srcStateMachine:
- key: start
code: |
const url = "http://localhost:7199/manifest.json";
// Navigate to origin so the browser allows the request (CORS)
await $.navLoad(new URL(url).origin);
// JSON request
$.log(`Fetching ${url} from browser`, "success");
const response = await $.doRequest(url);
$.log([response?.status, response?.headers, response?.data]);
// Fetch headers only
$.log(`Fetching ${url} without data from browser`, "success");
const responseNoData = await $.doRequest(url, { resData: false });
$.log([responseNoData?.status, responseNoData?.headers, responseNoData?.data]);
srcFunctions: []
srcInputs: []
srcOutputs: []
$.doTick( name, amount = 1 )
Document: Increment a named counter in the Status bar.
Up to 5 counters can be displayed at a time.
@param {string} name Counter name. The following strings are displayed as icons:
"contact", "view", "like", "post", "repost", "comment",
"upload", "download", "screenshot", "collect",
"success", "warning"
@param {int} amount (optional) Strictly positive number; [0,1000]; default 1; 0 won't increment the counter
async $.doHighlight( elKey, options = {} )
Document: Highlight an HTML Element in the viewport for 1 second.
@param {string} elKey Element key - obtained with $.doQuery
@param {Object} options (optional) Highlight options
@param {boolean} options.scrollIntoView (optional) Scroll element into view before highlighting; default true
@param {boolean} options.hoverAfterScroll (optional) Move mouse over the center of the element after scrolling into view; default true
async $.doHighlightBox( box )
Document: Highlight a box in the viewport for 1 second.
@param {Object} box Rectangle details; obtained with $.doGetBox
@param {int} box.left Left coordinate in pixels
@param {int} box.top Top coordinate in pixels
@param {int} box.width Width in pixels
@param {int} box.height Height in pixels
async $.doGetMouse()
Document: Get current mouse position.
@return {{ left: int, top: int}}
async $.doGetBox( elKey )
Document: Get the box of an HTML Element.
@typedef {Object} Box
@property {int} left Left coordinate (px)
@property {int} top Top coordinate (px)
@property {int} width Width of border-box, including padding and borders (px)
@property {int} height Height of border-box, including padding and borders (px)
@property {int} scrollLeft Distance of scrolled content from the left (px)
@property {int} scrollTop Distance of scrolled content from the top (px)
@property {int} scrollWidth Total width of content inside element, including overflow (px)
@property {int} scrollHeight Total height of content inside element, including overflow (px)
@param {string} elKey Element key - obtained with $.doQuery
@return {Box|null} Element box or null on error
async $.doGetType( elKey )
Document: Get the type of an HTML Element.
@param {string} elKey Element key - obtained with $.doQuery
@return {string|null} Element type or null on error
async $.doGetValue( elKey )
Document: Get the value of an HTML Element. Supported elements:
- input (includes checkbox and radio)
- textarea
- select
Returns multiple values for checboxes and <select multiple/>.
@param {string} elKey Element key - obtained with $.doQuery
@return {string|string[]|boolean|null} Value or null on error
async $.doGetAttribute( elKey, attr )
Document: Get a single HTML Element attribute.
@param {string} elKey Element key - obtained with $.doQuery
@param {string} attr HTML attribute (lowercase)
@return {string|null} Attribute value or null on error
async $.doGetAttributes( elKey, attrs = [] )
Document: Get all or multiple HTML Element attributes.
@param {string} elKey Element key - obtained with $.doQuery
@param {string[]} attrs (optional) HTML attributes (lowercase) or empty array for all; default []
@return {Object<string,string>} Map of attribute and value
async $.doGetContent( elKey, asHtml = false )
Document: Get the content of an HTML Element.
@param {string} elKey Element key - obtained with $.doQuery
@param {boolean} asHtml (optional) Use innerHTML instead of innerText; default false
@return {string|null} Element contents or null on error
async $.doGetStyle( elKey, props = [] )
Document: Get the resolved values of this Element's CSS properties.
@param {string} elKey Element key - obtained with $.doQuery
@param {string[]} props List of CSS properties to return; default [] to return all
@return {object|null} Element CSS properties or null on error; invalid CSS properties are discarded from the result object
async $.doGetVisible( elKey )
Document: Get whether HTML Element is visible on page.
@param {string} elKey Element key - obtained with $.doQuery
@return {boolean}
async $.doGetScrollable( elKey )
Document: Get whether HTML Element has scroll bars.
@param {string} elKey Element key - obtained with $.doQuery
@return {{ horizontal: boolean, vertical: boolean}}
async $.doGetInViewport( elKey )
Document: Get whether HTML Element is even partially located in the viewport.
@param {string} elKey Element key - obtained with $.doQuery
@return {boolean}
async $.doGetViewport()
Document: Get the viewport box.
@typedef {Object} Box
@property {int} left Left coordinate (px)
@property {int} top Top coordinate (px)
@property {int} width Width of viewport (px)
@property {int} height Height of viewport (px)
@property {int} scrollLeft Distance of scrolled content from the left (px)
@property {int} scrollTop Distance of scrolled content from the top (px)
@property {int} scrollWidth Total width of content, including overflow (px)
@property {int} scrollHeight Total height of content, including overflow (px)
@return {Box}
async $.doClick( elKey, options = {} )
Document: Click or double-click on HTML Element.
Automatically scroll to Element before action.
@param {string} elKey Element key - obtained with $.doQuery
@param {Object} options (optional) Click options
@param {boolean} options.double (optional) Double-click; default false
@param {boolean} options.hover (optional) Hover after click; default false to move mouse to the side after clicking
@return {boolean} true on success, false on failure
async $.doClickAt( left, top, options = {} )
Document: Click or double-click at coordinates in viewport.
@param {int} left Left coordinate in pixels
@param {int} top Top coordinate in pixels
@param {Object} options (optional) Click options
@param {boolean} options.double (optional) Double-click; default false
@param {boolean} options.hover (optional) Hover after click; default false to move mouse to the side after clicking
@return {boolean} true on success, false on failure
async $.doHover( elKey )
Document: Move mouse over an HTML Element.
Automatically scroll to Element before action.
@param {string} elKey Element key - obtained with $.doQuery
@return {boolean} true on success, false on failure
async $.doHoverAt( left, top )
Document: Move mouse to coordinates in viewport.
@param {int} left Left coordinate in pixels
@param {int} top Top coordinate in pixels
@return {boolean} true on success, false on failure
async $.doHoverCenter()
Document: Move mouse just slightly outside of viewport center.
@return {boolean} true on success, false on failure
async $.doJiggle( radius = 50 )
Document: Jiggle the mouse at the current coordinates.
@param {int} radius (optional) Jiggle radius in pixels; [10,500]; default 50
@return {boolean} true on success, false on failure
async $.doScroll( amount, options = {} )
Document: Issue mouse wheel (scroll) events at the current cursor position.
@param {int} amount Scroll amount in pixels
@param {Object} options (optional) Scroll options
@param {int} options.speed (optional) Scroll speed in pixels/second; default 100; between 1 and 2000
@param {boolean} options.vertical (optional) Vertical or Horizontal scroll; default true for vertical
@return {boolean} true on success, false on failure
async $.doScrollTo( elKey, options = {} )
Document: Scroll to HTML Element.
@param {string} elKey Element key - obtained with $.doQuery
@param {Object} options (optional) Scroll to options
@param {int} options.top (optional) Top margin; default 0; target Element distance to the top of the page in pixels
@param {boolean} options.hover (optional) Hover mouse over center of element after scrolling; default true
@return {boolean} true on success, false on failure
async $.doType( elKey, text, options = {} )
Document: Type text to specified HTML element.
Automatically scroll to Element before action.
Skips typing if the Element is not editable.
To save time on large texts, the first part of the text is pasted,
and only the last 250 characters are typed one character at a time.
@param {string} elKey Element key - obtained with $.doQuery
@param {string} text Text to type
@param {Object} options (optional) Typing options
@param {boolean} options.replace (optional) Replace current text; default false to append text
@param {boolean} options.submit (optional) Press the Enter key at the end; default false
@param {int} options.speed (optional) Typing speed in characters per second; [1,250]; default 5
@param {int} options.sequence (optional) Type last N characters in sequence; use clipboard for the rest; [1,1000]; default 250
@return {boolean} Returns false if target element is not editable
async $.doTypeAt( left, top, text, options = {} )
Document: Type text at coordinates in viewport.
To save time on large texts, the first part of the text is pasted,
and only the last 250 characters are typed one character at a time.
@param {int} left Left coordinate in pixels
@param {int} top Top coordinate in pixels
@param {string} text Text to type
@param {Object} options (optional) Typing options
@param {boolean} options.replace (optional) Replace current text; default false to append text
@param {boolean} options.submit (optional) Press the Enter key at the end; default false
@param {int} options.speed (optional) Typing speed in characters per second; [1,250]; default 5
@param {int} options.sequence (optional) Type last N characters in sequence; use clipboard for the rest; [1,1000]; default 250
@return {boolean} true on success, false on failure
async $.doSelect( elKey, values )
Document: Select zero, one or more options, replacing previous selection.
Automatically scroll to Element before action.
@param {string} elKey Element key - obtained with $.doQuery
@param {string|string[]} values A single value or an array of values for <select multiple/>
@return {boolean} true on success, false on failure
async $.doCheck( elKey, values )
Document: Check radio or checkbox values. The element's siblings must share the same name attribute.
Automatically scroll to Element(s) before action.
@param {string} elKey Element key - obtained with $.doQuery
@param {string|string[]} values A single value or an array of values
@return {boolean} true on success, false on failure
async $.doChooseFiles( elKey, filePaths )
Document: Choose files for <input type="file" /> HTML Element.
Automatically scroll to Element before action.
@param {string} elKey Element key - obtained with $.doQuery
@param {string|string[]} filePaths File path(s) generated with $.ioSave* methods or $.ioInputFiles
@return {boolean} true on success, false on failure
async $.doAwaitPresent( selector, options = {} )
Document: Wait for an Element to be present in the DOM.
@param {string} selector Standard CSS selector
@param {Object} options (optional) Query options
@param {string} options.parent (optional) Parent Element key; default null to search the entire Document
@param {string} options.contains (optional) Text contained by Element (case insensitive); default null for no restrictions
@param {boolean} options.scrollable (optional) Restrict results to elements that have active scrollbars; default false
@param {int} options.timeout (optional) Timeout in seconds; default 60
@param {boolean} options.first (optional) Return only the first Element's key (string instead of string[]); default false
@return {string[]|string|false} Array of Element keys; Element key if options.first; false on timeout
async $.doAwaitNotPresent( elKey, options = {} )
Document: Wait for an Element to be removed from the DOM.
@param {string} elKey Element key - obtained with $.doQuery or $.doAwaitPresent
@param {Object} options (optional) Query options
@param {int} options.timeout (optional) Timeout in seconds; default 60
@return {boolean} true on success, false on timeout
async $.doAwaitVisible( elKey, options = {} )
Document: Wait for an Element to become visible to the user (display, visibility, opacity).
@param {string} elKey Element key - obtained with $.doQuery or $.doAwaitPresent
@param {Object} options (optional) Query options
@param {int} options.timeout (optional) Timeout in seconds; default 60
@return {boolean} true on success, false on timeout
async $.doAwaitNotVisible( elKey, options = {} )
Document: Wait for an Element to become invisible to the user (display, visibility, opacity).
@param {string} elKey Element key - obtained with $.doQuery or $.doAwaitPresent
@param {Object} options (optional) Query options
@param {int} options.timeout (optional) Timeout in seconds; default 60
@return {boolean} true on success, false on timeout