@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
package/dist/node.js CHANGED
@@ -1,733 +1,738 @@
1
- 'use strict'
2
- var __create = Object.create
3
- var __defProp = Object.defineProperty
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor
5
- var __getOwnPropNames = Object.getOwnPropertyNames
6
- var __getProtoOf = Object.getPrototypeOf
7
- var __hasOwnProp = Object.prototype.hasOwnProperty
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
8
  var __export = (target, all) => {
9
- for (var name in all) __defProp(target, name, { get: all[name], enumerable: true })
10
- }
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
11
12
  var __copyProps = (to, from, except, desc) => {
12
- if ((from && typeof from === 'object') || typeof from === 'function') {
13
+ if (from && typeof from === "object" || typeof from === "function") {
13
14
  for (let key of __getOwnPropNames(from))
14
15
  if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, {
16
- get: () => from[key],
17
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable,
18
- })
19
- }
20
- return to
21
- }
22
- var __toESM = (mod, isNodeMode, target) => (
23
- (target = mod != null ? __create(__getProtoOf(mod)) : {}),
24
- __copyProps(
25
- // If the importer is in node compatibility mode or this is not an ESM
26
- // file that has been converted to a CommonJS file using a Babel-
27
- // compatible transform (i.e. "__esModule" has not been set), then set
28
- // "default" to the CommonJS "module.exports" for node compatibility.
29
- isNodeMode || !mod || !mod.__esModule
30
- ? __defProp(target, 'default', { value: mod, enumerable: true })
31
- : target,
32
- mod,
33
- )
34
- )
35
- var __toCommonJS = (mod) => __copyProps(__defProp({}, '__esModule', { value: true }), mod)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
29
 
37
30
  // src/node.ts
38
- var node_exports = {}
31
+ var node_exports = {};
39
32
  __export(node_exports, {
40
33
  buildWsUrl: () => buildWsUrl,
41
34
  configureVoiceClient: () => configureVoiceClient,
42
35
  createProtocolState: () => createProtocolState,
43
36
  createReconnectingWebSocket: () => createReconnectingWebSocket,
44
37
  handleServerMessage: () => handleServerMessage,
45
- parseIncomingCall: () => parseIncomingCall,
46
- })
47
- module.exports = __toCommonJS(node_exports)
38
+ parseIncomingCall: () => parseIncomingCall
39
+ });
40
+ module.exports = __toCommonJS(node_exports);
48
41
 
49
42
  // src/config.ts
50
43
  function normalizeConfig(config) {
51
- if (!config) throw new Error('configureVoiceClient: config is required')
52
- if ('apiKey' in config) {
44
+ if (!config) throw new Error("configureVoiceClient: config is required");
45
+ if ("apiKey" in config) {
53
46
  throw new Error(
54
- 'configureVoiceClient: `apiKey` is no longer supported. Embedding sk_ in JS code ships server-grade credentials to every client. Pass `fetchToken: async ({ agentId }) => { /* call YOUR backend mint */ }` instead \u2014 see the @craftedxp/voice-js README for the migration recipe.',
55
- )
47
+ "configureVoiceClient: `apiKey` is no longer supported. Embedding sk_ in JS code ships server-grade credentials to every client. Pass `fetchToken: async ({ agentId }) => { /* call YOUR backend mint */ }` instead \u2014 see the @craftedxp/voice-js README for the migration recipe."
48
+ );
56
49
  }
57
50
  if (!config.apiBase) {
58
- throw new Error('configureVoiceClient: apiBase is required')
51
+ throw new Error("configureVoiceClient: apiBase is required");
59
52
  }
60
- if (typeof config.fetchToken !== 'function') {
61
- throw new Error('configureVoiceClient: fetchToken must be a function')
53
+ if (typeof config.fetchToken !== "function") {
54
+ throw new Error("configureVoiceClient: fetchToken must be a function");
62
55
  }
63
56
  return {
64
57
  ...config,
65
- apiBase: config.apiBase.replace(/\/+$/, ''),
66
- }
58
+ apiBase: config.apiBase.replace(/\/+$/, "")
59
+ };
67
60
  }
68
61
  function mergeStartCallContext(factory, call) {
69
- const context =
70
- factory.defaultContext || call.context
71
- ? { ...(factory.defaultContext ?? {}), ...(call.context ?? {}) }
72
- : void 0
73
- const metadata =
74
- factory.defaultMetadata || call.metadata
75
- ? { ...(factory.defaultMetadata ?? {}), ...(call.metadata ?? {}) }
76
- : void 0
77
- return { context, metadata }
62
+ const context = factory.defaultContext || call.context ? { ...factory.defaultContext ?? {}, ...call.context ?? {} } : void 0;
63
+ const metadata = factory.defaultMetadata || call.metadata ? { ...factory.defaultMetadata ?? {}, ...call.metadata ?? {} } : void 0;
64
+ return { context, metadata };
78
65
  }
79
66
 
80
67
  // src/ReconnectingWebSocket.ts
