@absolutejs/voice 0.0.22-beta.351 → 0.0.22-beta.353

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.
@@ -0,0 +1,8 @@
1
+ import { type VoiceProfileComparisonClientOptions } from '../client/profileComparison';
2
+ export declare const useVoiceProfileComparison: (path?: string, options?: VoiceProfileComparisonClientOptions) => {
3
+ refresh: () => Promise<import("..").VoiceRealCallProfileHistoryReport | undefined>;
4
+ error: string | null;
5
+ isLoading: boolean;
6
+ report?: import("..").VoiceRealCallProfileHistoryReport;
7
+ updatedAt?: number;
8
+ };
@@ -0,0 +1,7 @@
1
+ import type { VoiceProfileComparisonClientOptions } from '../client/profileComparison';
2
+ export declare const createVoiceProfileComparison: (path?: string, options?: VoiceProfileComparisonClientOptions) => {
3
+ close: () => void;
4
+ getSnapshot: () => import("../client").VoiceProfileComparisonSnapshot;
5
+ refresh: () => Promise<import("..").VoiceRealCallProfileHistoryReport | undefined>;
6
+ subscribe: (listener: () => void) => () => void;
7
+ };
@@ -5,6 +5,7 @@ export { createVoiceLiveOps } from './createVoiceLiveOps';
5
5
  export { createVoiceOpsStatus } from './createVoiceOpsStatus';
6
6
  export { createVoicePlatformCoverage } from './createVoicePlatformCoverage';
7
7
  export { createVoiceProofTrends } from './createVoiceProofTrends';
8
+ export { createVoiceProfileComparison } from './createVoiceProfileComparison';
8
9
  export { createVoiceReadinessFailures } from './createVoiceReadinessFailures';
9
10
  export { createVoiceProviderSimulationControls } from './createVoiceProviderSimulationControls';
10
11
  export { createVoiceProviderCapabilities } from './createVoiceProviderCapabilities';
@@ -2588,6 +2588,91 @@ var createVoiceProofTrends = (path = "/api/voice/proof-trends", options = {}) =>
2588
2588
  subscribe: store.subscribe
2589
2589
  };
2590
2590
  };
2591
+ // src/client/profileComparison.ts
2592
+ var fetchVoiceProfileComparison = async (path = "/api/voice/real-call-profile-history", options = {}) => {
2593
+ const fetchImpl = options.fetch ?? globalThis.fetch;
2594
+ const response = await fetchImpl(path);
2595
+ if (!response.ok) {
2596
+ throw new Error(`Voice profile comparison failed: HTTP ${response.status}`);
2597
+ }
2598
+ return await response.json();
2599
+ };
2600
+ var createVoiceProfileComparisonStore = (path = "/api/voice/real-call-profile-history", options = {}) => {
2601
+ const listeners = new Set;
2602
+ let closed = false;
2603
+ let timer;
2604
+ let snapshot = {
2605
+ error: null,
2606
+ isLoading: false
2607
+ };
2608
+ const emit = () => {
2609
+ for (const listener of listeners) {
2610
+ listener();
2611
+ }
2612
+ };
2613
+ const refresh = async () => {
2614
+ if (closed) {
2615
+ return snapshot.report;
2616
+ }
2617
+ snapshot = { ...snapshot, error: null, isLoading: true };
2618
+ emit();
2619
+ try {
2620
+ const report = await fetchVoiceProfileComparison(path, options);
2621
+ snapshot = {
2622
+ error: null,
2623
+ isLoading: false,
2624
+ report,
2625
+ updatedAt: Date.now()
2626
+ };
2627
+ emit();
2628
+ return report;
2629
+ } catch (error) {
2630
+ snapshot = {
2631
+ ...snapshot,
2632
+ error: error instanceof Error ? error.message : String(error),
2633
+ isLoading: false
2634
+ };
2635
+ emit();
2636
+ throw error;
2637
+ }
2638
+ };
2639
+ const close = () => {
2640
+ closed = true;
2641
+ if (timer) {
2642
+ clearInterval(timer);
2643
+ timer = undefined;
2644
+ }
2645
+ listeners.clear();
2646
+ };
2647
+ if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
2648
+ timer = setInterval(() => {
2649
+ refresh().catch(() => {});
2650
+ }, options.intervalMs);
2651
+ }
2652
+ return {
2653
+ close,
2654
+ getServerSnapshot: () => snapshot,
2655
+ getSnapshot: () => snapshot,
2656
+ refresh,
2657
+ subscribe: (listener) => {
2658
+ listeners.add(listener);
2659
+ return () => {
2660
+ listeners.delete(listener);
2661
+ };
2662
+ }
2663
+ };
2664
+ };
2665
+
2666
+ // src/svelte/createVoiceProfileComparison.ts
2667
+ var createVoiceProfileComparison = (path = "/api/voice/real-call-profile-history", options = {}) => {
2668
+ const store = createVoiceProfileComparisonStore(path, options);
2669
+ return {
2670
+ close: store.close,
2671
+ getSnapshot: store.getSnapshot,
2672
+ refresh: store.refresh,
2673
+ subscribe: store.subscribe
2674
+ };
2675
+ };
2591
2676
  // src/client/readinessFailures.ts
