signalk-server
Version:
An implementation of a [Signal K](http://signalk.org) server for boats.
145 lines (133 loc) • 29.3 kB
HTML
<html class="default" lang="en" data-base="../../../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>Best Practices for WASM Plugins | Signal K</title><meta name="description" content="Documentation for Signal K"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../../../assets/style.css?cache=1783009712609"/><link rel="stylesheet" href="../../../assets/highlight.css?cache=1783009712609"/><script defer src="../../../assets/main.js?cache=1783009712609"></script><script async src="../../../assets/icons.js?cache=1783009712609" id="tsd-icons-script"></script><script async src="../../../assets/search.js?cache=1783009712609" id="tsd-search-script"></script><script async src="../../../assets/navigation.js?cache=1783009712609" id="tsd-nav-script"></script><script async src="../../../assets/hierarchy.js?cache=1783009712609" id="tsd-hierarchy-script"></script><link rel="stylesheet" href="../../../assets/theme.css"/><script>if(window.self!==window.top){document.documentElement.classList.add('embedded')}</script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../../../index.html" class="title"><img class="title-logo" src="../../../assets/logo.svg" alt="Signal K"/><svg class="title-home-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-label="Documentation home"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg></a><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../../../assets/icons.svg#icon-search"></use></svg><span class="visible@s">Search</span></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><div id="tsd-toolbar-links"><a href="https://discord.gg/uuZrwz4dCS" target="_blank" rel="noopener" class="toolbar-icon visible@s" aria-label="Discord"><svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M524.5 69.8a1.5 1.5 0 0 0 -.8-.7A485.1 485.1 0 0 0 404.1 32a1.8 1.8 0 0 0 -1.9 .9 337.5 337.5 0 0 0 -14.9 30.6 447.8 447.8 0 0 0 -134.4 0 309.5 309.5 0 0 0 -15.1-30.6 1.9 1.9 0 0 0 -1.9-.9A483.7 483.7 0 0 0 116.1 69.1a1.7 1.7 0 0 0 -.8 .7C39.1 183.7 18.2 294.7 28.4 404.4a2 2 0 0 0 .8 1.4A487.7 487.7 0 0 0 176 479.9a1.9 1.9 0 0 0 2.1-.7A348.2 348.2 0 0 0 208.1 430.4a1.9 1.9 0 0 0 -1-2.6 321.2 321.2 0 0 1 -45.9-21.9 1.9 1.9 0 0 1 -.2-3.1c3.1-2.3 6.2-4.7 9.1-7.1a1.8 1.8 0 0 1 1.9-.3c96.2 43.9 200.4 43.9 295.5 0a1.8 1.8 0 0 1 1.9 .2c2.9 2.4 6 4.9 9.1 7.2a1.9 1.9 0 0 1 -.2 3.1 301.4 301.4 0 0 1 -45.9 21.8 1.9 1.9 0 0 0 -1 2.6 391.1 391.1 0 0 0 30 48.8 1.9 1.9 0 0 0 2.1 .7A486 486 0 0 0 610.7 405.7a1.9 1.9 0 0 0 .8-1.4C623.7 277.6 590.9 167.5 524.5 69.8zM222.5 337.6c-29 0-52.8-26.6-52.8-59.2S193.1 219.1 222.5 219.1c29.7 0 53.3 26.8 52.8 59.2C275.3 311 251.9 337.6 222.5 337.6zm195.4 0c-29 0-52.8-26.6-52.8-59.2S388.4 219.1 417.9 219.1c29.7 0 53.3 26.8 52.8 59.2C470.7 311 447.5 337.6 417.9 337.6z"></path></svg></a><a href="https://github.com/SignalK/signalk-server" target="_blank" rel="noopener" class="toolbar-icon visible@s" aria-label="Discord"><svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"></path></svg></a><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../../../assets/icons.svg#icon-menu"></use></svg></a></div></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="../../../Developing.html">Developing</a></li><li><a href="../../Plugins.html">Plugins</a></li><li><a href="../WASM_Plugins.html">WASM Plugins</a></li><li><a href="" aria-current="page">Best Practices for WASM Plugins</a></li></ul></div><div class="tsd-panel tsd-typography"><h1 id="best-practices-for-wasm-plugins" class="tsd-anchor-link">Best Practices for WASM Plugins<a href="#best-practices-for-wasm-plugins" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h1>
<h2 id="hot-reload" class="tsd-anchor-link">Hot Reload<a href="#hot-reload" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h2>
<p>WASM plugins support hot-reload without server restart:</p>
<h3 id="manual-reload" class="tsd-anchor-link">Manual Reload<a href="#manual-reload" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<ol>
<li>Build new WASM binary: <code>cargo build --target wasm32-wasip1 --release</code></li>
<li>Copy to plugin directory: <code>cp target/wasm32-wasip1/release/*.wasm ~/.signalk/...</code></li>
<li>In Admin UI: <strong>Server</strong> → <strong>Plugin Config</strong> → Click <strong>Reload</strong> button</li>
</ol>
<h3 id="reload-behavior" class="tsd-anchor-link">Reload Behavior<a href="#reload-behavior" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>During reload:</p>
<ul>
<li><code>stop()</code> is called on old instance</li>
<li>Subscriptions are preserved</li>
<li>Deltas are buffered (not lost)</li>
<li>New instance is loaded</li>
<li><code>start()</code> is called with saved config</li>
<li>Buffered deltas are replayed</li>
</ul>
<h2 id="error-handling" class="tsd-anchor-link">Error Handling<a href="#error-handling" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h2>
<h3 id="crash-recovery" class="tsd-anchor-link">Crash Recovery<a href="#crash-recovery" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>If a WASM plugin crashes:</p>
<ol>
<li><strong>First crash</strong>: Automatic restart after 1 second</li>
<li><strong>Second crash</strong>: Restart after 2 seconds</li>
<li><strong>Third crash</strong>: Restart after 4 seconds</li>
<li><strong>After 3 crashes</strong>: Plugin disabled, admin notification</li>
</ol>
<h3 id="error-reporting" class="tsd-anchor-link">Error Reporting<a href="#error-reporting" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>Report errors to admin UI:</p>
<pre><code class="rust"><span class="hl-1">fn</span><span class="hl-0"> </span><span class="hl-7">handle_error</span><span class="hl-0">(err</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-1">&</span><span class="hl-5">str</span><span class="hl-0">) {</span><br/><span class="hl-0"> </span><span class="hl-7">sk_set_error</span><span class="hl-0">(</span><span class="hl-1">&</span><span class="hl-7">format!</span><span class="hl-0">(</span><span class="hl-4">"Error: {}"</span><span class="hl-0">, err));</span><br/><span class="hl-0">}</span>
</code><button type="button">Copy</button></pre>
<h2 id="optimization" class="tsd-anchor-link">Optimization<a href="#optimization" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h2>
<h3 id="1-minimize-binary-size" class="tsd-anchor-link">1. Minimize Binary Size<a href="#1-minimize-binary-size" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<pre><code class="toml"><span class="hl-0">[</span><span class="hl-5">profile</span><span class="hl-0">.</span><span class="hl-5">release</span><span class="hl-0">]</span><br/><span class="hl-0">opt-level = </span><span class="hl-4">"z"</span><span class="hl-0"> </span><span class="hl-6"># Optimize for size</span><br/><span class="hl-0">lto = </span><span class="hl-2">true</span><span class="hl-0"> </span><span class="hl-6"># Enable link-time optimization</span><br/><span class="hl-0">strip = </span><span class="hl-2">true</span><span class="hl-0"> </span><span class="hl-6"># Strip debug symbols</span>
</code><button type="button">Copy</button></pre>
<p>Use <code>wasm-opt</code> for further optimization:</p>
<pre><code class="bash"><span class="hl-5">wasm-opt</span><span class="hl-0"> </span><span class="hl-2">-Oz</span><span class="hl-0"> </span><span class="hl-4">plugin.wasm</span><span class="hl-0"> </span><span class="hl-2">-o</span><span class="hl-0"> </span><span class="hl-4">plugin.wasm</span>
</code><button type="button">Copy</button></pre>
<h3 id="2-handle-errors-gracefully" class="tsd-anchor-link">2. Handle Errors Gracefully<a href="#2-handle-errors-gracefully" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<pre><code class="rust"><span class="hl-1">fn</span><span class="hl-0"> </span><span class="hl-7">start</span><span class="hl-0">(config_ptr</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-1">*const</span><span class="hl-0"> </span><span class="hl-5">u8</span><span class="hl-0">, config_len</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-5">usize</span><span class="hl-0">) </span><span class="hl-1">-></span><span class="hl-0"> </span><span class="hl-5">i32</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-1">match</span><span class="hl-0"> </span><span class="hl-7">initialize_plugin</span><span class="hl-0">(config_ptr, config_len) {</span><br/><span class="hl-0"> </span><span class="hl-5">Ok</span><span class="hl-0">(_) </span><span class="hl-1">=></span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-7">sk_set_status</span><span class="hl-0">(</span><span class="hl-4">"Started"</span><span class="hl-0">);</span><br/><span class="hl-0"> </span><span class="hl-2">0</span><span class="hl-0"> </span><span class="hl-6">// Success</span><br/><span class="hl-0"> }</span><br/><span class="hl-0"> </span><span class="hl-5">Err</span><span class="hl-0">(e) </span><span class="hl-1">=></span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-7">sk_set_error</span><span class="hl-0">(</span><span class="hl-1">&</span><span class="hl-7">format!</span><span class="hl-0">(</span><span class="hl-4">"Failed to start: {}"</span><span class="hl-0">, e));</span><br/><span class="hl-0"> </span><span class="hl-2">1</span><span class="hl-0"> </span><span class="hl-6">// Error</span><br/><span class="hl-0"> }</span><br/><span class="hl-0"> }</span><br/><span class="hl-0">}</span>
</code><button type="button">Copy</button></pre>
<h3 id="3-use-efficient-json-parsing" class="tsd-anchor-link">3. Use Efficient JSON Parsing<a href="#3-use-efficient-json-parsing" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<pre><code class="rust"><span class="hl-1">use</span><span class="hl-0"> </span><span class="hl-5">serde</span><span class="hl-1">::</span><span class="hl-0">{</span><span class="hl-5">Deserialize</span><span class="hl-0">, </span><span class="hl-5">Serialize</span><span class="hl-0">};</span><br/><br/><span class="hl-0">#[derive(</span><span class="hl-5">Deserialize</span><span class="hl-0">)]</span><br/><span class="hl-1">struct</span><span class="hl-0"> </span><span class="hl-5">Config</span><span class="hl-0"> {</span><br/><span class="hl-0"> #[serde(default)]</span><br/><span class="hl-0"> enabled</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-5">bool</span><span class="hl-0">,</span><br/><span class="hl-0">}</span><br/><br/><span class="hl-1">fn</span><span class="hl-0"> </span><span class="hl-7">parse_config</span><span class="hl-0">(json</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-1">&</span><span class="hl-5">str</span><span class="hl-0">) </span><span class="hl-1">-></span><span class="hl-0"> </span><span class="hl-5">Result</span><span class="hl-0"><</span><span class="hl-5">Config</span><span class="hl-0">, serde_json</span><span class="hl-1">::</span><span class="hl-5">Error</span><span class="hl-0">> {</span><br/><span class="hl-0"> </span><span class="hl-5">serde_json</span><span class="hl-1">::</span><span class="hl-7">from_str</span><span class="hl-0">(json)</span><br/><span class="hl-0">}</span>
</code><button type="button">Copy</button></pre>
<h3 id="4-limit-memory-usage" class="tsd-anchor-link">4. Limit Memory Usage<a href="#4-limit-memory-usage" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<ul>
<li>Avoid large allocations</li>
<li>Clear buffers after use</li>
<li>Use streaming for large data</li>
</ul>
<h3 id="wasm-memory-limitations" class="tsd-anchor-link">WASM Memory Limitations<a href="#wasm-memory-limitations" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>WASM plugins running in Node.js have <strong>~64KB buffer limitations</strong> for stdin/stdout operations. This is a fundamental limitation of the Node.js WASI implementation, not a Signal K restriction.</p>
<p><strong>Impact:</strong></p>
<ul>
<li>Small JSON responses (< 64KB): Work fine in pure WASM</li>
<li>Medium data (64KB - 1MB): May freeze or fail</li>
<li>Large data (> 1MB): Will fail or freeze the server</li>
</ul>
<p><strong>Hybrid Architecture Pattern</strong></p>
<p>For plugins that need to handle large data volumes (logs, file streaming, large JSON responses), use a <strong>hybrid approach</strong>:</p>
<ul>
<li><strong>WASM Plugin</strong>: Registers HTTP endpoints and provides configuration UI</li>
<li><strong>Node.js Handler</strong>: Server intercepts specific endpoints and handles I/O directly in Node.js</li>
<li><strong>Result</strong>: Can handle unlimited data without memory constraints</li>
</ul>
<p>Use this pattern when your plugin needs to:</p>
<ul>
<li>Return large JSON responses (> 64KB)</li>
<li>Process large file uploads</li>
<li>Handle streaming data</li>
</ul>
<h3 id="5-provide-good-ux" class="tsd-anchor-link">5. Provide Good UX<a href="#5-provide-good-ux" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<ul>
<li>Clear status messages</li>
<li>Descriptive error messages</li>
<li>Comprehensive JSON schema for configuration</li>
</ul>
<h2 id="debugging" class="tsd-anchor-link">Debugging<a href="#debugging" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h2>
<h3 id="logging" class="tsd-anchor-link">Logging<a href="#logging" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<pre><code class="rust"><span class="hl-1">fn</span><span class="hl-0"> </span><span class="hl-7">debug_log</span><span class="hl-0">(message</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-1">&</span><span class="hl-5">str</span><span class="hl-0">) {</span><br/><span class="hl-0"> </span><span class="hl-1">unsafe</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-7">sk_debug</span><span class="hl-0">(message</span><span class="hl-1">.</span><span class="hl-7">as_ptr</span><span class="hl-0">(), message</span><span class="hl-1">.</span><span class="hl-7">len</span><span class="hl-0">());</span><br/><span class="hl-0"> }</span><br/><span class="hl-0">}</span>
</code><button type="button">Copy</button></pre>
<h3 id="testing-locally" class="tsd-anchor-link">Testing Locally<a href="#testing-locally" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<ol>
<li>Build with debug symbols: <code>cargo build --target wasm32-wasip1</code></li>
<li>Use <code>wasmtime</code> for local testing:</li>
</ol>
<pre><code class="bash"><span class="hl-5">wasmtime</span><span class="hl-0"> </span><span class="hl-2">--dir</span><span class="hl-0"> </span><span class="hl-4">/tmp::/</span><span class="hl-0"> </span><span class="hl-4">plugin.wasm</span>
</code><button type="button">Copy</button></pre>
<h3 id="enable-server-debug-logging" class="tsd-anchor-link">Enable Server Debug Logging<a href="#enable-server-debug-logging" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<pre><code class="bash"><span class="hl-6"># Linux/macOS</span><br/><span class="hl-0">DEBUG</span><span class="hl-1">=</span><span class="hl-4">signalk:wasm:*</span><span class="hl-0"> </span><span class="hl-5">signalk-server</span>
</code><button type="button">Copy</button></pre>
<h3 id="common-issues" class="tsd-anchor-link">Common Issues<a href="#common-issues" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p><strong>Issue</strong>: Plugin doesn't load
<strong>Solution</strong>: Check <code>wasmManifest</code> path in package.json</p>
<p><strong>Issue</strong>: Capability errors
<strong>Solution</strong>: Ensure required capabilities declared in package.json</p>
<p><strong>Issue</strong>: Crashes on start
<strong>Solution</strong>: Check server logs for error details</p>
<h2 id="migration-from-nodejs" class="tsd-anchor-link">Migration from Node.js<a href="#migration-from-nodejs" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h2>
<h3 id="1-assess-compatibility" class="tsd-anchor-link">1. Assess Compatibility<a href="#1-assess-compatibility" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>Check if your plugin:</p>
<ul>
<li>✅ Processes deltas</li>
<li>✅ Reads/writes configuration</li>
<li>✅ Uses data model APIs</li>
<li>✅ Registers REST endpoints</li>
<li>❌ Uses serial ports (planned but not there yet)</li>
<li>✅ Makes HTTP requests (via as-fetch in AssemblyScript)</li>
<li>✅ Uses UDP/TCP sockets (rawSockets capability)</li>
</ul>
<h3 id="2-port-logic-to-rust" class="tsd-anchor-link">2. Port Logic to Rust<a href="#2-port-logic-to-rust" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>Convert TypeScript/JavaScript logic to Rust:</p>
<p><strong>Before (Node.js):</strong></p>
<pre><code class="javascript"><span class="hl-0">plugin.</span><span class="hl-7">start</span><span class="hl-0"> </span><span class="hl-1">=</span><span class="hl-0"> </span><span class="hl-1">function</span><span class="hl-0"> (</span><span class="hl-5">config</span><span class="hl-0">) {</span><br/><span class="hl-0"> app.</span><span class="hl-7">handleMessage</span><span class="hl-0">(</span><span class="hl-4">'my-plugin'</span><span class="hl-0">, {</span><br/><span class="hl-0"> updates: [{ values: [{ path: </span><span class="hl-4">'foo'</span><span class="hl-0">, value: </span><span class="hl-4">'bar'</span><span class="hl-0"> }] }]</span><br/><span class="hl-0"> })</span><br/><span class="hl-0">}</span>
</code><button type="button">Copy</button></pre>
<p><strong>After (WASM/Rust):</strong></p>
<pre><code class="rust"><span class="hl-1">fn</span><span class="hl-0"> </span><span class="hl-7">start</span><span class="hl-0">(config_ptr</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-1">*const</span><span class="hl-0"> </span><span class="hl-5">u8</span><span class="hl-0">, config_len</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-5">usize</span><span class="hl-0">) </span><span class="hl-1">-></span><span class="hl-0"> </span><span class="hl-5">i32</span><span class="hl-0"> {</span><br/><span class="hl-0"> </span><span class="hl-1">let</span><span class="hl-0"> delta </span><span class="hl-1">=</span><span class="hl-0"> </span><span class="hl-7">json!</span><span class="hl-0">({</span><br/><span class="hl-0"> </span><span class="hl-4">"updates"</span><span class="hl-1">:</span><span class="hl-0"> [{ </span><span class="hl-4">"values"</span><span class="hl-1">:</span><span class="hl-0"> [{ </span><span class="hl-4">"path"</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-4">"foo"</span><span class="hl-0">, </span><span class="hl-4">"value"</span><span class="hl-1">:</span><span class="hl-0"> </span><span class="hl-4">"bar"</span><span class="hl-0"> }] }]</span><br/><span class="hl-0"> });</span><br/><span class="hl-0"> </span><span class="hl-7">sk_emit_delta</span><span class="hl-0">(</span><span class="hl-1">&</span><span class="hl-0">delta</span><span class="hl-1">.</span><span class="hl-7">to_string</span><span class="hl-0">());</span><br/><span class="hl-0"> </span><span class="hl-2">0</span><br/><span class="hl-0">}</span>
</code><button type="button">Copy</button></pre>
<h3 id="3-migrate-data" class="tsd-anchor-link">3. Migrate Data<a href="#3-migrate-data" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h3>
<p>Use migration helper to copy existing data to VFS:</p>
<pre><code class="rust"><span class="hl-1">fn</span><span class="hl-0"> </span><span class="hl-7">first_run_migration</span><span class="hl-0">() {</span><br/><span class="hl-0"> </span><span class="hl-6">// Server provides migration API</span><br/><span class="hl-0"> </span><span class="hl-6">// Copies files from ~/.signalk/plugin-config-data/{id}/</span><br/><span class="hl-0"> </span><span class="hl-6">// to ~/.signalk/plugin-config-data/{id}/vfs/data/</span><br/><span class="hl-0">}</span>
</code><button type="button">Copy</button></pre>
<h2 id="example-plugins" class="tsd-anchor-link">Example Plugins<a href="#example-plugins" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../../../assets/icons.svg#icon-anchor"></use></svg></a></h2>
<p>The following example plugins are available in the repository:</p>
<ul>
<li><a href="https://github.com/SignalK/signalk-server/tree/master/examples/wasm-plugins/example-hello-assemblyscript">example-hello-assemblyscript</a> - Minimal AssemblyScript plugin that emits a delta on start</li>
<li><a href="https://github.com/SignalK/signalk-server/tree/master/examples/wasm-plugins/example-anchor-watch-rust">example-anchor-watch-rust</a> - Anchor watch plugin in Rust</li>
<li><a href="https://github.com/SignalK/signalk-server/tree/master/examples/wasm-plugins/example-routes-waypoints">example-routes-waypoints</a> - Resource provider for routes and waypoints</li>
<li><a href="https://github.com/SignalK/signalk-server/tree/master/examples/wasm-plugins/example-weather-provider">example-weather-provider</a> - Weather API provider implementation</li>
<li><a href="https://github.com/SignalK/signalk-server/tree/master/examples/wasm-plugins/example-weather-plugin">example-weather-plugin</a> - Weather data plugin</li>
</ul>
</div></div><div class="col-sidebar"><div class="page-menu"><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../../../assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#hot-reload"><span>Hot <wbr/>Reload</span></a><ul><li><a href="#manual-reload"><span>Manual <wbr/>Reload</span></a></li><li><a href="#reload-behavior"><span>Reload <wbr/>Behavior</span></a></li></ul><a href="#error-handling"><span>Error <wbr/>Handling</span></a><ul><li><a href="#crash-recovery"><span>Crash <wbr/>Recovery</span></a></li><li><a href="#error-reporting"><span>Error <wbr/>Reporting</span></a></li></ul><a href="#optimization"><span>Optimization</span></a><ul><li><a href="#1-minimize-binary-size"><span>1. <wbr/>Minimize <wbr/>Binary <wbr/>Size</span></a></li><li><a href="#2-handle-errors-gracefully"><span>2. <wbr/>Handle <wbr/>Errors <wbr/>Gracefully</span></a></li><li><a href="#3-use-efficient-json-parsing"><span>3. <wbr/>Use <wbr/>Efficient <wbr/>JSON <wbr/>Parsing</span></a></li><li><a href="#4-limit-memory-usage"><span>4. <wbr/>Limit <wbr/>Memory <wbr/>Usage</span></a></li><li><a href="#wasm-memory-limitations"><span>WASM <wbr/>Memory <wbr/>Limitations</span></a></li><li><a href="#5-provide-good-ux"><span>5. <wbr/>Provide <wbr/>Good <wbr/>UX</span></a></li></ul><a href="#debugging"><span>Debugging</span></a><ul><li><a href="#logging"><span>Logging</span></a></li><li><a href="#testing-locally"><span>Testing <wbr/>Locally</span></a></li><li><a href="#enable-server-debug-logging"><span>Enable <wbr/>Server <wbr/>Debug <wbr/>Logging</span></a></li><li><a href="#common-issues"><span>Common <wbr/>Issues</span></a></li></ul><a href="#migration-from-nodejs"><span>Migration from <wbr/>Node.js</span></a><ul><li><a href="#1-assess-compatibility"><span>1. <wbr/>Assess <wbr/>Compatibility</span></a></li><li><a href="#2-port-logic-to-rust"><span>2. <wbr/>Port <wbr/>Logic to <wbr/>Rust</span></a></li><li><a href="#3-migrate-data"><span>3. <wbr/>Migrate <wbr/>Data</span></a></li></ul><a href="#example-plugins"><span>Example <wbr/>Plugins</span></a></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="../../../modules.html">Signal K</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>