api
The ZeroJS public API: zerojs.new/eval, VM run/get/set, sentinels, and version. The package root init.luau re-exports this module.
api
The ZeroJS public API: zerojs.new/eval, VM run/get/set, sentinels, and version. The package root init.luau re-exports this module.
Interface
What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.
conforms to
zero/source-extract/v2strict
resetLoop(loop: any) → void
Reset the loop to a clean state at a run boundary: drop every armed timer and forget any recorded unhandled rejections. A run reports only the rejections it itself produced, and a rejection reported once is consumed — so the next run starts from an empty loop rather than inheriting the prior run's stale state. This is the cleanup both vm:run and vm:runAsync apply when a run starts and when it finishes (settle, refusal, or error).
| arg | type | description |
|---|---|---|
| loop | any |
renderError(rt: any, jsErr: any) → void
Render a thrown JS Error value into the message text `vm:run` raises. The first line is the tagged "<Name>: <message>"; the remaining lines are the captured stack frames read from the error's own "stack" property.
| arg | type | description |
|---|---|---|
| rt | any | |
| jsErr | any |
renderUnhandled(rt: any, loop: any) → void
Render the earliest still-unhandled rejection on `loop` into the message and structured payload `vm:run`/`vm:runAsync` surface, or nil when none remains. The policy is first-wins: the head of the list is the earliest rejection a handler never claimed.
| arg | type | description |
|---|---|---|
| rt | any | |
| loop | any |
recordBail(sourceName: string, reason: string) → void
| arg | type | description |
|---|---|---|
| sourceName | string | |
| reason | string |
compiledChunk(self: Vm, src: string, sourceName: string) → void
Resolve a source string to a compiled-tier chunk per the VM's engine mode. Returns the runnable chunk, or nil when this run must use the interpreter: "interp" always, or "auto" when compilation bailed (recorded loudly; a plain syntax error is not a bail — the interpreter raises the same error). In strict "compiled" mode a failed compile raises.
| arg | type | description |
|---|---|---|
| self | Vm | |
| src | string | |
| sourceName | string |
runCompiled(self: Vm, chunk: (any) → void
Execute a compiled chunk against the VM's realm, global object, and the interpreter's global env cells (the same value model and the same script scope, so state persists across runs and mixes freely between tiers). Returns interpreter-shaped (ok, jsValueOrError). A raw Luau error inside compiled code is an engine defect, not a JS throw, and re-raises — except native stack exhaustion, which surfaces as the JS RangeError it is.
| arg | type | description |
|---|---|---|
| self | Vm | |
| chunk | (any |
currentStack( ) → void
Error stacks constructed during this run carry the run's source name. Compiled frames carry no per-call bookkeeping, so the stack is a single synthetic frame naming the compiled source.
run(self: Vm, src: string, opts: { sourceName: string? }?) → any
| arg | type | description |
|---|---|---|
| self | Vm | |
| src | string | |
| opts | { sourceName: string? }? |
eval(self: Vm, src: string, opts: { sourceName: string? }?) → any
Evaluate `src` against the live loop without disturbing scheduled work: armed timers stay armed and recorded unhandled rejections stay recorded. This is the inspection path for a VM that is mid-flight — a console command against a running app session — where `vm:run`'s run-boundary reset would silently kill the app's pending timers. The script itself must complete synchronously: a script that parks its own coroutine raises (with the loop untouched). Work the script schedules onto the loop (timers, promise chains) is left in place for the session's own pump to drive.
| arg | type | description |
|---|---|---|
| self | Vm | |
| src | string | |
| opts | { sourceName: string? }? |
runAsync(self: Vm, src: string, opts: { timeoutMs: number? }?) → RunHandle
Execute `src` like `vm:run` but, instead of refusing a script that leaves asynchronous work pending, drive it to completion by pumping the VM loop once per engine frame. Returns a handle whose `task.spawn` driver runs `loop:runDueTimers(rt.nowMs())` then `loop:drainMicrotasks()` each frame and settles the handle when the script's completion value has settled (awaiting it when it is a promise) and no loop work remains, or when an uncaught error or unhandled rejection surfaces, or when `opts.timeoutMs` elapses. On timeout or error the handle rejects with the rendered message (a timeout message contains "timeout"); the pump then stops and cancels any armed timers so the loop is left clean for the next run. The handle is awaitable from a yieldable Luau context via `handle:await()`, which polls `handle.done` frame-by-frame without busy-waiting. Only one runAsync may be in flight on a given VM at a time. A second call while the first has not yet settled raises immediately with a message containing "already in flight" and "runAsync". Sequential calls — each after the previous handle has settled — are supported and keep working.
| arg | type | description |
|---|---|---|
| self | Vm | |
| src | string | |
| opts | { timeoutMs: number? }? |
awaitHandle(selfHandle: RunHandle, maxFrames: number?) → RunHandle
Yield the calling (yieldable) context frame-by-frame until this handle settles, then return it. Polling `done` across `task.wait()` frames lets the driver's own per-frame pump make progress between checks.
| arg | type | description |
|---|---|---|
| selfHandle | RunHandle | |
| maxFrames | number? |
finish(ok: boolean, value: any, errText: string?, payload: LastError?) → void
Resolve/reject the handle exactly once, then leave the loop clean: any timer still armed (an interval mid-flight on timeout, a pending one-shot) is cleared and the unhandled-rejection list is forgotten so no orphaned callback runs after settlement, a reported rejection is consumed, and a following run on this VM starts from an empty loop.
| arg | type | description |
|---|---|---|
| ok | boolean | |
| value | any | |
| errText | string? | |
| payload | LastError? |
currentStack( ) → void
considerCompletion( ) → void
pump( ) → void
evalModule(self: Vm, source: string, opts: { id: string, resolve: (string, string) → void
Evaluate a module graph rooted at `source` under `opts.id`, resolving each import through `opts.resolve(specifier, importerId)` (which returns `{ id, source }` or nil for an unresolvable specifier). Returns the root module's namespace object: a frozen-lite object keyed by the module's exported names, with export values snapshotted at completion. The per-VM registry keys evaluated modules by id, so a repeated id returns the cached namespace without re-running the body, and a module that threw re-raises its cached error. A thrown JS error (cycle, unresolved specifier, submodule parse failure, or a module body throw) surfaces the rendered message and structured `lastError`, mirroring `vm:run`. evalModule is synchronous: a graph that leaves timers or a suspended coroutine pending is refused, since top-level `await` is a SyntaxError in module mode and cannot legitimately suspend a body.
| arg | type | description |
|---|---|---|
| self | Vm | |
| source | string | |
| opts | { id: string, resolve: (string, string |
get(self: Vm, name: string) → any
| arg | type | description |
|---|---|---|
| self | Vm | |
| name | string |
set(self: Vm, name: string, v: any) → void
| arg | type | description |
|---|---|---|
| self | Vm | |
| name | string | |
| v | any |
new(opts: { stepBudget: number?, env: { [string]: any }?, engine: string? }?) → Vm
Build a fresh VM: a realm, its installed global object, and a global env bound to that object. `opts.env` seeds marshaled host values as globals; `opts.stepBudget` bounds each run.
| arg | type | description |
|---|---|---|
| opts | { stepBudget: number?, env: { [string]: any }?, engine: string? }? |
eval(src: string) → any
Run one source string on a fresh VM and return its marshaled completion.
| arg | type | description |
|---|---|---|
| src | string |
lastError(vm: Vm) → LastError
The structured payload of the most recent JS error a run raised on `vm`, or nil if the last run completed normally.
| arg | type | description |
|---|---|---|
| vm | Vm |
LastError = {RunHandle = {Vm = {Sub-parts
Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.
Problems
Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.
agent_score is exposed.+ quality × 0.35
+ performance × 0.25
± compat factor
Usability ratings
Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".
Scoped to this part · feeds back into the world's score.