@vanira/sdk 0.0.86 → 0.0.88

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.
@@ -1,7 +1,7 @@
1
- var H = Object.defineProperty;
2
- var G = (a, e, t) => e in a ? H(a, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[e] = t;
3
- var d = (a, e, t) => G(a, typeof e != "symbol" ? e + "" : e, t);
4
- class z {
1
+ var q = Object.defineProperty;
2
+ var X = (n, e, t) => e in n ? q(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t;
3
+ var d = (n, e, t) => X(n, typeof e != "symbol" ? e + "" : e, t);
4
+ class Z {
5
5
  pause() {
6
6
  }
7
7
  cleanup() {
@@ -9,12 +9,12 @@ class z {
9
9
  onEnded(e) {
10
10
  }
11
11
  }
12
- class Y {
12
+ class Q {
13
13
  createRemotePlayer(e) {
14
- return new z();
14
+ return new Z();
15
15
  }
16
16
  }
17
- class q {
17
+ class F {
18
18
  async getUserAudio(e) {
19
19
  return navigator.mediaDevices.getUserMedia({
20
20
  audio: e
@@ -24,7 +24,7 @@ class q {
24
24
  e.getTracks().forEach((t) => t.stop());
25
25
  }
26
26
  }
27
- class X {
27
+ class ee {
28
28
  create(e) {
29
29
  return new globalThis.RTCPeerConnection({
30
30
  iceServers: e.iceServers,
@@ -32,7 +32,7 @@ class X {
32
32
  });
33
33
  }
34
34
  }
35
- class Z {
35
+ class te {
36
36
  bind(e, t) {
37
37
  return e.onopen = () => t.onOpen(), e.onerror = (i) => t.onError(i), e.onmessage = (i) => {
38
38
  if (typeof i.data == "string") {
@@ -41,8 +41,8 @@ class Z {
41
41
  }
42
42
  if (i.data instanceof ArrayBuffer) {
43
43
  try {
44
- const n = new TextDecoder().decode(i.data), r = JSON.parse(n);
45
- (r == null ? void 0 : r.event) === "client_tool_call" && t.onMessage({ text: n });
44
+ const a = new TextDecoder().decode(i.data), r = JSON.parse(a);
45
+ (r == null ? void 0 : r.event) === "client_tool_call" && t.onMessage({ text: a });
46
46
  } catch {
47
47
  }
48
48
  return;
@@ -60,7 +60,7 @@ class Z {
60
60
  };
61
61
  }
62
62
  }
63
- const Q = "https://api.vanira.io", c = {
63
+ const ie = "https://api.vanira.io", c = {
64
64
  Form: "vanira_form",
65
65
  Calendar: "vanira_calendar",
66
66
  Navigate: "vanira_navigate",
@@ -72,6 +72,7 @@ const Q = "https://api.vanira.io", c = {
72
72
  SetDate: "vanira_set_date",
73
73
  TypeText: "vanira_type_text",
74
74
  WriteLatexText: "vanira_write_latex_text",
75
+ GeoGebra: "vanira_geogebra",
75
76
  EraseText: "vanira_erase_text",
76
77
  LiveVision: "vanira_live_vision",
77
78
  CloseLiveCamera: "vanira_close_live_camera",
@@ -86,20 +87,20 @@ const Q = "https://api.vanira.io", c = {
86
87
  KycDocumentCapture: "vanira_kyc_document_capture",
87
88
  KycSelfieCapture: "vanira_kyc_selfie_capture",
88
89
  KycSignatureCapture: "vanira_kyc_signature_capture"
89
- }, F = Object.values(c), ee = new Set(F);
90
- function V(a) {
91
- return !!a && ee.has(a);
90
+ }, ne = Object.values(c), ae = new Set(ne);
91
+ function K(n) {
92
+ return !!n && ae.has(n);
92
93
  }
93
- function j(a) {
94
- if (typeof a == "string")
94
+ function J(n) {
95
+ if (typeof n == "string")
95
96
  try {
96
- return JSON.parse(a);
97
+ return JSON.parse(n);
97
98
  } catch {
98
99
  return {};
99
100
  }
100
- return a && typeof a == "object" ? a : {};
101
+ return n && typeof n == "object" ? n : {};
101
102
  }
102
- const N = {
103
+ const $ = {
103
104
  type_on_whiteboard: c.TypeText,
104
105
  write_on_whiteboard: c.TypeText,
105
106
  write_on_white_board: c.TypeText,
@@ -107,6 +108,9 @@ const N = {
107
108
  write_latex_text: c.WriteLatexText,
108
109
  write_latex_on_board: c.WriteLatexText,
109
110
  latex_on_whiteboard: c.WriteLatexText,
111
+ show_geogebra: c.GeoGebra,
112
+ geogebra_diagram: c.GeoGebra,
113
+ geogebra: c.GeoGebra,
110
114
  erase_text: c.EraseText,
111
115
  dom_erase: c.EraseText,
112
116
  open_live_camera: c.LiveVision,
@@ -142,74 +146,84 @@ const N = {
142
146
  kyc_signature_capture: c.KycSignatureCapture,
143
147
  capture_kyc_signature: c.KycSignatureCapture,
144
148
  signature_capture: c.KycSignatureCapture
145
- }, D = {
149
+ }, j = {
146
150
  vanira_tab_screenshot: c.ScreenVision,
147
151
  vanira_document_capture: c.KycDocumentCapture,
148
152
  vanira_selfie_capture: c.KycSelfieCapture,
149
153
  vanira_signature_capture: c.KycSignatureCapture,
150
154
  vanira_kyc_signature: c.KycSignatureCapture
151
155
  };
152
- function te(a, e) {
153
- const t = a.latex_text ?? (e == null ? void 0 : e.latex_text);
156
+ function re(n, e) {
157
+ const t = n.commands ?? (e == null ? void 0 : e.commands) ?? n.construction ?? (e == null ? void 0 : e.construction) ?? n.geogebra_commands ?? (e == null ? void 0 : e.geogebra_commands) ?? n.script ?? (e == null ? void 0 : e.script);
158
+ return Array.isArray(t) ? t.some((i) => String(i).trim().length > 0) : typeof t == "string" && t.trim().length > 0;
159
+ }
160
+ function se(n, e) {
161
+ const t = n.material_id ?? (e == null ? void 0 : e.material_id) ?? n.materialId ?? (e == null ? void 0 : e.materialId);
154
162
  return typeof t == "string" && t.trim().length > 0;
155
163
  }
156
- function K(a, e) {
157
- const t = a.text_to_type ?? (e == null ? void 0 : e.text_to_type) ?? a.text ?? (e == null ? void 0 : e.text) ?? a.value ?? (e == null ? void 0 : e.value);
164
+ function oe(n, e) {
165
+ const t = n.latex_text ?? (e == null ? void 0 : e.latex_text);
158
166
  return typeof t == "string" && t.trim().length > 0;
159
167
  }
160
- function ie(a, e) {
161
- const t = a.fields ?? (e == null ? void 0 : e.fields);
168
+ function G(n, e) {
169
+ const t = n.text_to_type ?? (e == null ? void 0 : e.text_to_type) ?? n.text ?? (e == null ? void 0 : e.text) ?? n.value ?? (e == null ? void 0 : e.value);
170
+ return typeof t == "string" && t.trim().length > 0;
171
+ }
172
+ function ce(n, e) {
173
+ const t = n.fields ?? (e == null ? void 0 : e.fields);
162
174
  return Array.isArray(t) ? t.length > 0 : typeof t == "string" ? t.split(",").map((i) => i.trim()).filter(Boolean).length > 0 : !1;
163
175
  }
164
- function ne(a, e) {
165
- const t = a == null ? void 0 : a.preset_id;
176
+ function le(n, e) {
177
+ const t = n == null ? void 0 : n.preset_id;
166
178
  if (typeof t == "string") {
167
- if (V(t)) return t;
168
- const r = D[t];
179
+ if (K(t)) return t;
180
+ const r = j[t];
169
181
  if (r) return r;
170
182
  }
171
- const n = j(e).preset_id;
172
- if (typeof n == "string") {
173
- if (V(n)) return n;
174
- const r = D[n];
183
+ const a = J(e).preset_id;
184
+ if (typeof a == "string") {
185
+ if (K(a)) return a;
186
+ const r = j[a];
175
187
  if (r) return r;
176
188
  }
177
189
  }
178
- function ae(a, e, t) {
179
- const i = j(e);
180
- let n = ne(a, i);
181
- if (n === c.Form && K(i, a) && !ie(i, a))
190
+ function de(n, e, t) {
191
+ const i = J(e);
192
+ let a = le(n, i);
193
+ if (a === c.Form && G(i, n) && !ce(i, n))
182
194
  return c.TypeText;
183
- if (n) return n;
195
+ if (a) return a;
184
196
  const r = String(t ?? "").trim().toLowerCase();
185
- if (r && N[r])
186
- return N[r];
187
- if (te(i, a))
197
+ if (r && $[r])
198
+ return $[r];
199
+ if (re(i, n) || se(i, n))
200
+ return c.GeoGebra;
201
+ if (oe(i, n))
188
202
  return c.WriteLatexText;
189
- if (K(i, a))
203
+ if (G(i, n))
190
204
  return c.TypeText;
191
205
  }
192
- const g = "vanira_latest_call_id", k = "vanira_prospect_id";
193
- function C(a) {
194
- return `vanira_latest_call_id_${a}`;
206
+ const I = "vanira_latest_call_id", k = "vanira_prospect_id";
207
+ function T(n) {
208
+ return `vanira_latest_call_id_${n}`;
195
209
  }
196
- function I(a) {
197
- return `vanira_prospect_id_${a}`;
210
+ function b(n) {
211
+ return `vanira_prospect_id_${n}`;
198
212
  }
199
- function W(a) {
200
- return `vanira_call_meta_${a}`;
213
+ function z(n) {
214
+ return `vanira_call_meta_${n}`;
201
215
  }
202
- function w(a, e) {
203
- if (!a) return null;
216
+ function S(n, e) {
217
+ if (!n) return null;
204
218
  try {
205
- return a.getItem(e);
219
+ return n.getItem(e);
206
220
  } catch {
207
221
  return null;
208
222
  }
209
223
  }
210
- function B(a) {
211
- if (typeof window > "u" || !a) return null;
212
- const e = [], t = w(window.localStorage, W(a));
224
+ function W(n) {
225
+ if (typeof window > "u" || !n) return null;
226
+ const e = [], t = S(window.localStorage, z(n));
213
227
  if (t)
214
228
  try {
215
229
  const h = JSON.parse(t);
@@ -220,124 +234,182 @@ function B(a) {
220
234
  });
221
235
  } catch {
222
236
  }
223
- const i = (h, s, u) => {
237
+ const i = (h, _, s) => {
224
238
  h && e.push({
225
239
  callId: h,
226
- prospectId: s || void 0,
227
- updatedAt: u
240
+ prospectId: _ || void 0,
241
+ updatedAt: s
228
242
  });
229
- }, n = w(window.localStorage, I(a)), r = w(window.sessionStorage, I(a)), o = w(window.localStorage, k);
243
+ }, a = S(window.localStorage, b(n)), r = S(window.sessionStorage, b(n)), o = S(window.localStorage, k);
230
244
  return i(
231
- w(window.localStorage, C(a)),
232
- n || o,
245
+ S(window.localStorage, T(n)),
246
+ a || o,
233
247
  2
234
248
  ), i(
235
- w(window.sessionStorage, C(a)),
249
+ S(window.sessionStorage, T(n)),
236
250
  r || o,
237
251
  1
238
- ), i(w(window.localStorage, g), o, 0), i(w(window.sessionStorage, g), o, 0), e.length ? (e.sort((h, s) => s.updatedAt - h.updatedAt), e[0]) : null;
252
+ ), i(S(window.localStorage, I), o, 0), i(S(window.sessionStorage, I), o, 0), e.length ? (e.sort((h, _) => _.updatedAt - h.updatedAt), e[0]) : null;
239
253
  }
240
- function re(a, e, t) {
241
- var n, r, o, h, s, u, p, l, _;
242
- if (typeof window > "u" || !a || !e) return;
254
+ function he(n, e, t) {
255
+ var a, r, o, h, _, s, u, l, p;
256
+ if (typeof window > "u" || !n || !e) return;
243
257
  const i = {
244
258
  callId: e,
245
259
  prospectId: t,
246
260
  updatedAt: Date.now()
247
261
  };
248
262
  try {
249
- (n = window.localStorage) == null || n.setItem(W(a), JSON.stringify(i)), (r = window.localStorage) == null || r.setItem(C(a), e), (o = window.sessionStorage) == null || o.setItem(C(a), e), t && ((h = window.localStorage) == null || h.setItem(I(a), t), (s = window.sessionStorage) == null || s.setItem(I(a), t)), (u = window.localStorage) == null || u.setItem(g, e), (p = window.sessionStorage) == null || p.setItem(g, e), t && ((l = window.localStorage) == null || l.setItem(k, t), (_ = window.sessionStorage) == null || _.setItem(k, t));
263
+ (a = window.localStorage) == null || a.setItem(z(n), JSON.stringify(i)), (r = window.localStorage) == null || r.setItem(T(n), e), (o = window.sessionStorage) == null || o.setItem(T(n), e), t && ((h = window.localStorage) == null || h.setItem(b(n), t), (_ = window.sessionStorage) == null || _.setItem(b(n), t)), (s = window.localStorage) == null || s.setItem(I, e), (u = window.sessionStorage) == null || u.setItem(I, e), t && ((l = window.localStorage) == null || l.setItem(k, t), (p = window.sessionStorage) == null || p.setItem(k, t));
250
264
  } catch {
251
265
  }
252
266
  }
253
- const se = /* @__PURE__ */ new Set([
267
+ const ue = /* @__PURE__ */ new Set([
254
268
  "client_tool_call",
255
269
  "clearAudio",
256
270
  "client_tool_cancel"
257
271
  ]);
258
- function oe(a) {
259
- if (!a || typeof a != "object") return !1;
260
- const e = a.event;
261
- return typeof e == "string" && se.has(e);
272
+ function pe(n) {
273
+ if (!n || typeof n != "object") return !1;
274
+ const e = n.event;
275
+ return typeof e == "string" && ue.has(e);
262
276
  }
263
- const T = 16 * 1024, ce = 256 * 1024;
264
- function E(a, e) {
265
- return (a == null ? void 0 : a.readyState) === "open" && (e == null ? void 0 : e.readyState) === "open";
277
+ const x = 16 * 1024, _e = 256 * 1024;
278
+ function E(n, e) {
279
+ return (n == null ? void 0 : n.readyState) === "open" && (e == null ? void 0 : e.readyState) === "open";
266
280
  }
267
- function le(a, e) {
281
+ function me(n, e) {
268
282
  return {
269
- control: (a == null ? void 0 : a.readyState) ?? "missing",
283
+ control: (n == null ? void 0 : n.readyState) ?? "missing",
270
284
  mediaBytes: (e == null ? void 0 : e.readyState) ?? "missing"
271
285
  };
272
286
  }
273
- async function de(a, e, t = 8e3) {
274
- if (E(a, e))
287
+ async function fe(n, e, t = 8e3) {
288
+ if (E(n, e))
275
289
  return !0;
276
290
  const i = Date.now() + t;
277
291
  for (; Date.now() < i; ) {
278
- if (E(a, e))
292
+ if (E(n, e))
279
293
  return !0;
280
- await new Promise((n) => setTimeout(n, 50));
294
+ await new Promise((a) => setTimeout(a, 50));
281
295
  }
282
- return E(a, e);
296
+ return E(n, e);
283
297
  }
284
- async function $(a) {
285
- for (; a.bufferedAmount > ce; )
298
+ async function H(n) {
299
+ for (; n.bufferedAmount > _e; )
286
300
  await new Promise((e) => setTimeout(e, 10));
287
301
  }
288
- async function he(a) {
302
+ async function ye(n) {
289
303
  const {
290
304
  bytes: e,
291
305
  filename: t,
292
306
  contentType: i,
293
- reason: n,
307
+ reason: a,
294
308
  message: r,
295
309
  callId: o,
296
310
  mediaBytesChannel: h,
297
- sendControlEvent: s,
298
- uploadId: u = crypto.randomUUID(),
299
- uploadKind: p = "media"
300
- } = a, l = e.byteLength, _ = l === 0 ? 0 : Math.ceil(l / T);
301
- s("client_media_upload_start", {
311
+ sendControlEvent: _,
312
+ uploadId: s = crypto.randomUUID(),
313
+ uploadKind: u = "media"
314
+ } = n, l = e.byteLength, p = l === 0 ? 0 : Math.ceil(l / x);
315
+ _("client_media_upload_start", {
302
316
  data: {
303
- upload_id: u,
317
+ upload_id: s,
304
318
  call_id: o,
305
- reason: n,
319
+ reason: a,
306
320
  message: r,
307
321
  filename: t,
308
322
  content_type: i,
309
323
  size: l,
310
- chunk_count: _,
311
- upload_kind: p
324
+ chunk_count: p,
325
+ upload_kind: u
312
326
  }
313
327
  });
314
328
  const m = new Uint8Array(e);
315
- for (let f = 0; f < l; f += T) {
316
- await $(h);
317
- const S = Math.min(f + T, l);
318
- h.send(m.subarray(f, S));
329
+ for (let f = 0; f < l; f += x) {
330
+ await H(h);
331
+ const w = Math.min(f + x, l);
332
+ h.send(m.subarray(f, w));
319
333
  }
320
- return await $(h), s("client_media_upload_complete", {
334
+ return await H(h), _("client_media_upload_complete", {
321
335
  data: {
322
- upload_id: u,
336
+ upload_id: s,
323
337
  call_id: o,
324
- reason: n,
338
+ reason: a,
325
339
  message: r,
326
- chunk_count: _,
327
- upload_kind: p
340
+ chunk_count: p,
341
+ upload_kind: u
328
342
  }
329
- }), { media_id: u, url: "", content_type: i };
343
+ }), { media_id: s, url: "", content_type: i };
344
+ }
345
+ async function Se(n) {
346
+ return typeof n.arrayBuffer == "function" ? n.arrayBuffer() : new Response(n).arrayBuffer();
330
347
  }
331
- async function ue(a) {
332
- return typeof a.arrayBuffer == "function" ? a.arrayBuffer() : new Response(a).arrayBuffer();
348
+ const we = 15e3, R = "vanira-connect-stall-prompt";
349
+ let v = null;
350
+ function ge(n = we) {
351
+ typeof window > "u" || (g(!1), v = setTimeout(() => {
352
+ v = null, ve(), window.dispatchEvent(new CustomEvent("vanira:connect-stall"));
353
+ }, n));
333
354
  }
334
- function pe(a) {
355
+ function g(n = !0) {
356
+ v !== null && (clearTimeout(v), v = null), n && P();
357
+ }
358
+ function P() {
359
+ var n;
360
+ typeof document > "u" || (n = document.getElementById(R)) == null || n.remove();
361
+ }
362
+ function ve() {
363
+ var t, i;
364
+ if (typeof document > "u" || document.getElementById(R)) return;
365
+ const n = document.createElement("div");
366
+ n.id = R, n.setAttribute("role", "alertdialog"), n.setAttribute("aria-modal", "true"), n.setAttribute("aria-labelledby", "vanira-stall-title"), n.style.cssText = [
367
+ "position:fixed",
368
+ "inset:0",
369
+ "z-index:2147483646",
370
+ "display:flex",
371
+ "align-items:center",
372
+ "justify-content:center",
373
+ "padding:24px",
374
+ "background:rgba(0,0,0,0.55)",
375
+ "font-family:system-ui,-apple-system,'Segoe UI',Roboto,sans-serif"
376
+ ].join(";");
377
+ const e = document.createElement("div");
378
+ e.style.cssText = [
379
+ "max-width:400px",
380
+ "width:100%",
381
+ "padding:24px",
382
+ "border-radius:16px",
383
+ "background:#fff",
384
+ "box-shadow:0 20px 60px rgba(0,0,0,0.25)",
385
+ "color:#111"
386
+ ].join(";"), e.innerHTML = `
387
+ <h2 id="vanira-stall-title" style="margin:0 0 12px;font-size:18px;font-weight:600">Browser is blocking the connection</h2>
388
+ <p style="margin:0 0 20px;font-size:14px;line-height:1.5;color:#444">
389
+ The call is still connecting. Please <strong>hard refresh</strong> your browser to reconnect.
390
+ </p>
391
+ <div style="display:flex;gap:12px;flex-wrap:wrap">
392
+ <button type="button" id="vanira-stall-refresh" style="flex:1;min-width:140px;padding:10px 16px;border:none;border-radius:8px;background:#111;color:#fff;font-size:14px;font-weight:600;cursor:pointer">
393
+ Hard refresh
394
+ </button>
395
+ <button type="button" id="vanira-stall-dismiss" style="flex:1;min-width:100px;padding:10px 16px;border:1px solid #ddd;border-radius:8px;background:#fff;color:#333;font-size:14px;cursor:pointer">
396
+ Dismiss
397
+ </button>
398
+ </div>
399
+ <p style="margin:12px 0 0;font-size:12px;color:#888">
400
+ Tip: Ctrl+Shift+R (Windows) or Cmd+Shift+R (Mac)
401
+ </p>
402
+ `, n.appendChild(e), document.body.appendChild(n), (t = e.querySelector("#vanira-stall-refresh")) == null || t.addEventListener("click", () => {
403
+ P(), window.location.reload();
404
+ }), (i = e.querySelector("#vanira-stall-dismiss")) == null || i.addEventListener("click", () => P());
405
+ }
406
+ function Ce(n) {
335
407
  return null;
336
408
  }
337
- function v() {
409
+ function C() {
338
410
  return typeof window > "u" ? "/" : `${window.location.pathname}${window.location.search}${window.location.hash}` || "/";
339
411
  }
340
- class _e {
412
+ class Ie {
341
413
  constructor(e) {
342
414
  d(this, "active", !1);
343
415
  d(this, "initialSent", !1);
@@ -352,7 +424,7 @@ class _e {
352
424
  this.sendContext = e.sendContext, this.isReady = e.isReady ?? (() => !0);
353
425
  }
354
426
  start() {
355
- typeof window > "u" || this.active || (this.active = !0, this.initialSent = !1, this.lastRoute = v(), this.attachListeners(), this.scheduleInitialContextSend());
427
+ typeof window > "u" || this.active || (this.active = !0, this.initialSent = !1, this.lastRoute = C(), this.attachListeners(), this.scheduleInitialContextSend());
356
428
  }
357
429
  stop() {
358
430
  if (!(!this.active && this.cleanupFns.length === 0)) {
@@ -384,11 +456,11 @@ class _e {
384
456
  attachListeners() {
385
457
  const e = (r, o = 0) => {
386
458
  const h = () => {
387
- const s = v();
388
- s !== this.lastRoute && this.handleRouteChange(s, r);
459
+ const _ = C();
460
+ _ !== this.lastRoute && this.handleRouteChange(_, r);
389
461
  };
390
462
  o > 0 ? window.setTimeout(h, o) : queueMicrotask(h);
391
- }, t = () => e("popstate"), i = () => e("hashchange"), n = (r) => {
463
+ }, t = () => e("popstate"), i = () => e("hashchange"), a = (r) => {
392
464
  const o = r.detail;
393
465
  if ((o == null ? void 0 : o.initiated_by) === "agent") {
394
466
  e("vanira_navigate_agent", 120);
@@ -396,17 +468,17 @@ class _e {
396
468
  }
397
469
  e("vanira_navigate", 120);
398
470
  };
399
- window.addEventListener("popstate", t), window.addEventListener("hashchange", i), window.addEventListener("vanira:navigate", n), this.cleanupFns.push(
471
+ window.addEventListener("popstate", t), window.addEventListener("hashchange", i), window.addEventListener("vanira:navigate", a), this.cleanupFns.push(
400
472
  () => window.removeEventListener("popstate", t),
401
473
  () => window.removeEventListener("hashchange", i),
402
- () => window.removeEventListener("vanira:navigate", n)
474
+ () => window.removeEventListener("vanira:navigate", a)
403
475
  ), this.originalPushState = history.pushState.bind(history), this.originalReplaceState = history.replaceState.bind(history), history.pushState = (...r) => {
404
476
  this.originalPushState(...r), e("pushState");
405
477
  }, history.replaceState = (...r) => {
406
478
  this.originalReplaceState(...r), e("replaceState");
407
479
  }, this.routePollTimer = window.setInterval(() => {
408
480
  if (!this.active) return;
409
- const r = v();
481
+ const r = C();
410
482
  r !== this.lastRoute && this.handleRouteChange(r, "location_poll");
411
483
  }, 1e3);
412
484
  }
@@ -418,14 +490,14 @@ class _e {
418
490
  this.scheduleInitialContextSend();
419
491
  return;
420
492
  }
421
- !this.isReady() || pe() || this.sendRouteContext("route_changed", i, t, "user");
493
+ !this.isReady() || Ce() || this.sendRouteContext("route_changed", i, t, "user");
422
494
  }
423
- sendRouteContext(e, t, i, n = "user") {
424
- const r = v();
495
+ sendRouteContext(e, t, i, a = "user") {
496
+ const r = C();
425
497
  this.lastRoute = r;
426
498
  const o = {
427
499
  ui_state: "page_navigation",
428
- navigation_led_by: n,
500
+ navigation_led_by: a,
429
501
  current_route: r,
430
502
  current_page: r,
431
503
  user_action: e === "call_started" ? "call_started_on_page" : "user_navigated"
@@ -446,6 +518,9 @@ const y = class y {
446
518
  d(this, "apiKey");
447
519
  d(this, "backendUrl");
448
520
  d(this, "token");
521
+ d(this, "prospectName");
522
+ d(this, "welcomeMessage");
523
+ d(this, "extraDetails");
449
524
  d(this, "onConnected");
450
525
  d(this, "onDisconnected");
451
526
  d(this, "onError");
@@ -463,8 +538,10 @@ const y = class y {
463
538
  d(this, "localStream", null);
464
539
  d(this, "micMuted", !1);
465
540
  d(this, "connected", !1);
466
- d(this, "icePollInterval", null);
467
541
  d(this, "appliedRemoteCandidates", /* @__PURE__ */ new Set());
542
+ d(this, "remoteDescSet", !1);
543
+ d(this, "pendingServerIce", []);
544
+ d(this, "icePollStop", !1);
468
545
  d(this, "iceServers");
469
546
  d(this, "callSessionLoaded", !1);
470
547
  d(this, "connectGeneration", 0);
@@ -476,25 +553,27 @@ const y = class y {
476
553
  /** Live vision config — auto-starts camera on connect when scope is full_call. */
477
554
  d(this, "liveVision");
478
555
  d(this, "liveVisionAutoStarted", !1);
556
+ d(this, "connectStallTimeoutMs");
557
+ var _;
479
558
  if (!e.agentId) throw new Error("agentId is required");
480
- const t = !!(e.apiKey || e.token), i = !!(e.serverUrl && e.callId), n = y.normalizeIceServers(
559
+ const t = !!(e.apiKey || e.token), i = !!(e.serverUrl && e.callId), a = y.normalizeIceServers(
481
560
  e.iceServers
482
561
  );
483
562
  if (!t && !i)
484
563
  throw new Error(
485
564
  "apiKey or token is required — or pass serverUrl and callId from a prior POST /calls/create"
486
565
  );
487
- this.agentId = e.agentId, this.sessionBehavior = e.sessionBehavior, this.serverUrl = (e.serverUrl || "").replace(/\/$/, ""), this.apiKey = e.apiKey, this.token = e.token, this.backendUrl = (e.backendUrl || Q).replace(/\/$/, ""), n.length && (this.iceServers = n), i && (this.callSessionLoaded = !0);
566
+ this.agentId = e.agentId, this.sessionBehavior = e.sessionBehavior, this.serverUrl = (e.serverUrl || "").replace(/\/$/, ""), this.apiKey = e.apiKey, this.token = e.token, this.prospectName = e.prospectName, this.welcomeMessage = ((_ = e.welcomeMessage) == null ? void 0 : _.trim()) || void 0, this.extraDetails = e.extraDetails, this.backendUrl = (e.backendUrl || ie).replace(/\/$/, ""), a.length && (this.iceServers = a), i && (this.callSessionLoaded = !0);
488
567
  const r = typeof window < "u";
489
568
  this.prospectId = e.prospectId;
490
569
  const o = e.sessionBehavior === "continue";
491
570
  if (o && r && !e.callId) {
492
- const s = B(this.agentId);
571
+ const s = W(this.agentId);
493
572
  s && (e.callId || (this.callId = s.callId), !this.prospectId && s.prospectId && (this.prospectId = s.prospectId));
494
573
  }
495
574
  if (!this.prospectId && r)
496
575
  try {
497
- const s = B(this.agentId);
576
+ const s = W(this.agentId);
498
577
  this.prospectId = (s == null ? void 0 : s.prospectId) || window.sessionStorage && window.sessionStorage.getItem("vanira_prospect_id") || window.localStorage && window.localStorage.getItem("vanira_prospect_id") || void 0;
499
578
  } catch {
500
579
  }
@@ -502,36 +581,36 @@ const y = class y {
502
581
  const h = e.onSessionStarted;
503
582
  this.onSessionStarted = (s) => {
504
583
  h == null || h(s), this.emit("session_started", s);
505
- }, this.liveVision = e.liveVision, this.onConnected = () => {
584
+ }, this.liveVision = e.liveVision, this.connectStallTimeoutMs = e.connectStallTimeoutMs ?? 15e3, this.onConnected = () => {
506
585
  var s;
507
- this._status = "connected", (s = e.onConnected) == null || s.call(e), this.emit("connected"), this.maybeAutoStartLiveCamera();
586
+ g(), this._status = "connected", (s = e.onConnected) == null || s.call(e), this.emit("connected"), this.maybeAutoStartLiveCamera();
508
587
  }, this.onDisconnected = () => {
509
588
  var s;
510
- this._status = "disconnected", (s = e.onDisconnected) == null || s.call(e), this.emit("disconnected");
589
+ g(), this._status = "disconnected", (s = e.onDisconnected) == null || s.call(e), this.emit("disconnected");
511
590
  }, this.onError = (s) => {
512
- var p;
513
- this._status = "error";
591
+ var l;
592
+ g(), this._status = "error";
514
593
  const u = typeof s == "string" ? s : (s == null ? void 0 : s.message) || "Connection error";
515
- (p = e.onError) == null || p.call(e, s), this.emit("error", u);
516
- }, this.onTranscription = (s, u) => {
594
+ (l = e.onError) == null || l.call(e, s), this.emit("error", u);
595
+ }, this.onTranscription = (s, u, l) => {
517
596
  var p;
518
- (p = e.onTranscription) == null || p.call(e, s, u), this.emit("transcription", { text: s, isFinal: u });
597
+ (p = e.onTranscription) == null || p.call(e, s, u), this.emit("transcription", { text: s, isFinal: u, role: l });
519
598
  }, this.onLocalStream = e.onLocalStream || (() => {
520
599
  }), this.onRemoteTrack = (s, u) => {
521
- var p;
522
- (p = e.onRemoteTrack) == null || p.call(e, s, u), this.emit("track", { track: s, stream: u });
523
- }, this.onClientToolCall = (s) => {
524
600
  var l;
525
- (l = e.onClientToolCall) == null || l.call(e, s);
526
- const u = (s == null ? void 0 : s.data) || s, p = {
601
+ (l = e.onRemoteTrack) == null || l.call(e, s, u), this.emit("track", { track: s, stream: u });
602
+ }, this.onClientToolCall = (s) => {
603
+ var p;
604
+ (p = e.onClientToolCall) == null || p.call(e, s);
605
+ const u = (s == null ? void 0 : s.data) || s, l = {
527
606
  name: String(u.name || u.tool_name || ""),
528
607
  arguments: u.arguments || u.args || {},
529
608
  tool_call_id: String(u.tool_call_id || u.call_id || ""),
530
609
  execution_mode: u.execution_mode === "blocking" ? "blocking" : "fire_and_forget",
531
610
  client_fields: u.client_fields || {}
532
611
  };
533
- p.name && p.tool_call_id && this.emit("tool_call", p);
534
- }, this.runtime = e.runtime, typeof window < "u" && e.trackRouteContext !== !1 && (this.routeTracker = new _e({
612
+ l.name && l.tool_call_id && this.emit("tool_call", l);
613
+ }, this.runtime = e.runtime, typeof window < "u" && e.trackRouteContext !== !1 && (this.routeTracker = new Ie({
535
614
  sendContext: (s) => this.sendContextUpdate(s),
536
615
  isReady: () => {
537
616
  var s;
@@ -557,7 +636,7 @@ const y = class y {
557
636
  */
558
637
  async connect() {
559
638
  var t;
560
- this._status = "connecting";
639
+ this._status = "connecting", this.connectStallTimeoutMs > 0 && ge(this.connectStallTimeoutMs);
561
640
  const e = ++this.connectGeneration;
562
641
  if (await this.loadCallSession(), !this.isConnectCancelled(e)) {
563
642
  if (!this.serverUrl)
@@ -570,15 +649,15 @@ const y = class y {
570
649
  } catch {
571
650
  }
572
651
  try {
573
- this.appliedRemoteCandidates.clear(), this.stopRemoteIcePolling();
652
+ this.appliedRemoteCandidates.clear(), this.remoteDescSet = !1, this.pendingServerIce = [], this.icePollStop = !1, this.stopRemoteIcePolling();
574
653
  const i = this.getIceServers();
575
654
  this.pc = new RTCPeerConnection({
576
655
  iceServers: i,
577
656
  iceTransportPolicy: "all"
578
657
  });
579
- let n;
658
+ let a;
580
659
  try {
581
- n = await navigator.mediaDevices.getUserMedia({
660
+ a = await navigator.mediaDevices.getUserMedia({
582
661
  audio: {
583
662
  echoCancellation: !0,
584
663
  noiseSuppression: !0,
@@ -589,25 +668,25 @@ const y = class y {
589
668
  });
590
669
  } catch (l) {
591
670
  if (l.name === "NotAllowedError" || l.name === "PermissionDeniedError" || (t = l.message) != null && t.includes("Permission denied")) {
592
- const _ = navigator.userAgent, m = /iPad|iPhone|iPod/.test(_) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1;
671
+ const p = navigator.userAgent, m = /iPad|iPhone|iPod/.test(p) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1;
593
672
  let f = "Microphone access denied. Please allow microphone access in your browser settings.";
594
- m && (_.includes("CriOS") ? f = "Microphone access blocked. Please enable it in iOS Settings > Chrome > Microphone, then reload the page." : _.includes("FxiOS") ? f = "Microphone access blocked. Please enable it in iOS Settings > Firefox > Microphone, then reload the page." : f = "Microphone access blocked. Please enable it in iOS Settings > Safari > Microphone (or tap 'aA' > Website Settings > Allow Microphone).");
595
- const S = new Error(f);
596
- throw S.name = l.name, S;
673
+ m && (p.includes("CriOS") ? f = "Microphone access blocked. Please enable it in iOS Settings > Chrome > Microphone, then reload the page." : p.includes("FxiOS") ? f = "Microphone access blocked. Please enable it in iOS Settings > Firefox > Microphone, then reload the page." : f = "Microphone access blocked. Please enable it in iOS Settings > Safari > Microphone (or tap 'aA' > Website Settings > Allow Microphone).");
674
+ const w = new Error(f);
675
+ throw w.name = l.name, w;
597
676
  }
598
677
  throw l;
599
678
  }
600
679
  if (this.isConnectCancelled(e)) {
601
- n.getTracks().forEach((l) => l.stop());
680
+ a.getTracks().forEach((l) => l.stop());
602
681
  return;
603
682
  }
604
- if (this.localStream = n, !this.pc || this.isConnectCancelled(e)) {
605
- n.getTracks().forEach((l) => l.stop());
683
+ if (this.localStream = a, !this.pc || this.isConnectCancelled(e)) {
684
+ a.getTracks().forEach((l) => l.stop());
606
685
  return;
607
686
  }
608
- if (this.onLocalStream(n), n.getTracks().forEach((l) => {
609
- var _;
610
- (_ = this.pc) == null || _.addTrack(l, n);
687
+ if (this.onLocalStream(a), a.getTracks().forEach((l) => {
688
+ var p;
689
+ (p = this.pc) == null || p.addTrack(l, a);
611
690
  }), !this.pc)
612
691
  throw new Error("RTCPeerConnection was closed unexpectedly");
613
692
  this.dataChannel = this.pc.createDataChannel("control"), this.dataChannel.onopen = () => {
@@ -621,17 +700,17 @@ const y = class y {
621
700
  }
622
701
  else if (l.data instanceof ArrayBuffer)
623
702
  try {
624
- const _ = new TextDecoder().decode(l.data);
703
+ const p = new TextDecoder().decode(l.data);
625
704
  try {
626
- const m = JSON.parse(_);
627
- oe(m) && this.handleControlEvent(m);
705
+ const m = JSON.parse(p);
706
+ pe(m) && this.handleControlEvent(m);
628
707
  } catch {
629
708
  }
630
709
  } catch {
631
710
  }
632
- else l.data instanceof Blob && l.data.text().then((_) => {
711
+ else l.data instanceof Blob && l.data.text().then((p) => {
633
712
  try {
634
- this.handleControlEvent(JSON.parse(_));
713
+ this.handleControlEvent(JSON.parse(p));
635
714
  } catch {
636
715
  }
637
716
  });
@@ -639,30 +718,25 @@ const y = class y {
639
718
  }, this.mediaBytesChannel = this.pc.createDataChannel("media-bytes", { ordered: !0 }), this.mediaBytesChannel.binaryType = "arraybuffer", this.mediaBytesChannel.onopen = () => {
640
719
  }, this.mediaBytesChannel.onerror = (l) => {
641
720
  }, this.pc.ontrack = (l) => {
642
- const _ = l.track, m = l.streams[0];
643
- _.kind === "audio" ? (this.audioElement = new Audio(), this.audioElement.srcObject = m, this.audioElement.play().catch((f) => {
721
+ const p = l.track, m = l.streams[0];
722
+ p.kind === "audio" ? (this.audioElement = new Audio(), this.audioElement.srcObject = m, this.audioElement.play().catch((f) => {
644
723
  }), this.audioElement.onended = () => {
645
724
  this.sendEvent("playedStream"), typeof window < "u" && window.dispatchEvent(new CustomEvent("vanira:agent-playback-ended"));
646
- }, this.onRemoteTrack(_, m)) : _.kind === "video" && this.onRemoteTrack(_, m);
725
+ }, this.onRemoteTrack(p, m)) : p.kind === "video" && this.onRemoteTrack(p, m);
647
726
  };
648
727
  const r = () => {
649
- var m, f, S, b, x, A, P, U, L, M, O;
650
- const l = ((m = this.pc) == null ? void 0 : m.connectionState) === "connected" || ((f = this.pc) == null ? void 0 : f.iceConnectionState) === "connected" || ((S = this.pc) == null ? void 0 : S.iceConnectionState) === "completed", _ = ((b = this.pc) == null ? void 0 : b.connectionState) === "failed" || ((x = this.pc) == null ? void 0 : x.iceConnectionState) === "failed" || ((A = this.pc) == null ? void 0 : A.connectionState) === "closed" || ((P = this.pc) == null ? void 0 : P.iceConnectionState) === "closed" || ((U = this.pc) == null ? void 0 : U.connectionState) === "disconnected" || ((L = this.pc) == null ? void 0 : L.iceConnectionState) === "disconnected";
651
- ((M = this.pc) == null ? void 0 : M.connectionState) === "connected" && this.stopRemoteIcePolling(), l && !this.connected ? (this.connected = !0, (O = this.routeTracker) == null || O.start(), this.onConnected()) : _ && this.connected && (this.connected = !1, this.liveVisionAutoStarted = !1, this.onDisconnected());
728
+ var m, f, w, U, M, L, D, O, N, V, B;
729
+ const l = ((m = this.pc) == null ? void 0 : m.connectionState) === "connected" || ((f = this.pc) == null ? void 0 : f.iceConnectionState) === "connected" || ((w = this.pc) == null ? void 0 : w.iceConnectionState) === "completed", p = ((U = this.pc) == null ? void 0 : U.connectionState) === "failed" || ((M = this.pc) == null ? void 0 : M.iceConnectionState) === "failed" || ((L = this.pc) == null ? void 0 : L.connectionState) === "closed" || ((D = this.pc) == null ? void 0 : D.iceConnectionState) === "closed" || ((O = this.pc) == null ? void 0 : O.connectionState) === "disconnected" || ((N = this.pc) == null ? void 0 : N.iceConnectionState) === "disconnected";
730
+ ((V = this.pc) == null ? void 0 : V.connectionState) === "connected" && this.stopRemoteIcePolling(), l && !this.connected ? (this.connected = !0, (B = this.routeTracker) == null || B.start(), this.onConnected()) : p && this.connected && (this.connected = !1, this.liveVisionAutoStarted = !1, this.onDisconnected());
652
731
  };
653
732
  this.pc.onconnectionstatechange = r, this.pc.oniceconnectionstatechange = r;
654
733
  const o = this.getIceTrickleUrl();
655
734
  this.pc.onicecandidate = (l) => {
656
- l.candidate && fetch(o, {
657
- method: "POST",
658
- headers: { "Content-Type": "application/json" },
659
- body: JSON.stringify({ candidate: l.candidate.toJSON() })
660
- }).catch((_) => {
661
- });
735
+ l.candidate && this.sendRemoteIceCandidate(l.candidate, o);
662
736
  };
663
737
  const h = await this.pc.createOffer();
664
738
  if (this.isConnectCancelled(e) || (await this.pc.setLocalDescription(h), this.isConnectCancelled(e))) return;
665
- const s = this.serverUrl.includes("?") ? this.serverUrl : `${this.serverUrl}/webrtc?agent=${this.agentId}_${this.callId}`, u = await fetch(s, {
739
+ const _ = this.serverUrl.includes("?") ? this.serverUrl : `${this.serverUrl}/webrtc?agent=${this.agentId}_${this.callId}`, s = await fetch(_, {
666
740
  method: "POST",
667
741
  headers: { "Content-Type": "application/json" },
668
742
  body: JSON.stringify({
@@ -672,12 +746,12 @@ const y = class y {
672
746
  })
673
747
  });
674
748
  if (this.isConnectCancelled(e)) return;
675
- if (!u.ok) {
676
- const l = await u.json();
677
- throw new Error(l.error || `HTTP ${u.status}`);
749
+ if (!s.ok) {
750
+ const l = await s.json();
751
+ throw new Error(l.error || `HTTP ${s.status}`);
678
752
  }
679
- const { answer: p } = await u.json();
680
- if (this.isConnectCancelled(e) || !this.pc || (await this.pc.setRemoteDescription(p), this.isConnectCancelled(e))) return;
753
+ const { answer: u } = await s.json();
754
+ if (this.isConnectCancelled(e) || !this.pc || (await this.pc.setRemoteDescription(u), this.isConnectCancelled(e)) || (this.remoteDescSet = !0, await this.flushPendingServerIce(), this.isConnectCancelled(e))) return;
681
755
  this.startRemoteIcePolling(o);
682
756
  } catch (i) {
683
757
  if (this.isConnectCancelled(e)) return;
@@ -697,24 +771,27 @@ const y = class y {
697
771
  ].join("|");
698
772
  }
699
773
  async postCreateCall(e, t, i) {
700
- var h, s, u;
701
- const n = await fetch(`${this.backendUrl}/calls/create`, {
774
+ var h, _, s;
775
+ const a = await fetch(`${this.backendUrl}/calls/create`, {
702
776
  method: "POST",
703
777
  headers: e,
704
778
  body: JSON.stringify({
705
779
  agent_id: this.agentId,
706
780
  type: ((h = this.runtime) == null ? void 0 : h.callType) || "web",
707
781
  mode: t,
708
- ...(s = this.runtime) != null && s.runtimeName ? { runtime: this.runtime.runtimeName } : {},
782
+ ...(_ = this.runtime) != null && _.runtimeName ? { runtime: this.runtime.runtimeName } : {},
709
783
  prospect_id: this.prospectId,
784
+ ...this.prospectName ? { prospect_name: this.prospectName } : {},
785
+ ...this.welcomeMessage ? { welcome_message: this.welcomeMessage } : {},
786
+ ...this.extraDetails && Object.keys(this.extraDetails).length ? { extra_details: this.extraDetails } : {},
710
787
  ...i ? { call_id: i } : {}
711
788
  })
712
789
  });
713
- if (!n.ok) {
714
- const p = await n.json().catch(() => ({}));
715
- throw new Error(`[VaniraClient] createCall failed (${n.status}): ${((u = p == null ? void 0 : p.detail) == null ? void 0 : u.message) || (p == null ? void 0 : p.message) || n.statusText}`);
790
+ if (!a.ok) {
791
+ const u = await a.json().catch(() => ({}));
792
+ throw new Error(`[VaniraClient] createCall failed (${a.status}): ${((s = u == null ? void 0 : u.detail) == null ? void 0 : s.message) || (u == null ? void 0 : u.message) || a.statusText}`);
716
793
  }
717
- const r = await n.json();
794
+ const r = await a.json();
718
795
  if (!r.call_id || !r.worker_url)
719
796
  throw new Error("[VaniraClient] /calls/create response missing call_id or worker_url");
720
797
  const o = y.normalizeIceServers(r.ice_servers);
@@ -728,7 +805,7 @@ const y = class y {
728
805
  };
729
806
  }
730
807
  applyCreateCallSession(e) {
731
- if (this.callId = e.callId, this.prospectId = e.prospectId || this.prospectId, this.serverUrl = e.serverUrl, this.iceServers = e.iceServers, this.callSessionLoaded = !0, re(this.agentId, this.callId || "", this.prospectId), this.onSessionStarted && this.prospectId && this.callId && !this.sessionStartedEmitted)
808
+ if (this.callId = e.callId, this.prospectId = e.prospectId || this.prospectId, this.serverUrl = e.serverUrl, this.iceServers = e.iceServers, this.callSessionLoaded = !0, he(this.agentId, this.callId || "", this.prospectId), this.onSessionStarted && this.prospectId && this.callId && !this.sessionStartedEmitted)
732
809
  try {
733
810
  this.onSessionStarted({ prospectId: this.prospectId, callId: this.callId, serverUrl: this.serverUrl }), this.sessionStartedEmitted = !0;
734
811
  } catch {
@@ -744,10 +821,10 @@ const y = class y {
744
821
  throw new Error("[VaniraClient] apiKey or token is required to create a call session");
745
822
  const e = { "Content-Type": "application/json" };
746
823
  this.apiKey ? e["X-API-Key"] = this.apiKey : this.token && (e.Authorization = this.token.startsWith("Bearer ") ? this.token : `Bearer ${this.token}`);
747
- const t = this.sessionBehavior === "continue" ? this.callId : void 0, i = this.sessionBehavior === "continue" ? "continue" : "new", n = this.createCallCacheKey(i, t);
748
- let r = y.inflightCreates.get(n);
749
- r || (r = this.postCreateCall(e, i, t), y.inflightCreates.set(n, r), r.finally(() => {
750
- y.inflightCreates.get(n) === r && y.inflightCreates.delete(n);
824
+ const t = this.sessionBehavior === "continue" ? this.callId : void 0, i = this.sessionBehavior === "continue" ? "continue" : "new", a = this.createCallCacheKey(i, t);
825
+ let r = y.inflightCreates.get(a);
826
+ r || (r = this.postCreateCall(e, i, t), y.inflightCreates.set(a, r), r.finally(() => {
827
+ y.inflightCreates.get(a) === r && y.inflightCreates.delete(a);
751
828
  }));
752
829
  const o = await r;
753
830
  this.applyCreateCallSession(o);
@@ -761,10 +838,10 @@ const y = class y {
761
838
  if (!Array.isArray(e)) return [];
762
839
  const t = [];
763
840
  for (const i of e) {
764
- const n = i == null ? void 0 : i.urls, r = Array.isArray(n) ? n.filter(Boolean) : typeof n == "string" && n.trim() ? [n.trim()] : [];
841
+ const a = i == null ? void 0 : i.urls, r = Array.isArray(a) ? a.filter(Boolean) : typeof a == "string" && a.trim() ? [a.trim()] : [];
765
842
  if (!r.length) continue;
766
- const o = { urls: r.length === 1 ? r[0] : r }, h = i.username, s = i.credential;
767
- h && (o.username = h), s && (o.credential = s), t.push(o);
843
+ const o = { urls: r.length === 1 ? r[0] : r }, h = i.username, _ = i.credential;
844
+ h && (o.username = h), _ && (o.credential = _), t.push(o);
768
845
  }
769
846
  return t;
770
847
  }
@@ -789,36 +866,76 @@ const y = class y {
789
866
  return `${this.getWorkerOrigin()}/webrtc/ice?agent_id=${this.agentId}&call_id=${this.callId}`;
790
867
  }
791
868
  }
792
- startRemoteIcePolling(e) {
793
- this.stopRemoteIcePolling(), this.icePollInterval = setInterval(async () => {
794
- if (!this.pc) {
795
- this.stopRemoteIcePolling();
796
- return;
869
+ async sendRemoteIceCandidate(e, t) {
870
+ try {
871
+ const i = await fetch(t, {
872
+ method: "POST",
873
+ headers: { "Content-Type": "application/json" },
874
+ body: JSON.stringify({ candidate: e.toJSON() })
875
+ });
876
+ if (i.ok) {
877
+ const a = await i.json();
878
+ await this.applyServerIceCandidates(a.candidates);
797
879
  }
798
- if (this.pc.connectionState === "connected") {
799
- this.stopRemoteIcePolling();
880
+ } catch {
881
+ }
882
+ }
883
+ /** Queue server ICE until setRemoteDescription(answer), then apply. */
884
+ async applyServerIceCandidates(e) {
885
+ if (!(!this.pc || !(e != null && e.length))) {
886
+ if (!this.remoteDescSet) {
887
+ this.pendingServerIce.push(...e);
800
888
  return;
801
889
  }
802
- try {
803
- const t = await fetch(e);
804
- if (!t.ok) return;
805
- const { candidates: i } = await t.json();
806
- for (const n of i || []) {
807
- const r = JSON.stringify(n);
808
- if (!this.appliedRemoteCandidates.has(r)) {
809
- this.appliedRemoteCandidates.add(r);
810
- try {
811
- await this.pc.addIceCandidate(n);
812
- } catch {
813
- }
890
+ for (const t of e) {
891
+ const i = JSON.stringify(t);
892
+ if (!this.appliedRemoteCandidates.has(i)) {
893
+ this.appliedRemoteCandidates.add(i);
894
+ try {
895
+ await this.pc.addIceCandidate(t);
896
+ } catch {
814
897
  }
815
898
  }
899
+ }
900
+ }
901
+ }
902
+ async flushPendingServerIce() {
903
+ if (!this.pc || !this.remoteDescSet || this.pendingServerIce.length === 0) return;
904
+ const e = this.pendingServerIce;
905
+ this.pendingServerIce = [];
906
+ for (const t of e) {
907
+ const i = JSON.stringify(t);
908
+ if (!this.appliedRemoteCandidates.has(i)) {
909
+ this.appliedRemoteCandidates.add(i);
910
+ try {
911
+ await this.pc.addIceCandidate(t);
912
+ } catch {
913
+ }
914
+ }
915
+ }
916
+ }
917
+ startRemoteIcePolling(e) {
918
+ this.icePollStop = !1, this.pollServerIce(e);
919
+ }
920
+ async pollServerIce(e) {
921
+ var i;
922
+ const t = Date.now() + 15e3;
923
+ for (; !this.icePollStop && Date.now() < t; ) {
924
+ const a = (i = this.pc) == null ? void 0 : i.connectionState;
925
+ if (a === "connected" || a === "failed" || a === "closed") break;
926
+ try {
927
+ const r = await fetch(e, { method: "GET" });
928
+ if (r.ok) {
929
+ const o = await r.json();
930
+ if (await this.applyServerIceCandidates(o.candidates), o.done && (!o.candidates || o.candidates.length === 0)) break;
931
+ }
816
932
  } catch {
817
933
  }
818
- }, 150);
934
+ await new Promise((r) => setTimeout(r, 150));
935
+ }
819
936
  }
820
937
  stopRemoteIcePolling() {
821
- this.icePollInterval !== null && (clearInterval(this.icePollInterval), this.icePollInterval = null);
938
+ this.icePollStop = !0;
822
939
  }
823
940
  /**
824
941
  * Send control event via DataChannel
@@ -826,15 +943,15 @@ const y = class y {
826
943
  sendEvent(e, t = {}) {
827
944
  var i;
828
945
  if (((i = this.dataChannel) == null ? void 0 : i.readyState) === "open") {
829
- const n = { event: e, ...t };
830
- this.dataChannel.send(JSON.stringify(n));
946
+ const a = { event: e, ...t };
947
+ this.dataChannel.send(JSON.stringify(a));
831
948
  }
832
949
  }
833
950
  /** Wait for control DataChannel, then send (live vision lifecycle events). */
834
951
  async sendEventWhenReady(e, t = {}, i = 1e4) {
835
952
  var r;
836
- const n = Date.now() + i;
837
- for (; Date.now() < n; ) {
953
+ const a = Date.now() + i;
954
+ for (; Date.now() < a; ) {
838
955
  if (((r = this.dataChannel) == null ? void 0 : r.readyState) === "open")
839
956
  return this.sendEvent(e, t), !0;
840
957
  await new Promise((o) => setTimeout(o, 50));
@@ -877,32 +994,42 @@ const y = class y {
877
994
  var t;
878
995
  switch (e.event) {
879
996
  case "clearAudio":
997
+ this.dispatchBoardAbort(
998
+ "User interrupted while LaTeX was writing",
999
+ void 0,
1000
+ c.WriteLatexText
1001
+ );
880
1002
  break;
881
1003
  case "transcription":
882
- this.onTranscription(e.text, e.isFinal);
1004
+ {
1005
+ const i = e.data && typeof e.data == "object" ? e.data : {}, a = String(e.text ?? i.text ?? "").trim(), r = e.isFinal ?? e.is_final ?? i.isFinal ?? i.is_final, o = r === void 0 ? !0 : r === !0 || r === "true", h = String(
1006
+ e.role ?? e.speaker ?? i.role ?? i.speaker ?? ""
1007
+ ).trim() || void 0;
1008
+ a && this.onTranscription(a, o, h);
1009
+ }
883
1010
  break;
884
1011
  case "mark":
885
1012
  break;
886
1013
  case "client_tool_cancel": {
887
- const n = (e.data || e).tool_call_id || e.tool_call_id;
888
- this.dispatchBoardAbort("Tool cancelled by server", n);
1014
+ const a = (e.data || e).tool_call_id || e.tool_call_id;
1015
+ this.dispatchBoardAbort("Tool cancelled by server", a);
889
1016
  break;
890
1017
  }
891
1018
  case "client_tool_call": {
892
- const i = e.tool_call || e.data || e, n = (i == null ? void 0 : i.tool_call_id) || (i == null ? void 0 : i.call_id) || e.tool_call_id || "";
893
- n && ((t = this.dataChannel) == null ? void 0 : t.readyState) === "open" && this.dataChannel.send(JSON.stringify({
1019
+ const i = e.tool_call || e.data || e, a = (i == null ? void 0 : i.tool_call_id) || (i == null ? void 0 : i.call_id) || e.tool_call_id || "";
1020
+ a && ((t = this.dataChannel) == null ? void 0 : t.readyState) === "open" && this.dataChannel.send(JSON.stringify({
894
1021
  event: "client_tool_ack",
895
- data: { tool_call_id: n }
1022
+ data: { tool_call_id: a }
896
1023
  }));
897
- const r = (i == null ? void 0 : i.arguments) || (i == null ? void 0 : i.args) || {}, o = (i == null ? void 0 : i.client_fields) || {}, h = (i == null ? void 0 : i.name) || (i == null ? void 0 : i.tool_name) || "", s = ae(o, r, h);
1024
+ const r = (i == null ? void 0 : i.arguments) || (i == null ? void 0 : i.args) || {}, o = (i == null ? void 0 : i.client_fields) || {}, h = (i == null ? void 0 : i.name) || (i == null ? void 0 : i.tool_name) || "", _ = de(o, r, h);
898
1025
  if (h === "end_call") {
899
- n && this.sendToolResult(n, {
1026
+ a && this.sendToolResult(a, {
900
1027
  status: "client_ack_end_call",
901
1028
  message: "Ending call."
902
1029
  }), window.setTimeout(() => this.disconnect(), 120);
903
1030
  break;
904
1031
  }
905
- if (s) {
1032
+ if (_) {
906
1033
  window.dispatchEvent(new CustomEvent("vanira:preset", {
907
1034
  detail: { toolCall: i, client: this }
908
1035
  })), this.onClientToolCall(i);
@@ -918,7 +1045,7 @@ const y = class y {
918
1045
  */
919
1046
  disconnect() {
920
1047
  var e;
921
- this.connectGeneration++, this.stopRemoteIcePolling(), this.appliedRemoteCandidates.clear(), this.audioElement && (this.audioElement.pause(), this.audioElement.srcObject = null), this.dataChannel && (this.dataChannel.close(), this.dataChannel = null), this.mediaBytesChannel && (this.mediaBytesChannel.close(), this.mediaBytesChannel = null), this.pc && (this.pc.getSenders().forEach((t) => {
1048
+ g(), this.connectGeneration++, this.stopRemoteIcePolling(), this.appliedRemoteCandidates.clear(), this.remoteDescSet = !1, this.pendingServerIce = [], this.audioElement && (this.audioElement.pause(), this.audioElement.srcObject = null), this.dataChannel && (this.dataChannel.close(), this.dataChannel = null), this.mediaBytesChannel && (this.mediaBytesChannel.close(), this.mediaBytesChannel = null), this.pc && (this.pc.getSenders().forEach((t) => {
922
1049
  t.track && t.track.stop();
923
1050
  }), this.pc.close(), this.pc = null), this.localStream && (this.localStream.getTracks().forEach((t) => {
924
1051
  try {
@@ -933,11 +1060,11 @@ const y = class y {
933
1060
  */
934
1061
  setMicrophoneMuted(e) {
935
1062
  var t, i;
936
- this.micMuted = e, (t = this.localStream) == null || t.getAudioTracks().forEach((n) => {
937
- n.enabled = !e;
938
- }), (i = this.pc) == null || i.getSenders().forEach((n) => {
1063
+ this.micMuted = e, (t = this.localStream) == null || t.getAudioTracks().forEach((a) => {
1064
+ a.enabled = !e;
1065
+ }), (i = this.pc) == null || i.getSenders().forEach((a) => {
939
1066
  var r;
940
- ((r = n.track) == null ? void 0 : r.kind) === "audio" && (n.track.enabled = !e);
1067
+ ((r = a.track) == null ? void 0 : r.kind) === "audio" && (a.track.enabled = !e);
941
1068
  });
942
1069
  }
943
1070
  isMicrophoneMuted() {
@@ -950,9 +1077,9 @@ const y = class y {
950
1077
  return e !== this.connectGeneration;
951
1078
  }
952
1079
  /** Notify WidgetPresetRenderer to cancel in-flight board animations */
953
- dispatchBoardAbort(e, t) {
1080
+ dispatchBoardAbort(e, t, i) {
954
1081
  typeof window > "u" || window.dispatchEvent(new CustomEvent("vanira:board_abort", {
955
- detail: { reason: e, toolCallId: t }
1082
+ detail: { reason: e, toolCallId: t, presetId: i }
956
1083
  }));
957
1084
  }
958
1085
  /**
@@ -967,7 +1094,7 @@ const y = class y {
967
1094
  call_id: this.callId,
968
1095
  data: { tool_call_id: e, result: t },
969
1096
  result: t
970
- });
1097
+ }), this.emit("tool_result", { toolCallId: e, result: t });
971
1098
  }
972
1099
  /**
973
1100
  * Send an acknowledgement that the client received a tool call and rendered it.
@@ -1042,7 +1169,7 @@ const y = class y {
1042
1169
  * @param message Optional user text message about the file
1043
1170
  */
1044
1171
  async uploadMedia(e, t = "general", i = "") {
1045
- return await de(this.dataChannel, this.mediaBytesChannel) ? this._uploadMediaViaDataChannel(e, t, i) : (le(this.dataChannel, this.mediaBytesChannel), this._uploadMediaViaHTTP(e, t, i));
1172
+ return await fe(this.dataChannel, this.mediaBytesChannel) ? this._uploadMediaViaDataChannel(e, t, i) : (me(this.dataChannel, this.mediaBytesChannel), this._uploadMediaViaHTTP(e, t, i));
1046
1173
  }
1047
1174
  /**
1048
1175
  * Upload a live vision / screen frame — HTTP only for now, never sends client_media_update.
@@ -1052,71 +1179,71 @@ const y = class y {
1052
1179
  * the server adds client_media_upload_ready ack — use HTTP for frame JPEGs until then.
1053
1180
  */
1054
1181
  async uploadMediaFrame(e, t = "camera_capture", i) {
1055
- const n = i && !(e instanceof File) ? new File([e], i, { type: e.type || "image/jpeg" }) : e, { media_id: r, url: o, contentType: h } = await this._postMediaUpload(n, t, !0);
1182
+ const a = i && !(e instanceof File) ? new File([e], i, { type: e.type || "image/jpeg" }) : e, { media_id: r, url: o, contentType: h } = await this._postMediaUpload(a, t, !0);
1056
1183
  if (!r || !o)
1057
1184
  throw new Error("Frame upload failed: server response missing media_id or url");
1058
1185
  return { media_id: r, url: o, content_type: h };
1059
1186
  }
1060
1187
  /** WebRTC media-bytes path (control start/complete + binary chunks). */
1061
- async _uploadBytesViaDataChannel(e, t, i, n, r) {
1188
+ async _uploadBytesViaDataChannel(e, t, i, a, r) {
1062
1189
  if (!this.callId || !this.mediaBytesChannel)
1063
1190
  throw new Error("Upload failed: call not ready for WebRTC media upload.");
1064
- const o = r || (e instanceof File ? e.name : n === "frame" ? "frame.jpg" : "upload.bin"), h = e.type || (n === "frame" ? "image/jpeg" : "application/octet-stream"), s = await ue(e);
1065
- return he({
1066
- bytes: s,
1191
+ const o = r || (e instanceof File ? e.name : a === "frame" ? "frame.jpg" : "upload.bin"), h = e.type || (a === "frame" ? "image/jpeg" : "application/octet-stream"), _ = await Se(e);
1192
+ return ye({
1193
+ bytes: _,
1067
1194
  filename: o,
1068
1195
  contentType: h,
1069
1196
  reason: t,
1070
1197
  message: i,
1071
1198
  callId: this.callId,
1072
1199
  mediaBytesChannel: this.mediaBytesChannel,
1073
- sendControlEvent: (u, p) => this.sendEvent(u, p),
1074
- uploadKind: n
1200
+ sendControlEvent: (s, u) => this.sendEvent(s, u),
1201
+ uploadKind: a
1075
1202
  });
1076
1203
  }
1077
1204
  async _uploadMediaViaDataChannel(e, t, i) {
1078
- const n = await this._uploadBytesViaDataChannel(e, t, i, "media");
1079
- return { media_id: n.media_id, url: n.url };
1205
+ const a = await this._uploadBytesViaDataChannel(e, t, i, "media");
1206
+ return { media_id: a.media_id, url: a.url };
1080
1207
  }
1081
1208
  /** HTTP fallback — original uploadMedia behavior (unchanged). */
1082
1209
  async _uploadMediaViaHTTP(e, t = "general", i = "") {
1083
- const { media_id: n, url: r, contentType: o } = await this._postMediaUpload(e, t, !0);
1210
+ const { media_id: a, url: r, contentType: o } = await this._postMediaUpload(e, t, !0);
1084
1211
  return this.sendMediaUpdate({
1085
- media_id: n,
1212
+ media_id: a,
1086
1213
  media_url: r,
1087
1214
  content_type: o,
1088
1215
  reason: t,
1089
1216
  message: i
1090
- }), { media_id: n, url: r };
1217
+ }), { media_id: a, url: r };
1091
1218
  }
1092
1219
  async _postMediaUpload(e, t, i = !1) {
1093
1220
  if (!this.serverUrl)
1094
1221
  throw new Error("Upload failed: serverUrl is not set. Connect the VaniraClient first.");
1095
1222
  if (!this.callId)
1096
1223
  throw new Error("Upload failed: callId is missing.");
1097
- const n = this.getWorkerOrigin();
1098
- if (!n)
1224
+ const a = this.getWorkerOrigin();
1225
+ if (!a)
1099
1226
  throw new Error(
1100
1227
  "Upload failed: worker_url is not set. Connect the call before uploading media."
1101
1228
  );
1102
- const r = `${n}/media/upload`, o = new FormData();
1229
+ const r = `${a}/media/upload`, o = new FormData();
1103
1230
  o.append("file", e), o.append("call_id", this.callId), o.append("reason", t);
1104
1231
  const h = await fetch(r, {
1105
1232
  method: "POST",
1106
1233
  body: o
1107
1234
  });
1108
1235
  if (!h.ok) {
1109
- let _ = `HTTP ${h.status}`;
1236
+ let p = `HTTP ${h.status}`;
1110
1237
  try {
1111
- _ = (await h.json()).error || _;
1238
+ p = (await h.json()).error || p;
1112
1239
  } catch {
1113
1240
  }
1114
- throw new Error(`Upload failed: ${_}`);
1241
+ throw new Error(`Upload failed: ${p}`);
1115
1242
  }
1116
- const s = await h.json(), u = s.media_id, p = s.url, l = s.content_type || e.type;
1117
- if (!u || !p)
1243
+ const _ = await h.json(), s = _.media_id, u = _.url, l = _.content_type || e.type;
1244
+ if (!s || !u)
1118
1245
  throw new Error("Upload failed: server response missing media_id or url");
1119
- return i ? { media_id: u, url: p, contentType: l } : { media_id: u, url: p, contentType: l };
1246
+ return i ? { media_id: s, url: u, contentType: l } : { media_id: s, url: u, contentType: l };
1120
1247
  }
1121
1248
  // ─── Event emitter (replaces retired VaniraAI) ───────────────────────────
1122
1249
  get status() {
@@ -1134,7 +1261,7 @@ const y = class y {
1134
1261
  }
1135
1262
  emit(e, t) {
1136
1263
  var i;
1137
- (i = this.listeners.get(e)) == null || i.forEach((n) => n(t));
1264
+ (i = this.listeners.get(e)) == null || i.forEach((a) => a(t));
1138
1265
  }
1139
1266
  /** Alias for connect() — VaniraAI compatibility */
1140
1267
  async start() {
@@ -1165,8 +1292,8 @@ const y = class y {
1165
1292
  };
1166
1293
  /** Dedupes concurrent POST /calls/create (e.g. React StrictMode double-mount). */
1167
1294
  d(y, "inflightCreates", /* @__PURE__ */ new Map());
1168
- let R = y;
1169
- const me = {
1295
+ let A = y;
1296
+ const Te = {
1170
1297
  supportsAudioEndedEvent: !1,
1171
1298
  supportsScreenShare: !1,
1172
1299
  supportsDom: !1,
@@ -1174,40 +1301,40 @@ const me = {
1174
1301
  supportsCustomElements: !1,
1175
1302
  supportsLocalStorage: !1,
1176
1303
  supportsBroadcastChannel: !1
1177
- }, fe = {
1304
+ }, be = {
1178
1305
  name: "react-native",
1179
1306
  callType: "web",
1180
1307
  runtimeName: "react-native",
1181
1308
  callIdPrefix: "rn_",
1182
- capabilities: me,
1183
- audio: new Y(),
1184
- media: new q(),
1185
- peer: new X(),
1186
- dataChannel: new Z()
1309
+ capabilities: Te,
1310
+ audio: new Q(),
1311
+ media: new F(),
1312
+ peer: new ee(),
1313
+ dataChannel: new te()
1187
1314
  };
1188
- function J(a) {
1189
- return new R({
1190
- ...a,
1191
- runtime: fe
1315
+ function Y(n) {
1316
+ return new A({
1317
+ ...n,
1318
+ runtime: be
1192
1319
  });
1193
1320
  }
1194
- const Se = J;
1195
- function ye(a) {
1196
- return J(a);
1321
+ const ke = Y;
1322
+ function xe(n) {
1323
+ return Y(n);
1197
1324
  }
1198
- const ve = ye;
1325
+ const Re = xe;
1199
1326
  export {
1200
- Y as RNAudioAdapter,
1201
- Z as RNDataChannelAdapter,
1202
- q as RNMediaAdapter,
1203
- X as RNPeerAdapter,
1204
- R as VaniraAI,
1205
- R as VaniraClient,
1206
- R as WebRTCClient,
1207
- Se as createReactNativeAI,
1208
- J as createReactNativeClient,
1209
- ve as createVaniraAI,
1210
- ye as createVaniraClient,
1211
- me as reactNativeCapabilities,
1212
- fe as reactNativeRuntime
1327
+ Q as RNAudioAdapter,
1328
+ te as RNDataChannelAdapter,
1329
+ F as RNMediaAdapter,
1330
+ ee as RNPeerAdapter,
1331
+ A as VaniraAI,
1332
+ A as VaniraClient,
1333
+ A as WebRTCClient,
1334
+ ke as createReactNativeAI,
1335
+ Y as createReactNativeClient,
1336
+ Re as createVaniraAI,
1337
+ xe as createVaniraClient,
1338
+ Te as reactNativeCapabilities,
1339
+ be as reactNativeRuntime
1213
1340
  };