telnyx 6.41.1 → 6.43.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 (256) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/client.d.mts +2 -2
  3. package/client.d.mts.map +1 -1
  4. package/client.d.ts +2 -2
  5. package/client.d.ts.map +1 -1
  6. package/client.js +11 -0
  7. package/client.js.map +1 -1
  8. package/client.mjs +11 -0
  9. package/client.mjs.map +1 -1
  10. package/core/EventEmitter.d.mts +11 -0
  11. package/core/EventEmitter.d.mts.map +1 -1
  12. package/core/EventEmitter.d.ts +11 -0
  13. package/core/EventEmitter.d.ts.map +1 -1
  14. package/core/EventEmitter.js +15 -1
  15. package/core/EventEmitter.js.map +1 -1
  16. package/core/EventEmitter.mjs +13 -0
  17. package/core/EventEmitter.mjs.map +1 -1
  18. package/internal/types.d.mts +6 -6
  19. package/internal/types.d.mts.map +1 -1
  20. package/internal/types.d.ts +6 -6
  21. package/internal/types.d.ts.map +1 -1
  22. package/internal/utils/env.js +2 -2
  23. package/internal/utils/env.js.map +1 -1
  24. package/internal/utils/env.mjs +2 -2
  25. package/internal/utils/env.mjs.map +1 -1
  26. package/internal/ws-adapter-browser.d.mts +34 -0
  27. package/internal/ws-adapter-browser.d.mts.map +1 -0
  28. package/internal/ws-adapter-browser.d.ts +34 -0
  29. package/internal/ws-adapter-browser.d.ts.map +1 -0
  30. package/internal/ws-adapter-browser.js +88 -0
  31. package/internal/ws-adapter-browser.js.map +1 -0
  32. package/internal/ws-adapter-browser.mjs +84 -0
  33. package/internal/ws-adapter-browser.mjs.map +1 -0
  34. package/internal/ws-adapter-node.d.mts +27 -0
  35. package/internal/ws-adapter-node.d.mts.map +1 -0
  36. package/internal/ws-adapter-node.d.ts +27 -0
  37. package/internal/ws-adapter-node.d.ts.map +1 -0
  38. package/internal/ws-adapter-node.js +90 -0
  39. package/internal/ws-adapter-node.js.map +1 -0
  40. package/internal/ws-adapter-node.mjs +86 -0
  41. package/internal/ws-adapter-node.mjs.map +1 -0
  42. package/internal/ws-adapter.d.mts +24 -0
  43. package/internal/ws-adapter.d.mts.map +1 -0
  44. package/internal/ws-adapter.d.ts +24 -0
  45. package/internal/ws-adapter.d.ts.map +1 -0
  46. package/internal/ws-adapter.js +11 -0
  47. package/internal/ws-adapter.js.map +1 -0
  48. package/internal/ws-adapter.mjs +8 -0
  49. package/internal/ws-adapter.mjs.map +1 -0
  50. package/internal/ws.d.mts +80 -0
  51. package/internal/ws.d.mts.map +1 -0
  52. package/internal/ws.d.ts +80 -0
  53. package/internal/ws.d.ts.map +1 -0
  54. package/internal/ws.js +153 -0
  55. package/internal/ws.js.map +1 -0
  56. package/internal/ws.mjs +147 -0
  57. package/internal/ws.mjs.map +1 -0
  58. package/lib/text-to-speech-ws-base.d.mts +106 -0
  59. package/lib/text-to-speech-ws-base.d.mts.map +1 -0
  60. package/lib/text-to-speech-ws-base.d.ts +106 -0
  61. package/lib/text-to-speech-ws-base.d.ts.map +1 -0
  62. package/lib/text-to-speech-ws-base.js +475 -0
  63. package/lib/text-to-speech-ws-base.js.map +1 -0
  64. package/lib/text-to-speech-ws-base.mjs +471 -0
  65. package/lib/text-to-speech-ws-base.mjs.map +1 -0
  66. package/lib/text-to-speech-ws-internal.d.mts +71 -0
  67. package/lib/text-to-speech-ws-internal.d.mts.map +1 -0
  68. package/lib/text-to-speech-ws-internal.d.ts +71 -0
  69. package/lib/text-to-speech-ws-internal.d.ts.map +1 -0
  70. package/lib/text-to-speech-ws-internal.js +47 -0
  71. package/lib/text-to-speech-ws-internal.js.map +1 -0
  72. package/lib/text-to-speech-ws-internal.mjs +41 -0
  73. package/lib/text-to-speech-ws-internal.mjs.map +1 -0
  74. package/lib/text-to-speech-ws.d.mts +13 -0
  75. package/lib/text-to-speech-ws.d.mts.map +1 -0
  76. package/lib/text-to-speech-ws.d.ts +13 -0
  77. package/lib/text-to-speech-ws.d.ts.map +1 -0
  78. package/lib/text-to-speech-ws.js +30 -0
  79. package/lib/text-to-speech-ws.js.map +1 -0
  80. package/lib/text-to-speech-ws.mjs +25 -0
  81. package/lib/text-to-speech-ws.mjs.map +1 -0
  82. package/lib/webhooks.d.mts +6 -0
  83. package/lib/webhooks.d.mts.map +1 -1
  84. package/lib/webhooks.d.ts +6 -0
  85. package/lib/webhooks.d.ts.map +1 -1
  86. package/lib/webhooks.js +16 -0
  87. package/lib/webhooks.js.map +1 -1
  88. package/lib/webhooks.mjs +14 -0
  89. package/lib/webhooks.mjs.map +1 -1
  90. package/package.json +1 -1
  91. package/resources/ai/assistants/assistants.d.mts +938 -65
  92. package/resources/ai/assistants/assistants.d.mts.map +1 -1
  93. package/resources/ai/assistants/assistants.d.ts +938 -65
  94. package/resources/ai/assistants/assistants.d.ts.map +1 -1
  95. package/resources/ai/assistants/assistants.js +0 -1
  96. package/resources/ai/assistants/assistants.js.map +1 -1
  97. package/resources/ai/assistants/assistants.mjs +0 -1
  98. package/resources/ai/assistants/assistants.mjs.map +1 -1
  99. package/resources/ai/assistants/versions.d.mts +563 -25
  100. package/resources/ai/assistants/versions.d.mts.map +1 -1
  101. package/resources/ai/assistants/versions.d.ts +563 -25
  102. package/resources/ai/assistants/versions.d.ts.map +1 -1
  103. package/resources/ai/conversations/conversations.d.mts +2 -2
  104. package/resources/ai/conversations/conversations.d.mts.map +1 -1
  105. package/resources/ai/conversations/conversations.d.ts +2 -2
  106. package/resources/ai/conversations/conversations.d.ts.map +1 -1
  107. package/resources/ai/conversations/conversations.js.map +1 -1
  108. package/resources/ai/conversations/conversations.mjs +1 -1
  109. package/resources/ai/conversations/conversations.mjs.map +1 -1
  110. package/resources/ai/conversations/index.d.mts +1 -1
  111. package/resources/ai/conversations/index.d.mts.map +1 -1
  112. package/resources/ai/conversations/index.d.ts +1 -1
  113. package/resources/ai/conversations/index.d.ts.map +1 -1
  114. package/resources/ai/conversations/index.js.map +1 -1
  115. package/resources/ai/conversations/index.mjs +1 -1
  116. package/resources/ai/conversations/index.mjs.map +1 -1
  117. package/resources/ai/conversations/messages.d.mts +46 -48
  118. package/resources/ai/conversations/messages.d.mts.map +1 -1
  119. package/resources/ai/conversations/messages.d.ts +46 -48
  120. package/resources/ai/conversations/messages.d.ts.map +1 -1
  121. package/resources/ai/conversations/messages.js +9 -6
  122. package/resources/ai/conversations/messages.js.map +1 -1
  123. package/resources/ai/conversations/messages.mjs +9 -6
  124. package/resources/ai/conversations/messages.mjs.map +1 -1
  125. package/resources/calls/actions.d.mts +114 -6
  126. package/resources/calls/actions.d.mts.map +1 -1
  127. package/resources/calls/actions.d.ts +114 -6
  128. package/resources/calls/actions.d.ts.map +1 -1
  129. package/resources/calls/actions.js +4 -0
  130. package/resources/calls/actions.js.map +1 -1
  131. package/resources/calls/actions.mjs +4 -0
  132. package/resources/calls/actions.mjs.map +1 -1
  133. package/resources/calls/calls.d.mts +168 -8
  134. package/resources/calls/calls.d.mts.map +1 -1
  135. package/resources/calls/calls.d.ts +168 -8
  136. package/resources/calls/calls.d.ts.map +1 -1
  137. package/resources/calls/calls.js +4 -0
  138. package/resources/calls/calls.js.map +1 -1
  139. package/resources/calls/calls.mjs +4 -0
  140. package/resources/calls/calls.mjs.map +1 -1
  141. package/resources/index.d.mts +2 -3
  142. package/resources/index.d.mts.map +1 -1
  143. package/resources/index.d.ts +2 -3
  144. package/resources/index.d.ts.map +1 -1
  145. package/resources/index.js +2 -7
  146. package/resources/index.js.map +1 -1
  147. package/resources/index.mjs +1 -2
  148. package/resources/index.mjs.map +1 -1
  149. package/resources/messages/messages.d.mts +4 -0
  150. package/resources/messages/messages.d.mts.map +1 -1
  151. package/resources/messages/messages.d.ts +4 -0
  152. package/resources/messages/messages.d.ts.map +1 -1
  153. package/resources/messages/messages.js.map +1 -1
  154. package/resources/messages/messages.mjs.map +1 -1
  155. package/resources/session-analysis/session-analysis.d.mts +3 -13
  156. package/resources/session-analysis/session-analysis.d.mts.map +1 -1
  157. package/resources/session-analysis/session-analysis.d.ts +3 -13
  158. package/resources/session-analysis/session-analysis.d.ts.map +1 -1
  159. package/resources/session-analysis/session-analysis.js.map +1 -1
  160. package/resources/session-analysis/session-analysis.mjs.map +1 -1
  161. package/resources/texml/accounts/calls/calls.d.mts +45 -0
  162. package/resources/texml/accounts/calls/calls.d.mts.map +1 -1
  163. package/resources/texml/accounts/calls/calls.d.ts +45 -0
  164. package/resources/texml/accounts/calls/calls.d.ts.map +1 -1
  165. package/resources/texml/accounts/calls/calls.js.map +1 -1
  166. package/resources/texml/accounts/calls/calls.mjs.map +1 -1
  167. package/resources/text-to-speech/index.d.mts +2 -1
  168. package/resources/text-to-speech/index.d.mts.map +1 -1
  169. package/resources/text-to-speech/index.d.ts +2 -1
  170. package/resources/text-to-speech/index.d.ts.map +1 -1
  171. package/resources/text-to-speech/index.js.map +1 -1
  172. package/resources/text-to-speech/index.mjs.map +1 -1
  173. package/resources/text-to-speech/internal-base.d.mts +1 -48
  174. package/resources/text-to-speech/internal-base.d.mts.map +1 -1
  175. package/resources/text-to-speech/internal-base.d.ts +1 -48
  176. package/resources/text-to-speech/internal-base.d.ts.map +1 -1
  177. package/resources/text-to-speech/internal-base.js +5 -48
  178. package/resources/text-to-speech/internal-base.js.map +1 -1
  179. package/resources/text-to-speech/internal-base.mjs +1 -44
  180. package/resources/text-to-speech/internal-base.mjs.map +1 -1
  181. package/resources/text-to-speech/text-to-speech.d.mts +28 -3
  182. package/resources/text-to-speech/text-to-speech.d.mts.map +1 -1
  183. package/resources/text-to-speech/text-to-speech.d.ts +28 -3
  184. package/resources/text-to-speech/text-to-speech.d.ts.map +1 -1
  185. package/resources/text-to-speech/text-to-speech.js +1 -1
  186. package/resources/text-to-speech/text-to-speech.mjs +1 -1
  187. package/resources/text-to-speech/ws-base.d.mts +2 -0
  188. package/resources/text-to-speech/ws-base.d.mts.map +1 -0
  189. package/resources/text-to-speech/ws-base.d.ts +2 -0
  190. package/resources/text-to-speech/ws-base.d.ts.map +1 -0
  191. package/resources/text-to-speech/ws-base.js +7 -0
  192. package/resources/text-to-speech/ws-base.js.map +1 -0
  193. package/resources/text-to-speech/ws-base.mjs +3 -0
  194. package/resources/text-to-speech/ws-base.mjs.map +1 -0
  195. package/resources/text-to-speech/ws.d.mts +2 -41
  196. package/resources/text-to-speech/ws.d.mts.map +1 -1
  197. package/resources/text-to-speech/ws.d.ts +2 -41
  198. package/resources/text-to-speech/ws.d.ts.map +1 -1
  199. package/resources/text-to-speech/ws.js +2 -182
  200. package/resources/text-to-speech/ws.js.map +1 -1
  201. package/resources/text-to-speech/ws.mjs +1 -180
  202. package/resources/text-to-speech/ws.mjs.map +1 -1
  203. package/resources/verify-profiles.d.mts +97 -121
  204. package/resources/verify-profiles.d.mts.map +1 -1
  205. package/resources/verify-profiles.d.ts +97 -121
  206. package/resources/verify-profiles.d.ts.map +1 -1
  207. package/resources/webhooks.d.mts +642 -7
  208. package/resources/webhooks.d.mts.map +1 -1
  209. package/resources/webhooks.d.ts +642 -7
  210. package/resources/webhooks.d.ts.map +1 -1
  211. package/resources/webhooks.js +4 -10
  212. package/resources/webhooks.js.map +1 -1
  213. package/resources/webhooks.mjs +5 -11
  214. package/resources/webhooks.mjs.map +1 -1
  215. package/resources/whatsapp/phone-numbers/profile/profile.d.mts +5 -0
  216. package/resources/whatsapp/phone-numbers/profile/profile.d.mts.map +1 -1
  217. package/resources/whatsapp/phone-numbers/profile/profile.d.ts +5 -0
  218. package/resources/whatsapp/phone-numbers/profile/profile.d.ts.map +1 -1
  219. package/resources/whatsapp/phone-numbers/profile/profile.js.map +1 -1
  220. package/resources/whatsapp/phone-numbers/profile/profile.mjs.map +1 -1
  221. package/src/client.ts +22 -0
  222. package/src/core/EventEmitter.ts +16 -0
  223. package/src/internal/types.ts +6 -8
  224. package/src/internal/utils/env.ts +2 -2
  225. package/src/internal/ws-adapter-browser.ts +123 -0
  226. package/src/internal/ws-adapter-node.ts +105 -0
  227. package/src/internal/ws-adapter.ts +30 -0
  228. package/src/internal/ws.ts +193 -0
  229. package/src/lib/text-to-speech-ws-base.ts +618 -0
  230. package/src/lib/text-to-speech-ws-internal.ts +111 -0
  231. package/src/lib/text-to-speech-ws.ts +40 -0
  232. package/src/lib/webhooks.ts +27 -0
  233. package/src/resources/ai/assistants/assistants.ts +1065 -65
  234. package/src/resources/ai/assistants/versions.ts +639 -25
  235. package/src/resources/ai/conversations/conversations.ts +12 -2
  236. package/src/resources/ai/conversations/index.ts +6 -1
  237. package/src/resources/ai/conversations/messages.ts +67 -54
  238. package/src/resources/calls/actions.ts +184 -4
  239. package/src/resources/calls/calls.ts +191 -4
  240. package/src/resources/index.ts +6 -12
  241. package/src/resources/messages/messages.ts +5 -0
  242. package/src/resources/session-analysis/session-analysis.ts +3 -16
  243. package/src/resources/texml/accounts/calls/calls.ts +54 -0
  244. package/src/resources/text-to-speech/index.ts +2 -1
  245. package/src/resources/text-to-speech/internal-base.ts +6 -95
  246. package/src/resources/text-to-speech/text-to-speech.ts +33 -3
  247. package/src/resources/text-to-speech/ws-base.ts +7 -0
  248. package/src/resources/text-to-speech/ws.ts +2 -201
  249. package/src/resources/verify-profiles.ts +109 -142
  250. package/src/resources/webhooks.ts +886 -45
  251. package/src/resources/whatsapp/phone-numbers/profile/profile.ts +7 -0
  252. package/src/version.ts +1 -1
  253. package/version.d.mts +1 -1
  254. package/version.d.ts +1 -1
  255. package/version.js +1 -1
  256. package/version.mjs +1 -1
@@ -0,0 +1,123 @@
1
+ import type { WebSocketLike } from './ws-adapter';
2
+
3
+ /** A generic event listener callback. */
4
+ type Listener = (...args: any[]) => void;
5
+
6
+ /** A DOM-style event handler passed to addEventListener/removeEventListener. */
7
+ type DOMEventHandler = (ev: any) => void;
8
+
9
+ // Minimal browser API type declarations.
10
+ declare class WebSocket {
11
+ readonly readyState: number;
12
+ binaryType: string;
13
+ send(data: string | ArrayBufferLike | ArrayBufferView): void;
14
+ close(code?: number, reason?: string): void;
15
+ addEventListener(type: string, listener: DOMEventHandler): void;
16
+ removeEventListener(type: string, listener: DOMEventHandler): void;
17
+ }
18
+
19
+ interface MessageEvent {
20
+ data: any;
21
+ }
22
+
23
+ interface CloseEvent {
24
+ code: number;
25
+ reason: string;
26
+ }
27
+
28
+ export class BrowserWebSocket implements WebSocketLike {
29
+ private _ws: WebSocket;
30
+ private _listenerMap = new Map<string, Map<Listener, DOMEventHandler>>();
31
+
32
+ constructor(ws: WebSocket) {
33
+ this._ws = ws;
34
+ this._ws.binaryType = 'arraybuffer';
35
+ }
36
+
37
+ /** The underlying platform-specific socket. Code that accesses this will not be isomorphic across server and browser environments. */
38
+ get platformSocket(): WebSocket {
39
+ return this._ws;
40
+ }
41
+
42
+ get readyState(): number {
43
+ return this._ws.readyState;
44
+ }
45
+
46
+ send(data: string | ArrayBufferLike | ArrayBufferView): void {
47
+ this._ws.send(data);
48
+ }
49
+
50
+ close(code?: number, reason?: string): void {
51
+ this._ws.close(code, reason);
52
+ }
53
+
54
+ on(event: string, listener: Listener): void {
55
+ const wrapped = this._wrapListener(event, listener);
56
+ this._listenersFor(event).set(listener, wrapped);
57
+ this._ws.addEventListener(event, wrapped);
58
+ }
59
+
60
+ off(event: string, listener: Listener): void {
61
+ const byListener = this._listenerMap.get(event);
62
+ if (!byListener) return;
63
+ const wrapped = byListener.get(listener);
64
+ if (wrapped) {
65
+ byListener.delete(listener);
66
+ this._ws.removeEventListener(event, wrapped);
67
+ }
68
+ }
69
+
70
+ once(event: string, listener: Listener): void {
71
+ const onceListener: Listener = (...args) => {
72
+ this.off(event, listener);
73
+ listener(...args);
74
+ };
75
+ const wrapped = this._wrapListener(event, onceListener);
76
+ this._listenersFor(event).set(listener, wrapped);
77
+ this._ws.addEventListener(event, wrapped);
78
+ }
79
+
80
+ private _listenersFor(event: string): Map<Listener, DOMEventHandler> {
81
+ let map = this._listenerMap.get(event);
82
+ if (!map) {
83
+ map = new Map();
84
+ this._listenerMap.set(event, map);
85
+ }
86
+ return map;
87
+ }
88
+
89
+ /**
90
+ * Converts browser event objects to positional arguments matching the
91
+ * {@link WebSocketLike} interface.
92
+ */
93
+ private _wrapListener(event: string, listener: Listener): DOMEventHandler {
94
+ switch (event) {
95
+ case 'message':
96
+ return (ev: MessageEvent) => {
97
+ const isBinary = typeof ev.data !== 'string';
98
+ listener(ev.data, isBinary);
99
+ };
100
+
101
+ case 'close':
102
+ return (ev: CloseEvent) => {
103
+ listener(ev.code, ev.reason);
104
+ };
105
+
106
+ case 'error':
107
+ return (ev: any) => {
108
+ // Some environments provide an ErrorEvent with a `.message`;
109
+ // fall back to a generic message when the event carries nothing.
110
+ const message = ev?.message || ev?.error?.message || 'WebSocket error';
111
+ const err = new Error(message);
112
+ if (ev?.error) {
113
+ (err as any).cause = ev.error;
114
+ }
115
+ listener(err);
116
+ };
117
+
118
+ case 'open':
119
+ default:
120
+ return listener as DOMEventHandler;
121
+ }
122
+ }
123
+ }
@@ -0,0 +1,105 @@
1
+ import type * as WS from 'ws';
2
+ import type { WebSocketLike } from './ws-adapter';
3
+
4
+ /** A generic event listener callback. */
5
+ type Listener = (...args: any[]) => void;
6
+
7
+ export class NodeWebSocket implements WebSocketLike {
8
+ private _ws: WS.WebSocket;
9
+
10
+ /** Maps `(event, originalListener)` -> wrapped listener for correct `off()` removal. */
11
+ private _listenerMap = new Map<string, Map<Listener, Listener>>();
12
+
13
+ constructor(ws: WS.WebSocket) {
14
+ this._ws = ws;
15
+ }
16
+
17
+ /** The underlying platform-specific socket. Code that accesses this will not be isomorphic across server and browser environments. */
18
+ get platformSocket(): WS.WebSocket {
19
+ return this._ws;
20
+ }
21
+
22
+ get readyState(): number {
23
+ return this._ws.readyState;
24
+ }
25
+
26
+ send(data: string | ArrayBufferLike | ArrayBufferView): void {
27
+ this._ws.send(data);
28
+ }
29
+
30
+ close(code?: number, reason?: string): void {
31
+ this._ws.close(code, reason);
32
+ }
33
+
34
+ on(event: string, listener: Listener): void {
35
+ const wrapped = this._wrapListener(event, listener);
36
+ this._listenersFor(event).set(listener, wrapped);
37
+ this._ws.on(event, wrapped);
38
+ }
39
+
40
+ off(event: string, listener: Listener): void {
41
+ const byListener = this._listenerMap.get(event);
42
+ if (!byListener) return;
43
+ const wrapped = byListener.get(listener);
44
+ if (wrapped) {
45
+ byListener.delete(listener);
46
+ this._ws.removeListener(event, wrapped);
47
+ }
48
+ }
49
+
50
+ once(event: string, listener: Listener): void {
51
+ const onceListener: Listener = (...args) => {
52
+ this.off(event, listener);
53
+ listener(...args);
54
+ };
55
+ const wrapped = this._wrapListener(event, onceListener);
56
+ this._listenersFor(event).set(listener, wrapped);
57
+ this._ws.on(event, wrapped);
58
+ }
59
+
60
+ private _listenersFor(event: string): Map<Listener, Listener> {
61
+ let map = this._listenerMap.get(event);
62
+ if (!map) {
63
+ map = new Map();
64
+ this._listenerMap.set(event, map);
65
+ }
66
+ return map;
67
+ }
68
+
69
+ /**
70
+ * Normalizes `ws` message payloads: text frames become strings,
71
+ * binary frames stay as `Buffer`, and fragmented frames are merged.
72
+ */
73
+ private static _normalizeMessageData(
74
+ data: Buffer | ArrayBuffer | Buffer[],
75
+ isBinary: boolean,
76
+ ): string | Buffer {
77
+ if (!isBinary) {
78
+ if (Array.isArray(data)) return Buffer.concat(data).toString();
79
+ if (data instanceof ArrayBuffer) return Buffer.from(data).toString();
80
+ return data.toString();
81
+ }
82
+
83
+ if (Array.isArray(data)) return Buffer.concat(data);
84
+ if (data instanceof ArrayBuffer) return Buffer.from(data);
85
+ return data;
86
+ }
87
+
88
+ private _wrapListener(event: string, listener: Listener): Listener {
89
+ switch (event) {
90
+ case 'message':
91
+ return (data: Buffer | ArrayBuffer | Buffer[], isBinary: boolean) => {
92
+ listener(NodeWebSocket._normalizeMessageData(data, isBinary), isBinary);
93
+ };
94
+
95
+ case 'close':
96
+ return (code: number, reason: Buffer) => {
97
+ listener(code, reason.toString());
98
+ };
99
+
100
+ // 'open' and 'error' pass through unchanged
101
+ default:
102
+ return listener;
103
+ }
104
+ }
105
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Normalized WebSocket interface that abstracts over the `ws` package (Node.js)
3
+ * and the native WebSocket API (browser).
4
+ */
5
+ export interface WebSocketLike {
6
+ readonly readyState: number;
7
+
8
+ send(data: string | ArrayBufferLike | ArrayBufferView): void;
9
+ close(code?: number, reason?: string): void;
10
+
11
+ on(event: 'open', listener: () => void): void;
12
+ on(
13
+ event: 'message',
14
+ listener: (data: string | ArrayBuffer | ArrayBufferView, isBinary: boolean) => void,
15
+ ): void;
16
+ on(event: 'close', listener: (code: number, reason: string) => void): void;
17
+ on(event: 'error', listener: (err: Error) => void): void;
18
+ on(event: string, listener: (...args: any[]) => void): void;
19
+
20
+ off(event: string, listener: (...args: any[]) => void): void;
21
+ once(event: string, listener: (...args: any[]) => void): void;
22
+ }
23
+
24
+ /** Standard WebSocket readyState values (RFC 6455). */
25
+ export const ReadyState = {
26
+ CONNECTING: 0,
27
+ OPEN: 1,
28
+ CLOSING: 2,
29
+ CLOSED: 3,
30
+ } as const;
@@ -0,0 +1,193 @@
1
+ import { concatBytes, encodeUTF8 } from './utils/bytes';
2
+
3
+ /** Reconnection event passed to the `onReconnecting` handler and event listeners. */
4
+ export interface ReconnectingEvent<Parameters = Record<string, unknown>> {
5
+ /** Which retry attempt this is (1-based). */
6
+ readonly attempt: number;
7
+ /** Total attempts that will be made. */
8
+ readonly maxAttempts: number;
9
+ /** Delay in ms before this attempt connects. */
10
+ readonly delay: number;
11
+ /** The WebSocket close code that triggered reconnection. */
12
+ readonly closeCode: number;
13
+ /** The current query parameters. */
14
+ readonly parameters: (Parameters & Record<string, unknown>) | undefined;
15
+ }
16
+
17
+ /**
18
+ * Optional overrides returned from the `onReconnecting` handler
19
+ * to customize the next reconnection attempt.
20
+ */
21
+ export type ReconnectingOverrides<Parameters = Record<string, unknown>> =
22
+ | {
23
+ /**
24
+ * If provided, assigns the query parameters for the next connection.
25
+ * Set to `undefined` to clear all query parameters.
26
+ */
27
+ parameters?: (Parameters & Record<string, unknown>) | undefined;
28
+ }
29
+ | {
30
+ /**
31
+ * If set, will stop attempting to reconnect.
32
+ */
33
+ abort: true;
34
+ };
35
+
36
+ /**
37
+ * Raw data types that can be sent over a WebSocket without serialization.
38
+ */
39
+ export type RawWebSocketData = string | ArrayBufferLike | ArrayBufferView | ArrayBufferView[];
40
+
41
+ export type UnsentMessage<T> = { type: 'message'; message: T } | { type: 'raw'; data: RawWebSocketData };
42
+
43
+ type QueueEntry =
44
+ | { kind: 'json'; data: string; byteLength: number }
45
+ | { kind: 'raw'; data: RawWebSocketData; byteLength: number };
46
+
47
+ function toUint8Array(view: ArrayBufferView): Uint8Array {
48
+ if (view instanceof Uint8Array) return view;
49
+ return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
50
+ }
51
+
52
+ /**
53
+ * Flatten `ArrayBufferView[]` fragments into a single `Uint8Array` so that
54
+ * `ws.send()` transmits the correct bytes.
55
+ */
56
+ export function flattenRawData(data: RawWebSocketData): Exclude<RawWebSocketData, ArrayBufferView[]> {
57
+ if (Array.isArray(data)) return concatBytes(data.map(toUint8Array));
58
+ return data;
59
+ }
60
+
61
+ function snapshotRawData(data: RawWebSocketData): Exclude<RawWebSocketData, ArrayBufferView[]> {
62
+ if (typeof data === 'string') return data;
63
+ if (Array.isArray(data)) return concatBytes(data.map(toUint8Array));
64
+ if (ArrayBuffer.isView(data)) {
65
+ const copy = new Uint8Array(data.byteLength);
66
+ copy.set(toUint8Array(data));
67
+ return copy;
68
+ }
69
+ return data.slice(0);
70
+ }
71
+
72
+ function rawByteLength(data: RawWebSocketData): number {
73
+ if (typeof data === 'string') return encodeUTF8(data).byteLength;
74
+ if (Array.isArray(data)) return data.reduce((sum, buf) => sum + buf.byteLength, 0);
75
+ if ('byteLength' in data) return data.byteLength;
76
+ return 0;
77
+ }
78
+
79
+ /**
80
+ * A bounded queue for outgoing WebSocket messages. JSON messages are
81
+ * serialized on enqueue; raw messages are stored as-is. The queue enforces
82
+ * a configurable byte-size limit and can return the original messages via
83
+ * {@link drain} when the connection permanently closes.
84
+ */
85
+ export class SendQueue<T = unknown> {
86
+ private _queue: QueueEntry[] = [];
87
+ private _bytes: number = 0;
88
+ private _maxBytes: number;
89
+
90
+ constructor(maxBytes: number = 1_048_576) {
91
+ this._maxBytes = maxBytes;
92
+ }
93
+
94
+ /**
95
+ * Serialize and enqueue a JSON message. Returns `true` if the message was
96
+ * accepted, `false` if it would exceed the byte-size limit.
97
+ */
98
+ enqueue(event: T): boolean {
99
+ const data = JSON.stringify(event);
100
+ const byteLength = encodeUTF8(data).byteLength;
101
+ if (this._bytes + byteLength > this._maxBytes && this._queue.length > 0) {
102
+ return false;
103
+ }
104
+ this._queue.push({ kind: 'json', data, byteLength });
105
+ this._bytes += byteLength;
106
+ return true;
107
+ }
108
+
109
+ /**
110
+ * Enqueue raw data without serialization. Returns `true` if the data was
111
+ * accepted, `false` if it would exceed the byte-size limit.
112
+ */
113
+ enqueueRaw(data: RawWebSocketData): boolean {
114
+ const snapshot = snapshotRawData(data);
115
+ const byteLength = rawByteLength(snapshot);
116
+ if (this._bytes + byteLength > this._maxBytes && this._queue.length > 0) {
117
+ return false;
118
+ }
119
+ this._queue.push({ kind: 'raw', data: snapshot, byteLength });
120
+ this._bytes += byteLength;
121
+ return true;
122
+ }
123
+
124
+ /**
125
+ * Send every queued message via `send`. If `send` throws, the failing
126
+ * message and all subsequent messages are re-queued and the error is
127
+ * re-thrown so the caller can report it.
128
+ */
129
+ flush(send: (data: RawWebSocketData) => void): void {
130
+ const pending = this._queue.splice(0);
131
+ this._bytes = 0;
132
+ for (let i = 0; i < pending.length; i++) {
133
+ try {
134
+ send(pending[i]!.data);
135
+ } catch (err) {
136
+ const remaining = pending.slice(i);
137
+ this._queue = remaining.concat(this._queue);
138
+ this._bytes = this._queue.reduce((sum, item) => sum + item.byteLength, 0);
139
+ throw err;
140
+ }
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Drain the queue and return the unsent messages. JSON messages are
146
+ * deserialized back to their original form. Resets byte tracking to zero.
147
+ */
148
+ drain(): UnsentMessage<T>[] {
149
+ const unsent = this._queue.map((entry): UnsentMessage<T> => {
150
+ if (entry.kind === 'raw') return { type: 'raw', data: entry.data };
151
+ return { type: 'message', message: JSON.parse(entry.data) as T };
152
+ });
153
+ this._queue = [];
154
+ this._bytes = 0;
155
+ return unsent;
156
+ }
157
+ }
158
+
159
+ // RFC 6455 §7.4.1
160
+ export function isRecoverableClose(code: number): boolean {
161
+ switch (code) {
162
+ case 1000:
163
+ return false; // Normal closure
164
+ case 1001:
165
+ return true; // Going away (server shutting down)
166
+ case 1002:
167
+ return false; // Protocol error
168
+ case 1003:
169
+ return false; // Unsupported data
170
+ case 1005:
171
+ return true; // No status code (abnormal)
172
+ case 1006:
173
+ return true; // Abnormal closure (network drop)
174
+ case 1007:
175
+ return false; // Invalid payload
176
+ case 1008:
177
+ return false; // Policy violation
178
+ case 1009:
179
+ return false; // Message too big
180
+ case 1010:
181
+ return false; // Missing extension
182
+ case 1011:
183
+ return true; // Internal server error
184
+ case 1012:
185
+ return true; // Service restart
186
+ case 1013:
187
+ return true; // Try again later
188
+ case 1015:
189
+ return true; // TLS handshake failure
190
+ default:
191
+ return false;
192
+ }
193
+ }