Rawtoh Rawtoh / Docs

Scripting

Write triggers and actions in TypeScript to power your automations.

Triggers and actions are written in TypeScript. Rawtoh runs your code in a secure, sandboxed environment every time a matching event arrives.

All runtime APIs are available via import { ... } from "rawtoh". You can also import shared scripts to reuse code across your automations.

The script editor

Rawtoh includes a built-in code editor with TypeScript autocompletion and syntax highlighting. The editor is split into three panels:

You can have multiple scripts open in tabs and save with Ctrl+S. The editor provides autocompletion for "rawtoh" imports and shared script paths. You can Ctrl+Click on an import path to navigate to the shared script.

Writing trigger code

A trigger's code is a filter function. It receives the event and must use export default with a truthy value for the associated action to run. Trigger code has a 5-second timeout.

Available imports

Import Description
eventThe event object (name, payload, emitter_group, emitter_name)
triggerThe trigger object itself

Only event and trigger are available in triggers. log, sleep, module, and storage are not available — calling them will throw an error.

The event object

import { event } from "rawtoh"

event.name           // "chat.message"
event.payload        // { user_name: "alice", message: "!hello", ... }
event.emitter_group  // "twitch"
event.emitter_name   // "main-bot"

Examples

// Always fire (pass-through trigger)
export default true
import { event } from "rawtoh"

// Only fire for a specific command
export default event.payload.message === "!hello"
import { event } from "rawtoh"

// Fire for subscribers only
export default event.payload.is_subscriber === true

Writing action code

An action's code is the business logic — what actually happens when the trigger fires. Actions run asynchronously with a 30-second timeout. Top-level await is supported.

Available imports

Import Description
eventThe event that triggered this execution
triggerThe trigger that matched
module(group, name?)Returns a proxy with .request() and .notify()
storageKey-value store with .get(key) and .set(key, value)
log(...args)Log output visible in the Activity panel
sleep(ms)Pause execution for the given duration

Calling module methods

Use the module() function to call methods on connected modules:

import { module } from "rawtoh"

// Send a Twitch chat message
await module("twitch").request("chat.say", {
  message: "Hello from Rawtoh!"
})

// Change OBS scene (fire-and-forget)
await module("obs").notify("scene.set_current", {
  scene_name: "BRB"
})

// Target a specific instance
await module("twitch", "alerts-bot").request("chat.say", {
  message: "New follower!"
})

Full example

import { event, log, module, storage } from "rawtoh"

// Welcome new subscribers with a custom message
const user = event.payload.user_name
const tier = event.payload.tier

// Get the sub count from storage
let count = await storage.get("sub_count") || 0
count++
await storage.set("sub_count", count)

// Send a chat message
await module("twitch").request("chat.say", {
  message: `Welcome @${user}! You're subscriber #${count} (Tier ${tier})`
})

log(`New sub: ${user} (Tier ${tier}), total: ${count}`)

Shared scripts

Shared scripts let you reuse code across multiple triggers and actions. They appear in the Explorer alongside your actions and triggers.

Use standard export and import syntax. Shared scripts can be imported by absolute path (from the tree root) or relative path:

Defining a shared script

// /utils/format (shared script)
export function greet(name) {
  return `Hello, ${name}!`
}

export function upper(str) {
  return str.toUpperCase()
}

Importing shared scripts

import { event, log, module } from "rawtoh"
import { greet } from "/utils/format"

// Use shared function in your action
await module("twitch").request("chat.say", {
  message: greet(event.payload.user_name)
})
// Relative imports also work (from the current script's directory)
import { upper } from "./format"
import { double } from "../math/double"

Shared scripts can also import from "rawtoh" and from other shared scripts. However, shared scripts imported by triggers must not use action-only APIs (log, sleep, module, storage) — calling them will throw a runtime error.

Organizing your scripts

Actions and shared scripts use a path-based hierarchy, like a file system. Group related automations into folders:

/twitch
  /chat
    /greet          <- action: welcome new users
    /commands       <- action: handle !commands
  /subs
    /alert          <- action: sub notification
/obs
  /scenes
    /auto-switch    <- action: switch scenes automatically
/utils
  /format           <- shared: reusable formatting functions
  /config           <- shared: common configuration
/alerts
  /donation         <- action: donation alert

You can enable or disable entire folders at once — handy for turning off a group of automations without deleting them.

Tips