81
- var READYSTATE_OPEN = 1
82
- var READYSTATE_CLOSED = 3
68
+ var READYSTATE_OPEN = 1;
69
+ var READYSTATE_CLOSED = 3;
83
70
  var createReconnectingWebSocket = (options, onEvent) => {
84
- const maxRetries = options.maxRetries ?? 3
85
- const initialBackoff = options.initialBackoffMs ?? 500
86
- const maxBackoff = options.maxBackoffMs ?? 8e3
87
- let ws = null
88
- let intentionalClose = false
89
- let retries = 0
90
- let backoff = initialBackoff
91
- let reconnectTimer = null
71
+ const maxRetries = options.maxRetries ?? 3;
72
+ const initialBackoff = options.initialBackoffMs ?? 500;
73
+ const maxBackoff = options.maxBackoffMs ?? 8e3;
74
+ let ws = null;
75
+ let intentionalClose = false;
76
+ let retries = 0;
77
+ let backoff = initialBackoff;
78
+ let reconnectTimer = null;
92
79
  const openOnce = () => {
93
- ws = options.wsFactory(options.url)
94
- ws.binaryType = 'arraybuffer'
80
+ ws = options.wsFactory(options.url);
81
+ ws.binaryType = "arraybuffer";
95
82
  ws.onopen = () => {
96
- if (retries === 0) onEvent({ type: 'open' })
97
- else onEvent({ type: 'reconnected' })
98
- retries = 0
99
- backoff = initialBackoff
100
- }
83
+ if (retries === 0) onEvent({ type: "open" });
84
+ else onEvent({ type: "reconnected" });
85
+ retries = 0;
86
+ backoff = initialBackoff;
87
+ };
101
88
  ws.onmessage = (ev) => {
102
- onEvent({ type: 'message', data: ev.data })
103
- }
89
+ onEvent({ type: "message", data: ev.data });
90
+ };
104
91
  ws.onerror = () => {
105
- onEvent({ type: 'error', error: new Error('WebSocket error') })
106
- }
92
+ onEvent({ type: "error", error: new Error("WebSocket error") });
93
+ };
107
94
  ws.onclose = (ev) => {
108
- ws = null
109
- const shouldRetry = !intentionalClose && retries < maxRetries
95
+ ws = null;
96
+ const shouldRetry = !intentionalClose && retries < maxRetries;
110
97
  if (!shouldRetry) {
111
98
  onEvent({
112
- type: 'close',
99
+ type: "close",
113
100
  code: ev.code,
114
101
  reason: ev.reason,
115
- permanent: true,
116
- })
117
- return
102
+ permanent: true
103
+ });
104
+ return;
118
105
  }
119
106
  onEvent({
120
- type: 'close',
107
+ type: "close",
121
108
  code: ev.code,
122
109
  reason: ev.reason,
123
- permanent: false,
124
- })
125
- retries++
126
- const delay = Math.min(backoff, maxBackoff)
127
- backoff = Math.min(backoff * 2, maxBackoff)
128
- reconnectTimer = setTimeout(openOnce, delay)
129
- }
130
- }
131
- openOnce()
110
+ permanent: false
111
+ });
112
+ retries++;
113
+ const delay = Math.min(backoff, maxBackoff);
114
+ backoff = Math.min(backoff * 2, maxBackoff);
115
+ reconnectTimer = setTimeout(openOnce, delay);
116
+ };
117
+ };
118
+ openOnce();
132
119
  return {
133
120
  send: (data) => {
134
- if (ws && ws.readyState === READYSTATE_OPEN) ws.send(data)
121
+ if (ws && ws.readyState === READYSTATE_OPEN) ws.send(data);
135
122
  },
136
- close: (code = 1e3, reason = 'client-requested') => {
137
- intentionalClose = true
123
+ close: (code = 1e3, reason = "client-requested") => {
124
+ intentionalClose = true;
138
125
  if (reconnectTimer) {
139
- clearTimeout(reconnectTimer)
140
- reconnectTimer = null
126
+ clearTimeout(reconnectTimer);
127
+ reconnectTimer = null;
141
128
  }
142
129
  try {
143
- ws?.close(code, reason)
144
- } catch {}
130
+ ws?.close(code, reason);
131
+ } catch {
132
+ }
145
133
  },
146
- readyState: () => ws?.readyState ?? READYSTATE_CLOSED,
147
- }
148
- }
134
+ readyState: () => ws?.readyState ?? READYSTATE_CLOSED
135
+ };
136
+ };
149
137
 
150
138
  // src/protocol.ts
