@jsenv/server 17.3.1 → 17.4.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.
|
@@ -297,41 +297,41 @@ var hasRequiredUtils;
|
|
|
297
297
|
function requireUtils () {
|
|
298
298
|
if (hasRequiredUtils) return utils;
|
|
299
299
|
hasRequiredUtils = 1;
|
|
300
|
-
(function (exports
|
|
300
|
+
(function (exports) {
|
|
301
301
|
/**
|
|
302
302
|
* Utilities for hex, bytes, CSPRNG.
|
|
303
303
|
* @module
|
|
304
304
|
*/
|
|
305
305
|
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
306
|
-
Object.defineProperty(exports
|
|
307
|
-
exports
|
|
308
|
-
exports
|
|
309
|
-
exports
|
|
310
|
-
exports
|
|
311
|
-
exports
|
|
312
|
-
exports
|
|
313
|
-
exports
|
|
314
|
-
exports
|
|
315
|
-
exports
|
|
316
|
-
exports
|
|
317
|
-
exports
|
|
318
|
-
exports
|
|
319
|
-
exports
|
|
320
|
-
exports
|
|
321
|
-
exports
|
|
322
|
-
exports
|
|
323
|
-
exports
|
|
324
|
-
exports
|
|
325
|
-
exports
|
|
326
|
-
exports
|
|
327
|
-
exports
|
|
328
|
-
exports
|
|
329
|
-
exports
|
|
330
|
-
exports
|
|
331
|
-
exports
|
|
332
|
-
exports
|
|
333
|
-
exports
|
|
334
|
-
exports
|
|
306
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
307
|
+
exports.wrapXOFConstructorWithOpts = exports.wrapConstructorWithOpts = exports.wrapConstructor = exports.Hash = exports.nextTick = exports.swap32IfBE = exports.byteSwapIfBE = exports.swap8IfBE = exports.isLE = void 0;
|
|
308
|
+
exports.isBytes = isBytes;
|
|
309
|
+
exports.anumber = anumber;
|
|
310
|
+
exports.abytes = abytes;
|
|
311
|
+
exports.ahash = ahash;
|
|
312
|
+
exports.aexists = aexists;
|
|
313
|
+
exports.aoutput = aoutput;
|
|
314
|
+
exports.u8 = u8;
|
|
315
|
+
exports.u32 = u32;
|
|
316
|
+
exports.clean = clean;
|
|
317
|
+
exports.createView = createView;
|
|
318
|
+
exports.rotr = rotr;
|
|
319
|
+
exports.rotl = rotl;
|
|
320
|
+
exports.byteSwap = byteSwap;
|
|
321
|
+
exports.byteSwap32 = byteSwap32;
|
|
322
|
+
exports.bytesToHex = bytesToHex;
|
|
323
|
+
exports.hexToBytes = hexToBytes;
|
|
324
|
+
exports.asyncLoop = asyncLoop;
|
|
325
|
+
exports.utf8ToBytes = utf8ToBytes;
|
|
326
|
+
exports.bytesToUtf8 = bytesToUtf8;
|
|
327
|
+
exports.toBytes = toBytes;
|
|
328
|
+
exports.kdfInputToBytes = kdfInputToBytes;
|
|
329
|
+
exports.concatBytes = concatBytes;
|
|
330
|
+
exports.checkOpts = checkOpts;
|
|
331
|
+
exports.createHasher = createHasher;
|
|
332
|
+
exports.createOptHasher = createOptHasher;
|
|
333
|
+
exports.createXOFer = createXOFer;
|
|
334
|
+
exports.randomBytes = randomBytes;
|
|
335
335
|
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
|
|
336
336
|
// node.js versions earlier than v19 don't declare it in global scope.
|
|
337
337
|
// For node.js, package.json#exports field mapping rewrites import
|
|
@@ -404,7 +404,7 @@ function requireUtils () {
|
|
|
404
404
|
return (word << shift) | ((word >>> (32 - shift)) >>> 0);
|
|
405
405
|
}
|
|
406
406
|
/** Is current platform little-endian? Most are. Big-Endian platform: IBM */
|
|
407
|
-
exports
|
|
407
|
+
exports.isLE = (() => new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)();
|
|
408
408
|
/** The byte swap operation for uint32 */
|
|
409
409
|
function byteSwap(word) {
|
|
410
410
|
return (((word << 24) & 0xff000000) |
|
|
@@ -413,11 +413,11 @@ function requireUtils () {
|
|
|
413
413
|
((word >>> 24) & 0xff));
|
|
414
414
|
}
|
|
415
415
|
/** Conditionally byte swap if on a big-endian platform */
|
|
416
|
-
exports
|
|
416
|
+
exports.swap8IfBE = exports.isLE
|
|
417
417
|
? (n) => n
|
|
418
418
|
: (n) => byteSwap(n);
|
|
419
419
|
/** @deprecated */
|
|
420
|
-
exports
|
|
420
|
+
exports.byteSwapIfBE = exports.swap8IfBE;
|
|
421
421
|
/** In place byte swap for Uint32Array */
|
|
422
422
|
function byteSwap32(arr) {
|
|
423
423
|
for (let i = 0; i < arr.length; i++) {
|
|
@@ -425,7 +425,7 @@ function requireUtils () {
|
|
|
425
425
|
}
|
|
426
426
|
return arr;
|
|
427
427
|
}
|
|
428
|
-
exports
|
|
428
|
+
exports.swap32IfBE = exports.isLE
|
|
429
429
|
? (u) => u
|
|
430
430
|
: byteSwap32;
|
|
431
431
|
// Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex
|
|
@@ -493,7 +493,7 @@ function requireUtils () {
|
|
|
493
493
|
* next scheduler queue processing step and this is exactly what we need.
|
|
494
494
|
*/
|
|
495
495
|
const nextTick = async () => { };
|
|
496
|
-
exports
|
|
496
|
+
exports.nextTick = nextTick;
|
|
497
497
|
/** Returns control to thread each 'tick' ms to avoid blocking. */
|
|
498
498
|
async function asyncLoop(iters, tick, cb) {
|
|
499
499
|
let ts = Date.now();
|
|
@@ -503,7 +503,7 @@ function requireUtils () {
|
|
|
503
503
|
const diff = Date.now() - ts;
|
|
504
504
|
if (diff >= 0 && diff < tick)
|
|
505
505
|
continue;
|
|
506
|
-
await (0, exports
|
|
506
|
+
await (0, exports.nextTick)();
|
|
507
507
|
ts += diff;
|
|
508
508
|
}
|
|
509
509
|
}
|
|
@@ -569,7 +569,7 @@ function requireUtils () {
|
|
|
569
569
|
/** For runtime check if class implements interface */
|
|
570
570
|
class Hash {
|
|
571
571
|
}
|
|
572
|
-
exports
|
|
572
|
+
exports.Hash = Hash;
|
|
573
573
|
/** Wraps hash function, creating an interface on top of it */
|
|
574
574
|
function createHasher(hashCons) {
|
|
575
575
|
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
|
|
@@ -595,9 +595,9 @@ function requireUtils () {
|
|
|
595
595
|
hashC.create = (opts) => hashCons(opts);
|
|
596
596
|
return hashC;
|
|
597
597
|
}
|
|
598
|
-
exports
|
|
599
|
-
exports
|
|
600
|
-
exports
|
|
598
|
+
exports.wrapConstructor = createHasher;
|
|
599
|
+
exports.wrapConstructorWithOpts = createOptHasher;
|
|
600
|
+
exports.wrapXOFConstructorWithOpts = createXOFer;
|
|
601
601
|
/** Cryptographically secure PRNG. Uses internal OS-level `crypto.getRandomValues`. */
|
|
602
602
|
function randomBytes(bytesLength = 32) {
|
|
603
603
|
if (crypto_1.crypto && typeof crypto_1.crypto.getRandomValues === 'function') {
|
package/dist/jsenv_server.js
CHANGED
|
@@ -2907,6 +2907,30 @@ const trackHttp1ServerPendingRequests = (nodeServer) => {
|
|
|
2907
2907
|
* But we don't really need a class so we are just returning a regular object under the hood
|
|
2908
2908
|
*/
|
|
2909
2909
|
|
|
2910
|
+
/**
|
|
2911
|
+
* Return this from a route `fetch` to accept a websocket upgrade on that
|
|
2912
|
+
* endpoint.
|
|
2913
|
+
*
|
|
2914
|
+
* @param {(websocket: import("ws").WebSocket) => void | (() => void)} webSocketHandler
|
|
2915
|
+
* Called with the raw `ws` socket once the upgrade completes. Use
|
|
2916
|
+
* `websocket.on("message", …)` / `websocket.send(…)`. If it returns a
|
|
2917
|
+
* function, that function runs as cleanup when the socket closes.
|
|
2918
|
+
* @param {object} [init]
|
|
2919
|
+
* @param {number} [init.status=101]
|
|
2920
|
+
* @param {string} [init.statusText]
|
|
2921
|
+
* @param {object} [init.headers]
|
|
2922
|
+
*
|
|
2923
|
+
* @example
|
|
2924
|
+
* {
|
|
2925
|
+
* endpoint: "GET /chat.websocket",
|
|
2926
|
+
* fetch: () => new WebSocketResponse((websocket) => {
|
|
2927
|
+
* websocket.on("message", (data) => websocket.send(data));
|
|
2928
|
+
* return () => {
|
|
2929
|
+
* // socket closed
|
|
2930
|
+
* };
|
|
2931
|
+
* }),
|
|
2932
|
+
* }
|
|
2933
|
+
*/
|
|
2910
2934
|
class WebSocketResponse {
|
|
2911
2935
|
constructor(
|
|
2912
2936
|
webSocketHandler,
|
|
@@ -2986,7 +3010,7 @@ const getWebSocketHandler = (responseProperties) => {
|
|
|
2986
3010
|
* // Use in server route
|
|
2987
3011
|
* {
|
|
2988
3012
|
* endpoint: "GET /events",
|
|
2989
|
-
*
|
|
3013
|
+
* fetch: (request) => serverEvents.fetch(request)
|
|
2990
3014
|
* }
|
|
2991
3015
|
*/
|
|
2992
3016
|
class ServerEvents {
|
|
@@ -3044,7 +3068,7 @@ class ServerEvents {
|
|
|
3044
3068
|
* // Use in server route
|
|
3045
3069
|
* {
|
|
3046
3070
|
* endpoint: "GET /events",
|
|
3047
|
-
*
|
|
3071
|
+
* fetch: (request) => events.fetch(request)
|
|
3048
3072
|
* }
|
|
3049
3073
|
*/
|
|
3050
3074
|
class LazyServerEvents {
|
package/dist/ws/ws.js
CHANGED
|
@@ -8,6 +8,7 @@ import require$$0$2 from "node:stream";
|
|
|
8
8
|
import require$$7 from "node:url";
|
|
9
9
|
import require$$0 from "node:zlib";
|
|
10
10
|
import require$$0$1 from "node:buffer";
|
|
11
|
+
import require$$2 from "node:util";
|
|
11
12
|
|
|
12
13
|
function getDefaultExportFromCjs (x) {
|
|
13
14
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
@@ -987,6 +988,10 @@ function requireReceiver () {
|
|
|
987
988
|
* extensions
|
|
988
989
|
* @param {Boolean} [options.isServer=false] Specifies whether to operate in
|
|
989
990
|
* client or server mode
|
|
991
|
+
* @param {Number} [options.maxBufferedChunks=0] The maximum number of
|
|
992
|
+
* buffered data chunks
|
|
993
|
+
* @param {Number} [options.maxFragments=0] The maximum number of message
|
|
994
|
+
* fragments
|
|
990
995
|
* @param {Number} [options.maxPayload=0] The maximum allowed message length
|
|
991
996
|
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
|
|
992
997
|
* not to skip UTF-8 validation for text and close messages
|
|
@@ -1001,6 +1006,8 @@ function requireReceiver () {
|
|
|
1001
1006
|
this._binaryType = options.binaryType || BINARY_TYPES[0];
|
|
1002
1007
|
this._extensions = options.extensions || {};
|
|
1003
1008
|
this._isServer = !!options.isServer;
|
|
1009
|
+
this._maxBufferedChunks = options.maxBufferedChunks | 0;
|
|
1010
|
+
this._maxFragments = options.maxFragments | 0;
|
|
1004
1011
|
this._maxPayload = options.maxPayload | 0;
|
|
1005
1012
|
this._skipUTF8Validation = !!options.skipUTF8Validation;
|
|
1006
1013
|
this[kWebSocket] = undefined;
|
|
@@ -1018,6 +1025,7 @@ function requireReceiver () {
|
|
|
1018
1025
|
|
|
1019
1026
|
this._totalPayloadLength = 0;
|
|
1020
1027
|
this._messageLength = 0;
|
|
1028
|
+
this._numFragments = 0;
|
|
1021
1029
|
this._fragments = [];
|
|
1022
1030
|
|
|
1023
1031
|
this._errored = false;
|
|
@@ -1036,6 +1044,22 @@ function requireReceiver () {
|
|
|
1036
1044
|
_write(chunk, encoding, cb) {
|
|
1037
1045
|
if (this._opcode === 0x08 && this._state == GET_INFO) return cb();
|
|
1038
1046
|
|
|
1047
|
+
if (
|
|
1048
|
+
this._maxBufferedChunks > 0 &&
|
|
1049
|
+
this._buffers.length >= this._maxBufferedChunks
|
|
1050
|
+
) {
|
|
1051
|
+
cb(
|
|
1052
|
+
this.createError(
|
|
1053
|
+
RangeError,
|
|
1054
|
+
'Too many buffered chunks',
|
|
1055
|
+
false,
|
|
1056
|
+
1008,
|
|
1057
|
+
'WS_ERR_TOO_MANY_BUFFERED_PARTS'
|
|
1058
|
+
)
|
|
1059
|
+
);
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1039
1063
|
this._bufferedBytes += chunk.length;
|
|
1040
1064
|
this._buffers.push(chunk);
|
|
1041
1065
|
this.startLoop(cb);
|
|
@@ -1425,6 +1449,19 @@ function requireReceiver () {
|
|
|
1425
1449
|
return;
|
|
1426
1450
|
}
|
|
1427
1451
|
|
|
1452
|
+
if (this._maxFragments > 0 && ++this._numFragments > this._maxFragments) {
|
|
1453
|
+
const error = this.createError(
|
|
1454
|
+
RangeError,
|
|
1455
|
+
'Too many message fragments',
|
|
1456
|
+
false,
|
|
1457
|
+
1008,
|
|
1458
|
+
'WS_ERR_TOO_MANY_BUFFERED_PARTS'
|
|
1459
|
+
);
|
|
1460
|
+
|
|
1461
|
+
cb(error);
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1428
1465
|
if (this._compressed) {
|
|
1429
1466
|
this._state = INFLATING;
|
|
1430
1467
|
this.decompress(data, cb);
|
|
@@ -1497,6 +1534,7 @@ function requireReceiver () {
|
|
|
1497
1534
|
this._totalPayloadLength = 0;
|
|
1498
1535
|
this._messageLength = 0;
|
|
1499
1536
|
this._fragmented = 0;
|
|
1537
|
+
this._numFragments = 0;
|
|
1500
1538
|
this._fragments = [];
|
|
1501
1539
|
|
|
1502
1540
|
if (this._opcode === 2) {
|
|
@@ -1665,6 +1703,9 @@ function requireSender () {
|
|
|
1665
1703
|
|
|
1666
1704
|
const { Duplex } = require$$0$2;
|
|
1667
1705
|
const { randomFillSync } = require$$1;
|
|
1706
|
+
const {
|
|
1707
|
+
types: { isUint8Array }
|
|
1708
|
+
} = require$$2;
|
|
1668
1709
|
|
|
1669
1710
|
const PerMessageDeflate = requirePermessageDeflate();
|
|
1670
1711
|
const { EMPTY_BUFFER, kWebSocket, NOOP } = requireConstants();
|
|
@@ -1861,8 +1902,10 @@ function requireSender () {
|
|
|
1861
1902
|
|
|
1862
1903
|
if (typeof data === 'string') {
|
|
1863
1904
|
buf.write(data, 2);
|
|
1864
|
-
} else {
|
|
1905
|
+
} else if (isUint8Array(data)) {
|
|
1865
1906
|
buf.set(data, 2);
|
|
1907
|
+
} else {
|
|
1908
|
+
throw new TypeError('Second argument must be a string or a Uint8Array');
|
|
1866
1909
|
}
|
|
1867
1910
|
}
|
|
1868
1911
|
|
|
@@ -2983,6 +3026,10 @@ function requireWebsocket () {
|
|
|
2983
3026
|
* multiple times in the same tick
|
|
2984
3027
|
* @param {Function} [options.generateMask] The function used to generate the
|
|
2985
3028
|
* masking key
|
|
3029
|
+
* @param {Number} [options.maxBufferedChunks=0] The maximum number of
|
|
3030
|
+
* buffered data chunks
|
|
3031
|
+
* @param {Number} [options.maxFragments=0] The maximum number of message
|
|
3032
|
+
* fragments
|
|
2986
3033
|
* @param {Number} [options.maxPayload=0] The maximum allowed message size
|
|
2987
3034
|
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
|
|
2988
3035
|
* not to skip UTF-8 validation for text and close messages
|
|
@@ -2994,6 +3041,8 @@ function requireWebsocket () {
|
|
|
2994
3041
|
binaryType: this.binaryType,
|
|
2995
3042
|
extensions: this._extensions,
|
|
2996
3043
|
isServer: this._isServer,
|
|
3044
|
+
maxBufferedChunks: options.maxBufferedChunks,
|
|
3045
|
+
maxFragments: options.maxFragments,
|
|
2997
3046
|
maxPayload: options.maxPayload,
|
|
2998
3047
|
skipUTF8Validation: options.skipUTF8Validation
|
|
2999
3048
|
});
|
|
@@ -3422,6 +3471,10 @@ function requireWebsocket () {
|
|
|
3422
3471
|
* masking key
|
|
3423
3472
|
* @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the
|
|
3424
3473
|
* handshake request
|
|
3474
|
+
* @param {Number} [options.maxBufferedChunks=262144] The maximum number of
|
|
3475
|
+
* buffered data chunks
|
|
3476
|
+
* @param {Number} [options.maxFragments=16384] The maximum number of message
|
|
3477
|
+
* fragments
|
|
3425
3478
|
* @param {Number} [options.maxPayload=104857600] The maximum allowed message
|
|
3426
3479
|
* size
|
|
3427
3480
|
* @param {Number} [options.maxRedirects=10] The maximum number of redirects
|
|
@@ -3442,6 +3495,8 @@ function requireWebsocket () {
|
|
|
3442
3495
|
autoPong: true,
|
|
3443
3496
|
closeTimeout: CLOSE_TIMEOUT,
|
|
3444
3497
|
protocolVersion: protocolVersions[1],
|
|
3498
|
+
maxBufferedChunks: 256 * 1024,
|
|
3499
|
+
maxFragments: 16 * 1024,
|
|
3445
3500
|
maxPayload: 100 * 1024 * 1024,
|
|
3446
3501
|
skipUTF8Validation: false,
|
|
3447
3502
|
perMessageDeflate: true,
|
|
@@ -3799,6 +3854,8 @@ function requireWebsocket () {
|
|
|
3799
3854
|
websocket.setSocket(socket, head, {
|
|
3800
3855
|
allowSynchronousEvents: opts.allowSynchronousEvents,
|
|
3801
3856
|
generateMask: opts.generateMask,
|
|
3857
|
+
maxBufferedChunks: opts.maxBufferedChunks,
|
|
3858
|
+
maxFragments: opts.maxFragments,
|
|
3802
3859
|
maxPayload: opts.maxPayload,
|
|
3803
3860
|
skipUTF8Validation: opts.skipUTF8Validation
|
|
3804
3861
|
});
|
|
@@ -4480,6 +4537,10 @@ function requireWebsocketServer () {
|
|
|
4480
4537
|
* called
|
|
4481
4538
|
* @param {Function} [options.handleProtocols] A hook to handle protocols
|
|
4482
4539
|
* @param {String} [options.host] The hostname where to bind the server
|
|
4540
|
+
* @param {Number} [options.maxBufferedChunks=262144] The maximum number of
|
|
4541
|
+
* buffered data chunks
|
|
4542
|
+
* @param {Number} [options.maxFragments=16384] The maximum number of message
|
|
4543
|
+
* fragments
|
|
4483
4544
|
* @param {Number} [options.maxPayload=104857600] The maximum allowed message
|
|
4484
4545
|
* size
|
|
4485
4546
|
* @param {Boolean} [options.noServer=false] Enable no server mode
|
|
@@ -4502,6 +4563,8 @@ function requireWebsocketServer () {
|
|
|
4502
4563
|
options = {
|
|
4503
4564
|
allowSynchronousEvents: true,
|
|
4504
4565
|
autoPong: true,
|
|
4566
|
+
maxBufferedChunks: 256 * 1024,
|
|
4567
|
+
maxFragments: 16 * 1024,
|
|
4505
4568
|
maxPayload: 100 * 1024 * 1024,
|
|
4506
4569
|
skipUTF8Validation: false,
|
|
4507
4570
|
perMessageDeflate: false,
|
|
@@ -4861,6 +4924,8 @@ function requireWebsocketServer () {
|
|
|
4861
4924
|
|
|
4862
4925
|
ws.setSocket(socket, head, {
|
|
4863
4926
|
allowSynchronousEvents: this.options.allowSynchronousEvents,
|
|
4927
|
+
maxBufferedChunks: this.options.maxBufferedChunks,
|
|
4928
|
+
maxFragments: this.options.maxFragments,
|
|
4864
4929
|
maxPayload: this.options.maxPayload,
|
|
4865
4930
|
skipUTF8Validation: this.options.skipUTF8Validation
|
|
4866
4931
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/server",
|
|
3
|
-
"version": "17.
|
|
3
|
+
"version": "17.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A modern Node.js HTTP server with declarative routing, content negotiation, and WebSocket support",
|
|
6
6
|
"repository": {
|
|
@@ -56,9 +56,9 @@
|
|
|
56
56
|
"@jsenv/utils": "../../tooling/utils",
|
|
57
57
|
"eventsource": "4.1.0",
|
|
58
58
|
"formidable": "3.5.4",
|
|
59
|
-
"playwright": "1.
|
|
60
|
-
"undici": "
|
|
61
|
-
"ws": "8.
|
|
59
|
+
"playwright": "1.61.1",
|
|
60
|
+
"undici": "8.8.0",
|
|
61
|
+
"ws": "8.21.1"
|
|
62
62
|
},
|
|
63
63
|
"publishConfig": {
|
|
64
64
|
"access": "public"
|
package/src/server_events.js
CHANGED
|
@@ -49,7 +49,7 @@ import { WebSocketResponse } from "./web_socket_response.js";
|
|
|
49
49
|
* // Use in server route
|
|
50
50
|
* {
|
|
51
51
|
* endpoint: "GET /events",
|
|
52
|
-
*
|
|
52
|
+
* fetch: (request) => serverEvents.fetch(request)
|
|
53
53
|
* }
|
|
54
54
|
*/
|
|
55
55
|
export class ServerEvents {
|
|
@@ -107,7 +107,7 @@ export class ServerEvents {
|
|
|
107
107
|
* // Use in server route
|
|
108
108
|
* {
|
|
109
109
|
* endpoint: "GET /events",
|
|
110
|
-
*
|
|
110
|
+
* fetch: (request) => events.fetch(request)
|
|
111
111
|
* }
|
|
112
112
|
*/
|
|
113
113
|
export class LazyServerEvents {
|
|
@@ -14,6 +14,30 @@
|
|
|
14
14
|
* But we don't really need a class so we are just returning a regular object under the hood
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Return this from a route `fetch` to accept a websocket upgrade on that
|
|
19
|
+
* endpoint.
|
|
20
|
+
*
|
|
21
|
+
* @param {(websocket: import("ws").WebSocket) => void | (() => void)} webSocketHandler
|
|
22
|
+
* Called with the raw `ws` socket once the upgrade completes. Use
|
|
23
|
+
* `websocket.on("message", …)` / `websocket.send(…)`. If it returns a
|
|
24
|
+
* function, that function runs as cleanup when the socket closes.
|
|
25
|
+
* @param {object} [init]
|
|
26
|
+
* @param {number} [init.status=101]
|
|
27
|
+
* @param {string} [init.statusText]
|
|
28
|
+
* @param {object} [init.headers]
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* {
|
|
32
|
+
* endpoint: "GET /chat.websocket",
|
|
33
|
+
* fetch: () => new WebSocketResponse((websocket) => {
|
|
34
|
+
* websocket.on("message", (data) => websocket.send(data));
|
|
35
|
+
* return () => {
|
|
36
|
+
* // socket closed
|
|
37
|
+
* };
|
|
38
|
+
* }),
|
|
39
|
+
* }
|
|
40
|
+
*/
|
|
17
41
|
export class WebSocketResponse {
|
|
18
42
|
constructor(
|
|
19
43
|
webSocketHandler,
|