Skip to main content

CHANGELOG.md

# Changelog

## v0.3.0 (2026-05-23)

### Added

- New `:startup_timeout` option for `Tyrex.start/1` and `Tyrex.start_link/1`
  (defaults to 30s); the GenServer init callback now returns
  `{:stop, :nif_startup_timeout}` if the NIF does not acknowledge in time.
- New `examples/error_handling.exs` demonstrating pattern-matching on
  `Tyrex.Error` (`:execution_error`, `:promise_rejection`,
  `:conversion_error`, `:dead_runtime_error`) and on `Tyrex.eval!` raising.
- New `examples/least_loaded.exs` implementing the LeastLoaded custom
  `Tyrex.Pool.Strategy` from the README as a real runnable script.
- New `examples/ink_tui/` example demonstrating terminal UI rendering.
- Documented the `deny_import` permission key (always supported by the Rust
  side; previously missing from Elixir docs and the README permission table).

### Changed

- `Tyrex.eval!/1,2` and `Tyrex.Pool.eval!/2,3` now raise `Tyrex.Error` on
  failure instead of crashing with `MatchError`.
- `Tyrex.Pool.Strategy.RoundRobin`'s first selection now returns index `0`
  (previously `1`). The counter is now seeded at `size - 1` so the first
  `update_counter/3` wraps to `0`.
- `Tyrex.Pool` is now supervised as `:rest_for_one` with a dedicated internal
  registry GenServer that owns the `:persistent_term` entry and the strategy
  state so they get cleaned up on supervisor shutdown.
- Tightened the `mix.exs` package description.

### Fixed

- ~16 panic sites in the Rust NIF and Deno worker event loop (BEAM crash
  risk) replaced with proper error propagation or best-effort logging.
- Pending promises now receive a `:dead_runtime_error` reply when the
  worker shuts down — callers no longer hang on `Tyrex.stop/1`.
- `Tyrex.Pool` now erases its `:persistent_term` entry and invokes the
  strategy's `terminate/1` callback (cleaning up ETS tables for
  `RoundRobin`) on supervisor shutdown, so create/destroy cycles no
  longer leak VM state.
- Recover from mutex poisoning in the Rust runtime registry rather than
  panicking on `lock().unwrap()`.
- The Rust→JS apply-reply path now dispatches via a JS bridge function
  (`Tyrex._applyReply`) instead of `format!`-interpolating
  attacker-influenceable values into a `Tyrex._applications[...].fn(...)`
  expression.
- The `~JS` sigil now raises a `CompileError` for unknown modifiers
  (previously silently ignored).
- The `Tyrex` GenServer now has a configurable startup timeout (default 30s)
  instead of hanging forever on the inner `receive`.
- `[allow_all: true, deny_X: true]` now actually honors the deny overrides —
  the Rust permission parser used to short-circuit to `allow_all` and ignore
  any sibling `deny_*` keys, contradicting the README's documented pattern.
- Removed false "TypeScript main module" claim from the README and dropped
  the (broken) `examples/typescript/`. The default `FsModuleLoader` does not
  transpile `.ts` files; first-class TypeScript module loading is tracked
  for a future release. JavaScript (`.js`) main modules continue to work.

## v0.2.1 (2026-03-15)

### Fixed

- Fixed precompiled NIF archive packaging — files inside tar.gz are now named
  to match RustlerPrecompiled convention (`libtyrex-v{version}-nif-2.16-{target}.so`)
- Fixed CI: V8 source builds now work on all targets (tolerate bindgen failure,
  use pre-generated bindings from rusty_v8 releases)
- Replaced `philss/rustler-precompiled-action` with manual cargo build + tar
  (action installed cross even with `use-cross: false`)
- Fixed macOS runner: `macos-13` deprecated, switched to `macos-15`
- Fixed LLVM 19 → 20 in docker-build.sh Phase 2

### Changed

- NIF version 2.15 → 2.16 (requires OTP 27+)
- Removed Windows (`x86_64-pc-windows-msvc`) target (not building it)
- Upgraded Deno embedded runtime to v2.7.5 (see v0.2.0 for Deno changelog)

### Deno 2.7.5 highlights

- `deno compile` improvements with npm/jsr package support
- `deno init --npm vite` scaffolding
- `deno task` supports `dependencies` field for task ordering
- `Temporal` API support (behind `--unstable-temporal`)
- Node.js compatibility improvements (http2, worker_threads, async_hooks)
- V8 engine upgraded to 14.6

## v0.2.0 (2026-03-11)

### Changed

- Upgraded embedded Deno runtime to v2.7.5
  - deno_core 0.330.0 → 0.391.0
  - deno_runtime 0.194.0 → 0.246.0
  - deno_fs 0.96.0 → 0.148.0
  - deno_resolver 0.17.0 → 0.69.0
  - serde_v8 0.239.0 → 0.300.0
  - sys_traits 0.1.7 → 0.1.24
- Relaxed serde version pin

## v0.1.0 (2026-03-08)

Initial release.

### Features

- **Embedded Deno runtime** — Full Deno JS/TS runtime embedded in Elixir via Rustler NIFs
- **JavaScript & TypeScript evaluation**`Tyrex.eval/1,2` with automatic promise awaiting
- **Blocking & async modes** — Choose NIF-blocking (fast, <1ms) or async eval
- **Bidirectional calls** — Call Elixir functions from JavaScript via `Tyrex.apply()`
- **Module loading** — Import ES modules with `import`/`export`, load main modules at startup
- **`~JS` sigil** — Write JavaScript inline in Elixir code with `Tyrex.Sigil`
- **`Tyrex.Inline`** — Process-local runtime binding with `set_runtime/1` and `with_runtime/2`
- **Granular permissions** — Control network, filesystem, env, subprocess, FFI, and system access per runtime
- **Runtime pool**`Tyrex.Pool` supervisor with pluggable dispatch strategies:
  - `RoundRobin` (default) — Lock-free ETS atomic counter
  - `Random` — Random runtime selection
  - `Hash` — Key-based sticky sessions
- **Named runtimes** — Add Tyrex to supervision trees with `start_link/1`
- **Deno APIs**`fetch`, `Deno.readTextFile`, `setTimeout`, Node.js compatibility, and more

### Precompiled binaries

- `aarch64-apple-darwin`
- `aarch64-unknown-linux-gnu`
- `x86_64-apple-darwin`
- `x86_64-pc-windows-msvc`
- `x86_64-unknown-linux-gnu`