@craftedxp/voice-js 0.5.4 → 0.9.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 (42) hide show
  1. package/CONSUMING.md +6 -2
  2. package/README.md +31 -4
  3. package/dist/assistant.d.mts +32 -0
  4. package/dist/assistant.d.ts +32 -0
  5. package/dist/assistant.js +1241 -0
  6. package/dist/assistant.js.map +1 -0
  7. package/dist/assistant.mjs +23 -0
  8. package/dist/assistant.mjs.map +1 -0
  9. package/dist/browser.d.mts +12 -509
  10. package/dist/browser.d.ts +12 -608
  11. package/dist/browser.js +1020 -896
  12. package/dist/browser.js.map +1 -1
  13. package/dist/browser.mjs +25 -1283
  14. package/dist/browser.mjs.map +1 -1
  15. package/dist/chunk-LV7JGPYW.mjs +200 -0
  16. package/dist/chunk-LV7JGPYW.mjs.map +1 -0
  17. package/dist/chunk-ZW22Y67M.mjs +1208 -0
  18. package/dist/chunk-ZW22Y67M.mjs.map +1 -0
  19. package/dist/config-D2TbvIqT.d.mts +297 -0
  20. package/dist/config-D2TbvIqT.d.ts +297 -0
  21. package/dist/embed.iife.js +30 -23358
  22. package/dist/incomingCall-CfRRzj2P.d.mts +103 -0
  23. package/dist/incomingCall-CfRRzj2P.d.ts +103 -0
  24. package/dist/node.d.mts +69 -139
  25. package/dist/node.d.ts +342 -496
  26. package/dist/node.js +472 -467
  27. package/dist/node.js.map +1 -1
  28. package/dist/node.mjs +19 -0
  29. package/dist/node.mjs.map +1 -1
  30. package/dist/room.d.mts +156 -0
  31. package/dist/room.d.ts +156 -0
  32. package/dist/room.js +236 -0
  33. package/dist/room.js.map +1 -0
  34. package/dist/room.mjs +7 -0
  35. package/dist/room.mjs.map +1 -0
  36. package/dist/transcribe.d.mts +14 -0
  37. package/dist/transcribe.d.ts +14 -0
  38. package/dist/transcribe.js +1213 -0
  39. package/dist/transcribe.js.map +1 -0
  40. package/dist/transcribe.mjs +18 -0
  41. package/dist/transcribe.mjs.map +1 -0
  42. package/package.json +22 -4
