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

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
@@ -2756,6 +2756,13 @@ app.use(
2756
2756
  artifactIntegrity: {
2757
2757
  maxAgeMs: 15 * 60 * 1000
2758
2758
  },
2759
+ deliveryDestinations: [
2760
+ {
2761
+ directory: '.voice-runtime/observability-exports',
2762
+ kind: 'file',
2763
+ label: 'Local customer-owned observability archive'
2764
+ }
2765
+ ],
2759
2766
  artifacts: [
2760
2767
  {
2761
2768
  id: 'latest-proof-pack',
@@ -2791,7 +2798,7 @@ const exportReport = await buildVoiceObservabilityExport({
2791
2798
  });
2792
2799
  ```
2793
2800
 
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.
2801
+ 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`, delivery at `POST /api/voice/observability-export/deliveries`, 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. File delivery writes `manifest.json`, `artifact-index.json`, and artifact files into a customer-owned archive directory; webhook delivery posts the manifest and artifact index to a buyer-owned collector, SIEM bridge, or warehouse endpoint. 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
2802
 
2796
2803
  Pass the same report into production readiness when export health should block deploys:
2797
2804
 
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, deliverVoiceObservabilityExport, 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, VoiceObservabilityExportDeliveryDestination, VoiceObservabilityExportDeliveryDestinationResult, VoiceObservabilityExportDeliveryOptions, VoiceObservabilityExportDeliveryReport, 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
@@ -6972,14 +6972,14 @@ var createProofFetch = (provider, requests) => {
6972
6972
  };
6973
6973
  };
6974
6974
  var createProofDialer = (input) => {
6975
- const fetch = createProofFetch(input.provider, input.requests);
6975
+ const fetch2 = createProofFetch(input.provider, input.requests);
6976
6976
  if (input.provider === "twilio") {
6977
6977
  return createVoiceTwilioCampaignDialer({
6978
6978
  accountSid: "AC_dry_run",
6979
6979
  answerUrl: joinUrlPath(input.baseUrl, "/api/twilio/voice"),
6980
6980
  apiBaseUrl: "https://twilio.dry-run.absolutejs.local",
6981
6981
  authToken: "dry-run-token",
6982
- fetch,
6982
+ fetch: fetch2,
6983
6983
  from: input.from,
6984
6984
  statusCallbackEvents: ["answered", "completed"],
6985
6985
  statusCallbackUrl: joinUrlPath(input.baseUrl, "/api/telephony-webhook")
@@ -6990,7 +6990,7 @@ var createProofDialer = (input) => {
6990
6990
  apiBaseUrl: "https://telnyx.dry-run.absolutejs.local",
6991
6991
  apiKey: "dry-run-token",
6992
6992
  connectionId: "dry-run-connection",
6993
- fetch,
6993
+ fetch: fetch2,
6994
6994
  from: input.from,
6995
6995
  webhookUrl: joinUrlPath(input.baseUrl, "/api/telnyx/webhook")
6996
6996
  });
@@ -7001,7 +7001,7 @@ var createProofDialer = (input) => {
7001
7001
  authId: "dry-run-auth-id",
7002
7002
  authToken: "dry-run-token",
7003
7003
  callbackUrl: joinUrlPath(input.baseUrl, "/api/plivo/webhook"),
7004
- fetch,
7004
+ fetch: fetch2,
7005
7005
  from: input.from
7006
7006
  });
7007
7007
  };
@@ -24943,7 +24943,8 @@ var createVoiceOperationsRecordRoutes = (options) => {
24943
24943
  // src/observabilityExport.ts
24944
24944
  import { Elysia as Elysia42 } from "elysia";
24945
24945
  import { createHash } from "crypto";
24946
- import { readFile as readFile2, stat } from "fs/promises";
24946
+ import { mkdir as mkdir4, readFile as readFile2, stat } from "fs/promises";
24947
+ import { join as join3 } from "path";
24947
24948
  var isDeliveryStore = (value) => !Array.isArray(value) && typeof value.list === "function";
24948
24949
  var getString18 = (value) => typeof value === "string" ? value : undefined;
24949
24950
  var getProviderKind = (payload) => getString18(payload.kind) ?? getString18(payload.providerKind);
@@ -24982,6 +24983,41 @@ var checksumFile = async (path) => {
24982
24983
  const buffer = await readFile2(path);
24983
24984
  return createHash("sha256").update(buffer).digest("hex");
24984
24985
  };
24986
+ var byteLength = (value) => new TextEncoder().encode(value).byteLength;
24987
+ var safeArtifactFileName = (artifact) => {
24988
+ const extension = artifact.contentType === "image/png" ? ".png" : artifact.contentType?.includes("markdown") ? ".md" : artifact.contentType?.includes("json") ? ".json" : "";
24989
+ return `${artifact.id.replace(/[^a-z0-9_.-]/gi, "-")}${extension}`;
24990
+ };
24991
+ var inferContentType = (artifact) => {
24992
+ if (artifact.contentType) {
24993
+ return artifact.contentType;
24994
+ }
24995
+ const path = artifact.path ? stripArtifactPathAnchor(artifact.path) : "";
24996
+ if (path.endsWith(".json")) {
24997
+ return "application/json; charset=utf-8";
24998
+ }
24999
+ if (path.endsWith(".md") || path.endsWith(".markdown")) {
25000
+ return "text/markdown; charset=utf-8";
25001
+ }
25002
+ if (path.endsWith(".html")) {
25003
+ return "text/html; charset=utf-8";
25004
+ }
25005
+ if (path.endsWith(".png")) {
25006
+ return "image/png";
25007
+ }
25008
+ if (path.endsWith(".jpg") || path.endsWith(".jpeg")) {
25009
+ return "image/jpeg";
25010
+ }
25011
+ if (path.endsWith(".txt") || path.endsWith(".log")) {
25012
+ return "text/plain; charset=utf-8";
25013
+ }
25014
+ return "application/octet-stream";
25015
+ };
25016
+ var addArtifactDownloadHrefs = (artifacts, links) => artifacts.map((artifact) => ({
25017
+ ...artifact,
25018
+ contentType: artifact.contentType ?? inferContentType(artifact),
25019
+ downloadHref: artifact.downloadHref ?? (artifact.path ? links?.artifactDownload?.(artifact) : undefined)
25020
+ }));
24985
25021
  var verifyArtifact = async (artifact, options) => {
24986
25022
  const now = options.now ?? Date.now();
24987
25023
  const maxAgeMs = artifact.maxAgeMs ?? options.maxAgeMs;
@@ -25171,7 +25207,7 @@ var buildVoiceObservabilityExport = async (options = {}) => {
25171
25207
  const traceDeliverySummary = traceDeliveries ? await summarizeVoiceTraceSinkDeliveries(traceDeliveries) : undefined;
25172
25208
  const auditDeliverySummary = auditDeliveries ? await summarizeVoiceAuditSinkDeliveries(auditDeliveries) : undefined;
25173
25209
  const operationArtifacts = operationsRecords.map((record) => createOperationArtifact(record, options.links?.operationsRecord?.(record.sessionId)));
25174
- const artifacts = await verifyArtifacts([...operationArtifacts, ...options.artifacts ?? []], options.artifactIntegrity);
25210
+ const artifacts = addArtifactDownloadHrefs(await verifyArtifacts([...operationArtifacts, ...options.artifacts ?? []], options.artifactIntegrity), options.links);
25175
25211
  const operationHrefBySessionId = new Map(sessionIds.map((sessionId) => [
25176
25212
  sessionId,
25177
25213
  options.links?.operationsRecord?.(sessionId)
@@ -25252,19 +25288,191 @@ ${artifacts}
25252
25288
  ${issues}
25253
25289
  `;
25254
25290
  };
25291
+ var buildVoiceObservabilityArtifactIndex = (report) => {
25292
+ const artifacts = report.artifacts.map((artifact) => ({
25293
+ bytes: artifact.bytes,
25294
+ checksum: artifact.checksum,
25295
+ contentType: artifact.contentType,
25296
+ downloadHref: artifact.downloadHref,
25297
+ freshness: artifact.freshness,
25298
+ href: artifact.href,
25299
+ id: artifact.id,
25300
+ kind: artifact.kind,
25301
+ label: artifact.label,
25302
+ required: artifact.required,
25303
+ sessionId: artifact.sessionId,
25304
+ status: artifact.status
25305
+ }));
25306
+ return {
25307
+ artifacts,
25308
+ checkedAt: report.checkedAt,
25309
+ status: report.status,
25310
+ summary: {
25311
+ downloadable: artifacts.filter((artifact) => artifact.downloadHref).length,
25312
+ failed: artifacts.filter((artifact) => artifact.status === "fail").length,
25313
+ required: artifacts.filter((artifact) => artifact.required).length,
25314
+ total: artifacts.length,
25315
+ warn: artifacts.filter((artifact) => artifact.status === "warn").length
25316
+ }
25317
+ };
25318
+ };
25319
+ var deliverVoiceObservabilityExport = async (options) => {
25320
+ const checkedAt = Date.now();
25321
+ const runId = options.runId ?? new Date(checkedAt).toISOString().replaceAll(":", "-");
25322
+ const artifactIndex = buildVoiceObservabilityArtifactIndex(options.report);
25323
+ const manifest = `${JSON.stringify(options.report, null, 2)}
25324
+ `;
25325
+ const index = `${JSON.stringify(artifactIndex, null, 2)}
25326
+ `;
25327
+ const destinations = await Promise.all(options.destinations.map(async (destination) => {
25328
+ const destinationId = destination.id ?? `${destination.kind}-${destination.label ?? "export"}`;
25329
+ const label = destination.label ?? (destination.kind === "file" ? "File observability export" : "Webhook observability export");
25330
+ try {
25331
+ if (destination.kind === "file") {
25332
+ const target = join3(destination.directory, runId);
25333
+ await mkdir4(join3(target, "artifacts"), { recursive: true });
25334
+ await Bun.write(join3(target, "manifest.json"), manifest);
25335
+ await Bun.write(join3(target, "artifact-index.json"), index);
25336
+ if (destination.includeArtifacts !== false) {
25337
+ for (const artifact of options.report.artifacts) {
25338
+ if (!artifact.path) {
25339
+ continue;
25340
+ }
25341
+ await Bun.write(join3(target, "artifacts", safeArtifactFileName(artifact)), await readFile2(stripArtifactPathAnchor(artifact.path)));
25342
+ }
25343
+ }
25344
+ return {
25345
+ artifactCount: destination.includeArtifacts === false ? 0 : options.report.artifacts.filter((artifact) => artifact.path).length,
25346
+ deliveredAt: Date.now(),
25347
+ destinationId,
25348
+ destinationKind: destination.kind,
25349
+ label,
25350
+ manifestBytes: byteLength(manifest),
25351
+ status: "delivered",
25352
+ target
25353
+ };
25354
+ }
25355
+ const controller = new AbortController;
25356
+ const timeout = setTimeout(() => controller.abort(), destination.timeoutMs ?? 1e4);
25357
+ try {
25358
+ const response = await (destination.fetch ?? fetch)(destination.url, {
25359
+ body: JSON.stringify({
25360
+ artifactIndex,
25361
+ artifacts: destination.includeArtifacts === false ? [] : options.report.artifacts,
25362
+ manifest: options.report,
25363
+ runId,
25364
+ source: "absolutejs-voice"
25365
+ }),
25366
+ headers: {
25367
+ "content-type": "application/json",
25368
+ ...destination.headers ?? {}
25369
+ },
25370
+ method: "POST",
25371
+ signal: controller.signal
25372
+ });
25373
+ if (!response.ok) {
25374
+ throw new Error(`Webhook returned HTTP ${response.status}`);
25375
+ }
25376
+ } finally {
25377
+ clearTimeout(timeout);
25378
+ }
25379
+ return {
25380
+ artifactCount: destination.includeArtifacts === false ? 0 : options.report.artifacts.length,
25381
+ deliveredAt: Date.now(),
25382
+ destinationId,
25383
+ destinationKind: destination.kind,
25384
+ label,
25385
+ manifestBytes: byteLength(manifest),
25386
+ status: "delivered",
25387
+ target: destination.url
25388
+ };
25389
+ } catch (error) {
25390
+ return {
25391
+ artifactCount: 0,
25392
+ deliveredAt: Date.now(),
25393
+ destinationId,
25394
+ destinationKind: destination.kind,
25395
+ error: error instanceof Error ? error.message : String(error),
25396
+ label,
25397
+ manifestBytes: byteLength(manifest),
25398
+ status: "failed",
25399
+ target: destination.kind === "file" ? destination.directory : destination.url
25400
+ };
25401
+ }
25402
+ }));
25403
+ const failed = destinations.filter((destination) => destination.status === "failed").length;
25404
+ return {
25405
+ checkedAt,
25406
+ destinations,
25407
+ exportStatus: options.report.status,
25408
+ status: failed > 0 || options.report.status === "fail" ? "fail" : options.report.status === "warn" ? "warn" : "pass",
25409
+ summary: {
25410
+ delivered: destinations.length - failed,
25411
+ failed,
25412
+ total: destinations.length
25413
+ }
25414
+ };
25415
+ };
25255
25416
  var createVoiceObservabilityExportRoutes = (options = {}) => {
25256
25417
  const path = options.path ?? "/api/voice/observability-export";
25418
+ const artifactIndexPath = options.artifactIndexPath ?? `${path}/artifacts`;
25419
+ const artifactDownloadPath = options.artifactDownloadPath ?? `${path}/artifacts`;
25420
+ const deliveryPath = options.deliveryPath ?? `${path}/deliveries`;
25257
25421
  const markdownPath = options.markdownPath ?? "/voice/observability-export.md";
25258
25422
  const htmlPath = options.htmlPath ?? "/voice/observability-export";
25259
25423
  const headers = {
25260
25424
  "cache-control": "no-store",
25261
25425
  ...options.headers ?? {}
25262
25426
  };
25263
- const buildReport = () => buildVoiceObservabilityExport(options);
25427
+ const buildReport = () => buildVoiceObservabilityExport({
25428
+ ...options,
25429
+ links: {
25430
+ ...options.links,
25431
+ artifactDownload: options.links?.artifactDownload ?? (artifactDownloadPath ? (artifact) => `${artifactDownloadPath}/${encodeURIComponent(artifact.id)}` : undefined)
25432
+ }
25433
+ });
25264
25434
  const app = new Elysia42({
25265
25435
  name: options.name ?? "absolute-voice-observability-export"
25266
25436
  });
25267
25437
  app.get(path, async () => Response.json(await buildReport(), { headers }));
25438
+ if (artifactIndexPath !== false) {
25439
+ app.get(artifactIndexPath, async () => Response.json(buildVoiceObservabilityArtifactIndex(await buildReport()), { headers }));
25440
+ }
25441
+ if (artifactDownloadPath !== false) {
25442
+ app.get(`${artifactDownloadPath}/:artifactId`, async ({ params }) => {
25443
+ const artifactId = decodeURIComponent(params.artifactId);
25444
+ const report = await buildReport();
25445
+ const artifact = report.artifacts.find((item) => item.id === artifactId);
25446
+ if (!artifact?.path) {
25447
+ return Response.json({ error: "Artifact is not downloadable.", artifactId }, { headers, status: 404 });
25448
+ }
25449
+ try {
25450
+ const body = await readFile2(stripArtifactPathAnchor(artifact.path));
25451
+ return new Response(body, {
25452
+ headers: {
25453
+ ...headers,
25454
+ "content-disposition": `attachment; filename="${encodeURIComponent(artifact.id)}"`,
25455
+ "content-type": artifact.contentType ?? inferContentType(artifact),
25456
+ ...artifact.checksum ? {
25457
+ "x-absolute-voice-artifact-sha256": artifact.checksum.value
25458
+ } : {},
25459
+ "x-absolute-voice-artifact-id": artifact.id,
25460
+ ...artifact.freshness ? {
25461
+ "x-absolute-voice-artifact-freshness": artifact.freshness.status
25462
+ } : {}
25463
+ }
25464
+ });
25465
+ } catch {
25466
+ return Response.json({ error: "Artifact file is not available.", artifactId }, { headers, status: 404 });
25467
+ }
25468
+ });
25469
+ }
25470
+ if (deliveryPath !== false && options.deliveryDestinations) {
25471
+ app.post(deliveryPath, async () => Response.json(await deliverVoiceObservabilityExport({
25472
+ destinations: options.deliveryDestinations ?? [],
25473
+ report: await buildReport()
25474
+ }), { headers }));
25475
+ }
25268
25476
  if (markdownPath !== false) {
25269
25477
  app.get(markdownPath, async () => {
25270
25478
  const report = await buildReport();
@@ -27059,7 +27267,7 @@ var createVoiceOpsRuntime = (config) => {
27059
27267
  pollIntervalMs: _pollIntervalMs,
27060
27268
  backoffMs,
27061
27269
  eventTypes,
27062
- fetch,
27270
+ fetch: fetch2,
27063
27271
  headers,
27064
27272
  retries,
27065
27273
  signingSecret,
@@ -27073,7 +27281,7 @@ var createVoiceOpsRuntime = (config) => {
27073
27281
  webhook: {
27074
27282
  backoffMs,
27075
27283
  eventTypes,
27076
- fetch,
27284
+ fetch: fetch2,
27077
27285
  headers,
27078
27286
  retries,
27079
27287
  signingSecret,
@@ -28015,6 +28223,7 @@ export {
28015
28223
  evaluateVoiceProviderStackGaps,
28016
28224
  encodeTwilioMulawBase64,
28017
28225
  deliverVoiceTraceEventsToSinks,
28226
+ deliverVoiceObservabilityExport,
28018
28227
  deliverVoiceIntegrationEventToSinks,
28019
28228
  deliverVoiceIntegrationEvent,
28020
28229
  deliverVoiceHandoffDelivery,
@@ -28291,6 +28500,7 @@ export {
28291
28500
  buildVoiceOpsActionHistoryReport,
28292
28501
  buildVoiceOperationsRecord,
28293
28502
  buildVoiceObservabilityExport,
28503
+ buildVoiceObservabilityArtifactIndex,
28294
28504
  buildVoiceLiveOpsControlState,
28295
28505
  buildVoiceLatencySLOGate,
28296
28506
  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,75 @@ 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
+ };
110
+ export type VoiceObservabilityExportDeliveryDestination = {
111
+ directory: string;
112
+ id?: string;
113
+ includeArtifacts?: boolean;
114
+ kind: 'file';
115
+ label?: string;
116
+ } | {
117
+ fetch?: typeof fetch;
118
+ headers?: Record<string, string>;
119
+ id?: string;
120
+ includeArtifacts?: boolean;
121
+ kind: 'webhook';
122
+ label?: string;
123
+ timeoutMs?: number;
124
+ url: string;
125
+ };
126
+ export type VoiceObservabilityExportDeliveryDestinationResult = {
127
+ artifactCount: number;
128
+ deliveredAt: number;
129
+ destinationId: string;
130
+ destinationKind: VoiceObservabilityExportDeliveryDestination['kind'];
131
+ error?: string;
132
+ label: string;
133
+ manifestBytes: number;
134
+ status: 'delivered' | 'failed';
135
+ target: string;
136
+ };
137
+ export type VoiceObservabilityExportDeliveryReport = {
138
+ checkedAt: number;
139
+ destinations: VoiceObservabilityExportDeliveryDestinationResult[];
140
+ exportStatus: VoiceObservabilityExportStatus;
141
+ status: VoiceObservabilityExportStatus;
142
+ summary: {
143
+ delivered: number;
144
+ failed: number;
145
+ total: number;
146
+ };
147
+ };
148
+ export type VoiceObservabilityExportDeliveryOptions = {
149
+ destinations: VoiceObservabilityExportDeliveryDestination[];
150
+ report: VoiceObservabilityExportReport;
151
+ runId?: string;
152
+ };
83
153
  export type VoiceObservabilityExportOptions = {
84
154
  artifacts?: VoiceObservabilityExportArtifact[];
85
155
  artifactIntegrity?: {
@@ -94,6 +164,7 @@ export type VoiceObservabilityExportOptions = {
94
164
  events?: StoredVoiceTraceEvent[];
95
165
  includeOperationsRecords?: boolean;
96
166
  links?: {
167
+ artifactDownload?: (artifact: VoiceObservabilityExportArtifact) => string;
97
168
  operationsRecord?: (sessionId: string) => string;
98
169
  };
99
170
  operationsRecords?: VoiceOperationsRecord[];
@@ -104,6 +175,10 @@ export type VoiceObservabilityExportOptions = {
104
175
  };
105
176
  export type VoiceObservabilityExportRoutesOptions = VoiceObservabilityExportOptions & {
106
177
  headers?: HeadersInit;
178
+ artifactDownloadPath?: false | string;
179
+ artifactIndexPath?: false | string;
180
+ deliveryDestinations?: VoiceObservabilityExportDeliveryDestination[];
181
+ deliveryPath?: false | string;
107
182
  htmlPath?: false | string;
108
183
  markdownPath?: false | string;
109
184
  name?: string;
@@ -115,6 +190,8 @@ export declare const buildVoiceObservabilityExport: (options?: VoiceObservabilit
115
190
  export declare const renderVoiceObservabilityExportMarkdown: (report: VoiceObservabilityExportReport, options?: {
116
191
  title?: string;
117
192
  }) => string;
193
+ export declare const buildVoiceObservabilityArtifactIndex: (report: VoiceObservabilityExportReport) => VoiceObservabilityExportArtifactIndex;
194
+ export declare const deliverVoiceObservabilityExport: (options: VoiceObservabilityExportDeliveryOptions) => Promise<VoiceObservabilityExportDeliveryReport>;
118
195
  export declare const createVoiceObservabilityExportRoutes: (options?: VoiceObservabilityExportRoutesOptions) => Elysia<"", {
119
196
  decorator: {};
120
197
  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.223",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",