@absolutejs/voice 0.0.22-beta.81 → 0.0.22-beta.82
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 -4
- package/dist/index.js +279 -0
- package/dist/telephony/plivo.d.ts +101 -1
- package/dist/telephony/telnyx.d.ts +109 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -82,13 +82,13 @@ export type { VoiceSQLiteRuntimeStorage, VoiceSQLiteStoreOptions } from './sqlit
|
|
|
82
82
|
export type { StoredVoiceIntegrationEvent, StoredVoiceExternalObjectMap, StoredVoiceOpsTask, VoiceExternalObjectMap, VoiceExternalObjectMapStore, VoiceOpsTaskAgeBucket, VoiceOpsTaskAnalyticsOptions, VoiceOpsTaskAnalyticsSummary, VoiceOpsTaskAssignmentRule, VoiceOpsTaskAssignmentRuleCondition, VoiceOpsTaskAssignmentRules, VoiceOpsTaskAssigneeAnalytics, VoiceOpsDispositionTaskPolicies, VoiceOpsSLABreachPolicy, VoiceIntegrationDeliveryStatus, VoiceIntegrationEvent, VoiceIntegrationEventStore, VoiceIntegrationSinkDelivery, VoiceIntegrationEventType, VoiceIntegrationWebhookConfig, VoiceOpsTask, VoiceOpsTaskHistoryEntry, VoiceOpsTaskKind, VoiceOpsTaskPolicy, VoiceOpsTaskPriority, VoiceOpsTaskStatus, VoiceOpsTaskStore, VoiceOpsTaskSummary, VoiceOpsTaskWorkerAnalytics } from './ops';
|
|
83
83
|
export { createTwilioMediaStreamBridge, createTwilioVoiceRoutes, createTwilioVoiceResponse, decodeTwilioMulawBase64, encodeTwilioMulawBase64, transcodePCMToTwilioOutboundPayload, transcodeTwilioInboundPayloadToPCM16 } from './telephony/twilio';
|
|
84
84
|
export { evaluateVoiceTelephonyContract } from './telephony/contract';
|
|
85
|
-
export { createTelnyxVoiceResponse, createTelnyxVoiceRoutes, verifyVoiceTelnyxWebhookSignature } from './telephony/telnyx';
|
|
86
|
-
export { createPlivoVoiceResponse, createPlivoVoiceRoutes, signVoicePlivoWebhook, verifyVoicePlivoWebhookSignature } from './telephony/plivo';
|
|
85
|
+
export { createTelnyxMediaStreamBridge, createTelnyxVoiceResponse, createTelnyxVoiceRoutes, verifyVoiceTelnyxWebhookSignature } from './telephony/telnyx';
|
|
86
|
+
export { createPlivoMediaStreamBridge, createPlivoVoiceResponse, createPlivoVoiceRoutes, signVoicePlivoWebhook, verifyVoicePlivoWebhookSignature } from './telephony/plivo';
|
|
87
87
|
export { createVoiceTelephonyCarrierMatrix, createVoiceTelephonyCarrierMatrixRoutes, renderVoiceTelephonyCarrierMatrixHTML } from './telephony/matrix';
|
|
88
88
|
export type { TwilioInboundMessage, TwilioMediaStreamBridge, TwilioMediaStreamBridgeOptions, TwilioMediaStreamSocket, TwilioOutboundClearMessage, TwilioOutboundMarkMessage, TwilioOutboundMediaMessage, TwilioOutboundMessage, TwilioVoiceRouteParameters, TwilioVoiceResponseOptions, TwilioVoiceSmokeCheck, TwilioVoiceSmokeOptions, TwilioVoiceSmokeReport, TwilioVoiceSetupOptions, TwilioVoiceSetupStatus, TwilioVoiceRoutesOptions } from './telephony/twilio';
|
|
89
89
|
export type { VoiceTelephonyContractIssue, VoiceTelephonyContractOptions, VoiceTelephonyContractReport, VoiceTelephonyContractRequirement, VoiceTelephonyProvider, VoiceTelephonySetupStatus, VoiceTelephonySmokeCheck, VoiceTelephonySmokeReport } from './telephony/contract';
|
|
90
|
-
export type { TelnyxVoiceResponseOptions, TelnyxVoiceRoutesOptions, TelnyxVoiceSetupOptions, TelnyxVoiceSetupStatus, TelnyxVoiceSmokeCheck, TelnyxVoiceSmokeOptions, TelnyxVoiceSmokeReport } from './telephony/telnyx';
|
|
91
|
-
export type { PlivoVoiceResponseOptions, PlivoVoiceRoutesOptions, PlivoVoiceSetupOptions, PlivoVoiceSetupStatus, PlivoVoiceSmokeCheck, PlivoVoiceSmokeOptions, PlivoVoiceSmokeReport } from './telephony/plivo';
|
|
90
|
+
export type { TelnyxInboundMessage, TelnyxMediaPayload, TelnyxMediaStreamBridge, TelnyxMediaStreamBridgeOptions, TelnyxMediaStreamSocket, TelnyxOutboundClearMessage, TelnyxOutboundMarkMessage, TelnyxOutboundMediaMessage, TelnyxOutboundMessage, TelnyxVoiceResponseOptions, TelnyxVoiceRoutesOptions, TelnyxVoiceSetupOptions, TelnyxVoiceSetupStatus, TelnyxVoiceSmokeCheck, TelnyxVoiceSmokeOptions, TelnyxVoiceSmokeReport } from './telephony/telnyx';
|
|
91
|
+
export type { PlivoInboundMessage, PlivoMediaStreamBridge, PlivoMediaStreamBridgeOptions, PlivoMediaStreamSocket, PlivoOutboundCheckpointMessage, PlivoOutboundClearAudioMessage, PlivoOutboundMessage, PlivoOutboundPlayAudioMessage, PlivoVoiceResponseOptions, PlivoVoiceRoutesOptions, PlivoVoiceSetupOptions, PlivoVoiceSetupStatus, PlivoVoiceSmokeCheck, PlivoVoiceSmokeOptions, PlivoVoiceSmokeReport } from './telephony/plivo';
|
|
92
92
|
export type { VoiceTelephonyCarrierMatrix, VoiceTelephonyCarrierMatrixEntry, VoiceTelephonyCarrierMatrixInput, VoiceTelephonyCarrierMatrixOptions, VoiceTelephonyCarrierMatrixRoutesOptions, VoiceTelephonyCarrierMatrixStatus } from './telephony/matrix';
|
|
93
93
|
export { shapeTelephonyAssistantText } from './telephony/response';
|
|
94
94
|
export type { TelephonyResponseShapeMode, TelephonyResponseShapeOptions } from './telephony/response';
|
package/dist/index.js
CHANGED
|
@@ -16028,6 +16028,114 @@ var createTelnyxVoiceResponse = (options) => {
|
|
|
16028
16028
|
].filter((value) => Boolean(value)).join(" ");
|
|
16029
16029
|
return `<?xml version="1.0" encoding="UTF-8"?><Response><Start><Stream ${attributes} /></Start></Response>`;
|
|
16030
16030
|
};
|
|
16031
|
+
var parseTelnyxMessage = (raw) => {
|
|
16032
|
+
if (typeof raw !== "string") {
|
|
16033
|
+
return raw;
|
|
16034
|
+
}
|
|
16035
|
+
return JSON.parse(raw);
|
|
16036
|
+
};
|
|
16037
|
+
var normalizeTelnyxTrack = (track) => track === "outbound" || track === "outbound_track" ? "outbound" : "inbound";
|
|
16038
|
+
var telnyxToTwilioMessage = (message) => {
|
|
16039
|
+
switch (message.event) {
|
|
16040
|
+
case "connected":
|
|
16041
|
+
return {
|
|
16042
|
+
event: "connected",
|
|
16043
|
+
version: message.version
|
|
16044
|
+
};
|
|
16045
|
+
case "start": {
|
|
16046
|
+
const streamSid = message.stream_id ?? "telnyx-stream";
|
|
16047
|
+
return {
|
|
16048
|
+
event: "start",
|
|
16049
|
+
start: {
|
|
16050
|
+
callSid: message.start?.call_control_id ?? message.start?.call_session_id ?? message.start?.call_leg_id,
|
|
16051
|
+
customParameters: {
|
|
16052
|
+
...message.start?.custom_parameters ?? {},
|
|
16053
|
+
...message.start?.call_session_id ? { sessionId: message.start.call_session_id } : {}
|
|
16054
|
+
},
|
|
16055
|
+
mediaFormat: {
|
|
16056
|
+
channels: message.start?.media_format?.channels,
|
|
16057
|
+
encoding: message.start?.media_format?.encoding,
|
|
16058
|
+
sampleRate: message.start?.media_format?.sample_rate
|
|
16059
|
+
},
|
|
16060
|
+
streamSid
|
|
16061
|
+
},
|
|
16062
|
+
streamSid
|
|
16063
|
+
};
|
|
16064
|
+
}
|
|
16065
|
+
case "media": {
|
|
16066
|
+
const streamSid = message.stream_id ?? "telnyx-stream";
|
|
16067
|
+
return {
|
|
16068
|
+
event: "media",
|
|
16069
|
+
media: {
|
|
16070
|
+
chunk: message.media.chunk,
|
|
16071
|
+
payload: message.media.payload,
|
|
16072
|
+
timestamp: message.media.timestamp,
|
|
16073
|
+
track: normalizeTelnyxTrack(message.media.track)
|
|
16074
|
+
},
|
|
16075
|
+
streamSid
|
|
16076
|
+
};
|
|
16077
|
+
}
|
|
16078
|
+
case "mark":
|
|
16079
|
+
return {
|
|
16080
|
+
event: "mark",
|
|
16081
|
+
mark: message.mark,
|
|
16082
|
+
streamSid: message.stream_id ?? "telnyx-stream"
|
|
16083
|
+
};
|
|
16084
|
+
case "stop":
|
|
16085
|
+
return {
|
|
16086
|
+
event: "stop",
|
|
16087
|
+
stop: {
|
|
16088
|
+
callSid: message.stop?.call_control_id
|
|
16089
|
+
},
|
|
16090
|
+
streamSid: message.stream_id ?? "telnyx-stream"
|
|
16091
|
+
};
|
|
16092
|
+
case "dtmf":
|
|
16093
|
+
case "error":
|
|
16094
|
+
return null;
|
|
16095
|
+
}
|
|
16096
|
+
};
|
|
16097
|
+
var createTelnyxTwilioSocketAdapter = (socket) => ({
|
|
16098
|
+
close: (code, reason) => socket.close(code, reason),
|
|
16099
|
+
send: async (data) => {
|
|
16100
|
+
const message = JSON.parse(data);
|
|
16101
|
+
const telnyxMessage = message.event === "media" ? {
|
|
16102
|
+
event: "media",
|
|
16103
|
+
media: {
|
|
16104
|
+
payload: message.media.payload
|
|
16105
|
+
}
|
|
16106
|
+
} : message.event === "clear" ? {
|
|
16107
|
+
event: "clear"
|
|
16108
|
+
} : message.event === "mark" ? {
|
|
16109
|
+
event: "mark",
|
|
16110
|
+
mark: message.mark
|
|
16111
|
+
} : null;
|
|
16112
|
+
if (telnyxMessage) {
|
|
16113
|
+
await Promise.resolve(socket.send(JSON.stringify(telnyxMessage)));
|
|
16114
|
+
}
|
|
16115
|
+
}
|
|
16116
|
+
});
|
|
16117
|
+
var createTelnyxMediaStreamBridge = (socket, options) => {
|
|
16118
|
+
const bridge = createTwilioMediaStreamBridge(createTelnyxTwilioSocketAdapter(socket), {
|
|
16119
|
+
...options,
|
|
16120
|
+
onVoiceMessage: options.onVoiceMessage ? (input) => options.onVoiceMessage?.({
|
|
16121
|
+
callControlId: input.callSid,
|
|
16122
|
+
message: input.message,
|
|
16123
|
+
sessionId: input.sessionId,
|
|
16124
|
+
streamId: input.streamSid
|
|
16125
|
+
}) : undefined
|
|
16126
|
+
});
|
|
16127
|
+
return {
|
|
16128
|
+
close: bridge.close,
|
|
16129
|
+
getSessionId: bridge.getSessionId,
|
|
16130
|
+
getStreamId: bridge.getStreamSid,
|
|
16131
|
+
handleMessage: async (raw) => {
|
|
16132
|
+
const message = telnyxToTwilioMessage(parseTelnyxMessage(raw));
|
|
16133
|
+
if (message) {
|
|
16134
|
+
await bridge.handleMessage(message);
|
|
16135
|
+
}
|
|
16136
|
+
}
|
|
16137
|
+
};
|
|
16138
|
+
};
|
|
16031
16139
|
var decodeBase64 = (value) => Uint8Array.from(Buffer4.from(value, "base64"));
|
|
16032
16140
|
var verifyVoiceTelnyxWebhookSignature = async (input) => {
|
|
16033
16141
|
if (!input.publicKey) {
|
|
@@ -16182,6 +16290,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
16182
16290
|
const webhookPath = options.webhook?.path ?? "/api/voice/telnyx/webhook";
|
|
16183
16291
|
const setupPath = options.setup?.path === false ? false : options.setup?.path ?? "/api/voice/telnyx/setup";
|
|
16184
16292
|
const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/telnyx/smoke";
|
|
16293
|
+
const bridges = new WeakMap;
|
|
16185
16294
|
const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
|
|
16186
16295
|
const verify = options.webhook?.verify ?? (options.webhook?.publicKey ? (input) => verifyVoiceTelnyxWebhookSignature({
|
|
16187
16296
|
body: input.rawBody,
|
|
@@ -16219,6 +16328,31 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
16219
16328
|
"content-type": "text/xml; charset=utf-8"
|
|
16220
16329
|
}
|
|
16221
16330
|
});
|
|
16331
|
+
}).ws(streamPath, {
|
|
16332
|
+
close: async (ws, _code, reason) => {
|
|
16333
|
+
const bridge = bridges.get(ws);
|
|
16334
|
+
bridges.delete(ws);
|
|
16335
|
+
await bridge?.close(reason);
|
|
16336
|
+
},
|
|
16337
|
+
message: async (ws, raw) => {
|
|
16338
|
+
if (!options.bridge) {
|
|
16339
|
+
ws.close(1011, "Telnyx media bridge is not configured.");
|
|
16340
|
+
return;
|
|
16341
|
+
}
|
|
16342
|
+
let bridge = bridges.get(ws);
|
|
16343
|
+
if (!bridge) {
|
|
16344
|
+
bridge = createTelnyxMediaStreamBridge({
|
|
16345
|
+
close: (code, reason) => {
|
|
16346
|
+
ws.close(code, reason);
|
|
16347
|
+
},
|
|
16348
|
+
send: (data) => {
|
|
16349
|
+
ws.send(data);
|
|
16350
|
+
}
|
|
16351
|
+
}, options.bridge);
|
|
16352
|
+
bridges.set(ws, bridge);
|
|
16353
|
+
}
|
|
16354
|
+
await bridge.handleMessage(raw);
|
|
16355
|
+
}
|
|
16222
16356
|
}).use(createVoiceTelephonyWebhookRoutes({
|
|
16223
16357
|
...options.webhook ?? {},
|
|
16224
16358
|
context: options.context,
|
|
@@ -16327,6 +16461,123 @@ var createPlivoVoiceResponse = (options) => {
|
|
|
16327
16461
|
const openTag = attributes ? `<Stream ${attributes}>` : "<Stream>";
|
|
16328
16462
|
return `<?xml version="1.0" encoding="UTF-8"?><Response>${openTag}${escapeXml4(options.streamUrl)}</Stream></Response>`;
|
|
16329
16463
|
};
|
|
16464
|
+
var parsePlivoMessage = (raw) => {
|
|
16465
|
+
if (typeof raw !== "string") {
|
|
16466
|
+
return raw;
|
|
16467
|
+
}
|
|
16468
|
+
return JSON.parse(raw);
|
|
16469
|
+
};
|
|
16470
|
+
var parsePlivoExtraHeaders = (headers) => {
|
|
16471
|
+
if (!headers) {
|
|
16472
|
+
return {};
|
|
16473
|
+
}
|
|
16474
|
+
return Object.fromEntries(headers.split(/[;,]/).map((header) => header.trim()).filter(Boolean).map((header) => {
|
|
16475
|
+
const separator = header.indexOf("=");
|
|
16476
|
+
if (separator === -1) {
|
|
16477
|
+
return [header, ""];
|
|
16478
|
+
}
|
|
16479
|
+
return [
|
|
16480
|
+
header.slice(0, separator).trim(),
|
|
16481
|
+
header.slice(separator + 1).trim()
|
|
16482
|
+
];
|
|
16483
|
+
}).filter((entry) => (entry[0] ?? "").length > 0));
|
|
16484
|
+
};
|
|
16485
|
+
var plivoToTwilioMessage = (message) => {
|
|
16486
|
+
switch (message.event) {
|
|
16487
|
+
case "start": {
|
|
16488
|
+
const streamSid = message.streamId ?? message.start?.streamId ?? "plivo-stream";
|
|
16489
|
+
const callSid = message.start?.callId ?? message.start?.callUuid;
|
|
16490
|
+
const customParameters = parsePlivoExtraHeaders(message.start?.extra_headers);
|
|
16491
|
+
return {
|
|
16492
|
+
event: "start",
|
|
16493
|
+
start: {
|
|
16494
|
+
callSid,
|
|
16495
|
+
customParameters,
|
|
16496
|
+
mediaFormat: message.start?.mediaFormat,
|
|
16497
|
+
streamSid
|
|
16498
|
+
},
|
|
16499
|
+
streamSid
|
|
16500
|
+
};
|
|
16501
|
+
}
|
|
16502
|
+
case "media": {
|
|
16503
|
+
const streamSid = message.streamId ?? "plivo-stream";
|
|
16504
|
+
return {
|
|
16505
|
+
event: "media",
|
|
16506
|
+
media: {
|
|
16507
|
+
payload: message.media.payload,
|
|
16508
|
+
timestamp: message.media.timestamp,
|
|
16509
|
+
track: message.media.track ?? "inbound"
|
|
16510
|
+
},
|
|
16511
|
+
streamSid
|
|
16512
|
+
};
|
|
16513
|
+
}
|
|
16514
|
+
case "playedStream":
|
|
16515
|
+
return {
|
|
16516
|
+
event: "mark",
|
|
16517
|
+
mark: {
|
|
16518
|
+
name: message.name
|
|
16519
|
+
},
|
|
16520
|
+
streamSid: message.streamId ?? "plivo-stream"
|
|
16521
|
+
};
|
|
16522
|
+
case "stop":
|
|
16523
|
+
return {
|
|
16524
|
+
event: "stop",
|
|
16525
|
+
stop: {
|
|
16526
|
+
callSid: message.stop?.callId ?? message.stop?.callUuid
|
|
16527
|
+
},
|
|
16528
|
+
streamSid: message.streamId ?? "plivo-stream"
|
|
16529
|
+
};
|
|
16530
|
+
case "clearedAudio":
|
|
16531
|
+
case "dtmf":
|
|
16532
|
+
return null;
|
|
16533
|
+
}
|
|
16534
|
+
};
|
|
16535
|
+
var createPlivoTwilioSocketAdapter = (socket) => ({
|
|
16536
|
+
close: (code, reason) => socket.close(code, reason),
|
|
16537
|
+
send: async (data) => {
|
|
16538
|
+
const message = JSON.parse(data);
|
|
16539
|
+
const plivoMessage = message.event === "media" ? {
|
|
16540
|
+
event: "playAudio",
|
|
16541
|
+
media: {
|
|
16542
|
+
contentType: "audio/x-mulaw",
|
|
16543
|
+
payload: message.media.payload,
|
|
16544
|
+
sampleRate: 8000
|
|
16545
|
+
}
|
|
16546
|
+
} : message.event === "clear" ? {
|
|
16547
|
+
event: "clearAudio",
|
|
16548
|
+
streamId: message.streamSid
|
|
16549
|
+
} : message.event === "mark" ? {
|
|
16550
|
+
event: "checkpoint",
|
|
16551
|
+
name: message.mark.name,
|
|
16552
|
+
streamId: message.streamSid
|
|
16553
|
+
} : null;
|
|
16554
|
+
if (plivoMessage) {
|
|
16555
|
+
await Promise.resolve(socket.send(JSON.stringify(plivoMessage)));
|
|
16556
|
+
}
|
|
16557
|
+
}
|
|
16558
|
+
});
|
|
16559
|
+
var createPlivoMediaStreamBridge = (socket, options) => {
|
|
16560
|
+
const bridge = createTwilioMediaStreamBridge(createPlivoTwilioSocketAdapter(socket), {
|
|
16561
|
+
...options,
|
|
16562
|
+
onVoiceMessage: options.onVoiceMessage ? (input) => options.onVoiceMessage?.({
|
|
16563
|
+
callId: input.callSid,
|
|
16564
|
+
message: input.message,
|
|
16565
|
+
sessionId: input.sessionId,
|
|
16566
|
+
streamId: input.streamSid
|
|
16567
|
+
}) : undefined
|
|
16568
|
+
});
|
|
16569
|
+
return {
|
|
16570
|
+
close: bridge.close,
|
|
16571
|
+
getSessionId: bridge.getSessionId,
|
|
16572
|
+
getStreamId: bridge.getStreamSid,
|
|
16573
|
+
handleMessage: async (raw) => {
|
|
16574
|
+
const message = plivoToTwilioMessage(parsePlivoMessage(raw));
|
|
16575
|
+
if (message) {
|
|
16576
|
+
await bridge.handleMessage(message);
|
|
16577
|
+
}
|
|
16578
|
+
}
|
|
16579
|
+
};
|
|
16580
|
+
};
|
|
16330
16581
|
var toBase642 = (bytes) => Buffer5.from(new Uint8Array(bytes)).toString("base64");
|
|
16331
16582
|
var timingSafeEqual3 = (left, right) => {
|
|
16332
16583
|
const encoder = new TextEncoder;
|
|
@@ -16507,6 +16758,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
16507
16758
|
const webhookPath = options.webhook?.path ?? "/api/voice/plivo/webhook";
|
|
16508
16759
|
const setupPath = options.setup?.path === false ? false : options.setup?.path ?? "/api/voice/plivo/setup";
|
|
16509
16760
|
const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/plivo/smoke";
|
|
16761
|
+
const bridges = new WeakMap;
|
|
16510
16762
|
const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
|
|
16511
16763
|
const verificationUrl = options.webhook?.verificationUrl;
|
|
16512
16764
|
const verify = options.webhook?.verify ?? (options.webhook?.authToken ? (input) => verifyVoicePlivoWebhookSignature({
|
|
@@ -16548,6 +16800,31 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
16548
16800
|
"content-type": "text/xml; charset=utf-8"
|
|
16549
16801
|
}
|
|
16550
16802
|
});
|
|
16803
|
+
}).ws(streamPath, {
|
|
16804
|
+
close: async (ws, _code, reason) => {
|
|
16805
|
+
const bridge = bridges.get(ws);
|
|
16806
|
+
bridges.delete(ws);
|
|
16807
|
+
await bridge?.close(reason);
|
|
16808
|
+
},
|
|
16809
|
+
message: async (ws, raw) => {
|
|
16810
|
+
if (!options.bridge) {
|
|
16811
|
+
ws.close(1011, "Plivo media bridge is not configured.");
|
|
16812
|
+
return;
|
|
16813
|
+
}
|
|
16814
|
+
let bridge = bridges.get(ws);
|
|
16815
|
+
if (!bridge) {
|
|
16816
|
+
bridge = createPlivoMediaStreamBridge({
|
|
16817
|
+
close: (code, reason) => {
|
|
16818
|
+
ws.close(code, reason);
|
|
16819
|
+
},
|
|
16820
|
+
send: (data) => {
|
|
16821
|
+
ws.send(data);
|
|
16822
|
+
}
|
|
16823
|
+
}, options.bridge);
|
|
16824
|
+
bridges.set(ws, bridge);
|
|
16825
|
+
}
|
|
16826
|
+
await bridge.handleMessage(raw);
|
|
16827
|
+
}
|
|
16551
16828
|
}).use(createVoiceTelephonyWebhookRoutes({
|
|
16552
16829
|
...options.webhook ?? {},
|
|
16553
16830
|
context: options.context,
|
|
@@ -17013,6 +17290,7 @@ export {
|
|
|
17013
17290
|
createTwilioMediaStreamBridge,
|
|
17014
17291
|
createTelnyxVoiceRoutes,
|
|
17015
17292
|
createTelnyxVoiceResponse,
|
|
17293
|
+
createTelnyxMediaStreamBridge,
|
|
17016
17294
|
createStoredVoiceOpsTask,
|
|
17017
17295
|
createStoredVoiceIntegrationEvent,
|
|
17018
17296
|
createStoredVoiceExternalObjectMap,
|
|
@@ -17020,6 +17298,7 @@ export {
|
|
|
17020
17298
|
createRiskyTurnCorrectionHandler,
|
|
17021
17299
|
createPlivoVoiceRoutes,
|
|
17022
17300
|
createPlivoVoiceResponse,
|
|
17301
|
+
createPlivoMediaStreamBridge,
|
|
17023
17302
|
createPhraseHintCorrectionHandler,
|
|
17024
17303
|
createOpenAIVoiceAssistantModel,
|
|
17025
17304
|
createMemoryVoiceTelephonyWebhookIdempotencyStore,
|
|
@@ -1,7 +1,95 @@
|
|
|
1
1
|
import { Elysia } from 'elysia';
|
|
2
2
|
import { type VoiceTelephonyContractReport, type VoiceTelephonySetupStatus, type VoiceTelephonySmokeCheck, type VoiceTelephonySmokeReport } from './contract';
|
|
3
3
|
import { type VoiceTelephonyOutcomePolicy, type VoiceTelephonyWebhookRoutesOptions, type VoiceTelephonyWebhookVerificationResult } from '../telephonyOutcome';
|
|
4
|
-
import type { VoiceSessionRecord } from '../types';
|
|
4
|
+
import type { VoiceServerMessage, VoiceSessionRecord } from '../types';
|
|
5
|
+
import { type TwilioMediaStreamBridgeOptions } from './twilio';
|
|
6
|
+
export type PlivoInboundMessage = {
|
|
7
|
+
event: 'start';
|
|
8
|
+
sequenceNumber?: number;
|
|
9
|
+
start?: {
|
|
10
|
+
callId?: string;
|
|
11
|
+
callUuid?: string;
|
|
12
|
+
extra_headers?: string;
|
|
13
|
+
mediaFormat?: {
|
|
14
|
+
channels?: number;
|
|
15
|
+
encoding?: string;
|
|
16
|
+
sampleRate?: number;
|
|
17
|
+
};
|
|
18
|
+
streamId?: string;
|
|
19
|
+
};
|
|
20
|
+
streamId?: string;
|
|
21
|
+
} | {
|
|
22
|
+
event: 'media';
|
|
23
|
+
media: {
|
|
24
|
+
payload: string;
|
|
25
|
+
timestamp?: string;
|
|
26
|
+
track?: 'inbound' | 'outbound';
|
|
27
|
+
};
|
|
28
|
+
sequenceNumber?: number;
|
|
29
|
+
streamId?: string;
|
|
30
|
+
} | {
|
|
31
|
+
event: 'dtmf';
|
|
32
|
+
dtmf?: {
|
|
33
|
+
digit?: string;
|
|
34
|
+
timestamp?: string;
|
|
35
|
+
track?: string;
|
|
36
|
+
};
|
|
37
|
+
sequenceNumber?: number;
|
|
38
|
+
streamId?: string;
|
|
39
|
+
} | {
|
|
40
|
+
event: 'playedStream';
|
|
41
|
+
name?: string;
|
|
42
|
+
sequenceNumber?: number;
|
|
43
|
+
streamId?: string;
|
|
44
|
+
} | {
|
|
45
|
+
event: 'clearedAudio';
|
|
46
|
+
sequenceNumber?: number;
|
|
47
|
+
streamId?: string;
|
|
48
|
+
} | {
|
|
49
|
+
event: 'stop';
|
|
50
|
+
sequenceNumber?: number;
|
|
51
|
+
stop?: {
|
|
52
|
+
callId?: string;
|
|
53
|
+
callUuid?: string;
|
|
54
|
+
};
|
|
55
|
+
streamId?: string;
|
|
56
|
+
};
|
|
57
|
+
export type PlivoOutboundPlayAudioMessage = {
|
|
58
|
+
event: 'playAudio';
|
|
59
|
+
media: {
|
|
60
|
+
contentType: 'audio/x-mulaw';
|
|
61
|
+
payload: string;
|
|
62
|
+
sampleRate: 8000;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
export type PlivoOutboundClearAudioMessage = {
|
|
66
|
+
event: 'clearAudio';
|
|
67
|
+
streamId?: string;
|
|
68
|
+
};
|
|
69
|
+
export type PlivoOutboundCheckpointMessage = {
|
|
70
|
+
event: 'checkpoint';
|
|
71
|
+
name: string;
|
|
72
|
+
streamId?: string;
|
|
73
|
+
};
|
|
74
|
+
export type PlivoOutboundMessage = PlivoOutboundPlayAudioMessage | PlivoOutboundClearAudioMessage | PlivoOutboundCheckpointMessage;
|
|
75
|
+
export type PlivoMediaStreamSocket = {
|
|
76
|
+
close: (code?: number, reason?: string) => void | Promise<void>;
|
|
77
|
+
send: (data: string) => void | Promise<void>;
|
|
78
|
+
};
|
|
79
|
+
export type PlivoMediaStreamBridgeOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = Omit<TwilioMediaStreamBridgeOptions<TContext, TSession, TResult>, 'onVoiceMessage'> & {
|
|
80
|
+
onVoiceMessage?: (input: {
|
|
81
|
+
callId?: string;
|
|
82
|
+
message: VoiceServerMessage<TResult>;
|
|
83
|
+
sessionId: string;
|
|
84
|
+
streamId?: string;
|
|
85
|
+
}) => Promise<void> | void;
|
|
86
|
+
};
|
|
87
|
+
export type PlivoMediaStreamBridge = {
|
|
88
|
+
close: (reason?: string) => Promise<void>;
|
|
89
|
+
getSessionId: () => string | null;
|
|
90
|
+
getStreamId: () => string | null;
|
|
91
|
+
handleMessage: (raw: string | PlivoInboundMessage) => Promise<void>;
|
|
92
|
+
};
|
|
5
93
|
export type PlivoVoiceResponseOptions = {
|
|
6
94
|
audioTrack?: 'both' | 'inbound' | 'outbound';
|
|
7
95
|
bidirectional?: boolean;
|
|
@@ -53,6 +141,7 @@ export type PlivoVoiceRoutesOptions<TContext = unknown, TSession extends VoiceSe
|
|
|
53
141
|
streamPath: string;
|
|
54
142
|
}) => Promise<string> | string);
|
|
55
143
|
};
|
|
144
|
+
bridge?: PlivoMediaStreamBridgeOptions<TContext, TSession, TResult>;
|
|
56
145
|
context?: TContext;
|
|
57
146
|
name?: string;
|
|
58
147
|
outcomePolicy?: VoiceTelephonyOutcomePolicy;
|
|
@@ -70,6 +159,7 @@ export type PlivoVoiceRoutesOptions<TContext = unknown, TSession extends VoiceSe
|
|
|
70
159
|
};
|
|
71
160
|
};
|
|
72
161
|
export declare const createPlivoVoiceResponse: (options: PlivoVoiceResponseOptions) => string;
|
|
162
|
+
export declare const createPlivoMediaStreamBridge: <TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown>(socket: PlivoMediaStreamSocket, options: PlivoMediaStreamBridgeOptions<TContext, TSession, TResult>) => PlivoMediaStreamBridge;
|
|
73
163
|
export declare const signVoicePlivoWebhook: (input: {
|
|
74
164
|
authToken: string;
|
|
75
165
|
body?: unknown;
|
|
@@ -121,6 +211,16 @@ export declare const createPlivoVoiceRoutes: <TContext = unknown, TSession exten
|
|
|
121
211
|
};
|
|
122
212
|
};
|
|
123
213
|
};
|
|
214
|
+
} & {
|
|
215
|
+
[x: string]: {
|
|
216
|
+
subscribe: {
|
|
217
|
+
body: unknown;
|
|
218
|
+
params: {};
|
|
219
|
+
query: unknown;
|
|
220
|
+
headers: unknown;
|
|
221
|
+
response: {};
|
|
222
|
+
};
|
|
223
|
+
};
|
|
124
224
|
} & {
|
|
125
225
|
[x: string]: {
|
|
126
226
|
post: {
|
|
@@ -1,7 +1,103 @@
|
|
|
1
1
|
import { Elysia } from 'elysia';
|
|
2
2
|
import { type VoiceTelephonyContractReport, type VoiceTelephonySetupStatus, type VoiceTelephonySmokeCheck, type VoiceTelephonySmokeReport } from './contract';
|
|
3
3
|
import { type VoiceTelephonyOutcomePolicy, type VoiceTelephonyWebhookRoutesOptions, type VoiceTelephonyWebhookVerificationResult } from '../telephonyOutcome';
|
|
4
|
-
import type { VoiceSessionRecord } from '../types';
|
|
4
|
+
import type { VoiceServerMessage, VoiceSessionRecord } from '../types';
|
|
5
|
+
import { type TwilioMediaStreamBridgeOptions } from './twilio';
|
|
6
|
+
export type TelnyxMediaPayload = {
|
|
7
|
+
chunk?: string;
|
|
8
|
+
payload: string;
|
|
9
|
+
timestamp?: string;
|
|
10
|
+
track?: 'inbound' | 'outbound' | 'inbound_track' | 'outbound_track';
|
|
11
|
+
};
|
|
12
|
+
export type TelnyxInboundMessage = {
|
|
13
|
+
event: 'connected';
|
|
14
|
+
version?: string;
|
|
15
|
+
} | {
|
|
16
|
+
event: 'start';
|
|
17
|
+
sequence_number?: string;
|
|
18
|
+
start?: {
|
|
19
|
+
call_control_id?: string;
|
|
20
|
+
call_leg_id?: string;
|
|
21
|
+
call_session_id?: string;
|
|
22
|
+
custom_parameters?: Record<string, string>;
|
|
23
|
+
media_format?: {
|
|
24
|
+
channels?: number;
|
|
25
|
+
encoding?: string;
|
|
26
|
+
sample_rate?: number;
|
|
27
|
+
};
|
|
28
|
+
user_id?: string;
|
|
29
|
+
};
|
|
30
|
+
stream_id?: string;
|
|
31
|
+
} | {
|
|
32
|
+
event: 'media';
|
|
33
|
+
media: TelnyxMediaPayload;
|
|
34
|
+
sequence_number?: string;
|
|
35
|
+
stream_id?: string;
|
|
36
|
+
} | {
|
|
37
|
+
event: 'mark';
|
|
38
|
+
mark?: {
|
|
39
|
+
name?: string;
|
|
40
|
+
};
|
|
41
|
+
sequence_number?: string;
|
|
42
|
+
stream_id?: string;
|
|
43
|
+
} | {
|
|
44
|
+
event: 'dtmf';
|
|
45
|
+
dtmf?: {
|
|
46
|
+
digit?: string;
|
|
47
|
+
};
|
|
48
|
+
sequence_number?: string;
|
|
49
|
+
stream_id?: string;
|
|
50
|
+
} | {
|
|
51
|
+
event: 'error';
|
|
52
|
+
payload?: {
|
|
53
|
+
code?: number;
|
|
54
|
+
detail?: string;
|
|
55
|
+
title?: string;
|
|
56
|
+
};
|
|
57
|
+
stream_id?: string;
|
|
58
|
+
} | {
|
|
59
|
+
event: 'stop';
|
|
60
|
+
sequence_number?: string;
|
|
61
|
+
stop?: {
|
|
62
|
+
call_control_id?: string;
|
|
63
|
+
user_id?: string;
|
|
64
|
+
};
|
|
65
|
+
stream_id?: string;
|
|
66
|
+
};
|
|
67
|
+
export type TelnyxOutboundMediaMessage = {
|
|
68
|
+
event: 'media';
|
|
69
|
+
media: {
|
|
70
|
+
payload: string;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
export type TelnyxOutboundClearMessage = {
|
|
74
|
+
event: 'clear';
|
|
75
|
+
};
|
|
76
|
+
export type TelnyxOutboundMarkMessage = {
|
|
77
|
+
event: 'mark';
|
|
78
|
+
mark: {
|
|
79
|
+
name: string;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
export type TelnyxOutboundMessage = TelnyxOutboundMediaMessage | TelnyxOutboundClearMessage | TelnyxOutboundMarkMessage;
|
|
83
|
+
export type TelnyxMediaStreamSocket = {
|
|
84
|
+
close: (code?: number, reason?: string) => void | Promise<void>;
|
|
85
|
+
send: (data: string) => void | Promise<void>;
|
|
86
|
+
};
|
|
87
|
+
export type TelnyxMediaStreamBridgeOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = Omit<TwilioMediaStreamBridgeOptions<TContext, TSession, TResult>, 'onVoiceMessage'> & {
|
|
88
|
+
onVoiceMessage?: (input: {
|
|
89
|
+
callControlId?: string;
|
|
90
|
+
message: VoiceServerMessage<TResult>;
|
|
91
|
+
sessionId: string;
|
|
92
|
+
streamId?: string;
|
|
93
|
+
}) => Promise<void> | void;
|
|
94
|
+
};
|
|
95
|
+
export type TelnyxMediaStreamBridge = {
|
|
96
|
+
close: (reason?: string) => Promise<void>;
|
|
97
|
+
getSessionId: () => string | null;
|
|
98
|
+
getStreamId: () => string | null;
|
|
99
|
+
handleMessage: (raw: string | TelnyxInboundMessage) => Promise<void>;
|
|
100
|
+
};
|
|
5
101
|
export type TelnyxVoiceResponseOptions = {
|
|
6
102
|
bidirectionalCodec?: 'AMR-WB' | 'G722' | 'OPUS' | 'PCMA' | 'PCMU';
|
|
7
103
|
bidirectionalMode?: 'mp3' | 'rtp';
|
|
@@ -38,6 +134,7 @@ export type TelnyxVoiceSmokeOptions = {
|
|
|
38
134
|
title?: string;
|
|
39
135
|
};
|
|
40
136
|
export type TelnyxVoiceRoutesOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = {
|
|
137
|
+
bridge?: TelnyxMediaStreamBridgeOptions<TContext, TSession, TResult>;
|
|
41
138
|
context?: TContext;
|
|
42
139
|
name?: string;
|
|
43
140
|
outcomePolicy?: VoiceTelephonyOutcomePolicy;
|
|
@@ -61,6 +158,7 @@ export type TelnyxVoiceRoutesOptions<TContext = unknown, TSession extends VoiceS
|
|
|
61
158
|
};
|
|
62
159
|
};
|
|
63
160
|
export declare const createTelnyxVoiceResponse: (options: TelnyxVoiceResponseOptions) => string;
|
|
161
|
+
export declare const createTelnyxMediaStreamBridge: <TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown>(socket: TelnyxMediaStreamSocket, options: TelnyxMediaStreamBridgeOptions<TContext, TSession, TResult>) => TelnyxMediaStreamBridge;
|
|
64
162
|
export declare const verifyVoiceTelnyxWebhookSignature: (input: {
|
|
65
163
|
body: string;
|
|
66
164
|
headers: Headers;
|
|
@@ -106,6 +204,16 @@ export declare const createTelnyxVoiceRoutes: <TContext = unknown, TSession exte
|
|
|
106
204
|
};
|
|
107
205
|
};
|
|
108
206
|
};
|
|
207
|
+
} & {
|
|
208
|
+
[x: string]: {
|
|
209
|
+
subscribe: {
|
|
210
|
+
body: unknown;
|
|
211
|
+
params: {};
|
|
212
|
+
query: unknown;
|
|
213
|
+
headers: unknown;
|
|
214
|
+
response: {};
|
|
215
|
+
};
|
|
216
|
+
};
|
|
109
217
|
} & {
|
|
110
218
|
[x: string]: {
|
|
111
219
|
post: {
|