151
139
  var createProtocolState = () => ({
152
- state: 'idle',
140
+ state: "idle",
153
141
  transcript: [],
154
142
  agentBubbleId: null,
155
143
  idCounter: 0,
156
- endReason: null,
157
- })
144
+ endReason: null
145
+ });
158
146
  var mapEndReason = (raw) => {
159
- if (raw === 'agent_ended') return 'agent_ended'
160
- if (raw === 'caller_hung_up') return 'user_hangup'
161
- if (raw === 'silence_timeout' || raw === 'max_duration') return 'timeout'
162
- return 'error'
163
- }
147
+ if (raw === "agent_ended") return "agent_ended";
148
+ if (raw === "caller_hung_up") return "user_hangup";
149
+ if (raw === "silence_timeout" || raw === "max_duration") return "timeout";
150
+ return "error";
151
+ };
164
152
  function handleServerMessage(raw, state, cb) {
165
- let msg
153
+ let msg;
166
154
  try {
167
- msg = JSON.parse(raw)
155
+ msg = JSON.parse(raw);
168
156
  } catch {
169
- return
157
+ return;
170
158
  }
171
159
  switch (msg.type) {
172
- case 'connected':
173
- cb.onConnected()
174
- setState(state, 'listening', cb)
175
- return
176
- case 'transcript': {
177
- const text = msg.text ?? ''
178
- if (!text) return
179
- const isFinal = !!msg.isFinal
180
- if (!isFinal) setState(state, 'user_speaking', cb)
181
- upsertUserPartial(state, text, isFinal)
182
- cb.onTranscript(state.transcript)
183
- return
184
- }
185
- case 'agent_turn_start': {
186
- const id = `m${state.idCounter++}`
187
- state.agentBubbleId = id
188
- state.transcript = [...state.transcript, { id, role: 'agent', text: '' }]
189
- cb.onTranscript(state.transcript)
190
- const seq = typeof msg.seq === 'number' ? msg.seq : void 0
191
- cb.onAgentTurnStart(seq)
192
- setState(state, 'agent_speaking', cb)
193
- return
194
- }
195
- case 'agent_text': {
196
- const delta = msg.text ?? ''
197
- if (!delta || !state.agentBubbleId) return
198
- const id = state.agentBubbleId
199
- state.transcript = state.transcript.map((e) =>
200
- e.id === id && e.role === 'agent' ? { ...e, text: e.text + delta } : e,
201
- )
202
- cb.onTranscript(state.transcript)
203
- return
204
- }
205
- case 'agent_turn_end': {
206
- state.agentBubbleId = null
207
- const seq = typeof msg.seq === 'number' ? msg.seq : void 0
208
- cb.onAgentTurnEnd(seq)
209
- setState(state, 'listening', cb)
210
- return
211
- }
212
- case 'interrupt':
213
- cb.onInterrupt()
214
- return
215
- case 'agent_turn_abort': {
216
- const committed = (msg.committedText ?? '').trim()
160
+ case "connected":
161
+ cb.onConnected();
162
+ setState(state, "listening", cb);
163
+ return;
164
+ case "transcript": {
165
+ const text = msg.text ?? "";
166
+ if (!text) return;
167
+ const isFinal = !!msg.isFinal;
168
+ if (!isFinal) setState(state, "user_speaking", cb);
169
+ upsertUserPartial(state, text, isFinal);
170
+ cb.onTranscript(state.transcript);
171
+ return;
172
+ }
173
+ case "agent_turn_start": {
174
+ const id = `m${state.idCounter++}`;
175
+ state.agentBubbleId = id;
176
+ state.transcript = [...state.transcript, { id, role: "agent", text: "" }];
177
+ cb.onTranscript(state.transcript);
178
+ const seq = typeof msg.seq === "number" ? msg.seq : void 0;
179
+ cb.onAgentTurnStart(seq);
180
+ setState(state, "agent_speaking", cb);
181
+ return;
182
+ }
183
+ case "agent_text": {
184
+ const delta = msg.text ?? "";
185
+ if (!delta || !state.agentBubbleId) return;
186
+ const id = state.agentBubbleId;
187
+ state.transcript = state.transcript.map(
188
+ (e) => e.id === id && e.role === "agent" ? { ...e, text: e.text + delta } : e
189
+ );
190
+ cb.onTranscript(state.transcript);
191
+ return;
192
+ }
193
+ case "agent_turn_end": {
194
+ state.agentBubbleId = null;
195
+ const seq = typeof msg.seq === "number" ? msg.seq : void 0;
196
+ cb.onAgentTurnEnd(seq);
197
+ setState(state, "listening", cb);
198
+ return;
199
+ }
200
+ case "interrupt":
201
+ cb.onInterrupt();
202
+ return;
203
+ case "agent_turn_abort": {
204
+ const committed = (msg.committedText ?? "").trim();
217
205
  if (state.agentBubbleId) {
218
- const id = state.agentBubbleId
206
+ const id = state.agentBubbleId;
219
207
  if (committed) {
220
- state.transcript = state.transcript.map((e) =>
221
- e.id === id && e.role === 'agent' ? { ...e, text: committed, interrupted: true } : e,
222
- )
208
+ state.transcript = state.transcript.map(
209
+ (e) => e.id === id && e.role === "agent" ? { ...e, text: committed, interrupted: true } : e
210
+ );
223
211
  } else {
224
- state.transcript = state.transcript.filter((e) => e.id !== id)
212
+ state.transcript = state.transcript.filter((e) => e.id !== id);
225
213
  }
226
- cb.onTranscript(state.transcript)
214
+ cb.onTranscript(state.transcript);
227
215
  }
228
- state.agentBubbleId = null
229
- return
216
+ state.agentBubbleId = null;
217
+ return;
230
218
  }
231
- case 'tool_call':
219
+ case "tool_call":
232
220
  state.transcript = [
233
221
  ...state.transcript,
234
222
  {
235
223
  id: `m${state.idCounter++}`,
236
- role: 'tool',
237
- text: `\u2192 ${String(msg.tool ?? '?')}(${msg.args ? JSON.stringify(msg.args) : ''})`,
238
- },
239
- ]
240
- cb.onTranscript(state.transcript)
241
- return
242
- case 'tool_result':
224
+ role: "tool",
225
+ text: `\u2192 ${String(msg.tool ?? "?")}(${msg.args ? JSON.stringify(msg.args) : ""})`
226
+ }
227
+ ];
228
+ cb.onTranscript(state.transcript);
229
+ return;
230
+ case "tool_result":
243
231
  state.transcript = [
244
232
  ...state.transcript,
245
233
  {
246
234
  id: `m${state.idCounter++}`,
247
- role: 'tool',
248
- text: `${msg.ok ? '\u2713' : '\u2717'} ${String(msg.tool ?? '?')}`,
249
- },
250
- ]
251
- cb.onTranscript(state.transcript)
252
- return
253
- case 'client_tool_call': {
254
- const toolCallId = String(msg.toolCallId ?? '')
255
- const name = String(msg.name ?? '')
256
- const args = msg.args ?? {}
257
- if (!toolCallId || !name) return
258
- cb.onClientToolCall({ toolCallId, name, args })
259
- return
260
- }
261
- case 'call_end': {
262
- const reasonRaw = String(msg.reason ?? '')
263
- const reason = mapEndReason(reasonRaw)
264
- state.endReason = reason
235
+ role: "tool",
236
+ text: `${msg.ok ? "\u2713" : "\u2717"} ${String(msg.tool ?? "?")}`
237
+ }
238
+ ];
239
+ cb.onTranscript(state.transcript);
240
+ return;
241
+ case "client_tool_call": {
242
+ const toolCallId = String(msg.toolCallId ?? "");
243
+ const name = String(msg.name ?? "");
244
+ const args = msg.args ?? {};
245
+ if (!toolCallId || !name) return;
246
+ cb.onClientToolCall({ toolCallId, name, args });
247
+ return;
248
+ }
249
+ case "call_end": {
250
+ const reasonRaw = String(msg.reason ?? "");
251
+ const reason = mapEndReason(reasonRaw);
252
+ state.endReason = reason;
265
253
  state.transcript = [
266
254
  ...state.transcript,
267
255
  {
268
256
  id: `m${state.idCounter++}`,
269
- role: 'system',
270
- text: `call ended${reasonRaw ? ` (${reasonRaw})` : ''}`,
271
- },
272
- ]
273
- cb.onTranscript(state.transcript)
274
- cb.onCallEnd(reason)
275
- return
257
+ role: "system",
258
+ text: `call ended${reasonRaw ? ` (${reasonRaw})` : ""}`
259
+ }
260
+ ];
261
+ cb.onTranscript(state.transcript);
262
+ cb.onCallEnd(reason);
263
+ return;
276
264
  }
