JavaScript SDK
The JavaScript SDK (sdk/js/) provides Node.js tooling for interacting with
world-runner from scripts and headless test suites.
Requirements
- Node.js ≥ 22
plant_world_runnerbinary built withserver+brand-pluginfeatures
Setup
cd sdk/js
npm install
Running tests
npm test # all suites
npm run test:smoke # server lifecycle, auth, clock, stream
npm run test:hob # HobDriver observation + Phase II stubs
The binary path defaults to ../../target/debug/plant_world_runner. Override
with WORLD_RUNNER_BIN.
WorldRunnerHarness
test/harness.js — spawn and terminate world-runner for testing.
import { WorldRunnerHarness } from "./test/harness.js";
const harness = new WorldRunnerHarness({ adminEmail: "me@example.com" });
await harness.start(); // spawns process, waits for ready, bootstraps auth
const client = harness.client();
await harness.stop();
Constructor options
| Option | Type | Default | Description |
|---|---|---|---|
binaryPath |
string |
../../target/debug/plant_world_runner |
Absolute path to binary |
adminEmail |
string |
test@harness.local |
Email for admin magic-link session |
extraArgs |
string[] |
[] |
Additional CLI args for world-runner |
Properties
| Property | Type | Description |
|---|---|---|
baseUrl |
string |
e.g. http://127.0.0.1:43829 |
port |
number |
Bound TCP port |
sessionCookie |
string |
Raw key=value session cookie |
Methods
| Method | Returns | Description |
|---|---|---|
start() |
Promise<this> |
Spawn, wait for ready, bootstrap auth |
client() |
WorldRunnerClient |
Authenticated client for this session |
stop() |
Promise<void> |
SIGTERM + drain |
WorldRunnerClient
src/world-client.js — authenticated HTTP + WebSocket client.
import { WorldRunnerClient } from "./src/world-client.js";
const client = new WorldRunnerClient("http://127.0.0.1:8080", sessionCookie);
Clock
| Method | Description |
|---|---|
status() |
GET /status — clock/frame status (no auth required) |
clockStep() |
POST /clock {"action":"step"} — advance one tick |
clockSetInterval(ms) |
Start continuous clock at ms milliseconds/tick |
clockPause() |
Pause continuous clock |
clockResume() |
Resume paused clock |
Atoms
| Method | Description |
|---|---|
getAtomKinds() |
GET /atoms — list of kind strings |
getAtoms(kind) |
GET /atoms/:kind — all instances of a kind |
getAtom(kind, id) |
GET /atoms/:kind/:id — single atom, throws on 404 |
Services
| Method | Description |
|---|---|
getServices() |
GET /services — service descriptor list |
getService(kind) |
GET /services/:kind |
getServiceRegistry(kind) |
GET /services/:kind/registry |
WebSocket stream
// Open a stream (optionally filtered)
const ws = client.openStream({ prefix: "hob/", entityId: "hob-1" });
// Wait for a matching event
const event = await client.waitForStreamEvent(
ws,
(e) => e.event === "heartbeat",
5_000, // timeout ms
);
ws.close();
The ws package is used instead of the native WebSocket API so that the
session cookie can be forwarded on the HTTP upgrade request.
HobDriver
src/hob-driver.js — high-level per-hob wrapper.
import { HobDriver } from "./src/hob-driver.js";
const driver = new HobDriver(client, "hob-1");
Reading state
const state = await driver.getState();
// → raw atom JSON from /atoms/hob/hob-1
const ids = await HobDriver.listHobs(client);
// → ['hob-1', 'hob-2', ...]
Observing the stream
// Open an entity-filtered WebSocket
const ws = driver.openStream();
// Step clock + wait for any event (returns event or null on timeout)
const event = await driver.stepAndObserve(3_000);
Phase II movement (stubs)
The following methods are planned for implementation once world-runner exposes hob input patch endpoints:
walkToNode(nodeId)walkAlongSegment(segmentId)setStance(stance)—'idle'|'walking'|'stationary_watch'awaitLocation(predicate, timeoutMs)