@absolutejs/voice 0.0.22-beta.167 → 0.0.22-beta.169
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.
- package/dist/angular/index.d.ts +1 -0
- package/dist/angular/index.js +177 -58
- package/dist/angular/voice-provider-contracts.service.d.ts +12 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.js +234 -47
- package/dist/client/providerContracts.d.ts +19 -0
- package/dist/client/providerContractsWidget.d.ts +37 -0
- package/dist/index.js +38 -2
- package/dist/providerStackRecommendations.d.ts +8 -0
- package/dist/react/VoiceProviderContracts.d.ts +6 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.js +494 -195
- package/dist/react/useVoiceProviderContracts.d.ts +8 -0
- package/dist/svelte/createVoiceProviderContracts.d.ts +10 -0
- package/dist/svelte/index.d.ts +1 -0
- package/dist/svelte/index.js +270 -78
- package/dist/vue/VoiceProviderContracts.d.ts +21 -0
- package/dist/vue/index.d.ts +2 -0
- package/dist/vue/index.js +460 -170
- package/dist/vue/useVoiceProviderContracts.d.ts +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type VoiceProviderContractsClientOptions } from '../client/providerContracts';
|
|
2
|
+
export declare const useVoiceProviderContracts: <TProvider extends string = string>(path?: string, options?: VoiceProviderContractsClientOptions) => {
|
|
3
|
+
refresh: () => Promise<import("..").VoiceProviderContractMatrixReport<TProvider> | undefined>;
|
|
4
|
+
error: string | null;
|
|
5
|
+
isLoading: boolean;
|
|
6
|
+
report?: import("..").VoiceProviderContractMatrixReport<TProvider> | undefined;
|
|
7
|
+
updatedAt?: number;
|
|
8
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type VoiceProviderContractsWidgetOptions } from '../client/providerContractsWidget';
|
|
2
|
+
export declare const createVoiceProviderContracts: <TProvider extends string = string>(path?: string, options?: VoiceProviderContractsWidgetOptions) => {
|
|
3
|
+
getHTML: () => string;
|
|
4
|
+
getViewModel: () => import("../client").VoiceProviderContractsViewModel<TProvider>;
|
|
5
|
+
close: () => void;
|
|
6
|
+
getServerSnapshot: () => import("../client").VoiceProviderContractsSnapshot<TProvider>;
|
|
7
|
+
getSnapshot: () => import("../client").VoiceProviderContractsSnapshot<TProvider>;
|
|
8
|
+
refresh: () => Promise<import("..").VoiceProviderContractMatrixReport<TProvider> | undefined>;
|
|
9
|
+
subscribe: (listener: () => void) => () => void;
|
|
10
|
+
};
|
package/dist/svelte/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { createVoiceOpsActionCenter } from './createVoiceOpsActionCenter';
|
|
|
4
4
|
export { createVoiceOpsStatus } from './createVoiceOpsStatus';
|
|
5
5
|
export { createVoiceProviderSimulationControls } from './createVoiceProviderSimulationControls';
|
|
6
6
|
export { createVoiceProviderCapabilities } from './createVoiceProviderCapabilities';
|
|
7
|
+
export { createVoiceProviderContracts } from './createVoiceProviderContracts';
|
|
7
8
|
export { createVoiceStream } from './createVoiceStream';
|
|
8
9
|
export { createVoiceProviderStatus } from './createVoiceProviderStatus';
|
|
9
10
|
export { createVoiceRoutingStatus } from './createVoiceRoutingStatus';
|
package/dist/svelte/index.js
CHANGED
|
@@ -1367,6 +1367,197 @@ var createVoiceProviderCapabilities = (path = "/api/provider-capabilities", opti
|
|
|
1367
1367
|
getViewModel: () => createVoiceProviderCapabilitiesViewModel(store.getSnapshot(), options)
|
|
1368
1368
|
};
|
|
1369
1369
|
};
|
|
1370
|
+
// src/client/providerContracts.ts
|
|
1371
|
+
var fetchVoiceProviderContracts = async (path = "/api/provider-contracts", options = {}) => {
|
|
1372
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
1373
|
+
const response = await fetchImpl(path);
|
|
1374
|
+
if (!response.ok) {
|
|
1375
|
+
throw new Error(`Voice provider contracts failed: HTTP ${response.status}`);
|
|
1376
|
+
}
|
|
1377
|
+
return await response.json();
|
|
1378
|
+
};
|
|
1379
|
+
var createVoiceProviderContractsStore = (path = "/api/provider-contracts", options = {}) => {
|
|
1380
|
+
const listeners = new Set;
|
|
1381
|
+
let closed = false;
|
|
1382
|
+
let timer;
|
|
1383
|
+
let snapshot = {
|
|
1384
|
+
error: null,
|
|
1385
|
+
isLoading: false
|
|
1386
|
+
};
|
|
1387
|
+
const emit = () => {
|
|
1388
|
+
for (const listener of listeners) {
|
|
1389
|
+
listener();
|
|
1390
|
+
}
|
|
1391
|
+
};
|
|
1392
|
+
const refresh = async () => {
|
|
1393
|
+
if (closed) {
|
|
1394
|
+
return snapshot.report;
|
|
1395
|
+
}
|
|
1396
|
+
snapshot = { ...snapshot, error: null, isLoading: true };
|
|
1397
|
+
emit();
|
|
1398
|
+
try {
|
|
1399
|
+
const report = await fetchVoiceProviderContracts(path, options);
|
|
1400
|
+
snapshot = {
|
|
1401
|
+
error: null,
|
|
1402
|
+
isLoading: false,
|
|
1403
|
+
report,
|
|
1404
|
+
updatedAt: Date.now()
|
|
1405
|
+
};
|
|
1406
|
+
emit();
|
|
1407
|
+
return report;
|
|
1408
|
+
} catch (error) {
|
|
1409
|
+
snapshot = {
|
|
1410
|
+
...snapshot,
|
|
1411
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1412
|
+
isLoading: false
|
|
1413
|
+
};
|
|
1414
|
+
emit();
|
|
1415
|
+
throw error;
|
|
1416
|
+
}
|
|
1417
|
+
};
|
|
1418
|
+
const close = () => {
|
|
1419
|
+
closed = true;
|
|
1420
|
+
if (timer) {
|
|
1421
|
+
clearInterval(timer);
|
|
1422
|
+
timer = undefined;
|
|
1423
|
+
}
|
|
1424
|
+
listeners.clear();
|
|
1425
|
+
};
|
|
1426
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
1427
|
+
timer = setInterval(() => {
|
|
1428
|
+
refresh().catch(() => {});
|
|
1429
|
+
}, options.intervalMs);
|
|
1430
|
+
}
|
|
1431
|
+
return {
|
|
1432
|
+
close,
|
|
1433
|
+
getServerSnapshot: () => snapshot,
|
|
1434
|
+
getSnapshot: () => snapshot,
|
|
1435
|
+
refresh,
|
|
1436
|
+
subscribe: (listener) => {
|
|
1437
|
+
listeners.add(listener);
|
|
1438
|
+
return () => {
|
|
1439
|
+
listeners.delete(listener);
|
|
1440
|
+
};
|
|
1441
|
+
}
|
|
1442
|
+
};
|
|
1443
|
+
};
|
|
1444
|
+
|
|
1445
|
+
// src/client/providerContractsWidget.ts
|
|
1446
|
+
var DEFAULT_TITLE5 = "Provider Contracts";
|
|
1447
|
+
var DEFAULT_DESCRIPTION5 = "Production contract coverage for provider env, latency, fallback, streaming, and capabilities.";
|
|
1448
|
+
var escapeHtml6 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
1449
|
+
var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
|
|
1450
|
+
var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
1451
|
+
var contractDetail = (row) => {
|
|
1452
|
+
const failing = row.checks.filter((check) => check.status !== "pass");
|
|
1453
|
+
if (failing.length === 0) {
|
|
1454
|
+
return "Provider contract is production-ready.";
|
|
1455
|
+
}
|
|
1456
|
+
return failing.map((check) => `${check.label}: ${check.detail ?? check.status}`).join(" ");
|
|
1457
|
+
};
|
|
1458
|
+
var createVoiceProviderContractsViewModel = (snapshot, options = {}) => {
|
|
1459
|
+
const rows = (snapshot.report?.rows ?? []).map((row) => ({
|
|
1460
|
+
...row,
|
|
1461
|
+
detail: contractDetail(row),
|
|
1462
|
+
label: `${formatProvider2(row.provider)} ${row.kind.toUpperCase()}`,
|
|
1463
|
+
remediations: row.checks.filter((check) => check.status !== "pass" && check.remediation).map((check) => ({
|
|
1464
|
+
detail: check.remediation?.detail ?? "",
|
|
1465
|
+
href: check.remediation?.href,
|
|
1466
|
+
label: check.remediation?.label ?? check.label
|
|
1467
|
+
})),
|
|
1468
|
+
rows: [
|
|
1469
|
+
{ label: "Status", value: formatStatus2(row.status) },
|
|
1470
|
+
{ label: "Selected", value: row.selected ? "Yes" : "No" },
|
|
1471
|
+
{ label: "Configured", value: row.configured ? "Yes" : "No" },
|
|
1472
|
+
{
|
|
1473
|
+
label: "Checks",
|
|
1474
|
+
value: row.checks.map((check) => `${check.label}: ${formatStatus2(check.status)}`).join(", ")
|
|
1475
|
+
}
|
|
1476
|
+
]
|
|
1477
|
+
}));
|
|
1478
|
+
const warningCount = snapshot.report ? snapshot.report.failed + snapshot.report.warned : rows.filter((row) => row.status !== "pass").length;
|
|
1479
|
+
return {
|
|
1480
|
+
description: options.description ?? DEFAULT_DESCRIPTION5,
|
|
1481
|
+
error: snapshot.error,
|
|
1482
|
+
isLoading: snapshot.isLoading,
|
|
1483
|
+
label: snapshot.error ? "Unavailable" : rows.length ? warningCount > 0 ? `${warningCount} needs attention` : `${rows.length} passing` : snapshot.isLoading ? "Checking" : "No contracts",
|
|
1484
|
+
rows,
|
|
1485
|
+
status: snapshot.error ? "error" : rows.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
1486
|
+
title: options.title ?? DEFAULT_TITLE5,
|
|
1487
|
+
updatedAt: snapshot.updatedAt
|
|
1488
|
+
};
|
|
1489
|
+
};
|
|
1490
|
+
var renderVoiceProviderContractsHTML = (snapshot, options = {}) => {
|
|
1491
|
+
const model = createVoiceProviderContractsViewModel(snapshot, options);
|
|
1492
|
+
const rows = model.rows.length ? `<div class="absolute-voice-provider-contracts__rows">${model.rows.map((row) => `<article class="absolute-voice-provider-contracts__row absolute-voice-provider-contracts__row--${escapeHtml6(row.status)}">
|
|
1493
|
+
<header>
|
|
1494
|
+
<strong>${escapeHtml6(row.label)}</strong>
|
|
1495
|
+
<span>${escapeHtml6(formatStatus2(row.status))}</span>
|
|
1496
|
+
</header>
|
|
1497
|
+
<p>${escapeHtml6(row.detail)}</p>
|
|
1498
|
+
${row.remediations.length ? `<ul class="absolute-voice-provider-contracts__remediations">${row.remediations.map((remediation) => `<li>${remediation.href ? `<a href="${escapeHtml6(remediation.href)}">${escapeHtml6(remediation.label)}</a>` : `<strong>${escapeHtml6(remediation.label)}</strong>`}<span>${escapeHtml6(remediation.detail)}</span></li>`).join("")}</ul>` : ""}
|
|
1499
|
+
<dl>${row.rows.map((item) => `<div>
|
|
1500
|
+
<dt>${escapeHtml6(item.label)}</dt>
|
|
1501
|
+
<dd>${escapeHtml6(item.value)}</dd>
|
|
1502
|
+
</div>`).join("")}</dl>
|
|
1503
|
+
</article>`).join("")}</div>` : '<p class="absolute-voice-provider-contracts__empty">Configure provider contracts to see production coverage.</p>';
|
|
1504
|
+
return `<section class="absolute-voice-provider-contracts absolute-voice-provider-contracts--${escapeHtml6(model.status)}">
|
|
1505
|
+
<header class="absolute-voice-provider-contracts__header">
|
|
1506
|
+
<span class="absolute-voice-provider-contracts__eyebrow">${escapeHtml6(model.title)}</span>
|
|
1507
|
+
<strong class="absolute-voice-provider-contracts__label">${escapeHtml6(model.label)}</strong>
|
|
1508
|
+
</header>
|
|
1509
|
+
<p class="absolute-voice-provider-contracts__description">${escapeHtml6(model.description)}</p>
|
|
1510
|
+
${rows}
|
|
1511
|
+
${model.error ? `<p class="absolute-voice-provider-contracts__error">${escapeHtml6(model.error)}</p>` : ""}
|
|
1512
|
+
</section>`;
|
|
1513
|
+
};
|
|
1514
|
+
var getVoiceProviderContractsCSS = () => `.absolute-voice-provider-contracts{border:1px solid #b8dcc7;border-radius:20px;background:#f7fff9;color:#09140d;padding:18px;box-shadow:0 18px 40px rgba(21,83,45,.12);font-family:inherit}.absolute-voice-provider-contracts--error,.absolute-voice-provider-contracts--warning{border-color:#f2a7a7;background:#fff7f4}.absolute-voice-provider-contracts__header,.absolute-voice-provider-contracts__row header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-contracts__eyebrow{color:#166534;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-contracts__label{font-size:24px;line-height:1}.absolute-voice-provider-contracts__description,.absolute-voice-provider-contracts__row p,.absolute-voice-provider-contracts__row dt,.absolute-voice-provider-contracts__empty{color:#405448}.absolute-voice-provider-contracts__rows{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-contracts__row{background:#fff;border:1px solid #d6eadb;border-radius:16px;padding:14px}.absolute-voice-provider-contracts__row--pass{border-color:#86efac}.absolute-voice-provider-contracts__row--warn,.absolute-voice-provider-contracts__row--fail{border-color:#f2a7a7}.absolute-voice-provider-contracts__row p{margin:10px 0}.absolute-voice-provider-contracts__remediations{display:grid;gap:8px;list-style:none;margin:0 0 10px;padding:0}.absolute-voice-provider-contracts__remediations li{background:#fff7ed;border:1px solid #fed7aa;border-radius:12px;display:grid;gap:3px;padding:8px}.absolute-voice-provider-contracts__remediations a,.absolute-voice-provider-contracts__remediations strong{color:#9a3412}.absolute-voice-provider-contracts__remediations span{color:#7c2d12}.absolute-voice-provider-contracts__row dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-contracts__row div{background:#f7fff9;border:1px solid #d6eadb;border-radius:12px;padding:8px}.absolute-voice-provider-contracts__row dt{font-size:12px}.absolute-voice-provider-contracts__row dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-contracts__error{color:#9f1239;font-weight:700}`;
|
|
1515
|
+
var mountVoiceProviderContracts = (element, path = "/api/provider-contracts", options = {}) => {
|
|
1516
|
+
const store = createVoiceProviderContractsStore(path, options);
|
|
1517
|
+
const render = () => {
|
|
1518
|
+
element.innerHTML = renderVoiceProviderContractsHTML(store.getSnapshot(), options);
|
|
1519
|
+
};
|
|
1520
|
+
const unsubscribe = store.subscribe(render);
|
|
1521
|
+
render();
|
|
1522
|
+
store.refresh().catch(() => {});
|
|
1523
|
+
return {
|
|
1524
|
+
close: () => {
|
|
1525
|
+
unsubscribe();
|
|
1526
|
+
store.close();
|
|
1527
|
+
},
|
|
1528
|
+
refresh: store.refresh
|
|
1529
|
+
};
|
|
1530
|
+
};
|
|
1531
|
+
var defineVoiceProviderContractsElement = (tagName = "absolute-voice-provider-contracts") => {
|
|
1532
|
+
if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1535
|
+
customElements.define(tagName, class AbsoluteVoiceProviderContractsElement extends HTMLElement {
|
|
1536
|
+
mounted;
|
|
1537
|
+
connectedCallback() {
|
|
1538
|
+
const intervalMs = Number(this.getAttribute("interval-ms") ?? 5000);
|
|
1539
|
+
this.mounted = mountVoiceProviderContracts(this, this.getAttribute("path") ?? "/api/provider-contracts", {
|
|
1540
|
+
description: this.getAttribute("description") ?? undefined,
|
|
1541
|
+
intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
|
|
1542
|
+
title: this.getAttribute("title") ?? undefined
|
|
1543
|
+
});
|
|
1544
|
+
}
|
|
1545
|
+
disconnectedCallback() {
|
|
1546
|
+
this.mounted?.close();
|
|
1547
|
+
this.mounted = undefined;
|
|
1548
|
+
}
|
|
1549
|
+
});
|
|
1550
|
+
};
|
|
1551
|
+
|
|
1552
|
+
// src/svelte/createVoiceProviderContracts.ts
|
|
1553
|
+
var createVoiceProviderContracts = (path = "/api/provider-contracts", options = {}) => {
|
|
1554
|
+
const store = createVoiceProviderContractsStore(path, options);
|
|
1555
|
+
return {
|
|
1556
|
+
...store,
|
|
1557
|
+
getHTML: () => renderVoiceProviderContractsHTML(store.getSnapshot(), options),
|
|
1558
|
+
getViewModel: () => createVoiceProviderContractsViewModel(store.getSnapshot(), options)
|
|
1559
|
+
};
|
|
1560
|
+
};
|
|
1370
1561
|
// src/client/actions.ts
|
|
1371
1562
|
var normalizeErrorMessage = (value) => {
|
|
1372
1563
|
if (typeof value === "string" && value.trim()) {
|
|
@@ -2090,11 +2281,11 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
|
|
|
2090
2281
|
};
|
|
2091
2282
|
|
|
2092
2283
|
// src/client/providerStatusWidget.ts
|
|
2093
|
-
var
|
|
2094
|
-
var
|
|
2095
|
-
var
|
|
2096
|
-
var
|
|
2097
|
-
var
|
|
2284
|
+
var DEFAULT_TITLE6 = "Voice Providers";
|
|
2285
|
+
var DEFAULT_DESCRIPTION6 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
|
|
2286
|
+
var escapeHtml7 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2287
|
+
var formatProvider3 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
|
|
2288
|
+
var formatStatus3 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
2098
2289
|
var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
|
|
2099
2290
|
var formatSuppression = (value) => typeof value === "number" ? `${Math.ceil(value / 1000)}s` : "None";
|
|
2100
2291
|
var getProviderDetail = (provider) => {
|
|
@@ -2120,7 +2311,7 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
|
|
|
2120
2311
|
const providers = snapshot.providers.map((provider) => ({
|
|
2121
2312
|
...provider,
|
|
2122
2313
|
detail: getProviderDetail(provider),
|
|
2123
|
-
label: `${
|
|
2314
|
+
label: `${formatProvider3(provider.provider)}${provider.recommended ? " recommended" : ""}`,
|
|
2124
2315
|
rows: [
|
|
2125
2316
|
{ label: "Runs", value: String(provider.runCount) },
|
|
2126
2317
|
{ label: "Avg latency", value: formatLatency(provider.averageElapsedMs) },
|
|
@@ -2136,37 +2327,37 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
|
|
|
2136
2327
|
const warningCount = providers.filter((provider) => isWarningStatus2(provider.status)).length;
|
|
2137
2328
|
const healthyCount = providers.filter((provider) => provider.status === "healthy").length;
|
|
2138
2329
|
return {
|
|
2139
|
-
description: options.description ??
|
|
2330
|
+
description: options.description ?? DEFAULT_DESCRIPTION6,
|
|
2140
2331
|
error: snapshot.error,
|
|
2141
2332
|
isLoading: snapshot.isLoading,
|
|
2142
2333
|
label: snapshot.error ? "Unavailable" : providers.length ? warningCount > 0 ? `${warningCount} needs attention` : `${healthyCount} healthy` : snapshot.isLoading ? "Checking" : "No provider traffic",
|
|
2143
2334
|
providers,
|
|
2144
2335
|
status: snapshot.error ? "error" : providers.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
2145
|
-
title: options.title ??
|
|
2336
|
+
title: options.title ?? DEFAULT_TITLE6,
|
|
2146
2337
|
updatedAt: snapshot.updatedAt
|
|
2147
2338
|
};
|
|
2148
2339
|
};
|
|
2149
2340
|
var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
|
|
2150
2341
|
const model = createVoiceProviderStatusViewModel(snapshot, options);
|
|
2151
|
-
const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${
|
|
2342
|
+
const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${escapeHtml7(provider.status)}">
|
|
2152
2343
|
<header>
|
|
2153
|
-
<strong>${
|
|
2154
|
-
<span>${
|
|
2344
|
+
<strong>${escapeHtml7(provider.label)}</strong>
|
|
2345
|
+
<span>${escapeHtml7(formatStatus3(provider.status))}</span>
|
|
2155
2346
|
</header>
|
|
2156
|
-
<p>${
|
|
2347
|
+
<p>${escapeHtml7(provider.detail)}</p>
|
|
2157
2348
|
<dl>${provider.rows.map((row) => `<div>
|
|
2158
|
-
<dt>${
|
|
2159
|
-
<dd>${
|
|
2349
|
+
<dt>${escapeHtml7(row.label)}</dt>
|
|
2350
|
+
<dd>${escapeHtml7(row.value)}</dd>
|
|
2160
2351
|
</div>`).join("")}</dl>
|
|
2161
2352
|
</article>`).join("")}</div>` : '<p class="absolute-voice-provider-status__empty">Run voice traffic to see provider health.</p>';
|
|
2162
|
-
return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${
|
|
2353
|
+
return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml7(model.status)}">
|
|
2163
2354
|
<header class="absolute-voice-provider-status__header">
|
|
2164
|
-
<span class="absolute-voice-provider-status__eyebrow">${
|
|
2165
|
-
<strong class="absolute-voice-provider-status__label">${
|
|
2355
|
+
<span class="absolute-voice-provider-status__eyebrow">${escapeHtml7(model.title)}</span>
|
|
2356
|
+
<strong class="absolute-voice-provider-status__label">${escapeHtml7(model.label)}</strong>
|
|
2166
2357
|
</header>
|
|
2167
|
-
<p class="absolute-voice-provider-status__description">${
|
|
2358
|
+
<p class="absolute-voice-provider-status__description">${escapeHtml7(model.description)}</p>
|
|
2168
2359
|
${providers}
|
|
2169
|
-
${model.error ? `<p class="absolute-voice-provider-status__error">${
|
|
2360
|
+
${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml7(model.error)}</p>` : ""}
|
|
2170
2361
|
</section>`;
|
|
2171
2362
|
};
|
|
2172
2363
|
var getVoiceProviderStatusCSS = () => `.absolute-voice-provider-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-provider-status--error,.absolute-voice-provider-status--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-status__header,.absolute-voice-provider-status__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-status__label{font-size:24px;line-height:1}.absolute-voice-provider-status__description,.absolute-voice-provider-status__provider p,.absolute-voice-provider-status__provider dt,.absolute-voice-provider-status__empty{color:#514733}.absolute-voice-provider-status__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-status__provider{background:#fff;border:1px solid #eee4d2;border-radius:16px;padding:14px}.absolute-voice-provider-status__provider--degraded,.absolute-voice-provider-status__provider--rate-limited,.absolute-voice-provider-status__provider--suppressed{border-color:#f2a7a7}.absolute-voice-provider-status__provider--recoverable{border-color:#fbbf24}.absolute-voice-provider-status__provider p{margin:10px 0}.absolute-voice-provider-status__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-status__provider div{background:#fffaf0;border:1px solid #eee4d2;border-radius:12px;padding:8px}.absolute-voice-provider-status__provider dt{font-size:12px}.absolute-voice-provider-status__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-status__empty{margin:14px 0 0}.absolute-voice-provider-status__error{color:#9f1239;font-weight:700}`;
|
|
@@ -2297,9 +2488,9 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
|
|
|
2297
2488
|
};
|
|
2298
2489
|
|
|
2299
2490
|
// src/client/routingStatusWidget.ts
|
|
2300
|
-
var
|
|
2301
|
-
var
|
|
2302
|
-
var
|
|
2491
|
+
var DEFAULT_TITLE7 = "Voice Routing";
|
|
2492
|
+
var DEFAULT_DESCRIPTION7 = "Latest provider routing decision from the self-hosted trace store.";
|
|
2493
|
+
var escapeHtml8 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2303
2494
|
var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
|
|
2304
2495
|
var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
|
|
2305
2496
|
const decision = snapshot.decision;
|
|
@@ -2323,30 +2514,30 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
|
|
|
2323
2514
|
] : [];
|
|
2324
2515
|
return {
|
|
2325
2516
|
decision,
|
|
2326
|
-
description: options.description ??
|
|
2517
|
+
description: options.description ?? DEFAULT_DESCRIPTION7,
|
|
2327
2518
|
error: snapshot.error,
|
|
2328
2519
|
isLoading: snapshot.isLoading,
|
|
2329
2520
|
label: snapshot.error ? "Unavailable" : decision ? `${formatValue(decision.kind).toUpperCase()} ${formatValue(decision.status, "unknown")}` : snapshot.isLoading ? "Checking" : "No routing yet",
|
|
2330
2521
|
rows,
|
|
2331
2522
|
status: snapshot.error ? "error" : decision ? "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
2332
|
-
title: options.title ??
|
|
2523
|
+
title: options.title ?? DEFAULT_TITLE7,
|
|
2333
2524
|
updatedAt: snapshot.updatedAt
|
|
2334
2525
|
};
|
|
2335
2526
|
};
|
|
2336
2527
|
var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
|
|
2337
2528
|
const model = createVoiceRoutingStatusViewModel(snapshot, options);
|
|
2338
2529
|
const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
|
|
2339
|
-
<span>${
|
|
2340
|
-
<strong>${
|
|
2530
|
+
<span>${escapeHtml8(row.label)}</span>
|
|
2531
|
+
<strong>${escapeHtml8(row.value)}</strong>
|
|
2341
2532
|
</div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
|
|
2342
|
-
return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${
|
|
2533
|
+
return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml8(model.status)}">
|
|
2343
2534
|
<header class="absolute-voice-routing-status__header">
|
|
2344
|
-
<span class="absolute-voice-routing-status__eyebrow">${
|
|
2345
|
-
<strong class="absolute-voice-routing-status__label">${
|
|
2535
|
+
<span class="absolute-voice-routing-status__eyebrow">${escapeHtml8(model.title)}</span>
|
|
2536
|
+
<strong class="absolute-voice-routing-status__label">${escapeHtml8(model.label)}</strong>
|
|
2346
2537
|
</header>
|
|
2347
|
-
<p class="absolute-voice-routing-status__description">${
|
|
2538
|
+
<p class="absolute-voice-routing-status__description">${escapeHtml8(model.description)}</p>
|
|
2348
2539
|
${rows}
|
|
2349
|
-
${model.error ? `<p class="absolute-voice-routing-status__error">${
|
|
2540
|
+
${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml8(model.error)}</p>` : ""}
|
|
2350
2541
|
</section>`;
|
|
2351
2542
|
};
|
|
2352
2543
|
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}`;
|
|
@@ -2477,9 +2668,9 @@ var createVoiceTraceTimelineStore = (path = "/api/voice-traces", options = {}) =
|
|
|
2477
2668
|
};
|
|
2478
2669
|
|
|
2479
2670
|
// src/client/traceTimelineWidget.ts
|
|
2480
|
-
var
|
|
2481
|
-
var
|
|
2482
|
-
var
|
|
2671
|
+
var DEFAULT_TITLE8 = "Voice Traces";
|
|
2672
|
+
var DEFAULT_DESCRIPTION8 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
|
|
2673
|
+
var escapeHtml9 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2483
2674
|
var formatMs = (value) => typeof value === "number" ? `${value}ms` : "n/a";
|
|
2484
2675
|
var formatProviders = (session) => session.providers.length ? session.providers.map((provider) => provider.provider).join(", ") : "No providers";
|
|
2485
2676
|
var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
|
|
@@ -2493,34 +2684,34 @@ var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
|
|
|
2493
2684
|
const failed = sessions.filter((session) => session.status === "failed").length;
|
|
2494
2685
|
const warnings = sessions.filter((session) => session.status === "warning").length;
|
|
2495
2686
|
return {
|
|
2496
|
-
description: options.description ??
|
|
2687
|
+
description: options.description ?? DEFAULT_DESCRIPTION8,
|
|
2497
2688
|
error: snapshot.error,
|
|
2498
2689
|
isLoading: snapshot.isLoading,
|
|
2499
2690
|
label: snapshot.error ? "Unavailable" : failed > 0 ? `${failed} failed` : warnings > 0 ? `${warnings} warning` : sessions.length ? `${sessions.length} recent` : snapshot.isLoading ? "Checking" : "No traces yet",
|
|
2500
2691
|
sessions,
|
|
2501
2692
|
status: snapshot.error ? "error" : failed > 0 ? "failed" : warnings > 0 ? "warning" : sessions.length ? "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
2502
|
-
title: options.title ??
|
|
2693
|
+
title: options.title ?? DEFAULT_TITLE8,
|
|
2503
2694
|
updatedAt: snapshot.updatedAt
|
|
2504
2695
|
};
|
|
2505
2696
|
};
|
|
2506
2697
|
var renderVoiceTraceTimelineWidgetHTML = (snapshot, options = {}) => {
|
|
2507
2698
|
const model = createVoiceTraceTimelineViewModel(snapshot, options);
|
|
2508
|
-
const sessions = model.sessions.length ? `<div class="absolute-voice-trace-timeline__sessions">${model.sessions.map((session) => `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${
|
|
2699
|
+
const sessions = model.sessions.length ? `<div class="absolute-voice-trace-timeline__sessions">${model.sessions.map((session) => `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${escapeHtml9(session.status)}">
|
|
2509
2700
|
<header>
|
|
2510
|
-
<strong>${
|
|
2511
|
-
<span>${
|
|
2701
|
+
<strong>${escapeHtml9(session.sessionId)}</strong>
|
|
2702
|
+
<span>${escapeHtml9(session.status)}</span>
|
|
2512
2703
|
</header>
|
|
2513
|
-
<p>${
|
|
2514
|
-
<a href="${
|
|
2704
|
+
<p>${escapeHtml9(session.label)} \xB7 ${escapeHtml9(session.durationLabel)} \xB7 ${escapeHtml9(session.providerLabel)}</p>
|
|
2705
|
+
<a href="${escapeHtml9(session.detailHref)}">Open timeline</a>
|
|
2515
2706
|
</article>`).join("")}</div>` : '<p class="absolute-voice-trace-timeline__empty">Run a voice session to see call timelines.</p>';
|
|
2516
|
-
return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${
|
|
2707
|
+
return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml9(model.status)}">
|
|
2517
2708
|
<header class="absolute-voice-trace-timeline__header">
|
|
2518
|
-
<span class="absolute-voice-trace-timeline__eyebrow">${
|
|
2519
|
-
<strong class="absolute-voice-trace-timeline__label">${
|
|
2709
|
+
<span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml9(model.title)}</span>
|
|
2710
|
+
<strong class="absolute-voice-trace-timeline__label">${escapeHtml9(model.label)}</strong>
|
|
2520
2711
|
</header>
|
|
2521
|
-
<p class="absolute-voice-trace-timeline__description">${
|
|
2712
|
+
<p class="absolute-voice-trace-timeline__description">${escapeHtml9(model.description)}</p>
|
|
2522
2713
|
${sessions}
|
|
2523
|
-
${model.error ? `<p class="absolute-voice-trace-timeline__error">${
|
|
2714
|
+
${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml9(model.error)}</p>` : ""}
|
|
2524
2715
|
</section>`;
|
|
2525
2716
|
};
|
|
2526
2717
|
var getVoiceTraceTimelineCSS = () => `.absolute-voice-trace-timeline{border:1px solid #bad7d3;border-radius:20px;background:#f3fffb;color:#09201c;padding:18px;box-shadow:0 18px 40px rgba(9,32,28,.12);font-family:inherit}.absolute-voice-trace-timeline--error,.absolute-voice-trace-timeline--failed{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-trace-timeline--warning{border-color:#fbbf24;background:#fffaf0}.absolute-voice-trace-timeline__header,.absolute-voice-trace-timeline__session header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-trace-timeline__eyebrow{color:#17665b;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-trace-timeline__label{font-size:24px;line-height:1}.absolute-voice-trace-timeline__description,.absolute-voice-trace-timeline__session p,.absolute-voice-trace-timeline__empty{color:#35544f}.absolute-voice-trace-timeline__sessions{display:grid;gap:12px;margin-top:14px}.absolute-voice-trace-timeline__session{background:#fff;border:1px solid #cfe7e2;border-radius:16px;padding:14px}.absolute-voice-trace-timeline__session--failed{border-color:#f2a7a7}.absolute-voice-trace-timeline__session--warning{border-color:#fbbf24}.absolute-voice-trace-timeline__session p{margin:10px 0}.absolute-voice-trace-timeline__session a{color:#0f766e;font-weight:800}.absolute-voice-trace-timeline__empty{margin:14px 0 0}.absolute-voice-trace-timeline__error{color:#9f1239;font-weight:700}`;
|
|
@@ -2677,10 +2868,10 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
|
|
|
2677
2868
|
};
|
|
2678
2869
|
|
|
2679
2870
|
// src/client/turnLatencyWidget.ts
|
|
2680
|
-
var
|
|
2681
|
-
var
|
|
2871
|
+
var DEFAULT_TITLE9 = "Turn Latency";
|
|
2872
|
+
var DEFAULT_DESCRIPTION9 = "Per-turn timing from first transcript to commit and assistant response start.";
|
|
2682
2873
|
var DEFAULT_PROOF_LABEL = "Run latency proof";
|
|
2683
|
-
var
|
|
2874
|
+
var escapeHtml10 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2684
2875
|
var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
|
|
2685
2876
|
var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
|
|
2686
2877
|
const turns = (snapshot.report?.turns ?? []).map((turn) => ({
|
|
@@ -2694,39 +2885,39 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
|
|
|
2694
2885
|
const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
|
|
2695
2886
|
const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
|
|
2696
2887
|
return {
|
|
2697
|
-
description: options.description ??
|
|
2888
|
+
description: options.description ?? DEFAULT_DESCRIPTION9,
|
|
2698
2889
|
error: snapshot.error,
|
|
2699
2890
|
isLoading: snapshot.isLoading,
|
|
2700
2891
|
label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} slow` : warningCount > 0 ? `${warningCount} warnings` : `avg ${formatMs2(snapshot.report?.averageTotalMs)}` : snapshot.isLoading ? "Checking" : "No turns",
|
|
2701
2892
|
proofLabel: options.proofPath ? options.proofLabel ?? DEFAULT_PROOF_LABEL : undefined,
|
|
2702
2893
|
showProofAction: Boolean(options.proofPath),
|
|
2703
2894
|
status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
2704
|
-
title: options.title ??
|
|
2895
|
+
title: options.title ?? DEFAULT_TITLE9,
|
|
2705
2896
|
turns,
|
|
2706
2897
|
updatedAt: snapshot.updatedAt
|
|
2707
2898
|
};
|
|
2708
2899
|
};
|
|
2709
2900
|
var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
|
|
2710
2901
|
const model = createVoiceTurnLatencyViewModel(snapshot, options);
|
|
2711
|
-
const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${
|
|
2902
|
+
const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${escapeHtml10(turn.status)}">
|
|
2712
2903
|
<header>
|
|
2713
|
-
<strong>${
|
|
2714
|
-
<span>${
|
|
2904
|
+
<strong>${escapeHtml10(turn.label)}</strong>
|
|
2905
|
+
<span>${escapeHtml10(turn.status)}</span>
|
|
2715
2906
|
</header>
|
|
2716
2907
|
<dl>${turn.rows.map((row) => `<div>
|
|
2717
|
-
<dt>${
|
|
2718
|
-
<dd>${
|
|
2908
|
+
<dt>${escapeHtml10(row.label)}</dt>
|
|
2909
|
+
<dd>${escapeHtml10(row.value)}</dd>
|
|
2719
2910
|
</div>`).join("")}</dl>
|
|
2720
2911
|
</article>`).join("")}</div>` : '<p class="absolute-voice-turn-latency__empty">Complete a voice turn to see latency diagnostics.</p>';
|
|
2721
|
-
return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${
|
|
2912
|
+
return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml10(model.status)}">
|
|
2722
2913
|
<header class="absolute-voice-turn-latency__header">
|
|
2723
|
-
<span class="absolute-voice-turn-latency__eyebrow">${
|
|
2724
|
-
<strong class="absolute-voice-turn-latency__label">${
|
|
2914
|
+
<span class="absolute-voice-turn-latency__eyebrow">${escapeHtml10(model.title)}</span>
|
|
2915
|
+
<strong class="absolute-voice-turn-latency__label">${escapeHtml10(model.label)}</strong>
|
|
2725
2916
|
</header>
|
|
2726
|
-
<p class="absolute-voice-turn-latency__description">${
|
|
2727
|
-
${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${
|
|
2917
|
+
<p class="absolute-voice-turn-latency__description">${escapeHtml10(model.description)}</p>
|
|
2918
|
+
${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml10(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
|
|
2728
2919
|
${turns}
|
|
2729
|
-
${model.error ? `<p class="absolute-voice-turn-latency__error">${
|
|
2920
|
+
${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml10(model.error)}</p>` : ""}
|
|
2730
2921
|
</section>`;
|
|
2731
2922
|
};
|
|
2732
2923
|
var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {}) => {
|
|
@@ -2865,9 +3056,9 @@ var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) =>
|
|
|
2865
3056
|
};
|
|
2866
3057
|
|
|
2867
3058
|
// src/client/turnQualityWidget.ts
|
|
2868
|
-
var
|
|
2869
|
-
var
|
|
2870
|
-
var
|
|
3059
|
+
var DEFAULT_TITLE10 = "Turn Quality";
|
|
3060
|
+
var DEFAULT_DESCRIPTION10 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
|
|
3061
|
+
var escapeHtml11 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2871
3062
|
var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
|
|
2872
3063
|
var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
|
|
2873
3064
|
var getTurnDetail = (turn) => {
|
|
@@ -2905,37 +3096,37 @@ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
|
|
|
2905
3096
|
const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
|
|
2906
3097
|
const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
|
|
2907
3098
|
return {
|
|
2908
|
-
description: options.description ??
|
|
3099
|
+
description: options.description ?? DEFAULT_DESCRIPTION10,
|
|
2909
3100
|
error: snapshot.error,
|
|
2910
3101
|
isLoading: snapshot.isLoading,
|
|
2911
3102
|
label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} failed` : warningCount > 0 ? `${warningCount} warnings` : `${turns.length} healthy` : snapshot.isLoading ? "Checking" : "No turns",
|
|
2912
3103
|
status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
2913
|
-
title: options.title ??
|
|
3104
|
+
title: options.title ?? DEFAULT_TITLE10,
|
|
2914
3105
|
turns,
|
|
2915
3106
|
updatedAt: snapshot.updatedAt
|
|
2916
3107
|
};
|
|
2917
3108
|
};
|
|
2918
3109
|
var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
|
|
2919
3110
|
const model = createVoiceTurnQualityViewModel(snapshot, options);
|
|
2920
|
-
const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${
|
|
3111
|
+
const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${escapeHtml11(turn.status)}">
|
|
2921
3112
|
<header>
|
|
2922
|
-
<strong>${
|
|
2923
|
-
<span>${
|
|
3113
|
+
<strong>${escapeHtml11(turn.label)}</strong>
|
|
3114
|
+
<span>${escapeHtml11(turn.status)}</span>
|
|
2924
3115
|
</header>
|
|
2925
|
-
<p>${
|
|
3116
|
+
<p>${escapeHtml11(turn.detail)}</p>
|
|
2926
3117
|
<dl>${turn.rows.map((row) => `<div>
|
|
2927
|
-
<dt>${
|
|
2928
|
-
<dd>${
|
|
3118
|
+
<dt>${escapeHtml11(row.label)}</dt>
|
|
3119
|
+
<dd>${escapeHtml11(row.value)}</dd>
|
|
2929
3120
|
</div>`).join("")}</dl>
|
|
2930
3121
|
</article>`).join("")}</div>` : '<p class="absolute-voice-turn-quality__empty">Complete a voice turn to see STT quality diagnostics.</p>';
|
|
2931
|
-
return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${
|
|
3122
|
+
return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml11(model.status)}">
|
|
2932
3123
|
<header class="absolute-voice-turn-quality__header">
|
|
2933
|
-
<span class="absolute-voice-turn-quality__eyebrow">${
|
|
2934
|
-
<strong class="absolute-voice-turn-quality__label">${
|
|
3124
|
+
<span class="absolute-voice-turn-quality__eyebrow">${escapeHtml11(model.title)}</span>
|
|
3125
|
+
<strong class="absolute-voice-turn-quality__label">${escapeHtml11(model.label)}</strong>
|
|
2935
3126
|
</header>
|
|
2936
|
-
<p class="absolute-voice-turn-quality__description">${
|
|
3127
|
+
<p class="absolute-voice-turn-quality__description">${escapeHtml11(model.description)}</p>
|
|
2937
3128
|
${turns}
|
|
2938
|
-
${model.error ? `<p class="absolute-voice-turn-quality__error">${
|
|
3129
|
+
${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml11(model.error)}</p>` : ""}
|
|
2939
3130
|
</section>`;
|
|
2940
3131
|
};
|
|
2941
3132
|
var getVoiceTurnQualityCSS = () => `.absolute-voice-turn-quality{border:1px solid #e4d1a3;border-radius:20px;background:#fff9eb;color:#17120a;padding:18px;box-shadow:0 18px 40px rgba(73,48,14,.12);font-family:inherit}.absolute-voice-turn-quality--error,.absolute-voice-turn-quality--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-turn-quality__header,.absolute-voice-turn-quality__turn header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-turn-quality__eyebrow{color:#8a5a0a;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-turn-quality__label{font-size:24px;line-height:1}.absolute-voice-turn-quality__description,.absolute-voice-turn-quality__turn p,.absolute-voice-turn-quality__turn dt,.absolute-voice-turn-quality__empty{color:#5a4930}.absolute-voice-turn-quality__turns{display:grid;gap:12px;margin-top:14px}.absolute-voice-turn-quality__turn{background:#fff;border:1px solid #f0dfba;border-radius:16px;padding:14px}.absolute-voice-turn-quality__turn--pass{border-color:#86efac}.absolute-voice-turn-quality__turn--warn,.absolute-voice-turn-quality__turn--unknown{border-color:#fbbf24}.absolute-voice-turn-quality__turn--fail{border-color:#f2a7a7}.absolute-voice-turn-quality__turn p{margin:10px 0}.absolute-voice-turn-quality__turn dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-turn-quality__turn div{background:#fff9eb;border:1px solid #f0dfba;border-radius:12px;padding:8px}.absolute-voice-turn-quality__turn dt{font-size:12px}.absolute-voice-turn-quality__turn dd{font-weight:800;margin:4px 0 0}.absolute-voice-turn-quality__empty{margin:14px 0 0}.absolute-voice-turn-quality__error{color:#9f1239;font-weight:700}`;
|
|
@@ -3715,6 +3906,7 @@ export {
|
|
|
3715
3906
|
createVoiceRoutingStatus,
|
|
3716
3907
|
createVoiceProviderStatus,
|
|
3717
3908
|
createVoiceProviderSimulationControls,
|
|
3909
|
+
createVoiceProviderContracts,
|
|
3718
3910
|
createVoiceProviderCapabilities,
|
|
3719
3911
|
createVoiceOpsStatus,
|
|
3720
3912
|
createVoiceOpsActionCenter,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const VoiceProviderContracts: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
2
|
+
description: StringConstructor;
|
|
3
|
+
intervalMs: NumberConstructor;
|
|
4
|
+
path: {
|
|
5
|
+
default: string;
|
|
6
|
+
type: StringConstructor;
|
|
7
|
+
};
|
|
8
|
+
title: StringConstructor;
|
|
9
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
12
|
+
description: StringConstructor;
|
|
13
|
+
intervalMs: NumberConstructor;
|
|
14
|
+
path: {
|
|
15
|
+
default: string;
|
|
16
|
+
type: StringConstructor;
|
|
17
|
+
};
|
|
18
|
+
title: StringConstructor;
|
|
19
|
+
}>> & Readonly<{}>, {
|
|
20
|
+
path: string;
|
|
21
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
package/dist/vue/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { VoiceOpsActionCenter } from './VoiceOpsActionCenter';
|
|
|
3
3
|
export { VoiceDeliveryRuntime } from './VoiceDeliveryRuntime';
|
|
4
4
|
export { VoiceProviderSimulationControls } from './VoiceProviderSimulationControls';
|
|
5
5
|
export { VoiceProviderCapabilities } from './VoiceProviderCapabilities';
|
|
6
|
+
export { VoiceProviderContracts } from './VoiceProviderContracts';
|
|
6
7
|
export { VoiceProviderStatus } from './VoiceProviderStatus';
|
|
7
8
|
export { VoiceRoutingStatus } from './VoiceRoutingStatus';
|
|
8
9
|
export { VoiceTurnLatency } from './VoiceTurnLatency';
|
|
@@ -15,6 +16,7 @@ export { useVoiceStream } from './useVoiceStream';
|
|
|
15
16
|
export { useVoiceController } from './useVoiceController';
|
|
16
17
|
export { useVoiceProviderStatus } from './useVoiceProviderStatus';
|
|
17
18
|
export { useVoiceProviderCapabilities } from './useVoiceProviderCapabilities';
|
|
19
|
+
export { useVoiceProviderContracts } from './useVoiceProviderContracts';
|
|
18
20
|
export { useVoiceProviderSimulationControls } from './useVoiceProviderSimulationControls';
|
|
19
21
|
export { useVoiceRoutingStatus } from './useVoiceRoutingStatus';
|
|
20
22
|
export { useVoiceTraceTimeline } from './useVoiceTraceTimeline';
|