277
- case 'error': {
278
- const code = msg.code ?? 'server_error'
279
- const message = msg.message ?? 'server error'
280
- cb.onError({ code, message })
281
- return
265
+ case "error": {
266
+ const code = msg.code ?? "server_error";
267
+ const message = msg.message ?? "server error";
268
+ cb.onError({ code, message });
269
+ return;
282
270
  }
283
271
  }
284
272
  }
285
273
  var setState = (state, next, cb) => {
286
- if (state.state === next) return
287
- cb.onState(next)
288
- }
274
+ if (state.state === next) return;
275
+ cb.onState(next);
276
+ };
289
277
  var upsertUserPartial = (state, text, isFinal) => {
290
- let idx = -1
278
+ let idx = -1;
291
279
  for (let i = state.transcript.length - 1; i >= 0; i--) {
292
- const e = state.transcript[i]
293
- if (e.role === 'user' && e.committed === false) {
294
- idx = i
295
- break
280
+ const e = state.transcript[i];
281
+ if (e.role === "user" && e.committed === false) {
282
+ idx = i;
283
+ break;
296
284
  }
297
285
  }
298
286
  if (idx === -1) {
299
287
  state.transcript = [
300
288
  ...state.transcript,
301
- { id: `m${state.idCounter++}`, role: 'user', text, committed: isFinal },
302
- ]
303
- return
304
- }
305
- const target = state.transcript[idx]
306
- const next = [...state.transcript]
307
- next[idx] = { ...target, text, committed: isFinal }
308
- state.transcript = next
309
- }
289
+ { id: `m${state.idCounter++}`, role: "user", text, committed: isFinal }
290
+ ];
291
+ return;
292
+ }
293
+ const target = state.transcript[idx];
294
+ const next = [...state.transcript];
295
+ next[idx] = { ...target, text, committed: isFinal };
296
+ state.transcript = next;
297
+ };
310
298
  function buildWsUrl(args) {
311
- const base = new URL(args.apiBase)
312
- const proto = base.protocol === 'https:' ? 'wss:' : 'ws:'
313
- const bargeQS = args.bargeIn === false ? '&barge=off' : ''
314
- return `${proto}//${base.host}/v1/agents/${encodeURIComponent(args.agentId)}/call?token=${encodeURIComponent(args.token)}${bargeQS}`
299
+ const base = new URL(args.apiBase);
300
+ const proto = base.protocol === "https:" ? "wss:" : "ws:";
301
+ const bargeQS = args.bargeIn === false ? "&barge=off" : "";
302
+ return `${proto}//${base.host}/v1/agents/${encodeURIComponent(args.agentId)}/call?token=${encodeURIComponent(args.token)}${bargeQS}`;
315
303
  }
316
304
 
317
305
  // src/clientTools.ts
318
- var NAME_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/
319
- var MAX_TOOLS = 64
320
- var MAX_USAGE = 500
321
- var MAX_TIMEOUT_MS = 3e4
306
+ var NAME_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
307
+ var MAX_TOOLS = 64;
308
+ var MAX_USAGE = 500;
309
+ var MAX_TIMEOUT_MS = 3e4;
322
310
  var validateClientToolMap = (tools) => {
323
- if (tools === void 0) return
324
- if (typeof tools !== 'object' || tools === null || Array.isArray(tools)) {
325
- throw new Error('clientTools must be an object keyed by tool name')
311
+ if (tools === void 0) return;
312
+ if (typeof tools !== "object" || tools === null || Array.isArray(tools)) {
313
+ throw new Error("clientTools must be an object keyed by tool name");
326
314
  }
327
- const entries = Object.entries(tools)
315
+ const entries = Object.entries(tools);
328
316
  if (entries.length > MAX_TOOLS) {
329
- throw new Error(`clientTools may declare at most 64 tools (got ${entries.length})`)
317
+ throw new Error(`clientTools may declare at most 64 tools (got ${entries.length})`);
330
318
  }
331
319
  for (const [name, def] of entries) {
332
320
  if (!NAME_RE.test(name)) {
333
321
  throw new Error(
334
- `clientTools["${name}"]: name must be a valid identifier (^[a-zA-Z_][a-zA-Z0-9_]*$)`,
335
- )
322
+ `clientTools["${name}"]: name must be a valid identifier (^[a-zA-Z_][a-zA-Z0-9_]*$)`
323
+ );
336
324
  }
337
- if (!def || typeof def !== 'object') {
338
- throw new Error(`clientTools["${name}"]: must be an object`)
325
+ if (!def || typeof def !== "object") {
326
+ throw new Error(`clientTools["${name}"]: must be an object`);
339
327
  }
340
- if (typeof def.description !== 'string' || def.description.length === 0) {
341
- throw new Error(`clientTools["${name}"]: must have a description`)
328
+ if (typeof def.description !== "string" || def.description.length === 0) {
329
+ throw new Error(`clientTools["${name}"]: must have a description`);
342
330
  }
343
- if (typeof def.handler !== 'function') {
344
- throw new Error(`clientTools["${name}"]: must have a handler function`)
331
+ if (typeof def.handler !== "function") {
332
+ throw new Error(`clientTools["${name}"]: must have a handler function`);
345
333
  }
346
334
  if (def.usage !== void 0 && def.usage.length > MAX_USAGE) {
347
- throw new Error(`clientTools["${name}"]: usage must be \u2264500 chars`)
335
+ throw new Error(`clientTools["${name}"]: usage must be \u2264500 chars`);
348
336
  }
349
- if (
350
- def.timeoutMs !== void 0 &&
351
- (!Number.isFinite(def.timeoutMs) || def.timeoutMs <= 0 || def.timeoutMs > MAX_TIMEOUT_MS)
352
- ) {
353
- throw new Error(`clientTools["${name}"]: timeoutMs must be in (0, 30000]`)
337
+ if (def.timeoutMs !== void 0 && (!Number.isFinite(def.timeoutMs) || def.timeoutMs <= 0 || def.timeoutMs > MAX_TIMEOUT_MS)) {
338
+ throw new Error(`clientTools["${name}"]: timeoutMs must be in (0, 30000]`);
354
339
  }
355
340
  }
356
- }
341
+ };
357
342
  var buildRegisterFrame = (tools) => ({
358
- type: 'client_tools_register',
343
+ type: "client_tools_register",
359
344
  tools: Object.entries(tools).map(([name, def]) => ({
360
345
  name,
361
346
  description: def.description,
362
347
  parameters: def.parameters,
363
- ...(def.usage !== void 0 ? { usage: def.usage } : {}),
364
- ...(def.timeoutMs !== void 0 ? { timeoutMs: def.timeoutMs } : {}),
365
- })),
366
- })
348
+ ...def.usage !== void 0 ? { usage: def.usage } : {},
349
+ ...def.timeoutMs !== void 0 ? { timeoutMs: def.timeoutMs } : {}
350
+ }))
351
+ });
367
352
  var dispatchClientToolCall = (send, tools, frame) => {
368
353
  const safeSend = (payload) => {
369
354
  try {
370
- send(payload)
371
- } catch {}
372
- }
373
- const tool = tools[frame.name]
355
+ send(payload);
356
+ } catch {
357
+ }
358
+ };
359
+ const tool = tools[frame.name];
374
360
  if (!tool) {
375
361
  safeSend({
376
- type: 'client_tool_result',
362
+ type: "client_tool_result",
377
363
  toolCallId: frame.toolCallId,
378
- error: `No handler for ${frame.name}`,
379
- })
380
- return
364
+ error: `No handler for ${frame.name}`
365
+ });
366
+ return;
381
367
  }
