Denox (denox v0.7.0)

Copy Markdown View Source

Denox embeds a TypeScript/JavaScript runtime (Deno/V8) into Elixir via a Rustler NIF.

Telemetry Events

Denox emits the following telemetry events:

  • [:denox, :eval, :start] — emitted before evaluating code

    • Measurements: %{system_time: integer}
    • Metadata: %{type: atom} — type is the function name atom (e.g. :eval, :eval_ts, :eval_async, :eval_ts_async, :eval_module, :eval_file, :eval_file_async, :call, :call_async, :eval_async_decode, :eval_ts_async_decode, :eval_file_async_decode, :call_async_decode) Note: sync *_decode variants (:eval_decode, :call_decode, etc.) emit the base type (:eval, :call, etc.) since they delegate to the base function.
  • [:denox, :eval, :stop] — emitted after successful evaluation

    • Measurements: %{duration: integer} (native time units)
    • Metadata: %{type: atom}
  • [:denox, :eval, :exception] — emitted on evaluation error

    • Measurements: %{duration: integer}
    • Metadata: %{type: atom, kind: :error, reason: term}

Summary

Functions

Await the result of an async evaluation task.

Call a named JavaScript function with arguments.

Call a named async JavaScript function with arguments, returning a Task.

Call a named async JavaScript function and decode the JSON result.

Call a named JavaScript function and decode the JSON result.

Create a V8 snapshot from setup code.

Evaluate JavaScript code in the given runtime.

Evaluate JavaScript code as an ES module, returning a Task.

Evaluate JavaScript code asynchronously and decode the JSON result.

Evaluate JavaScript code and decode the JSON result to Elixir terms.

Read and evaluate a JavaScript or TypeScript file.

Read and evaluate a JavaScript or TypeScript file asynchronously.

Read and evaluate a JavaScript or TypeScript file asynchronously and decode the JSON result.

Read and evaluate a JavaScript or TypeScript file and decode the JSON result.

Load and evaluate an ES module file. Supports .ts/.js with import/export.

Evaluate TypeScript code in the given runtime. Transpiles via deno_ast/swc then evaluates. No type-checking.

Evaluate TypeScript code as an ES module, returning a Task.

Evaluate TypeScript code asynchronously and decode the JSON result.

Evaluate TypeScript code and decode the JSON result to Elixir terms.

Execute JavaScript code, ignoring the return value.

Execute TypeScript code, ignoring the return value.

Create a new JavaScript runtime.

Types

runtime()

@type runtime() :: reference()

Functions

await(task, timeout \\ 5000)

Await the result of an async evaluation task.

Delegates to Task.await/2. Use with tasks returned by eval_async/2, eval_ts_async/2, call_async/3, and call_async_decode/3.

Example

Denox.eval_async(rt, "export default await Promise.resolve(42)")
|> Denox.await()
#=> {:ok, "42"}

call(rt, func_name, args \\ [])

@spec call(runtime(), String.t(), list()) :: {:ok, String.t()} | {:error, String.t()}

Call a named JavaScript function with arguments.

Arguments are serialized to JSON. Returns {:ok, json_string} or {:error, message}.

call_async(rt, func_name, args \\ [])

@spec call_async(runtime(), String.t(), list()) :: Task.t()

Call a named async JavaScript function with arguments, returning a Task.

Use Task.await/2 to get the result.

Returns a Task that resolves to {:ok, json_string} or {:error, message}.

call_async_decode(rt, func_name, args \\ [])

@spec call_async_decode(runtime(), String.t(), list()) :: Task.t()

Call a named async JavaScript function and decode the JSON result.

Returns a Task that resolves to {:ok, term()} or {:error, term()}.

call_decode(rt, func_name, args \\ [])

@spec call_decode(runtime(), String.t(), list()) :: {:ok, term()} | {:error, term()}

Call a named JavaScript function and decode the JSON result.

create_snapshot(setup_code, opts \\ [])

@spec create_snapshot(
  String.t(),
  keyword()
) :: {:ok, binary()} | {:error, String.t()}

Create a V8 snapshot from setup code.

The snapshot captures all global state (variables, functions, etc.) after executing the setup code.

Snapshot compatibility

Custom V8 snapshots created by create_snapshot/2 are not compatible with the deno_runtime MainWorker backend currently used by Denox.runtime/1. Passing a snapshot via runtime(snapshot: bytes) will emit a warning and the snapshot will be ignored. Use Denox.eval/3 or Denox.exec/3 to run initialization code instead.

Options:

  • :transpile - if true, transpile TypeScript before executing (default: false)

Returns {:ok, snapshot_bytes} or {:error, message}.

eval(rt, code)

@spec eval(runtime(), String.t()) :: {:ok, String.t()} | {:error, String.t()}

Evaluate JavaScript code in the given runtime.

Pumps the event loop and resolves Promises automatically. Supports import(), setTimeout, and other async operations.

Returns {:ok, json_string} or {:error, message}.

eval_async(rt, code)

@spec eval_async(runtime(), String.t()) :: Task.t()

Evaluate JavaScript code as an ES module, returning a Task.

The code is evaluated as a proper ES module, so static import/export declarations and top-level await work natively. Use export default to return a value.

Returns a Task that resolves to {:ok, json_string} or {:error, message}.

Example

task = Denox.eval_async(rt, "const status = (await fetch('https://httpbin.org/get')).status; export default status;")
{:ok, "200"} = Task.await(task)

# Static imports work:
task = Denox.eval_async(rt, """
  import { something } from './my_module.js';
  export default something;
""")

eval_async_decode(rt, code)

@spec eval_async_decode(runtime(), String.t()) :: Task.t()

Evaluate JavaScript code asynchronously and decode the JSON result.

Returns a Task that resolves to {:ok, term()} or {:error, term()}.

eval_decode(rt, code)

@spec eval_decode(runtime(), String.t()) :: {:ok, term()} | {:error, term()}

Evaluate JavaScript code and decode the JSON result to Elixir terms.

eval_file(rt, path, opts \\ [])

@spec eval_file(runtime(), String.t(), keyword()) ::
  {:ok, String.t()} | {:error, String.t()}

Read and evaluate a JavaScript or TypeScript file.

Simpler than eval_module/2 — no import/export support, just script execution. TypeScript files (.ts, .tsx) are automatically transpiled.

Returns {:ok, json_string} or {:error, message}.

eval_file_async(rt, path, opts \\ [])

@spec eval_file_async(runtime(), String.t(), keyword()) :: Task.t()

Read and evaluate a JavaScript or TypeScript file asynchronously.

Returns a Task that resolves to {:ok, json_string} or {:error, message}.

eval_file_async_decode(rt, path, opts \\ [])

@spec eval_file_async_decode(runtime(), String.t(), keyword()) :: Task.t()

Read and evaluate a JavaScript or TypeScript file asynchronously and decode the JSON result.

Returns a Task that resolves to {:ok, term()} or {:error, term()}.

eval_file_decode(rt, path, opts \\ [])

@spec eval_file_decode(runtime(), String.t(), keyword()) ::
  {:ok, term()} | {:error, term()}

Read and evaluate a JavaScript or TypeScript file and decode the JSON result.

Returns {:ok, term()} or {:error, term()}.

eval_module(rt, path)

@spec eval_module(runtime(), String.t()) :: {:ok, String.t()} | {:error, String.t()}

Load and evaluate an ES module file. Supports .ts/.js with import/export.

Returns {:ok, "undefined"} or {:error, message}.

eval_ts(rt, code)

@spec eval_ts(runtime(), String.t()) :: {:ok, String.t()} | {:error, String.t()}

Evaluate TypeScript code in the given runtime. Transpiles via deno_ast/swc then evaluates. No type-checking.

Pumps the event loop and resolves Promises automatically.

Returns {:ok, json_string} or {:error, message}.

eval_ts_async(rt, code)

@spec eval_ts_async(runtime(), String.t()) :: Task.t()

Evaluate TypeScript code as an ES module, returning a Task.

Supports static import/export declarations and top-level await. Use export default to return a value.

Returns a Task that resolves to {:ok, json_string} or {:error, message}.

eval_ts_async_decode(rt, code)

@spec eval_ts_async_decode(runtime(), String.t()) :: Task.t()

Evaluate TypeScript code asynchronously and decode the JSON result.

Returns a Task that resolves to {:ok, term()} or {:error, term()}.

eval_ts_decode(rt, code)

@spec eval_ts_decode(runtime(), String.t()) :: {:ok, term()} | {:error, term()}

Evaluate TypeScript code and decode the JSON result to Elixir terms.

exec(rt, code)

@spec exec(runtime(), String.t()) :: :ok | {:error, String.t()}

Execute JavaScript code, ignoring the return value.

Returns :ok or {:error, message}.

exec_ts(rt, code)

@spec exec_ts(runtime(), String.t()) :: :ok | {:error, String.t()}

Execute TypeScript code, ignoring the return value.

Returns :ok or {:error, message}.

runtime(opts \\ [])

@spec runtime(keyword()) :: {:ok, runtime()} | {:error, String.t()}

Create a new JavaScript runtime.

Options:

  • :base_dir - base directory for resolving relative module imports
  • :sandbox - (deprecated) if true, deny all permissions. Use :permissions instead
  • :permissions - permission mode:
    • :all — allow everything (default)
    • :none — deny everything (same as sandbox: true)
    • keyword list — granular permissions. Supports both allow_* and deny_* keys. E.g. [allow_net: true, allow_read: ["/tmp"], deny_env: true]. Values can be true (blanket) or a list of strings (specific paths/hosts). false entries are ignored. Unknown keys raise ArgumentError.
  • :cache_dir - on-disk cache directory for remote module fetches
  • :import_map - map of bare specifiers to resolved URLs/paths (e.g. %{"lodash" => "https://esm.sh/lodash"})
  • :callback_pid - PID of the process that handles JS→Elixir callbacks (enables Denox.callback() in JS)
  • :snapshot - V8 snapshot binary for faster cold start (created via create_snapshot/2)

Returns {:ok, runtime} or {:error, message}.