Dev
Dev-mode helpers — hot-reload signal (file watch + child-process restart), route-list dump exposed via dev.stats(), and a request inspector courtesy of stdio: 'inherit' so the operator sees the spawned app's logs unchanged.
The hot-reload loop spawns the app as a child process, watches the source directories with fs.watch({ recursive: true }), and restarts the child when an unignored file changes. On-disk state (vault keys, encrypted DB, sealed cookies) survives the restart because the child re-opens the files; only in-process state is lost, which is the correct semantic for "I just edited a route handler and want to see it."
Hygiene baked in: - Bursts of file events (save-everything keystrokes, multi-file format-on-save) collapse into one restart via the graceMs debounce (default 250 ms). - A restart-in-flight queues at most one follow-up — many edits during a slow restart yield two restarts, not N. - Ignored kinds by default: node_modules/, .git/, dotfiles, SQLite journal/WAL/SHM siblings, .log, editor scratch files (.swp, ~$). - Crash without a pending stop/restart leaves the child corpse in place and waits for a file change rather than spawn-thrashing. - Graceful kill via SIGTERM; SIGKILL escalation after killTimeoutMs (default 4000 ms) if the child ignores it.
Production refusal: dev.create() throws dev/refused-in-production when NODE_ENV=production, unless the operator explicitly sets opts.allowProduction: true with an audited reason. This is what blamejs dev (CLI) calls; production deployments that accidentally wire it crash loudly at boot rather than spawning shells on every save.
Test seams: opts._spawn(cmd, args, sopts) and opts._watch(dir, wopts, listener) default to child_process.spawn and fs.watch; unit tests pass fakes to drive the engine without real subprocesses.
b.dev.create(opts) #
{
command: string, // required — program to spawn (e.g. "node")
args: [string], // argv after command; default []
watch: [string], // directories to watch (recursive); default ["."]
ignore: [RegExp | string], // appended to the framework default-ignore list
graceMs: number, // debounce window (ms); default 250
killSignal: string, // initial kill signal; default "SIGTERM"
killTimeoutMs: number, // SIGKILL escalation budget (ms); default 4000
log: object, // structured logger ({ info, warn, error })
env: object, // child env; default process.env
cwd: string, // child cwd; default process.cwd()
stdio: string | array, // child stdio; default "inherit"
allowProduction: boolean, // override the production refusal (audited reason required)
}
Build a hot-reload supervisor — spawn opts.command with opts.args, watch opts.watch directories, and restart the child on every unignored file change. Returns { start, stop, restart, stats }; stats() reports { pid, running, restarts, lastRestartAt, watchers }.
Throws DevError at config time on a missing command, a non-finite graceMs / killTimeoutMs, or an attempt to load with NODE_ENV=production (without opts.allowProduction).
var dev = b.dev.create({
command: "node",
args: ["./server.js"],
watch: ["./routes", "./views", "./lib"],
ignore: [/\.tmp$/],
graceMs: 250,
});
// await dev.start();
// dev.stats(); // → { pid: , running: true, restarts: 0, lastRestartAt: null, watchers: 3 }
// await dev.stop();
Last updated 2026-08-08T16:39:49.652Z by seeder.