Packages

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

Current section

Files

Jump to
boam doc Boam.Runtime.html
Raw

doc/Boam.Runtime.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="ExDoc v0.40.1">
<meta name="project" content="boam v0.1.2">
<title>Boam.Runtime — boam v0.1.2</title>
<link rel="stylesheet" href="dist/html-elixir-YJO4MOOW.css" />
<script defer src="dist/sidebar_items-4C4FEE2F.js"></script>
<script defer src="docs_config.js"></script>
<script defer src="dist/html-YU4BZFVS.js"></script>
</head>
<body>
<script>(()=>{var t="ex_doc:settings",e="dark";var o="dark",s="light";var E="sidebar_state",n="closed";var r="sidebar_width";var a="sidebar-open";var i=new URLSearchParams(window.location.search),S=i.get("theme")||JSON.parse(localStorage.getItem(t)||"{}").theme;(S===o||S!==s&&window.matchMedia("(prefers-color-scheme: dark)").matches)&&document.body.classList.add(e);var d=sessionStorage.getItem(E),A=d!==n&&!window.matchMedia(`screen and (max-width: ${768}px)`).matches;document.body.classList.toggle(a,A);var c=sessionStorage.getItem(r);c&&document.body.style.setProperty("--sidebarWidth",`${c}px`);var p=/(Macintosh|iPhone|iPad|iPod)/.test(window.navigator.userAgent);document.documentElement.classList.toggle("apple-os",p);})();
</script>
<div class="body-wrapper">
<button id="sidebar-menu" class="sidebar-button sidebar-toggle" aria-label="toggle sidebar" aria-controls="sidebar">
<i class="ri-menu-line ri-lg" title="Collapse/expand sidebar"></i>
</button>
<nav id="sidebar" class="sidebar">
<div class="sidebar-header">
<div class="sidebar-projectInfo">
<div>
<a href="readme.html" class="sidebar-projectName" translate="no">
boam
</a>
<div class="sidebar-projectVersion" translate="no">
v0.1.2
</div>
</div>
</div>
<ul id="sidebar-list-nav" class="sidebar-list-nav" role="tablist" data-extras="Pages"></ul>
</div>
</nav>
<output role="status" id="toast"></output>
<main class="content page-module" id="main" data-type="modules">
<div id="content" class="content-inner">
<div class="top-search">
<div class="search-settings">
<form class="search-bar" action="search.html">
<label class="search-label">
<span class="sr-only">Search documentation of boam</span>
<div class="search-input-wrapper">
<input name="q" type="text" class="search-input" placeholder="Press / to search" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
<button type="button" tabindex="-1" class="search-close-button" aria-hidden="true">
<i class="ri-close-line ri-lg" title="Cancel search"></i>
</button>
</div>
</label>
</form>
<div class="autocomplete">
</div>
<div class="engine-selector" data-multiple="false">
<button type="button" class="engine-button" aria-label="Select search engine" aria-haspopup="true" aria-expanded="false">
<i class="ri-search-2-line" aria-hidden="true"></i>
<span class="engine-name">Default</span>
<i class="ri-arrow-down-s-line" aria-hidden="true"></i>
</button>
<div class="engine-dropdown" hidden role="menu">
<button type="button"
class="engine-option"
data-engine-url="search.html?q="
role="menuitemradio"
aria-checked="true">
<span class="name">Default</span>
<span class="help">In-browser search</span>
</button>
</div>
</div>
<button class="icon-settings display-settings">
<i class="ri-settings-3-line"></i>
<span class="sr-only">Settings</span>
</button>
</div>
</div>
<div id="top-content">
<div class="heading-with-actions top-heading">
<h1>
<span translate="no">Boam.<wbr>Runtime</span>
<small class="app-vsn" translate="no">(boam v0.1.2)</small>
</h1>
<a href="Boam.Runtime.md" title="Copy Markdown (hold Ctrl/Cmd and click it to open as Markdown)" class="copy-markdown icon-action" rel="help">
<i class="ri-markdown-line" aria-hidden="true"></i>
<span class="sr-only">Copy Markdown</span>
</a>
</div>
<section id="moduledoc">
<p><a href="https://hexdocs.pm/elixir/GenServer.html"><code class="inline">GenServer</code></a> wrapper around a single Boa runtime.</p><p>Each <a href="Boam.Runtime.html"><code class="inline">Boam.Runtime</code></a> process owns one Rust resource, and that
resource owns one dedicated worker thread where the Boa engine actually runs.
This keeps the JavaScript engine isolated from BEAM scheduler threads while
still allowing synchronous <a href="#eval/2"><code class="inline">eval/2</code></a> calls from Elixir.</p><h2 id="module-options" class="section-heading"><a href="#module-options" class="hover-link"><i class="ri-link-m" aria-hidden="true"></i></a><span class="text">Options</span></h2><ul><li><code class="inline">:name</code> - optional <a href="https://hexdocs.pm/elixir/GenServer.html"><code class="inline">GenServer</code></a> name for the runtime process</li><li><code class="inline">:dispatcher</code> - existing dispatcher pid to receive <code class="inline">beam.call(...)</code>
messages; if omitted, a fresh <a href="Boam.Dispatcher.html"><code class="inline">Boam.Dispatcher</code></a>
process is started automatically</li><li><code class="inline">:exports</code> - map or keyword list of dispatch handlers when Boam starts
its own dispatcher</li><li><code class="inline">:expose</code> - nested tree of handlers that should also be installed as
JavaScript functions during startup</li><li><code class="inline">:prelude</code> - JavaScript source string or list of strings to evaluate
during startup, after any generated <code class="inline">:expose</code> shims</li><li><code class="inline">:fallback</code> - optional <code class="inline">(name, args -&gt; result)</code> function used when a
dispatch name is not present in <code class="inline">:exports</code></li><li><code class="inline">:dispatch_timeout</code> - timeout for a single <code class="inline">beam.call(...)</code> round-trip;
defaults to <code class="inline">30_000</code>, accepts <code class="inline">:infinity</code></li></ul><h2 id="module-dispatch-contract" class="section-heading"><a href="#module-dispatch-contract" class="hover-link"><i class="ri-link-m" aria-hidden="true"></i></a><span class="text">Dispatch Contract</span></h2><p>JavaScript code may call:</p><pre><code class="javascript">beam.call(&quot;name&quot;, arg1, arg2)</code></pre><p>The dispatcher receives the function name and arguments as JSON-compatible
Elixir values and may reply with:</p><ul><li>any JSON-compatible value</li><li><code class="inline">{:ok, value}</code></li><li><code class="inline">{:error, reason}</code></li></ul><p>Returning <code class="inline">{:error, reason}</code> raises a JavaScript error with <code class="inline">reason</code> as the
message.</p><h2 id="module-exposing-functions" class="section-heading"><a href="#module-exposing-functions" class="hover-link"><i class="ri-link-m" aria-hidden="true"></i></a><span class="text">Exposing Functions</span></h2><p><code class="inline">:expose</code> lets you define nested JavaScript functions from Elixir:</p><pre><code class="makeup elixir" translate="no"><span class="ss">expose</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="6998620932-1">%{</span><span class="w">
</span><span class="ss">console</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="6998620932-2">%{</span><span class="w">
</span><span class="ss">log</span><span class="p">:</span><span class="w"> </span><span class="k" data-group-id="6998620932-3">fn</span><span class="w"> </span><span class="p" data-group-id="6998620932-4">[</span><span class="n">message</span><span class="p" data-group-id="6998620932-4">]</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="s">&quot;logged: </span><span class="si" data-group-id="6998620932-5">#{</span><span class="n">message</span><span class="si" data-group-id="6998620932-5">}</span><span class="s">&quot;</span><span class="w"> </span><span class="k" data-group-id="6998620932-3">end</span><span class="p">,</span><span class="w">
</span><span class="ss">warn</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="6998620932-6">{</span><span class="ss">:dispatch</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;logger.warn&quot;</span><span class="p">,</span><span class="w"> </span><span class="k" data-group-id="6998620932-7">fn</span><span class="w"> </span><span class="p" data-group-id="6998620932-8">[</span><span class="n">message</span><span class="p" data-group-id="6998620932-8">]</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="s">&quot;warn: </span><span class="si" data-group-id="6998620932-9">#{</span><span class="n">message</span><span class="si" data-group-id="6998620932-9">}</span><span class="s">&quot;</span><span class="w"> </span><span class="k" data-group-id="6998620932-7">end</span><span class="p" data-group-id="6998620932-6">}</span><span class="w">
</span><span class="p" data-group-id="6998620932-2">}</span><span class="w">
</span><span class="p" data-group-id="6998620932-1">}</span></code></pre><p>This creates <code class="inline">console.log(...)</code> and <code class="inline">console.warn(...)</code> automatically.</p><p>If you already manage your own dispatcher process, use <code class="inline">:prelude</code> together
with <a href="Boam.JS.html#export_prelude/1"><code class="inline">Boam.JS.export_prelude/1</code></a> instead of <code class="inline">:expose</code>.</p><h2 id="module-notes" class="section-heading"><a href="#module-notes" class="hover-link"><i class="ri-link-m" aria-hidden="true"></i></a><span class="text">Notes</span></h2><ul><li>Avoid synchronously calling back into the same runtime from a dispatch
handler before replying, or the call will deadlock.</li><li>Top-level JavaScript <code class="inline">undefined</code> is surfaced as <code class="inline">{:ok, :undefined}</code>.</li></ul>
</section>
</div>
<section id="summary" class="details-list">
<h2 class="section-heading">
<a class="hover-link" href="#summary">
<i class="ri-link-m" aria-hidden="true"></i>
</a>
<span class="text">Summary</span>
</h2>
<div class="summary-types summary">
<h3>
<a href="#types">Types</a>
</h3>
<div class="summary-row">
<div class="summary-signature">
<a href="#t:dispatch_timeout/0" data-no-tooltip="" translate="no">dispatch_timeout()</a>
</div>
</div>
<div class="summary-row">
<div class="summary-signature">
<a href="#t:export_name/0" data-no-tooltip="" translate="no">export_name()</a>
</div>
</div>
<div class="summary-row">
<div class="summary-signature">
<a href="#t:prelude/0" data-no-tooltip="" translate="no">prelude()</a>
</div>
</div>
<div class="summary-row">
<div class="summary-signature">
<a href="#t:start_option/0" data-no-tooltip="" translate="no">start_option()</a>
</div>
</div>
</div>
<div class="summary-functions summary">
<h3>
<a href="#functions">Functions</a>
</h3>
<div class="summary-row">
<div class="summary-signature">
<a href="#child_spec/1" data-no-tooltip="" translate="no">child_spec(init_arg)</a>
</div>
<div class="summary-synopsis"><p>Returns a specification to start this module under a supervisor.</p></div>
</div>
<div class="summary-row">
<div class="summary-signature">
<a href="#eval/2" data-no-tooltip="" translate="no">eval(runtime, source)</a>
</div>
<div class="summary-synopsis"><p>Evaluates a JavaScript string inside the runtime.</p></div>
</div>
<div class="summary-row">
<div class="summary-signature">
<a href="#start_link/1" data-no-tooltip="" translate="no">start_link(opts \\ [])</a>
</div>
<div class="summary-synopsis"><p>Starts a runtime process.</p></div>
</div>
</div>
</section>
<section id="types" class="details-list">
<h2 class="section-heading">
<a class="hover-link" href="#types">
<i class="ri-link-m" aria-hidden="true"></i>
</a>
<span class="text">Types</span>
</h2>
<div class="types-list">
<section class="detail" id="t:dispatch_timeout/0">
<div class="detail-header">
<a href="#t:dispatch_timeout/0" class="detail-link" data-no-tooltip="" aria-label="Link to this type">
<i class="ri-link-m" aria-hidden="true"></i>
</a>
<div class="heading-with-actions">
<h1 class="signature" translate="no">dispatch_timeout()</h1>
</div>
</div>
<section class="docstring">
<div class="specs">
<pre translate="no"><span class="attribute">@type</span> dispatch_timeout() :: <a href="https://hexdocs.pm/elixir/typespecs.html#built-in-types">timeout</a>()</pre>
</div>
</section>
</section>
<section class="detail" id="t:export_name/0">
<div class="detail-header">
<a href="#t:export_name/0" class="detail-link" data-no-tooltip="" aria-label="Link to this type">
<i class="ri-link-m" aria-hidden="true"></i>
</a>
<div class="heading-with-actions">
<h1 class="signature" translate="no">export_name()</h1>
</div>
</div>
<section class="docstring">
<div class="specs">
<pre translate="no"><span class="attribute">@type</span> export_name() :: <a href="https://hexdocs.pm/elixir/typespecs.html#basic-types">atom</a>() | <a href="https://hexdocs.pm/elixir/String.html#t:t/0">String.t</a>()</pre>
</div>
</section>
</section>
<section class="detail" id="t:prelude/0">
<div class="detail-header">
<a href="#t:prelude/0" class="detail-link" data-no-tooltip="" aria-label="Link to this type">
<i class="ri-link-m" aria-hidden="true"></i>
</a>
<div class="heading-with-actions">
<h1 class="signature" translate="no">prelude()</h1>
</div>
</div>
<section class="docstring">
<div class="specs">
<pre translate="no"><span class="attribute">@type</span> prelude() :: <a href="https://hexdocs.pm/elixir/String.html#t:t/0">String.t</a>() | [<a href="https://hexdocs.pm/elixir/String.html#t:t/0">String.t</a>()]</pre>
</div>
</section>
</section>
<section class="detail" id="t:start_option/0">
<div class="detail-header">
<a href="#t:start_option/0" class="detail-link" data-no-tooltip="" aria-label="Link to this type">
<i class="ri-link-m" aria-hidden="true"></i>
</a>
<div class="heading-with-actions">
<h1 class="signature" translate="no">start_option()</h1>
</div>
</div>
<section class="docstring">
<div class="specs">
<pre translate="no"><span class="attribute">@type</span> start_option() ::
{:name, <a href="https://hexdocs.pm/elixir/GenServer.html#t:name/0">GenServer.name</a>()}
| {:dispatcher, <a href="https://hexdocs.pm/elixir/typespecs.html#basic-types">pid</a>()}
| {:exports,
%{optional(<a href="#t:export_name/0">export_name</a>()) =&gt; <a href="Boam.Dispatcher.html#t:handler/0">Boam.Dispatcher.handler</a>()}
| <a href="https://hexdocs.pm/elixir/typespecs.html#built-in-types">keyword</a>(<a href="Boam.Dispatcher.html#t:handler/0">Boam.Dispatcher.handler</a>())}
| {:expose, <a href="Boam.JS.html#t:export_tree/0">Boam.JS.export_tree</a>()}
| {:prelude, <a href="#t:prelude/0">prelude</a>()}
| {:fallback, (<a href="https://hexdocs.pm/elixir/String.html#t:t/0">String.t</a>(), <a href="https://hexdocs.pm/elixir/typespecs.html#built-in-types">list</a>() -&gt; <a href="https://hexdocs.pm/elixir/typespecs.html#built-in-types">term</a>())}
| {:dispatch_timeout, <a href="#t:dispatch_timeout/0">dispatch_timeout</a>()}</pre>
</div>
</section>
</section>
</div>
</section>
<section id="functions" class="details-list">
<h2 class="section-heading">
<a class="hover-link" href="#functions">
<i class="ri-link-m" aria-hidden="true"></i>
</a>
<span class="text">Functions</span>
</h2>
<div class="functions-list">
<section class="detail" id="child_spec/1">
<div class="detail-header">
<a href="#child_spec/1" class="detail-link" data-no-tooltip="" aria-label="Link to this function">
<i class="ri-link-m" aria-hidden="true"></i>
</a>
<div class="heading-with-actions">
<h1 class="signature" translate="no">child_spec(init_arg)</h1>
</div>
</div>
<section class="docstring">
<p>Returns a specification to start this module under a supervisor.</p><p>See <a href="https://hexdocs.pm/elixir/Supervisor.html"><code class="inline">Supervisor</code></a>.</p>
</section>
</section>
<section class="detail" id="eval/2">
<div class="detail-header">
<a href="#eval/2" class="detail-link" data-no-tooltip="" aria-label="Link to this function">
<i class="ri-link-m" aria-hidden="true"></i>
</a>
<div class="heading-with-actions">
<h1 class="signature" translate="no">eval(runtime, source)</h1>
</div>
</div>
<section class="docstring">
<div class="specs">
<pre translate="no"><span class="attribute">@spec</span> eval(<a href="https://hexdocs.pm/elixir/GenServer.html#t:server/0">GenServer.server</a>(), <a href="https://hexdocs.pm/elixir/String.html#t:t/0">String.t</a>()) :: {:ok, <a href="https://hexdocs.pm/elixir/typespecs.html#built-in-types">term</a>()} | {:error, <a href="https://hexdocs.pm/elixir/String.html#t:t/0">String.t</a>()}</pre>
</div>
<p>Evaluates a JavaScript string inside the runtime.</p><p>The return value is either:</p><ul><li><code class="inline">{:ok, value}</code> for a JSON-compatible JavaScript result</li><li><code class="inline">{:ok, :undefined}</code> for top-level JavaScript <code class="inline">undefined</code></li><li><code class="inline">{:error, message}</code> if evaluation or dispatch fails</li></ul><h2 id="eval/2-example" class="section-heading"><a href="#eval/2-example" class="hover-link"><i class="ri-link-m" aria-hidden="true"></i></a><span class="text">Example</span></h2><pre><code class="makeup elixir" translate="no"><span class="p" data-group-id="6661074560-1">{</span><span class="ss">:ok</span><span class="p">,</span><span class="w"> </span><span class="n">runtime</span><span class="p" data-group-id="6661074560-1">}</span><span class="w"> </span><span class="o">=</span><span class="w">
</span><span class="nc">Boam.Runtime</span><span class="o">.</span><span class="n">start_link</span><span class="p" data-group-id="6661074560-2">(</span><span class="w">
</span><span class="ss">exports</span><span class="p">:</span><span class="w"> </span><span class="p" data-group-id="6661074560-3">%{</span><span class="w">
</span><span class="ss">greet</span><span class="p">:</span><span class="w"> </span><span class="k" data-group-id="6661074560-4">fn</span><span class="w"> </span><span class="p" data-group-id="6661074560-5">[</span><span class="n">name</span><span class="p" data-group-id="6661074560-5">]</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="s">&quot;hello </span><span class="si" data-group-id="6661074560-6">#{</span><span class="n">name</span><span class="si" data-group-id="6661074560-6">}</span><span class="s">&quot;</span><span class="w"> </span><span class="k" data-group-id="6661074560-4">end</span><span class="w">
</span><span class="p" data-group-id="6661074560-3">}</span><span class="w">
</span><span class="p" data-group-id="6661074560-2">)</span><span class="w">
</span><span class="nc">Boam.Runtime</span><span class="o">.</span><span class="n">eval</span><span class="p" data-group-id="6661074560-7">(</span><span class="n">runtime</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;beam.call(&#39;greet&#39;, &#39;Ada&#39;)&quot;</span><span class="p" data-group-id="6661074560-7">)</span><span class="w">
</span><span class="c1">#=&gt; {:ok, &quot;hello Ada&quot;}</span></code></pre>
</section>
</section>
<section class="detail" id="start_link/1">
<span id="start_link/0"></span>
<div class="detail-header">
<a href="#start_link/1" class="detail-link" data-no-tooltip="" aria-label="Link to this function">
<i class="ri-link-m" aria-hidden="true"></i>
</a>
<div class="heading-with-actions">
<h1 class="signature" translate="no">start_link(opts \\ [])</h1>
</div>
</div>
<section class="docstring">
<div class="specs">
<pre translate="no"><span class="attribute">@spec</span> start_link([<a href="#t:start_option/0">start_option</a>()]) :: <a href="https://hexdocs.pm/elixir/GenServer.html#t:on_start/0">GenServer.on_start</a>()</pre>
</div>
<p>Starts a runtime process.</p><p>See the module documentation for the supported options and dispatch contract.</p>
</section>
</section>
</div>
</section>
<footer class="footer">
<p>
<span class="line">
<a href="https://hex.pm/packages/boam/0.1.2">Hex Package</a>
<a href="https://preview.hex.pm/preview/boam/0.1.2">Hex Preview</a>
</span>
<span class="line">
<button class="a-main footer-button display-quick-switch" title="Go to package docs">
Go to package docs
</button>
<a href="llms.txt" target="_blank">
View llms.txt
</a>
<a href="boam.epub">
Download ePub version
</a>
</span>
</p>
<p class="built-using">
Built using
<a href="https://github.com/elixir-lang/ex_doc" title="ExDoc" target="_blank" rel="help noopener" translate="no">ExDoc</a> (v0.40.1) for the
<a href="https://elixir-lang.org" title="Elixir" target="_blank" translate="no">Elixir programming language</a>
</p>
</footer>
</div>
</main>
</div>
</body>
</html>