svelte-adapter-uws 0.2.8 → 0.2.10
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/README.md +107 -23
- package/files/handler.js +5 -5
- package/index.d.ts +58 -9
- package/package.json +1 -1
- package/vite.js +4 -4
package/README.md
CHANGED
|
@@ -30,6 +30,7 @@ I've been loving Svelte and SvelteKit for a long time. I always wanted to expand
|
|
|
30
30
|
- [Authentication](#authentication)
|
|
31
31
|
- [Platform API (`event.platform`)](#platform-api-eventplatform)
|
|
32
32
|
- [Client store API](#client-store-api)
|
|
33
|
+
- [Seeding initial state](#seeding-initial-state)
|
|
33
34
|
- [TypeScript setup](#typescript-setup)
|
|
34
35
|
- [Svelte 4 support](#svelte-4-support)
|
|
35
36
|
- [Deploying with Docker](#deploying-with-docker)
|
|
@@ -389,8 +390,8 @@ If you set `envPrefix: 'MY_APP_'` in the adapter config, all variables are prefi
|
|
|
389
390
|
|
|
390
391
|
On `SIGTERM` or `SIGINT`, the server:
|
|
391
392
|
1. Stops accepting new connections
|
|
392
|
-
2.
|
|
393
|
-
3.
|
|
393
|
+
2. Waits for in-flight SSR requests to complete (up to `SHUTDOWN_TIMEOUT` seconds)
|
|
394
|
+
3. Emits a `sveltekit:shutdown` event on `process` (for cleanup hooks like closing database connections)
|
|
394
395
|
4. Exits
|
|
395
396
|
|
|
396
397
|
```js
|
|
@@ -455,7 +456,7 @@ export async function upgrade({ headers, cookies, url, remoteAddress }) {
|
|
|
455
456
|
}
|
|
456
457
|
|
|
457
458
|
// Called when a connection is established
|
|
458
|
-
export function open(ws) {
|
|
459
|
+
export function open(ws, { platform }) {
|
|
459
460
|
const { userId } = ws.getUserData();
|
|
460
461
|
console.log(`User ${userId} connected`);
|
|
461
462
|
|
|
@@ -466,27 +467,27 @@ export function open(ws) {
|
|
|
466
467
|
// Called when a message is received
|
|
467
468
|
// Note: subscribe/unsubscribe messages from the client store are
|
|
468
469
|
// handled automatically BEFORE this function is called
|
|
469
|
-
export function message(ws, data, isBinary) {
|
|
470
|
+
export function message(ws, { data, isBinary }) {
|
|
470
471
|
const msg = JSON.parse(Buffer.from(data).toString());
|
|
471
472
|
console.log('Got message:', msg);
|
|
472
473
|
}
|
|
473
474
|
|
|
474
475
|
// Called when a client tries to subscribe to a topic (optional)
|
|
475
476
|
// Return false to deny the subscription
|
|
476
|
-
export function subscribe(ws, topic) {
|
|
477
|
+
export function subscribe(ws, topic, { platform }) {
|
|
477
478
|
const { role } = ws.getUserData();
|
|
478
479
|
// Only admins can subscribe to admin topics
|
|
479
480
|
if (topic.startsWith('admin') && role !== 'admin') return false;
|
|
480
481
|
}
|
|
481
482
|
|
|
482
483
|
// Called when the connection closes
|
|
483
|
-
export function close(ws, code, message) {
|
|
484
|
+
export function close(ws, { code, message, platform }) {
|
|
484
485
|
const { userId } = ws.getUserData();
|
|
485
486
|
console.log(`User ${userId} disconnected`);
|
|
486
487
|
}
|
|
487
488
|
|
|
488
489
|
// Called when backpressure has drained (optional, for flow control)
|
|
489
|
-
export function drain(ws) {
|
|
490
|
+
export function drain(ws, { platform }) {
|
|
490
491
|
// You can resume sending large messages here
|
|
491
492
|
}
|
|
492
493
|
```
|
|
@@ -583,7 +584,7 @@ export async function upgrade({ cookies }) {
|
|
|
583
584
|
return { userId: user.id, name: user.name, role: user.role };
|
|
584
585
|
}
|
|
585
586
|
|
|
586
|
-
export function open(ws) {
|
|
587
|
+
export function open(ws, { platform }) {
|
|
587
588
|
const { userId, role } = ws.getUserData();
|
|
588
589
|
console.log(`${userId} connected (${role})`);
|
|
589
590
|
|
|
@@ -592,7 +593,7 @@ export function open(ws) {
|
|
|
592
593
|
if (role === 'admin') ws.subscribe('admin');
|
|
593
594
|
}
|
|
594
595
|
|
|
595
|
-
export function close(ws) {
|
|
596
|
+
export function close(ws, { platform }) {
|
|
596
597
|
const { userId } = ws.getUserData();
|
|
597
598
|
console.log(`${userId} disconnected`);
|
|
598
599
|
}
|
|
@@ -653,7 +654,7 @@ The WebSocket upgrade is an HTTP request. The browser treats it like any other r
|
|
|
653
654
|
|
|
654
655
|
## Platform API (`event.platform`)
|
|
655
656
|
|
|
656
|
-
Available in server hooks, load functions, form actions, and
|
|
657
|
+
Available in server hooks, load functions, form actions, API routes, and WebSocket hooks (`hooks.ws`).
|
|
657
658
|
|
|
658
659
|
### `platform.publish(topic, event, data)`
|
|
659
660
|
|
|
@@ -686,12 +687,12 @@ This is useful when you store WebSocket references (e.g. in a `Map`) and need to
|
|
|
686
687
|
// src/hooks.ws.js - store connections by user ID
|
|
687
688
|
const userSockets = new Map();
|
|
688
689
|
|
|
689
|
-
export function open(ws) {
|
|
690
|
+
export function open(ws, { platform }) {
|
|
690
691
|
const { userId } = ws.getUserData();
|
|
691
692
|
userSockets.set(userId, ws);
|
|
692
693
|
}
|
|
693
694
|
|
|
694
|
-
export function close(ws) {
|
|
695
|
+
export function close(ws, { platform }) {
|
|
695
696
|
const { userId } = ws.getUserData();
|
|
696
697
|
userSockets.delete(userId);
|
|
697
698
|
}
|
|
@@ -714,13 +715,15 @@ export async function POST({ request, platform }) {
|
|
|
714
715
|
}
|
|
715
716
|
```
|
|
716
717
|
|
|
717
|
-
|
|
718
|
+
You can also reply directly from inside `hooks.ws.js` using `platform.send()` or `ws.send()` with the envelope format:
|
|
718
719
|
|
|
719
720
|
```js
|
|
720
721
|
// src/hooks.ws.js
|
|
721
|
-
export function message(ws,
|
|
722
|
-
const msg = JSON.parse(Buffer.from(
|
|
723
|
-
//
|
|
722
|
+
export function message(ws, { data, platform }) {
|
|
723
|
+
const msg = JSON.parse(Buffer.from(data).toString());
|
|
724
|
+
// Using platform.send (recommended):
|
|
725
|
+
platform.send(ws, 'echo', 'reply', { got: msg });
|
|
726
|
+
// Or using ws.send with manual envelope:
|
|
724
727
|
ws.send(JSON.stringify({ topic: 'echo', event: 'reply', data: { got: msg } }));
|
|
725
728
|
}
|
|
726
729
|
```
|
|
@@ -980,13 +983,22 @@ Handles `set`, `increment`, and `decrement` events:
|
|
|
980
983
|
<p>{$online} users online</p>
|
|
981
984
|
```
|
|
982
985
|
|
|
983
|
-
Server:
|
|
986
|
+
Server (from any hook or handler that has `platform`):
|
|
984
987
|
```js
|
|
985
|
-
|
|
986
|
-
platform
|
|
988
|
+
// In hooks.ws.js - track connected users:
|
|
989
|
+
export function open(ws, { platform }) {
|
|
990
|
+
platform.topic('online-users').increment();
|
|
991
|
+
}
|
|
992
|
+
export function close(ws, { platform }) {
|
|
993
|
+
platform.topic('online-users').decrement();
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// Or from a SvelteKit handler:
|
|
987
997
|
platform.topic('online-users').set(42);
|
|
988
998
|
```
|
|
989
999
|
|
|
1000
|
+
> **Heads up:** The increment/decrement pattern above has a subtle race condition - a newly connected client won't see the current count because its `subscribe` message hasn't been processed yet when `open` fires. See [Seeding initial state](#seeding-initial-state) for the fix.
|
|
1001
|
+
|
|
990
1002
|
### `once(topic, event?, options?)` - wait for one event
|
|
991
1003
|
|
|
992
1004
|
Returns a promise that resolves with the first matching event and then unsubscribes:
|
|
@@ -1077,6 +1089,78 @@ ws.close();
|
|
|
1077
1089
|
|
|
1078
1090
|
---
|
|
1079
1091
|
|
|
1092
|
+
## Seeding initial state
|
|
1093
|
+
|
|
1094
|
+
When a client connects, there's a window between the WebSocket opening and the client's topic subscriptions being processed. Any `platform.publish()` calls that happen during `open` will be missed by the connecting client, because it hasn't subscribed to those topics yet.
|
|
1095
|
+
|
|
1096
|
+
This matters most with `count()`. If your `open` hook does `platform.topic('online').set(total)`, the connecting client won't see it - the `set` event is broadcast before the client's `subscribe` message arrives.
|
|
1097
|
+
|
|
1098
|
+
The fix is to use the `subscribe` hook instead of (or alongside) `open` to send the current value directly to the subscribing client:
|
|
1099
|
+
|
|
1100
|
+
```js
|
|
1101
|
+
// src/hooks.ws.js
|
|
1102
|
+
let online = 0;
|
|
1103
|
+
|
|
1104
|
+
export function open(ws, { platform }) {
|
|
1105
|
+
online++;
|
|
1106
|
+
platform.topic('online').set(online); // broadcasts to already-subscribed clients
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
export function subscribe(ws, topic, { platform }) {
|
|
1110
|
+
// When a client subscribes to 'online', send it the current count
|
|
1111
|
+
if (topic === 'online') {
|
|
1112
|
+
platform.send(ws, 'online', 'set', online);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
export function close(ws, { platform }) {
|
|
1117
|
+
online--;
|
|
1118
|
+
platform.topic('online').set(online);
|
|
1119
|
+
}
|
|
1120
|
+
```
|
|
1121
|
+
|
|
1122
|
+
```svelte
|
|
1123
|
+
<!-- src/routes/+page.svelte -->
|
|
1124
|
+
<script>
|
|
1125
|
+
import { count } from 'svelte-adapter-uws/client';
|
|
1126
|
+
|
|
1127
|
+
const online = count('online');
|
|
1128
|
+
</script>
|
|
1129
|
+
|
|
1130
|
+
<p>{$online} online</p>
|
|
1131
|
+
```
|
|
1132
|
+
|
|
1133
|
+
The `subscribe` hook fires at the right moment - after the client is actually subscribed to the topic. `platform.send()` sends only to that one client, so it gets the current value without waiting for the next broadcast.
|
|
1134
|
+
|
|
1135
|
+
This same pattern works for any topic where new subscribers need to see the current state. For a CRUD list, you could send the full dataset in `subscribe`:
|
|
1136
|
+
|
|
1137
|
+
```js
|
|
1138
|
+
// src/hooks.ws.js
|
|
1139
|
+
export async function subscribe(ws, topic, { platform }) {
|
|
1140
|
+
if (topic === 'todos') {
|
|
1141
|
+
const todos = await db.getTodos();
|
|
1142
|
+
for (const todo of todos) {
|
|
1143
|
+
platform.send(ws, 'todos', 'created', todo);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
```
|
|
1148
|
+
|
|
1149
|
+
```svelte
|
|
1150
|
+
<script>
|
|
1151
|
+
import { crud } from 'svelte-adapter-uws/client';
|
|
1152
|
+
|
|
1153
|
+
// No need for load() data - the subscribe hook seeds the list
|
|
1154
|
+
const todos = crud('todos');
|
|
1155
|
+
</script>
|
|
1156
|
+
|
|
1157
|
+
{#each $todos as todo (todo.id)}
|
|
1158
|
+
<p>{todo.text}</p>
|
|
1159
|
+
{/each}
|
|
1160
|
+
```
|
|
1161
|
+
|
|
1162
|
+
---
|
|
1163
|
+
|
|
1080
1164
|
## TypeScript setup
|
|
1081
1165
|
|
|
1082
1166
|
Add the platform type to your `src/app.d.ts`:
|
|
@@ -1229,10 +1313,10 @@ The static file gap is the largest because `adapter-node` uses sirv which calls
|
|
|
1229
1313
|
|
|
1230
1314
|
| Server | Messages delivered/s | vs adapter-uws |
|
|
1231
1315
|
|---|---|---|
|
|
1232
|
-
| **uWS native** (barebones) | 3,
|
|
1233
|
-
| **adapter-uws** (full handler) | 3,
|
|
1234
|
-
| **
|
|
1235
|
-
| **
|
|
1316
|
+
| **uWS native** (barebones) | 3,642,000 | baseline |
|
|
1317
|
+
| **adapter-uws** (full handler) | 3,625,000 | 1.0x |
|
|
1318
|
+
| **ws** library | 177,200 | **20.5x slower** |
|
|
1319
|
+
| **socket.io** | 164,500 | **22.1x slower** |
|
|
1236
1320
|
|
|
1237
1321
|
uWS native pub/sub delivered 3.6M messages/s with perfect 50x fan-out. After optimization, the adapter matches it -- the byte-prefix check and string template envelope add near-zero overhead to the hot path. `socket.io` and `ws` both collapsed under the same load, delivering less than 1x fan-out (massive message loss/queueing).
|
|
1238
1322
|
|
package/files/handler.js
CHANGED
|
@@ -836,7 +836,7 @@ if (WS_ENABLED) {
|
|
|
836
836
|
|
|
837
837
|
open: (ws) => {
|
|
838
838
|
wsConnections.add(ws);
|
|
839
|
-
wsModule.open?.(ws);
|
|
839
|
+
wsModule.open?.(ws, { platform });
|
|
840
840
|
},
|
|
841
841
|
|
|
842
842
|
message: (ws, message, isBinary) => {
|
|
@@ -851,7 +851,7 @@ if (WS_ENABLED) {
|
|
|
851
851
|
const msg = JSON.parse(Buffer.from(message).toString());
|
|
852
852
|
if (msg.type === 'subscribe' && typeof msg.topic === 'string') {
|
|
853
853
|
// If a subscribe hook exists, let it gate access
|
|
854
|
-
if (wsModule.subscribe && wsModule.subscribe(ws, msg.topic) === false) {
|
|
854
|
+
if (wsModule.subscribe && wsModule.subscribe(ws, msg.topic, { platform }) === false) {
|
|
855
855
|
return;
|
|
856
856
|
}
|
|
857
857
|
ws.subscribe(msg.topic);
|
|
@@ -866,14 +866,14 @@ if (WS_ENABLED) {
|
|
|
866
866
|
}
|
|
867
867
|
}
|
|
868
868
|
// Delegate everything else to the user's handler (if provided)
|
|
869
|
-
wsModule.message?.(ws, message, isBinary);
|
|
869
|
+
wsModule.message?.(ws, { data: message, isBinary, platform });
|
|
870
870
|
},
|
|
871
871
|
|
|
872
|
-
drain: wsModule.drain
|
|
872
|
+
drain: wsModule.drain ? (ws) => wsModule.drain(ws, { platform }) : undefined,
|
|
873
873
|
|
|
874
874
|
close: (ws, code, message) => {
|
|
875
875
|
wsConnections.delete(ws);
|
|
876
|
-
wsModule.close?.(ws, code, message);
|
|
876
|
+
wsModule.close?.(ws, { code, message, platform });
|
|
877
877
|
},
|
|
878
878
|
|
|
879
879
|
maxPayloadLength: wsOptions.maxPayloadLength,
|
package/index.d.ts
CHANGED
|
@@ -189,6 +189,46 @@ export interface UpgradeContext {
|
|
|
189
189
|
remoteAddress: string;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Context passed to `open` and `drain` handlers.
|
|
194
|
+
*/
|
|
195
|
+
export interface OpenContext {
|
|
196
|
+
/** The platform API - publish, send, topic helpers, etc. */
|
|
197
|
+
platform: Platform;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Context passed to the `message` handler.
|
|
202
|
+
*/
|
|
203
|
+
export interface MessageContext {
|
|
204
|
+
/** The raw message data. */
|
|
205
|
+
data: ArrayBuffer;
|
|
206
|
+
/** Whether the message is binary. */
|
|
207
|
+
isBinary: boolean;
|
|
208
|
+
/** The platform API - publish, send, topic helpers, etc. */
|
|
209
|
+
platform: Platform;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Context passed to the `close` handler.
|
|
214
|
+
*/
|
|
215
|
+
export interface CloseContext {
|
|
216
|
+
/** The WebSocket close code. */
|
|
217
|
+
code: number;
|
|
218
|
+
/** The close reason (as ArrayBuffer). */
|
|
219
|
+
message: ArrayBuffer;
|
|
220
|
+
/** The platform API - publish, send, topic helpers, etc. */
|
|
221
|
+
platform: Platform;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Context passed to the `subscribe` handler.
|
|
226
|
+
*/
|
|
227
|
+
export interface SubscribeContext {
|
|
228
|
+
/** The platform API - publish, send, topic helpers, etc. */
|
|
229
|
+
platform: Platform;
|
|
230
|
+
}
|
|
231
|
+
|
|
192
232
|
/**
|
|
193
233
|
* Shape of the user's WebSocket handler module.
|
|
194
234
|
*
|
|
@@ -196,6 +236,10 @@ export interface UpgradeContext {
|
|
|
196
236
|
* of these functions. All are optional - the built-in handler already
|
|
197
237
|
* handles subscribe/unsubscribe for the client store.
|
|
198
238
|
*
|
|
239
|
+
* Every hook receives `(ws, context)` where context always includes `platform`
|
|
240
|
+
* plus any hook-specific fields. This gives you full access to publish, send,
|
|
241
|
+
* and topic helpers directly in your WebSocket hooks.
|
|
242
|
+
*
|
|
199
243
|
* @example
|
|
200
244
|
* ```js
|
|
201
245
|
* // src/hooks.ws.js - auto-discovered, no config needed
|
|
@@ -207,8 +251,13 @@ export interface UpgradeContext {
|
|
|
207
251
|
* return { userId: user.id }; // attach data to socket
|
|
208
252
|
* }
|
|
209
253
|
*
|
|
210
|
-
* export function open(ws) {
|
|
254
|
+
* export function open(ws, { platform }) {
|
|
211
255
|
* ws.subscribe(`user:${ws.getUserData().userId}`);
|
|
256
|
+
* platform.topic('users').increment();
|
|
257
|
+
* }
|
|
258
|
+
*
|
|
259
|
+
* export function close(ws, { platform }) {
|
|
260
|
+
* platform.topic('users').decrement();
|
|
212
261
|
* }
|
|
213
262
|
* ```
|
|
214
263
|
*/
|
|
@@ -225,7 +274,7 @@ export interface WebSocketHandler<UserData = unknown> {
|
|
|
225
274
|
upgrade?: (ctx: UpgradeContext) => UserData | false | Promise<UserData | false>;
|
|
226
275
|
|
|
227
276
|
/** Called when a WebSocket connection is established. */
|
|
228
|
-
open?: (ws: WebSocket<UserData
|
|
277
|
+
open?: (ws: WebSocket<UserData>, ctx: OpenContext) => void;
|
|
229
278
|
|
|
230
279
|
/**
|
|
231
280
|
* Called when a message is received.
|
|
@@ -234,7 +283,7 @@ export interface WebSocketHandler<UserData = unknown> {
|
|
|
234
283
|
* handled automatically before this is called. You only need this for
|
|
235
284
|
* custom application-level messages.
|
|
236
285
|
*/
|
|
237
|
-
message?: (ws: WebSocket<UserData>,
|
|
286
|
+
message?: (ws: WebSocket<UserData>, ctx: MessageContext) => void;
|
|
238
287
|
|
|
239
288
|
/**
|
|
240
289
|
* Called when a client tries to subscribe to a topic.
|
|
@@ -246,22 +295,22 @@ export interface WebSocketHandler<UserData = unknown> {
|
|
|
246
295
|
*
|
|
247
296
|
* @example
|
|
248
297
|
* ```js
|
|
249
|
-
* export function subscribe(ws, topic) {
|
|
298
|
+
* export function subscribe(ws, topic, { platform }) {
|
|
250
299
|
* const { role } = ws.getUserData();
|
|
251
300
|
* if (topic.startsWith('admin') && role !== 'admin') return false;
|
|
252
301
|
* }
|
|
253
302
|
* ```
|
|
254
303
|
*/
|
|
255
|
-
subscribe?: (ws: WebSocket<UserData>, topic: string) => boolean | void;
|
|
304
|
+
subscribe?: (ws: WebSocket<UserData>, topic: string, ctx: SubscribeContext) => boolean | void;
|
|
256
305
|
|
|
257
306
|
/**
|
|
258
307
|
* Called when backpressure has drained (buffered data was sent).
|
|
259
308
|
* Use this for flow control when sending large or frequent messages.
|
|
260
309
|
*/
|
|
261
|
-
drain?: (ws: WebSocket<UserData
|
|
310
|
+
drain?: (ws: WebSocket<UserData>, ctx: OpenContext) => void;
|
|
262
311
|
|
|
263
312
|
/** Called when the connection closes. */
|
|
264
|
-
close?: (ws: WebSocket<UserData>,
|
|
313
|
+
close?: (ws: WebSocket<UserData>, ctx: CloseContext) => void;
|
|
265
314
|
}
|
|
266
315
|
|
|
267
316
|
// -- Platform type for event.platform ----------------------------------------
|
|
@@ -310,8 +359,8 @@ export interface Platform {
|
|
|
310
359
|
* @example
|
|
311
360
|
* ```js
|
|
312
361
|
* // In hooks.ws.js - reply to sender:
|
|
313
|
-
* export function message(ws,
|
|
314
|
-
* const msg = JSON.parse(Buffer.from(
|
|
362
|
+
* export function message(ws, { data }) {
|
|
363
|
+
* const msg = JSON.parse(Buffer.from(data).toString());
|
|
315
364
|
* ws.send(JSON.stringify({ topic: 'echo', event: 'reply', data: { got: msg } }));
|
|
316
365
|
* }
|
|
317
366
|
* ```
|
package/package.json
CHANGED
package/vite.js
CHANGED
|
@@ -310,7 +310,7 @@ export default function uws(options = {}) {
|
|
|
310
310
|
wsWrappers.set(ws, wrapped);
|
|
311
311
|
|
|
312
312
|
// Call user open handler
|
|
313
|
-
userHandlers.open?.(wrapped);
|
|
313
|
+
userHandlers.open?.(wrapped, { platform });
|
|
314
314
|
|
|
315
315
|
ws.on('message', async (raw, isBinary) => {
|
|
316
316
|
// Convert to ArrayBuffer (matching uWS interface)
|
|
@@ -324,7 +324,7 @@ export default function uws(options = {}) {
|
|
|
324
324
|
try {
|
|
325
325
|
const msg = JSON.parse(buf.toString());
|
|
326
326
|
if (msg.type === 'subscribe' && typeof msg.topic === 'string') {
|
|
327
|
-
if (userHandlers.subscribe && userHandlers.subscribe(wrapped, msg.topic) === false) {
|
|
327
|
+
if (userHandlers.subscribe && userHandlers.subscribe(wrapped, msg.topic, { platform }) === false) {
|
|
328
328
|
return;
|
|
329
329
|
}
|
|
330
330
|
subscriptions.get(ws)?.add(msg.topic);
|
|
@@ -342,14 +342,14 @@ export default function uws(options = {}) {
|
|
|
342
342
|
// Delegate to user handler
|
|
343
343
|
await handlerReady;
|
|
344
344
|
if (userHandlers.message) {
|
|
345
|
-
userHandlers.message(wrapped, arrayBuffer, !!isBinary);
|
|
345
|
+
userHandlers.message(wrapped, { data: arrayBuffer, isBinary: !!isBinary, platform });
|
|
346
346
|
}
|
|
347
347
|
});
|
|
348
348
|
|
|
349
349
|
ws.on('close', (code, reason) => {
|
|
350
350
|
const reasonBuf = reason || Buffer.alloc(0);
|
|
351
351
|
const reasonAB = reasonBuf.buffer.slice(reasonBuf.byteOffset, reasonBuf.byteOffset + reasonBuf.byteLength);
|
|
352
|
-
userHandlers.close?.(wrapped, code, reasonAB);
|
|
352
|
+
userHandlers.close?.(wrapped, { code, message: reasonAB, platform });
|
|
353
353
|
connections.delete(ws);
|
|
354
354
|
subscriptions.delete(ws);
|
|
355
355
|
wsWrappers.delete(ws);
|