@absolutejs/voice 0.0.22-beta.654 → 0.0.22-beta.655

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.
@@ -687,6 +687,21 @@ var createVoiceConnection = (path, options = {}) => {
687
687
  const emitConnection = (reconnect) => {
688
688
  listeners.forEach((listener) => listener(reconnect));
689
689
  };
690
+ const emitTerminalFailure = (message) => {
691
+ listeners.forEach((listener) => listener({
692
+ message,
693
+ recoverable: false,
694
+ type: "error"
695
+ }));
696
+ emitConnection({
697
+ reconnect: {
698
+ attempts: state.reconnectAttempts,
699
+ maxAttempts: maxReconnectAttempts,
700
+ status: "exhausted"
701
+ },
702
+ type: "connection"
703
+ });
704
+ };
690
705
  const clearTimers = () => {
691
706
  if (state.pingInterval) {
692
707
  clearInterval(state.pingInterval);
@@ -735,14 +750,7 @@ var createVoiceConnection = (path, options = {}) => {
735
750
  });
736
751
  state.reconnectTimeout = setTimeout(async () => {
737
752
  if (state.reconnectAttempts > maxReconnectAttempts) {
738
- emitConnection({
739
- reconnect: {
740
- attempts: state.reconnectAttempts,
741
- maxAttempts: maxReconnectAttempts,
742
- status: "exhausted"
743
- },
744
- type: "connection"
745
- });
753
+ emitTerminalFailure("Voice connection could not be restored.");
746
754
  return;
747
755
  }
748
756
  try {
@@ -756,14 +764,7 @@ var createVoiceConnection = (path, options = {}) => {
756
764
  if (state.reconnectAttempts < maxReconnectAttempts) {
757
765
  scheduleReconnect();
758
766
  } else {
759
- emitConnection({
760
- reconnect: {
761
- attempts: state.reconnectAttempts,
762
- maxAttempts: maxReconnectAttempts,
763
- status: "exhausted"
764
- },
765
- type: "connection"
766
- });
767
+ emitTerminalFailure("Voice authorization could not be renewed for reconnect.");
767
768
  }
768
769
  return;
769
770
  }
@@ -853,15 +854,19 @@ var createVoiceConnection = (path, options = {}) => {
853
854
  if (reconnectable) {
854
855
  scheduleReconnect();
855
856
  } else if (shouldReconnect && event.code !== WS_NORMAL_CLOSURE) {
856
- emitConnection({
857
- reconnect: {
858
- attempts: state.reconnectAttempts,
859
- lastDisconnectAt: Date.now(),
860
- maxAttempts: maxReconnectAttempts,
861
- status: "exhausted"
862
- },
863
- type: "connection"
864
- });
857
+ if (authorizationFailure) {
858
+ emitConnection({
859
+ reconnect: {
860
+ attempts: state.reconnectAttempts,
861
+ lastDisconnectAt: Date.now(),
862
+ maxAttempts: maxReconnectAttempts,
863
+ status: "exhausted"
864
+ },
865
+ type: "connection"
866
+ });
867
+ } else {
868
+ emitTerminalFailure("Voice connection could not be restored.");
869
+ }
865
870
  }
866
871
  };
867
872
  state.ws = ws;
@@ -604,6 +604,21 @@ var createVoiceConnection = (path, options = {}) => {
604
604
  const emitConnection = (reconnect) => {
605
605
  listeners.forEach((listener) => listener(reconnect));
606
606
  };
607
+ const emitTerminalFailure = (message) => {
608
+ listeners.forEach((listener) => listener({
609
+ message,
610
+ recoverable: false,
611
+ type: "error"
612
+ }));
613
+ emitConnection({
614
+ reconnect: {
615
+ attempts: state.reconnectAttempts,
616
+ maxAttempts: maxReconnectAttempts,
617
+ status: "exhausted"
618
+ },
619
+ type: "connection"
620
+ });
621
+ };
607
622
  const clearTimers = () => {
608
623
  if (state.pingInterval) {
609
624
  clearInterval(state.pingInterval);
@@ -652,14 +667,7 @@ var createVoiceConnection = (path, options = {}) => {
652
667
  });
653
668
  state.reconnectTimeout = setTimeout(async () => {
654
669
  if (state.reconnectAttempts > maxReconnectAttempts) {
655
- emitConnection({
656
- reconnect: {
657
- attempts: state.reconnectAttempts,
658
- maxAttempts: maxReconnectAttempts,
659
- status: "exhausted"
660
- },
661
- type: "connection"
662
- });
670
+ emitTerminalFailure("Voice connection could not be restored.");
663
671
  return;
664
672
  }
665
673
  try {
@@ -673,14 +681,7 @@ var createVoiceConnection = (path, options = {}) => {
673
681
  if (state.reconnectAttempts < maxReconnectAttempts) {
674
682
  scheduleReconnect();
675
683
  } else {
676
- emitConnection({
677
- reconnect: {
678
- attempts: state.reconnectAttempts,
679
- maxAttempts: maxReconnectAttempts,
680
- status: "exhausted"
681
- },
682
- type: "connection"
683
- });
684
+ emitTerminalFailure("Voice authorization could not be renewed for reconnect.");
684
685
  }
685
686
  return;
686
687
  }
@@ -770,15 +771,19 @@ var createVoiceConnection = (path, options = {}) => {
770
771
  if (reconnectable) {
771
772
  scheduleReconnect();
772
773
  } else if (shouldReconnect && event.code !== WS_NORMAL_CLOSURE) {
773
- emitConnection({
774
- reconnect: {
775
- attempts: state.reconnectAttempts,
776
- lastDisconnectAt: Date.now(),
777
- maxAttempts: maxReconnectAttempts,
778
- status: "exhausted"
779
- },
780
- type: "connection"
781
- });
774
+ if (authorizationFailure) {
775
+ emitConnection({
776
+ reconnect: {
777
+ attempts: state.reconnectAttempts,
778
+ lastDisconnectAt: Date.now(),
779
+ maxAttempts: maxReconnectAttempts,
780
+ status: "exhausted"
781
+ },
782
+ type: "connection"
783
+ });
784
+ } else {
785
+ emitTerminalFailure("Voice connection could not be restored.");
786
+ }
782
787
  }
783
788
  };
784
789
  state.ws = ws;
@@ -209,6 +209,21 @@ var createVoiceConnection = (path, options = {}) => {
209
209
  const emitConnection = (reconnect) => {
210
210
  listeners.forEach((listener) => listener(reconnect));
211
211
  };
212
+ const emitTerminalFailure = (message) => {
213
+ listeners.forEach((listener) => listener({
214
+ message,
215
+ recoverable: false,
216
+ type: "error"
217
+ }));
218
+ emitConnection({
219
+ reconnect: {
220
+ attempts: state.reconnectAttempts,
221
+ maxAttempts: maxReconnectAttempts,
222
+ status: "exhausted"
223
+ },
224
+ type: "connection"
225
+ });
226
+ };
212
227
  const clearTimers = () => {
213
228
  if (state.pingInterval) {
214
229
  clearInterval(state.pingInterval);
@@ -257,14 +272,7 @@ var createVoiceConnection = (path, options = {}) => {
257
272
  });
258
273
  state.reconnectTimeout = setTimeout(async () => {
259
274
  if (state.reconnectAttempts > maxReconnectAttempts) {
260
- emitConnection({
261
- reconnect: {
262
- attempts: state.reconnectAttempts,
263
- maxAttempts: maxReconnectAttempts,
264
- status: "exhausted"
265
- },
266
- type: "connection"
267
- });
275
+ emitTerminalFailure("Voice connection could not be restored.");
268
276
  return;
269
277
  }
270
278
  try {
@@ -278,14 +286,7 @@ var createVoiceConnection = (path, options = {}) => {
278
286
  if (state.reconnectAttempts < maxReconnectAttempts) {
279
287
  scheduleReconnect();
280
288
  } else {
281
- emitConnection({
282
- reconnect: {
283
- attempts: state.reconnectAttempts,
284
- maxAttempts: maxReconnectAttempts,
285
- status: "exhausted"
286
- },
287
- type: "connection"
288
- });
289
+ emitTerminalFailure("Voice authorization could not be renewed for reconnect.");
289
290
  }
290
291
  return;
291
292
  }
@@ -375,15 +376,19 @@ var createVoiceConnection = (path, options = {}) => {
375
376
  if (reconnectable) {
376
377
  scheduleReconnect();
377
378
  } else if (shouldReconnect && event.code !== WS_NORMAL_CLOSURE) {
378
- emitConnection({
379
- reconnect: {
380
- attempts: state.reconnectAttempts,
381
- lastDisconnectAt: Date.now(),
382
- maxAttempts: maxReconnectAttempts,
383
- status: "exhausted"
384
- },
385
- type: "connection"
386
- });
379
+ if (authorizationFailure) {
380
+ emitConnection({
381
+ reconnect: {
382
+ attempts: state.reconnectAttempts,
383
+ lastDisconnectAt: Date.now(),
384
+ maxAttempts: maxReconnectAttempts,
385
+ status: "exhausted"
386
+ },
387
+ type: "connection"
388
+ });
389
+ } else {
390
+ emitTerminalFailure("Voice connection could not be restored.");
391
+ }
387
392
  }
388
393
  };
389
394
  state.ws = ws;
@@ -601,6 +601,21 @@ var createVoiceConnection = (path, options = {}) => {
601
601
  const emitConnection = (reconnect) => {
602
602
  listeners.forEach((listener) => listener(reconnect));
603
603
  };
604
+ const emitTerminalFailure = (message) => {
605
+ listeners.forEach((listener) => listener({
606
+ message,
607
+ recoverable: false,
608
+ type: "error"
609
+ }));
610
+ emitConnection({
611
+ reconnect: {
612
+ attempts: state.reconnectAttempts,
613
+ maxAttempts: maxReconnectAttempts,
614
+ status: "exhausted"
615
+ },
616
+ type: "connection"
617
+ });
618
+ };
604
619
  const clearTimers = () => {
605
620
  if (state.pingInterval) {
606
621
  clearInterval(state.pingInterval);
@@ -649,14 +664,7 @@ var createVoiceConnection = (path, options = {}) => {
649
664
  });
650
665
  state.reconnectTimeout = setTimeout(async () => {
651
666
  if (state.reconnectAttempts > maxReconnectAttempts) {
652
- emitConnection({
653
- reconnect: {
654
- attempts: state.reconnectAttempts,
655
- maxAttempts: maxReconnectAttempts,
656
- status: "exhausted"
657
- },
658
- type: "connection"
659
- });
667
+ emitTerminalFailure("Voice connection could not be restored.");
660
668
  return;
661
669
  }
662
670
  try {
@@ -670,14 +678,7 @@ var createVoiceConnection = (path, options = {}) => {
670
678
  if (state.reconnectAttempts < maxReconnectAttempts) {
671
679
  scheduleReconnect();
672
680
  } else {
673
- emitConnection({
674
- reconnect: {
675
- attempts: state.reconnectAttempts,
676
- maxAttempts: maxReconnectAttempts,
677
- status: "exhausted"
678
- },
679
- type: "connection"
680
- });
681
+ emitTerminalFailure("Voice authorization could not be renewed for reconnect.");
681
682
  }
682
683
  return;
683
684
  }
@@ -767,15 +768,19 @@ var createVoiceConnection = (path, options = {}) => {
767
768
  if (reconnectable) {
768
769
  scheduleReconnect();
769
770
  } else if (shouldReconnect && event.code !== WS_NORMAL_CLOSURE) {
770
- emitConnection({
771
- reconnect: {
772
- attempts: state.reconnectAttempts,
773
- lastDisconnectAt: Date.now(),
774
- maxAttempts: maxReconnectAttempts,
775
- status: "exhausted"
776
- },
777
- type: "connection"
778
- });
771
+ if (authorizationFailure) {
772
+ emitConnection({
773
+ reconnect: {
774
+ attempts: state.reconnectAttempts,
775
+ lastDisconnectAt: Date.now(),
776
+ maxAttempts: maxReconnectAttempts,
777
+ status: "exhausted"
778
+ },
779
+ type: "connection"
780
+ });
781
+ } else {
782
+ emitTerminalFailure("Voice connection could not be restored.");
783
+ }
779
784
  }
780
785
  };
781
786
  state.ws = ws;
@@ -1,10 +1,10 @@
1
- (()=>{var{defineProperty:x,getOwnPropertyNames:U0,getOwnPropertyDescriptor:L0}=Object,G0=Object.prototype.hasOwnProperty;function W0(g){return this[g]}var D0=(g)=>{var A=(f??=new WeakMap).get(g),C;if(A)return A;if(A=x({},"__esModule",{value:!0}),g&&typeof g==="object"||typeof g==="function"){for(var V of U0(g))if(!G0.call(A,V))x(A,V,{get:W0.bind(g,V),enumerable:!(C=L0(g,V))||C.enumerable})}return f.set(g,A),A},f;var S0=(g)=>g;function y0(g,A){this[g]=S0.bind(null,A)}var X0=(g,A)=>{for(var C in A)x(g,C,{get:A[C],enumerable:!0,configurable:!0,set:y0.bind(A,C)})};var t0={};X0(t0,{mount:()=>T0,default:()=>e0,VOICE_EMBED_VERSION:()=>_0});var O0=(g)=>{if(typeof g!=="string")return g;return document.querySelector(g)},h0=(g,A,C,V)=>{let c=A??g.getAttribute("hx-get")??"";if(!c)return"";let T=new URL(c,window.location.origin);if(V)T.searchParams.set(C,V);else T.searchParams.delete(C);return`${T.pathname}${T.search}${T.hash}`},d=(g,A)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let C=O0(A.element);if(!C)return()=>{};let V=A.eventName??"voice-refresh",c=A.sessionQueryParam??"sessionId",T=()=>{let I=window,G=h0(C,A.route,c,g.sessionId);if(G)C.setAttribute("hx-get",G);I.htmx?.process?.(C),I.htmx?.trigger?.(C,V)},U=g.subscribe(T);return T(),()=>{U()}};var J0=(g)=>Math.max(-1,Math.min(1,g)),Y0=(g)=>{let A=new Int16Array(g.length);for(let C=0;C<g.length;C+=1){let V=J0(g[C]??0);A[C]=V<0?V*32768:V*32767}return new Uint8Array(A.buffer)},Z0=(g)=>{let A=g instanceof Uint8Array?g:new Uint8Array(g);if(A.byteLength<2)return 0;let C=new Int16Array(A.buffer,A.byteOffset,Math.floor(A.byteLength/2));if(C.length===0)return 0;let V=0;for(let c of C){let T=c/32768;V+=T*T}return Math.min(1,Math.max(0,Math.sqrt(V/C.length)*5.5))},w0=(g,A,C)=>{if(A===C)return g;let V=A/C,c=Math.round(g.length/V),T=new Float32Array(c),U=0,I=0;while(U<T.length){let G=Math.round((U+1)*V),W=0,_=0;for(let L=I;L<G&&L<g.length;L+=1)W+=g[L]??0,_+=1;T[U]=_>0?W/_:0,U+=1,I=G}return T},l=(g)=>{let A=null,C=null,V=null,c=null,T=async()=>{if(!g.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let I=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!I)throw Error("Browser microphone capture requires AudioContext support.");try{if(c=g.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:g.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),A=new I,A.state==="suspended")await A.resume();C=A.createMediaStreamSource(c),V=A.createScriptProcessor(4096,1,1),V.onaudioprocess=(G)=>{let W=G.inputBuffer.getChannelData(0),_=w0(W,A?.sampleRate??48000,g.sampleRateHz??16000),L=Y0(_);g.onLevel?.(Z0(L)),g.onAudio(L)},C.connect(V),V.connect(A.destination)}catch(G){throw U(),G}},U=()=>{V?.disconnect(),C?.disconnect(),c?.getTracks().forEach((I)=>I.stop()),A?.close(),g.onLevel?.(0),A=null,c=null,V=null,C=null};return{start:T,stop:U}};var k=(g)=>{if(typeof g==="string"&&g.trim())return g;if(g instanceof Error&&g.message.trim())return g.message;if(g&&typeof g==="object"){let A=g;for(let C of["message","reason","description"]){let V=A[C];if(typeof V==="string"&&V.trim())return V}if("error"in A)return k(A.error);if("cause"in A)return k(A.cause);try{return JSON.stringify(g)}catch{}}return"Unexpected error"},v=(g)=>{switch(g.type){case"audio":return{chunk:Uint8Array.from(atob(g.chunkBase64),(A)=>A.charCodeAt(0)),format:g.format,receivedAt:g.receivedAt,turnId:g.turnId,type:"audio"};case"assistant":return{text:g.text,turnId:g.turnId,type:"assistant"};case"assistant_delta":return{delta:g.delta,turnId:g.turnId,type:"assistant_delta"};case"complete":return{sessionId:g.sessionId,type:"complete"};case"connection":return{reconnect:g.reconnect,type:"connection"};case"call_lifecycle":return{event:g.event,sessionId:g.sessionId,type:"call_lifecycle"};case"error":return{message:k(g.message),recoverable:g.recoverable,type:"error"};case"call_control_ack":return null;case"final":return{transcript:g.transcript,type:"final"};case"partial":return{transcript:g.transcript,type:"partial"};case"replay":return{assistantTexts:g.assistantTexts,call:g.call,partial:g.partial,scenarioId:g.scenarioId,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,status:g.status,turns:g.turns,type:"replay"};case"session":return{sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,type:"session"};case"turn":return{turn:g.turn,type:"turn"};default:return null}};var Tg=Math.PI*2;var P=(g,A,C,V)=>{g.push({code:C,message:V,severity:A})};var Q0=(g)=>g.length===0?void 0:g.reduce((A,C)=>A+C,0)/g.length,M=(g)=>g.length===0?void 0:Math.max(...g);var X=(g,A)=>{let C=g[A];return typeof C==="number"&&Number.isFinite(C)?C:void 0},B=(g,A)=>{let C=g[A];return typeof C==="boolean"?C:void 0},J=(g,A)=>{let C=g[A];return typeof C==="string"?C:void 0},F=(g)=>String(g.id??J(g,"ssrc")??X(g,"ssrc")??J(g,"trackIdentifier")??J(g,"mid")??"unknown"),i=(g)=>g===void 0?void 0:g*1000;var P0=(g)=>{let A={};for(let[C,V]of Object.entries(g))if(V===null||typeof V==="boolean"||typeof V==="number"||typeof V==="string")A[C]=V;return A};var n=(g={})=>{let A=g.stats??[],C=[],V=A.filter((R)=>R.type==="inbound-rtp"&&J(R,"kind")!=="video"),c=A.filter((R)=>R.type==="outbound-rtp"&&J(R,"kind")!=="video"),T=A.filter((R)=>R.type==="candidate-pair"),U=A.filter((R)=>(R.type==="track"||R.type==="media-source")&&J(R,"kind")==="audio"),I=T.filter((R)=>B(R,"selected")===!0||B(R,"nominated")===!0||J(R,"state")==="succeeded").length,G=U.filter((R)=>J(R,"readyState")!=="ended"&&J(R,"trackState")!=="ended"&&B(R,"ended")!==!0).length,W=U.filter((R)=>J(R,"readyState")==="ended"||J(R,"trackState")==="ended"||B(R,"ended")===!0).length,_=V.reduce((R,O)=>R+(X(O,"packetsReceived")??0),0),L=c.reduce((R,O)=>R+(X(O,"packetsSent")??0),0),$=[...V,...c].reduce((R,O)=>R+Math.max(0,X(O,"packetsLost")??0),0),E=_+$,w=E===0?0:$/E,D=V.reduce((R,O)=>R+(X(O,"bytesReceived")??0),0),Y=c.reduce((R,O)=>R+(X(O,"bytesSent")??0),0),Z=M(T.map((R)=>i(X(R,"currentRoundTripTime")??X(R,"roundTripTime"))).filter((R)=>R!==void 0)),h=M([...V,...c].map((R)=>i(X(R,"jitter"))).filter((R)=>R!==void 0)),z=M(V.map((R)=>{let O=X(R,"jitterBufferDelay"),b=X(R,"jitterBufferEmittedCount");return O!==void 0&&b!==void 0&&b>0?O/b*1000:void 0}).filter((R)=>R!==void 0)),q=U.map((R)=>X(R,"audioLevel")).filter((R)=>R!==void 0);if(g.requireConnectedCandidatePair&&T.length>0&&I===0)P(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(g.requireLiveAudioTrack&&G===0)P(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(g.maxPacketLossRatio!==void 0&&w>g.maxPacketLossRatio)P(C,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(w)} above ${String(g.maxPacketLossRatio)}.`);if(g.maxRoundTripTimeMs!==void 0&&Z!==void 0&&Z>g.maxRoundTripTimeMs)P(C,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(Z)}ms above ${String(g.maxRoundTripTimeMs)}ms.`);if(g.maxJitterMs!==void 0&&h!==void 0&&h>g.maxJitterMs)P(C,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(h)}ms above ${String(g.maxJitterMs)}ms.`);return{activeCandidatePairs:I,audioLevelAverage:Q0(q),bytesReceived:D,bytesSent:Y,checkedAt:Date.now(),endedAudioTracks:W,inboundPackets:_,issues:C,jitterBufferDelayMs:z,jitterMs:h,liveAudioTracks:G,outboundPackets:L,packetLossRatio:w,packetsLost:$,roundTripTimeMs:Z,status:C.some((R)=>R.severity==="error")?"fail":C.length>0?"warn":"pass",totalStats:A.length}},o=async(g)=>{return[...(await g.peerConnection.getStats(g.selector??null)).values()].map(P0)};var m=(g={})=>{let A=g.stats??[],C=g.previousStats??[],V=[],c=new Map(C.map(($)=>[F($),$])),U=A.filter(($)=>($.type==="inbound-rtp"||$.type==="outbound-rtp")&&J($,"kind")!=="video"&&J($,"mediaType")!=="video").map(($)=>{let E=$.type==="outbound-rtp"?"outbound":"inbound",w=E==="outbound"?"packetsSent":"packetsReceived",D=E==="outbound"?"bytesSent":"bytesReceived",Y=c.get(F($)),Z=X($,w),h=Y?X(Y,w):void 0,z=X($,D),q=Y?X(Y,D):void 0,R=$.timestamp!==void 0&&Y?.timestamp!==void 0?$.timestamp-Y.timestamp:void 0;return{bytesDelta:z!==void 0&&q!==void 0?z-q:void 0,currentPackets:Z,direction:E,id:F($),packetDelta:Z!==void 0&&h!==void 0?Z-h:void 0,previousPackets:h,timeDeltaMs:R}}),I=U.filter(($)=>$.direction==="inbound"),G=U.filter(($)=>$.direction==="outbound"),W=M(U.map(($)=>$.timeDeltaMs).filter(($)=>$!==void 0)),_=I.filter(($)=>g.maxInboundPacketStallMs!==void 0&&$.timeDeltaMs!==void 0&&$.timeDeltaMs>=g.maxInboundPacketStallMs&&$.packetDelta!==void 0&&$.packetDelta<=0).length,L=G.filter(($)=>g.maxOutboundPacketStallMs!==void 0&&$.timeDeltaMs!==void 0&&$.timeDeltaMs>=g.maxOutboundPacketStallMs&&$.packetDelta!==void 0&&$.packetDelta<=0).length;if(g.requireInboundAudio&&I.length===0)P(V,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(g.requireOutboundAudio&&G.length===0)P(V,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(g.maxGapMs!==void 0&&W!==void 0&&W>g.maxGapMs)P(V,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(W)}ms above ${String(g.maxGapMs)}ms.`);if(_>0)P(V,"error","media.webrtc_inbound_stalled",`${String(_)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(L>0)P(V,"error","media.webrtc_outbound_stalled",`${String(L)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:I.length,issues:V,maxObservedGapMs:W,outboundAudioStreams:G.length,stalledInboundStreams:_,stalledOutboundStreams:L,status:V.some(($)=>$.severity==="error")?"fail":V.length>0?"warn":"pass",streams:U,totalStats:A.length}};var K0="/api/voice/browser-media",E0=5000,N0=async(g)=>g.peerConnection??await g.getPeerConnection?.()??null,z0=async(g,A)=>{let C=A.fetch??globalThis.fetch;if(!C)return;await C(A.path??K0,{body:JSON.stringify(g),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},r=(g)=>{let A=null,C=[],V=async()=>{let U=await N0(g);if(!U)return;let I=await o({peerConnection:U}),G=n({...g,stats:I}),W=g.continuity===!1?void 0:m({...g.continuity,previousStats:C,stats:I}),_={at:Date.now(),continuity:W,report:G,scenarioId:g.getScenarioId?.()??null,sessionId:g.getSessionId?.()??null};return C=I,g.onReport?.(_),await z0(_,g),_},c=()=>{V().catch((U)=>{g.onError?.(U)})},T=()=>{if(A)clearInterval(A),A=null};return{close:T,reportOnce:V,stop:T,start:()=>{if(A)return;c(),A=setInterval(c,g.intervalMs??E0)}}};var q0=(g,A,C)=>Math.min(C,A*2**(Math.max(1,g)-1));var N=()=>{},b0=()=>Promise.resolve(),B0=()=>N,M0={callControl:b0,close:N,disconnect:N,endTurn:N,send:N,sendAudio:N,simulateDisconnect:N,subscribe:B0,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},j0=()=>crypto.randomUUID(),x0=(g,A,C,V)=>{let{hostname:c,port:T,protocol:U}=window.location,I=U==="https:"?"wss:":"ws:",G=T?`:${T}`:"",W=new URL(`${I}//${c}${G}${g}`);if(W.searchParams.set("sessionId",A),C)W.searchParams.set("scenarioId",C);for(let[_,L]of Object.entries(V))if(_!=="sessionId"&&_!=="scenarioId"&&L)W.searchParams.set(_,L);return W.toString()},k0=(g)=>{if(!g||typeof g!=="object"||!("type"in g))return!1;switch(g.type){case"audio":case"assistant":case"call_lifecycle":case"call_control_ack":case"complete":case"connection":case"error":case"final":case"partial":case"pong":case"replay":case"session":case"turn":return!0;default:return!1}},F0=(g)=>{if(typeof g.data!=="string")return null;try{let A=JSON.parse(g.data);return k0(A)?A:null}catch{return null}},u=(g,A={})=>{if(typeof window>"u")return M0;let C=new Set,V=new Map,c=A.reconnect!==!1,T=A.maxReconnectAttempts??15,U=A.reconnectMaxDelayMs??8000,I=A.pingInterval??30000,G=A.reconnectResetAfterMs??30000,W=(H)=>q0(H,500,U),_={isConnected:!1,pendingMessages:[],scenarioId:A.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectResetTimeout:null,reconnectTimeout:null,sessionId:A.sessionId??j0(),ws:null},L=(H)=>{C.forEach((S)=>S(H))},$=()=>{if(_.pingInterval)clearInterval(_.pingInterval),_.pingInterval=null;if(_.reconnectTimeout)clearTimeout(_.reconnectTimeout),_.reconnectTimeout=null;if(_.reconnectResetTimeout)clearTimeout(_.reconnectResetTimeout),_.reconnectResetTimeout=null},E=()=>{if(_.ws?.readyState!==1)return;while(_.pendingMessages.length>0){let H=_.pendingMessages.shift();if(H!==void 0)_.ws.send(H)}},w=(H)=>{for(let S of V.values())clearTimeout(S.timeout),S.reject(Error(H));V.clear()},D=()=>{_.reconnectAttempts+=1;let H=W(_.reconnectAttempts),S=Date.now()+H;L({reconnect:{attempts:_.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:T,nextAttemptAt:S,status:"reconnecting"},type:"connection"}),_.reconnectTimeout=setTimeout(async()=>{if(_.reconnectAttempts>T){L({reconnect:{attempts:_.reconnectAttempts,maxAttempts:T,status:"exhausted"},type:"connection"});return}try{await A.prepareReconnect?.({attempt:_.reconnectAttempts,path:g,scenarioId:_.scenarioId,sessionId:_.sessionId})}catch{if(_.reconnectAttempts<T)D();else L({reconnect:{attempts:_.reconnectAttempts,maxAttempts:T,status:"exhausted"},type:"connection"});return}Y()},H)},Y=()=>{let H=new WebSocket(x0(g,_.sessionId,_.scenarioId,A.query??{}));H.binaryType="arraybuffer",H.onopen=()=>{if(_.ws!==H){H.close(1000);return}let S=_.reconnectAttempts>0;if(_.isConnected=!0,E(),S)L({reconnect:{attempts:_.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:T,status:"resumed"},type:"connection"}),_.reconnectResetTimeout=setTimeout(()=>{if(_.ws===H&&H.readyState===1)_.reconnectAttempts=0;_.reconnectResetTimeout=null},G);C.forEach((y)=>y({scenarioId:_.scenarioId??void 0,sessionId:_.sessionId,status:"active",type:"session"})),_.pingInterval=setInterval(()=>{if(H.readyState===1)H.send(JSON.stringify({type:"ping"}))},I)},H.onmessage=(S)=>{if(_.ws!==H)return;let y=F0(S);if(!y)return;if(y.type==="session")_.sessionId=y.sessionId,_.scenarioId=y.scenarioId??_.scenarioId;if(y.type==="call_control_ack"){let Q=V.get(y.requestId);if(Q)if(clearTimeout(Q.timeout),V.delete(y.requestId),y.ok)Q.resolve();else Q.reject(Error(y.message??`${y.action} was not applied`))}C.forEach((Q)=>Q(y))},H.onclose=(S)=>{if(_.ws!==H)return;_.ws=null,_.isConnected=!1,$();let y=c&&S.code!==1000&&S.code!==4401&&S.code!==4403&&_.reconnectAttempts<T;if(S.code===4401||S.code===4403)C.forEach((j)=>j({message:S.code===4401?"Voice authorization expired or was rejected.":"Voice authorization was forbidden.",recoverable:!1,type:"error"}));if(y)D();else if(c&&S.code!==1000)L({reconnect:{attempts:_.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:T,status:"exhausted"},type:"connection"})},_.ws=H},Z=(H)=>{if(_.ws?.readyState===1){_.ws.send(H);return}if(typeof H!=="string")return;if(_.pendingMessages.length>=100)_.pendingMessages.shift();_.pendingMessages.push(H)},h=(H)=>{Z(JSON.stringify(H))},z=(H={})=>{if(H.sessionId)_.sessionId=H.sessionId;if(H.scenarioId)_.scenarioId=H.scenarioId;h({scenarioId:_.scenarioId??void 0,sessionId:_.sessionId,type:"start"})},q=(H)=>{Z(H)},R=()=>{h({type:"end_turn"})},O=(H)=>{let S=crypto.randomUUID(),{promise:y,reject:Q,resolve:j}=Promise.withResolvers(),I0=setTimeout(()=>{V.delete(S),Q(Error(`${H.action} acknowledgement timed out`))},5000);return V.set(S,{reject:Q,resolve:j,timeout:I0}),h({...H,requestId:S,type:"call_control"}),y},b=(H="client-close")=>{if($(),w("Voice connection closed"),_.ws){let S=_.ws;if(_.ws=null,S.readyState===1)S.send(JSON.stringify({reason:H,type:"close"}));S.close(1000)}_.isConnected=!1,C.clear()},R0=()=>{if($(),w("Voice connection disconnected"),_.ws){let H=_.ws;_.ws=null,H.close(1000)}_.isConnected=!1,C.clear()},$0=()=>{if(_.ws?.readyState===1)_.ws.close(4000,"absolutejs-voice-reconnect-proof")},H0=(H)=>{return C.add(H),()=>{C.delete(H)}};return Y(),{callControl:O,close:b,disconnect:R0,endTurn:R,send:h,sendAudio:q,simulateDisconnect:$0,start:z,subscribe:H0,getReadyState:()=>_.ws?.readyState??3,getScenarioId:()=>_.scenarioId??"",getSessionId:()=>_.sessionId}};var f0=()=>({attempts:0,maxAttempts:0,status:"idle"}),d0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!C)return g;if(!g)return C;if(g===C||g.endsWith(C))return g;if(C.includes(g))return C;return`${g} ${C}`},l0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!g)return C;if(!C||g.endsWith(C))return g;return`${g} ${C}`},v0=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,partial:"",reconnect:f0(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),s=()=>{let g=v0(),A="",C=new Set,V=()=>{C.forEach((T)=>T())};return{dispatch:(T)=>{switch(T.type){case"audio":g={...g,assistantAudio:[...g.assistantAudio,{chunk:T.chunk,format:T.format,receivedAt:T.receivedAt,turnId:T.turnId}]};break;case"assistant":g={...g,assistantStreamingText:"",assistantTexts:[...g.assistantTexts,T.text]};break;case"assistant_delta":g={...g,assistantStreamingText:`${g.assistantStreamingText}${T.delta}`};break;case"complete":g={...g,sessionId:T.sessionId,status:"completed"};break;case"call_lifecycle":g={...g,call:{...g.call,disposition:T.event.type==="end"?T.event.disposition:g.call?.disposition,endedAt:T.event.type==="end"?T.event.at:g.call?.endedAt,events:[...g.call?.events??[],T.event],lastEventAt:T.event.at,startedAt:g.call?.startedAt??T.event.at},sessionId:T.sessionId};break;case"connected":g={...g,isConnected:!0,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect};break;case"connection":g={...g,reconnect:T.reconnect};break;case"disconnected":g={...g,isConnected:!1};break;case"error":g={...g,error:T.message,...T.recoverable===!1?{isConnected:!1,status:"failed"}:{}};break;case"final":A=d0(A,T.transcript.text),g={...g,partial:A};break;case"partial":g={...g,partial:l0(A,T.transcript.text)};break;case"replay":A=T.partial,g={...g,assistantStreamingText:"",assistantTexts:[...T.assistantTexts],call:T.call??null,error:null,isConnected:T.status==="active",partial:T.partial,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect,scenarioId:T.scenarioId??g.scenarioId,sessionId:T.sessionId,sessionMetadata:T.sessionMetadata??g.sessionMetadata,status:T.status,turns:[...T.turns]};break;case"session":g={...g,error:null,scenarioId:T.scenarioId??g.scenarioId,isConnected:T.status==="active",sessionId:T.sessionId,sessionMetadata:T.sessionMetadata??g.sessionMetadata,status:T.status};break;case"turn":A="",g={...g,partial:"",turns:[...g.turns,T.turn]};break}V()},getServerSnapshot:()=>g,getSnapshot:()=>g,subscribe:(T)=>{return C.add(T),()=>{C.delete(T)}}}};var a=(g,A={})=>{let C=u(g,A),V=s(),c=A.browserMedia&&typeof window<"u"?r({...A.browserMedia,getScenarioId:()=>A.browserMedia?A.browserMedia.getScenarioId?.()??C.getScenarioId():C.getScenarioId(),getSessionId:()=>A.browserMedia?A.browserMedia.getSessionId?.()??C.getSessionId():C.getSessionId()}):null,T=new Set,U=(_)=>Promise.resolve().then(()=>{if(!_?.sessionId&&!_?.scenarioId)return;C.start(_),c?.start()}),I=()=>{T.forEach((_)=>_())},G=()=>{if(!A.reconnectReportPath||typeof fetch>"u")return;let _=V.getSnapshot(),L=JSON.stringify({at:Date.now(),reconnect:_.reconnect,scenarioId:_.scenarioId,sessionId:C.getSessionId(),turnIds:_.turns.map(($)=>$.id)});fetch(A.reconnectReportPath,{body:L,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},W=C.subscribe((_)=>{let L=v(_);if(L){if(V.dispatch(L),_.type==="connection")G();I()}});return{start:U,get assistantAudio(){return V.getSnapshot().assistantAudio},get assistantTexts(){return V.getSnapshot().assistantTexts},get assistantStreamingText(){return V.getSnapshot().assistantStreamingText},get call(){return V.getSnapshot().call},callControl(_){return C.callControl(_)},close(_){W(),c?.close(),C.close(_),V.dispatch({type:"disconnected"}),I()},disconnect(){W(),c?.close(),C.disconnect(),V.dispatch({type:"disconnected"}),I()},endTurn(){C.endTurn()},get error(){return V.getSnapshot().error},getServerSnapshot(){return V.getServerSnapshot()},getSnapshot(){return V.getSnapshot()},get isConnected(){return V.getSnapshot().isConnected},get partial(){return V.getSnapshot().partial},get reconnect(){return V.getSnapshot().reconnect},get scenarioId(){return V.getSnapshot().scenarioId},sendAudio(_){C.sendAudio(_)},get sessionId(){return C.getSessionId()},get sessionMetadata(){return V.getSnapshot().sessionMetadata},simulateDisconnect(){C.simulateDisconnect()},get status(){return V.getSnapshot().status},subscribe(_){return T.add(_),()=>{T.delete(_)}},get turns(){return V.getSnapshot().turns}}};var p=(g)=>{if(!g||g.enabled===!1)return;return{enabled:!0,maxGain:g.maxGain??3,noiseGateAttenuation:g.noiseGateAttenuation??0.15,noiseGateThreshold:g.noiseGateThreshold??0.006,targetLevel:g.targetLevel??0.08}};var i0={balanced:{qualityProfile:"general",minSilenceMs:400,silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",minSilenceMs:300,silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",minSilenceMs:600,silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},n0={"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},general:{},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}};var t=(g)=>{let A=g?.profile??"fast",C=g?.qualityProfile??"general",V=i0[A],c=n0[C],T=g?.silenceMs??c.silenceMs??V.silenceMs;return{profile:A,qualityProfile:C,minSilenceMs:Math.min(T,g?.minSilenceMs??c.minSilenceMs??V.minSilenceMs),silenceMs:T,speechThreshold:g?.speechThreshold??c.speechThreshold??V.speechThreshold,transcriptStabilityMs:g?.transcriptStabilityMs??c.transcriptStabilityMs??V.transcriptStabilityMs}};var o0={chat:{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"balanced",qualityProfile:"short-command"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"fast",qualityProfile:"general"}},dictation:{audioConditioning:{enabled:!0,maxGain:2.25,noiseGateAttenuation:0.05,noiseGateThreshold:0.003,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"guided-intake":{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"turn-scoped",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"noisy-room":{audioConditioning:{enabled:!0,maxGain:3,noiseGateAttenuation:0.12,noiseGateThreshold:0.006,targetLevel:0.085},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:2100,speechThreshold:0.02,transcriptStabilityMs:1650}},"pstn-balanced":{audioConditioning:{enabled:!0,maxGain:2.8,noiseGateAttenuation:0.07,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:660,speechThreshold:0.012,transcriptStabilityMs:300}},"pstn-fast":{audioConditioning:{enabled:!0,maxGain:2.75,noiseGateAttenuation:0.06,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:620,speechThreshold:0.012,transcriptStabilityMs:280}},reliability:{audioConditioning:{enabled:!0,maxGain:2.9,noiseGateAttenuation:0.08,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room"}}},e=(g="default")=>{let A=o0[g];return{audioConditioning:p(A.audioConditioning),capture:{channelCount:A.capture?.channelCount??1,sampleRateHz:A.capture?.sampleRateHz??16000},connection:{...A.connection},name:g,sttLifecycle:A.sttLifecycle??"continuous",turnDetection:t(A.turnDetection)}};var m0=(g)=>({assistantAudio:[...g.assistantAudio],assistantStreamingText:g.assistantStreamingText,assistantTexts:[...g.assistantTexts],call:g.call,error:g.error,isConnected:g.isConnected,isRecording:!1,partial:g.partial,reconnect:g.reconnect,recordingError:null,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,turns:[...g.turns]}),g0=(g,A={})=>{let C=e(A.preset),V=a(g,{...C.connection,...A.connection}),c=null,T=m0(V),U=new Set,I=()=>{for(let D of U)D()},G=()=>{if(T={...T,assistantAudio:[...V.assistantAudio],assistantStreamingText:V.assistantStreamingText,assistantTexts:[...V.assistantTexts],call:V.call,error:V.error,isConnected:V.isConnected,partial:V.partial,reconnect:V.reconnect,sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,scenarioId:V.scenarioId,status:V.status,turns:[...V.turns]},A.autoStopOnComplete!==!1&&T.status==="completed"&&T.isRecording)c?.stop(),c=null,T={...T,isRecording:!1};I()},W=V.subscribe(G);G();let _=()=>{if(c)return c;return c=l({channelCount:A.capture?.channelCount??C.capture.channelCount,onLevel:A.capture?.onLevel,onAudio:(D)=>{if(A.capture?.onAudio){A.capture.onAudio(D,V.sendAudio);return}V.sendAudio(D)},sampleRateHz:A.capture?.sampleRateHz??C.capture.sampleRateHz,...A.capture?.stream?{stream:A.capture.stream}:{}}),c},L=()=>{c?.stop(),c=null,T={...T,isRecording:!1},I()},$=async()=>{if(T.isRecording)return;try{T={...T,recordingError:null},I(),await _().start(),T={...T,isRecording:!0},I()}catch(D){throw c?.stop(),c=null,T={...T,isRecording:!1,recordingError:D instanceof Error?D.message:String(D)},I(),D}};return{close:(D)=>{W(),L(),V.close(D)},disconnect:()=>{W(),L(),V.disconnect()},startRecording:$,stopRecording:L,get assistantAudio(){return T.assistantAudio},get assistantTexts(){return T.assistantTexts},get assistantStreamingText(){return T.assistantStreamingText},bindHTMX(D){return d(V,D)},get call(){return T.call},callControl:(D)=>V.callControl(D),endTurn:()=>V.endTurn(),get error(){return T.error},getServerSnapshot:()=>T,getSnapshot:()=>T,get isConnected(){return T.isConnected},get isRecording(){return T.isRecording},get partial(){return T.partial},get reconnect(){return T.reconnect},get recordingError(){return T.recordingError},get scenarioId(){return T.scenarioId},sendAudio:(D)=>V.sendAudio(D),get sessionId(){return T.sessionId},get sessionMetadata(){return T.sessionMetadata},simulateDisconnect:()=>V.simulateDisconnect(),get status(){return T.status},subscribe:(D)=>{return U.add(D),()=>{U.delete(D)}},toggleRecording:async()=>{if(T.isRecording){L();return}await $()},get turns(){return T.turns}}};var K=(g)=>String(g).replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#39;");var A0=(g)=>{if(!g.isConnected)return"idle";if(g.isPlaying)return"speaking";if(g.isRecording&&g.hasActivePartial)return"listening";if(g.isRecording)return"listening";if(g.lastTranscriptAt&&!g.lastAssistantAt)return"thinking";if(g.lastTranscriptAt&&g.lastAssistantAt&&g.lastTranscriptAt>g.lastAssistantAt)return"thinking";return"idle"};var r0={accent:"#3b82f6",background:"#0f172a",errorAccent:"#ef4444",fontFamily:'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',foreground:"#f8fafc",radius:16},u0={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},s0=(g,A)=>{switch(g){case"listening":return A.listening;case"speaking":return A.speaking;case"thinking":return A.thinking;case"idle":return A.idle}},V0=(g)=>{let A={...r0,...g.theme},C={...u0,...g.labels},V=g.state.assistantAudio.at(-1)?.receivedAt,c=g.state.turns.at(-1)?.committedAt,T=A0({hasActivePartial:g.state.partial.length>0,isConnected:g.state.isConnected,isPlaying:!1,isRecording:g.state.isRecording,lastAssistantAt:V,lastTranscriptAt:c}),U=!g.state.isConnected&&g.state.status!=="idle"&&!g.state.error,I=g.state.error?"Error":U?C.connecting:g.state.status==="completed"?C.callEnded:s0(T,C);return{agentState:T,classes:{container:`absolute-voice-widget absolute-voice-widget--${T}`,dot:`absolute-voice-widget__dot${g.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:g.state.isConnected,canMute:g.state.isRecording,canStart:!g.state.isRecording&&g.state.status!=="completed"},errorMessage:g.state.error??void 0,labels:C,partial:g.state.partial||void 0,statusLabel:I,theme:A,title:g.title??"Voice"}},a0=(g)=>typeof g==="number"?`${g}px`:g,C0=(g)=>{let A=g.theme,C=`background:${A.background};border-radius:${a0(A.radius)};color:${A.foreground};font-family:${A.fontFamily};min-width:240px;padding:20px 22px;`,V=`background:${g.errorMessage?A.errorAccent:g.agentState==="idle"?"rgba(148,163,184,0.6)":A.accent};border-radius:50%;height:10px;width:10px;`,c=[];if(g.controls.canStart)c.push(`<button type="button" data-action="start" style="background:${A.accent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${K(g.labels.startCall)}</button>`);if(g.controls.canMute)c.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${K(g.labels.mute)}</button>`);if(g.controls.canEnd)c.push(`<button type="button" data-action="end" style="background:${A.errorAccent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${K(g.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${g.agentState}" class="${K(g.classes.container)}" style="${C}">
1
+ (()=>{var{defineProperty:x,getOwnPropertyNames:L0,getOwnPropertyDescriptor:G0}=Object,W0=Object.prototype.hasOwnProperty;function D0(g){return this[g]}var S0=(g)=>{var A=(f??=new WeakMap).get(g),C;if(A)return A;if(A=x({},"__esModule",{value:!0}),g&&typeof g==="object"||typeof g==="function"){for(var V of L0(g))if(!W0.call(A,V))x(A,V,{get:D0.bind(g,V),enumerable:!(C=G0(g,V))||C.enumerable})}return f.set(g,A),A},f;var y0=(g)=>g;function X0(g,A){this[g]=y0.bind(null,A)}var O0=(g,A)=>{for(var C in A)x(g,C,{get:A[C],enumerable:!0,configurable:!0,set:X0.bind(A,C)})};var e0={};O0(e0,{mount:()=>c0,default:()=>gg,VOICE_EMBED_VERSION:()=>_0});var J0=(g)=>{if(typeof g!=="string")return g;return document.querySelector(g)},Y0=(g,A,C,V)=>{let T=A??g.getAttribute("hx-get")??"";if(!T)return"";let c=new URL(T,window.location.origin);if(V)c.searchParams.set(C,V);else c.searchParams.delete(C);return`${c.pathname}${c.search}${c.hash}`},d=(g,A)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let C=J0(A.element);if(!C)return()=>{};let V=A.eventName??"voice-refresh",T=A.sessionQueryParam??"sessionId",c=()=>{let I=window,G=Y0(C,A.route,T,g.sessionId);if(G)C.setAttribute("hx-get",G);I.htmx?.process?.(C),I.htmx?.trigger?.(C,V)},U=g.subscribe(c);return c(),()=>{U()}};var Z0=(g)=>Math.max(-1,Math.min(1,g)),h0=(g)=>{let A=new Int16Array(g.length);for(let C=0;C<g.length;C+=1){let V=Z0(g[C]??0);A[C]=V<0?V*32768:V*32767}return new Uint8Array(A.buffer)},w0=(g)=>{let A=g instanceof Uint8Array?g:new Uint8Array(g);if(A.byteLength<2)return 0;let C=new Int16Array(A.buffer,A.byteOffset,Math.floor(A.byteLength/2));if(C.length===0)return 0;let V=0;for(let T of C){let c=T/32768;V+=c*c}return Math.min(1,Math.max(0,Math.sqrt(V/C.length)*5.5))},Q0=(g,A,C)=>{if(A===C)return g;let V=A/C,T=Math.round(g.length/V),c=new Float32Array(T),U=0,I=0;while(U<c.length){let G=Math.round((U+1)*V),W=0,_=0;for(let L=I;L<G&&L<g.length;L+=1)W+=g[L]??0,_+=1;c[U]=_>0?W/_:0,U+=1,I=G}return c},l=(g)=>{let A=null,C=null,V=null,T=null,c=async()=>{if(!g.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let I=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!I)throw Error("Browser microphone capture requires AudioContext support.");try{if(T=g.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:g.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),A=new I,A.state==="suspended")await A.resume();C=A.createMediaStreamSource(T),V=A.createScriptProcessor(4096,1,1),V.onaudioprocess=(G)=>{let W=G.inputBuffer.getChannelData(0),_=Q0(W,A?.sampleRate??48000,g.sampleRateHz??16000),L=h0(_);g.onLevel?.(w0(L)),g.onAudio(L)},C.connect(V),V.connect(A.destination)}catch(G){throw U(),G}},U=()=>{V?.disconnect(),C?.disconnect(),T?.getTracks().forEach((I)=>I.stop()),A?.close(),g.onLevel?.(0),A=null,T=null,V=null,C=null};return{start:c,stop:U}};var k=(g)=>{if(typeof g==="string"&&g.trim())return g;if(g instanceof Error&&g.message.trim())return g.message;if(g&&typeof g==="object"){let A=g;for(let C of["message","reason","description"]){let V=A[C];if(typeof V==="string"&&V.trim())return V}if("error"in A)return k(A.error);if("cause"in A)return k(A.cause);try{return JSON.stringify(g)}catch{}}return"Unexpected error"},v=(g)=>{switch(g.type){case"audio":return{chunk:Uint8Array.from(atob(g.chunkBase64),(A)=>A.charCodeAt(0)),format:g.format,receivedAt:g.receivedAt,turnId:g.turnId,type:"audio"};case"assistant":return{text:g.text,turnId:g.turnId,type:"assistant"};case"assistant_delta":return{delta:g.delta,turnId:g.turnId,type:"assistant_delta"};case"complete":return{sessionId:g.sessionId,type:"complete"};case"connection":return{reconnect:g.reconnect,type:"connection"};case"call_lifecycle":return{event:g.event,sessionId:g.sessionId,type:"call_lifecycle"};case"error":return{message:k(g.message),recoverable:g.recoverable,type:"error"};case"call_control_ack":return null;case"final":return{transcript:g.transcript,type:"final"};case"partial":return{transcript:g.transcript,type:"partial"};case"replay":return{assistantTexts:g.assistantTexts,call:g.call,partial:g.partial,scenarioId:g.scenarioId,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,status:g.status,turns:g.turns,type:"replay"};case"session":return{sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,type:"session"};case"turn":return{turn:g.turn,type:"turn"};default:return null}};var _g=Math.PI*2;var P=(g,A,C,V)=>{g.push({code:C,message:V,severity:A})};var P0=(g)=>g.length===0?void 0:g.reduce((A,C)=>A+C,0)/g.length,M=(g)=>g.length===0?void 0:Math.max(...g);var X=(g,A)=>{let C=g[A];return typeof C==="number"&&Number.isFinite(C)?C:void 0},B=(g,A)=>{let C=g[A];return typeof C==="boolean"?C:void 0},J=(g,A)=>{let C=g[A];return typeof C==="string"?C:void 0},F=(g)=>String(g.id??J(g,"ssrc")??X(g,"ssrc")??J(g,"trackIdentifier")??J(g,"mid")??"unknown"),i=(g)=>g===void 0?void 0:g*1000;var K0=(g)=>{let A={};for(let[C,V]of Object.entries(g))if(V===null||typeof V==="boolean"||typeof V==="number"||typeof V==="string")A[C]=V;return A};var n=(g={})=>{let A=g.stats??[],C=[],V=A.filter((R)=>R.type==="inbound-rtp"&&J(R,"kind")!=="video"),T=A.filter((R)=>R.type==="outbound-rtp"&&J(R,"kind")!=="video"),c=A.filter((R)=>R.type==="candidate-pair"),U=A.filter((R)=>(R.type==="track"||R.type==="media-source")&&J(R,"kind")==="audio"),I=c.filter((R)=>B(R,"selected")===!0||B(R,"nominated")===!0||J(R,"state")==="succeeded").length,G=U.filter((R)=>J(R,"readyState")!=="ended"&&J(R,"trackState")!=="ended"&&B(R,"ended")!==!0).length,W=U.filter((R)=>J(R,"readyState")==="ended"||J(R,"trackState")==="ended"||B(R,"ended")===!0).length,_=V.reduce((R,O)=>R+(X(O,"packetsReceived")??0),0),L=T.reduce((R,O)=>R+(X(O,"packetsSent")??0),0),H=[...V,...T].reduce((R,O)=>R+Math.max(0,X(O,"packetsLost")??0),0),Z=_+H,E=Z===0?0:H/Z,D=V.reduce((R,O)=>R+(X(O,"bytesReceived")??0),0),h=T.reduce((R,O)=>R+(X(O,"bytesSent")??0),0),w=M(c.map((R)=>i(X(R,"currentRoundTripTime")??X(R,"roundTripTime"))).filter((R)=>R!==void 0)),Q=M([...V,...T].map((R)=>i(X(R,"jitter"))).filter((R)=>R!==void 0)),N=M(V.map((R)=>{let O=X(R,"jitterBufferDelay"),b=X(R,"jitterBufferEmittedCount");return O!==void 0&&b!==void 0&&b>0?O/b*1000:void 0}).filter((R)=>R!==void 0)),z=U.map((R)=>X(R,"audioLevel")).filter((R)=>R!==void 0);if(g.requireConnectedCandidatePair&&c.length>0&&I===0)P(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(g.requireLiveAudioTrack&&G===0)P(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(g.maxPacketLossRatio!==void 0&&E>g.maxPacketLossRatio)P(C,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(E)} above ${String(g.maxPacketLossRatio)}.`);if(g.maxRoundTripTimeMs!==void 0&&w!==void 0&&w>g.maxRoundTripTimeMs)P(C,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(w)}ms above ${String(g.maxRoundTripTimeMs)}ms.`);if(g.maxJitterMs!==void 0&&Q!==void 0&&Q>g.maxJitterMs)P(C,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(Q)}ms above ${String(g.maxJitterMs)}ms.`);return{activeCandidatePairs:I,audioLevelAverage:P0(z),bytesReceived:D,bytesSent:h,checkedAt:Date.now(),endedAudioTracks:W,inboundPackets:_,issues:C,jitterBufferDelayMs:N,jitterMs:Q,liveAudioTracks:G,outboundPackets:L,packetLossRatio:E,packetsLost:H,roundTripTimeMs:w,status:C.some((R)=>R.severity==="error")?"fail":C.length>0?"warn":"pass",totalStats:A.length}},o=async(g)=>{return[...(await g.peerConnection.getStats(g.selector??null)).values()].map(K0)};var m=(g={})=>{let A=g.stats??[],C=g.previousStats??[],V=[],T=new Map(C.map((H)=>[F(H),H])),U=A.filter((H)=>(H.type==="inbound-rtp"||H.type==="outbound-rtp")&&J(H,"kind")!=="video"&&J(H,"mediaType")!=="video").map((H)=>{let Z=H.type==="outbound-rtp"?"outbound":"inbound",E=Z==="outbound"?"packetsSent":"packetsReceived",D=Z==="outbound"?"bytesSent":"bytesReceived",h=T.get(F(H)),w=X(H,E),Q=h?X(h,E):void 0,N=X(H,D),z=h?X(h,D):void 0,R=H.timestamp!==void 0&&h?.timestamp!==void 0?H.timestamp-h.timestamp:void 0;return{bytesDelta:N!==void 0&&z!==void 0?N-z:void 0,currentPackets:w,direction:Z,id:F(H),packetDelta:w!==void 0&&Q!==void 0?w-Q:void 0,previousPackets:Q,timeDeltaMs:R}}),I=U.filter((H)=>H.direction==="inbound"),G=U.filter((H)=>H.direction==="outbound"),W=M(U.map((H)=>H.timeDeltaMs).filter((H)=>H!==void 0)),_=I.filter((H)=>g.maxInboundPacketStallMs!==void 0&&H.timeDeltaMs!==void 0&&H.timeDeltaMs>=g.maxInboundPacketStallMs&&H.packetDelta!==void 0&&H.packetDelta<=0).length,L=G.filter((H)=>g.maxOutboundPacketStallMs!==void 0&&H.timeDeltaMs!==void 0&&H.timeDeltaMs>=g.maxOutboundPacketStallMs&&H.packetDelta!==void 0&&H.packetDelta<=0).length;if(g.requireInboundAudio&&I.length===0)P(V,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(g.requireOutboundAudio&&G.length===0)P(V,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(g.maxGapMs!==void 0&&W!==void 0&&W>g.maxGapMs)P(V,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(W)}ms above ${String(g.maxGapMs)}ms.`);if(_>0)P(V,"error","media.webrtc_inbound_stalled",`${String(_)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(L>0)P(V,"error","media.webrtc_outbound_stalled",`${String(L)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:I.length,issues:V,maxObservedGapMs:W,outboundAudioStreams:G.length,stalledInboundStreams:_,stalledOutboundStreams:L,status:V.some((H)=>H.severity==="error")?"fail":V.length>0?"warn":"pass",streams:U,totalStats:A.length}};var E0="/api/voice/browser-media",N0=5000,q0=async(g)=>g.peerConnection??await g.getPeerConnection?.()??null,z0=async(g,A)=>{let C=A.fetch??globalThis.fetch;if(!C)return;await C(A.path??E0,{body:JSON.stringify(g),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},r=(g)=>{let A=null,C=[],V=async()=>{let U=await q0(g);if(!U)return;let I=await o({peerConnection:U}),G=n({...g,stats:I}),W=g.continuity===!1?void 0:m({...g.continuity,previousStats:C,stats:I}),_={at:Date.now(),continuity:W,report:G,scenarioId:g.getScenarioId?.()??null,sessionId:g.getSessionId?.()??null};return C=I,g.onReport?.(_),await z0(_,g),_},T=()=>{V().catch((U)=>{g.onError?.(U)})},c=()=>{if(A)clearInterval(A),A=null};return{close:c,reportOnce:V,stop:c,start:()=>{if(A)return;T(),A=setInterval(T,g.intervalMs??N0)}}};var b0=(g,A,C)=>Math.min(C,A*2**(Math.max(1,g)-1));var q=()=>{},B0=()=>Promise.resolve(),M0=()=>q,j0={callControl:B0,close:q,disconnect:q,endTurn:q,send:q,sendAudio:q,simulateDisconnect:q,subscribe:M0,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},x0=()=>crypto.randomUUID(),k0=(g,A,C,V)=>{let{hostname:T,port:c,protocol:U}=window.location,I=U==="https:"?"wss:":"ws:",G=c?`:${c}`:"",W=new URL(`${I}//${T}${G}${g}`);if(W.searchParams.set("sessionId",A),C)W.searchParams.set("scenarioId",C);for(let[_,L]of Object.entries(V))if(_!=="sessionId"&&_!=="scenarioId"&&L)W.searchParams.set(_,L);return W.toString()},F0=(g)=>{if(!g||typeof g!=="object"||!("type"in g))return!1;switch(g.type){case"audio":case"assistant":case"call_lifecycle":case"call_control_ack":case"complete":case"connection":case"error":case"final":case"partial":case"pong":case"replay":case"session":case"turn":return!0;default:return!1}},f0=(g)=>{if(typeof g.data!=="string")return null;try{let A=JSON.parse(g.data);return F0(A)?A:null}catch{return null}},u=(g,A={})=>{if(typeof window>"u")return j0;let C=new Set,V=new Map,T=A.reconnect!==!1,c=A.maxReconnectAttempts??15,U=A.reconnectMaxDelayMs??8000,I=A.pingInterval??30000,G=A.reconnectResetAfterMs??30000,W=($)=>b0($,500,U),_={isConnected:!1,pendingMessages:[],scenarioId:A.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectResetTimeout:null,reconnectTimeout:null,sessionId:A.sessionId??x0(),ws:null},L=($)=>{C.forEach((S)=>S($))},H=($)=>{C.forEach((S)=>S({message:$,recoverable:!1,type:"error"})),L({reconnect:{attempts:_.reconnectAttempts,maxAttempts:c,status:"exhausted"},type:"connection"})},Z=()=>{if(_.pingInterval)clearInterval(_.pingInterval),_.pingInterval=null;if(_.reconnectTimeout)clearTimeout(_.reconnectTimeout),_.reconnectTimeout=null;if(_.reconnectResetTimeout)clearTimeout(_.reconnectResetTimeout),_.reconnectResetTimeout=null},E=()=>{if(_.ws?.readyState!==1)return;while(_.pendingMessages.length>0){let $=_.pendingMessages.shift();if($!==void 0)_.ws.send($)}},D=($)=>{for(let S of V.values())clearTimeout(S.timeout),S.reject(Error($));V.clear()},h=()=>{_.reconnectAttempts+=1;let $=W(_.reconnectAttempts),S=Date.now()+$;L({reconnect:{attempts:_.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:c,nextAttemptAt:S,status:"reconnecting"},type:"connection"}),_.reconnectTimeout=setTimeout(async()=>{if(_.reconnectAttempts>c){H("Voice connection could not be restored.");return}try{await A.prepareReconnect?.({attempt:_.reconnectAttempts,path:g,scenarioId:_.scenarioId,sessionId:_.sessionId})}catch{if(_.reconnectAttempts<c)h();else H("Voice authorization could not be renewed for reconnect.");return}w()},$)},w=()=>{let $=new WebSocket(k0(g,_.sessionId,_.scenarioId,A.query??{}));$.binaryType="arraybuffer",$.onopen=()=>{if(_.ws!==$){$.close(1000);return}let S=_.reconnectAttempts>0;if(_.isConnected=!0,E(),S)L({reconnect:{attempts:_.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:c,status:"resumed"},type:"connection"}),_.reconnectResetTimeout=setTimeout(()=>{if(_.ws===$&&$.readyState===1)_.reconnectAttempts=0;_.reconnectResetTimeout=null},G);C.forEach((y)=>y({scenarioId:_.scenarioId??void 0,sessionId:_.sessionId,status:"active",type:"session"})),_.pingInterval=setInterval(()=>{if($.readyState===1)$.send(JSON.stringify({type:"ping"}))},I)},$.onmessage=(S)=>{if(_.ws!==$)return;let y=f0(S);if(!y)return;if(y.type==="session")_.sessionId=y.sessionId,_.scenarioId=y.scenarioId??_.scenarioId;if(y.type==="call_control_ack"){let Y=V.get(y.requestId);if(Y)if(clearTimeout(Y.timeout),V.delete(y.requestId),y.ok)Y.resolve();else Y.reject(Error(y.message??`${y.action} was not applied`))}C.forEach((Y)=>Y(y))},$.onclose=(S)=>{if(_.ws!==$)return;_.ws=null,_.isConnected=!1,Z();let y=T&&S.code!==1000&&S.code!==4401&&S.code!==4403&&_.reconnectAttempts<c,Y=S.code===4401||S.code===4403;if(Y)C.forEach((j)=>j({message:S.code===4401?"Voice authorization expired or was rejected.":"Voice authorization was forbidden.",recoverable:!1,type:"error"}));if(y)h();else if(T&&S.code!==1000)if(Y)L({reconnect:{attempts:_.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:c,status:"exhausted"},type:"connection"});else H("Voice connection could not be restored.")},_.ws=$},Q=($)=>{if(_.ws?.readyState===1){_.ws.send($);return}if(typeof $!=="string")return;if(_.pendingMessages.length>=100)_.pendingMessages.shift();_.pendingMessages.push($)},N=($)=>{Q(JSON.stringify($))},z=($={})=>{if($.sessionId)_.sessionId=$.sessionId;if($.scenarioId)_.scenarioId=$.scenarioId;N({scenarioId:_.scenarioId??void 0,sessionId:_.sessionId,type:"start"})},R=($)=>{Q($)},O=()=>{N({type:"end_turn"})},b=($)=>{let S=crypto.randomUUID(),{promise:y,reject:Y,resolve:j}=Promise.withResolvers(),U0=setTimeout(()=>{V.delete(S),Y(Error(`${$.action} acknowledgement timed out`))},5000);return V.set(S,{reject:Y,resolve:j,timeout:U0}),N({...$,requestId:S,type:"call_control"}),y},R0=($="client-close")=>{if(Z(),D("Voice connection closed"),_.ws){let S=_.ws;if(_.ws=null,S.readyState===1)S.send(JSON.stringify({reason:$,type:"close"}));S.close(1000)}_.isConnected=!1,C.clear()},$0=()=>{if(Z(),D("Voice connection disconnected"),_.ws){let $=_.ws;_.ws=null,$.close(1000)}_.isConnected=!1,C.clear()},H0=()=>{if(_.ws?.readyState===1)_.ws.close(4000,"absolutejs-voice-reconnect-proof")},I0=($)=>{return C.add($),()=>{C.delete($)}};return w(),{callControl:b,close:R0,disconnect:$0,endTurn:O,send:N,sendAudio:R,simulateDisconnect:H0,start:z,subscribe:I0,getReadyState:()=>_.ws?.readyState??3,getScenarioId:()=>_.scenarioId??"",getSessionId:()=>_.sessionId}};var d0=()=>({attempts:0,maxAttempts:0,status:"idle"}),l0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!C)return g;if(!g)return C;if(g===C||g.endsWith(C))return g;if(C.includes(g))return C;return`${g} ${C}`},v0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!g)return C;if(!C||g.endsWith(C))return g;return`${g} ${C}`},i0=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,partial:"",reconnect:d0(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),s=()=>{let g=i0(),A="",C=new Set,V=()=>{C.forEach((c)=>c())};return{dispatch:(c)=>{switch(c.type){case"audio":g={...g,assistantAudio:[...g.assistantAudio,{chunk:c.chunk,format:c.format,receivedAt:c.receivedAt,turnId:c.turnId}]};break;case"assistant":g={...g,assistantStreamingText:"",assistantTexts:[...g.assistantTexts,c.text]};break;case"assistant_delta":g={...g,assistantStreamingText:`${g.assistantStreamingText}${c.delta}`};break;case"complete":g={...g,sessionId:c.sessionId,status:"completed"};break;case"call_lifecycle":g={...g,call:{...g.call,disposition:c.event.type==="end"?c.event.disposition:g.call?.disposition,endedAt:c.event.type==="end"?c.event.at:g.call?.endedAt,events:[...g.call?.events??[],c.event],lastEventAt:c.event.at,startedAt:g.call?.startedAt??c.event.at},sessionId:c.sessionId};break;case"connected":g={...g,isConnected:!0,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect};break;case"connection":g={...g,reconnect:c.reconnect};break;case"disconnected":g={...g,isConnected:!1};break;case"error":g={...g,error:c.message,...c.recoverable===!1?{isConnected:!1,status:"failed"}:{}};break;case"final":A=l0(A,c.transcript.text),g={...g,partial:A};break;case"partial":g={...g,partial:v0(A,c.transcript.text)};break;case"replay":A=c.partial,g={...g,assistantStreamingText:"",assistantTexts:[...c.assistantTexts],call:c.call??null,error:null,isConnected:c.status==="active",partial:c.partial,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect,scenarioId:c.scenarioId??g.scenarioId,sessionId:c.sessionId,sessionMetadata:c.sessionMetadata??g.sessionMetadata,status:c.status,turns:[...c.turns]};break;case"session":g={...g,error:null,scenarioId:c.scenarioId??g.scenarioId,isConnected:c.status==="active",sessionId:c.sessionId,sessionMetadata:c.sessionMetadata??g.sessionMetadata,status:c.status};break;case"turn":A="",g={...g,partial:"",turns:[...g.turns,c.turn]};break}V()},getServerSnapshot:()=>g,getSnapshot:()=>g,subscribe:(c)=>{return C.add(c),()=>{C.delete(c)}}}};var a=(g,A={})=>{let C=u(g,A),V=s(),T=A.browserMedia&&typeof window<"u"?r({...A.browserMedia,getScenarioId:()=>A.browserMedia?A.browserMedia.getScenarioId?.()??C.getScenarioId():C.getScenarioId(),getSessionId:()=>A.browserMedia?A.browserMedia.getSessionId?.()??C.getSessionId():C.getSessionId()}):null,c=new Set,U=(_)=>Promise.resolve().then(()=>{if(!_?.sessionId&&!_?.scenarioId)return;C.start(_),T?.start()}),I=()=>{c.forEach((_)=>_())},G=()=>{if(!A.reconnectReportPath||typeof fetch>"u")return;let _=V.getSnapshot(),L=JSON.stringify({at:Date.now(),reconnect:_.reconnect,scenarioId:_.scenarioId,sessionId:C.getSessionId(),turnIds:_.turns.map((H)=>H.id)});fetch(A.reconnectReportPath,{body:L,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},W=C.subscribe((_)=>{let L=v(_);if(L){if(V.dispatch(L),_.type==="connection")G();I()}});return{start:U,get assistantAudio(){return V.getSnapshot().assistantAudio},get assistantTexts(){return V.getSnapshot().assistantTexts},get assistantStreamingText(){return V.getSnapshot().assistantStreamingText},get call(){return V.getSnapshot().call},callControl(_){return C.callControl(_)},close(_){W(),T?.close(),C.close(_),V.dispatch({type:"disconnected"}),I()},disconnect(){W(),T?.close(),C.disconnect(),V.dispatch({type:"disconnected"}),I()},endTurn(){C.endTurn()},get error(){return V.getSnapshot().error},getServerSnapshot(){return V.getServerSnapshot()},getSnapshot(){return V.getSnapshot()},get isConnected(){return V.getSnapshot().isConnected},get partial(){return V.getSnapshot().partial},get reconnect(){return V.getSnapshot().reconnect},get scenarioId(){return V.getSnapshot().scenarioId},sendAudio(_){C.sendAudio(_)},get sessionId(){return C.getSessionId()},get sessionMetadata(){return V.getSnapshot().sessionMetadata},simulateDisconnect(){C.simulateDisconnect()},get status(){return V.getSnapshot().status},subscribe(_){return c.add(_),()=>{c.delete(_)}},get turns(){return V.getSnapshot().turns}}};var p=(g)=>{if(!g||g.enabled===!1)return;return{enabled:!0,maxGain:g.maxGain??3,noiseGateAttenuation:g.noiseGateAttenuation??0.15,noiseGateThreshold:g.noiseGateThreshold??0.006,targetLevel:g.targetLevel??0.08}};var n0={balanced:{qualityProfile:"general",minSilenceMs:400,silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",minSilenceMs:300,silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",minSilenceMs:600,silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},o0={"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},general:{},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}};var t=(g)=>{let A=g?.profile??"fast",C=g?.qualityProfile??"general",V=n0[A],T=o0[C],c=g?.silenceMs??T.silenceMs??V.silenceMs;return{profile:A,qualityProfile:C,minSilenceMs:Math.min(c,g?.minSilenceMs??T.minSilenceMs??V.minSilenceMs),silenceMs:c,speechThreshold:g?.speechThreshold??T.speechThreshold??V.speechThreshold,transcriptStabilityMs:g?.transcriptStabilityMs??T.transcriptStabilityMs??V.transcriptStabilityMs}};var m0={chat:{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"balanced",qualityProfile:"short-command"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"fast",qualityProfile:"general"}},dictation:{audioConditioning:{enabled:!0,maxGain:2.25,noiseGateAttenuation:0.05,noiseGateThreshold:0.003,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"guided-intake":{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"turn-scoped",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"noisy-room":{audioConditioning:{enabled:!0,maxGain:3,noiseGateAttenuation:0.12,noiseGateThreshold:0.006,targetLevel:0.085},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:2100,speechThreshold:0.02,transcriptStabilityMs:1650}},"pstn-balanced":{audioConditioning:{enabled:!0,maxGain:2.8,noiseGateAttenuation:0.07,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:660,speechThreshold:0.012,transcriptStabilityMs:300}},"pstn-fast":{audioConditioning:{enabled:!0,maxGain:2.75,noiseGateAttenuation:0.06,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:620,speechThreshold:0.012,transcriptStabilityMs:280}},reliability:{audioConditioning:{enabled:!0,maxGain:2.9,noiseGateAttenuation:0.08,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room"}}},e=(g="default")=>{let A=m0[g];return{audioConditioning:p(A.audioConditioning),capture:{channelCount:A.capture?.channelCount??1,sampleRateHz:A.capture?.sampleRateHz??16000},connection:{...A.connection},name:g,sttLifecycle:A.sttLifecycle??"continuous",turnDetection:t(A.turnDetection)}};var r0=(g)=>({assistantAudio:[...g.assistantAudio],assistantStreamingText:g.assistantStreamingText,assistantTexts:[...g.assistantTexts],call:g.call,error:g.error,isConnected:g.isConnected,isRecording:!1,partial:g.partial,reconnect:g.reconnect,recordingError:null,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,turns:[...g.turns]}),g0=(g,A={})=>{let C=e(A.preset),V=a(g,{...C.connection,...A.connection}),T=null,c=r0(V),U=new Set,I=()=>{for(let D of U)D()},G=()=>{if(c={...c,assistantAudio:[...V.assistantAudio],assistantStreamingText:V.assistantStreamingText,assistantTexts:[...V.assistantTexts],call:V.call,error:V.error,isConnected:V.isConnected,partial:V.partial,reconnect:V.reconnect,sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,scenarioId:V.scenarioId,status:V.status,turns:[...V.turns]},A.autoStopOnComplete!==!1&&c.status==="completed"&&c.isRecording)T?.stop(),T=null,c={...c,isRecording:!1};I()},W=V.subscribe(G);G();let _=()=>{if(T)return T;return T=l({channelCount:A.capture?.channelCount??C.capture.channelCount,onLevel:A.capture?.onLevel,onAudio:(D)=>{if(A.capture?.onAudio){A.capture.onAudio(D,V.sendAudio);return}V.sendAudio(D)},sampleRateHz:A.capture?.sampleRateHz??C.capture.sampleRateHz,...A.capture?.stream?{stream:A.capture.stream}:{}}),T},L=()=>{T?.stop(),T=null,c={...c,isRecording:!1},I()},H=async()=>{if(c.isRecording)return;try{c={...c,recordingError:null},I(),await _().start(),c={...c,isRecording:!0},I()}catch(D){throw T?.stop(),T=null,c={...c,isRecording:!1,recordingError:D instanceof Error?D.message:String(D)},I(),D}};return{close:(D)=>{W(),L(),V.close(D)},disconnect:()=>{W(),L(),V.disconnect()},startRecording:H,stopRecording:L,get assistantAudio(){return c.assistantAudio},get assistantTexts(){return c.assistantTexts},get assistantStreamingText(){return c.assistantStreamingText},bindHTMX(D){return d(V,D)},get call(){return c.call},callControl:(D)=>V.callControl(D),endTurn:()=>V.endTurn(),get error(){return c.error},getServerSnapshot:()=>c,getSnapshot:()=>c,get isConnected(){return c.isConnected},get isRecording(){return c.isRecording},get partial(){return c.partial},get reconnect(){return c.reconnect},get recordingError(){return c.recordingError},get scenarioId(){return c.scenarioId},sendAudio:(D)=>V.sendAudio(D),get sessionId(){return c.sessionId},get sessionMetadata(){return c.sessionMetadata},simulateDisconnect:()=>V.simulateDisconnect(),get status(){return c.status},subscribe:(D)=>{return U.add(D),()=>{U.delete(D)}},toggleRecording:async()=>{if(c.isRecording){L();return}await H()},get turns(){return c.turns}}};var K=(g)=>String(g).replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#39;");var A0=(g)=>{if(!g.isConnected)return"idle";if(g.isPlaying)return"speaking";if(g.isRecording&&g.hasActivePartial)return"listening";if(g.isRecording)return"listening";if(g.lastTranscriptAt&&!g.lastAssistantAt)return"thinking";if(g.lastTranscriptAt&&g.lastAssistantAt&&g.lastTranscriptAt>g.lastAssistantAt)return"thinking";return"idle"};var u0={accent:"#3b82f6",background:"#0f172a",errorAccent:"#ef4444",fontFamily:'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',foreground:"#f8fafc",radius:16},s0={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},a0=(g,A)=>{switch(g){case"listening":return A.listening;case"speaking":return A.speaking;case"thinking":return A.thinking;case"idle":return A.idle}},V0=(g)=>{let A={...u0,...g.theme},C={...s0,...g.labels},V=g.state.assistantAudio.at(-1)?.receivedAt,T=g.state.turns.at(-1)?.committedAt,c=A0({hasActivePartial:g.state.partial.length>0,isConnected:g.state.isConnected,isPlaying:!1,isRecording:g.state.isRecording,lastAssistantAt:V,lastTranscriptAt:T}),U=!g.state.isConnected&&g.state.status!=="idle"&&!g.state.error,I=g.state.error?"Error":U?C.connecting:g.state.status==="completed"?C.callEnded:a0(c,C);return{agentState:c,classes:{container:`absolute-voice-widget absolute-voice-widget--${c}`,dot:`absolute-voice-widget__dot${g.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:g.state.isConnected,canMute:g.state.isRecording,canStart:!g.state.isRecording&&g.state.status!=="completed"},errorMessage:g.state.error??void 0,labels:C,partial:g.state.partial||void 0,statusLabel:I,theme:A,title:g.title??"Voice"}},p0=(g)=>typeof g==="number"?`${g}px`:g,C0=(g)=>{let A=g.theme,C=`background:${A.background};border-radius:${p0(A.radius)};color:${A.foreground};font-family:${A.fontFamily};min-width:240px;padding:20px 22px;`,V=`background:${g.errorMessage?A.errorAccent:g.agentState==="idle"?"rgba(148,163,184,0.6)":A.accent};border-radius:50%;height:10px;width:10px;`,T=[];if(g.controls.canStart)T.push(`<button type="button" data-action="start" style="background:${A.accent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${K(g.labels.startCall)}</button>`);if(g.controls.canMute)T.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${K(g.labels.mute)}</button>`);if(g.controls.canEnd)T.push(`<button type="button" data-action="end" style="background:${A.errorAccent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${K(g.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${g.agentState}" class="${K(g.classes.container)}" style="${C}">
2
2
  <div style="align-items:center;display:flex;gap:10px;margin-bottom:12px;">
3
3
  <span aria-hidden="true" class="${K(g.classes.dot)}" style="${V}"></span>
4
4
  <strong style="font-size:15px;">${K(g.title)}</strong>
5
5
  <span style="font-size:13px;margin-left:auto;opacity:0.7;">${K(g.statusLabel)}</span>
6
6
  </div>
7
7
  ${g.partial?`<p style="font-size:13px;margin:8px 0 12px;opacity:0.85;word-break:break-word;">“${K(g.partial)}”</p>`:""}
8
- <div style="display:flex;gap:10px;">${c.join("")}</div>
8
+ <div style="display:flex;gap:10px;">${T.join("")}</div>
9
9
  ${g.errorMessage?`<p style="color:${A.errorAccent};font-size:12px;margin-top:12px;">${K(g.errorMessage)}</p>`:""}
10
- </div>`};var p0=(g)=>{if(typeof g!=="string")return g;let A=document.querySelector(g);if(!A)throw Error(`AbsoluteVoice.mount: no element matches "${g}"`);return A},T0=(g,A={})=>{let C=p0(g),V=g0(A.path??"/voice",A.controllerOptions),c=null,T=null,U=()=>{let G=V0({...A.labels!==void 0?{labels:A.labels}:{},state:{assistantAudio:V.assistantAudio,error:V.error,isConnected:V.isConnected,isRecording:V.isRecording,partial:V.partial,status:V.status,turns:V.turns},...A.theme!==void 0?{theme:A.theme}:{},...A.title!==void 0?{title:A.title}:{}});C.innerHTML=C0(G);for(let W of C.querySelectorAll("button[data-action]")){let{action:_}=W.dataset;W.addEventListener("click",()=>{if(_==="start")V.startRecording();else if(_==="mute")V.stopRecording();else if(_==="end")V.close()})}if(V.error&&V.error!==c)c=V.error,A.onError?.(V.error);if(V.status!==T)T=V.status,A.onStatusChange?.(V.status)},I=V.subscribe(U);if(U(),A.autoStart)V.startRecording();return{controller:V,async end(){await V.close()},mute(){V.stopRecording()},async start(){await V.startRecording()},unmount(){I(),V.close(),C.innerHTML=""}}},_0="0.0.22-beta.516",c0={mount:T0,version:_0};if(typeof globalThis<"u")globalThis.AbsoluteVoice=c0;var e0=c0;})();
10
+ </div>`};var t0=(g)=>{if(typeof g!=="string")return g;let A=document.querySelector(g);if(!A)throw Error(`AbsoluteVoice.mount: no element matches "${g}"`);return A},c0=(g,A={})=>{let C=t0(g),V=g0(A.path??"/voice",A.controllerOptions),T=null,c=null,U=()=>{let G=V0({...A.labels!==void 0?{labels:A.labels}:{},state:{assistantAudio:V.assistantAudio,error:V.error,isConnected:V.isConnected,isRecording:V.isRecording,partial:V.partial,status:V.status,turns:V.turns},...A.theme!==void 0?{theme:A.theme}:{},...A.title!==void 0?{title:A.title}:{}});C.innerHTML=C0(G);for(let W of C.querySelectorAll("button[data-action]")){let{action:_}=W.dataset;W.addEventListener("click",()=>{if(_==="start")V.startRecording();else if(_==="mute")V.stopRecording();else if(_==="end")V.close()})}if(V.error&&V.error!==T)T=V.error,A.onError?.(V.error);if(V.status!==c)c=V.status,A.onStatusChange?.(V.status)},I=V.subscribe(U);if(U(),A.autoStart)V.startRecording();return{controller:V,async end(){await V.close()},mute(){V.stopRecording()},async start(){await V.startRecording()},unmount(){I(),V.close(),C.innerHTML=""}}},_0="0.0.22-beta.516",T0={mount:c0,version:_0};if(typeof globalThis<"u")globalThis.AbsoluteVoice=T0;var gg=T0;})();
@@ -11541,6 +11541,21 @@ var createVoiceConnection = (path, options = {}) => {
11541
11541
  const emitConnection = (reconnect) => {
11542
11542
  listeners.forEach((listener) => listener(reconnect));
11543
11543
  };
11544
+ const emitTerminalFailure = (message) => {
11545
+ listeners.forEach((listener) => listener({
11546
+ message,
11547
+ recoverable: false,
11548
+ type: "error"
11549
+ }));
11550
+ emitConnection({
11551
+ reconnect: {
11552
+ attempts: state.reconnectAttempts,
11553
+ maxAttempts: maxReconnectAttempts,
11554
+ status: "exhausted"
11555
+ },
11556
+ type: "connection"
11557
+ });
11558
+ };
11544
11559
  const clearTimers = () => {
11545
11560
  if (state.pingInterval) {
11546
11561
  clearInterval(state.pingInterval);
@@ -11589,14 +11604,7 @@ var createVoiceConnection = (path, options = {}) => {
11589
11604
  });
11590
11605
  state.reconnectTimeout = setTimeout(async () => {
11591
11606
  if (state.reconnectAttempts > maxReconnectAttempts) {
11592
- emitConnection({
11593
- reconnect: {
11594
- attempts: state.reconnectAttempts,
11595
- maxAttempts: maxReconnectAttempts,
11596
- status: "exhausted"
11597
- },
11598
- type: "connection"
11599
- });
11607
+ emitTerminalFailure("Voice connection could not be restored.");
11600
11608
  return;
11601
11609
  }
11602
11610
  try {
@@ -11610,14 +11618,7 @@ var createVoiceConnection = (path, options = {}) => {
11610
11618
  if (state.reconnectAttempts < maxReconnectAttempts) {
11611
11619
  scheduleReconnect();
11612
11620
  } else {
11613
- emitConnection({
11614
- reconnect: {
11615
- attempts: state.reconnectAttempts,
11616
- maxAttempts: maxReconnectAttempts,
11617
- status: "exhausted"
11618
- },
11619
- type: "connection"
11620
- });
11621
+ emitTerminalFailure("Voice authorization could not be renewed for reconnect.");
11621
11622
  }
11622
11623
  return;
11623
11624
  }
@@ -11707,15 +11708,19 @@ var createVoiceConnection = (path, options = {}) => {
11707
11708
  if (reconnectable) {
11708
11709
  scheduleReconnect();
11709
11710
  } else if (shouldReconnect && event.code !== WS_NORMAL_CLOSURE) {
11710
- emitConnection({
11711
- reconnect: {
11712
- attempts: state.reconnectAttempts,
11713
- lastDisconnectAt: Date.now(),
11714
- maxAttempts: maxReconnectAttempts,
11715
- status: "exhausted"
11716
- },
11717
- type: "connection"
11718
- });
11711
+ if (authorizationFailure) {
11712
+ emitConnection({
11713
+ reconnect: {
11714
+ attempts: state.reconnectAttempts,
11715
+ lastDisconnectAt: Date.now(),
11716
+ maxAttempts: maxReconnectAttempts,
11717
+ status: "exhausted"
11718
+ },
11719
+ type: "connection"
11720
+ });
11721
+ } else {
11722
+ emitTerminalFailure("Voice connection could not be restored.");
11723
+ }
11719
11724
  }
11720
11725
  };
11721
11726
  state.ws = ws;
@@ -869,6 +869,21 @@ var createVoiceConnection = (path, options = {}) => {
869
869
  const emitConnection = (reconnect) => {
870
870
  listeners.forEach((listener) => listener(reconnect));
871
871
  };
872
+ const emitTerminalFailure = (message) => {
873
+ listeners.forEach((listener) => listener({
874
+ message,
875
+ recoverable: false,
876
+ type: "error"
877
+ }));
878
+ emitConnection({
879
+ reconnect: {
880
+ attempts: state.reconnectAttempts,
881
+ maxAttempts: maxReconnectAttempts,
882
+ status: "exhausted"
883
+ },
884
+ type: "connection"
885
+ });
886
+ };
872
887
  const clearTimers = () => {
873
888
  if (state.pingInterval) {
874
889
  clearInterval(state.pingInterval);
@@ -917,14 +932,7 @@ var createVoiceConnection = (path, options = {}) => {
917
932
  });
918
933
  state.reconnectTimeout = setTimeout(async () => {
919
934
  if (state.reconnectAttempts > maxReconnectAttempts) {
920
- emitConnection({
921
- reconnect: {
922
- attempts: state.reconnectAttempts,
923
- maxAttempts: maxReconnectAttempts,
924
- status: "exhausted"
925
- },
926
- type: "connection"
927
- });
935
+ emitTerminalFailure("Voice connection could not be restored.");
928
936
  return;
929
937
  }
930
938
  try {
@@ -938,14 +946,7 @@ var createVoiceConnection = (path, options = {}) => {
938
946
  if (state.reconnectAttempts < maxReconnectAttempts) {
939
947
  scheduleReconnect();
940
948
  } else {
941
- emitConnection({
942
- reconnect: {
943
- attempts: state.reconnectAttempts,
944
- maxAttempts: maxReconnectAttempts,
945
- status: "exhausted"
946
- },
947
- type: "connection"
948
- });
949
+ emitTerminalFailure("Voice authorization could not be renewed for reconnect.");
949
950
  }
950
951
  return;
951
952
  }
@@ -1035,15 +1036,19 @@ var createVoiceConnection = (path, options = {}) => {
1035
1036
  if (reconnectable) {
1036
1037
  scheduleReconnect();
1037
1038
  } else if (shouldReconnect && event.code !== WS_NORMAL_CLOSURE) {
1038
- emitConnection({
1039
- reconnect: {
1040
- attempts: state.reconnectAttempts,
1041
- lastDisconnectAt: Date.now(),
1042
- maxAttempts: maxReconnectAttempts,
1043
- status: "exhausted"
1044
- },
1045
- type: "connection"
1046
- });
1039
+ if (authorizationFailure) {
1040
+ emitConnection({
1041
+ reconnect: {
1042
+ attempts: state.reconnectAttempts,
1043
+ lastDisconnectAt: Date.now(),
1044
+ maxAttempts: maxReconnectAttempts,
1045
+ status: "exhausted"
1046
+ },
1047
+ type: "connection"
1048
+ });
1049
+ } else {
1050
+ emitTerminalFailure("Voice connection could not be restored.");
1051
+ }
1047
1052
  }
1048
1053
  };
1049
1054
  state.ws = ws;
@@ -3090,6 +3090,21 @@ var createVoiceConnection = (path, options = {}) => {
3090
3090
  const emitConnection = (reconnect) => {
3091
3091
  listeners.forEach((listener) => listener(reconnect));
3092
3092
  };
3093
+ const emitTerminalFailure = (message) => {
3094
+ listeners.forEach((listener) => listener({
3095
+ message,
3096
+ recoverable: false,
3097
+ type: "error"
3098
+ }));
3099
+ emitConnection({
3100
+ reconnect: {
3101
+ attempts: state.reconnectAttempts,
3102
+ maxAttempts: maxReconnectAttempts,
3103
+ status: "exhausted"
3104
+ },
3105
+ type: "connection"
3106
+ });
3107
+ };
3093
3108
  const clearTimers = () => {
3094
3109
  if (state.pingInterval) {
3095
3110
  clearInterval(state.pingInterval);
@@ -3138,14 +3153,7 @@ var createVoiceConnection = (path, options = {}) => {
3138
3153
  });
3139
3154
  state.reconnectTimeout = setTimeout(async () => {
3140
3155
  if (state.reconnectAttempts > maxReconnectAttempts) {
3141
- emitConnection({
3142
- reconnect: {
3143
- attempts: state.reconnectAttempts,
3144
- maxAttempts: maxReconnectAttempts,
3145
- status: "exhausted"
3146
- },
3147
- type: "connection"
3148
- });
3156
+ emitTerminalFailure("Voice connection could not be restored.");
3149
3157
  return;
3150
3158
  }
3151
3159
  try {
@@ -3159,14 +3167,7 @@ var createVoiceConnection = (path, options = {}) => {
3159
3167
  if (state.reconnectAttempts < maxReconnectAttempts) {
3160
3168
  scheduleReconnect();
3161
3169
  } else {
3162
- emitConnection({
3163
- reconnect: {
3164
- attempts: state.reconnectAttempts,
3165
- maxAttempts: maxReconnectAttempts,
3166
- status: "exhausted"
3167
- },
3168
- type: "connection"
3169
- });
3170
+ emitTerminalFailure("Voice authorization could not be renewed for reconnect.");
3170
3171
  }
3171
3172
  return;
3172
3173
  }
@@ -3256,15 +3257,19 @@ var createVoiceConnection = (path, options = {}) => {
3256
3257
  if (reconnectable) {
3257
3258
  scheduleReconnect();
3258
3259
  } else if (shouldReconnect && event.code !== WS_NORMAL_CLOSURE) {
3259
- emitConnection({
3260
- reconnect: {
3261
- attempts: state.reconnectAttempts,
3262
- lastDisconnectAt: Date.now(),
3263
- maxAttempts: maxReconnectAttempts,
3264
- status: "exhausted"
3265
- },
3266
- type: "connection"
3267
- });
3260
+ if (authorizationFailure) {
3261
+ emitConnection({
3262
+ reconnect: {
3263
+ attempts: state.reconnectAttempts,
3264
+ lastDisconnectAt: Date.now(),
3265
+ maxAttempts: maxReconnectAttempts,
3266
+ status: "exhausted"
3267
+ },
3268
+ type: "connection"
3269
+ });
3270
+ } else {
3271
+ emitTerminalFailure("Voice connection could not be restored.");
3272
+ }
3268
3273
  }
3269
3274
  };
3270
3275
  state.ws = ws;
package/dist/vue/index.js CHANGED
@@ -10937,6 +10937,21 @@ var createVoiceConnection = (path, options = {}) => {
10937
10937
  const emitConnection = (reconnect) => {
10938
10938
  listeners.forEach((listener) => listener(reconnect));
10939
10939
  };
10940
+ const emitTerminalFailure = (message) => {
10941
+ listeners.forEach((listener) => listener({
10942
+ message,
10943
+ recoverable: false,
10944
+ type: "error"
10945
+ }));
10946
+ emitConnection({
10947
+ reconnect: {
10948
+ attempts: state.reconnectAttempts,
10949
+ maxAttempts: maxReconnectAttempts,
10950
+ status: "exhausted"
10951
+ },
10952
+ type: "connection"
10953
+ });
10954
+ };
10940
10955
  const clearTimers = () => {
10941
10956
  if (state.pingInterval) {
10942
10957
  clearInterval(state.pingInterval);
@@ -10985,14 +11000,7 @@ var createVoiceConnection = (path, options = {}) => {
10985
11000
  });
10986
11001
  state.reconnectTimeout = setTimeout(async () => {
10987
11002
  if (state.reconnectAttempts > maxReconnectAttempts) {
10988
- emitConnection({
10989
- reconnect: {
10990
- attempts: state.reconnectAttempts,
10991
- maxAttempts: maxReconnectAttempts,
10992
- status: "exhausted"
10993
- },
10994
- type: "connection"
10995
- });
11003
+ emitTerminalFailure("Voice connection could not be restored.");
10996
11004
  return;
10997
11005
  }
10998
11006
  try {
@@ -11006,14 +11014,7 @@ var createVoiceConnection = (path, options = {}) => {
11006
11014
  if (state.reconnectAttempts < maxReconnectAttempts) {
11007
11015
  scheduleReconnect();
11008
11016
  } else {
11009
- emitConnection({
11010
- reconnect: {
11011
- attempts: state.reconnectAttempts,
11012
- maxAttempts: maxReconnectAttempts,
11013
- status: "exhausted"
11014
- },
11015
- type: "connection"
11016
- });
11017
+ emitTerminalFailure("Voice authorization could not be renewed for reconnect.");
11017
11018
  }
11018
11019
  return;
11019
11020
  }
@@ -11103,15 +11104,19 @@ var createVoiceConnection = (path, options = {}) => {
11103
11104
  if (reconnectable) {
11104
11105
  scheduleReconnect();
11105
11106
  } else if (shouldReconnect && event.code !== WS_NORMAL_CLOSURE) {
11106
- emitConnection({
11107
- reconnect: {
11108
- attempts: state.reconnectAttempts,
11109
- lastDisconnectAt: Date.now(),
11110
- maxAttempts: maxReconnectAttempts,
11111
- status: "exhausted"
11112
- },
11113
- type: "connection"
11114
- });
11107
+ if (authorizationFailure) {
11108
+ emitConnection({
11109
+ reconnect: {
11110
+ attempts: state.reconnectAttempts,
11111
+ lastDisconnectAt: Date.now(),
11112
+ maxAttempts: maxReconnectAttempts,
11113
+ status: "exhausted"
11114
+ },
11115
+ type: "connection"
11116
+ });
11117
+ } else {
11118
+ emitTerminalFailure("Voice connection could not be restored.");
11119
+ }
11115
11120
  }
11116
11121
  };
11117
11122
  state.ws = ws;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.654",
3
+ "version": "0.0.22-beta.655",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",