@forklaunch/ws 0.1.8 → 0.2.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.
package/lib/index.d.mts CHANGED
@@ -149,7 +149,7 @@ declare class ForklaunchWebSocket<SV extends AnySchemaValidator, const ES extend
149
149
  *
150
150
  * @internal
151
151
  */
152
- protected validateAndEncode(data: unknown, schema: IdiomaticSchema<SV> | undefined, allowUndefined?: boolean, context?: string): Buffer<ArrayBufferLike> | undefined;
152
+ protected validateAndEncode(data: unknown, schema: IdiomaticSchema<SV> | undefined, allowUndefined?: boolean, context?: string): Buffer | undefined;
153
153
  /**
154
154
  * Transforms incoming event arguments by decoding and validating them.
155
155
  *
@@ -180,7 +180,7 @@ declare class ForklaunchWebSocket<SV extends AnySchemaValidator, const ES extend
180
180
  *
181
181
  * @internal
182
182
  */
183
- protected wrapListenerWithTransformation<Event extends string | symbol>(superMethod: (event: Event, listener: (ws: WebSocket, ...args: never[]) => void) => this, event: Event, listener: (ws: WebSocket, ...args: unknown[]) => void): this;
183
+ protected wrapListenerWithTransformation<Event extends string | symbol>(superMethod: (event: Event, listener: (this: WebSocket, ...args: never[]) => void) => this, event: Event, listener: (this: WebSocket, ...args: unknown[]) => void): this;
184
184
  /**
185
185
  * Registers an event listener with automatic data validation and transformation.
186
186
  *
@@ -361,6 +361,20 @@ declare class ForklaunchWebSocket<SV extends AnySchemaValidator, const ES extend
361
361
  * ws.emit('error', { code: 500, message: 'Server error' });
362
362
  * ```
363
363
  */
364
+ /**
365
+ * Emits an event on the WebSocket.
366
+ *
367
+ * This method passes through to the underlying EventEmitter without
368
+ * transforming data. The ws library uses emit() internally to dispatch
369
+ * incoming events (message, close, ping, pong), so encoding here would
370
+ * incorrectly process incoming data as outgoing data.
371
+ *
372
+ * For sending data, use the dedicated methods instead:
373
+ * - {@link send} for messages
374
+ * - {@link close} for closing with a reason
375
+ * - {@link ping} for ping frames
376
+ * - {@link pong} for pong frames
377
+ */
364
378
  emit<K extends keyof OutgoingEventMap<SV, ES>>(event: K, ...args: OutgoingEventMap<SV, ES>[K]): boolean;
365
379
  /**
366
380
  * Sends data over the WebSocket with automatic validation and encoding.
@@ -604,6 +618,16 @@ declare class ForklaunchWebSocketServer<SV extends AnySchemaValidator, const ES
604
618
  * ```
605
619
  */
606
620
  constructor(schemaValidator: SV, eventSchemas: ES, options?: ConstructorParameters<typeof WebSocketServer>[0], callback?: () => void);
621
+ /**
622
+ * Intercepts emit to enhance WebSocket instances on 'connection' events.
623
+ *
624
+ * When the ws library internally emits 'connection', we swap the raw WebSocket
625
+ * for an enhanced ForklaunchWebSocket before listeners receive it. This avoids
626
+ * infinite recursion that would occur if we used a listener + re-emit pattern.
627
+ *
628
+ * @internal
629
+ */
630
+ emit(event: string | symbol, ...args: unknown[]): boolean;
607
631
  /**
608
632
  * Enhances a plain WebSocket instance with ForklaunchWebSocket functionality.
609
633
  *
package/lib/index.d.ts CHANGED
@@ -149,7 +149,7 @@ declare class ForklaunchWebSocket<SV extends AnySchemaValidator, const ES extend
149
149
  *
150
150
  * @internal
151
151
  */
152
- protected validateAndEncode(data: unknown, schema: IdiomaticSchema<SV> | undefined, allowUndefined?: boolean, context?: string): Buffer<ArrayBufferLike> | undefined;
152
+ protected validateAndEncode(data: unknown, schema: IdiomaticSchema<SV> | undefined, allowUndefined?: boolean, context?: string): Buffer | undefined;
153
153
  /**
154
154
  * Transforms incoming event arguments by decoding and validating them.
155
155
  *
@@ -180,7 +180,7 @@ declare class ForklaunchWebSocket<SV extends AnySchemaValidator, const ES extend
180
180
  *
181
181
  * @internal
182
182
  */
