@absolutejs/voice 0.0.22-beta.97 → 0.0.22-beta.99

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.
@@ -1967,6 +1967,14 @@ var fetchVoiceTurnLatency = async (path = "/api/turn-latency", options = {}) =>
1967
1967
  }
1968
1968
  return await response.json();
1969
1969
  };
1970
+ var runVoiceTurnLatencyProof = async (path, options = {}) => {
1971
+ const fetchImpl = options.fetch ?? globalThis.fetch;
1972
+ const response = await fetchImpl(path, { method: "POST" });
1973
+ if (!response.ok) {
1974
+ throw new Error(`Voice turn latency proof failed: HTTP ${response.status}`);
1975
+ }
1976
+ return response.json();
1977
+ };
1970
1978
  var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) => {
1971
1979
  const listeners = new Set;
1972
1980
  let closed = false;
@@ -2006,6 +2014,25 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
2006
2014
  throw error;
2007
2015
  }
2008
2016
  };
2017
+ const runProof = async () => {
2018
+ if (!options.proofPath) {
2019
+ throw new Error("Voice turn latency proof path is not configured.");
2020
+ }
2021
+ snapshot = { ...snapshot, error: null, isLoading: true };
2022
+ emit();
2023
+ try {
2024
+ await runVoiceTurnLatencyProof(options.proofPath, options);
2025
+ return await refresh();
2026
+ } catch (error) {
2027
+ snapshot = {
2028
+ ...snapshot,
2029
+ error: error instanceof Error ? error.message : String(error),
2030
+ isLoading: false
2031
+ };
2032
+ emit();
2033
+ throw error;
2034
+ }
2035
+ };
2009
2036
  const close = () => {
2010
2037
  closed = true;
2011
2038
  if (timer) {
@@ -2024,6 +2051,7 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
2024
2051
  getServerSnapshot: () => snapshot,
2025
2052
  getSnapshot: () => snapshot,
2026
2053
  refresh,
2054
+ runProof,
2027
2055
  subscribe: (listener) => {
2028
2056
  listeners.add(listener);
2029
2057
  return () => {
@@ -2065,6 +2093,7 @@ class VoiceTurnLatencyService {
2065
2093
  isLoading: computed7(() => isLoadingSignal()),
2066
2094
  refresh: store.refresh,
2067
2095
  report: computed7(() => reportSignal()),
2096
+ runProof: store.runProof,
2068
2097
  updatedAt: computed7(() => updatedAtSignal())
2069
2098
  };
2070
2099
  }
@@ -7,6 +7,7 @@ export declare class VoiceTurnLatencyService {
7
7
  isLoading: import("@angular/core").Signal<boolean>;
8
8
  refresh: () => Promise<VoiceTurnLatencyReport | undefined>;
9
9
  report: import("@angular/core").Signal<VoiceTurnLatencyReport | undefined>;
10
+ runProof: () => Promise<VoiceTurnLatencyReport | undefined>;
10
11
  updatedAt: import("@angular/core").Signal<number | undefined>;
11
12
  };
12
13
  }
@@ -6,6 +6,7 @@ export { bindVoiceBargeIn, createVoiceDuplexController } from './duplex';
6
6
  export { bindVoiceHTMX } from './htmx';
7
7
  export { createMicrophoneCapture } from './microphone';
8
8
  export { createVoiceBargeInMonitor } from './bargeInMonitor';
9
+ export { createVoiceLiveTurnLatencyMonitor } from './liveTurnLatency';
9
10
  export { createVoiceAppKitStatusStore, fetchVoiceAppKitStatus } from './appKitStatus';
10
11
  export { createVoiceOpsStatusViewModel, defineVoiceOpsStatusElement, getVoiceOpsStatusCSS, getVoiceOpsStatusLabel, mountVoiceOpsStatus, renderVoiceOpsStatusHTML } from './opsStatusWidget';
11
12
  export { createVoiceRoutingStatusStore, fetchVoiceRoutingStatus } from './routingStatus';
@@ -13,7 +14,7 @@ export { createVoiceRoutingStatusViewModel, defineVoiceRoutingStatusElement, get
13
14
  export { createVoiceProviderStatusStore, fetchVoiceProviderStatus } from './providerStatus';
14
15
  export { createVoiceProviderCapabilitiesStore, fetchVoiceProviderCapabilities } from './providerCapabilities';
15
16
  export { createVoiceTurnQualityStore, fetchVoiceTurnQuality } from './turnQuality';
16
- export { createVoiceTurnLatencyStore, fetchVoiceTurnLatency } from './turnLatency';
17
+ export { createVoiceTurnLatencyStore, fetchVoiceTurnLatency, runVoiceTurnLatencyProof } from './turnLatency';
17
18
  export { createVoiceTraceTimelineStore, fetchVoiceTraceTimeline } from './traceTimeline';
18
19
  export { createVoiceProviderSimulationControlsStore } from './providerSimulationControls';
19
20
  export { bindVoiceProviderSimulationControls, createVoiceProviderSimulationControlsViewModel, defineVoiceProviderSimulationControlsElement, mountVoiceProviderSimulationControls, renderVoiceProviderSimulationControlsHTML } from './providerSimulationControlsWidget';
@@ -25,6 +26,7 @@ export { createVoiceTraceTimelineViewModel, defineVoiceTraceTimelineElement, get
25
26
  export { createVoiceWorkflowStatusStore, fetchVoiceWorkflowStatus } from './workflowStatus';
26
27
  export type { VoiceAppKitStatusClientOptions, VoiceAppKitStatusSnapshot } from './appKitStatus';
27
28
  export type { VoiceBargeInMonitorOptions } from './bargeInMonitor';
29
+ export type { VoiceLiveTurnLatencyEvent, VoiceLiveTurnLatencyMonitorOptions, VoiceLiveTurnLatencySnapshot, VoiceLiveTurnLatencyStatus } from './liveTurnLatency';
28
30
  export type { VoiceOpsStatusSurfaceView, VoiceOpsStatusViewModel, VoiceOpsStatusWidgetOptions } from './opsStatusWidget';
29
31
  export type { VoiceRoutingStatusClientOptions, VoiceRoutingStatusSnapshot } from './routingStatus';
30
32
  export type { VoiceRoutingStatusViewModel, VoiceRoutingStatusWidgetOptions } from './routingStatusWidget';
@@ -1724,6 +1724,116 @@ var createVoiceBargeInMonitor = (options = {}) => {
1724
1724
  }
1725
1725
  };
1726
1726
  };
1727
+ // src/client/liveTurnLatency.ts
1728
+ var getAudioLevel = (audio) => {
1729
+ const bytes = audio instanceof Uint8Array ? audio : new Uint8Array(audio);
1730
+ if (bytes.byteLength < 2) {
1731
+ return 0;
1732
+ }
1733
+ const samples = new Int16Array(bytes.buffer, bytes.byteOffset, Math.floor(bytes.byteLength / 2));
1734
+ if (samples.length === 0) {
1735
+ return 0;
1736
+ }
1737
+ let sumSquares = 0;
1738
+ for (const sample of samples) {
1739
+ const normalized = sample / 32768;
1740
+ sumSquares += normalized * normalized;
1741
+ }
1742
+ return Math.min(1, Math.max(0, Math.sqrt(sumSquares / samples.length) * 5.5));
1743
+ };
1744
+ var createVoiceLiveTurnLatencyMonitor = (options = {}) => {
1745
+ const listeners = new Set;
1746
+ const clock = options.clock ?? (() => Date.now());
1747
+ const failAfterMs = options.failAfterMs ?? 3200;
1748
+ const maxEvents = options.maxEvents ?? 20;
1749
+ const speechThreshold = options.speechThreshold ?? 0.04;
1750
+ const warnAfterMs = options.warnAfterMs ?? 1800;
1751
+ let events = [];
1752
+ let pending;
1753
+ let lastAudioCount = 0;
1754
+ let lastTextCount = 0;
1755
+ let lastSessionId;
1756
+ const emit = () => {
1757
+ for (const listener of listeners) {
1758
+ listener();
1759
+ }
1760
+ };
1761
+ const completePending = (input) => {
1762
+ if (!pending) {
1763
+ return;
1764
+ }
1765
+ const completedAt = input.assistantAudioAt ?? input.assistantTextAt ?? clock();
1766
+ const latencyMs = Math.max(0, completedAt - pending.startedAt);
1767
+ const status = latencyMs > failAfterMs ? "fail" : latencyMs > warnAfterMs ? "warn" : "pass";
1768
+ pending = {
1769
+ ...pending,
1770
+ ...input,
1771
+ completedAt,
1772
+ latencyMs,
1773
+ status
1774
+ };
1775
+ events = [pending, ...events].slice(0, maxEvents);
1776
+ pending = undefined;
1777
+ emit();
1778
+ };
1779
+ const observe = (state) => {
1780
+ const now = clock();
1781
+ if (pending) {
1782
+ if (state.assistantAudio.length > lastAudioCount) {
1783
+ completePending({ assistantAudioAt: now });
1784
+ } else if (state.assistantTexts.length > lastTextCount) {
1785
+ completePending({ assistantTextAt: now });
1786
+ }
1787
+ }
1788
+ lastAudioCount = state.assistantAudio.length;
1789
+ lastTextCount = state.assistantTexts.length;
1790
+ lastSessionId = state.sessionId;
1791
+ };
1792
+ const recordAudio = (audio) => {
1793
+ if (pending || getAudioLevel(audio) < speechThreshold) {
1794
+ return pending;
1795
+ }
1796
+ pending = {
1797
+ id: `live-turn-${crypto.randomUUID()}`,
1798
+ sessionId: lastSessionId ?? null,
1799
+ startedAt: clock(),
1800
+ status: "pending",
1801
+ thresholdMs: failAfterMs
1802
+ };
1803
+ emit();
1804
+ return pending;
1805
+ };
1806
+ const getSnapshot = () => {
1807
+ const completed = events.filter((event) => typeof event.latencyMs === "number");
1808
+ const latencies = completed.map((event) => event.latencyMs);
1809
+ const failed = events.filter((event) => event.status === "fail").length;
1810
+ const warnings = events.filter((event) => event.status === "warn").length;
1811
+ const passed = events.filter((event) => event.status === "pass").length;
1812
+ return {
1813
+ averageLatencyMs: latencies.length ? Math.round(latencies.reduce((total, value) => total + value, 0) / latencies.length) : undefined,
1814
+ events,
1815
+ failed,
1816
+ lastEvent: events[0],
1817
+ passed,
1818
+ pending,
1819
+ status: pending ? "pending" : events.length === 0 ? "empty" : failed > 0 ? "fail" : warnings > 0 ? "warn" : "pass",
1820
+ thresholdMs: failAfterMs,
1821
+ total: events.length,
1822
+ warnings
1823
+ };
1824
+ };
1825
+ return {
1826
+ getSnapshot,
1827
+ observe,
1828
+ recordAudio,
1829
+ subscribe: (listener) => {
1830
+ listeners.add(listener);
1831
+ return () => {
1832
+ listeners.delete(listener);
1833
+ };
1834
+ }
1835
+ };
1836
+ };
1727
1837
  // src/client/appKitStatus.ts
1728
1838
  var fetchVoiceAppKitStatus = async (path = "/app-kit/status", options = {}) => {
1729
1839
  const fetchImpl = options.fetch ?? globalThis.fetch;
@@ -2339,6 +2449,14 @@ var fetchVoiceTurnLatency = async (path = "/api/turn-latency", options = {}) =>
2339
2449
  }
2340
2450
  return await response.json();
2341
2451
  };
2452
+ var runVoiceTurnLatencyProof = async (path, options = {}) => {
2453
+ const fetchImpl = options.fetch ?? globalThis.fetch;
2454
+ const response = await fetchImpl(path, { method: "POST" });
2455
+ if (!response.ok) {
2456
+ throw new Error(`Voice turn latency proof failed: HTTP ${response.status}`);
2457
+ }
2458
+ return response.json();
2459
+ };
2342
2460
  var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) => {
2343
2461
  const listeners = new Set;
2344
2462
  let closed = false;
@@ -2378,6 +2496,25 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
2378
2496
  throw error;
2379
2497
  }
