vortez 5.0.2 → 6.0.0-dev.1

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 (143) hide show
  1. package/build/Template/Template.d.ts +0 -5
  2. package/build/Template/Template.js +5 -5
  3. package/build/Template/Template.js.map +1 -1
  4. package/build/Vortez.d.ts +2 -2
  5. package/build/Vortez.js +2 -2
  6. package/build/Vortez.js.map +1 -1
  7. package/build/beta/Mail.d.ts +2 -8
  8. package/build/beta/Mail.js +7 -2
  9. package/build/beta/Mail.js.map +1 -1
  10. package/build/server/Cookie.d.ts +9 -5
  11. package/build/server/Cookie.js +28 -24
  12. package/build/server/Cookie.js.map +1 -1
  13. package/build/server/LoggerManager.d.ts +1 -1
  14. package/build/server/LoggerManager.js +5 -5
  15. package/build/server/LoggerManager.js.map +1 -1
  16. package/build/server/Response.js +11 -11
  17. package/build/server/Response.js.map +1 -1
  18. package/build/server/Server.js +4 -4
  19. package/build/server/Server.js.map +1 -1
  20. package/build/server/ServerDebug.d.ts +1 -1
  21. package/build/server/ServerDebug.js +1 -1
  22. package/build/server/ServerDebug.js.map +1 -1
  23. package/build/server/config/Config.d.ts +7 -7
  24. package/build/server/config/Config.js +4 -3
  25. package/build/server/config/Config.js.map +1 -1
  26. package/build/server/config/Loader.js +5 -5
  27. package/build/server/config/Loader.js.map +1 -1
  28. package/build/server/router/HttpRule.d.ts +2 -2
  29. package/build/server/router/HttpRule.js +1 -1
  30. package/build/server/router/HttpRule.js.map +1 -1
  31. package/build/server/router/Router.d.ts +1 -1
  32. package/build/server/router/Router.js +5 -5
  33. package/build/server/router/Router.js.map +1 -1
  34. package/build/server/router/Rule.d.ts +1 -1
  35. package/build/server/router/WsRule.d.ts +2 -2
  36. package/build/server/router/WsRule.js +2 -2
  37. package/build/server/router/WsRule.js.map +1 -1
  38. package/build/server/router/algorithm/Algorithm.d.ts +1 -1
  39. package/build/server/router/algorithm/Algorithm.js +2 -2
  40. package/build/server/router/algorithm/Algorithm.js.map +1 -1
  41. package/build/server/router/algorithm/FIFO.d.ts +1 -1
  42. package/build/server/router/algorithm/FIFO.js +2 -2
  43. package/build/server/router/algorithm/FIFO.js.map +1 -1
  44. package/build/server/router/algorithm/Tree.d.ts +1 -1
  45. package/build/server/router/algorithm/Tree.js.map +1 -1
  46. package/build/server/router/middleware/Middleware.d.ts +5 -5
  47. package/build/server/router/middleware/WsMiddleware.d.ts +4 -4
  48. package/build/server/router/middleware/WsMiddleware.js +24 -23
  49. package/build/server/router/middleware/WsMiddleware.js.map +1 -1
  50. package/build/server/security/PathSecurity.js +5 -5
  51. package/build/server/security/PathSecurity.js.map +1 -1
  52. package/build/server/websocket/Codec.d.ts +128 -0
  53. package/build/server/websocket/Codec.js +192 -0
  54. package/build/server/websocket/Codec.js.map +1 -0
  55. package/build/server/websocket/Websocket.d.ts +38 -84
  56. package/build/server/websocket/Websocket.js +41 -221
  57. package/build/server/websocket/Websocket.js.map +1 -1
  58. package/build/server/websocket/WebsocketBase.d.ts +130 -0
  59. package/build/server/websocket/WebsocketBase.js +272 -0
  60. package/build/server/websocket/WebsocketBase.js.map +1 -0
  61. package/build/server/websocket/WebsocketCSInit.d.ts +57 -0
  62. package/build/server/websocket/WebsocketCSInit.js +95 -0
  63. package/build/server/websocket/WebsocketCSInit.js.map +1 -0
  64. package/build/server/websocket/WebsocketSSInit.d.ts +24 -0
  65. package/build/server/websocket/WebsocketSSInit.js +46 -0
  66. package/build/server/websocket/WebsocketSSInit.js.map +1 -0
  67. package/build/server/websocket/frame/Frame.d.ts +31 -0
  68. package/build/server/websocket/frame/Frame.js +45 -0
  69. package/build/server/websocket/frame/Frame.js.map +1 -0
  70. package/build/server/websocket/frame/Header.d.ts +31 -0
  71. package/build/server/websocket/frame/Header.js +31 -0
  72. package/build/server/websocket/frame/Header.js.map +1 -0
  73. package/build/server/websocket/frame/HeaderParser.d.ts +58 -0
  74. package/build/server/websocket/frame/HeaderParser.js +109 -0
  75. package/build/server/websocket/frame/HeaderParser.js.map +1 -0
  76. package/build/server/websocket/handshake/CSHandshaker.d.ts +46 -0
  77. package/build/server/websocket/handshake/CSHandshaker.js +122 -0
  78. package/build/server/websocket/handshake/CSHandshaker.js.map +1 -0
  79. package/build/server/websocket/handshake/SSHandshaker.d.ts +57 -0
  80. package/build/server/websocket/handshake/SSHandshaker.js +113 -0
  81. package/build/server/websocket/handshake/SSHandshaker.js.map +1 -0
  82. package/build/server/websocket/messageAssembler/Message.d.ts +21 -0
  83. package/build/server/websocket/messageAssembler/Message.js +20 -0
  84. package/build/server/websocket/messageAssembler/Message.js.map +1 -0
  85. package/build/server/websocket/messageAssembler/MessageAssembler.d.ts +25 -0
  86. package/build/server/websocket/messageAssembler/MessageAssembler.js +47 -0
  87. package/build/server/websocket/messageAssembler/MessageAssembler.js.map +1 -0
  88. package/changes.md +28 -0
  89. package/package.json +6 -1
  90. package/build/logger/Debug.d.ts +0 -174
  91. package/build/logger/Debug.js +0 -295
  92. package/build/logger/Debug.js.map +0 -1
  93. package/build/logger/Logger.d.ts +0 -38
  94. package/build/logger/Logger.js +0 -48
  95. package/build/logger/Logger.js.map +0 -1
  96. package/build/server/websocket/Chunk.d.ts +0 -36
  97. package/build/server/websocket/Chunk.js +0 -81
  98. package/build/server/websocket/Chunk.js.map +0 -1
  99. package/build/utilities/ConsoleUI.d.ts +0 -89
  100. package/build/utilities/ConsoleUI.js +0 -142
  101. package/build/utilities/ConsoleUI.js.map +0 -1
  102. package/build/utilities/DebugUI.d.ts +0 -66
  103. package/build/utilities/DebugUI.js +0 -98
  104. package/build/utilities/DebugUI.js.map +0 -1
  105. package/build/utilities/Encoding.d.ts +0 -22
  106. package/build/utilities/Encoding.js +0 -26
  107. package/build/utilities/Encoding.js.map +0 -1
  108. package/build/utilities/Env.d.ts +0 -81
  109. package/build/utilities/Env.js +0 -140
  110. package/build/utilities/Env.js.map +0 -1
  111. package/build/utilities/File.d.ts +0 -10
  112. package/build/utilities/File.js +0 -19
  113. package/build/utilities/File.js.map +0 -1
  114. package/build/utilities/Flatten.d.ts +0 -73
  115. package/build/utilities/Flatten.js +0 -76
  116. package/build/utilities/Flatten.js.map +0 -1
  117. package/build/utilities/Object.d.ts +0 -16
  118. package/build/utilities/Object.js +0 -48
  119. package/build/utilities/Object.js.map +0 -1
  120. package/build/utilities/Path.d.ts +0 -44
  121. package/build/utilities/Path.js +0 -69
  122. package/build/utilities/Path.js.map +0 -1
  123. package/build/utilities/Time.d.ts +0 -21
  124. package/build/utilities/Time.js +0 -25
  125. package/build/utilities/Time.js.map +0 -1
  126. package/build/utilities/Utilities.d.ts +0 -118
  127. package/build/utilities/Utilities.js +0 -112
  128. package/build/utilities/Utilities.js.map +0 -1
  129. package/build/utilities/schema/Introspection.d.ts +0 -24
  130. package/build/utilities/schema/Introspection.js +0 -87
  131. package/build/utilities/schema/Introspection.js.map +0 -1
  132. package/build/utilities/schema/JSONSchema.d.ts +0 -68
  133. package/build/utilities/schema/JSONSchema.js +0 -13
  134. package/build/utilities/schema/JSONSchema.js.map +0 -1
  135. package/build/utilities/schema/Schema.d.ts +0 -253
  136. package/build/utilities/schema/Schema.js +0 -241
  137. package/build/utilities/schema/Schema.js.map +0 -1
  138. package/build/utilities/schema/SchemaError.d.ts +0 -10
  139. package/build/utilities/schema/SchemaError.js +0 -13
  140. package/build/utilities/schema/SchemaError.js.map +0 -1
  141. package/build/utilities/schema/Validator.d.ts +0 -94
  142. package/build/utilities/schema/Validator.js +0 -246
  143. package/build/utilities/schema/Validator.js.map +0 -1
@@ -0,0 +1,272 @@
1
+ /**
2
+ * @author NetFeez <netfeez.dev@gmail.com>
3
+ * @description adds websocket functionality to Vortez
4
+ * @license Apache-2.0
5
+ */
6
+ import { randomUUID } from 'crypto';
7
+ import { Events } from '@netfeez/common';
8
+ import LoggerManager from '../LoggerManager.js';
9
+ import Codec from './Codec.js';
10
+ import Frame from './frame/Frame.js';
11
+ import MessageAssembler from './messageAssembler/MessageAssembler.js';
12
+ const logger = LoggerManager.getInstance().webSocket;
13
+ export class WebsocketBase extends Events {
14
+ connection;
15
+ vStatus = 'handshake';
16
+ vEventBuffer = {};
17
+ vEventBuffering = true;
18
+ assembler;
19
+ surplus = Buffer.alloc(0);
20
+ constructor(connection) {
21
+ super();
22
+ this.connection = connection;
23
+ this.assembler = new MessageAssembler();
24
+ }
25
+ get isClosed() { return this.connection.readableEnded; }
26
+ get status() { return this.vStatus; }
27
+ /**
28
+ * Sends a JSON-serializable object through the WebSocket connection as a text frame. The object is first serialized to a JSON string before being sent.
29
+ * @param data - The JSON-serializable object to be sent through the WebSocket connection.
30
+ */
31
+ sendJson(data) {
32
+ const jsonString = JSON.stringify(data);
33
+ this.send(jsonString);
34
+ }
35
+ /**
36
+ * Sends data through the WebSocket connection.
37
+ * The data can be either a string (which will be sent as a text frame) or a Buffer (which will be sent as a binary frame).
38
+ * If the connection is not open, a warning is logged and the data is not sent.
39
+ * @param data - The data to be sent through the WebSocket connection, which can be either a string or a Buffer.
40
+ * @remarks The method first checks the status of the connection to ensure that it is open before attempting to send data. If the connection is closed or still in the handshake phase, a warning is logged to inform the developer that data cannot be sent in the current state. If the connection is open, the method calls the internal `write` method to handle encoding and sending the data through the WebSocket connection.
41
+ */
42
+ send(data) {
43
+ if (typeof data === 'string')
44
+ return this.write(Buffer.from(data, 'utf-8'), 0x1);
45
+ else if (data instanceof Buffer)
46
+ return this.write(data, 0x2);
47
+ const stack = new Error().stack || '';
48
+ return logger.warn('&C3Unsupported data type for Websocket.send. Data must be a string or a Buffer.\nStack trace:\n&C0' + stack);
49
+ }
50
+ /**
51
+ * Sends a ping frame through the WebSocket connection and waits for a corresponding pong response to measure the round-trip time (RTT) of the ping-pong exchange. The method returns a promise that resolves with the measured RTT in milliseconds or rejects if a timeout occurs or if there is an error during the process.
52
+ * @param options - An optional object containing configuration options for the ping operation, including:
53
+ * - `timeout`: The maximum time to wait for a pong response before rejecting the promise (default is 5000 milliseconds).
54
+ * - `data`: Optional data to include in the ping frame, which can be a Buffer or a string. If a string is provided, it will be converted to a Buffer using UTF-8 encoding.
55
+ * @returns A promise that resolves with the measured round-trip time (RTT) in milliseconds if a pong response is received within the specified timeout, or rejects with an error if a timeout occurs or if there is an issue during the ping-pong exchange.
56
+ */
57
+ async ping(options = {}) {
58
+ const { timeout = 5000, data = randomUUID(), } = options;
59
+ const buffer = typeof data === 'string' ? Buffer.from(data, 'utf-8') : data;
60
+ const start = Date.now();
61
+ return new Promise((resolve, reject) => {
62
+ const handler = (payload) => {
63
+ if (payload.equals(buffer)) {
64
+ cleanup();
65
+ resolve(Date.now() - start);
66
+ }
67
+ };
68
+ const timer = setTimeout(() => {
69
+ cleanup();
70
+ reject(new Error(`Ping timeout after ${timeout}ms`));
71
+ }, timeout);
72
+ const cleanup = () => {
73
+ clearTimeout(timer);
74
+ this.off('pong', handler);
75
+ };
76
+ this.on('pong', handler);
77
+ try {
78
+ this.write(buffer, 0x09);
79
+ }
80
+ catch (error) {
81
+ cleanup();
82
+ reject(error);
83
+ }
84
+ });
85
+ }
86
+ /**
87
+ * Closes the WebSocket connection by sending a close frame and ending the connection. If the connection is already closed, this method does nothing.
88
+ * - It first checks if the connection is already closed, and if so, it simply returns without performing any actions.
89
+ * - If the connection is not closed, it updates the internal status to 'closed', sends a close frame to the peer, and ends the connection.
90
+ * @remarks This method ensures that the WebSocket connection is properly closed by sending the appropriate close frame and terminating the connection. It also prevents any further actions from being taken on a closed connection by checking the status before attempting to close it again.
91
+ */
92
+ close() {
93
+ this.write(Buffer.alloc(0), 0x8);
94
+ this.vStatus = 'closed';
95
+ this.connection.end();
96
+ }
97
+ /**
98
+ * Writes the given buffer with the specified opcode to the WebSocket connection.
99
+ * This method is responsible for encoding the data into a WebSocket frame format and sending it through the underlying connection.
100
+ * In the base implementation, it uses the `encode` method to perform the encoding, which can be overridden in subclasses to provide different encoding strategies (e.g., masking for client-to-server communication).
101
+ * @param buffer - The data buffer to be encoded and sent through the WebSocket connection.
102
+ * @param opcode - The opcode indicating the type of frame being sent (e.g., 0x1 for text frames, 0x2 for binary frames).
103
+ * @remarks This method is designed to be overridden in client-side implementations to allow for different encoding strategies, such as masking frames for client-to-server communication. In the base implementation, it simply encodes the buffer using the standard `encode` method and writes it to the connection, but subclasses can provide their own encoding logic as necessary.
104
+ */
105
+ write(buffer, opcode) {
106
+ if (this.vStatus !== 'open')
107
+ return logger.warn('&C3Attempted to send data on a WebSocket connection that is not open. Data will not be sent.');
108
+ if (this.connection.writableEnded ||
109
+ this.connection.destroyed ||
110
+ !this.connection.writable) {
111
+ this.vStatus = 'closed';
112
+ this.emit('close');
113
+ const stack = new Error().stack || '';
114
+ return logger.warn(`&C3Attempted to send data on a WebSocket connection that is already closed. Data will not be sent. ${stack}`);
115
+ }
116
+ const frame = this.encode(buffer, opcode);
117
+ this.connection.write(frame);
118
+ }
119
+ /**
120
+ * flush pending events. This method is used to emit any buffered events that were stored while there were no listeners for those events.
121
+ * It checks for buffered 'message', 'message:text', 'message:binary', and 'error' events and emits them if there are listeners available.
122
+ * Additionally, it handles re-emission of 'open' and 'close' events if they were emitted before listeners were added.
123
+ * This ensures that all relevant events are properly emitted to listeners once they are registered, allowing for correct handling of WebSocket events in the application.
124
+ *
125
+ * If you are using this class as a we client, you can use it after add your listeners.
126
+ *
127
+ * If you are using this class as a web server, you can use it after routing and executed the action rule on the router o middleware exec (vortez context).
128
+ *
129
+ * Here in **Vortez**, the WebsocketSSInit instance is created in the router on receive upgrade request.
130
+ * Before it is executed the middleware stack -> executed the action rule on the router and automatically is called flush() method to emit the buffered events.
131
+ * we are sure that the events will be received with your instance of Websocket on server side if you use `vortez`
132
+ *
133
+ * If you are using the class as a client ``WebsocketCSInit`` or out of Vortez, you can call it after add your listeners to make sure that you will receive the events emitted during the handshake phase.
134
+ * @remarks This method is essential for ensuring that all relevant events are emitted to listeners, especially in cases where events may have been emitted before listeners were registered. By calling this method after adding listeners, you can ensure that any buffered events are properly emitted and handled by the listeners, allowing for correct functionality of the WebSocket connection in your application.
135
+ */
136
+ flush() {
137
+ this.vEventBuffering = false;
138
+ const is = (name) => { return name in this.vEventBuffer; };
139
+ for (const name in this.vEventBuffer) {
140
+ if (!is(name))
141
+ continue;
142
+ const buffer = this.vEventBuffer[name] ?? [];
143
+ for (const args of buffer)
144
+ super.emit(name, ...args);
145
+ delete this.vEventBuffer[name];
146
+ }
147
+ }
148
+ /**
149
+ * ====== Override this method in Client side to use different codec ======
150
+ *
151
+ * Encodes the given buffer with the specified opcode and sends it through the WebSocket connection. This method is responsible for encoding the data into a WebSocket frame format and writing it to the underlying connection.
152
+ * In the base implementation, it uses the Codec.encode method to perform the encoding, but this method can be overridden in subclasses (such as WebsocketCSInit) to use a different encoding strategy if needed.
153
+ * @param buffer - The data buffer to be encoded and sent through the WebSocket connection.
154
+ * @param opcode - The opcode indicating the type of frame being sent (e.g., 0x1 for text frames, 0x2 for binary frames).
155
+ * @returns the encoded buffer that was sent through the connection. This allows for further processing or logging of the encoded data if necessary.
156
+ * @remarks This method is designed to be overridden in client-side implementations to allow for different encoding strategies, such as masking frames for client-to-server communication. In the base implementation, it simply encodes the buffer using the standard Codec.encode method and writes it to the connection, but subclasses can provide their own encoding logic as necessary.
157
+ */
158
+ encode(buffer, opcode) {
159
+ return Codec.encode(buffer, opcode);
160
+ }
161
+ /**
162
+ * Initializes the WebSocket connection by setting up event listeners for incoming data, message assembly, and connection events.
163
+ * This method is called after a successful handshake to start processing WebSocket frames and messages.
164
+ * It listens for 'data' events on the socket to process incoming frames, and uses the MessageAssembler to assemble complete messages from the frames.
165
+ * It also handles control frames (like close and ping) appropriately, emitting events for messages, errors, and connection closures as needed.
166
+ * @remarks The method sets up a 'data' event listener on the socket to process incoming data buffers. It uses the MessageAssembler to handle the assembly of messages from frames, emitting 'message' events when complete messages are assembled. It also handles control frames such as close and ping, emitting a 'close' event when a close frame is received and responding to ping frames with pong frames. Additionally, it listens for 'close' and 'error' events on the socket to emit corresponding events for the WebSocket instance.
167
+ */
168
+ startup() {
169
+ this.assembler.on('message', (message) => {
170
+ if (message.isText || message.isBinary) {
171
+ this.emit('message', message);
172
+ if (message.isText)
173
+ this.emit('message:text', message.payload.toString('utf-8'));
174
+ else if (message.isBinary)
175
+ this.emit('message:binary', message.payload);
176
+ }
177
+ else if (message.isClose) {
178
+ if (this.vStatus === 'closed')
179
+ return;
180
+ if (this.connection.writable && !this.connection.writableEnded) {
181
+ try {
182
+ this.write(message.payload, 0x8);
183
+ }
184
+ catch (error) { }
185
+ }
186
+ this.vStatus = 'closed';
187
+ this.connection.end();
188
+ this.emit('close');
189
+ }
190
+ else if (message.isPing) {
191
+ this.emit('ping', message.payload);
192
+ this.write(message.payload, 0xA);
193
+ }
194
+ else if (message.isPong) {
195
+ this.emit('pong', message.payload);
196
+ }
197
+ });
198
+ this.assembler.on('error', (error) => {
199
+ this.vStatus = 'closed';
200
+ this.emit('error', error);
201
+ this.encode(Buffer.alloc(0), 0x8);
202
+ this.connection.end();
203
+ });
204
+ this.connection.on('data', (data) => {
205
+ if (this.surplus.length > 0) {
206
+ data = Buffer.concat([this.surplus, data]);
207
+ this.surplus = Buffer.alloc(0);
208
+ }
209
+ this.processBuffer(data);
210
+ });
211
+ this.connection.on('close', () => {
212
+ this.vStatus = 'closed';
213
+ this.emit('close');
214
+ });
215
+ this.connection.on('error', this.emit.bind(this, 'error'));
216
+ }
217
+ /**
218
+ * Procesa el buffer recibido, extrayendo todos los frames completos y acumulando el surplus.
219
+ * Se encarga de manejar errores de parsing y de empujar los frames al assembler.
220
+ */
221
+ processBuffer(data) {
222
+ try {
223
+ while (data.length > 0) {
224
+ let result;
225
+ try {
226
+ result = Frame.fromBuffer(data);
227
+ }
228
+ catch (error) {
229
+ if (error instanceof RangeError) {
230
+ this.surplus = data;
231
+ break;
232
+ }
233
+ else if (error instanceof Error) {
234
+ this.emit('error', error);
235
+ break;
236
+ }
237
+ else {
238
+ this.emit('error', new Error(String(error)));
239
+ break;
240
+ }
241
+ }
242
+ const { frame, chunk, surplus: rest } = result;
243
+ this.assembler.push(frame);
244
+ data = rest;
245
+ }
246
+ }
247
+ catch (error) {
248
+ if (error instanceof Error)
249
+ this.emit('error', error);
250
+ else
251
+ this.emit('error', new Error(String(error)));
252
+ }
253
+ }
254
+ /**
255
+ * Middleware for emitting events. It handles buffering of messages and errors when there are no listeners, and re-emits 'open' and 'close' events if they were emitted before listeners were added.
256
+ * This method overrides the base emit method to provide additional functionality specific to WebSocket event handling, such as buffering messages and errors until listeners are available, and ensuring that 'open' and 'close' events are emitted appropriately based on the connection status and listener presence.
257
+ * @param event - The event to be emitted, which includes the event name and any associated arguments. The method processes the event based on its type and manages buffering and re-emission logic as needed.
258
+ */
259
+ emit(...event) {
260
+ if (!this.vEventBuffering)
261
+ return super.emit(...event);
262
+ const [name, ...args] = event;
263
+ if (this.vEventBuffering && this.eventCount(name) === 0) {
264
+ this.vEventBuffer[name] = this.vEventBuffer[name] ?? [];
265
+ this.vEventBuffer[name].push(args);
266
+ }
267
+ else
268
+ super.emit(...event);
269
+ }
270
+ }
271
+ export default WebsocketBase;
272
+ //# sourceMappingURL=WebsocketBase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebsocketBase.js","sourceRoot":"","sources":["../../../src/server/websocket/WebsocketBase.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAEhD,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,KAAK,MAAM,kBAAkB,CAAC;AAErC,OAAO,gBAAgB,MAAM,wCAAwC,CAAC;AAEtE,MAAM,MAAM,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC;AAErD,MAAM,OAAO,aAAc,SAAQ,MAA8B;IAUzC;IATV,OAAO,GAAyB,WAAW,CAAC;IAEnC,YAAY,GAA8B,EAAE,CAAC;IACtD,eAAe,GAAY,IAAI,CAAA;IAE/B,SAAS,CAAmB;IAC5B,OAAO,GAAW,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE5C,YACoB,UAAkB;QAElC,KAAK,EAAE,CAAC;QAFQ,eAAU,GAAV,UAAU,CAAQ;QAGlC,IAAI,CAAC,SAAS,GAAG,IAAI,gBAAgB,EAAE,CAAC;IAC5C,CAAC;IAED,IAAW,QAAQ,KAAc,OAAO,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC;IACxE,IAAW,MAAM,KAA2B,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAElE;;;OAGG;IACI,QAAQ,CAAC,IAAS;QACrB,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1B,CAAC;IACD;;;;;;OAMG;IACI,IAAI,CAAC,IAAqB;QAC7B,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC;aAC5E,IAAI,IAAI,YAAY,MAAM;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAE9D,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;QACtC,OAAO,MAAM,CAAC,IAAI,CAAC,oGAAoG,GAAG,KAAK,CAAC,CAAC;IACrI,CAAC;IACD;;;;;;OAMG;IACI,KAAK,CAAC,IAAI,CAAC,UAAqC,EAAE;QACrD,MAAM,EACF,OAAO,GAAG,IAAI,EACd,IAAI,GAAG,UAAU,EAAE,GACtB,GAAG,OAAO,CAAC;QAEZ,MAAM,MAAM,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5E,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEzB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,MAAM,OAAO,GAAG,CAAC,OAAe,EAAE,EAAE;gBAChC,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;oBACzB,OAAO,EAAE,CAAC;oBACV,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC;gBAChC,CAAC;YACL,CAAC,CAAC;YAEF,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC1B,OAAO,EAAE,CAAC;gBACV,MAAM,CAAC,IAAI,KAAK,CAAC,sBAAsB,OAAO,IAAI,CAAC,CAAC,CAAC;YACzD,CAAC,EAAE,OAAO,CAAC,CAAC;YAEZ,MAAM,OAAO,GAAG,GAAG,EAAE;gBACjB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC9B,CAAC,CAAC;YAEF,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAEzB,IAAI,CAAC;gBAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAAC,CAAC;YACjC,OAAO,KAAK,EAAE,CAAC;gBACX,OAAO,EAAE,CAAC;gBACV,MAAM,CAAC,KAAK,CAAC,CAAC;YAClB,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC;IACD;;;;;OAKG;IACI,KAAK;QACR,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC;QACxB,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;IAC1B,CAAC;IACD;;;;;;;OAOG;IACI,KAAK,CAAC,MAAc,EAAE,MAAc;QACvC,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM;YAAE,OAAO,MAAM,CAAC,IAAI,CAAC,8FAA8F,CAAC,CAAC;QAChJ,IACI,IAAI,CAAC,UAAU,CAAC,aAAa;YAC7B,IAAI,CAAC,UAAU,CAAC,SAAS;YACzB,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAC3B,CAAC;YACC,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACnB,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;YACtC,OAAO,MAAM,CAAC,IAAI,CAAC,sGAAsG,KAAK,EAAE,CAAC,CAAC;QACtI,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IACD;;;;;;;;;;;;;;;;OAgBG;IACI,KAAK;QACR,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QAC7B,MAAM,EAAE,GAAG,CAAmB,IAAO,EAA4C,EAAE,GAAG,OAAO,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC1H,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACnC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;gBAAE,SAAS;YACxB,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAC7C,KAAK,MAAM,IAAI,IAAI,MAAM;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC;YACrD,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;IACL,CAAC;IACD;;;;;;;;;OASG;IACO,MAAM,CAAC,MAAc,EAAE,MAAc;QAC3C,OAAO,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IACD;;;;;;OAMG;IACO,OAAO;QACb,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAgB,EAAE,EAAE;YAC9C,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBAC9B,IAAI,OAAO,CAAC,MAAM;oBAAE,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;qBAC5E,IAAI,OAAO,CAAC,QAAQ;oBAAE,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;YAC5E,CAAC;iBAAM,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACzB,IAAI,IAAI,CAAC,OAAO,KAAK,QAAQ;oBAAE,OAAO;gBACtC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC;oBAC7D,IAAI,CAAC;wBAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;oBACvC,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC,CAAA,CAAC;gBACtB,CAAC;gBACD,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC;gBACxB,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;gBACtB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvB,CAAC;iBAAM,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACxB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;gBACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACrC,CAAC;iBAAM,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACxB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;YACvC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACjC,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAClC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;QAC1B,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACxC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC3C,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACnC,CAAC;YAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAC7B,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD;;;OAGG;IACK,aAAa,CAAC,IAAY;QAC9B,IAAI,CAAC;YACD,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,IAAI,MAAwB,CAAC;gBAC7B,IAAI,CAAC;oBACD,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBACpC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACb,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;wBAC9B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;wBACpB,MAAM;oBACV,CAAC;yBAAM,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;wBAChC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;wBAC1B,MAAM;oBACV,CAAC;yBAAM,CAAC;wBACJ,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;wBAC7C,MAAM;oBACV,CAAC;gBACL,CAAC;gBACD,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC;gBAC/C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC3B,IAAI,GAAG,IAAI,CAAC;YAChB,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,KAAK,YAAY,KAAK;gBAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;;gBACjD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACtD,CAAC;IACL,CAAC;IACD;;;;OAIG;IACgB,IAAI,CAAkD,GAAG,KAAoD;QAC5H,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QACvD,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC;QAC9B,IAAI,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACtD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACxD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC;;YAAM,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;IAChC,CAAC;CACJ;AAyBD,eAAe,aAAa,CAAC"}
@@ -0,0 +1,57 @@
1
+ import type { Duplex } from 'stream';
2
+ import CSHandShaker from './handshake/CSHandshaker.js';
3
+ import WebsocketBase from './WebsocketBase.js';
4
+ export declare class WebsocketCSInit extends WebsocketBase {
5
+ protected handshaker: CSHandShaker;
6
+ request: WebsocketCSInit.Request;
7
+ constructor(socket: Duplex, request: WebsocketCSInit.Request);
8
+ protected encode(buffer: Buffer, opcode: number): Buffer;
9
+ /**
10
+ * Handles the WebSocket handshake process by listening for 'finish' and 'error' events from the CSHandShaker instance.
11
+ * When the handshake is completed successfully, it updates the connection status to 'open', initializes the WebSocket connection, and emits an 'open' event. If the handshake fails or encounters an error, it updates the status to 'closed' and emits a 'close' or 'error' event accordingly.
12
+ * This method is called internally during the construction of the WebsocketCSInit instance to automatically manage the handshake process when a new connection is established.
13
+ */
14
+ protected handshake(): void;
15
+ /**
16
+ * Establishes a WebSocket connection to the specified URL by performing the necessary handshake process. This method parses the provided URL, creates a socket connection to the server, and then initiates the WebSocket handshake to establish a full-duplex communication channel.
17
+ * @param url - The WebSocket URL to connect to, which should include the protocol (ws:// or wss://), host, optional port, and path.
18
+ * @returns A promise that resolves to a Websocket instance representing the established connection if the handshake is successful, or rejects with an error if the handshake fails or if there are issues during the connection process.
19
+ * @remarks The method first parses the URL to extract the necessary components (protocol, host, port, path), then creates a socket connection based on the protocol (using TLS for wss and a regular TCP socket for ws). After establishing the socket connection, it performs the WebSocket handshake using the CSHandShaker class.
20
+ * If the handshake is successful, it initializes a new ClientInit instance with the established socket and resolves the promise with this instance. If any errors occur during parsing, socket creation, or handshake, the promise is rejected with the corresponding error.
21
+ */
22
+ static connect(url: string): Promise<WebsocketBase>;
23
+ /**
24
+ * Creates a socket connection to the specified host and port using the appropriate protocol (TCP for ws and TLS for wss).
25
+ * This method is used internally to establish the underlying connection before performing the WebSocket handshake.
26
+ * @param protocol - The protocol to use for the connection, which should be either 'ws:' for a regular TCP connection or 'wss:' for a secure TLS connection.
27
+ * @param host - The hostname of the server to connect to.
28
+ * @param port - The port number of the server to connect to.
29
+ * @returns A Duplex stream representing the established socket connection, which will be used for the WebSocket handshake and subsequent communication.
30
+ * @remarks The method checks the protocol and creates a socket connection accordingly. For 'wss:', it uses TLS to create a secure connection, while for 'ws:', it creates a standard TCP connection. The returned Duplex stream can then be used for reading and writing data during the WebSocket communication.
31
+ */
32
+ static createSocket(protocol: string, host: string, port: number): Duplex;
33
+ /**
34
+ * Parses a WebSocket URL and extracts its components (protocol, host, port, path) to create a structured request object. This method is used internally to process the URL provided for establishing a WebSocket connection.
35
+ * @param url - The WebSocket URL to be parsed, which should include the protocol (ws:// or wss://), host, optional port, and path.
36
+ * @returns An object containing the parsed components of the URL: protocol, host, port, and path. The port is determined based on the protocol if not explicitly provided in the URL (defaulting to 80 for ws and 443 for wss).
37
+ * @throws Will throw an error if the URL does not use a valid WebSocket protocol (i.e., if it does not start with ws:// or wss://).
38
+ */
39
+ static parseURL(url: string): WebsocketCSInit.Request;
40
+ /**
41
+ * Valida si el protocolo es ws o wss. Este método se utiliza internamente para asegurar que solo se acepten URLs con los protocolos correctos durante el proceso de conexión.
42
+ * @param protocol - El protocolo extraído de la URL, que debe ser 'ws:' o 'wss:'.
43
+ * @returns Un valor booleano que indica si el protocolo es válido (true) o no (false).
44
+ */
45
+ protected static isProtocol(protocol: string): protocol is WebsocketCSInit.Protocol;
46
+ }
47
+ export declare namespace WebsocketCSInit {
48
+ type Protocol = 'ws:' | 'wss:';
49
+ interface Request {
50
+ protocol: Protocol;
51
+ authority: string;
52
+ host: string;
53
+ port: number;
54
+ path: string;
55
+ }
56
+ }
57
+ export default WebsocketCSInit;
@@ -0,0 +1,95 @@
1
+ import net from 'net';
2
+ import tls from 'tls';
3
+ import CSHandShaker from './handshake/CSHandshaker.js';
4
+ import WebsocketBase from './WebsocketBase.js';
5
+ import Codec from './Codec.js';
6
+ export class WebsocketCSInit extends WebsocketBase {
7
+ handshaker;
8
+ request;
9
+ constructor(socket, request) {
10
+ super(socket);
11
+ this.handshaker = new CSHandShaker(socket, request.authority, request.path);
12
+ this.request = request;
13
+ this.handshake();
14
+ }
15
+ encode(buffer, opcode) {
16
+ return Codec.clientEncode(buffer, opcode);
17
+ }
18
+ /**
19
+ * Handles the WebSocket handshake process by listening for 'finish' and 'error' events from the CSHandShaker instance.
20
+ * When the handshake is completed successfully, it updates the connection status to 'open', initializes the WebSocket connection, and emits an 'open' event. If the handshake fails or encounters an error, it updates the status to 'closed' and emits a 'close' or 'error' event accordingly.
21
+ * This method is called internally during the construction of the WebsocketCSInit instance to automatically manage the handshake process when a new connection is established.
22
+ */
23
+ handshake() {
24
+ this.handshaker.once('finish', (status) => {
25
+ this.vStatus = status;
26
+ if (status !== 'open')
27
+ this.emit('close');
28
+ else {
29
+ this.startup();
30
+ this.emit('open');
31
+ }
32
+ });
33
+ this.handshaker.once('error', (error) => {
34
+ this.vStatus = 'closed';
35
+ this.emit('error', error);
36
+ });
37
+ this.handshaker.start();
38
+ }
39
+ /**
40
+ * Establishes a WebSocket connection to the specified URL by performing the necessary handshake process. This method parses the provided URL, creates a socket connection to the server, and then initiates the WebSocket handshake to establish a full-duplex communication channel.
41
+ * @param url - The WebSocket URL to connect to, which should include the protocol (ws:// or wss://), host, optional port, and path.
42
+ * @returns A promise that resolves to a Websocket instance representing the established connection if the handshake is successful, or rejects with an error if the handshake fails or if there are issues during the connection process.
43
+ * @remarks The method first parses the URL to extract the necessary components (protocol, host, port, path), then creates a socket connection based on the protocol (using TLS for wss and a regular TCP socket for ws). After establishing the socket connection, it performs the WebSocket handshake using the CSHandShaker class.
44
+ * If the handshake is successful, it initializes a new ClientInit instance with the established socket and resolves the promise with this instance. If any errors occur during parsing, socket creation, or handshake, the promise is rejected with the corresponding error.
45
+ */
46
+ static async connect(url) {
47
+ const request = WebsocketCSInit.parseURL(url);
48
+ const socket = WebsocketCSInit.createSocket(request.protocol, request.host, request.port);
49
+ const websocket = new WebsocketCSInit(socket, request);
50
+ return websocket;
51
+ }
52
+ /**
53
+ * Creates a socket connection to the specified host and port using the appropriate protocol (TCP for ws and TLS for wss).
54
+ * This method is used internally to establish the underlying connection before performing the WebSocket handshake.
55
+ * @param protocol - The protocol to use for the connection, which should be either 'ws:' for a regular TCP connection or 'wss:' for a secure TLS connection.
56
+ * @param host - The hostname of the server to connect to.
57
+ * @param port - The port number of the server to connect to.
58
+ * @returns A Duplex stream representing the established socket connection, which will be used for the WebSocket handshake and subsequent communication.
59
+ * @remarks The method checks the protocol and creates a socket connection accordingly. For 'wss:', it uses TLS to create a secure connection, while for 'ws:', it creates a standard TCP connection. The returned Duplex stream can then be used for reading and writing data during the WebSocket communication.
60
+ */
61
+ static createSocket(protocol, host, port) {
62
+ if (protocol === 'wss:')
63
+ return tls.connect({ host, port, servername: host });
64
+ else
65
+ return net.connect({ host, port });
66
+ }
67
+ /**
68
+ * Parses a WebSocket URL and extracts its components (protocol, host, port, path) to create a structured request object. This method is used internally to process the URL provided for establishing a WebSocket connection.
69
+ * @param url - The WebSocket URL to be parsed, which should include the protocol (ws:// or wss://), host, optional port, and path.
70
+ * @returns An object containing the parsed components of the URL: protocol, host, port, and path. The port is determined based on the protocol if not explicitly provided in the URL (defaulting to 80 for ws and 443 for wss).
71
+ * @throws Will throw an error if the URL does not use a valid WebSocket protocol (i.e., if it does not start with ws:// or wss://).
72
+ */
73
+ static parseURL(url) {
74
+ const parsed = new URL(url);
75
+ const protocol = parsed.protocol;
76
+ if (!WebsocketCSInit.isProtocol(protocol))
77
+ throw new Error('Solo se aceptan protocolos ws:// o wss://');
78
+ const defaultPort = protocol === 'wss:' ? 443 : 80;
79
+ const host = parsed.hostname;
80
+ const port = Number(parsed.port || defaultPort);
81
+ const path = parsed.pathname + (parsed.search || '');
82
+ const authority = `${host}:${port}`;
83
+ return { protocol, host, port, path, authority };
84
+ }
85
+ /**
86
+ * Valida si el protocolo es ws o wss. Este método se utiliza internamente para asegurar que solo se acepten URLs con los protocolos correctos durante el proceso de conexión.
87
+ * @param protocol - El protocolo extraído de la URL, que debe ser 'ws:' o 'wss:'.
88
+ * @returns Un valor booleano que indica si el protocolo es válido (true) o no (false).
89
+ */
90
+ static isProtocol(protocol) {
91
+ return ['ws:', 'wss:'].includes(protocol);
92
+ }
93
+ }
94
+ export default WebsocketCSInit;
95
+ //# sourceMappingURL=WebsocketCSInit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebsocketCSInit.js","sourceRoot":"","sources":["../../../src/server/websocket/WebsocketCSInit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { Duplex } from 'stream';
2
+ import type Request from '../Request.js';
3
+ import SSHandshaker from './handshake/SSHandshaker.js';
4
+ import WebsocketBase from './WebsocketBase.js';
5
+ export declare class WebsocketSSInit extends WebsocketBase {
6
+ protected handshaker: SSHandshaker;
7
+ constructor(request: Request, socket: Duplex);
8
+ /**
9
+ * Accepts the WebSocket handshake by validating the client's request and sending the appropriate HTTP response to establish the WebSocket connection. This method should be called after verifying that the client's handshake request is valid and meets the necessary criteria for accepting the connection.
10
+ * - It generates the Sec-WebSocket-Accept key based on the client's Sec-WebSocket-Key and constructs the HTTP response with the required headers to complete the handshake.
11
+ * - After sending the response, it updates the internal status to 'open' and emits a 'finish' event with the new status.
12
+ * @throws Will throw an error if the client's handshake request does not contain a valid Sec-WebSocket-Key or if any other issue occurs during the acceptance process. The error will be emitted as an 'error' event for handling by the caller.
13
+ */
14
+ accept(): void;
15
+ /**
16
+ * Rejects the WebSocket handshake by sending an HTTP response with the specified status code and reason, and then closes the connection.
17
+ * @param code - The HTTP status code to indicate the reason for rejection (e.g., 400 for Bad Request).
18
+ * @param reason - A human-readable string explaining the reason for rejection.
19
+ * @remarks The generated response will have a JSON body containing the provided code and reason, and will include any specified cookies in the headers. This response can be sent back to the client to indicate that the handshake request was rejected, along with the reason for rejection.
20
+ */
21
+ reject(code: number, reason: string): void;
22
+ }
23
+ export declare namespace WebsocketSSInit { }
24
+ export default WebsocketSSInit;
@@ -0,0 +1,46 @@
1
+ import SSHandshaker from './handshake/SSHandshaker.js';
2
+ import WebsocketBase from './WebsocketBase.js';
3
+ export class WebsocketSSInit extends WebsocketBase {
4
+ handshaker;
5
+ constructor(request, socket) {
6
+ super(socket);
7
+ this.handshaker = new SSHandshaker(socket, request);
8
+ this.handshaker.once('error', (error) => {
9
+ this.vStatus = 'closed';
10
+ this.emit('error', error);
11
+ });
12
+ this.handshaker.once('finish', (status) => {
13
+ this.vStatus = status;
14
+ if (status !== 'open')
15
+ this.emit('close');
16
+ else {
17
+ this.startup();
18
+ this.emit('open');
19
+ }
20
+ });
21
+ }
22
+ /**
23
+ * Accepts the WebSocket handshake by validating the client's request and sending the appropriate HTTP response to establish the WebSocket connection. This method should be called after verifying that the client's handshake request is valid and meets the necessary criteria for accepting the connection.
24
+ * - It generates the Sec-WebSocket-Accept key based on the client's Sec-WebSocket-Key and constructs the HTTP response with the required headers to complete the handshake.
25
+ * - After sending the response, it updates the internal status to 'open' and emits a 'finish' event with the new status.
26
+ * @throws Will throw an error if the client's handshake request does not contain a valid Sec-WebSocket-Key or if any other issue occurs during the acceptance process. The error will be emitted as an 'error' event for handling by the caller.
27
+ */
28
+ accept() {
29
+ if (this.vStatus !== 'handshake')
30
+ return this.emit('error', new Error('Handshake already completed or connection is closed'));
31
+ this.handshaker.accept();
32
+ }
33
+ /**
34
+ * Rejects the WebSocket handshake by sending an HTTP response with the specified status code and reason, and then closes the connection.
35
+ * @param code - The HTTP status code to indicate the reason for rejection (e.g., 400 for Bad Request).
36
+ * @param reason - A human-readable string explaining the reason for rejection.
37
+ * @remarks The generated response will have a JSON body containing the provided code and reason, and will include any specified cookies in the headers. This response can be sent back to the client to indicate that the handshake request was rejected, along with the reason for rejection.
38
+ */
39
+ reject(code, reason) {
40
+ if (this.vStatus !== 'handshake')
41
+ return this.emit('error', new Error('Handshake already completed or connection is closed'));
42
+ this.handshaker.reject(code, reason);
43
+ }
44
+ }
45
+ export default WebsocketSSInit;
46
+ //# sourceMappingURL=WebsocketSSInit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebsocketSSInit.js","sourceRoot":"","sources":["../../../src/server/websocket/WebsocketSSInit.ts"],"names":[],"mappings":"AAIA,OAAO,YAAY,MAAM,6BAA6B,CAAC;AACvD,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAE/C,MAAM,OAAO,eAAgB,SAAQ,aAAa;IACpC,UAAU,CAAe;IACnC,YACI,OAAgB,EAChB,MAAc;QAEd,KAAK,CAAC,MAAM,CAAC,CAAC;QACd,IAAI,CAAC,UAAU,GAAG,IAAI,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACpC,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;YACtC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;YACtB,IAAI,MAAM,KAAK,MAAM;gBAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;iBACrC,CAAC;gBACF,IAAI,CAAC,OAAO,EAAE,CAAC;gBACf,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACtB,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC;IACD;;;;;QAKI;IACG,MAAM;QACT,IAAI,IAAI,CAAC,OAAO,KAAK,WAAW;YAAE,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC;QAC9H,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;IAC7B,CAAC;IACD;;;;;OAKG;IACI,MAAM,CAAC,IAAY,EAAE,MAAc;QACtC,IAAI,IAAI,CAAC,OAAO,KAAK,WAAW;YAAE,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC;QAC9H,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC;CACJ;AAED,eAAe,eAAe,CAAC"}
@@ -0,0 +1,31 @@
1
+ import Header from './Header.js';
2
+ export declare class Frame implements Frame.Content {
3
+ header: Header;
4
+ payload: Buffer;
5
+ constructor(data: Frame.Content);
6
+ get isContinuation(): boolean;
7
+ get isText(): boolean;
8
+ get isBinary(): boolean;
9
+ get isClose(): boolean;
10
+ get isPing(): boolean;
11
+ get isPong(): boolean;
12
+ get isControl(): boolean;
13
+ /**
14
+ * Reads the first complete frame from a buffer and returns its surplus.
15
+ * @throws `RangeError` If the buffer does not contain a complete frame or if the frame size exceeds supported limits.
16
+ * Note: This method assumes that the buffer starts with a valid frame header and does not perform additional validation on the frame contents.
17
+ */
18
+ static fromBuffer(buffer: Buffer): Frame.ReadResult;
19
+ }
20
+ export declare namespace Frame {
21
+ interface Content {
22
+ header: Header;
23
+ payload: Buffer;
24
+ }
25
+ interface ReadResult {
26
+ frame: Frame;
27
+ chunk: Buffer;
28
+ surplus: Buffer;
29
+ }
30
+ }
31
+ export default Frame;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Parser dedicado para extraer solo la cabecera de un frame WebSocket.
3
+ * Útil para validaciones previas, handshake, o inspección rápida.
4
+ */
5
+ import Codec from '../Codec.js';
6
+ import Header from './Header.js';
7
+ export class Frame {
8
+ header;
9
+ payload;
10
+ constructor(data) {
11
+ this.header = data.header;
12
+ this.payload = data.payload;
13
+ }
14
+ get isContinuation() { return this.header.opcode === 0x0; }
15
+ get isText() { return this.header.opcode === 0x1; }
16
+ get isBinary() { return this.header.opcode === 0x2; }
17
+ get isClose() { return this.header.opcode === 0x8; }
18
+ get isPing() { return this.header.opcode === 0x9; }
19
+ get isPong() { return this.header.opcode === 0xA; }
20
+ get isControl() { return this.header.opcode >= 0x8; }
21
+ /**
22
+ * Reads the first complete frame from a buffer and returns its surplus.
23
+ * @throws `RangeError` If the buffer does not contain a complete frame or if the frame size exceeds supported limits.
24
+ * Note: This method assumes that the buffer starts with a valid frame header and does not perform additional validation on the frame contents.
25
+ */
26
+ static fromBuffer(buffer) {
27
+ const header = Header.fromBuffer(buffer);
28
+ const expectedSize = BigInt(header.headerSize) + BigInt(header.size);
29
+ if (BigInt(buffer.length) < expectedSize)
30
+ throw new RangeError('Incomplete frame data');
31
+ if (expectedSize > BigInt(Number.MAX_SAFE_INTEGER))
32
+ throw new RangeError('Frame size exceeds supported buffer limits');
33
+ const chunkSize = Number(expectedSize);
34
+ const chunk = buffer.subarray(0, chunkSize);
35
+ const payload = Codec.decode(chunk, header.headerSize, header.maskKeys);
36
+ const frame = new Frame({ header: header, payload });
37
+ return {
38
+ frame,
39
+ chunk,
40
+ surplus: buffer.subarray(chunkSize)
41
+ };
42
+ }
43
+ }
44
+ export default Frame;
45
+ //# sourceMappingURL=Frame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Frame.js","sourceRoot":"","sources":["../../../../src/server/websocket/frame/Frame.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,MAAM,aAAa,CAAC;AAChC,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,MAAM,OAAO,KAAK;IACP,MAAM,CAAS;IACf,OAAO,CAAS;IAEvB,YAAmB,IAAmB;QAClC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAChC,CAAC;IAED,IAAW,cAAc,KAAc,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC;IAC3E,IAAW,MAAM,KAAc,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC;IACnE,IAAW,QAAQ,KAAc,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC;IACrE,IAAW,OAAO,KAAc,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC;IACpE,IAAW,MAAM,KAAc,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC;IACnE,IAAW,MAAM,KAAc,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC;IACnE,IAAW,SAAS,KAAc,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC;IAErE;;;;OAIG;IACI,MAAM,CAAC,UAAU,CAAC,MAAc;QACnC,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACzC,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAErE,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,YAAY;YAAE,MAAM,IAAI,UAAU,CAAC,uBAAuB,CAAC,CAAC;QACxF,IAAI,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,4CAA4C,CAAC,CAAC;QAEvH,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxE,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAErD,OAAO;YACH,KAAK;YACL,KAAK;YACL,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;SACtC,CAAC;IACN,CAAC;CACJ;AAcD,eAAe,KAAK,CAAC"}