@voicethere/client 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +74 -0
  3. package/dist/browser/audio-visualizer.d.ts +13 -0
  4. package/dist/browser/audio-visualizer.d.ts.map +1 -0
  5. package/dist/browser/audio-visualizer.js +86 -0
  6. package/dist/browser/audio-visualizer.js.map +1 -0
  7. package/dist/browser/browser-chat-session.d.ts +14 -0
  8. package/dist/browser/browser-chat-session.d.ts.map +1 -0
  9. package/dist/browser/browser-chat-session.js +12 -0
  10. package/dist/browser/browser-chat-session.js.map +1 -0
  11. package/dist/browser/browser-session.d.ts +23 -0
  12. package/dist/browser/browser-session.d.ts.map +1 -0
  13. package/dist/browser/browser-session.js +18 -0
  14. package/dist/browser/browser-session.js.map +1 -0
  15. package/dist/browser/browser-voice-session.d.ts +20 -0
  16. package/dist/browser/browser-voice-session.d.ts.map +1 -0
  17. package/dist/browser/browser-voice-session.js +174 -0
  18. package/dist/browser/browser-voice-session.js.map +1 -0
  19. package/dist/browser/debug-console.d.ts +21 -0
  20. package/dist/browser/debug-console.d.ts.map +1 -0
  21. package/dist/browser/debug-console.js +29 -0
  22. package/dist/browser/debug-console.js.map +1 -0
  23. package/dist/browser/session-provision.d.ts +52 -0
  24. package/dist/browser/session-provision.d.ts.map +1 -0
  25. package/dist/browser/session-provision.js +92 -0
  26. package/dist/browser/session-provision.js.map +1 -0
  27. package/dist/embed/index.d.ts +21 -0
  28. package/dist/embed/index.d.ts.map +1 -0
  29. package/dist/embed/index.js +131 -0
  30. package/dist/embed/index.js.map +1 -0
  31. package/dist/index.d.ts +9 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +26 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/resolve-connection.d.ts +9 -0
  36. package/dist/resolve-connection.d.ts.map +1 -0
  37. package/dist/resolve-connection.js +23 -0
  38. package/dist/resolve-connection.js.map +1 -0
  39. package/dist/types.d.ts +36 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +2 -0
  42. package/dist/types.js.map +1 -0
  43. package/package.json +67 -0
  44. package/templates/debug-page.html +56 -0
  45. package/templates/embed.html +25 -0
  46. package/templates/react-use-voicethere.ts +52 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ ## 0.3.0 — 2026-06-15
4
+
5
+ ### Added
6
+
7
+ - `@voicethere/client/browser` — voice + DC text chat, async session provisioning poll, debug console, mic visualizer
8
+ - `@voicethere/client/embed` — `createVoiceThereWidget` floating chat launcher
9
+ - `templates/` — React hook, embed HTML, debug page starters
10
+ - CI workflow and release tag publish (mirror `@voicethere/cli`)
11
+
12
+ ## 0.1.0
13
+
14
+ - Initial `connectVoiceSession` cloud/local signaling helper
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # @voicethere/client
2
+
3
+ Browser and Node client for VoiceThere voice sessions.
4
+
5
+ ## Modes
6
+
7
+ | Mode | When | Signaling URL |
8
+ |------|------|---------------|
9
+ | **local** | M1 dev — runner on localhost | `ws://127.0.0.1:8080/ws` |
10
+ | **cloud** | M4 — platform session mint | `wss://signaling…/ws?token=<joinToken>` |
11
+
12
+ Wire protocol: [`@node-webrtc-rust/signaling`](https://www.npmjs.com/package/@node-webrtc-rust/signaling).
13
+
14
+ ## Local (runner direct)
15
+
16
+ ```typescript
17
+ import { connectVoiceSession } from "@voicethere/client";
18
+
19
+ const client = await connectVoiceSession({
20
+ mode: "local",
21
+ signalingUrl: "ws://127.0.0.1:8080/ws",
22
+ sessionId: "local-dev",
23
+ });
24
+
25
+ client.on("peer-joined", (peerId) => console.log("peer", peerId));
26
+ ```
27
+
28
+ ## Cloud (platform + gateway)
29
+
30
+ ```typescript
31
+ // Use a **client** API key (prefix vthc_) — safe to embed in web/mobile apps.
32
+ // Create one in the dashboard (/api-keys) or: voicethere api-keys create --kind client --project-id <uuid> --name "Web app"
33
+ const res = await fetch("https://app.voicethere.dev/api/v1/sessions", {
34
+ method: "POST",
35
+ headers: {
36
+ Authorization: "Bearer vthc_…",
37
+ "Content-Type": "application/json",
38
+ },
39
+ body: JSON.stringify({ project_id: "<uuid>" }),
40
+ });
41
+
42
+ const credentials = await res.json();
43
+
44
+ const client = await connectVoiceSession({
45
+ mode: "cloud",
46
+ credentials: {
47
+ sessionId: credentials.session_id,
48
+ joinToken: credentials.join_token,
49
+ signalingUrl: credentials.signaling_url,
50
+ roomId: credentials.room_id,
51
+ iceServers: credentials.ice_servers,
52
+ },
53
+ });
54
+ ```
55
+
56
+ ## Local stack verify
57
+
58
+ From workspace root (after M4 smoke infra is up):
59
+
60
+ ```bash
61
+ cd client && npm run demo:cloud
62
+ ```
63
+
64
+ npm publish via GitHub Actions on `release/*` tags — see [`scripts/RELEASE.md`](scripts/RELEASE.md).
65
+
66
+ ## Browser test page
67
+
68
+ For manual cloud testing with a client API key in the browser:
69
+
70
+ ```bash
71
+ npm run demo:browser
72
+ ```
73
+
74
+ See [`examples/browser-test/README.md`](examples/browser-test/README.md).
@@ -0,0 +1,13 @@
1
+ export type AudioVisualizerOptions = {
2
+ canvas: HTMLCanvasElement;
3
+ audioElement?: HTMLAudioElement;
4
+ mediaStream?: MediaStream;
5
+ waveColor?: string;
6
+ barColor?: string;
7
+ };
8
+ export type AudioVisualizer = {
9
+ stop: () => void;
10
+ resume: () => void;
11
+ };
12
+ export declare function attachAudioVisualizer(options: AudioVisualizerOptions): AudioVisualizer;
13
+ //# sourceMappingURL=audio-visualizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-visualizer.d.ts","sourceRoot":"","sources":["../../src/browser/audio-visualizer.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAEF,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CAwGjB"}
@@ -0,0 +1,86 @@
1
+ export function attachAudioVisualizer(options) {
2
+ const { canvas, audioElement, mediaStream, waveColor = "#38bdf8", barColor = "#818cf8", } = options;
3
+ if (!audioElement && !mediaStream) {
4
+ throw new Error("attachAudioVisualizer requires audioElement or mediaStream");
5
+ }
6
+ const ctx = canvas.getContext("2d");
7
+ if (!ctx) {
8
+ throw new Error("canvas 2d context unavailable");
9
+ }
10
+ const audioCtx = new AudioContext();
11
+ const analyser = audioCtx.createAnalyser();
12
+ analyser.fftSize = 2048;
13
+ analyser.smoothingTimeConstant = 0.75;
14
+ const streamSource = mediaStream ??
15
+ (audioElement?.srcObject instanceof MediaStream
16
+ ? audioElement.srcObject
17
+ : null);
18
+ if (streamSource) {
19
+ audioCtx.createMediaStreamSource(streamSource).connect(analyser);
20
+ }
21
+ else if (audioElement) {
22
+ const source = audioCtx.createMediaElementSource(audioElement);
23
+ source.connect(analyser);
24
+ analyser.connect(audioCtx.destination);
25
+ }
26
+ else {
27
+ throw new Error("attachAudioVisualizer requires audioElement or mediaStream");
28
+ }
29
+ const ensureRunning = () => {
30
+ if (audioCtx.state === "suspended") {
31
+ void audioCtx.resume();
32
+ }
33
+ };
34
+ if (audioElement) {
35
+ audioElement.addEventListener("playing", ensureRunning);
36
+ }
37
+ for (const track of streamSource?.getAudioTracks() ?? []) {
38
+ track.addEventListener("unmute", ensureRunning);
39
+ }
40
+ const timeData = new Uint8Array(analyser.fftSize);
41
+ const freqData = new Uint8Array(analyser.frequencyBinCount);
42
+ let rafId = 0;
43
+ let stopped = false;
44
+ const draw = () => {
45
+ if (stopped)
46
+ return;
47
+ rafId = requestAnimationFrame(draw);
48
+ const width = canvas.width;
49
+ const height = canvas.height;
50
+ ctx.clearRect(0, 0, width, height);
51
+ analyser.getByteTimeDomainData(timeData);
52
+ ctx.lineWidth = 2;
53
+ ctx.strokeStyle = waveColor;
54
+ ctx.beginPath();
55
+ const sliceWidth = width / timeData.length;
56
+ let x = 0;
57
+ for (let i = 0; i < timeData.length; i++) {
58
+ const v = timeData[i] / 128.0;
59
+ const y = (v * height) / 2;
60
+ if (i === 0)
61
+ ctx.moveTo(x, y);
62
+ else
63
+ ctx.lineTo(x, y);
64
+ x += sliceWidth;
65
+ }
66
+ ctx.lineTo(width, height / 2);
67
+ ctx.stroke();
68
+ analyser.getByteFrequencyData(freqData);
69
+ const barWidth = width / freqData.length;
70
+ for (let i = 0; i < freqData.length; i++) {
71
+ const barHeight = (freqData[i] / 255) * (height * 0.45);
72
+ ctx.fillStyle = barColor;
73
+ ctx.fillRect(i * barWidth, height - barHeight, barWidth - 1, barHeight);
74
+ }
75
+ };
76
+ draw();
77
+ return {
78
+ stop: () => {
79
+ stopped = true;
80
+ cancelAnimationFrame(rafId);
81
+ void audioCtx.close();
82
+ },
83
+ resume: ensureRunning,
84
+ };
85
+ }
86
+ //# sourceMappingURL=audio-visualizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-visualizer.js","sourceRoot":"","sources":["../../src/browser/audio-visualizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { SessionCredentials } from "./session-provision.js";
2
+ import type { DebugConsole } from "./debug-console.js";
3
+ import { type BrowserVoiceSession } from "./browser-voice-session.js";
4
+ export declare const VOICETHERE_CHAT_CHANNEL_LABEL = "voicethere";
5
+ export type BrowserChatSessionOptions = {
6
+ credentials: SessionCredentials;
7
+ peerId?: string;
8
+ onDebugEvent?: DebugConsole;
9
+ };
10
+ /**
11
+ * DC-only session — connects WebRTC without microphone for text chat debugging.
12
+ */
13
+ export declare function connectBrowserChatSession(options: BrowserChatSessionOptions): Promise<BrowserVoiceSession>;
14
+ //# sourceMappingURL=browser-chat-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-chat-session.d.ts","sourceRoot":"","sources":["../../src/browser/browser-chat-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,4BAA4B,CAAC;AAEpC,eAAO,MAAM,6BAA6B,eAAe,CAAC;AAE1D,MAAM,MAAM,yBAAyB,GAAG;IACtC,WAAW,EAAE,kBAAkB,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,mBAAmB,CAAC,CAK9B"}
@@ -0,0 +1,12 @@
1
+ import { connectBrowserVoiceSession, } from "./browser-voice-session.js";
2
+ export const VOICETHERE_CHAT_CHANNEL_LABEL = "voicethere";
3
+ /**
4
+ * DC-only session — connects WebRTC without microphone for text chat debugging.
5
+ */
6
+ export async function connectBrowserChatSession(options) {
7
+ return connectBrowserVoiceSession({
8
+ ...options,
9
+ requestMic: false,
10
+ });
11
+ }
12
+ //# sourceMappingURL=browser-chat-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-chat-session.js","sourceRoot":"","sources":["../../src/browser/browser-chat-session.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,0BAA0B,GAE3B,MAAM,4BAA4B,CAAC;AAEpC,MAAM,CAAC,MAAM,6BAA6B,GAAG,YAAY,CAAC;AAQ1D;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,OAAkC;IAElC,OAAO,0BAA0B,CAAC;QAChC,GAAG,OAAO;QACV,UAAU,EAAE,KAAK;KAClB,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { DebugConsole } from "./debug-console.js";
2
+ import type { SessionCredentials } from "./session-provision.js";
3
+ import { type BrowserVoiceSession } from "./browser-voice-session.js";
4
+ export type BrowserSessionMode = "voice" | "chat" | "both";
5
+ export type ConnectBrowserSessionOptions = {
6
+ mode: BrowserSessionMode;
7
+ credentials: SessionCredentials;
8
+ peerId?: string;
9
+ audioElement?: HTMLAudioElement;
10
+ onDebugEvent?: DebugConsole;
11
+ };
12
+ export type BrowserSession = BrowserVoiceSession & {
13
+ mode: BrowserSessionMode;
14
+ };
15
+ export declare function connectBrowserSession(options: ConnectBrowserSessionOptions): Promise<BrowserSession>;
16
+ export { connectBrowserChatSession } from "./browser-chat-session.js";
17
+ export { connectBrowserVoiceSession } from "./browser-voice-session.js";
18
+ export { startSession } from "./session-provision.js";
19
+ export { attachAudioVisualizer } from "./audio-visualizer.js";
20
+ export { createDebugConsole } from "./debug-console.js";
21
+ export type { SessionCredentials, SessionStatusResponse, StartSessionOptions, StartSessionResult, } from "./session-provision.js";
22
+ export type { DebugConsole, DebugEvent } from "./debug-console.js";
23
+ //# sourceMappingURL=browser-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-session.d.ts","sourceRoot":"","sources":["../../src/browser/browser-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,4BAA4B,CAAC;AAEpC,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAE3D,MAAM,MAAM,4BAA4B,GAAG;IACzC,IAAI,EAAE,kBAAkB,CAAC;IACzB,WAAW,EAAE,kBAAkB,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,mBAAmB,GAAG;IACjD,IAAI,EAAE,kBAAkB,CAAC;CAC1B,CAAC;AAEF,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,cAAc,CAAC,CAWzB;AAED,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,YAAY,EACV,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { connectBrowserVoiceSession, } from "./browser-voice-session.js";
2
+ export async function connectBrowserSession(options) {
3
+ const requestMic = options.mode === "voice" || options.mode === "both";
4
+ const session = await connectBrowserVoiceSession({
5
+ credentials: options.credentials,
6
+ peerId: options.peerId,
7
+ requestMic,
8
+ audioElement: options.audioElement,
9
+ onDebugEvent: options.onDebugEvent,
10
+ });
11
+ return { ...session, mode: options.mode };
12
+ }
13
+ export { connectBrowserChatSession } from "./browser-chat-session.js";
14
+ export { connectBrowserVoiceSession } from "./browser-voice-session.js";
15
+ export { startSession } from "./session-provision.js";
16
+ export { attachAudioVisualizer } from "./audio-visualizer.js";
17
+ export { createDebugConsole } from "./debug-console.js";
18
+ //# sourceMappingURL=browser-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-session.js","sourceRoot":"","sources":["../../src/browser/browser-session.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,0BAA0B,GAE3B,MAAM,4BAA4B,CAAC;AAgBpC,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAqC;IAErC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC;IACvE,MAAM,OAAO,GAAG,MAAM,0BAA0B,CAAC;QAC/C,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,UAAU;QACV,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,YAAY,EAAE,OAAO,CAAC,YAAY;KACnC,CAAC,CAAC;IAEH,OAAO,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;AAC5C,CAAC;AAED,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { SessionCredentials } from "./session-provision.js";
2
+ import type { DebugConsole } from "./debug-console.js";
3
+ export declare const VOICE_AGENT_SERVER_PEER_ID = "voice-agent-server";
4
+ export declare const VOICE_CONTROL_CHANNEL_LABEL = "voice-control";
5
+ export type BrowserVoiceSessionOptions = {
6
+ credentials: SessionCredentials;
7
+ peerId?: string;
8
+ requestMic?: boolean;
9
+ audioElement?: HTMLAudioElement;
10
+ onDebugEvent?: DebugConsole;
11
+ };
12
+ export type BrowserVoiceSession = {
13
+ peerId: string;
14
+ disconnect: () => void;
15
+ sendSpeak: (text: string) => void;
16
+ sendChat: (text: string) => void;
17
+ getMicStream: () => MediaStream | null;
18
+ };
19
+ export declare function connectBrowserVoiceSession(options: BrowserVoiceSessionOptions): Promise<BrowserVoiceSession>;
20
+ //# sourceMappingURL=browser-voice-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-voice-session.d.ts","sourceRoot":"","sources":["../../src/browser/browser-voice-session.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,eAAO,MAAM,0BAA0B,uBAAuB,CAAC;AAC/D,eAAO,MAAM,2BAA2B,kBAAkB,CAAC;AAE3D,MAAM,MAAM,0BAA0B,GAAG;IACvC,WAAW,EAAE,kBAAkB,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;CACxC,CAAC;AAMF,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,mBAAmB,CAAC,CAkM9B"}
@@ -0,0 +1,174 @@
1
+ import { appendJoinToken } from "../resolve-connection.js";
2
+ export const VOICE_AGENT_SERVER_PEER_ID = "voice-agent-server";
3
+ export const VOICE_CONTROL_CHANNEL_LABEL = "voice-control";
4
+ function defaultPeerId() {
5
+ return `client-${Math.random().toString(36).slice(2, 10)}`;
6
+ }
7
+ export async function connectBrowserVoiceSession(options) {
8
+ const debug = options.onDebugEvent;
9
+ const peerId = options.peerId ?? defaultPeerId();
10
+ const roomId = options.credentials.room_id;
11
+ const signalingUrl = appendJoinToken(options.credentials.signaling_url, options.credentials.join_token);
12
+ const iceServers = options.credentials.ice_servers?.length
13
+ ? options.credentials.ice_servers
14
+ : [{ urls: "stun:stun.l.google.com:19302" }];
15
+ let ws = null;
16
+ let pc = null;
17
+ let controlChannel = null;
18
+ let micStream = null;
19
+ const pendingIce = [];
20
+ const sendSignal = (message) => {
21
+ if (ws?.readyState === WebSocket.OPEN) {
22
+ ws.send(JSON.stringify(message));
23
+ }
24
+ };
25
+ const sendToServer = (payload) => {
26
+ sendSignal({ room: roomId, peerId, ...payload });
27
+ };
28
+ if (options.requestMic !== false) {
29
+ micStream = await navigator.mediaDevices.getUserMedia({
30
+ audio: true,
31
+ video: false,
32
+ });
33
+ debug?.info("voice", "mic_granted");
34
+ }
35
+ ws = new WebSocket(signalingUrl);
36
+ await new Promise((resolve, reject) => {
37
+ if (!ws)
38
+ return reject(new Error("WebSocket missing"));
39
+ ws.onopen = () => {
40
+ sendSignal({ type: "join", room: roomId, peerId });
41
+ debug?.info("signaling", "joined", roomId);
42
+ resolve();
43
+ };
44
+ ws.onerror = () => reject(new Error("WebSocket error"));
45
+ });
46
+ const wireControl = (channel) => {
47
+ controlChannel = channel;
48
+ channel.onopen = () => debug?.info("dc", "open", VOICE_CONTROL_CHANNEL_LABEL);
49
+ channel.onclose = () => {
50
+ debug?.info("dc", "close", VOICE_CONTROL_CHANNEL_LABEL);
51
+ controlChannel = null;
52
+ };
53
+ channel.onmessage = (event) => {
54
+ debug?.debug("dc", "message", String(event.data));
55
+ try {
56
+ const message = JSON.parse(String(event.data));
57
+ if (message.type === "speech_event") {
58
+ debug?.info("speech", message.event ?? "event", message.text);
59
+ }
60
+ else {
61
+ debug?.info("dc", message.type ?? "json", message.text);
62
+ }
63
+ }
64
+ catch {
65
+ debug?.warn("dc", "malformed", String(event.data));
66
+ }
67
+ };
68
+ };
69
+ const onServerOffer = async (sdp) => {
70
+ if (pc) {
71
+ pc.close();
72
+ pc = null;
73
+ pendingIce.length = 0;
74
+ }
75
+ pc = new RTCPeerConnection({ iceServers });
76
+ pc.ontrack = (event) => {
77
+ if (event.track.kind !== "audio")
78
+ return;
79
+ const stream = event.streams[0] ?? new MediaStream([event.track]);
80
+ if (options.audioElement) {
81
+ options.audioElement.srcObject = stream;
82
+ void options.audioElement.play().catch(() => undefined);
83
+ }
84
+ debug?.info("webrtc", "agent_audio_track");
85
+ };
86
+ pc.ondatachannel = (event) => {
87
+ if (event.channel.label === VOICE_CONTROL_CHANNEL_LABEL) {
88
+ wireControl(event.channel);
89
+ }
90
+ };
91
+ pc.onicecandidate = (event) => {
92
+ if (event.candidate) {
93
+ sendToServer({
94
+ type: "ice-candidate",
95
+ targetPeerId: VOICE_AGENT_SERVER_PEER_ID,
96
+ candidate: event.candidate.toJSON(),
97
+ });
98
+ }
99
+ };
100
+ pc.onconnectionstatechange = () => {
101
+ debug?.info("webrtc", "connection_state", pc?.connectionState);
102
+ };
103
+ await pc.setRemoteDescription(sdp);
104
+ for (const candidate of pendingIce.splice(0)) {
105
+ await pc.addIceCandidate(candidate);
106
+ }
107
+ if (micStream) {
108
+ for (const track of micStream.getAudioTracks()) {
109
+ pc.addTrack(track, micStream);
110
+ }
111
+ }
112
+ const answer = await pc.createAnswer();
113
+ await pc.setLocalDescription(answer);
114
+ sendToServer({
115
+ type: "answer",
116
+ targetPeerId: VOICE_AGENT_SERVER_PEER_ID,
117
+ sdp: pc.localDescription,
118
+ });
119
+ debug?.info("signaling", "answer_sent");
120
+ };
121
+ ws.onmessage = (event) => {
122
+ const message = JSON.parse(String(event.data));
123
+ debug?.debug("signaling", message.type, message.peerId);
124
+ switch (message.type) {
125
+ case "offer":
126
+ if (message.peerId === VOICE_AGENT_SERVER_PEER_ID && message.sdp) {
127
+ void onServerOffer(message.sdp);
128
+ }
129
+ break;
130
+ case "ice-candidate":
131
+ if (message.peerId === VOICE_AGENT_SERVER_PEER_ID &&
132
+ message.candidate &&
133
+ pc) {
134
+ if (!pc.remoteDescription) {
135
+ pendingIce.push(message.candidate);
136
+ }
137
+ else {
138
+ void pc.addIceCandidate(message.candidate);
139
+ }
140
+ }
141
+ break;
142
+ default:
143
+ break;
144
+ }
145
+ };
146
+ return {
147
+ peerId,
148
+ getMicStream: () => micStream,
149
+ sendSpeak: (text) => {
150
+ if (!controlChannel || controlChannel.readyState !== "open") {
151
+ debug?.error("dc", "speak_failed", "control channel not open");
152
+ return;
153
+ }
154
+ controlChannel.send(JSON.stringify({ type: "speak", text }));
155
+ debug?.info("dc", "speak", text);
156
+ },
157
+ sendChat: (text) => {
158
+ if (!controlChannel || controlChannel.readyState !== "open") {
159
+ debug?.error("dc", "chat_failed", "control channel not open");
160
+ return;
161
+ }
162
+ controlChannel.send(JSON.stringify({ type: "chat", text }));
163
+ debug?.info("dc", "chat", text);
164
+ },
165
+ disconnect: () => {
166
+ controlChannel?.close();
167
+ pc?.close();
168
+ micStream?.getTracks().forEach((track) => track.stop());
169
+ ws?.close();
170
+ debug?.info("session", "disconnected");
171
+ },
172
+ };
173
+ }
174
+ //# sourceMappingURL=browser-voice-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-voice-session.js","sourceRoot":"","sources":["../../src/browser/browser-voice-session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export type DebugEventLevel = "info" | "warn" | "error" | "debug";
2
+ export type DebugEvent = {
3
+ level: DebugEventLevel;
4
+ source: string;
5
+ name: string;
6
+ detail?: string;
7
+ raw?: unknown;
8
+ ts: string;
9
+ };
10
+ export type DebugEventSink = (event: DebugEvent) => void;
11
+ export declare function createDebugConsole(onEvent?: DebugEventSink): {
12
+ events: () => DebugEvent[];
13
+ clear: () => void;
14
+ info: (source: string, name: string, detail?: string, raw?: unknown) => DebugEvent;
15
+ warn: (source: string, name: string, detail?: string, raw?: unknown) => DebugEvent;
16
+ error: (source: string, name: string, detail?: string, raw?: unknown) => DebugEvent;
17
+ debug: (source: string, name: string, detail?: string, raw?: unknown) => DebugEvent;
18
+ exportText: () => string;
19
+ };
20
+ export type DebugConsole = ReturnType<typeof createDebugConsole>;
21
+ //# sourceMappingURL=debug-console.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-console.d.ts","sourceRoot":"","sources":["../../src/browser/debug-console.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAElE,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,eAAe,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;AAEzD,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,cAAc;;;mBAkBxC,MAAM,QAAQ,MAAM,WAAW,MAAM,QAAQ,OAAO;mBAEpD,MAAM,QAAQ,MAAM,WAAW,MAAM,QAAQ,OAAO;oBAEnD,MAAM,QAAQ,MAAM,WAAW,MAAM,QAAQ,OAAO;oBAEpD,MAAM,QAAQ,MAAM,WAAW,MAAM,QAAQ,OAAO;;EAUvE;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
@@ -0,0 +1,29 @@
1
+ export function createDebugConsole(onEvent) {
2
+ const events = [];
3
+ const emit = (partial) => {
4
+ const event = {
5
+ ...partial,
6
+ ts: new Date().toISOString(),
7
+ };
8
+ events.push(event);
9
+ onEvent?.(event);
10
+ return event;
11
+ };
12
+ return {
13
+ events: () => [...events],
14
+ clear: () => {
15
+ events.length = 0;
16
+ },
17
+ info: (source, name, detail, raw) => emit({ level: "info", source, name, detail, raw }),
18
+ warn: (source, name, detail, raw) => emit({ level: "warn", source, name, detail, raw }),
19
+ error: (source, name, detail, raw) => emit({ level: "error", source, name, detail, raw }),
20
+ debug: (source, name, detail, raw) => emit({ level: "debug", source, name, detail, raw }),
21
+ exportText: () => events
22
+ .map((event) => {
23
+ const detail = event.detail ? `: ${event.detail}` : "";
24
+ return `${event.ts} [${event.level}] ${event.source}/${event.name}${detail}`;
25
+ })
26
+ .join("\n"),
27
+ };
28
+ }
29
+ //# sourceMappingURL=debug-console.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-console.js","sourceRoot":"","sources":["../../src/browser/debug-console.ts"],"names":[],"mappings":"AAaA,MAAM,UAAU,kBAAkB,CAAC,OAAwB;IACzD,MAAM,MAAM,GAAiB,EAAE,CAAC;IAEhC,MAAM,IAAI,GAAG,CAAC,OAA+B,EAAE,EAAE;QAC/C,MAAM,KAAK,GAAe;YACxB,GAAG,OAAO;YACV,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SAC7B,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;QACjB,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAEF,OAAO;QACL,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC;QACzB,KAAK,EAAE,GAAG,EAAE;YACV,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QACpB,CAAC;QACD,IAAI,EAAE,CAAC,MAAc,EAAE,IAAY,EAAE,MAAe,EAAE,GAAa,EAAE,EAAE,CACrE,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;QACpD,IAAI,EAAE,CAAC,MAAc,EAAE,IAAY,EAAE,MAAe,EAAE,GAAa,EAAE,EAAE,CACrE,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;QACpD,KAAK,EAAE,CAAC,MAAc,EAAE,IAAY,EAAE,MAAe,EAAE,GAAa,EAAE,EAAE,CACtE,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;QACrD,KAAK,EAAE,CAAC,MAAc,EAAE,IAAY,EAAE,MAAe,EAAE,GAAa,EAAE,EAAE,CACtE,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;QACrD,UAAU,EAAE,GAAG,EAAE,CACf,MAAM;aACH,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACb,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,OAAO,GAAG,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,GAAG,MAAM,EAAE,CAAC;QAC/E,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC;KAChB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,52 @@
1
+ import type { DebugConsole } from "./debug-console.js";
2
+ export type SessionFailureCode = "NOT_DEPLOYED" | "RUNNER_UNAVAILABLE" | "ORCHESTRATOR_ERROR" | "JOIN_TOKEN_ERROR" | "TIMEOUT";
3
+ export type SessionJobStatus = "queued" | "provisioning" | "ready" | "failed";
4
+ export type SessionCredentials = {
5
+ session_id: string;
6
+ join_token: string;
7
+ signaling_url: string;
8
+ room_id: string;
9
+ ice_servers: Array<{
10
+ urls: string | string[];
11
+ username?: string;
12
+ credential?: string;
13
+ }>;
14
+ expires_at: string;
15
+ };
16
+ export type SessionStatusResponse = {
17
+ session_id: string;
18
+ status: SessionJobStatus;
19
+ project_id: string;
20
+ build_id: string | null;
21
+ failure_code?: SessionFailureCode | null;
22
+ failure_message?: string | null;
23
+ credentials?: SessionCredentials | null;
24
+ created_at: string;
25
+ updated_at: string;
26
+ completed_at?: string | null;
27
+ };
28
+ export type StartSessionOptions = {
29
+ apiBase: string;
30
+ projectId: string;
31
+ buildId?: string;
32
+ async?: boolean;
33
+ headers?: Record<string, string>;
34
+ pollIntervalMs?: number;
35
+ pollTimeoutMs?: number;
36
+ onStatus?: (status: SessionStatusResponse) => void;
37
+ debug?: DebugConsole;
38
+ };
39
+ export type StartSessionResult = {
40
+ ok: true;
41
+ credentials: SessionCredentials;
42
+ jobId: string;
43
+ } | {
44
+ ok: false;
45
+ code: SessionFailureCode | "TIMEOUT" | "HTTP_ERROR";
46
+ message: string;
47
+ };
48
+ /**
49
+ * POST /api/v1/sessions with async=true and poll GET until ready or failed.
50
+ */
51
+ export declare function startSession(options: StartSessionOptions): Promise<StartSessionResult>;
52
+ //# sourceMappingURL=session-provision.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-provision.d.ts","sourceRoot":"","sources":["../../src/browser/session-provision.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,MAAM,kBAAkB,GAC1B,cAAc,GACd,oBAAoB,GACpB,oBAAoB,GACpB,kBAAkB,GAClB,SAAS,CAAC;AAEd,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE9E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,KAAK,CAAC;QACjB,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;IACH,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACzC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACnD,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC5D;IACE,EAAE,EAAE,KAAK,CAAC;IACV,IAAI,EAAE,kBAAkB,GAAG,SAAS,GAAG,YAAY,CAAC;IACpD,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AA4DN;;GAEG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CA2D7B"}