@absolutejs/voice 0.0.22-beta.216 → 0.0.22-beta.218
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/README.md +45 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +274 -12
- package/dist/observabilityExport.d.ts +123 -0
- package/dist/providerSlo.d.ts +2 -0
- package/dist/resilienceRoutes.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2741,6 +2741,51 @@ app.use(
|
|
|
2741
2741
|
|
|
2742
2742
|
Readiness emits the stable `voice.readiness.ops_recovery` gate code when unresolved recovery issues remain.
|
|
2743
2743
|
|
|
2744
|
+
## Customer-Owned Observability Export
|
|
2745
|
+
|
|
2746
|
+
Use observability exports when a buyer wants the hosted-dashboard evidence graph, but inside their own storage, warehouse, SIEM, incident flow, or release notes. The export manifest links traces, audits, operations records, delivery queues, provider SLOs, readiness reports, screenshots, and proof-pack artifacts without making AbsoluteJS Voice the dashboard.
|
|
2747
|
+
|
|
2748
|
+
```ts
|
|
2749
|
+
import {
|
|
2750
|
+
buildVoiceObservabilityExport,
|
|
2751
|
+
createVoiceObservabilityExportRoutes
|
|
2752
|
+
} from '@absolutejs/voice';
|
|
2753
|
+
|
|
2754
|
+
app.use(
|
|
2755
|
+
createVoiceObservabilityExportRoutes({
|
|
2756
|
+
artifacts: [
|
|
2757
|
+
{
|
|
2758
|
+
id: 'latest-proof-pack',
|
|
2759
|
+
kind: 'proof-pack',
|
|
2760
|
+
label: 'Latest proof pack',
|
|
2761
|
+
path: '.voice-runtime/proof-pack/latest.md'
|
|
2762
|
+
}
|
|
2763
|
+
],
|
|
2764
|
+
audit: runtimeStorage.audit,
|
|
2765
|
+
auditDeliveries: runtimeStorage.auditDeliveries,
|
|
2766
|
+
links: {
|
|
2767
|
+
operationsRecord: (sessionId) => `/voice-operations/${sessionId}`
|
|
2768
|
+
},
|
|
2769
|
+
redact: true,
|
|
2770
|
+
store: runtimeStorage.traces,
|
|
2771
|
+
traceDeliveries: runtimeStorage.traceDeliveries
|
|
2772
|
+
})
|
|
2773
|
+
);
|
|
2774
|
+
|
|
2775
|
+
const exportReport = await buildVoiceObservabilityExport({
|
|
2776
|
+
audit: runtimeStorage.audit,
|
|
2777
|
+
auditDeliveries: runtimeStorage.auditDeliveries,
|
|
2778
|
+
links: {
|
|
2779
|
+
operationsRecord: (sessionId) => `/voice-operations/${sessionId}`
|
|
2780
|
+
},
|
|
2781
|
+
redact: true,
|
|
2782
|
+
store: runtimeStorage.traces,
|
|
2783
|
+
traceDeliveries: runtimeStorage.traceDeliveries
|
|
2784
|
+
});
|
|
2785
|
+
```
|
|
2786
|
+
|
|
2787
|
+
The route helper exposes JSON at `/api/voice/observability-export`, Markdown at `/voice/observability-export.md`, and HTML at `/voice/observability-export`. Failed trace/audit deliveries fail the export report, pending deliveries warn, and every trace/audit envelope includes the linked operations-record URL when one is configured. This is the primitive to use when customers ask how voice evidence leaves the app without going through a hosted vendor dashboard.
|
|
2788
|
+
|
|
2744
2789
|
## Production Voice Ops
|
|
2745
2790
|
|
|
2746
2791
|
The recommended production pattern is:
|
package/dist/index.d.ts
CHANGED
|
@@ -53,6 +53,7 @@ export { createVoiceReadinessProfile, recommendVoiceReadinessProfile } from './r
|
|
|
53
53
|
export { buildVoiceProviderContractMatrix, createVoiceProviderContractMatrixHTMLHandler, createVoiceProviderContractMatrixJSONHandler, createVoiceProviderContractMatrixPreset, createVoiceProviderContractMatrixRoutes, evaluateVoiceProviderStackGaps, renderVoiceProviderContractMatrixHTML, recommendVoiceProviderStack } from './providerStackRecommendations';
|
|
54
54
|
export { buildVoiceOpsConsoleReport, createVoiceOpsConsoleRoutes, renderVoiceOpsConsoleHTML } from './opsConsoleRoutes';
|
|
55
55
|
export { buildVoiceOperationsRecord, createVoiceOperationsRecordRoutes, renderVoiceOperationsRecordHTML, renderVoiceOperationsRecordIncidentMarkdown } from './operationsRecord';
|
|
56
|
+
export { buildVoiceObservabilityExport, createVoiceObservabilityExportRoutes, renderVoiceObservabilityExportMarkdown } from './observabilityExport';
|
|
56
57
|
export { buildVoiceOpsRecoveryReadinessCheck, buildVoiceOpsRecoveryReport, createVoiceOpsRecoveryRoutes, renderVoiceOpsRecoveryHTML, renderVoiceOpsRecoveryMarkdown } from './opsRecovery';
|
|
57
58
|
export { buildVoiceIncidentBundle, createStoredVoiceIncidentBundleArtifact, createVoiceIncidentBundleRoutes, createVoiceMemoryIncidentBundleStore, pruneVoiceIncidentBundleArtifacts, saveVoiceIncidentBundleArtifact } from './incidentBundle';
|
|
58
59
|
export { summarizeVoiceOpsStatus } from './opsStatus';
|
|
@@ -117,6 +118,7 @@ export type { VoiceProductionReadinessAction, VoiceProductionReadinessAuditOptio
|
|
|
117
118
|
export type { VoiceReadinessProfileName, VoiceReadinessProfileOptions, VoiceReadinessProfileRecommendation, VoiceReadinessProfileRecommendationScore, VoiceReadinessProfileRoutesOptions } from './readinessProfiles';
|
|
118
119
|
export type { VoiceProviderStackChoice, VoiceProviderStackCapabilities, VoiceProviderStackCapabilityGap, VoiceProviderStackCapabilityGapInput, VoiceProviderStackCapabilityGapReport, VoiceProviderContractCheck, VoiceProviderContractCheckStatus, VoiceProviderContractDefinition, VoiceProviderContractMatrixHandlerOptions, VoiceProviderContractMatrixHTMLHandlerOptions, VoiceProviderContractMatrixInput, VoiceProviderContractMatrixPresetOptions, VoiceProviderContractMatrixReport, VoiceProviderContractMatrixRoutesOptions, VoiceProviderContractMatrixRow, VoiceProviderStackInput, VoiceProviderStackKind, VoiceProviderStackRecommendation } from './providerStackRecommendations';
|
|
119
120
|
export type { VoiceOperationsRecord, VoiceOperationsRecordAgentHandoff, VoiceOperationsRecordAuditSummary, VoiceOperationsRecordIntegrationEventSummary, VoiceOperationsRecordOptions, VoiceOperationsRecordOutcome, VoiceOperationsRecordProviderDecision, VoiceOperationsRecordReviewSummary, VoiceOperationsRecordRoutesOptions, VoiceOperationsRecordStatus, VoiceOperationsRecordTaskSummary, VoiceOperationsRecordTranscriptTurn, VoiceOperationsRecordTool } from './operationsRecord';
|
|
121
|
+
export type { VoiceObservabilityExportArtifact, VoiceObservabilityExportArtifactKind, VoiceObservabilityExportDeliverySummary, VoiceObservabilityExportEnvelope, VoiceObservabilityExportIssue, VoiceObservabilityExportIssueCode, VoiceObservabilityExportOptions, VoiceObservabilityExportRedactionSummary, VoiceObservabilityExportReport, VoiceObservabilityExportRoutesOptions, VoiceObservabilityExportStatus } from './observabilityExport';
|
|
120
122
|
export type { VoiceOpsRecoveryFailedSession, VoiceOpsRecoveryInterventionSummary, VoiceOpsRecoveryIssue, VoiceOpsRecoveryIssueCode, VoiceOpsRecoveryLinks, VoiceOpsRecoveryProviderSummary, VoiceOpsRecoveryReport, VoiceOpsRecoveryReportOptions, VoiceOpsRecoveryRoutesOptions, VoiceOpsRecoveryStatus } from './opsRecovery';
|
|
121
123
|
export type { StoredVoiceIncidentBundleArtifact, VoiceIncidentBundle, VoiceIncidentBundleArtifactOptions, VoiceIncidentBundleFormat, VoiceIncidentBundleOptions, VoiceIncidentBundleRetentionOptions, VoiceIncidentBundleRetentionReport, VoiceIncidentBundleRoutesOptions, VoiceIncidentBundleStore, VoiceIncidentBundleStoreFilter, VoiceIncidentBundleSummary } from './incidentBundle';
|
|
122
124
|
export type { VoiceQualityLink, VoiceQualityMetric, VoiceQualityReport, VoiceQualityRoutesOptions, VoiceQualityStatus, VoiceQualityThresholds } from './qualityRoutes';
|
package/dist/index.js
CHANGED
|
@@ -21397,6 +21397,7 @@ var listVoiceRoutingEvents = (events) => {
|
|
|
21397
21397
|
operation: getString13(event.payload.operation),
|
|
21398
21398
|
provider,
|
|
21399
21399
|
routing: getString13(event.payload.routing),
|
|
21400
|
+
scenarioId: event.scenarioId,
|
|
21400
21401
|
selectedProvider: getString13(event.payload.selectedProvider),
|
|
21401
21402
|
sessionId: event.sessionId,
|
|
21402
21403
|
status: providerStatus,
|
|
@@ -22067,7 +22068,7 @@ var summarizeSessions = (events) => {
|
|
|
22067
22068
|
var buildVoiceProviderSloReport = async (options = {}) => {
|
|
22068
22069
|
const rawEvents = options.events ?? await options.store?.list() ?? [];
|
|
22069
22070
|
const now = options.now ?? Date.now();
|
|
22070
|
-
const events = normalizeEvents2(rawEvents).filter((event) => typeof options.maxAgeMs !== "number" || now - event.at <= options.maxAgeMs);
|
|
22071
|
+
const events = normalizeEvents2(rawEvents).filter((event) => (typeof options.maxAgeMs !== "number" || now - event.at <= options.maxAgeMs) && (!options.sessionId || event.sessionId === options.sessionId) && (!options.scenarioId || event.scenarioId === options.scenarioId));
|
|
22071
22072
|
const thresholds = mergeThresholds(options.thresholds);
|
|
22072
22073
|
const observedKinds = new Set(events.map((event) => event.kind));
|
|
22073
22074
|
const requiredKinds = new Set(options.requiredKinds ?? [...observedKinds]);
|
|
@@ -24900,8 +24901,266 @@ var createVoiceOperationsRecordRoutes = (options) => {
|
|
|
24900
24901
|
}
|
|
24901
24902
|
return routes;
|
|
24902
24903
|
};
|
|
24903
|
-
// src/
|
|
24904
|
+
// src/observabilityExport.ts
|
|
24904
24905
|
import { Elysia as Elysia42 } from "elysia";
|
|
24906
|
+
var isDeliveryStore = (value) => !Array.isArray(value) && typeof value.list === "function";
|
|
24907
|
+
var getString18 = (value) => typeof value === "string" ? value : undefined;
|
|
24908
|
+
var getProviderKind = (payload) => getString18(payload.kind) ?? getString18(payload.providerKind);
|
|
24909
|
+
var toSeverityFromTrace = (event) => {
|
|
24910
|
+
if (event.type === "session.error" || event.payload.status === "error" || event.payload.providerStatus === "error") {
|
|
24911
|
+
return "fail";
|
|
24912
|
+
}
|
|
24913
|
+
if (event.payload.status === "fallback" || event.payload.providerStatus === "fallback") {
|
|
24914
|
+
return "warn";
|
|
24915
|
+
}
|
|
24916
|
+
return "pass";
|
|
24917
|
+
};
|
|
24918
|
+
var toSeverityFromAudit = (event) => event.outcome === "error" ? "fail" : event.outcome === "skipped" ? "warn" : "pass";
|
|
24919
|
+
var createOperationArtifact = (record, href) => ({
|
|
24920
|
+
generatedAt: record.checkedAt,
|
|
24921
|
+
href,
|
|
24922
|
+
id: `operations-record:${record.sessionId}`,
|
|
24923
|
+
kind: "operations-record",
|
|
24924
|
+
label: `Operations record ${record.sessionId}`,
|
|
24925
|
+
sessionId: record.sessionId,
|
|
24926
|
+
status: record.status === "failed" ? "fail" : record.status === "warning" ? "warn" : "pass"
|
|
24927
|
+
});
|
|
24928
|
+
var unique2 = (values) => [...new Set(values)].sort();
|
|
24929
|
+
var collectSessionIds = (input) => unique2([
|
|
24930
|
+
...input.sessionIds ?? [],
|
|
24931
|
+
...input.events.map((event) => event.sessionId),
|
|
24932
|
+
...input.auditEvents.map((event) => event.sessionId).filter((sessionId) => Boolean(sessionId)),
|
|
24933
|
+
...input.operationsRecords.map((record) => record.sessionId)
|
|
24934
|
+
]);
|
|
24935
|
+
var collectIssues = (input) => {
|
|
24936
|
+
const issues = [];
|
|
24937
|
+
const failedOperationsRecords = input.operationsRecords.filter((record) => record.status === "failed").length;
|
|
24938
|
+
if (input.totalEvidence === 0) {
|
|
24939
|
+
issues.push({
|
|
24940
|
+
code: "voice.observability.no_evidence",
|
|
24941
|
+
detail: "No traces, audits, operations records, or artifacts were included in the export manifest.",
|
|
24942
|
+
label: "Observability evidence",
|
|
24943
|
+
severity: "warn",
|
|
24944
|
+
value: 0
|
|
24945
|
+
});
|
|
24946
|
+
}
|
|
24947
|
+
if (failedOperationsRecords > 0) {
|
|
24948
|
+
issues.push({
|
|
24949
|
+
code: "voice.observability.operation_failed",
|
|
24950
|
+
label: "Failed operations records",
|
|
24951
|
+
severity: "fail",
|
|
24952
|
+
value: failedOperationsRecords
|
|
24953
|
+
});
|
|
24954
|
+
}
|
|
24955
|
+
if ((input.auditDeliveries?.failed ?? 0) > 0) {
|
|
24956
|
+
issues.push({
|
|
24957
|
+
code: "voice.observability.audit_delivery_failed",
|
|
24958
|
+
label: "Failed audit exports",
|
|
24959
|
+
severity: "fail",
|
|
24960
|
+
value: input.auditDeliveries?.failed
|
|
24961
|
+
});
|
|
24962
|
+
}
|
|
24963
|
+
if ((input.auditDeliveries?.pending ?? 0) > 0) {
|
|
24964
|
+
issues.push({
|
|
24965
|
+
code: "voice.observability.audit_delivery_pending",
|
|
24966
|
+
label: "Pending audit exports",
|
|
24967
|
+
severity: "warn",
|
|
24968
|
+
value: input.auditDeliveries?.pending
|
|
24969
|
+
});
|
|
24970
|
+
}
|
|
24971
|
+
if ((input.traceDeliveries?.failed ?? 0) > 0) {
|
|
24972
|
+
issues.push({
|
|
24973
|
+
code: "voice.observability.trace_delivery_failed",
|
|
24974
|
+
label: "Failed trace exports",
|
|
24975
|
+
severity: "fail",
|
|
24976
|
+
value: input.traceDeliveries?.failed
|
|
24977
|
+
});
|
|
24978
|
+
}
|
|
24979
|
+
if ((input.traceDeliveries?.pending ?? 0) > 0) {
|
|
24980
|
+
issues.push({
|
|
24981
|
+
code: "voice.observability.trace_delivery_pending",
|
|
24982
|
+
label: "Pending trace exports",
|
|
24983
|
+
severity: "warn",
|
|
24984
|
+
value: input.traceDeliveries?.pending
|
|
24985
|
+
});
|
|
24986
|
+
}
|
|
24987
|
+
return issues;
|
|
24988
|
+
};
|
|
24989
|
+
var buildTraceEnvelope = (event, operationsRecordHref) => ({
|
|
24990
|
+
at: event.at,
|
|
24991
|
+
eventId: event.id,
|
|
24992
|
+
eventType: event.type,
|
|
24993
|
+
kind: "trace",
|
|
24994
|
+
operationsRecordHref,
|
|
24995
|
+
provider: getString18(event.payload.provider),
|
|
24996
|
+
providerKind: getProviderKind(event.payload),
|
|
24997
|
+
scenarioId: event.scenarioId,
|
|
24998
|
+
sessionId: event.sessionId,
|
|
24999
|
+
severity: toSeverityFromTrace(event),
|
|
25000
|
+
traceId: event.traceId
|
|
25001
|
+
});
|
|
25002
|
+
var buildAuditEnvelope = (event, operationsRecordHref) => ({
|
|
25003
|
+
at: event.at,
|
|
25004
|
+
eventId: event.id,
|
|
25005
|
+
eventType: event.type,
|
|
25006
|
+
kind: "audit",
|
|
25007
|
+
operationsRecordHref,
|
|
25008
|
+
provider: getString18(event.payload?.provider),
|
|
25009
|
+
providerKind: getProviderKind(event.payload ?? {}),
|
|
25010
|
+
sessionId: event.sessionId,
|
|
25011
|
+
severity: toSeverityFromAudit(event),
|
|
25012
|
+
traceId: event.traceId
|
|
25013
|
+
});
|
|
25014
|
+
var buildVoiceObservabilityExport = async (options = {}) => {
|
|
25015
|
+
const events = options.events ?? await options.store?.list() ?? [];
|
|
25016
|
+
const auditEvents = options.audit ? await options.audit.list() : [];
|
|
25017
|
+
const baseOperationsRecords = options.operationsRecords ?? [];
|
|
25018
|
+
const sessionIds = collectSessionIds({
|
|
25019
|
+
auditEvents,
|
|
25020
|
+
events,
|
|
25021
|
+
operationsRecords: baseOperationsRecords,
|
|
25022
|
+
sessionIds: options.sessionIds
|
|
25023
|
+
});
|
|
25024
|
+
const shouldBuildOperationsRecords = options.includeOperationsRecords !== false && options.store;
|
|
25025
|
+
const builtOperationsRecords = shouldBuildOperationsRecords ? await Promise.all(sessionIds.map((sessionId) => buildVoiceOperationsRecord({
|
|
25026
|
+
audit: options.audit,
|
|
25027
|
+
redact: options.redact,
|
|
25028
|
+
sessionId,
|
|
25029
|
+
store: options.store
|
|
25030
|
+
}))) : [];
|
|
25031
|
+
const operationsRecords = [
|
|
25032
|
+
...baseOperationsRecords,
|
|
25033
|
+
...builtOperationsRecords.filter((record) => !baseOperationsRecords.some((existing) => existing.sessionId === record.sessionId))
|
|
25034
|
+
];
|
|
25035
|
+
const traceDeliveries = options.traceDeliveries ? isDeliveryStore(options.traceDeliveries) ? await options.traceDeliveries.list() : options.traceDeliveries : undefined;
|
|
25036
|
+
const auditDeliveries = options.auditDeliveries ? isDeliveryStore(options.auditDeliveries) ? await options.auditDeliveries.list() : options.auditDeliveries : undefined;
|
|
25037
|
+
const traceDeliverySummary = traceDeliveries ? await summarizeVoiceTraceSinkDeliveries(traceDeliveries) : undefined;
|
|
25038
|
+
const auditDeliverySummary = auditDeliveries ? await summarizeVoiceAuditSinkDeliveries(auditDeliveries) : undefined;
|
|
25039
|
+
const operationArtifacts = operationsRecords.map((record) => createOperationArtifact(record, options.links?.operationsRecord?.(record.sessionId)));
|
|
25040
|
+
const artifacts = [...operationArtifacts, ...options.artifacts ?? []];
|
|
25041
|
+
const operationHrefBySessionId = new Map(operationsRecords.map((record) => [
|
|
25042
|
+
record.sessionId,
|
|
25043
|
+
options.links?.operationsRecord?.(record.sessionId)
|
|
25044
|
+
]));
|
|
25045
|
+
const envelopes = [
|
|
25046
|
+
...events.map((event) => buildTraceEnvelope(event, operationHrefBySessionId.get(event.sessionId))),
|
|
25047
|
+
...auditEvents.map((event) => buildAuditEnvelope(event, event.sessionId ? operationHrefBySessionId.get(event.sessionId) : undefined))
|
|
25048
|
+
].sort((left, right) => left.at - right.at);
|
|
25049
|
+
const issues = collectIssues({
|
|
25050
|
+
auditDeliveries: auditDeliverySummary,
|
|
25051
|
+
operationsRecords,
|
|
25052
|
+
totalEvidence: events.length + auditEvents.length + operationsRecords.length + artifacts.length,
|
|
25053
|
+
traceDeliveries: traceDeliverySummary
|
|
25054
|
+
});
|
|
25055
|
+
const status = issues.some((issue) => issue.severity === "fail") ? "fail" : issues.some((issue) => issue.severity === "warn") ? "warn" : "pass";
|
|
25056
|
+
return {
|
|
25057
|
+
artifacts,
|
|
25058
|
+
checkedAt: Date.now(),
|
|
25059
|
+
deliveries: {
|
|
25060
|
+
audit: auditDeliverySummary,
|
|
25061
|
+
trace: traceDeliverySummary
|
|
25062
|
+
},
|
|
25063
|
+
envelopes,
|
|
25064
|
+
issues,
|
|
25065
|
+
operationsRecords,
|
|
25066
|
+
redaction: {
|
|
25067
|
+
enabled: Boolean(options.redact),
|
|
25068
|
+
mode: options.redact ? "redacted" : "none"
|
|
25069
|
+
},
|
|
25070
|
+
sessionIds,
|
|
25071
|
+
status,
|
|
25072
|
+
summary: {
|
|
25073
|
+
auditEvents: auditEvents.length,
|
|
25074
|
+
events: events.length + auditEvents.length,
|
|
25075
|
+
failedOperationsRecords: operationsRecords.filter((record) => record.status === "failed").length,
|
|
25076
|
+
trace: summarizeVoiceTrace(events),
|
|
25077
|
+
traceEvents: events.length
|
|
25078
|
+
}
|
|
25079
|
+
};
|
|
25080
|
+
};
|
|
25081
|
+
var renderVoiceObservabilityExportMarkdown = (report, options = {}) => {
|
|
25082
|
+
const title = options.title ?? "Voice Observability Export";
|
|
25083
|
+
const issues = report.issues.map((issue) => `- ${issue.severity}: ${issue.label}${issue.value !== undefined ? ` (${issue.value})` : ""}${issue.detail ? ` - ${issue.detail}` : ""}`).join(`
|
|
25084
|
+
`) || "No observability export issues.";
|
|
25085
|
+
const artifacts = report.artifacts.map((artifact) => `- ${artifact.label}: ${artifact.kind}${artifact.href ? ` (${artifact.href})` : ""}${artifact.status ? ` - ${artifact.status}` : ""}`).join(`
|
|
25086
|
+
`) || "No artifacts attached.";
|
|
25087
|
+
return `# ${title}
|
|
25088
|
+
|
|
25089
|
+
Generated: ${new Date(report.checkedAt).toISOString()}
|
|
25090
|
+
|
|
25091
|
+
Overall: **${report.status}**
|
|
25092
|
+
|
|
25093
|
+
Redaction: **${report.redaction.mode}**
|
|
25094
|
+
|
|
25095
|
+
Sessions: ${report.sessionIds.length}
|
|
25096
|
+
|
|
25097
|
+
Trace events: ${report.summary.traceEvents}
|
|
25098
|
+
|
|
25099
|
+
Audit events: ${report.summary.auditEvents}
|
|
25100
|
+
|
|
25101
|
+
Operations records: ${report.operationsRecords.length}
|
|
25102
|
+
|
|
25103
|
+
Artifacts: ${report.artifacts.length}
|
|
25104
|
+
|
|
25105
|
+
## Delivery Summary
|
|
25106
|
+
|
|
25107
|
+
Trace deliveries: ${report.deliveries.trace ? `${report.deliveries.trace.delivered} delivered, ${report.deliveries.trace.pending} pending, ${report.deliveries.trace.failed} failed` : "not configured"}
|
|
25108
|
+
|
|
25109
|
+
Audit deliveries: ${report.deliveries.audit ? `${report.deliveries.audit.delivered} delivered, ${report.deliveries.audit.pending} pending, ${report.deliveries.audit.failed} failed` : "not configured"}
|
|
25110
|
+
|
|
25111
|
+
## Artifacts
|
|
25112
|
+
|
|
25113
|
+
${artifacts}
|
|
25114
|
+
|
|
25115
|
+
## Issues
|
|
25116
|
+
|
|
25117
|
+
${issues}
|
|
25118
|
+
`;
|
|
25119
|
+
};
|
|
25120
|
+
var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
25121
|
+
const path = options.path ?? "/api/voice/observability-export";
|
|
25122
|
+
const markdownPath = options.markdownPath ?? "/voice/observability-export.md";
|
|
25123
|
+
const htmlPath = options.htmlPath ?? "/voice/observability-export";
|
|
25124
|
+
const headers = {
|
|
25125
|
+
"cache-control": "no-store",
|
|
25126
|
+
...options.headers ?? {}
|
|
25127
|
+
};
|
|
25128
|
+
const buildReport = () => buildVoiceObservabilityExport(options);
|
|
25129
|
+
const app = new Elysia42({
|
|
25130
|
+
name: options.name ?? "absolute-voice-observability-export"
|
|
25131
|
+
});
|
|
25132
|
+
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
25133
|
+
if (markdownPath !== false) {
|
|
25134
|
+
app.get(markdownPath, async () => {
|
|
25135
|
+
const report = await buildReport();
|
|
25136
|
+
return new Response(renderVoiceObservabilityExportMarkdown(report, {
|
|
25137
|
+
title: options.title
|
|
25138
|
+
}), {
|
|
25139
|
+
headers: {
|
|
25140
|
+
...headers,
|
|
25141
|
+
"content-type": "text/markdown; charset=utf-8"
|
|
25142
|
+
}
|
|
25143
|
+
});
|
|
25144
|
+
});
|
|
25145
|
+
}
|
|
25146
|
+
if (htmlPath !== false) {
|
|
25147
|
+
app.get(htmlPath, async () => {
|
|
25148
|
+
const report = await buildReport();
|
|
25149
|
+
const markdown = options.render ? await options.render(report) : renderVoiceObservabilityExportMarkdown(report, {
|
|
25150
|
+
title: options.title
|
|
25151
|
+
});
|
|
25152
|
+
return new Response(`<!doctype html><html><head><meta charset="utf-8" /><title>${options.title ?? "Voice Observability Export"}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:auto;max-width:920px;padding:32px;white-space:pre-wrap}</style></head><body>${markdown}</body></html>`, {
|
|
25153
|
+
headers: {
|
|
25154
|
+
...headers,
|
|
25155
|
+
"content-type": "text/html; charset=utf-8"
|
|
25156
|
+
}
|
|
25157
|
+
});
|
|
25158
|
+
});
|
|
25159
|
+
}
|
|
25160
|
+
return app;
|
|
25161
|
+
};
|
|
25162
|
+
// src/incidentBundle.ts
|
|
25163
|
+
import { Elysia as Elysia43 } from "elysia";
|
|
24905
25164
|
var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
|
|
24906
25165
|
if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
|
|
24907
25166
|
return false;
|
|
@@ -25100,7 +25359,7 @@ var buildVoiceIncidentBundle = async (options) => {
|
|
|
25100
25359
|
var createVoiceIncidentBundleRoutes = (options) => {
|
|
25101
25360
|
const path = options.path ?? "/api/voice-incidents/:sessionId";
|
|
25102
25361
|
const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
|
|
25103
|
-
const routes = new
|
|
25362
|
+
const routes = new Elysia43({
|
|
25104
25363
|
name: options.name ?? "absolutejs-voice-incident-bundle"
|
|
25105
25364
|
});
|
|
25106
25365
|
const getSessionId = (params) => params.sessionId ?? "";
|
|
@@ -25301,7 +25560,7 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
25301
25560
|
};
|
|
25302
25561
|
};
|
|
25303
25562
|
// src/opsStatusRoutes.ts
|
|
25304
|
-
import { Elysia as
|
|
25563
|
+
import { Elysia as Elysia44 } from "elysia";
|
|
25305
25564
|
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25306
25565
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
25307
25566
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
@@ -25313,7 +25572,7 @@ var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
|
25313
25572
|
};
|
|
25314
25573
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
25315
25574
|
const path = options.path ?? "/api/voice/ops-status";
|
|
25316
|
-
const routes = new
|
|
25575
|
+
const routes = new Elysia44({
|
|
25317
25576
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
25318
25577
|
});
|
|
25319
25578
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -25746,9 +26005,9 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
25746
26005
|
};
|
|
25747
26006
|
};
|
|
25748
26007
|
// src/traceDeliveryRoutes.ts
|
|
25749
|
-
import { Elysia as
|
|
26008
|
+
import { Elysia as Elysia45 } from "elysia";
|
|
25750
26009
|
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25751
|
-
var
|
|
26010
|
+
var getString19 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
25752
26011
|
var getNumber11 = (value) => {
|
|
25753
26012
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
25754
26013
|
return value;
|
|
@@ -25760,13 +26019,13 @@ var getNumber11 = (value) => {
|
|
|
25760
26019
|
return;
|
|
25761
26020
|
};
|
|
25762
26021
|
var parseStatus2 = (value) => {
|
|
25763
|
-
const text =
|
|
26022
|
+
const text = getString19(value);
|
|
25764
26023
|
return text === "pending" || text === "delivered" || text === "failed" || text === "skipped" || text === "all" ? text : undefined;
|
|
25765
26024
|
};
|
|
25766
26025
|
var resolveVoiceTraceDeliveryFilter = (query = {}, base = {}) => ({
|
|
25767
26026
|
...base,
|
|
25768
26027
|
limit: getNumber11(query.limit) ?? base.limit,
|
|
25769
|
-
q:
|
|
26028
|
+
q: getString19(query.q) ?? base.q,
|
|
25770
26029
|
status: parseStatus2(query.status) ?? base.status
|
|
25771
26030
|
});
|
|
25772
26031
|
var deliverySearchText2 = (delivery) => [
|
|
@@ -25855,7 +26114,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
25855
26114
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
25856
26115
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
25857
26116
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
25858
|
-
const routes = new
|
|
26117
|
+
const routes = new Elysia45({
|
|
25859
26118
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
25860
26119
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
25861
26120
|
if (htmlPath !== false) {
|
|
@@ -26479,7 +26738,7 @@ var createVoiceMemoryStore = () => {
|
|
|
26479
26738
|
return { get, getOrCreate, list, remove, set };
|
|
26480
26739
|
};
|
|
26481
26740
|
// src/opsWebhook.ts
|
|
26482
|
-
import { Elysia as
|
|
26741
|
+
import { Elysia as Elysia46 } from "elysia";
|
|
26483
26742
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
26484
26743
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
26485
26744
|
const encoder = new TextEncoder;
|
|
@@ -26609,7 +26868,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
26609
26868
|
};
|
|
26610
26869
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
26611
26870
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
26612
|
-
return new
|
|
26871
|
+
return new Elysia46().post(path, async ({ body, request, set }) => {
|
|
26613
26872
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
26614
26873
|
if (options.signingSecret) {
|
|
26615
26874
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -27560,6 +27819,7 @@ export {
|
|
|
27560
27819
|
renderVoiceOpsActionHistoryHTML,
|
|
27561
27820
|
renderVoiceOperationsRecordIncidentMarkdown,
|
|
27562
27821
|
renderVoiceOperationsRecordHTML,
|
|
27822
|
+
renderVoiceObservabilityExportMarkdown,
|
|
27563
27823
|
renderVoiceLiveLatencyHTML,
|
|
27564
27824
|
renderVoiceLatencySLOMarkdown,
|
|
27565
27825
|
renderVoiceHandoffHealthHTML,
|
|
@@ -27758,6 +28018,7 @@ export {
|
|
|
27758
28018
|
createVoiceOpsConsoleRoutes,
|
|
27759
28019
|
createVoiceOpsActionAuditRoutes,
|
|
27760
28020
|
createVoiceOperationsRecordRoutes,
|
|
28021
|
+
createVoiceObservabilityExportRoutes,
|
|
27761
28022
|
createVoiceMemoryTraceSinkDeliveryStore,
|
|
27762
28023
|
createVoiceMemoryTraceEventStore,
|
|
27763
28024
|
createVoiceMemoryStore,
|
|
@@ -27894,6 +28155,7 @@ export {
|
|
|
27894
28155
|
buildVoiceOpsConsoleReport,
|
|
27895
28156
|
buildVoiceOpsActionHistoryReport,
|
|
27896
28157
|
buildVoiceOperationsRecord,
|
|
28158
|
+
buildVoiceObservabilityExport,
|
|
27897
28159
|
buildVoiceLiveOpsControlState,
|
|
27898
28160
|
buildVoiceLatencySLOGate,
|
|
27899
28161
|
buildVoiceIncidentBundle,
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import { type VoiceAuditSinkDeliveryQueueSummary, type VoiceAuditSinkDeliveryRecord, type VoiceAuditSinkDeliveryStore } from './auditSinks';
|
|
3
|
+
import type { VoiceAuditEventStore, VoiceAuditEventType } from './audit';
|
|
4
|
+
import { type VoiceOperationsRecord } from './operationsRecord';
|
|
5
|
+
import { type VoiceTraceSinkDeliveryQueueSummary } from './queue';
|
|
6
|
+
import { type StoredVoiceTraceEvent, type VoiceTraceEventStore, type VoiceTraceEventType, type VoiceTraceRedactionConfig, type VoiceTraceSinkDeliveryRecord, type VoiceTraceSinkDeliveryStore, type VoiceTraceSummary } from './trace';
|
|
7
|
+
export type VoiceObservabilityExportStatus = 'fail' | 'pass' | 'warn';
|
|
8
|
+
export type VoiceObservabilityExportArtifactKind = 'incident' | 'markdown' | 'operations-record' | 'proof-pack' | 'readiness' | 'screenshot' | 'slo' | 'trace' | 'audit' | 'custom';
|
|
9
|
+
export type VoiceObservabilityExportArtifact = {
|
|
10
|
+
bytes?: number;
|
|
11
|
+
contentType?: string;
|
|
12
|
+
generatedAt?: number | string;
|
|
13
|
+
href?: string;
|
|
14
|
+
id: string;
|
|
15
|
+
kind: VoiceObservabilityExportArtifactKind;
|
|
16
|
+
label: string;
|
|
17
|
+
path?: string;
|
|
18
|
+
sessionId?: string;
|
|
19
|
+
status?: VoiceObservabilityExportStatus;
|
|
20
|
+
};
|
|
21
|
+
export type VoiceObservabilityExportEnvelope = {
|
|
22
|
+
at: number;
|
|
23
|
+
eventId: string;
|
|
24
|
+
eventType: VoiceTraceEventType | VoiceAuditEventType;
|
|
25
|
+
kind: 'audit' | 'trace';
|
|
26
|
+
operationsRecordHref?: string;
|
|
27
|
+
provider?: string;
|
|
28
|
+
providerKind?: string;
|
|
29
|
+
scenarioId?: string;
|
|
30
|
+
sessionId?: string;
|
|
31
|
+
severity: VoiceObservabilityExportStatus;
|
|
32
|
+
traceId?: string;
|
|
33
|
+
};
|
|
34
|
+
export type VoiceObservabilityExportIssueCode = 'voice.observability.no_evidence' | 'voice.observability.operation_failed' | 'voice.observability.audit_delivery_failed' | 'voice.observability.audit_delivery_pending' | 'voice.observability.trace_delivery_failed' | 'voice.observability.trace_delivery_pending';
|
|
35
|
+
export type VoiceObservabilityExportIssue = {
|
|
36
|
+
code: VoiceObservabilityExportIssueCode;
|
|
37
|
+
detail?: string;
|
|
38
|
+
label: string;
|
|
39
|
+
severity: Exclude<VoiceObservabilityExportStatus, 'pass'>;
|
|
40
|
+
value?: number | string;
|
|
41
|
+
};
|
|
42
|
+
export type VoiceObservabilityExportDeliverySummary = {
|
|
43
|
+
audit?: VoiceAuditSinkDeliveryQueueSummary;
|
|
44
|
+
trace?: VoiceTraceSinkDeliveryQueueSummary;
|
|
45
|
+
};
|
|
46
|
+
export type VoiceObservabilityExportRedactionSummary = {
|
|
47
|
+
enabled: boolean;
|
|
48
|
+
mode: 'none' | 'redacted';
|
|
49
|
+
};
|
|
50
|
+
export type VoiceObservabilityExportReport = {
|
|
51
|
+
artifacts: VoiceObservabilityExportArtifact[];
|
|
52
|
+
checkedAt: number;
|
|
53
|
+
deliveries: VoiceObservabilityExportDeliverySummary;
|
|
54
|
+
envelopes: VoiceObservabilityExportEnvelope[];
|
|
55
|
+
issues: VoiceObservabilityExportIssue[];
|
|
56
|
+
operationsRecords: VoiceOperationsRecord[];
|
|
57
|
+
redaction: VoiceObservabilityExportRedactionSummary;
|
|
58
|
+
sessionIds: string[];
|
|
59
|
+
status: VoiceObservabilityExportStatus;
|
|
60
|
+
summary: {
|
|
61
|
+
auditEvents: number;
|
|
62
|
+
events: number;
|
|
63
|
+
failedOperationsRecords: number;
|
|
64
|
+
trace: VoiceTraceSummary;
|
|
65
|
+
traceEvents: number;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
export type VoiceObservabilityExportOptions = {
|
|
69
|
+
artifacts?: VoiceObservabilityExportArtifact[];
|
|
70
|
+
audit?: VoiceAuditEventStore;
|
|
71
|
+
auditDeliveries?: VoiceAuditSinkDeliveryRecord[] | VoiceAuditSinkDeliveryStore;
|
|
72
|
+
events?: StoredVoiceTraceEvent[];
|
|
73
|
+
includeOperationsRecords?: boolean;
|
|
74
|
+
links?: {
|
|
75
|
+
operationsRecord?: (sessionId: string) => string;
|
|
76
|
+
};
|
|
77
|
+
operationsRecords?: VoiceOperationsRecord[];
|
|
78
|
+
redact?: VoiceTraceRedactionConfig;
|
|
79
|
+
sessionIds?: string[];
|
|
80
|
+
store?: VoiceTraceEventStore;
|
|
81
|
+
traceDeliveries?: VoiceTraceSinkDeliveryRecord[] | VoiceTraceSinkDeliveryStore;
|
|
82
|
+
};
|
|
83
|
+
export type VoiceObservabilityExportRoutesOptions = VoiceObservabilityExportOptions & {
|
|
84
|
+
headers?: HeadersInit;
|
|
85
|
+
htmlPath?: false | string;
|
|
86
|
+
markdownPath?: false | string;
|
|
87
|
+
name?: string;
|
|
88
|
+
path?: string;
|
|
89
|
+
render?: (report: VoiceObservabilityExportReport) => string | Promise<string>;
|
|
90
|
+
title?: string;
|
|
91
|
+
};
|
|
92
|
+
export declare const buildVoiceObservabilityExport: (options?: VoiceObservabilityExportOptions) => Promise<VoiceObservabilityExportReport>;
|
|
93
|
+
export declare const renderVoiceObservabilityExportMarkdown: (report: VoiceObservabilityExportReport, options?: {
|
|
94
|
+
title?: string;
|
|
95
|
+
}) => string;
|
|
96
|
+
export declare const createVoiceObservabilityExportRoutes: (options?: VoiceObservabilityExportRoutesOptions) => Elysia<"", {
|
|
97
|
+
decorator: {};
|
|
98
|
+
store: {};
|
|
99
|
+
derive: {};
|
|
100
|
+
resolve: {};
|
|
101
|
+
}, {
|
|
102
|
+
typebox: {};
|
|
103
|
+
error: {};
|
|
104
|
+
}, {
|
|
105
|
+
schema: {};
|
|
106
|
+
standaloneSchema: {};
|
|
107
|
+
macro: {};
|
|
108
|
+
macroFn: {};
|
|
109
|
+
parser: {};
|
|
110
|
+
response: {};
|
|
111
|
+
}, {}, {
|
|
112
|
+
derive: {};
|
|
113
|
+
resolve: {};
|
|
114
|
+
schema: {};
|
|
115
|
+
standaloneSchema: {};
|
|
116
|
+
response: {};
|
|
117
|
+
}, {
|
|
118
|
+
derive: {};
|
|
119
|
+
resolve: {};
|
|
120
|
+
schema: {};
|
|
121
|
+
standaloneSchema: {};
|
|
122
|
+
response: {};
|
|
123
|
+
}>;
|
package/dist/providerSlo.d.ts
CHANGED
|
@@ -65,6 +65,8 @@ export type VoiceProviderSloReportOptions = {
|
|
|
65
65
|
maxAgeMs?: number;
|
|
66
66
|
now?: number;
|
|
67
67
|
requiredKinds?: readonly VoiceRoutingEventKind[];
|
|
68
|
+
scenarioId?: string;
|
|
69
|
+
sessionId?: string;
|
|
68
70
|
store?: VoiceTraceEventStore;
|
|
69
71
|
thresholds?: VoiceProviderSloThresholdConfig;
|
|
70
72
|
};
|