diff --git a/pom.xml b/pom.xml index 4636cb1b..6c72e4b3 100644 --- a/pom.xml +++ b/pom.xml @@ -107,8 +107,8 @@ maven-compiler-plugin 3.5.1 - 1.7 - 1.7 + 17 + 17 -Xlint:unchecked diff --git a/src/site/markdown/initialization.md b/src/site/markdown/initialization.md index 0311b39e..26396c81 100644 --- a/src/site/markdown/initialization.md +++ b/src/site/markdown/initialization.md @@ -42,12 +42,18 @@ IO.Options options = IO.Options.builder() .setMultiplex(true) // low-level engine options - .setTransports(new String[] { Polling.NAME, WebSocket.NAME }) + .setTransports(new String[] { Polling.NAME, WebSocket.NAME, WebTransport.NAME }) .setUpgrade(true) .setRememberUpgrade(false) .setPath("/socket.io/") .setQuery(null) .setExtraHeaders(null) + + // WebTransport options + .setWebTransportEnabled(true) + .setWebTransportConnectTimeout(30000) + .setWebTransportIdleTimeout(60000) + .setWebTransportTrustAllCertificates(false) // Manager options .setReconnection(true) @@ -114,12 +120,13 @@ The opposite of `forceNew`: whether to reuse an existing Manager instance. #### `transports` -Default value: `new String[] { Polling.NAME, WebSocket.NAME }` +Default value: `new String[] { Polling.NAME, WebSocket.NAME, WebTransport.NAME }` -The low-level connection to the Socket.IO server can either be established with: +The low-level connection to the Socket.IO server can be established with: - HTTP long-polling: successive HTTP requests (`POST` for writing, `GET` for reading) - [WebSocket](https://en.wikipedia.org/wiki/WebSocket) +- [WebTransport](https://www.w3.org/TR/webtransport/): HTTP/3-based transport with QUIC protocol for improved performance The following example disables the HTTP long-polling transport: @@ -133,6 +140,17 @@ Socket socket = IO.socket(URI.create("https://example.com"), options); Note: in that case, sticky sessions are not required on the server side (more information [here](https://socket.io/docs/v4/using-multiple-nodes/)). +The following example enables only WebTransport: + +```java +IO.Options options = IO.Options.builder() + .setTransports(new String[] { WebTransport.NAME }) + .setWebTransportEnabled(true) + .build(); + +Socket socket = IO.socket(URI.create("https://example.com"), options); +``` + #### `upgrade` Default value: `true` @@ -190,7 +208,94 @@ Socket socket = IO.socket(URI.create("https://example.com/order"), options); ``` - the Socket instance is attached to the "order" Namespace -- the HTTP requests will look like: `GET https://example.com/my-custom-path/?EIO=4&transport=polling&t=ML4jUwU` + +### WebTransport support + +WebTransport is a modern transport protocol based on HTTP/3 and QUIC that provides improved performance, reduced latency, and better handling of network conditions compared to traditional WebSocket connections. + +WebTransport is configured exactly like other transports - simply include it in the `transports` array: + +```java +import io.socket.engineio.client.transports.WebTransport; +import io.socket.engineio.client.transports.WebSocket; +import io.socket.engineio.client.transports.Polling; + +IO.Options options = IO.Options.builder() + .setTransports(new String[] { + WebTransport.NAME, // Try WebTransport first + WebSocket.NAME, // Fall back to WebSocket + Polling.NAME // Final fallback to Polling + }) + .build(); + +Socket socket = IO.socket(URI.create("https://example.com"), options); +``` + +#### Transport-specific options (advanced) + +For advanced WebTransport configuration, you can provide transport-specific options: + +```java +import io.socket.engineio.client.Transport; + +// Create WebTransport-specific options +Transport.Options webTransportOptions = new Transport.Options(); +webTransportOptions.hostname = "127.0.0.1"; // Override hostname if needed +webTransportOptions.port = 3000; // Override port if needed +webTransportOptions.secure = true; // WebTransport requires HTTPS +webTransportOptions.path = "/socket.io/"; // Socket.IO path + +// Apply transport-specific options +IO.Options options = IO.Options.builder() + .setTransports(new String[] { WebTransport.NAME, WebSocket.NAME, Polling.NAME }) + .build(); + +// Add transport-specific options +if (options.transportOptions == null) { + options.transportOptions = new HashMap<>(); +} +options.transportOptions.put("webtransport", webTransportOptions); + +Socket socket = IO.socket(URI.create("https://example.com"), options); +``` + +#### SSL configuration for self-signed certificates (development only) + +For development with self-signed certificates, configure the OkHttp client: + +```java +import okhttp3.OkHttpClient; +import javax.net.ssl.X509TrustManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; + +// Create trust-all SSL configuration (DEVELOPMENT ONLY!) +X509TrustManager trustAllCerts = new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } + public void checkClientTrusted(X509Certificate[] certs, String authType) {} + public void checkServerTrusted(X509Certificate[] certs, String authType) {} +}; + +SSLContext sslContext = SSLContext.getInstance("TLS"); +sslContext.init(null, new TrustManager[]{trustAllCerts}, new SecureRandom()); + +OkHttpClient okHttpClient = new OkHttpClient.Builder() + .sslSocketFactory(sslContext.getSocketFactory(), trustAllCerts) + .hostnameVerifier((hostname, session) -> true) + .build(); + +IO.Options options = IO.Options.builder() + .setTransports(new String[] { WebTransport.NAME, WebSocket.NAME, Polling.NAME }) + .setCallFactory(okHttpClient) // For HTTP requests + .setWebSocketFactory(okHttpClient) // For WebSocket connections + .build(); +``` + +**Important notes:** +- WebTransport requires HTTPS connections and HTTP/3 support on both client and server sides +- The client will automatically fall back to WebSocket or Polling if WebTransport fails +- WebTransport uses the same configuration approach as other transports - no special setup required +- Only use SSL certificate bypassing in development environments #### `query` diff --git a/src/site/markdown/webtransport_example.md b/src/site/markdown/webtransport_example.md new file mode 100644 index 00000000..d17de845 --- /dev/null +++ b/src/site/markdown/webtransport_example.md @@ -0,0 +1,394 @@ +# WebTransport Example + +This example demonstrates how to use WebTransport with the Socket.IO Java client. + +## Prerequisites + +- Java 8 or higher +- A Socket.IO server that supports WebTransport (version 4.7.0+) +- HTTP/3 support on both client and server + +## Basic WebTransport Usage + +```java +import io.socket.client.IO; +import io.socket.client.Socket; +import io.socket.emitter.Emitter; +import io.socket.engineio.client.transports.Polling; +import io.socket.engineio.client.transports.WebSocket; +import io.socket.engineio.client.transports.WebTransport; + +import java.net.URI; + +public class WebTransportExample { + private static volatile String currentTransportName = null; + + public static void main(String[] args) { + // Create Socket.IO options with WebTransport enabled + IO.Options options = IO.Options.builder() + .setTransports(new String[] { WebTransport.NAME, WebSocket.NAME, Polling.NAME }) + .build(); + + // Create socket connection + Socket socket = IO.socket(URI.create("https://localhost:3000"), options); + + // Listen for transport events to track current transport + socket.io().on("transport", new Emitter.Listener() { + @Override + public void call(Object... args) { + if (args.length > 0 && args[0] instanceof io.socket.engineio.client.Transport) { + io.socket.engineio.client.Transport transport = (io.socket.engineio.client.Transport) args[0]; + currentTransportName = transport.name; + System.out.println("Transport event: " + currentTransportName); + } + } + }); + + // Set up event listeners + socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() { + @Override + public void call(Object... args) { + System.out.println("Connected with transport: " + currentTransportName); + } + }); + + socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() { + @Override + public void call(Object... args) { + System.out.println("Disconnected"); + } + }); + + socket.on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener() { + @Override + public void call(Object... args) { + System.err.println("Connection error: " + args[0]); + } + }); + + // Connect to server + socket.connect(); + } +} +``` + +## SSL Configuration for Development + +When working with self-signed certificates in development, you need to configure the OkHttp client to trust all certificates: + +```java +import io.socket.client.IO; +import io.socket.client.Socket; +import io.socket.engineio.client.transports.WebTransport; +import io.socket.engineio.client.transports.WebSocket; +import io.socket.engineio.client.transports.Polling; +import okhttp3.OkHttpClient; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.net.URI; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; + +public class WebTransportDevelopmentExample { + public static void main(String[] args) throws Exception { + // Create trust-all SSL configuration (DEVELOPMENT ONLY!) + X509TrustManager trustAllCerts = new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } + public void checkClientTrusted(X509Certificate[] certs, String authType) {} + public void checkServerTrusted(X509Certificate[] certs, String authType) {} + }; + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, new TrustManager[]{trustAllCerts}, new SecureRandom()); + + OkHttpClient okHttpClient = new OkHttpClient.Builder() + .sslSocketFactory(sslContext.getSocketFactory(), trustAllCerts) + .hostnameVerifier((hostname, session) -> true) + .build(); + + IO.Options options = IO.Options.builder() + .setTransports(new String[] { WebTransport.NAME, WebSocket.NAME, Polling.NAME }) + .setCallFactory(okHttpClient) // For HTTP requests + .setWebSocketFactory(okHttpClient) // For WebSocket connections + .build(); + + Socket socket = IO.socket(URI.create("https://localhost:3000"), options); + + // Rest of your socket code... + socket.connect(); + } +} +``` + +## Advanced WebTransport Configuration + +```java +import io.socket.client.IO; +import io.socket.client.Socket; +import io.socket.client.SocketOptionBuilder; +import io.socket.engineio.client.transports.WebTransport; +import io.socket.engineio.client.transports.WebSocket; +import io.socket.engineio.client.transports.Polling; + +import java.net.URI; +import java.util.HashMap; + +public class AdvancedWebTransportExample { + public static void main(String[] args) { + + // Create Socket.IO options with advanced configuration + IO.Options options = SocketOptionBuilder.builder() + .setTransports(new String[] { WebTransport.NAME, "websocket", "polling" }) + .setReconnection(true) + .setReconnectionAttempts(5) + .setReconnectionDelay(2000) + .build(); + + // Configure WebTransport-specific options (advanced) + if (options.transportOptions == null) { + options.transportOptions = new HashMap<>(); + } + + io.socket.engineio.client.Transport.Options webTransportOptions = + new io.socket.engineio.client.Transport.Options(); + webTransportOptions.hostname = "example.com"; // Override hostname if needed + webTransportOptions.port = 443; // Override port if needed + webTransportOptions.secure = true; // WebTransport requires HTTPS + webTransportOptions.path = "/socket.io/"; // Socket.IO path + + options.transportOptions.put("webtransport", webTransportOptions); + + // Create socket connection + Socket socket = IO.socket(URI.create("https://example.com"), options); + + // Listen for transport events + socket.io().on(Manager.EVENT_TRANSPORT, new Emitter.Listener() { + @Override + public void call(Object... args) { + Transport transport = (Transport) args[0]; + System.out.println("Transport created: " + transport.getName()); + + // Listen for request headers + transport.on(Transport.EVENT_REQUEST_HEADERS, new Emitter.Listener() { + @Override + public void call(Object... args) { + @SuppressWarnings("unchecked") + Map> headers = + (Map>) args[0]; + System.out.println("Request headers: " + headers); + } + }); + + // Listen for response headers + transport.on(Transport.EVENT_RESPONSE_HEADERS, new Emitter.Listener() { + @Override + public void call(Object... args) { + @SuppressWarnings("unchecked") + Map> headers = + (Map>) args[0]; + System.out.println("Response headers: " + headers); + } + }); + } + }); + + // Set up application event listeners + socket.on("message", new Emitter.Listener() { + @Override + public void call(Object... args) { + System.out.println("Received message: " + args[0]); + } + }); + + socket.on("data", new Emitter.Listener() { + @Override + public void call(Object... args) { + System.out.println("Received data: " + args[0]); + } + }); + + // Connect to server + socket.connect(); + + // Send some test messages + socket.emit("message", "Hello from WebTransport client!"); + socket.emit("data", "Test data payload"); + } +} +``` + +## WebTransport-Only Configuration + +If you want to use only WebTransport (no fallback to other transports): + +```java +import io.socket.client.IO; +import io.socket.client.Socket; +import io.socket.client.SocketOptionBuilder; +import io.socket.engineio.client.transports.WebTransport; + +import java.net.URI; + +public class WebTransportOnlyExample { + public static void main(String[] args) { + // Create options with only WebTransport + IO.Options options = SocketOptionBuilder.builder() + .setTransports(new String[] { WebTransport.NAME }) + .build(); + + // Create socket connection + Socket socket = IO.socket(URI.create("https://localhost:3000"), options); + + socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() { + @Override + public void call(Object... args) { + System.out.println("Connected with WebTransport!"); + + // Verify we're using WebTransport + String transportName = socket.io().engine.transport.name; + if (WebTransport.NAME.equals(transportName)) { + System.out.println("Successfully using WebTransport"); + } else { + System.err.println("Expected WebTransport but got: " + transportName); + } + } + }); + + socket.on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener() { + @Override + public void call(Object... args) { + System.err.println("WebTransport connection failed: " + args[0]); + System.err.println("Make sure your server supports WebTransport and HTTP/3"); + } + }); + + // Connect to server + socket.connect(); + } +} +``` + +## Error Handling + +```java +import io.socket.client.IO; +import io.socket.client.Socket; +import io.socket.client.SocketOptionBuilder; +import io.socket.engineio.client.transports.WebTransport; + +import java.net.URI; + +public class WebTransportErrorHandling { + public static void main(String[] args) { + IO.Options options = SocketOptionBuilder.builder() + .setTransports(new String[] { WebTransport.NAME, "websocket", "polling" }) + .build(); + + Socket socket = IO.socket(URI.create("https://localhost:3000"), options); + + socket.on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener() { + @Override + public void call(Object... args) { + Exception error = (Exception) args[0]; + System.err.println("Connection error: " + error.getMessage()); + + // Check if it's a WebTransport-specific error + if (error.getMessage().contains("WebTransport") || + error.getMessage().contains("HTTP/3") || + error.getMessage().contains("QUIC")) { + System.err.println("WebTransport connection failed. Falling back to other transports."); + } + } + }); + + socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() { + @Override + public void call(Object... args) { + String reason = (String) args[0]; + System.out.println("Disconnected: " + reason); + + if ("transport error".equals(reason)) { + System.err.println("Transport error occurred. Check server WebTransport support."); + } + } + }); + + socket.connect(); + } +} +``` + +## Server Requirements + +To use WebTransport, your Socket.IO server must: + +1. **Support WebTransport**: Use Socket.IO server version 4.7.0 or higher +2. **Enable HTTP/3**: Configure your server to support HTTP/3 and QUIC +3. **Use HTTPS**: WebTransport requires secure connections + +### Node.js Server Example + +```javascript +const { Server } = require("socket.io"); +const { createServer } = require("https"); +const { readFileSync } = require("fs"); + +// Create HTTPS server +const httpsServer = createServer({ + key: readFileSync("key.pem"), + cert: readFileSync("cert.pem") +}); + +// Create Socket.IO server with WebTransport support +const io = new Server(httpsServer, { + transports: ["polling", "websocket", "webtransport"] +}); + +io.on("connection", (socket) => { + console.log(`Client connected with transport: ${socket.conn.transport.name}`); + + socket.on("message", (data) => { + console.log("Received:", data); + socket.emit("message", `Echo: ${data}`); + }); +}); + +httpsServer.listen(3000, () => { + console.log("Server listening on https://localhost:3000"); +}); +``` + +## Troubleshooting + +### Common Issues + +1. **"WebTransport not supported"**: Ensure your server supports WebTransport (Socket.IO 4.7.0+) +2. **"HTTP/3 not available"**: Check that your server has HTTP/3 enabled +3. **"Connection timeout"**: Increase `webTransportConnectTimeout` or check network connectivity +4. **"SSL/TLS errors"**: Verify SSL certificates or set `webTransportTrustAllCertificates(true)` for development + +### Debugging + +Enable debug logging to troubleshoot WebTransport issues: + +```java +import java.util.logging.Logger; +import java.util.logging.Level; + +// Enable debug logging +Logger.getLogger("io.socket.client").setLevel(Level.FINE); +Logger.getLogger("io.socket.client.WebTransport").setLevel(Level.FINE); +``` + +## Performance Benefits + +WebTransport provides several advantages over traditional WebSocket connections: + +- **Reduced latency**: QUIC protocol reduces connection establishment time +- **Better multiplexing**: Multiple streams without head-of-line blocking +- **Improved reliability**: Better handling of network conditions and packet loss +- **Modern protocol**: Built on HTTP/3 and QUIC standards + +For applications requiring real-time communication with high performance requirements, WebTransport can provide significant improvements over traditional WebSocket connections. diff --git a/src/test/resources/package-lock.json b/src/test/resources/package-lock.json index 929d9591..da92918b 100644 --- a/src/test/resources/package-lock.json +++ b/src/test/resources/package-lock.json @@ -1,78 +1,100 @@ { + "name": "resources", + "lockfileVersion": 3, "requires": true, - "lockfileVersion": 1, - "dependencies": { - "@types/component-emitter": { + "packages": { + "": { + "dependencies": { + "socket.io": "^3.0.4" + } + }, + "node_modules/@types/component-emitter": { "version": "1.2.10", "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz", "integrity": "sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg==" }, - "@types/cookie": { + "node_modules/@types/cookie": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.0.tgz", "integrity": "sha512-y7mImlc/rNkvCRmg8gC3/lj87S7pTUIJ6QGjwHR9WQJcFs+ZMTOaoPrkdFA/YdbuqVEmEbb5RdhVxMkAcgOnpg==" }, - "@types/cors": { + "node_modules/@types/cors": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.9.tgz", "integrity": "sha512-zurD1ibz21BRlAOIKP8yhrxlqKx6L9VCwkB5kMiP6nZAhoF5MvC7qS1qPA7nRcr1GJolfkQC7/EAL4hdYejLtg==" }, - "@types/node": { + "node_modules/@types/node": { "version": "14.14.12", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.12.tgz", "integrity": "sha512-ASH8OPHMNlkdjrEdmoILmzFfsJICvhBsFfAum4aKZ/9U4B6M6tTmTPh+f3ttWdD74CEGV5XvXWkbyfSdXaTd7g==" }, - "accepts": { + "node_modules/accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { + "dependencies": { "mime-types": "~2.1.24", "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" } }, - "base64-arraybuffer": { + "node_modules/base64-arraybuffer": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", - "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" + "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=", + "engines": { + "node": ">= 0.6.0" + } }, - "base64id": { + "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } }, - "component-emitter": { + "node_modules/component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, - "cookie": { + "node_modules/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } }, - "cors": { + "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "requires": { + "dependencies": { "object-assign": "^4", "vary": "^1" + }, + "engines": { + "node": ">= 0.10" } }, - "debug": { + "node_modules/debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dependencies": { "ms": "^2.1.1" } }, - "engine.io": { + "node_modules/engine.io": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-4.0.5.tgz", "integrity": "sha512-Ri+whTNr2PKklxQkfbGjwEo+kCBUM4Qxk4wtLqLrhH+b1up2NFL9g9pjYWiCV/oazwB0rArnvF/ZmZN2ab5Hpg==", - "requires": { + "dependencies": { "accepts": "~1.3.4", "base64id": "2.0.0", "cookie": "~0.4.1", @@ -80,49 +102,67 @@ "debug": "~4.1.0", "engine.io-parser": "~4.0.0", "ws": "^7.1.2" + }, + "engines": { + "node": ">=10.0.0" } }, - "engine.io-parser": { + "node_modules/engine.io-parser": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.2.tgz", "integrity": "sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/MqJdZbUjW97JU72iYg==", - "requires": { + "dependencies": { "base64-arraybuffer": "0.1.4" + }, + "engines": { + "node": ">=8.0.0" } }, - "mime-db": { + "node_modules/mime-db": { "version": "1.44.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "engines": { + "node": ">= 0.6" + } }, - "mime-types": { + "node_modules/mime-types": { "version": "2.1.27", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "requires": { + "dependencies": { "mime-db": "1.44.0" + }, + "engines": { + "node": ">= 0.6" } }, - "ms": { + "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "negotiator": { + "node_modules/negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } }, - "object-assign": { + "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } }, - "socket.io": { + "node_modules/socket.io": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-3.0.4.tgz", "integrity": "sha512-Vj1jUoO75WGc9txWd311ZJJqS9Dr8QtNJJ7gk2r7dcM/yGe9sit7qOijQl3GAwhpBOz/W8CwkD7R6yob07nLbA==", - "requires": { + "dependencies": { "@types/cookie": "^0.4.0", "@types/cors": "^2.8.8", "@types/node": "^14.14.7", @@ -132,32 +172,56 @@ "engine.io": "~4.0.0", "socket.io-adapter": "~2.0.3", "socket.io-parser": "~4.0.1" + }, + "engines": { + "node": ">=10.0.0" } }, - "socket.io-adapter": { + "node_modules/socket.io-adapter": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.0.3.tgz", "integrity": "sha512-2wo4EXgxOGSFueqvHAdnmi5JLZzWqMArjuP4nqC26AtLh5PoCPsaRbRdah2xhcwTAMooZfjYiNVNkkmmSMaxOQ==" }, - "socket.io-parser": { + "node_modules/socket.io-parser": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.2.tgz", "integrity": "sha512-Bs3IYHDivwf+bAAuW/8xwJgIiBNtlvnjYRc4PbXgniLmcP1BrakBoq/QhO24rgtgW7VZ7uAaswRGxutUnlAK7g==", - "requires": { + "dependencies": { "@types/component-emitter": "^1.2.10", "component-emitter": "~1.3.0", "debug": "~4.1.0" + }, + "engines": { + "node": ">=10.0.0" } }, - "vary": { + "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } }, - "ws": { + "node_modules/ws": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", - "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==" + "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } } } }