@kuralle-syrinx/server-websocket 4.4.0 → 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.
Files changed (132) hide show
  1. package/dist/backchannel-cue-fixtures.d.ts +4 -0
  2. package/dist/backchannel-cue-fixtures.d.ts.map +1 -0
  3. package/dist/backchannel-cue-fixtures.js +25 -0
  4. package/dist/backchannel-cue-fixtures.js.map +1 -0
  5. package/dist/background-audio.d.ts +59 -0
  6. package/dist/background-audio.d.ts.map +1 -0
  7. package/dist/background-audio.js +248 -0
  8. package/dist/background-audio.js.map +1 -0
  9. package/dist/browser-opus.d.ts +12 -0
  10. package/dist/browser-opus.d.ts.map +1 -0
  11. package/dist/browser-opus.js +48 -0
  12. package/dist/browser-opus.js.map +1 -0
  13. package/dist/carrier-commands.d.ts +124 -0
  14. package/dist/carrier-commands.d.ts.map +1 -0
  15. package/dist/carrier-commands.js +193 -0
  16. package/dist/carrier-commands.js.map +1 -0
  17. package/dist/edge-telnyx.d.ts +37 -0
  18. package/dist/edge-telnyx.d.ts.map +1 -0
  19. package/dist/edge-telnyx.js +320 -0
  20. package/dist/edge-telnyx.js.map +1 -0
  21. package/dist/edge-twilio.d.ts +31 -0
  22. package/dist/edge-twilio.d.ts.map +1 -0
  23. package/dist/edge-twilio.js +286 -0
  24. package/dist/edge-twilio.js.map +1 -0
  25. package/dist/edge.d.ts +71 -0
  26. package/dist/edge.d.ts.map +1 -0
  27. package/dist/edge.js +560 -0
  28. package/dist/edge.js.map +1 -0
  29. package/dist/inbound-audio.d.ts +13 -0
  30. package/dist/inbound-audio.d.ts.map +1 -0
  31. package/dist/inbound-audio.js +66 -0
  32. package/dist/inbound-audio.js.map +1 -0
  33. package/dist/index.d.ts +81 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +718 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/json-message.d.ts +7 -0
  38. package/dist/json-message.d.ts.map +1 -0
  39. package/dist/json-message.js +41 -0
  40. package/dist/json-message.js.map +1 -0
  41. package/dist/outbound-playout-pipeline.d.ts +53 -0
  42. package/dist/outbound-playout-pipeline.d.ts.map +1 -0
  43. package/dist/outbound-playout-pipeline.js +148 -0
  44. package/dist/outbound-playout-pipeline.js.map +1 -0
  45. package/dist/paced-playout.d.ts +42 -0
  46. package/dist/paced-playout.d.ts.map +1 -0
  47. package/dist/paced-playout.js +151 -0
  48. package/dist/paced-playout.js.map +1 -0
  49. package/dist/playout-progress.d.ts +26 -0
  50. package/dist/playout-progress.d.ts.map +1 -0
  51. package/dist/playout-progress.js +64 -0
  52. package/dist/playout-progress.js.map +1 -0
  53. package/dist/session-store.d.ts +39 -0
  54. package/dist/session-store.d.ts.map +1 -0
  55. package/dist/session-store.js +80 -0
  56. package/dist/session-store.js.map +1 -0
  57. package/dist/smartpbx.d.ts +47 -0
  58. package/dist/smartpbx.d.ts.map +1 -0
  59. package/dist/smartpbx.js +437 -0
  60. package/dist/smartpbx.js.map +1 -0
  61. package/dist/telnyx-codec.d.ts +41 -0
  62. package/dist/telnyx-codec.d.ts.map +1 -0
  63. package/dist/telnyx-codec.js +114 -0
  64. package/dist/telnyx-codec.js.map +1 -0
  65. package/dist/telnyx.d.ts +52 -0
  66. package/dist/telnyx.d.ts.map +1 -0
  67. package/dist/telnyx.js +550 -0
  68. package/dist/telnyx.js.map +1 -0
  69. package/dist/test-helpers.d.ts +20 -0
  70. package/dist/test-helpers.d.ts.map +1 -0
  71. package/dist/test-helpers.js +242 -0
  72. package/dist/test-helpers.js.map +1 -0
  73. package/dist/transport-helpers.d.ts +12 -0
  74. package/dist/transport-helpers.d.ts.map +1 -0
  75. package/dist/transport-helpers.js +90 -0
  76. package/dist/transport-helpers.js.map +1 -0
  77. package/dist/transport-host.d.ts +56 -0
  78. package/dist/transport-host.d.ts.map +1 -0
  79. package/dist/transport-host.js +110 -0
  80. package/dist/transport-host.js.map +1 -0
  81. package/dist/turn-metrics.d.ts +79 -0
  82. package/dist/turn-metrics.d.ts.map +1 -0
  83. package/dist/turn-metrics.js +208 -0
  84. package/dist/turn-metrics.js.map +1 -0
  85. package/dist/twilio-auth.d.ts +12 -0
  86. package/dist/twilio-auth.d.ts.map +1 -0
  87. package/dist/twilio-auth.js +44 -0
  88. package/dist/twilio-auth.js.map +1 -0
  89. package/dist/twilio.d.ts +56 -0
  90. package/dist/twilio.d.ts.map +1 -0
  91. package/dist/twilio.js +511 -0
  92. package/dist/twilio.js.map +1 -0
  93. package/dist/websocket-close.d.ts +12 -0
  94. package/dist/websocket-close.d.ts.map +1 -0
  95. package/dist/websocket-close.js +58 -0
  96. package/dist/websocket-close.js.map +1 -0
  97. package/dist/websocket-lifecycle.d.ts +29 -0
  98. package/dist/websocket-lifecycle.d.ts.map +1 -0
  99. package/dist/websocket-lifecycle.js +87 -0
  100. package/dist/websocket-lifecycle.js.map +1 -0
  101. package/dist/websocket-upgrade.d.ts +9 -0
  102. package/dist/websocket-upgrade.d.ts.map +1 -0
  103. package/dist/websocket-upgrade.js +91 -0
  104. package/dist/websocket-upgrade.js.map +1 -0
  105. package/dist/wire-carrier-control.d.ts +27 -0
  106. package/dist/wire-carrier-control.d.ts.map +1 -0
  107. package/dist/wire-carrier-control.js +116 -0
  108. package/dist/wire-carrier-control.js.map +1 -0
  109. package/package.json +32 -11
  110. package/src/admission-control.test.ts +270 -0
  111. package/src/background-audio.test.ts +224 -0
  112. package/src/browser-opus.test.ts +41 -0
  113. package/src/browser-pacing.test.ts +440 -0
  114. package/src/carrier-commands.test.ts +198 -0
  115. package/src/edge-telnyx.test.ts +333 -0
  116. package/src/edge-twilio.test.ts +293 -0
  117. package/src/edge.test.ts +727 -0
  118. package/src/graceful-drain.test.ts +306 -0
  119. package/src/inbound-audio.test.ts +58 -0
  120. package/src/index.test.ts +2078 -0
  121. package/src/outbound-playout-pipeline.test.ts +314 -0
  122. package/src/paced-playout.test.ts +247 -0
  123. package/src/playout-progress.test.ts +56 -0
  124. package/src/session-store.test.ts +274 -0
  125. package/src/smartpbx.test.ts +986 -0
  126. package/src/telnyx.test.ts +1633 -0
  127. package/src/transport-host.test.ts +51 -0
  128. package/src/turn-metrics.test.ts +503 -0
  129. package/src/twilio-auth.test.ts +36 -0
  130. package/src/twilio.test.ts +1274 -0
  131. package/src/websocket-close.test.ts +63 -0
  132. package/src/websocket-lifecycle.test.ts +49 -0