2592
2677
  var fetchVoiceReadinessFailures = async (path = "/api/production-readiness", options = {}) => {
2593
2678
  const fetchImpl = options.fetch ?? globalThis.fetch;
@@ -4932,8 +5017,43 @@ var DEFAULT_DESCRIPTION7 = "Latest provider routing decision from the self-hoste
4932
5017
  var escapeHtml10 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
4933
5018
  var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
4934
5019
  var formatProviderRoutes = (routes) => routes && typeof routes === "object" ? Object.entries(routes).map(([role, provider]) => `${role}: ${formatValue(provider)}`).join(", ") || "None" : "None";
5020
+ var getProviderRoute = (routes, role) => routes && typeof routes === "object" ? formatValue(routes[role], "Not configured") : "Not configured";
5021
+ var formatFallbackPath = (decision) => {
5022
+ const provider = formatValue(decision.provider, "Unknown");
5023
+ const selectedProvider = formatValue(decision.selectedProvider, provider);
5024
+ const fallbackProvider = formatValue(decision.fallbackProvider, "");
5025
+ if (fallbackProvider !== "None" && fallbackProvider.trim()) {
5026
+ return `${provider} -> ${fallbackProvider}`;
5027
+ }
5028
+ if (selectedProvider !== provider) {
5029
+ return `${provider} -> ${selectedProvider}`;
5030
+ }
5031
+ return `${provider} primary`;
5032
+ };
4935
5033
  var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
4936
5034
  const decision = snapshot.decision;
5035
+ const activeStack = decision ? [
5036
+ {
5037
+ label: "Profile",
5038
+ value: formatValue(decision.profileLabel ?? decision.profileId)
5039
+ },
5040
+ {
5041
+ label: "LLM",
5042
+ value: getProviderRoute(decision.providerRoutes, "llm")
5043
+ },
5044
+ {
5045
+ label: "STT",
5046
+ value: getProviderRoute(decision.providerRoutes, "stt")
5047
+ },
5048
+ {
5049
+ label: "TTS",
5050
+ value: getProviderRoute(decision.providerRoutes, "tts")
5051
+ },
5052
+ {
5053
+ label: "Fallback path",
5054
+ value: formatFallbackPath(decision)
5055
+ }
5056
+ ] : [];
4937
5057
  const rows = decision ? [
4938
5058
  { label: "Kind", value: decision.kind.toUpperCase() },
4939
5059
  { label: "Policy", value: formatValue(decision.routing, "Unknown") },
@@ -4961,6 +5081,7 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
4961
5081
  }
4962
5082
  ] : [];
4963
5083
  return {
5084
+ activeStack,
4964
5085
  decision,
4965
5086
  description: options.description ?? DEFAULT_DESCRIPTION7,
4966
5087
  error: snapshot.error,
@@ -4974,6 +5095,10 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
4974
5095
  };
4975
5096
  var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
4976
5097
  const model = createVoiceRoutingStatusViewModel(snapshot, options);
5098
+ const activeStack = model.activeStack.length ? `<div class="absolute-voice-routing-status__stack" aria-label="Active voice stack">${model.activeStack.map((item) => `<div>
5099
+ <span>${escapeHtml10(item.label)}</span>
5100
+ <strong>${escapeHtml10(item.value)}</strong>
5101
+ </div>`).join("")}</div>` : "";
4977
5102
  const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
4978
5103
  <span>${escapeHtml10(row.label)}</span>
4979
5104
  <strong>${escapeHtml10(row.value)}</strong>
@@ -4984,11 +5109,12 @@ var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
4984
5109
  <strong class="absolute-voice-routing-status__label">${escapeHtml10(model.label)}</strong>
4985
5110
  </header>
4986
5111
  <p class="absolute-voice-routing-status__description">${escapeHtml10(model.description)}</p>
5112
+ ${activeStack}
4987
5113
  ${rows}
4988
5114
  ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml10(model.error)}</p>` : ""}
4989
5115
  </section>`;
4990
5116
  };