@@ -1,514 +1,17 @@
1
- import { RemoteTrack, LocalVideoTrack } from 'livekit-client';
2
-
3
- interface ClientTool {
4
- description: string;
5
- parameters: Record<string, unknown>;
6
- usage?: string;
7
- timeoutMs?: number;
8
- example?: string;
9
- handler: (args: Record<string, unknown>) => Promise<string | object> | string | object;
10
- }
11
- type ClientToolMap = Record<string, ClientTool>;
12
- interface ClientToolCallFrame {
13
- toolCallId: string;
14
- name: string;
15
- args: Record<string, unknown>;
16
- }
17
-
18
- type CallState = 'idle' | 'connecting' | 'listening' | 'user_speaking' | 'agent_speaking' | 'ended' | 'error';
19
- type TranscriptEntry = {
20
- id: string;
21
- role: 'user';
22
- text: string;
23
- committed: boolean;
24
- } | {
25
- id: string;
26
- role: 'agent';
27
- text: string;
28
- interrupted?: boolean;
29
- } | {
30
- id: string;
31
- role: 'tool';
32
- text: string;
33
- } | {
34
- id: string;
35
- role: 'system';
36
- text: string;
37
- };
38
- type CallErrorCode = 'missing_credentials' | 'forbidden' | 'mic_denied' | 'mic_start_failed' | 'audio_session_failed' | 'token_expired' | 'token_invalid' | 'unauthorized' | 'network_unreachable' | 'socket_error' | 'payment_required' | 'not_found' | 'silence_timeout' | 'server_error';
39
- interface CallError {
40
- code: CallErrorCode;
41
- message: string;
42
- }
43
- type CallEndReason = 'agent_ended' | 'user_hangup' | 'timeout' | 'error';
44
- interface CallEndEvent {
45
- reason: CallEndReason;
46
- errorCode?: CallErrorCode;
47
- durationMs: number;
48
- }
49
- interface VolumeEvent {
50
- input: number;
51
- output: number;
52
- }
53
- type ServerMessage = Record<string, unknown> & {
54
- type?: string;
55
- };
56
- interface ProtocolState {
57
- state: CallState;
58
- transcript: TranscriptEntry[];
59
- agentBubbleId: string | null;
60
- idCounter: number;
61
- endReason: CallEndReason | null;
62
- }
63
- declare const createProtocolState: () => ProtocolState;
64
- interface ProtocolCallbacks {
65
- onState: (next: CallState) => void;
66
- onTranscript: (entries: TranscriptEntry[]) => void;
67
- onError: (err: CallError) => void;
68
- onInterrupt: () => void;
69
- onAgentTurnStart: (seq?: number) => void;
70
- onAgentTurnEnd: (seq?: number) => void;
71
- onCallEnd: (reason: CallEndReason) => void;
72
- onConnected: () => void;
73
- onClientToolCall: (frame: ClientToolCallFrame) => void;
74
- }
75
- declare function handleServerMessage(raw: string, state: ProtocolState, cb: ProtocolCallbacks): void;
76
- interface BuildWsUrlArgs {
77
- apiBase: string;
78
- agentId: string;
79
- token: string;
80
- bargeIn?: boolean;
81
- }
82
- declare function buildWsUrl(args: BuildWsUrlArgs): string;
83
-
84
- type SystemMessage = {
85
- kind: 'room.starting';
86
- at: string;
87
- } | {
88
- kind: 'room.ending.soon';
89
- minutesRemaining: 5 | 1;
90
- } | {
91
- kind: 'room.ended';
92
- reason: 'duration_reached' | 'manual' | 'empty';
93
- } | {
94
- kind: 'role.promoted';
95
- participantId: string;
96
- name: string;
97
- } | {
98
- kind: 'role.demoted';
99
- participantId: string;
100
- name: string;
101
- } | {
102
- kind: 'participant.removed';
103
- participantId: string;
104
- name: string;
105
- byHost?: string;
106
- } | {
107
- kind: 'notetaker.connected';
108
- } | {
109
- kind: 'notetaker.disconnected';
110
- } | {
111
- kind: 'notetaker.partial_degraded';
112
- participantId: string;
113
- };
114
- type TranscriptMessage = {
115
- kind: 'partial';
116
- participantId: string;
117
- speakerName: string;
118
- text: string;
119
- startedAt: string;
120
- };
121
-
122
- interface JoinRoomOptions {
123
- /** Full HTTPS URL of the Voissia server. Same shape as VoiceClientConfig.apiBase. */
124
- apiBase: string;
125
- /** Server-generated room id (`rm_…`). */
126
- roomId: string;
127
- /** Shared room join token from the invite link. Mints a fresh participant each call. */
128
- joinCode: string;
129
- /** Display name the joiner registers under for this participant. */
130
- name: string;
131
- }
132
- interface RoomParticipantInfo {
133
- /** Stable participant id (`p_…`); strips any `guest:` LiveKit identity prefix. */
134
- participantId: string;
135
- /** Display name as the worker registered it; may be empty. */
136
- name: string;
137
- }
138
- type RoomTrackKind = 'audio' | 'video';
139
- /** What a track is — lets consumers tell a camera apart from a screen share
140
- * (a participant can publish both at once). Mirrors livekit `Track.Source`. */
141
- type RoomTrackSource = 'camera' | 'microphone' | 'screen_share' | 'screen_share_audio' | 'unknown';
142
- interface RoomTrackEvent {
143
- /** Stable participant id (`p_…`); `guest:` prefix stripped. */
144
- participantId: string;
145
- kind: RoomTrackKind;
146
- /** Distinguishes camera vs screen_share so each can render as its own tile. */
147
- source: RoomTrackSource;
148
- /** livekit-client track — call `.attach(el)` / `.detach()` to render. */
149
- track: RemoteTrack;
150
- }
151
- type RoomEventName = 'participant.joined' | 'participant.left' | 'transcript.partial' | 'transcript.final' | 'system.message' | 'room.ended' | 'track.subscribed' | 'track.unsubscribed' | 'active.speakers';
152
- interface RoomEventPayloads {
153
- 'participant.joined': RoomParticipantInfo;
154
- 'participant.left': RoomParticipantInfo;
155
- 'transcript.partial': TranscriptMessage;
156
- /**
157
- * Reserved — the worker currently emits only partials over the transcript
158
- * topic. Final-utterance events will land in Phase 8 once the worker
159
- * publishes a `final` kind; the SDK keeps the slot reserved so consumers
160
- * can register handlers today.
161
- */
162
- 'transcript.final': {
163
- participantId: string;
164
- speakerName: string;
165
- text: string;
166
- startedAt: string;
167
- };
168
- 'system.message': SystemMessage;
169
- 'room.ended': undefined;
170
- 'track.subscribed': RoomTrackEvent;
171
- 'track.unsubscribed': RoomTrackEvent;
172
- /** participantIds currently speaking (drives an active-speaker UI). */
173
- 'active.speakers': string[];
174
- }
175
- type Handler<E extends RoomEventName> = (payload: RoomEventPayloads[E]) => void;
176
- interface RoomSession {
177
- /** This session's own stable participant id (`p_…`). Useful to filter
178
- * yourself out of `active.speakers`, which includes the local participant. */
179
- readonly participantId: string;
180
- /** Snapshot of the remote participants currently connected. */
181
- readonly participants: RoomParticipantInfo[];
182
- /** Subscribe to a typed event. No unsubscribe surface yet (mirrors `Call.onX`). */
183
- on<E extends RoomEventName>(event: E, handler: Handler<E>): void;
184
- /** Publish the local mic track. Resolves once the track is live on LiveKit. */
185
- publishMic(): Promise<void>;
186
- /** Publish the local camera track. */
187
- publishCamera(): Promise<void>;
188
- /** Mid-call mute/unmute of the local mic. */
189
- setMicEnabled(on: boolean): Promise<void>;
190
- /** Mid-call camera on/off. */
191
- setCameraEnabled(on: boolean): Promise<void>;
192
- /** Current local mic state (for toggle UI). */
193
- isMicEnabled(): boolean;
194
- /** Current local camera state (for toggle UI). */
195
- isCameraEnabled(): boolean;
196
- /** The local camera track for self-view, or null before publishCamera resolves. */
197
- getLocalCameraTrack(): LocalVideoTrack | null;
198
- /**
199
- * Remote tracks already subscribed at this moment. A late joiner misses the
200
- * live `track.subscribed` events for tracks published before it connected
201
- * (LiveKit delivers them during `connect`, before consumer listeners attach).
202
- * Call this right after registering `track.subscribed` to backfill them.
203
- */
204
- getRemoteTracks(): RoomTrackEvent[];
205
- /**
206
- * Start/stop sharing the screen (via `getDisplayMedia`). Pass `{ audio: true }`
207
- * to also capture shared/system audio where the browser allows it (Chrome:
208
- * tab or system audio; macOS Chrome is tab-audio only; Safari/Firefox don't
209
- * capture share audio). Publishes a `screen_share` video track (+ optional
210
- * `screen_share_audio`); remote peers receive them via `track.subscribed`.
211
- */
212
- setScreenShareEnabled(on: boolean, opts?: {
213
- audio?: boolean;
214
- }): Promise<void>;
215
- /** Current local screen-share state (for toggle UI). */
216
- isScreenShareEnabled(): boolean;
217
- /** The local screen-share video track for self-preview, or null when off. */
218
- getLocalScreenTrack(): LocalVideoTrack | null;
219
- /** Disconnect from LiveKit. Idempotent. Triggers `room.ended` via Disconnected. */
220
- leave(): Promise<void>;
221
- }
222
- declare const joinRoom: (opts: JoinRoomOptions) => Promise<RoomSession>;
223
-
224
- interface FetchTokenArgs {
225
- /** The agent the SDK is about to call. */
226
- agentId: string;
227
- /**
228
- * Optional consumer-side user identifier. Round-tripped to the server
229
- * as `contactId` for Phase 11 contact memory. The SDK does not
230
- * inspect this; your backend uses it to scope the token mint.
231
- */
232
- userId?: string;
233
- /**
234
- * Per-call structured context lowered into the agent's effective
235
- * system prompt server-side at session open. Opaque to the SDK.
236
- */
237
- context?: Record<string, unknown>;
238
- /**
239
- * String key/value pairs round-tripped on the `call.ended` webhook.
240
- * Capped at 1 KB total server-side. NOT lowered into the system prompt.
241
- */
242
- metadata?: Record<string, string>;
243
- }
244
- /**
245
- * What `fetchToken` may return. The rich object form lets the server
246
- * choose the transport per call. Returning a bare string is backwards-
247
- * compatible — the SDK treats it as `{ token, transport: 'ws' }`.
248
- */
249
- interface FetchTokenResult {
250
- /** Raw `ct_` to feed into the WS open / WebRTC offer. */
251
- token: string;
252
- /** Server-selected transport. Default `'ws'` if absent. */
253
- transport?: 'ws' | 'webrtc';
254
- /** Required when `transport === 'webrtc'` AND the server uses a
255
- * separate signaling gateway. When omitted on a webrtc result, the
256
- * SDK falls back to the API base's Phase-1 routes (local dev). */
257
- webrtcGatewayBase?: string;
258
- }
259
- type FetchToken = (args: FetchTokenArgs) => Promise<string | FetchTokenResult>;
260
- interface VoiceClientConfig {
261
- /**
262
- * Full HTTPS URL of the Voissia server. The WebSocket scheme is
263
- * derived: `https` → `wss`, `http` → `ws`. No trailing slash needed.
264
- */
265
- apiBase: string;
266
- /**
267
- * Called by the SDK whenever it needs a fresh `ct_` token (initial
268
- * connect; mid-call refresh on `token_expired`). Your implementation
269
- * should hit YOUR backend, which holds the `sk_` API key and mints
270
- * via `POST /v1/call-tokens` (or `client.callTokens.mint` from
271
- * @craftedxp/sdk-node). Never embed `sk_` in JS code that ships to a
272
- * client.
273
- */
274
- fetchToken: FetchToken;
275
- /**
276
- * Optional metadata applied to EVERY startCall. Per-call `metadata`
277
- * in `startCall` is merged on top (per-call wins on key conflicts).
278
- * Useful for dashboard-wide tags like `{ surface: 'web', appVersion }`.
279
- */
280
- defaultMetadata?: Record<string, string>;
281
- /**
282
- * Optional context applied to EVERY startCall. Per-call `context` in
283
- * `startCall` is merged on top. Useful for cross-call invariants like
284
- * the signed-in user's locale.
285
- */
286
- defaultContext?: Record<string, unknown>;
287
- }
288
- interface StartCallOptions {
289
- /** The agent to call. */
290
- agentId: string;
291
- /** Per-call user identifier. Round-tripped to fetchToken as `userId`. */
292
- userId?: string;
293
- /**
294
- * Per-call structured context. Merged on top of `defaultContext`
295
- * configured at factory time.
296
- */
297
- context?: Record<string, unknown>;
298
- /**
299
- * Per-call metadata. Merged on top of `defaultMetadata` configured
300
- * at factory time.
301
- */
302
- metadata?: Record<string, string>;
303
- /**
304
- * When false, the SDK + server stay full-duplex but barge-in is
305
- * suppressed. Useful for alarm-style flows where the user shouldn't
306
- * accidentally interrupt the script. Default true.
307
- */
308
- bargeIn?: boolean;
309
- /**
310
- * Client-side tools the agent's LLM can call mid-conversation. Each
311
- * tool's handler runs on the consumer's side; result is fed back to
312
- * the LLM through the existing call WebSocket. Schema and handler
313
- * colocate. Validated synchronously at startCall — bad input throws.
314
- *
315
- * See docs/integration-echocheck.md for the wire protocol and the
316
- * server-side guarantees.
317
- */
318
- clientTools?: ClientToolMap;
319
- /**
320
- * Test-only escape hatch — pass a pre-minted `ct_` directly and skip
321
- * the `fetchToken` call. Don't use this in production code: tokens
322
- * expire and the SDK can't re-mint without the callback.
323
- */
324
- token?: string;
325
- onStateChange?: (state: CallState) => void;
326
- onTranscript?: (entries: TranscriptEntry[]) => void;
327
- onError?: (err: CallError) => void;
328
- onEnd?: (end: CallEndEvent) => void;
329
- /** Volume-meter event for VU UIs. ~10 Hz cadence (browser bundle only). */
330
- onVolume?: (vol: VolumeEvent) => void;
331
- /**
332
- * Fires when the server signals barge-in (the user started talking
333
- * mid-agent-turn). The browser bundle automatically flushes its
334
- * built-in audio playback before this callback runs; the callback is
335
- * fired regardless. Node / Electron consumers with custom playback
336
- * should drain their audio queue here so the agent goes silent
337
- * immediately.
338
- */
339
- onInterrupt?: () => void;
340
- /**
341
- * Fires on `agent_turn_start` — the server has begun a new agent
342
- * turn. The state-machine transition to `agent_speaking` happens at
343
- * the same moment via `onStateChange`; use this when you want a
344
- * precise turn anchor (e.g. "agent has been speaking for N ms" UIs)
345
- * without diffing state.
346
- */
347
- onAgentTurnStart?: () => void;
348
- }
349
- interface Call {
350
- /** Current state. Snapshot — subscribe via onStateChange for live updates. */
351
- readonly state: CallState;
352
- /** Full transcript so far. Snapshot — subscribe via onTranscript for live updates. */
353
- readonly transcript: TranscriptEntry[];
354
- /** True after `mute()` and before `unmute()`. */
355
- readonly isMuted: boolean;
356
- /** End the call locally. Closes the WS, stops the mic, fires onEnd. Idempotent. */
357
- end: () => void;
358
- /** Mute mic frames. Wire stays active so server endpointing doesn't false-positive. Idempotent. */
359
- mute: () => void;
360
- /** Unmute mic frames. Idempotent. */
361
- unmute: () => void;
362
- }
363
- interface VoiceClientFactory {
364
- /** Read back the resolved config (post trailing-slash normalisation). */
365
- readonly config: VoiceClientConfig;
366
- /**
367
- * Open a fresh call. Returns when the WS is open; rejects on
368
- * pre-flight failure (missing config, fetchToken throw, etc). Mid-
369
- * call failures arrive via the per-call `onError` callback — they
370
- * don't reject this promise.
371
- */
372
- startCall: (options: StartCallOptions) => Promise<Call>;
373
- /**
374
- * Phase 7 (multi-party rooms). Browser only. Exchange a single-use
375
- * joinCode for a LiveKit JWT and connect to the room. The returned
376
- * `RoomSession` exposes a typed event surface
377
- * (participant.joined / participant.left / transcript.partial /
378
- * transcript.final / system.message / room.ended) plus
379
- * publishMic / publishCamera / leave. The Node bundle does NOT
380
- * implement this — livekit-client is a browser-only WebRTC client.
381
- */
382
- joinRoom?: (options: Omit<JoinRoomOptions, 'apiBase'>) => Promise<RoomSession>;
383
- }
384
-
385
- type OnChunk = (pcm: ArrayBuffer) => void;
386
- type OnVolume$1 = (rms01: number) => void;
387
- type OnError = (err: Error) => void;
388
- interface CaptureOptions {
389
- onChunk: OnChunk;
390
- onVolume?: OnVolume$1;
391
- onError?: OnError;
392
- }
393
- interface CaptureController {
394
- start: () => Promise<void>;
395
- stop: () => void;
396
- mute: (muted: boolean) => void;
397
- isCapturing: () => boolean;
398
- }
399
- declare const createAudioCapture: (options: CaptureOptions) => CaptureController;
400
-
401
- type OnVolume = (rms01: number) => void;
402
- type OnAgentSpeakingChange = (speaking: boolean) => void;
403
- interface PlaybackOptions {
404
- sampleRate?: number;
405
- onVolume?: OnVolume;
406
- onSpeakingChange?: OnAgentSpeakingChange;
407
- }
408
- interface PlaybackController {
409
- enqueue: (pcm: ArrayBuffer) => void;
410
- flush: () => void;
411
- close: () => void;
412
- resume: () => Promise<void>;
413
- }
414
- declare const createAudioPlayback: (options?: PlaybackOptions) => PlaybackController;
415
-
416
- type RWSEvent = {
417
- type: 'open';
418
- } | {
419
- type: 'reconnected';
420
- } | {
421
- type: 'message';
422
- data: string | ArrayBuffer;
423
- } | {
424
- type: 'close';
425
- code: number;
426
- reason: string;
427
- permanent: boolean;
428
- } | {
429
- type: 'error';
430
- error: Error;
431
- };
432
- interface WebSocketLike {
433
- binaryType: string;
434
- readyState: number;
435
- onopen: ((ev: unknown) => void) | null;
436
- onmessage: ((ev: {
437
- data: string | ArrayBuffer;
438
- }) => void) | null;
439
- onerror: ((ev: unknown) => void) | null;
440
- onclose: ((ev: {
441
- code: number;
442
- reason: string;
443
- }) => void) | null;
444
- send: (data: string | ArrayBuffer | ArrayBufferView) => void;
445
- close: (code?: number, reason?: string) => void;
446
- }
447
- type WebSocketFactory = (url: string) => WebSocketLike;
448
- interface RWSOptions {
449
- url: string;
450
- wsFactory: WebSocketFactory;
451
- maxRetries?: number;
452
- initialBackoffMs?: number;
453
- maxBackoffMs?: number;
454
- }
455
- declare const createReconnectingWebSocket: (options: RWSOptions, onEvent: (ev: RWSEvent) => void) => {
456
- send: (data: string | ArrayBuffer | ArrayBufferView) => void;
457
- close: (code?: number, reason?: string) => void;
458
- readyState: () => number;
459
- };
460
- type ReconnectingWebSocket = ReturnType<typeof createReconnectingWebSocket>;
461
-
462
- /**
463
- * Canonical payload a tenant places in their VoIP/FCM push so an
464
- * agent-initiated call can connect. It is the `callTokens.mint` result
465
- * (token + transport) plus two optional display fields for the native
466
- * incoming-call UI. The host receives the push, runs `parseIncomingCall`,
467
- * and on accept passes `token` (+ transport / webrtcGatewayBase) into the
468
- * voice client. Web background-wake is best-effort (Web Push); native is
469
- * the real target. See docs/sdks.md "Agent-initiated calls".
470
- */
471
- interface IncomingCallPayload {
472
- token: string;
473
- agentId: string;
474
- transport: 'ws' | 'webrtc';
475
- webrtcGatewayBase?: string;
476
- expiresAt?: number;
477
- agentName?: string;
478
- agentAvatarUrl?: string;
479
- }
480
- /**
481
- * Validate + normalise a raw push payload into an IncomingCallPayload.
482
- * Throws synchronously on malformed input. Unknown transports fall back to
483
- * 'ws'; webrtcGatewayBase is ignored unless transport === 'webrtc'.
484
- */
485
- declare const parseIncomingCall: (raw: unknown) => IncomingCallPayload;
1
+ import { V as VoiceClientConfig, a as VoiceClientFactory } from './config-D2TbvIqT.mjs';
2
+ export { C as Call, b as CallEndEvent, c as CallEndReason, d as CallError, e as CallErrorCode, f as CallState, g as ChatEvent, h as ClientTool, i as ClientToolMap, F as FetchToken, j as FetchTokenArgs, k as FetchTokenResult, P as ProtocolCallbacks, l as ProtocolState, S as ServerMessage, m as StartCallOptions, n as StartTextSessionOpts, T as TextSession, o as TranscriptEntry, p as VolumeEvent, q as buildWsUrl, r as createProtocolState, s as handleServerMessage, t as startTextSession } from './config-D2TbvIqT.mjs';
3
+ import { JoinRoomOptions, RoomSession } from './room.mjs';
4
+ export { AnalysisMessage, RoomEventName, RoomEventPayloads, RoomParticipantInfo, SystemMessage, TranscriptMessage, joinRoom } from './room.mjs';
5
+ export { C as CaptureController, a as CaptureOptions, I as IncomingCallPayload, O as OnAgentSpeakingChange, b as OnChunk, c as OnError, d as OnVolume, P as PlaybackController, e as PlaybackOptions, R as RWSEvent, f as RWSOptions, g as ReconnectingWebSocket, W as WebSocketFactory, h as WebSocketLike, i as createAudioCapture, j as createAudioPlayback, k as createReconnectingWebSocket, p as parseIncomingCall } from './incomingCall-CfRRzj2P.mjs';
6
+ import 'livekit-client';
486
7
 
