Packages

Boa-powered JavaScript runtimes for Elixir with BEAM dispatch hooks.

Current section

Files

Jump to
boam doc dist search_data-4882550B.js
Raw

doc/dist/search_data-4882550B.js

searchData={"items":[{"type":"module","title":"Boam","doc":"High-level entrypoint for running JavaScript through Boa from Elixir.\n\n`Boam` wraps a dedicated Boa runtime behind a `GenServer`. Each runtime owns a\nsingle Rust worker thread because Boa `Context` values are not thread-safe.\n\nJavaScript code can call back into Elixir with `beam.call(name, ...args)`. The\ndispatch itself happens through a separate BEAM process, which keeps the\nruntime process focused on driving the JavaScript engine.\n\nYou can either:\n\n * pass your own dispatcher with `:dispatcher`\n * install JavaScript shims with `:js_expose`\n * register Elixir handlers with `:exports` when Boam manages the dispatcher\n * use legacy combined config with `:expose`\n * run startup JavaScript with `:prelude`\n * generate shim code manually with `Boam.JS.export_prelude/1`","ref":"Boam.html"},{"type":"module","title":"Quick Start - Boam","doc":"```elixir\n{:ok, _dispatcher} =\n MyApp.JsDispatcher.start_link(name: MyApp.JsDispatcher)\n\n{:ok, runtime} =\n Boam.start_link(\n dispatcher: MyApp.JsDispatcher,\n js_expose: %{math: %{sum: true}}\n )\n\nBoam.eval(runtime, \"1 + 2\")\n#=> {:ok, 3}\n\nBoam.eval(runtime, \"math.sum(2, 3)\")\n#=> {:ok, 5}\n```\n\nThe built-in dispatcher is available for simpler cases:\n\n```elixir\n{:ok, runtime} =\n Boam.start_link(\n exports: %{\n \"console.log\" => fn [message] -> \"logged: #{message}\" end\n },\n js_expose: %{\n console: %{\n log: true\n }\n }\n )\n\nBoam.eval(runtime, \"console.log('hello')\")\n#=> {:ok, \"logged: hello\"}\n```","ref":"Boam.html#module-quick-start"},{"type":"module","title":"Value Bridge - Boam","doc":"Values crossing between JavaScript and Elixir are intentionally restricted to\nJSON-compatible data:\n\n * `null` maps to `nil`\n * booleans, numbers, strings, arrays, and objects round-trip normally\n * top-level JavaScript `undefined` is returned as `:undefined`\n * `undefined` cannot be passed through `beam.call/1`\n\nReturned JavaScript objects are serialized through Boa's JSON conversion, so\nobject keys come back to Elixir as strings.","ref":"Boam.html#module-value-bridge"},{"type":"module","title":"Architecture - Boam","doc":"* [`Boam.Runtime`](`Boam.Runtime`) owns the Rust runtime resource\n * [`Boam.Dispatcher`](`Boam.Dispatcher`) receives `beam.call(...)` requests\n * [`Boam.JS`](`Boam.JS`) generates JavaScript shim preludes\n * `Boam` provides the small public entrypoint for the common case","ref":"Boam.html#module-architecture"},{"type":"type","title":"Boam.start_option/0","doc":"","ref":"Boam.html#t:start_option/0"},{"type":"function","title":"Boam.dispatcher/1","doc":"Returns the dispatcher pid attached to a runtime.","ref":"Boam.html#dispatcher/1"},{"type":"function","title":"Boam.eval/2","doc":"Evaluates JavaScript source code inside a running runtime.\n\nThis is a convenience wrapper around `Boam.Runtime.eval/2`.","ref":"Boam.html#eval/2"},{"type":"function","title":"Boam.expose_js/2","doc":"Installs JavaScript shim functions on `globalThis`.","ref":"Boam.html#expose_js/2"},{"type":"function","title":"Boam.notify_expose_js/2","doc":"Queues JavaScript shim installation through an asynchronous message.","ref":"Boam.html#notify_expose_js/2"},{"type":"function","title":"Boam.start_link/1","doc":"Starts a Boa runtime process.\n\nThis is a convenience wrapper around `Boam.Runtime.start_link/1`.\n\nSee `Boam.Runtime` for the full option contract.","ref":"Boam.html#start_link/1"},{"type":"module","title":"Boam.Dispatcher","doc":"Dispatch process for `beam.call(...)` requests originating in JavaScript.\n\nA dispatcher is an ordinary `GenServer` that receives messages from the Rust\nruntime, resolves the requested handler, executes it on the BEAM, and replies\nback to the waiting JavaScript call.\n\nIn the default setup you do not need to start this module manually;\n[`Boam.Runtime`](`Boam.Runtime`) starts one automatically when no explicit\n`:dispatcher` pid is supplied.","ref":"Boam.Dispatcher.html"},{"type":"module","title":"Handler Forms - Boam.Dispatcher","doc":"Handlers can be provided in three shapes:\n\n * `fn args -> result end`\n * `fn name, args -> result end`\n * `{Module, :function}` which is called as `apply(Module, :function, [args])`","ref":"Boam.Dispatcher.html#module-handler-forms"},{"type":"module","title":"Return Contract - Boam.Dispatcher","doc":"A handler may return:\n\n * any JSON-compatible value, which becomes the JavaScript return value\n * `{:ok, value}`, which unwraps to `value`\n * `{:error, reason}`, which raises a JavaScript error\n\nIf a handler crashes, the formatted exception is sent back as a JavaScript\nerror message instead of leaving the runtime hanging.","ref":"Boam.Dispatcher.html#module-return-contract"},{"type":"type","title":"Boam.Dispatcher.export_name/0","doc":"","ref":"Boam.Dispatcher.html#t:export_name/0"},{"type":"type","title":"Boam.Dispatcher.handler/0","doc":"Function or MFA that can satisfy a `beam.call(...)` request.","ref":"Boam.Dispatcher.html#t:handler/0"},{"type":"type","title":"Boam.Dispatcher.start_option/0","doc":"","ref":"Boam.Dispatcher.html#t:start_option/0"},{"type":"function","title":"Boam.Dispatcher.child_spec/1","doc":"Returns a specification to start this module under a supervisor.\n\nSee `Supervisor`.","ref":"Boam.Dispatcher.html#child_spec/1"},{"type":"function","title":"Boam.Dispatcher.register/2","doc":"Registers or replaces one or more handlers at runtime.","ref":"Boam.Dispatcher.html#register/2"},{"type":"function","title":"Boam.Dispatcher.register/3","doc":"Registers or replaces a single handler at runtime.","ref":"Boam.Dispatcher.html#register/3"},{"type":"function","title":"Boam.Dispatcher.start_link/1","doc":"Starts a dispatcher process.\n\nMost callers should let `Boam.Runtime` create a dispatcher\nautomatically. Start this module directly when you want to reuse a single\ndispatch process across several runtimes or supervise it yourself.","ref":"Boam.Dispatcher.html#start_link/1"},{"type":"function","title":"Boam.Dispatcher.unregister/2","doc":"Removes a handler at runtime.","ref":"Boam.Dispatcher.html#unregister/2"},{"type":"module","title":"Boam.JS","doc":"Helpers for generating JavaScript shim code around the `beam.call(...)` bridge.\n\nThe main entrypoint is `export_prelude/1`, which takes a nested export tree and\nreturns JavaScript source that installs functions on `globalThis`.\n\nThis is useful in two modes:\n\n * pass the generated string through `prelude:` when you want manual control\n over dispatching\n * let `Boam.Runtime` do the same work automatically with `:js_expose`","ref":"Boam.JS.html"},{"type":"module","title":"Examples - Boam.JS","doc":"Generate a manual prelude:\n\n```elixir\nprelude =\n Boam.JS.export_prelude(%{\n console: %{\n log: true,\n error: {:dispatch, \"logger.error\"}\n }\n })\n```\n\nThat produces JavaScript equivalent to:\n\n```javascript\nif (globalThis[\"console\"] == null) { globalThis[\"console\"] = {}; }\nglobalThis[\"console\"][\"log\"] = (...args) => beam.call(\"console.log\", ...args);\nglobalThis[\"console\"][\"error\"] = (...args) => beam.call(\"logger.error\", ...args);\n```","ref":"Boam.JS.html#module-examples"},{"type":"type","title":"Boam.JS.export_tree/0","doc":"","ref":"Boam.JS.html#t:export_tree/0"},{"type":"type","title":"Boam.JS.leaf/0","doc":"Leaf spec for a generated JavaScript function.\n\n * `true` derives the dispatch name from the nested path\n * `{:dispatch, name}` generates a shim without attaching a handler","ref":"Boam.JS.html#t:leaf/0"},{"type":"type","title":"Boam.JS.path_key/0","doc":"","ref":"Boam.JS.html#t:path_key/0"},{"type":"function","title":"Boam.JS.export_prelude/1","doc":"Builds a JavaScript prelude that exposes nested shim functions on `globalThis`.\n\nLeaf dispatch names default to the dot-joined path. For example:\n\n```elixir\nBoam.JS.export_prelude(%{\n console: %{\n log: true\n }\n})\n```\n\ndefines `globalThis.console.log = (...args) => beam.call(\"console.log\", ...args)`.","ref":"Boam.JS.html#export_prelude/1"},{"type":"module","title":"Boam.Runtime","doc":"`GenServer` wrapper around a single Boa runtime.\n\nEach `Boam.Runtime` process owns one Rust resource, and that\nresource owns one dedicated worker thread where the Boa engine actually runs.\nThis keeps the JavaScript engine isolated from BEAM scheduler threads while\nstill allowing synchronous `eval/2` calls from Elixir.","ref":"Boam.Runtime.html"},{"type":"module","title":"Options - Boam.Runtime","doc":"* `:name` - optional `GenServer` name for the runtime process\n * `:dispatcher` - existing dispatcher server to receive `beam.call(...)`\n messages; accepts any `GenServer.server/0`. This is the primary way to\n integrate Boam into a supervised application.\n * `:exports` - map or keyword list of dispatch handlers when Boam starts\n its own convenience dispatcher\n * `:js_expose` - nested tree of JavaScript shims to install on `globalThis`\n during startup\n * `:expose` - legacy combined tree that configures both `:exports` and\n `:js_expose`\n * `:prelude` - JavaScript source string or list of strings to evaluate\n during startup, after any generated exposure shims\n * `:fallback` - optional `(name, args -> result)` function used when a\n dispatch name is not present in `:exports`\n * `:dispatch_timeout` - timeout for a single `beam.call(...)` round-trip;\n defaults to `30_000`, accepts `:infinity`","ref":"Boam.Runtime.html#module-options"},{"type":"module","title":"Dispatch Contract - Boam.Runtime","doc":"JavaScript code may call:\n\n```javascript\nbeam.call(\"name\", arg1, arg2)\n```\n\nThe dispatcher receives the function name and arguments as JSON-compatible\nElixir values and may reply with:\n\n * any JSON-compatible value\n * `{:ok, value}`\n * `{:error, reason}`\n\nReturning `{:error, reason}` raises a JavaScript error with `reason` as the\nmessage.","ref":"Boam.Runtime.html#module-dispatch-contract"},{"type":"module","title":"Exposing Functions - Boam.Runtime","doc":"In most applications you will manage your own dispatch process and pass it in\nthrough `:dispatcher`:\n\n```elixir\nchildren = [\n {MyApp.JsDispatcher, name: MyApp.JsDispatcher},\n {Boam.Runtime,\n dispatcher: MyApp.JsDispatcher,\n js_expose: %{console: %{log: true}}}\n]\n```\n\nThe built-in dispatcher exists as convenience sugar. Register Elixir handlers\nwith `:exports` and install JavaScript shims with `:js_expose`:\n\n```elixir\nexports: %{\n \"console.log\" => fn [message] -> \"logged: #{message}\" end,\n \"logger.warn\" => fn [message] -> \"warn: #{message}\" end\n},\njs_expose: %{\n console: %{\n log: true,\n warn: {:dispatch, \"logger.warn\"}\n }\n}\n```\n\nThis creates `console.log(...)` and `console.warn(...)` automatically.\n\nDispatch handlers can also queue JS exposure at runtime by sending:\n\n```elixir\nsend(runtime, {:boam_expose_js, %{console: %{debug: true}}})\n```\n\nThe message is applied after the current runtime operation completes, which\navoids deadlocking a `beam.call(...)` handler.","ref":"Boam.Runtime.html#module-exposing-functions"},{"type":"module","title":"Notes - Boam.Runtime","doc":"* Avoid synchronously calling back into the same runtime from a dispatch\n handler before replying, or the call will deadlock. Use\n `notify_expose_js/2` or `send(runtime, {:boam_expose_js, tree})` from\n dispatch handlers instead.\n * If you pass a named sibling dispatcher, use a supervisor strategy that\n restarts the runtime after the dispatcher restarts, because the runtime\n resolves the dispatcher to a pid during startup.\n * Top-level JavaScript `undefined` is surfaced as `{:ok, :undefined}`.","ref":"Boam.Runtime.html#module-notes"},{"type":"type","title":"Boam.Runtime.dispatch_timeout/0","doc":"","ref":"Boam.Runtime.html#t:dispatch_timeout/0"},{"type":"type","title":"Boam.Runtime.export_name/0","doc":"","ref":"Boam.Runtime.html#t:export_name/0"},{"type":"type","title":"Boam.Runtime.legacy_expose/0","doc":"","ref":"Boam.Runtime.html#t:legacy_expose/0"},{"type":"type","title":"Boam.Runtime.prelude/0","doc":"","ref":"Boam.Runtime.html#t:prelude/0"},{"type":"type","title":"Boam.Runtime.start_option/0","doc":"","ref":"Boam.Runtime.html#t:start_option/0"},{"type":"function","title":"Boam.Runtime.child_spec/1","doc":"Returns a specification to start this module under a supervisor.\n\nSee `Supervisor`.","ref":"Boam.Runtime.html#child_spec/1"},{"type":"function","title":"Boam.Runtime.dispatcher/1","doc":"Returns the dispatcher pid currently attached to the runtime.","ref":"Boam.Runtime.html#dispatcher/1"},{"type":"function","title":"Boam.Runtime.eval/2","doc":"Evaluates a JavaScript string inside the runtime.\n\nThe return value is either:\n\n * `{:ok, value}` for a JSON-compatible JavaScript result\n * `{:ok, :undefined}` for top-level JavaScript `undefined`\n * `{:error, message}` if evaluation or dispatch fails","ref":"Boam.Runtime.html#eval/2"},{"type":"function","title":"Example - Boam.Runtime.eval/2","doc":"```elixir\n{:ok, runtime} =\n Boam.Runtime.start_link(\n exports: %{\n greet: fn [name] -> \"hello #{name}\" end\n }\n )\n\nBoam.Runtime.eval(runtime, \"beam.call('greet', 'Ada')\")\n#=> {:ok, \"hello Ada\"}\n```","ref":"Boam.Runtime.html#eval/2-example"},{"type":"function","title":"Boam.Runtime.expose_js/2","doc":"Installs JavaScript shim functions on `globalThis`.\n\nThis call is synchronous and should be used only when the runtime is idle.\nDo not call it from a `beam.call(...)` dispatch handler; use\n`notify_expose_js/2` instead.","ref":"Boam.Runtime.html#expose_js/2"},{"type":"function","title":"Boam.Runtime.notify_expose_js/2","doc":"Queues JavaScript shim exposure through an asynchronous message.\n\nThis is safe to use from dispatch handlers because it does not wait for the\nruntime process to finish its current evaluation.","ref":"Boam.Runtime.html#notify_expose_js/2"},{"type":"function","title":"Boam.Runtime.start_link/1","doc":"Starts a runtime process.\n\nSee the module documentation for the supported options and dispatch contract.","ref":"Boam.Runtime.html#start_link/1"},{"type":"extras","title":"Boam","doc":"# Boam\n\nBoam is an Elixir wrapper around the [Boa](https://boajs.dev/) JavaScript\nengine, implemented as a Rustler NIF.\n\nThe library starts a dedicated JavaScript runtime per Elixir process and lets\nJavaScript call back into the BEAM through an explicit dispatch bridge.","ref":"readme.html"},{"type":"extras","title":"Features - Boam","doc":"- Boa-backed JavaScript evaluation from Elixir\n- Dedicated runtime thread per engine, matching Boa's thread-safety model\n- `beam.call(name, ...args)` bridge from JavaScript into Elixir\n- JSON-compatible value round-tripping between JS and Elixir\n- Configurable dispatcher process for custom routing and supervision setups","ref":"readme.html#features"},{"type":"extras","title":"Installation - Boam","doc":"Add `boam` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n [\n {:boam, \"~> 0.1.0\"}\n ]\nend\n```","ref":"readme.html#installation"},{"type":"extras","title":"Quick Start - Boam","doc":"```elixir\n{:ok, _dispatcher} =\n MyApp.JsDispatcher.start_link(name: MyApp.JsDispatcher)\n\n{:ok, runtime} =\n Boam.start_link(\n dispatcher: MyApp.JsDispatcher,\n js_expose: %{math: %{sum: true, greet: {:dispatch, \"app.greet\"}}}\n )\n\nBoam.eval(runtime, \"1 + 2\")\n#=> {:ok, 3}\n\nBoam.eval(runtime, \"math.sum(2, 3)\")\n#=> {:ok, 5}\n\nBoam.eval(runtime, \"math.greet('Ada')\")\n#=> {:ok, \"hello Ada\"}\n```\n\nIn most applications, managing your own dispatcher is the intended setup.\n`dispatcher:` accepts any `GenServer.server/0`, so a named sibling child works\ncleanly under supervision.","ref":"readme.html#quick-start"},{"type":"extras","title":"Startup Prelude - Boam","doc":"Run JavaScript during runtime startup with `prelude:`:\n\n```elixir\n{:ok, runtime} =\n Boam.start_link(\n prelude: [\n \"globalThis.appName = 'boam';\",\n \"globalThis.version = 1;\"\n ]\n )\n```\n\nThose snippets run before your first call to `Boam.eval/2`.","ref":"readme.html#startup-prelude"},{"type":"extras","title":"Managed Dispatcher - Boam","doc":"If you want to own the dispatch process yourself, pass it directly:\n\n```elixir\nchildren = [\n {MyApp.JsDispatcher, name: MyApp.JsDispatcher},\n {Boam.Runtime,\n dispatcher: MyApp.JsDispatcher,\n js_expose: %{console: %{log: true}}}\n]\n```\n\nIf the dispatcher is a sibling child, prefer a supervisor strategy like\n`:rest_for_one` so the runtime restarts after the dispatcher restarts. Boam\nresolves the dispatcher to a pid during startup.","ref":"readme.html#managed-dispatcher"},{"type":"extras","title":"Convenience Dispatcher - Boam","doc":"If you want JavaScript functions like `console.log(...)` without writing a\ndispatcher process, Boam can start a small convenience dispatcher from\n`:exports` and `:js_expose`:\n\n```elixir\n{:ok, runtime} =\n Boam.start_link(\n exports: %{\n \"console.log\" => fn [message] -> \"logged: #{message}\" end,\n \"logger.warn\" => fn [message] -> \"warn: #{message}\" end\n },\n js_expose: %{\n console: %{\n log: true,\n warn: {:dispatch, \"logger.warn\"}\n }\n }\n )\n\nBoam.eval(runtime, \"console.log('hello')\")\n#=> {:ok, \"logged: hello\"}\n```\n\nLeaf dispatch names default to the dot-joined path, so `console.log` dispatches\nto `\"console.log\"` unless you override it with `{:dispatch, \"custom.name\"}`.\n\n`expose:` still exists as legacy sugar when you want to configure both the JS\nshim and the Elixir handler in one tree.","ref":"readme.html#convenience-dispatcher"},{"type":"extras","title":"Manual Shim Generation - Boam","doc":"If you want to keep dispatch setup separate from runtime startup, generate the\nshim code yourself:\n\n```elixir\nprelude =\n Boam.JS.export_prelude(%{\n console: %{\n log: true,\n error: {:dispatch, \"logger.error\"}\n }\n })\n\n{:ok, runtime} =\n Boam.start_link(\n prelude: prelude,\n fallback: fn name, args -> {name, args} end\n )\n```","ref":"readme.html#manual-shim-generation"},{"type":"extras","title":"Runtime JS Exposure - Boam","doc":"You can add JS functions after startup with either a synchronous call or an\nasynchronous message:\n\n```elixir\n:ok = Boam.expose_js(runtime, %{console: %{log: true}})\n\nsend(runtime, {:boam_expose_js, %{console: %{debug: true}}})\n```\n\nThe message form is the one to use from a `beam.call(...)` handler, because the\nruntime only applies it after the current evaluation unwinds.","ref":"readme.html#runtime-js-exposure"},{"type":"extras","title":"Value Model - Boam","doc":"Boam intentionally restricts the bridge to JSON-compatible values:\n\n- JavaScript `null` maps to Elixir `nil`\n- booleans, numbers, strings, arrays, and objects round-trip normally\n- top-level JavaScript `undefined` becomes `{:ok, :undefined}`\n- `undefined` is rejected when passed through `beam.call(...)`\n- JavaScript object keys come back as strings\n\nFor predictable round-tripping, return Elixir maps with string keys from\ndispatch handlers.","ref":"readme.html#value-model"},{"type":"extras","title":"Dispatching Into Elixir - Boam","doc":"JavaScript code can call:\n\n```javascript\nbeam.call(\"name\", arg1, arg2)\n```\n\nThat request is delivered to a `Boam.Dispatcher` process on the BEAM side. A\nhandler can return:\n\n- any JSON-compatible value\n- `{:ok, value}`\n- `{:error, reason}`\n\nIf a handler crashes, the JavaScript caller receives an error instead of\nhanging forever.","ref":"readme.html#dispatching-into-elixir"},{"type":"extras","title":"Architecture - Boam","doc":"- `Boam` is the small public entrypoint\n- `Boam.Runtime` owns the NIF resource and runtime lifecycle\n- `Boam.Dispatcher` resolves and executes `beam.call(...)` handlers\n- `Boam.JS` generates JavaScript shim preludes from nested export trees\n- the internal NIF bridge module is intentionally hidden from the generated docs","ref":"readme.html#architecture"},{"type":"extras","title":"Generating Docs - Boam","doc":"Generate the docs locally with:\n\n```bash\nmix docs\n```\n\nThe generated site will be written to `doc/`.","ref":"readme.html#generating-docs"}],"proglang":"elixir","content_type":"text/markdown","producer":{"name":"ex_doc","version":"0.40.1"}}