4991
- var getVoiceRoutingStatusCSS = () => `.absolute-voice-routing-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-routing-status--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-routing-status__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-routing-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-routing-status__label{font-size:24px;line-height:1}.absolute-voice-routing-status__description{color:#514733;margin:12px 0 0}.absolute-voice-routing-status__grid{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin-top:14px}.absolute-voice-routing-status__grid div{background:#fff;border:1px solid #eee4d2;border-radius:14px;padding:10px 12px}.absolute-voice-routing-status__grid span{color:#655944;display:block;font-size:12px;margin-bottom:4px}.absolute-voice-routing-status__grid strong{overflow-wrap:anywhere}.absolute-voice-routing-status__empty{color:#655944;margin:14px 0 0}.absolute-voice-routing-status__error{color:#9f1239;font-weight:700}`;
5117
+ var getVoiceRoutingStatusCSS = () => `.absolute-voice-routing-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-routing-status--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-routing-status__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-routing-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-routing-status__label{font-size:24px;line-height:1}.absolute-voice-routing-status__description{color:#514733;margin:12px 0 0}.absolute-voice-routing-status__stack{background:linear-gradient(135deg,#16130d,#49391f);border-radius:18px;color:#fff;display:grid;gap:8px;grid-template-columns:repeat(5,minmax(0,1fr));margin-top:14px;padding:12px}.absolute-voice-routing-status__stack div{border-left:1px solid rgba(255,255,255,.18);padding-left:10px}.absolute-voice-routing-status__stack div:first-child{border-left:0;padding-left:0}.absolute-voice-routing-status__stack span{color:#e9d9b8;display:block;font-size:11px;font-weight:800;letter-spacing:.08em;margin-bottom:5px;text-transform:uppercase}.absolute-voice-routing-status__stack strong{display:block;font-size:13px;line-height:1.25;overflow-wrap:anywhere}.absolute-voice-routing-status__grid{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin-top:14px}.absolute-voice-routing-status__grid div{background:#fff;border:1px solid #eee4d2;border-radius:14px;padding:10px 12px}.absolute-voice-routing-status__grid span{color:#655944;display:block;font-size:12px;margin-bottom:4px}.absolute-voice-routing-status__grid strong{overflow-wrap:anywhere}.absolute-voice-routing-status__empty{color:#655944;margin:14px 0 0}.absolute-voice-routing-status__error{color:#9f1239;font-weight:700}@media (max-width:760px){.absolute-voice-routing-status__stack{grid-template-columns:repeat(2,minmax(0,1fr))}.absolute-voice-routing-status__stack div{border-left:0;border-top:1px solid rgba(255,255,255,.18);padding-left:0;padding-top:8px}.absolute-voice-routing-status__stack div:first-child{border-top:0;padding-top:0}}`;
4992
5118
  var mountVoiceRoutingStatus = (element, path = "/api/routing/latest", options = {}) => {
4993
5119
  const store = createVoiceRoutingStatusStore(path, options);
4994
5120
  const render = () => {
@@ -6546,6 +6672,7 @@ export {
6546
6672
  createVoiceProviderContracts,
6547
6673
  createVoiceProviderCapabilities,
6548
6674
  createVoiceProofTrends,
6675
+ createVoiceProfileComparison,
6549
6676
  createVoicePlatformCoverage,
6550
6677
  createVoiceOpsStatus,
6551
6678
  createVoiceOpsActionCenter,
@@ -15,6 +15,7 @@ export { VoiceTurnQuality } from './VoiceTurnQuality';
15
15
  export { useVoiceOpsStatus } from './useVoiceOpsStatus';
16
16
  export { useVoicePlatformCoverage } from './useVoicePlatformCoverage';
17
17
  export { useVoiceProofTrends } from './useVoiceProofTrends';
18
+ export { useVoiceProfileComparison } from './useVoiceProfileComparison';
18
19
  export { useVoiceReadinessFailures } from './useVoiceReadinessFailures';
19
20
  export { useVoiceOpsActionCenter } from './useVoiceOpsActionCenter';
20
21
  export { useVoiceLiveOps } from './useVoiceLiveOps';
package/dist/vue/index.js CHANGED
@@ -4280,8 +4280,43 @@ var DEFAULT_DESCRIPTION10 = "Latest provider routing decision from the self-host
4280
4280
  var escapeHtml12 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
4281
4281
  var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
4282
4282
  var formatProviderRoutes = (routes) => routes && typeof routes === "object" ? Object.entries(routes).map(([role, provider]) => `${role}: ${formatValue(provider)}`).join(", ") || "None" : "None";
4283
+ var getProviderRoute = (routes, role) => routes && typeof routes === "object" ? formatValue(routes[role], "Not configured") : "Not configured";
4284
+ var formatFallbackPath = (decision) => {
4285
+ const provider = formatValue(decision.provider, "Unknown");
4286
+ const selectedProvider = formatValue(decision.selectedProvider, provider);
4287
+ const fallbackProvider = formatValue(decision.fallbackProvider, "");
4288
+ if (fallbackProvider !== "None" && fallbackProvider.trim()) {
4289
+ return `${provider} -> ${fallbackProvider}`;
4290
+ }
4291
+ if (selectedProvider !== provider) {
4292
+ return `${provider} -> ${selectedProvider}`;
4293
+ }
4294
+ return `${provider} primary`;
4295
+ };
4283
4296
  var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
4284
4297
  const decision = snapshot.decision;
4298
+ const activeStack = decision ? [
4299
+ {
4300
+ label: "Profile",
4301
+ value: formatValue(decision.profileLabel ?? decision.profileId)
4302
+ },
4303
+ {
4304
+ label: "LLM",
4305
+ value: getProviderRoute(decision.providerRoutes, "llm")
4306
+ },
4307
+ {
4308
+ label: "STT",
4309
+ value: getProviderRoute(decision.providerRoutes, "stt")
4310
+ },
4311
+ {
4312
+ label: "TTS",
4313
+ value: getProviderRoute(decision.providerRoutes, "tts")
4314
+ },
4315
+ {
4316
+ label: "Fallback path",
4317
+ value: formatFallbackPath(decision)
4318
+ }
4319
+ ] : [];
4285
4320
  const rows = decision ? [
4286
4321
  { label: "Kind", value: decision.kind.toUpperCase() },
4287
4322
  { label: "Policy", value: formatValue(decision.routing, "Unknown") },
@@ -4309,6 +4344,7 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
4309
4344
  }
4310
4345
  ] : [];
4311
4346
  return {
4347
+ activeStack,
4312
4348
  decision,
4313
4349
  description: options.description ?? DEFAULT_DESCRIPTION10,
4314
4350
  error: snapshot.error,
@@ -4322,6 +4358,10 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
4322
4358
  };
4323
4359
  var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
4324
4360
  const model = createVoiceRoutingStatusViewModel(snapshot, options);
4361
+ const activeStack = model.activeStack.length ? `<div class="absolute-voice-routing-status__stack" aria-label="Active voice stack">${model.activeStack.map((item) => `<div>
4362
+ <span>${escapeHtml12(item.label)}</span>
4363
+ <strong>${escapeHtml12(item.value)}</strong>
4364
+ </div>`).join("")}</div>` : "";
4325
4365
  const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
4326
4366
  <span>${escapeHtml12(row.label)}</span>
4327
4367
  <strong>${escapeHtml12(row.value)}</strong>
@@ -4332,11 +4372,12 @@ var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
4332
4372
  <strong class="absolute-voice-routing-status__label">${escapeHtml12(model.label)}</strong>
4333
4373
  </header>
4334
4374
  <p class="absolute-voice-routing-status__description">${escapeHtml12(model.description)}</p>
4375
+ ${activeStack}
4335
4376
  ${rows}
4336
4377
  ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml12(model.error)}</p>` : ""}
4337
4378
  </section>`;
4338
4379
  };
