# `Denox`
[🔗](https://github.com/gsmlg-dev/denox/blob/v0.9.0/lib/denox.ex#L1)

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}`

# `runtime`

```elixir
@type runtime() :: reference()
```

# `await`

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`

```elixir
@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`

```elixir
@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`

```elixir
@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`

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

Call a named JavaScript function and decode the JSON result.

# `create_snapshot`

```elixir
@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 {: .warning}
>
> 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`

```elixir
@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`

```elixir
@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`

```elixir
@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`

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

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

# `eval_file`

```elixir
@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`

```elixir
@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`

```elixir
@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`

```elixir
@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`

```elixir
@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`

```elixir
@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`

```elixir
@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`

```elixir
@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`

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

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

# `exec`

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

Execute JavaScript code, ignoring the return value.

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

# `exec_ts`

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

Execute TypeScript code, ignoring the return value.

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

# `runtime`

```elixir
@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}`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
