前端代码

This commit is contained in:
ChloeChen0423
2025-05-12 16:42:36 +09:00
commit 7c63f2f07b
4531 changed files with 656010 additions and 0 deletions

19
node_modules/engine.io/LICENSE generated vendored Normal file
View File

@ -0,0 +1,19 @@
(The MIT License)
Copyright (c) 2014-present Guillermo Rauch and Socket.IO contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the 'Software'), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

603
node_modules/engine.io/README.md generated vendored Normal file
View File

@ -0,0 +1,603 @@
# Engine.IO: the realtime engine
[![Build Status](https://github.com/socketio/engine.io/workflows/CI/badge.svg?branch=master)](https://github.com/socketio/engine.io/actions)
[![NPM version](https://badge.fury.io/js/engine.io.svg)](http://badge.fury.io/js/engine.io)
`Engine.IO` is the implementation of transport-based
cross-browser/cross-device bi-directional communication layer for
[Socket.IO](http://github.com/socketio/socket.io).
## How to use
### Server
#### (A) Listening on a port
```js
const engine = require('engine.io');
const server = engine.listen(80);
server.on('connection', socket => {
socket.send('utf 8 string');
socket.send(Buffer.from([0, 1, 2, 3, 4, 5])); // binary data
});
```
#### (B) Intercepting requests for a http.Server
```js
const engine = require('engine.io');
const http = require('http').createServer().listen(3000);
const server = engine.attach(http);
server.on('connection', socket => {
socket.on('message', data => { });
socket.on('close', () => { });
});
```
#### (C) Passing in requests
```js
const engine = require('engine.io');
const server = new engine.Server();
server.on('connection', socket => {
socket.send('hi');
});
// …
httpServer.on('upgrade', (req, socket, head) => {
server.handleUpgrade(req, socket, head);
});
httpServer.on('request', (req, res) => {
server.handleRequest(req, res);
});
```
### Client
```html
<script src="/path/to/engine.io.js"></script>
<script>
const socket = new eio.Socket('ws://localhost/');
socket.on('open', () => {
socket.on('message', data => {});
socket.on('close', () => {});
});
</script>
```
For more information on the client refer to the
[engine-client](http://github.com/socketio/engine.io-client) repository.
## What features does it have?
- **Maximum reliability**. Connections are established even in the presence of:
- proxies and load balancers.
- personal firewall and antivirus software.
- for more information refer to **Goals** and **Architecture** sections
- **Minimal client size** aided by:
- lazy loading of flash transports.
- lack of redundant transports.
- **Scalable**
- load balancer friendly
- **Future proof**
- **100% Node.JS core style**
- No API sugar (left for higher level projects)
## API
### Server
<hr><br>
#### Top-level
These are exposed by `require('engine.io')`:
##### Events
- `flush`
- Called when a socket buffer is being flushed.
- **Arguments**
- `Socket`: socket being flushed
- `Array`: write buffer
- `drain`
- Called when a socket buffer is drained
- **Arguments**
- `Socket`: socket being flushed
##### Properties
- `protocol` _(Number)_: protocol revision number
- `Server`: Server class constructor
- `Socket`: Socket class constructor
- `Transport` _(Function)_: transport constructor
- `transports` _(Object)_: map of available transports
##### Methods
- `()`
- Returns a new `Server` instance. If the first argument is an `http.Server` then the
new `Server` instance will be attached to it. Otherwise, the arguments are passed
directly to the `Server` constructor.
- **Parameters**
- `http.Server`: optional, server to attach to.
- `Object`: optional, options object (see `Server#constructor` api docs below)
The following are identical ways to instantiate a server and then attach it.
```js
const httpServer; // previously created with `http.createServer();` from node.js api.
// create a server first, and then attach
const eioServer = require('engine.io').Server();
eioServer.attach(httpServer);
// or call the module as a function to get `Server`
const eioServer = require('engine.io')();
eioServer.attach(httpServer);
// immediately attach
const eioServer = require('engine.io')(httpServer);
// with custom options
const eioServer = require('engine.io')(httpServer, {
maxHttpBufferSize: 1e3
});
```
- `listen`
- Creates an `http.Server` which listens on the given port and attaches WS
to it. It returns `501 Not Implemented` for regular http requests.
- **Parameters**
- `Number`: port to listen on.
- `Object`: optional, options object
- `Function`: callback for `listen`.
- **Options**
- All options from `Server.attach` method, documented below.
- **Additionally** See Server `constructor` below for options you can pass for creating the new Server
- **Returns** `Server`
```js
const engine = require('engine.io');
const server = engine.listen(3000, {
pingTimeout: 2000,
pingInterval: 10000
});
server.on('connection', /* ... */);
```
- `attach`
- Captures `upgrade` requests for a `http.Server`. In other words, makes
a regular http.Server WebSocket-compatible.
- **Parameters**
- `http.Server`: server to attach to.
- `Object`: optional, options object
- **Options**
- All options from `Server.attach` method, documented below.
- **Additionally** See Server `constructor` below for options you can pass for creating the new Server
- **Returns** `Server` a new Server instance.
```js
const engine = require('engine.io');
const httpServer = require('http').createServer().listen(3000);
const server = engine.attach(httpServer, {
wsEngine: require('eiows').Server // requires having eiows as dependency
});
server.on('connection', /* ... */);
```
#### Server
The main server/manager. _Inherits from EventEmitter_.
##### Events
- `connection`
- Fired when a new connection is established.
- **Arguments**
- `Socket`: a Socket object
- `initial_headers`
- Fired on the first request of the connection, before writing the response headers
- **Arguments**
- `headers` (`Object`): a hash of headers
- `req` (`http.IncomingMessage`): the request
- `headers`
- Fired on the all requests of the connection, before writing the response headers
- **Arguments**
- `headers` (`Object`): a hash of headers
- `req` (`http.IncomingMessage`): the request
- `connection_error`
- Fired when an error occurs when establishing the connection.
- **Arguments**
- `error`: an object with following properties:
- `req` (`http.IncomingMessage`): the request that was dropped
- `code` (`Number`): one of `Server.errors`
- `message` (`string`): one of `Server.errorMessages`
- `context` (`Object`): extra info about the error
| Code | Message |
| ---- | ------- |
| 0 | "Transport unknown"
| 1 | "Session ID unknown"
| 2 | "Bad handshake method"
| 3 | "Bad request"
| 4 | "Forbidden"
| 5 | "Unsupported protocol version"
##### Properties
**Important**: if you plan to use Engine.IO in a scalable way, please
keep in mind the properties below will only reflect the clients connected
to a single process.
- `clients` _(Object)_: hash of connected clients by id.
- `clientsCount` _(Number)_: number of connected clients.
##### Methods
- **constructor**
- Initializes the server
- **Parameters**
- `Object`: optional, options object
- **Options**
- `pingTimeout` (`Number`): how many ms without a pong packet to
consider the connection closed (`20000`)
- `pingInterval` (`Number`): how many ms before sending a new ping
packet (`25000`)
- `upgradeTimeout` (`Number`): how many ms before an uncompleted transport upgrade is cancelled (`10000`)
- `maxHttpBufferSize` (`Number`): how many bytes or characters a message
can be, before closing the session (to avoid DoS). Default
value is `1E6`.
- `allowRequest` (`Function`): A function that receives a given handshake
or upgrade request as its first parameter, and can decide whether to
continue or not. The second argument is a function that needs to be
called with the decided information: `fn(err, success)`, where
`success` is a boolean value where false means that the request is
rejected, and err is an error code.
- `transports` (`<Array> String`): transports to allow connections
to (`['polling', 'websocket']`)
- `allowUpgrades` (`Boolean`): whether to allow transport upgrades
(`true`)
- `perMessageDeflate` (`Object|Boolean`): parameters of the WebSocket permessage-deflate extension
(see [ws module](https://github.com/einaros/ws) api docs). Set to `true` to enable. (defaults to `false`)
- `threshold` (`Number`): data is compressed only if the byte size is above this value (`1024`)
- `httpCompression` (`Object|Boolean`): parameters of the http compression for the polling transports
(see [zlib](http://nodejs.org/api/zlib.html#zlib_options) api docs). Set to `false` to disable. (`true`)
- `threshold` (`Number`): data is compressed only if the byte size is above this value (`1024`)
- `cookie` (`Object|Boolean`): configuration of the cookie that
contains the client sid to send as part of handshake response
headers. This cookie might be used for sticky-session. Defaults to not sending any cookie (`false`).
See [here](https://github.com/jshttp/cookie#options-1) for all supported options.
- `wsEngine` (`Function`): what WebSocket server implementation to use. Specified module must conform to the `ws` interface (see [ws module api docs](https://github.com/websockets/ws/blob/master/doc/ws.md)). Default value is `ws`. An alternative c++ addon is also available by installing `eiows` module.
- `cors` (`Object`): the options that will be forwarded to the cors module. See [there](https://github.com/expressjs/cors#configuration-options) for all available options. Defaults to no CORS allowed.
- `initialPacket` (`Object`): an optional packet which will be concatenated to the handshake packet emitted by Engine.IO.
- `allowEIO3` (`Boolean`): whether to support v3 Engine.IO clients (defaults to `false`)
- `close`
- Closes all clients
- **Returns** `Server` for chaining
- `handleRequest`
- Called internally when a `Engine` request is intercepted.
- **Parameters**
- `http.IncomingMessage`: a node request object
- `http.ServerResponse`: a node response object
- **Returns** `Server` for chaining
- `handleUpgrade`
- Called internally when a `Engine` ws upgrade is intercepted.
- **Parameters** (same as `upgrade` event)
- `http.IncomingMessage`: a node request object
- `net.Stream`: TCP socket for the request
- `Buffer`: legacy tail bytes
- **Returns** `Server` for chaining
- `attach`
- Attach this Server instance to an `http.Server`
- Captures `upgrade` requests for a `http.Server`. In other words, makes
a regular http.Server WebSocket-compatible.
- **Parameters**
- `http.Server`: server to attach to.
- `Object`: optional, options object
- **Options**
- `path` (`String`): name of the path to capture (`/engine.io`).
- `destroyUpgrade` (`Boolean`): destroy unhandled upgrade requests (`true`)
- `destroyUpgradeTimeout` (`Number`): milliseconds after which unhandled requests are ended (`1000`)
- `generateId`
- Generate a socket id.
- Overwrite this method to generate your custom socket id.
- **Parameters**
- `http.IncomingMessage`: a node request object
- **Returns** A socket id for connected client.
<hr><br>
#### Socket
A representation of a client. _Inherits from EventEmitter_.
##### Events
- `close`
- Fired when the client is disconnected.
- **Arguments**
- `String`: reason for closing
- `Object`: description object (optional)
- `message`
- Fired when the client sends a message.
- **Arguments**
- `String` or `Buffer`: Unicode string or Buffer with binary contents
- `error`
- Fired when an error occurs.
- **Arguments**
- `Error`: error object
- `upgrading`
- Fired when the client starts the upgrade to a better transport like WebSocket.
- **Arguments**
- `Object`: the transport
- `upgrade`
- Fired when the client completes the upgrade to a better transport like WebSocket.
- **Arguments**
- `Object`: the transport
- `flush`
- Called when the write buffer is being flushed.
- **Arguments**
- `Array`: write buffer
- `drain`
- Called when the write buffer is drained
- `packet`
- Called when a socket received a packet (`message`, `ping`)
- **Arguments**
- `type`: packet type
- `data`: packet data (if type is message)
- `packetCreate`
- Called before a socket sends a packet (`message`, `ping`)
- **Arguments**
- `type`: packet type
- `data`: packet data (if type is message)
- `heartbeat`
- Called when `ping` or `pong` packed is received (depends of client version)
##### Properties
- `id` _(String)_: unique identifier
- `server` _(Server)_: engine parent reference
- `request` _(http.IncomingMessage)_: request that originated the Socket
- `upgraded` _(Boolean)_: whether the transport has been upgraded
- `readyState` _(String)_: opening|open|closing|closed
- `transport` _(Transport)_: transport reference
##### Methods
- `send`:
- Sends a message, performing `message = toString(arguments[0])` unless
sending binary data, which is sent as is.
- **Parameters**
- `String` | `Buffer` | `ArrayBuffer` | `ArrayBufferView`: a string or any object implementing `toString()`, with outgoing data, or a Buffer or ArrayBuffer with binary data. Also any ArrayBufferView can be sent as is.
- `Object`: optional, options object
- `Function`: optional, a callback executed when the message gets flushed out by the transport
- **Options**
- `compress` (`Boolean`): whether to compress sending data. This option might be ignored and forced to be `true` when using polling. (`true`)
- **Returns** `Socket` for chaining
- `close`
- Disconnects the client
- **Returns** `Socket` for chaining
### Client
<hr><br>
Exposed in the `eio` global namespace (in the browser), or by
`require('engine.io-client')` (in Node.JS).
For the client API refer to the
[engine-client](http://github.com/learnboost/engine.io-client) repository.
## Debug / logging
Engine.IO is powered by [debug](http://github.com/visionmedia/debug).
In order to see all the debug output, run your app with the environment variable
`DEBUG` including the desired scope.
To see the output from all of Engine.IO's debugging scopes you can use:
```
DEBUG=engine* node myapp
```
## Transports
- `polling`: XHR / JSONP polling transport.
- `websocket`: WebSocket transport.
## Plugins
- [engine.io-conflation](https://github.com/EugenDueck/engine.io-conflation): Makes **conflation and aggregation** of messages straightforward.
## Support
The support channels for `engine.io` are the same as `socket.io`:
- irc.freenode.net **#socket.io**
- [Google Groups](http://groups.google.com/group/socket_io)
- [Website](http://socket.io)
## Development
To contribute patches, run tests or benchmarks, make sure to clone the
repository:
```
git clone git://github.com/LearnBoost/engine.io.git
```
Then:
```
cd engine.io
npm install
```
## Tests
Tests run with `npm test`. It runs the server tests that are aided by
the usage of `engine.io-client`.
Make sure `npm install` is run first.
## Goals
The main goal of `Engine` is ensuring the most reliable realtime communication.
Unlike the previous Socket.IO core, it always establishes a long-polling
connection first, then tries to upgrade to better transports that are "tested" on
the side.
During the lifetime of the Socket.IO projects, we've found countless drawbacks
to relying on `HTML5 WebSocket` or `Flash Socket` as the first connection
mechanisms.
Both are clearly the _right way_ of establishing a bidirectional communication,
with HTML5 WebSocket being the way of the future. However, to answer most business
needs, alternative traditional HTTP 1.1 mechanisms are just as good as delivering
the same solution.
WebSocket based connections have two fundamental benefits:
1. **Better server performance**
- _A: Load balancers_<br>
Load balancing a long polling connection poses a serious architectural nightmare
since requests can come from any number of open sockets by the user agent, but
they all need to be routed to the process and computer that owns the `Engine`
connection. This negatively impacts RAM and CPU usage.
- _B: Network traffic_<br>
WebSocket is designed around the premise that each message frame has to be
surrounded by the least amount of data. In HTTP 1.1 transports, each message
frame is surrounded by HTTP headers and chunked encoding frames. If you try to
send the message _"Hello world"_ with xhr-polling, the message ultimately
becomes larger than if you were to send it with WebSocket.
- _C: Lightweight parser_<br>
As an effect of **B**, the server has to do a lot more work to parse the network
data and figure out the message when traditional HTTP requests are used
(as in long polling). This means that another advantage of WebSocket is
less server CPU usage.
2. **Better user experience**
Due to the reasons stated in point **1**, the most important effect of being able
to establish a WebSocket connection is raw data transfer speed, which translates
in _some_ cases in better user experience.
Applications with heavy realtime interaction (such as games) will benefit greatly,
whereas applications like realtime chat (Gmail/Facebook), newsfeeds (Facebook) or
timelines (Twitter) will have negligible user experience improvements.
Having said this, attempting to establish a WebSocket connection directly so far has
proven problematic:
1. **Proxies**<br>
Many corporate proxies block WebSocket traffic.
2. **Personal firewall and antivirus software**<br>
As a result of our research, we've found that at least 3 personal security
applications block WebSocket traffic.
3. **Cloud application platforms**<br>
Platforms like Heroku or No.de have had trouble keeping up with the fast-paced
nature of the evolution of the WebSocket protocol. Applications therefore end up
inevitably using long polling, but the seamless installation experience of
Socket.IO we strive for (_"require() it and it just works"_) disappears.
Some of these problems have solutions. In the case of proxies and personal programs,
however, the solutions many times involve upgrading software. Experience has shown
that relying on client software upgrades to deliver a business solution is
fruitless: the very existence of this project has to do with a fragmented panorama
of user agent distribution, with clients connecting with latest versions of the most
modern user agents (Chrome, Firefox and Safari), but others with versions as low as
IE 5.5.
From the user perspective, an unsuccessful WebSocket connection can translate in
up to at least 10 seconds of waiting for the realtime application to begin
exchanging data. This **perceptively** hurts user experience.
To summarize, **Engine** focuses on reliability and user experience first, marginal
potential UX improvements and increased server performance second. `Engine` is the
result of all the lessons learned with WebSocket in the wild.
## Architecture
The main premise of `Engine`, and the core of its existence, is the ability to
swap transports on the fly. A connection starts as xhr-polling, but it can
switch to WebSocket.
The central problem this poses is: how do we switch transports without losing
messages?
`Engine` only switches from polling to another transport in between polling
cycles. Since the server closes the connection after a certain timeout when
there's no activity, and the polling transport implementation buffers messages
in between connections, this ensures no message loss and optimal performance.
Another benefit of this design is that we workaround almost all the limitations
of **Flash Socket**, such as slow connection times, increased file size (we can
safely lazy load it without hurting user experience), etc.
## FAQ
### Can I use engine without Socket.IO ?
Absolutely. Although the recommended framework for building realtime applications
is Socket.IO, since it provides fundamental features for real-world applications
such as multiplexing, reconnection support, etc.
`Engine` is to Socket.IO what Connect is to Express. An essential piece for building
realtime frameworks, but something you _probably_ won't be using for building
actual applications.
### Does the server serve the client?
No. The main reason is that `Engine` is meant to be bundled with frameworks.
Socket.IO includes `Engine`, therefore serving two clients is not necessary. If
you use Socket.IO, including
```html
<script src="/socket.io/socket.io.js">
```
has you covered.
### Can I implement `Engine` in other languages?
Absolutely. The [engine.io-protocol](https://github.com/socketio/engine.io-protocol)
repository contains the most up-to-date description of the specification
at all times.
## License
(The MIT License)
Copyright (c) 2014 Guillermo Rauch &lt;guillermo@learnboost.com&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

113
node_modules/engine.io/build/contrib/types.cookie.d.ts generated vendored Normal file
View File

@ -0,0 +1,113 @@
/**
* Basic HTTP cookie parser and serializer for HTTP servers.
*/
/**
* Additional serialization options
*/
export interface CookieSerializeOptions {
/**
* Specifies the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.3|Domain Set-Cookie attribute}. By default, no
* domain is set, and most clients will consider the cookie to apply to only
* the current domain.
*/
domain?: string | undefined;
/**
* Specifies a function that will be used to encode a cookie's value. Since
* value of a cookie has a limited character set (and must be a simple
* string), this function can be used to encode a value into a string suited
* for a cookie's value.
*
* The default function is the global `encodeURIComponent`, which will
* encode a JavaScript string into UTF-8 byte sequences and then URL-encode
* any that fall outside of the cookie range.
*/
encode?(value: string): string;
/**
* Specifies the `Date` object to be the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.1|`Expires` `Set-Cookie` attribute}. By default,
* no expiration is set, and most clients will consider this a "non-persistent cookie" and will delete
* it on a condition like exiting a web browser application.
*
* *Note* the {@link https://tools.ietf.org/html/rfc6265#section-5.3|cookie storage model specification}
* states that if both `expires` and `maxAge` are set, then `maxAge` takes precedence, but it is
* possible not all clients by obey this, so if both are set, they should
* point to the same date and time.
*/
expires?: Date | undefined;
/**
* Specifies the boolean value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.6|`HttpOnly` `Set-Cookie` attribute}.
* When truthy, the `HttpOnly` attribute is set, otherwise it is not. By
* default, the `HttpOnly` attribute is not set.
*
* *Note* be careful when setting this to true, as compliant clients will
* not allow client-side JavaScript to see the cookie in `document.cookie`.
*/
httpOnly?: boolean | undefined;
/**
* Specifies the number (in seconds) to be the value for the `Max-Age`
* `Set-Cookie` attribute. The given number will be converted to an integer
* by rounding down. By default, no maximum age is set.
*
* *Note* the {@link https://tools.ietf.org/html/rfc6265#section-5.3|cookie storage model specification}
* states that if both `expires` and `maxAge` are set, then `maxAge` takes precedence, but it is
* possible not all clients by obey this, so if both are set, they should
* point to the same date and time.
*/
maxAge?: number | undefined;
/**
* Specifies the `boolean` value for the [`Partitioned` `Set-Cookie`](rfc-cutler-httpbis-partitioned-cookies)
* attribute. When truthy, the `Partitioned` attribute is set, otherwise it is not. By default, the
* `Partitioned` attribute is not set.
*
* **note** This is an attribute that has not yet been fully standardized, and may change in the future.
* This also means many clients may ignore this attribute until they understand it.
*
* More information about can be found in [the proposal](https://github.com/privacycg/CHIPS)
*/
partitioned?: boolean | undefined;
/**
* Specifies the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.4|`Path` `Set-Cookie` attribute}.
* By default, the path is considered the "default path".
*/
path?: string | undefined;
/**
* Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute][rfc-west-cookie-priority-00-4.1].
*
* - `'low'` will set the `Priority` attribute to `Low`.
* - `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set.
* - `'high'` will set the `Priority` attribute to `High`.
*
* More information about the different priority levels can be found in
* [the specification][rfc-west-cookie-priority-00-4.1].
*
* **note** This is an attribute that has not yet been fully standardized, and may change in the future.
* This also means many clients may ignore this attribute until they understand it.
*/
priority?: "low" | "medium" | "high" | undefined;
/**
* Specifies the boolean or string to be the value for the {@link https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7|`SameSite` `Set-Cookie` attribute}.
*
* - `true` will set the `SameSite` attribute to `Strict` for strict same
* site enforcement.
* - `false` will not set the `SameSite` attribute.
* - `'lax'` will set the `SameSite` attribute to Lax for lax same site
* enforcement.
* - `'strict'` will set the `SameSite` attribute to Strict for strict same
* site enforcement.
* - `'none'` will set the SameSite attribute to None for an explicit
* cross-site cookie.
*
* More information about the different enforcement levels can be found in {@link https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7|the specification}.
*
* *note* This is an attribute that has not yet been fully standardized, and may change in the future. This also means many clients may ignore this attribute until they understand it.
*/
sameSite?: true | false | "lax" | "strict" | "none" | undefined;
/**
* Specifies the boolean value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.5|`Secure` `Set-Cookie` attribute}. When truthy, the
* `Secure` attribute is set, otherwise it is not. By default, the `Secure` attribute is not set.
*
* *Note* be careful when setting this to `true`, as compliant clients will
* not send the cookie back to the server in the future if the browser does
* not have an HTTPS connection.
*/
secure?: boolean | undefined;
}

6
node_modules/engine.io/build/contrib/types.cookie.js generated vendored Normal file
View File

@ -0,0 +1,6 @@
"use strict";
// imported from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/b83cf9ef8b044e69f05b2a00aa7c6cb767a9acd2/types/cookie/index.d.ts (now deleted)
/**
* Basic HTTP cookie parser and serializer for HTTP servers.
*/
Object.defineProperty(exports, "__esModule", { value: true });

26
node_modules/engine.io/build/engine.io.d.ts generated vendored Normal file
View File

@ -0,0 +1,26 @@
import { Server, AttachOptions, ServerOptions } from "./server";
import transports from "./transports/index";
import * as parser from "engine.io-parser";
export { Server, transports, listen, attach, parser };
export type { AttachOptions, ServerOptions, BaseServer } from "./server";
export { uServer } from "./userver";
export { Socket } from "./socket";
export { Transport } from "./transport";
export declare const protocol = 4;
/**
* Creates an http.Server exclusively used for WS upgrades.
*
* @param {Number} port
* @param {Function} callback
* @param {Object} options
* @return {Server} websocket.io server
*/
declare function listen(port: any, options: AttachOptions & ServerOptions, fn: any): Server;
/**
* Captures upgrade requests for a http.Server.
*
* @param {http.Server} server
* @param {Object} options
* @return {Server} engine server
*/
declare function attach(server: any, options: AttachOptions & ServerOptions): Server;

54
node_modules/engine.io/build/engine.io.js generated vendored Normal file
View File

@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.protocol = exports.Transport = exports.Socket = exports.uServer = exports.parser = exports.transports = exports.Server = void 0;
exports.listen = listen;
exports.attach = attach;
const http_1 = require("http");
const server_1 = require("./server");
Object.defineProperty(exports, "Server", { enumerable: true, get: function () { return server_1.Server; } });
const index_1 = require("./transports/index");
exports.transports = index_1.default;
const parser = require("engine.io-parser");
exports.parser = parser;
var userver_1 = require("./userver");
Object.defineProperty(exports, "uServer", { enumerable: true, get: function () { return userver_1.uServer; } });
var socket_1 = require("./socket");
Object.defineProperty(exports, "Socket", { enumerable: true, get: function () { return socket_1.Socket; } });
var transport_1 = require("./transport");
Object.defineProperty(exports, "Transport", { enumerable: true, get: function () { return transport_1.Transport; } });
exports.protocol = parser.protocol;
/**
* Creates an http.Server exclusively used for WS upgrades.
*
* @param {Number} port
* @param {Function} callback
* @param {Object} options
* @return {Server} websocket.io server
*/
function listen(port, options, fn) {
if ("function" === typeof options) {
fn = options;
options = {};
}
const server = (0, http_1.createServer)(function (req, res) {
res.writeHead(501);
res.end("Not Implemented");
});
// create engine server
const engine = attach(server, options);
engine.httpServer = server;
server.listen(port, fn);
return engine;
}
/**
* Captures upgrade requests for a http.Server.
*
* @param {http.Server} server
* @param {Object} options
* @return {Server} engine server
*/
function attach(server, options) {
const engine = new server_1.Server(options);
engine.attach(server, options);
return engine;
}

94
node_modules/engine.io/build/parser-v3/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,94 @@
/**
* Current protocol version.
*/
export declare const protocol = 3;
/**
* Packet types.
*/
export declare const packets: {
open: number;
close: number;
ping: number;
pong: number;
message: number;
upgrade: number;
noop: number;
};
/**
* Encodes a packet.
*
* <packet type id> [ <data> ]
*
* Example:
*
* 5hello world
* 3
* 4
*
* Binary is encoded in an identical principle
*
* @api private
*/
export declare function encodePacket(packet: any, supportsBinary: any, utf8encode: any, callback: any): any;
/**
* Encodes a packet with binary data in a base64 string
*
* @param {Object} packet, has `type` and `data`
* @return {String} base64 encoded message
*/
export declare function encodeBase64Packet(packet: any, callback: any): any;
/**
* Decodes a packet. Data also available as an ArrayBuffer if requested.
*
* @return {Object} with `type` and `data` (if any)
* @api private
*/
export declare function decodePacket(data: any, binaryType: any, utf8decode: any): {
type: string;
data: any;
} | {
type: string;
data?: undefined;
};
/**
* Decodes a packet encoded in a base64 string.
*
* @param {String} base64 encoded message
* @return {Object} with `type` and `data` (if any)
*/
export declare function decodeBase64Packet(msg: any, binaryType: any): {
type: string;
data: Buffer;
};
/**
* Encodes multiple messages (payload).
*
* <length>:data
*
* Example:
*
* 11:hello world2:hi
*
* If any contents are binary, they will be encoded as base64 strings. Base64
* encoded strings are marked with a b before the length specifier
*
* @param {Array} packets
* @api private
*/
export declare function encodePayload(packets: any, supportsBinary: any, callback: any): any;
export declare function decodePayload(data: any, binaryType: any, callback: any): any;
/**
* Encodes multiple messages (payload) as binary.
*
* <1 = binary, 0 = string><number from 0-9><number from 0-9>[...]<number
* 255><data>
*
* Example:
* 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers
*
* @param {Array} packets
* @return {Buffer} encoded payload
* @api private
*/
export declare function encodePayloadAsBinary(packets: any, callback: any): any;
export declare function decodePayloadAsBinary(data: any, binaryType: any, callback: any): any;

424
node_modules/engine.io/build/parser-v3/index.js generated vendored Normal file
View File

@ -0,0 +1,424 @@
"use strict";
// imported from https://github.com/socketio/engine.io-parser/tree/2.2.x
Object.defineProperty(exports, "__esModule", { value: true });
exports.packets = exports.protocol = void 0;
exports.encodePacket = encodePacket;
exports.encodeBase64Packet = encodeBase64Packet;
exports.decodePacket = decodePacket;
exports.decodeBase64Packet = decodeBase64Packet;
exports.encodePayload = encodePayload;
exports.decodePayload = decodePayload;
exports.encodePayloadAsBinary = encodePayloadAsBinary;
exports.decodePayloadAsBinary = decodePayloadAsBinary;
/**
* Module dependencies.
*/
var utf8 = require('./utf8');
/**
* Current protocol version.
*/
exports.protocol = 3;
const hasBinary = (packets) => {
for (const packet of packets) {
if (packet.data instanceof ArrayBuffer || ArrayBuffer.isView(packet.data)) {
return true;
}
}
return false;
};
/**
* Packet types.
*/
exports.packets = {
open: 0 // non-ws
,
close: 1 // non-ws
,
ping: 2,
pong: 3,
message: 4,
upgrade: 5,
noop: 6
};
var packetslist = Object.keys(exports.packets);
/**
* Premade error packet.
*/
var err = { type: 'error', data: 'parser error' };
const EMPTY_BUFFER = Buffer.concat([]);
/**
* Encodes a packet.
*
* <packet type id> [ <data> ]
*
* Example:
*
* 5hello world
* 3
* 4
*
* Binary is encoded in an identical principle
*
* @api private
*/
function encodePacket(packet, supportsBinary, utf8encode, callback) {
if (typeof supportsBinary === 'function') {
callback = supportsBinary;
supportsBinary = null;
}
if (typeof utf8encode === 'function') {
callback = utf8encode;
utf8encode = null;
}
if (Buffer.isBuffer(packet.data)) {
return encodeBuffer(packet, supportsBinary, callback);
}
else if (packet.data && (packet.data.buffer || packet.data) instanceof ArrayBuffer) {
return encodeBuffer({ type: packet.type, data: arrayBufferToBuffer(packet.data) }, supportsBinary, callback);
}
// Sending data as a utf-8 string
var encoded = exports.packets[packet.type];
// data fragment is optional
if (undefined !== packet.data) {
encoded += utf8encode ? utf8.encode(String(packet.data), { strict: false }) : String(packet.data);
}
return callback('' + encoded);
}
;
/**
* Encode Buffer data
*/
function encodeBuffer(packet, supportsBinary, callback) {
if (!supportsBinary) {
return encodeBase64Packet(packet, callback);
}
var data = packet.data;
var typeBuffer = Buffer.allocUnsafe(1);
typeBuffer[0] = exports.packets[packet.type];
return callback(Buffer.concat([typeBuffer, data]));
}
/**
* Encodes a packet with binary data in a base64 string
*
* @param {Object} packet, has `type` and `data`
* @return {String} base64 encoded message
*/
function encodeBase64Packet(packet, callback) {
var data = Buffer.isBuffer(packet.data) ? packet.data : arrayBufferToBuffer(packet.data);
var message = 'b' + exports.packets[packet.type];
message += data.toString('base64');
return callback(message);
}
;
/**
* Decodes a packet. Data also available as an ArrayBuffer if requested.
*
* @return {Object} with `type` and `data` (if any)
* @api private
*/
function decodePacket(data, binaryType, utf8decode) {
if (data === undefined) {
return err;
}
var type;
// String data
if (typeof data === 'string') {
type = data.charAt(0);
if (type === 'b') {
return decodeBase64Packet(data.slice(1), binaryType);
}
if (utf8decode) {
data = tryDecode(data);
if (data === false) {
return err;
}
}
if (Number(type) != type || !packetslist[type]) {
return err;
}
if (data.length > 1) {
return { type: packetslist[type], data: data.slice(1) };
}
else {
return { type: packetslist[type] };
}
}
// Binary data
if (binaryType === 'arraybuffer') {
// wrap Buffer/ArrayBuffer data into an Uint8Array
var intArray = new Uint8Array(data);
type = intArray[0];
return { type: packetslist[type], data: intArray.buffer.slice(1) };
}
if (data instanceof ArrayBuffer) {
data = arrayBufferToBuffer(data);
}
type = data[0];
return { type: packetslist[type], data: data.slice(1) };
}
;
function tryDecode(data) {
try {
data = utf8.decode(data, { strict: false });
}
catch (e) {
return false;
}
return data;
}
/**
* Decodes a packet encoded in a base64 string.
*
* @param {String} base64 encoded message
* @return {Object} with `type` and `data` (if any)
*/
function decodeBase64Packet(msg, binaryType) {
var type = packetslist[msg.charAt(0)];
var data = Buffer.from(msg.slice(1), 'base64');
if (binaryType === 'arraybuffer') {
var abv = new Uint8Array(data.length);
for (var i = 0; i < abv.length; i++) {
abv[i] = data[i];
}
// @ts-ignore
data = abv.buffer;
}
return { type: type, data: data };
}
;
/**
* Encodes multiple messages (payload).
*
* <length>:data
*
* Example:
*
* 11:hello world2:hi
*
* If any contents are binary, they will be encoded as base64 strings. Base64
* encoded strings are marked with a b before the length specifier
*
* @param {Array} packets
* @api private
*/
function encodePayload(packets, supportsBinary, callback) {
if (typeof supportsBinary === 'function') {
callback = supportsBinary;
supportsBinary = null;
}
if (supportsBinary && hasBinary(packets)) {
return encodePayloadAsBinary(packets, callback);
}
if (!packets.length) {
return callback('0:');
}
function encodeOne(packet, doneCallback) {
encodePacket(packet, supportsBinary, false, function (message) {
doneCallback(null, setLengthHeader(message));
});
}
map(packets, encodeOne, function (err, results) {
return callback(results.join(''));
});
}
;
function setLengthHeader(message) {
return message.length + ':' + message;
}
/**
* Async array map using after
*/
function map(ary, each, done) {
const results = new Array(ary.length);
let count = 0;
for (let i = 0; i < ary.length; i++) {
each(ary[i], (error, msg) => {
results[i] = msg;
if (++count === ary.length) {
done(null, results);
}
});
}
}
/*
* Decodes data when a payload is maybe expected. Possible binary contents are
* decoded from their base64 representation
*
* @param {String} data, callback method
* @api public
*/
function decodePayload(data, binaryType, callback) {
if (typeof data !== 'string') {
return decodePayloadAsBinary(data, binaryType, callback);
}
if (typeof binaryType === 'function') {
callback = binaryType;
binaryType = null;
}
if (data === '') {
// parser error - ignoring payload
return callback(err, 0, 1);
}
var length = '', n, msg, packet;
for (var i = 0, l = data.length; i < l; i++) {
var chr = data.charAt(i);
if (chr !== ':') {
length += chr;
continue;
}
// @ts-ignore
if (length === '' || (length != (n = Number(length)))) {
// parser error - ignoring payload
return callback(err, 0, 1);
}
msg = data.slice(i + 1, i + 1 + n);
if (length != msg.length) {
// parser error - ignoring payload
return callback(err, 0, 1);
}
if (msg.length) {
packet = decodePacket(msg, binaryType, false);
if (err.type === packet.type && err.data === packet.data) {
// parser error in individual packet - ignoring payload
return callback(err, 0, 1);
}
var more = callback(packet, i + n, l);
if (false === more)
return;
}
// advance cursor
i += n;
length = '';
}
if (length !== '') {
// parser error - ignoring payload
return callback(err, 0, 1);
}
}
;
/**
*
* Converts a buffer to a utf8.js encoded string
*
* @api private
*/
function bufferToString(buffer) {
var str = '';
for (var i = 0, l = buffer.length; i < l; i++) {
str += String.fromCharCode(buffer[i]);
}
return str;
}
/**
*
* Converts a utf8.js encoded string to a buffer
*
* @api private
*/
function stringToBuffer(string) {
var buf = Buffer.allocUnsafe(string.length);
for (var i = 0, l = string.length; i < l; i++) {
buf.writeUInt8(string.charCodeAt(i), i);
}
return buf;
}
/**
*
* Converts an ArrayBuffer to a Buffer
*
* @api private
*/
function arrayBufferToBuffer(data) {
// data is either an ArrayBuffer or ArrayBufferView.
var length = data.byteLength || data.length;
var offset = data.byteOffset || 0;
return Buffer.from(data.buffer || data, offset, length);
}
/**
* Encodes multiple messages (payload) as binary.
*
* <1 = binary, 0 = string><number from 0-9><number from 0-9>[...]<number
* 255><data>
*
* Example:
* 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers
*
* @param {Array} packets
* @return {Buffer} encoded payload
* @api private
*/
function encodePayloadAsBinary(packets, callback) {
if (!packets.length) {
return callback(EMPTY_BUFFER);
}
map(packets, encodeOneBinaryPacket, function (err, results) {
return callback(Buffer.concat(results));
});
}
;
function encodeOneBinaryPacket(p, doneCallback) {
function onBinaryPacketEncode(packet) {
var encodingLength = '' + packet.length;
var sizeBuffer;
if (typeof packet === 'string') {
sizeBuffer = Buffer.allocUnsafe(encodingLength.length + 2);
sizeBuffer[0] = 0; // is a string (not true binary = 0)
for (var i = 0; i < encodingLength.length; i++) {
sizeBuffer[i + 1] = parseInt(encodingLength[i], 10);
}
sizeBuffer[sizeBuffer.length - 1] = 255;
return doneCallback(null, Buffer.concat([sizeBuffer, stringToBuffer(packet)]));
}
sizeBuffer = Buffer.allocUnsafe(encodingLength.length + 2);
sizeBuffer[0] = 1; // is binary (true binary = 1)
for (var i = 0; i < encodingLength.length; i++) {
sizeBuffer[i + 1] = parseInt(encodingLength[i], 10);
}
sizeBuffer[sizeBuffer.length - 1] = 255;
doneCallback(null, Buffer.concat([sizeBuffer, packet]));
}
encodePacket(p, true, true, onBinaryPacketEncode);
}
/*
* Decodes data when a payload is maybe expected. Strings are decoded by
* interpreting each byte as a key code for entries marked to start with 0. See
* description of encodePayloadAsBinary
* @param {Buffer} data, callback method
* @api public
*/
function decodePayloadAsBinary(data, binaryType, callback) {
if (typeof binaryType === 'function') {
callback = binaryType;
binaryType = null;
}
var bufferTail = data;
var buffers = [];
var i;
while (bufferTail.length > 0) {
var strLen = '';
var isString = bufferTail[0] === 0;
for (i = 1;; i++) {
if (bufferTail[i] === 255)
break;
// 310 = char length of Number.MAX_VALUE
if (strLen.length > 310) {
return callback(err, 0, 1);
}
strLen += '' + bufferTail[i];
}
bufferTail = bufferTail.slice(strLen.length + 1);
var msgLength = parseInt(strLen, 10);
var msg = bufferTail.slice(1, msgLength + 1);
if (isString)
msg = bufferToString(msg);
buffers.push(msg);
bufferTail = bufferTail.slice(msgLength + 1);
}
var total = buffers.length;
for (i = 0; i < total; i++) {
var buffer = buffers[i];
callback(decodePacket(buffer, binaryType, true), i, total);
}
}
;

14
node_modules/engine.io/build/parser-v3/utf8.d.ts generated vendored Normal file
View File

@ -0,0 +1,14 @@
/*! https://mths.be/utf8js v2.1.2 by @mathias */
declare var stringFromCharCode: (...codes: number[]) => string;
declare function ucs2decode(string: any): any[];
declare function ucs2encode(array: any): string;
declare function checkScalarValue(codePoint: any, strict: any): boolean;
declare function createByte(codePoint: any, shift: any): string;
declare function encodeCodePoint(codePoint: any, strict: any): string;
declare function utf8encode(string: any, opts: any): string;
declare function readContinuationByte(): number;
declare function decodeSymbol(strict: any): any;
declare var byteArray: any;
declare var byteCount: any;
declare var byteIndex: any;
declare function utf8decode(byteString: any, opts: any): string;

187
node_modules/engine.io/build/parser-v3/utf8.js generated vendored Normal file
View File

@ -0,0 +1,187 @@
/*! https://mths.be/utf8js v2.1.2 by @mathias */
var stringFromCharCode = String.fromCharCode;
// Taken from https://mths.be/punycode
function ucs2decode(string) {
var output = [];
var counter = 0;
var length = string.length;
var value;
var extra;
while (counter < length) {
value = string.charCodeAt(counter++);
if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
// high surrogate, and there is a next character
extra = string.charCodeAt(counter++);
if ((extra & 0xFC00) == 0xDC00) { // low surrogate
output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
}
else {
// unmatched surrogate; only append this code unit, in case the next
// code unit is the high surrogate of a surrogate pair
output.push(value);
counter--;
}
}
else {
output.push(value);
}
}
return output;
}
// Taken from https://mths.be/punycode
function ucs2encode(array) {
var length = array.length;
var index = -1;
var value;
var output = '';
while (++index < length) {
value = array[index];
if (value > 0xFFFF) {
value -= 0x10000;
output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
value = 0xDC00 | value & 0x3FF;
}
output += stringFromCharCode(value);
}
return output;
}
function checkScalarValue(codePoint, strict) {
if (codePoint >= 0xD800 && codePoint <= 0xDFFF) {
if (strict) {
throw Error('Lone surrogate U+' + codePoint.toString(16).toUpperCase() +
' is not a scalar value');
}
return false;
}
return true;
}
/*--------------------------------------------------------------------------*/
function createByte(codePoint, shift) {
return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80);
}
function encodeCodePoint(codePoint, strict) {
if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence
return stringFromCharCode(codePoint);
}
var symbol = '';
if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence
symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0);
}
else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence
if (!checkScalarValue(codePoint, strict)) {
codePoint = 0xFFFD;
}
symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0);
symbol += createByte(codePoint, 6);
}
else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence
symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0);
symbol += createByte(codePoint, 12);
symbol += createByte(codePoint, 6);
}
symbol += stringFromCharCode((codePoint & 0x3F) | 0x80);
return symbol;
}
function utf8encode(string, opts) {
opts = opts || {};
var strict = false !== opts.strict;
var codePoints = ucs2decode(string);
var length = codePoints.length;
var index = -1;
var codePoint;
var byteString = '';
while (++index < length) {
codePoint = codePoints[index];
byteString += encodeCodePoint(codePoint, strict);
}
return byteString;
}
/*--------------------------------------------------------------------------*/
function readContinuationByte() {
if (byteIndex >= byteCount) {
throw Error('Invalid byte index');
}
var continuationByte = byteArray[byteIndex] & 0xFF;
byteIndex++;
if ((continuationByte & 0xC0) == 0x80) {
return continuationByte & 0x3F;
}
// If we end up here, its not a continuation byte
throw Error('Invalid continuation byte');
}
function decodeSymbol(strict) {
var byte1;
var byte2;
var byte3;
var byte4;
var codePoint;
if (byteIndex > byteCount) {
throw Error('Invalid byte index');
}
if (byteIndex == byteCount) {
return false;
}
// Read first byte
byte1 = byteArray[byteIndex] & 0xFF;
byteIndex++;
// 1-byte sequence (no continuation bytes)
if ((byte1 & 0x80) == 0) {
return byte1;
}
// 2-byte sequence
if ((byte1 & 0xE0) == 0xC0) {
byte2 = readContinuationByte();
codePoint = ((byte1 & 0x1F) << 6) | byte2;
if (codePoint >= 0x80) {
return codePoint;
}
else {
throw Error('Invalid continuation byte');
}
}
// 3-byte sequence (may include unpaired surrogates)
if ((byte1 & 0xF0) == 0xE0) {
byte2 = readContinuationByte();
byte3 = readContinuationByte();
codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
if (codePoint >= 0x0800) {
return checkScalarValue(codePoint, strict) ? codePoint : 0xFFFD;
}
else {
throw Error('Invalid continuation byte');
}
}
// 4-byte sequence
if ((byte1 & 0xF8) == 0xF0) {
byte2 = readContinuationByte();
byte3 = readContinuationByte();
byte4 = readContinuationByte();
codePoint = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0C) |
(byte3 << 0x06) | byte4;
if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
return codePoint;
}
}
throw Error('Invalid UTF-8 detected');
}
var byteArray;
var byteCount;
var byteIndex;
function utf8decode(byteString, opts) {
opts = opts || {};
var strict = false !== opts.strict;
byteArray = ucs2decode(byteString);
byteCount = byteArray.length;
byteIndex = 0;
var codePoints = [];
var tmp;
while ((tmp = decodeSymbol(strict)) !== false) {
codePoints.push(tmp);
}
return ucs2encode(codePoints);
}
module.exports = {
version: '2.1.2',
encode: utf8encode,
decode: utf8decode
};

267
node_modules/engine.io/build/server.d.ts generated vendored Normal file
View File

@ -0,0 +1,267 @@
import { EventEmitter } from "events";
import { Socket } from "./socket";
import type { IncomingMessage, Server as HttpServer, ServerResponse } from "http";
import type { CorsOptions, CorsOptionsDelegate } from "cors";
import type { Duplex } from "stream";
import type { EngineRequest } from "./transport";
import type { CookieSerializeOptions } from "./contrib/types.cookie";
type Transport = "polling" | "websocket" | "webtransport";
export interface AttachOptions {
/**
* name of the path to capture
* @default "/engine.io"
*/
path?: string;
/**
* destroy unhandled upgrade requests
* @default true
*/
destroyUpgrade?: boolean;
/**
* milliseconds after which unhandled requests are ended
* @default 1000
*/
destroyUpgradeTimeout?: number;
/**
* Whether we should add a trailing slash to the request path.
* @default true
*/
addTrailingSlash?: boolean;
}
export interface ServerOptions {
/**
* how many ms without a pong packet to consider the connection closed
* @default 20000
*/
pingTimeout?: number;
/**
* how many ms before sending a new ping packet
* @default 25000
*/
pingInterval?: number;
/**
* how many ms before an uncompleted transport upgrade is cancelled
* @default 10000
*/
upgradeTimeout?: number;
/**
* how many bytes or characters a message can be, before closing the session (to avoid DoS).
* @default 1e5 (100 KB)
*/
maxHttpBufferSize?: number;
/**
* A function that receives a given handshake or upgrade request as its first parameter,
* and can decide whether to continue or not. The second argument is a function that needs
* to be called with the decided information: fn(err, success), where success is a boolean
* value where false means that the request is rejected, and err is an error code.
*/
allowRequest?: (req: IncomingMessage, fn: (err: string | null | undefined, success: boolean) => void) => void;
/**
* The low-level transports that are enabled. WebTransport is disabled by default and must be manually enabled:
*
* @example
* new Server({
* transports: ["polling", "websocket", "webtransport"]
* });
*
* @default ["polling", "websocket"]
*/
transports?: Transport[];
/**
* whether to allow transport upgrades
* @default true
*/
allowUpgrades?: boolean;
/**
* parameters of the WebSocket permessage-deflate extension (see ws module api docs). Set to false to disable.
* @default false
*/
perMessageDeflate?: boolean | object;
/**
* parameters of the http compression for the polling transports (see zlib api docs). Set to false to disable.
* @default true
*/
httpCompression?: boolean | object;
/**
* what WebSocket server implementation to use. Specified module must
* conform to the ws interface (see ws module api docs).
* An alternative c++ addon is also available by installing eiows module.
*
* @default `require("ws").Server`
*/
wsEngine?: any;
/**
* an optional packet which will be concatenated to the handshake packet emitted by Engine.IO.
*/
initialPacket?: any;
/**
* configuration of the cookie that contains the client sid to send as part of handshake response headers. This cookie
* might be used for sticky-session. Defaults to not sending any cookie.
* @default false
*/
cookie?: (CookieSerializeOptions & {
name: string;
}) | boolean;
/**
* the options that will be forwarded to the cors module
*/
cors?: CorsOptions | CorsOptionsDelegate;
/**
* whether to enable compatibility with Socket.IO v2 clients
* @default false
*/
allowEIO3?: boolean;
}
/**
* An Express-compatible middleware.
*
* Middleware functions are functions that have access to the request object (req), the response object (res), and the
* next middleware function in the applications request-response cycle.
*
* @see https://expressjs.com/en/guide/using-middleware.html
*/
type Middleware = (req: IncomingMessage, res: ServerResponse, next: (err?: any) => void) => void;
export declare abstract class BaseServer extends EventEmitter {
opts: ServerOptions;
protected clients: Record<string, Socket>;
clientsCount: number;
protected middlewares: Middleware[];
/**
* Server constructor.
*
* @param {Object} opts - options
*/
constructor(opts?: ServerOptions);
protected abstract init(): any;
/**
* Compute the pathname of the requests that are handled by the server
* @param options
* @protected
*/
protected _computePath(options: AttachOptions): string;
/**
* Returns a list of available transports for upgrade given a certain transport.
*
* @return {Array}
*/
upgrades(transport: string): any;
/**
* Verifies a request.
*
* @param {EngineRequest} req
* @param upgrade - whether it's an upgrade request
* @param fn
* @protected
*/
protected verify(req: any, upgrade: boolean, fn: (errorCode?: number, errorContext?: any) => void): void;
/**
* Adds a new middleware.
*
* @example
* import helmet from "helmet";
*
* engine.use(helmet());
*
* @param fn
*/
use(fn: any): void;
/**
* Apply the middlewares to the request.
*
* @param req
* @param res
* @param callback
* @protected
*/
protected _applyMiddlewares(req: IncomingMessage, res: ServerResponse, callback: (err?: any) => void): void;
/**
* Closes all clients.
*/
close(): this;
protected abstract cleanup(): any;
/**
* generate a socket id.
* Overwrite this method to generate your custom socket id
*
* @param {IncomingMessage} req - the request object
*/
generateId(req: IncomingMessage): any;
/**
* Handshakes a new client.
*
* @param {String} transportName
* @param {Object} req - the request object
* @param {Function} closeConnection
*
* @protected
*/
protected handshake(transportName: string, req: any, closeConnection: (errorCode?: number, errorContext?: any) => void): Promise<any>;
onWebTransportSession(session: any): Promise<any>;
protected abstract createTransport(transportName: any, req: any): any;
/**
* Protocol errors mappings.
*/
static errors: {
UNKNOWN_TRANSPORT: number;
UNKNOWN_SID: number;
BAD_HANDSHAKE_METHOD: number;
BAD_REQUEST: number;
FORBIDDEN: number;
UNSUPPORTED_PROTOCOL_VERSION: number;
};
static errorMessages: {
0: string;
1: string;
2: string;
3: string;
4: string;
5: string;
};
}
/**
* An Engine.IO server based on Node.js built-in HTTP server and the `ws` package for WebSocket connections.
*/
export declare class Server extends BaseServer {
httpServer?: HttpServer;
private ws;
/**
* Initialize websocket server
*
* @protected
*/
protected init(): void;
protected cleanup(): void;
/**
* Prepares a request by processing the query string.
*
* @private
*/
private prepare;
protected createTransport(transportName: string, req: IncomingMessage): any;
/**
* Handles an Engine.IO HTTP request.
*
* @param {EngineRequest} req
* @param {ServerResponse} res
*/
handleRequest(req: EngineRequest, res: ServerResponse): void;
/**
* Handles an Engine.IO HTTP Upgrade.
*/
handleUpgrade(req: EngineRequest, socket: Duplex, upgradeHead: Buffer): void;
/**
* Called upon a ws.io connection.
*
* @param {ws.Socket} websocket
* @private
*/
private onWebSocket;
/**
* Captures upgrade requests for a http.Server.
*
* @param {http.Server} server
* @param {Object} options
*/
attach(server: HttpServer, options?: AttachOptions): void;
}
export {};

786
node_modules/engine.io/build/server.js generated vendored Normal file
View File

@ -0,0 +1,786 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Server = exports.BaseServer = void 0;
const qs = require("querystring");
const url_1 = require("url");
const base64id = require("base64id");
const transports_1 = require("./transports");
const events_1 = require("events");
const socket_1 = require("./socket");
const debug_1 = require("debug");
const cookie_1 = require("cookie");
const ws_1 = require("ws");
const webtransport_1 = require("./transports/webtransport");
const engine_io_parser_1 = require("engine.io-parser");
const debug = (0, debug_1.default)("engine");
const kResponseHeaders = Symbol("responseHeaders");
function parseSessionId(data) {
try {
const parsed = JSON.parse(data);
if (typeof parsed.sid === "string") {
return parsed.sid;
}
}
catch (e) { }
}
class BaseServer extends events_1.EventEmitter {
/**
* Server constructor.
*
* @param {Object} opts - options
*/
constructor(opts = {}) {
super();
this.middlewares = [];
this.clients = {};
this.clientsCount = 0;
this.opts = Object.assign({
wsEngine: ws_1.Server,
pingTimeout: 20000,
pingInterval: 25000,
upgradeTimeout: 10000,
maxHttpBufferSize: 1e6,
transports: ["polling", "websocket"], // WebTransport is disabled by default
allowUpgrades: true,
httpCompression: {
threshold: 1024,
},
cors: false,
allowEIO3: false,
}, opts);
if (opts.cookie) {
this.opts.cookie = Object.assign({
name: "io",
path: "/",
// @ts-ignore
httpOnly: opts.cookie.path !== false,
sameSite: "lax",
}, opts.cookie);
}
if (this.opts.cors) {
this.use(require("cors")(this.opts.cors));
}
if (opts.perMessageDeflate) {
this.opts.perMessageDeflate = Object.assign({
threshold: 1024,
}, opts.perMessageDeflate);
}
this.init();
}
/**
* Compute the pathname of the requests that are handled by the server
* @param options
* @protected
*/
_computePath(options) {
let path = (options.path || "/engine.io").replace(/\/$/, "");
if (options.addTrailingSlash !== false) {
// normalize path
path += "/";
}
return path;
}
/**
* Returns a list of available transports for upgrade given a certain transport.
*
* @return {Array}
*/
upgrades(transport) {
if (!this.opts.allowUpgrades)
return [];
return transports_1.default[transport].upgradesTo || [];
}
/**
* Verifies a request.
*
* @param {EngineRequest} req
* @param upgrade - whether it's an upgrade request
* @param fn
* @protected
*/
verify(req, upgrade, fn) {
// transport check
const transport = req._query.transport;
// WebTransport does not go through the verify() method, see the onWebTransportSession() method
if (!~this.opts.transports.indexOf(transport) ||
transport === "webtransport") {
debug('unknown transport "%s"', transport);
return fn(Server.errors.UNKNOWN_TRANSPORT, { transport });
}
// 'Origin' header check
const isOriginInvalid = checkInvalidHeaderChar(req.headers.origin);
if (isOriginInvalid) {
const origin = req.headers.origin;
req.headers.origin = null;
debug("origin header invalid");
return fn(Server.errors.BAD_REQUEST, {
name: "INVALID_ORIGIN",
origin,
});
}
// sid check
const sid = req._query.sid;
if (sid) {
if (!this.clients.hasOwnProperty(sid)) {
debug('unknown sid "%s"', sid);
return fn(Server.errors.UNKNOWN_SID, {
sid,
});
}
const previousTransport = this.clients[sid].transport.name;
if (!upgrade && previousTransport !== transport) {
debug("bad request: unexpected transport without upgrade");
return fn(Server.errors.BAD_REQUEST, {
name: "TRANSPORT_MISMATCH",
transport,
previousTransport,
});
}
}
else {
// handshake is GET only
if ("GET" !== req.method) {
return fn(Server.errors.BAD_HANDSHAKE_METHOD, {
method: req.method,
});
}
if (transport === "websocket" && !upgrade) {
debug("invalid transport upgrade");
return fn(Server.errors.BAD_REQUEST, {
name: "TRANSPORT_HANDSHAKE_ERROR",
});
}
if (!this.opts.allowRequest)
return fn();
return this.opts.allowRequest(req, (message, success) => {
if (!success) {
return fn(Server.errors.FORBIDDEN, {
message,
});
}
fn();
});
}
fn();
}
/**
* Adds a new middleware.
*
* @example
* import helmet from "helmet";
*
* engine.use(helmet());
*
* @param fn
*/
use(fn) {
this.middlewares.push(fn);
}
/**
* Apply the middlewares to the request.
*
* @param req
* @param res
* @param callback
* @protected
*/
_applyMiddlewares(req, res, callback) {
if (this.middlewares.length === 0) {
debug("no middleware to apply, skipping");
return callback();
}
const apply = (i) => {
debug("applying middleware n°%d", i + 1);
this.middlewares[i](req, res, (err) => {
if (err) {
return callback(err);
}
if (i + 1 < this.middlewares.length) {
apply(i + 1);
}
else {
callback();
}
});
};
apply(0);
}
/**
* Closes all clients.
*/
close() {
debug("closing all open clients");
for (let i in this.clients) {
if (this.clients.hasOwnProperty(i)) {
this.clients[i].close(true);
}
}
this.cleanup();
return this;
}
/**
* generate a socket id.
* Overwrite this method to generate your custom socket id
*
* @param {IncomingMessage} req - the request object
*/
generateId(req) {
return base64id.generateId();
}
/**
* Handshakes a new client.
*
* @param {String} transportName
* @param {Object} req - the request object
* @param {Function} closeConnection
*
* @protected
*/
async handshake(transportName, req, closeConnection) {
const protocol = req._query.EIO === "4" ? 4 : 3; // 3rd revision by default
if (protocol === 3 && !this.opts.allowEIO3) {
debug("unsupported protocol version");
this.emit("connection_error", {
req,
code: Server.errors.UNSUPPORTED_PROTOCOL_VERSION,
message: Server.errorMessages[Server.errors.UNSUPPORTED_PROTOCOL_VERSION],
context: {
protocol,
},
});
closeConnection(Server.errors.UNSUPPORTED_PROTOCOL_VERSION);
return;
}
let id;
try {
id = await this.generateId(req);
}
catch (e) {
debug("error while generating an id");
this.emit("connection_error", {
req,
code: Server.errors.BAD_REQUEST,
message: Server.errorMessages[Server.errors.BAD_REQUEST],
context: {
name: "ID_GENERATION_ERROR",
error: e,
},
});
closeConnection(Server.errors.BAD_REQUEST);
return;
}
debug('handshaking client "%s"', id);
try {
var transport = this.createTransport(transportName, req);
if ("polling" === transportName) {
transport.maxHttpBufferSize = this.opts.maxHttpBufferSize;
transport.httpCompression = this.opts.httpCompression;
}
else if ("websocket" === transportName) {
transport.perMessageDeflate = this.opts.perMessageDeflate;
}
}
catch (e) {
debug('error handshaking to transport "%s"', transportName);
this.emit("connection_error", {
req,
code: Server.errors.BAD_REQUEST,
message: Server.errorMessages[Server.errors.BAD_REQUEST],
context: {
name: "TRANSPORT_HANDSHAKE_ERROR",
error: e,
},
});
closeConnection(Server.errors.BAD_REQUEST);
return;
}
const socket = new socket_1.Socket(id, this, transport, req, protocol);
transport.on("headers", (headers, req) => {
const isInitialRequest = !req._query.sid;
if (isInitialRequest) {
if (this.opts.cookie) {
headers["Set-Cookie"] = [
// @ts-ignore
(0, cookie_1.serialize)(this.opts.cookie.name, id, this.opts.cookie),
];
}
this.emit("initial_headers", headers, req);
}
this.emit("headers", headers, req);
});
transport.onRequest(req);
this.clients[id] = socket;
this.clientsCount++;
socket.once("close", () => {
delete this.clients[id];
this.clientsCount--;
});
this.emit("connection", socket);
return transport;
}
async onWebTransportSession(session) {
const timeout = setTimeout(() => {
debug("the client failed to establish a bidirectional stream in the given period");
session.close();
}, this.opts.upgradeTimeout);
const streamReader = session.incomingBidirectionalStreams.getReader();
const result = await streamReader.read();
if (result.done) {
debug("session is closed");
return;
}
const stream = result.value;
const transformStream = (0, engine_io_parser_1.createPacketDecoderStream)(this.opts.maxHttpBufferSize, "nodebuffer");
const reader = stream.readable.pipeThrough(transformStream).getReader();
// reading the first packet of the stream
const { value, done } = await reader.read();
if (done) {
debug("stream is closed");
return;
}
clearTimeout(timeout);
if (value.type !== "open") {
debug("invalid WebTransport handshake");
return session.close();
}
if (value.data === undefined) {
const transport = new webtransport_1.WebTransport(session, stream, reader);
// note: we cannot use "this.generateId()", because there is no "req" argument
const id = base64id.generateId();
debug('handshaking client "%s" (WebTransport)', id);
const socket = new socket_1.Socket(id, this, transport, null, 4);
this.clients[id] = socket;
this.clientsCount++;
socket.once("close", () => {
delete this.clients[id];
this.clientsCount--;
});
this.emit("connection", socket);
return;
}
const sid = parseSessionId(value.data);
if (!sid) {
debug("invalid WebTransport handshake");
return session.close();
}
const client = this.clients[sid];
if (!client) {
debug("upgrade attempt for closed client");
session.close();
}
else if (client.upgrading) {
debug("transport has already been trying to upgrade");
session.close();
}
else if (client.upgraded) {
debug("transport had already been upgraded");
session.close();
}
else {
debug("upgrading existing transport");
const transport = new webtransport_1.WebTransport(session, stream, reader);
client._maybeUpgrade(transport);
}
}
}
exports.BaseServer = BaseServer;
/**
* Protocol errors mappings.
*/
BaseServer.errors = {
UNKNOWN_TRANSPORT: 0,
UNKNOWN_SID: 1,
BAD_HANDSHAKE_METHOD: 2,
BAD_REQUEST: 3,
FORBIDDEN: 4,
UNSUPPORTED_PROTOCOL_VERSION: 5,
};
BaseServer.errorMessages = {
0: "Transport unknown",
1: "Session ID unknown",
2: "Bad handshake method",
3: "Bad request",
4: "Forbidden",
5: "Unsupported protocol version",
};
/**
* Exposes a subset of the http.ServerResponse interface, in order to be able to apply the middlewares to an upgrade
* request.
*
* @see https://nodejs.org/api/http.html#class-httpserverresponse
*/
class WebSocketResponse {
constructor(req, socket) {
this.req = req;
this.socket = socket;
// temporarily store the response headers on the req object (see the "headers" event)
req[kResponseHeaders] = {};
}
setHeader(name, value) {
this.req[kResponseHeaders][name] = value;
}
getHeader(name) {
return this.req[kResponseHeaders][name];
}
removeHeader(name) {
delete this.req[kResponseHeaders][name];
}
write() { }
writeHead() { }
end() {
// we could return a proper error code, but the WebSocket client will emit an "error" event anyway.
this.socket.destroy();
}
}
/**
* An Engine.IO server based on Node.js built-in HTTP server and the `ws` package for WebSocket connections.
*/
class Server extends BaseServer {
/**
* Initialize websocket server
*
* @protected
*/
init() {
if (!~this.opts.transports.indexOf("websocket"))
return;
if (this.ws)
this.ws.close();
this.ws = new this.opts.wsEngine({
noServer: true,
clientTracking: false,
perMessageDeflate: this.opts.perMessageDeflate,
maxPayload: this.opts.maxHttpBufferSize,
});
if (typeof this.ws.on === "function") {
this.ws.on("headers", (headersArray, req) => {
// note: 'ws' uses an array of headers, while Engine.IO uses an object (response.writeHead() accepts both formats)
// we could also try to parse the array and then sync the values, but that will be error-prone
const additionalHeaders = req[kResponseHeaders] || {};
delete req[kResponseHeaders];
const isInitialRequest = !req._query.sid;
if (isInitialRequest) {
this.emit("initial_headers", additionalHeaders, req);
}
this.emit("headers", additionalHeaders, req);
debug("writing headers: %j", additionalHeaders);
Object.keys(additionalHeaders).forEach((key) => {
headersArray.push(`${key}: ${additionalHeaders[key]}`);
});
});
}
}
cleanup() {
if (this.ws) {
debug("closing webSocketServer");
this.ws.close();
// don't delete this.ws because it can be used again if the http server starts listening again
}
}
/**
* Prepares a request by processing the query string.
*
* @private
*/
prepare(req) {
// try to leverage pre-existing `req._query` (e.g: from connect)
if (!req._query) {
req._query = (~req.url.indexOf("?") ? qs.parse((0, url_1.parse)(req.url).query) : {});
}
}
createTransport(transportName, req) {
return new transports_1.default[transportName](req);
}
/**
* Handles an Engine.IO HTTP request.
*
* @param {EngineRequest} req
* @param {ServerResponse} res
*/
handleRequest(req, res) {
debug('handling "%s" http request "%s"', req.method, req.url);
this.prepare(req);
req.res = res;
const callback = (errorCode, errorContext) => {
if (errorCode !== undefined) {
this.emit("connection_error", {
req,
code: errorCode,
message: Server.errorMessages[errorCode],
context: errorContext,
});
abortRequest(res, errorCode, errorContext);
return;
}
if (req._query.sid) {
debug("setting new request for existing client");
this.clients[req._query.sid].transport.onRequest(req);
}
else {
const closeConnection = (errorCode, errorContext) => abortRequest(res, errorCode, errorContext);
this.handshake(req._query.transport, req, closeConnection);
}
};
this._applyMiddlewares(req, res, (err) => {
if (err) {
callback(Server.errors.BAD_REQUEST, { name: "MIDDLEWARE_FAILURE" });
}
else {
this.verify(req, false, callback);
}
});
}
/**
* Handles an Engine.IO HTTP Upgrade.
*/
handleUpgrade(req, socket, upgradeHead) {
this.prepare(req);
const res = new WebSocketResponse(req, socket);
const callback = (errorCode, errorContext) => {
if (errorCode !== undefined) {
this.emit("connection_error", {
req,
code: errorCode,
message: Server.errorMessages[errorCode],
context: errorContext,
});
abortUpgrade(socket, errorCode, errorContext);
return;
}
const head = Buffer.from(upgradeHead);
upgradeHead = null;
// some middlewares (like express-session) wait for the writeHead() call to flush their headers
// see https://github.com/expressjs/session/blob/1010fadc2f071ddf2add94235d72224cf65159c6/index.js#L220-L244
res.writeHead();
// delegate to ws
this.ws.handleUpgrade(req, socket, head, (websocket) => {
this.onWebSocket(req, socket, websocket);
});
};
this._applyMiddlewares(req, res, (err) => {
if (err) {
callback(Server.errors.BAD_REQUEST, { name: "MIDDLEWARE_FAILURE" });
}
else {
this.verify(req, true, callback);
}
});
}
/**
* Called upon a ws.io connection.
*
* @param {ws.Socket} websocket
* @private
*/
onWebSocket(req, socket, websocket) {
websocket.on("error", onUpgradeError);
if (transports_1.default[req._query.transport] !== undefined &&
!transports_1.default[req._query.transport].prototype.handlesUpgrades) {
debug("transport doesnt handle upgraded requests");
websocket.close();
return;
}
// get client id
const id = req._query.sid;
// keep a reference to the ws.Socket
req.websocket = websocket;
if (id) {
const client = this.clients[id];
if (!client) {
debug("upgrade attempt for closed client");
websocket.close();
}
else if (client.upgrading) {
debug("transport has already been trying to upgrade");
websocket.close();
}
else if (client.upgraded) {
debug("transport had already been upgraded");
websocket.close();
}
else {
debug("upgrading existing transport");
// transport error handling takes over
websocket.removeListener("error", onUpgradeError);
const transport = this.createTransport(req._query.transport, req);
transport.perMessageDeflate = this.opts.perMessageDeflate;
client._maybeUpgrade(transport);
}
}
else {
const closeConnection = (errorCode, errorContext) => abortUpgrade(socket, errorCode, errorContext);
this.handshake(req._query.transport, req, closeConnection);
}
function onUpgradeError() {
debug("websocket error before upgrade");
// websocket.close() not needed
}
}
/**
* Captures upgrade requests for a http.Server.
*
* @param {http.Server} server
* @param {Object} options
*/
attach(server, options = {}) {
const path = this._computePath(options);
const destroyUpgradeTimeout = options.destroyUpgradeTimeout || 1000;
function check(req) {
// TODO use `path === new URL(...).pathname` in the next major release (ref: https://nodejs.org/api/url.html)
return path === req.url.slice(0, path.length);
}
// cache and clean up listeners
const listeners = server.listeners("request").slice(0);
server.removeAllListeners("request");
server.on("close", this.close.bind(this));
server.on("listening", this.init.bind(this));
// add request handler
server.on("request", (req, res) => {
if (check(req)) {
debug('intercepting request for path "%s"', path);
this.handleRequest(req, res);
}
else {
let i = 0;
const l = listeners.length;
for (; i < l; i++) {
listeners[i].call(server, req, res);
}
}
});
if (~this.opts.transports.indexOf("websocket")) {
server.on("upgrade", (req, socket, head) => {
if (check(req)) {
this.handleUpgrade(req, socket, head);
}
else if (false !== options.destroyUpgrade) {
// default node behavior is to disconnect when no handlers
// but by adding a handler, we prevent that
// and if no eio thing handles the upgrade
// then the socket needs to die!
setTimeout(function () {
// @ts-ignore
if (socket.writable && socket.bytesWritten <= 0) {
socket.on("error", (e) => {
debug("error while destroying upgrade: %s", e.message);
});
return socket.end();
}
}, destroyUpgradeTimeout);
}
});
}
}
}
exports.Server = Server;
/**
* Close the HTTP long-polling request
*
* @param res - the response object
* @param errorCode - the error code
* @param errorContext - additional error context
*
* @private
*/
function abortRequest(res, errorCode, errorContext) {
const statusCode = errorCode === Server.errors.FORBIDDEN ? 403 : 400;
const message = errorContext && errorContext.message
? errorContext.message
: Server.errorMessages[errorCode];
res.writeHead(statusCode, { "Content-Type": "application/json" });
res.end(JSON.stringify({
code: errorCode,
message,
}));
}
/**
* Close the WebSocket connection
*
* @param {net.Socket} socket
* @param {string} errorCode - the error code
* @param {object} errorContext - additional error context
*/
function abortUpgrade(socket, errorCode, errorContext = {}) {
socket.on("error", () => {
debug("ignoring error from closed connection");
});
if (socket.writable) {
const message = errorContext.message || Server.errorMessages[errorCode];
const length = Buffer.byteLength(message);
socket.write("HTTP/1.1 400 Bad Request\r\n" +
"Connection: close\r\n" +
"Content-type: text/html\r\n" +
"Content-Length: " +
length +
"\r\n" +
"\r\n" +
message);
}
socket.destroy();
}
/* eslint-disable */
/**
* From https://github.com/nodejs/node/blob/v8.4.0/lib/_http_common.js#L303-L354
*
* True if val contains an invalid field-vchar
* field-value = *( field-content / obs-fold )
* field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
* field-vchar = VCHAR / obs-text
*
* checkInvalidHeaderChar() is currently designed to be inlinable by v8,
* so take care when making changes to the implementation so that the source
* code size does not exceed v8's default max_inlined_source_size setting.
**/
// prettier-ignore
const validHdrChars = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0 - 15
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32 - 47
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48 - 63
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80 - 95
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112 - 127
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128 ...
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // ... 255
];
function checkInvalidHeaderChar(val) {
val += "";
if (val.length < 1)
return false;
if (!validHdrChars[val.charCodeAt(0)]) {
debug('invalid header, index 0, char "%s"', val.charCodeAt(0));
return true;
}
if (val.length < 2)
return false;
if (!validHdrChars[val.charCodeAt(1)]) {
debug('invalid header, index 1, char "%s"', val.charCodeAt(1));
return true;
}
if (val.length < 3)
return false;
if (!validHdrChars[val.charCodeAt(2)]) {
debug('invalid header, index 2, char "%s"', val.charCodeAt(2));
return true;
}
if (val.length < 4)
return false;
if (!validHdrChars[val.charCodeAt(3)]) {
debug('invalid header, index 3, char "%s"', val.charCodeAt(3));
return true;
}
for (let i = 4; i < val.length; ++i) {
if (!validHdrChars[val.charCodeAt(i)]) {
debug('invalid header, index "%i", char "%s"', i, val.charCodeAt(i));
return true;
}
}
return false;
}

180
node_modules/engine.io/build/socket.d.ts generated vendored Normal file
View File

@ -0,0 +1,180 @@
import { EventEmitter } from "events";
import type { IncomingMessage } from "http";
import type { EngineRequest, Transport } from "./transport";
import type { BaseServer } from "./server";
import type { RawData } from "engine.io-parser";
export interface SendOptions {
compress?: boolean;
}
type ReadyState = "opening" | "open" | "closing" | "closed";
type SendCallback = (transport: Transport) => void;
export declare class Socket extends EventEmitter {
/**
* The revision of the protocol:
*
* - 3rd is used in Engine.IO v3 / Socket.IO v2
* - 4th is used in Engine.IO v4 and above / Socket.IO v3 and above
*
* It is found in the `EIO` query parameters of the HTTP requests.
*
* @see https://github.com/socketio/engine.io-protocol
*/
readonly protocol: number;
/**
* A reference to the first HTTP request of the session
*
* TODO for the next major release: remove it
*/
request: IncomingMessage;
/**
* The IP address of the client.
*/
readonly remoteAddress: string;
/**
* The current state of the socket.
*/
_readyState: ReadyState;
/**
* The current low-level transport.
*/
transport: Transport;
private server;
upgrading: boolean;
upgraded: boolean;
private writeBuffer;
private packetsFn;
private sentCallbackFn;
private cleanupFn;
private pingTimeoutTimer;
private pingIntervalTimer;
/**
* This is the session identifier that the client will use in the subsequent HTTP requests. It must not be shared with
* others parties, as it might lead to session hijacking.
*
* @private
*/
private readonly id;
get readyState(): ReadyState;
set readyState(state: ReadyState);
constructor(id: string, server: BaseServer, transport: Transport, req: EngineRequest, protocol: number);
/**
* Called upon transport considered open.
*
* @private
*/
private onOpen;
/**
* Called upon transport packet.
*
* @param {Object} packet
* @private
*/
private onPacket;
/**
* Called upon transport error.
*
* @param {Error} err - error object
* @private
*/
private onError;
/**
* Pings client every `this.pingInterval` and expects response
* within `this.pingTimeout` or closes connection.
*
* @private
*/
private schedulePing;
/**
* Resets ping timeout.
*
* @private
*/
private resetPingTimeout;
/**
* Attaches handlers for the given transport.
*
* @param {Transport} transport
* @private
*/
private setTransport;
/**
* Upon transport "drain" event
*
* @private
*/
private onDrain;
/**
* Upgrades socket to the given transport
*
* @param {Transport} transport
* @private
*/
_maybeUpgrade(transport: Transport): void;
/**
* Clears listeners and timers associated with current transport.
*
* @private
*/
private clearTransport;
/**
* Called upon transport considered closed.
* Possible reasons: `ping timeout`, `client error`, `parse error`,
* `transport error`, `server close`, `transport close`
*/
private onClose;
/**
* Sends a message packet.
*
* @param {Object} data
* @param {Object} options
* @param {Function} callback
* @return {Socket} for chaining
*/
send(data: RawData, options?: SendOptions, callback?: SendCallback): this;
/**
* Alias of {@link send}.
*
* @param data
* @param options
* @param callback
*/
write(data: RawData, options?: SendOptions, callback?: SendCallback): this;
/**
* Sends a packet.
*
* @param {String} type - packet type
* @param {String} data
* @param {Object} options
* @param {Function} callback
*
* @private
*/
private sendPacket;
/**
* Attempts to flush the packets buffer.
*
* @private
*/
private flush;
/**
* Get available upgrades for this socket.
*
* @private
*/
private getAvailableUpgrades;
/**
* Closes the socket and underlying transport.
*
* @param {Boolean} discard - optional, discard the transport
* @return {Socket} for chaining
*/
close(discard?: boolean): void;
/**
* Closes the underlying transport.
*
* @param {Boolean} discard
* @private
*/
private closeTransport;
}
export {};

460
node_modules/engine.io/build/socket.js generated vendored Normal file
View File

@ -0,0 +1,460 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Socket = void 0;
const events_1 = require("events");
const debug_1 = require("debug");
const timers_1 = require("timers");
const debug = (0, debug_1.default)("engine:socket");
class Socket extends events_1.EventEmitter {
get readyState() {
return this._readyState;
}
set readyState(state) {
debug("readyState updated from %s to %s", this._readyState, state);
this._readyState = state;
}
constructor(id, server, transport, req, protocol) {
super();
/**
* The current state of the socket.
*/
this._readyState = "opening";
/* private */ this.upgrading = false;
/* private */ this.upgraded = false;
this.writeBuffer = [];
this.packetsFn = [];
this.sentCallbackFn = [];
this.cleanupFn = [];
this.id = id;
this.server = server;
this.request = req;
this.protocol = protocol;
// Cache IP since it might not be in the req later
if (req) {
if (req.websocket && req.websocket._socket) {
this.remoteAddress = req.websocket._socket.remoteAddress;
}
else {
this.remoteAddress = req.connection.remoteAddress;
}
}
else {
// TODO there is currently no way to get the IP address of the client when it connects with WebTransport
// see https://github.com/fails-components/webtransport/issues/114
}
this.pingTimeoutTimer = null;
this.pingIntervalTimer = null;
this.setTransport(transport);
this.onOpen();
}
/**
* Called upon transport considered open.
*
* @private
*/
onOpen() {
this.readyState = "open";
// sends an `open` packet
this.transport.sid = this.id;
this.sendPacket("open", JSON.stringify({
sid: this.id,
upgrades: this.getAvailableUpgrades(),
pingInterval: this.server.opts.pingInterval,
pingTimeout: this.server.opts.pingTimeout,
maxPayload: this.server.opts.maxHttpBufferSize,
}));
if (this.server.opts.initialPacket) {
this.sendPacket("message", this.server.opts.initialPacket);
}
this.emit("open");
if (this.protocol === 3) {
// in protocol v3, the client sends a ping, and the server answers with a pong
this.resetPingTimeout();
}
else {
// in protocol v4, the server sends a ping, and the client answers with a pong
this.schedulePing();
}
}
/**
* Called upon transport packet.
*
* @param {Object} packet
* @private
*/
onPacket(packet) {
if ("open" !== this.readyState) {
return debug("packet received with closed socket");
}
// export packet event
debug(`received packet ${packet.type}`);
this.emit("packet", packet);
switch (packet.type) {
case "ping":
if (this.transport.protocol !== 3) {
this.onError(new Error("invalid heartbeat direction"));
return;
}
debug("got ping");
this.pingTimeoutTimer.refresh();
this.sendPacket("pong");
this.emit("heartbeat");
break;
case "pong":
if (this.transport.protocol === 3) {
this.onError(new Error("invalid heartbeat direction"));
return;
}
debug("got pong");
(0, timers_1.clearTimeout)(this.pingTimeoutTimer);
this.pingIntervalTimer.refresh();
this.emit("heartbeat");
break;
case "error":
this.onClose("parse error");
break;
case "message":
this.emit("data", packet.data);
this.emit("message", packet.data);
break;
}
}
/**
* Called upon transport error.
*
* @param {Error} err - error object
* @private
*/
onError(err) {
debug("transport error");
this.onClose("transport error", err);
}
/**
* Pings client every `this.pingInterval` and expects response
* within `this.pingTimeout` or closes connection.
*
* @private
*/
schedulePing() {
this.pingIntervalTimer = (0, timers_1.setTimeout)(() => {
debug("writing ping packet - expecting pong within %sms", this.server.opts.pingTimeout);
this.sendPacket("ping");
this.resetPingTimeout();
}, this.server.opts.pingInterval);
}
/**
* Resets ping timeout.
*
* @private
*/
resetPingTimeout() {
(0, timers_1.clearTimeout)(this.pingTimeoutTimer);
this.pingTimeoutTimer = (0, timers_1.setTimeout)(() => {
if (this.readyState === "closed")
return;
this.onClose("ping timeout");
}, this.protocol === 3
? this.server.opts.pingInterval + this.server.opts.pingTimeout
: this.server.opts.pingTimeout);
}
/**
* Attaches handlers for the given transport.
*
* @param {Transport} transport
* @private
*/
setTransport(transport) {
const onError = this.onError.bind(this);
const onReady = () => this.flush();
const onPacket = this.onPacket.bind(this);
const onDrain = this.onDrain.bind(this);
const onClose = this.onClose.bind(this, "transport close");
this.transport = transport;
this.transport.once("error", onError);
this.transport.on("ready", onReady);
this.transport.on("packet", onPacket);
this.transport.on("drain", onDrain);
this.transport.once("close", onClose);
this.cleanupFn.push(function () {
transport.removeListener("error", onError);
transport.removeListener("ready", onReady);
transport.removeListener("packet", onPacket);
transport.removeListener("drain", onDrain);
transport.removeListener("close", onClose);
});
}
/**
* Upon transport "drain" event
*
* @private
*/
onDrain() {
if (this.sentCallbackFn.length > 0) {
debug("executing batch send callback");
const seqFn = this.sentCallbackFn.shift();
if (seqFn) {
for (let i = 0; i < seqFn.length; i++) {
seqFn[i](this.transport);
}
}
}
}
/**
* Upgrades socket to the given transport
*
* @param {Transport} transport
* @private
*/
/* private */ _maybeUpgrade(transport) {
debug('might upgrade socket transport from "%s" to "%s"', this.transport.name, transport.name);
this.upgrading = true;
// set transport upgrade timer
const upgradeTimeoutTimer = (0, timers_1.setTimeout)(() => {
debug("client did not complete upgrade - closing transport");
cleanup();
if ("open" === transport.readyState) {
transport.close();
}
}, this.server.opts.upgradeTimeout);
let checkIntervalTimer;
const onPacket = (packet) => {
if ("ping" === packet.type && "probe" === packet.data) {
debug("got probe ping packet, sending pong");
transport.send([{ type: "pong", data: "probe" }]);
this.emit("upgrading", transport);
clearInterval(checkIntervalTimer);
checkIntervalTimer = setInterval(check, 100);
}
else if ("upgrade" === packet.type && this.readyState !== "closed") {
debug("got upgrade packet - upgrading");
cleanup();
this.transport.discard();
this.upgraded = true;
this.clearTransport();
this.setTransport(transport);
this.emit("upgrade", transport);
this.flush();
if (this.readyState === "closing") {
transport.close(() => {
this.onClose("forced close");
});
}
}
else {
cleanup();
transport.close();
}
};
// we force a polling cycle to ensure a fast upgrade
const check = () => {
if ("polling" === this.transport.name && this.transport.writable) {
debug("writing a noop packet to polling for fast upgrade");
this.transport.send([{ type: "noop" }]);
}
};
const cleanup = () => {
this.upgrading = false;
clearInterval(checkIntervalTimer);
(0, timers_1.clearTimeout)(upgradeTimeoutTimer);
transport.removeListener("packet", onPacket);
transport.removeListener("close", onTransportClose);
transport.removeListener("error", onError);
this.removeListener("close", onClose);
};
const onError = (err) => {
debug("client did not complete upgrade - %s", err);
cleanup();
transport.close();
transport = null;
};
const onTransportClose = () => {
onError("transport closed");
};
const onClose = () => {
onError("socket closed");
};
transport.on("packet", onPacket);
transport.once("close", onTransportClose);
transport.once("error", onError);
this.once("close", onClose);
}
/**
* Clears listeners and timers associated with current transport.
*
* @private
*/
clearTransport() {
let cleanup;
const toCleanUp = this.cleanupFn.length;
for (let i = 0; i < toCleanUp; i++) {
cleanup = this.cleanupFn.shift();
cleanup();
}
// silence further transport errors and prevent uncaught exceptions
this.transport.on("error", function () {
debug("error triggered by discarded transport");
});
// ensure transport won't stay open
this.transport.close();
(0, timers_1.clearTimeout)(this.pingTimeoutTimer);
}
/**
* Called upon transport considered closed.
* Possible reasons: `ping timeout`, `client error`, `parse error`,
* `transport error`, `server close`, `transport close`
*/
onClose(reason, description) {
if ("closed" !== this.readyState) {
this.readyState = "closed";
// clear timers
(0, timers_1.clearTimeout)(this.pingIntervalTimer);
(0, timers_1.clearTimeout)(this.pingTimeoutTimer);
// clean writeBuffer in next tick, so developers can still
// grab the writeBuffer on 'close' event
process.nextTick(() => {
this.writeBuffer = [];
});
this.packetsFn = [];
this.sentCallbackFn = [];
this.clearTransport();
this.emit("close", reason, description);
}
}
/**
* Sends a message packet.
*
* @param {Object} data
* @param {Object} options
* @param {Function} callback
* @return {Socket} for chaining
*/
send(data, options, callback) {
this.sendPacket("message", data, options, callback);
return this;
}
/**
* Alias of {@link send}.
*
* @param data
* @param options
* @param callback
*/
write(data, options, callback) {
this.sendPacket("message", data, options, callback);
return this;
}
/**
* Sends a packet.
*
* @param {String} type - packet type
* @param {String} data
* @param {Object} options
* @param {Function} callback
*
* @private
*/
sendPacket(type, data, options = {}, callback) {
if ("function" === typeof options) {
callback = options;
options = {};
}
if ("closing" !== this.readyState && "closed" !== this.readyState) {
debug('sending packet "%s" (%s)', type, data);
// compression is enabled by default
options.compress = options.compress !== false;
const packet = {
type,
options: options,
};
if (data)
packet.data = data;
// exports packetCreate event
this.emit("packetCreate", packet);
this.writeBuffer.push(packet);
// add send callback to object, if defined
if ("function" === typeof callback)
this.packetsFn.push(callback);
this.flush();
}
}
/**
* Attempts to flush the packets buffer.
*
* @private
*/
flush() {
if ("closed" !== this.readyState &&
this.transport.writable &&
this.writeBuffer.length) {
debug("flushing buffer to transport");
this.emit("flush", this.writeBuffer);
this.server.emit("flush", this, this.writeBuffer);
const wbuf = this.writeBuffer;
this.writeBuffer = [];
if (this.packetsFn.length) {
this.sentCallbackFn.push(this.packetsFn);
this.packetsFn = [];
}
else {
this.sentCallbackFn.push(null);
}
this.transport.send(wbuf);
this.emit("drain");
this.server.emit("drain", this);
}
}
/**
* Get available upgrades for this socket.
*
* @private
*/
getAvailableUpgrades() {
const availableUpgrades = [];
const allUpgrades = this.server.upgrades(this.transport.name);
for (let i = 0; i < allUpgrades.length; ++i) {
const upg = allUpgrades[i];
if (this.server.opts.transports.indexOf(upg) !== -1) {
availableUpgrades.push(upg);
}
}
return availableUpgrades;
}
/**
* Closes the socket and underlying transport.
*
* @param {Boolean} discard - optional, discard the transport
* @return {Socket} for chaining
*/
close(discard) {
if (discard &&
(this.readyState === "open" || this.readyState === "closing")) {
return this.closeTransport(discard);
}
if ("open" !== this.readyState)
return;
this.readyState = "closing";
if (this.writeBuffer.length) {
debug("there are %d remaining packets in the buffer, waiting for the 'drain' event", this.writeBuffer.length);
this.once("drain", () => {
debug("all packets have been sent, closing the transport");
this.closeTransport(discard);
});
return;
}
debug("the buffer is empty, closing the transport right away");
this.closeTransport(discard);
}
/**
* Closes the underlying transport.
*
* @param {Boolean} discard
* @private
*/
closeTransport(discard) {
debug("closing the transport (discard? %s)", !!discard);
if (discard)
this.transport.discard();
this.transport.close(this.onClose.bind(this, "forced close"));
}
}
exports.Socket = Socket;

124
node_modules/engine.io/build/transport.d.ts generated vendored Normal file
View File

@ -0,0 +1,124 @@
import { EventEmitter } from "events";
import type { IncomingMessage, ServerResponse } from "http";
import { Packet, RawData } from "engine.io-parser";
type ReadyState = "open" | "closing" | "closed";
export type EngineRequest = IncomingMessage & {
_query: Record<string, string>;
res?: ServerResponse;
cleanup?: Function;
websocket?: any;
};
export declare abstract class Transport extends EventEmitter {
/**
* The session ID.
*/
sid: string;
/**
* Whether the transport is currently ready to send packets.
*/
writable: boolean;
/**
* The revision of the protocol:
*
* - 3 is used in Engine.IO v3 / Socket.IO v2
* - 4 is used in Engine.IO v4 and above / Socket.IO v3 and above
*
* It is found in the `EIO` query parameters of the HTTP requests.
*
* @see https://github.com/socketio/engine.io-protocol
*/
protocol: number;
/**
* The current state of the transport.
* @protected
*/
protected _readyState: ReadyState;
/**
* Whether the transport is discarded and can be safely closed (used during upgrade).
* @protected
*/
protected discarded: boolean;
/**
* The parser to use (depends on the revision of the {@link Transport#protocol}.
* @protected
*/
protected parser: any;
/**
* Whether the transport supports binary payloads (else it will be base64-encoded)
* @protected
*/
protected supportsBinary: boolean;
get readyState(): ReadyState;
set readyState(state: ReadyState);
/**
* Transport constructor.
*
* @param {EngineRequest} req
*/
constructor(req: {
_query: Record<string, string>;
});
/**
* Flags the transport as discarded.
*
* @package
*/
discard(): void;
/**
* Called with an incoming HTTP request.
*
* @param req
* @package
*/
onRequest(req: any): void;
/**
* Closes the transport.
*
* @package
*/
close(fn?: () => void): void;
/**
* Called with a transport error.
*
* @param {String} msg - message error
* @param {Object} desc - error description
* @protected
*/
protected onError(msg: string, desc?: any): void;
/**
* Called with parsed out a packets from the data stream.
*
* @param {Object} packet
* @protected
*/
protected onPacket(packet: Packet): void;
/**
* Called with the encoded packet data.
*
* @param {String} data
* @protected
*/
protected onData(data: RawData): void;
/**
* Called upon transport close.
*
* @protected
*/
protected onClose(): void;
/**
* The name of the transport.
*/
abstract get name(): string;
/**
* Sends an array of packets.
*
* @param {Array} packets
* @package
*/
abstract send(packets: Packet[]): void;
/**
* Closes the transport.
*/
abstract doClose(fn?: () => void): void;
}
export {};

117
node_modules/engine.io/build/transport.js generated vendored Normal file
View File

@ -0,0 +1,117 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Transport = void 0;
const events_1 = require("events");
const parser_v4 = require("engine.io-parser");
const parser_v3 = require("./parser-v3/index");
const debug_1 = require("debug");
const debug = (0, debug_1.default)("engine:transport");
function noop() { }
class Transport extends events_1.EventEmitter {
get readyState() {
return this._readyState;
}
set readyState(state) {
debug("readyState updated from %s to %s (%s)", this._readyState, state, this.name);
this._readyState = state;
}
/**
* Transport constructor.
*
* @param {EngineRequest} req
*/
constructor(req) {
super();
/**
* Whether the transport is currently ready to send packets.
*/
this.writable = false;
/**
* The current state of the transport.
* @protected
*/
this._readyState = "open";
/**
* Whether the transport is discarded and can be safely closed (used during upgrade).
* @protected
*/
this.discarded = false;
this.protocol = req._query.EIO === "4" ? 4 : 3; // 3rd revision by default
this.parser = this.protocol === 4 ? parser_v4 : parser_v3;
this.supportsBinary = !(req._query && req._query.b64);
}
/**
* Flags the transport as discarded.
*
* @package
*/
discard() {
this.discarded = true;
}
/**
* Called with an incoming HTTP request.
*
* @param req
* @package
*/
onRequest(req) { }
/**
* Closes the transport.
*
* @package
*/
close(fn) {
if ("closed" === this.readyState || "closing" === this.readyState)
return;
this.readyState = "closing";
this.doClose(fn || noop);
}
/**
* Called with a transport error.
*
* @param {String} msg - message error
* @param {Object} desc - error description
* @protected
*/
onError(msg, desc) {
if (this.listeners("error").length) {
const err = new Error(msg);
// @ts-ignore
err.type = "TransportError";
// @ts-ignore
err.description = desc;
this.emit("error", err);
}
else {
debug("ignored transport error %s (%s)", msg, desc);
}
}
/**
* Called with parsed out a packets from the data stream.
*
* @param {Object} packet
* @protected
*/
onPacket(packet) {
this.emit("packet", packet);
}
/**
* Called with the encoded packet data.
*
* @param {String} data
* @protected
*/
onData(data) {
this.onPacket(this.parser.decodePacket(data));
}
/**
* Called upon transport close.
*
* @protected
*/
onClose() {
this.readyState = "closed";
this.emit("close");
}
}
exports.Transport = Transport;

View File

@ -0,0 +1,7 @@
import { Polling } from "./polling";
import { WebSocket } from "./websocket";
declare const _default: {
polling: typeof Polling;
websocket: typeof WebSocket;
};
export default _default;

8
node_modules/engine.io/build/transports-uws/index.js generated vendored Normal file
View File

@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const polling_1 = require("./polling");
const websocket_1 = require("./websocket");
exports.default = {
polling: polling_1.Polling,
websocket: websocket_1.WebSocket,
};

View File

@ -0,0 +1,99 @@
import { Transport } from "../transport";
export declare class Polling extends Transport {
maxHttpBufferSize: number;
httpCompression: any;
private req;
private res;
private dataReq;
private dataRes;
private shouldClose;
private readonly closeTimeout;
/**
* HTTP polling constructor.
*/
constructor(req: any);
/**
* Transport name
*/
get name(): string;
/**
* Overrides onRequest.
*
* @param req
*
* @private
*/
onRequest(req: any): void;
/**
* The client sends a request awaiting for us to send data.
*
* @private
*/
onPollRequest(req: any, res: any): void;
/**
* The client sends a request with data.
*
* @private
*/
onDataRequest(req: any, res: any): void;
/**
* Cleanup request.
*
* @private
*/
private onDataRequestCleanup;
/**
* Processes the incoming data payload.
*
* @param {String} encoded payload
* @private
*/
onData(data: any): void;
/**
* Overrides onClose.
*
* @private
*/
onClose(): void;
/**
* Writes a packet payload.
*
* @param {Object} packet
* @private
*/
send(packets: any): void;
/**
* Writes data as response to poll request.
*
* @param {String} data
* @param {Object} options
* @private
*/
write(data: any, options: any): void;
/**
* Performs the write.
*
* @private
*/
doWrite(data: any, options: any, callback: any): void;
/**
* Compresses data.
*
* @private
*/
compress(data: any, encoding: any, callback: any): void;
/**
* Closes the transport.
*
* @private
*/
doClose(fn: any): void;
/**
* Returns headers for a response.
*
* @param req - request
* @param {Object} extra headers
* @private
*/
headers(req: any, headers: any): any;
}

364
node_modules/engine.io/build/transports-uws/polling.js generated vendored Normal file
View File

@ -0,0 +1,364 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Polling = void 0;
const transport_1 = require("../transport");
const zlib_1 = require("zlib");
const accepts = require("accepts");
const debug_1 = require("debug");
const debug = (0, debug_1.default)("engine:polling");
const compressionMethods = {
gzip: zlib_1.createGzip,
deflate: zlib_1.createDeflate,
};
class Polling extends transport_1.Transport {
/**
* HTTP polling constructor.
*/
constructor(req) {
super(req);
this.closeTimeout = 30 * 1000;
}
/**
* Transport name
*/
get name() {
return "polling";
}
/**
* Overrides onRequest.
*
* @param req
*
* @private
*/
onRequest(req) {
const res = req.res;
// remove the reference to the ServerResponse object (as the first request of the session is kept in memory by default)
req.res = null;
if (req.getMethod() === "get") {
this.onPollRequest(req, res);
}
else if (req.getMethod() === "post") {
this.onDataRequest(req, res);
}
else {
res.writeStatus("500 Internal Server Error");
res.end();
}
}
/**
* The client sends a request awaiting for us to send data.
*
* @private
*/
onPollRequest(req, res) {
if (this.req) {
debug("request overlap");
// assert: this.res, '.req and .res should be (un)set together'
this.onError("overlap from client");
res.writeStatus("500 Internal Server Error");
res.end();
return;
}
debug("setting request");
this.req = req;
this.res = res;
const onClose = () => {
this.writable = false;
this.onError("poll connection closed prematurely");
};
const cleanup = () => {
this.req = this.res = null;
};
req.cleanup = cleanup;
res.onAborted(onClose);
this.writable = true;
this.emit("ready");
// if we're still writable but had a pending close, trigger an empty send
if (this.writable && this.shouldClose) {
debug("triggering empty send to append close packet");
this.send([{ type: "noop" }]);
}
}
/**
* The client sends a request with data.
*
* @private
*/
onDataRequest(req, res) {
if (this.dataReq) {
// assert: this.dataRes, '.dataReq and .dataRes should be (un)set together'
this.onError("data request overlap from client");
res.writeStatus("500 Internal Server Error");
res.end();
return;
}
const expectedContentLength = Number(req.headers["content-length"]);
if (!expectedContentLength) {
this.onError("content-length header required");
res.writeStatus("411 Length Required").end();
return;
}
if (expectedContentLength > this.maxHttpBufferSize) {
this.onError("payload too large");
res.writeStatus("413 Payload Too Large").end();
return;
}
const isBinary = "application/octet-stream" === req.headers["content-type"];
if (isBinary && this.protocol === 4) {
return this.onError("invalid content");
}
this.dataReq = req;
this.dataRes = res;
let buffer;
let offset = 0;
const headers = {
// text/html is required instead of text/plain to avoid an
// unwanted download dialog on certain user-agents (GH-43)
"Content-Type": "text/html",
};
this.headers(req, headers);
for (let key in headers) {
res.writeHeader(key, String(headers[key]));
}
const onEnd = (buffer) => {
this.onData(buffer.toString());
this.onDataRequestCleanup();
res.cork(() => {
res.end("ok");
});
};
res.onAborted(() => {
this.onDataRequestCleanup();
this.onError("data request connection closed prematurely");
});
res.onData((arrayBuffer, isLast) => {
const totalLength = offset + arrayBuffer.byteLength;
if (totalLength > expectedContentLength) {
this.onError("content-length mismatch");
res.close(); // calls onAborted
return;
}
if (!buffer) {
if (isLast) {
onEnd(Buffer.from(arrayBuffer));
return;
}
buffer = Buffer.allocUnsafe(expectedContentLength);
}
Buffer.from(arrayBuffer).copy(buffer, offset);
if (isLast) {
if (totalLength != expectedContentLength) {
this.onError("content-length mismatch");
res.writeStatus("400 Content-Length Mismatch").end();
this.onDataRequestCleanup();
return;
}
onEnd(buffer);
return;
}
offset = totalLength;
});
}
/**
* Cleanup request.
*
* @private
*/
onDataRequestCleanup() {
this.dataReq = this.dataRes = null;
}
/**
* Processes the incoming data payload.
*
* @param {String} encoded payload
* @private
*/
onData(data) {
debug('received "%s"', data);
const callback = (packet) => {
if ("close" === packet.type) {
debug("got xhr close packet");
this.onClose();
return false;
}
this.onPacket(packet);
};
if (this.protocol === 3) {
this.parser.decodePayload(data, callback);
}
else {
this.parser.decodePayload(data).forEach(callback);
}
}
/**
* Overrides onClose.
*
* @private
*/
onClose() {
if (this.writable) {
// close pending poll request
this.send([{ type: "noop" }]);
}
super.onClose();
}
/**
* Writes a packet payload.
*
* @param {Object} packet
* @private
*/
send(packets) {
this.writable = false;
if (this.shouldClose) {
debug("appending close packet to payload");
packets.push({ type: "close" });
this.shouldClose();
this.shouldClose = null;
}
const doWrite = (data) => {
const compress = packets.some((packet) => {
return packet.options && packet.options.compress;
});
this.write(data, { compress });
};
if (this.protocol === 3) {
this.parser.encodePayload(packets, this.supportsBinary, doWrite);
}
else {
this.parser.encodePayload(packets, doWrite);
}
}
/**
* Writes data as response to poll request.
*
* @param {String} data
* @param {Object} options
* @private
*/
write(data, options) {
debug('writing "%s"', data);
this.doWrite(data, options, () => {
this.req.cleanup();
this.emit("drain");
});
}
/**
* Performs the write.
*
* @private
*/
doWrite(data, options, callback) {
// explicit UTF-8 is required for pages not served under utf
const isString = typeof data === "string";
const contentType = isString
? "text/plain; charset=UTF-8"
: "application/octet-stream";
const headers = {
"Content-Type": contentType,
};
const respond = (data) => {
this.headers(this.req, headers);
this.res.cork(() => {
Object.keys(headers).forEach((key) => {
this.res.writeHeader(key, String(headers[key]));
});
this.res.end(data);
});
callback();
};
if (!this.httpCompression || !options.compress) {
respond(data);
return;
}
const len = isString ? Buffer.byteLength(data) : data.length;
if (len < this.httpCompression.threshold) {
respond(data);
return;
}
const encoding = accepts(this.req).encodings(["gzip", "deflate"]);
if (!encoding) {
respond(data);
return;
}
this.compress(data, encoding, (err, data) => {
if (err) {
this.res.writeStatus("500 Internal Server Error");
this.res.end();
callback(err);
return;
}
headers["Content-Encoding"] = encoding;
respond(data);
});
}
/**
* Compresses data.
*
* @private
*/
compress(data, encoding, callback) {
debug("compressing");
const buffers = [];
let nread = 0;
compressionMethods[encoding](this.httpCompression)
.on("error", callback)
.on("data", function (chunk) {
buffers.push(chunk);
nread += chunk.length;
})
.on("end", function () {
callback(null, Buffer.concat(buffers, nread));
})
.end(data);
}
/**
* Closes the transport.
*
* @private
*/
doClose(fn) {
debug("closing");
let closeTimeoutTimer;
const onClose = () => {
clearTimeout(closeTimeoutTimer);
fn();
this.onClose();
};
if (this.writable) {
debug("transport writable - closing right away");
this.send([{ type: "close" }]);
onClose();
}
else if (this.discarded) {
debug("transport discarded - closing right away");
onClose();
}
else {
debug("transport not writable - buffering orderly close");
this.shouldClose = onClose;
closeTimeoutTimer = setTimeout(onClose, this.closeTimeout);
}
}
/**
* Returns headers for a response.
*
* @param req - request
* @param {Object} extra headers
* @private
*/
headers(req, headers) {
headers = headers || {};
// prevent XSS warnings on IE
// https://github.com/LearnBoost/socket.io/pull/1333
const ua = req.headers["user-agent"];
if (ua && (~ua.indexOf(";MSIE") || ~ua.indexOf("Trident/"))) {
headers["X-XSS-Protection"] = "0";
}
headers["cache-control"] = "no-store";
this.emit("headers", headers, req);
return headers;
}
}
exports.Polling = Polling;

View File

@ -0,0 +1,32 @@
import { Transport } from "../transport";
export declare class WebSocket extends Transport {
protected perMessageDeflate: any;
private socket;
/**
* WebSocket transport
*
* @param req
*/
constructor(req: any);
/**
* Transport name
*/
get name(): string;
/**
* Advertise upgrade support.
*/
get handlesUpgrades(): boolean;
/**
* Writes a packet payload.
*
* @param {Array} packets
* @private
*/
send(packets: any): void;
/**
* Closes the transport.
*
* @private
*/
doClose(fn: any): void;
}

View File

@ -0,0 +1,73 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebSocket = void 0;
const transport_1 = require("../transport");
const debug_1 = require("debug");
const debug = (0, debug_1.default)("engine:ws");
class WebSocket extends transport_1.Transport {
/**
* WebSocket transport
*
* @param req
*/
constructor(req) {
super(req);
this.writable = false;
this.perMessageDeflate = null;
}
/**
* Transport name
*/
get name() {
return "websocket";
}
/**
* Advertise upgrade support.
*/
get handlesUpgrades() {
return true;
}
/**
* Writes a packet payload.
*
* @param {Array} packets
* @private
*/
send(packets) {
this.writable = false;
for (let i = 0; i < packets.length; i++) {
const packet = packets[i];
const isLast = i + 1 === packets.length;
const send = (data) => {
const isBinary = typeof data !== "string";
const compress = this.perMessageDeflate &&
Buffer.byteLength(data) > this.perMessageDeflate.threshold;
debug('writing "%s"', data);
this.socket.send(data, isBinary, compress);
if (isLast) {
this.emit("drain");
this.writable = true;
this.emit("ready");
}
};
if (packet.options && typeof packet.options.wsPreEncoded === "string") {
send(packet.options.wsPreEncoded);
}
else {
this.parser.encodePacket(packet, this.supportsBinary, send);
}
}
}
/**
* Closes the transport.
*
* @private
*/
doClose(fn) {
debug("closing");
fn && fn();
// call fn first since socket.end() immediately emits a "close" event
this.socket.end();
}
}
exports.WebSocket = WebSocket;

16
node_modules/engine.io/build/transports/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,16 @@
import { Polling as XHR } from "./polling";
import { WebSocket } from "./websocket";
import { WebTransport } from "./webtransport";
declare const _default: {
polling: typeof polling;
websocket: typeof WebSocket;
webtransport: typeof WebTransport;
};
export default _default;
/**
* Polling polymorphic constructor.
*/
declare function polling(req: any): XHR;
declare namespace polling {
var upgradesTo: string[];
}

23
node_modules/engine.io/build/transports/index.js generated vendored Normal file
View File

@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const polling_1 = require("./polling");
const polling_jsonp_1 = require("./polling-jsonp");
const websocket_1 = require("./websocket");
const webtransport_1 = require("./webtransport");
exports.default = {
polling: polling,
websocket: websocket_1.WebSocket,
webtransport: webtransport_1.WebTransport,
};
/**
* Polling polymorphic constructor.
*/
function polling(req) {
if ("string" === typeof req._query.j) {
return new polling_jsonp_1.JSONP(req);
}
else {
return new polling_1.Polling(req);
}
}
polling.upgradesTo = ["websocket", "webtransport"];

View File

@ -0,0 +1,12 @@
import { Polling } from "./polling";
import type { RawData } from "engine.io-parser";
export declare class JSONP extends Polling {
private readonly head;
private readonly foot;
/**
* JSON-P polling transport.
*/
constructor(req: any);
onData(data: RawData): void;
doWrite(data: any, options: any, callback: any): void;
}

View File

@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.JSONP = void 0;
const polling_1 = require("./polling");
const qs = require("querystring");
const rDoubleSlashes = /\\\\n/g;
const rSlashes = /(\\)?\\n/g;
class JSONP extends polling_1.Polling {
/**
* JSON-P polling transport.
*/
constructor(req) {
super(req);
this.head = "___eio[" + (req._query.j || "").replace(/[^0-9]/g, "") + "](";
this.foot = ");";
}
onData(data) {
// we leverage the qs module so that we get built-in DoS protection
// and the fast alternative to decodeURIComponent
data = qs.parse(data).d;
if ("string" === typeof data) {
// client will send already escaped newlines as \\\\n and newlines as \\n
// \\n must be replaced with \n and \\\\n with \\n
data = data.replace(rSlashes, function (match, slashes) {
return slashes ? match : "\n";
});
super.onData(data.replace(rDoubleSlashes, "\\n"));
}
}
doWrite(data, options, callback) {
// we must output valid javascript, not valid json
// see: http://timelessrepo.com/json-isnt-a-javascript-subset
const js = JSON.stringify(data)
.replace(/\u2028/g, "\\u2028")
.replace(/\u2029/g, "\\u2029");
// prepare response
data = this.head + js + this.foot;
super.doWrite(data, options, callback);
}
}
exports.JSONP = JSONP;

87
node_modules/engine.io/build/transports/polling.d.ts generated vendored Normal file
View File

@ -0,0 +1,87 @@
import { EngineRequest, Transport } from "../transport";
import type { Packet, RawData } from "engine.io-parser";
export declare class Polling extends Transport {
maxHttpBufferSize: number;
httpCompression: any;
private req;
private res;
private dataReq;
private dataRes;
private shouldClose;
private readonly closeTimeout;
/**
* HTTP polling constructor.
*/
constructor(req: any);
/**
* Transport name
*/
get name(): string;
/**
* Overrides onRequest.
*
* @param {EngineRequest} req
* @package
*/
onRequest(req: EngineRequest): void;
/**
* The client sends a request awaiting for us to send data.
*
* @private
*/
private onPollRequest;
/**
* The client sends a request with data.
*
* @private
*/
private onDataRequest;
/**
* Processes the incoming data payload.
*
* @param data - encoded payload
* @protected
*/
onData(data: RawData): void;
/**
* Overrides onClose.
*
* @private
*/
onClose(): void;
send(packets: Packet[]): void;
/**
* Writes data as response to poll request.
*
* @param {String} data
* @param {Object} options
* @private
*/
private write;
/**
* Performs the write.
*
* @protected
*/
protected doWrite(data: any, options: any, callback: any): void;
/**
* Compresses data.
*
* @private
*/
private compress;
/**
* Closes the transport.
*
* @private
*/
doClose(fn: () => void): void;
/**
* Returns headers for a response.
*
* @param {http.IncomingMessage} req
* @param {Object} headers - extra headers
* @private
*/
private headers;
}

332
node_modules/engine.io/build/transports/polling.js generated vendored Normal file
View File

@ -0,0 +1,332 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Polling = void 0;
const transport_1 = require("../transport");
const zlib_1 = require("zlib");
const accepts = require("accepts");
const debug_1 = require("debug");
const debug = (0, debug_1.default)("engine:polling");
const compressionMethods = {
gzip: zlib_1.createGzip,
deflate: zlib_1.createDeflate,
};
class Polling extends transport_1.Transport {
/**
* HTTP polling constructor.
*/
constructor(req) {
super(req);
this.closeTimeout = 30 * 1000;
}
/**
* Transport name
*/
get name() {
return "polling";
}
/**
* Overrides onRequest.
*
* @param {EngineRequest} req
* @package
*/
onRequest(req) {
const res = req.res;
// remove the reference to the ServerResponse object (as the first request of the session is kept in memory by default)
req.res = null;
if ("GET" === req.method) {
this.onPollRequest(req, res);
}
else if ("POST" === req.method) {
this.onDataRequest(req, res);
}
else {
res.writeHead(500);
res.end();
}
}
/**
* The client sends a request awaiting for us to send data.
*
* @private
*/
onPollRequest(req, res) {
if (this.req) {
debug("request overlap");
// assert: this.res, '.req and .res should be (un)set together'
this.onError("overlap from client");
res.writeHead(400);
res.end();
return;
}
debug("setting request");
this.req = req;
this.res = res;
const onClose = () => {
this.onError("poll connection closed prematurely");
};
const cleanup = () => {
req.removeListener("close", onClose);
this.req = this.res = null;
};
req.cleanup = cleanup;
req.on("close", onClose);
this.writable = true;
this.emit("ready");
// if we're still writable but had a pending close, trigger an empty send
if (this.writable && this.shouldClose) {
debug("triggering empty send to append close packet");
this.send([{ type: "noop" }]);
}
}
/**
* The client sends a request with data.
*
* @private
*/
onDataRequest(req, res) {
if (this.dataReq) {
// assert: this.dataRes, '.dataReq and .dataRes should be (un)set together'
this.onError("data request overlap from client");
res.writeHead(400);
res.end();
return;
}
const isBinary = "application/octet-stream" === req.headers["content-type"];
if (isBinary && this.protocol === 4) {
return this.onError("invalid content");
}
this.dataReq = req;
this.dataRes = res;
let chunks = isBinary ? Buffer.concat([]) : "";
const cleanup = () => {
req.removeListener("data", onData);
req.removeListener("end", onEnd);
req.removeListener("close", onClose);
this.dataReq = this.dataRes = chunks = null;
};
const onClose = () => {
cleanup();
this.onError("data request connection closed prematurely");
};
const onData = (data) => {
let contentLength;
if (isBinary) {
chunks = Buffer.concat([chunks, data]);
contentLength = chunks.length;
}
else {
chunks += data;
contentLength = Buffer.byteLength(chunks);
}
if (contentLength > this.maxHttpBufferSize) {
res.writeHead(413).end();
cleanup();
}
};
const onEnd = () => {
this.onData(chunks);
const headers = {
// text/html is required instead of text/plain to avoid an
// unwanted download dialog on certain user-agents (GH-43)
"Content-Type": "text/html",
"Content-Length": "2",
};
res.writeHead(200, this.headers(req, headers));
res.end("ok");
cleanup();
};
req.on("close", onClose);
if (!isBinary)
req.setEncoding("utf8");
req.on("data", onData);
req.on("end", onEnd);
}
/**
* Processes the incoming data payload.
*
* @param data - encoded payload
* @protected
*/
onData(data) {
debug('received "%s"', data);
const callback = (packet) => {
if ("close" === packet.type) {
debug("got xhr close packet");
this.onClose();
return false;
}
this.onPacket(packet);
};
if (this.protocol === 3) {
this.parser.decodePayload(data, callback);
}
else {
this.parser.decodePayload(data).forEach(callback);
}
}
/**
* Overrides onClose.
*
* @private
*/
onClose() {
if (this.writable) {
// close pending poll request
this.send([{ type: "noop" }]);
}
super.onClose();
}
send(packets) {
this.writable = false;
if (this.shouldClose) {
debug("appending close packet to payload");
packets.push({ type: "close" });
this.shouldClose();
this.shouldClose = null;
}
const doWrite = (data) => {
const compress = packets.some((packet) => {
return packet.options && packet.options.compress;
});
this.write(data, { compress });
};
if (this.protocol === 3) {
this.parser.encodePayload(packets, this.supportsBinary, doWrite);
}
else {
this.parser.encodePayload(packets, doWrite);
}
}
/**
* Writes data as response to poll request.
*
* @param {String} data
* @param {Object} options
* @private
*/
write(data, options) {
debug('writing "%s"', data);
this.doWrite(data, options, () => {
this.req.cleanup();
this.emit("drain");
});
}
/**
* Performs the write.
*
* @protected
*/
doWrite(data, options, callback) {
// explicit UTF-8 is required for pages not served under utf
const isString = typeof data === "string";
const contentType = isString
? "text/plain; charset=UTF-8"
: "application/octet-stream";
const headers = {
"Content-Type": contentType,
};
const respond = (data) => {
headers["Content-Length"] =
"string" === typeof data ? Buffer.byteLength(data) : data.length;
this.res.writeHead(200, this.headers(this.req, headers));
this.res.end(data);
callback();
};
if (!this.httpCompression || !options.compress) {
respond(data);
return;
}
const len = isString ? Buffer.byteLength(data) : data.length;
if (len < this.httpCompression.threshold) {
respond(data);
return;
}
const encoding = accepts(this.req).encodings(["gzip", "deflate"]);
if (!encoding) {
respond(data);
return;
}
this.compress(data, encoding, (err, data) => {
if (err) {
this.res.writeHead(500);
this.res.end();
callback(err);
return;
}
headers["Content-Encoding"] = encoding;
respond(data);
});
}
/**
* Compresses data.
*
* @private
*/
compress(data, encoding, callback) {
debug("compressing");
const buffers = [];
let nread = 0;
compressionMethods[encoding](this.httpCompression)
.on("error", callback)
.on("data", function (chunk) {
buffers.push(chunk);
nread += chunk.length;
})
.on("end", function () {
callback(null, Buffer.concat(buffers, nread));
})
.end(data);
}
/**
* Closes the transport.
*
* @private
*/
doClose(fn) {
debug("closing");
let closeTimeoutTimer;
if (this.dataReq) {
debug("aborting ongoing data request");
this.dataReq.destroy();
}
const onClose = () => {
clearTimeout(closeTimeoutTimer);
fn();
this.onClose();
};
if (this.writable) {
debug("transport writable - closing right away");
this.send([{ type: "close" }]);
onClose();
}
else if (this.discarded) {
debug("transport discarded - closing right away");
onClose();
}
else {
debug("transport not writable - buffering orderly close");
this.shouldClose = onClose;
closeTimeoutTimer = setTimeout(onClose, this.closeTimeout);
}
}
/**
* Returns headers for a response.
*
* @param {http.IncomingMessage} req
* @param {Object} headers - extra headers
* @private
*/
headers(req, headers = {}) {
// prevent XSS warnings on IE
// https://github.com/LearnBoost/socket.io/pull/1333
const ua = req.headers["user-agent"];
if (ua && (~ua.indexOf(";MSIE") || ~ua.indexOf("Trident/"))) {
headers["X-XSS-Protection"] = "0";
}
headers["cache-control"] = "no-store";
this.emit("headers", headers, req);
return headers;
}
}
exports.Polling = Polling;

32
node_modules/engine.io/build/transports/websocket.d.ts generated vendored Normal file
View File

@ -0,0 +1,32 @@
import { EngineRequest, Transport } from "../transport";
import type { Packet } from "engine.io-parser";
export declare class WebSocket extends Transport {
protected perMessageDeflate: any;
private socket;
/**
* WebSocket transport
*
* @param {EngineRequest} req
*/
constructor(req: EngineRequest);
/**
* Transport name
*/
get name(): string;
/**
* Advertise upgrade support.
*/
get handlesUpgrades(): boolean;
send(packets: Packet[]): void;
/**
* Whether the encoding of the WebSocket frame can be skipped.
* @param packet
* @private
*/
private _canSendPreEncodedFrame;
private _doSend;
private _doSendLast;
private _onSent;
private _onSentLast;
doClose(fn?: () => void): void;
}

94
node_modules/engine.io/build/transports/websocket.js generated vendored Normal file
View File

@ -0,0 +1,94 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebSocket = void 0;
const transport_1 = require("../transport");
const debug_1 = require("debug");
const debug = (0, debug_1.default)("engine:ws");
class WebSocket extends transport_1.Transport {
/**
* WebSocket transport
*
* @param {EngineRequest} req
*/
constructor(req) {
super(req);
this._doSend = (data) => {
this.socket.send(data, this._onSent);
};
this._doSendLast = (data) => {
this.socket.send(data, this._onSentLast);
};
this._onSent = (err) => {
if (err) {
this.onError("write error", err.stack);
}
};
this._onSentLast = (err) => {
if (err) {
this.onError("write error", err.stack);
}
else {
this.emit("drain");
this.writable = true;
this.emit("ready");
}
};
this.socket = req.websocket;
this.socket.on("message", (data, isBinary) => {
const message = isBinary ? data : data.toString();
debug('received "%s"', message);
super.onData(message);
});
this.socket.once("close", this.onClose.bind(this));
this.socket.on("error", this.onError.bind(this));
this.writable = true;
this.perMessageDeflate = null;
}
/**
* Transport name
*/
get name() {
return "websocket";
}
/**
* Advertise upgrade support.
*/
get handlesUpgrades() {
return true;
}
send(packets) {
this.writable = false;
for (let i = 0; i < packets.length; i++) {
const packet = packets[i];
const isLast = i + 1 === packets.length;
if (this._canSendPreEncodedFrame(packet)) {
// the WebSocket frame was computed with WebSocket.Sender.frame()
// see https://github.com/websockets/ws/issues/617#issuecomment-283002469
this.socket._sender.sendFrame(
// @ts-ignore
packet.options.wsPreEncodedFrame, isLast ? this._onSentLast : this._onSent);
}
else {
this.parser.encodePacket(packet, this.supportsBinary, isLast ? this._doSendLast : this._doSend);
}
}
}
/**
* Whether the encoding of the WebSocket frame can be skipped.
* @param packet
* @private
*/
_canSendPreEncodedFrame(packet) {
var _a, _b, _c;
return (!this.perMessageDeflate &&
typeof ((_b = (_a = this.socket) === null || _a === void 0 ? void 0 : _a._sender) === null || _b === void 0 ? void 0 : _b.sendFrame) === "function" &&
// @ts-ignore
((_c = packet.options) === null || _c === void 0 ? void 0 : _c.wsPreEncodedFrame) !== undefined);
}
doClose(fn) {
debug("closing");
this.socket.close();
fn && fn();
}
}
exports.WebSocket = WebSocket;

View File

@ -0,0 +1,12 @@
import { Transport } from "../transport";
/**
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/WebTransport_API
*/
export declare class WebTransport extends Transport {
private readonly session;
private readonly writer;
constructor(session: any, stream: any, reader: any);
get name(): string;
send(packets: any): Promise<void>;
doClose(fn: any): void;
}

View File

@ -0,0 +1,63 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebTransport = void 0;
const transport_1 = require("../transport");
const debug_1 = require("debug");
const engine_io_parser_1 = require("engine.io-parser");
const debug = (0, debug_1.default)("engine:webtransport");
/**
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/WebTransport_API
*/
class WebTransport extends transport_1.Transport {
constructor(session, stream, reader) {
super({ _query: { EIO: "4" } });
this.session = session;
const transformStream = (0, engine_io_parser_1.createPacketEncoderStream)();
transformStream.readable.pipeTo(stream.writable).catch(() => {
debug("the stream was closed");
});
this.writer = transformStream.writable.getWriter();
(async () => {
try {
while (true) {
const { value, done } = await reader.read();
if (done) {
debug("session is closed");
break;
}
debug("received chunk: %o", value);
this.onPacket(value);
}
}
catch (e) {
debug("error while reading: %s", e.message);
}
})();
session.closed.then(() => this.onClose());
this.writable = true;
}
get name() {
return "webtransport";
}
async send(packets) {
this.writable = false;
try {
for (let i = 0; i < packets.length; i++) {
const packet = packets[i];
await this.writer.write(packet);
}
}
catch (e) {
debug("error while writing: %s", e.message);
}
this.emit("drain");
this.writable = true;
this.emit("ready");
}
doClose(fn) {
debug("closing WebTransport session");
this.session.close();
fn && fn();
}
}
exports.WebTransport = WebTransport;

42
node_modules/engine.io/build/userver.d.ts generated vendored Normal file
View File

@ -0,0 +1,42 @@
import { AttachOptions, BaseServer } from "./server";
export interface uOptions {
/**
* What permessage-deflate compression to use. uWS.DISABLED, uWS.SHARED_COMPRESSOR or any of the uWS.DEDICATED_COMPRESSOR_xxxKB.
* @default uWS.DISABLED
*/
compression?: number;
/**
* Maximum amount of seconds that may pass without sending or getting a message. Connection is closed if this timeout passes. Resolution (granularity) for timeouts are typically 4 seconds, rounded to closest. Disable by using 0.
* @default 120
*/
idleTimeout?: number;
/**
* Maximum length of allowed backpressure per socket when publishing or sending messages. Slow receivers with too high backpressure will be skipped until they catch up or timeout.
* @default 1024 * 1024
*/
maxBackpressure?: number;
}
/**
* An Engine.IO server based on the `uWebSockets.js` package.
*/
export declare class uServer extends BaseServer {
protected init(): void;
protected cleanup(): void;
/**
* Prepares a request by processing the query string.
*
* @private
*/
private prepare;
protected createTransport(transportName: any, req: any): any;
/**
* Attach the engine to a µWebSockets.js server
* @param app
* @param options
*/
attach(app: any, options?: AttachOptions & uOptions): void;
_applyMiddlewares(req: any, res: any, callback: (err?: any) => void): void;
private handleRequest;
private handleUpgrade;
private abortRequest;
}

279
node_modules/engine.io/build/userver.js generated vendored Normal file
View File

@ -0,0 +1,279 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.uServer = void 0;
const debug_1 = require("debug");
const server_1 = require("./server");
const transports_uws_1 = require("./transports-uws");
const debug = (0, debug_1.default)("engine:uws");
/**
* An Engine.IO server based on the `uWebSockets.js` package.
*/
// TODO export it into its own package
class uServer extends server_1.BaseServer {
init() { }
cleanup() { }
/**
* Prepares a request by processing the query string.
*
* @private
*/
prepare(req, res) {
req.method = req.getMethod().toUpperCase();
req.url = req.getUrl();
const params = new URLSearchParams(req.getQuery());
req._query = Object.fromEntries(params.entries());
req.headers = {};
req.forEach((key, value) => {
req.headers[key] = value;
});
req.connection = {
remoteAddress: Buffer.from(res.getRemoteAddressAsText()).toString(),
};
res.onAborted(() => {
debug("response has been aborted");
});
}
createTransport(transportName, req) {
return new transports_uws_1.default[transportName](req);
}
/**
* Attach the engine to a µWebSockets.js server
* @param app
* @param options
*/
attach(app /* : TemplatedApp */, options = {}) {
const path = this._computePath(options);
app
.any(path, this.handleRequest.bind(this))
//
.ws(path, {
compression: options.compression,
idleTimeout: options.idleTimeout,
maxBackpressure: options.maxBackpressure,
maxPayloadLength: this.opts.maxHttpBufferSize,
upgrade: this.handleUpgrade.bind(this),
open: (ws) => {
const transport = ws.getUserData().transport;
transport.socket = ws;
transport.writable = true;
transport.emit("ready");
},
message: (ws, message, isBinary) => {
ws.getUserData().transport.onData(isBinary ? message : Buffer.from(message).toString());
},
close: (ws, code, message) => {
ws.getUserData().transport.onClose(code, message);
},
});
}
_applyMiddlewares(req, res, callback) {
if (this.middlewares.length === 0) {
return callback();
}
// needed to buffer headers until the status is computed
req.res = new ResponseWrapper(res);
super._applyMiddlewares(req, req.res, (err) => {
// some middlewares (like express-session) wait for the writeHead() call to flush their headers
// see https://github.com/expressjs/session/blob/1010fadc2f071ddf2add94235d72224cf65159c6/index.js#L220-L244
req.res.writeHead();
callback(err);
});
}
handleRequest(res, req) {
debug('handling "%s" http request "%s"', req.getMethod(), req.getUrl());
this.prepare(req, res);
req.res = res;
const callback = (errorCode, errorContext) => {
if (errorCode !== undefined) {
this.emit("connection_error", {
req,
code: errorCode,
message: server_1.Server.errorMessages[errorCode],
context: errorContext,
});
this.abortRequest(req.res, errorCode, errorContext);
return;
}
if (req._query.sid) {
debug("setting new request for existing client");
// @ts-ignore
this.clients[req._query.sid].transport.onRequest(req);
}
else {
const closeConnection = (errorCode, errorContext) => this.abortRequest(res, errorCode, errorContext);
this.handshake(req._query.transport, req, closeConnection);
}
};
this._applyMiddlewares(req, res, (err) => {
if (err) {
callback(server_1.Server.errors.BAD_REQUEST, { name: "MIDDLEWARE_FAILURE" });
}
else {
this.verify(req, false, callback);
}
});
}
handleUpgrade(res, req, context) {
debug("on upgrade");
this.prepare(req, res);
req.res = res;
const callback = async (errorCode, errorContext) => {
if (errorCode !== undefined) {
this.emit("connection_error", {
req,
code: errorCode,
message: server_1.Server.errorMessages[errorCode],
context: errorContext,
});
this.abortRequest(res, errorCode, errorContext);
return;
}
const id = req._query.sid;
let transport;
if (id) {
const client = this.clients[id];
if (!client) {
debug("upgrade attempt for closed client");
return res.close();
}
else if (client.upgrading) {
debug("transport has already been trying to upgrade");
return res.close();
}
else if (client.upgraded) {
debug("transport had already been upgraded");
return res.close();
}
else {
debug("upgrading existing transport");
transport = this.createTransport(req._query.transport, req);
client._maybeUpgrade(transport);
}
}
else {
transport = await this.handshake(req._query.transport, req, (errorCode, errorContext) => this.abortRequest(res, errorCode, errorContext));
if (!transport) {
return;
}
}
// calling writeStatus() triggers the flushing of any header added in a middleware
req.res.writeStatus("101 Switching Protocols");
res.upgrade({
transport,
}, req.getHeader("sec-websocket-key"), req.getHeader("sec-websocket-protocol"), req.getHeader("sec-websocket-extensions"), context);
};
this._applyMiddlewares(req, res, (err) => {
if (err) {
callback(server_1.Server.errors.BAD_REQUEST, { name: "MIDDLEWARE_FAILURE" });
}
else {
this.verify(req, true, callback);
}
});
}
abortRequest(res, errorCode, errorContext) {
const statusCode = errorCode === server_1.Server.errors.FORBIDDEN
? "403 Forbidden"
: "400 Bad Request";
const message = errorContext && errorContext.message
? errorContext.message
: server_1.Server.errorMessages[errorCode];
res.writeStatus(statusCode);
res.writeHeader("Content-Type", "application/json");
res.end(JSON.stringify({
code: errorCode,
message,
}));
}
}
exports.uServer = uServer;
class ResponseWrapper {
constructor(res) {
this.res = res;
this.statusWritten = false;
this.headers = [];
this.isAborted = false;
}
set statusCode(status) {
if (!status) {
return;
}
// FIXME: handle all status codes?
this.writeStatus(status === 200 ? "200 OK" : "204 No Content");
}
writeHead(status) {
this.statusCode = status;
}
setHeader(key, value) {
if (Array.isArray(value)) {
value.forEach((val) => {
this.writeHeader(key, val);
});
}
else {
this.writeHeader(key, value);
}
}
removeHeader() {
// FIXME: not implemented
}
// needed by vary: https://github.com/jshttp/vary/blob/5d725d059b3871025cf753e9dfa08924d0bcfa8f/index.js#L134
getHeader() { }
writeStatus(status) {
if (this.isAborted)
return;
this.res.writeStatus(status);
this.statusWritten = true;
this.writeBufferedHeaders();
return this;
}
writeHeader(key, value) {
if (this.isAborted)
return;
if (key === "Content-Length") {
// the content length is automatically added by uWebSockets.js
return;
}
if (this.statusWritten) {
this.res.writeHeader(key, value);
}
else {
this.headers.push([key, value]);
}
}
writeBufferedHeaders() {
this.headers.forEach(([key, value]) => {
this.res.writeHeader(key, value);
});
}
end(data) {
if (this.isAborted)
return;
this.res.cork(() => {
if (!this.statusWritten) {
// status will be inferred as "200 OK"
this.writeBufferedHeaders();
}
this.res.end(data);
});
}
onData(fn) {
if (this.isAborted)
return;
this.res.onData(fn);
}
onAborted(fn) {
if (this.isAborted)
return;
this.res.onAborted(() => {
// Any attempt to use the UWS response object after abort will throw!
this.isAborted = true;
fn();
});
}
cork(fn) {
if (this.isAborted)
return;
this.res.cork(fn);
}
}

70
node_modules/engine.io/package.json generated vendored Normal file
View File

@ -0,0 +1,70 @@
{
"name": "engine.io",
"version": "6.6.4",
"description": "The realtime engine behind Socket.IO. Provides the foundation of a bidirectional connection between client and server",
"type": "commonjs",
"main": "./build/engine.io.js",
"types": "./build/engine.io.d.ts",
"exports": {
"types": "./build/engine.io.d.ts",
"import": "./wrapper.mjs",
"require": "./build/engine.io.js"
},
"author": "Guillermo Rauch <guillermo@learnboost.com>",
"contributors": [
{
"name": "Eugen Dueck",
"web": "https://github.com/EugenDueck"
},
{
"name": "Afshin Mehrabani",
"web": "https://github.com/afshinm"
},
{
"name": "Christoph Dorn",
"web": "https://github.com/cadorn"
},
{
"name": "Mark Mokryn",
"email": "mokesmokes@gmail.com"
}
],
"license": "MIT",
"dependencies": {
"@types/cors": "^2.8.12",
"@types/node": ">=10.0.0",
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.7.2",
"cors": "~2.8.5",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.17.1"
},
"scripts": {
"compile": "rimraf ./build && tsc",
"test": "npm run compile && npm run format:check && npm run test:default && npm run test:compat-v3",
"test:default": "mocha --bail --exit",
"test:compat-v3": "EIO_CLIENT=3 mocha --exit",
"test:eiows": "EIO_WS_ENGINE=eiows mocha --exit",
"test:uws": "EIO_WS_ENGINE=uws mocha --exit",
"format:check": "prettier --check \"wrapper.mjs\" \"lib/**/*.ts\" \"test/**/*.js\" \"test/webtransport.mjs\"",
"format:fix": "prettier --write \"wrapper.mjs\" \"lib/**/*.ts\" \"test/**/*.js\" \"test/webtransport.mjs\"",
"prepack": "npm run compile"
},
"homepage": "https://github.com/socketio/socket.io/tree/main/packages/engine.io#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/socketio/socket.io.git"
},
"bugs": {
"url": "https://github.com/socketio/socket.io/issues"
},
"files": [
"build/",
"wrapper.mjs"
],
"engines": {
"node": ">=10.2.0"
}
}

10
node_modules/engine.io/wrapper.mjs generated vendored Normal file
View File

@ -0,0 +1,10 @@
export {
Server,
Socket,
Transport,
transports,
listen,
attach,
parser,
protocol,
} from "./build/engine.io.js";