@absolutejs/voice 0.0.22-beta.222 → 0.0.22-beta.224
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 +14 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +170 -7
- package/dist/observabilityExport.d.ts +55 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2756,6 +2756,19 @@ 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
|
+
{
|
|
2766
|
+
bucket: process.env.VOICE_OBSERVABILITY_EXPORT_S3_BUCKET,
|
|
2767
|
+
keyPrefix: 'voice/observability-exports',
|
|
2768
|
+
kind: 's3',
|
|
2769
|
+
label: 'S3 customer-owned observability archive'
|
|
2770
|
+
}
|
|
2771
|
+
],
|
|
2759
2772
|
artifacts: [
|
|
2760
2773
|
{
|
|
2761
2774
|
id: 'latest-proof-pack',
|
|
@@ -2791,7 +2804,7 @@ const exportReport = await buildVoiceObservabilityExport({
|
|
|
2791
2804
|
});
|
|
2792
2805
|
```
|
|
2793
2806
|
|
|
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.
|
|
2807
|
+
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; S3 delivery writes the same manifest, index, and artifact files through Bun's native S3 client. 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
2808
|
|
|
2796
2809
|
Pass the same report into production readiness when export health should block deploys:
|
|
2797
2810
|
|
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, 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, VoiceObservabilityExportArtifactChecksum, VoiceObservabilityExportArtifactFreshness, VoiceObservabilityExportArtifactIndex, VoiceObservabilityExportArtifactIndexItem, 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
|
|
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,19 @@ 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 normalizeExportS3KeyPrefix = (prefix) => prefix?.trim().replace(/^\/+|\/+$/g, "") ?? "voice/observability-exports";
|
|
24992
|
+
var joinS3Key = (...parts) => parts.map((part) => part.trim().replace(/^\/+|\/+$/g, "")).filter(Boolean).join("/");
|
|
24993
|
+
var writeS3Object = async (input) => {
|
|
24994
|
+
const file = input.client.file(input.key, input.options);
|
|
24995
|
+
await file.write(input.value, {
|
|
24996
|
+
type: input.contentType
|
|
24997
|
+
});
|
|
24998
|
+
};
|
|
24985
24999
|
var inferContentType = (artifact) => {
|
|
24986
25000
|
if (artifact.contentType) {
|
|
24987
25001
|
return artifact.contentType;
|
|
@@ -25310,10 +25324,152 @@ var buildVoiceObservabilityArtifactIndex = (report) => {
|
|
|
25310
25324
|
}
|
|
25311
25325
|
};
|
|
25312
25326
|
};
|
|
25327
|
+
var deliverVoiceObservabilityExport = async (options) => {
|
|
25328
|
+
const checkedAt = Date.now();
|
|
25329
|
+
const runId = options.runId ?? new Date(checkedAt).toISOString().replaceAll(":", "-");
|
|
25330
|
+
const artifactIndex = buildVoiceObservabilityArtifactIndex(options.report);
|
|
25331
|
+
const manifest = `${JSON.stringify(options.report, null, 2)}
|
|
25332
|
+
`;
|
|
25333
|
+
const index = `${JSON.stringify(artifactIndex, null, 2)}
|
|
25334
|
+
`;
|
|
25335
|
+
const destinations = await Promise.all(options.destinations.map(async (destination) => {
|
|
25336
|
+
const destinationId = destination.id ?? `${destination.kind}-${destination.label ?? "export"}`;
|
|
25337
|
+
const label = destination.label ?? (destination.kind === "file" ? "File observability export" : "Webhook observability export");
|
|
25338
|
+
try {
|
|
25339
|
+
if (destination.kind === "file") {
|
|
25340
|
+
const target = join3(destination.directory, runId);
|
|
25341
|
+
await mkdir4(join3(target, "artifacts"), { recursive: true });
|
|
25342
|
+
await Bun.write(join3(target, "manifest.json"), manifest);
|
|
25343
|
+
await Bun.write(join3(target, "artifact-index.json"), index);
|
|
25344
|
+
if (destination.includeArtifacts !== false) {
|
|
25345
|
+
for (const artifact of options.report.artifacts) {
|
|
25346
|
+
if (!artifact.path) {
|
|
25347
|
+
continue;
|
|
25348
|
+
}
|
|
25349
|
+
await Bun.write(join3(target, "artifacts", safeArtifactFileName(artifact)), await readFile2(stripArtifactPathAnchor(artifact.path)));
|
|
25350
|
+
}
|
|
25351
|
+
}
|
|
25352
|
+
return {
|
|
25353
|
+
artifactCount: destination.includeArtifacts === false ? 0 : options.report.artifacts.filter((artifact) => artifact.path).length,
|
|
25354
|
+
deliveredAt: Date.now(),
|
|
25355
|
+
destinationId,
|
|
25356
|
+
destinationKind: destination.kind,
|
|
25357
|
+
label,
|
|
25358
|
+
manifestBytes: byteLength(manifest),
|
|
25359
|
+
status: "delivered",
|
|
25360
|
+
target
|
|
25361
|
+
};
|
|
25362
|
+
}
|
|
25363
|
+
if (destination.kind === "s3") {
|
|
25364
|
+
const keyPrefix = normalizeExportS3KeyPrefix(destination.keyPrefix);
|
|
25365
|
+
const rootKey = joinS3Key(keyPrefix, runId);
|
|
25366
|
+
const client = destination.client ?? new Bun.S3Client(destination);
|
|
25367
|
+
const s3Options = destination;
|
|
25368
|
+
await writeS3Object({
|
|
25369
|
+
client,
|
|
25370
|
+
contentType: "application/json",
|
|
25371
|
+
key: joinS3Key(rootKey, "manifest.json"),
|
|
25372
|
+
options: s3Options,
|
|
25373
|
+
value: manifest
|
|
25374
|
+
});
|
|
25375
|
+
await writeS3Object({
|
|
25376
|
+
client,
|
|
25377
|
+
contentType: "application/json",
|
|
25378
|
+
key: joinS3Key(rootKey, "artifact-index.json"),
|
|
25379
|
+
options: s3Options,
|
|
25380
|
+
value: index
|
|
25381
|
+
});
|
|
25382
|
+
if (destination.includeArtifacts !== false) {
|
|
25383
|
+
for (const artifact of options.report.artifacts) {
|
|
25384
|
+
if (!artifact.path) {
|
|
25385
|
+
continue;
|
|
25386
|
+
}
|
|
25387
|
+
await writeS3Object({
|
|
25388
|
+
client,
|
|
25389
|
+
contentType: artifact.contentType ?? inferContentType(artifact),
|
|
25390
|
+
key: joinS3Key(rootKey, "artifacts", safeArtifactFileName(artifact)),
|
|
25391
|
+
options: s3Options,
|
|
25392
|
+
value: await readFile2(stripArtifactPathAnchor(artifact.path))
|
|
25393
|
+
});
|
|
25394
|
+
}
|
|
25395
|
+
}
|
|
25396
|
+
return {
|
|
25397
|
+
artifactCount: destination.includeArtifacts === false ? 0 : options.report.artifacts.filter((artifact) => artifact.path).length,
|
|
25398
|
+
deliveredAt: Date.now(),
|
|
25399
|
+
destinationId,
|
|
25400
|
+
destinationKind: destination.kind,
|
|
25401
|
+
label,
|
|
25402
|
+
manifestBytes: byteLength(manifest),
|
|
25403
|
+
status: "delivered",
|
|
25404
|
+
target: destination.bucket ? `s3://${destination.bucket}/${rootKey}` : rootKey
|
|
25405
|
+
};
|
|
25406
|
+
}
|
|
25407
|
+
const controller = new AbortController;
|
|
25408
|
+
const timeout = setTimeout(() => controller.abort(), destination.timeoutMs ?? 1e4);
|
|
25409
|
+
try {
|
|
25410
|
+
const response = await (destination.fetch ?? fetch)(destination.url, {
|
|
25411
|
+
body: JSON.stringify({
|
|
25412
|
+
artifactIndex,
|
|
25413
|
+
artifacts: destination.includeArtifacts === false ? [] : options.report.artifacts,
|
|
25414
|
+
manifest: options.report,
|
|
25415
|
+
runId,
|
|
25416
|
+
source: "absolutejs-voice"
|
|
25417
|
+
}),
|
|
25418
|
+
headers: {
|
|
25419
|
+
"content-type": "application/json",
|
|
25420
|
+
...destination.headers ?? {}
|
|
25421
|
+
},
|
|
25422
|
+
method: "POST",
|
|
25423
|
+
signal: controller.signal
|
|
25424
|
+
});
|
|
25425
|
+
if (!response.ok) {
|
|
25426
|
+
throw new Error(`Webhook returned HTTP ${response.status}`);
|
|
25427
|
+
}
|
|
25428
|
+
} finally {
|
|
25429
|
+
clearTimeout(timeout);
|
|
25430
|
+
}
|
|
25431
|
+
return {
|
|
25432
|
+
artifactCount: destination.includeArtifacts === false ? 0 : options.report.artifacts.length,
|
|
25433
|
+
deliveredAt: Date.now(),
|
|
25434
|
+
destinationId,
|
|
25435
|
+
destinationKind: destination.kind,
|
|
25436
|
+
label,
|
|
25437
|
+
manifestBytes: byteLength(manifest),
|
|
25438
|
+
status: "delivered",
|
|
25439
|
+
target: destination.url
|
|
25440
|
+
};
|
|
25441
|
+
} catch (error) {
|
|
25442
|
+
return {
|
|
25443
|
+
artifactCount: 0,
|
|
25444
|
+
deliveredAt: Date.now(),
|
|
25445
|
+
destinationId,
|
|
25446
|
+
destinationKind: destination.kind,
|
|
25447
|
+
error: error instanceof Error ? error.message : String(error),
|
|
25448
|
+
label,
|
|
25449
|
+
manifestBytes: byteLength(manifest),
|
|
25450
|
+
status: "failed",
|
|
25451
|
+
target: destination.kind === "file" ? destination.directory : destination.kind === "s3" ? destination.bucket ? `s3://${destination.bucket}/${normalizeExportS3KeyPrefix(destination.keyPrefix)}` : normalizeExportS3KeyPrefix(destination.keyPrefix) : destination.url
|
|
25452
|
+
};
|
|
25453
|
+
}
|
|
25454
|
+
}));
|
|
25455
|
+
const failed = destinations.filter((destination) => destination.status === "failed").length;
|
|
25456
|
+
return {
|
|
25457
|
+
checkedAt,
|
|
25458
|
+
destinations,
|
|
25459
|
+
exportStatus: options.report.status,
|
|
25460
|
+
status: failed > 0 || options.report.status === "fail" ? "fail" : options.report.status === "warn" ? "warn" : "pass",
|
|
25461
|
+
summary: {
|
|
25462
|
+
delivered: destinations.length - failed,
|
|
25463
|
+
failed,
|
|
25464
|
+
total: destinations.length
|
|
25465
|
+
}
|
|
25466
|
+
};
|
|
25467
|
+
};
|
|
25313
25468
|
var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
25314
25469
|
const path = options.path ?? "/api/voice/observability-export";
|
|
25315
25470
|
const artifactIndexPath = options.artifactIndexPath ?? `${path}/artifacts`;
|
|
25316
25471
|
const artifactDownloadPath = options.artifactDownloadPath ?? `${path}/artifacts`;
|
|
25472
|
+
const deliveryPath = options.deliveryPath ?? `${path}/deliveries`;
|
|
25317
25473
|
const markdownPath = options.markdownPath ?? "/voice/observability-export.md";
|
|
25318
25474
|
const htmlPath = options.htmlPath ?? "/voice/observability-export";
|
|
25319
25475
|
const headers = {
|
|
@@ -25363,6 +25519,12 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
25363
25519
|
}
|
|
25364
25520
|
});
|
|
25365
25521
|
}
|
|
25522
|
+
if (deliveryPath !== false && options.deliveryDestinations) {
|
|
25523
|
+
app.post(deliveryPath, async () => Response.json(await deliverVoiceObservabilityExport({
|
|
25524
|
+
destinations: options.deliveryDestinations ?? [],
|
|
25525
|
+
report: await buildReport()
|
|
25526
|
+
}), { headers }));
|
|
25527
|
+
}
|
|
25366
25528
|
if (markdownPath !== false) {
|
|
25367
25529
|
app.get(markdownPath, async () => {
|
|
25368
25530
|
const report = await buildReport();
|
|
@@ -27157,7 +27319,7 @@ var createVoiceOpsRuntime = (config) => {
|
|
|
27157
27319
|
pollIntervalMs: _pollIntervalMs,
|
|
27158
27320
|
backoffMs,
|
|
27159
27321
|
eventTypes,
|
|
27160
|
-
fetch,
|
|
27322
|
+
fetch: fetch2,
|
|
27161
27323
|
headers,
|
|
27162
27324
|
retries,
|
|
27163
27325
|
signingSecret,
|
|
@@ -27171,7 +27333,7 @@ var createVoiceOpsRuntime = (config) => {
|
|
|
27171
27333
|
webhook: {
|
|
27172
27334
|
backoffMs,
|
|
27173
27335
|
eventTypes,
|
|
27174
|
-
fetch,
|
|
27336
|
+
fetch: fetch2,
|
|
27175
27337
|
headers,
|
|
27176
27338
|
retries,
|
|
27177
27339
|
signingSecret,
|
|
@@ -28113,6 +28275,7 @@ export {
|
|
|
28113
28275
|
evaluateVoiceProviderStackGaps,
|
|
28114
28276
|
encodeTwilioMulawBase64,
|
|
28115
28277
|
deliverVoiceTraceEventsToSinks,
|
|
28278
|
+
deliverVoiceObservabilityExport,
|
|
28116
28279
|
deliverVoiceIntegrationEventToSinks,
|
|
28117
28280
|
deliverVoiceIntegrationEvent,
|
|
28118
28281
|
deliverVoiceHandoffDelivery,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Elysia } from 'elysia';
|
|
2
|
+
import type { S3Client, S3Options } from 'bun';
|
|
2
3
|
import { type VoiceAuditSinkDeliveryQueueSummary, type VoiceAuditSinkDeliveryRecord, type VoiceAuditSinkDeliveryStore } from './auditSinks';
|
|
3
4
|
import type { VoiceAuditEventStore, VoiceAuditEventType } from './audit';
|
|
4
5
|
import { type VoiceOperationsRecord } from './operationsRecord';
|
|
@@ -107,6 +108,57 @@ export type VoiceObservabilityExportArtifactIndex = {
|
|
|
107
108
|
warn: number;
|
|
108
109
|
};
|
|
109
110
|
};
|
|
111
|
+
export type VoiceObservabilityExportDeliveryDestination = {
|
|
112
|
+
directory: string;
|
|
113
|
+
id?: string;
|
|
114
|
+
includeArtifacts?: boolean;
|
|
115
|
+
kind: 'file';
|
|
116
|
+
label?: string;
|
|
117
|
+
} | (S3Options & {
|
|
118
|
+
bucket?: string;
|
|
119
|
+
client?: Pick<S3Client, 'file'>;
|
|
120
|
+
id?: string;
|
|
121
|
+
includeArtifacts?: boolean;
|
|
122
|
+
keyPrefix?: string;
|
|
123
|
+
kind: 's3';
|
|
124
|
+
label?: string;
|
|
125
|
+
}) | {
|
|
126
|
+
fetch?: typeof fetch;
|
|
127
|
+
headers?: Record<string, string>;
|
|
128
|
+
id?: string;
|
|
129
|
+
includeArtifacts?: boolean;
|
|
130
|
+
kind: 'webhook';
|
|
131
|
+
label?: string;
|
|
132
|
+
timeoutMs?: number;
|
|
133
|
+
url: string;
|
|
134
|
+
};
|
|
135
|
+
export type VoiceObservabilityExportDeliveryDestinationResult = {
|
|
136
|
+
artifactCount: number;
|
|
137
|
+
deliveredAt: number;
|
|
138
|
+
destinationId: string;
|
|
139
|
+
destinationKind: VoiceObservabilityExportDeliveryDestination['kind'];
|
|
140
|
+
error?: string;
|
|
141
|
+
label: string;
|
|
142
|
+
manifestBytes: number;
|
|
143
|
+
status: 'delivered' | 'failed';
|
|
144
|
+
target: string;
|
|
145
|
+
};
|
|
146
|
+
export type VoiceObservabilityExportDeliveryReport = {
|
|
147
|
+
checkedAt: number;
|
|
148
|
+
destinations: VoiceObservabilityExportDeliveryDestinationResult[];
|
|
149
|
+
exportStatus: VoiceObservabilityExportStatus;
|
|
150
|
+
status: VoiceObservabilityExportStatus;
|
|
151
|
+
summary: {
|
|
152
|
+
delivered: number;
|
|
153
|
+
failed: number;
|
|
154
|
+
total: number;
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
export type VoiceObservabilityExportDeliveryOptions = {
|
|
158
|
+
destinations: VoiceObservabilityExportDeliveryDestination[];
|
|
159
|
+
report: VoiceObservabilityExportReport;
|
|
160
|
+
runId?: string;
|
|
161
|
+
};
|
|
110
162
|
export type VoiceObservabilityExportOptions = {
|
|
111
163
|
artifacts?: VoiceObservabilityExportArtifact[];
|
|
112
164
|
artifactIntegrity?: {
|
|
@@ -134,6 +186,8 @@ export type VoiceObservabilityExportRoutesOptions = VoiceObservabilityExportOpti
|
|
|
134
186
|
headers?: HeadersInit;
|
|
135
187
|
artifactDownloadPath?: false | string;
|
|
136
188
|
artifactIndexPath?: false | string;
|
|
189
|
+
deliveryDestinations?: VoiceObservabilityExportDeliveryDestination[];
|
|
190
|
+
deliveryPath?: false | string;
|
|
137
191
|
htmlPath?: false | string;
|
|
138
192
|
markdownPath?: false | string;
|
|
139
193
|
name?: string;
|
|
@@ -146,6 +200,7 @@ export declare const renderVoiceObservabilityExportMarkdown: (report: VoiceObser
|
|
|
146
200
|
title?: string;
|
|
147
201
|
}) => string;
|
|
148
202
|
export declare const buildVoiceObservabilityArtifactIndex: (report: VoiceObservabilityExportReport) => VoiceObservabilityExportArtifactIndex;
|
|
203
|
+
export declare const deliverVoiceObservabilityExport: (options: VoiceObservabilityExportDeliveryOptions) => Promise<VoiceObservabilityExportDeliveryReport>;
|
|
149
204
|
export declare const createVoiceObservabilityExportRoutes: (options?: VoiceObservabilityExportRoutesOptions) => Elysia<"", {
|
|
150
205
|
decorator: {};
|
|
151
206
|
store: {};
|