@absolutejs/voice 0.0.22-beta.217 → 0.0.22-beta.219
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 +272 -11
- package/dist/observabilityExport.d.ts +123 -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
|
@@ -24901,8 +24901,266 @@ var createVoiceOperationsRecordRoutes = (options) => {
|
|
|
24901
24901
|
}
|
|
24902
24902
|
return routes;
|
|
24903
24903
|
};
|
|
24904
|
-
// src/
|
|
24904
|
+
// src/observabilityExport.ts
|
|
24905
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 === true && 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(sessionIds.map((sessionId) => [
|
|
25042
|
+
sessionId,
|
|
25043
|
+
options.links?.operationsRecord?.(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";
|
|
24906
25164
|
var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
|
|
24907
25165
|
if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
|
|
24908
25166
|
return false;
|
|
@@ -25101,7 +25359,7 @@ var buildVoiceIncidentBundle = async (options) => {
|
|
|
25101
25359
|
var createVoiceIncidentBundleRoutes = (options) => {
|
|
25102
25360
|
const path = options.path ?? "/api/voice-incidents/:sessionId";
|
|
25103
25361
|
const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
|
|
25104
|
-
const routes = new
|
|
25362
|
+
const routes = new Elysia43({
|
|
25105
25363
|
name: options.name ?? "absolutejs-voice-incident-bundle"
|
|
25106
25364
|
});
|
|
25107
25365
|
const getSessionId = (params) => params.sessionId ?? "";
|
|
@@ -25302,7 +25560,7 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
25302
25560
|
};
|
|
25303
25561
|
};
|
|
25304
25562
|
// src/opsStatusRoutes.ts
|
|
25305
|
-
import { Elysia as
|
|
25563
|
+
import { Elysia as Elysia44 } from "elysia";
|
|
25306
25564
|
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25307
25565
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
25308
25566
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
@@ -25314,7 +25572,7 @@ var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
|
25314
25572
|
};
|
|
25315
25573
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
25316
25574
|
const path = options.path ?? "/api/voice/ops-status";
|
|
25317
|
-
const routes = new
|
|
25575
|
+
const routes = new Elysia44({
|
|
25318
25576
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
25319
25577
|
});
|
|
25320
25578
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -25747,9 +26005,9 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
25747
26005
|
};
|
|
25748
26006
|
};
|
|
25749
26007
|
// src/traceDeliveryRoutes.ts
|
|
25750
|
-
import { Elysia as
|
|
26008
|
+
import { Elysia as Elysia45 } from "elysia";
|
|
25751
26009
|
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25752
|
-
var
|
|
26010
|
+
var getString19 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
25753
26011
|
var getNumber11 = (value) => {
|
|
25754
26012
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
25755
26013
|
return value;
|
|
@@ -25761,13 +26019,13 @@ var getNumber11 = (value) => {
|
|
|
25761
26019
|
return;
|
|
25762
26020
|
};
|
|
25763
26021
|
var parseStatus2 = (value) => {
|
|
25764
|
-
const text =
|
|
26022
|
+
const text = getString19(value);
|
|
25765
26023
|
return text === "pending" || text === "delivered" || text === "failed" || text === "skipped" || text === "all" ? text : undefined;
|
|
25766
26024
|
};
|
|
25767
26025
|
var resolveVoiceTraceDeliveryFilter = (query = {}, base = {}) => ({
|
|
25768
26026
|
...base,
|
|
25769
26027
|
limit: getNumber11(query.limit) ?? base.limit,
|
|
25770
|
-
q:
|
|
26028
|
+
q: getString19(query.q) ?? base.q,
|
|
25771
26029
|
status: parseStatus2(query.status) ?? base.status
|
|
25772
26030
|
});
|
|
25773
26031
|
var deliverySearchText2 = (delivery) => [
|
|
@@ -25856,7 +26114,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
25856
26114
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
25857
26115
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
25858
26116
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
25859
|
-
const routes = new
|
|
26117
|
+
const routes = new Elysia45({
|
|
25860
26118
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
25861
26119
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
25862
26120
|
if (htmlPath !== false) {
|
|
@@ -26480,7 +26738,7 @@ var createVoiceMemoryStore = () => {
|
|
|
26480
26738
|
return { get, getOrCreate, list, remove, set };
|
|
26481
26739
|
};
|
|
26482
26740
|
// src/opsWebhook.ts
|
|
26483
|
-
import { Elysia as
|
|
26741
|
+
import { Elysia as Elysia46 } from "elysia";
|
|
26484
26742
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
26485
26743
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
26486
26744
|
const encoder = new TextEncoder;
|
|
@@ -26610,7 +26868,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
26610
26868
|
};
|
|
26611
26869
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
26612
26870
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
26613
|
-
return new
|
|
26871
|
+
return new Elysia46().post(path, async ({ body, request, set }) => {
|
|
26614
26872
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
26615
26873
|
if (options.signingSecret) {
|
|
26616
26874
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -27561,6 +27819,7 @@ export {
|
|
|
27561
27819
|
renderVoiceOpsActionHistoryHTML,
|
|
27562
27820
|
renderVoiceOperationsRecordIncidentMarkdown,
|
|
27563
27821
|
renderVoiceOperationsRecordHTML,
|
|
27822
|
+
renderVoiceObservabilityExportMarkdown,
|
|
27564
27823
|
renderVoiceLiveLatencyHTML,
|
|
27565
27824
|
renderVoiceLatencySLOMarkdown,
|
|
27566
27825
|
renderVoiceHandoffHealthHTML,
|
|
@@ -27759,6 +28018,7 @@ export {
|
|
|
27759
28018
|
createVoiceOpsConsoleRoutes,
|
|
27760
28019
|
createVoiceOpsActionAuditRoutes,
|
|
27761
28020
|
createVoiceOperationsRecordRoutes,
|
|
28021
|
+
createVoiceObservabilityExportRoutes,
|
|
27762
28022
|
createVoiceMemoryTraceSinkDeliveryStore,
|
|
27763
28023
|
createVoiceMemoryTraceEventStore,
|
|
27764
28024
|
createVoiceMemoryStore,
|
|
@@ -27895,6 +28155,7 @@ export {
|
|
|
27895
28155
|
buildVoiceOpsConsoleReport,
|
|
27896
28156
|
buildVoiceOpsActionHistoryReport,
|
|
27897
28157
|
buildVoiceOperationsRecord,
|
|
28158
|
+
buildVoiceObservabilityExport,
|
|
27898
28159
|
buildVoiceLiveOpsControlState,
|
|
27899
28160
|
buildVoiceLatencySLOGate,
|
|
27900
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
|
+
}>;
|