@absolutejs/voice 0.0.22-beta.484 → 0.0.22-beta.486
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/dist/index.d.ts +4 -0
- package/dist/index.js +222 -4
- package/dist/otelExporter.d.ts +83 -0
- package/dist/webhookVerification.d.ts +27 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -80,6 +80,10 @@ export type { CreateVoiceCostAccountantOptions, VoiceCostAccountant, VoiceCostBr
|
|
|
80
80
|
export { describeVoiceAssistantMode, resolveVoiceAssistantMode, } from "./assistantMode";
|
|
81
81
|
export type { VoiceAssistantMode, VoiceAssistantModality, VoiceAssistantModeDescriptor, VoiceSemanticVADConfig, } from "./assistantMode";
|
|
82
82
|
export { createPunctuationSemanticTurnDetector, createRegexSemanticTurnDetector, } from "./semanticTurn";
|
|
83
|
+
export { VOICE_WEBHOOK_SIGNATURE_HEADER, VOICE_WEBHOOK_TIMESTAMP_HEADER, extractVoiceWebhookSignatureFromHeaders, signVoiceWebhookBody, verifyVoiceWebhookSignature, } from "./webhookVerification";
|
|
84
|
+
export { aggregateVoiceTurnLatencySpans, buildOTELSpanId, buildOTELTraceId, buildVoiceOTELPayload, createVoiceOTELHTTPExporter, } from "./otelExporter";
|
|
85
|
+
export type { VoiceOTELAttribute, VoiceOTELExporter, VoiceOTELExporterOptions, VoiceOTELPayload, VoiceOTELResourceSpans, VoiceOTELSpan, VoiceTurnLatencySpanSet, VoiceTurnLatencySpanStage, } from "./otelExporter";
|
|
86
|
+
export type { VoiceWebhookVerificationInput, VoiceWebhookVerificationReason, VoiceWebhookVerificationResult, } from "./webhookVerification";
|
|
83
87
|
export type { CreatePunctuationSemanticTurnDetectorOptions, CreateRegexSemanticTurnDetectorOptions, VoiceSemanticTurnDetector, VoiceSemanticTurnInput, VoiceSemanticTurnVerdict, } from "./semanticTurn";
|
|
84
88
|
export { createMonologueAMDDetector } from "./amdDetector";
|
|
85
89
|
export type { MonologueAMDDetectorOptions, VoiceAMDDetector, VoiceAMDDetectorInput, VoiceAMDVerdict, } from "./amdDetector";
|
package/dist/index.js
CHANGED
|
@@ -35404,6 +35404,214 @@ var createRegexSemanticTurnDetector = (options) => {
|
|
|
35404
35404
|
}
|
|
35405
35405
|
};
|
|
35406
35406
|
};
|
|
35407
|
+
// src/webhookVerification.ts
|
|
35408
|
+
var VOICE_WEBHOOK_SIGNATURE_HEADER = "x-absolutejs-signature";
|
|
35409
|
+
var VOICE_WEBHOOK_TIMESTAMP_HEADER = "x-absolutejs-timestamp";
|
|
35410
|
+
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
35411
|
+
var timingSafeEqual3 = (left, right) => {
|
|
35412
|
+
if (left.length !== right.length) {
|
|
35413
|
+
return false;
|
|
35414
|
+
}
|
|
35415
|
+
let result = 0;
|
|
35416
|
+
for (let index = 0;index < left.length; index += 1) {
|
|
35417
|
+
result |= left.charCodeAt(index) ^ right.charCodeAt(index);
|
|
35418
|
+
}
|
|
35419
|
+
return result === 0;
|
|
35420
|
+
};
|
|
35421
|
+
var computeSignature = async (input) => {
|
|
35422
|
+
const encoder2 = new TextEncoder;
|
|
35423
|
+
const key = await crypto.subtle.importKey("raw", encoder2.encode(input.secret), { hash: "SHA-256", name: "HMAC" }, false, ["sign"]);
|
|
35424
|
+
const payload = encoder2.encode(`${input.timestamp}.${input.body}`);
|
|
35425
|
+
const signature = await crypto.subtle.sign("HMAC", key, payload);
|
|
35426
|
+
return `sha256=${toHex6(new Uint8Array(signature))}`;
|
|
35427
|
+
};
|
|
35428
|
+
var signVoiceWebhookBody = async (input) => computeSignature(input);
|
|
35429
|
+
var verifyVoiceWebhookSignature = async (input) => {
|
|
35430
|
+
if (!input.secret) {
|
|
35431
|
+
return { ok: false, reason: "missing-secret" };
|
|
35432
|
+
}
|
|
35433
|
+
if (!input.signature) {
|
|
35434
|
+
return { ok: false, reason: "missing-signature" };
|
|
35435
|
+
}
|
|
35436
|
+
if (!input.signature.startsWith("sha256=")) {
|
|
35437
|
+
return { ok: false, reason: "unsupported-algorithm" };
|
|
35438
|
+
}
|
|
35439
|
+
if (!input.timestamp) {
|
|
35440
|
+
return { ok: false, reason: "missing-timestamp" };
|
|
35441
|
+
}
|
|
35442
|
+
const timestampMs = Number(input.timestamp);
|
|
35443
|
+
const toleranceMs = Math.max(0, input.toleranceMs ?? 5 * 60 * 1000);
|
|
35444
|
+
if (!Number.isFinite(timestampMs) || toleranceMs > 0 && Math.abs((input.now ?? Date.now()) - timestampMs) > toleranceMs) {
|
|
35445
|
+
return { ok: false, reason: "stale-timestamp" };
|
|
35446
|
+
}
|
|
35447
|
+
const expected = await computeSignature({
|
|
35448
|
+
body: input.body,
|
|
35449
|
+
secret: input.secret,
|
|
35450
|
+
timestamp: input.timestamp
|
|
35451
|
+
});
|
|
35452
|
+
if (!timingSafeEqual3(expected, input.signature)) {
|
|
35453
|
+
return { ok: false, reason: "signature-mismatch" };
|
|
35454
|
+
}
|
|
35455
|
+
return { ok: true };
|
|
35456
|
+
};
|
|
35457
|
+
var extractVoiceWebhookSignatureFromHeaders = (headers) => {
|
|
35458
|
+
const get = (name) => {
|
|
35459
|
+
if (headers instanceof Headers) {
|
|
35460
|
+
return headers.get(name);
|
|
35461
|
+
}
|
|
35462
|
+
const lowerTarget = name.toLowerCase();
|
|
35463
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
35464
|
+
if (key.toLowerCase() === lowerTarget) {
|
|
35465
|
+
if (Array.isArray(value)) {
|
|
35466
|
+
return value[0] ?? null;
|
|
35467
|
+
}
|
|
35468
|
+
return value ?? null;
|
|
35469
|
+
}
|
|
35470
|
+
}
|
|
35471
|
+
return null;
|
|
35472
|
+
};
|
|
35473
|
+
return {
|
|
35474
|
+
signature: get(VOICE_WEBHOOK_SIGNATURE_HEADER),
|
|
35475
|
+
timestamp: get(VOICE_WEBHOOK_TIMESTAMP_HEADER)
|
|
35476
|
+
};
|
|
35477
|
+
};
|
|
35478
|
+
// src/otelExporter.ts
|
|
35479
|
+
var SCOPE_NAME = "@absolutejs/voice";
|
|
35480
|
+
var SPAN_KIND_INTERNAL = 1;
|
|
35481
|
+
var STATUS_OK = 1;
|
|
35482
|
+
var HEX_CHARS = "0123456789abcdef";
|
|
35483
|
+
var hashToHex = (input, length) => {
|
|
35484
|
+
let hash = 0xcbf29ce4_84222325n;
|
|
35485
|
+
const prime = 0x100000001_b3n;
|
|
35486
|
+
for (let index = 0;index < input.length; index += 1) {
|
|
35487
|
+
hash ^= BigInt(input.charCodeAt(index));
|
|
35488
|
+
hash = hash * prime & 0xffffffffffffffffn;
|
|
35489
|
+
}
|
|
35490
|
+
let hex = hash.toString(16).padStart(16, "0");
|
|
35491
|
+
while (hex.length < length) {
|
|
35492
|
+
let next = 0n;
|
|
35493
|
+
for (const ch of hex) {
|
|
35494
|
+
next = next * 31n + BigInt(HEX_CHARS.indexOf(ch)) & 0xffffffffffffffffn;
|
|
35495
|
+
}
|
|
35496
|
+
hex += next.toString(16).padStart(16, "0");
|
|
35497
|
+
}
|
|
35498
|
+
return hex.slice(0, length);
|
|
35499
|
+
};
|
|
35500
|
+
var buildOTELTraceId = (sessionId) => hashToHex(`voice-trace:${sessionId}`, 32);
|
|
35501
|
+
var buildOTELSpanId = (sessionId, suffix) => hashToHex(`voice-span:${sessionId}:${suffix}`, 16);
|
|
35502
|
+
var toUnixNano = (ms) => `${Math.trunc(ms * 1e6)}`;
|
|
35503
|
+
var stringAttr = (key, value) => ({
|
|
35504
|
+
key,
|
|
35505
|
+
value: { stringValue: value }
|
|
35506
|
+
});
|
|
35507
|
+
var aggregateVoiceTurnLatencySpans = (events) => {
|
|
35508
|
+
const byTurn = new Map;
|
|
35509
|
+
for (const event of events) {
|
|
35510
|
+
if (event.type !== "turn_latency.stage" || !event.turnId) {
|
|
35511
|
+
continue;
|
|
35512
|
+
}
|
|
35513
|
+
const stage = typeof event.payload?.stage === "string" ? event.payload.stage : undefined;
|
|
35514
|
+
if (!stage) {
|
|
35515
|
+
continue;
|
|
35516
|
+
}
|
|
35517
|
+
const key = `${event.sessionId}::${event.turnId}`;
|
|
35518
|
+
const existing = byTurn.get(key);
|
|
35519
|
+
if (!existing) {
|
|
35520
|
+
byTurn.set(key, {
|
|
35521
|
+
endedAt: event.at,
|
|
35522
|
+
scenarioId: event.scenarioId,
|
|
35523
|
+
sessionId: event.sessionId,
|
|
35524
|
+
stages: [{ at: event.at, stage }],
|
|
35525
|
+
startedAt: event.at,
|
|
35526
|
+
turnId: event.turnId
|
|
35527
|
+
});
|
|
35528
|
+
continue;
|
|
35529
|
+
}
|
|
35530
|
+
existing.stages.push({ at: event.at, stage });
|
|
35531
|
+
existing.startedAt = Math.min(existing.startedAt, event.at);
|
|
35532
|
+
existing.endedAt = Math.max(existing.endedAt, event.at);
|
|
35533
|
+
}
|
|
35534
|
+
return Array.from(byTurn.values()).sort((left, right) => left.startedAt - right.startedAt);
|
|
35535
|
+
};
|
|
35536
|
+
var buildVoiceOTELPayload = (spanSets, options = {}) => {
|
|
35537
|
+
const resourceAttributes = [
|
|
35538
|
+
stringAttr("service.name", options.serviceName ?? "absolutejs-voice")
|
|
35539
|
+
];
|
|
35540
|
+
for (const [key, value] of Object.entries(options.resourceAttributes ?? {})) {
|
|
35541
|
+
resourceAttributes.push(stringAttr(key, value));
|
|
35542
|
+
}
|
|
35543
|
+
const spans = [];
|
|
35544
|
+
for (const set of spanSets) {
|
|
35545
|
+
const traceId = buildOTELTraceId(set.sessionId);
|
|
35546
|
+
const parentSpanId = buildOTELSpanId(set.sessionId, `turn:${set.turnId}`);
|
|
35547
|
+
spans.push({
|
|
35548
|
+
attributes: [
|
|
35549
|
+
stringAttr("voice.session_id", set.sessionId),
|
|
35550
|
+
stringAttr("voice.turn_id", set.turnId),
|
|
35551
|
+
...set.scenarioId ? [stringAttr("voice.scenario_id", set.scenarioId)] : []
|
|
35552
|
+
],
|
|
35553
|
+
endTimeUnixNano: toUnixNano(set.endedAt),
|
|
35554
|
+
kind: SPAN_KIND_INTERNAL,
|
|
35555
|
+
name: "voice.turn",
|
|
35556
|
+
spanId: parentSpanId,
|
|
35557
|
+
startTimeUnixNano: toUnixNano(set.startedAt),
|
|
35558
|
+
status: { code: STATUS_OK },
|
|
35559
|
+
traceId
|
|
35560
|
+
});
|
|
35561
|
+
for (let index = 0;index < set.stages.length; index += 1) {
|
|
35562
|
+
const stage = set.stages[index];
|
|
35563
|
+
const next = set.stages[index + 1];
|
|
35564
|
+
const endsAt = next ? next.at : set.endedAt;
|
|
35565
|
+
spans.push({
|
|
35566
|
+
attributes: [
|
|
35567
|
+
stringAttr("voice.session_id", set.sessionId),
|
|
35568
|
+
stringAttr("voice.turn_id", set.turnId),
|
|
35569
|
+
stringAttr("voice.stage", stage.stage)
|
|
35570
|
+
],
|
|
35571
|
+
endTimeUnixNano: toUnixNano(endsAt),
|
|
35572
|
+
kind: SPAN_KIND_INTERNAL,
|
|
35573
|
+
name: `voice.turn.stage.${stage.stage}`,
|
|
35574
|
+
parentSpanId,
|
|
35575
|
+
spanId: buildOTELSpanId(set.sessionId, `${set.turnId}:${stage.stage}:${index}`),
|
|
35576
|
+
startTimeUnixNano: toUnixNano(stage.at),
|
|
35577
|
+
status: { code: STATUS_OK },
|
|
35578
|
+
traceId
|
|
35579
|
+
});
|
|
35580
|
+
}
|
|
35581
|
+
}
|
|
35582
|
+
return {
|
|
35583
|
+
resourceSpans: [
|
|
35584
|
+
{
|
|
35585
|
+
resource: { attributes: resourceAttributes },
|
|
35586
|
+
scopeSpans: [{ scope: { name: SCOPE_NAME }, spans }]
|
|
35587
|
+
}
|
|
35588
|
+
]
|
|
35589
|
+
};
|
|
35590
|
+
};
|
|
35591
|
+
var createVoiceOTELHTTPExporter = (options) => {
|
|
35592
|
+
const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
35593
|
+
return {
|
|
35594
|
+
export: async (events) => {
|
|
35595
|
+
const spanSets = aggregateVoiceTurnLatencySpans(events);
|
|
35596
|
+
if (spanSets.length === 0) {
|
|
35597
|
+
return { ok: true };
|
|
35598
|
+
}
|
|
35599
|
+
const payload = buildVoiceOTELPayload(spanSets, {
|
|
35600
|
+
resourceAttributes: options.resourceAttributes,
|
|
35601
|
+
serviceName: options.serviceName
|
|
35602
|
+
});
|
|
35603
|
+
const response = await fetchImpl(options.url, {
|
|
35604
|
+
body: JSON.stringify(payload),
|
|
35605
|
+
headers: {
|
|
35606
|
+
"content-type": "application/json",
|
|
35607
|
+
...options.headers
|
|
35608
|
+
},
|
|
35609
|
+
method: "POST"
|
|
35610
|
+
});
|
|
35611
|
+
return { ok: response.ok, status: response.status };
|
|
35612
|
+
}
|
|
35613
|
+
};
|
|
35614
|
+
};
|
|
35407
35615
|
// src/amdDetector.ts
|
|
35408
35616
|
var createMonologueAMDDetector = (options = {}) => {
|
|
35409
35617
|
const minMonologueMs = options.minMonologueMs ?? 8000;
|
|
@@ -41951,7 +42159,7 @@ var createVoiceMemoryStore = () => {
|
|
|
41951
42159
|
};
|
|
41952
42160
|
// src/opsWebhook.ts
|
|
41953
42161
|
import { Elysia as Elysia66 } from "elysia";
|
|
41954
|
-
var
|
|
42162
|
+
var toHex7 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
41955
42163
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
41956
42164
|
const encoder2 = new TextEncoder;
|
|
41957
42165
|
const key = await crypto.subtle.importKey("raw", encoder2.encode(input.secret), {
|
|
@@ -41959,9 +42167,9 @@ var signVoiceOpsWebhookBody = async (input) => {
|
|
|
41959
42167
|
name: "HMAC"
|
|
41960
42168
|
}, false, ["sign"]);
|
|
41961
42169
|
const signature = await crypto.subtle.sign("HMAC", key, encoder2.encode(`${input.timestamp}.${input.body}`));
|
|
41962
|
-
return `sha256=${
|
|
42170
|
+
return `sha256=${toHex7(new Uint8Array(signature))}`;
|
|
41963
42171
|
};
|
|
41964
|
-
var
|
|
42172
|
+
var timingSafeEqual4 = (left, right) => {
|
|
41965
42173
|
const encoder2 = new TextEncoder;
|
|
41966
42174
|
const leftBytes = encoder2.encode(left);
|
|
41967
42175
|
const rightBytes = encoder2.encode(right);
|
|
@@ -42068,7 +42276,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
42068
42276
|
secret: input.secret,
|
|
42069
42277
|
timestamp: input.timestamp
|
|
42070
42278
|
});
|
|
42071
|
-
if (!
|
|
42279
|
+
if (!timingSafeEqual4(expected, input.signature)) {
|
|
42072
42280
|
return {
|
|
42073
42281
|
ok: false,
|
|
42074
42282
|
reason: "invalid-signature"
|
|
@@ -45977,6 +46185,7 @@ export {
|
|
|
45977
46185
|
voiceGuardrailPolicyPresets,
|
|
45978
46186
|
voiceComplianceRedactionDefaults,
|
|
45979
46187
|
voice,
|
|
46188
|
+
verifyVoiceWebhookSignature,
|
|
45980
46189
|
verifyVoiceTwilioWebhookSignature,
|
|
45981
46190
|
verifyVoiceTelnyxWebhookSignature,
|
|
45982
46191
|
verifyVoicePlivoWebhookSignature,
|
|
@@ -46020,6 +46229,7 @@ export {
|
|
|
46020
46229
|
summarizeVoiceAssistantRuns,
|
|
46021
46230
|
summarizeVoiceAssistantHealth,
|
|
46022
46231
|
startVoiceOpsTask,
|
|
46232
|
+
signVoiceWebhookBody,
|
|
46023
46233
|
signVoiceTwilioWebhook,
|
|
46024
46234
|
signVoicePlivoWebhook,
|
|
46025
46235
|
shapeTelephonyAssistantText,
|
|
@@ -46219,6 +46429,7 @@ export {
|
|
|
46219
46429
|
filterVoiceAuditEvents,
|
|
46220
46430
|
fetchVoiceProofTarget,
|
|
46221
46431
|
failVoiceOpsTask,
|
|
46432
|
+
extractVoiceWebhookSignatureFromHeaders,
|
|
46222
46433
|
extractVoiceMediaPipelineIssueEntries,
|
|
46223
46434
|
exportVoiceTrace,
|
|
46224
46435
|
exportVoiceAuditTrail,
|
|
@@ -46466,6 +46677,7 @@ export {
|
|
|
46466
46677
|
createVoiceObservabilityExportSchema,
|
|
46467
46678
|
createVoiceObservabilityExportRoutes,
|
|
46468
46679
|
createVoiceObservabilityExportReplayRoutes,
|
|
46680
|
+
createVoiceOTELHTTPExporter,
|
|
46469
46681
|
createVoiceMonitorWebhookNotifier,
|
|
46470
46682
|
createVoiceMonitorSession,
|
|
46471
46683
|
createVoiceMonitorRuntimeBinding,
|
|
@@ -46684,6 +46896,7 @@ export {
|
|
|
46684
46896
|
buildVoiceObservabilityExportDeliveryHistory,
|
|
46685
46897
|
buildVoiceObservabilityExport,
|
|
46686
46898
|
buildVoiceObservabilityArtifactIndex,
|
|
46899
|
+
buildVoiceOTELPayload,
|
|
46687
46900
|
buildVoiceMultilingualProofReadinessCheck,
|
|
46688
46901
|
buildVoiceMonitorRunReport,
|
|
46689
46902
|
buildVoiceMonitorPlan,
|
|
@@ -46714,6 +46927,8 @@ export {
|
|
|
46714
46927
|
buildVoiceAuditTrailReport,
|
|
46715
46928
|
buildVoiceAuditExport,
|
|
46716
46929
|
buildVoiceAuditDeliveryReport,
|
|
46930
|
+
buildOTELTraceId,
|
|
46931
|
+
buildOTELSpanId,
|
|
46717
46932
|
buildEmptyVoiceProofTrendReport,
|
|
46718
46933
|
assignVoiceOpsTask,
|
|
46719
46934
|
assertVoiceToolContractEvidence,
|
|
@@ -46764,7 +46979,10 @@ export {
|
|
|
46764
46979
|
appendVoiceRealCallProfileRecoveryEvidence,
|
|
46765
46980
|
appendVoiceProviderRouterTraceEvent,
|
|
46766
46981
|
appendVoiceIOProviderRouterTraceEvent,
|
|
46982
|
+
aggregateVoiceTurnLatencySpans,
|
|
46767
46983
|
acknowledgeVoiceMonitorIssue,
|
|
46984
|
+
VOICE_WEBHOOK_TIMESTAMP_HEADER,
|
|
46985
|
+
VOICE_WEBHOOK_SIGNATURE_HEADER,
|
|
46768
46986
|
VOICE_LIVE_OPS_ACTIONS,
|
|
46769
46987
|
TURN_PROFILE_DEFAULTS,
|
|
46770
46988
|
DEFAULT_VOICE_REDACTION_PATTERNS,
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { StoredVoiceTraceEvent } from "./trace";
|
|
2
|
+
export type VoiceOTELAttribute = {
|
|
3
|
+
key: string;
|
|
4
|
+
value: {
|
|
5
|
+
boolValue: boolean;
|
|
6
|
+
};
|
|
7
|
+
} | {
|
|
8
|
+
key: string;
|
|
9
|
+
value: {
|
|
10
|
+
doubleValue: number;
|
|
11
|
+
};
|
|
12
|
+
} | {
|
|
13
|
+
key: string;
|
|
14
|
+
value: {
|
|
15
|
+
intValue: string;
|
|
16
|
+
};
|
|
17
|
+
} | {
|
|
18
|
+
key: string;
|
|
19
|
+
value: {
|
|
20
|
+
stringValue: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export type VoiceOTELSpan = {
|
|
24
|
+
attributes: VoiceOTELAttribute[];
|
|
25
|
+
endTimeUnixNano: string;
|
|
26
|
+
kind: number;
|
|
27
|
+
name: string;
|
|
28
|
+
parentSpanId?: string;
|
|
29
|
+
spanId: string;
|
|
30
|
+
startTimeUnixNano: string;
|
|
31
|
+
status: {
|
|
32
|
+
code: number;
|
|
33
|
+
};
|
|
34
|
+
traceId: string;
|
|
35
|
+
};
|
|
36
|
+
export type VoiceOTELResourceSpans = {
|
|
37
|
+
resource: {
|
|
38
|
+
attributes: VoiceOTELAttribute[];
|
|
39
|
+
};
|
|
40
|
+
scopeSpans: ReadonlyArray<{
|
|
41
|
+
scope: {
|
|
42
|
+
name: string;
|
|
43
|
+
version?: string;
|
|
44
|
+
};
|
|
45
|
+
spans: VoiceOTELSpan[];
|
|
46
|
+
}>;
|
|
47
|
+
};
|
|
48
|
+
export type VoiceOTELPayload = {
|
|
49
|
+
resourceSpans: VoiceOTELResourceSpans[];
|
|
50
|
+
};
|
|
51
|
+
export type VoiceTurnLatencySpanStage = {
|
|
52
|
+
at: number;
|
|
53
|
+
stage: string;
|
|
54
|
+
};
|
|
55
|
+
export type VoiceTurnLatencySpanSet = {
|
|
56
|
+
endedAt: number;
|
|
57
|
+
scenarioId?: string;
|
|
58
|
+
sessionId: string;
|
|
59
|
+
stages: VoiceTurnLatencySpanStage[];
|
|
60
|
+
startedAt: number;
|
|
61
|
+
turnId: string;
|
|
62
|
+
};
|
|
63
|
+
export declare const buildOTELTraceId: (sessionId: string) => string;
|
|
64
|
+
export declare const buildOTELSpanId: (sessionId: string, suffix: string) => string;
|
|
65
|
+
export declare const aggregateVoiceTurnLatencySpans: (events: StoredVoiceTraceEvent[]) => VoiceTurnLatencySpanSet[];
|
|
66
|
+
export type VoiceOTELExporterOptions = {
|
|
67
|
+
fetch?: typeof fetch;
|
|
68
|
+
headers?: Record<string, string>;
|
|
69
|
+
resourceAttributes?: Record<string, string>;
|
|
70
|
+
serviceName?: string;
|
|
71
|
+
url: string;
|
|
72
|
+
};
|
|
73
|
+
export declare const buildVoiceOTELPayload: (spanSets: VoiceTurnLatencySpanSet[], options?: {
|
|
74
|
+
resourceAttributes?: Record<string, string>;
|
|
75
|
+
serviceName?: string;
|
|
76
|
+
}) => VoiceOTELPayload;
|
|
77
|
+
export type VoiceOTELExporter = {
|
|
78
|
+
export: (events: StoredVoiceTraceEvent[]) => Promise<{
|
|
79
|
+
ok: boolean;
|
|
80
|
+
status?: number;
|
|
81
|
+
}>;
|
|
82
|
+
};
|
|
83
|
+
export declare const createVoiceOTELHTTPExporter: (options: VoiceOTELExporterOptions) => VoiceOTELExporter;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type VoiceWebhookVerificationReason = "missing-secret" | "missing-signature" | "missing-timestamp" | "signature-mismatch" | "stale-timestamp" | "unsupported-algorithm";
|
|
2
|
+
export type VoiceWebhookVerificationResult = {
|
|
3
|
+
ok: true;
|
|
4
|
+
} | {
|
|
5
|
+
ok: false;
|
|
6
|
+
reason: VoiceWebhookVerificationReason;
|
|
7
|
+
};
|
|
8
|
+
export type VoiceWebhookVerificationInput = {
|
|
9
|
+
body: string;
|
|
10
|
+
now?: number;
|
|
11
|
+
secret?: string;
|
|
12
|
+
signature?: string | null;
|
|
13
|
+
timestamp?: string | null;
|
|
14
|
+
toleranceMs?: number;
|
|
15
|
+
};
|
|
16
|
+
export declare const VOICE_WEBHOOK_SIGNATURE_HEADER = "x-absolutejs-signature";
|
|
17
|
+
export declare const VOICE_WEBHOOK_TIMESTAMP_HEADER = "x-absolutejs-timestamp";
|
|
18
|
+
export declare const signVoiceWebhookBody: (input: {
|
|
19
|
+
body: string;
|
|
20
|
+
secret: string;
|
|
21
|
+
timestamp: string;
|
|
22
|
+
}) => Promise<string>;
|
|
23
|
+
export declare const verifyVoiceWebhookSignature: (input: VoiceWebhookVerificationInput) => Promise<VoiceWebhookVerificationResult>;
|
|
24
|
+
export declare const extractVoiceWebhookSignatureFromHeaders: (headers: Headers | Record<string, string | string[] | undefined>) => {
|
|
25
|
+
signature: string | null;
|
|
26
|
+
timestamp: string | null;
|
|
27
|
+
};
|