@absolutejs/voice 0.0.22-beta.227 → 0.0.22-beta.229

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
@@ -2753,6 +2753,19 @@ Readiness emits the stable `voice.readiness.ops_recovery` gate code when unresol
2753
2753
 
2754
2754
  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.
2755
2755
 
2756
+ Every export manifest and artifact index includes a stable schema contract:
2757
+
2758
+ ```ts
2759
+ import {
2760
+ assertVoiceObservabilityExportSchema,
2761
+ voiceObservabilityExportSchemaId,
2762
+ voiceObservabilityExportSchemaVersion
2763
+ } from '@absolutejs/voice';
2764
+
2765
+ assertVoiceObservabilityExportSchema(exportReport);
2766
+ console.log(voiceObservabilityExportSchemaId, voiceObservabilityExportSchemaVersion);
2767
+ ```
2768
+
2756
2769
  ```ts
2757
2770
  import {
2758
2771
  buildVoiceObservabilityExport,
@@ -2781,6 +2794,19 @@ app.use(
2781
2794
  keyPrefix: 'voice/observability-exports',
2782
2795
  kind: 's3',
2783
2796
  label: 'S3 customer-owned observability archive'
2797
+ },
2798
+ {
2799
+ kind: 'sqlite',
2800
+ path: '.voice-runtime/observability-exports.sqlite',
2801
+ tableName: 'voice_observability_exports',
2802
+ label: 'SQLite customer-owned observability warehouse'
2803
+ },
2804
+ {
2805
+ connectionString: process.env.VOICE_OBSERVABILITY_EXPORT_POSTGRES_URL,
2806
+ kind: 'postgres',
2807
+ schemaName: 'voice',
2808
+ tableName: 'observability_exports',
2809
+ label: 'Postgres customer-owned observability warehouse'
2784
2810
  }
2785
2811
  ],
2786
2812
  deliveryReceipts: observabilityReceipts,
@@ -2819,7 +2845,7 @@ const exportReport = await buildVoiceObservabilityExport({
2819
2845
  });
2820
2846
  ```
2821
2847
 
2822
- 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`, delivery history at `GET /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; S3 delivery writes the same manifest, index, and artifact files through Bun's native S3 client. Delivery receipt stores persist run id, destinations, status, and target history so operators can prove exports have been continuously healthy. 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.
2848
+ 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`, delivery history at `GET /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; S3 delivery writes the same manifest, index, and artifact files through Bun's native S3 client; SQLite and Postgres delivery persist the schema id/version, manifest, artifact index, checksum metadata, status, run id, and timestamps into buyer-owned database tables. Delivery receipt stores persist run id, destinations, status, schema, and target history so operators can prove exports have been continuously healthy. 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.
2823
2849
 
2824
2850
  Pass the same report into production readiness when export health should block deploys:
2825
2851
 
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 { buildVoiceObservabilityArtifactIndex, buildVoiceObservabilityExportDeliveryHistory, buildVoiceObservabilityExport, createVoiceFileObservabilityExportDeliveryReceiptStore, createVoiceMemoryObservabilityExportDeliveryReceiptStore, createVoiceObservabilityExportRoutes, deliverVoiceObservabilityExport, renderVoiceObservabilityExportMarkdown } from './observabilityExport';
56
+ export { buildVoiceObservabilityArtifactIndex, buildVoiceObservabilityExportDeliveryHistory, buildVoiceObservabilityExport, assertVoiceObservabilityExportSchema, createVoiceObservabilityExportSchema, createVoiceFileObservabilityExportDeliveryReceiptStore, createVoiceMemoryObservabilityExportDeliveryReceiptStore, createVoiceObservabilityExportRoutes, deliverVoiceObservabilityExport, renderVoiceObservabilityExportMarkdown, voiceObservabilityExportSchemaId, voiceObservabilityExportSchemaVersion } 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, VoiceObservabilityExportArtifactChecksum, VoiceObservabilityExportArtifactFreshness, VoiceObservabilityExportArtifactIndex, VoiceObservabilityExportArtifactIndexItem, VoiceObservabilityExportArtifactKind, VoiceObservabilityExportDeliverySummary, VoiceObservabilityExportDeliveryDestination, VoiceObservabilityExportDeliveryDestinationResult, VoiceObservabilityExportDeliveryHistory, VoiceObservabilityExportDeliveryOptions, VoiceObservabilityExportDeliveryReceipt, VoiceObservabilityExportDeliveryReceiptStore, VoiceObservabilityExportDeliveryReport, VoiceObservabilityExportEnvelope, VoiceObservabilityExportIssue, VoiceObservabilityExportIssueCode, VoiceObservabilityExportOptions, VoiceObservabilityExportRedactionSummary, VoiceObservabilityExportReport, VoiceObservabilityExportRoutesOptions, VoiceObservabilityExportStatus } from './observabilityExport';
121
+ export type { VoiceObservabilityExportArtifact, VoiceObservabilityExportArtifactChecksum, VoiceObservabilityExportArtifactFreshness, VoiceObservabilityExportArtifactIndex, VoiceObservabilityExportArtifactIndexItem, VoiceObservabilityExportArtifactKind, VoiceObservabilityExportDeliverySummary, VoiceObservabilityExportDeliveryDestination, VoiceObservabilityExportDeliveryDestinationResult, VoiceObservabilityExportDeliveryHistory, VoiceObservabilityExportDeliveryOptions, VoiceObservabilityExportDeliveryReceipt, VoiceObservabilityExportDeliveryReceiptStore, VoiceObservabilityExportDeliveryReport, VoiceObservabilityExportEnvelope, VoiceObservabilityExportIssue, VoiceObservabilityExportIssueCode, VoiceObservabilityExportOptions, VoiceObservabilityExportRedactionSummary, VoiceObservabilityExportReport, VoiceObservabilityExportRoutesOptions, VoiceObservabilityExportSchema, 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
@@ -22448,6 +22448,7 @@ var createVoiceOpsRecoveryRoutes = (options = {}) => {
22448
22448
 
22449
22449
  // src/observabilityExport.ts
22450
22450
  import { Elysia as Elysia39 } from "elysia";
22451
+ import { Database } from "bun:sqlite";
22451
22452
  import { createHash } from "crypto";
22452
22453
  import { mkdir as mkdir4, readFile as readFile2, stat, unlink } from "fs/promises";
22453
22454
  import { join as join3 } from "path";
@@ -22986,6 +22987,17 @@ var createVoiceOperationsRecordRoutes = (options) => {
22986
22987
  };
22987
22988
 
22988
22989
  // src/observabilityExport.ts
22990
+ var voiceObservabilityExportSchemaVersion = "1.0.0";
22991
+ var voiceObservabilityExportSchemaId = "com.absolutejs.voice.observability-export";
22992
+ var createVoiceObservabilityExportSchema = () => ({
22993
+ id: voiceObservabilityExportSchemaId,
22994
+ version: voiceObservabilityExportSchemaVersion
22995
+ });
22996
+ var assertVoiceObservabilityExportSchema = (input) => {
22997
+ if (input.schema?.id !== voiceObservabilityExportSchemaId || input.schema?.version !== voiceObservabilityExportSchemaVersion) {
22998
+ throw new Error(`Unsupported voice observability export schema: ${input.schema?.id ?? "missing"}@${input.schema?.version ?? "missing"}`);
22999
+ }
23000
+ };
22989
23001
  var isDeliveryStore = (value) => !Array.isArray(value) && typeof value.list === "function";
22990
23002
  var getString17 = (value) => typeof value === "string" ? value : undefined;
22991
23003
  var getProviderKind = (payload) => getString17(payload.kind) ?? getString17(payload.providerKind);
@@ -23038,6 +23050,117 @@ var writeS3Object = async (input) => {
23038
23050
  type: input.contentType
23039
23051
  });
23040
23052
  };
