@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 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: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.81",
3
+ "version": "0.0.22-beta.82",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",