4339
- var getVoiceRoutingStatusCSS = () => `.absolute-voice-routing-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-routing-status--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-routing-status__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-routing-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-routing-status__label{font-size:24px;line-height:1}.absolute-voice-routing-status__description{color:#514733;margin:12px 0 0}.absolute-voice-routing-status__grid{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin-top:14px}.absolute-voice-routing-status__grid div{background:#fff;border:1px solid #eee4d2;border-radius:14px;padding:10px 12px}.absolute-voice-routing-status__grid span{color:#655944;display:block;font-size:12px;margin-bottom:4px}.absolute-voice-routing-status__grid strong{overflow-wrap:anywhere}.absolute-voice-routing-status__empty{color:#655944;margin:14px 0 0}.absolute-voice-routing-status__error{color:#9f1239;font-weight:700}`;
4380
+ var getVoiceRoutingStatusCSS = () => `.absolute-voice-routing-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-routing-status--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-routing-status__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-routing-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-routing-status__label{font-size:24px;line-height:1}.absolute-voice-routing-status__description{color:#514733;margin:12px 0 0}.absolute-voice-routing-status__stack{background:linear-gradient(135deg,#16130d,#49391f);border-radius:18px;color:#fff;display:grid;gap:8px;grid-template-columns:repeat(5,minmax(0,1fr));margin-top:14px;padding:12px}.absolute-voice-routing-status__stack div{border-left:1px solid rgba(255,255,255,.18);padding-left:10px}.absolute-voice-routing-status__stack div:first-child{border-left:0;padding-left:0}.absolute-voice-routing-status__stack span{color:#e9d9b8;display:block;font-size:11px;font-weight:800;letter-spacing:.08em;margin-bottom:5px;text-transform:uppercase}.absolute-voice-routing-status__stack strong{display:block;font-size:13px;line-height:1.25;overflow-wrap:anywhere}.absolute-voice-routing-status__grid{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin-top:14px}.absolute-voice-routing-status__grid div{background:#fff;border:1px solid #eee4d2;border-radius:14px;padding:10px 12px}.absolute-voice-routing-status__grid span{color:#655944;display:block;font-size:12px;margin-bottom:4px}.absolute-voice-routing-status__grid strong{overflow-wrap:anywhere}.absolute-voice-routing-status__empty{color:#655944;margin:14px 0 0}.absolute-voice-routing-status__error{color:#9f1239;font-weight:700}@media (max-width:760px){.absolute-voice-routing-status__stack{grid-template-columns:repeat(2,minmax(0,1fr))}.absolute-voice-routing-status__stack div{border-left:0;border-top:1px solid rgba(255,255,255,.18);padding-left:0;padding-top:8px}.absolute-voice-routing-status__stack div:first-child{border-top:0;padding-top:0}}`;
4340
4381
  var mountVoiceRoutingStatus = (element, path = "/api/routing/latest", options = {}) => {
4341
4382
  const store = createVoiceRoutingStatusStore(path, options);
4342
4383
  const render = () => {
@@ -5233,9 +5274,118 @@ var VoiceTurnQuality = defineComponent13({
5233
5274
  ]);
5234
5275
  }
5235
5276
  });
