Sandbox
Run a snippet of operator-supplied JavaScript away from the process that is serving requests. The snippet goes to a worker thread with a context built from a named allow-list, so it reaches JSON, Math and the other pure builtins and reaches no filesystem, no network, no process and no require.
A worker rather than node:vm in this thread, because vm shares the event loop and the heap: a snippet that loops forever stalls the server, and one that allocates without stopping takes the server's memory with it. A worker is killed on either, and only its own budget is spent.
Both budgets are on by default and capped: time at 250 ms up to a ceiling of 10 s, and memory at 64 MiB between 4 MiB and 1 GiB. An operator raises them within the ceilings and cannot turn them off.
The snippet's value comes back through JSON, so what crosses the boundary is data. A function or a live object does not survive it.
b.sandbox.run(opts) #
{
source: string, // the JavaScript to evaluate; required
input: any, // data the snippet reads, carried as JSON
allowed: string[], // builtins to add, from KNOWN_SAFE_BUILTINS
timeoutMs: number, // default 250, cap 10000
maxBytes: number, // default 67108864, between 4194304 and 1073741824
}
Evaluate source on a worker and resolve with { result, runtimeMs, peakBytes }. source is the body of a function taking one parameter named input, so it returns its answer; a body that returns nothing answers undefined. result comes back as JSON, so a function or a live object does not survive the trip.
input is the data the snippet reads, carried the same way. allowed names the builtins to put in its context beyond the ones that are always there, and a name outside b.sandbox.KNOWN_SAFE_BUILTINS is refused rather than added, so the list cannot be widened into a way out.
timeoutMs defaults to 250 and cannot exceed 10000. maxBytes defaults to 64 MiB and must fall between 4 MiB and 1 GiB. Passing either above its cap throws rather than being clamped, so a budget an operator writes is the budget that runs or no run happens.
var b = require("@blamejs/core");
var out = await b.sandbox.run({
source: "return input.items.filter(function (n) { return n > 2; });",
input: { items: [1, 2, 3, 4] },
allowed: ["Math"],
});
out.result; // → [3, 4]