183
- protected wrapListenerWithTransformation<Event extends string | symbol>(superMethod: (event: Event, listener: (ws: WebSocket, ...args: never[]) => void) => this, event: Event, listener: (ws: WebSocket, ...args: unknown[]) => void): this;
183
+ protected wrapListenerWithTransformation<Event extends string | symbol>(superMethod: (event: Event, listener: (this: WebSocket, ...args: never[]) => void) => this, event: Event, listener: (this: WebSocket, ...args: unknown[]) => void): this;
184
184
  /**
185
185
  * Registers an event listener with automatic data validation and transformation.
186
186
  *
@@ -361,6 +361,20 @@ declare class ForklaunchWebSocket<SV extends AnySchemaValidator, const ES extend
361
361
  * ws.emit('error', { code: 500, message: 'Server error' });
362
362
  * ```
363
363
  */
364
+ /**
365
+ * Emits an event on the WebSocket.
366
+ *
367
+ * This method passes through to the underlying EventEmitter without
368
+ * transforming data. The ws library uses emit() internally to dispatch
369
+ * incoming events (message, close, ping, pong), so encoding here would
370
+ * incorrectly process incoming data as outgoing data.
371
+ *
372
+ * For sending data, use the dedicated methods instead:
373
+ * - {@link send} for messages
374
+ * - {@link close} for closing with a reason
375
+ * - {@link ping} for ping frames
376
+ * - {@link pong} for pong frames
377
+ */
364
378
  emit<K extends keyof OutgoingEventMap<SV, ES>>(event: K, ...args: OutgoingEventMap<SV, ES>[K]): boolean;
365
379
  /**
366
380
  * Sends data over the WebSocket with automatic validation and encoding.
@@ -604,6 +618,16 @@ declare class ForklaunchWebSocketServer<SV extends AnySchemaValidator, const ES
604
618
  * ```
605
619
  */
606
620
  constructor(schemaValidator: SV, eventSchemas: ES, options?: ConstructorParameters<typeof WebSocketServer>[0], callback?: () => void);
621
+ /**
622
+ * Intercepts emit to enhance WebSocket instances on 'connection' events.
623
+ *
624
+ * When the ws library internally emits 'connection', we swap the raw WebSocket
625
+ * for an enhanced ForklaunchWebSocket before listeners receive it. This avoids
626
+ * infinite recursion that would occur if we used a listener + re-emit pattern.
627
+ *
628
+ * @internal
629
+ */
630
+ emit(event: string | symbol, ...args: unknown[]): boolean;
607
631
  /**
608
632
  * Enhances a plain WebSocket instance with ForklaunchWebSocket functionality.
609
633
  *
package/lib/index.js CHANGED
@@ -139,9 +139,8 @@ var ForklaunchWebSocket = class extends import_ws2.WebSocket {
139
139
  let transformedArgs = args;
140
140
  if (event === "message" && args.length >= 2) {
141
141
  const data = args[0];
142
- const isBinary = args[1];
143
142
  const serverSchema = this.schemas.serverMessagesSchema;
144
- if (typeof isBinary === "boolean" && isBinary && serverSchema) {
143
+ if (serverSchema) {
145
144
  const validated = this.decodeAndValidate(data, serverSchema);
146
145
  transformedArgs = [validated, false, ...args.slice(2)];
147
146
  }
@@ -179,9 +178,14 @@ var ForklaunchWebSocket = class extends import_ws2.WebSocket {
179
178
  * @internal
180
179
  */
