@absolutejs/voice 0.0.22-beta.276 → 0.0.22-beta.278
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/index.d.ts +2 -0
- package/dist/index.js +278 -40
- package/dist/productionReadiness.d.ts +12 -0
- package/dist/readinessProfiles.d.ts +1 -0
- package/dist/voiceMonitoring.d.ts +252 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -53,6 +53,7 @@ export { assertVoiceProviderRoutingContractEvidence, assertVoiceProviderRoutingC
|
|
|
53
53
|
export { assertVoiceProviderSloEvidence, buildVoiceProviderSloReport, createVoiceProviderSloRoutes, evaluateVoiceProviderSloEvidence, renderVoiceProviderSloHTML, renderVoiceProviderSloMarkdown } from './providerSlo';
|
|
54
54
|
export { createVoicePhoneAgentProductionSmokeHTMLHandler, createVoicePhoneAgentProductionSmokeJSONHandler, createVoicePhoneAgentProductionSmokeRoutes, renderVoicePhoneAgentProductionSmokeHTML, runVoicePhoneAgentProductionSmokeContract } from './phoneAgentProductionSmoke';
|
|
55
55
|
export { assertVoiceProductionReadinessEvidence, buildVoiceProductionReadinessGate, buildVoiceProductionReadinessReport, createVoiceProductionReadinessRoutes, evaluateVoiceProductionReadinessEvidence, renderVoiceProductionReadinessHTML, summarizeVoiceProductionReadinessGate } from './productionReadiness';
|
|
56
|
+
export { acknowledgeVoiceMonitorIssue, buildVoiceMonitorRunReport, createVoiceMemoryMonitorIssueStore, createVoiceMonitorRoutes, muteVoiceMonitorIssue, renderVoiceMonitorHTML, renderVoiceMonitorMarkdown, resolveVoiceMonitorIssue } from './voiceMonitoring';
|
|
56
57
|
export { createVoiceReadinessProfile, recommendVoiceReadinessProfile } from './readinessProfiles';
|
|
57
58
|
export { assertVoiceProviderContractMatrixEvidence, assertVoiceProviderStackEvidence, buildVoiceProviderContractMatrix, createVoiceProviderContractMatrixHTMLHandler, createVoiceProviderContractMatrixJSONHandler, createVoiceProviderContractMatrixPreset, createVoiceProviderContractMatrixRoutes, evaluateVoiceProviderContractMatrixEvidence, evaluateVoiceProviderStackEvidence, evaluateVoiceProviderStackGaps, renderVoiceProviderContractMatrixHTML, recommendVoiceProviderStack } from './providerStackRecommendations';
|
|
58
59
|
export { buildVoiceOpsConsoleReport, createVoiceOpsConsoleRoutes, renderVoiceOpsConsoleHTML } from './opsConsoleRoutes';
|
|
@@ -121,6 +122,7 @@ export type { VoicePhoneAgentProductionSmokeIssue, VoicePhoneAgentProductionSmok
|
|
|
121
122
|
export type { VoiceOpsConsoleLink, VoiceOpsConsoleReport, VoiceOpsConsoleRoutesOptions } from './opsConsoleRoutes';
|
|
122
123
|
export type { VoiceOpsStatus, VoiceOpsStatusLink, VoiceOpsStatusOptions, VoiceOpsStatusReport, VoiceOpsStatusRoutesOptions } from './opsStatus';
|
|
123
124
|
export type { VoiceProductionReadinessAction, VoiceProductionReadinessAuditOptions, VoiceProductionReadinessAuditRequirement, VoiceProductionReadinessAuditSummary, VoiceProductionReadinessAssertionInput, VoiceProductionReadinessAssertionReport, VoiceProductionReadinessCheck, VoiceProductionReadinessGateIssue, VoiceProductionReadinessGateOptions, VoiceProductionReadinessGateProfile, VoiceProductionReadinessGateProfileSurface, VoiceProductionReadinessGateReport, VoiceProductionReadinessOpsActionHistoryOptions, VoiceProductionReadinessOpsActionHistorySummary, VoiceProductionReadinessOperationsRecordLink, VoiceProductionReadinessOperationsRecordLinks, VoiceProductionReadinessProfileExplanation, VoiceProductionReadinessProfileSurface, VoiceProductionReadinessProofSource, VoiceProductionReadinessReport, VoiceProductionReadinessRoutesOptions, VoiceProductionReadinessTraceDeliverySummary, VoiceProductionReadinessAuditDeliveryOptions, VoiceProductionReadinessAuditDeliverySummary, VoiceProductionReadinessTraceDeliveryOptions, VoiceProductionReadinessStatus } from './productionReadiness';
|
|
125
|
+
export type { VoiceMonitorDefinition, VoiceMonitorEvaluation, VoiceMonitorEvaluationInput, VoiceMonitorIssue, VoiceMonitorIssueStatus, VoiceMonitorIssueStore, VoiceMonitorRoutesOptions, VoiceMonitorRun, VoiceMonitorRunOptions, VoiceMonitorRunReport, VoiceMonitorSeverity, VoiceMonitorStatus } from './voiceMonitoring';
|
|
124
126
|
export type { VoiceReadinessProfileName, VoiceReadinessProfileOptions, VoiceReadinessProfileRecommendation, VoiceReadinessProfileRecommendationScore, VoiceReadinessProfileRoutesOptions } from './readinessProfiles';
|
|
125
127
|
export type { VoiceProviderStackChoice, VoiceProviderStackCapabilities, VoiceProviderStackCapabilityGap, VoiceProviderStackCapabilityGapInput, VoiceProviderStackCapabilityGapReport, VoiceProviderContractCheck, VoiceProviderContractCheckStatus, VoiceProviderContractDefinition, VoiceProviderContractMatrixAssertionInput, VoiceProviderContractMatrixAssertionReport, VoiceProviderContractMatrixHandlerOptions, VoiceProviderContractMatrixHTMLHandlerOptions, VoiceProviderContractMatrixInput, VoiceProviderContractMatrixPresetOptions, VoiceProviderContractMatrixReport, VoiceProviderContractMatrixRoutesOptions, VoiceProviderContractMatrixRow, VoiceProviderStackAssertionInput, VoiceProviderStackAssertionReport, VoiceProviderStackInput, VoiceProviderStackKind, VoiceProviderStackRecommendation } from './providerStackRecommendations';
|
|
126
128
|
export type { VoiceOperationsRecord, VoiceOperationsRecordAgentHandoff, VoiceOperationsRecordAuditSummary, VoiceOperationsRecordGuardrailAssertionInput, VoiceOperationsRecordGuardrailAssertionReport, VoiceOperationsRecordGuardrailDecision, VoiceOperationsRecordGuardrailFinding, VoiceOperationsRecordGuardrailSummary, VoiceOperationsRecordIntegrationEventSummary, VoiceOperationsRecordOptions, VoiceOperationsRecordOutcome, VoiceOperationsRecordProviderDecision, VoiceOperationsRecordReviewSummary, VoiceOperationsRecordRoutesOptions, VoiceOperationsRecordStatus, VoiceOperationsRecordTaskSummary, VoiceOperationsRecordTranscriptTurn, VoiceOperationsRecordTool } from './operationsRecord';
|
package/dist/index.js
CHANGED
|
@@ -27328,6 +27328,12 @@ var resolvePhoneAgentSmokes = async (options, input) => {
|
|
|
27328
27328
|
}
|
|
27329
27329
|
return typeof options.phoneAgentSmokes === "function" ? await options.phoneAgentSmokes(input) : options.phoneAgentSmokes;
|
|
27330
27330
|
};
|
|
27331
|
+
var resolveMonitoring = async (options, input) => {
|
|
27332
|
+
if (options.monitoring === false || options.monitoring === undefined) {
|
|
27333
|
+
return;
|
|
27334
|
+
}
|
|
27335
|
+
return typeof options.monitoring === "function" ? await options.monitoring(input) : options.monitoring;
|
|
27336
|
+
};
|
|
27331
27337
|
var isVoiceTelephonyWebhookSecurityReport = (value) => typeof value.generatedAt === "number" && Array.isArray(value.providers) && typeof value.status === "string";
|
|
27332
27338
|
var resolveTelephonyWebhookSecurity = async (options, input) => {
|
|
27333
27339
|
if (options.telephonyWebhookSecurity === false || options.telephonyWebhookSecurity === undefined) {
|
|
@@ -27698,6 +27704,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
27698
27704
|
providerStack,
|
|
27699
27705
|
providerContractMatrix,
|
|
27700
27706
|
phoneAgentSmokes,
|
|
27707
|
+
monitoring,
|
|
27701
27708
|
telephonyWebhookSecurity,
|
|
27702
27709
|
reconnectContracts,
|
|
27703
27710
|
bargeInReports,
|
|
@@ -27737,6 +27744,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
27737
27744
|
resolveProviderStack(options, { query, request }),
|
|
27738
27745
|
resolveProviderContractMatrix(options, { query, request }),
|
|
27739
27746
|
resolvePhoneAgentSmokes(options, { query, request }),
|
|
27747
|
+
resolveMonitoring(options, { query, request }),
|
|
27740
27748
|
resolveTelephonyWebhookSecurity(options, { query, request }),
|
|
27741
27749
|
resolveReconnectContracts(options, { query, request }),
|
|
27742
27750
|
resolveBargeInReports(options, { query, request }),
|
|
@@ -27945,6 +27953,12 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
27945
27953
|
status: phoneAgentSmokes.some((report) => !report.pass) ? "fail" : phoneAgentSmokes.length === 0 ? "warn" : "pass",
|
|
27946
27954
|
total: phoneAgentSmokes.length
|
|
27947
27955
|
} : undefined;
|
|
27956
|
+
const monitoringSummary = monitoring ? {
|
|
27957
|
+
criticalOpen: monitoring.summary.criticalOpen,
|
|
27958
|
+
open: monitoring.summary.open,
|
|
27959
|
+
status: monitoring.status,
|
|
27960
|
+
total: monitoring.summary.total
|
|
27961
|
+
} : undefined;
|
|
27948
27962
|
const telephonyWebhookSecuritySummary = telephonyWebhookSecurity ? {
|
|
27949
27963
|
enabled: telephonyWebhookSecurity.summary.enabled,
|
|
27950
27964
|
failed: telephonyWebhookSecurity.summary.failed,
|
|
@@ -28341,6 +28355,22 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
28341
28355
|
]
|
|
28342
28356
|
});
|
|
28343
28357
|
}
|
|
28358
|
+
if (monitoring && monitoringSummary) {
|
|
28359
|
+
checks.push({
|
|
28360
|
+
detail: monitoringSummary.status === "pass" ? `${monitoringSummary.total} monitor(s) are passing with no open issues.` : `${monitoringSummary.open} monitor issue(s) open, ${monitoringSummary.criticalOpen} critical.`,
|
|
28361
|
+
href: options.links?.monitoring ?? "/voice/monitors",
|
|
28362
|
+
label: "Monitoring issues",
|
|
28363
|
+
status: monitoringSummary.status,
|
|
28364
|
+
value: `${monitoring.summary.passed}/${monitoringSummary.total}`,
|
|
28365
|
+
actions: monitoringSummary.status === "pass" ? [] : [
|
|
28366
|
+
{
|
|
28367
|
+
description: "Open monitor issues and resolve or acknowledge customer-owned alerts before deploy.",
|
|
28368
|
+
href: options.links?.monitoring ?? "/voice/monitors",
|
|
28369
|
+
label: "Open monitor issues"
|
|
28370
|
+
}
|
|
28371
|
+
]
|
|
28372
|
+
});
|
|
28373
|
+
}
|
|
28344
28374
|
return {
|
|
28345
28375
|
checkedAt: Date.now(),
|
|
28346
28376
|
checks,
|
|
@@ -28358,6 +28388,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
28358
28388
|
operationsRecords: "/voice-operations",
|
|
28359
28389
|
observabilityExport: "/voice/observability-export",
|
|
28360
28390
|
observabilityExportDeliveries: "/api/voice/observability-export/deliveries",
|
|
28391
|
+
monitoring: "/voice/monitors",
|
|
28361
28392
|
opsActions: "/voice/ops-actions",
|
|
28362
28393
|
opsRecovery: "/ops-recovery",
|
|
28363
28394
|
phoneAgentSmoke: "/sessions",
|
|
@@ -28389,6 +28420,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
28389
28420
|
total: handoffs.total
|
|
28390
28421
|
},
|
|
28391
28422
|
liveLatency,
|
|
28423
|
+
monitoring: monitoringSummary,
|
|
28392
28424
|
opsActionHistory,
|
|
28393
28425
|
opsRecovery: opsRecovery ? {
|
|
28394
28426
|
issues: opsRecovery.issues.length,
|
|
@@ -28502,6 +28534,193 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
28502
28534
|
}
|
|
28503
28535
|
return routes;
|
|
28504
28536
|
};
|
|
28537
|
+
// src/voiceMonitoring.ts
|
|
28538
|
+
import { Elysia as Elysia44 } from "elysia";
|
|
28539
|
+
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
28540
|
+
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
28541
|
+
var rollupStatus4 = (runs) => runs.some((run) => run.status === "fail") ? "fail" : runs.some((run) => run.status === "warn") ? "warn" : "pass";
|
|
28542
|
+
var createVoiceMemoryMonitorIssueStore = (initial = []) => {
|
|
28543
|
+
const issues = new Map(initial.map((issue) => [issue.id, { ...issue }]));
|
|
28544
|
+
return {
|
|
28545
|
+
list: () => Array.from(issues.values()).map((issue) => ({ ...issue })),
|
|
28546
|
+
upsert: (issue) => {
|
|
28547
|
+
const previous = issues.get(issue.id);
|
|
28548
|
+
const next = previous ? {
|
|
28549
|
+
...previous,
|
|
28550
|
+
...issue,
|
|
28551
|
+
createdAt: previous.createdAt,
|
|
28552
|
+
status: previous.status === "resolved" || previous.status === "muted" ? previous.status : issue.status
|
|
28553
|
+
} : issue;
|
|
28554
|
+
issues.set(issue.id, { ...next });
|
|
28555
|
+
return { ...next };
|
|
28556
|
+
},
|
|
28557
|
+
update: (id, patch) => {
|
|
28558
|
+
const previous = issues.get(id);
|
|
28559
|
+
if (!previous) {
|
|
28560
|
+
return;
|
|
28561
|
+
}
|
|
28562
|
+
const next = { ...previous, ...patch };
|
|
28563
|
+
issues.set(id, next);
|
|
28564
|
+
return { ...next };
|
|
28565
|
+
}
|
|
28566
|
+
};
|
|
28567
|
+
};
|
|
28568
|
+
var buildVoiceMonitorRunReport = async (options) => {
|
|
28569
|
+
const checkedAt = options.now ?? Date.now();
|
|
28570
|
+
const runs = await Promise.all(options.monitors.map(async (monitor) => {
|
|
28571
|
+
const evaluation = await monitor.evaluate({
|
|
28572
|
+
evidence: options.evidence,
|
|
28573
|
+
now: checkedAt
|
|
28574
|
+
});
|
|
28575
|
+
return {
|
|
28576
|
+
...evaluation,
|
|
28577
|
+
checkedAt,
|
|
28578
|
+
description: monitor.description,
|
|
28579
|
+
id: monitor.id,
|
|
28580
|
+
label: monitor.label,
|
|
28581
|
+
severity: monitor.severity ?? "warn",
|
|
28582
|
+
windowMs: monitor.windowMs
|
|
28583
|
+
};
|
|
28584
|
+
}));
|
|
28585
|
+
for (const run of runs) {
|
|
28586
|
+
if (run.status === "pass") {
|
|
28587
|
+
continue;
|
|
28588
|
+
}
|
|
28589
|
+
await options.issueStore?.upsert({
|
|
28590
|
+
createdAt: checkedAt,
|
|
28591
|
+
detail: run.detail,
|
|
28592
|
+
id: issueIdForRun(run),
|
|
28593
|
+
impactedSessions: [...run.impactedSessions ?? []],
|
|
28594
|
+
label: run.label,
|
|
28595
|
+
lastSeenAt: checkedAt,
|
|
28596
|
+
monitorId: run.id,
|
|
28597
|
+
operationsRecordHrefs: [...run.operationsRecordHrefs ?? []],
|
|
28598
|
+
severity: run.status === "fail" ? run.severity : "warn",
|
|
28599
|
+
status: "open",
|
|
28600
|
+
threshold: run.threshold,
|
|
28601
|
+
value: run.value
|
|
28602
|
+
});
|
|
28603
|
+
}
|
|
28604
|
+
const issues = await options.issueStore?.list() ?? [];
|
|
28605
|
+
const openIssues = issues.filter((issue) => issue.status === "open");
|
|
28606
|
+
const criticalOpen = openIssues.filter((issue) => issue.severity === "critical").length;
|
|
28607
|
+
return {
|
|
28608
|
+
checkedAt,
|
|
28609
|
+
issues,
|
|
28610
|
+
runs,
|
|
28611
|
+
status: criticalOpen > 0 ? "fail" : openIssues.length > 0 || rollupStatus4(runs) === "warn" ? "warn" : rollupStatus4(runs),
|
|
28612
|
+
summary: {
|
|
28613
|
+
acknowledged: issues.filter((issue) => issue.status === "acknowledged").length,
|
|
28614
|
+
criticalOpen,
|
|
28615
|
+
failed: runs.filter((run) => run.status === "fail").length,
|
|
28616
|
+
muted: issues.filter((issue) => issue.status === "muted").length,
|
|
28617
|
+
open: openIssues.length,
|
|
28618
|
+
passed: runs.filter((run) => run.status === "pass").length,
|
|
28619
|
+
resolved: issues.filter((issue) => issue.status === "resolved").length,
|
|
28620
|
+
total: runs.length,
|
|
28621
|
+
warned: runs.filter((run) => run.status === "warn").length
|
|
28622
|
+
}
|
|
28623
|
+
};
|
|
28624
|
+
};
|
|
28625
|
+
var acknowledgeVoiceMonitorIssue = async (store, id, input = {}) => store.update(id, {
|
|
28626
|
+
acknowledgedAt: input.now ?? Date.now(),
|
|
28627
|
+
acknowledgedBy: input.actorId,
|
|
28628
|
+
status: "acknowledged"
|
|
28629
|
+
});
|
|
28630
|
+
var resolveVoiceMonitorIssue = async (store, id, input = {}) => store.update(id, {
|
|
28631
|
+
resolvedAt: input.now ?? Date.now(),
|
|
28632
|
+
resolvedBy: input.actorId,
|
|
28633
|
+
status: "resolved"
|
|
28634
|
+
});
|
|
28635
|
+
var muteVoiceMonitorIssue = async (store, id, input = {}) => store.update(id, {
|
|
28636
|
+
mutedAt: input.now ?? Date.now(),
|
|
28637
|
+
mutedBy: input.actorId,
|
|
28638
|
+
status: "muted"
|
|
28639
|
+
});
|
|
28640
|
+
var renderVoiceMonitorMarkdown = (report) => {
|
|
28641
|
+
const rows = report.runs.map((run) => `| ${run.id} | ${run.status} | ${run.severity} | ${run.value ?? ""} | ${run.threshold ?? ""} | ${run.detail ?? ""} |`).join(`
|
|
28642
|
+
`);
|
|
28643
|
+
return `# Voice Monitor Report
|
|
28644
|
+
|
|
28645
|
+
- Status: ${report.status}
|
|
28646
|
+
- Checks: ${report.summary.passed}/${report.summary.total} passing
|
|
28647
|
+
- Open issues: ${report.summary.open}
|
|
28648
|
+
- Critical open issues: ${report.summary.criticalOpen}
|
|
28649
|
+
|
|
28650
|
+
| Monitor | Status | Severity | Value | Threshold | Detail |
|
|
28651
|
+
| --- | --- | --- | --- | --- | --- |
|
|
28652
|
+
${rows || "| none | pass | info | | | No monitors configured. |"}
|
|
28653
|
+
`;
|
|
28654
|
+
};
|
|
28655
|
+
var renderVoiceMonitorHTML = (report, options = {}) => {
|
|
28656
|
+
const title = options.title ?? "Voice Monitors";
|
|
28657
|
+
const runs = report.runs.map((run) => `<tr><td>${escapeHtml41(run.label)}</td><td class="${escapeHtml41(run.status)}">${escapeHtml41(run.status)}</td><td>${escapeHtml41(run.severity)}</td><td>${escapeHtml41(String(run.value ?? ""))}</td><td>${escapeHtml41(String(run.threshold ?? ""))}</td><td>${escapeHtml41(run.detail ?? "")}</td></tr>`).join("");
|
|
28658
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml41(issue.label)}</strong> <span class="${escapeHtml41(issue.status)}">${escapeHtml41(issue.status)}</span> ${escapeHtml41(issue.detail ?? "")}</li>`).join("");
|
|
28659
|
+
const snippet = escapeHtml41(`app.use(createVoiceMonitorRoutes({
|
|
28660
|
+
evidence,
|
|
28661
|
+
issueStore,
|
|
28662
|
+
monitors: [defineVoiceMonitor(...)]
|
|
28663
|
+
}));`);
|
|
28664
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml41(title)}</title><style>body{background:#10141b;color:#f8f2df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.hero,.card{background:#171f2b;border:1px solid #2e3a4b;border-radius:24px;margin-bottom:16px;padding:22px}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);line-height:.92;margin:.2rem 0 1rem}.pill{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;margin-right:8px;padding:8px 12px}.pass{color:#86efac}.warn,.acknowledged{color:#fde68a}.fail,.open{color:#fca5a5}.resolved,.muted{color:#cbd5e1}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2e3a4b;padding:12px;text-align:left;vertical-align:top}pre{background:#0c1118;border:1px solid #2e3a4b;border-radius:16px;color:#dbeafe;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Code-owned monitoring</p><h1>${escapeHtml41(title)}</h1><p class="pill ${escapeHtml41(report.status)}">Status: ${escapeHtml41(report.status)}</p><p class="pill">Open issues: ${String(report.summary.open)}</p><p class="pill">Critical: ${String(report.summary.criticalOpen)}</p></section><section class="card"><h2>Monitor Runs</h2><table><thead><tr><th>Monitor</th><th>Status</th><th>Severity</th><th>Value</th><th>Threshold</th><th>Detail</th></tr></thead><tbody>${runs}</tbody></table></section><section class="card"><h2>Issues</h2>${issues ? `<ul>${issues}</ul>` : '<p class="pass">No monitor issues.</p>'}</section><section class="card"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceMonitorRoutes(...)</code></h2><pre><code>${snippet}</code></pre></section></main></body></html>`;
|
|
28665
|
+
};
|
|
28666
|
+
var actorFromRequest = async (request) => {
|
|
28667
|
+
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
28668
|
+
return;
|
|
28669
|
+
}
|
|
28670
|
+
const body = await request.json().catch(() => {
|
|
28671
|
+
return;
|
|
28672
|
+
});
|
|
28673
|
+
return typeof body?.actorId === "string" ? body.actorId : undefined;
|
|
28674
|
+
};
|
|
28675
|
+
var createVoiceMonitorRoutes = (options) => {
|
|
28676
|
+
const path = options.path ?? "/api/voice/monitors";
|
|
28677
|
+
const htmlPath = options.htmlPath === undefined ? "/voice/monitors" : options.htmlPath;
|
|
28678
|
+
const issuePath = options.issuePath ?? "/api/voice/monitor-issues";
|
|
28679
|
+
const issueStore = options.issueStore ?? createVoiceMemoryMonitorIssueStore();
|
|
28680
|
+
const report = () => buildVoiceMonitorRunReport({
|
|
28681
|
+
evidence: options.evidence,
|
|
28682
|
+
issueStore,
|
|
28683
|
+
monitors: options.monitors,
|
|
28684
|
+
now: options.now
|
|
28685
|
+
});
|
|
28686
|
+
const routes = new Elysia44({
|
|
28687
|
+
name: options.name ?? "absolutejs-voice-monitoring"
|
|
28688
|
+
}).get(path, report).get(`${path}.md`, async () => {
|
|
28689
|
+
return new Response(renderVoiceMonitorMarkdown(await report()), {
|
|
28690
|
+
headers: {
|
|
28691
|
+
"Content-Type": "text/markdown; charset=utf-8",
|
|
28692
|
+
...options.headers
|
|
28693
|
+
}
|
|
28694
|
+
});
|
|
28695
|
+
}).get(issuePath, () => issueStore.list()).post(`${issuePath}/:id/acknowledge`, async ({ params, request }) => {
|
|
28696
|
+
const issue = await acknowledgeVoiceMonitorIssue(issueStore, params.id, {
|
|
28697
|
+
actorId: await actorFromRequest(request)
|
|
28698
|
+
});
|
|
28699
|
+
return issue ?? new Response("Issue not found", { status: 404 });
|
|
28700
|
+
}).post(`${issuePath}/:id/resolve`, async ({ params, request }) => {
|
|
28701
|
+
const issue = await resolveVoiceMonitorIssue(issueStore, params.id, {
|
|
28702
|
+
actorId: await actorFromRequest(request)
|
|
28703
|
+
});
|
|
28704
|
+
return issue ?? new Response("Issue not found", { status: 404 });
|
|
28705
|
+
}).post(`${issuePath}/:id/mute`, async ({ params, request }) => {
|
|
28706
|
+
const issue = await muteVoiceMonitorIssue(issueStore, params.id, {
|
|
28707
|
+
actorId: await actorFromRequest(request)
|
|
28708
|
+
});
|
|
28709
|
+
return issue ?? new Response("Issue not found", { status: 404 });
|
|
28710
|
+
});
|
|
28711
|
+
if (htmlPath !== false) {
|
|
28712
|
+
routes.get(htmlPath, async () => {
|
|
28713
|
+
const body = await (options.render ?? renderVoiceMonitorHTML)(await report(), { title: options.title });
|
|
28714
|
+
return new Response(body, {
|
|
28715
|
+
headers: {
|
|
28716
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
28717
|
+
...options.headers
|
|
28718
|
+
}
|
|
28719
|
+
});
|
|
28720
|
+
});
|
|
28721
|
+
}
|
|
28722
|
+
return routes;
|
|
28723
|
+
};
|
|
28505
28724
|
// src/readinessProfiles.ts
|
|
28506
28725
|
var profileSurfaceLabels = {
|
|
28507
28726
|
"meeting-recorder": {
|
|
@@ -28525,6 +28744,7 @@ var profileSurfaceLabels = {
|
|
|
28525
28744
|
observabilityExportDeliveryHistory: "observability export delivery history configured",
|
|
28526
28745
|
phoneAgentSmokes: "phone-agent smoke proof configured",
|
|
28527
28746
|
providerRoutingContracts: "provider routing contracts configured",
|
|
28747
|
+
telephonyWebhookSecurity: "carrier webhook security configured",
|
|
28528
28748
|
traceDeliveries: "trace delivery queue configured"
|
|
28529
28749
|
}
|
|
28530
28750
|
};
|
|
@@ -28547,6 +28767,7 @@ var profileRequiredKeys = {
|
|
|
28547
28767
|
"phoneAgentSmokes",
|
|
28548
28768
|
"campaignReadiness",
|
|
28549
28769
|
"providerRoutingContracts",
|
|
28770
|
+
"telephonyWebhookSecurity",
|
|
28550
28771
|
"auditDeliveries",
|
|
28551
28772
|
"traceDeliveries",
|
|
28552
28773
|
"observabilityExportDeliveryHistory",
|
|
@@ -28567,6 +28788,7 @@ var configuredProfileKeys = (options) => {
|
|
|
28567
28788
|
"phoneAgentSmokes",
|
|
28568
28789
|
"providerRoutingContracts",
|
|
28569
28790
|
"reconnectContracts",
|
|
28791
|
+
"telephonyWebhookSecurity",
|
|
28570
28792
|
"traceDeliveries"
|
|
28571
28793
|
]) {
|
|
28572
28794
|
if (isConfigured(options[key])) {
|
|
@@ -28675,6 +28897,12 @@ var profileExplanation = (profile, options, links) => {
|
|
|
28675
28897
|
key: "providerRoutingContracts",
|
|
28676
28898
|
label: "Provider routing contracts"
|
|
28677
28899
|
},
|
|
28900
|
+
{
|
|
28901
|
+
configured: isConfigured(options.telephonyWebhookSecurity),
|
|
28902
|
+
href: links.telephonyWebhookSecurity,
|
|
28903
|
+
key: "telephonyWebhookSecurity",
|
|
28904
|
+
label: "Carrier webhook security"
|
|
28905
|
+
},
|
|
28678
28906
|
{
|
|
28679
28907
|
configured: isConfigured(options.deliveryRuntime),
|
|
28680
28908
|
href: links.deliveryRuntime,
|
|
@@ -28779,6 +29007,7 @@ var createVoiceReadinessProfile = (profile, options = {}) => {
|
|
|
28779
29007
|
providerRoutingContracts: "/resilience",
|
|
28780
29008
|
resilience: "/resilience",
|
|
28781
29009
|
sessions: "/sessions",
|
|
29010
|
+
telephonyWebhookSecurity: "/api/voice/telephony/webhook-security",
|
|
28782
29011
|
traceDeliveries: "/traces/deliveries"
|
|
28783
29012
|
}, options.links);
|
|
28784
29013
|
return withDefined({
|
|
@@ -28793,6 +29022,7 @@ var createVoiceReadinessProfile = (profile, options = {}) => {
|
|
|
28793
29022
|
profile: profileExplanation(profile, options, links2),
|
|
28794
29023
|
proofSources: options.proofSources,
|
|
28795
29024
|
providerRoutingContracts: options.providerRoutingContracts,
|
|
29025
|
+
telephonyWebhookSecurity: options.telephonyWebhookSecurity,
|
|
28796
29026
|
traceDeliveries: options.traceDeliveries
|
|
28797
29027
|
});
|
|
28798
29028
|
}
|
|
@@ -28851,8 +29081,8 @@ var recommendVoiceReadinessProfile = (options) => {
|
|
|
28851
29081
|
};
|
|
28852
29082
|
};
|
|
28853
29083
|
// src/providerStackRecommendations.ts
|
|
28854
|
-
import { Elysia as
|
|
28855
|
-
var
|
|
29084
|
+
import { Elysia as Elysia45 } from "elysia";
|
|
29085
|
+
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
28856
29086
|
var profileProviderPriorities = {
|
|
28857
29087
|
"meeting-recorder": {
|
|
28858
29088
|
llm: ["openai", "anthropic", "gemini"],
|
|
@@ -29171,17 +29401,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
|
|
|
29171
29401
|
var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
|
|
29172
29402
|
const title = options.title ?? "Voice Provider Contract Matrix";
|
|
29173
29403
|
const rows = report.rows.map((row) => {
|
|
29174
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
29175
|
-
return `<article class="row ${
|
|
29404
|
+
const checks = row.checks.map((check) => `<li class="${escapeHtml42(check.status)}"><strong>${escapeHtml42(check.label)}</strong><span>${escapeHtml42(check.detail ?? check.status)}</span>${check.remediation ? `<em>${check.remediation.href ? `<a href="${escapeHtml42(check.remediation.href)}">${escapeHtml42(check.remediation.label)}</a>` : escapeHtml42(check.remediation.label)}: ${escapeHtml42(check.remediation.detail)}</em>` : ""}</li>`).join("");
|
|
29405
|
+
return `<article class="row ${escapeHtml42(row.status)}">
|
|
29176
29406
|
<div>
|
|
29177
|
-
<p class="eyebrow">${
|
|
29178
|
-
<h2>${
|
|
29179
|
-
<p class="status ${
|
|
29407
|
+
<p class="eyebrow">${escapeHtml42(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
|
|
29408
|
+
<h2>${escapeHtml42(row.provider)}</h2>
|
|
29409
|
+
<p class="status ${escapeHtml42(row.status)}">${escapeHtml42(row.status.toUpperCase())}</p>
|
|
29180
29410
|
</div>
|
|
29181
29411
|
<ul>${checks}</ul>
|
|
29182
29412
|
</article>`;
|
|
29183
29413
|
}).join("");
|
|
29184
|
-
const snippet =
|
|
29414
|
+
const snippet = escapeHtml42(`const providerContracts = () =>
|
|
29185
29415
|
createVoiceProviderContractMatrixPreset('phone-agent', {
|
|
29186
29416
|
env: process.env,
|
|
29187
29417
|
providers: {
|
|
@@ -29202,7 +29432,7 @@ createVoiceProductionReadinessRoutes({
|
|
|
29202
29432
|
providerContractMatrix: () =>
|
|
29203
29433
|
buildVoiceProviderContractMatrix(providerContracts())
|
|
29204
29434
|
});`);
|
|
29205
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
29435
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml42(title)}</title><style>body{background:#0f1412;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive,.row{background:#17201b;border:1px solid #2d3b32;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(125,211,252,.12))}.primitive{background:#111814;border-color:#41604a}.eyebrow{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill,.status{border:1px solid #3f4f45;border-radius:999px;display:inline-flex;padding:8px 12px}.primitive code{color:#bbf7d0}.primitive p{color:#c8d8ca;line-height:1.55;margin:.45rem 0 0}.primitive pre{background:#08110d;border:1px solid #294132;border-radius:18px;color:#d9f99d;margin:16px 0 0;overflow:auto;padding:16px}.status.pass,.row.pass,.pass{border-color:rgba(34,197,94,.65)}.status.warn,.row.warn,.warn{border-color:rgba(245,158,11,.7)}.status.fail,.row.fail,.fail{border-color:rgba(239,68,68,.75)}.row{display:grid;gap:20px;grid-template-columns:minmax(180px,.45fr) 1fr}.row ul{display:grid;gap:10px;list-style:none;margin:0;padding:0}.row li{background:#111814;border:1px solid #2d3b32;border-radius:16px;display:grid;gap:4px;padding:12px}.row li span{color:#b8c2ba}.row li em{color:#f9d77e;font-style:normal}.row li a{color:#86efac}@media(max-width:760px){main{padding:18px}.row{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider contracts</p><h1>${escapeHtml42(title)}</h1><p>Self-hosted provider proof for configured state, required env, latency budgets, fallback, streaming, and declared capabilities.</p><div class="summary"><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.warned)} warning</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} total</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProviderContractMatrixPreset(...)</code> builds this matrix</h2><p>Give AbsoluteJS your configured LLM, STT, and TTS providers once. It turns them into deploy-checkable proof for env, fallback, streaming, latency budgets, selected providers, and profile-required capabilities without a hosted dashboard.</p><pre><code>${snippet}</code></pre></section>${rows || '<article class="row"><p>No provider contracts configured.</p></article>'}</main></body></html>`;
|
|
29206
29436
|
};
|
|
29207
29437
|
var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
|
|
29208
29438
|
var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
@@ -29217,7 +29447,7 @@ var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
|
29217
29447
|
var createVoiceProviderContractMatrixRoutes = (options) => {
|
|
29218
29448
|
const path = options.path ?? "/api/provider-contracts";
|
|
29219
29449
|
const htmlPath = options.htmlPath ?? "/provider-contracts";
|
|
29220
|
-
const routes = new
|
|
29450
|
+
const routes = new Elysia45({
|
|
29221
29451
|
name: options.name ?? "absolutejs-voice-provider-contract-matrix"
|
|
29222
29452
|
});
|
|
29223
29453
|
const jsonHandler = createVoiceProviderContractMatrixJSONHandler(options.matrix);
|
|
@@ -29335,7 +29565,7 @@ var assertVoiceProviderStackEvidence = (report, input = {}) => {
|
|
|
29335
29565
|
return assertion;
|
|
29336
29566
|
};
|
|
29337
29567
|
// src/opsConsoleRoutes.ts
|
|
29338
|
-
import { Elysia as
|
|
29568
|
+
import { Elysia as Elysia46 } from "elysia";
|
|
29339
29569
|
var DEFAULT_LINKS = [
|
|
29340
29570
|
{
|
|
29341
29571
|
description: "Quality gates for CI, deploy checks, and production readiness.",
|
|
@@ -29370,7 +29600,7 @@ var DEFAULT_LINKS = [
|
|
|
29370
29600
|
label: "Handoffs"
|
|
29371
29601
|
}
|
|
29372
29602
|
];
|
|
29373
|
-
var
|
|
29603
|
+
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
29374
29604
|
var countProviderStatuses = (providers) => {
|
|
29375
29605
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
29376
29606
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -29439,20 +29669,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
29439
29669
|
trace
|
|
29440
29670
|
};
|
|
29441
29671
|
};
|
|
29442
|
-
var renderMetricCard = (input) => `<article class="metric"><span>${
|
|
29672
|
+
var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml43(input.label)}</span><strong>${escapeHtml43(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml43(input.status)}">${escapeHtml43(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml43(input.href)}">Open</a>` : ""}</article>`;
|
|
29443
29673
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
29444
29674
|
const links = report.links.map((link) => `<article class="surface">
|
|
29445
|
-
<div><h2>${
|
|
29446
|
-
<p><a href="${
|
|
29675
|
+
<div><h2>${escapeHtml43(link.label)}</h2>${link.description ? `<p>${escapeHtml43(link.description)}</p>` : ""}</div>
|
|
29676
|
+
<p><a href="${escapeHtml43(link.href)}">Open ${escapeHtml43(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml43(link.statusHref)}">Status</a>` : ""}</p>
|
|
29447
29677
|
</article>`).join("");
|
|
29448
|
-
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${
|
|
29449
|
-
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${
|
|
29678
|
+
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml43(session.sessionId)}</td><td>${escapeHtml43(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml43(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
|
|
29679
|
+
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml43(event.kind)}</td><td>${escapeHtml43(event.provider ?? "unknown")}</td><td>${escapeHtml43(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml43(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
|
|
29450
29680
|
const title = options.title ?? "AbsoluteJS Voice Ops Console";
|
|
29451
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
29681
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml43(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;background:#101316;color:#f6f2e8;margin:0}main{max-width:1180px;margin:auto;padding:32px}a{color:#fbbf24}header{display:flex;justify-content:space-between;gap:24px;align-items:flex-start;margin-bottom:24px}.eyebrow{color:#fbbf24;font-weight:800;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.5rem);line-height:.95;margin:.2rem 0 1rem}.muted{color:#a8b0b8}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.metric,.surface{background:#181d22;border:1px solid #2a323a;border-radius:20px;padding:18px}.metric strong{display:block;font-size:2.2rem;margin:.25rem 0}.pass,.healthy{color:#86efac}.fail,.failed,.degraded{color:#fca5a5}.surfaces{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));margin:24px 0}table{width:100%;border-collapse:collapse;background:#181d22;border-radius:16px;overflow:hidden;margin:12px 0 28px}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left}section{margin-top:30px}@media(max-width:700px){main{padding:20px}header{display:block}}</style></head><body><main><header><div><p class="eyebrow">Self-hosted voice operations</p><h1>${escapeHtml43(title)}</h1><p class="muted">One deployable control plane for quality gates, failover, traces, sessions, handoffs, and provider health.</p></div><p class="muted">Checked ${escapeHtml43(new Date(report.checkedAt).toLocaleString())}</p></header><div class="grid">${renderMetricCard({ label: "Quality", value: report.quality.status, status: report.quality.status, href: "/quality" })}${renderMetricCard({ label: "Events", value: report.eventCount, href: "/diagnostics" })}${renderMetricCard({ label: "Sessions", value: report.sessions.total, status: report.sessions.failed > 0 ? "failed" : "healthy", href: "/sessions" })}${renderMetricCard({ label: "Handoffs failed", value: report.handoffs.failed, status: report.handoffs.failed > 0 ? "failed" : "healthy", href: "/handoffs" })}${renderMetricCard({ label: "Providers degraded", value: report.providers.degraded, status: report.providers.degraded > 0 ? "degraded" : "healthy", href: "/resilience" })}</div><section><h2>Operational Surfaces</h2><div class="surfaces">${links}</div></section><section><h2>Recent Sessions</h2><table><thead><tr><th>Session</th><th>Status</th><th>Turns</th><th>Errors</th><th>Replay</th></tr></thead><tbody>${sessions}</tbody></table></section><section><h2>Recent Provider Routing</h2><table><thead><tr><th>Kind</th><th>Provider</th><th>Status</th><th>Elapsed</th><th>Session</th></tr></thead><tbody>${routing}</tbody></table></section></main></body></html>`;
|
|
29452
29682
|
};
|
|
29453
29683
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
29454
29684
|
const path = options.path ?? "/ops-console";
|
|
29455
|
-
const routes = new
|
|
29685
|
+
const routes = new Elysia46({
|
|
29456
29686
|
name: options.name ?? "absolutejs-voice-ops-console"
|
|
29457
29687
|
});
|
|
29458
29688
|
const getReport = () => buildVoiceOpsConsoleReport(options);
|
|
@@ -29469,7 +29699,7 @@ var createVoiceOpsConsoleRoutes = (options) => {
|
|
|
29469
29699
|
return routes;
|
|
29470
29700
|
};
|
|
29471
29701
|
// src/incidentBundle.ts
|
|
29472
|
-
import { Elysia as
|
|
29702
|
+
import { Elysia as Elysia47 } from "elysia";
|
|
29473
29703
|
var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
|
|
29474
29704
|
if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
|
|
29475
29705
|
return false;
|
|
@@ -29670,7 +29900,7 @@ var buildVoiceIncidentBundle = async (options) => {
|
|
|
29670
29900
|
var createVoiceIncidentBundleRoutes = (options) => {
|
|
29671
29901
|
const path = options.path ?? "/api/voice-incidents/:sessionId";
|
|
29672
29902
|
const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
|
|
29673
|
-
const routes = new
|
|
29903
|
+
const routes = new Elysia47({
|
|
29674
29904
|
name: options.name ?? "absolutejs-voice-incident-bundle"
|
|
29675
29905
|
});
|
|
29676
29906
|
const getSessionId = (params) => params.sessionId ?? "";
|
|
@@ -29871,19 +30101,19 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
29871
30101
|
};
|
|
29872
30102
|
};
|
|
29873
30103
|
// src/opsStatusRoutes.ts
|
|
29874
|
-
import { Elysia as
|
|
29875
|
-
var
|
|
30104
|
+
import { Elysia as Elysia48 } from "elysia";
|
|
30105
|
+
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
29876
30106
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
29877
30107
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
29878
30108
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
29879
30109
|
const value = "recovered" in surface ? surface.total === 0 ? "0 events" : `${surface.recovered}/${surface.total}` : ("auditTotal" in surface) ? `${surface.auditTotal + surface.traceTotal} deliveries` : ("total" in surface) ? `${Math.max(surface.total - ("failed" in surface ? surface.failed : ("degraded" in surface) ? surface.degraded : 0), 0)}/${surface.total}` : surface.status;
|
|
29880
|
-
return `<article class="surface ${
|
|
30110
|
+
return `<article class="surface ${escapeHtml44(surface.status)}"><span>${escapeHtml44(surface.status.toUpperCase())}</span><h2>${escapeHtml44(key)}</h2><strong>${escapeHtml44(value)}</strong></article>`;
|
|
29881
30111
|
}).join("");
|
|
29882
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30112
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml44(title)}</title><style>body{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.2),rgba(245,158,11,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.surfaces{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.surface{background:#151d26;border:1px solid #283544;border-radius:20px;padding:18px}.surface span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.surface strong{font-size:1.5rem}.pass{border-color:rgba(34,197,94,.55)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Ops status</p><h1>${escapeHtml44(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml44(report.status)}">Overall: ${escapeHtml44(report.status.toUpperCase())}</p><p>${report.passed}/${report.total} checks passing</p></section><section class="surfaces">${surfaces || '<article class="surface pass"><span>PASS</span><h2>No checks configured</h2><strong>0/0</strong></article>'}</section></main></body></html>`;
|
|
29883
30113
|
};
|
|
29884
30114
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
29885
30115
|
const path = options.path ?? "/api/voice/ops-status";
|
|
29886
|
-
const routes = new
|
|
30116
|
+
const routes = new Elysia48({
|
|
29887
30117
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
29888
30118
|
});
|
|
29889
30119
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -30316,8 +30546,8 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
30316
30546
|
};
|
|
30317
30547
|
};
|
|
30318
30548
|
// src/traceDeliveryRoutes.ts
|
|
30319
|
-
import { Elysia as
|
|
30320
|
-
var
|
|
30549
|
+
import { Elysia as Elysia49 } from "elysia";
|
|
30550
|
+
var escapeHtml45 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30321
30551
|
var getString19 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
30322
30552
|
var getNumber11 = (value) => {
|
|
30323
30553
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -30398,14 +30628,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
30398
30628
|
if (entries.length === 0) {
|
|
30399
30629
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
30400
30630
|
}
|
|
30401
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
30631
|
+
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml45(sinkId)}</strong>: ${escapeHtml45(result.status)}${result.deliveredTo ? ` to ${escapeHtml45(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml45(result.error)})` : ""}</li>`).join("")}</ul>`;
|
|
30402
30632
|
};
|
|
30403
|
-
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
30633
|
+
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml45(event.type)} <small>${escapeHtml45(event.id)}</small>${event.sessionId ? ` session=${escapeHtml45(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
|
|
30404
30634
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
30405
30635
|
const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
|
|
30406
|
-
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${
|
|
30407
|
-
const rows = report.deliveries.map((delivery) => `<article class="delivery ${
|
|
30408
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30636
|
+
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml45(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
|
|
30637
|
+
const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml45(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml45(delivery.deliveryStatus)}</span><h2>${escapeHtml45(delivery.id)}</h2><p>${escapeHtml45(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml45(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml45(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
|
|
30638
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml45(title)}</title><style>body{background:#0f1318;color:#f4efe1;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(14,165,233,.14));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#86efac;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.grid{display:grid;gap:12px;grid-template-columns:repeat(4,1fr);margin-bottom:16px}.grid article,.delivery{background:#151b22;border:1px solid #26313d;border-radius:22px;padding:18px}.grid span,.delivery span{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.grid strong{display:block;font-size:2rem}.deliveries{display:grid;gap:14px}.delivery.failed{border-color:rgba(239,68,68,.75)}.delivery.pending{border-color:rgba(245,158,11,.7)}.delivery.delivered{border-color:rgba(34,197,94,.55)}.delivery.skipped{border-color:rgba(148,163,184,.6)}.head{align-items:start;display:flex;gap:14px;justify-content:space-between}.delivery h2{font-size:1.05rem;margin:.3rem 0;overflow-wrap:anywhere}.delivery h3{margin:1rem 0 .3rem}.delivery p,.delivery li{color:#c8d0d8}.error{color:#fecaca!important}button{background:#86efac;border:0;border-radius:999px;color:#07111f;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}@media(max-width:760px){main{padding:20px}.grid{grid-template-columns:1fr 1fr}.head{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Trace export health</p><h1>${escapeHtml45(title)}</h1><p>Checked ${escapeHtml45(new Date(report.checkedAt).toLocaleString())}. Showing ${String(report.deliveries.length)} delivery item(s).</p>${drainAction}</section>${renderMetricGrid3(report)}<section class="deliveries">${rows || "<p>No trace deliveries match this filter.</p>"}</section></main></body></html>`;
|
|
30409
30639
|
};
|
|
30410
30640
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
30411
30641
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -30425,7 +30655,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
30425
30655
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
30426
30656
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
30427
30657
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
30428
|
-
const routes = new
|
|
30658
|
+
const routes = new Elysia49({
|
|
30429
30659
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
30430
30660
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
30431
30661
|
if (htmlPath !== false) {
|
|
@@ -30522,7 +30752,7 @@ var createVoiceMemoryStore = () => {
|
|
|
30522
30752
|
return { get, getOrCreate, list, remove, set };
|
|
30523
30753
|
};
|
|
30524
30754
|
// src/opsWebhook.ts
|
|
30525
|
-
import { Elysia as
|
|
30755
|
+
import { Elysia as Elysia50 } from "elysia";
|
|
30526
30756
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
30527
30757
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
30528
30758
|
const encoder = new TextEncoder;
|
|
@@ -30652,7 +30882,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
30652
30882
|
};
|
|
30653
30883
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
30654
30884
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
30655
|
-
return new
|
|
30885
|
+
return new Elysia50().post(path, async ({ body, request, set }) => {
|
|
30656
30886
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
30657
30887
|
if (options.signingSecret) {
|
|
30658
30888
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -31107,7 +31337,7 @@ var resolveVoiceOpsPreset = (name, overrides = {}) => {
|
|
|
31107
31337
|
};
|
|
31108
31338
|
};
|
|
31109
31339
|
// src/postCallAnalysis.ts
|
|
31110
|
-
import { Elysia as
|
|
31340
|
+
import { Elysia as Elysia51 } from "elysia";
|
|
31111
31341
|
var isStore = (value) => Boolean(value) && typeof value === "object" && value !== null && ("list" in value);
|
|
31112
31342
|
var asArray = async (value) => Array.isArray(value) ? value : isStore(value) ? await value.list() : [];
|
|
31113
31343
|
var getPathValue3 = (source, path) => {
|
|
@@ -31286,7 +31516,7 @@ var resolvePostCallAnalysisReport = async (options, input) => {
|
|
|
31286
31516
|
};
|
|
31287
31517
|
var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
31288
31518
|
const path = options.path ?? "/api/voice/post-call-analysis";
|
|
31289
|
-
const routes = new
|
|
31519
|
+
const routes = new Elysia51({
|
|
31290
31520
|
name: options.name ?? "absolutejs-voice-post-call-analysis"
|
|
31291
31521
|
});
|
|
31292
31522
|
routes.get(path, async ({ query }) => {
|
|
@@ -31311,7 +31541,7 @@ var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
|
31311
31541
|
return routes;
|
|
31312
31542
|
};
|
|
31313
31543
|
// src/guardrails.ts
|
|
31314
|
-
import { Elysia as
|
|
31544
|
+
import { Elysia as Elysia52 } from "elysia";
|
|
31315
31545
|
var stringifyContent = (value) => typeof value === "string" ? value : JSON.stringify(value) ?? "";
|
|
31316
31546
|
var appliesToStage = (rule, stage) => !rule.stages || rule.stages.length === 0 || rule.stages.includes(stage);
|
|
31317
31547
|
var matchesRule = async (rule, input) => {
|
|
@@ -31613,7 +31843,7 @@ var resolveGuardrailReport = async (options, input) => {
|
|
|
31613
31843
|
};
|
|
31614
31844
|
var createVoiceGuardrailRoutes = (options = {}) => {
|
|
31615
31845
|
const path = options.path ?? "/api/voice/guardrails";
|
|
31616
|
-
const routes = new
|
|
31846
|
+
const routes = new Elysia52({
|
|
31617
31847
|
name: options.name ?? "absolutejs-voice-guardrails"
|
|
31618
31848
|
});
|
|
31619
31849
|
routes.all(path, async ({ request }) => {
|
|
@@ -32109,6 +32339,7 @@ export {
|
|
|
32109
32339
|
resolveVoiceOpsTaskAssignment,
|
|
32110
32340
|
resolveVoiceOpsTaskAgeBucket,
|
|
32111
32341
|
resolveVoiceOpsPreset,
|
|
32342
|
+
resolveVoiceMonitorIssue,
|
|
32112
32343
|
resolveVoiceDiagnosticsTraceFilter,
|
|
32113
32344
|
resolveVoiceAuditTrailFilter,
|
|
32114
32345
|
resolveVoiceAuditDeliveryFilter,
|
|
@@ -32153,6 +32384,8 @@ export {
|
|
|
32153
32384
|
renderVoiceOperationsRecordGuardrailMarkdown,
|
|
32154
32385
|
renderVoiceObservabilityExportReplayHTML,
|
|
32155
32386
|
renderVoiceObservabilityExportMarkdown,
|
|
32387
|
+
renderVoiceMonitorMarkdown,
|
|
32388
|
+
renderVoiceMonitorHTML,
|
|
32156
32389
|
renderVoiceLiveLatencyHTML,
|
|
32157
32390
|
renderVoiceLatencySLOMarkdown,
|
|
32158
32391
|
renderVoiceHandoffHealthHTML,
|
|
@@ -32195,6 +32428,7 @@ export {
|
|
|
32195
32428
|
pruneVoiceIncidentBundleArtifacts,
|
|
32196
32429
|
parseVoiceTelephonyWebhookEvent,
|
|
32197
32430
|
normalizeVoiceProofTrendReport,
|
|
32431
|
+
muteVoiceMonitorIssue,
|
|
32198
32432
|
matchesVoiceOpsTaskAssignmentRule,
|
|
32199
32433
|
markVoiceOpsTaskSLABreached,
|
|
32200
32434
|
loadVoiceObservabilityExportReplaySource,
|
|
@@ -32397,10 +32631,12 @@ export {
|
|
|
32397
32631
|
createVoiceObservabilityExportSchema,
|
|
32398
32632
|
createVoiceObservabilityExportRoutes,
|
|
32399
32633
|
createVoiceObservabilityExportReplayRoutes,
|
|
32634
|
+
createVoiceMonitorRoutes,
|
|
32400
32635
|
createVoiceMemoryTraceSinkDeliveryStore,
|
|
32401
32636
|
createVoiceMemoryTraceEventStore,
|
|
32402
32637
|
createVoiceMemoryStore,
|
|
32403
32638
|
createVoiceMemoryObservabilityExportDeliveryReceiptStore,
|
|
32639
|
+
createVoiceMemoryMonitorIssueStore,
|
|
32404
32640
|
createVoiceMemoryLiveOpsControlStore,
|
|
32405
32641
|
createVoiceMemoryIncidentBundleStore,
|
|
32406
32642
|
createVoiceMemoryHandoffDeliveryStore,
|
|
@@ -32548,6 +32784,7 @@ export {
|
|
|
32548
32784
|
buildVoiceObservabilityExportDeliveryHistory,
|
|
32549
32785
|
buildVoiceObservabilityExport,
|
|
32550
32786
|
buildVoiceObservabilityArtifactIndex,
|
|
32787
|
+
buildVoiceMonitorRunReport,
|
|
32551
32788
|
buildVoiceLiveOpsControlState,
|
|
32552
32789
|
buildVoiceLatencySLOGate,
|
|
32553
32790
|
buildVoiceIncidentBundle,
|
|
@@ -32600,6 +32837,7 @@ export {
|
|
|
32600
32837
|
applyVoiceCampaignTelephonyOutcome,
|
|
32601
32838
|
applyRiskTieredPhraseHintCorrections,
|
|
32602
32839
|
applyPhraseHintCorrections,
|
|
32840
|
+
acknowledgeVoiceMonitorIssue,
|
|
32603
32841
|
VOICE_LIVE_OPS_ACTIONS,
|
|
32604
32842
|
TURN_PROFILE_DEFAULTS,
|
|
32605
32843
|
DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS
|
|
@@ -2,6 +2,7 @@ import { Elysia } from 'elysia';
|
|
|
2
2
|
import { type VoiceProviderFallbackRecoverySummary } from './sessionReplay';
|
|
3
3
|
import { type VoiceTelephonyCarrierMatrixInput } from './telephony/matrix';
|
|
4
4
|
import { type VoiceTelephonyWebhookSecurityOptions, type VoiceTelephonyWebhookSecurityReport } from './telephony/security';
|
|
5
|
+
import type { VoiceMonitorRunReport } from './voiceMonitoring';
|
|
5
6
|
import type { VoiceTraceEventStore } from './trace';
|
|
6
7
|
import type { VoiceTraceSinkDeliveryStore } from './trace';
|
|
7
8
|
import type { VoiceAgentSquadContractReport } from './agentSquadContract';
|
|
@@ -118,6 +119,7 @@ export type VoiceProductionReadinessReport = {
|
|
|
118
119
|
operationsRecords?: string;
|
|
119
120
|
observabilityExport?: string;
|
|
120
121
|
observabilityExportDeliveries?: string;
|
|
122
|
+
monitoring?: string;
|
|
121
123
|
opsActions?: string;
|
|
122
124
|
opsRecovery?: string;
|
|
123
125
|
phoneAgentSmoke?: string;
|
|
@@ -176,6 +178,12 @@ export type VoiceProductionReadinessReport = {
|
|
|
176
178
|
total: number;
|
|
177
179
|
warnings: number;
|
|
178
180
|
};
|
|
181
|
+
monitoring?: {
|
|
182
|
+
criticalOpen: number;
|
|
183
|
+
open: number;
|
|
184
|
+
status: VoiceProductionReadinessStatus;
|
|
185
|
+
total: number;
|
|
186
|
+
};
|
|
179
187
|
opsActionHistory?: VoiceProductionReadinessOpsActionHistorySummary;
|
|
180
188
|
opsRecovery?: {
|
|
181
189
|
issues: number;
|
|
@@ -393,6 +401,10 @@ export type VoiceProductionReadinessRoutesOptions = {
|
|
|
393
401
|
links?: VoiceProductionReadinessReport['links'];
|
|
394
402
|
llmProviders?: readonly string[];
|
|
395
403
|
name?: string;
|
|
404
|
+
monitoring?: false | VoiceMonitorRunReport | ((input: {
|
|
405
|
+
query: Record<string, unknown>;
|
|
406
|
+
request: Request;
|
|
407
|
+
}) => Promise<VoiceMonitorRunReport> | VoiceMonitorRunReport);
|
|
396
408
|
opsActionHistory?: false | VoiceProductionReadinessOpsActionHistoryOptions;
|
|
397
409
|
opsRecovery?: false | VoiceOpsRecoveryReport | ((input: {
|
|
398
410
|
query: Record<string, unknown>;
|
|
@@ -16,6 +16,7 @@ export type VoiceReadinessProfileOptions = {
|
|
|
16
16
|
proofSources?: VoiceProductionReadinessRoutesOptions['proofSources'];
|
|
17
17
|
providerRoutingContracts?: VoiceProductionReadinessRoutesOptions['providerRoutingContracts'];
|
|
18
18
|
reconnectContracts?: VoiceProductionReadinessRoutesOptions['reconnectContracts'];
|
|
19
|
+
telephonyWebhookSecurity?: VoiceProductionReadinessRoutesOptions['telephonyWebhookSecurity'];
|
|
19
20
|
traceDeliveries?: VoiceProductionReadinessTraceDeliveryOptions;
|
|
20
21
|
};
|
|
21
22
|
export type VoiceReadinessProfileRoutesOptions = Partial<Omit<VoiceProductionReadinessRoutesOptions, 'store'>>;
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
export type VoiceMonitorStatus = 'fail' | 'pass' | 'warn';
|
|
3
|
+
export type VoiceMonitorSeverity = 'critical' | 'info' | 'warn';
|
|
4
|
+
export type VoiceMonitorIssueStatus = 'acknowledged' | 'muted' | 'open' | 'resolved';
|
|
5
|
+
export type VoiceMonitorEvaluationInput<TEvidence = unknown> = {
|
|
6
|
+
evidence: TEvidence;
|
|
7
|
+
now: number;
|
|
8
|
+
};
|
|
9
|
+
export type VoiceMonitorEvaluation = {
|
|
10
|
+
detail?: string;
|
|
11
|
+
impactedSessions?: readonly string[];
|
|
12
|
+
operationsRecordHrefs?: readonly string[];
|
|
13
|
+
status: VoiceMonitorStatus;
|
|
14
|
+
threshold?: number | string;
|
|
15
|
+
value?: number | string;
|
|
16
|
+
};
|
|
17
|
+
export type VoiceMonitorDefinition<TEvidence = unknown> = {
|
|
18
|
+
description?: string;
|
|
19
|
+
id: string;
|
|
20
|
+
label: string;
|
|
21
|
+
severity?: VoiceMonitorSeverity;
|
|
22
|
+
windowMs?: number;
|
|
23
|
+
evaluate: (input: VoiceMonitorEvaluationInput<TEvidence>) => Promise<VoiceMonitorEvaluation> | VoiceMonitorEvaluation;
|
|
24
|
+
};
|
|
25
|
+
export type VoiceMonitorRun = VoiceMonitorEvaluation & {
|
|
26
|
+
checkedAt: number;
|
|
27
|
+
description?: string;
|
|
28
|
+
id: string;
|
|
29
|
+
label: string;
|
|
30
|
+
severity: VoiceMonitorSeverity;
|
|
31
|
+
windowMs?: number;
|
|
32
|
+
};
|
|
33
|
+
export type VoiceMonitorIssue = {
|
|
34
|
+
acknowledgedAt?: number;
|
|
35
|
+
acknowledgedBy?: string;
|
|
36
|
+
createdAt: number;
|
|
37
|
+
detail?: string;
|
|
38
|
+
id: string;
|
|
39
|
+
impactedSessions: string[];
|
|
40
|
+
label: string;
|
|
41
|
+
lastSeenAt: number;
|
|
42
|
+
monitorId: string;
|
|
43
|
+
mutedAt?: number;
|
|
44
|
+
mutedBy?: string;
|
|
45
|
+
operationsRecordHrefs: string[];
|
|
46
|
+
resolvedAt?: number;
|
|
47
|
+
resolvedBy?: string;
|
|
48
|
+
severity: VoiceMonitorSeverity;
|
|
49
|
+
status: VoiceMonitorIssueStatus;
|
|
50
|
+
threshold?: number | string;
|
|
51
|
+
value?: number | string;
|
|
52
|
+
};
|
|
53
|
+
export type VoiceMonitorIssueStore = {
|
|
54
|
+
list: () => Promise<VoiceMonitorIssue[]> | VoiceMonitorIssue[];
|
|
55
|
+
upsert: (issue: VoiceMonitorIssue) => Promise<VoiceMonitorIssue> | VoiceMonitorIssue;
|
|
56
|
+
update: (id: string, patch: Partial<VoiceMonitorIssue>) => Promise<VoiceMonitorIssue | undefined> | VoiceMonitorIssue | undefined;
|
|
57
|
+
};
|
|
58
|
+
export type VoiceMonitorRunReport = {
|
|
59
|
+
checkedAt: number;
|
|
60
|
+
issues: VoiceMonitorIssue[];
|
|
61
|
+
runs: VoiceMonitorRun[];
|
|
62
|
+
status: VoiceMonitorStatus;
|
|
63
|
+
summary: {
|
|
64
|
+
acknowledged: number;
|
|
65
|
+
criticalOpen: number;
|
|
66
|
+
failed: number;
|
|
67
|
+
muted: number;
|
|
68
|
+
open: number;
|
|
69
|
+
passed: number;
|
|
70
|
+
resolved: number;
|
|
71
|
+
total: number;
|
|
72
|
+
warned: number;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
export type VoiceMonitorRunOptions<TEvidence = unknown> = {
|
|
76
|
+
evidence: TEvidence;
|
|
77
|
+
issueStore?: VoiceMonitorIssueStore;
|
|
78
|
+
monitors: readonly VoiceMonitorDefinition<TEvidence>[];
|
|
79
|
+
now?: number;
|
|
80
|
+
};
|
|
81
|
+
export type VoiceMonitorRoutesOptions<TEvidence = unknown> = VoiceMonitorRunOptions<TEvidence> & {
|
|
82
|
+
headers?: HeadersInit;
|
|
83
|
+
htmlPath?: false | string;
|
|
84
|
+
issuePath?: string;
|
|
85
|
+
name?: string;
|
|
86
|
+
path?: string;
|
|
87
|
+
render?: (report: VoiceMonitorRunReport) => Promise<string> | string;
|
|
88
|
+
title?: string;
|
|
89
|
+
};
|
|
90
|
+
export declare const createVoiceMemoryMonitorIssueStore: (initial?: readonly VoiceMonitorIssue[]) => VoiceMonitorIssueStore;
|
|
91
|
+
export declare const buildVoiceMonitorRunReport: <TEvidence = unknown>(options: VoiceMonitorRunOptions<TEvidence>) => Promise<VoiceMonitorRunReport>;
|
|
92
|
+
export declare const acknowledgeVoiceMonitorIssue: (store: VoiceMonitorIssueStore, id: string, input?: {
|
|
93
|
+
actorId?: string;
|
|
94
|
+
now?: number;
|
|
95
|
+
}) => Promise<VoiceMonitorIssue | undefined>;
|
|
96
|
+
export declare const resolveVoiceMonitorIssue: (store: VoiceMonitorIssueStore, id: string, input?: {
|
|
97
|
+
actorId?: string;
|
|
98
|
+
now?: number;
|
|
99
|
+
}) => Promise<VoiceMonitorIssue | undefined>;
|
|
100
|
+
export declare const muteVoiceMonitorIssue: (store: VoiceMonitorIssueStore, id: string, input?: {
|
|
101
|
+
actorId?: string;
|
|
102
|
+
now?: number;
|
|
103
|
+
}) => Promise<VoiceMonitorIssue | undefined>;
|
|
104
|
+
export declare const renderVoiceMonitorMarkdown: (report: VoiceMonitorRunReport) => string;
|
|
105
|
+
export declare const renderVoiceMonitorHTML: (report: VoiceMonitorRunReport, options?: {
|
|
106
|
+
title?: string;
|
|
107
|
+
}) => string;
|
|
108
|
+
export declare const createVoiceMonitorRoutes: <TEvidence = unknown>(options: VoiceMonitorRoutesOptions<TEvidence>) => Elysia<"", {
|
|
109
|
+
decorator: {};
|
|
110
|
+
store: {};
|
|
111
|
+
derive: {};
|
|
112
|
+
resolve: {};
|
|
113
|
+
}, {
|
|
114
|
+
typebox: {};
|
|
115
|
+
error: {};
|
|
116
|
+
}, {
|
|
117
|
+
schema: {};
|
|
118
|
+
standaloneSchema: {};
|
|
119
|
+
macro: {};
|
|
120
|
+
macroFn: {};
|
|
121
|
+
parser: {};
|
|
122
|
+
response: {};
|
|
123
|
+
}, {
|
|
124
|
+
[x: string]: {
|
|
125
|
+
get: {
|
|
126
|
+
body: unknown;
|
|
127
|
+
params: {};
|
|
128
|
+
query: unknown;
|
|
129
|
+
headers: unknown;
|
|
130
|
+
response: {
|
|
131
|
+
200: VoiceMonitorRunReport;
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
} & {
|
|
136
|
+
[x: `${string}.md`]: {
|
|
137
|
+
get: {
|
|
138
|
+
body: unknown;
|
|
139
|
+
params: {};
|
|
140
|
+
query: unknown;
|
|
141
|
+
headers: unknown;
|
|
142
|
+
response: {
|
|
143
|
+
200: Response;
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
} & {
|
|
148
|
+
[x: string]: {
|
|
149
|
+
get: {
|
|
150
|
+
body: unknown;
|
|
151
|
+
params: {};
|
|
152
|
+
query: unknown;
|
|
153
|
+
headers: unknown;
|
|
154
|
+
response: {
|
|
155
|
+
200: VoiceMonitorIssue[];
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
} & {
|
|
160
|
+
[x: string]: {
|
|
161
|
+
":id": {
|
|
162
|
+
acknowledge: {
|
|
163
|
+
post: {
|
|
164
|
+
body: unknown;
|
|
165
|
+
params: {
|
|
166
|
+
id: string;
|
|
167
|
+
} & {};
|
|
168
|
+
query: unknown;
|
|
169
|
+
headers: unknown;
|
|
170
|
+
response: {
|
|
171
|
+
200: Response | VoiceMonitorIssue;
|
|
172
|
+
422: {
|
|
173
|
+
type: "validation";
|
|
174
|
+
on: string;
|
|
175
|
+
summary?: string;
|
|
176
|
+
message?: string;
|
|
177
|
+
found?: unknown;
|
|
178
|
+
property?: string;
|
|
179
|
+
expected?: string;
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
} & {
|
|
187
|
+
[x: string]: {
|
|
188
|
+
":id": {
|
|
189
|
+
resolve: {
|
|
190
|
+
post: {
|
|
191
|
+
body: unknown;
|
|
192
|
+
params: {
|
|
193
|
+
id: string;
|
|
194
|
+
} & {};
|
|
195
|
+
query: unknown;
|
|
196
|
+
headers: unknown;
|
|
197
|
+
response: {
|
|
198
|
+
200: Response | VoiceMonitorIssue;
|
|
199
|
+
422: {
|
|
200
|
+
type: "validation";
|
|
201
|
+
on: string;
|
|
202
|
+
summary?: string;
|
|
203
|
+
message?: string;
|
|
204
|
+
found?: unknown;
|
|
205
|
+
property?: string;
|
|
206
|
+
expected?: string;
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
} & {
|
|
214
|
+
[x: string]: {
|
|
215
|
+
":id": {
|
|
216
|
+
mute: {
|
|
217
|
+
post: {
|
|
218
|
+
body: unknown;
|
|
219
|
+
params: {
|
|
220
|
+
id: string;
|
|
221
|
+
} & {};
|
|
222
|
+
query: unknown;
|
|
223
|
+
headers: unknown;
|
|
224
|
+
response: {
|
|
225
|
+
200: Response | VoiceMonitorIssue;
|
|
226
|
+
422: {
|
|
227
|
+
type: "validation";
|
|
228
|
+
on: string;
|
|
229
|
+
summary?: string;
|
|
230
|
+
message?: string;
|
|
231
|
+
found?: unknown;
|
|
232
|
+
property?: string;
|
|
233
|
+
expected?: string;
|
|
234
|
+
};
|
|
235
|
+
};
|
|
236
|
+
};
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
};
|
|
240
|
+
}, {
|
|
241
|
+
derive: {};
|
|
242
|
+
resolve: {};
|
|
243
|
+
schema: {};
|
|
244
|
+
standaloneSchema: {};
|
|
245
|
+
response: {};
|
|
246
|
+
}, {
|
|
247
|
+
derive: {};
|
|
248
|
+
resolve: {};
|
|
249
|
+
schema: {};
|
|
250
|
+
standaloneSchema: {};
|
|
251
|
+
response: {};
|
|
252
|
+
}>;
|