@absolutejs/voice 0.0.22-beta.195 → 0.0.22-beta.196
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 +265 -20
- package/dist/opsRecovery.d.ts +136 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -52,6 +52,7 @@ export { createVoiceReadinessProfile, recommendVoiceReadinessProfile } from './r
|
|
|
52
52
|
export { buildVoiceProviderContractMatrix, createVoiceProviderContractMatrixHTMLHandler, createVoiceProviderContractMatrixJSONHandler, createVoiceProviderContractMatrixPreset, createVoiceProviderContractMatrixRoutes, evaluateVoiceProviderStackGaps, renderVoiceProviderContractMatrixHTML, recommendVoiceProviderStack } from './providerStackRecommendations';
|
|
53
53
|
export { buildVoiceOpsConsoleReport, createVoiceOpsConsoleRoutes, renderVoiceOpsConsoleHTML } from './opsConsoleRoutes';
|
|
54
54
|
export { buildVoiceOperationsRecord, createVoiceOperationsRecordRoutes, renderVoiceOperationsRecordHTML } from './operationsRecord';
|
|
55
|
+
export { buildVoiceOpsRecoveryReadinessCheck, buildVoiceOpsRecoveryReport, createVoiceOpsRecoveryRoutes, renderVoiceOpsRecoveryHTML, renderVoiceOpsRecoveryMarkdown } from './opsRecovery';
|
|
55
56
|
export { buildVoiceIncidentBundle, createStoredVoiceIncidentBundleArtifact, createVoiceIncidentBundleRoutes, createVoiceMemoryIncidentBundleStore, pruneVoiceIncidentBundleArtifacts, saveVoiceIncidentBundleArtifact } from './incidentBundle';
|
|
56
57
|
export { summarizeVoiceOpsStatus } from './opsStatus';
|
|
57
58
|
export { createVoiceOpsStatusRoutes, renderVoiceOpsStatusHTML } from './opsStatusRoutes';
|
|
@@ -114,6 +115,7 @@ export type { VoiceProductionReadinessAction, VoiceProductionReadinessAuditOptio
|
|
|
114
115
|
export type { VoiceReadinessProfileName, VoiceReadinessProfileOptions, VoiceReadinessProfileRecommendation, VoiceReadinessProfileRecommendationScore, VoiceReadinessProfileRoutesOptions } from './readinessProfiles';
|
|
115
116
|
export type { VoiceProviderStackChoice, VoiceProviderStackCapabilities, VoiceProviderStackCapabilityGap, VoiceProviderStackCapabilityGapInput, VoiceProviderStackCapabilityGapReport, VoiceProviderContractCheck, VoiceProviderContractCheckStatus, VoiceProviderContractDefinition, VoiceProviderContractMatrixHandlerOptions, VoiceProviderContractMatrixHTMLHandlerOptions, VoiceProviderContractMatrixInput, VoiceProviderContractMatrixPresetOptions, VoiceProviderContractMatrixReport, VoiceProviderContractMatrixRoutesOptions, VoiceProviderContractMatrixRow, VoiceProviderStackInput, VoiceProviderStackKind, VoiceProviderStackRecommendation } from './providerStackRecommendations';
|
|
116
117
|
export type { VoiceOperationsRecord, VoiceOperationsRecordAgentHandoff, VoiceOperationsRecordAuditSummary, VoiceOperationsRecordIntegrationEventSummary, VoiceOperationsRecordOptions, VoiceOperationsRecordOutcome, VoiceOperationsRecordReviewSummary, VoiceOperationsRecordRoutesOptions, VoiceOperationsRecordStatus, VoiceOperationsRecordTaskSummary, VoiceOperationsRecordTool } from './operationsRecord';
|
|
118
|
+
export type { VoiceOpsRecoveryFailedSession, VoiceOpsRecoveryInterventionSummary, VoiceOpsRecoveryIssue, VoiceOpsRecoveryIssueCode, VoiceOpsRecoveryLinks, VoiceOpsRecoveryProviderSummary, VoiceOpsRecoveryReport, VoiceOpsRecoveryReportOptions, VoiceOpsRecoveryRoutesOptions, VoiceOpsRecoveryStatus } from './opsRecovery';
|
|
117
119
|
export type { StoredVoiceIncidentBundleArtifact, VoiceIncidentBundle, VoiceIncidentBundleArtifactOptions, VoiceIncidentBundleFormat, VoiceIncidentBundleOptions, VoiceIncidentBundleRetentionOptions, VoiceIncidentBundleRetentionReport, VoiceIncidentBundleRoutesOptions, VoiceIncidentBundleStore, VoiceIncidentBundleStoreFilter, VoiceIncidentBundleSummary } from './incidentBundle';
|
|
118
120
|
export type { VoiceQualityLink, VoiceQualityMetric, VoiceQualityReport, VoiceQualityRoutesOptions, VoiceQualityStatus, VoiceQualityThresholds } from './qualityRoutes';
|
|
119
121
|
export type { VoiceResilienceIOSimulator, VoiceResilienceLink, VoiceResiliencePageData, VoiceResilienceRoutesOptions, VoiceResilienceSimulationProvider, VoiceRoutingKindSummary, VoiceRoutingDecisionSummary, VoiceRoutingDecisionSummaryOptions, VoiceRoutingEvent, VoiceRoutingEventKind, VoiceRoutingSessionSummary, VoiceRoutingSessionSummaryOptions } from './resilienceRoutes';
|
package/dist/index.js
CHANGED
|
@@ -24008,8 +24008,248 @@ var createVoiceOperationsRecordRoutes = (options) => {
|
|
|
24008
24008
|
}
|
|
24009
24009
|
return routes;
|
|
24010
24010
|
};
|
|
24011
|
-
// src/
|
|
24011
|
+
// src/opsRecovery.ts
|
|
24012
24012
|
import { Elysia as Elysia40 } from "elysia";
|
|
24013
|
+
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24014
|
+
var getString16 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
24015
|
+
var hrefForSession = (value, sessionId) => typeof value === "function" ? value(sessionId) : value;
|
|
24016
|
+
var rollupStatus3 = (issues) => issues.some((issue) => issue.severity === "fail") ? "fail" : issues.some((issue) => issue.severity === "warn") ? "warn" : "pass";
|
|
24017
|
+
var providerUnresolved = (provider) => provider.status === "degraded" || provider.status === "rate-limited" || provider.status === "suppressed";
|
|
24018
|
+
var collectFailedSessions = (events, limit) => events.filter((event) => {
|
|
24019
|
+
if (event.type !== "session.error") {
|
|
24020
|
+
return false;
|
|
24021
|
+
}
|
|
24022
|
+
const providerStatus = event.payload.providerStatus;
|
|
24023
|
+
return providerStatus !== "success" && providerStatus !== "fallback";
|
|
24024
|
+
}).sort((left, right) => right.at - left.at).slice(0, limit).map((event) => ({
|
|
24025
|
+
at: event.at,
|
|
24026
|
+
error: getString16(event.payload.error),
|
|
24027
|
+
provider: getString16(event.payload.provider),
|
|
24028
|
+
sessionId: event.sessionId,
|
|
24029
|
+
traceId: event.traceId
|
|
24030
|
+
}));
|
|
24031
|
+
var collectInterventions = (events, limit) => {
|
|
24032
|
+
const interventionEvents = events.filter((event) => event.type === "operator.action").sort((left, right) => right.at - left.at);
|
|
24033
|
+
return {
|
|
24034
|
+
events: interventionEvents.slice(0, limit).map((event) => ({
|
|
24035
|
+
action: getString16(event.payload.action),
|
|
24036
|
+
at: event.at,
|
|
24037
|
+
operatorId: getString16(event.payload.operatorId) ?? getString16(event.payload.actorId),
|
|
24038
|
+
sessionId: event.sessionId,
|
|
24039
|
+
traceId: event.traceId
|
|
24040
|
+
})),
|
|
24041
|
+
total: interventionEvents.length
|
|
24042
|
+
};
|
|
24043
|
+
};
|
|
24044
|
+
var addDeliveryIssues = (issues, input) => {
|
|
24045
|
+
if (!input.summary) {
|
|
24046
|
+
return;
|
|
24047
|
+
}
|
|
24048
|
+
const failed = input.summary.failed + input.summary.deadLettered;
|
|
24049
|
+
if (failed > 0) {
|
|
24050
|
+
issues.push({
|
|
24051
|
+
code: input.failedCode,
|
|
24052
|
+
detail: `${failed} failed or dead-lettered delivery record(s).`,
|
|
24053
|
+
href: input.href,
|
|
24054
|
+
label: input.failedLabel,
|
|
24055
|
+
severity: "fail",
|
|
24056
|
+
value: failed
|
|
24057
|
+
});
|
|
24058
|
+
}
|
|
24059
|
+
const pending = input.summary.pending + input.summary.retryEligible;
|
|
24060
|
+
if (pending > 0) {
|
|
24061
|
+
issues.push({
|
|
24062
|
+
code: input.pendingCode,
|
|
24063
|
+
detail: `${pending} pending or retry-eligible delivery record(s).`,
|
|
24064
|
+
href: input.href,
|
|
24065
|
+
label: input.pendingLabel,
|
|
24066
|
+
severity: "warn",
|
|
24067
|
+
value: pending
|
|
24068
|
+
});
|
|
24069
|
+
}
|
|
24070
|
+
};
|
|
24071
|
+
var buildVoiceOpsRecoveryReport = async (options = {}) => {
|
|
24072
|
+
const limit = options.limit ?? 50;
|
|
24073
|
+
const events = options.events ?? await options.traces?.list({ limit: Math.max(limit, 500) }) ?? [];
|
|
24074
|
+
const providers = await summarizeVoiceProviderHealth({
|
|
24075
|
+
events,
|
|
24076
|
+
providers: options.providers
|
|
24077
|
+
});
|
|
24078
|
+
const auditDeliveries = options.auditDeliveries ? await summarizeVoiceAuditSinkDeliveries(await options.auditDeliveries.list(), {
|
|
24079
|
+
deadLetters: options.auditDeliveryDeadLetters
|
|
24080
|
+
}) : undefined;
|
|
24081
|
+
const traceDeliveries = options.traceDeliveries ? await summarizeVoiceTraceSinkDeliveries(await options.traceDeliveries.list(), {
|
|
24082
|
+
deadLetters: options.traceDeliveryDeadLetters
|
|
24083
|
+
}) : undefined;
|
|
24084
|
+
const handoffDeliveries = options.handoffDeliveries ? await summarizeVoiceHandoffDeliveries(await options.handoffDeliveries.list(), {
|
|
24085
|
+
deadLetters: options.handoffDeliveryDeadLetters
|
|
24086
|
+
}) : undefined;
|
|
24087
|
+
const latency = options.latency === false ? undefined : await buildVoiceLatencySLOGate({
|
|
24088
|
+
events,
|
|
24089
|
+
...options.latency ?? {}
|
|
24090
|
+
});
|
|
24091
|
+
const failedSessions = collectFailedSessions(events, limit);
|
|
24092
|
+
const interventions = collectInterventions(events, limit);
|
|
24093
|
+
const issues = [];
|
|
24094
|
+
const unresolvedProviders = providers.filter(providerUnresolved);
|
|
24095
|
+
for (const provider of unresolvedProviders) {
|
|
24096
|
+
issues.push({
|
|
24097
|
+
code: "voice.ops_recovery.provider_unresolved_failure",
|
|
24098
|
+
detail: provider.lastError ?? `${provider.provider} status is ${provider.status}.`,
|
|
24099
|
+
href: options.links?.providers,
|
|
24100
|
+
label: `Provider ${provider.provider} needs recovery`,
|
|
24101
|
+
severity: "fail",
|
|
24102
|
+
value: provider.status
|
|
24103
|
+
});
|
|
24104
|
+
}
|
|
24105
|
+
addDeliveryIssues(issues, {
|
|
24106
|
+
failedCode: "voice.ops_recovery.audit_delivery_failed",
|
|
24107
|
+
failedLabel: "Audit delivery failures",
|
|
24108
|
+
href: options.links?.auditDeliveries,
|
|
24109
|
+
pendingCode: "voice.ops_recovery.audit_delivery_pending",
|
|
24110
|
+
pendingLabel: "Audit delivery backlog",
|
|
24111
|
+
summary: auditDeliveries
|
|
24112
|
+
});
|
|
24113
|
+
addDeliveryIssues(issues, {
|
|
24114
|
+
failedCode: "voice.ops_recovery.trace_delivery_failed",
|
|
24115
|
+
failedLabel: "Trace delivery failures",
|
|
24116
|
+
href: options.links?.traceDeliveries,
|
|
24117
|
+
pendingCode: "voice.ops_recovery.trace_delivery_pending",
|
|
24118
|
+
pendingLabel: "Trace delivery backlog",
|
|
24119
|
+
summary: traceDeliveries
|
|
24120
|
+
});
|
|
24121
|
+
addDeliveryIssues(issues, {
|
|
24122
|
+
failedCode: "voice.ops_recovery.handoff_failed",
|
|
24123
|
+
failedLabel: "Handoff delivery failures",
|
|
24124
|
+
href: options.links?.handoffs,
|
|
24125
|
+
pendingCode: "voice.ops_recovery.handoff_pending",
|
|
24126
|
+
pendingLabel: "Handoff delivery backlog",
|
|
24127
|
+
summary: handoffDeliveries
|
|
24128
|
+
});
|
|
24129
|
+
if (latency?.failed) {
|
|
24130
|
+
issues.push({
|
|
24131
|
+
code: "voice.ops_recovery.latency_slo_failed",
|
|
24132
|
+
detail: `${latency.failed} latency SLO measurement(s) failed.`,
|
|
24133
|
+
href: options.links?.traces ? hrefForSession(options.links.traces, latency.measurements[0]?.sessionId ?? "") : undefined,
|
|
24134
|
+
label: "Latency SLO failures",
|
|
24135
|
+
severity: "fail",
|
|
24136
|
+
value: latency.failed
|
|
24137
|
+
});
|
|
24138
|
+
} else if (latency?.warnings) {
|
|
24139
|
+
issues.push({
|
|
24140
|
+
code: "voice.ops_recovery.latency_slo_warn",
|
|
24141
|
+
detail: `${latency.warnings} latency SLO measurement(s) are warning.`,
|
|
24142
|
+
label: "Latency SLO warnings",
|
|
24143
|
+
severity: "warn",
|
|
24144
|
+
value: latency.warnings
|
|
24145
|
+
});
|
|
24146
|
+
}
|
|
24147
|
+
return {
|
|
24148
|
+
auditDeliveries,
|
|
24149
|
+
checkedAt: Date.now(),
|
|
24150
|
+
failedSessions,
|
|
24151
|
+
handoffDeliveries,
|
|
24152
|
+
interventions,
|
|
24153
|
+
issues,
|
|
24154
|
+
latency,
|
|
24155
|
+
providers: {
|
|
24156
|
+
healthy: providers.filter((provider) => provider.status === "healthy").length,
|
|
24157
|
+
providers,
|
|
24158
|
+
recoveredFallbacks: providers.reduce((total, provider) => total + provider.fallbackCount, 0),
|
|
24159
|
+
unresolvedFailures: unresolvedProviders.length
|
|
24160
|
+
},
|
|
24161
|
+
status: rollupStatus3(issues),
|
|
24162
|
+
traceDeliveries
|
|
24163
|
+
};
|
|
24164
|
+
};
|
|
24165
|
+
var buildVoiceOpsRecoveryReadinessCheck = (report, options = {}) => ({
|
|
24166
|
+
detail: report.status === "pass" ? `${report.providers.recoveredFallbacks} recovered fallback(s), ${report.interventions.total} operator intervention(s), and no unresolved recovery issues.` : `${report.issues.length} recovery issue(s) require attention.`,
|
|
24167
|
+
href: options.href,
|
|
24168
|
+
label: options.label ?? "Ops recovery",
|
|
24169
|
+
status: report.status,
|
|
24170
|
+
value: report.issues.length
|
|
24171
|
+
});
|
|
24172
|
+
var renderVoiceOpsRecoveryMarkdown = (report, options = {}) => {
|
|
24173
|
+
const title = options.title ?? "Voice Ops Recovery";
|
|
24174
|
+
const issueRows = report.issues.map((issue) => `| ${issue.severity} | ${issue.code} | ${issue.label} | ${issue.value ?? ""} | ${issue.detail ?? ""} |`).join(`
|
|
24175
|
+
`);
|
|
24176
|
+
const providers = report.providers.providers.map((provider) => `| ${provider.provider} | ${provider.status} | ${provider.runCount} | ${provider.errorCount} | ${provider.fallbackCount} | ${provider.lastError ?? ""} |`).join(`
|
|
24177
|
+
`);
|
|
24178
|
+
const failedSessions = report.failedSessions.map((session) => `- ${session.sessionId}${session.provider ? ` via ${session.provider}` : ""}${session.error ? `: ${session.error}` : ""}`).join(`
|
|
24179
|
+
`);
|
|
24180
|
+
return `# ${title}
|
|
24181
|
+
|
|
24182
|
+
Status: ${report.status}
|
|
24183
|
+
|
|
24184
|
+
Checked at: ${new Date(report.checkedAt).toISOString()}
|
|
24185
|
+
|
|
24186
|
+
Recovered fallbacks: ${report.providers.recoveredFallbacks}
|
|
24187
|
+
Unresolved provider failures: ${report.providers.unresolvedFailures}
|
|
24188
|
+
Operator interventions: ${report.interventions.total}
|
|
24189
|
+
|
|
24190
|
+
## Issues
|
|
24191
|
+
|
|
24192
|
+
| Severity | Code | Label | Value | Detail |
|
|
24193
|
+
| --- | --- | --- | ---: | --- |
|
|
24194
|
+
${issueRows || "| pass | none | No recovery issues | 0 | |"}
|
|
24195
|
+
|
|
24196
|
+
## Providers
|
|
24197
|
+
|
|
24198
|
+
| Provider | Status | Runs | Errors | Fallbacks | Last error |
|
|
24199
|
+
| --- | --- | ---: | ---: | ---: | --- |
|
|
24200
|
+
${providers || "| none | idle | 0 | 0 | 0 | |"}
|
|
24201
|
+
|
|
24202
|
+
## Failed Sessions
|
|
24203
|
+
|
|
24204
|
+
${failedSessions || "None."}
|
|
24205
|
+
|
|
24206
|
+
## Latency
|
|
24207
|
+
|
|
24208
|
+
${report.latency ? renderVoiceLatencySLOMarkdown(report.latency, { title: "Latency SLO" }) : "Latency SLO disabled."}
|
|
24209
|
+
`;
|
|
24210
|
+
};
|
|
24211
|
+
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${escapeHtml41(label)}</span><strong>${String(summary.failed + summary.deadLettered)} failed</strong><small>${String(summary.pending)} pending \xB7 ${String(summary.retryEligible)} retry eligible \xB7 ${String(summary.total)} total</small></article>` : `<article><span>${escapeHtml41(label)}</span><strong>not configured</strong></article>`;
|
|
24212
|
+
var renderVoiceOpsRecoveryHTML = (report, options = {}) => {
|
|
24213
|
+
const title = options.title ?? "Voice Ops Recovery";
|
|
24214
|
+
const issues = report.issues.map((issue) => `<tr><td>${escapeHtml41(issue.severity)}</td><td><code>${escapeHtml41(issue.code)}</code></td><td>${escapeHtml41(issue.label)}</td><td>${escapeHtml41(String(issue.value ?? ""))}</td><td>${escapeHtml41(issue.detail ?? "")}</td></tr>`).join("");
|
|
24215
|
+
const providers = report.providers.providers.map((provider) => `<tr><td>${escapeHtml41(provider.provider)}</td><td>${escapeHtml41(provider.status)}</td><td>${String(provider.runCount)}</td><td>${String(provider.errorCount)}</td><td>${String(provider.fallbackCount)}</td><td>${escapeHtml41(provider.lastError ?? "")}</td></tr>`).join("");
|
|
24216
|
+
const failedSessions = report.failedSessions.map((session) => `<li>${escapeHtml41(session.sessionId)}${session.provider ? ` via ${escapeHtml41(session.provider)}` : ""}${session.error ? `: ${escapeHtml41(session.error)}` : ""}</li>`).join("");
|
|
24217
|
+
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{font-family:ui-sans-serif,system-ui,sans-serif;background:#f8fafc;color:#172033;margin:2rem;line-height:1.45}main{max-width:1180px;margin:auto}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:.75rem;margin:1rem 0}article{background:white;border:1px solid #dbe3ef;border-radius:14px;padding:1rem;box-shadow:0 10px 28px rgba(15,23,42,.05)}article span{display:block;color:#64748b;font-size:.85rem}article strong{display:block;font-size:1.5rem;margin:.2rem 0}article small{color:#64748b}table{border-collapse:collapse;width:100%;background:white;border:1px solid #dbe3ef;border-radius:14px;overflow:hidden}th,td{border-bottom:1px solid #e2e8f0;padding:.7rem;text-align:left;vertical-align:top}code{font-size:.85em}.status{display:inline-flex;border-radius:999px;padding:.35rem .7rem;background:${report.status === "fail" ? "#fee2e2" : report.status === "warn" ? "#fef3c7" : "#dcfce7"};color:${report.status === "fail" ? "#991b1b" : report.status === "warn" ? "#92400e" : "#166534"};font-weight:700}</style></head><body><main><h1>${escapeHtml41(title)}</h1><p><span class="status">${escapeHtml41(report.status)}</span> Checked ${escapeHtml41(new Date(report.checkedAt).toLocaleString())}</p><section class="grid"><article><span>Recovered fallbacks</span><strong>${String(report.providers.recoveredFallbacks)}</strong></article><article><span>Unresolved providers</span><strong>${String(report.providers.unresolvedFailures)}</strong></article><article><span>Operator interventions</span><strong>${String(report.interventions.total)}</strong></article><article><span>Latency status</span><strong>${escapeHtml41(report.latency?.status ?? "disabled")}</strong></article>${renderDeliverySummary("Audit delivery", report.auditDeliveries)}${renderDeliverySummary("Trace delivery", report.traceDeliveries)}${renderDeliverySummary("Handoff delivery", report.handoffDeliveries)}</section><h2>Issues</h2><table><thead><tr><th>Severity</th><th>Code</th><th>Label</th><th>Value</th><th>Detail</th></tr></thead><tbody>${issues || '<tr><td colspan="5">No recovery issues.</td></tr>'}</tbody></table><h2>Providers</h2><table><thead><tr><th>Provider</th><th>Status</th><th>Runs</th><th>Errors</th><th>Fallbacks</th><th>Last error</th></tr></thead><tbody>${providers || '<tr><td colspan="6">No provider activity.</td></tr>'}</tbody></table><h2>Failed Sessions</h2><ul>${failedSessions || "<li>None.</li>"}</ul></main></body></html>`;
|
|
24218
|
+
};
|
|
24219
|
+
var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
24220
|
+
const path = options.path ?? "/api/voice/ops-recovery";
|
|
24221
|
+
const htmlPath = options.htmlPath === undefined ? "/ops-recovery" : options.htmlPath;
|
|
24222
|
+
const markdownPath = options.markdownPath === undefined ? `${path}.md` : options.markdownPath;
|
|
24223
|
+
const routes = new Elysia40({
|
|
24224
|
+
name: options.name ?? "absolutejs-voice-ops-recovery"
|
|
24225
|
+
}).get(path, async () => buildVoiceOpsRecoveryReport(options));
|
|
24226
|
+
if (htmlPath) {
|
|
24227
|
+
routes.get(htmlPath, async () => {
|
|
24228
|
+
const report = await buildVoiceOpsRecoveryReport(options);
|
|
24229
|
+
const render = options.render ?? renderVoiceOpsRecoveryHTML;
|
|
24230
|
+
return new Response(await render(report), {
|
|
24231
|
+
headers: {
|
|
24232
|
+
"content-type": "text/html; charset=utf-8",
|
|
24233
|
+
...options.headers
|
|
24234
|
+
}
|
|
24235
|
+
});
|
|
24236
|
+
});
|
|
24237
|
+
}
|
|
24238
|
+
if (markdownPath) {
|
|
24239
|
+
routes.get(markdownPath, async () => {
|
|
24240
|
+
const report = await buildVoiceOpsRecoveryReport(options);
|
|
24241
|
+
return new Response(renderVoiceOpsRecoveryMarkdown(report, { title: options.title }), {
|
|
24242
|
+
headers: {
|
|
24243
|
+
"content-type": "text/markdown; charset=utf-8",
|
|
24244
|
+
...options.headers
|
|
24245
|
+
}
|
|
24246
|
+
});
|
|
24247
|
+
});
|
|
24248
|
+
}
|
|
24249
|
+
return routes;
|
|
24250
|
+
};
|
|
24251
|
+
// src/incidentBundle.ts
|
|
24252
|
+
import { Elysia as Elysia41 } from "elysia";
|
|
24013
24253
|
var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
|
|
24014
24254
|
if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
|
|
24015
24255
|
return false;
|
|
@@ -24208,7 +24448,7 @@ var buildVoiceIncidentBundle = async (options) => {
|
|
|
24208
24448
|
var createVoiceIncidentBundleRoutes = (options) => {
|
|
24209
24449
|
const path = options.path ?? "/api/voice-incidents/:sessionId";
|
|
24210
24450
|
const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
|
|
24211
|
-
const routes = new
|
|
24451
|
+
const routes = new Elysia41({
|
|
24212
24452
|
name: options.name ?? "absolutejs-voice-incident-bundle"
|
|
24213
24453
|
});
|
|
24214
24454
|
const getSessionId = (params) => params.sessionId ?? "";
|
|
@@ -24409,19 +24649,19 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
24409
24649
|
};
|
|
24410
24650
|
};
|
|
24411
24651
|
// src/opsStatusRoutes.ts
|
|
24412
|
-
import { Elysia as
|
|
24413
|
-
var
|
|
24652
|
+
import { Elysia as Elysia42 } from "elysia";
|
|
24653
|
+
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24414
24654
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
24415
24655
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
24416
24656
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
24417
24657
|
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;
|
|
24418
|
-
return `<article class="surface ${
|
|
24658
|
+
return `<article class="surface ${escapeHtml42(surface.status)}"><span>${escapeHtml42(surface.status.toUpperCase())}</span><h2>${escapeHtml42(key)}</h2><strong>${escapeHtml42(value)}</strong></article>`;
|
|
24419
24659
|
}).join("");
|
|
24420
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
24660
|
+
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:#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>${escapeHtml42(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml42(report.status)}">Overall: ${escapeHtml42(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>`;
|
|
24421
24661
|
};
|
|
24422
24662
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
24423
24663
|
const path = options.path ?? "/api/voice/ops-status";
|
|
24424
|
-
const routes = new
|
|
24664
|
+
const routes = new Elysia42({
|
|
24425
24665
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
24426
24666
|
});
|
|
24427
24667
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -24854,9 +25094,9 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
24854
25094
|
};
|
|
24855
25095
|
};
|
|
24856
25096
|
// src/traceDeliveryRoutes.ts
|
|
24857
|
-
import { Elysia as
|
|
24858
|
-
var
|
|
24859
|
-
var
|
|
25097
|
+
import { Elysia as Elysia43 } from "elysia";
|
|
25098
|
+
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25099
|
+
var getString17 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
24860
25100
|
var getNumber11 = (value) => {
|
|
24861
25101
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
24862
25102
|
return value;
|
|
@@ -24868,13 +25108,13 @@ var getNumber11 = (value) => {
|
|
|
24868
25108
|
return;
|
|
24869
25109
|
};
|
|
24870
25110
|
var parseStatus2 = (value) => {
|
|
24871
|
-
const text =
|
|
25111
|
+
const text = getString17(value);
|
|
24872
25112
|
return text === "pending" || text === "delivered" || text === "failed" || text === "skipped" || text === "all" ? text : undefined;
|
|
24873
25113
|
};
|
|
24874
25114
|
var resolveVoiceTraceDeliveryFilter = (query = {}, base = {}) => ({
|
|
24875
25115
|
...base,
|
|
24876
25116
|
limit: getNumber11(query.limit) ?? base.limit,
|
|
24877
|
-
q:
|
|
25117
|
+
q: getString17(query.q) ?? base.q,
|
|
24878
25118
|
status: parseStatus2(query.status) ?? base.status
|
|
24879
25119
|
});
|
|
24880
25120
|
var deliverySearchText2 = (delivery) => [
|
|
@@ -24936,14 +25176,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
24936
25176
|
if (entries.length === 0) {
|
|
24937
25177
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
24938
25178
|
}
|
|
24939
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
25179
|
+
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml43(sinkId)}</strong>: ${escapeHtml43(result.status)}${result.deliveredTo ? ` to ${escapeHtml43(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml43(result.error)})` : ""}</li>`).join("")}</ul>`;
|
|
24940
25180
|
};
|
|
24941
|
-
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
25181
|
+
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml43(event.type)} <small>${escapeHtml43(event.id)}</small>${event.sessionId ? ` session=${escapeHtml43(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
|
|
24942
25182
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
24943
25183
|
const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
|
|
24944
|
-
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${
|
|
24945
|
-
const rows = report.deliveries.map((delivery) => `<article class="delivery ${
|
|
24946
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25184
|
+
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml43(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
|
|
25185
|
+
const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml43(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml43(delivery.deliveryStatus)}</span><h2>${escapeHtml43(delivery.id)}</h2><p>${escapeHtml43(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml43(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml43(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
|
|
25186
|
+
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{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>${escapeHtml43(title)}</h1><p>Checked ${escapeHtml43(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>`;
|
|
24947
25187
|
};
|
|
24948
25188
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
24949
25189
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -24963,7 +25203,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
24963
25203
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
24964
25204
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
24965
25205
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
24966
|
-
const routes = new
|
|
25206
|
+
const routes = new Elysia43({
|
|
24967
25207
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
24968
25208
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
24969
25209
|
if (htmlPath !== false) {
|
|
@@ -25587,7 +25827,7 @@ var createVoiceMemoryStore = () => {
|
|
|
25587
25827
|
return { get, getOrCreate, list, remove, set };
|
|
25588
25828
|
};
|
|
25589
25829
|
// src/opsWebhook.ts
|
|
25590
|
-
import { Elysia as
|
|
25830
|
+
import { Elysia as Elysia44 } from "elysia";
|
|
25591
25831
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
25592
25832
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
25593
25833
|
const encoder = new TextEncoder;
|
|
@@ -25717,7 +25957,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
25717
25957
|
};
|
|
25718
25958
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
25719
25959
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
25720
|
-
return new
|
|
25960
|
+
return new Elysia44().post(path, async ({ body, request, set }) => {
|
|
25721
25961
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
25722
25962
|
if (options.signingSecret) {
|
|
25723
25963
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -26660,6 +26900,8 @@ export {
|
|
|
26660
26900
|
renderVoicePhoneAgentProductionSmokeHTML,
|
|
26661
26901
|
renderVoiceOutcomeContractHTML,
|
|
26662
26902
|
renderVoiceOpsStatusHTML,
|
|
26903
|
+
renderVoiceOpsRecoveryMarkdown,
|
|
26904
|
+
renderVoiceOpsRecoveryHTML,
|
|
26663
26905
|
renderVoiceOpsConsoleHTML,
|
|
26664
26906
|
renderVoiceOpsActionHistoryHTML,
|
|
26665
26907
|
renderVoiceOperationsRecordHTML,
|
|
@@ -26856,6 +27098,7 @@ export {
|
|
|
26856
27098
|
createVoiceOpsTaskProcessorWorker,
|
|
26857
27099
|
createVoiceOpsStatusRoutes,
|
|
26858
27100
|
createVoiceOpsRuntime,
|
|
27101
|
+
createVoiceOpsRecoveryRoutes,
|
|
26859
27102
|
createVoiceOpsConsoleRoutes,
|
|
26860
27103
|
createVoiceOpsActionAuditRoutes,
|
|
26861
27104
|
createVoiceOperationsRecordRoutes,
|
|
@@ -26989,6 +27232,8 @@ export {
|
|
|
26989
27232
|
buildVoiceProductionReadinessGate,
|
|
26990
27233
|
buildVoiceOpsTaskFromSLABreach,
|
|
26991
27234
|
buildVoiceOpsTaskFromReview,
|
|
27235
|
+
buildVoiceOpsRecoveryReport,
|
|
27236
|
+
buildVoiceOpsRecoveryReadinessCheck,
|
|
26992
27237
|
buildVoiceOpsConsoleReport,
|
|
26993
27238
|
buildVoiceOpsActionHistoryReport,
|
|
26994
27239
|
buildVoiceOperationsRecord,
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import { type VoiceAuditSinkDeliveryQueueSummary, type VoiceAuditSinkDeliveryStore } from './auditSinks';
|
|
3
|
+
import { type VoiceLatencySLOGateOptions, type VoiceLatencySLOGateReport } from './latencySlo';
|
|
4
|
+
import { type VoiceHandoffDeliveryQueueSummary, type VoiceTraceSinkDeliveryQueueSummary } from './queue';
|
|
5
|
+
import { type VoiceProviderHealthSummary } from './providerHealth';
|
|
6
|
+
import type { VoiceProductionReadinessCheck } from './productionReadiness';
|
|
7
|
+
import type { VoiceHandoffDeliveryStore } from './types';
|
|
8
|
+
import type { StoredVoiceTraceEvent, VoiceTraceEventStore, VoiceTraceSinkDeliveryStore } from './trace';
|
|
9
|
+
export type VoiceOpsRecoveryStatus = 'fail' | 'pass' | 'warn';
|
|
10
|
+
export type VoiceOpsRecoveryIssueCode = 'voice.ops_recovery.audit_delivery_failed' | 'voice.ops_recovery.audit_delivery_pending' | 'voice.ops_recovery.handoff_failed' | 'voice.ops_recovery.handoff_pending' | 'voice.ops_recovery.latency_slo_failed' | 'voice.ops_recovery.latency_slo_warn' | 'voice.ops_recovery.provider_unresolved_failure' | 'voice.ops_recovery.trace_delivery_failed' | 'voice.ops_recovery.trace_delivery_pending';
|
|
11
|
+
export type VoiceOpsRecoveryIssue = {
|
|
12
|
+
code: VoiceOpsRecoveryIssueCode;
|
|
13
|
+
detail?: string;
|
|
14
|
+
href?: string;
|
|
15
|
+
label: string;
|
|
16
|
+
severity: Exclude<VoiceOpsRecoveryStatus, 'pass'>;
|
|
17
|
+
value?: number | string;
|
|
18
|
+
};
|
|
19
|
+
export type VoiceOpsRecoveryProviderSummary<TProvider extends string = string> = {
|
|
20
|
+
healthy: number;
|
|
21
|
+
providers: VoiceProviderHealthSummary<TProvider>[];
|
|
22
|
+
recoveredFallbacks: number;
|
|
23
|
+
unresolvedFailures: number;
|
|
24
|
+
};
|
|
25
|
+
export type VoiceOpsRecoveryInterventionSummary = {
|
|
26
|
+
events: Array<{
|
|
27
|
+
action?: string;
|
|
28
|
+
at: number;
|
|
29
|
+
operatorId?: string;
|
|
30
|
+
sessionId: string;
|
|
31
|
+
traceId?: string;
|
|
32
|
+
}>;
|
|
33
|
+
total: number;
|
|
34
|
+
};
|
|
35
|
+
export type VoiceOpsRecoveryFailedSession = {
|
|
36
|
+
at: number;
|
|
37
|
+
error?: string;
|
|
38
|
+
provider?: string;
|
|
39
|
+
sessionId: string;
|
|
40
|
+
traceId?: string;
|
|
41
|
+
};
|
|
42
|
+
export type VoiceOpsRecoveryReport<TProvider extends string = string> = {
|
|
43
|
+
auditDeliveries?: VoiceAuditSinkDeliveryQueueSummary;
|
|
44
|
+
checkedAt: number;
|
|
45
|
+
failedSessions: VoiceOpsRecoveryFailedSession[];
|
|
46
|
+
handoffDeliveries?: VoiceHandoffDeliveryQueueSummary;
|
|
47
|
+
interventions: VoiceOpsRecoveryInterventionSummary;
|
|
48
|
+
issues: VoiceOpsRecoveryIssue[];
|
|
49
|
+
latency?: VoiceLatencySLOGateReport;
|
|
50
|
+
providers: VoiceOpsRecoveryProviderSummary<TProvider>;
|
|
51
|
+
status: VoiceOpsRecoveryStatus;
|
|
52
|
+
traceDeliveries?: VoiceTraceSinkDeliveryQueueSummary;
|
|
53
|
+
};
|
|
54
|
+
export type VoiceOpsRecoveryLinks = {
|
|
55
|
+
auditDeliveries?: string;
|
|
56
|
+
handoffs?: string;
|
|
57
|
+
operationsRecords?: string | ((sessionId: string) => string);
|
|
58
|
+
providers?: string;
|
|
59
|
+
sessions?: string | ((sessionId: string) => string);
|
|
60
|
+
traceDeliveries?: string;
|
|
61
|
+
traces?: string | ((sessionId: string) => string);
|
|
62
|
+
};
|
|
63
|
+
export type VoiceOpsRecoveryReportOptions<TProvider extends string = string> = {
|
|
64
|
+
auditDeliveryDeadLetters?: VoiceAuditSinkDeliveryStore;
|
|
65
|
+
auditDeliveries?: VoiceAuditSinkDeliveryStore;
|
|
66
|
+
events?: StoredVoiceTraceEvent[];
|
|
67
|
+
handoffDeliveryDeadLetters?: VoiceHandoffDeliveryStore;
|
|
68
|
+
handoffDeliveries?: VoiceHandoffDeliveryStore;
|
|
69
|
+
latency?: VoiceLatencySLOGateOptions | false;
|
|
70
|
+
limit?: number;
|
|
71
|
+
links?: VoiceOpsRecoveryLinks;
|
|
72
|
+
providers?: readonly TProvider[];
|
|
73
|
+
traceDeliveryDeadLetters?: VoiceTraceSinkDeliveryStore;
|
|
74
|
+
traceDeliveries?: VoiceTraceSinkDeliveryStore;
|
|
75
|
+
traces?: VoiceTraceEventStore;
|
|
76
|
+
};
|
|
77
|
+
export type VoiceOpsRecoveryRoutesOptions<TProvider extends string = string> = VoiceOpsRecoveryReportOptions<TProvider> & {
|
|
78
|
+
headers?: HeadersInit;
|
|
79
|
+
htmlPath?: false | string;
|
|
80
|
+
markdownPath?: false | string;
|
|
81
|
+
name?: string;
|
|
82
|
+
path?: string;
|
|
83
|
+
render?: (report: VoiceOpsRecoveryReport<TProvider>) => string | Promise<string>;
|
|
84
|
+
title?: string;
|
|
85
|
+
};
|
|
86
|
+
export declare const buildVoiceOpsRecoveryReport: <TProvider extends string = string>(options?: VoiceOpsRecoveryReportOptions<TProvider>) => Promise<VoiceOpsRecoveryReport<TProvider>>;
|
|
87
|
+
export declare const buildVoiceOpsRecoveryReadinessCheck: (report: VoiceOpsRecoveryReport, options?: {
|
|
88
|
+
href?: string;
|
|
89
|
+
label?: string;
|
|
90
|
+
}) => VoiceProductionReadinessCheck;
|
|
91
|
+
export declare const renderVoiceOpsRecoveryMarkdown: (report: VoiceOpsRecoveryReport, options?: {
|
|
92
|
+
title?: string;
|
|
93
|
+
}) => string;
|
|
94
|
+
export declare const renderVoiceOpsRecoveryHTML: (report: VoiceOpsRecoveryReport, options?: {
|
|
95
|
+
title?: string;
|
|
96
|
+
}) => string;
|
|
97
|
+
export declare const createVoiceOpsRecoveryRoutes: <TProvider extends string = string>(options?: VoiceOpsRecoveryRoutesOptions<TProvider>) => Elysia<"", {
|
|
98
|
+
decorator: {};
|
|
99
|
+
store: {};
|
|
100
|
+
derive: {};
|
|
101
|
+
resolve: {};
|
|
102
|
+
}, {
|
|
103
|
+
typebox: {};
|
|
104
|
+
error: {};
|
|
105
|
+
}, {
|
|
106
|
+
schema: {};
|
|
107
|
+
standaloneSchema: {};
|
|
108
|
+
macro: {};
|
|
109
|
+
macroFn: {};
|
|
110
|
+
parser: {};
|
|
111
|
+
response: {};
|
|
112
|
+
}, {
|
|
113
|
+
[x: string]: {
|
|
114
|
+
get: {
|
|
115
|
+
body: unknown;
|
|
116
|
+
params: {};
|
|
117
|
+
query: unknown;
|
|
118
|
+
headers: unknown;
|
|
119
|
+
response: {
|
|
120
|
+
200: VoiceOpsRecoveryReport<TProvider>;
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
}, {
|
|
125
|
+
derive: {};
|
|
126
|
+
resolve: {};
|
|
127
|
+
schema: {};
|
|
128
|
+
standaloneSchema: {};
|
|
129
|
+
response: {};
|
|
130
|
+
}, {
|
|
131
|
+
derive: {};
|
|
132
|
+
resolve: {};
|
|
133
|
+
schema: {};
|
|
134
|
+
standaloneSchema: {};
|
|
135
|
+
response: {};
|
|
136
|
+
}>;
|