Reference

Plugin API

What register(ctx, options) gets, the events it can listen to, and the routes every stack serves. For a walkthrough, see the plugins guide.

BraidPlugin

type BraidPlugin = {
	name: string;
	register(ctx: PluginContext, options?: Record<string, unknown>): void | Promise<void>;
};

PluginContext

MethodDescription
registerRoute(method, path, handler)Add a node:http handler. Token-protected. Throws if the method and path are taken.
registerStatic(prefix, dir)Serve files from dir under prefix, without a token.
registerUpgrade(path, handler)Handle an HTTP upgrade, such as a WebSocket, on an exact path. Token or ticket protected.
on(event, listener)Listen to a lifecycle event.
getProcesses()A status entry for every configured process.
startProcess(name)Start a process that isn't running. Does nothing if it is.
stopProcess(name)Stop one process.
restartProcess(name)Restart one process, running its hooks and dependents as a file change would.
shutdown()Stop the whole stack, as braid stop does. Ignored during register.
log(message)Write a line to the daemon log, tagged with the plugin's name.

The three process methods resolve to "ok", "unknown" (no such process, or for stopProcess, not running) or "busy" (a restart is already in progress).

Process status

Each entry from getProcesses(), and from GET /api/status:

FieldTypeDescription
namestringThe process's name.
alivebooleanWhether it's running.
pidnumber?braid's wrapper process for it. Absent before its first start.
appPidnumber?The app itself, while it's running.
startedAtstring?ISO time it was started.
cpunumber?Percent of one core, across the app's process tree.
memorynumber?Bytes, across the app's process tree.
restartCountnumberRestarts since the stack started.
urlstring?The process's configured url.

Lifecycle events

EventPayloadFires when
controlServerReady{ port, token }Once, when the server is listening and every plugin has registered. The first point the port and token are known.
processStart{ name, pid }A process's wrapper starts: at startup, and on a manual or dependsOn restart.
processRestart{ name }A watch-triggered or autoRestart restart begins.
processOutput{ name, stream, chunk }Output bytes, with braid's [name] prefix. Chunks aren't split on line boundaries.
processExit{ name, code, signal }A process's wrapper exits.
processCrash{ name, code }A process crashed; the stack is about to stop.
daemonShutdownnoneShutdown has begun; processes are about to stop.
daemonStoppednoneEvery process has stopped and its output is delivered. The last event before the server closes.

Built-in routes

Every route needs Authorization: Bearer <token>. The token and port are in .braid/run.json.

RouteDescription
GET /api/statusThe status entries, as JSON.
GET /api/logsOutput. Query: name, lines, follow=true, json=true.
GET /api/logs/historyOlder output, a page at a time. Query: name, lines, before (a cursor from the previous page), json=true.
POST /api/processes/startStart a process. Query: name.
POST /api/processes/stopStop a process. Query: name.
POST /api/processes/restartRestart a process. Query: name.
POST /api/shutdownStop the stack.
POST /api/ws-ticketA single-use WebSocket ticket, valid for 30 seconds.

Security

The control server only listens on 127.0.0.1, and rejects:

  • requests without the token (static files excepted);
  • a Host that isn't a loopback name, which blocks DNS rebinding (port forwards still work);
  • a POST or upgrade whose Origin isn't the page that made it, which blocks other sites and other local ports.

The token is never accepted in a cookie or query string.