5236
- // src/vue/useVoiceLiveOps.ts
5277
+ // src/vue/useVoiceProfileComparison.ts
5237
5278
  import { onUnmounted as onUnmounted14, ref as ref11, shallowRef as shallowRef13 } from "vue";
5238
5279
 
5280
+ // src/client/profileComparison.ts
5281
+ var fetchVoiceProfileComparison = async (path = "/api/voice/real-call-profile-history", options = {}) => {
5282
+ const fetchImpl = options.fetch ?? globalThis.fetch;
5283
+ const response = await fetchImpl(path);
5284
+ if (!response.ok) {
5285
+ throw new Error(`Voice profile comparison failed: HTTP ${response.status}`);
5286
+ }
5287
+ return await response.json();
5288
+ };
5289
+ var createVoiceProfileComparisonStore = (path = "/api/voice/real-call-profile-history", options = {}) => {
5290
+ const listeners = new Set;
5291
+ let closed = false;
5292
+ let timer;
5293
+ let snapshot = {
5294
+ error: null,
5295
+ isLoading: false
5296
+ };
5297
+ const emit = () => {
5298
+ for (const listener of listeners) {
5299
+ listener();
5300
+ }
5301
+ };
5302
+ const refresh = async () => {
5303
+ if (closed) {
5304
+ return snapshot.report;
5305
+ }
5306
+ snapshot = { ...snapshot, error: null, isLoading: true };
5307
+ emit();
5308
+ try {
5309
+ const report = await fetchVoiceProfileComparison(path, options);
5310
+ snapshot = {
5311
+ error: null,
5312
+ isLoading: false,
5313
+ report,
5314
+ updatedAt: Date.now()
5315
+ };
5316
+ emit();
5317
+ return report;
5318
+ } catch (error) {
5319
+ snapshot = {
5320
+ ...snapshot,
5321
+ error: error instanceof Error ? error.message : String(error),
5322
+ isLoading: false
5323
+ };
5324
+ emit();
5325
+ throw error;
5326
+ }
5327
+ };
5328
+ const close = () => {
5329
+ closed = true;
5330
+ if (timer) {
5331
+ clearInterval(timer);
5332
+ timer = undefined;
5333
+ }
5334
+ listeners.clear();
5335
+ };
5336
+ if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
5337
+ timer = setInterval(() => {
5338
+ refresh().catch(() => {});
5339
+ }, options.intervalMs);
5340
+ }
5341
+ return {
5342
+ close,
5343
+ getServerSnapshot: () => snapshot,
5344
+ getSnapshot: () => snapshot,
5345
+ refresh,
5346
+ subscribe: (listener) => {
5347
+ listeners.add(listener);
5348
+ return () => {
5349
+ listeners.delete(listener);
5350
+ };
5351
+ }
5352
+ };
5353
+ };
5354
+
5355
+ // src/vue/useVoiceProfileComparison.ts
5356
+ function useVoiceProfileComparison(path = "/api/voice/real-call-profile-history", options = {}) {
5357
+ const store = createVoiceProfileComparisonStore(path, options);
5358
+ const error = ref11(null);
5359
+ const isLoading = ref11(false);
5360
+ const report = shallowRef13(undefined);
5361
+ const updatedAt = ref11(undefined);
5362
+ const sync = () => {
5363
+ const snapshot = store.getSnapshot();
5364
+ error.value = snapshot.error;
5365
+ isLoading.value = snapshot.isLoading;
5366
+ report.value = snapshot.report;
5367
+ updatedAt.value = snapshot.updatedAt;
5368
+ };
5369
+ const unsubscribe = store.subscribe(sync);
5370
+ sync();
5371
+ if (typeof window !== "undefined") {
5372
+ store.refresh().catch(() => {});
5373
+ }
5374
+ onUnmounted14(() => {
5375
+ unsubscribe();
5376
+ store.close();
5377
+ });
5378
+ return {
5379
+ error,
5380
+ isLoading,
5381
+ refresh: store.refresh,
5382
+ report,
5383
+ updatedAt
5384
+ };
5385
+ }
5386
+ // src/vue/useVoiceLiveOps.ts
5387
+ import { onUnmounted as onUnmounted15, ref as ref12, shallowRef as shallowRef14 } from "vue";
5388
+
5239
5389
  // src/client/liveOps.ts
