@absolutejs/voice 0.0.22-beta.221 → 0.0.22-beta.222

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 CHANGED
@@ -2791,7 +2791,7 @@ const exportReport = await buildVoiceObservabilityExport({
2791
2791
  });
2792
2792
  ```
2793
2793
 
2794
- The route helper exposes JSON at `/api/voice/observability-export`, Markdown at `/voice/observability-export.md`, and HTML at `/voice/observability-export`. Path-backed artifacts are hashed with SHA-256 by default, include byte size and freshness metadata, and can fail the export when required evidence is missing or stale. 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.
2794
+ The route helper exposes JSON at `/api/voice/observability-export`, an artifact index at `/api/voice/observability-export/artifacts`, per-artifact downloads at `/api/voice/observability-export/artifacts/:artifactId`, Markdown at `/voice/observability-export.md`, and HTML at `/voice/observability-export`. Path-backed artifacts are hashed with SHA-256 by default, include byte size and freshness metadata, and can fail the export when required evidence is missing or stale. 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.
2795
2795
 
2796
2796
  Pass the same report into production readiness when export health should block deploys:
2797
2797
 
package/dist/index.d.ts CHANGED
@@ -53,7 +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
+ export { buildVoiceObservabilityArtifactIndex, buildVoiceObservabilityExport, createVoiceObservabilityExportRoutes, renderVoiceObservabilityExportMarkdown } from './observabilityExport';
57
57
  export { buildVoiceOpsRecoveryReadinessCheck, buildVoiceOpsRecoveryReport, createVoiceOpsRecoveryRoutes, renderVoiceOpsRecoveryHTML, renderVoiceOpsRecoveryMarkdown } from './opsRecovery';
58
58
  export { buildVoiceIncidentBundle, createStoredVoiceIncidentBundleArtifact, createVoiceIncidentBundleRoutes, createVoiceMemoryIncidentBundleStore, pruneVoiceIncidentBundleArtifacts, saveVoiceIncidentBundleArtifact } from './incidentBundle';
59
59
  export { summarizeVoiceOpsStatus } from './opsStatus';
@@ -118,7 +118,7 @@ export type { VoiceProductionReadinessAction, VoiceProductionReadinessAuditOptio
118
118
  export type { VoiceReadinessProfileName, VoiceReadinessProfileOptions, VoiceReadinessProfileRecommendation, VoiceReadinessProfileRecommendationScore, VoiceReadinessProfileRoutesOptions } from './readinessProfiles';
119
119
  export type { VoiceProviderStackChoice, VoiceProviderStackCapabilities, VoiceProviderStackCapabilityGap, VoiceProviderStackCapabilityGapInput, VoiceProviderStackCapabilityGapReport, VoiceProviderContractCheck, VoiceProviderContractCheckStatus, VoiceProviderContractDefinition, VoiceProviderContractMatrixHandlerOptions, VoiceProviderContractMatrixHTMLHandlerOptions, VoiceProviderContractMatrixInput, VoiceProviderContractMatrixPresetOptions, VoiceProviderContractMatrixReport, VoiceProviderContractMatrixRoutesOptions, VoiceProviderContractMatrixRow, VoiceProviderStackInput, VoiceProviderStackKind, VoiceProviderStackRecommendation } from './providerStackRecommendations';
120
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';
121
+ export type { VoiceObservabilityExportArtifact, VoiceObservabilityExportArtifactChecksum, VoiceObservabilityExportArtifactFreshness, VoiceObservabilityExportArtifactIndex, VoiceObservabilityExportArtifactIndexItem, VoiceObservabilityExportArtifactKind, VoiceObservabilityExportDeliverySummary, VoiceObservabilityExportEnvelope, VoiceObservabilityExportIssue, VoiceObservabilityExportIssueCode, VoiceObservabilityExportOptions, VoiceObservabilityExportRedactionSummary, VoiceObservabilityExportReport, VoiceObservabilityExportRoutesOptions, VoiceObservabilityExportStatus } from './observabilityExport';
122
122
  export type { VoiceOpsRecoveryFailedSession, VoiceOpsRecoveryInterventionSummary, VoiceOpsRecoveryIssue, VoiceOpsRecoveryIssueCode, VoiceOpsRecoveryLinks, VoiceOpsRecoveryProviderSummary, VoiceOpsRecoveryReport, VoiceOpsRecoveryReportOptions, VoiceOpsRecoveryRoutesOptions, VoiceOpsRecoveryStatus } from './opsRecovery';
123
123
  export type { StoredVoiceIncidentBundleArtifact, VoiceIncidentBundle, VoiceIncidentBundleArtifactOptions, VoiceIncidentBundleFormat, VoiceIncidentBundleOptions, VoiceIncidentBundleRetentionOptions, VoiceIncidentBundleRetentionReport, VoiceIncidentBundleRoutesOptions, VoiceIncidentBundleStore, VoiceIncidentBundleStoreFilter, VoiceIncidentBundleSummary } from './incidentBundle';
124
124
  export type { VoiceQualityLink, VoiceQualityMetric, VoiceQualityReport, VoiceQualityRoutesOptions, VoiceQualityStatus, VoiceQualityThresholds } from './qualityRoutes';
package/dist/index.js CHANGED
@@ -24982,6 +24982,36 @@ var checksumFile = async (path) => {
24982
24982
  const buffer = await readFile2(path);
24983
24983
  return createHash("sha256").update(buffer).digest("hex");
24984
24984
  };
24985
+ var inferContentType = (artifact) => {
24986
+ if (artifact.contentType) {
24987
+ return artifact.contentType;
24988
+ }
24989
+ const path = artifact.path ? stripArtifactPathAnchor(artifact.path) : "";
24990
+ if (path.endsWith(".json")) {
24991
+ return "application/json; charset=utf-8";
24992
+ }
24993
+ if (path.endsWith(".md") || path.endsWith(".markdown")) {
24994
+ return "text/markdown; charset=utf-8";
24995
+ }
24996
+ if (path.endsWith(".html")) {
24997
+ return "text/html; charset=utf-8";
24998
+ }
24999
+ if (path.endsWith(".png")) {
25000
+ return "image/png";
25001
+ }
25002
+ if (path.endsWith(".jpg") || path.endsWith(".jpeg")) {
25003
+ return "image/jpeg";
25004
+ }
25005
+ if (path.endsWith(".txt") || path.endsWith(".log")) {
25006
+ return "text/plain; charset=utf-8";
25007
+ }
25008
+ return "application/octet-stream";
25009
+ };
25010
+ var addArtifactDownloadHrefs = (artifacts, links) => artifacts.map((artifact) => ({
25011
+ ...artifact,
25012
+ contentType: artifact.contentType ?? inferContentType(artifact),
25013
+ downloadHref: artifact.downloadHref ?? (artifact.path ? links?.artifactDownload?.(artifact) : undefined)
25014
+ }));
24985
25015
  var verifyArtifact = async (artifact, options) => {
24986
25016
  const now = options.now ?? Date.now();
24987
25017
  const maxAgeMs = artifact.maxAgeMs ?? options.maxAgeMs;
@@ -25171,7 +25201,7 @@ var buildVoiceObservabilityExport = async (options = {}) => {
25171
25201
  const traceDeliverySummary = traceDeliveries ? await summarizeVoiceTraceSinkDeliveries(traceDeliveries) : undefined;
25172
25202
  const auditDeliverySummary = auditDeliveries ? await summarizeVoiceAuditSinkDeliveries(auditDeliveries) : undefined;
25173
25203
  const operationArtifacts = operationsRecords.map((record) => createOperationArtifact(record, options.links?.operationsRecord?.(record.sessionId)));
25174
- const artifacts = await verifyArtifacts([...operationArtifacts, ...options.artifacts ?? []], options.artifactIntegrity);
25204
+ const artifacts = addArtifactDownloadHrefs(await verifyArtifacts([...operationArtifacts, ...options.artifacts ?? []], options.artifactIntegrity), options.links);
25175
25205
  const operationHrefBySessionId = new Map(sessionIds.map((sessionId) => [
25176
25206
  sessionId,
25177
25207
  options.links?.operationsRecord?.(sessionId)
@@ -25252,19 +25282,87 @@ ${artifacts}
25252
25282
  ${issues}
25253
25283
  `;
