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
| Method | Description |
|---|---|
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:
| Field | Type | Description |
|---|---|---|
name | string | The process's name. |
alive | boolean | Whether it's running. |
pid | number? | braid's wrapper process for it. Absent before its first start. |
appPid | number? | The app itself, while it's running. |
startedAt | string? | ISO time it was started. |
cpu | number? | Percent of one core, across the app's process tree. |
memory | number? | Bytes, across the app's process tree. |
restartCount | number | Restarts since the stack started. |
url | string? | The process's configured url. |
Lifecycle events
| Event | Payload | Fires 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. |
daemonShutdown | none | Shutdown has begun; processes are about to stop. |
daemonStopped | none | Every 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.
| Route | Description |
|---|---|
GET /api/status | The status entries, as JSON. |
GET /api/logs | Output. Query: name, lines, follow=true, json=true. |
GET /api/logs/history | Older output, a page at a time. Query: name, lines, before (a cursor from the previous page), json=true. |
POST /api/processes/start | Start a process. Query: name. |
POST /api/processes/stop | Stop a process. Query: name. |
POST /api/processes/restart | Restart a process. Query: name. |
POST /api/shutdown | Stop the stack. |
POST /api/ws-ticket | A 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
Hostthat isn't a loopback name, which blocks DNS rebinding (port forwards still work); - a
POSTor upgrade whoseOriginisn'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.