Repository navigation
Java scripts
With scripts.enabled: true, a token with the code permission can send Java to the server. WorldAPI compiles it with the Eclipse compiler bundled in the jar, so a JRE is enough, and loads it in its own class loader.
Only owner has code. Give it only to people you'd trust with SSH.
| Endpoint | Permission | What it does |
|---|---|---|
GET /scripts |
code |
Loaded scripts |
POST /scripts |
code |
Load a script that stays: it can listen to events and schedule tasks |
POST /scripts/run |
code |
Compile and run Java once, and return what it returns |
GET /scripts/{id} |
code |
One script with its source |
DELETE /scripts/{id} |
code |
Unload a script: remove its listeners and tasks |
GET /scripts/{id}/logs |
code |
The latest lines a script logged |
curl -H "Authorization: Bearer $CODE_TOKEN" -H 'Content-Type: application/json' \
-X POST http://localhost:8110/api/v1/scripts/run \
-d '{"source": "return server.getWorlds().stream().map(w -> w.getName() + \": \" + w.getEntityCount()).toList();"}'A snippet is the body of a method with ctx and server in scope and the common Bukkit imports. A whole class works too.
A loaded script reacts to events and runs tasks:
import com.mairwunnx.worldapi.script.api.*;
import org.bukkit.event.player.PlayerJoinEvent;
public class Welcome implements WorldApiScript {
@Override
public void enable(ScriptContext ctx) {
ctx.on(PlayerJoinEvent.class, event -> event.getPlayer().sendMessage("Welcome back!"));
ctx.every(20 * 60, 20 * 60 * 10, () -> ctx.log("still here"));
}
}- Send it to
POST /scriptswith anid, andpersistent: trueto load it again after restarts. - Watch it with
GET /scripts/{id}/logsor thescript.logtopic. -
DELETE /scripts/{id}callsdisable(), removes every listener and task the script registered throughctx, closes its class loader, and deletes its classes.
Scripts see only Java and the Paper API (Bukkit, Paper, Adventure, and what their signatures expose). Before a script loads, WorldAPI checks its bytecode against scripts.blockedApis: processes, reflection, class loaders, native access, System.exit, environment variables, and the file system are blocked by default.
That is a guard rail, not a sandbox. Java has no way to fully contain code that runs in the same process: a script can still freeze the tick with an endless loop on the server thread, or do anything the Bukkit API allows, such as running console commands. Every script, run or loaded, goes to the audit log in full.