@absolutejs/voice 0.0.22-beta.80 → 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
@@ -11223,6 +11223,8 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
11223
11223
  }
11224
11224
  throw error;
11225
11225
  }
11226
+ }, {
11227
+ parse: "none"
11226
11228
  });
11227
11229
  };
11228
11230
  // src/fileStore.ts
@@ -16026,6 +16028,114 @@ var createTelnyxVoiceResponse = (options) => {
16026
16028
  ].filter((value) => Boolean(value)).join(" ");
16027
16029
  return `<?xml version="1.0" encoding="UTF-8"?><Response><Start><Stream ${attributes} /></Start></Response>`;
16028
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
+ };
16029
16139
  var decodeBase64 = (value) => Uint8Array.from(Buffer4.from(value, "base64"));
16030
16140
  var verifyVoiceTelnyxWebhookSignature = async (input) => {
16031
16141
  if (!input.publicKey) {
@@ -16180,6 +16290,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
16180
16290
  const webhookPath = options.webhook?.path ?? "/api/voice/telnyx/webhook";
16181
16291
  const setupPath = options.setup?.path === false ? false : options.setup?.path ?? "/api/voice/telnyx/setup";
16182
16292
  const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/telnyx/smoke";
16293
+ const bridges = new WeakMap;
16183
16294
  const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
16184
16295
  const verify = options.webhook?.verify ?? (options.webhook?.publicKey ? (input) => verifyVoiceTelnyxWebhookSignature({
16185
16296
  body: input.rawBody,
@@ -16217,6 +16328,31 @@ var createTelnyxVoiceRoutes = (options = {}) => {
16217
16328
  "content-type": "text/xml; charset=utf-8"
16218
16329
  }
16219
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
+ }
16220
16356
  }).use(createVoiceTelephonyWebhookRoutes({
16221
16357
  ...options.webhook ?? {},
16222
16358
  context: options.context,
@@ -16325,6 +16461,123 @@ var createPlivoVoiceResponse = (options) => {
16325
16461
  const openTag = attributes ? `<Stream ${attributes}>` : "<Stream>";
16326
16462
  return `<?xml version="1.0" encoding="UTF-8"?><Response>${openTag}${escapeXml4(options.streamUrl)}</Stream></Response>`;
16327
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
+ };
16328
16581
  var toBase642 = (bytes) => Buffer5.from(new Uint8Array(bytes)).toString("base64");
16329
16582
  var timingSafeEqual3 = (left, right) => {
16330
16583
  const encoder = new TextEncoder;
@@ -16505,6 +16758,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
16505
16758
  const webhookPath = options.webhook?.path ?? "/api/voice/plivo/webhook";
16506
16759
  const setupPath = options.setup?.path === false ? false : options.setup?.path ?? "/api/voice/plivo/setup";
16507
16760
  const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/plivo/smoke";
16761
+ const bridges = new WeakMap;
16508
16762
  const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
16509
16763
  const verificationUrl = options.webhook?.verificationUrl;
16510
16764
  const verify = options.webhook?.verify ?? (options.webhook?.authToken ? (input) => verifyVoicePlivoWebhookSignature({
@@ -16546,6 +16800,31 @@ var createPlivoVoiceRoutes = (options = {}) => {
16546
16800
  "content-type": "text/xml; charset=utf-8"
16547
16801
  }
16548
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
+ }
16549
16828
  }).use(createVoiceTelephonyWebhookRoutes({
16550
16829
  ...options.webhook ?? {},
16551
16830
  context: options.context,
@@ -17011,6 +17290,7 @@ export {
17011
17290
  createTwilioMediaStreamBridge,
17012
17291
  createTelnyxVoiceRoutes,
17013
17292
  createTelnyxVoiceResponse,
17293
+ createTelnyxMediaStreamBridge,
17014
17294
  createStoredVoiceOpsTask,
17015
17295
  createStoredVoiceIntegrationEvent,
17016
17296
  createStoredVoiceExternalObjectMap,
@@ -17018,6 +17298,7 @@ export {
17018
17298
  createRiskyTurnCorrectionHandler,
17019
17299
  createPlivoVoiceRoutes,
17020
17300
  createPlivoVoiceResponse,
17301
+ createPlivoMediaStreamBridge,
17021
17302
  createPhraseHintCorrectionHandler,
17022
17303
  createOpenAIVoiceAssistantModel,
17023
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: {
@@ -8533,6 +8533,8 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
8533
8533
  }
8534
8534
  throw error;
8535
8535
  }
8536
+ }, {
8537
+ parse: "none"
8536
8538
  });
8537
8539
  };
8538
8540
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.80",
3
+ "version": "0.0.22-beta.82",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",