@@ -0,0 +1,20 @@
1
+ import type { Server as HttpServer } from "node:http";
2
+ import WebSocket from "ws";
3
+ export declare const DEFAULT_CONDITION_TIMEOUT_MS = 5000;
4
+ interface ClosableServer {
5
+ close(): Promise<void>;
6
+ }
7
+ export declare function registerServer<T extends ClosableServer>(server: T): T;
8
+ export declare function registerHttpServer(server: HttpServer): HttpServer;
9
+ export declare function registerSocket(socket: WebSocket): WebSocket;
10
+ export declare function setupTransportTestCleanup(): void;
11
+ export declare function openSocket(url: string, options?: WebSocket.ClientOptions): Promise<WebSocket>;
12
+ export declare function openSmartPbxSocket(url: string): Promise<WebSocket>;
13
+ export declare function openBrowserSocketReady(url: string, options?: WebSocket.ClientOptions): Promise<WebSocket>;
14
+ export declare function openBrowserClientAndReadReady(url: string, options?: WebSocket.ClientOptions): Promise<[WebSocket, any]>;
15
+ export declare function readJson(socket: WebSocket): Promise<any>;
16
+ export declare function readJsonMatching(socket: WebSocket, predicate: (message: any) => boolean): Promise<any>;
17
+ export declare function waitForCondition(predicate: () => boolean, timeoutMs?: number): Promise<void>;
18
+ export declare function waitForClose(socket: WebSocket): Promise<number>;
19
+ export {};
20
+ //# sourceMappingURL=test-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AAEtD,OAAO,SAAS,MAAM,IAAI,CAAC;AAE3B,eAAO,MAAM,4BAA4B,OAAO,CAAC;AA0BjD,UAAU,cAAc;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAMD,wBAAgB,cAAc,CAAC,CAAC,SAAS,cAAc,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAGrE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAGjE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAG3D;AAED,wBAAgB,yBAAyB,IAAI,IAAI,CA0BhD;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CAOnG;AAED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAsCxE;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CAmB/G;AAED,wBAAsB,6BAA6B,CACjD,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,SAAS,CAAC,aAAa,GAChC,OAAO,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAqB3B;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAwB9D;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,GACnC,OAAO,CAAC,GAAG,CAAC,CA0Bd;AAED,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,OAAO,EACxB,SAAS,SAA+B,GACvC,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAe/D"}
@@ -0,0 +1,242 @@
1
+ // SPDX-License-Identifier: MIT
2
+ import { afterEach, beforeEach } from "vitest";
3
+ import WebSocket from "ws";
4
+ export const DEFAULT_CONDITION_TIMEOUT_MS = 5000;
5
+ const HTTP_SERVER_CLOSE_FALLBACK_MS = 500;
6
+ function closeHttpServerBounded(httpServer) {
7
+ return new Promise((resolve) => {
8
+ let settled = false;
9
+ const finish = () => {
10
+ if (settled)
11
+ return;
12
+ settled = true;
13
+ clearTimeout(fallbackTimer);
14
+ resolve();
15
+ };
16
+ const fallbackTimer = setTimeout(finish, HTTP_SERVER_CLOSE_FALLBACK_MS);
17
+ if (typeof httpServer.closeAllConnections === "function") {
18
+ httpServer.closeAllConnections();
19
+ }
20
+ else if (typeof httpServer.closeIdleConnections === "function") {
21
+ httpServer.closeIdleConnections();
22
+ }
23
+ httpServer.close(() => finish());
24
+ });
25
+ }
26
+ let activeServers = [];
27
+ let activeHttpServers = [];
28
+ let activeSockets = [];
29
+ export function registerServer(server) {
30
+ activeServers.push(server);
31
+ return server;
32
+ }
33
+ export function registerHttpServer(server) {
34
+ activeHttpServers.push(server);
35
+ return server;
36
+ }
37
+ export function registerSocket(socket) {
38
+ activeSockets.push(socket);
39
+ return socket;
40
+ }
41
+ export function setupTransportTestCleanup() {
42
+ beforeEach(() => {
43
+ activeServers = [];
44
+ activeHttpServers = [];
45
+ activeSockets = [];
46
+ });
47
+ afterEach(async () => {
48
+ await Promise.allSettled(activeSockets.map((socket) => {
49
+ if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
50
+ socket.terminate();
51
+ }
52
+ return new Promise((resolve) => {
53
+ if (socket.readyState === WebSocket.CLOSED) {
54
+ resolve();
55
+ return;
56
+ }
57
+ socket.once("close", () => resolve());
58
+ });
59
+ }));
60
+ await Promise.allSettled(activeServers.map((server) => server.close()));
61
+ await Promise.allSettled(activeHttpServers.map((httpServer) => closeHttpServerBounded(httpServer)));
62
+ activeServers = [];
63
+ activeHttpServers = [];
64
+ activeSockets = [];
65
+ });
66
+ }
67
+ export async function openSocket(url, options) {
68
+ const socket = registerSocket(new WebSocket(url, options));
69
+ await new Promise((resolveOpen, reject) => {
70
+ socket.once("open", resolveOpen);
71
+ socket.once("error", reject);
72
+ });
73
+ return socket;
74
+ }
75
+ export async function openSmartPbxSocket(url) {
76
+ const startedAt = Date.now();
77
+ let lastError;
78
+ while (Date.now() - startedAt < DEFAULT_CONDITION_TIMEOUT_MS) {
79
+ const socket = registerSocket(new WebSocket(url));
80
+ try {
81
+ await new Promise((resolveOpen, reject) => {
82
+ const cleanup = () => {
83
+ socket.off("open", onOpen);
84
+ socket.off("error", onError);
85
+ socket.off("unexpected-response", onUnexpectedResponse);
86
+ };
87
+ const onOpen = () => {
88
+ cleanup();
89
+ resolveOpen();
90
+ };
91
+ const onError = (err) => {
92
+ cleanup();
93
+ reject(err);
94
+ };
95
+ const onUnexpectedResponse = (_request, response) => {
96
+ cleanup();
97
+ response.resume();
98
+ reject(new Error(`Unexpected server response: ${String(response.statusCode)}`));
99
+ };
100
+ socket.once("open", onOpen);
101
+ socket.once("error", onError);
102
+ socket.once("unexpected-response", onUnexpectedResponse);
103
+ });
104
+ return socket;
105
+ }
106
+ catch (err) {
107
+ socket.terminate();
108
+ lastError = err;
109
+ if (!(err instanceof Error) || !err.message.includes("Unexpected server response: 404"))
110
+ throw err;
111
+ await new Promise((resolve) => setTimeout(resolve, 10));
112
+ }
113
+ }
114
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
115
+ }
116
+ export async function openBrowserSocketReady(url, options) {
117
+ const socket = registerSocket(new WebSocket(url, options));
118
+ await new Promise((resolve, reject) => {
119
+ const onMessage = (data, isBinary) => {
120
+ if (isBinary)
121
+ return;
122
+ try {
123
+ const parsed = JSON.parse(data.toString());
124
+ if (parsed.type === "ready") {
125
+ socket.off("message", onMessage);
126
+ resolve();
127
+ }
128
+ }
129
+ catch {
130
+ // Ignore non-JSON frames while waiting for ready.
131
+ }
132
+ };
133
+ socket.on("message", onMessage);
134
+ socket.once("error", reject);
135
+ });
136
+ return socket;
137
+ }
138
+ export async function openBrowserClientAndReadReady(url, options) {
139
+ const socket = registerSocket(new WebSocket(url, options));
140
+ let readyMessage;
141
+ await new Promise((resolve, reject) => {
142
+ const onMessage = (data, isBinary) => {
143
+ if (isBinary)
144
+ return;
145
+ try {
146
+ const parsed = JSON.parse(data.toString());
147
+ if (parsed.type === "ready") {
148
+ readyMessage = parsed;
149
+ socket.off("message", onMessage);
150
+ resolve();
151
+ }
152
+ }
153
+ catch {
154
+ // Ignore non-JSON frames while waiting for ready.
155
+ }
156
+ };
157
+ socket.on("message", onMessage);
158
+ socket.once("error", reject);
159
+ });
160
+ return [socket, readyMessage];
161
+ }
162
+ export async function readJson(socket) {
163
+ return new Promise((resolve, reject) => {
164
+ const cleanup = () => {
165
+ socket.off("message", onMessage);
166
+ socket.off("close", onClose);
167
+ socket.off("error", onError);
168
+ };
169
+ const onMessage = (data, isBinary) => {
170
+ if (isBinary)
171
+ return;
172
+ cleanup();
173
+ resolve(JSON.parse(data.toString()));
174
+ };
175
+ const onClose = () => {
176
+ cleanup();
177
+ reject(new Error("Socket closed before JSON message"));
178
+ };
179
+ const onError = (err) => {
180
+ cleanup();
181
+ reject(err);
182
+ };
183
+ socket.on("message", onMessage);
184
+ socket.once("close", onClose);
185
+ socket.once("error", onError);
186
+ });
187
+ }
188
+ export async function readJsonMatching(socket, predicate) {
189
+ return new Promise((resolve, reject) => {
190
+ const cleanup = () => {
191
+ socket.off("message", onMessage);
192
+ socket.off("close", onClose);
193
+ socket.off("error", onError);
194
+ };
195
+ const onMessage = (data, isBinary) => {
196
+ if (isBinary)
197
+ return;
198
+ const message = JSON.parse(data.toString());
199
+ if (!predicate(message))
200
+ return;
201
+ cleanup();
202
+ resolve(message);
203
+ };
204
+ const onClose = () => {
205
+ cleanup();
206
+ reject(new Error("Socket closed before matching JSON message"));
207
+ };
208
+ const onError = (err) => {
209
+ cleanup();
210
+ reject(err);
211
+ };
212
+ socket.on("message", onMessage);
213
+ socket.once("close", onClose);
214
+ socket.once("error", onError);
215
+ });
216
+ }
217
+ export async function waitForCondition(predicate, timeoutMs = DEFAULT_CONDITION_TIMEOUT_MS) {
218
+ const startedAt = Date.now();
219
+ while (Date.now() - startedAt < timeoutMs) {
220
+ if (predicate())
221
+ return;
222
+ await new Promise((resolve) => setTimeout(resolve, 10));
223
+ }
224
+ throw new Error("Timed out waiting for condition");
225
+ }
226
+ export function waitForClose(socket) {
227
+ if (socket.readyState === WebSocket.CLOSED) {
228
+ return Promise.resolve(1006);
229
+ }
230
+ return new Promise((resolve) => {
231
+ let done = false;
232
+ const finish = (code) => {
233
+ if (!done) {
234
+ done = true;
235
+ resolve(code);
236
+ }
237
+ };
238
+ socket.on("close", (code) => finish(code));
239
+ socket.on("error", () => finish(1006));
240
+ });
241
+ }
242
+ //# sourceMappingURL=test-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { RawData } from "ws";
2
+ export declare function positiveInteger(value: unknown): number | null;
3
+ export declare function nonNegativeInteger(value: unknown): number | null;
4
+ export declare function numberFromString(value: number | string | undefined): number | null;
5
+ export declare function optionalPositiveIntegerString(value: string | undefined, name: string): number | undefined;
6
+ export declare function optionalNonNegativeIntegerString(value: string | undefined, name: string): number | undefined;
7
+ export declare function rawDataToText(data: RawData): string;
8
+ export declare function rawDataByteLength(data: RawData): number;
9
+ export declare function cloneRawData(data: RawData): RawData;
10
+ export declare function decodeStrictBase64(value: string, fieldName: string): Uint8Array;
11
+ export declare function requireTtsAudioSampleRate(value: unknown): number;
12
+ //# sourceMappingURL=transport-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport-helpers.d.ts","sourceRoot":"","sources":["../src/transport-helpers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAElC,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAG7D;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAGhE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAOlF;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMzG;AAED,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAM5G;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAMnD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAMvD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAMnD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU,CAQ/E;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAIhE"}
@@ -0,0 +1,90 @@
1
+ // SPDX-License-Identifier: MIT
2
+ export function positiveInteger(value) {
3
+ if (typeof value !== "number" || !Number.isInteger(value) || value <= 0)
4
+ return null;
5
+ return value;
6
+ }
7
+ export function nonNegativeInteger(value) {
8
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0)
9
+ return null;
10
+ return value;
11
+ }
12
+ export function numberFromString(value) {
13
+ if (typeof value === "number" && Number.isFinite(value))
14
+ return value;
15
+ if (typeof value === "string" && value.trim().length > 0) {
16
+ const parsed = Number(value);
17
+ if (Number.isFinite(parsed))
18
+ return parsed;
19
+ }
20
+ return null;
21
+ }
22
+ export function optionalPositiveIntegerString(value, name) {
23
+ if (value === undefined)
24
+ return undefined;
25
+ if (!/^[0-9]+$/.test(value))
26
+ throw new Error(`${name} must be a positive integer string`);
27
+ const parsed = Number(value);
28
+ if (!Number.isSafeInteger(parsed) || parsed <= 0)
29
+ throw new Error(`${name} must be a positive integer string`);
30
+ return parsed;
31
+ }
32
+ export function optionalNonNegativeIntegerString(value, name) {
33
+ if (value === undefined)
34
+ return undefined;
35
+ if (!/^[0-9]+$/.test(value))
36
+ throw new Error(`${name} must be a non-negative integer string`);
37
+ const parsed = Number(value);
38
+ if (!Number.isSafeInteger(parsed))
39
+ throw new Error(`${name} must be a non-negative integer string`);
40
+ return parsed;
41
+ }
42
+ export function rawDataToText(data) {
43
+ if (typeof data === "string")
44
+ return data;
45
+ if (Buffer.isBuffer(data))
46
+ return data.toString("utf8");
47
+ if (data instanceof ArrayBuffer)
48
+ return Buffer.from(data).toString("utf8");
49
+ if (Array.isArray(data))
50
+ return Buffer.concat(data).toString("utf8");
51
+ throw new Error("Unsupported text message payload");
52
+ }
53
+ export function rawDataByteLength(data) {
54
+ if (typeof data === "string")
55
+ return Buffer.byteLength(data, "utf8");
56
+ if (Buffer.isBuffer(data))
57
+ return data.byteLength;
58
+ if (data instanceof ArrayBuffer)
59
+ return data.byteLength;
60
+ if (Array.isArray(data))
61
+ return data.reduce((sum, chunk) => sum + chunk.byteLength, 0);
62
+ return 0;
63
+ }
64
+ export function cloneRawData(data) {
65
+ if (typeof data === "string")
66
+ return data;
67
+ if (Buffer.isBuffer(data))
68
+ return Buffer.from(data);
69
+ if (data instanceof ArrayBuffer)
70
+ return data.slice(0);
71
+ if (Array.isArray(data))
72
+ return data.map((chunk) => Buffer.from(chunk));
73
+ throw new Error("Unsupported websocket message payload");
74
+ }
75
+ export function decodeStrictBase64(value, fieldName) {
76
+ if (typeof value !== "string" || value.length === 0) {
77
+ throw new Error(`${fieldName} must be a non-empty base64 string`);
78
+ }
79
+ if (value.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) {
80
+ throw new Error(`${fieldName} must be valid base64`);
81
+ }
82
+ return Uint8Array.from(Buffer.from(value, "base64"));
83
+ }
84
+ export function requireTtsAudioSampleRate(value) {
85
+ const sampleRateHz = positiveInteger(value);
86
+ if (sampleRateHz === null)
87
+ throw new Error("tts.audio sampleRateHz must be a positive integer");
88
+ return sampleRateHz;
89
+ }
90
+ //# sourceMappingURL=transport-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport-helpers.js","sourceRoot":"","sources":["../src/transport-helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import type { IncomingMessage } from "node:http";
2
+ import type { Socket } from "node:net";
3
+ import { WebSocket, WebSocketServer, type RawData } from "ws";
4
+ import type { VoiceAgentSession } from "@kuralle-syrinx/core";
5
+ export interface TransportHostConfig {
6
+ readonly heartbeatIntervalMs: number;
7
+ readonly startupTimeoutMs: number;
8
+ readonly maxSessionDurationMs: number;
9
+ readonly maxBufferedAmountBytes: number;
10
+ readonly maxInboundMessageBytes: number;
11
+ }
12
+ export interface TransportAdmissionOptions {
13
+ readonly maxConcurrentSessions?: number;
14
+ readonly maxConcurrentSessionsScope?: "path" | "server";
15
+ readonly onAdmissionRejected?: () => void;
16
+ /**
17
+ * Authorize an inbound connection before the WebSocket upgrade completes. Return
18
+ * false (or throw) to reject with 4401. Voice endpoints are unauthenticated by
19
+ * default and each connection incurs provider cost and can attach to a live
20
+ * session — set this (shared secret / bearer / Twilio signature) before exposing
21
+ * the endpoint. Receives the raw upgrade request (headers + URL) so it can read
22
+ * an `Authorization` header or a `?token=` query param.
23
+ */
24
+ readonly authorize?: (request: IncomingMessage) => boolean | Promise<boolean>;
25
+ }
26
+ export declare const TRANSPORT_ADMISSION_REJECTED_METRIC = "transport.admission_rejected";
27
+ export declare function rejectWebSocketAdmission(wsServer: WebSocketServer, request: IncomingMessage, socket: Socket, head: Buffer, code?: number, reason?: string): void;
28
+ export interface GracefulCloseOptions {
29
+ readonly graceful?: boolean;
30
+ readonly drainDeadlineMs?: number;
31
+ }
32
+ export interface TransportAdapter<TState> {
33
+ createState(): TState;
34
+ acquireSession(args: {
35
+ readonly request: IncomingMessage;
36
+ readonly state: TState;
37
+ readonly shouldAbort: () => boolean;
38
+ readonly onSessionCreated: (session: VoiceAgentSession) => void;
39
+ }): Promise<{
40
+ readonly session: VoiceAgentSession;
41
+ readonly resumed: boolean;
42
+ }>;
43
+ wireSession(session: VoiceAgentSession, socket: WebSocket, state: TState, disposers: Array<() => void>): (reason: string) => void;
44
+ processMessage(data: RawData, isBinary: boolean, session: VoiceAgentSession, state: TState): void;
45
+ onSocketClose?(state: TState, session: VoiceAgentSession | null): void;
46
+ onDisconnect(session: VoiceAgentSession, state: TState, opts: {
47
+ readonly maxSessionTimedOut: boolean;
48
+ }): void;
49
+ onStartupTimeout(state: TState, session: VoiceAgentSession): void;
50
+ sendReady?(session: VoiceAgentSession, socket: WebSocket, state: TState, resumed: boolean, config: TransportHostConfig): void;
51
+ sendError(socket: WebSocket, state: TState, message: string): void;
52
+ sendStartupError(socket: WebSocket, state: TState, err: unknown, isTimeout: boolean): void;
53
+ onMaxSessionTimeout?(socket: WebSocket, state: TState): void;
54
+ }
55
+ export declare function runWebSocketConnection<TState>(socket: WebSocket, request: IncomingMessage, config: TransportHostConfig, adapter: TransportAdapter<TState>): Promise<void>;
56
+ //# sourceMappingURL=transport-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport-host.d.ts","sourceRoot":"","sources":["../src/transport-host.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ // SPDX-License-Identifier: MIT
2
+ import { WebSocket } from "ws";
3
+ import { WebSocketStartupTimeoutError, startWebSocketHeartbeat, startWebSocketMaxSessionDuration, withWebSocketStartupTimeout, } from "./websocket-lifecycle.js";
4
+ import { cloneRawData, rawDataByteLength } from "./transport-helpers.js";
5
+ export const TRANSPORT_ADMISSION_REJECTED_METRIC = "transport.admission_rejected";
6
+ export function rejectWebSocketAdmission(wsServer, request, socket, head, code = 1013, reason = "try again later") {
7
+ wsServer.handleUpgrade(request, socket, head, (websocket) => {
8
+ websocket.close(code, reason);
9
+ });
10
+ }
11
+ export async function runWebSocketConnection(socket, request, config, adapter) {
12
+ const state = adapter.createState();
13
+ const disposers = [];
14
+ const pendingMessages = [];
15
+ let pendingMessageBytes = 0;
16
+ let ready = false;
17
+ let socketClosed = socket.readyState === WebSocket.CLOSED || socket.readyState === WebSocket.CLOSING;
18
+ if (socketClosed) {
19
+ return;
20
+ }
21
+ let maxSessionTimedOut = false;
22
+ let startupTimedOut = false;
23
+ let teardown = () => undefined;
24
+ let session = null;
25
+ const startupSession = {};
26
+ const processMessage = (data, isBinary) => {
27
+ if (!session)
28
+ return;
29
+ adapter.processMessage(data, isBinary, session, state);
30
+ };
31
+ const handleMessage = (data, isBinary) => {
32
+ try {
33
+ const byteLength = rawDataByteLength(data);
34
+ if (byteLength > config.maxInboundMessageBytes) {
35
+ adapter.sendError(socket, state, `Websocket message exceeds maxInboundMessageBytes (${String(config.maxInboundMessageBytes)})`);
36
+ socket.close(1009, "websocket message too large");
37
+ return;
38
+ }
39
+ if (!ready) {
40
+ pendingMessageBytes += byteLength;
41
+ if (pendingMessageBytes > config.maxInboundMessageBytes) {
42
+ adapter.sendError(socket, state, `Pending websocket input exceeds maxInboundMessageBytes (${String(config.maxInboundMessageBytes)}) before session ready`);
43
+ socket.close(1009, "websocket pending input too large");
44
+ return;
45
+ }
46
+ pendingMessages.push({ data: cloneRawData(data), isBinary, byteLength });
47
+ return;
48
+ }
49
+ processMessage(data, isBinary);
50
+ }
51
+ catch (err) {
52
+ adapter.sendError(socket, state, err instanceof Error ? err.message : String(err));
53
+ }
54
+ };
55
+ socket.on("message", handleMessage);
56
+ socket.on("close", () => {
57
+ socketClosed = true;
58
+ adapter.onSocketClose?.(state, session);
59
+ teardown("disconnect");
60
+ for (const dispose of disposers.splice(0))
61
+ dispose();
62
+ if (session) {
63
+ adapter.onDisconnect(session, state, { maxSessionTimedOut });
64
+ }
65
+ });
66
+ try {
67
+ const startup = adapter.acquireSession({
68
+ request,
69
+ state,
70
+ shouldAbort: () => socketClosed || startupTimedOut,
71
+ onSessionCreated: (s) => { startupSession.current = s; },
72
+ });
73
+ startup.catch(() => undefined);
74
+ const acquired = await withWebSocketStartupTimeout(startup, config.startupTimeoutMs);
75
+ session = acquired.session;
76
+ if (socketClosed) {
77
+ adapter.onDisconnect(session, state, { maxSessionTimedOut });
78
+ return;
79
+ }
80
+ startWebSocketHeartbeat(socket, config.heartbeatIntervalMs, disposers);
81
+ startWebSocketMaxSessionDuration(socket, config.maxSessionDurationMs, disposers, () => {
82
+ maxSessionTimedOut = true;
83
+ adapter.onMaxSessionTimeout?.(socket, state);
84
+ });
85
+ teardown = adapter.wireSession(session, socket, state, disposers);
86
+ adapter.sendReady?.(session, socket, state, acquired.resumed, config);
87
+ ready = true;
88
+ for (const pending of pendingMessages.splice(0)) {
89
+ pendingMessageBytes -= pending.byteLength;
90
+ try {
91
+ processMessage(pending.data, pending.isBinary);
92
+ }
93
+ catch (err) {
94
+ adapter.sendError(socket, state, err instanceof Error ? err.message : String(err));
95
+ }
96
+ }
97
+ pendingMessageBytes = 0;
98
+ }
99
+ catch (err) {
100
+ if (err instanceof WebSocketStartupTimeoutError) {
101
+ startupTimedOut = true;
102
+ if (startupSession.current) {
103
+ adapter.onStartupTimeout(state, startupSession.current);
104
+ }
105
+ }
106
+ adapter.sendStartupError(socket, state, err, err instanceof WebSocketStartupTimeoutError);
107
+ socket.close(1011, "session initialization failed");
108
+ }
109
+ }
110
+ //# sourceMappingURL=transport-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport-host.js","sourceRoot":"","sources":["../src/transport-host.ts"],"names":[],"mappings":"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"}