382
368
  void (async () => {
383
369
  try {
384
- const out = await tool.handler(frame.args)
370
+ const out = await tool.handler(frame.args);
385
371
  safeSend({
386
- type: 'client_tool_result',
372
+ type: "client_tool_result",
387
373
  toolCallId: frame.toolCallId,
388
- result: typeof out === 'string' ? out : JSON.stringify(out),
389
- })
374
+ result: typeof out === "string" ? out : JSON.stringify(out)
375
+ });
390
376
  } catch (err) {
391
377
  safeSend({
392
- type: 'client_tool_result',
378
+ type: "client_tool_result",
393
379
  toolCallId: frame.toolCallId,
394
- error: err instanceof Error ? err.message : String(err),
395
- })
380
+ error: err instanceof Error ? err.message : String(err)
381
+ });
396
382
  }
397
- })()
398
- }
383
+ })();
384
+ };
399
385
 
400
386
  // src/ClientMarksBuffer.ts
401
387
  var createClientMarksBuffer = (args) => {
402
- const now = args.now ?? (() => performance.now())
403
- let pendingFirstOutboundAt = null
404
- const inFlight = /* @__PURE__ */ new Map()
388
+ const now = args.now ?? (() => performance.now());
389
+ let pendingFirstOutboundAt = null;
390
+ const inFlight = /* @__PURE__ */ new Map();
405
391
  const tryEmit = (seq) => {
406
- const slot = inFlight.get(seq)
407
- if (!slot) return
408
- if (!slot.ended) return
409
- const marks = {}
392
+ const slot = inFlight.get(seq);
393
+ if (!slot) return;
394
+ if (!slot.ended) return;
395
+ const marks = {};
410
396
  if (slot.firstOutboundAt !== null && slot.firstAudibleAt !== null) {
411
- marks.client_mic_to_first_audible_ms = slot.firstAudibleAt - slot.firstOutboundAt
397
+ marks.client_mic_to_first_audible_ms = slot.firstAudibleAt - slot.firstOutboundAt;
412
398
  }
413
399
  args.send({
414
- type: 'client_marks',
400
+ type: "client_marks",
415
401
  seq,
416
402
  marks,
417
- clientNow: Date.now(),
418
- })
419
- inFlight.delete(seq)
420
- }
403
+ clientNow: Date.now()
404
+ });
405
+ inFlight.delete(seq);
406
+ };
421
407
  const markFirstOutboundAudio = () => {
422
- if (pendingFirstOutboundAt !== null) return
423
- pendingFirstOutboundAt = now()
424
- }
408
+ if (pendingFirstOutboundAt !== null) return;
409
+ pendingFirstOutboundAt = now();
410
+ };
425
411
  const markFirstAudibleOutput = () => {
426
- let target
412
+ let target;
427
413
  for (const slot of inFlight.values()) {
428
414
  if (!slot.ended) {
429
- target = slot
415
+ target = slot;
430
416
  }
431
417
  }
432
- if (!target) return
433
- if (target.firstAudibleAt !== null) return
434
- target.firstAudibleAt = now()
435
- }
418
+ if (!target) return;
419
+ if (target.firstAudibleAt !== null) return;
420
+ target.firstAudibleAt = now();
421
+ };
436
422
  const onAgentTurnStart = (seq) => {
437
423
  inFlight.set(seq, {
438
424
  firstOutboundAt: pendingFirstOutboundAt,
439
425
  firstAudibleAt: null,
440
- ended: false,
441
- })
442
- pendingFirstOutboundAt = null
443
- }
426
+ ended: false
427
+ });
428
+ pendingFirstOutboundAt = null;
429
+ };
444
430
  const onAgentTurnEnd = (seq) => {
445
- const slot = inFlight.get(seq)
431
+ const slot = inFlight.get(seq);
446
432
  if (!slot) {
447
- args.send({ type: 'client_marks', seq, marks: {}, clientNow: Date.now() })
448
- return
433
+ args.send({ type: "client_marks", seq, marks: {}, clientNow: Date.now() });
434
+ return;
449
435
  }
450
- slot.ended = true
451
- tryEmit(seq)
452
- }
436
+ slot.ended = true;
437
+ tryEmit(seq);
438
+ };
453
439
  const flush = () => {
454
440
  for (const seq of [...inFlight.keys()]) {
455
- const slot = inFlight.get(seq)
456
- slot.ended = true
457
- tryEmit(seq)
441
+ const slot = inFlight.get(seq);
442
+ slot.ended = true;
443
+ tryEmit(seq);
458
444
  }
459
- pendingFirstOutboundAt = null
460
- }
445
+ pendingFirstOutboundAt = null;
446
+ };
461
447
  return {
462
448
  markFirstOutboundAudio,
463
449
  markFirstAudibleOutput,
464
450
  onAgentTurnStart,
465
451
  onAgentTurnEnd,
466
- flush,
467
- }
468
- }
452
+ flush
453
+ };
454
+ };
469
455
 