23053
+ var quoteObservabilityIdentifier = (value) => `"${value.replace(/"/g, '""')}"`;
23054
+ var normalizeObservabilityIdentifier = (value) => value?.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice_observability_exports";
23055
+ var buildObservabilityExportDatabaseRecord = (input) => ({
23056
+ artifactCount: input.artifactIndex.summary.total,
23057
+ artifactIndex: input.artifactIndex,
23058
+ checkedAt: input.checkedAt,
23059
+ exportStatus: input.report.status,
23060
+ manifest: input.report,
23061
+ runId: input.runId,
23062
+ schema: input.report.schema,
23063
+ status: input.report.status
23064
+ });
23065
+ var deliverObservabilityExportToSQLite = async (input) => {
23066
+ if (!input.destination.database && !input.destination.path) {
23067
+ throw new Error("SQLite observability export delivery requires destination.database or destination.path.");
23068
+ }
23069
+ const database = input.destination.database ?? new Database(input.destination.path, { create: true });
23070
+ const table = quoteObservabilityIdentifier(normalizeObservabilityIdentifier(input.destination.tableName));
23071
+ const record = buildObservabilityExportDatabaseRecord(input);
23072
+ database.exec(`CREATE TABLE IF NOT EXISTS ${table} (
23073
+ run_id TEXT PRIMARY KEY,
23074
+ checked_at INTEGER NOT NULL,
23075
+ status TEXT NOT NULL,
23076
+ export_status TEXT NOT NULL,
23077
+ artifact_count INTEGER NOT NULL,
23078
+ manifest_json TEXT NOT NULL,
23079
+ artifact_index_json TEXT NOT NULL,
23080
+ payload_json TEXT NOT NULL
23081
+ )`);
23082
+ database.query(`INSERT INTO ${table}
23083
+ (run_id, checked_at, status, export_status, artifact_count, manifest_json, artifact_index_json, payload_json)
23084
+ VALUES ($runId, $checkedAt, $status, $exportStatus, $artifactCount, $manifest, $artifactIndex, $payload)
23085
+ ON CONFLICT(run_id) DO UPDATE SET
23086
+ checked_at = excluded.checked_at,
23087
+ status = excluded.status,
23088
+ export_status = excluded.export_status,
23089
+ artifact_count = excluded.artifact_count,
23090
+ manifest_json = excluded.manifest_json,
23091
+ artifact_index_json = excluded.artifact_index_json,
23092
+ payload_json = excluded.payload_json`).run({
23093
+ $artifactCount: input.artifactIndex.summary.total,
23094
+ $artifactIndex: input.index,
23095
+ $checkedAt: input.checkedAt,
23096
+ $exportStatus: input.report.status,
23097
+ $manifest: input.manifest,
23098
+ $payload: JSON.stringify(record),
23099
+ $runId: input.runId,
23100
+ $status: input.report.status
23101
+ });
23102
+ return input.destination.path ? `sqlite://${input.destination.path}/${table.replaceAll('"', "")}` : `sqlite://memory/${table.replaceAll('"', "")}`;
23103
+ };
23104
+ var deliverObservabilityExportToPostgres = async (input) => {
23105
+ const sql = input.destination.sql ?? (input.destination.connectionString ? (() => {
23106
+ const client = new Bun.SQL(input.destination.connectionString);
23107
+ return { unsafe: client.unsafe.bind(client) };
23108
+ })() : undefined);
23109
+ if (!sql) {
23110
+ throw new Error("Postgres observability export delivery requires destination.sql or destination.connectionString.");
23111
+ }
23112
+ const schema = normalizeObservabilityIdentifier(input.destination.schemaName ?? "public");
23113
+ const table = normalizeObservabilityIdentifier(input.destination.tableName);
23114
+ const qualifiedTable = `${quoteObservabilityIdentifier(schema)}.${quoteObservabilityIdentifier(table)}`;
23115
+ const record = buildObservabilityExportDatabaseRecord(input);
23116
+ await sql.unsafe(`CREATE SCHEMA IF NOT EXISTS ${quoteObservabilityIdentifier(schema)}`);
23117
+ await sql.unsafe(`CREATE TABLE IF NOT EXISTS ${qualifiedTable} (
23118
+ run_id TEXT PRIMARY KEY,
23119
+ checked_at BIGINT NOT NULL,
23120
+ status TEXT NOT NULL,
23121
+ export_status TEXT NOT NULL,
23122
+ artifact_count INTEGER NOT NULL,
23123
+ manifest_json JSONB NOT NULL,
23124
+ artifact_index_json JSONB NOT NULL,
23125
+ payload JSONB NOT NULL
23126
+ )`);
23127
+ await sql.unsafe(`INSERT INTO ${qualifiedTable}
23128
+ (run_id, checked_at, status, export_status, artifact_count, manifest_json, artifact_index_json, payload)
23129
+ VALUES ($1, $2, $3, $4, $5, $6::jsonb, $7::jsonb, $8::jsonb)
23130
+ ON CONFLICT (run_id) DO UPDATE SET
23131
+ checked_at = EXCLUDED.checked_at,
23132
+ status = EXCLUDED.status,
23133
+ export_status = EXCLUDED.export_status,
23134
+ artifact_count = EXCLUDED.artifact_count,
23135
+ manifest_json = EXCLUDED.manifest_json,
23136
+ artifact_index_json = EXCLUDED.artifact_index_json,
23137
+ payload = EXCLUDED.payload`, [
23138
+ input.runId,
23139
+ input.checkedAt,
23140
+ input.report.status,
23141
+ input.report.status,
23142
+ input.artifactIndex.summary.total,
23143
+ input.manifest,
23144
+ input.index,
23145
+ JSON.stringify(record)
23146
+ ]);
23147
+ return `postgres://${schema}/${table}`;
23148
+ };
23149
+ var observabilityExportDeliveryFailureTarget = (destination) => {
23150
+ if (destination.kind === "file") {
23151
+ return destination.directory;
23152
+ }
23153
+ if (destination.kind === "s3") {
23154
+ return destination.bucket ? `s3://${destination.bucket}/${normalizeExportS3KeyPrefix(destination.keyPrefix)}` : normalizeExportS3KeyPrefix(destination.keyPrefix);
23155
+ }
23156
+ if (destination.kind === "sqlite") {
23157
+ return destination.path ?? "sqlite://memory";
23158
+ }
23159
+ if (destination.kind === "postgres") {
23160
+ return destination.connectionString ?? "postgres://configured-client";
23161
+ }
23162
+ return destination.url;
23163
+ };
23041
23164
  var createVoiceMemoryObservabilityExportDeliveryReceiptStore = () => {
23042
23165
  const receipts = new Map;
23043
23166
  return {
@@ -23349,6 +23472,7 @@ var buildVoiceObservabilityExport = async (options = {}) => {
23349
23472
  enabled: Boolean(options.redact),
23350
23473
  mode: options.redact ? "redacted" : "none"
23351
23474
  },
23475
+ schema: createVoiceObservabilityExportSchema(),
23352
23476
  sessionIds,
23353
23477
  status,
23354
23478
  summary: {
@@ -23417,6 +23541,7 @@ var buildVoiceObservabilityArtifactIndex = (report) => {
23417
23541
  return {
23418
23542
  artifacts,
23419
23543
  checkedAt: report.checkedAt,
23544
+ schema: report.schema,
23420
23545
  status: report.status,
23421
23546
  summary: {
23422
23547
  downloadable: artifacts.filter((artifact) => artifact.downloadHref).length,
@@ -23437,7 +23562,7 @@ var deliverVoiceObservabilityExport = async (options) => {
23437
23562
  `;
23438
23563
  const destinations = await Promise.all(options.destinations.map(async (destination) => {
23439
23564
  const destinationId = destination.id ?? `${destination.kind}-${destination.label ?? "export"}`;
23440
- const label = destination.label ?? (destination.kind === "file" ? "File observability export" : "Webhook observability export");
23565
+ const label = destination.label ?? (destination.kind === "file" ? "File observability export" : destination.kind === "s3" ? "S3 observability export" : destination.kind === "sqlite" ? "SQLite observability export" : destination.kind === "postgres" ? "Postgres observability export" : "Webhook observability export");
23441
23566
  try {
23442
23567
  if (destination.kind === "file") {
23443
23568
  const target = join3(destination.directory, runId);
@@ -23459,6 +23584,7 @@ var deliverVoiceObservabilityExport = async (options) => {
23459
23584
  destinationKind: destination.kind,
23460
23585
  label,
23461
23586
  manifestBytes: byteLength(manifest),
23587
+ schema: options.report.schema,
23462
23588
  status: "delivered",
23463
23589
  target
23464
23590
  };
@@ -23503,10 +23629,55 @@ var deliverVoiceObservabilityExport = async (options) => {
23503
23629
  destinationKind: destination.kind,
23504
23630
  label,
23505
23631
  manifestBytes: byteLength(manifest),
23632
+ schema: options.report.schema,
23506
23633
  status: "delivered",
23507
23634
  target: destination.bucket ? `s3://${destination.bucket}/${rootKey}` : rootKey
23508
23635
  };
23509
23636
  }
23637
+ if (destination.kind === "sqlite") {
23638
+ const target = await deliverObservabilityExportToSQLite({
23639
+ artifactIndex,
23640
+ checkedAt,
23641
+ destination,
23642
+ index,
23643
+ manifest,
23644
+ report: options.report,
23645
+ runId
23646
+ });
23647
+ return {
23648
+ artifactCount: artifactIndex.summary.total,
23649
+ deliveredAt: Date.now(),
23650
+ destinationId,
23651
+ destinationKind: destination.kind,
23652
+ label,
23653
+ manifestBytes: byteLength(manifest),
23654
+ schema: options.report.schema,
23655
+ status: "delivered",
23656
+ target
23657
+ };
23658
+ }
23659
+ if (destination.kind === "postgres") {
23660
+ const target = await deliverObservabilityExportToPostgres({
23661
+ artifactIndex,
23662
+ checkedAt,
23663
+ destination,
23664
+ index,
23665
+ manifest,
23666
+ report: options.report,
23667
+ runId
23668
+ });
23669
+ return {
23670
+ artifactCount: artifactIndex.summary.total,
23671
+ deliveredAt: Date.now(),
23672
+ destinationId,
23673
+ destinationKind: destination.kind,
23674
+ label,
23675
+ manifestBytes: byteLength(manifest),
23676
+ schema: options.report.schema,
23677
+ status: "delivered",
23678
+ target
23679
+ };
23680
+ }
23510
23681
  const controller = new AbortController;
23511
23682
  const timeout = setTimeout(() => controller.abort(), destination.timeoutMs ?? 1e4);
23512
23683
  try {
@@ -23538,6 +23709,7 @@ var deliverVoiceObservabilityExport = async (options) => {
23538
23709
  destinationKind: destination.kind,
23539
23710
  label,
23540
23711
  manifestBytes: byteLength(manifest),
23712
+ schema: options.report.schema,
23541
23713
  status: "delivered",
23542
23714
  target: destination.url
23543
23715
  };
@@ -23550,8 +23722,9 @@ var deliverVoiceObservabilityExport = async (options) => {
23550
23722
  error: error instanceof Error ? error.message : String(error),
23551
23723
  label,
23552
23724
  manifestBytes: byteLength(manifest),
23725
+ schema: options.report.schema,
23553
23726
  status: "failed",
23554
- target: destination.kind === "file" ? destination.directory : destination.kind === "s3" ? destination.bucket ? `s3://${destination.bucket}/${normalizeExportS3KeyPrefix(destination.keyPrefix)}` : normalizeExportS3KeyPrefix(destination.keyPrefix) : destination.url
23727
+ target: observabilityExportDeliveryFailureTarget(destination)
23555
23728
  };
23556
23729
  }
23557
23730
  }));
@@ -26701,7 +26874,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
26701
26874
  return routes;
26702
26875
  };
26703
26876
  // src/sqliteStore.ts
26704
- import { Database } from "bun:sqlite";
26877
+ import { Database as Database2 } from "bun:sqlite";
26705
26878
  var normalizeTableNameSegment = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice";
26706
26879
  var resolveTableName = (input) => {
26707
26880
  if (input.options.tableName) {
@@ -26712,7 +26885,7 @@ var resolveTableName = (input) => {
26712
26885
  return `${prefix}_${fallback}`;
26713
26886
  };
26714
26887
  var openVoiceSQLiteDatabase = (path) => {
26715
- const database = new Database(path, {
26888
+ const database = new Database2(path, {
26716
26889
  create: true
26717
26890
  });
26718
26891
  database.exec("PRAGMA journal_mode = WAL;");
@@ -28281,6 +28454,8 @@ export {
28281
28454
  withVoiceOpsTaskId,
28282
28455
  withVoiceIntegrationEventId,
28283
28456
  voiceTelephonyOutcomeToRouteResult,
28457
+ voiceObservabilityExportSchemaVersion,
28458
+ voiceObservabilityExportSchemaId,
28284
28459
  voiceComplianceRedactionDefaults,
28285
28460
  voice,
28286
28461
  verifyVoiceTwilioWebhookSignature,
@@ -28588,6 +28763,7 @@ export {
28588
28763
  createVoiceOpsConsoleRoutes,
28589
28764
  createVoiceOpsActionAuditRoutes,
28590
28765
  createVoiceOperationsRecordRoutes,
28766
+ createVoiceObservabilityExportSchema,
28591
28767
  createVoiceObservabilityExportRoutes,
28592
28768
  createVoiceMemoryTraceSinkDeliveryStore,
28593
28769
  createVoiceMemoryTraceEventStore,
@@ -28745,6 +28921,7 @@ export {
28745
28921
  buildVoiceAuditDeliveryReport,
28746
28922
  assignVoiceOpsTask,
28747
28923
  assertVoiceProviderRoutingContract,
28924
+ assertVoiceObservabilityExportSchema,
28748
28925
  assertVoiceLatencySLOGate,
28749
28926
  assertVoiceAgentSquadContract,
28750
28927
  applyVoiceTelephonyOutcome,
@@ -1,11 +1,23 @@
1
1
  import { Elysia } from 'elysia';
2
2
  import type { S3Client, S3Options } from 'bun';
3
+ import { Database } from 'bun:sqlite';
3
4
  import { type VoiceAuditSinkDeliveryQueueSummary, type VoiceAuditSinkDeliveryRecord, type VoiceAuditSinkDeliveryStore } from './auditSinks';
4
5
  import type { VoiceAuditEventStore, VoiceAuditEventType } from './audit';
5
6
  import { type VoiceOperationsRecord } from './operationsRecord';
6
7
  import { type VoiceTraceSinkDeliveryQueueSummary } from './queue';
7
8
  import { type StoredVoiceTraceEvent, type VoiceTraceEventStore, type VoiceTraceEventType, type VoiceTraceRedactionConfig, type VoiceTraceSinkDeliveryRecord, type VoiceTraceSinkDeliveryStore, type VoiceTraceSummary } from './trace';
9
+ import type { VoicePostgresClient } from './postgresStore';
8
10
  export type VoiceObservabilityExportStatus = 'fail' | 'pass' | 'warn';
11
+ export declare const voiceObservabilityExportSchemaVersion = "1.0.0";
12
+ export declare const voiceObservabilityExportSchemaId = "com.absolutejs.voice.observability-export";
13
+ export type VoiceObservabilityExportSchema = {
14
+ id: typeof voiceObservabilityExportSchemaId;
15
+ version: typeof voiceObservabilityExportSchemaVersion;
16
+ };
17
+ export declare const createVoiceObservabilityExportSchema: () => VoiceObservabilityExportSchema;
18
+ export declare const assertVoiceObservabilityExportSchema: (input: {
19
+ schema?: Partial<VoiceObservabilityExportSchema>;
20
+ }) => void;
9
21
  export type VoiceObservabilityExportArtifactKind = 'incident' | 'markdown' | 'operations-record' | 'proof-pack' | 'readiness' | 'screenshot' | 'slo' | 'trace' | 'audit' | 'custom';
10
22
  export type VoiceObservabilityExportArtifactChecksum = {
11
23
  algorithm: 'sha256';
@@ -72,6 +84,7 @@ export type VoiceObservabilityExportReport = {
72
84
  issues: VoiceObservabilityExportIssue[];
73
85
  operationsRecords: VoiceOperationsRecord[];
74
86
  redaction: VoiceObservabilityExportRedactionSummary;
87
+ schema: VoiceObservabilityExportSchema;
75
88
  sessionIds: string[];
76
89
  status: VoiceObservabilityExportStatus;
77
90
  summary: {
@@ -99,6 +112,7 @@ export type VoiceObservabilityExportArtifactIndexItem = {
99
112
  export type VoiceObservabilityExportArtifactIndex = {
100
113
  artifacts: VoiceObservabilityExportArtifactIndexItem[];
101
114
  checkedAt: number;
115
+ schema: VoiceObservabilityExportSchema;
102
116
  status: VoiceObservabilityExportStatus;
103
117
  summary: {
104
118
  downloadable: number;
@@ -123,6 +137,21 @@ export type VoiceObservabilityExportDeliveryDestination = {
123
137
  kind: 's3';
124
138
  label?: string;
125
139
  }) | {
140
+ database?: Database;
141
+ id?: string;
142
+ kind: 'sqlite';
143
+ label?: string;
144
+ path?: string;
145
+ tableName?: string;
146
+ } | {
147
+ connectionString?: string;
148
+ id?: string;
149
+ kind: 'postgres';
150
+ label?: string;
151
+ schemaName?: string;
152
+ sql?: VoicePostgresClient;
153
+ tableName?: string;
154
+ } | {
126
155
  fetch?: typeof fetch;
127
156
  headers?: Record<string, string>;
128
157
  id?: string;
@@ -140,6 +169,7 @@ export type VoiceObservabilityExportDeliveryDestinationResult = {
140
169
  error?: string;
141
170
  label: string;
142
171
  manifestBytes: number;
172
+ schema: VoiceObservabilityExportSchema;
143
173
  status: 'delivered' | 'failed';
144
174
  target: string;
145
175
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.227",
3
+ "version": "0.0.22-beta.229",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",