UNPKG

adam-sdk

Version:

A JavaScript SDK for integrating A.D.A.M. 3D avatars into web applications.

158 lines (142 loc) 34 kB
<!DOCTYPE html><html class="default" lang="en" data-base="./"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>adam-sdk</title><meta name="description" content="Documentation for adam-sdk"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="assets/style.css"/><link rel="stylesheet" href="assets/highlight.css"/><script defer src="assets/main.js"></script><script async src="assets/icons.js" id="tsd-icons-script"></script><script async src="assets/search.js" id="tsd-search-script"></script><script async src="assets/navigation.js" id="tsd-nav-script"></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">adam-sdk</a><div id="tsd-toolbar-links"></div><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></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><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></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><h1>adam-sdk</h1></div><div class="tsd-panel tsd-typography"><h1 id="adam-sdk" class="tsd-anchor-link">adam-sdk<a href="#adam-sdk" 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><p>A JavaScript SDK for integrating A.D.A.M. 3D avatars into your web applications.</p> <h2 id="installation" class="tsd-anchor-link">Installation<a href="#installation" 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><pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">install</span><span class="hl-1"> </span><span class="hl-2">adam-sdk</span> </code><button type="button">Copy</button></pre> <h2 id="quick-start" class="tsd-anchor-link">Quick Start<a href="#quick-start" 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><pre><code class="javascript"><span class="hl-3">import</span><span class="hl-1"> { </span><span class="hl-4">AvatarSDK</span><span class="hl-1"> } </span><span class="hl-3">from</span><span class="hl-1"> </span><span class="hl-2">&#39;adam-sdk&#39;</span><span class="hl-1">;</span><br/><br/><span class="hl-5">// Get the iframe element from your page</span><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">avatarIframe</span><span class="hl-1"> = </span><span class="hl-4">document</span><span class="hl-1">.</span><span class="hl-0">getElementById</span><span class="hl-1">(</span><span class="hl-2">&#39;avatar-iframe&#39;</span><span class="hl-1">);</span><br/><br/><span class="hl-5">// Instantiate the SDK</span><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">sdk</span><span class="hl-1"> = </span><span class="hl-6">new</span><span class="hl-1"> </span><span class="hl-0">AvatarSDK</span><span class="hl-1">(</span><span class="hl-4">avatarIframe</span><span class="hl-1">);</span><br/><br/><span class="hl-5">// Listen for the &#39;ready&#39; event, which fires after a successful and secure connection</span><br/><span class="hl-4">sdk</span><span class="hl-1">.</span><span class="hl-0">on</span><span class="hl-1">(</span><span class="hl-2">&#39;ready&#39;</span><span class="hl-1">, () </span><span class="hl-6">=&gt;</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">console</span><span class="hl-1">.</span><span class="hl-0">log</span><span class="hl-1">(</span><span class="hl-2">&#39;SDK is ready! The avatar can now receive commands.&#39;</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-4">sdk</span><span class="hl-1">.</span><span class="hl-0">speak</span><span class="hl-1">(</span><span class="hl-2">&#39;Hello from the packaged SDK!&#39;</span><span class="hl-1">);</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-5">// Always handle potential connection errors</span><br/><span class="hl-4">sdk</span><span class="hl-1">.</span><span class="hl-0">connect</span><span class="hl-1">().</span><span class="hl-0">catch</span><span class="hl-1">(</span><span class="hl-4">error</span><span class="hl-1"> </span><span class="hl-6">=&gt;</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">console</span><span class="hl-1">.</span><span class="hl-0">error</span><span class="hl-1">(</span><span class="hl-2">&quot;Failed to connect to avatar:&quot;</span><span class="hl-1">, </span><span class="hl-4">error</span><span class="hl-1">);</span><br/><span class="hl-1">});</span> </code><button type="button">Copy</button></pre> <h2 id="important-changes" class="tsd-anchor-link">Important Changes<a href="#important-changes" 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>All SDK commands wait for handshake completion before sending messages to the avatar iframe. This ensures consistent behavior and reliable communication between the parent application and the avatar. All commands, including <code>speak</code>, <code>playAnimation</code>, and <code>setExpression</code>, follow the same pattern of verifying the connection before sending messages.</p> <h2 id="security-architecture" class="tsd-anchor-link">Security Architecture<a href="#security-architecture" 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>Protecting user data and sensitive API keys is the most critical aspect of the A.D.A.M. platform. Our security model is designed to be robust and transparent, ensuring that your keys are never exposed to the client-side.</p> <p>The responsibility for security is intentionally separated between this SDK and the A.D.A.M. iframe application.</p> <ul> <li><strong>The SDK (<code>adam-sdk</code>):</strong> Acts as a well-behaved <strong>messenger</strong>. Its only job is to send commands and listen for events. It has no access to your configuration or API keys.</li> <li><strong>The A.D.A.M. Iframe (<code>adam-speaks.com</code>):</strong> Acts as the <strong>security gatekeeper</strong>. It is solely responsible for verifying the identity of the website it is embedded on <em>before</em> loading any sensitive data.</li> </ul> <h3 id="the-secure-handshake-process" class="tsd-anchor-link">The Secure Handshake Process<a href="#the-secure-handshake-process" 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>When you call <code>sdk.connect()</code>, the following secure handshake takes place:</p> <ol> <li><strong>SDK Sends Handshake Request:</strong> The SDK sends a non-sensitive <code>CHECK_READY_STATUS</code> message to the iframe.</li> <li><strong>Iframe Receives Request:</strong> The iframe receives the message and inspects the <code>event.origin</code> property, which is a browser-verified value indicating the domain of your website.</li> <li><strong>Origin Verification:</strong> The iframe's internal <code>IframeSecurityService</code> sends the <code>origin</code> to a secure backend Cloud Function. This function retrieves the <strong>Trusted Origins</strong> list associated with your avatar's configuration from Firestore.</li> <li><strong>The Critical Check:</strong> The backend function compares the calling <code>origin</code> against your list of trusted domains. <ul> <li><strong>If it matches:</strong> The function signals success to the iframe.</li> <li><strong>If it does not match:</strong> The process is immediately halted. The iframe remains silent and does not respond to the SDK.</li> </ul> </li> <li><strong>Secure Config Loading:</strong> Only after a successful origin check does the <code>IframeSecurityService</code> call a second, separate Cloud Function to fetch the sensitive configuration, including your API keys.</li> <li><strong>Connection Complete:</strong> The iframe, now fully configured, sends the <code>AVATAR_READY</code> message back to the SDK. The <code>ready</code> event is fired, and your application can begin sending commands.</li> </ol> <h3 id="firestore-security-rules" class="tsd-anchor-link">Firestore Security Rules<a href="#firestore-security-rules" 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>To complete this security model, our Firestore database is locked down with the following rule, making it impossible for any client-side code to read or write to the avatar configuration collection. All data access is brokered through secure, server-side Cloud Functions.</p> <pre><code><span class="hl-5">// firestore.rules</span><br/><span class="hl-4">rules_version</span><span class="hl-1"> = </span><span class="hl-2">&#39;2&#39;</span><span class="hl-1">;</span><br/><span class="hl-4">service</span><span class="hl-1"> </span><span class="hl-4">cloud</span><span class="hl-1">.</span><span class="hl-4">firestore</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">match</span><span class="hl-1"> /</span><span class="hl-4">databases</span><span class="hl-1">/{</span><span class="hl-4">database</span><span class="hl-1">}/</span><span class="hl-4">documents</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">// Disallow ALL client-side reads/writes to the avatars collection.</span><br/><span class="hl-1"> </span><span class="hl-4">match</span><span class="hl-1"> /</span><span class="hl-4">avatars</span><span class="hl-1">/{</span><span class="hl-4">avatarId</span><span class="hl-1">} {</span><br/><span class="hl-1"> </span><span class="hl-4">allow</span><span class="hl-1"> </span><span class="hl-4">read</span><span class="hl-1">, </span><span class="hl-8">write</span><span class="hl-1">: </span><span class="hl-3">if</span><span class="hl-1"> </span><span class="hl-6">false</span><span class="hl-1">;</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> </code><button>Copy</button></pre> <h3 id="troubleshooting-connection-timeouts" class="tsd-anchor-link">Troubleshooting Connection Timeouts<a href="#troubleshooting-connection-timeouts" 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>If the <code>sdk.connect()</code> promise rejects with a timeout error, it is a direct result of the security model working as intended.</strong></p> <p>This error means that the domain of the website where you are running the SDK has <strong>not</strong> been added to the <strong>&quot;Trusted Origins&quot;</strong> list in your A.D.A.M. admin console. To fix this, simply add the required domain (e.g., <code>https://www.your-production-site.com</code> or <code>http://localhost:3000</code> for development) to the list.</p> <h2 id="common-message-contract" class="tsd-anchor-link">Common Message Contract<a href="#common-message-contract" 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 SDK and example templates communicate with the avatar iframe using <code>window.postMessage</code>. Messages are simple JSON objects with a <code>type</code> and an optional <code>payload</code>.</p> <p>Security note: Always set the <code>targetOrigin</code> to your trusted iframe origin (e.g., <code>https://your-avatar-host.example</code>) instead of <code>*</code> in production.</p> <h3 id="outgoing-commands-parent-→-iframe" class="tsd-anchor-link">Outgoing Commands (parent → iframe)<a href="#outgoing-commands-parent-→-iframe" 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><code>speak</code><pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-9">&quot;type&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;speak&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-9">&quot;requestId&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;optional-uuid&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-9">&quot;payload&quot;</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-9">&quot;text&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;Hello world&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-9">&quot;animation&quot;</span><span class="hl-1">: { </span><span class="hl-9">&quot;name&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;wave&quot;</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-9">&quot;expression&quot;</span><span class="hl-1">: { </span><span class="hl-9">&quot;name&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;smile&quot;</span><span class="hl-1">, </span><span class="hl-9">&quot;intensity&quot;</span><span class="hl-1">: </span><span class="hl-10">0.8</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-9">&quot;voice&quot;</span><span class="hl-1">: { </span><span class="hl-9">&quot;id&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;en-US-JennyNeural&quot;</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-9">&quot;backgroundUrl&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;https://cdn.example.com/scenes/lobby.jpg&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-9">&quot;scene&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;lobby&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-9">&quot;customFlag&quot;</span><span class="hl-1">: </span><span class="hl-6">true</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> </code><button type="button">Copy</button></pre> </li> <li><code>animation</code><pre><code class="json"><span class="hl-1">{ </span><span class="hl-9">&quot;type&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;animation&quot;</span><span class="hl-1">, </span><span class="hl-9">&quot;payload&quot;</span><span class="hl-1">: { </span><span class="hl-9">&quot;name&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;wave&quot;</span><span class="hl-1"> }, </span><span class="hl-9">&quot;requestId&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;optional-uuid&quot;</span><span class="hl-1"> }</span> </code><button type="button">Copy</button></pre> </li> <li><code>expression</code><pre><code class="json"><span class="hl-1">{ </span><span class="hl-9">&quot;type&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;expression&quot;</span><span class="hl-1">, </span><span class="hl-9">&quot;payload&quot;</span><span class="hl-1">: { </span><span class="hl-9">&quot;name&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;smile&quot;</span><span class="hl-1">, </span><span class="hl-9">&quot;intensity&quot;</span><span class="hl-1">: </span><span class="hl-10">0.8</span><span class="hl-1"> }, </span><span class="hl-9">&quot;requestId&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;optional-uuid&quot;</span><span class="hl-1"> }</span> </code><button type="button">Copy</button></pre> </li> </ul> <p>Fields:</p> <ul> <li><code>type</code>: Command name.</li> <li><code>payload</code>: Command parameters (<code>text</code> is required; <code>animation</code>, <code>expression</code>, and <code>voice</code> are optional). You may include any additional custom key/value pairs. They will be forwarded to the iframe payload as-is.</li> <li><code>requestId</code> (optional): Provide to correlate command responses.</li> </ul> <h3 id="incoming-events-iframe-→-parent" class="tsd-anchor-link">Incoming Events (iframe → parent)<a href="#incoming-events-iframe-→-parent" 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>Ready<pre><code class="json"><span class="hl-1">{ </span><span class="hl-9">&quot;type&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;ready&quot;</span><span class="hl-1"> }</span> </code><button type="button">Copy</button></pre> </li> <li>Speech start/end<pre><code class="json"><span class="hl-1">{ </span><span class="hl-9">&quot;type&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;speech:start&quot;</span><span class="hl-1">, </span><span class="hl-9">&quot;payload&quot;</span><span class="hl-1">: { </span><span class="hl-9">&quot;utteranceId&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;u1&quot;</span><span class="hl-1"> } }</span><br/><span class="hl-1">{ </span><span class="hl-9">&quot;type&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;speech:end&quot;</span><span class="hl-1">, </span><span class="hl-9">&quot;payload&quot;</span><span class="hl-1">: { </span><span class="hl-9">&quot;utteranceId&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;u1&quot;</span><span class="hl-1"> } }</span> </code><button type="button">Copy</button></pre> </li> <li>Command success/error<pre><code class="json"><span class="hl-1">{ </span><span class="hl-9">&quot;type&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;command:success&quot;</span><span class="hl-1">, </span><span class="hl-9">&quot;payload&quot;</span><span class="hl-1">: { </span><span class="hl-9">&quot;requestId&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;optional-uuid&quot;</span><span class="hl-1">, </span><span class="hl-9">&quot;result&quot;</span><span class="hl-1">: { } } }</span><br/><span class="hl-1">{ </span><span class="hl-9">&quot;type&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;command:error&quot;</span><span class="hl-1">, </span><span class="hl-9">&quot;payload&quot;</span><span class="hl-1">: { </span><span class="hl-9">&quot;requestId&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;optional-uuid&quot;</span><span class="hl-1">, </span><span class="hl-9">&quot;message&quot;</span><span class="hl-1">: </span><span class="hl-2">&quot;details&quot;</span><span class="hl-1"> } }</span> </code><button type="button">Copy</button></pre> </li> </ul> <p>Event notes:</p> <ul> <li>Always validate <code>event.origin</code> against your trusted domain list before acting on events.</li> <li>If you use <code>requestId</code> on commands, include it in success/error payloads for correlation.</li> </ul> <h2 id="starter-templates-react-angular-vue" class="tsd-anchor-link">Starter Templates (React, Angular, Vue)<a href="#starter-templates-react-angular-vue" 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>We include minimal, no-bloat starter templates under <code>adam-sdk/examples/</code> that are ready to embed the avatar via an iframe and communicate using <code>window.postMessage</code>. Each template exposes simple placeholder methods and event handling:</p> <ul> <li><code>speak(text)</code></li> <li><code>animation(name)</code></li> <li><code>expression(name, intensity)</code></li> <li><code>onEvent(handler)</code> for iframe-emitted events like <code>ready</code>, <code>speech:start</code>, <code>speech:end</code>, etc.</li> </ul> <p>Important: In the example bridges, the postMessage <code>origin</code> is <code>*</code> for convenience. For production, replace <code>*</code> with your real iframe origin (e.g., <code>https://your-avatar-host.example</code>).</p> <h3 id="react-vite" class="tsd-anchor-link">React (Vite)<a href="#react-vite" 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>Directory: <code>adam-sdk/examples/react/</code></p> <ol> <li>Install and run:<pre><code class="bash"><span class="hl-0">cd</span><span class="hl-1"> </span><span class="hl-2">adam-sdk/examples/react</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">install</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">dev</span> </code><button type="button">Copy</button></pre> </li> <li>Edit <code>src/avatarBridge.js</code> to lock the <code>origin</code> and update the <code>&lt;iframe src&gt;</code> in <code>src/App.jsx</code> to your hosted avatar URL.</li> </ol> <h3 id="angular-standalone--vite" class="tsd-anchor-link">Angular (Standalone + Vite)<a href="#angular-standalone--vite" 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>Directory: <code>adam-sdk/examples/angular/</code></p> <ol> <li>Install and run:<pre><code class="bash"><span class="hl-0">cd</span><span class="hl-1"> </span><span class="hl-2">adam-sdk/examples/angular</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">install</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">start</span> </code><button type="button">Copy</button></pre> </li> <li>Edit <code>src/app/avatar-bridge.ts</code> to lock the <code>origin</code> and update the <code>&lt;iframe&gt;</code> <code>src</code> in <code>src/app/app.component.html</code>.</li> <li>Template is separate from the class, following the project guideline.</li> </ol> <h3 id="vue-3-vite" class="tsd-anchor-link">Vue 3 (Vite)<a href="#vue-3-vite" 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>Directory: <code>adam-sdk/examples/vue/</code></p> <ol> <li>Install and run:<pre><code class="bash"><span class="hl-0">cd</span><span class="hl-1"> </span><span class="hl-2">adam-sdk/examples/vue</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">install</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">dev</span> </code><button type="button">Copy</button></pre> </li> <li>Edit <code>src/avatarBridge.js</code> to lock the <code>origin</code> and update the <code>&lt;iframe src&gt;</code> in <code>src/App.vue</code>.</li> </ol> <p>All templates are intentionally small, with just enough structure to demonstrate:</p> <ul> <li>Embedding the iframe and sending commands</li> <li>Receiving events and basic logging</li> <li>Where to securely configure origins and endpoints</li> </ul> <h2 id="additional-docs" class="tsd-anchor-link">Additional Docs<a href="#additional-docs" 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><ul> <li>Message Contract: <code>docs/message-contract.html</code></li> <li>Starter Templates: <code>docs/examples-starters.html</code></li> </ul> <h2 id="api-documentation" class="tsd-anchor-link">API Documentation<a href="#api-documentation" 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>To view the full, detailed API documentation:</p> <ol> <li><strong>Generate the docs:</strong><pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">docs</span> </code><button type="button">Copy</button></pre> </li> <li><strong>Serve the docs locally:</strong><pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">docs:serve</span> </code><button type="button">Copy</button></pre> </li> </ol> <p>This will start a local web server and provide a URL to view the documentation in your browser.</p> <h2 id="events" class="tsd-anchor-link">Events<a href="#events" 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>Listen for events using the <code>sdk.on()</code> method:</p> <ul> <li><code>ready</code>: Fired when the SDK has successfully and securely connected to the avatar iframe.</li> <li><code>speech:start</code>: Fired when the avatar starts speaking.</li> <li><code>speech:end</code>: Fired when the avatar finishes speaking.</li> <li><code>command:success</code>: Fired when a command is successfully executed.</li> <li><code>command:error</code>: Fired when a command fails.</li> </ul> <h2 id="release--publish" class="tsd-anchor-link">Release &amp; Publish<a href="#release--publish" 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>We include the built API docs (<code>docs/</code>) in the npm package alongside the compiled library (<code>dist/</code>). The publish flow automatically builds both via <code>prepublishOnly</code>.</p> <ul> <li><strong>Version</strong>: set in <code>package.json</code> (current: <code>1.0.3</code>). For future releases: <code>npm version patch|minor|major -m &quot;chore(release): %s&quot;</code>.</li> <li><strong>Build</strong>: <code>npm run build</code> (Vite)</li> <li><strong>Docs</strong>: <code>npm run docs</code> (TypeDoc → <code>docs/</code>)</li> <li><strong>Auto step on publish</strong>: <code>prepublishOnly</code> runs <code>build</code> and <code>docs</code> automatically.</li> </ul> <h3 id="steps-to-publish" class="tsd-anchor-link">Steps to publish<a href="#steps-to-publish" 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>Run from <code>adam-sdk/adam-sdk/</code>:</p> <pre><code class="bash"><span class="hl-5"># 1) Verify npm login and access</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">whoami</span><br/><br/><span class="hl-5"># 2) Install clean deps</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">ci</span><br/><br/><span class="hl-5"># 3) (Optional) Test/build/docs locally</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">test</span><span class="hl-1"> || </span><span class="hl-0">true</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">build</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">docs</span><br/><br/><span class="hl-5"># 4) Publish (triggers prepublishOnly: build + docs)</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">publish</span><span class="hl-1"> </span><span class="hl-6">--access</span><span class="hl-1"> </span><span class="hl-2">public</span> </code><button type="button">Copy</button></pre> <p>Notes:</p> <ul> <li>If your npm account uses 2FA for publishing, be ready to enter your OTP.</li> <li>The published tarball includes <code>dist/</code> and <code>docs/</code> (see the <code>files</code> field).</li> </ul> </div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><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>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><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="#adam-sdk"><span>adam-<wbr/>sdk</span></a><ul><li><a href="#installation"><span>Installation</span></a></li><li><a href="#quick-start"><span>Quick <wbr/>Start</span></a></li><li><a href="#important-changes"><span>Important <wbr/>Changes</span></a></li><li><a href="#security-architecture"><span>Security <wbr/>Architecture</span></a></li><li><ul><li><a href="#the-secure-handshake-process"><span>The <wbr/>Secure <wbr/>Handshake <wbr/>Process</span></a></li><li><a href="#firestore-security-rules"><span>Firestore <wbr/>Security <wbr/>Rules</span></a></li><li><a href="#troubleshooting-connection-timeouts"><span>Troubleshooting <wbr/>Connection <wbr/>Timeouts</span></a></li></ul></li><li><a href="#common-message-contract"><span>Common <wbr/>Message <wbr/>Contract</span></a></li><li><ul><li><a href="#outgoing-commands-parent-→-iframe"><span>Outgoing <wbr/>Commands (parent → iframe)</span></a></li><li><a href="#incoming-events-iframe-→-parent"><span>Incoming <wbr/>Events (iframe → parent)</span></a></li></ul></li><li><a href="#starter-templates-react-angular-vue"><span>Starter <wbr/>Templates (<wbr/>React, <wbr/>Angular, <wbr/>Vue)</span></a></li><li><ul><li><a href="#react-vite"><span>React (<wbr/>Vite)</span></a></li><li><a href="#angular-standalone--vite"><span>Angular (<wbr/>Standalone + <wbr/>Vite)</span></a></li><li><a href="#vue-3-vite"><span>Vue 3 (<wbr/>Vite)</span></a></li></ul></li><li><a href="#additional-docs"><span>Additional <wbr/>Docs</span></a></li><li><a href="#api-documentation"><span>API <wbr/>Documentation</span></a></li><li><a href="#events"><span>Events</span></a></li><li><a href="#release--publish"><span>Release &amp; <wbr/>Publish</span></a></li><li><ul><li><a href="#steps-to-publish"><span>Steps to publish</span></a></li></ul></li></ul></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="modules.html">adam-sdk</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>