470
456
  // src/NodeVoiceClient.ts
457
+ var READYSTATE_OPEN2 = 1;
471
458
  var NodeVoiceClient = class {
472
459
  constructor(args) {
473
- this.rws = null
474
- this.muted = false
475
- this.startedAt = null
476
- this.endedFired = false
477
- this.lastError = null
460
+ this.rws = null;
461
+ this.muted = false;
462
+ this.startedAt = null;
463
+ this.endedFired = false;
464
+ this.lastError = null;
478
465
  this.end = () => {
479
- this.teardown('user_hangup')
480
- }
466
+ this.teardown("user_hangup");
467
+ };
481
468
  this.mute = () => {
482
- this.muted = true
483
- }
469
+ this.muted = true;
470
+ };
484
471
  this.unmute = () => {
485
- this.muted = false
486
- }
472
+ this.muted = false;
473
+ };
487
474
  // ---------------------------------------------------------------
488
475
  // Node-only raw audio surface
489
476
  // ---------------------------------------------------------------
490
477
  this.sendAudioChunk = (pcm) => {
491
- if (!this.rws) return false
492
- this.marks.markFirstOutboundAudio()
478
+ if (!this.rws) return false;
479
+ this.marks.markFirstOutboundAudio();
493
480
  if (this.muted) {
494
- const len = ArrayBuffer.isView(pcm) ? pcm.byteLength : pcm.byteLength
495
- this.rws.send(new ArrayBuffer(len))
496
- return true
481
+ const len = ArrayBuffer.isView(pcm) ? pcm.byteLength : pcm.byteLength;
482
+ this.rws.send(new ArrayBuffer(len));
483
+ return true;
497
484
  }
498
- this.rws.send(pcm)
499
- return true
500
- }
485
+ this.rws.send(pcm);
486
+ return true;
487
+ };
488
+ this.sendClientEvent = (text) => {
489
+ if (!this.rws) return false;
490
+ const t = text.trim().slice(0, 400);
491
+ if (!t) return false;
492
+ this.rws.send(JSON.stringify({ type: "client_event", text: t }));
493
+ return true;
494
+ };
495
+ // Typed user turn (text/multimodal sessions — token minted with
496
+ // channel:'text'). The server accepts user_text only on text-channel
497
+ // sessions and rejects it on voice (anti-injection), so this is a
498
+ // no-op in practice on voice calls beyond the frame being ignored
499
+ // server-side.
500
+ this.sendText = (text) => {
501
+ const t = text.trim();
502
+ if (!t || !this.rws || this.rws.readyState() !== READYSTATE_OPEN2) return false;
503
+ this.rws.send(JSON.stringify({ type: "user_text", text: t }));
504
+ return true;
505
+ };
501
506
  // ---------------------------------------------------------------
502
507
  // Internal
503
508
  // ---------------------------------------------------------------
504
509
  this.setState = (next) => {
505
- if (this.proto.state === next) return
506
- this.proto.state = next
507
- this.args.options.onStateChange?.(next)
508
- }
510
+ if (this.proto.state === next) return;
511
+ this.proto.state = next;
512
+ this.args.options.onStateChange?.(next);
513
+ };
509
514
  this.sendClientToolsRegister = () => {
510
- const frame = buildRegisterFrame(this.args.options.clientTools ?? {})
511
- this.rws?.send(JSON.stringify(frame))
512
- }
515
+ const frame = buildRegisterFrame(this.args.options.clientTools ?? {});
516
+ this.rws?.send(JSON.stringify(frame));
517
+ };
513
518
  this.emitError = (err) => {
514
- this.lastError = err
515
- this.args.options.onError?.(err)
516
- }
519
+ this.lastError = err;
520
+ this.args.options.onError?.(err);
521
+ };
517
522
  this.handleSocketEvent = (ev) => {
518
523
  switch (ev.type) {
519
- case 'open':
520
- break
521
- case 'reconnected':
522
- this.proto.transcript = []
523
- this.proto.agentBubbleId = null
524
- this.args.options.onTranscript?.(this.proto.transcript)
525
- this.setState('listening')
526
- break
527
- case 'message':
528
- if (typeof ev.data === 'string') {
524
+ case "open":
525
+ break;
526
+ case "reconnected":
527
+ this.proto.transcript = [];
528
+ this.proto.agentBubbleId = null;
529
+ this.args.options.onTranscript?.(this.proto.transcript);
530
+ this.setState("listening");
531
+ break;
532
+ case "message":
533
+ if (typeof ev.data === "string") {
529
534
  handleServerMessage(ev.data, this.proto, {
530
535
  onState: this.setState,
531
536
  onTranscript: (entries) => this.args.options.onTranscript?.(entries),
532
537
  onError: this.emitError,
533
538
  onInterrupt: () => this.args.options.onInterrupt?.(),
534
539
  onAgentTurnStart: (seq) => {
535
- if (typeof seq === 'number') this.marks.onAgentTurnStart(seq)
536
- this.args.options.onAgentTurnStart?.()
540
+ if (typeof seq === "number") this.marks.onAgentTurnStart(seq);
541
+ this.args.options.onAgentTurnStart?.();
537
542
  },
538
543
  onAgentTurnEnd: (seq) => {
539
- if (typeof seq === 'number') this.marks.onAgentTurnEnd(seq)
544
+ if (typeof seq === "number") this.marks.onAgentTurnEnd(seq);
540
545
  },
541
546
  onCallEnd: (reason) => this.teardown(reason),
542
547
  onConnected: () => this.sendClientToolsRegister(),
543
- onClientToolCall: (frame) =>
544
- dispatchClientToolCall(
545
- (f) => this.rws?.send(JSON.stringify(f)),
546
- this.args.options.clientTools ?? {},
547
- frame,
548
- ),
549
- })
548
+ onClientToolCall: (frame) => dispatchClientToolCall(
549
+ (f) => this.rws?.send(JSON.stringify(f)),
550
+ this.args.options.clientTools ?? {},
551
+ frame
552
+ )
553
+ });
550
554
  } else {
551
- this.marks.markFirstAudibleOutput()
552
- this.args.options.onAudioChunk?.(ev.data)
555
+ this.marks.markFirstAudibleOutput();
556
+ this.args.options.onAudioChunk?.(ev.data);
553
557
  }
554
- break
555
- case 'close':
558
+ break;
559
+ case "close":
556
560
  if (ev.permanent) {
557
- const reason = this.proto.endReason ?? (this.lastError ? 'error' : 'user_hangup')
558
- this.teardown(reason)
561
+ const reason = this.proto.endReason ?? (this.lastError ? "error" : "user_hangup");
562
+ this.teardown(reason);
559
563
  }
560
- break
561
- case 'error':
562
- this.emitError({ code: 'socket_error', message: ev.error.message })
563
- break
564
+ break;
565
+ case "error":
566
+ this.emitError({ code: "socket_error", message: ev.error.message });
567
+ break;
564
568
  }