181
180
  wrapListenerWithTransformation(superMethod, event, listener) {
182
- return superMethod(event, (ws, ...args) => {
183
- const transformedArgs = this.transformIncomingArgs(event, args);
184
- return listener(ws, ...transformedArgs);
181
+ const self = this;
182
+ return superMethod(event, function(...args) {
183
+ try {
184
+ const transformedArgs = self.transformIncomingArgs(event, args);
185
+ return listener.call(this, ...transformedArgs);
186
+ } catch (err) {
187
+ import_ws2.WebSocket.prototype.emit.call(self, "error", err);
188
+ }
185
189
  });
186
190
  }
187
191
  on(event, listener) {
@@ -244,68 +248,22 @@ var ForklaunchWebSocket = class extends import_ws2.WebSocket {
244
248
  * ws.emit('error', { code: 500, message: 'Server error' });
245
249
  * ```
246
250
  */
251
+ /**
252
+ * Emits an event on the WebSocket.
253
+ *
254
+ * This method passes through to the underlying EventEmitter without
255
+ * transforming data. The ws library uses emit() internally to dispatch
256
+ * incoming events (message, close, ping, pong), so encoding here would
257
+ * incorrectly process incoming data as outgoing data.
258
+ *
259
+ * For sending data, use the dedicated methods instead:
260
+ * - {@link send} for messages
261
+ * - {@link close} for closing with a reason
262
+ * - {@link ping} for ping frames
263
+ * - {@link pong} for pong frames
264
+ */
247
265
  emit(event, ...args) {
248
- let transformedArgs = args;
249
- if (event === "message" && args.length >= 2) {
250
- const typedArgs = args;
251
- const data = typedArgs[0];
252
- const isBinary = typedArgs[1];
253
- const clientSchema = this.schemas.clientMessagesSchema;
254
- if (typeof isBinary === "boolean" && isBinary && clientSchema) {
255
- const encoded = this.validateAndEncode(
256
- data,
257
- clientSchema,
258
- false,
259
- "web socket message"
260
- );
261
- transformedArgs = [encoded, true, ...typedArgs.slice(2)];
262
- }
263
- } else if (event === "close" && args.length >= 2) {
264
- const typedArgs = args;
265
- const code = typedArgs[0];
266
- const reason = typedArgs[1];
267
- const encoded = this.validateAndEncode(
268
- reason,
269
- this.schemas.closeReasonSchema,
270
- false,
271
- "web socket close"
272
- );
273
- transformedArgs = [code, encoded, ...typedArgs.slice(2)];
274
- } else if (event === "ping" && args.length >= 1) {
275
- const typedArgs = args;
276
- const data = typedArgs[0];
277
- const encoded = this.validateAndEncode(
278
- data,
279
- this.schemas.pingSchema,
280
- false,
281
- "web socket ping"
282
- );
283
- transformedArgs = [encoded, ...typedArgs.slice(1)];
284
- } else if (event === "pong" && args.length >= 1) {
285
- const typedArgs = args;
286
- const data = typedArgs[0];
287
- const encoded = this.validateAndEncode(
288
- data,
289
- this.schemas.pongSchema,
290
- false,
291
- "web socket pong"
292
- );
293
- transformedArgs = [encoded, ...typedArgs.slice(1)];
294
- } else if (event === "error" && args.length >= 1) {
295
- const typedArgs = args;
296
- const error = typedArgs[0];
297
- const errorsSchema = this.schemas.errorsSchema;
298
- if (errorsSchema) {
299
- const encoded = this.validateAndEncode(
300
- error,
301
- errorsSchema,
302
- false,
303
- "web socket error"
304
- );
305
- transformedArgs = [encoded, ...typedArgs.slice(1)];
306
- }
307
- }
308
- return super.emit(event, ...transformedArgs);
266
+ return super.emit(event, ...args);
309
267
  }
310
268
  // @ts-expect-error - Implementation accepts unknown for internal validation
311
269
  send(data, optionsOrCb, cb) {
@@ -483,10 +441,23 @@ var ForklaunchWebSocketServer = class extends import_ws4.WebSocketServer {
483
441
  super(options, callback);
484
442
  this.schemaValidator = schemaValidator;
485
443
  this.eventSchemas = eventSchemas;
486
- super.on("connection", (ws, request) => {
487
- const forklaunchWs = this.enhanceWebSocket(ws);
488
- super.emit("connection", forklaunchWs, request);
489
- });
444
+ }
445
+ /**
446
+ * Intercepts emit to enhance WebSocket instances on 'connection' events.
447
+ *
448
+ * When the ws library internally emits 'connection', we swap the raw WebSocket
449
+ * for an enhanced ForklaunchWebSocket before listeners receive it. This avoids
450
+ * infinite recursion that would occur if we used a listener + re-emit pattern.
451
+ *
452
+ * @internal
453
+ */
454
+ emit(event, ...args) {
455
+ if (event === "connection" && args.length >= 1) {
456
+ const ws = args[0];
457
+ const enhancedWs = this.enhanceWebSocket(ws);
458
+ return super.emit(event, enhancedWs, ...args.slice(1));
459
+ }
460
+ return super.emit(event, ...args);
490
461
  }
491
462
  /**
492
463
  * Enhances a plain WebSocket instance with ForklaunchWebSocket functionality.
package/lib/index.mjs CHANGED
@@ -109,9 +109,8 @@ var ForklaunchWebSocket = class extends WebSocket {
109
109
  let transformedArgs = args;
110
110
  if (event === "message" && args.length >= 2) {
111
111
  const data = args[0];
112
- const isBinary = args[1];
113
112
  const serverSchema = this.schemas.serverMessagesSchema;
114
- if (typeof isBinary === "boolean" && isBinary && serverSchema) {
113
+ if (serverSchema) {
115
114
  const validated = this.decodeAndValidate(data, serverSchema);
116
115
  transformedArgs = [validated, false, ...args.slice(2)];
117
116
  }
@@ -149,9 +148,14 @@ var ForklaunchWebSocket = class extends WebSocket {
149
148
  * @internal
150
149
  */
151
150
  wrapListenerWithTransformation(superMethod, event, listener) {
152
- return superMethod(event, (ws, ...args) => {
153
- const transformedArgs = this.transformIncomingArgs(event, args);
154
- return listener(ws, ...transformedArgs);
151
+ const self = this;
152
+ return superMethod(event, function(...args) {
153
+ try {
154
+ const transformedArgs = self.transformIncomingArgs(event, args);
155
+ return listener.call(this, ...transformedArgs);
156
+ } catch (err) {
157
+ WebSocket.prototype.emit.call(self, "error", err);
158
+ }
155
159
  });
156
160
  }
157
161
  on(event, listener) {
@@ -214,68 +218,22 @@ var ForklaunchWebSocket = class extends WebSocket {
214
218
  * ws.emit('error', { code: 500, message: 'Server error' });
215
219
  * ```
216
220
  */
221
+ /**
222
+ * Emits an event on the WebSocket.
223
+ *
224
+ * This method passes through to the underlying EventEmitter without
225
+ * transforming data. The ws library uses emit() internally to dispatch
226
+ * incoming events (message, close, ping, pong), so encoding here would
227
+ * incorrectly process incoming data as outgoing data.
228
+ *
229
+ * For sending data, use the dedicated methods instead:
230
+ * - {@link send} for messages
231
+ * - {@link close} for closing with a reason
232
+ * - {@link ping} for ping frames
233
+ * - {@link pong} for pong frames
234
+ */
217
235
  emit(event, ...args) {
218
- let transformedArgs = args;
219
- if (event === "message" && args.length >= 2) {
220
- const typedArgs = args;
221
- const data = typedArgs[0];
222
- const isBinary = typedArgs[1];
223
- const clientSchema = this.schemas.clientMessagesSchema;
224
- if (typeof isBinary === "boolean" && isBinary && clientSchema) {
225
- const encoded = this.validateAndEncode(
226
- data,
227
- clientSchema,
228
- false,
229
- "web socket message"
230
- );
231
- transformedArgs = [encoded, true, ...typedArgs.slice(2)];
232
- }
233
- } else if (event === "close" && args.length >= 2) {
234
- const typedArgs = args;
235
- const code = typedArgs[0];
236
- const reason = typedArgs[1];
237
- const encoded = this.validateAndEncode(
238
- reason,
239
- this.schemas.closeReasonSchema,
240
- false,
241
- "web socket close"
242
- );
243
- transformedArgs = [code, encoded, ...typedArgs.slice(2)];
244
- } else if (event === "ping" && args.length >= 1) {
245
- const typedArgs = args;
246
- const data = typedArgs[0];
247
- const encoded = this.validateAndEncode(
248
- data,
249
- this.schemas.pingSchema,
250
- false,
251
- "web socket ping"
252
- );
253
- transformedArgs = [encoded, ...typedArgs.slice(1)];
254
- } else if (event === "pong" && args.length >= 1) {
255
- const typedArgs = args;
256
- const data = typedArgs[0];
257
- const encoded = this.validateAndEncode(
258
- data,
259
- this.schemas.pongSchema,
260
- false,
261
- "web socket pong"
262
- );
263
- transformedArgs = [encoded, ...typedArgs.slice(1)];
264
- } else if (event === "error" && args.length >= 1) {
265
- const typedArgs = args;
266
- const error = typedArgs[0];
267
- const errorsSchema = this.schemas.errorsSchema;
268
- if (errorsSchema) {
269
- const encoded = this.validateAndEncode(
270
- error,
271
- errorsSchema,
272
- false,
273
- "web socket error"
274
- );
275
- transformedArgs = [encoded, ...typedArgs.slice(1)];
276
- }
277
- }
278
- return super.emit(event, ...transformedArgs);
236
+ return super.emit(event, ...args);
279
237
  }
280
238
  // @ts-expect-error - Implementation accepts unknown for internal validation
281
239
  send(data, optionsOrCb, cb) {
@@ -455,10 +413,23 @@ var ForklaunchWebSocketServer = class extends WebSocketServer {
455
413
  super(options, callback);
456
414
  this.schemaValidator = schemaValidator;
457
415
  this.eventSchemas = eventSchemas;
458
- super.on("connection", (ws, request) => {
459
- const forklaunchWs = this.enhanceWebSocket(ws);
460
- super.emit("connection", forklaunchWs, request);
461
- });
416
+ }
417
+ /**
418
+ * Intercepts emit to enhance WebSocket instances on 'connection' events.
419
+ *
420
+ * When the ws library internally emits 'connection', we swap the raw WebSocket
421
+ * for an enhanced ForklaunchWebSocket before listeners receive it. This avoids
422
+ * infinite recursion that would occur if we used a listener + re-emit pattern.
423
+ *
424
+ * @internal
425
+ */
426
+ emit(event, ...args) {
427
+ if (event === "connection" && args.length >= 1) {
428
+ const ws = args[0];
429
+ const enhancedWs = this.enhanceWebSocket(ws);
430
+ return super.emit(event, enhancedWs, ...args.slice(1));
431
+ }
432
+ return super.emit(event, ...args);
462
433
  }
463
434
  /**
464
435
  * Enhances a plain WebSocket instance with ForklaunchWebSocket functionality.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forklaunch/ws",
3
- "version": "0.1.8",
3
+ "version": "0.2.1",
4
4
  "description": "Typed framework for ws, by ForkLaunch.",
5
5
  "homepage": "https://github.com/forklaunch/forklaunch-js#readme",
6
6
  "bugs": {
@@ -28,21 +28,21 @@
28
28
  "@asyncapi/parser": "^3.6.0",
29
29
  "@types/ws": "^8.18.1",
30
30
  "ws": "^8.19.0",
31
- "@forklaunch/common": "0.6.28",
32
- "@forklaunch/core": "0.18.1",
33
- "@forklaunch/validator": "0.10.28"
31
+ "@forklaunch/common": "0.6.30",
32
+ "@forklaunch/core": "0.18.3",
33
+ "@forklaunch/validator": "0.10.30"
34
34
  },
35
35
  "devDependencies": {
36
- "@eslint/js": "^9.39.2",
37
- "@typescript/native-preview": "7.0.0-dev.20260204.1",
36
+ "@eslint/js": "^10.0.1",
37
+ "@typescript/native-preview": "7.0.0-dev.20260302.1",
38
38
  "jest": "^30.2.0",
39
39
  "prettier": "^3.8.1",
40
40
  "ts-jest": "^29.4.6",
41
41
  "ts-node": "^10.9.2",
42
42
  "tsup": "^8.5.1",
43
- "typedoc": "^0.28.16",
43
+ "typedoc": "^0.28.17",
44
44
  "typescript": "^5.9.3",
45
- "typescript-eslint": "^8.54.0",
45
+ "typescript-eslint": "^8.56.1",
46
46
  "zod": "^4.3.6"
47
47
  },
48
48
  "scripts": {