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

GenServer-based pool of JavaScript runtimes for concurrent workloads.

V8 isolates are single-threaded, so the pool round-robins requests
across N runtimes to achieve parallelism.

## Usage

    # In your supervision tree
    children = [
      {Denox.Pool, name: :js_pool, size: 4, permissions: :all}
    ]

    # Then use the pool
    {:ok, result} = Denox.Pool.eval(:js_pool, "1 + 2")
    {:ok, result} = Denox.Pool.eval_ts(:js_pool, "const x: number = 42; x")

## Pre-loading shared code

Use `load_npm/2` to load a bundled JS file into all pool runtimes at once.
This is the recommended way to share npm packages across a pool:

    Denox.Npm.bundle!("npm:zod@3.22", "priv/bundles/zod.js")
    :ok = Denox.Pool.load_npm(:js_pool, "priv/bundles/zod.js")

Or use `exec/2` to initialise shared globals:

    :ok = Denox.Pool.exec(:js_pool, "globalThis.helper = (x) => x * 2")

Note that each runtime in the pool has independent state, so mutations made
via `exec/2` are distributed round-robin and may not reach all runtimes.
Use `load_npm/2` (which broadcasts to all runtimes) for shared initialisation.

# `pool`

```elixir
@type pool() :: GenServer.server()
```

# `call`

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

Call a named JavaScript function with arguments.

# `call_async`

```elixir
@spec call_async(pool(), String.t(), list()) :: Task.t()
```

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

# `call_async_decode`

```elixir
@spec call_async_decode(pool(), String.t(), list()) :: Task.t()
```

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

# `call_decode`

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

Call a named JavaScript function and decode the JSON result.

# `child_spec`

```elixir
@spec child_spec(keyword()) :: Supervisor.child_spec()
```

Returns a child specification for the pool, using the `:name` option as the child id.

This allows multiple pools to coexist in the same supervisor without id conflicts.

# `eval`

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

Evaluate JavaScript code using the next runtime in the pool.

# `eval_async`

```elixir
@spec eval_async(pool(), String.t()) :: Task.t()
```

Evaluate JavaScript code asynchronously, returning a Task.

# `eval_async_decode`

```elixir
@spec eval_async_decode(pool(), String.t()) :: Task.t()
```

Evaluate JavaScript asynchronously and decode JSON result, returning a Task.

# `eval_decode`

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

Evaluate and decode JSON result.

# `eval_file`

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

Read and evaluate a JavaScript or TypeScript file.

# `eval_file_async`

```elixir
@spec eval_file_async(pool(), String.t(), keyword()) :: Task.t()
```

Read and evaluate a JavaScript or TypeScript file asynchronously, returning a Task.

# `eval_file_async_decode`

```elixir
@spec eval_file_async_decode(pool(), String.t(), keyword()) :: Task.t()
```

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

# `eval_file_decode`

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

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

# `eval_module`

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

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

# `eval_ts`

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

Evaluate TypeScript code using the next runtime in the pool.

# `eval_ts_async`

```elixir
@spec eval_ts_async(pool(), String.t()) :: Task.t()
```

Evaluate TypeScript code asynchronously, returning a Task.

# `eval_ts_async_decode`

```elixir
@spec eval_ts_async_decode(pool(), String.t()) :: Task.t()
```

Evaluate TypeScript asynchronously and decode JSON result, returning a Task.

# `eval_ts_decode`

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

Evaluate TypeScript and decode JSON result.

# `exec`

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

Execute JavaScript code, ignoring the return value.

Returns `:ok` on success. Returns `{:error, message}` if the JavaScript
throws or if evaluation fails — callers must still handle the error.

# `exec_ts`

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

Execute TypeScript code, ignoring the return value.

Returns `:ok` on success. Returns `{:error, message}` if the code
throws or if evaluation fails — callers must still handle the error.

# `load_npm`

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

Load a bundled JS file into all runtimes in the pool.

# `size`

```elixir
@spec size(pool()) :: non_neg_integer()
```

Return the pool size.

# `start_link`

```elixir
@spec start_link(keyword()) :: GenServer.on_start()
```

Start a pool of runtimes.

Options:
  - `:name` - registered name for the pool (required)
  - `:size` - number of runtimes (default: `System.schedulers_online()`)
  - `:permissions` - permission mode for all runtimes (`:all`, `:none`, or keyword list)
  - `:sandbox` - (deprecated) use `permissions: :none` instead
  - `:base_dir` - base directory for module resolution
  - `:cache_dir` - cache directory for remote modules
  - `:import_map` - map of bare specifiers to resolved URLs/paths
  - `:callback_pid` - PID that handles JS→Elixir callbacks
  - `:snapshot` - V8 snapshot binary for faster cold start (applied to all runtimes)

---

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