{"_id":"@eclatira/realtime","_rev":"4-37b4fec8e549b02a11bc92eb78a6e90b","name":"@eclatira/realtime","dist-tags":{"latest":"0.1.3"},"versions":{"0.1.0":{"name":"@eclatira/realtime","version":"0.1.0","keywords":["eclatira","voice","realtime","screen-share","webrtc","ai-agent"],"license":"MIT","_id":"@eclatira/realtime@0.1.0","maintainers":[{"name":"moadrbt","email":"contact@eclatira.com"}],"homepage":"https://docs.eclatira.com/realtime/overview","bugs":{"url":"https://github.com/Eclatira/eclatira-website-demo/issues"},"dist":{"shasum":"eec63fbc29d086e41d7850d6bfe722bef8f1a6ec","tarball":"https://registry.npmjs.org/@eclatira/realtime/-/realtime-0.1.0.tgz","fileCount":4,"integrity":"sha512-1lMLyKqz58EQ3m12CQn+GwtmzROccZZrrSyRSQcJr/0blWlKzCSrW6qYxV7PpP7t5xDxOdEvQEkizpuVKsq0WQ==","signatures":[{"sig":"MEYCIQDVdg/FdVbZOt81a4i+QYO+SNvPsSvjEkGAVAFYOUTA4wIhAOMK5b8X5jVpgbIfs4s0Yv7Wf+SnyO6ds7F4pAYFaRbR","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32917},"main":"eclatira-realtime.js","type":"module","module":"eclatira-realtime.js","engines":{"node":">=18"},"exports":{".":"./eclatira-realtime.js"},"gitHead":"dc3c37f125e1743e58a10a1a501064e3a94efc43","scripts":{"test":"node scripts/check-worklets.mjs"},"_npmUser":{"name":"moadrbt","email":"contact@eclatira.com"},"repository":{"url":"git+https://github.com/Eclatira/eclatira-website-demo.git","type":"git","directory":"packages/realtime-js"},"_npmVersion":"10.9.2","description":"Browser client for Eclatira realtime voice, camera and screen-share sessions.","directories":{},"sideEffects":false,"_nodeVersion":"23.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/realtime_0.1.0_1790101267992_0.3648907556712655","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@eclatira/realtime","version":"0.1.1","keywords":["eclatira","voice","realtime","screen-share","webrtc","ai-agent"],"license":"MIT","_id":"@eclatira/realtime@0.1.1","maintainers":[{"name":"moadrbt","email":"contact@eclatira.com"}],"homepage":"https://docs.eclatira.com/realtime/overview","bugs":{"url":"https://github.com/Eclatira/eclatira-website-demo/issues"},"dist":{"shasum":"e663a5424309b15d3778cb7b5d2edd687b2e6c76","tarball":"https://registry.npmjs.org/@eclatira/realtime/-/realtime-0.1.1.tgz","fileCount":4,"integrity":"sha512-ETXDeQu/Rl+V4zwHTlyaCz6+G3pFsNPZixSAkIn3IbLF/+vbL2hR3W2zST6DqKfGKUaLSawnLlhKj8QIgSk+gg==","signatures":[{"sig":"MEYCIQDzx+UNsnSIxL2Djo8A4+GqjFJ+EFwLAbHV2z8FuvylDAIhAKrYVVYsFQLluiixYXCK1J7BE9gd5PL/eU5kxSC1WglZ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQC44UaFg4aGqxP3e3whvO2ozJ7Z9OfyLyKfzmfhiv//UgIhAPncyniVK642DgubvUs3N26s6krwBd0zTFugitslwn0r","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33057},"main":"eclatira-realtime.js","type":"module","module":"eclatira-realtime.js","engines":{"node":">=18"},"exports":{".":"./eclatira-realtime.js"},"gitHead":"d62c2a3b06c99124e5094a4541379d5797a2bcc9","scripts":{"test":"node scripts/check-worklets.mjs"},"_npmUser":{"name":"moadrbt","email":"contact@eclatira.com"},"repository":{"url":"git+https://github.com/Eclatira/eclatira-website-demo.git","type":"git","directory":"packages/realtime-js"},"_npmVersion":"10.9.2","description":"Browser client for Eclatira realtime voice, camera and screen-share sessions.","directories":{},"sideEffects":false,"_nodeVersion":"23.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/realtime_0.1.1_1790101697373_0.026683353232192175","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@eclatira/realtime","version":"0.1.2","keywords":["eclatira","voice","realtime","screen-share","webrtc","ai-agent"],"author":{"name":"Eclatira"},"license":"MIT","_id":"@eclatira/realtime@0.1.2","maintainers":[{"name":"moadrbt","email":"contact@eclatira.com"}],"homepage":"https://docs.eclatira.com/realtime/overview","dist":{"shasum":"ba100adda0a06e36036a77baaa841febdde23478","tarball":"https://registry.npmjs.org/@eclatira/realtime/-/realtime-0.1.2.tgz","fileCount":5,"integrity":"sha512-yucHVsAp1WxhUjUG6HjjWgMzBzbkjM3/7FPSxMgHo1xmUctBv04Xl1Htv2rFL10fVUgeDykNAh6AJgxlCa7zgQ==","signatures":[{"sig":"MEYCIQC0bGVTOBUaaNmF5o9MMgjsFIRXyqc53AhDn+Z6igmCBAIhAMQdqHRfGCHuV/qnInQJu5J9rfxwf6FyAKvgRPJo7eA9","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIA/3vw7a4gAT/6/64kDThyX5IeYdrY0Zy1MLuJPKEHPCAiEAiXndJZWK+Ymjg2lyA8tsLnB4hPkl/+NfEciv080qC8s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":39149},"main":"eclatira-realtime.js","type":"module","types":"eclatira-realtime.d.ts","module":"eclatira-realtime.js","engines":{"node":">=18"},"exports":{".":{"types":"./eclatira-realtime.d.ts","default":"./eclatira-realtime.js"}},"gitHead":"9bf4dffa087dca154481d41e04384896a89147a7","scripts":{"test":"node scripts/check-worklets.mjs"},"_npmUser":{"name":"moadrbt","email":"contact@eclatira.com"},"_npmVersion":"10.9.2","description":"Browser client for Eclatira realtime voice, camera and screen-share sessions.","directories":{},"sideEffects":false,"_nodeVersion":"23.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/realtime_0.1.2_1790103009064_0.9716937078777388","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"_id":"@eclatira/realtime@0.1.3","dist":{"shasum":"4f8124248f55765145b67d0e77da4438cdf86d04","tarball":"https://registry.npmjs.org/@eclatira/realtime/-/realtime-0.1.3.tgz","fileCount":7,"integrity":"sha512-f10R6mbgnwcjaFOj/pFt+IOXb4qifb79taWjan3KQj4NriWwSHKHYHUEIy7k7tKVoRHDQH/0L90gBi7WldbmfA==","signatures":[{"sig":"MEUCIQCPo72qyHU/GfaiIznpaQCUkMe9UD8X4vt8drtyda7rVwIgbdVTrMqIWJWecmvuVlBQdzAFSDpnhbelG1cjEnrira0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC/XpHzV+lh2w2q+/ftFCh8wDsD1y5iqIL+rlFUcKGe2QIgCnXnTAmtAHiL88IQXbBGKR8ECS1fHFKVkiNG/c5Znvg="}],"unpackedSize":47317},"main":"eclatira-realtime.js","name":"@eclatira/realtime","type":"module","types":"eclatira-realtime.d.ts","author":{"name":"Eclatira"},"module":"eclatira-realtime.js","engines":{"node":">=18"},"exports":{".":{"types":"./eclatira-realtime.d.ts","default":"./eclatira-realtime.js"}},"gitHead":"a4fc73e723cf2bd5f20308d4b3ed3ce72a43bdab","license":"MIT","scripts":{"test":"node scripts/check-worklets.mjs"},"version":"0.1.3","_npmUser":{"name":"moadrbt","email":"contact@eclatira.com"},"homepage":"https://docs.eclatira.com/realtime/overview","keywords":["eclatira","voice","realtime","screen-share","webrtc","ai-agent"],"_npmVersion":"10.9.2","description":"Browser client for Eclatira realtime voice, camera and screen-share sessions.","directories":{},"maintainers":[{"name":"moadrbt","email":"contact@eclatira.com"}],"sideEffects":false,"_nodeVersion":"23.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/realtime_0.1.3_1790108403333_0.46297806040615863"}}},"time":{"created":"2026-09-22T18:21:07.754Z","modified":"2026-09-22T20:20:03.612Z","0.1.0":"2026-09-22T18:21:08.155Z","0.1.1":"2026-09-22T18:28:17.490Z","0.1.2":"2026-09-22T18:50:09.176Z","0.1.3":"2026-09-22T20:20:03.455Z"},"author":{"name":"Eclatira"},"license":"MIT","homepage":"https://docs.eclatira.com/realtime/overview","keywords":["eclatira","voice","realtime","screen-share","webrtc","ai-agent"],"description":"Browser client for Eclatira realtime voice, camera and screen-share sessions.","maintainers":[{"name":"moadrbt","email":"contact@eclatira.com"}],"readme":"# @eclatira/realtime\n\nBrowser client for Eclatira realtime sessions: voice, camera, and screen share.\n\n[![npm version](https://img.shields.io/npm/v/@eclatira/realtime)](https://www.npmjs.com/package/@eclatira/realtime)\n[![npm downloads](https://img.shields.io/npm/dm/@eclatira/realtime)](https://www.npmjs.com/package/@eclatira/realtime)\n[![types included](https://img.shields.io/npm/types/@eclatira/realtime)](https://www.npmjs.com/package/@eclatira/realtime)\n[![license](https://img.shields.io/npm/l/@eclatira/realtime)](./LICENSE)\n\nNo dependencies, no build step, nothing to host. Both `AudioWorklet`\nprocessors are compiled from source embedded in the module. Ships with\nTypeScript declarations.\n\n```bash\nnpm install @eclatira/realtime\n```\n\n```js\nimport { EclatiraSession } from \"@eclatira/realtime\";\n```\n\nNo bundler? Import it straight from a CDN, pinned to an exact version:\n\n```js\nimport { EclatiraSession } from \"https://cdn.jsdelivr.net/npm/@eclatira/realtime@0.1.2/eclatira-realtime.js\";\n```\n\nOr copy `eclatira-realtime.js` into your project directly. Use this if you\nwant zero external requests at runtime. It is one file with no dependencies\nand no build step either way.\n\n## Why this exists\n\nThe realtime protocol is a WebSocket carrying base64 audio and JPEG frames.\nThat part is simple. The media pipeline around it is not. Most of it fails\nsilently: the socket stays open, no error is raised, and the agent never\nspeaks.\n\n- The microphone must be resampled to exactly 16 kHz. `new AudioContext({ sampleRate: 16000 })`\n  is a request, not a guarantee. Safari and Firefox often ignore it and use\n  the hardware rate instead. 48 kHz audio sent as 16 kHz reaches the model\n  at 3x speed and never triggers voice activity detection.\n- The agent's reply is 24 kHz and arrives as a stream of chunks. Playing it\n  back with no gaps needs a second `AudioContext`.\n- Barge-in needs local voice activity detection plus an immediate flush of\n  the playback queue. Without it, the agent keeps talking over the user for\n  the full length of whatever is buffered.\n- `getDisplayMedia` does not give you the microphone. Its audio track is\n  system or tab audio. A screen session needs two `MediaStream`s merged\n  into one.\n- A camera or screen session with no audio connects, accepts frames, and\n  never replies, because turn-taking runs entirely on voice activity\n  detection.\n\nThis library handles all of that.\n\n## Usage\n\n```js\nimport { EclatiraSession } from \"@eclatira/realtime\";\n\nconst session = new EclatiraSession({ tokenUrl: \"/api/eclatira/token\" });\n\nsession.on(\"transcript\", ({ speaker, text, final }) => {\n  console.log(speaker, text, final);\n});\nsession.on(\"error\", (error) => console.error(error.code, error.message));\n\nawait session.start({ source: \"screen\", videoElement: preview });\n\n// later\nawait session.stop();\n```\n\n`source` is one of `\"audio\"`, `\"camera\"`, `\"screen\"`, or `\"text\"`.\n\n## You need a backend\n\nAn Eclatira API key has no scopes. The same `ek_` key can delete agents,\nplace billable calls, and read every transcript in the account, so it must\nnever reach a browser. CORS on `/api/v1/*` is also a fixed allowlist that\nwill not include your origin, so the browser cannot mint a session even if\nyou expose the key.\n\n`tokenUrl` points at an endpoint on **your** server that mints a session and\nreturns `{ ws_url }`. A complete example is in\n[`examples/token-server.mjs`](examples/token-server.mjs).\n\n```js\n// Your backend, holding the key.\nconst minted = await fetch(\"https://app.eclatira.com/api/v1/realtime/sessions\", {\n  method: \"POST\",\n  headers: {\n    authorization: `Bearer ${process.env.ECLATIRA_API_KEY}`,\n    \"content-type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    agent_id: process.env.ECLATIRA_AGENT_ID,\n    user_id: `web_${crypto.randomUUID()}`, // unique per concurrent session\n    source: \"screen\",\n  }),\n});\n```\n\nThe token is single-use and expires in 60 seconds, so mint one per\nconnection instead of caching it. If minting needs more than a `GET`, pass\n`getSession` instead of `tokenUrl`:\n\n```js\nnew EclatiraSession({\n  getSession: async ({ source }) => {\n    const response = await fetch(\"/api/eclatira/token\", {\n      method: \"POST\",\n      headers: { \"content-type\": \"application/json\" },\n      body: JSON.stringify({ source, conversationId }),\n    });\n    return response.json(); // { ws_url }\n  },\n});\n```\n\n## Options\n\n| Option | Default | Purpose |\n| --- | --- | --- |\n| `tokenUrl` | none | Your minting endpoint. Returns `{ ws_url }`. |\n| `getSession` | none | Async alternative to `tokenUrl`. |\n| `frameIntervalMs` | `2000` | Camera/screen capture interval. |\n| `frameQuality` | `0.8` | JPEG quality. |\n| `frameMaxEdge` | `1280` | Longest frame edge in pixels, after downscaling. |\n\nThe server forwards at most one frame every 3 seconds and keeps only the\nnewest one received in that window. Capturing a bit faster than that gives\nyou a fresher frame. Capturing at video rate just wastes bandwidth.\n\n## Events\n\nSubscribe with `session.on(event, handler)`, or use `addEventListener` and\nread `event.detail`.\n\n| Event | Payload |\n| --- | --- |\n| `open` | `{}`, socket opened |\n| `ready` | `{ source }`, media acquired and capture running |\n| `sessioncreated` | the server's `session_created` message |\n| `sessionended` | the server's `session_ended` message |\n| `transcript` | `{ speaker, text, final }` |\n| `agentaudio` | `{ bytes }`, decoded PCM byte count queued for playback. At 24 kHz 16-bit mono, `bytes / 48000` is seconds. |\n| `toolcall` | a `function_call` or `function_response` part |\n| `speakingchange` | `{ user, agent }` |\n| `billing` | `credits_low`, `limit_reached`, or `topup_succeeded` |\n| `error` | an `EclatiraError` with `code` and `message` |\n| `close` | `{ code, reason }` |\n| `stopped` | `{ reason }`, teardown complete and devices released |\n\n## Methods\n\n- `start({ source, videoElement })`: acquires media, mints a token,\n  connects, and begins the session, in that order. The token lives 60\n  seconds and is spent by the first connection attempt. The screen picker\n  and microphone prompt can take longer than that, so media is acquired\n  first. It resolves on the first `session_created` message, not on the\n  socket opening. A rejected session is still accepted then closed, so\n  `onopen` fires even for a bad token. A close before `session_created`\n  rejects with a mapped code: `invalid_token`, `rate_limited`,\n  `limit_reached`, `billing_blocked`, `source_not_enabled`, or\n  `server_error`.\n- `sendText(text)`: sends a typed text message. It also forces a turn,\n  which is the only way to make the agent respond to what it has seen\n  without you speaking.\n- `stop(reason)`: closes the socket, stops every track, and closes both\n  audio contexts.\n\n## Properties\n\n- `state`: `\"idle\"`, `\"connecting\"`, `\"live\"`, or `\"closed\"`\n- `agentSpeaking`, `userSpeaking`: booleans\n\n## Examples\n\nBoth files ship inside this package (`node_modules/@eclatira/realtime/examples/`\nafter `npm install`). You can also view them directly:\n\n- [`examples/token-server.mjs`](https://unpkg.com/@eclatira/realtime@0.1.3/examples/token-server.mjs): a Node token\n  proxy.\n- [`examples/screen-share.html`](https://unpkg.com/@eclatira/realtime@0.1.3/examples/screen-share.html): a complete\n  screen-share page with transcript and status.\n\nRun them together:\n\n```bash\nECLATIRA_API_KEY=ek_... ECLATIRA_AGENT_ID=agt_... node examples/token-server.mjs\nnpx serve .   # then open examples/screen-share.html\n```\n\n## Browser support\n\nRequires `AudioWorklet` and `MediaStream`: Chrome, Edge, Firefox, and Safari\n14.1+. Screen share also requires `getDisplayMedia`, which is not available\non iOS Safari. Every media API here needs a secure context (HTTPS or\n`localhost`) and a user gesture to start.\n\n## Documentation\n\n- [Realtime overview](https://docs.eclatira.com/realtime/overview)\n- [Screen share](https://docs.eclatira.com/realtime/screen-share)\n- [Media format](https://docs.eclatira.com/realtime/media-format)\n- [Troubleshooting](https://docs.eclatira.com/realtime/troubleshooting)\n","readmeFilename":"README.md"}