@kognitivedev/telephony 0.2.29

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.
@@ -0,0 +1,2 @@
1
+
2
+ $ tsc
@@ -0,0 +1,13 @@
1
+ $ vitest run
2
+
3
+ RUN v3.2.4 /Users/vserifsaglam/work/memory-experiment/packages/telephony
4
+
5
+ ✓ src/__tests__/registry.test.ts (2 tests) 4ms
6
+ ✓ src/__tests__/twilio.test.ts (4 tests) 6ms
7
+ ✓ src/__tests__/audio.test.ts (3 tests) 19ms
8
+
9
+ Test Files 3 passed (3)
10
+ Tests 9 passed (9)
11
+ Start at 17:30:12
12
+ Duration 622ms (transform 163ms, setup 0ms, collect 246ms, tests 29ms, environment 0ms, prepare 732ms)
13
+
package/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # @kognitivedev/telephony
2
+
3
+ ## 0.2.29
4
+
5
+ ### Patch Changes
6
+
7
+ - release
8
+
9
+ - Updated dependencies []:
10
+ - @kognitivedev/voice@0.2.29
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # Kognitive Telephony
2
+
3
+ `@kognitivedev/telephony` is the Node-side call-control package for Kognitive voice agents. It handles phone-provider ingress, outbound dialing, media-stream message normalization, and audio codec helpers. Cloud Voice uses it underneath for PSTN/SIP channels.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ bun add @kognitivedev/telephony
9
+ ```
10
+
11
+ ## Inbound Calls
12
+
13
+ ```ts
14
+ import { createTwilioInboundCallResponse } from "@kognitivedev/telephony/twilio";
15
+
16
+ const result = await createTwilioInboundCallResponse({
17
+ service: telephony,
18
+ authToken: process.env.TWILIO_AUTH_TOKEN,
19
+ resourceId: { userId: "caller:+15550001111" },
20
+ buildStreamUrl: (session) =>
21
+ `wss://api.example.com/api/cloud/voice/telephony/twilio/media/${session.sessionId}`,
22
+ }, {
23
+ url: "https://api.example.com/api/cloud/voice/telephony/twilio/inbound",
24
+ headers: { "x-twilio-signature": request.headers.get("x-twilio-signature") ?? "" },
25
+ params,
26
+ });
27
+
28
+ return new Response(result.twiml, {
29
+ headers: { "Content-Type": "text/xml" },
30
+ });
31
+ ```
32
+
33
+ ## Outbound Calls
34
+
35
+ ```ts
36
+ import { createTwilioOutboundCall } from "@kognitivedev/telephony/twilio";
37
+
38
+ const call = await createTwilioOutboundCall({
39
+ accountSid: process.env.TWILIO_ACCOUNT_SID!,
40
+ authToken: process.env.TWILIO_AUTH_TOKEN!,
41
+ from: "+15550001111",
42
+ to: "+15550002222",
43
+ answerUrl: "https://api.example.com/api/cloud/voice/telephony/twilio/outbound-answer/session_123",
44
+ statusCallbackUrl: "https://api.example.com/api/cloud/voice/telephony/twilio/status",
45
+ });
46
+ ```
47
+
48
+ ## Runtime Tool Calls
49
+
50
+ Phone calls do not have a browser runtime. Cloud Voice phone tools should be
51
+ normal Kognitive runtime tools, synced from the customer's Kognitive instance
52
+ and executed by the Cloud Voice backend during the call.
53
+
54
+ ```ts
55
+ import { Kognitive } from "@kognitivedev/core";
56
+ import { createTool } from "@kognitivedev/tools";
57
+ import { z } from "zod";
58
+
59
+ const lookupOrder = createTool({
60
+ id: "lookup_order",
61
+ description: "Look up an order",
62
+ inputSchema: z.object({ orderNumber: z.string() }),
63
+ execute: async ({ orderNumber }) => db.orders.findByNumber(orderNumber),
64
+ });
65
+
66
+ export const kognitive = new Kognitive({
67
+ apiKey: process.env.KOGNITIVE_API_KEY,
68
+ baseUrl: process.env.KOGNITIVE_API_URL,
69
+ tools: [lookupOrder],
70
+ });
71
+ ```
72
+
73
+ The Cloud Voice media bridge owns tracing and provider tool-result delivery.
74
+ Application code does not call `appendCloudVoiceEvent()` or `sendToolResult()`
75
+ directly.
76
+
77
+ ## Phone Control Adapter
78
+
79
+ Cloud Voice phone-control tools use provider adapters. Twilio call control lives
80
+ in this package; Cloud Voice orchestration receives it as a plain structural
81
+ adapter.
82
+
83
+ ```ts
84
+ import { createTwilioPhoneControlAdapter } from "@kognitivedev/telephony/twilio";
85
+
86
+ const adapter = createTwilioPhoneControlAdapter({
87
+ accountSid: process.env.TWILIO_ACCOUNT_SID!,
88
+ authToken: process.env.TWILIO_AUTH_TOKEN!,
89
+ });
90
+
91
+ await adapter.hangUpCall({
92
+ providerCallId: "CA...",
93
+ reason: "caller said goodbye",
94
+ });
95
+ ```
96
+
97
+ The adapter completes the active Twilio call through the Calls REST API with
98
+ `Status=completed`.
@@ -0,0 +1,4 @@
1
+ export interface Pcm16ResampleOptions {
2
+ filterRadius?: number;
3
+ }
4
+ export declare function resamplePcm16WindowedSinc(samples: Int16Array, sourceRate: number, targetRate: number, options?: Pcm16ResampleOptions): Int16Array<ArrayBuffer>;
package/dist/audio.js ADDED
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resamplePcm16WindowedSinc = resamplePcm16WindowedSinc;
4
+ const DEFAULT_FILTER_RADIUS = 18;
5
+ const DOWNSAMPLE_CUTOFF_HEADROOM = 0.94;
6
+ function sinc(value) {
7
+ if (Math.abs(value) < 1e-8)
8
+ return 1;
9
+ const radians = Math.PI * value;
10
+ return Math.sin(radians) / radians;
11
+ }
12
+ function blackmanWindow(distance, width) {
13
+ if (width <= 0 || distance > width)
14
+ return 0;
15
+ const ratio = distance / width;
16
+ return 0.42 + (0.5 * Math.cos(Math.PI * ratio)) + (0.08 * Math.cos(2 * Math.PI * ratio));
17
+ }
18
+ function clampPcm16(value) {
19
+ if (value > 32767)
20
+ return 32767;
21
+ if (value < -32768)
22
+ return -32768;
23
+ return Math.round(value);
24
+ }
25
+ function resamplePcm16WindowedSinc(samples, sourceRate, targetRate, options = {}) {
26
+ var _a, _b;
27
+ if (sourceRate <= 0 || targetRate <= 0)
28
+ throw new Error("Sample rates must be positive");
29
+ if (samples.length === 0 || sourceRate === targetRate)
30
+ return new Int16Array(samples);
31
+ const outputLength = Math.max(1, Math.round((samples.length * targetRate) / sourceRate));
32
+ const output = new Int16Array(outputLength);
33
+ const sourcePerTarget = sourceRate / targetRate;
34
+ const cutoff = Math.min(1, targetRate / sourceRate) * DOWNSAMPLE_CUTOFF_HEADROOM;
35
+ const filterRadius = Math.max(4, Math.round((_a = options.filterRadius) !== null && _a !== void 0 ? _a : DEFAULT_FILTER_RADIUS));
36
+ const kernelWidth = filterRadius / cutoff;
37
+ for (let outputIndex = 0; outputIndex < outputLength; outputIndex += 1) {
38
+ const sourcePosition = outputIndex * sourcePerTarget;
39
+ const firstInputIndex = Math.max(0, Math.ceil(sourcePosition - kernelWidth));
40
+ const lastInputIndex = Math.min(samples.length - 1, Math.floor(sourcePosition + kernelWidth));
41
+ let weightedSum = 0;
42
+ let weightTotal = 0;
43
+ for (let inputIndex = firstInputIndex; inputIndex <= lastInputIndex; inputIndex += 1) {
44
+ const distance = sourcePosition - inputIndex;
45
+ const window = blackmanWindow(Math.abs(distance), kernelWidth);
46
+ if (window === 0)
47
+ continue;
48
+ const weight = cutoff * sinc(cutoff * distance) * window;
49
+ weightedSum += ((_b = samples[inputIndex]) !== null && _b !== void 0 ? _b : 0) * weight;
50
+ weightTotal += weight;
51
+ }
52
+ output[outputIndex] = clampPcm16(weightTotal === 0 ? 0 : weightedSum / weightTotal);
53
+ }
54
+ return output;
55
+ }
@@ -0,0 +1,6 @@
1
+ export * from "./types";
2
+ export * from "./audio";
3
+ export * from "./rtp";
4
+ export * from "./twilio";
5
+ export * from "./registry";
6
+ export { createVoiceTelephonyService, type CreateVoiceTelephonySessionRequest, type EndVoiceTelephonySessionOptions, type UpdateVoiceTelephonySessionOptions, type VoiceCallContext, type VoiceCallDirection, type VoiceCallProvider, type VoiceCallTransport, type VoiceTelephonyAgentResolutionContext, type VoiceTelephonyAgentResolver, type VoiceTelephonyAudioFrame, type VoiceTelephonyProviderEvent, type VoiceTelephonyService, type VoiceTelephonyServiceConfig, type VoiceTelephonySessionRecord, } from "@kognitivedev/voice/telephony";
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.createVoiceTelephonyService = void 0;
18
+ __exportStar(require("./types"), exports);
19
+ __exportStar(require("./audio"), exports);
20
+ __exportStar(require("./rtp"), exports);
21
+ __exportStar(require("./twilio"), exports);
22
+ __exportStar(require("./registry"), exports);
23
+ var telephony_1 = require("@kognitivedev/voice/telephony");
24
+ Object.defineProperty(exports, "createVoiceTelephonyService", { enumerable: true, get: function () { return telephony_1.createVoiceTelephonyService; } });
@@ -0,0 +1,15 @@
1
+ import type { TelephonyCallControlAdapter, TelephonyProvider, TelephonyProviderAdapter } from "./types";
2
+ export interface TelephonyAdapterRegistry {
3
+ registerProvider(adapter: TelephonyProviderAdapter): void;
4
+ registerCallControl(adapter: TelephonyCallControlAdapter): void;
5
+ getProvider(provider: TelephonyProvider): TelephonyProviderAdapter | undefined;
6
+ getCallControl(provider: TelephonyProvider): TelephonyCallControlAdapter | undefined;
7
+ requireProvider(provider: TelephonyProvider): TelephonyProviderAdapter;
8
+ requireCallControl(provider: TelephonyProvider): TelephonyCallControlAdapter;
9
+ listProviders(): TelephonyProvider[];
10
+ listCallControlProviders(): TelephonyProvider[];
11
+ }
12
+ export declare function createTelephonyAdapterRegistry(input?: {
13
+ providers?: TelephonyProviderAdapter[];
14
+ callControls?: TelephonyCallControlAdapter[];
15
+ }): TelephonyAdapterRegistry;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createTelephonyAdapterRegistry = createTelephonyAdapterRegistry;
4
+ function createTelephonyAdapterRegistry(input = {}) {
5
+ var _a, _b;
6
+ const providers = new Map();
7
+ const callControls = new Map();
8
+ const registry = {
9
+ registerProvider(adapter) {
10
+ providers.set(adapter.provider, adapter);
11
+ },
12
+ registerCallControl(adapter) {
13
+ callControls.set(adapter.provider, adapter);
14
+ },
15
+ getProvider(provider) {
16
+ return providers.get(provider);
17
+ },
18
+ getCallControl(provider) {
19
+ return callControls.get(provider);
20
+ },
21
+ requireProvider(provider) {
22
+ const adapter = providers.get(provider);
23
+ if (!adapter)
24
+ throw new Error(`Telephony provider "${provider}" is not registered`);
25
+ return adapter;
26
+ },
27
+ requireCallControl(provider) {
28
+ const adapter = callControls.get(provider);
29
+ if (!adapter)
30
+ throw new Error(`Telephony call-control provider "${provider}" is not registered`);
31
+ return adapter;
32
+ },
33
+ listProviders() {
34
+ return [...providers.keys()];
35
+ },
36
+ listCallControlProviders() {
37
+ return [...callControls.keys()];
38
+ },
39
+ };
40
+ for (const adapter of (_a = input.providers) !== null && _a !== void 0 ? _a : [])
41
+ registry.registerProvider(adapter);
42
+ for (const adapter of (_b = input.callControls) !== null && _b !== void 0 ? _b : [])
43
+ registry.registerCallControl(adapter);
44
+ return registry;
45
+ }
package/dist/rtp.d.ts ADDED
@@ -0,0 +1,28 @@
1
+ export declare const RTP_VERSION = 2;
2
+ export declare const RTP_PAYLOAD_TYPE_PCMU = 0;
3
+ export declare const RTP_PAYLOAD_TYPE_PCMA = 8;
4
+ export interface RtpPacket {
5
+ version: number;
6
+ padding: boolean;
7
+ extension: boolean;
8
+ marker: boolean;
9
+ payloadType: number;
10
+ sequenceNumber: number;
11
+ timestamp: number;
12
+ ssrc: number;
13
+ csrc: number[];
14
+ payload: Buffer;
15
+ }
16
+ export interface SerializeRtpPacketInput {
17
+ marker?: boolean;
18
+ payloadType?: number;
19
+ sequenceNumber: number;
20
+ timestamp: number;
21
+ ssrc: number;
22
+ payload: Buffer | Uint8Array;
23
+ csrc?: number[];
24
+ }
25
+ export declare function nextRtpSequenceNumber(value: number): number;
26
+ export declare function nextRtpTimestamp(value: number, increment: number): number;
27
+ export declare function parseRtpPacket(buffer: Buffer | Uint8Array): RtpPacket;
28
+ export declare function serializeRtpPacket(input: SerializeRtpPacketInput): Buffer;
package/dist/rtp.js ADDED
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RTP_PAYLOAD_TYPE_PCMA = exports.RTP_PAYLOAD_TYPE_PCMU = exports.RTP_VERSION = void 0;
4
+ exports.nextRtpSequenceNumber = nextRtpSequenceNumber;
5
+ exports.nextRtpTimestamp = nextRtpTimestamp;
6
+ exports.parseRtpPacket = parseRtpPacket;
7
+ exports.serializeRtpPacket = serializeRtpPacket;
8
+ exports.RTP_VERSION = 2;
9
+ exports.RTP_PAYLOAD_TYPE_PCMU = 0;
10
+ exports.RTP_PAYLOAD_TYPE_PCMA = 8;
11
+ function assertUint16(value, label) {
12
+ if (!Number.isInteger(value) || value < 0 || value > 0xffff) {
13
+ throw new Error(`${label} must be a uint16`);
14
+ }
15
+ }
16
+ function assertUint32(value, label) {
17
+ if (!Number.isInteger(value) || value < 0 || value > 0xffffffff) {
18
+ throw new Error(`${label} must be a uint32`);
19
+ }
20
+ }
21
+ function nextRtpSequenceNumber(value) {
22
+ return (value + 1) & 0xffff;
23
+ }
24
+ function nextRtpTimestamp(value, increment) {
25
+ assertUint32(value, "timestamp");
26
+ if (!Number.isInteger(increment) || increment < 0)
27
+ throw new Error("increment must be a non-negative integer");
28
+ return (value + increment) >>> 0;
29
+ }
30
+ function parseRtpPacket(buffer) {
31
+ var _a, _b;
32
+ const data = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer);
33
+ if (data.length < 12)
34
+ throw new Error("RTP packet is too short");
35
+ const first = (_a = data[0]) !== null && _a !== void 0 ? _a : 0;
36
+ const version = first >> 6;
37
+ if (version !== exports.RTP_VERSION)
38
+ throw new Error(`Unsupported RTP version ${version}`);
39
+ const csrcCount = first & 0x0f;
40
+ const headerLength = 12 + csrcCount * 4;
41
+ if (data.length < headerLength)
42
+ throw new Error("RTP packet has truncated CSRC list");
43
+ const second = (_b = data[1]) !== null && _b !== void 0 ? _b : 0;
44
+ const csrc = [];
45
+ for (let offset = 12; offset < headerLength; offset += 4) {
46
+ csrc.push(data.readUInt32BE(offset));
47
+ }
48
+ return {
49
+ version,
50
+ padding: Boolean(first & 0x20),
51
+ extension: Boolean(first & 0x10),
52
+ marker: Boolean(second & 0x80),
53
+ payloadType: second & 0x7f,
54
+ sequenceNumber: data.readUInt16BE(2),
55
+ timestamp: data.readUInt32BE(4),
56
+ ssrc: data.readUInt32BE(8),
57
+ csrc,
58
+ payload: data.subarray(headerLength),
59
+ };
60
+ }
61
+ function serializeRtpPacket(input) {
62
+ var _a, _b, _c;
63
+ assertUint16(input.sequenceNumber, "sequenceNumber");
64
+ assertUint32(input.timestamp, "timestamp");
65
+ assertUint32(input.ssrc, "ssrc");
66
+ const payloadType = (_a = input.payloadType) !== null && _a !== void 0 ? _a : exports.RTP_PAYLOAD_TYPE_PCMU;
67
+ if (!Number.isInteger(payloadType) || payloadType < 0 || payloadType > 0x7f) {
68
+ throw new Error("payloadType must be a 7-bit integer");
69
+ }
70
+ const csrc = (_b = input.csrc) !== null && _b !== void 0 ? _b : [];
71
+ if (csrc.length > 15)
72
+ throw new Error("RTP packets can contain at most 15 CSRC entries");
73
+ for (const [index, value] of csrc.entries())
74
+ assertUint32(value, `csrc[${index}]`);
75
+ const payload = Buffer.isBuffer(input.payload) ? input.payload : Buffer.from(input.payload);
76
+ const headerLength = 12 + csrc.length * 4;
77
+ const packet = Buffer.alloc(headerLength + payload.length);
78
+ packet[0] = (exports.RTP_VERSION << 6) | csrc.length;
79
+ packet[1] = (input.marker ? 0x80 : 0) | payloadType;
80
+ packet.writeUInt16BE(input.sequenceNumber, 2);
81
+ packet.writeUInt32BE(input.timestamp >>> 0, 4);
82
+ packet.writeUInt32BE(input.ssrc >>> 0, 8);
83
+ for (let index = 0; index < csrc.length; index += 1) {
84
+ packet.writeUInt32BE((_c = csrc[index]) !== null && _c !== void 0 ? _c : 0, 12 + index * 4);
85
+ }
86
+ payload.copy(packet, headerLength);
87
+ return packet;
88
+ }
@@ -0,0 +1,24 @@
1
+ import { computeTwilioBodySha256, createTwilioInboundCallResponse, createTwilioMediaStreamClearMessage, createTwilioMediaStreamMarkMessage, createTwilioMediaStreamMediaMessage, createTwilioMediaStreamTwiml, decodeTwilioMulawBase64ToFloat32, decodeTwilioMulawBase64ToPcm16, encodeFloat32ToTwilioMulawBase64, encodePcm16ToTwilioMulawBase64, handleTwilioMediaStreamMessage, parseTwilioMediaStreamMessage, serializeTwilioMediaStreamMessage, validateTwilioRequestSignature, type CreateTwilioMediaStreamTwimlOptions, type TwilioInboundCallContext, type TwilioInboundCallResponse, type TwilioInboundCallResponseConfig, type TwilioInboundMediaStreamMessage, type TwilioOutboundMediaStreamMessage, type TwilioRequestSignatureValidationOptions } from "@kognitivedev/voice/telephony";
2
+ import type { TelephonyCallControlAdapter, TelephonyCallControlResult, TelephonyOutboundCallInput, TelephonyOutboundCallResult, TelephonyProviderAdapter } from "./types";
3
+ export { computeTwilioBodySha256, createTwilioInboundCallResponse, createTwilioMediaStreamClearMessage, createTwilioMediaStreamMarkMessage, createTwilioMediaStreamMediaMessage, createTwilioMediaStreamTwiml, decodeTwilioMulawBase64ToFloat32, decodeTwilioMulawBase64ToPcm16, encodeFloat32ToTwilioMulawBase64, encodePcm16ToTwilioMulawBase64, handleTwilioMediaStreamMessage, parseTwilioMediaStreamMessage, serializeTwilioMediaStreamMessage, validateTwilioRequestSignature, };
4
+ export type { CreateTwilioMediaStreamTwimlOptions, TwilioInboundCallContext, TwilioInboundCallResponse, TwilioInboundCallResponseConfig, TwilioInboundMediaStreamMessage, TwilioOutboundMediaStreamMessage, TwilioRequestSignatureValidationOptions, };
5
+ export interface TwilioOutboundCallOptions extends TelephonyOutboundCallInput {
6
+ accountSid: string;
7
+ authToken: string;
8
+ fetch?: typeof fetch;
9
+ }
10
+ export interface TwilioTelephonyProviderConfig {
11
+ accountSid: string;
12
+ authToken: string;
13
+ fetch?: typeof fetch;
14
+ }
15
+ export interface TwilioCompleteCallOptions {
16
+ accountSid: string;
17
+ authToken: string;
18
+ providerCallId: string;
19
+ fetch?: typeof fetch;
20
+ }
21
+ export declare function createTwilioOutboundCall(options: TwilioOutboundCallOptions): Promise<TelephonyOutboundCallResult>;
22
+ export declare function completeTwilioCall(options: TwilioCompleteCallOptions): Promise<TelephonyCallControlResult>;
23
+ export declare function createTwilioTelephonyProvider(config: TwilioTelephonyProviderConfig): TelephonyProviderAdapter;
24
+ export declare function createTwilioPhoneControlAdapter(config: TwilioTelephonyProviderConfig): TelephonyCallControlAdapter;
package/dist/twilio.js ADDED
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateTwilioRequestSignature = exports.serializeTwilioMediaStreamMessage = exports.parseTwilioMediaStreamMessage = exports.handleTwilioMediaStreamMessage = exports.encodePcm16ToTwilioMulawBase64 = exports.encodeFloat32ToTwilioMulawBase64 = exports.decodeTwilioMulawBase64ToPcm16 = exports.decodeTwilioMulawBase64ToFloat32 = exports.createTwilioMediaStreamTwiml = exports.createTwilioMediaStreamMediaMessage = exports.createTwilioMediaStreamMarkMessage = exports.createTwilioMediaStreamClearMessage = exports.createTwilioInboundCallResponse = exports.computeTwilioBodySha256 = void 0;
4
+ exports.createTwilioOutboundCall = createTwilioOutboundCall;
5
+ exports.completeTwilioCall = completeTwilioCall;
6
+ exports.createTwilioTelephonyProvider = createTwilioTelephonyProvider;
7
+ exports.createTwilioPhoneControlAdapter = createTwilioPhoneControlAdapter;
8
+ const telephony_1 = require("@kognitivedev/voice/telephony");
9
+ Object.defineProperty(exports, "computeTwilioBodySha256", { enumerable: true, get: function () { return telephony_1.computeTwilioBodySha256; } });
10
+ Object.defineProperty(exports, "createTwilioInboundCallResponse", { enumerable: true, get: function () { return telephony_1.createTwilioInboundCallResponse; } });
11
+ Object.defineProperty(exports, "createTwilioMediaStreamClearMessage", { enumerable: true, get: function () { return telephony_1.createTwilioMediaStreamClearMessage; } });
12
+ Object.defineProperty(exports, "createTwilioMediaStreamMarkMessage", { enumerable: true, get: function () { return telephony_1.createTwilioMediaStreamMarkMessage; } });
13
+ Object.defineProperty(exports, "createTwilioMediaStreamMediaMessage", { enumerable: true, get: function () { return telephony_1.createTwilioMediaStreamMediaMessage; } });
14
+ Object.defineProperty(exports, "createTwilioMediaStreamTwiml", { enumerable: true, get: function () { return telephony_1.createTwilioMediaStreamTwiml; } });
15
+ Object.defineProperty(exports, "decodeTwilioMulawBase64ToFloat32", { enumerable: true, get: function () { return telephony_1.decodeTwilioMulawBase64ToFloat32; } });
16
+ Object.defineProperty(exports, "decodeTwilioMulawBase64ToPcm16", { enumerable: true, get: function () { return telephony_1.decodeTwilioMulawBase64ToPcm16; } });
17
+ Object.defineProperty(exports, "encodeFloat32ToTwilioMulawBase64", { enumerable: true, get: function () { return telephony_1.encodeFloat32ToTwilioMulawBase64; } });
18
+ Object.defineProperty(exports, "encodePcm16ToTwilioMulawBase64", { enumerable: true, get: function () { return telephony_1.encodePcm16ToTwilioMulawBase64; } });
19
+ Object.defineProperty(exports, "handleTwilioMediaStreamMessage", { enumerable: true, get: function () { return telephony_1.handleTwilioMediaStreamMessage; } });
20
+ Object.defineProperty(exports, "parseTwilioMediaStreamMessage", { enumerable: true, get: function () { return telephony_1.parseTwilioMediaStreamMessage; } });
21
+ Object.defineProperty(exports, "serializeTwilioMediaStreamMessage", { enumerable: true, get: function () { return telephony_1.serializeTwilioMediaStreamMessage; } });
22
+ Object.defineProperty(exports, "validateTwilioRequestSignature", { enumerable: true, get: function () { return telephony_1.validateTwilioRequestSignature; } });
23
+ function normalizeTwilioStatus(value) {
24
+ switch (value) {
25
+ case "queued":
26
+ case "ringing":
27
+ case "in-progress":
28
+ return value === "in-progress" ? "active" : value;
29
+ case "completed":
30
+ case "failed":
31
+ case "busy":
32
+ case "no-answer":
33
+ case "cancelled":
34
+ return value;
35
+ default:
36
+ return "unknown";
37
+ }
38
+ }
39
+ function assertTwilioValue(value, label) {
40
+ if (!(value === null || value === void 0 ? void 0 : value.trim()))
41
+ throw new Error(`${label} is required`);
42
+ return value.trim();
43
+ }
44
+ async function createTwilioOutboundCall(options) {
45
+ var _a;
46
+ const accountSid = assertTwilioValue(options.accountSid, "Twilio accountSid");
47
+ const authToken = assertTwilioValue(options.authToken, "Twilio authToken");
48
+ const from = assertTwilioValue(options.from, "from");
49
+ const to = assertTwilioValue(options.to, "to");
50
+ const answerUrl = assertTwilioValue(options.answerUrl, "answerUrl");
51
+ const fetchImpl = (_a = options.fetch) !== null && _a !== void 0 ? _a : globalThis.fetch.bind(globalThis);
52
+ const form = new URLSearchParams({
53
+ From: from,
54
+ To: to,
55
+ Url: answerUrl,
56
+ });
57
+ if (options.statusCallbackUrl) {
58
+ form.set("StatusCallback", options.statusCallbackUrl);
59
+ for (const event of ["initiated", "ringing", "answered", "completed"]) {
60
+ form.append("StatusCallbackEvent", event);
61
+ }
62
+ }
63
+ const response = await fetchImpl(`https://api.twilio.com/2010-04-01/Accounts/${encodeURIComponent(accountSid)}/Calls.json`, {
64
+ method: "POST",
65
+ headers: {
66
+ Authorization: `Basic ${Buffer.from(`${accountSid}:${authToken}`).toString("base64")}`,
67
+ "Content-Type": "application/x-www-form-urlencoded",
68
+ },
69
+ body: form,
70
+ });
71
+ const raw = await response.json().catch(() => ({}));
72
+ if (!response.ok) {
73
+ const message = typeof raw.message === "string" ? raw.message : response.statusText;
74
+ throw new Error(`Twilio outbound call failed: ${message}`);
75
+ }
76
+ const providerCallId = typeof raw.sid === "string" ? raw.sid : options.providerCallId;
77
+ if (!providerCallId) {
78
+ throw new Error("Twilio outbound call response did not include sid");
79
+ }
80
+ return {
81
+ provider: "twilio",
82
+ providerCallId,
83
+ status: normalizeTwilioStatus(raw.status),
84
+ from,
85
+ to,
86
+ raw,
87
+ };
88
+ }
89
+ async function completeTwilioCall(options) {
90
+ var _a, _b;
91
+ const accountSid = assertTwilioValue(options.accountSid, "Twilio accountSid");
92
+ const authToken = assertTwilioValue(options.authToken, "Twilio authToken");
93
+ const providerCallId = assertTwilioValue(options.providerCallId, "Twilio providerCallId");
94
+ const fetchImpl = (_a = options.fetch) !== null && _a !== void 0 ? _a : globalThis.fetch.bind(globalThis);
95
+ const form = new URLSearchParams({ Status: "completed" });
96
+ const response = await fetchImpl(`https://api.twilio.com/2010-04-01/Accounts/${encodeURIComponent(accountSid)}/Calls/${encodeURIComponent(providerCallId)}.json`, {
97
+ method: "POST",
98
+ headers: {
99
+ Authorization: `Basic ${Buffer.from(`${accountSid}:${authToken}`).toString("base64")}`,
100
+ "Content-Type": "application/x-www-form-urlencoded",
101
+ },
102
+ body: form,
103
+ });
104
+ const raw = await response.json().catch(() => ({}));
105
+ if (!response.ok) {
106
+ const message = typeof raw.message === "string" ? raw.message : response.statusText;
107
+ throw new Error(`Twilio call completion failed: ${message}`);
108
+ }
109
+ return {
110
+ provider: "twilio",
111
+ providerCallId,
112
+ status: normalizeTwilioStatus((_b = raw.status) !== null && _b !== void 0 ? _b : "completed"),
113
+ raw,
114
+ };
115
+ }
116
+ function createTwilioTelephonyProvider(config) {
117
+ return {
118
+ provider: "twilio",
119
+ createOutboundCall(input) {
120
+ return createTwilioOutboundCall(Object.assign(Object.assign({}, input), { accountSid: config.accountSid, authToken: config.authToken, fetch: config.fetch }));
121
+ },
122
+ };
123
+ }
124
+ function createTwilioPhoneControlAdapter(config) {
125
+ return {
126
+ provider: "twilio",
127
+ hangUpCall(input) {
128
+ return completeTwilioCall({
129
+ accountSid: config.accountSid,
130
+ authToken: config.authToken,
131
+ providerCallId: input.providerCallId,
132
+ fetch: config.fetch,
133
+ });
134
+ },
135
+ };
136
+ }