Skip to main content
Seraph loads two kinds of file out of the plugins folder, and the only difference is the name. Reach for a script by default. Reach for a module when the plugin does work every tick or every frame, where compiled bytecode is markedly quicker, or when it needs to clean something up on shutdown.

Scripts

A script is just a file. It runs top to bottom when it loads, and everything it registered, its listeners, commands and timers, is cleared and re-registered whenever it reloads. There is nothing to tear down by hand.

Modules

Name a file <name>.mod.js and it is treated as a module. It is compiled rather than interpreted, and it stays loaded for the life of the client: editing it does not reload it, and neither the watcher nor /seraph plugin swaps it out. Both tell you a restart is needed instead. Ordinary scripts carry on reloading around any running modules, which stay up. Because a module outlives a reload, anything it registers conditionally is its own to remove:
enable runs once the file has been evaluated. disable runs when the client shuts down, which is where anything outliving the game, a written file or an open connection, should be closed. The runaway guard applies to modules exactly as it does to scripts, so a loop that never ends is stopped rather than left to hang the client.

ES module syntax

Modules may use import and export, which Seraph rewrites to its own loader:

require

require loads either another plugin or another file.
A specifier matching the name of a loaded module returns that module’s exports. Declare it in dependsOn so it is guaranteed to have loaded first. Anything else is treated as a path relative to the requiring file, with or without the .js suffix, which is how you keep shared code in a subfolder even though only top level .js files are discovered.

Timers

Timers are available both as globals and on the scheduler object, and both return an id you can stop later.
cron takes the usual five fields, minute, hour, day of month, month and day of week, aligned to the wall clock. Each accepts a number, *, a first-last range, a comma separated list and a /step suffix. Months and days may be named, jan or mon, and both 0 and 7 mean Sunday. When both the day of month and the day of week are restricted the callback runs when either matches, as cron traditionally behaves. An expression that cannot be read returns -1. A script’s timers are cleared for it on reload. A module’s are not, which is what disable is for.

Commands

events.registerCommand adds a real chat command, with tab completion:
events.completePlayers narrows the players currently in tab down to those matching the argument being typed, the same set Seraph’s own commands complete against. Subcommands are a map rather than a function: