ExZapcode.Sandbox (ExZapcode v0.1.1)

Copy Markdown View Source

High-level driver for interactive TypeScript execution — the ExMonty.Sandbox analog for zapcode.

Automates the start/resume loop: each external function the guest awaits is dispatched to a handler in the :functions map, and the run is resumed with the result until it completes. The return contract matches ExMonty.Sandbox.run/2 so the two are drop-in siblings:

{:ok, value, output} | {:error, %ExZapcode.Exception{}}

Example

{:ok, 1, ""} =
  ExZapcode.Sandbox.run(
    """
    const r = await execute_sql({ statement: "SELECT 1 as val" });
    r.rows[0].val
    """,
    functions: %{
      "execute_sql" => fn [args] -> {:ok, %{"rows" => [%{"val" => 1}]}} end
    }
  )

Handlers

A handler is fn args -> result (or fn args, kwargs -> result for ExMonty parity — kwargs is always %{} since TypeScript calls are positional). By TS convention a tool is called with a single options object, so args is typically [opts_map].

Return {:ok, value} or {:error, type, message}.

Fidelity gap vs Monty

zapcode-core's resume only accepts a return value — there is no way to inject a throwable error into the guest. So a handler {:error, ...} aborts the whole run and is returned to the caller, rather than raising a catchable exception inside the TypeScript (which Monty supports).

Summary

Functions

Compiles and runs TypeScript code with automatic handler dispatch.

Types

handler_result()

@type handler_result() :: {:ok, term()} | {:error, atom(), String.t()}

Functions

run(code, opts \\ [])

@spec run(
  String.t(),
  keyword()
) :: {:ok, term(), String.t()} | {:error, ExZapcode.Exception.t()}

Compiles and runs TypeScript code with automatic handler dispatch.

Options

  • :inputs — map of name => value bound as globals (default: %{})
  • :functions — map of function-name strings to handler funs (default: %{})
  • :limits — resource limits map (merged over ExZapcode.default_limits/0)
  • :script_name — accepted for ExMonty parity; currently unused

Examples

# Pure expression — no tools
{:ok, 6, ""} = ExZapcode.Sandbox.run("[1, 2, 3].reduce((a, b) => a + b, 0)")

# With a tool the guest awaits
{:ok, 2, ""} =
  ExZapcode.Sandbox.run(
    ~s(const r = await db({ sql: "SELECT 1" }); r.rows[0].n + 1),
    functions: %{"db" => fn [%{"sql" => _}] -> {:ok, %{"rows" => [%{"n" => 1}]}} end}
  )

# A handler error aborts the run
{:error, %ExZapcode.Exception{type: :runtime_error}} =
  ExZapcode.Sandbox.run("await boom()",
    functions: %{"boom" => fn _ -> {:error, :runtime_error, "kaboom"} end})