565
- }
569
+ };
566
570
  this.teardown = (reason) => {
567
571
  try {
568
- this.marks.flush()
569
- } catch {}
572
+ this.marks.flush();
573
+ } catch {
574
+ }
570
575
  try {
571
- this.rws?.close(1e3, reason)
572
- } catch {}
573
- this.rws = null
574
- this.setState('ended')
575
- this.fireEndOnce(reason)
576
- }
576
+ this.rws?.close(1e3, reason);
577
+ } catch {
578
+ }
579
+ this.rws = null;
580
+ this.setState("ended");
581
+ this.fireEndOnce(reason);
582
+ };
577
583
  this.fireEndOnce = (reason) => {
578
- if (this.endedFired) return
579
- this.endedFired = true
580
- const startedAt = this.startedAt ?? Date.now()
584
+ if (this.endedFired) return;
585
+ this.endedFired = true;
586
+ const startedAt = this.startedAt ?? Date.now();
581
587
  this.args.options.onEnd?.({
582
588
  reason,
583
- errorCode: reason === 'error' ? this.lastError?.code : void 0,
584
- durationMs: Date.now() - startedAt,
585
- })
586
- }
587
- this.args = args
588
- this.proto = createProtocolState()
589
- validateClientToolMap(args.options.clientTools)
589
+ errorCode: reason === "error" ? this.lastError?.code : void 0,
590
+ durationMs: Date.now() - startedAt
591
+ });
592
+ };
593
+ this.args = args;
594
+ this.proto = createProtocolState();
595
+ validateClientToolMap(args.options.clientTools);
590
596
  this.marks = createClientMarksBuffer({
591
597
  send: (frame) => {
592
598
  try {
593
- this.rws?.send(JSON.stringify(frame))
594
- } catch {}
595
- },
596
- })
599
+ this.rws?.send(JSON.stringify(frame));
600
+ } catch {
601
+ }
602
+ }
603
+ });
597
604
  }
598
605
  // ---------------------------------------------------------------
599
606
  // Call interface
600
607
  // ---------------------------------------------------------------
601
608
  get state() {
602
- return this.proto.state
609
+ return this.proto.state;
603
610
  }
604
611
  get transcript() {
605
- return this.proto.transcript.slice()
612
+ return this.proto.transcript.slice();
606
613
  }
607
614
  get isMuted() {
608
- return this.muted
615
+ return this.muted;
609
616
  }
610
617
  // ---------------------------------------------------------------
611
618
  // Lifecycle
612
619
  // ---------------------------------------------------------------
613
620
  async start() {
614
- this.setState('connecting')
615
- this.startedAt = Date.now()
621
+ this.setState("connecting");
622
+ this.startedAt = Date.now();
616
623
  const url = buildWsUrl({
617
624
  apiBase: this.args.config.apiBase,
618
625
  agentId: this.args.options.agentId,
619
626
  token: this.args.token,
620
- bargeIn: this.args.options.bargeIn,
621
- })
627
+ bargeIn: this.args.options.bargeIn
628
+ });
622
629
  this.rws = createReconnectingWebSocket(
623
630
  {
624
631
  url,
625
632
  wsFactory: this.args.wsFactory,
626
- maxRetries: 3,
633
+ maxRetries: 3
627
634
  },
628
- (ev) => this.handleSocketEvent(ev),
629
- )
635
+ (ev) => this.handleSocketEvent(ev)
636
+ );
630
637
  }
631
- }
638
+ };
632
639
 
633
640
  // src/incomingCall.ts
634
641
  var parseIncomingCall = (raw) => {
635
- if (typeof raw !== 'object' || raw === null) {
636
- throw new Error('parseIncomingCall: payload must be an object')
637
- }
638
- const p = raw
639
- if (typeof p.token !== 'string' || !p.token.startsWith('ct_')) {
640
- throw new Error('parseIncomingCall: missing or invalid `token` (expected a ct_ string)')
641
- }
642
- if (typeof p.agentId !== 'string' || p.agentId.length === 0) {
643
- throw new Error('parseIncomingCall: missing `agentId`')
644
- }
645
- const transport = p.transport === 'webrtc' ? 'webrtc' : 'ws'
646
- const out = { token: p.token, agentId: p.agentId, transport }
647
- if (transport === 'webrtc' && typeof p.webrtcGatewayBase === 'string') {
648
- out.webrtcGatewayBase = p.webrtcGatewayBase
649
- }
650
- if (typeof p.expiresAt === 'number') out.expiresAt = p.expiresAt
651
- if (typeof p.agentName === 'string') out.agentName = p.agentName
652
- if (typeof p.agentAvatarUrl === 'string') out.agentAvatarUrl = p.agentAvatarUrl
653
- return out
654
- }
642
+ if (typeof raw !== "object" || raw === null) {
643
+ throw new Error("parseIncomingCall: payload must be an object");
644
+ }
645
+ const p = raw;
646
+ if (typeof p.token !== "string" || !p.token.startsWith("ct_")) {
647
+ throw new Error("parseIncomingCall: missing or invalid `token` (expected a ct_ string)");
648
+ }
649
+ if (typeof p.agentId !== "string" || p.agentId.length === 0) {
650
+ throw new Error("parseIncomingCall: missing `agentId`");
651
+ }
652
+ const transport = p.transport === "webrtc" ? "webrtc" : "ws";
653
+ const out = { token: p.token, agentId: p.agentId, transport };
654
+ if (transport === "webrtc" && typeof p.webrtcGatewayBase === "string") {
655
+ out.webrtcGatewayBase = p.webrtcGatewayBase;
656
+ }
657
+ if (typeof p.expiresAt === "number") out.expiresAt = p.expiresAt;
658
+ if (typeof p.agentName === "string") out.agentName = p.agentName;
659
+ if (typeof p.agentAvatarUrl === "string") out.agentAvatarUrl = p.agentAvatarUrl;
660
+ return out;
661
+ };
655
662
 