25254
25284
  };
25285
+ var buildVoiceObservabilityArtifactIndex = (report) => {
25286
+ const artifacts = report.artifacts.map((artifact) => ({
25287
+ bytes: artifact.bytes,
25288
+ checksum: artifact.checksum,
25289
+ contentType: artifact.contentType,
25290
+ downloadHref: artifact.downloadHref,
25291
+ freshness: artifact.freshness,
25292
+ href: artifact.href,
25293
+ id: artifact.id,
25294
+ kind: artifact.kind,
25295
+ label: artifact.label,
25296
+ required: artifact.required,
25297
+ sessionId: artifact.sessionId,
25298
+ status: artifact.status
25299
+ }));
25300
+ return {
25301
+ artifacts,
25302
+ checkedAt: report.checkedAt,
25303
+ status: report.status,
25304
+ summary: {
25305
+ downloadable: artifacts.filter((artifact) => artifact.downloadHref).length,
25306
+ failed: artifacts.filter((artifact) => artifact.status === "fail").length,
25307
+ required: artifacts.filter((artifact) => artifact.required).length,
25308
+ total: artifacts.length,
25309
+ warn: artifacts.filter((artifact) => artifact.status === "warn").length
25310
+ }
25311
+ };
25312
+ };
25255
25313
  var createVoiceObservabilityExportRoutes = (options = {}) => {
25256
25314
  const path = options.path ?? "/api/voice/observability-export";
25315
+ const artifactIndexPath = options.artifactIndexPath ?? `${path}/artifacts`;
25316
+ const artifactDownloadPath = options.artifactDownloadPath ?? `${path}/artifacts`;
25257
25317
  const markdownPath = options.markdownPath ?? "/voice/observability-export.md";
25258
25318
  const htmlPath = options.htmlPath ?? "/voice/observability-export";
25259
25319
  const headers = {
25260
25320
  "cache-control": "no-store",
25261
25321
  ...options.headers ?? {}
25262
25322
  };
25263
- const buildReport = () => buildVoiceObservabilityExport(options);
25323
+ const buildReport = () => buildVoiceObservabilityExport({
25324
+ ...options,
25325
+ links: {
25326
+ ...options.links,
25327
+ artifactDownload: options.links?.artifactDownload ?? (artifactDownloadPath ? (artifact) => `${artifactDownloadPath}/${encodeURIComponent(artifact.id)}` : undefined)
25328
+ }
25329
+ });
25264
25330
  const app = new Elysia42({
25265
25331
  name: options.name ?? "absolute-voice-observability-export"
25266
25332
  });
25267
25333
  app.get(path, async () => Response.json(await buildReport(), { headers }));
25334
+ if (artifactIndexPath !== false) {
25335
+ app.get(artifactIndexPath, async () => Response.json(buildVoiceObservabilityArtifactIndex(await buildReport()), { headers }));
25336
+ }
25337
+ if (artifactDownloadPath !== false) {
25338
+ app.get(`${artifactDownloadPath}/:artifactId`, async ({ params }) => {
25339
+ const artifactId = decodeURIComponent(params.artifactId);
25340
+ const report = await buildReport();
25341
+ const artifact = report.artifacts.find((item) => item.id === artifactId);
25342
+ if (!artifact?.path) {
25343
+ return Response.json({ error: "Artifact is not downloadable.", artifactId }, { headers, status: 404 });
25344
+ }
25345
+ try {
25346
+ const body = await readFile2(stripArtifactPathAnchor(artifact.path));
25347
+ return new Response(body, {
25348
+ headers: {
25349
+ ...headers,
25350
+ "content-disposition": `attachment; filename="${encodeURIComponent(artifact.id)}"`,
25351
+ "content-type": artifact.contentType ?? inferContentType(artifact),
25352
+ ...artifact.checksum ? {
25353
+ "x-absolute-voice-artifact-sha256": artifact.checksum.value
25354
+ } : {},
25355
+ "x-absolute-voice-artifact-id": artifact.id,
25356
+ ...artifact.freshness ? {
25357
+ "x-absolute-voice-artifact-freshness": artifact.freshness.status
25358
+ } : {}
25359
+ }
25360
+ });
25361
+ } catch {
25362
+ return Response.json({ error: "Artifact file is not available.", artifactId }, { headers, status: 404 });
25363
+ }
25364
+ });
25365
+ }
25268
25366
  if (markdownPath !== false) {
25269
25367
  app.get(markdownPath, async () => {
25270
25368
  const report = await buildReport();
@@ -28291,6 +28389,7 @@ export {
28291
28389
  buildVoiceOpsActionHistoryReport,
28292
28390
  buildVoiceOperationsRecord,
28293
28391
  buildVoiceObservabilityExport,
28392
+ buildVoiceObservabilityArtifactIndex,
28294
28393
  buildVoiceLiveOpsControlState,
28295
28394
  buildVoiceLatencySLOGate,
28296
28395
  buildVoiceIncidentBundle,
@@ -21,6 +21,7 @@ export type VoiceObservabilityExportArtifact = {
21
21
  bytes?: number;
22
22
  checksum?: VoiceObservabilityExportArtifactChecksum;
23
23
  contentType?: string;
24
+ downloadHref?: string;
24
25
  freshness?: VoiceObservabilityExportArtifactFreshness;
25
26
  generatedAt?: number | string;
26
27
  href?: string;
@@ -80,6 +81,32 @@ export type VoiceObservabilityExportReport = {
80
81
  traceEvents: number;
81
82
  };
82
83
  };
84
+ export type VoiceObservabilityExportArtifactIndexItem = {
85
+ bytes?: number;
86
+ checksum?: VoiceObservabilityExportArtifactChecksum;
87
+ contentType?: string;
88
+ downloadHref?: string;
89
+ freshness?: VoiceObservabilityExportArtifactFreshness;
90
+ href?: string;
91
+ id: string;
92
+ kind: VoiceObservabilityExportArtifactKind;
93
+ label: string;
94
+ required?: boolean;
95
+ sessionId?: string;
96
+ status?: VoiceObservabilityExportStatus;
97
+ };
98
+ export type VoiceObservabilityExportArtifactIndex = {
99
+ artifacts: VoiceObservabilityExportArtifactIndexItem[];
100
+ checkedAt: number;
101
+ status: VoiceObservabilityExportStatus;
102
+ summary: {
103
+ downloadable: number;
104
+ failed: number;
105
+ required: number;
106
+ total: number;
107
+ warn: number;
108
+ };
109
+ };
83
110
  export type VoiceObservabilityExportOptions = {
84
111
  artifacts?: VoiceObservabilityExportArtifact[];
85
112
  artifactIntegrity?: {
@@ -94,6 +121,7 @@ export type VoiceObservabilityExportOptions = {
94
121
  events?: StoredVoiceTraceEvent[];
95
122
  includeOperationsRecords?: boolean;
96
123
  links?: {
124
+ artifactDownload?: (artifact: VoiceObservabilityExportArtifact) => string;
97
125
  operationsRecord?: (sessionId: string) => string;
98
126
  };
99
127
  operationsRecords?: VoiceOperationsRecord[];
@@ -104,6 +132,8 @@ export type VoiceObservabilityExportOptions = {
104
132
  };
105
133
  export type VoiceObservabilityExportRoutesOptions = VoiceObservabilityExportOptions & {
106
134
  headers?: HeadersInit;
135
+ artifactDownloadPath?: false | string;
136
+ artifactIndexPath?: false | string;
107
137
  htmlPath?: false | string;
108
138
  markdownPath?: false | string;
109
139
  name?: string;
@@ -115,6 +145,7 @@ export declare const buildVoiceObservabilityExport: (options?: VoiceObservabilit
115
145
  export declare const renderVoiceObservabilityExportMarkdown: (report: VoiceObservabilityExportReport, options?: {
116
146
  title?: string;
117
147
  }) => string;
148
+ export declare const buildVoiceObservabilityArtifactIndex: (report: VoiceObservabilityExportReport) => VoiceObservabilityExportArtifactIndex;
118
149
  export declare const createVoiceObservabilityExportRoutes: (options?: VoiceObservabilityExportRoutesOptions) => Elysia<"", {
119
150
  decorator: {};
120
151
  store: {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.221",
3
+ "version": "0.0.22-beta.222",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",