487
8
  /**
488
9
  * One-time SDK setup. Returns a factory you call `startCall` on for
489
- * every voice call.
490
- *
491
- * Example:
492
- * const voice = configureVoiceClient({
493
- * apiBase: 'https://api.your-server.com',
494
- * fetchToken: async ({ agentId }) => {
495
- * const r = await fetch('/api/voice-token', {
496
- * method: 'POST',
497
- * body: JSON.stringify({ agentId }),
498
- * })
499
- * return (await r.json()).token
500
- * },
501
- * })
502
- *
503
- * // Per call (typically inside a click handler):
504
- * const call = await voice.startCall({
505
- * agentId: 'agt_xxx',
506
- * onTranscript: (entries) => render(entries),
507
- * onEnd: ({ reason }) => log(reason),
508
- * })
509
- * call.mute()
510
- * call.end()
10
+ * every voice call. Also exposes `joinRoom` as a method for multi-party
11
+ * room joining (back-compat; prefer `@craftedxp/voice-js/room` for new code).
511
12
  */
512
- declare function configureVoiceClient(config: VoiceClientConfig): VoiceClientFactory;
13
+ declare function configureVoiceClient(config: VoiceClientConfig): VoiceClientFactory & {
14
+ joinRoom: (opts: Omit<JoinRoomOptions, 'apiBase'>) => Promise<RoomSession>;
15
+ };
513
16
 
514
- export { type Call, type CallEndEvent, type CallEndReason, type CallError, type CallErrorCode, type CallState, type CaptureController, type CaptureOptions, type ClientTool, type ClientToolMap, type FetchToken, type FetchTokenArgs, type FetchTokenResult, type IncomingCallPayload, type JoinRoomOptions, type OnAgentSpeakingChange, type OnChunk, type OnError, type OnVolume$1 as OnVolume, type PlaybackController, type PlaybackOptions, type ProtocolCallbacks, type ProtocolState, type RWSEvent, type RWSOptions, type ReconnectingWebSocket, type RoomEventName, type RoomEventPayloads, type RoomParticipantInfo, type RoomSession, type ServerMessage, type StartCallOptions, type SystemMessage, type TranscriptEntry, type TranscriptMessage, type VoiceClientConfig, type VoiceClientFactory, type VolumeEvent, type WebSocketFactory, type WebSocketLike, buildWsUrl, configureVoiceClient, createAudioCapture, createAudioPlayback, createProtocolState, createReconnectingWebSocket, handleServerMessage, joinRoom, parseIncomingCall };
17
+ export { JoinRoomOptions, RoomSession, VoiceClientConfig, VoiceClientFactory, configureVoiceClient };