656
663
  // src/node.ts
657
- var cachedWsCtor = null
664
+ var cachedWsCtor = null;
658
665
  var loadWsCtor = async () => {
659
- if (cachedWsCtor) return cachedWsCtor
666
+ if (cachedWsCtor) return cachedWsCtor;
660
667
  try {
661
- const mod = await import('ws')
662
- const ctor = mod.WebSocket ?? mod.default
668
+ const mod = await import("ws");
669
+ const ctor = mod.WebSocket ?? mod.default;
663
670
  if (!ctor) {
664
- throw new Error('imported `ws` but neither default nor named WebSocket export was found')
671
+ throw new Error("imported `ws` but neither default nor named WebSocket export was found");
665
672
  }
666
- cachedWsCtor = ctor
667
- return ctor
673
+ cachedWsCtor = ctor;
674
+ return ctor;
668
675
  } catch (err) {
669
676
  throw new Error(
670
- "@craftedxp/voice-js (node): missing optional peer `ws`. Install it with `npm install ws` (ws is declared as `peerDependenciesMeta.optional` so npm doesn't install it automatically). Original: " +
671
- (err instanceof Error ? err.message : String(err)),
672
- )
677
+ "@craftedxp/voice-js (node): missing optional peer `ws`. Install it with `npm install ws` (ws is declared as `peerDependenciesMeta.optional` so npm doesn't install it automatically). Original: " + (err instanceof Error ? err.message : String(err))
678
+ );
673
679
  }
674
- }
680
+ };
675
681
  var NodeVoiceFactory = class {
676
682
  constructor(config) {
677
683
  this.startCall = async (options) => {
678
684
  if (!options.agentId) {
679
- throw new Error('startCall: agentId is required')
685
+ throw new Error("startCall: agentId is required");
680
686
  }
681
- const WsCtor = await loadWsCtor()
682
- const wsFactory = (url) => new WsCtor(url)
683
- const { context, metadata } = mergeStartCallContext(this.config, options)
687
+ const WsCtor = await loadWsCtor();
688
+ const wsFactory = (url) => new WsCtor(url);
689
+ const { context, metadata } = mergeStartCallContext(this.config, options);
684
690
  const fetchArgs = {
685
691
  agentId: options.agentId,
686
692
  userId: options.userId,
687
693
  context,
688
- metadata,
689
- }
690
- let token
694
+ metadata
695
+ };
696
+ let token;
691
697
  if (options.token) {
692
- token = options.token
698
+ token = options.token;
693
699
  } else {
694
- const r = await this.config.fetchToken(fetchArgs)
700
+ const r = await this.config.fetchToken(fetchArgs);
695
701
  if (!r) {
696
- throw new Error('configureVoiceClient.fetchToken returned empty token')
702
+ throw new Error("configureVoiceClient.fetchToken returned empty token");
697
703
  }
698
- token = typeof r === 'string' ? r : r.token
704
+ token = typeof r === "string" ? r : r.token;
699
705
  if (!token) {
700
- throw new Error('configureVoiceClient.fetchToken returned an object without `token`')
706
+ throw new Error("configureVoiceClient.fetchToken returned an object without `token`");
701
707
  }
702
- if (typeof r !== 'string' && r.transport === 'webrtc') {
708
+ if (typeof r !== "string" && r.transport === "webrtc") {
703
709
  console.warn(
704
- '@craftedxp/voice-js (node): agent is configured for WebRTC but the Node bundle only supports WebSocket \u2014 falling back to WS. Use the browser bundle for WebRTC transport.',
705
- )
710
+ "@craftedxp/voice-js (node): agent is configured for WebRTC but the Node bundle only supports WebSocket \u2014 falling back to WS. Use the browser bundle for WebRTC transport."
711
+ );
706
712
  }
707
713
  }
708
714
  const client = new NodeVoiceClient({
709
715
  config: this.config,
710
716
  options: { ...options, context, metadata },
711
717
  token,
712
- wsFactory,
713
- })
714
- await client.start()
715
- return client
716
- }
717
- this.config = config
718
- }
719
- }
718
+ wsFactory
719
+ });
720
+ await client.start();
721
+ return client;
722
+ };
723
+ this.config = config;
724
+ }
725
+ };
720
726
  function configureVoiceClient(config) {
721
- return new NodeVoiceFactory(normalizeConfig(config))
727
+ return new NodeVoiceFactory(normalizeConfig(config));
722
728
  }
723
729
  // Annotate the CommonJS export names for ESM import in node:
724
- 0 &&
725
- (module.exports = {
726
- buildWsUrl,
727
- configureVoiceClient,
728
- createProtocolState,
729
- createReconnectingWebSocket,
730
- handleServerMessage,
731
- parseIncomingCall,
732
- })
733
- //# sourceMappingURL=node.js.map
730
+ 0 && (module.exports = {
731
+ buildWsUrl,
732
+ configureVoiceClient,
733
+ createProtocolState,
734
+ createReconnectingWebSocket,
735
+ handleServerMessage,
736
+ parseIncomingCall
737
+ });
738
+ //# sourceMappingURL=node.js.map