2380
2498
  };
2499
+ const runProof = async () => {
2500
+ if (!options.proofPath) {
2501
+ throw new Error("Voice turn latency proof path is not configured.");
2502
+ }
2503
+ snapshot = { ...snapshot, error: null, isLoading: true };
2504
+ emit();
2505
+ try {
2506
+ await runVoiceTurnLatencyProof(options.proofPath, options);
2507
+ return await refresh();
2508
+ } catch (error) {
2509
+ snapshot = {
2510
+ ...snapshot,
2511
+ error: error instanceof Error ? error.message : String(error),
2512
+ isLoading: false
2513
+ };
2514
+ emit();
2515
+ throw error;
2516
+ }
2517
+ };
2381
2518
  const close = () => {
2382
2519
  closed = true;
2383
2520
  if (timer) {
@@ -2396,6 +2533,7 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
2396
2533
  getServerSnapshot: () => snapshot,
2397
2534
  getSnapshot: () => snapshot,
2398
2535
  refresh,
2536
+ runProof,
2399
2537
  subscribe: (listener) => {
2400
2538
  listeners.add(listener);
2401
2539
  return () => {
@@ -3004,6 +3142,7 @@ var defineVoiceTurnQualityElement = (tagName = "absolute-voice-turn-quality") =>
3004
3142
  // src/client/turnLatencyWidget.ts
3005
3143
  var DEFAULT_TITLE6 = "Turn Latency";
3006
3144
  var DEFAULT_DESCRIPTION6 = "Per-turn timing from first transcript to commit and assistant response start.";
3145
+ var DEFAULT_PROOF_LABEL = "Run latency proof";
3007
3146
  var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3008
3147
  var formatMs = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
3009
3148
  var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
@@ -3022,6 +3161,8 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
3022
3161
  error: snapshot.error,
3023
3162
  isLoading: snapshot.isLoading,
3024
3163
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} slow` : warningCount > 0 ? `${warningCount} warnings` : `avg ${formatMs(snapshot.report?.averageTotalMs)}` : snapshot.isLoading ? "Checking" : "No turns",
3164
+ proofLabel: options.proofPath ? options.proofLabel ?? DEFAULT_PROOF_LABEL : undefined,
3165
+ showProofAction: Boolean(options.proofPath),
3025
3166
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
3026
3167
  title: options.title ?? DEFAULT_TITLE6,
3027
3168
  turns,
@@ -3046,6 +3187,7 @@ var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
3046
3187
  <strong class="absolute-voice-turn-latency__label">${escapeHtml7(model.label)}</strong>
3047
3188
  </header>
3048
3189
  <p class="absolute-voice-turn-latency__description">${escapeHtml7(model.description)}</p>
3190
+ ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml7(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
3049
3191
  ${turns}
3050
3192
  ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml7(model.error)}</p>` : ""}
3051
3193
  </section>`;
@@ -3055,11 +3197,19 @@ var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {})
3055
3197
  const render = () => {
3056
3198
  element.innerHTML = renderVoiceTurnLatencyHTML(store.getSnapshot(), options);
3057
3199
  };
3200
+ const handleClick = (event) => {
3201
+ const target = event.target;
3202
+ if (target instanceof Element && target.closest("[data-absolute-voice-turn-latency-proof]")) {
3203
+ store.runProof().catch(() => {});
3204
+ }
3205
+ };
3058
3206
  const unsubscribe = store.subscribe(render);
3207
+ element.addEventListener("click", handleClick);
3059
3208
  render();
3060
3209
  store.refresh().catch(() => {});
3061
3210
  return {
3062
3211
  close: () => {
3212
+ element.removeEventListener("click", handleClick);
3063
3213
  unsubscribe();
3064
3214
  store.close();
3065
3215
  },
@@ -3077,6 +3227,8 @@ var defineVoiceTurnLatencyElement = (tagName = "absolute-voice-turn-latency") =>
3077
3227
  this.mounted = mountVoiceTurnLatency(this, this.getAttribute("path") ?? "/api/turn-latency", {
3078
3228
  description: this.getAttribute("description") ?? undefined,
3079
3229
  intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
3230
+ proofLabel: this.getAttribute("proof-label") ?? undefined,
3231
+ proofPath: this.getAttribute("proof-path") ?? undefined,
3080
3232
  title: this.getAttribute("title") ?? undefined
3081
3233
  });
3082
3234
  }
@@ -3252,6 +3404,7 @@ var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options =
3252
3404
  };
3253
3405
  };
3254
3406
  export {
3407
+ runVoiceTurnLatencyProof,
3255
3408
  renderVoiceTurnQualityHTML,
3256
3409
  renderVoiceTurnLatencyHTML,
3257
3410
  renderVoiceTraceTimelineWidgetHTML,
@@ -3309,6 +3462,7 @@ export {
3309
3462
  createVoiceProviderCapabilitiesViewModel,
3310
3463
  createVoiceProviderCapabilitiesStore,
3311
3464
  createVoiceOpsStatusViewModel,
3465
+ createVoiceLiveTurnLatencyMonitor,
3312
3466
  createVoiceDuplexController,
3313
3467
  createVoiceController,
3314
3468
  createVoiceConnection,
@@ -0,0 +1,38 @@
1
+ import type { VoiceStreamState } from '../types';
2
+ export type VoiceLiveTurnLatencyStatus = 'empty' | 'pending' | 'pass' | 'warn' | 'fail';
3
+ export type VoiceLiveTurnLatencyEvent = {
4
+ assistantAudioAt?: number;
5
+ assistantTextAt?: number;
6
+ completedAt?: number;
7
+ id: string;
8
+ latencyMs?: number;
9
+ sessionId?: string | null;
10
+ startedAt: number;
11
+ status: Exclude<VoiceLiveTurnLatencyStatus, 'empty'>;
12
+ thresholdMs: number;
13
+ };
14
+ export type VoiceLiveTurnLatencySnapshot = {
15
+ averageLatencyMs?: number;
16
+ events: VoiceLiveTurnLatencyEvent[];
17
+ failed: number;
18
+ lastEvent?: VoiceLiveTurnLatencyEvent;
19
+ passed: number;
20
+ pending?: VoiceLiveTurnLatencyEvent;
21
+ status: VoiceLiveTurnLatencyStatus;
22
+ thresholdMs: number;
23
+ total: number;
24
+ warnings: number;
25
+ };
26
+ export type VoiceLiveTurnLatencyMonitorOptions = {
27
+ clock?: () => number;
28
+ failAfterMs?: number;
29
+ maxEvents?: number;
30
+ speechThreshold?: number;
31
+ warnAfterMs?: number;
32
+ };
33
+ export declare const createVoiceLiveTurnLatencyMonitor: (options?: VoiceLiveTurnLatencyMonitorOptions) => {
34
+ getSnapshot: () => VoiceLiveTurnLatencySnapshot;
35
+ observe: <TResult = unknown>(state: VoiceStreamState<TResult>) => void;
36
+ recordAudio: (audio: Uint8Array | ArrayBuffer) => VoiceLiveTurnLatencyEvent | undefined;
37
+ subscribe: (listener: () => void) => () => void;
38
+ };
@@ -2,6 +2,7 @@ import type { VoiceTurnLatencyReport } from '../turnLatency';
2
2
  export type VoiceTurnLatencyClientOptions = {
3
3
  fetch?: typeof fetch;
4
4
  intervalMs?: number;
5
+ proofPath?: string;
5
6
  };
6
7
  export type VoiceTurnLatencySnapshot = {
7
8
  error: string | null;
@@ -10,10 +11,12 @@ export type VoiceTurnLatencySnapshot = {
10
11
  updatedAt?: number;
11
12
  };
12
13
  export declare const fetchVoiceTurnLatency: (path?: string, options?: Pick<VoiceTurnLatencyClientOptions, "fetch">) => Promise<VoiceTurnLatencyReport>;
14
+ export declare const runVoiceTurnLatencyProof: (path: string, options?: Pick<VoiceTurnLatencyClientOptions, "fetch">) => Promise<unknown>;
13
15
  export declare const createVoiceTurnLatencyStore: (path?: string, options?: VoiceTurnLatencyClientOptions) => {
14
16
  close: () => void;
15
17
  getServerSnapshot: () => VoiceTurnLatencySnapshot;
16
18
  getSnapshot: () => VoiceTurnLatencySnapshot;
17
19
  refresh: () => Promise<VoiceTurnLatencyReport | undefined>;
20
+ runProof: () => Promise<VoiceTurnLatencyReport | undefined>;
18
21
  subscribe: (listener: () => void) => () => void;
19
22
  };
@@ -12,6 +12,8 @@ export type VoiceTurnLatencyViewModel = {
12
12
  error: string | null;
13
13
  isLoading: boolean;
14
14
  label: string;
15
+ proofLabel?: string;
16
+ showProofAction: boolean;
15
17
  status: 'empty' | 'error' | 'loading' | 'ready' | 'warning';
16
18
  title: string;
17
19
  turns: VoiceTurnLatencyCardView[];
@@ -19,6 +21,7 @@ export type VoiceTurnLatencyViewModel = {
19
21
  };
20
22
  export type VoiceTurnLatencyWidgetOptions = VoiceTurnLatencyClientOptions & {
21
23
  description?: string;
24
+ proofLabel?: string;
22
25
  title?: string;
23
26
  };
24
27
  export declare const createVoiceTurnLatencyViewModel: (snapshot: VoiceTurnLatencySnapshot, options?: VoiceTurnLatencyWidgetOptions) => VoiceTurnLatencyViewModel;
@@ -1771,6 +1771,14 @@ var fetchVoiceTurnLatency = async (path = "/api/turn-latency", options = {}) =>
1771
1771
  }
1772
1772
  return await response.json();
1773
1773
  };
1774
+ var runVoiceTurnLatencyProof = async (path, options = {}) => {
1775
+ const fetchImpl = options.fetch ?? globalThis.fetch;
1776
+ const response = await fetchImpl(path, { method: "POST" });
1777
+ if (!response.ok) {
1778
+ throw new Error(`Voice turn latency proof failed: HTTP ${response.status}`);
1779
+ }
1780
+ return response.json();
1781
+ };
1774
1782
  var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) => {
1775
1783
  const listeners = new Set;
1776
1784
  let closed = false;
@@ -1810,6 +1818,25 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
1810
1818
  throw error;
1811
1819
  }
1812
1820
  };
1821
+ const runProof = async () => {
1822
+ if (!options.proofPath) {
1823
+ throw new Error("Voice turn latency proof path is not configured.");
1824
+ }
1825
+ snapshot = { ...snapshot, error: null, isLoading: true };
1826
+ emit();
1827
+ try {
1828
+ await runVoiceTurnLatencyProof(options.proofPath, options);
1829
+ return await refresh();
1830
+ } catch (error) {
1831
+ snapshot = {
1832
+ ...snapshot,
1833
+ error: error instanceof Error ? error.message : String(error),
1834
+ isLoading: false
1835
+ };
1836
+ emit();
1837
+ throw error;
1838
+ }
1839
+ };
1813
1840
  const close = () => {
1814
1841
  closed = true;
1815
1842
  if (timer) {
@@ -1828,6 +1855,7 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
1828
1855
  getServerSnapshot: () => snapshot,
1829
1856
  getSnapshot: () => snapshot,
1830
1857
  refresh,
1858
+ runProof,
1831
1859
  subscribe: (listener) => {
1832
1860
  listeners.add(listener);
1833
1861
  return () => {
@@ -1850,13 +1878,15 @@ var useVoiceTurnLatency = (path = "/api/turn-latency", options = {}) => {
1850
1878
  }, [store]);
1851
1879
  return {
1852
1880
  ...useSyncExternalStore7(store.subscribe, store.getSnapshot, store.getServerSnapshot),
1853
- refresh: store.refresh
1881
+ refresh: store.refresh,
1882
+ runProof: store.runProof
1854
1883
  };
1855
1884
  };
1856
1885
 
1857
1886
  // src/client/turnLatencyWidget.ts
1858
1887
  var DEFAULT_TITLE6 = "Turn Latency";
1859
1888
  var DEFAULT_DESCRIPTION6 = "Per-turn timing from first transcript to commit and assistant response start.";
1889
+ var DEFAULT_PROOF_LABEL = "Run latency proof";
1860
1890
  var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1861
1891
  var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
1862
1892
  var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
@@ -1875,6 +1905,8 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
1875
1905
  error: snapshot.error,
1876
1906
  isLoading: snapshot.isLoading,
1877
1907
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} slow` : warningCount > 0 ? `${warningCount} warnings` : `avg ${formatMs2(snapshot.report?.averageTotalMs)}` : snapshot.isLoading ? "Checking" : "No turns",
1908
+ proofLabel: options.proofPath ? options.proofLabel ?? DEFAULT_PROOF_LABEL : undefined,
1909
+ showProofAction: Boolean(options.proofPath),
1878
1910
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
1879
1911
  title: options.title ?? DEFAULT_TITLE6,
1880
1912
  turns,
@@ -1899,6 +1931,7 @@ var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
1899
1931
  <strong class="absolute-voice-turn-latency__label">${escapeHtml7(model.label)}</strong>
1900
1932
  </header>
1901
1933
  <p class="absolute-voice-turn-latency__description">${escapeHtml7(model.description)}</p>
1934
+ ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml7(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
1902
1935
  ${turns}
1903
1936
  ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml7(model.error)}</p>` : ""}
1904
1937
  </section>`;
@@ -1908,11 +1941,19 @@ var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {})
1908
1941
  const render = () => {
1909
1942
  element.innerHTML = renderVoiceTurnLatencyHTML(store.getSnapshot(), options);
1910
1943
  };
1944
+ const handleClick = (event) => {
1945
+ const target = event.target;
1946
+ if (target instanceof Element && target.closest("[data-absolute-voice-turn-latency-proof]")) {
1947
+ store.runProof().catch(() => {});
1948
+ }
1949
+ };
1911
1950
  const unsubscribe = store.subscribe(render);
1951
+ element.addEventListener("click", handleClick);
1912
1952
  render();
1913
1953
  store.refresh().catch(() => {});
1914
1954
  return {
1915
1955
  close: () => {
1956
+ element.removeEventListener("click", handleClick);
1916
1957
  unsubscribe();
1917
1958
  store.close();
1918
1959
  },
@@ -1930,6 +1971,8 @@ var defineVoiceTurnLatencyElement = (tagName = "absolute-voice-turn-latency") =>
1930
1971
  this.mounted = mountVoiceTurnLatency(this, this.getAttribute("path") ?? "/api/turn-latency", {
1931
1972
  description: this.getAttribute("description") ?? undefined,
1932
1973
  intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
1974
+ proofLabel: this.getAttribute("proof-label") ?? undefined,
1975
+ proofPath: this.getAttribute("proof-path") ?? undefined,
1933
1976
  title: this.getAttribute("title") ?? undefined
1934
1977
  });
1935
1978
  }
@@ -1947,8 +1990,8 @@ var VoiceTurnLatency = ({
1947
1990
  path = "/api/turn-latency",
1948
1991
  ...options
1949
1992
  }) => {
1950
- const snapshot = useVoiceTurnLatency(path, options);
1951
- const model = createVoiceTurnLatencyViewModel(snapshot, options);
1993
+ const latency = useVoiceTurnLatency(path, options);
1994
+ const model = createVoiceTurnLatencyViewModel(latency, options);
1952
1995
  return /* @__PURE__ */ jsxDEV7("section", {
1953
1996
  className: [
1954
1997
  "absolute-voice-turn-latency",
@@ -1973,6 +2016,14 @@ var VoiceTurnLatency = ({
1973
2016
  className: "absolute-voice-turn-latency__description",
1974
2017
  children: model.description
1975
2018
  }, undefined, false, undefined, this),
2019
+ model.showProofAction ? /* @__PURE__ */ jsxDEV7("button", {
2020
+ className: "absolute-voice-turn-latency__proof",
2021
+ onClick: () => {
2022
+ latency.runProof().catch(() => {});
2023
+ },
2024
+ type: "button",
2025
+ children: model.proofLabel
2026
+ }, undefined, false, undefined, this) : null,
1976
2027
  model.turns.length ? /* @__PURE__ */ jsxDEV7("div", {
1977
2028
  className: "absolute-voice-turn-latency__turns",
1978
2029
  children: model.turns.map((turn) => /* @__PURE__ */ jsxDEV7("article", {
@@ -1,6 +1,7 @@
1
1
  import { type VoiceTurnLatencyClientOptions } from '../client/turnLatency';
2
2
  export declare const useVoiceTurnLatency: (path?: string, options?: VoiceTurnLatencyClientOptions) => {
3
3
  refresh: () => Promise<import("..").VoiceTurnLatencyReport | undefined>;
4
+ runProof: () => Promise<import("..").VoiceTurnLatencyReport | undefined>;
4
5
  error: string | null;
5
6
  isLoading: boolean;
6
7
  report?: import("..").VoiceTurnLatencyReport;
@@ -6,5 +6,6 @@ export declare const createVoiceTurnLatency: (path?: string, options?: VoiceTurn
6
6
  getServerSnapshot: () => import("../client").VoiceTurnLatencySnapshot;
7
7
  getSnapshot: () => import("../client").VoiceTurnLatencySnapshot;
8
8
  refresh: () => Promise<import("..").VoiceTurnLatencyReport | undefined>;
9
+ runProof: () => Promise<import("..").VoiceTurnLatencyReport | undefined>;
9
10
  subscribe: (listener: () => void) => () => void;
10
11
  };
@@ -1766,6 +1766,14 @@ var fetchVoiceTurnLatency = async (path = "/api/turn-latency", options = {}) =>
1766
1766
  }
1767
1767
  return await response.json();
1768
1768
  };
1769
+ var runVoiceTurnLatencyProof = async (path, options = {}) => {
1770
+ const fetchImpl = options.fetch ?? globalThis.fetch;
1771
+ const response = await fetchImpl(path, { method: "POST" });
1772
+ if (!response.ok) {
1773
+ throw new Error(`Voice turn latency proof failed: HTTP ${response.status}`);
1774
+ }
1775
+ return response.json();
1776
+ };
1769
1777
  var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) => {
1770
1778
  const listeners = new Set;
1771
1779
  let closed = false;
@@ -1805,6 +1813,25 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
1805
1813
  throw error;
1806
1814
  }
1807
1815
  };
1816
+ const runProof = async () => {
1817
+ if (!options.proofPath) {
1818
+ throw new Error("Voice turn latency proof path is not configured.");
1819
+ }
1820
+ snapshot = { ...snapshot, error: null, isLoading: true };
1821
+ emit();
1822
+ try {
1823
+ await runVoiceTurnLatencyProof(options.proofPath, options);
1824
+ return await refresh();
1825
+ } catch (error) {
1826
+ snapshot = {
1827
+ ...snapshot,
1828
+ error: error instanceof Error ? error.message : String(error),
1829
+ isLoading: false
1830
+ };
1831
+ emit();
1832
+ throw error;
1833
+ }
1834
+ };
1808
1835
  const close = () => {
1809
1836
  closed = true;
1810
1837
  if (timer) {
@@ -1823,6 +1850,7 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
1823
1850
  getServerSnapshot: () => snapshot,
1824
1851
  getSnapshot: () => snapshot,
1825
1852
  refresh,
1853
+ runProof,
1826
1854
  subscribe: (listener) => {
1827
1855
  listeners.add(listener);
1828
1856
  return () => {
@@ -1835,6 +1863,7 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
1835
1863
  // src/client/turnLatencyWidget.ts
1836
1864
  var DEFAULT_TITLE6 = "Turn Latency";
1837
1865
  var DEFAULT_DESCRIPTION6 = "Per-turn timing from first transcript to commit and assistant response start.";
1866
+ var DEFAULT_PROOF_LABEL = "Run latency proof";
1838
1867
  var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1839
1868
  var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
1840
1869
  var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
@@ -1853,6 +1882,8 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
1853
1882
  error: snapshot.error,
1854
1883
  isLoading: snapshot.isLoading,
1855
1884
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} slow` : warningCount > 0 ? `${warningCount} warnings` : `avg ${formatMs2(snapshot.report?.averageTotalMs)}` : snapshot.isLoading ? "Checking" : "No turns",
1885
+ proofLabel: options.proofPath ? options.proofLabel ?? DEFAULT_PROOF_LABEL : undefined,
1886
+ showProofAction: Boolean(options.proofPath),
1856
1887
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
1857
1888
  title: options.title ?? DEFAULT_TITLE6,
1858
1889
  turns,
@@ -1877,6 +1908,7 @@ var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
1877
1908
  <strong class="absolute-voice-turn-latency__label">${escapeHtml7(model.label)}</strong>
1878
1909
  </header>
1879
1910
  <p class="absolute-voice-turn-latency__description">${escapeHtml7(model.description)}</p>
1911
+ ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml7(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
1880
1912
  ${turns}
1881
1913
  ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml7(model.error)}</p>` : ""}
1882
1914
  </section>`;
@@ -1886,11 +1918,19 @@ var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {})
1886
1918
  const render = () => {
1887
1919
  element.innerHTML = renderVoiceTurnLatencyHTML(store.getSnapshot(), options);
1888
1920
  };
1921
+ const handleClick = (event) => {
1922
+ const target = event.target;
1923
+ if (target instanceof Element && target.closest("[data-absolute-voice-turn-latency-proof]")) {
1924
+ store.runProof().catch(() => {});
1925
+ }
1926
+ };
1889
1927
  const unsubscribe = store.subscribe(render);
1928
+ element.addEventListener("click", handleClick);
1890
1929
  render();
1891
1930
  store.refresh().catch(() => {});
1892
1931
  return {
1893
1932
  close: () => {
1933
+ element.removeEventListener("click", handleClick);
1894
1934
  unsubscribe();
1895
1935
  store.close();
1896
1936
  },
@@ -1908,6 +1948,8 @@ var defineVoiceTurnLatencyElement = (tagName = "absolute-voice-turn-latency") =>
1908
1948
  this.mounted = mountVoiceTurnLatency(this, this.getAttribute("path") ?? "/api/turn-latency", {
1909
1949
  description: this.getAttribute("description") ?? undefined,
1910
1950
  intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
1951
+ proofLabel: this.getAttribute("proof-label") ?? undefined,
1952
+ proofPath: this.getAttribute("proof-path") ?? undefined,
1911
1953
  title: this.getAttribute("title") ?? undefined
1912
1954
  });
1913
1955
  }
@@ -15,6 +15,14 @@ export declare const VoiceTurnLatency: import("vue").DefineComponent<import("vue
15
15
  default: string;
16
16
  type: StringConstructor;
17
17
  };
18
+ proofLabel: {
19
+ default: undefined;
20
+ type: StringConstructor;
21
+ };
22
+ proofPath: {
23
+ default: undefined;
24
+ type: StringConstructor;
25
+ };
18
26
  title: {
19
27
  default: undefined;
20
28
  type: StringConstructor;
@@ -38,6 +46,14 @@ export declare const VoiceTurnLatency: import("vue").DefineComponent<import("vue
38
46
  default: string;
39
47
  type: StringConstructor;
40
48
  };
49
+ proofLabel: {
50
+ default: undefined;
51
+ type: StringConstructor;
52
+ };
53
+ proofPath: {
54
+ default: undefined;
55
+ type: StringConstructor;
56
+ };
41
57
  title: {
42
58
  default: undefined;
43
59
  type: StringConstructor;
@@ -47,5 +63,7 @@ export declare const VoiceTurnLatency: import("vue").DefineComponent<import("vue
47
63
  title: string;
48
64
  path: string;
49
65
  intervalMs: number;
66
+ proofPath: string;
67
+ proofLabel: string;
50
68
  class: string;
51
69
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
package/dist/vue/index.js CHANGED
@@ -1543,6 +1543,14 @@ var fetchVoiceTurnLatency = async (path = "/api/turn-latency", options = {}) =>
1543
1543
  }
1544
1544
  return await response.json();
1545
1545
  };
1546
+ var runVoiceTurnLatencyProof = async (path, options = {}) => {
1547
+ const fetchImpl = options.fetch ?? globalThis.fetch;
1548
+ const response = await fetchImpl(path, { method: "POST" });
1549
+ if (!response.ok) {
1550
+ throw new Error(`Voice turn latency proof failed: HTTP ${response.status}`);
1551
+ }
1552
+ return response.json();
1553
+ };
1546
1554
  var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) => {
1547
1555
  const listeners = new Set;
1548
1556
  let closed = false;
@@ -1582,6 +1590,25 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
1582
1590
  throw error;
1583
1591
  }
1584
1592
  };
1593
+ const runProof = async () => {
1594
+ if (!options.proofPath) {
1595
+ throw new Error("Voice turn latency proof path is not configured.");
1596
+ }
1597
+ snapshot = { ...snapshot, error: null, isLoading: true };
1598
+ emit();
1599
+ try {
1600
+ await runVoiceTurnLatencyProof(options.proofPath, options);
1601
+ return await refresh();
1602
+ } catch (error) {
1603
+ snapshot = {
1604
+ ...snapshot,
1605
+ error: error instanceof Error ? error.message : String(error),
1606
+ isLoading: false
1607
+ };
1608
+ emit();
1609
+ throw error;
1610
+ }
1611
+ };
1585
1612
  const close = () => {
1586
1613
  closed = true;
1587
1614
  if (timer) {
@@ -1600,6 +1627,7 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
1600
1627
  getServerSnapshot: () => snapshot,
1601
1628
  getSnapshot: () => snapshot,
1602
1629
  refresh,
1630
+ runProof,
1603
1631
  subscribe: (listener) => {
1604
1632
  listeners.add(listener);
1605
1633
  return () => {
@@ -1612,6 +1640,7 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
1612
1640
  // src/client/turnLatencyWidget.ts
1613
1641
  var DEFAULT_TITLE5 = "Turn Latency";
1614
1642
  var DEFAULT_DESCRIPTION5 = "Per-turn timing from first transcript to commit and assistant response start.";
1643
+ var DEFAULT_PROOF_LABEL = "Run latency proof";
1615
1644
  var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1616
1645
  var formatMs = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
1617
1646
  var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
@@ -1630,6 +1659,8 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
1630
1659
  error: snapshot.error,
1631
1660
  isLoading: snapshot.isLoading,
1632
1661
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} slow` : warningCount > 0 ? `${warningCount} warnings` : `avg ${formatMs(snapshot.report?.averageTotalMs)}` : snapshot.isLoading ? "Checking" : "No turns",
1662
+ proofLabel: options.proofPath ? options.proofLabel ?? DEFAULT_PROOF_LABEL : undefined,
1663
+ showProofAction: Boolean(options.proofPath),
1633
1664
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
1634
1665
  title: options.title ?? DEFAULT_TITLE5,
1635
1666
  turns,
@@ -1654,6 +1685,7 @@ var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
1654
1685
  <strong class="absolute-voice-turn-latency__label">${escapeHtml6(model.label)}</strong>
1655
1686
  </header>
1656
1687
  <p class="absolute-voice-turn-latency__description">${escapeHtml6(model.description)}</p>
1688
+ ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml6(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
1657
1689
  ${turns}
1658
1690
  ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml6(model.error)}</p>` : ""}
1659
1691
  </section>`;
@@ -1663,11 +1695,19 @@ var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {})
1663
1695
  const render = () => {
1664
1696
  element.innerHTML = renderVoiceTurnLatencyHTML(store.getSnapshot(), options);
1665
1697
  };
1698
+ const handleClick = (event) => {
1699
+ const target = event.target;
1700
+ if (target instanceof Element && target.closest("[data-absolute-voice-turn-latency-proof]")) {
1701
+ store.runProof().catch(() => {});
1702
+ }
1703
+ };
1666
1704
  const unsubscribe = store.subscribe(render);
1705
+ element.addEventListener("click", handleClick);
1667
1706
  render();
1668
1707
  store.refresh().catch(() => {});
1669
1708
  return {
1670
1709
  close: () => {
1710
+ element.removeEventListener("click", handleClick);
1671
1711
  unsubscribe();
1672
1712
  store.close();
1673
1713
  },
@@ -1685,6 +1725,8 @@ var defineVoiceTurnLatencyElement = (tagName = "absolute-voice-turn-latency") =>
1685
1725
  this.mounted = mountVoiceTurnLatency(this, this.getAttribute("path") ?? "/api/turn-latency", {
1686
1726
  description: this.getAttribute("description") ?? undefined,
1687
1727
  intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
1728
+ proofLabel: this.getAttribute("proof-label") ?? undefined,
1729
+ proofPath: this.getAttribute("proof-path") ?? undefined,
1688
1730
  title: this.getAttribute("title") ?? undefined
1689
1731
  });
1690
1732
  }
@@ -1717,7 +1759,14 @@ var useVoiceTurnLatency = (path = "/api/turn-latency", options = {}) => {
1717
1759
  unsubscribe();
1718
1760
  store.close();
1719
1761
  });
1720
- return { error, isLoading, refresh: store.refresh, report, updatedAt };
1762
+ return {
1763
+ error,
1764
+ isLoading,
1765
+ refresh: store.refresh,
1766
+ report,
1767
+ runProof: store.runProof,
1768
+ updatedAt
1769
+ };
1721
1770
  };
1722
1771
 
1723
1772
  // src/vue/VoiceTurnLatency.ts
@@ -1728,12 +1777,16 @@ var VoiceTurnLatency = defineComponent6({
1728
1777
  description: { default: undefined, type: String },
1729
1778
  intervalMs: { default: 5000, type: Number },
1730
1779
  path: { default: "/api/turn-latency", type: String },
1780
+ proofLabel: { default: undefined, type: String },
1781
+ proofPath: { default: undefined, type: String },
1731
1782
  title: { default: undefined, type: String }
1732
1783
  },
1733
1784
  setup(props) {
1734
1785
  const options = {
1735
1786
  description: props.description,
1736
1787
  intervalMs: props.intervalMs,
1788
+ proofLabel: props.proofLabel,
1789
+ proofPath: props.proofPath,
1737
1790
  title: props.title
1738
1791
  };
1739
1792
  const latency = useVoiceTurnLatency(props.path, options);
@@ -1755,6 +1808,13 @@ var VoiceTurnLatency = defineComponent6({
1755
1808
  h6("strong", { class: "absolute-voice-turn-latency__label" }, model.value.label)
1756
1809
  ]),
1757
1810
  h6("p", { class: "absolute-voice-turn-latency__description" }, model.value.description),
1811
+ model.value.showProofAction ? h6("button", {
1812
+ class: "absolute-voice-turn-latency__proof",
1813
+ onClick: () => {
1814
+ latency.runProof().catch(() => {});
1815
+ },
1816
+ type: "button"
1817
+ }, model.value.proofLabel) : null,
1758
1818
  model.value.turns.length ? h6("div", { class: "absolute-voice-turn-latency__turns" }, model.value.turns.map((turn) => h6("article", {
1759
1819
  class: [
1760
1820
  "absolute-voice-turn-latency__turn",
@@ -5,5 +5,6 @@ export declare const useVoiceTurnLatency: (path?: string, options?: VoiceTurnLat
5
5
  isLoading: import("vue").ShallowRef<boolean, boolean>;
6
6
  refresh: () => Promise<VoiceTurnLatencyReport | undefined>;
7
7
  report: import("vue").ShallowRef<VoiceTurnLatencyReport | undefined, VoiceTurnLatencyReport | undefined>;
8
+ runProof: () => Promise<VoiceTurnLatencyReport | undefined>;
8
9
  updatedAt: import("vue").ShallowRef<number | undefined, number | undefined>;
9
10
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.97",
3
+ "version": "0.0.22-beta.99",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",