Skip to content

Module header

A module is a TypeScript file with one export default defineAutomation({...}). Everything except run is the header: it must be literals only (strings, numbers, booleans, arrays and objects) because heliana reads it without running the code.

import { defineAutomation } from '@heliana/automation'
Field Meaning
counters Named event counters. Each entry counts events of one kind inside a sliding window, per actor.
game The game this module is written for. It must match the game of the organization.
inputs Fields the operator fills in before a button runs. The shape of ctx.input is derived from this record.
limits Per-minute ceilings on the bans and kicks of this module. They only narrow the platform ceiling, never raise it.
name The display name of the automation. It is what the list and the run history show.
pause Cooldown after a run. While it lasts the module does not start again for the same player, or at all when the scope is the automation.
trigger What starts the module: an event, a button or a schedule.
Kind Meaning
button A manual run from the player card or the server page. “on” says which subject the button acts on, “label” is the text on it.
event Runs when the named event arrives from a connected server. The event key comes from the game vocabulary.
schedule Runs on a timer: “every” takes a duration such as 15m, “cron” takes a five-field cron expression. “for” picks whether the run is per online player or per server.

Durations use one grammar everywhere: a number and a unit s, m, h or d, for example 90s or 2h.

The same declarations ship in automation.d.ts.

export type Duration = `${number}${"d" | "h" | "m" | "s"}`
export interface NumberInput {
readonly kind: 'number'
readonly required?: boolean
}
export interface TextInput {
readonly kind: 'text'
readonly required?: boolean
}
export interface OptionInput {
readonly kind: 'option'
readonly options: readonly string[]
readonly required?: boolean
}
export type InputSpec = NumberInput | OptionInput | TextInput
export type Subject = "player" | "server"
export interface EventTrigger {
readonly event: string
readonly kind: "event"
}
export interface ButtonTrigger {
readonly kind: "button"
readonly label: string
readonly on: Subject
}
export interface IntervalTrigger {
readonly every: Duration
readonly for: Subject
readonly kind: "schedule"
}
export interface CronTrigger {
readonly cron: string
readonly for: Subject
readonly kind: "schedule"
}
export type AutomationTrigger = ButtonTrigger | CronTrigger | EventTrigger | IntervalTrigger
export interface CounterSpec {
readonly event: string
readonly per: "actor"
readonly window: Duration
}
export interface PauseSpec {
readonly for: Duration
readonly per: "player" | "automation"
}
export interface AutomationLimits {
readonly bansPerMinute?: number
readonly kicksPerMinute?: number
}
export interface AutomationHeader {
readonly counters?: Readonly<Record<string, CounterSpec>>
readonly game: string
readonly inputs?: Readonly<Record<string, InputSpec>>
readonly limits?: AutomationLimits
readonly name: string
readonly pause?: PauseSpec
readonly trigger: AutomationTrigger
}