5240
5390
  var postVoiceLiveOpsAction = async (input, options = {}) => {
5241
5391
  if (!input.sessionId) {
@@ -5325,11 +5475,11 @@ var createVoiceLiveOpsStore = (options = {}) => {
5325
5475
  // src/vue/useVoiceLiveOps.ts
5326
5476
  function useVoiceLiveOps(options = {}) {
5327
5477
  const store = createVoiceLiveOpsStore(options);
5328
- const error = ref11(null);
5329
- const isRunning = ref11(false);
5330
- const lastResult = shallowRef13(undefined);
5331
- const runningAction = ref11(undefined);
5332
- const updatedAt = ref11(undefined);
5478
+ const error = ref12(null);
5479
+ const isRunning = ref12(false);
5480
+ const lastResult = shallowRef14(undefined);
5481
+ const runningAction = ref12(undefined);
5482
+ const updatedAt = ref12(undefined);
5333
5483
  const sync = () => {
5334
5484
  const snapshot = store.getSnapshot();
5335
5485
  error.value = snapshot.error;
@@ -5340,7 +5490,7 @@ function useVoiceLiveOps(options = {}) {
5340
5490
  };
5341
5491
  const unsubscribe = store.subscribe(sync);
5342
5492
  sync();
5343
- onUnmounted14(() => {
5493
+ onUnmounted15(() => {
5344
5494
  unsubscribe();
5345
5495
  store.close();
5346
5496
  });
@@ -5354,7 +5504,7 @@ function useVoiceLiveOps(options = {}) {
5354
5504
  };
5355
5505
  }
5356
5506
  // src/vue/useVoiceCampaignDialerProof.ts
5357
- import { onUnmounted as onUnmounted15, shallowRef as shallowRef14 } from "vue";
5507
+ import { onUnmounted as onUnmounted16, shallowRef as shallowRef15 } from "vue";
5358
5508
 
5359
5509
  // src/client/campaignDialerProof.ts
5360
5510
  var fetchVoiceCampaignDialerProofStatus = async (path = "/api/voice/campaigns/dialer-proof", options = {}) => {
@@ -5477,11 +5627,11 @@ var createVoiceCampaignDialerProofStore = (path = "/api/voice/campaigns/dialer-p
5477
5627
  // src/vue/useVoiceCampaignDialerProof.ts
5478
5628
  function useVoiceCampaignDialerProof(path = "/api/voice/campaigns/dialer-proof", options = {}) {
5479
5629
  const store = createVoiceCampaignDialerProofStore(path, options);
5480
- const error = shallowRef14(null);
5481
- const isLoading = shallowRef14(false);
5482
- const report = shallowRef14();
5483
- const status = shallowRef14();
5484
- const updatedAt = shallowRef14(undefined);
5630
+ const error = shallowRef15(null);
5631
+ const isLoading = shallowRef15(false);
5632
+ const report = shallowRef15();
5633
+ const status = shallowRef15();
5634
+ const updatedAt = shallowRef15(undefined);
5485
5635
  const sync = () => {
5486
5636
  const snapshot = store.getSnapshot();
5487
5637
  error.value = snapshot.error;
@@ -5495,7 +5645,7 @@ function useVoiceCampaignDialerProof(path = "/api/voice/campaigns/dialer-proof",
5495
5645
  if (typeof window !== "undefined") {
5496
5646
  store.refresh().catch(() => {});
5497
5647
  }
5498
- onUnmounted15(() => {
5648
+ onUnmounted16(() => {
5499
5649
  unsubscribe();
5500
5650
  store.close();
5501
5651
  });
@@ -5510,7 +5660,7 @@ function useVoiceCampaignDialerProof(path = "/api/voice/campaigns/dialer-proof",
5510
5660
  };
5511
5661
  }
5512
5662
  // src/vue/useVoiceStream.ts
5513
- import { onUnmounted as onUnmounted16, ref as ref12, shallowRef as shallowRef15 } from "vue";
5663
+ import { onUnmounted as onUnmounted17, ref as ref13, shallowRef as shallowRef16 } from "vue";
5514
5664
 
5515
5665
  // src/client/actions.ts
5516
5666
  var normalizeErrorMessage = (value) => {
@@ -6897,16 +7047,16 @@ var createVoiceStream = (path, options = {}) => {
6897
7047
  // src/vue/useVoiceStream.ts
6898
7048
  function useVoiceStream(path, options = {}) {
6899
7049
  const stream = createVoiceStream(path, options);
6900
- const assistantAudio = shallowRef15([]);
6901
- const assistantTexts = shallowRef15([]);
6902
- const call = shallowRef15(null);
6903
- const error = ref12(null);
6904
- const isConnected = ref12(false);
6905
- const partial = ref12("");
6906
- const reconnect = shallowRef15(stream.reconnect);
6907
- const sessionId = ref12(stream.sessionId);
6908
- const status = ref12(stream.status);
6909
- const turns = shallowRef15([]);
7050
+ const assistantAudio = shallowRef16([]);
7051
+ const assistantTexts = shallowRef16([]);
7052
+ const call = shallowRef16(null);
7053
+ const error = ref13(null);
7054
+ const isConnected = ref13(false);
7055
+ const partial = ref13("");
7056
+ const reconnect = shallowRef16(stream.reconnect);
7057
+ const sessionId = ref13(stream.sessionId);
7058
+ const status = ref13(stream.status);
7059
+ const turns = shallowRef16([]);
6910
7060
  const sync = () => {
6911
7061
  assistantAudio.value = [...stream.assistantAudio];
6912
7062
  assistantTexts.value = [...stream.assistantTexts];
@@ -6925,7 +7075,7 @@ function useVoiceStream(path, options = {}) {
6925
7075
  unsubscribe();
6926
7076
  stream.close();
6927
7077
  };
6928
- onUnmounted16(destroy);
7078
+ onUnmounted17(destroy);
6929
7079
  return {
6930
7080
  assistantAudio,
6931
7081
  assistantTexts,
@@ -6944,7 +7094,7 @@ function useVoiceStream(path, options = {}) {
6944
7094
  };
6945
7095
  }
6946
7096
  // src/vue/useVoiceController.ts
6947
- import { onUnmounted as onUnmounted17, ref as ref13, shallowRef as shallowRef16 } from "vue";
7097
+ import { onUnmounted as onUnmounted18, ref as ref14, shallowRef as shallowRef17 } from "vue";
6948
7098
 
6949
7099
  // src/client/htmx.ts
6950
7100
  var DEFAULT_EVENT_NAME = "voice-refresh";
@@ -7590,17 +7740,17 @@ var createVoiceController = (path, options = {}) => {
7590
7740
  // src/vue/useVoiceController.ts
7591
7741
  function useVoiceController(path, options = {}) {
7592
7742
  const controller = createVoiceController(path, options);
7593
- const assistantAudio = shallowRef16([]);
7594
- const assistantTexts = shallowRef16([]);
7595
- const error = ref13(null);
7596
- const isConnected = ref13(false);
7597
- const isRecording = ref13(false);
7598
- const partial = ref13("");
7599
- const reconnect = shallowRef16(controller.reconnect);
7600
- const recordingError = ref13(null);
7601
- const sessionId = ref13(controller.sessionId);
7602
- const status = ref13(controller.status);
7603
- const turns = shallowRef16([]);
7743
+ const assistantAudio = shallowRef17([]);
7744
+ const assistantTexts = shallowRef17([]);
7745
+ const error = ref14(null);
7746
+ const isConnected = ref14(false);
7747
+ const isRecording = ref14(false);
7748
+ const partial = ref14("");
7749
+ const reconnect = shallowRef17(controller.reconnect);
7750
+ const recordingError = ref14(null);
7751
+ const sessionId = ref14(controller.sessionId);
7752
+ const status = ref14(controller.status);
7753
+ const turns = shallowRef17([]);
7604
7754
  const sync = () => {
7605
7755
  assistantAudio.value = [...controller.assistantAudio];
7606
7756
  assistantTexts.value = [...controller.assistantTexts];
@@ -7620,7 +7770,7 @@ function useVoiceController(path, options = {}) {
7620
7770
  unsubscribe();
7621
7771
  controller.close();
7622
7772
  };
7623
- onUnmounted17(destroy);
7773
+ onUnmounted18(destroy);
7624
7774
  return {
7625
7775
  assistantAudio,
7626
7776
  assistantTexts,
@@ -7643,13 +7793,13 @@ function useVoiceController(path, options = {}) {
7643
7793
  };
7644
7794
  }
7645
7795
  // src/vue/useVoiceTraceTimeline.ts
7646
- import { onUnmounted as onUnmounted18, ref as ref14, shallowRef as shallowRef17 } from "vue";
7796
+ import { onUnmounted as onUnmounted19, ref as ref15, shallowRef as shallowRef18 } from "vue";
7647
7797
  function useVoiceTraceTimeline(path = "/api/voice-traces", options = {}) {
7648
7798
  const store = createVoiceTraceTimelineStore(path, options);
7649
- const error = ref14(null);
7650
- const isLoading = ref14(false);
7651
- const report = shallowRef17(null);
7652
- const updatedAt = ref14(undefined);
7799
+ const error = ref15(null);
7800
+ const isLoading = ref15(false);
7801
+ const report = shallowRef18(null);
7802
+ const updatedAt = ref15(undefined);
7653
7803
  const sync = () => {
7654
7804
  const snapshot = store.getSnapshot();
7655
7805
  error.value = snapshot.error;
@@ -7660,7 +7810,7 @@ function useVoiceTraceTimeline(path = "/api/voice-traces", options = {}) {
7660
7810
  const unsubscribe = store.subscribe(sync);
7661
7811
  sync();
7662
7812
  store.refresh().catch(() => {});
7663
- onUnmounted18(() => {
7813
+ onUnmounted19(() => {
7664
7814
  unsubscribe();
7665
7815
  store.close();
7666
7816
  });
@@ -7673,7 +7823,7 @@ function useVoiceTraceTimeline(path = "/api/voice-traces", options = {}) {
7673
7823
  };
7674
7824
  }
7675
7825
  // src/vue/useVoiceWorkflowStatus.ts
7676
- import { onUnmounted as onUnmounted19, ref as ref15, shallowRef as shallowRef18 } from "vue";
7826
+ import { onUnmounted as onUnmounted20, ref as ref16, shallowRef as shallowRef19 } from "vue";
7677
7827
 
7678
7828
  // src/client/workflowStatus.ts
7679
7829
  var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
@@ -7757,10 +7907,10 @@ var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options =
7757
7907
  // src/vue/useVoiceWorkflowStatus.ts
7758
7908
  function useVoiceWorkflowStatus(path = "/evals/scenarios/json", options = {}) {
7759
7909
  const store = createVoiceWorkflowStatusStore(path, options);
7760
- const error = ref15(null);
7761
- const isLoading = ref15(false);
7762
- const report = shallowRef18(undefined);
7763
- const updatedAt = ref15(undefined);
7910
+ const error = ref16(null);
7911
+ const isLoading = ref16(false);
7912
+ const report = shallowRef19(undefined);
7913
+ const updatedAt = ref16(undefined);
7764
7914
  const sync = () => {
7765
7915
  const snapshot = store.getSnapshot();
7766
7916
  error.value = snapshot.error;
@@ -7773,7 +7923,7 @@ function useVoiceWorkflowStatus(path = "/evals/scenarios/json", options = {}) {
7773
7923
  if (typeof window !== "undefined") {
7774
7924
  store.refresh().catch(() => {});
7775
7925
  }
7776
- onUnmounted19(() => {
7926
+ onUnmounted20(() => {
7777
7927
  unsubscribe();
7778
7928
  store.close();
7779
7929
  });
@@ -7798,6 +7948,7 @@ export {
7798
7948
  useVoiceProviderContracts,
7799
7949
  useVoiceProviderCapabilities,
7800
7950
  useVoiceProofTrends,
7951
+ useVoiceProfileComparison,
7801
7952
  useVoicePlatformCoverage,
7802
7953
  useVoiceOpsStatus,
7803
7954
  useVoiceOpsActionCenter,
@@ -0,0 +1,9 @@
1
+ import { type VoiceProfileComparisonClientOptions } from '../client/profileComparison';
2
+ import type { VoiceRealCallProfileHistoryReport } from '../proofTrends';
3
+ export declare function useVoiceProfileComparison(path?: string, options?: VoiceProfileComparisonClientOptions): {
4
+ error: import("vue").Ref<string | null, string | null>;
5
+ isLoading: import("vue").Ref<boolean, boolean>;
6
+ refresh: () => Promise<VoiceRealCallProfileHistoryReport | undefined>;
7
+ report: import("vue").ShallowRef<VoiceRealCallProfileHistoryReport | undefined, VoiceRealCallProfileHistoryReport | undefined>;
8
+ updatedAt: import("vue").Ref<number | undefined, number | undefined>;
9
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.351",
3
+ "version": "0.0.22-beta.353",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",