@kuralle-syrinx/server-websocket 4.4.1 → 4.5.0
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/backchannel-cue-fixtures.d.ts +4 -0
- package/dist/backchannel-cue-fixtures.d.ts.map +1 -0
- package/dist/backchannel-cue-fixtures.js +25 -0
- package/dist/backchannel-cue-fixtures.js.map +1 -0
- package/dist/background-audio.d.ts +59 -0
- package/dist/background-audio.d.ts.map +1 -0
- package/dist/background-audio.js +248 -0
- package/dist/background-audio.js.map +1 -0
- package/dist/browser-opus.d.ts +12 -0
- package/dist/browser-opus.d.ts.map +1 -0
- package/dist/browser-opus.js +48 -0
- package/dist/browser-opus.js.map +1 -0
- package/dist/carrier-commands.d.ts +124 -0
- package/dist/carrier-commands.d.ts.map +1 -0
- package/dist/carrier-commands.js +193 -0
- package/dist/carrier-commands.js.map +1 -0
- package/dist/edge-telnyx.d.ts +37 -0
- package/dist/edge-telnyx.d.ts.map +1 -0
- package/dist/edge-telnyx.js +320 -0
- package/dist/edge-telnyx.js.map +1 -0
- package/dist/edge-twilio.d.ts +31 -0
- package/dist/edge-twilio.d.ts.map +1 -0
- package/dist/edge-twilio.js +286 -0
- package/dist/edge-twilio.js.map +1 -0
- package/dist/edge.d.ts +71 -0
- package/dist/edge.d.ts.map +1 -0
- package/dist/edge.js +560 -0
- package/dist/edge.js.map +1 -0
- package/dist/inbound-audio.d.ts +13 -0
- package/dist/inbound-audio.d.ts.map +1 -0
- package/dist/inbound-audio.js +66 -0
- package/dist/inbound-audio.js.map +1 -0
- package/dist/index.d.ts +81 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +718 -0
- package/dist/index.js.map +1 -0
- package/dist/json-message.d.ts +7 -0
- package/dist/json-message.d.ts.map +1 -0
- package/dist/json-message.js +41 -0
- package/dist/json-message.js.map +1 -0
- package/dist/outbound-playout-pipeline.d.ts +53 -0
- package/dist/outbound-playout-pipeline.d.ts.map +1 -0
- package/dist/outbound-playout-pipeline.js +148 -0
- package/dist/outbound-playout-pipeline.js.map +1 -0
- package/dist/paced-playout.d.ts +42 -0
- package/dist/paced-playout.d.ts.map +1 -0
- package/dist/paced-playout.js +151 -0
- package/dist/paced-playout.js.map +1 -0
- package/dist/playout-progress.d.ts +26 -0
- package/dist/playout-progress.d.ts.map +1 -0
- package/dist/playout-progress.js +64 -0
- package/dist/playout-progress.js.map +1 -0
- package/dist/session-store.d.ts +39 -0
- package/dist/session-store.d.ts.map +1 -0
- package/dist/session-store.js +80 -0
- package/dist/session-store.js.map +1 -0
- package/dist/smartpbx.d.ts +47 -0
- package/dist/smartpbx.d.ts.map +1 -0
- package/dist/smartpbx.js +437 -0
- package/dist/smartpbx.js.map +1 -0
- package/dist/telnyx-codec.d.ts +41 -0
- package/dist/telnyx-codec.d.ts.map +1 -0
- package/dist/telnyx-codec.js +114 -0
- package/dist/telnyx-codec.js.map +1 -0
- package/dist/telnyx.d.ts +52 -0
- package/dist/telnyx.d.ts.map +1 -0
- package/dist/telnyx.js +550 -0
- package/dist/telnyx.js.map +1 -0
- package/dist/test-helpers.d.ts +20 -0
- package/dist/test-helpers.d.ts.map +1 -0
- package/dist/test-helpers.js +242 -0
- package/dist/test-helpers.js.map +1 -0
- package/dist/transport-helpers.d.ts +12 -0
- package/dist/transport-helpers.d.ts.map +1 -0
- package/dist/transport-helpers.js +90 -0
- package/dist/transport-helpers.js.map +1 -0
- package/dist/transport-host.d.ts +56 -0
- package/dist/transport-host.d.ts.map +1 -0
- package/dist/transport-host.js +110 -0
- package/dist/transport-host.js.map +1 -0
- package/dist/turn-metrics.d.ts +79 -0
- package/dist/turn-metrics.d.ts.map +1 -0
- package/dist/turn-metrics.js +208 -0
- package/dist/turn-metrics.js.map +1 -0
- package/dist/twilio-auth.d.ts +12 -0
- package/dist/twilio-auth.d.ts.map +1 -0
- package/dist/twilio-auth.js +44 -0
- package/dist/twilio-auth.js.map +1 -0
- package/dist/twilio.d.ts +56 -0
- package/dist/twilio.d.ts.map +1 -0
- package/dist/twilio.js +511 -0
- package/dist/twilio.js.map +1 -0
- package/dist/websocket-close.d.ts +12 -0
- package/dist/websocket-close.d.ts.map +1 -0
- package/dist/websocket-close.js +58 -0
- package/dist/websocket-close.js.map +1 -0
- package/dist/websocket-lifecycle.d.ts +29 -0
- package/dist/websocket-lifecycle.d.ts.map +1 -0
- package/dist/websocket-lifecycle.js +87 -0
- package/dist/websocket-lifecycle.js.map +1 -0
- package/dist/websocket-upgrade.d.ts +9 -0
- package/dist/websocket-upgrade.d.ts.map +1 -0
- package/dist/websocket-upgrade.js +91 -0
- package/dist/websocket-upgrade.js.map +1 -0
- package/dist/wire-carrier-control.d.ts +27 -0
- package/dist/wire-carrier-control.d.ts.map +1 -0
- package/dist/wire-carrier-control.js +116 -0
- package/dist/wire-carrier-control.js.map +1 -0
- package/package.json +32 -11
- package/src/admission-control.test.ts +270 -0
- package/src/background-audio.test.ts +224 -0
- package/src/browser-opus.test.ts +41 -0
- package/src/browser-pacing.test.ts +440 -0
- package/src/carrier-commands.test.ts +198 -0
- package/src/edge-telnyx.test.ts +333 -0
- package/src/edge-twilio.test.ts +293 -0
- package/src/edge.test.ts +727 -0
- package/src/graceful-drain.test.ts +306 -0
- package/src/inbound-audio.test.ts +58 -0
- package/src/index.test.ts +2078 -0
- package/src/outbound-playout-pipeline.test.ts +314 -0
- package/src/paced-playout.test.ts +247 -0
- package/src/playout-progress.test.ts +56 -0
- package/src/session-store.test.ts +274 -0
- package/src/smartpbx.test.ts +986 -0
- package/src/telnyx.test.ts +1633 -0
- package/src/transport-host.test.ts +51 -0
- package/src/turn-metrics.test.ts +503 -0
- package/src/twilio-auth.test.ts +36 -0
- package/src/twilio.test.ts +1274 -0
- package/src/websocket-close.test.ts +63 -0
- package/src/websocket-lifecycle.test.ts +49 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { WebSocket } from "ws";
|
|
2
|
+
export declare class WebSocketStartupTimeoutError extends Error {
|
|
3
|
+
constructor(timeoutMs: number);
|
|
4
|
+
}
|
|
5
|
+
export declare function withWebSocketStartupTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T>;
|
|
6
|
+
export declare function startWebSocketHeartbeat(socket: WebSocket, heartbeatIntervalMs: number, disposers: Array<() => void>): void;
|
|
7
|
+
/** Minimal closable shape: a voice websocket server (or any server) that drains on graceful close. */
|
|
8
|
+
export interface GracefulClosable {
|
|
9
|
+
close(opts?: {
|
|
10
|
+
graceful?: boolean;
|
|
11
|
+
drainDeadlineMs?: number;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Wire process termination signals to the server's graceful drain so a deploy/scale-down
|
|
16
|
+
* drains active calls instead of killing them (Hard Rule: "drain, don't kill"). Idempotent
|
|
17
|
+
* (a second signal during shutdown is ignored). Returns a disposer that removes the handlers.
|
|
18
|
+
*
|
|
19
|
+
* Production hosts call this once after creating the server:
|
|
20
|
+
* installGracefulShutdown(server, { drainDeadlineMs: 10_000, onClosed: () => process.exit(0) });
|
|
21
|
+
*/
|
|
22
|
+
export declare function installGracefulShutdown(server: GracefulClosable, opts?: {
|
|
23
|
+
readonly drainDeadlineMs?: number;
|
|
24
|
+
readonly signals?: readonly NodeJS.Signals[];
|
|
25
|
+
readonly onClosed?: () => void;
|
|
26
|
+
readonly onError?: (err: unknown) => void;
|
|
27
|
+
}): () => void;
|
|
28
|
+
export declare function startWebSocketMaxSessionDuration(socket: WebSocket, maxSessionDurationMs: number, disposers: Array<() => void>, onTimeout?: () => void): void;
|
|
29
|
+
//# sourceMappingURL=websocket-lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-lifecycle.d.ts","sourceRoot":"","sources":["../src/websocket-lifecycle.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAG/B,qBAAa,4BAA6B,SAAQ,KAAK;gBACzC,SAAS,EAAE,MAAM;CAI9B;AAED,wBAAsB,2BAA2B,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAavG;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,mBAAmB,EAAE,MAAM,EAC3B,SAAS,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,GAC3B,IAAI,CAoBN;AAED,sGAAsG;AACtG,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/E;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,gBAAgB,EACxB,IAAI,CAAC,EAAE;IACL,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,CAAC,OAAO,EAAE,CAAC;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CAC3C,GACA,MAAM,IAAI,CAgBZ;AAED,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,SAAS,EACjB,oBAAoB,EAAE,MAAM,EAC5B,SAAS,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,EAC5B,SAAS,CAAC,EAAE,MAAM,IAAI,GACrB,IAAI,CAON"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import { WebSocket } from "ws";
|
|
3
|
+
import { closeWebSocketWithFallback } from "./websocket-close.js";
|
|
4
|
+
export class WebSocketStartupTimeoutError extends Error {
|
|
5
|
+
constructor(timeoutMs) {
|
|
6
|
+
super(`websocket session startup exceeded ${String(timeoutMs)}ms`);
|
|
7
|
+
this.name = "WebSocketStartupTimeoutError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export async function withWebSocketStartupTimeout(promise, timeoutMs) {
|
|
11
|
+
if (timeoutMs <= 0)
|
|
12
|
+
return await promise;
|
|
13
|
+
let timeout = null;
|
|
14
|
+
try {
|
|
15
|
+
return await Promise.race([
|
|
16
|
+
promise,
|
|
17
|
+
new Promise((_resolve, reject) => {
|
|
18
|
+
timeout = setTimeout(() => reject(new WebSocketStartupTimeoutError(timeoutMs)), timeoutMs);
|
|
19
|
+
}),
|
|
20
|
+
]);
|
|
21
|
+
}
|
|
22
|
+
finally {
|
|
23
|
+
if (timeout)
|
|
24
|
+
clearTimeout(timeout);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function startWebSocketHeartbeat(socket, heartbeatIntervalMs, disposers) {
|
|
28
|
+
if (heartbeatIntervalMs <= 0)
|
|
29
|
+
return;
|
|
30
|
+
let alive = true;
|
|
31
|
+
const onPong = () => {
|
|
32
|
+
alive = true;
|
|
33
|
+
};
|
|
34
|
+
socket.on("pong", onPong);
|
|
35
|
+
const interval = setInterval(() => {
|
|
36
|
+
if (socket.readyState !== WebSocket.OPEN)
|
|
37
|
+
return;
|
|
38
|
+
if (!alive) {
|
|
39
|
+
socket.terminate();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
alive = false;
|
|
43
|
+
socket.ping();
|
|
44
|
+
}, heartbeatIntervalMs);
|
|
45
|
+
disposers.push(() => {
|
|
46
|
+
clearInterval(interval);
|
|
47
|
+
socket.off("pong", onPong);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Wire process termination signals to the server's graceful drain so a deploy/scale-down
|
|
52
|
+
* drains active calls instead of killing them (Hard Rule: "drain, don't kill"). Idempotent
|
|
53
|
+
* (a second signal during shutdown is ignored). Returns a disposer that removes the handlers.
|
|
54
|
+
*
|
|
55
|
+
* Production hosts call this once after creating the server:
|
|
56
|
+
* installGracefulShutdown(server, { drainDeadlineMs: 10_000, onClosed: () => process.exit(0) });
|
|
57
|
+
*/
|
|
58
|
+
export function installGracefulShutdown(server, opts) {
|
|
59
|
+
const drainDeadlineMs = opts?.drainDeadlineMs ?? 10_000;
|
|
60
|
+
const signals = opts?.signals ?? ["SIGTERM", "SIGINT"];
|
|
61
|
+
let shuttingDown = false;
|
|
62
|
+
const handler = () => {
|
|
63
|
+
if (shuttingDown)
|
|
64
|
+
return;
|
|
65
|
+
shuttingDown = true;
|
|
66
|
+
server
|
|
67
|
+
.close({ graceful: true, drainDeadlineMs })
|
|
68
|
+
.then(() => opts?.onClosed?.())
|
|
69
|
+
.catch((err) => (opts?.onError ? opts.onError(err) : opts?.onClosed?.()));
|
|
70
|
+
};
|
|
71
|
+
for (const signal of signals)
|
|
72
|
+
process.once(signal, handler);
|
|
73
|
+
return () => {
|
|
74
|
+
for (const signal of signals)
|
|
75
|
+
process.removeListener(signal, handler);
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export function startWebSocketMaxSessionDuration(socket, maxSessionDurationMs, disposers, onTimeout) {
|
|
79
|
+
if (maxSessionDurationMs <= 0)
|
|
80
|
+
return;
|
|
81
|
+
const timeout = setTimeout(() => {
|
|
82
|
+
onTimeout?.();
|
|
83
|
+
closeWebSocketWithFallback(socket, 1000, "websocket max session duration exceeded");
|
|
84
|
+
}, maxSessionDurationMs);
|
|
85
|
+
disposers.push(() => clearTimeout(timeout));
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=websocket-lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-lifecycle.js","sourceRoot":"","sources":["../src/websocket-lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Server as HttpServer } from "node:http";
|
|
2
|
+
import { WebSocketServer } from "ws";
|
|
3
|
+
import { type TransportAdmissionOptions } from "./transport-host.js";
|
|
4
|
+
export interface RoutedWebSocketServer {
|
|
5
|
+
readonly wsServer: WebSocketServer;
|
|
6
|
+
readonly detach: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function createRoutedWebSocketServer(httpServer: HttpServer, path: string, admission?: TransportAdmissionOptions): RoutedWebSocketServer;
|
|
9
|
+
//# sourceMappingURL=websocket-upgrade.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-upgrade.d.ts","sourceRoot":"","sources":["../src/websocket-upgrade.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAmB,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvE,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AACrC,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC;CAC7B;AA+CD,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,yBAAyB,GACpC,qBAAqB,CAwDvB"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import { WebSocketServer } from "ws";
|
|
3
|
+
import { rejectWebSocketAdmission, } from "./transport-host.js";
|
|
4
|
+
const routers = new WeakMap();
|
|
5
|
+
function getOrCreateRouter(httpServer) {
|
|
6
|
+
const existing = routers.get(httpServer);
|
|
7
|
+
if (existing)
|
|
8
|
+
return existing;
|
|
9
|
+
const handlers = new Map();
|
|
10
|
+
const listener = (request, socket, head) => {
|
|
11
|
+
const pathname = requestPathname(request);
|
|
12
|
+
const handler = handlers.get(pathname);
|
|
13
|
+
if (handler) {
|
|
14
|
+
handler(request, socket, head);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (httpServer.listenerCount("upgrade") > 1) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
socket.destroy();
|
|
21
|
+
};
|
|
22
|
+
httpServer.on("upgrade", listener);
|
|
23
|
+
const router = { handlers, servers: new Set(), listener };
|
|
24
|
+
routers.set(httpServer, router);
|
|
25
|
+
return router;
|
|
26
|
+
}
|
|
27
|
+
function requestPathname(request) {
|
|
28
|
+
try {
|
|
29
|
+
return new URL(request.url ?? "/", "http://localhost").pathname;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return "/";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function createRoutedWebSocketServer(httpServer, path, admission) {
|
|
36
|
+
const wsServer = new WebSocketServer({
|
|
37
|
+
noServer: true,
|
|
38
|
+
perMessageDeflate: false,
|
|
39
|
+
});
|
|
40
|
+
const router = getOrCreateRouter(httpServer);
|
|
41
|
+
const accept = (request, socket, head) => {
|
|
42
|
+
const maxConcurrentSessions = admission?.maxConcurrentSessions;
|
|
43
|
+
const scope = admission?.maxConcurrentSessionsScope ?? "path";
|
|
44
|
+
const activeSessions = scope === "server"
|
|
45
|
+
? [...router.servers].reduce((sum, server) => sum + server.clients.size, 0)
|
|
46
|
+
: wsServer.clients.size;
|
|
47
|
+
if (maxConcurrentSessions !== undefined
|
|
48
|
+
&& activeSessions >= maxConcurrentSessions) {
|
|
49
|
+
admission?.onAdmissionRejected?.();
|
|
50
|
+
rejectWebSocketAdmission(wsServer, request, socket, head);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
wsServer.handleUpgrade(request, socket, head, (websocket) => {
|
|
54
|
+
wsServer.emit("connection", websocket, request);
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
const handler = (request, socket, head) => {
|
|
58
|
+
if (!admission?.authorize) {
|
|
59
|
+
accept(request, socket, head);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// Authorize before completing the upgrade; reject with 4401 on failure/throw.
|
|
63
|
+
void Promise.resolve()
|
|
64
|
+
.then(() => admission.authorize(request))
|
|
65
|
+
.then((ok) => {
|
|
66
|
+
if (ok) {
|
|
67
|
+
accept(request, socket, head);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
rejectWebSocketAdmission(wsServer, request, socket, head, 4401, "unauthorized");
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
.catch(() => {
|
|
74
|
+
rejectWebSocketAdmission(wsServer, request, socket, head, 4401, "unauthorized");
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
router.handlers.set(path, handler);
|
|
78
|
+
router.servers.add(wsServer);
|
|
79
|
+
return {
|
|
80
|
+
wsServer,
|
|
81
|
+
detach: () => {
|
|
82
|
+
router.handlers.delete(path);
|
|
83
|
+
router.servers.delete(wsServer);
|
|
84
|
+
if (router.handlers.size === 0) {
|
|
85
|
+
httpServer.off("upgrade", router.listener);
|
|
86
|
+
routers.delete(httpServer);
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=websocket-upgrade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-upgrade.js","sourceRoot":"","sources":["../src/websocket-upgrade.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type VoiceAgentSession } from "@kuralle-syrinx/core";
|
|
2
|
+
import { type FetchLike, type TelnyxRestCredentials, type TwilioRestCredentials, type WarmTransferSummarizer } from "./carrier-commands.js";
|
|
3
|
+
export interface TwilioCarrierControlOptions {
|
|
4
|
+
readonly carrier: "twilio";
|
|
5
|
+
/** Call SID for the active media stream (injected; may resolve lazily). */
|
|
6
|
+
getCallSid: () => string | undefined;
|
|
7
|
+
readonly credentials?: TwilioRestCredentials;
|
|
8
|
+
readonly fetchImpl?: FetchLike;
|
|
9
|
+
readonly redirectUrl?: string;
|
|
10
|
+
readonly warmSummarizer?: WarmTransferSummarizer;
|
|
11
|
+
}
|
|
12
|
+
export interface TelnyxCarrierControlOptions {
|
|
13
|
+
readonly carrier: "telnyx";
|
|
14
|
+
getCallControlId: () => string | undefined;
|
|
15
|
+
readonly credentials?: TelnyxRestCredentials;
|
|
16
|
+
readonly fetchImpl?: FetchLike;
|
|
17
|
+
readonly webhookUrl?: string;
|
|
18
|
+
readonly warmSummarizer?: WarmTransferSummarizer;
|
|
19
|
+
}
|
|
20
|
+
export type CarrierControlOptions = TwilioCarrierControlOptions | TelnyxCarrierControlOptions;
|
|
21
|
+
/**
|
|
22
|
+
* Subscribe to `dtmf.send` and `call.transfer` on the session bus.
|
|
23
|
+
* When credentials are absent, still builds the command and emits a metric so
|
|
24
|
+
* unit tests can assert the constructor path without live HTTP.
|
|
25
|
+
*/
|
|
26
|
+
export declare function wireCarrierControl(session: VoiceAgentSession, disposers: Array<() => void>, options: CarrierControlOptions): void;
|
|
27
|
+
//# sourceMappingURL=wire-carrier-control.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire-carrier-control.d.ts","sourceRoot":"","sources":["../src/wire-carrier-control.ts"],"names":[],"mappings":"AAKA,OAAO,EAAuD,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACnH,OAAO,EAQL,KAAK,SAAS,EACd,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC5B,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,2EAA2E;IAC3E,UAAU,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,WAAW,CAAC,EAAE,qBAAqB,CAAC;IAC7C,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,cAAc,CAAC,EAAE,sBAAsB,CAAC;CAClD;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,gBAAgB,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,WAAW,CAAC,EAAE,qBAAqB,CAAC;IAC7C,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,CAAC,EAAE,sBAAsB,CAAC;CAClD;AAED,MAAM,MAAM,qBAAqB,GAAG,2BAA2B,GAAG,2BAA2B,CAAC;AAE9F;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,EAC5B,OAAO,EAAE,qBAAqB,GAC7B,IAAI,CASN"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
//
|
|
3
|
+
// Bus wiring for dtmf.send + call.transfer → pure constructor + injectable dispatch.
|
|
4
|
+
// Mechanism unit-tested; live carrier HTTP unverified.
|
|
5
|
+
import { Route } from "@kuralle-syrinx/core";
|
|
6
|
+
import { buildTelnyxSendDtmf, buildTelnyxTransfer, buildTwilioSendDigits, buildTwilioTransfer, dispatchTelnyxCommand, dispatchTwilioCommand, resolveTransferSummary, } from "./carrier-commands.js";
|
|
7
|
+
/**
|
|
8
|
+
* Subscribe to `dtmf.send` and `call.transfer` on the session bus.
|
|
9
|
+
* When credentials are absent, still builds the command and emits a metric so
|
|
10
|
+
* unit tests can assert the constructor path without live HTTP.
|
|
11
|
+
*/
|
|
12
|
+
export function wireCarrierControl(session, disposers, options) {
|
|
13
|
+
disposers.push(session.bus.on("dtmf.send", (pkt) => {
|
|
14
|
+
void handleDtmfSend(session, pkt, options);
|
|
15
|
+
}), session.bus.on("call.transfer", (pkt) => {
|
|
16
|
+
void handleCallTransfer(session, pkt, options);
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
async function handleDtmfSend(session, pkt, options) {
|
|
20
|
+
try {
|
|
21
|
+
if (options.carrier === "twilio") {
|
|
22
|
+
const callSid = options.getCallSid();
|
|
23
|
+
if (!callSid) {
|
|
24
|
+
emitMetric(session, pkt.contextId, "carrier.dtmf_send.missing_call_handle", "twilio");
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const command = buildTwilioSendDigits(callSid, pkt);
|
|
28
|
+
emitMetric(session, pkt.contextId, "carrier.dtmf_send.built", JSON.stringify({ carrier: "twilio", digits: command.form.SendDigits }));
|
|
29
|
+
if (!options.credentials) {
|
|
30
|
+
emitMetric(session, pkt.contextId, "carrier.dtmf_send.no_credentials", "twilio");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const res = await dispatchTwilioCommand(options.credentials, command, options.fetchImpl);
|
|
34
|
+
emitMetric(session, pkt.contextId, "carrier.dtmf_send.dispatched", String(res.status));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const callControlId = options.getCallControlId();
|
|
38
|
+
if (!callControlId) {
|
|
39
|
+
emitMetric(session, pkt.contextId, "carrier.dtmf_send.missing_call_handle", "telnyx");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const command = buildTelnyxSendDtmf(callControlId, pkt);
|
|
43
|
+
emitMetric(session, pkt.contextId, "carrier.dtmf_send.built", JSON.stringify({ carrier: "telnyx", digits: command.json.digits }));
|
|
44
|
+
if (!options.credentials) {
|
|
45
|
+
emitMetric(session, pkt.contextId, "carrier.dtmf_send.no_credentials", "telnyx");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const res = await dispatchTelnyxCommand(options.credentials, command, options.fetchImpl);
|
|
49
|
+
emitMetric(session, pkt.contextId, "carrier.dtmf_send.dispatched", String(res.status));
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
emitMetric(session, pkt.contextId, "carrier.dtmf_send.error", err instanceof Error ? err.message : String(err));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function handleCallTransfer(session, pkt, options) {
|
|
56
|
+
try {
|
|
57
|
+
const summary = await resolveTransferSummary(pkt, options.warmSummarizer);
|
|
58
|
+
const resolved = summary !== undefined ? { ...pkt, summary } : pkt;
|
|
59
|
+
if (options.carrier === "twilio") {
|
|
60
|
+
const callSid = options.getCallSid();
|
|
61
|
+
if (!callSid) {
|
|
62
|
+
emitMetric(session, pkt.contextId, "carrier.transfer.missing_call_handle", "twilio");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const command = buildTwilioTransfer(callSid, resolved, {
|
|
66
|
+
redirectUrl: options.redirectUrl,
|
|
67
|
+
});
|
|
68
|
+
emitMetric(session, pkt.contextId, "carrier.transfer.built", JSON.stringify({
|
|
69
|
+
carrier: "twilio",
|
|
70
|
+
mode: command.mode,
|
|
71
|
+
target: resolved.target,
|
|
72
|
+
summary: command.summary ?? null,
|
|
73
|
+
}));
|
|
74
|
+
if (!options.credentials) {
|
|
75
|
+
emitMetric(session, pkt.contextId, "carrier.transfer.no_credentials", "twilio");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const res = await dispatchTwilioCommand(options.credentials, command, options.fetchImpl);
|
|
79
|
+
emitMetric(session, pkt.contextId, "carrier.transfer.dispatched", String(res.status));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const callControlId = options.getCallControlId();
|
|
83
|
+
if (!callControlId) {
|
|
84
|
+
emitMetric(session, pkt.contextId, "carrier.transfer.missing_call_handle", "telnyx");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const command = buildTelnyxTransfer(callControlId, resolved, {
|
|
88
|
+
webhookUrl: options.webhookUrl,
|
|
89
|
+
});
|
|
90
|
+
emitMetric(session, pkt.contextId, "carrier.transfer.built", JSON.stringify({
|
|
91
|
+
carrier: "telnyx",
|
|
92
|
+
mode: command.mode,
|
|
93
|
+
target: command.json.to,
|
|
94
|
+
summary: command.summary ?? null,
|
|
95
|
+
}));
|
|
96
|
+
if (!options.credentials) {
|
|
97
|
+
emitMetric(session, pkt.contextId, "carrier.transfer.no_credentials", "telnyx");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const res = await dispatchTelnyxCommand(options.credentials, command, options.fetchImpl);
|
|
101
|
+
emitMetric(session, pkt.contextId, "carrier.transfer.dispatched", String(res.status));
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
emitMetric(session, pkt.contextId, "carrier.transfer.error", err instanceof Error ? err.message : String(err));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function emitMetric(session, contextId, name, value) {
|
|
108
|
+
session.bus.push(Route.Background, {
|
|
109
|
+
kind: "metric.conversation",
|
|
110
|
+
contextId,
|
|
111
|
+
timestampMs: Date.now(),
|
|
112
|
+
name,
|
|
113
|
+
value,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=wire-carrier-control.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire-carrier-control.js","sourceRoot":"","sources":["../src/wire-carrier-control.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,EAAE;AACF,qFAAqF;AACrF,uDAAuD;AAEvD,OAAO,EAAE,KAAK,EAAwE,MAAM,sBAAsB,CAAC;AACnH,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,GAKvB,MAAM,uBAAuB,CAAC;AAuB/B;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAA0B,EAC1B,SAA4B,EAC5B,OAA8B;IAE9B,SAAS,CAAC,IAAI,CACZ,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE;QAClC,KAAK,cAAc,CAAC,OAAO,EAAE,GAAqB,EAAE,OAAO,CAAC,CAAC;IAC/D,CAAC,CAAC,EACF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,GAAG,EAAE,EAAE;QACtC,KAAK,kBAAkB,CAAC,OAAO,EAAE,GAAyB,EAAE,OAAO,CAAC,CAAC;IACvE,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,cAAc,CAC3B,OAA0B,EAC1B,GAAmB,EACnB,OAA8B;IAE9B,IAAI,CAAC;QACH,IAAI,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;YACrC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,uCAAuC,EAAE,QAAQ,CAAC,CAAC;gBACtF,OAAO;YACT,CAAC;YACD,MAAM,OAAO,GAAG,qBAAqB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACpD,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,yBAAyB,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YACtI,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;gBACzB,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,kCAAkC,EAAE,QAAQ,CAAC,CAAC;gBACjF,OAAO;YACT,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,qBAAqB,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;YACzF,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,8BAA8B,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;YACvF,OAAO;QACT,CAAC;QAED,MAAM,aAAa,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;QACjD,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,uCAAuC,EAAE,QAAQ,CAAC,CAAC;YACtF,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAG,mBAAmB,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QACxD,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,yBAAyB,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAClI,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YACzB,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,kCAAkC,EAAE,QAAQ,CAAC,CAAC;YACjF,OAAO;QACT,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,qBAAqB,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QACzF,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,8BAA8B,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACzF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,yBAAyB,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAClH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,OAA0B,EAC1B,GAAuB,EACvB,OAA8B;IAE9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,sBAAsB,CAAC,GAAG,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;QAC1E,MAAM,QAAQ,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAEnE,IAAI,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;YACrC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,sCAAsC,EAAE,QAAQ,CAAC,CAAC;gBACrF,OAAO;YACT,CAAC;YACD,MAAM,OAAO,GAAG,mBAAmB,CAAC,OAAO,EAAE,QAAQ,EAAE;gBACrD,WAAW,EAAE,OAAO,CAAC,WAAW;aACjC,CAAC,CAAC;YACH,UAAU,CACR,OAAO,EACP,GAAG,CAAC,SAAS,EACb,wBAAwB,EACxB,IAAI,CAAC,SAAS,CAAC;gBACb,OAAO,EAAE,QAAQ;gBACjB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;aACjC,CAAC,CACH,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;gBACzB,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,iCAAiC,EAAE,QAAQ,CAAC,CAAC;gBAChF,OAAO;YACT,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,qBAAqB,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;YACzF,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,6BAA6B,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;YACtF,OAAO;QACT,CAAC;QAED,MAAM,aAAa,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;QACjD,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,sCAAsC,EAAE,QAAQ,CAAC,CAAC;YACrF,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAG,mBAAmB,CAAC,aAAa,EAAE,QAAQ,EAAE;YAC3D,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B,CAAC,CAAC;QACH,UAAU,CACR,OAAO,EACP,GAAG,CAAC,SAAS,EACb,wBAAwB,EACxB,IAAI,CAAC,SAAS,CAAC;YACb,OAAO,EAAE,QAAQ;YACjB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE;YACvB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;SACjC,CAAC,CACH,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YACzB,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,iCAAiC,EAAE,QAAQ,CAAC,CAAC;YAChF,OAAO;QACT,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,qBAAqB,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QACzF,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,6BAA6B,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACxF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,wBAAwB,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACjH,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,OAA0B,EAAE,SAAiB,EAAE,IAAY,EAAE,KAAa;IAC5F,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE;QACjC,IAAI,EAAE,qBAAqB;QAC3B,SAAS;QACT,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;QACvB,IAAI;QACJ,KAAK;KACN,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kuralle-syrinx/server-websocket",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Node WebSocket voice host for Syrinx — browser transport plus Twilio/Telnyx/SmartPBX telephony adapters, background audio, admission control",
|
|
6
6
|
"keywords": [
|
|
@@ -23,20 +23,35 @@
|
|
|
23
23
|
"url": "https://github.com/kuralle/syrinx/issues"
|
|
24
24
|
},
|
|
25
25
|
"type": "module",
|
|
26
|
-
"main": "./
|
|
27
|
-
"types": "./
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
28
|
"exports": {
|
|
29
|
-
".":
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"./
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"default": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./edge": {
|
|
34
|
+
"types": "./dist/edge.d.ts",
|
|
35
|
+
"default": "./dist/edge.js"
|
|
36
|
+
},
|
|
37
|
+
"./edge-twilio": {
|
|
38
|
+
"types": "./dist/edge-twilio.d.ts",
|
|
39
|
+
"default": "./dist/edge-twilio.js"
|
|
40
|
+
},
|
|
41
|
+
"./edge-telnyx": {
|
|
42
|
+
"types": "./dist/edge-telnyx.d.ts",
|
|
43
|
+
"default": "./dist/edge-telnyx.js"
|
|
44
|
+
},
|
|
45
|
+
"./session-store": {
|
|
46
|
+
"types": "./dist/session-store.d.ts",
|
|
47
|
+
"default": "./dist/session-store.js"
|
|
48
|
+
}
|
|
34
49
|
},
|
|
35
50
|
"dependencies": {
|
|
36
51
|
"@evan/opus": "1.0.3",
|
|
37
52
|
"ws": "^8.21.0",
|
|
38
|
-
"@kuralle-syrinx/core": "4.
|
|
39
|
-
"@kuralle-syrinx/ws": "4.
|
|
53
|
+
"@kuralle-syrinx/core": "4.5.0",
|
|
54
|
+
"@kuralle-syrinx/ws": "4.5.0"
|
|
40
55
|
},
|
|
41
56
|
"devDependencies": {
|
|
42
57
|
"@types/node": "^22.0.0",
|
|
@@ -44,8 +59,14 @@
|
|
|
44
59
|
"typescript": "^5.7.0",
|
|
45
60
|
"vitest": "^3.2.6"
|
|
46
61
|
},
|
|
62
|
+
"files": [
|
|
63
|
+
"dist",
|
|
64
|
+
"src",
|
|
65
|
+
"README.md"
|
|
66
|
+
],
|
|
47
67
|
"scripts": {
|
|
48
68
|
"typecheck": "tsc --noEmit",
|
|
49
|
-
"test": "vitest run --fileParallelism=false"
|
|
69
|
+
"test": "vitest run --fileParallelism=false",
|
|
70
|
+
"build": "tsc -p tsconfig.build.json"
|
|
50
71
|
}
|
|
51
72
|
}
|