2134
									
								
								packages/polyfill/src/buffer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2134
									
								
								packages/polyfill/src/buffer.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -12,6 +12,7 @@ import 'core-js'
 | 
			
		||||
process.on('exit', () => require.disable())
 | 
			
		||||
global.setGlobal('Proxy', require('./proxy').Proxy)
 | 
			
		||||
global.setGlobal('XMLHttpRequest', require('./xml-http-request').XMLHttpRequest)
 | 
			
		||||
global.setGlobal('Buffer', require('./buffer').Buffer)
 | 
			
		||||
global.setGlobal('Blob', require('blob-polyfill').Blob)
 | 
			
		||||
console.i18n("ms.polyfill.completed", { time: (new Date().getTime() - polyfillStartTime) / 1000 })
 | 
			
		||||
export default true
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@
 | 
			
		||||
        "test": "echo \"Error: run tests from root\" && exit 1"
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@socket.io/component-emitter": "^3.1.0",
 | 
			
		||||
        "backo2": "^1.0.2",
 | 
			
		||||
        "parseuri": "^0.0.6"
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ export class WebSocket extends EventEmitter {
 | 
			
		||||
 | 
			
		||||
    private client: Transport
 | 
			
		||||
 | 
			
		||||
    constructor(url: string, subProtocol: string = '', headers: WebSocketHeader = {}) {
 | 
			
		||||
    constructor(url: string, subProtocol: string | string[] = '', headers: WebSocketHeader = {}) {
 | 
			
		||||
        super()
 | 
			
		||||
        this.manager = manager
 | 
			
		||||
        this._url = url
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1,54 @@
 | 
			
		||||
export = (namepsace) => (...args) => { }//console.debug(namepsace, ...args)
 | 
			
		||||
export = (namepsace) => (...args) => { console.trace(`[${namepsace}] ` + format(...args)) }//console.debug(namepsace, ...args)
 | 
			
		||||
let formatters: any = {}
 | 
			
		||||
formatters.s = function (v) {
 | 
			
		||||
    return v
 | 
			
		||||
}
 | 
			
		||||
formatters.j = function (v) {
 | 
			
		||||
    try {
 | 
			
		||||
        return JSON.stringify(v)
 | 
			
		||||
    } catch (error: any) {
 | 
			
		||||
        return '[UnexpectedJSONParseError]: ' + error.message
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
* Coerce `val`.
 | 
			
		||||
*
 | 
			
		||||
* @param {Mixed} val
 | 
			
		||||
* @return {Mixed}
 | 
			
		||||
* @api private
 | 
			
		||||
*/
 | 
			
		||||
function coerce(val) {
 | 
			
		||||
    if (val instanceof Error) {
 | 
			
		||||
        return val.stack || val.message
 | 
			
		||||
    }
 | 
			
		||||
    return val
 | 
			
		||||
}
 | 
			
		||||
function format(...args) {
 | 
			
		||||
    // Apply any `formatters` transformations
 | 
			
		||||
    args[0] = coerce(args[0])
 | 
			
		||||
 | 
			
		||||
    if (typeof args[0] !== 'string') {
 | 
			
		||||
        // Anything else let's inspect with %O
 | 
			
		||||
        args.unshift('%O')
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let index = 0
 | 
			
		||||
    args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
 | 
			
		||||
        // If we encounter an escaped % then don't increase the array index
 | 
			
		||||
        if (match === '%%') {
 | 
			
		||||
            return '%'
 | 
			
		||||
        }
 | 
			
		||||
        index++
 | 
			
		||||
        const formatter = formatters[format]
 | 
			
		||||
        if (typeof formatter === 'function') {
 | 
			
		||||
            const val = args[index]
 | 
			
		||||
            match = formatter.call(format, val)
 | 
			
		||||
 | 
			
		||||
            // Now we need to remove `args[index]` since it's inlined in the `format`
 | 
			
		||||
            args.splice(index, 1)
 | 
			
		||||
            index--
 | 
			
		||||
        }
 | 
			
		||||
        return match
 | 
			
		||||
    })
 | 
			
		||||
    return args[0]
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								packages/websocket/src/engine.io-client/contrib/has-cors.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								packages/websocket/src/engine.io-client/contrib/has-cors.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
// imported from https://github.com/component/has-cors
 | 
			
		||||
let value = false;
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
    value = typeof XMLHttpRequest !== 'undefined' &&
 | 
			
		||||
        'withCredentials' in new XMLHttpRequest();
 | 
			
		||||
} catch (err) {
 | 
			
		||||
    // if XMLHttp support is disabled in IE then it will throw
 | 
			
		||||
    // when trying to create
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const hasCORS = value;
 | 
			
		||||
							
								
								
									
										38
									
								
								packages/websocket/src/engine.io-client/contrib/parseqs.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								packages/websocket/src/engine.io-client/contrib/parseqs.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
// imported from https://github.com/galkn/querystring
 | 
			
		||||
/**
 | 
			
		||||
 * Compiles a querystring
 | 
			
		||||
 * Returns string representation of the object
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Object}
 | 
			
		||||
 * @api private
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export function encode(obj) {
 | 
			
		||||
    let str = ''
 | 
			
		||||
 | 
			
		||||
    for (let i in obj) {
 | 
			
		||||
        if (obj.hasOwnProperty(i)) {
 | 
			
		||||
            if (str.length) str += '&'
 | 
			
		||||
            str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i])
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return str
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Parses a simple querystring into an object
 | 
			
		||||
 *
 | 
			
		||||
 * @param {String} qs
 | 
			
		||||
 * @api private
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export function decode(qs) {
 | 
			
		||||
    let qry = {}
 | 
			
		||||
    let pairs = qs.split('&')
 | 
			
		||||
    for (let i = 0, l = pairs.length; i < l; i++) {
 | 
			
		||||
        let pair = pairs[i].split('=')
 | 
			
		||||
        qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1])
 | 
			
		||||
    }
 | 
			
		||||
    return qry
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								packages/websocket/src/engine.io-client/contrib/parseuri.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								packages/websocket/src/engine.io-client/contrib/parseuri.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
// imported from https://github.com/galkn/parseuri
 | 
			
		||||
/**
 | 
			
		||||
 * Parses an URI
 | 
			
		||||
 *
 | 
			
		||||
 * @author Steven Levithan <stevenlevithan.com> (MIT license)
 | 
			
		||||
 * @api private
 | 
			
		||||
 */
 | 
			
		||||
const re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
 | 
			
		||||
 | 
			
		||||
const parts = [
 | 
			
		||||
    'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
export function parse(str) {
 | 
			
		||||
    const src = str,
 | 
			
		||||
        b = str.indexOf('['),
 | 
			
		||||
        e = str.indexOf(']')
 | 
			
		||||
 | 
			
		||||
    if (b != -1 && e != -1) {
 | 
			
		||||
        str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let m = re.exec(str || ''),
 | 
			
		||||
        uri = {} as any,
 | 
			
		||||
        i = 14
 | 
			
		||||
 | 
			
		||||
    while (i--) {
 | 
			
		||||
        uri[parts[i]] = m[i] || ''
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (b != -1 && e != -1) {
 | 
			
		||||
        uri.source = src
 | 
			
		||||
        uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':')
 | 
			
		||||
        uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':')
 | 
			
		||||
        uri.ipv6uri = true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uri.pathNames = pathNames(uri, uri['path'])
 | 
			
		||||
    uri.queryKey = queryKey(uri, uri['query'])
 | 
			
		||||
 | 
			
		||||
    return uri
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function pathNames(obj, path) {
 | 
			
		||||
    const regx = /\/{2,9}/g,
 | 
			
		||||
        names = path.replace(regx, "/").split("/")
 | 
			
		||||
 | 
			
		||||
    if (path.slice(0, 1) == '/' || path.length === 0) {
 | 
			
		||||
        names.splice(0, 1)
 | 
			
		||||
    }
 | 
			
		||||
    if (path.slice(-1) == '/') {
 | 
			
		||||
        names.splice(names.length - 1, 1)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return names
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function queryKey(uri, query) {
 | 
			
		||||
    const data = {}
 | 
			
		||||
 | 
			
		||||
    query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g, function ($0, $1, $2) {
 | 
			
		||||
        if ($1) {
 | 
			
		||||
            data[$1] = $2
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    return data
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										62
									
								
								packages/websocket/src/engine.io-client/contrib/yeast.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								packages/websocket/src/engine.io-client/contrib/yeast.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
			
		||||
// imported from https://github.com/unshiftio/yeast
 | 
			
		||||
'use strict'
 | 
			
		||||
 | 
			
		||||
const alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'.split('')
 | 
			
		||||
    , length = 64
 | 
			
		||||
    , map = {}
 | 
			
		||||
let seed = 0
 | 
			
		||||
    , i = 0
 | 
			
		||||
    , prev
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Return a string representing the specified number.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Number} num The number to convert.
 | 
			
		||||
 * @returns {String} The string representation of the number.
 | 
			
		||||
 * @api public
 | 
			
		||||
 */
 | 
			
		||||
export function encode(num) {
 | 
			
		||||
    let encoded = ''
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        encoded = alphabet[num % length] + encoded
 | 
			
		||||
        num = Math.floor(num / length)
 | 
			
		||||
    } while (num > 0)
 | 
			
		||||
 | 
			
		||||
    return encoded
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Return the integer value specified by the given string.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {String} str The string to convert.
 | 
			
		||||
 * @returns {Number} The integer value represented by the string.
 | 
			
		||||
 * @api public
 | 
			
		||||
 */
 | 
			
		||||
export function decode(str) {
 | 
			
		||||
    let decoded = 0
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < str.length; i++) {
 | 
			
		||||
        decoded = decoded * length + map[str.charAt(i)]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return decoded
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Yeast: A tiny growing id generator.
 | 
			
		||||
 *
 | 
			
		||||
 * @returns {String} A unique id.
 | 
			
		||||
 * @api public
 | 
			
		||||
 */
 | 
			
		||||
export function yeast() {
 | 
			
		||||
    const now = encode(+new Date())
 | 
			
		||||
 | 
			
		||||
    if (now !== prev) return seed = 0, prev = now
 | 
			
		||||
    return now + '.' + encode(seed++)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Map each character to its index.
 | 
			
		||||
//
 | 
			
		||||
for (; i < length; i++) map[alphabet[i]] = i
 | 
			
		||||
@@ -1,16 +1,10 @@
 | 
			
		||||
import { Socket } from './socket'
 | 
			
		||||
import { Socket } from "./socket"
 | 
			
		||||
 | 
			
		||||
export default (uri, opts) => new Socket(uri, opts)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Expose deps for legacy compatibility
 | 
			
		||||
 * and standalone browser access.
 | 
			
		||||
 */
 | 
			
		||||
const protocol = Socket.protocol // this is an int
 | 
			
		||||
export { Socket, protocol }
 | 
			
		||||
// module.exports.Transport = require("./transport")
 | 
			
		||||
// module.exports.transports = require("./transports/index")
 | 
			
		||||
// module.exports.parser = require("../engine.io-parser")
 | 
			
		||||
export * from './transport'
 | 
			
		||||
export * from './transports/index'
 | 
			
		||||
export * from '../engine.io-parser'
 | 
			
		||||
export { Socket }
 | 
			
		||||
export { SocketOptions } from "./socket"
 | 
			
		||||
export const protocol = Socket.protocol
 | 
			
		||||
export { Transport } from "./transport"
 | 
			
		||||
export { transports } from "./transports/index"
 | 
			
		||||
export { installTimerFunctions } from "./util"
 | 
			
		||||
export { parse } from "./contrib/parseuri"
 | 
			
		||||
export { nextTick } from "./transports/websocket-constructor.js"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,21 +1,278 @@
 | 
			
		||||
import transports from "./transports"
 | 
			
		||||
// const transports = require("./transports/index")
 | 
			
		||||
const Emitter = require("component-emitter")
 | 
			
		||||
const debug = (...args: any) => console.debug('engine.io-client:socket', ...args)//require("debug")("engine.io-client:socket")
 | 
			
		||||
import parser from "../engine.io-parser"
 | 
			
		||||
const parseuri = require("parseuri")
 | 
			
		||||
const parseqs = require("parseqs")
 | 
			
		||||
import { installTimerFunctions } from "./util"
 | 
			
		||||
// import { transports } from "./transports/index.js";
 | 
			
		||||
import { transports } from "./transports"
 | 
			
		||||
import { installTimerFunctions, byteLength } from "./util"
 | 
			
		||||
import { decode } from "./contrib/parseqs"
 | 
			
		||||
import { parse } from "./contrib/parseuri"
 | 
			
		||||
// import debugModule from "debug"; // debug()
 | 
			
		||||
import { Emitter } from "@socket.io/component-emitter"
 | 
			
		||||
// import { protocol } from "engine.io-parser";
 | 
			
		||||
import { protocol } from "../engine.io-parser"
 | 
			
		||||
import { CloseDetails } from "./transport"
 | 
			
		||||
 | 
			
		||||
// const debug = debugModule("engine.io-client:socket"); // debug()
 | 
			
		||||
const debug = require('../debug')('engine.io-client:socket')
 | 
			
		||||
 | 
			
		||||
export interface SocketOptions {
 | 
			
		||||
    /**
 | 
			
		||||
     * The host that we're connecting to. Set from the URI passed when connecting
 | 
			
		||||
     */
 | 
			
		||||
    host: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The hostname for our connection. Set from the URI passed when connecting
 | 
			
		||||
     */
 | 
			
		||||
    hostname: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * If this is a secure connection. Set from the URI passed when connecting
 | 
			
		||||
     */
 | 
			
		||||
    secure: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The port for our connection. Set from the URI passed when connecting
 | 
			
		||||
     */
 | 
			
		||||
    port: string | number
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Any query parameters in our uri. Set from the URI passed when connecting
 | 
			
		||||
     */
 | 
			
		||||
    query: { [key: string]: any }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * `http.Agent` to use, defaults to `false` (NodeJS only)
 | 
			
		||||
     */
 | 
			
		||||
    agent: string | boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether the client should try to upgrade the transport from
 | 
			
		||||
     * long-polling to something better.
 | 
			
		||||
     * @default true
 | 
			
		||||
     */
 | 
			
		||||
    upgrade: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Forces base 64 encoding for polling transport even when XHR2
 | 
			
		||||
     * responseType is available and WebSocket even if the used standard
 | 
			
		||||
     * supports binary.
 | 
			
		||||
     */
 | 
			
		||||
    forceBase64: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The param name to use as our timestamp key
 | 
			
		||||
     * @default 't'
 | 
			
		||||
     */
 | 
			
		||||
    timestampParam: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether to add the timestamp with each transport request. Note: this
 | 
			
		||||
     * is ignored if the browser is IE or Android, in which case requests
 | 
			
		||||
     * are always stamped
 | 
			
		||||
     * @default false
 | 
			
		||||
     */
 | 
			
		||||
    timestampRequests: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A list of transports to try (in order). Engine.io always attempts to
 | 
			
		||||
     * connect directly with the first one, provided the feature detection test
 | 
			
		||||
     * for it passes.
 | 
			
		||||
     * @default ['polling','websocket']
 | 
			
		||||
     */
 | 
			
		||||
    transports: string[]
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The port the policy server listens on
 | 
			
		||||
     * @default 843
 | 
			
		||||
     */
 | 
			
		||||
    policyPost: number
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * If true and if the previous websocket connection to the server succeeded,
 | 
			
		||||
     * the connection attempt will bypass the normal upgrade process and will
 | 
			
		||||
     * initially try websocket. A connection attempt following a transport error
 | 
			
		||||
     * will use the normal upgrade process. It is recommended you turn this on
 | 
			
		||||
     * only when using SSL/TLS connections, or if you know that your network does
 | 
			
		||||
     * not block websockets.
 | 
			
		||||
     * @default false
 | 
			
		||||
     */
 | 
			
		||||
    rememberUpgrade: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Are we only interested in transports that support binary?
 | 
			
		||||
     */
 | 
			
		||||
    onlyBinaryUpgrades: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Timeout for xhr-polling requests in milliseconds (0) (only for polling transport)
 | 
			
		||||
     */
 | 
			
		||||
    requestTimeout: number
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Transport options for Node.js client (headers etc)
 | 
			
		||||
     */
 | 
			
		||||
    transportOptions: Object
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * (SSL) Certificate, Private key and CA certificates to use for SSL.
 | 
			
		||||
     * Can be used in Node.js client environment to manually specify
 | 
			
		||||
     * certificate information.
 | 
			
		||||
     */
 | 
			
		||||
    pfx: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * (SSL) Private key to use for SSL. Can be used in Node.js client
 | 
			
		||||
     * environment to manually specify certificate information.
 | 
			
		||||
     */
 | 
			
		||||
    key: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * (SSL) A string or passphrase for the private key or pfx. Can be
 | 
			
		||||
     * used in Node.js client environment to manually specify certificate
 | 
			
		||||
     * information.
 | 
			
		||||
     */
 | 
			
		||||
    passphrase: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * (SSL) Public x509 certificate to use. Can be used in Node.js client
 | 
			
		||||
     * environment to manually specify certificate information.
 | 
			
		||||
     */
 | 
			
		||||
    cert: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * (SSL) An authority certificate or array of authority certificates to
 | 
			
		||||
     * check the remote host against.. Can be used in Node.js client
 | 
			
		||||
     * environment to manually specify certificate information.
 | 
			
		||||
     */
 | 
			
		||||
    ca: string | string[]
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * (SSL) A string describing the ciphers to use or exclude. Consult the
 | 
			
		||||
     * [cipher format list]
 | 
			
		||||
     * (http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT) for
 | 
			
		||||
     * details on the format.. Can be used in Node.js client environment to
 | 
			
		||||
     * manually specify certificate information.
 | 
			
		||||
     */
 | 
			
		||||
    ciphers: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * (SSL) If true, the server certificate is verified against the list of
 | 
			
		||||
     * supplied CAs. An 'error' event is emitted if verification fails.
 | 
			
		||||
     * Verification happens at the connection level, before the HTTP request
 | 
			
		||||
     * is sent. Can be used in Node.js client environment to manually specify
 | 
			
		||||
     * certificate information.
 | 
			
		||||
     */
 | 
			
		||||
    rejectUnauthorized: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Headers that will be passed for each request to the server (via xhr-polling and via websockets).
 | 
			
		||||
     * These values then can be used during handshake or for special proxies.
 | 
			
		||||
     */
 | 
			
		||||
    extraHeaders?: { [header: string]: string }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether to include credentials (cookies, authorization headers, TLS
 | 
			
		||||
     * client certificates, etc.) with cross-origin XHR polling requests
 | 
			
		||||
     * @default false
 | 
			
		||||
     */
 | 
			
		||||
    withCredentials: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether to automatically close the connection whenever the beforeunload event is received.
 | 
			
		||||
     * @default true
 | 
			
		||||
     */
 | 
			
		||||
    closeOnBeforeunload: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether to always use the native timeouts. This allows the client to
 | 
			
		||||
     * reconnect when the native timeout functions are overridden, such as when
 | 
			
		||||
     * mock clocks are installed.
 | 
			
		||||
     * @default false
 | 
			
		||||
     */
 | 
			
		||||
    useNativeTimers: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * weather we should unref the reconnect timer when it is
 | 
			
		||||
     * create automatically
 | 
			
		||||
     * @default false
 | 
			
		||||
     */
 | 
			
		||||
    autoUnref: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * parameters of the WebSocket permessage-deflate extension (see ws module api docs). Set to false to disable.
 | 
			
		||||
     * @default false
 | 
			
		||||
     */
 | 
			
		||||
    perMessageDeflate: { threshold: number }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The path to get our client file from, in the case of the server
 | 
			
		||||
     * serving it
 | 
			
		||||
     * @default '/engine.io'
 | 
			
		||||
     */
 | 
			
		||||
    path: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Either a single protocol string or an array of protocol strings. These strings are used to indicate sub-protocols,
 | 
			
		||||
     * so that a single server can implement multiple WebSocket sub-protocols (for example, you might want one server to
 | 
			
		||||
     * be able to handle different types of interactions depending on the specified protocol)
 | 
			
		||||
     * @default []
 | 
			
		||||
     */
 | 
			
		||||
    protocols: string | string[]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface SocketReservedEvents {
 | 
			
		||||
    open: () => void
 | 
			
		||||
    handshake: (data) => void
 | 
			
		||||
    packet: (packet) => void
 | 
			
		||||
    packetCreate: (packet) => void
 | 
			
		||||
    data: (data) => void
 | 
			
		||||
    message: (data) => void
 | 
			
		||||
    drain: () => void
 | 
			
		||||
    flush: () => void
 | 
			
		||||
    heartbeat: () => void
 | 
			
		||||
    ping: () => void
 | 
			
		||||
    pong: () => void
 | 
			
		||||
    error: (err: string | Error) => void
 | 
			
		||||
    upgrading: (transport) => void
 | 
			
		||||
    upgrade: (transport) => void
 | 
			
		||||
    upgradeError: (err: Error) => void
 | 
			
		||||
    close: (reason: string, description?: CloseDetails | Error) => void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class Socket extends Emitter<{}, {}, SocketReservedEvents> {
 | 
			
		||||
    public id: string
 | 
			
		||||
    public transport: any
 | 
			
		||||
    public binaryType: string
 | 
			
		||||
 | 
			
		||||
    private readyState: string
 | 
			
		||||
    private writeBuffer
 | 
			
		||||
    private prevBufferLen: number
 | 
			
		||||
    private upgrades
 | 
			
		||||
    private pingInterval: number
 | 
			
		||||
    private pingTimeout: number
 | 
			
		||||
    private pingTimeoutTimer: NodeJS.Timer
 | 
			
		||||
    private setTimeoutFn: typeof setTimeout
 | 
			
		||||
    private clearTimeoutFn: typeof clearTimeout
 | 
			
		||||
    private readonly beforeunloadEventListener: () => void
 | 
			
		||||
    private readonly offlineEventListener: () => void
 | 
			
		||||
    private upgrading: boolean
 | 
			
		||||
    private maxPayload?: number
 | 
			
		||||
 | 
			
		||||
    private readonly opts: Partial<SocketOptions>
 | 
			
		||||
    private readonly secure: boolean
 | 
			
		||||
    private readonly hostname: string
 | 
			
		||||
    private readonly port: string | number
 | 
			
		||||
    private readonly transports: string[]
 | 
			
		||||
 | 
			
		||||
    static priorWebsocketSuccess: boolean
 | 
			
		||||
    static protocol = protocol;
 | 
			
		||||
 | 
			
		||||
export class Socket extends Emitter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Socket constructor.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String|Object} uri or options
 | 
			
		||||
     * @param {Object} options
 | 
			
		||||
     * @param {Object} opts - options
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    constructor(uri, opts: any = {}) {
 | 
			
		||||
    constructor(uri, opts: Partial<SocketOptions> = {}) {
 | 
			
		||||
        super()
 | 
			
		||||
 | 
			
		||||
        if (uri && "object" === typeof uri) {
 | 
			
		||||
@@ -24,13 +281,13 @@ export class Socket extends Emitter {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (uri) {
 | 
			
		||||
            uri = parseuri(uri)
 | 
			
		||||
            uri = parse(uri)
 | 
			
		||||
            opts.hostname = uri.host
 | 
			
		||||
            opts.secure = uri.protocol === "https" || uri.protocol === "wss"
 | 
			
		||||
            opts.port = uri.port
 | 
			
		||||
            if (uri.query) opts.query = uri.query
 | 
			
		||||
        } else if (opts.host) {
 | 
			
		||||
            opts.hostname = parseuri(opts.host).host
 | 
			
		||||
            opts.hostname = parse(opts.host).host
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        installTimerFunctions(this, opts)
 | 
			
		||||
@@ -53,10 +310,10 @@ export class Socket extends Emitter {
 | 
			
		||||
            (typeof location !== "undefined" && location.port
 | 
			
		||||
                ? location.port
 | 
			
		||||
                : this.secure
 | 
			
		||||
                    ? 443
 | 
			
		||||
                    : 80)
 | 
			
		||||
                    ? "443"
 | 
			
		||||
                    : "80")
 | 
			
		||||
 | 
			
		||||
        this.transports = ["websocket"]
 | 
			
		||||
        this.transports = opts.transports || ["polling", "websocket"]
 | 
			
		||||
        this.readyState = ""
 | 
			
		||||
        this.writeBuffer = []
 | 
			
		||||
        this.prevBufferLen = 0
 | 
			
		||||
@@ -67,7 +324,6 @@ export class Socket extends Emitter {
 | 
			
		||||
                agent: false,
 | 
			
		||||
                withCredentials: false,
 | 
			
		||||
                upgrade: true,
 | 
			
		||||
                jsonp: true,
 | 
			
		||||
                timestampParam: "t",
 | 
			
		||||
                rememberUpgrade: false,
 | 
			
		||||
                rejectUnauthorized: true,
 | 
			
		||||
@@ -83,7 +339,7 @@ export class Socket extends Emitter {
 | 
			
		||||
        this.opts.path = this.opts.path.replace(/\/$/, "") + "/"
 | 
			
		||||
 | 
			
		||||
        if (typeof this.opts.query === "string") {
 | 
			
		||||
            this.opts.query = parseqs.decode(this.opts.query)
 | 
			
		||||
            this.opts.query = decode(this.opts.query)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // set on handshake
 | 
			
		||||
@@ -100,21 +356,20 @@ export class Socket extends Emitter {
 | 
			
		||||
                // Firefox closes the connection when the "beforeunload" event is emitted but not Chrome. This event listener
 | 
			
		||||
                // ensures every browser behaves the same (no "disconnect" event at the Socket.IO level when the page is
 | 
			
		||||
                // closed/reloaded)
 | 
			
		||||
                addEventListener(
 | 
			
		||||
                    "beforeunload",
 | 
			
		||||
                    () => {
 | 
			
		||||
                        if (this.transport) {
 | 
			
		||||
                            // silently close the transport
 | 
			
		||||
                            this.transport.removeAllListeners()
 | 
			
		||||
                            this.transport.close()
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    false
 | 
			
		||||
                )
 | 
			
		||||
                this.beforeunloadEventListener = () => {
 | 
			
		||||
                    if (this.transport) {
 | 
			
		||||
                        // silently close the transport
 | 
			
		||||
                        this.transport.removeAllListeners()
 | 
			
		||||
                        this.transport.close()
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                addEventListener("beforeunload", this.beforeunloadEventListener, false)
 | 
			
		||||
            }
 | 
			
		||||
            if (this.hostname !== "localhost") {
 | 
			
		||||
                this.offlineEventListener = () => {
 | 
			
		||||
                    this.onClose("transport close")
 | 
			
		||||
                    this.onClose("transport close", {
 | 
			
		||||
                        description: "network connection lost"
 | 
			
		||||
                    })
 | 
			
		||||
                }
 | 
			
		||||
                addEventListener("offline", this.offlineEventListener, false)
 | 
			
		||||
            }
 | 
			
		||||
@@ -130,15 +385,12 @@ export class Socket extends Emitter {
 | 
			
		||||
     * @return {Transport}
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    createTransport(name, opt?) {
 | 
			
		||||
        if (name != 'websocket') {
 | 
			
		||||
            throw new Error('Only Support WebSocket in MiaoScript!')
 | 
			
		||||
        }
 | 
			
		||||
    private createTransport(name) {
 | 
			
		||||
        debug('creating transport "%s"', name)
 | 
			
		||||
        const query: any = clone(this.opts.query)
 | 
			
		||||
        const query: any = Object.assign({}, this.opts.query)
 | 
			
		||||
 | 
			
		||||
        // append engine.io protocol identifier
 | 
			
		||||
        query.EIO = parser.protocol
 | 
			
		||||
        query.EIO = protocol
 | 
			
		||||
 | 
			
		||||
        // transport name
 | 
			
		||||
        query.transport = name
 | 
			
		||||
@@ -159,8 +411,8 @@ export class Socket extends Emitter {
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        debug("options: %j", JSON.stringify(opts))
 | 
			
		||||
        debug("new func", transports[name])
 | 
			
		||||
        debug("options: %j", opts)
 | 
			
		||||
 | 
			
		||||
        return new transports[name](opts)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -169,7 +421,7 @@ export class Socket extends Emitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    open() {
 | 
			
		||||
    private open() {
 | 
			
		||||
        let transport
 | 
			
		||||
        if (
 | 
			
		||||
            this.opts.rememberUpgrade &&
 | 
			
		||||
@@ -180,7 +432,7 @@ export class Socket extends Emitter {
 | 
			
		||||
        } else if (0 === this.transports.length) {
 | 
			
		||||
            // Emit error on next tick so it can be listened to
 | 
			
		||||
            this.setTimeoutFn(() => {
 | 
			
		||||
                this.emit("error", "No transports available")
 | 
			
		||||
                this.emitReserved("error", "No transports available")
 | 
			
		||||
            }, 0)
 | 
			
		||||
            return
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -191,8 +443,8 @@ export class Socket extends Emitter {
 | 
			
		||||
        // Retry with the next transport if the transport is disabled (jsonp: false)
 | 
			
		||||
        try {
 | 
			
		||||
            transport = this.createTransport(transport)
 | 
			
		||||
        } catch (error: any) {
 | 
			
		||||
            debug("error while creating transport: %s", error)
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            debug("error while creating transport: %s", e)
 | 
			
		||||
            this.transports.shift()
 | 
			
		||||
            this.open()
 | 
			
		||||
            return
 | 
			
		||||
@@ -207,7 +459,7 @@ export class Socket extends Emitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    setTransport(transport) {
 | 
			
		||||
    private setTransport(transport) {
 | 
			
		||||
        debug("setting transport %s", transport.name)
 | 
			
		||||
 | 
			
		||||
        if (this.transport) {
 | 
			
		||||
@@ -223,9 +475,7 @@ export class Socket extends Emitter {
 | 
			
		||||
            .on("drain", this.onDrain.bind(this))
 | 
			
		||||
            .on("packet", this.onPacket.bind(this))
 | 
			
		||||
            .on("error", this.onError.bind(this))
 | 
			
		||||
            .on("close", () => {
 | 
			
		||||
                this.onClose("transport close")
 | 
			
		||||
            })
 | 
			
		||||
            .on("close", reason => this.onClose("transport close", reason))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -234,9 +484,9 @@ export class Socket extends Emitter {
 | 
			
		||||
     * @param {String} transport name
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    probe(name) {
 | 
			
		||||
    private probe(name) {
 | 
			
		||||
        debug('probing transport "%s"', name)
 | 
			
		||||
        let transport = this.createTransport(name, { probe: 1 })
 | 
			
		||||
        let transport = this.createTransport(name)
 | 
			
		||||
        let failed = false
 | 
			
		||||
 | 
			
		||||
        Socket.priorWebsocketSuccess = false
 | 
			
		||||
@@ -251,7 +501,7 @@ export class Socket extends Emitter {
 | 
			
		||||
                if ("pong" === msg.type && "probe" === msg.data) {
 | 
			
		||||
                    debug('probe transport "%s" pong', name)
 | 
			
		||||
                    this.upgrading = true
 | 
			
		||||
                    this.emit("upgrading", transport)
 | 
			
		||||
                    this.emitReserved("upgrading", transport)
 | 
			
		||||
                    if (!transport) return
 | 
			
		||||
                    Socket.priorWebsocketSuccess = "websocket" === transport.name
 | 
			
		||||
 | 
			
		||||
@@ -265,16 +515,17 @@ export class Socket extends Emitter {
 | 
			
		||||
 | 
			
		||||
                        this.setTransport(transport)
 | 
			
		||||
                        transport.send([{ type: "upgrade" }])
 | 
			
		||||
                        this.emit("upgrade", transport)
 | 
			
		||||
                        this.emitReserved("upgrade", transport)
 | 
			
		||||
                        transport = null
 | 
			
		||||
                        this.upgrading = false
 | 
			
		||||
                        this.flush()
 | 
			
		||||
                    })
 | 
			
		||||
                } else {
 | 
			
		||||
                    debug('probe transport "%s" failed', name)
 | 
			
		||||
                    const err: any = new Error("probe error")
 | 
			
		||||
                    const err = new Error("probe error")
 | 
			
		||||
                    // @ts-ignore
 | 
			
		||||
                    err.transport = transport.name
 | 
			
		||||
                    this.emit("upgradeError", err)
 | 
			
		||||
                    this.emitReserved("upgradeError", err)
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
@@ -293,14 +544,15 @@ export class Socket extends Emitter {
 | 
			
		||||
 | 
			
		||||
        // Handle any error that happens while probing
 | 
			
		||||
        const onerror = err => {
 | 
			
		||||
            const error: any = new Error("probe error: " + err)
 | 
			
		||||
            const error = new Error("probe error: " + err)
 | 
			
		||||
            // @ts-ignore
 | 
			
		||||
            error.transport = transport.name
 | 
			
		||||
 | 
			
		||||
            freezeTransport()
 | 
			
		||||
 | 
			
		||||
            debug('probe transport "%s" failed because of error: %s', name, err)
 | 
			
		||||
 | 
			
		||||
            this.emit("upgradeError", error)
 | 
			
		||||
            this.emitReserved("upgradeError", error)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function onTransportClose() {
 | 
			
		||||
@@ -325,8 +577,8 @@ export class Socket extends Emitter {
 | 
			
		||||
            transport.removeListener("open", onTransportOpen)
 | 
			
		||||
            transport.removeListener("error", onerror)
 | 
			
		||||
            transport.removeListener("close", onTransportClose)
 | 
			
		||||
            this.removeListener("close", onclose)
 | 
			
		||||
            this.removeListener("upgrading", onupgrade)
 | 
			
		||||
            this.off("close", onclose)
 | 
			
		||||
            this.off("upgrading", onupgrade)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        transport.once("open", onTransportOpen)
 | 
			
		||||
@@ -342,13 +594,13 @@ export class Socket extends Emitter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Called when connection is deemed open.
 | 
			
		||||
     *
 | 
			
		||||
     * @api public
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    onOpen() {
 | 
			
		||||
    private onOpen() {
 | 
			
		||||
        debug("socket open")
 | 
			
		||||
        this.readyState = "open"
 | 
			
		||||
        Socket.priorWebsocketSuccess = "websocket" === this.transport.name
 | 
			
		||||
        this.emit("open")
 | 
			
		||||
        this.emitReserved("open")
 | 
			
		||||
        this.flush()
 | 
			
		||||
 | 
			
		||||
        // we check for `readyState` in case an `open`
 | 
			
		||||
@@ -372,7 +624,7 @@ export class Socket extends Emitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    onPacket(packet) {
 | 
			
		||||
    private onPacket(packet) {
 | 
			
		||||
        if (
 | 
			
		||||
            "opening" === this.readyState ||
 | 
			
		||||
            "open" === this.readyState ||
 | 
			
		||||
@@ -380,10 +632,10 @@ export class Socket extends Emitter {
 | 
			
		||||
        ) {
 | 
			
		||||
            debug('socket receive: type "%s", data "%s"', packet.type, packet.data)
 | 
			
		||||
 | 
			
		||||
            this.emit("packet", packet)
 | 
			
		||||
            this.emitReserved("packet", packet)
 | 
			
		||||
 | 
			
		||||
            // Socket is live - any packet counts
 | 
			
		||||
            this.emit("heartbeat")
 | 
			
		||||
            this.emitReserved("heartbeat")
 | 
			
		||||
 | 
			
		||||
            switch (packet.type) {
 | 
			
		||||
                case "open":
 | 
			
		||||
@@ -393,19 +645,20 @@ export class Socket extends Emitter {
 | 
			
		||||
                case "ping":
 | 
			
		||||
                    this.resetPingTimeout()
 | 
			
		||||
                    this.sendPacket("pong")
 | 
			
		||||
                    this.emit("ping")
 | 
			
		||||
                    this.emit("pong")
 | 
			
		||||
                    this.emitReserved("ping")
 | 
			
		||||
                    this.emitReserved("pong")
 | 
			
		||||
                    break
 | 
			
		||||
 | 
			
		||||
                case "error":
 | 
			
		||||
                    const err: any = new Error("server error")
 | 
			
		||||
                    const err = new Error("server error")
 | 
			
		||||
                    // @ts-ignore
 | 
			
		||||
                    err.code = packet.data
 | 
			
		||||
                    this.onError(err)
 | 
			
		||||
                    break
 | 
			
		||||
 | 
			
		||||
                case "message":
 | 
			
		||||
                    this.emit("data", packet.data)
 | 
			
		||||
                    this.emit("message", packet.data)
 | 
			
		||||
                    this.emitReserved("data", packet.data)
 | 
			
		||||
                    this.emitReserved("message", packet.data)
 | 
			
		||||
                    break
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -416,16 +669,17 @@ export class Socket extends Emitter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Called upon handshake completion.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Object} handshake obj
 | 
			
		||||
     * @param {Object} data - handshake obj
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    onHandshake(data) {
 | 
			
		||||
        this.emit("handshake", data)
 | 
			
		||||
    private onHandshake(data) {
 | 
			
		||||
        this.emitReserved("handshake", data)
 | 
			
		||||
        this.id = data.sid
 | 
			
		||||
        this.transport.query.sid = data.sid
 | 
			
		||||
        this.upgrades = this.filterUpgrades(data.upgrades)
 | 
			
		||||
        this.pingInterval = data.pingInterval
 | 
			
		||||
        this.pingTimeout = data.pingTimeout
 | 
			
		||||
        this.maxPayload = data.maxPayload
 | 
			
		||||
        this.onOpen()
 | 
			
		||||
        // In case open handler closes socket
 | 
			
		||||
        if ("closed" === this.readyState) return
 | 
			
		||||
@@ -437,7 +691,7 @@ export class Socket extends Emitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    resetPingTimeout() {
 | 
			
		||||
    private resetPingTimeout() {
 | 
			
		||||
        this.clearTimeoutFn(this.pingTimeoutTimer)
 | 
			
		||||
        this.pingTimeoutTimer = this.setTimeoutFn(() => {
 | 
			
		||||
            this.onClose("ping timeout")
 | 
			
		||||
@@ -452,7 +706,7 @@ export class Socket extends Emitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    onDrain() {
 | 
			
		||||
    private onDrain() {
 | 
			
		||||
        this.writeBuffer.splice(0, this.prevBufferLen)
 | 
			
		||||
 | 
			
		||||
        // setting prevBufferLen = 0 is very important
 | 
			
		||||
@@ -461,7 +715,7 @@ export class Socket extends Emitter {
 | 
			
		||||
        this.prevBufferLen = 0
 | 
			
		||||
 | 
			
		||||
        if (0 === this.writeBuffer.length) {
 | 
			
		||||
            this.emit("drain")
 | 
			
		||||
            this.emitReserved("drain")
 | 
			
		||||
        } else {
 | 
			
		||||
            this.flush()
 | 
			
		||||
        }
 | 
			
		||||
@@ -472,22 +726,53 @@ export class Socket extends Emitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    flush() {
 | 
			
		||||
    private flush() {
 | 
			
		||||
        if (
 | 
			
		||||
            "closed" !== this.readyState &&
 | 
			
		||||
            this.transport.writable &&
 | 
			
		||||
            !this.upgrading &&
 | 
			
		||||
            this.writeBuffer.length
 | 
			
		||||
        ) {
 | 
			
		||||
            debug("flushing %d packets in socket", this.writeBuffer.length)
 | 
			
		||||
            this.transport.send(this.writeBuffer)
 | 
			
		||||
            const packets = this.getWritablePackets()
 | 
			
		||||
            debug("flushing %d packets in socket", packets.length)
 | 
			
		||||
            this.transport.send(packets)
 | 
			
		||||
            // keep track of current length of writeBuffer
 | 
			
		||||
            // splice writeBuffer and callbackBuffer on `drain`
 | 
			
		||||
            this.prevBufferLen = this.writeBuffer.length
 | 
			
		||||
            this.emit("flush")
 | 
			
		||||
            this.prevBufferLen = packets.length
 | 
			
		||||
            this.emitReserved("flush")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Ensure the encoded size of the writeBuffer is below the maxPayload value sent by the server (only for HTTP
 | 
			
		||||
     * long-polling)
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private getWritablePackets() {
 | 
			
		||||
        const shouldCheckPayloadSize =
 | 
			
		||||
            this.maxPayload &&
 | 
			
		||||
            this.transport.name === "polling" &&
 | 
			
		||||
            this.writeBuffer.length > 1
 | 
			
		||||
        if (!shouldCheckPayloadSize) {
 | 
			
		||||
            return this.writeBuffer
 | 
			
		||||
        }
 | 
			
		||||
        let payloadSize = 1 // first packet type
 | 
			
		||||
        for (let i = 0; i < this.writeBuffer.length; i++) {
 | 
			
		||||
            const data = this.writeBuffer[i].data
 | 
			
		||||
            if (data) {
 | 
			
		||||
                payloadSize += byteLength(data)
 | 
			
		||||
            }
 | 
			
		||||
            if (i > 0 && payloadSize > this.maxPayload) {
 | 
			
		||||
                debug("only send %d out of %d packets", i, this.writeBuffer.length)
 | 
			
		||||
                return this.writeBuffer.slice(0, i)
 | 
			
		||||
            }
 | 
			
		||||
            payloadSize += 2 // separator + packet type
 | 
			
		||||
        }
 | 
			
		||||
        debug("payload size is %d (max: %d)", payloadSize, this.maxPayload)
 | 
			
		||||
        return this.writeBuffer
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a message.
 | 
			
		||||
     *
 | 
			
		||||
@@ -497,12 +782,12 @@ export class Socket extends Emitter {
 | 
			
		||||
     * @return {Socket} for chaining.
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    write(msg, options, fn) {
 | 
			
		||||
    public write(msg, options, fn?) {
 | 
			
		||||
        this.sendPacket("message", msg, options, fn)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    send(msg, options, fn) {
 | 
			
		||||
    public send(msg, options, fn?) {
 | 
			
		||||
        this.sendPacket("message", msg, options, fn)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
@@ -516,7 +801,7 @@ export class Socket extends Emitter {
 | 
			
		||||
     * @param {Function} callback function.
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    sendPacket(type, data?, options?, fn?) {
 | 
			
		||||
    private sendPacket(type, data?, options?, fn?) {
 | 
			
		||||
        if ("function" === typeof data) {
 | 
			
		||||
            fn = data
 | 
			
		||||
            data = undefined
 | 
			
		||||
@@ -539,7 +824,7 @@ export class Socket extends Emitter {
 | 
			
		||||
            data: data,
 | 
			
		||||
            options: options
 | 
			
		||||
        }
 | 
			
		||||
        this.emit("packetCreate", packet)
 | 
			
		||||
        this.emitReserved("packetCreate", packet)
 | 
			
		||||
        this.writeBuffer.push(packet)
 | 
			
		||||
        if (fn) this.once("flush", fn)
 | 
			
		||||
        this.flush()
 | 
			
		||||
@@ -548,9 +833,9 @@ export class Socket extends Emitter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the connection.
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    close() {
 | 
			
		||||
    public close() {
 | 
			
		||||
        const close = () => {
 | 
			
		||||
            this.onClose("forced close")
 | 
			
		||||
            debug("socket closing - telling transport to close")
 | 
			
		||||
@@ -558,8 +843,8 @@ export class Socket extends Emitter {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const cleanupAndClose = () => {
 | 
			
		||||
            this.removeListener("upgrade", cleanupAndClose)
 | 
			
		||||
            this.removeListener("upgradeError", cleanupAndClose)
 | 
			
		||||
            this.off("upgrade", cleanupAndClose)
 | 
			
		||||
            this.off("upgradeError", cleanupAndClose)
 | 
			
		||||
            close()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -595,10 +880,10 @@ export class Socket extends Emitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    onError(err) {
 | 
			
		||||
    private onError(err) {
 | 
			
		||||
        debug("socket error %j", err)
 | 
			
		||||
        Socket.priorWebsocketSuccess = false
 | 
			
		||||
        this.emit("error", err)
 | 
			
		||||
        this.emitReserved("error", err)
 | 
			
		||||
        this.onClose("transport error", err)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -607,7 +892,7 @@ export class Socket extends Emitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    onClose(reason, desc?) {
 | 
			
		||||
    private onClose(reason: string, description?: CloseDetails | Error) {
 | 
			
		||||
        if (
 | 
			
		||||
            "opening" === this.readyState ||
 | 
			
		||||
            "open" === this.readyState ||
 | 
			
		||||
@@ -616,7 +901,6 @@ export class Socket extends Emitter {
 | 
			
		||||
            debug('socket close with reason: "%s"', reason)
 | 
			
		||||
 | 
			
		||||
            // clear timers
 | 
			
		||||
            this.clearTimeoutFn(this.pingIntervalTimer)
 | 
			
		||||
            this.clearTimeoutFn(this.pingTimeoutTimer)
 | 
			
		||||
 | 
			
		||||
            // stop event from firing again for transport
 | 
			
		||||
@@ -629,6 +913,11 @@ export class Socket extends Emitter {
 | 
			
		||||
            this.transport.removeAllListeners()
 | 
			
		||||
 | 
			
		||||
            if (typeof removeEventListener === "function") {
 | 
			
		||||
                removeEventListener(
 | 
			
		||||
                    "beforeunload",
 | 
			
		||||
                    this.beforeunloadEventListener,
 | 
			
		||||
                    false
 | 
			
		||||
                )
 | 
			
		||||
                removeEventListener("offline", this.offlineEventListener, false)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -639,7 +928,7 @@ export class Socket extends Emitter {
 | 
			
		||||
            this.id = null
 | 
			
		||||
 | 
			
		||||
            // emit close event
 | 
			
		||||
            this.emit("close", reason, desc)
 | 
			
		||||
            this.emitReserved("close", reason, description)
 | 
			
		||||
 | 
			
		||||
            // clean buffers after, so users can still
 | 
			
		||||
            // grab the buffers on `close` event
 | 
			
		||||
@@ -655,7 +944,7 @@ export class Socket extends Emitter {
 | 
			
		||||
     * @api private
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    filterUpgrades(upgrades) {
 | 
			
		||||
    private filterUpgrades(upgrades) {
 | 
			
		||||
        const filteredUpgrades = []
 | 
			
		||||
        let i = 0
 | 
			
		||||
        const j = upgrades.length
 | 
			
		||||
@@ -666,23 +955,3 @@ export class Socket extends Emitter {
 | 
			
		||||
        return filteredUpgrades
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Socket.priorWebsocketSuccess = false
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Protocol version.
 | 
			
		||||
 *
 | 
			
		||||
 * @api public
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
Socket.protocol = parser.protocol // this is an int
 | 
			
		||||
 | 
			
		||||
function clone(obj) {
 | 
			
		||||
    const o = {}
 | 
			
		||||
    for (let i in obj) {
 | 
			
		||||
        if (obj.hasOwnProperty(i)) {
 | 
			
		||||
            o[i] = obj[i]
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return o
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,59 @@
 | 
			
		||||
import parser from "../engine.io-parser"
 | 
			
		||||
const Emitter = require("component-emitter")
 | 
			
		||||
// import { decodePacket, Packet, RawData } from "engine.io-parser"
 | 
			
		||||
import { decodePacket, Packet, RawData } from "../engine.io-parser"
 | 
			
		||||
import { Emitter } from "@socket.io/component-emitter"
 | 
			
		||||
import { installTimerFunctions } from "./util"
 | 
			
		||||
const debug = (...args: any) => console.debug('engine.io-client:transport', ...args)//require("debug")("engine.io-client:transport")
 | 
			
		||||
// import debugModule from "debug"; // debug()
 | 
			
		||||
import { SocketOptions } from "./socket"
 | 
			
		||||
 | 
			
		||||
// const debug = debugModule("engine.io-client:transport"); // debug()
 | 
			
		||||
const debug = require('../debug')("engine.io-client:transport") // debug()
 | 
			
		||||
 | 
			
		||||
class TransportError extends Error {
 | 
			
		||||
    public readonly type = "TransportError";
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        reason: string,
 | 
			
		||||
        readonly description: any,
 | 
			
		||||
        readonly context: any
 | 
			
		||||
    ) {
 | 
			
		||||
        super(reason)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface CloseDetails {
 | 
			
		||||
    description: string
 | 
			
		||||
    context?: CloseEvent | XMLHttpRequest
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface TransportReservedEvents {
 | 
			
		||||
    open: () => void
 | 
			
		||||
    error: (err: TransportError) => void
 | 
			
		||||
    packet: (packet: Packet) => void
 | 
			
		||||
    close: (details?: CloseDetails) => void
 | 
			
		||||
    poll: () => void
 | 
			
		||||
    pollComplete: () => void
 | 
			
		||||
    drain: () => void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export abstract class Transport extends Emitter<
 | 
			
		||||
    {},
 | 
			
		||||
    {},
 | 
			
		||||
    TransportReservedEvents
 | 
			
		||||
> {
 | 
			
		||||
    protected opts: SocketOptions
 | 
			
		||||
    protected supportsBinary: boolean
 | 
			
		||||
    protected query: object
 | 
			
		||||
    protected readyState: string
 | 
			
		||||
    protected writable: boolean = false;
 | 
			
		||||
    protected socket: any
 | 
			
		||||
    protected setTimeoutFn: typeof setTimeout
 | 
			
		||||
 | 
			
		||||
export class Transport extends Emitter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Transport abstract constructor.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Object} options.
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    * Transport abstract constructor.
 | 
			
		||||
    *
 | 
			
		||||
    * @param {Object} options.
 | 
			
		||||
    * @api private
 | 
			
		||||
    */
 | 
			
		||||
    constructor(opts) {
 | 
			
		||||
        super()
 | 
			
		||||
        installTimerFunctions(this, opts)
 | 
			
		||||
@@ -23,15 +67,17 @@ export class Transport extends Emitter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Emits an error.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String} str
 | 
			
		||||
     * @param {String} reason
 | 
			
		||||
     * @param description
 | 
			
		||||
     * @param context - the error context
 | 
			
		||||
     * @return {Transport} for chaining
 | 
			
		||||
     * @api public
 | 
			
		||||
     * @api protected
 | 
			
		||||
     */
 | 
			
		||||
    onError(msg, desc) {
 | 
			
		||||
        const err: any = new Error(msg)
 | 
			
		||||
        err.type = "TransportError"
 | 
			
		||||
        err.description = desc
 | 
			
		||||
        this.emit("error", err)
 | 
			
		||||
    protected onError(reason: string, description: any, context?: any) {
 | 
			
		||||
        super.emitReserved(
 | 
			
		||||
            "error",
 | 
			
		||||
            new TransportError(reason, description, context)
 | 
			
		||||
        )
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -40,7 +86,7 @@ export class Transport extends Emitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    open() {
 | 
			
		||||
    private open() {
 | 
			
		||||
        if ("closed" === this.readyState || "" === this.readyState) {
 | 
			
		||||
            this.readyState = "opening"
 | 
			
		||||
            this.doOpen()
 | 
			
		||||
@@ -52,9 +98,9 @@ export class Transport extends Emitter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the transport.
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    close() {
 | 
			
		||||
    public close() {
 | 
			
		||||
        if ("opening" === this.readyState || "open" === this.readyState) {
 | 
			
		||||
            this.doClose()
 | 
			
		||||
            this.onClose()
 | 
			
		||||
@@ -64,12 +110,12 @@ export class Transport extends Emitter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends multiple packets.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Array} packets
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    send(packets) {
 | 
			
		||||
   * Sends multiple packets.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Array} packets
 | 
			
		||||
   * @api public
 | 
			
		||||
   */
 | 
			
		||||
    public send(packets) {
 | 
			
		||||
        if ("open" === this.readyState) {
 | 
			
		||||
            this.write(packets)
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -81,39 +127,45 @@ export class Transport extends Emitter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Called upon open
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     * @api protected
 | 
			
		||||
     */
 | 
			
		||||
    onOpen() {
 | 
			
		||||
    protected onOpen() {
 | 
			
		||||
        this.readyState = "open"
 | 
			
		||||
        this.writable = true
 | 
			
		||||
        this.emit("open")
 | 
			
		||||
        super.emitReserved("open")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called with data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String} data
 | 
			
		||||
     * @api private
 | 
			
		||||
     * @api protected
 | 
			
		||||
     */
 | 
			
		||||
    onData(data) {
 | 
			
		||||
        const packet = parser.decodePacket(data, this.socket.binaryType)
 | 
			
		||||
    protected onData(data: RawData) {
 | 
			
		||||
        const packet = decodePacket(data, this.socket.binaryType)
 | 
			
		||||
        this.onPacket(packet)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called with a decoded packet.
 | 
			
		||||
     *
 | 
			
		||||
     * @api protected
 | 
			
		||||
     */
 | 
			
		||||
    onPacket(packet) {
 | 
			
		||||
        this.emit("packet", packet)
 | 
			
		||||
    protected onPacket(packet: Packet) {
 | 
			
		||||
        super.emitReserved("packet", packet)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called upon close.
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     * @api protected
 | 
			
		||||
     */
 | 
			
		||||
    onClose() {
 | 
			
		||||
    protected onClose(details?: CloseDetails) {
 | 
			
		||||
        this.readyState = "closed"
 | 
			
		||||
        this.emit("close")
 | 
			
		||||
        super.emitReserved("close", details)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract doOpen()
 | 
			
		||||
    protected abstract doClose()
 | 
			
		||||
    protected abstract write(packets)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
import { WS } from "./websocket"
 | 
			
		||||
export default {
 | 
			
		||||
    'websocket': WS
 | 
			
		||||
import { WS } from "./websocket.js"
 | 
			
		||||
 | 
			
		||||
export const transports = {
 | 
			
		||||
    websocket: WS,
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
import { WebSocket as ws } from "../../client"
 | 
			
		||||
 | 
			
		||||
export const WebSocket = ws
 | 
			
		||||
export const usingBrowserWebSocket = false
 | 
			
		||||
export const defaultBinaryType = "nodebuffer"
 | 
			
		||||
export const nextTick = process.nextTick
 | 
			
		||||
@@ -1,21 +1,18 @@
 | 
			
		||||
import { Transport } from '../transport'
 | 
			
		||||
// const Transport = require("../transport")
 | 
			
		||||
import parser from '../../engine.io-parser'
 | 
			
		||||
// const parser = require("../engine.io-parser")
 | 
			
		||||
const parseqs = require("parseqs")
 | 
			
		||||
const yeast = require("yeast")
 | 
			
		||||
import { pick } from '../util'
 | 
			
		||||
// const { pick } = require("../util")
 | 
			
		||||
import { WebSocket } from '../../client'
 | 
			
		||||
const usingBrowserWebSocket = true
 | 
			
		||||
// const {
 | 
			
		||||
//     WebSocket,
 | 
			
		||||
//     usingBrowserWebSocket,
 | 
			
		||||
//     defaultBinaryType,
 | 
			
		||||
//     nextTick
 | 
			
		||||
// } = require("./websocket-constructor")
 | 
			
		||||
import { Transport } from "../transport"
 | 
			
		||||
import { encode } from "../contrib/parseqs"
 | 
			
		||||
import { yeast } from "../contrib/yeast"
 | 
			
		||||
import { pick } from "../util"
 | 
			
		||||
import {
 | 
			
		||||
    defaultBinaryType,
 | 
			
		||||
    nextTick,
 | 
			
		||||
    usingBrowserWebSocket,
 | 
			
		||||
    WebSocket
 | 
			
		||||
} from "./websocket-constructor"
 | 
			
		||||
// import debugModule from "debug" // debug()
 | 
			
		||||
import { encodePacket } from "../../engine.io-parser"
 | 
			
		||||
 | 
			
		||||
const debug = (...args: any) => console.debug('engine.io-client:websocket', ...args)//require("debug")("engine.io-client:websocket")
 | 
			
		||||
// const debug = debugModule("engine.io-client:websocket") // debug()
 | 
			
		||||
const debug = (...args: any) => console.debug('engine.io-client:websocket', ...args)
 | 
			
		||||
 | 
			
		||||
// detect ReactNative environment
 | 
			
		||||
const isReactNative =
 | 
			
		||||
@@ -24,6 +21,8 @@ const isReactNative =
 | 
			
		||||
    navigator.product.toLowerCase() === "reactnative"
 | 
			
		||||
 | 
			
		||||
export class WS extends Transport {
 | 
			
		||||
    private ws: any
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * WebSocket transport constructor.
 | 
			
		||||
     *
 | 
			
		||||
@@ -86,17 +85,17 @@ export class WS extends Transport {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            this.ws = new WebSocket(uri, protocols)
 | 
			
		||||
            // usingBrowserWebSocket && !isReactNative
 | 
			
		||||
            //     ? protocols
 | 
			
		||||
            //         ? new WebSocket(uri, protocols)
 | 
			
		||||
            //         : new WebSocket(uri)
 | 
			
		||||
            //     : new WebSocket(uri, protocols, opts)
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
            return this.emit("error", err)
 | 
			
		||||
            this.ws =
 | 
			
		||||
                usingBrowserWebSocket && !isReactNative
 | 
			
		||||
                    ? protocols
 | 
			
		||||
                        ? new WebSocket(uri, protocols)
 | 
			
		||||
                        : new WebSocket(uri)
 | 
			
		||||
                    : new WebSocket(uri, protocols, opts)
 | 
			
		||||
        } catch (err: any) {
 | 
			
		||||
            return this.emitReserved("error", err)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.ws.binaryType = this.socket.binaryType || 'arraybuffer'
 | 
			
		||||
        this.ws.binaryType = this.socket.binaryType || defaultBinaryType
 | 
			
		||||
 | 
			
		||||
        this.addEventListeners()
 | 
			
		||||
    }
 | 
			
		||||
@@ -113,7 +112,11 @@ export class WS extends Transport {
 | 
			
		||||
            }
 | 
			
		||||
            this.onOpen()
 | 
			
		||||
        }
 | 
			
		||||
        this.ws.onclose = this.onClose.bind(this)
 | 
			
		||||
        this.ws.onclose = closeEvent =>
 | 
			
		||||
            this.onClose({
 | 
			
		||||
                description: "websocket connection closed",
 | 
			
		||||
                context: closeEvent
 | 
			
		||||
            })
 | 
			
		||||
        this.ws.onmessage = ev => this.onData(ev.data)
 | 
			
		||||
        this.ws.onerror = e => this.onError("websocket error", e)
 | 
			
		||||
    }
 | 
			
		||||
@@ -133,9 +136,9 @@ export class WS extends Transport {
 | 
			
		||||
            const packet = packets[i]
 | 
			
		||||
            const lastPacket = i === packets.length - 1
 | 
			
		||||
 | 
			
		||||
            parser.encodePacket(packet, this.supportsBinary, data => {
 | 
			
		||||
            encodePacket(packet, this.supportsBinary, data => {
 | 
			
		||||
                // always create a new object (GH-437)
 | 
			
		||||
                const opts: any = {}
 | 
			
		||||
                const opts: { compress?: boolean } = {}
 | 
			
		||||
                if (!usingBrowserWebSocket) {
 | 
			
		||||
                    if (packet.options) {
 | 
			
		||||
                        opts.compress = packet.options.compress
 | 
			
		||||
@@ -143,6 +146,7 @@ export class WS extends Transport {
 | 
			
		||||
 | 
			
		||||
                    if (this.opts.perMessageDeflate) {
 | 
			
		||||
                        const len =
 | 
			
		||||
                            // @ts-ignore
 | 
			
		||||
                            "string" === typeof data ? Buffer.byteLength(data) : data.length
 | 
			
		||||
                        if (len < this.opts.perMessageDeflate.threshold) {
 | 
			
		||||
                            opts.compress = false
 | 
			
		||||
@@ -160,31 +164,22 @@ export class WS extends Transport {
 | 
			
		||||
                    } else {
 | 
			
		||||
                        this.ws.send(data, opts)
 | 
			
		||||
                    }
 | 
			
		||||
                } catch (error: any) {
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    debug("websocket closed before onclose event")
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (lastPacket) {
 | 
			
		||||
                    // fake drain
 | 
			
		||||
                    // defer to next tick to allow Socket to clear writeBuffer
 | 
			
		||||
                    process.nextTick(() => {
 | 
			
		||||
                    nextTick(() => {
 | 
			
		||||
                        this.writable = true
 | 
			
		||||
                        this.emit("drain")
 | 
			
		||||
                        this.emitReserved("drain")
 | 
			
		||||
                    }, this.setTimeoutFn)
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called upon close
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    onClose() {
 | 
			
		||||
        Transport.prototype.onClose.call(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes socket.
 | 
			
		||||
     *
 | 
			
		||||
@@ -203,7 +198,7 @@ export class WS extends Transport {
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    uri() {
 | 
			
		||||
        let query = this.query || {}
 | 
			
		||||
        let query: { b64?: number } = this.query || {}
 | 
			
		||||
        const schema = this.opts.secure ? "wss" : "ws"
 | 
			
		||||
        let port = ""
 | 
			
		||||
 | 
			
		||||
@@ -226,21 +221,16 @@ export class WS extends Transport {
 | 
			
		||||
            query.b64 = 1
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        query = parseqs.encode(query)
 | 
			
		||||
 | 
			
		||||
        // prepend ? to query
 | 
			
		||||
        if (query.length) {
 | 
			
		||||
            query = "?" + query
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const encodedQuery = encode(query)
 | 
			
		||||
        const ipv6 = this.opts.hostname.indexOf(":") !== -1
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
            schema +
 | 
			
		||||
            "://" +
 | 
			
		||||
            (ipv6 ? "[" + this.opts.hostname + "]" : this.opts.hostname) +
 | 
			
		||||
            port +
 | 
			
		||||
            this.opts.path +
 | 
			
		||||
            query
 | 
			
		||||
            (encodedQuery.length ? "?" + encodedQuery : "")
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -251,9 +241,6 @@ export class WS extends Transport {
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    check() {
 | 
			
		||||
        return (
 | 
			
		||||
            !!WebSocket &&
 | 
			
		||||
            !("__initialize" in WebSocket && this.name === WS.prototype.name)
 | 
			
		||||
        )
 | 
			
		||||
        return !!WebSocket
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
const pick = (obj, ...attr) => {
 | 
			
		||||
// import { globalThisShim as globalThis } from "./globalThis.js"
 | 
			
		||||
 | 
			
		||||
export function pick(obj, ...attr) {
 | 
			
		||||
    return attr.reduce((acc, k) => {
 | 
			
		||||
        if (obj.hasOwnProperty(k)) {
 | 
			
		||||
            acc[k] = obj[k]
 | 
			
		||||
@@ -11,7 +13,7 @@ const pick = (obj, ...attr) => {
 | 
			
		||||
const NATIVE_SET_TIMEOUT = setTimeout
 | 
			
		||||
const NATIVE_CLEAR_TIMEOUT = clearTimeout
 | 
			
		||||
 | 
			
		||||
const installTimerFunctions = (obj, opts) => {
 | 
			
		||||
export function installTimerFunctions(obj, opts) {
 | 
			
		||||
    if (opts.useNativeTimers) {
 | 
			
		||||
        obj.setTimeoutFn = NATIVE_SET_TIMEOUT.bind(globalThis)
 | 
			
		||||
        obj.clearTimeoutFn = NATIVE_CLEAR_TIMEOUT.bind(globalThis)
 | 
			
		||||
@@ -20,4 +22,34 @@ const installTimerFunctions = (obj, opts) => {
 | 
			
		||||
        obj.clearTimeoutFn = clearTimeout.bind(globalThis)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
export { pick, installTimerFunctions }
 | 
			
		||||
 | 
			
		||||
// base64 encoded buffers are about 33% bigger (https://en.wikipedia.org/wiki/Base64)
 | 
			
		||||
const BASE64_OVERHEAD = 1.33
 | 
			
		||||
 | 
			
		||||
// we could also have used `new Blob([obj]).size`, but it isn't supported in IE9
 | 
			
		||||
export function byteLength(obj) {
 | 
			
		||||
    if (typeof obj === "string") {
 | 
			
		||||
        return utf8Length(obj)
 | 
			
		||||
    }
 | 
			
		||||
    // arraybuffer or blob
 | 
			
		||||
    return Math.ceil((obj.byteLength || obj.size) * BASE64_OVERHEAD)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function utf8Length(str) {
 | 
			
		||||
    let c = 0,
 | 
			
		||||
        length = 0
 | 
			
		||||
    for (let i = 0, l = str.length; i < l; i++) {
 | 
			
		||||
        c = str.charCodeAt(i)
 | 
			
		||||
        if (c < 0x80) {
 | 
			
		||||
            length += 1
 | 
			
		||||
        } else if (c < 0x800) {
 | 
			
		||||
            length += 2
 | 
			
		||||
        } else if (c < 0xd800 || c >= 0xe000) {
 | 
			
		||||
            length += 3
 | 
			
		||||
        } else {
 | 
			
		||||
            i++
 | 
			
		||||
            length += 4
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return length
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,10 +12,28 @@ Object.keys(PACKET_TYPES).forEach(key => {
 | 
			
		||||
    PACKET_TYPES_REVERSE[PACKET_TYPES[key]] = key
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const ERROR_PACKET = { type: "error", data: "parser error" }
 | 
			
		||||
const ERROR_PACKET: Packet = { type: "error", data: "parser error" }
 | 
			
		||||
 | 
			
		||||
export = {
 | 
			
		||||
    PACKET_TYPES,
 | 
			
		||||
    PACKET_TYPES_REVERSE,
 | 
			
		||||
    ERROR_PACKET
 | 
			
		||||
export { PACKET_TYPES, PACKET_TYPES_REVERSE, ERROR_PACKET }
 | 
			
		||||
 | 
			
		||||
export type PacketType =
 | 
			
		||||
    | "open"
 | 
			
		||||
    | "close"
 | 
			
		||||
    | "ping"
 | 
			
		||||
    | "pong"
 | 
			
		||||
    | "message"
 | 
			
		||||
    | "upgrade"
 | 
			
		||||
    | "noop"
 | 
			
		||||
    | "error"
 | 
			
		||||
 | 
			
		||||
// RawData should be "string | Buffer | ArrayBuffer | ArrayBufferView | Blob", but Blob does not exist in Node.js and
 | 
			
		||||
// requires to add the dom lib in tsconfig.json
 | 
			
		||||
export type RawData = any
 | 
			
		||||
 | 
			
		||||
export interface Packet {
 | 
			
		||||
    type: PacketType
 | 
			
		||||
    options?: { compress: boolean }
 | 
			
		||||
    data?: RawData
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type BinaryType = "nodebuffer" | "arraybuffer" | "blob"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,15 @@
 | 
			
		||||
const { PACKET_TYPES_REVERSE, ERROR_PACKET } = require("./commons")
 | 
			
		||||
import {
 | 
			
		||||
    ERROR_PACKET,
 | 
			
		||||
    PACKET_TYPES_REVERSE,
 | 
			
		||||
    Packet,
 | 
			
		||||
    BinaryType,
 | 
			
		||||
    RawData
 | 
			
		||||
} from "./commons.js"
 | 
			
		||||
 | 
			
		||||
export const decodePacket = (encodedPacket, binaryType) => {
 | 
			
		||||
const decodePacket = (
 | 
			
		||||
    encodedPacket: RawData,
 | 
			
		||||
    binaryType?: BinaryType
 | 
			
		||||
): Packet => {
 | 
			
		||||
    if (typeof encodedPacket !== "string") {
 | 
			
		||||
        return {
 | 
			
		||||
            type: "message",
 | 
			
		||||
@@ -28,17 +37,18 @@ export const decodePacket = (encodedPacket, binaryType) => {
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const mapBinary = (data, binaryType) => {
 | 
			
		||||
const mapBinary = (data: RawData, binaryType?: BinaryType) => {
 | 
			
		||||
    const isBuffer = Buffer.isBuffer(data)
 | 
			
		||||
    switch (binaryType) {
 | 
			
		||||
        case "arraybuffer":
 | 
			
		||||
            return Buffer.isBuffer(data) ? toArrayBuffer(data) : data
 | 
			
		||||
            return isBuffer ? toArrayBuffer(data) : data
 | 
			
		||||
        case "nodebuffer":
 | 
			
		||||
        default:
 | 
			
		||||
            return data // assuming the data is already a Buffer
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const toArrayBuffer = buffer => {
 | 
			
		||||
const toArrayBuffer = (buffer: Buffer): ArrayBuffer => {
 | 
			
		||||
    const arrayBuffer = new ArrayBuffer(buffer.length)
 | 
			
		||||
    const view = new Uint8Array(arrayBuffer)
 | 
			
		||||
    for (let i = 0; i < buffer.length; i++) {
 | 
			
		||||
@@ -46,3 +56,5 @@ const toArrayBuffer = buffer => {
 | 
			
		||||
    }
 | 
			
		||||
    return arrayBuffer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default decodePacket
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,10 @@
 | 
			
		||||
const { PACKET_TYPES } = require("./commons")
 | 
			
		||||
import { PACKET_TYPES, Packet, RawData } from "./commons.js"
 | 
			
		||||
 | 
			
		||||
export const encodePacket = ({ type, data }, supportsBinary, callback) => {
 | 
			
		||||
    console.trace('encodePacket', type, JSON.stringify(data))
 | 
			
		||||
const encodePacket = (
 | 
			
		||||
    { type, data }: Packet,
 | 
			
		||||
    supportsBinary: boolean,
 | 
			
		||||
    callback: (encodedPacket: RawData) => void
 | 
			
		||||
) => {
 | 
			
		||||
    if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
 | 
			
		||||
        const buffer = toBuffer(data)
 | 
			
		||||
        return callback(encodeBuffer(buffer, supportsBinary))
 | 
			
		||||
@@ -21,6 +24,8 @@ const toBuffer = data => {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// only 'message' packets can contain binary, so the type prefix is not needed
 | 
			
		||||
const encodeBuffer = (data, supportsBinary) => {
 | 
			
		||||
const encodeBuffer = (data: Buffer, supportsBinary: boolean): RawData => {
 | 
			
		||||
    return supportsBinary ? data : "b" + data.toString("base64")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default encodePacket
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,13 @@
 | 
			
		||||
import { encodePacket } from "./encodePacket"
 | 
			
		||||
import { decodePacket } from "./decodePacket"
 | 
			
		||||
import encodePacket from "./encodePacket.js"
 | 
			
		||||
import decodePacket from "./decodePacket.js"
 | 
			
		||||
import { Packet, PacketType, RawData, BinaryType } from "./commons.js"
 | 
			
		||||
 | 
			
		||||
const SEPARATOR = String.fromCharCode(30) // see https://en.wikipedia.org/wiki/Delimiter#ASCII_delimited_text
 | 
			
		||||
 | 
			
		||||
const encodePayload = (packets, callback) => {
 | 
			
		||||
const encodePayload = (
 | 
			
		||||
    packets: Packet[],
 | 
			
		||||
    callback: (encodedPayload: string) => void
 | 
			
		||||
) => {
 | 
			
		||||
    // some packets may be added to the array while encoding, so the initial length must be saved
 | 
			
		||||
    const length = packets.length
 | 
			
		||||
    const encodedPackets = new Array(length)
 | 
			
		||||
@@ -20,7 +24,10 @@ const encodePayload = (packets, callback) => {
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const decodePayload = (encodedPayload, binaryType) => {
 | 
			
		||||
const decodePayload = (
 | 
			
		||||
    encodedPayload: string,
 | 
			
		||||
    binaryType?: BinaryType
 | 
			
		||||
): Packet[] => {
 | 
			
		||||
    const encodedPackets = encodedPayload.split(SEPARATOR)
 | 
			
		||||
    const packets = []
 | 
			
		||||
    for (let i = 0; i < encodedPackets.length; i++) {
 | 
			
		||||
@@ -33,10 +40,14 @@ const decodePayload = (encodedPayload, binaryType) => {
 | 
			
		||||
    return packets
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    protocol: 4,
 | 
			
		||||
export const protocol = 4
 | 
			
		||||
export {
 | 
			
		||||
    encodePacket,
 | 
			
		||||
    encodePayload,
 | 
			
		||||
    decodePacket,
 | 
			
		||||
    decodePayload
 | 
			
		||||
    decodePayload,
 | 
			
		||||
    Packet,
 | 
			
		||||
    PacketType,
 | 
			
		||||
    RawData,
 | 
			
		||||
    BinaryType
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,45 @@
 | 
			
		||||
// import { createServer } from "http"
 | 
			
		||||
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 { Server, transports, attach, parser }
 | 
			
		||||
export { AttachOptions, ServerOptions } from "./server"
 | 
			
		||||
// export { uServer } from "./userver";
 | 
			
		||||
export { Socket } from "./socket"
 | 
			
		||||
export { Transport } from "./transport"
 | 
			
		||||
export const protocol = parser.protocol
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Module dependencies.
 | 
			
		||||
 * Creates an http.Server exclusively used for WS upgrades.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Number} port
 | 
			
		||||
 * @param {Function} callback
 | 
			
		||||
 * @param {Object} options
 | 
			
		||||
 * @return {Server} websocket.io server
 | 
			
		||||
 * @api public
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// const http = require("http")
 | 
			
		||||
// const Server = require("./server")
 | 
			
		||||
import { Server } from './server'
 | 
			
		||||
// function listen(port, options: AttachOptions & ServerOptions, fn) {
 | 
			
		||||
//   if ("function" === typeof options) {
 | 
			
		||||
//     fn = options;
 | 
			
		||||
//     options = {};
 | 
			
		||||
//   }
 | 
			
		||||
 | 
			
		||||
//   const server = 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.
 | 
			
		||||
@@ -15,12 +50,8 @@ import { Server } from './server'
 | 
			
		||||
 * @api public
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
function attach(srv, options) {
 | 
			
		||||
function attach(server, options: AttachOptions & ServerOptions) {
 | 
			
		||||
    const engine = new Server(options)
 | 
			
		||||
    engine.attach(srv, options)
 | 
			
		||||
    engine.attach(server, options)
 | 
			
		||||
    return engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export = {
 | 
			
		||||
    attach
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										484
									
								
								packages/websocket/src/engine.io/parser-v3/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										484
									
								
								packages/websocket/src/engine.io/parser-v3/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,484 @@
 | 
			
		||||
// imported from https://github.com/socketio/engine.io-parser/tree/2.2.x
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Module dependencies.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
var utf8 = require('./utf8')
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Current protocol version.
 | 
			
		||||
 */
 | 
			
		||||
export const 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export const packets = {
 | 
			
		||||
    open: 0    // non-ws
 | 
			
		||||
    , close: 1    // non-ws
 | 
			
		||||
    , ping: 2
 | 
			
		||||
    , pong: 3
 | 
			
		||||
    , message: 4
 | 
			
		||||
    , upgrade: 5
 | 
			
		||||
    , noop: 6
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var packetslist = Object.keys(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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export 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 = 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] = 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export function encodeBase64Packet(packet, callback) {
 | 
			
		||||
    var data = Buffer.isBuffer(packet.data) ? packet.data : arrayBufferToBuffer(packet.data)
 | 
			
		||||
    var message = 'b' + 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export 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)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export 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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										210
									
								
								packages/websocket/src/engine.io/parser-v3/utf8.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								packages/websocket/src/engine.io/parser-v3/utf8.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,210 @@
 | 
			
		||||
/*! 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, it’s 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
 | 
			
		||||
}
 | 
			
		||||
@@ -1,52 +1,141 @@
 | 
			
		||||
const qs = require("querystring")
 | 
			
		||||
const parse = require("url").parse
 | 
			
		||||
import * as qs from "querystring"
 | 
			
		||||
import { parse } from "url"
 | 
			
		||||
// const base64id = require("base64id")
 | 
			
		||||
import transports from './transports'
 | 
			
		||||
import { EventEmitter } from 'events'
 | 
			
		||||
// const EventEmitter = require("events").EventEmitter
 | 
			
		||||
import { Socket } from './socket'
 | 
			
		||||
// const debug = require("debug")("engine")
 | 
			
		||||
const debug = function (...args) { }
 | 
			
		||||
// const cookieMod = require("cookie")
 | 
			
		||||
 | 
			
		||||
// const DEFAULT_WS_ENGINE = require("ws").Server;
 | 
			
		||||
import { WebSocketServer } from '../server'
 | 
			
		||||
import { Transport } from './transport'
 | 
			
		||||
const DEFAULT_WS_ENGINE = WebSocketServer
 | 
			
		||||
import transports from "./transports"
 | 
			
		||||
import { EventEmitter } from "events"
 | 
			
		||||
import { Socket } from "./socket"
 | 
			
		||||
// import debugModule from "debug"
 | 
			
		||||
// import { serialize } from "cookie"
 | 
			
		||||
// import { Server as DEFAULT_WS_ENGINE } from "ws"
 | 
			
		||||
import { WebSocketServer as DEFAULT_WS_ENGINE } from "../server"
 | 
			
		||||
// import { IncomingMessage, Server as HttpServer } from "http"
 | 
			
		||||
// import { CookieSerializeOptions } from "cookie"
 | 
			
		||||
// import { CorsOptions, CorsOptionsDelegate } from "cors"
 | 
			
		||||
 | 
			
		||||
// const debug = debugModule("engine");
 | 
			
		||||
const debug = require("../debug")("engine")
 | 
			
		||||
import { Request } from '../server/request'
 | 
			
		||||
import { WebSocketClient } from '../server/client'
 | 
			
		||||
 | 
			
		||||
export class Server extends EventEmitter {
 | 
			
		||||
    public static errors = {
 | 
			
		||||
        UNKNOWN_TRANSPORT: 0,
 | 
			
		||||
        UNKNOWN_SID: 1,
 | 
			
		||||
        BAD_HANDSHAKE_METHOD: 2,
 | 
			
		||||
        BAD_REQUEST: 3,
 | 
			
		||||
        FORBIDDEN: 4,
 | 
			
		||||
        UNSUPPORTED_PROTOCOL_VERSION: 5
 | 
			
		||||
    }
 | 
			
		||||
type Transport = "polling" | "websocket"
 | 
			
		||||
 | 
			
		||||
    public static errorMessages = {
 | 
			
		||||
        0: "Transport unknown",
 | 
			
		||||
        1: "Session ID unknown",
 | 
			
		||||
        2: "Bad handshake method",
 | 
			
		||||
        3: "Bad request",
 | 
			
		||||
        4: "Forbidden",
 | 
			
		||||
        5: "Unsupported protocol version"
 | 
			
		||||
    }
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    private clients = {}
 | 
			
		||||
    private clientsCount = 0
 | 
			
		||||
    public opts: any
 | 
			
		||||
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
 | 
			
		||||
     * @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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    private corsMiddleware: any
 | 
			
		||||
export abstract class BaseServer extends EventEmitter {
 | 
			
		||||
    public opts: ServerOptions
 | 
			
		||||
 | 
			
		||||
    private ws: any
 | 
			
		||||
    private perMessageDeflate: any
 | 
			
		||||
    protected clients: any
 | 
			
		||||
    private clientsCount: number
 | 
			
		||||
    protected corsMiddleware: Function
 | 
			
		||||
 | 
			
		||||
    constructor(opts: any = {}) {
 | 
			
		||||
    /**
 | 
			
		||||
     * Server constructor.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Object} opts - options
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    constructor(opts: ServerOptions = {}) {
 | 
			
		||||
        super()
 | 
			
		||||
 | 
			
		||||
        this.clients = {}
 | 
			
		||||
        this.clientsCount = 0
 | 
			
		||||
 | 
			
		||||
        this.opts = Object.assign(
 | 
			
		||||
            {
 | 
			
		||||
                wsEngine: DEFAULT_WS_ENGINE,
 | 
			
		||||
@@ -70,6 +159,7 @@ export class Server extends EventEmitter {
 | 
			
		||||
        //         {
 | 
			
		||||
        //             name: "io",
 | 
			
		||||
        //             path: "/",
 | 
			
		||||
        //             // @ts-ignore
 | 
			
		||||
        //             httpOnly: opts.cookie.path !== false,
 | 
			
		||||
        //             sameSite: "lax"
 | 
			
		||||
        //         },
 | 
			
		||||
@@ -93,42 +183,7 @@ export class Server extends EventEmitter {
 | 
			
		||||
        // this.init()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // /**
 | 
			
		||||
    //  * Initialize websocket server
 | 
			
		||||
    //  *
 | 
			
		||||
    //  * @api private
 | 
			
		||||
    //  */
 | 
			
		||||
    // 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 = {}
 | 
			
		||||
 | 
			
		||||
    //             const isInitialRequest = !req._query.sid
 | 
			
		||||
    //             if (isInitialRequest) {
 | 
			
		||||
    //                 this.emit("initial_headers", additionalHeaders, req)
 | 
			
		||||
    //             }
 | 
			
		||||
 | 
			
		||||
    //             this.emit("headers", additionalHeaders, req)
 | 
			
		||||
 | 
			
		||||
    //             Object.keys(additionalHeaders).forEach(key => {
 | 
			
		||||
    //                 headersArray.push(`${key}: ${additionalHeaders[key]}`)
 | 
			
		||||
    //             })
 | 
			
		||||
    //         })
 | 
			
		||||
    //     }
 | 
			
		||||
    // }
 | 
			
		||||
    protected abstract init()
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a list of available transports for upgrade given a certain transport.
 | 
			
		||||
@@ -136,7 +191,7 @@ export class Server extends EventEmitter {
 | 
			
		||||
     * @return {Array}
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    upgrades(transport): Array<any> {
 | 
			
		||||
    public upgrades(transport) {
 | 
			
		||||
        if (!this.opts.allowUpgrades) return []
 | 
			
		||||
        return transports[transport].upgradesTo || []
 | 
			
		||||
    }
 | 
			
		||||
@@ -148,7 +203,7 @@ export class Server extends EventEmitter {
 | 
			
		||||
    //  * @return {Boolean} whether the request is valid
 | 
			
		||||
    //  * @api private
 | 
			
		||||
    //  */
 | 
			
		||||
    // verify(req, upgrade, fn) {
 | 
			
		||||
    // protected verify(req, upgrade, fn) {
 | 
			
		||||
    //     // transport check
 | 
			
		||||
    //     const transport = req._query.transport
 | 
			
		||||
    //     if (!~this.opts.transports.indexOf(transport)) {
 | 
			
		||||
@@ -194,6 +249,13 @@ export class Server extends EventEmitter {
 | 
			
		||||
    //             })
 | 
			
		||||
    //         }
 | 
			
		||||
 | 
			
		||||
    //         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) => {
 | 
			
		||||
@@ -209,36 +271,234 @@ export class Server extends EventEmitter {
 | 
			
		||||
    //     fn()
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Prepares a request by processing the query string.
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    prepare(req) {
 | 
			
		||||
        // try to leverage pre-existing `req._query` (e.g: from connect)
 | 
			
		||||
        if (!req._query) {
 | 
			
		||||
            req._query = ~req.url.indexOf("?") ? qs.parse(parse(req.url).query) : {}
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes all clients.
 | 
			
		||||
     *
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    close() {
 | 
			
		||||
    public 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
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract cleanup()
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * generate a socket id.
 | 
			
		||||
     * Overwrite this method to generate your custom socket id
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Object} request object
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    public generateId(req) {
 | 
			
		||||
        // return base64id.generateId()
 | 
			
		||||
        return req.id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handshakes a new client.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String} transport name
 | 
			
		||||
     * @param {Object} request object
 | 
			
		||||
     * @param {Function} closeConnection
 | 
			
		||||
     *
 | 
			
		||||
     * @api protected
 | 
			
		||||
     */
 | 
			
		||||
    // protected async handshake(transportName, req, closeConnection) {
 | 
			
		||||
    // @java-patch sync handshake
 | 
			
		||||
    protected 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 = 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 ("websocket" !== transportName) {
 | 
			
		||||
                throw new Error('Unsupport polling at MiaoScript!')
 | 
			
		||||
            }
 | 
			
		||||
            // if ("polling" === transportName) {
 | 
			
		||||
            //     transport.maxHttpBufferSize = this.opts.maxHttpBufferSize
 | 
			
		||||
            //     transport.httpCompression = this.opts.httpCompression
 | 
			
		||||
            // } else if ("websocket" === transportName) {
 | 
			
		||||
            transport.perMessageDeflate = this.opts.perMessageDeflate
 | 
			
		||||
            // }
 | 
			
		||||
 | 
			
		||||
            if (req._query && req._query.b64) {
 | 
			
		||||
                transport.supportsBinary = false
 | 
			
		||||
            } else {
 | 
			
		||||
                transport.supportsBinary = true
 | 
			
		||||
            }
 | 
			
		||||
        } 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(id, this, transport, req, protocol)
 | 
			
		||||
 | 
			
		||||
        transport.on("headers", (headers, req) => {
 | 
			
		||||
            const isInitialRequest = !req._query.sid
 | 
			
		||||
 | 
			
		||||
            if (isInitialRequest) {
 | 
			
		||||
                if (this.opts.cookie) {
 | 
			
		||||
                    headers["Set-Cookie"] = [
 | 
			
		||||
                        // 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
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract createTransport(transportName, req)
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Protocol errors mappings.
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    static errors = {
 | 
			
		||||
        UNKNOWN_TRANSPORT: 0,
 | 
			
		||||
        UNKNOWN_SID: 1,
 | 
			
		||||
        BAD_HANDSHAKE_METHOD: 2,
 | 
			
		||||
        BAD_REQUEST: 3,
 | 
			
		||||
        FORBIDDEN: 4,
 | 
			
		||||
        UNSUPPORTED_PROTOCOL_VERSION: 5
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static errorMessages = {
 | 
			
		||||
        0: "Transport unknown",
 | 
			
		||||
        1: "Session ID unknown",
 | 
			
		||||
        2: "Bad handshake method",
 | 
			
		||||
        3: "Bad request",
 | 
			
		||||
        4: "Forbidden",
 | 
			
		||||
        5: "Unsupported protocol version"
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class Server extends BaseServer {
 | 
			
		||||
    // public httpServer?: HttpServer
 | 
			
		||||
    private ws: any
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize websocket server
 | 
			
		||||
     *
 | 
			
		||||
     * @api protected
 | 
			
		||||
     */
 | 
			
		||||
    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 = {}
 | 
			
		||||
 | 
			
		||||
                const isInitialRequest = !req._query.sid
 | 
			
		||||
                if (isInitialRequest) {
 | 
			
		||||
                    this.emit("initial_headers", additionalHeaders, req)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.emit("headers", additionalHeaders, req)
 | 
			
		||||
 | 
			
		||||
                Object.keys(additionalHeaders).forEach(key => {
 | 
			
		||||
                    headersArray.push(`${key}: ${additionalHeaders[key]}`)
 | 
			
		||||
                })
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected 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
 | 
			
		||||
        }
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Prepares a request by processing the query string.
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    private prepare(req) {
 | 
			
		||||
        // try to leverage pre-existing `req._query` (e.g: from connect)
 | 
			
		||||
        if (!req._query) {
 | 
			
		||||
            req._query = ~req.url.indexOf("?") ? qs.parse(parse(req.url).query) : {}
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected createTransport(transportName, req) {
 | 
			
		||||
        return new transports[transportName](req)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // /**
 | 
			
		||||
@@ -248,7 +508,7 @@ export class Server extends EventEmitter {
 | 
			
		||||
    //  * @param {http.ServerResponse|http.OutgoingMessage} response
 | 
			
		||||
    //  * @api public
 | 
			
		||||
    //  */
 | 
			
		||||
    // handleRequest(req, res) {
 | 
			
		||||
    // public handleRequest(req, res) {
 | 
			
		||||
    //     debug('handling "%s" http request "%s"', req.method, req.url)
 | 
			
		||||
    //     this.prepare(req)
 | 
			
		||||
    //     req.res = res
 | 
			
		||||
@@ -284,131 +544,12 @@ export class Server extends EventEmitter {
 | 
			
		||||
    //     }
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * generate a socket id.
 | 
			
		||||
     * Overwrite this method to generate your custom socket id
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Object} request object
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    generateId(req) {
 | 
			
		||||
        return req.id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handshakes a new client.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String} transport name
 | 
			
		||||
     * @param {Object} request object
 | 
			
		||||
     * @param {Function} closeConnection
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    // @java-patch sync handshake
 | 
			
		||||
    handshake(transportName, req, closeConnection: (code: number) => void) {
 | 
			
		||||
        console.debug('engine.io server handshake transport', transportName, 'from', req.url)
 | 
			
		||||
        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 = this.generateId(req)
 | 
			
		||||
        } catch (error: any) {
 | 
			
		||||
            console.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
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            closeConnection(Server.errors.BAD_REQUEST)
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        console.debug('engine.io server handshaking client "' + id + '"')
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            var transport: Transport = new transports[transportName](req)
 | 
			
		||||
            if ("websocket" !== transportName) {
 | 
			
		||||
                throw new Error('Unsupport polling at MiaoScript!')
 | 
			
		||||
            }
 | 
			
		||||
            // if ("polling" === transportName) {
 | 
			
		||||
            //     transport.maxHttpBufferSize = this.opts.maxHttpBufferSize
 | 
			
		||||
            //     transport.httpCompression = this.opts.httpCompression
 | 
			
		||||
            // } else if ("websocket" === transportName) {
 | 
			
		||||
            transport.perMessageDeflate = this.opts.perMessageDeflate
 | 
			
		||||
            // }
 | 
			
		||||
 | 
			
		||||
            if (req._query && req._query.b64) {
 | 
			
		||||
                transport.supportsBinary = false
 | 
			
		||||
            } else {
 | 
			
		||||
                transport.supportsBinary = true
 | 
			
		||||
            }
 | 
			
		||||
        } catch (e: any) {
 | 
			
		||||
            console.ex(e)
 | 
			
		||||
            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
 | 
			
		||||
        }
 | 
			
		||||
        console.debug(`engine.io server create socket ${id} from transport ${transport.name} protocol ${protocol}`)
 | 
			
		||||
        const socket = new 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"] = [
 | 
			
		||||
                        // cookieMod.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)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // /**
 | 
			
		||||
    //  * Handles an Engine.IO HTTP Upgrade.
 | 
			
		||||
    //  *
 | 
			
		||||
    //  * @api public
 | 
			
		||||
    //  */
 | 
			
		||||
    // handleUpgrade(req, socket, upgradeHead) {
 | 
			
		||||
    // public handleUpgrade(req, socket, upgradeHead) {
 | 
			
		||||
    //     this.prepare(req)
 | 
			
		||||
 | 
			
		||||
    //     this.verify(req, true, (errorCode, errorContext) => {
 | 
			
		||||
@@ -423,7 +564,7 @@ export class Server extends EventEmitter {
 | 
			
		||||
    //             return
 | 
			
		||||
    //         }
 | 
			
		||||
 | 
			
		||||
    //         const head = Buffer.from(upgradeHead) // eslint-disable-line node/no-deprecated-api
 | 
			
		||||
    //         const head = Buffer.from(upgradeHead)
 | 
			
		||||
    //         upgradeHead = null
 | 
			
		||||
 | 
			
		||||
    //         // delegate to ws
 | 
			
		||||
@@ -439,14 +580,14 @@ export class Server extends EventEmitter {
 | 
			
		||||
     * @param {ws.Socket} websocket
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    onWebSocket(req: Request, socket, websocket: WebSocketClient) {
 | 
			
		||||
    private onWebSocket(req: Request, socket, websocket: WebSocketClient) {
 | 
			
		||||
        websocket.on("error", onUpgradeError)
 | 
			
		||||
 | 
			
		||||
        if (
 | 
			
		||||
            transports[req._query.transport] !== undefined &&
 | 
			
		||||
            !transports[req._query.transport].prototype.handlesUpgrades
 | 
			
		||||
        ) {
 | 
			
		||||
            console.debug("transport doesnt handle upgraded requests")
 | 
			
		||||
            debug("transport doesnt handle upgraded requests")
 | 
			
		||||
            websocket.close()
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
@@ -460,40 +601,37 @@ export class Server extends EventEmitter {
 | 
			
		||||
        if (id) {
 | 
			
		||||
            const client = this.clients[id]
 | 
			
		||||
            if (!client) {
 | 
			
		||||
                console.debug("upgrade attempt for closed client")
 | 
			
		||||
                debug("upgrade attempt for closed client")
 | 
			
		||||
                websocket.close()
 | 
			
		||||
            } else if (client.upgrading) {
 | 
			
		||||
                console.debug("transport has already been trying to upgrade")
 | 
			
		||||
                debug("transport has already been trying to upgrade")
 | 
			
		||||
                websocket.close()
 | 
			
		||||
            } else if (client.upgraded) {
 | 
			
		||||
                console.debug("transport had already been upgraded")
 | 
			
		||||
                debug("transport had already been upgraded")
 | 
			
		||||
                websocket.close()
 | 
			
		||||
            } else {
 | 
			
		||||
                console.debug("upgrading existing transport")
 | 
			
		||||
                debug("upgrading existing transport")
 | 
			
		||||
 | 
			
		||||
                // transport error handling takes over
 | 
			
		||||
                websocket.removeListener("error", onUpgradeError)
 | 
			
		||||
 | 
			
		||||
                const transport = new transports[req._query.transport](req)
 | 
			
		||||
                const transport = this.createTransport(req._query.transport, req)
 | 
			
		||||
                if (req._query && req._query.b64) {
 | 
			
		||||
                    transport.supportsBinary = false
 | 
			
		||||
                } else {
 | 
			
		||||
                    transport.supportsBinary = true
 | 
			
		||||
                }
 | 
			
		||||
                transport.perMessageDeflate = this.perMessageDeflate
 | 
			
		||||
                transport.perMessageDeflate = this.opts.perMessageDeflate
 | 
			
		||||
                client.maybeUpgrade(transport)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            // transport error handling takes over
 | 
			
		||||
            websocket.removeListener("error", onUpgradeError)
 | 
			
		||||
 | 
			
		||||
            // const closeConnection = (errorCode, errorContext) =>
 | 
			
		||||
            //     abortUpgrade(socket, errorCode, errorContext)
 | 
			
		||||
            this.handshake(req._query.transport, req, () => { })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function onUpgradeError() {
 | 
			
		||||
            console.debug("websocket error before upgrade")
 | 
			
		||||
        function onUpgradeError(...args) {
 | 
			
		||||
            debug("websocket error before upgrade %s", ...args)
 | 
			
		||||
            // websocket.close() not needed
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -505,7 +643,9 @@ export class Server extends EventEmitter {
 | 
			
		||||
     * @param {Object} options
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    attach(server, options: any = {}) {
 | 
			
		||||
    // public attach(server: HttpServer, options: AttachOptions = {}) {
 | 
			
		||||
    // @java-patch
 | 
			
		||||
    public attach(server, options: AttachOptions = {}) {
 | 
			
		||||
        // let path = (options.path || "/engine.io").replace(/\/$/, "")
 | 
			
		||||
 | 
			
		||||
        // const destroyUpgradeTimeout = options.destroyUpgradeTimeout || 1000
 | 
			
		||||
@@ -514,7 +654,7 @@ export class Server extends EventEmitter {
 | 
			
		||||
        // path += "/"
 | 
			
		||||
 | 
			
		||||
        // function check(req) {
 | 
			
		||||
        //     return path === req.url.substr(0, path.length)
 | 
			
		||||
        //     return path === req.url.slice(0, path.length)
 | 
			
		||||
        // }
 | 
			
		||||
 | 
			
		||||
        // cache and clean up listeners
 | 
			
		||||
@@ -555,7 +695,11 @@ export class Server extends EventEmitter {
 | 
			
		||||
        //             // 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)
 | 
			
		||||
@@ -601,7 +745,11 @@ export class Server extends EventEmitter {
 | 
			
		||||
//  * @api private
 | 
			
		||||
//  */
 | 
			
		||||
 | 
			
		||||
// function abortUpgrade(socket, errorCode, errorContext: any = {}) {
 | 
			
		||||
// function abortUpgrade(
 | 
			
		||||
//     socket,
 | 
			
		||||
//     errorCode,
 | 
			
		||||
//     errorContext: { message?: string } = {}
 | 
			
		||||
// ) {
 | 
			
		||||
//     socket.on("error", () => {
 | 
			
		||||
//         debug("ignoring error from closed connection")
 | 
			
		||||
//     })
 | 
			
		||||
@@ -622,8 +770,6 @@ export class Server extends EventEmitter {
 | 
			
		||||
//     socket.destroy()
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// module.exports = Server
 | 
			
		||||
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
 | 
			
		||||
// /**
 | 
			
		||||
 
 | 
			
		||||
@@ -1,38 +1,63 @@
 | 
			
		||||
import { EventEmitter } from "events"
 | 
			
		||||
import { Server } from "./server"
 | 
			
		||||
// import debugModule from "debug"
 | 
			
		||||
// import { IncomingMessage } from "http"
 | 
			
		||||
import { Transport } from "./transport"
 | 
			
		||||
import type { Request } from "../server/request"
 | 
			
		||||
// const debug = require("debug")("engine:socket")
 | 
			
		||||
import { Server } from "./server"
 | 
			
		||||
// import { setTimeout, clearTimeout } from "timers"
 | 
			
		||||
// import { Packet, PacketType, RawData } from "engine.io-parser"
 | 
			
		||||
import { Packet, PacketType, RawData } from "../engine.io-parser"
 | 
			
		||||
 | 
			
		||||
// const debug = debugModule("engine:socket")
 | 
			
		||||
const debug = require('../debug')("engine:socket")
 | 
			
		||||
 | 
			
		||||
export class Socket extends EventEmitter {
 | 
			
		||||
    public id: string
 | 
			
		||||
    private server: Server
 | 
			
		||||
    private upgrading = false
 | 
			
		||||
    private upgraded = false
 | 
			
		||||
    public readyState = "opening"
 | 
			
		||||
    private writeBuffer = []
 | 
			
		||||
    private packetsFn = []
 | 
			
		||||
    private sentCallbackFn = []
 | 
			
		||||
    private cleanupFn = []
 | 
			
		||||
    public request: Request
 | 
			
		||||
    public protocol: number
 | 
			
		||||
    public remoteAddress: any
 | 
			
		||||
    public readonly protocol: number
 | 
			
		||||
    // public readonly request: IncomingMessage
 | 
			
		||||
    public readonly request: any
 | 
			
		||||
    public readonly remoteAddress: string
 | 
			
		||||
 | 
			
		||||
    public _readyState: string
 | 
			
		||||
    public transport: Transport
 | 
			
		||||
 | 
			
		||||
    private checkIntervalTimer: NodeJS.Timeout
 | 
			
		||||
    private upgradeTimeoutTimer: NodeJS.Timeout
 | 
			
		||||
    private pingTimeoutTimer: NodeJS.Timeout
 | 
			
		||||
    private pingIntervalTimer: NodeJS.Timeout
 | 
			
		||||
    private server: Server
 | 
			
		||||
    private upgrading: boolean
 | 
			
		||||
    private upgraded: boolean
 | 
			
		||||
    private writeBuffer: Packet[]
 | 
			
		||||
    private packetsFn: any[]
 | 
			
		||||
    private sentCallbackFn: any[]
 | 
			
		||||
    private cleanupFn: any[]
 | 
			
		||||
    private checkIntervalTimer
 | 
			
		||||
    private upgradeTimeoutTimer
 | 
			
		||||
    private pingTimeoutTimer
 | 
			
		||||
    private pingIntervalTimer
 | 
			
		||||
 | 
			
		||||
    private readonly id: string
 | 
			
		||||
 | 
			
		||||
    get readyState() {
 | 
			
		||||
        return this._readyState
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set readyState(state) {
 | 
			
		||||
        debug("readyState updated from %s to %s", this._readyState, state)
 | 
			
		||||
        this._readyState = state
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Client class (abstract).
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    constructor(id: string, server: Server, transport: Transport, req: Request, protocol: number) {
 | 
			
		||||
    constructor(id, server, transport, req, protocol) {
 | 
			
		||||
        super()
 | 
			
		||||
        this.id = id
 | 
			
		||||
        this.server = server
 | 
			
		||||
        this.upgrading = false
 | 
			
		||||
        this.upgraded = false
 | 
			
		||||
        this.readyState = "opening"
 | 
			
		||||
        this.writeBuffer = []
 | 
			
		||||
        this.packetsFn = []
 | 
			
		||||
        this.sentCallbackFn = []
 | 
			
		||||
        this.cleanupFn = []
 | 
			
		||||
        this.request = req
 | 
			
		||||
        this.protocol = protocol
 | 
			
		||||
 | 
			
		||||
@@ -57,7 +82,7 @@ export class Socket extends EventEmitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    onOpen() {
 | 
			
		||||
    private onOpen() {
 | 
			
		||||
        this.readyState = "open"
 | 
			
		||||
 | 
			
		||||
        // sends an `open` packet
 | 
			
		||||
@@ -68,7 +93,8 @@ export class Socket extends EventEmitter {
 | 
			
		||||
                sid: this.id,
 | 
			
		||||
                upgrades: this.getAvailableUpgrades(),
 | 
			
		||||
                pingInterval: this.server.opts.pingInterval,
 | 
			
		||||
                pingTimeout: this.server.opts.pingTimeout
 | 
			
		||||
                pingTimeout: this.server.opts.pingTimeout,
 | 
			
		||||
                maxPayload: this.server.opts.maxHttpBufferSize
 | 
			
		||||
            })
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
@@ -95,13 +121,12 @@ export class Socket extends EventEmitter {
 | 
			
		||||
     * @param {Object} packet
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    onPacket(packet: { type: any; data: any }) {
 | 
			
		||||
    private onPacket(packet: Packet) {
 | 
			
		||||
        if ("open" !== this.readyState) {
 | 
			
		||||
            console.debug("packet received with closed socket")
 | 
			
		||||
            return
 | 
			
		||||
            return debug("packet received with closed socket")
 | 
			
		||||
        }
 | 
			
		||||
        // export packet event
 | 
			
		||||
        // debug(`received packet ${packet.type}`)
 | 
			
		||||
        debug(`received packet ${packet.type}`)
 | 
			
		||||
        this.emit("packet", packet)
 | 
			
		||||
 | 
			
		||||
        // Reset ping timeout on any packet, incoming data is a good sign of
 | 
			
		||||
@@ -116,7 +141,7 @@ export class Socket extends EventEmitter {
 | 
			
		||||
                    this.onError("invalid heartbeat direction")
 | 
			
		||||
                    return
 | 
			
		||||
                }
 | 
			
		||||
                // debug("got ping")
 | 
			
		||||
                debug("got ping")
 | 
			
		||||
                this.sendPacket("pong")
 | 
			
		||||
                this.emit("heartbeat")
 | 
			
		||||
                break
 | 
			
		||||
@@ -126,7 +151,8 @@ export class Socket extends EventEmitter {
 | 
			
		||||
                    this.onError("invalid heartbeat direction")
 | 
			
		||||
                    return
 | 
			
		||||
                }
 | 
			
		||||
                // debug("got pong")
 | 
			
		||||
                debug("got pong")
 | 
			
		||||
                // this.pingIntervalTimer.refresh()
 | 
			
		||||
                this.schedulePing()
 | 
			
		||||
                this.emit("heartbeat")
 | 
			
		||||
                break
 | 
			
		||||
@@ -148,8 +174,8 @@ export class Socket extends EventEmitter {
 | 
			
		||||
     * @param {Error} error object
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    onError(err: string) {
 | 
			
		||||
        // debug("transport error")
 | 
			
		||||
    private onError(err) {
 | 
			
		||||
        debug("transport error")
 | 
			
		||||
        this.onClose("transport error", err)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -159,13 +185,12 @@ export class Socket extends EventEmitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    schedulePing() {
 | 
			
		||||
        clearTimeout(this.pingIntervalTimer)
 | 
			
		||||
    private schedulePing() {
 | 
			
		||||
        this.pingIntervalTimer = setTimeout(() => {
 | 
			
		||||
            // debug(
 | 
			
		||||
            //     "writing ping packet - expecting pong within %sms",
 | 
			
		||||
            //     this.server.opts.pingTimeout
 | 
			
		||||
            // )
 | 
			
		||||
            debug(
 | 
			
		||||
                "writing ping packet - expecting pong within %sms",
 | 
			
		||||
                this.server.opts.pingTimeout
 | 
			
		||||
            )
 | 
			
		||||
            this.sendPacket("ping")
 | 
			
		||||
            this.resetPingTimeout(this.server.opts.pingTimeout)
 | 
			
		||||
        }, this.server.opts.pingInterval)
 | 
			
		||||
@@ -176,7 +201,7 @@ export class Socket extends EventEmitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    resetPingTimeout(timeout: number) {
 | 
			
		||||
    private resetPingTimeout(timeout) {
 | 
			
		||||
        clearTimeout(this.pingTimeoutTimer)
 | 
			
		||||
        this.pingTimeoutTimer = setTimeout(() => {
 | 
			
		||||
            if (this.readyState === "closed") return
 | 
			
		||||
@@ -190,8 +215,7 @@ export class Socket extends EventEmitter {
 | 
			
		||||
     * @param {Transport} transport
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    setTransport(transport: Transport) {
 | 
			
		||||
        console.debug(`engine.io socket ${this.id} set transport ${transport.name}`)
 | 
			
		||||
    private setTransport(transport) {
 | 
			
		||||
        const onError = this.onError.bind(this)
 | 
			
		||||
        const onPacket = this.onPacket.bind(this)
 | 
			
		||||
        const flush = this.flush.bind(this)
 | 
			
		||||
@@ -219,30 +243,33 @@ export class Socket extends EventEmitter {
 | 
			
		||||
     * @param {Transport} transport
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    maybeUpgrade(transport: Transport) {
 | 
			
		||||
        console.debug(
 | 
			
		||||
            'might upgrade socket transport from "', this.transport.name, '" to "', transport.name, '"'
 | 
			
		||||
    private maybeUpgrade(transport) {
 | 
			
		||||
        debug(
 | 
			
		||||
            'might upgrade socket transport from "%s" to "%s"',
 | 
			
		||||
            this.transport.name,
 | 
			
		||||
            transport.name
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        this.upgrading = true
 | 
			
		||||
 | 
			
		||||
        // set transport upgrade timer
 | 
			
		||||
        this.upgradeTimeoutTimer = setTimeout(() => {
 | 
			
		||||
            console.debug("client did not complete upgrade - closing transport")
 | 
			
		||||
            debug("client did not complete upgrade - closing transport")
 | 
			
		||||
            cleanup()
 | 
			
		||||
            if ("open" === transport.readyState) {
 | 
			
		||||
                transport.close()
 | 
			
		||||
            }
 | 
			
		||||
        }, this.server.opts.upgradeTimeout)
 | 
			
		||||
 | 
			
		||||
        const onPacket = (packet: { type: string; data: string }) => {
 | 
			
		||||
        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(this.checkIntervalTimer)
 | 
			
		||||
                this.checkIntervalTimer = setInterval(check, 100)
 | 
			
		||||
            } else if ("upgrade" === packet.type && this.readyState !== "closed") {
 | 
			
		||||
                // debug("got upgrade packet - upgrading")
 | 
			
		||||
                debug("got upgrade packet - upgrading")
 | 
			
		||||
                cleanup()
 | 
			
		||||
                this.transport.discard()
 | 
			
		||||
                this.upgraded = true
 | 
			
		||||
@@ -264,7 +291,7 @@ export class Socket extends EventEmitter {
 | 
			
		||||
        // 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")
 | 
			
		||||
                debug("writing a noop packet to polling for fast upgrade")
 | 
			
		||||
                this.transport.send([{ type: "noop" }])
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -284,8 +311,8 @@ export class Socket extends EventEmitter {
 | 
			
		||||
            this.removeListener("close", onClose)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const onError = (err: string) => {
 | 
			
		||||
            // debug("client did not complete upgrade - %s", err)
 | 
			
		||||
        const onError = err => {
 | 
			
		||||
            debug("client did not complete upgrade - %s", err)
 | 
			
		||||
            cleanup()
 | 
			
		||||
            transport.close()
 | 
			
		||||
            transport = null
 | 
			
		||||
@@ -311,8 +338,8 @@ export class Socket extends EventEmitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    clearTransport() {
 | 
			
		||||
        let cleanup: () => void
 | 
			
		||||
    private clearTransport() {
 | 
			
		||||
        let cleanup
 | 
			
		||||
 | 
			
		||||
        const toCleanUp = this.cleanupFn.length
 | 
			
		||||
 | 
			
		||||
@@ -323,7 +350,7 @@ export class Socket extends EventEmitter {
 | 
			
		||||
 | 
			
		||||
        // silence further transport errors and prevent uncaught exceptions
 | 
			
		||||
        this.transport.on("error", function () {
 | 
			
		||||
            // debug("error triggered by discarded transport")
 | 
			
		||||
            debug("error triggered by discarded transport")
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        // ensure transport won't stay open
 | 
			
		||||
@@ -337,7 +364,7 @@ export class Socket extends EventEmitter {
 | 
			
		||||
     * Possible reasons: `ping timeout`, `client error`, `parse error`,
 | 
			
		||||
     * `transport error`, `server close`, `transport close`
 | 
			
		||||
     */
 | 
			
		||||
    onClose(reason: string, description?: string) {
 | 
			
		||||
    private onClose(reason: string, description?) {
 | 
			
		||||
        if ("closed" !== this.readyState) {
 | 
			
		||||
            this.readyState = "closed"
 | 
			
		||||
 | 
			
		||||
@@ -365,16 +392,16 @@ export class Socket extends EventEmitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    setupSendCallback() {
 | 
			
		||||
    private setupSendCallback() {
 | 
			
		||||
        // the message was sent successfully, execute the callback
 | 
			
		||||
        const onDrain = () => {
 | 
			
		||||
            if (this.sentCallbackFn.length > 0) {
 | 
			
		||||
                const seqFn = this.sentCallbackFn.splice(0, 1)[0]
 | 
			
		||||
                if ("function" === typeof seqFn) {
 | 
			
		||||
                    // debug("executing send callback")
 | 
			
		||||
                    debug("executing send callback")
 | 
			
		||||
                    seqFn(this.transport)
 | 
			
		||||
                } else if (Array.isArray(seqFn)) {
 | 
			
		||||
                    // debug("executing batch send callback")
 | 
			
		||||
                    debug("executing batch send callback")
 | 
			
		||||
                    const l = seqFn.length
 | 
			
		||||
                    let i = 0
 | 
			
		||||
                    for (; i < l; i++) {
 | 
			
		||||
@@ -396,18 +423,18 @@ export class Socket extends EventEmitter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a message packet.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String} message
 | 
			
		||||
     * @param {Object} data
 | 
			
		||||
     * @param {Object} options
 | 
			
		||||
     * @param {Function} callback
 | 
			
		||||
     * @return {Socket} for chaining
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    send(data: any, options: any, callback: any) {
 | 
			
		||||
    public send(data, options, callback?) {
 | 
			
		||||
        this.sendPacket("message", data, options, callback)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    write(data: any, options: any, callback?: any) {
 | 
			
		||||
    public write(data, options, callback?) {
 | 
			
		||||
        this.sendPacket("message", data, options, callback)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
@@ -415,12 +442,14 @@ export class Socket extends EventEmitter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a packet.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String} packet type
 | 
			
		||||
     * @param {String} optional, data
 | 
			
		||||
     * @param {String} type - packet type
 | 
			
		||||
     * @param {String} data
 | 
			
		||||
     * @param {Object} options
 | 
			
		||||
     * @param {Function} callback
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    sendPacket(type: string, data?: string, options?: { compress?: any }, callback?: undefined) {
 | 
			
		||||
    private sendPacket(type: PacketType, data?: RawData, options?, callback?) {
 | 
			
		||||
        if ("function" === typeof options) {
 | 
			
		||||
            callback = options
 | 
			
		||||
            options = null
 | 
			
		||||
@@ -430,12 +459,13 @@ export class Socket extends EventEmitter {
 | 
			
		||||
        options.compress = false !== options.compress
 | 
			
		||||
 | 
			
		||||
        if ("closing" !== this.readyState && "closed" !== this.readyState) {
 | 
			
		||||
            // console.debug('sending packet "%s" (%s)', type, data)
 | 
			
		||||
            debug('sending packet "%s" (%s)', type, data)
 | 
			
		||||
 | 
			
		||||
            const packet: any = {
 | 
			
		||||
                type: type,
 | 
			
		||||
                options: options
 | 
			
		||||
            const packet: Packet = {
 | 
			
		||||
                type,
 | 
			
		||||
                options
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (data) packet.data = data
 | 
			
		||||
 | 
			
		||||
            // exports packetCreate event
 | 
			
		||||
@@ -455,13 +485,13 @@ export class Socket extends EventEmitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    flush() {
 | 
			
		||||
    private flush() {
 | 
			
		||||
        if (
 | 
			
		||||
            "closed" !== this.readyState &&
 | 
			
		||||
            this.transport.writable &&
 | 
			
		||||
            this.writeBuffer.length
 | 
			
		||||
        ) {
 | 
			
		||||
            console.trace("flushing buffer to transport")
 | 
			
		||||
            debug("flushing buffer to transport")
 | 
			
		||||
            this.emit("flush", this.writeBuffer)
 | 
			
		||||
            this.server.emit("flush", this, this.writeBuffer)
 | 
			
		||||
            const wbuf = this.writeBuffer
 | 
			
		||||
@@ -483,7 +513,7 @@ export class Socket extends EventEmitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    getAvailableUpgrades() {
 | 
			
		||||
    private getAvailableUpgrades() {
 | 
			
		||||
        const availableUpgrades = []
 | 
			
		||||
        const allUpgrades = this.server.upgrades(this.transport.name)
 | 
			
		||||
        let i = 0
 | 
			
		||||
@@ -500,11 +530,11 @@ export class Socket extends EventEmitter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the socket and underlying transport.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Boolean} optional, discard
 | 
			
		||||
     * @param {Boolean} discard - optional, discard the transport
 | 
			
		||||
     * @return {Socket} for chaining
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    close(discard?: any) {
 | 
			
		||||
    public close(discard?: boolean) {
 | 
			
		||||
        if ("open" !== this.readyState) return
 | 
			
		||||
 | 
			
		||||
        this.readyState = "closing"
 | 
			
		||||
@@ -523,7 +553,7 @@ export class Socket extends EventEmitter {
 | 
			
		||||
     * @param {Boolean} discard
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    closeTransport(discard: any) {
 | 
			
		||||
    private closeTransport(discard) {
 | 
			
		||||
        if (discard) this.transport.discard()
 | 
			
		||||
        this.transport.close(this.onClose.bind(this, "forced close"))
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,13 @@
 | 
			
		||||
import { EventEmitter } from 'events'
 | 
			
		||||
import parser_v4 from "../engine.io-parser"
 | 
			
		||||
import type { WebSocketClient } from '../server/client'
 | 
			
		||||
import { EventEmitter } from "events"
 | 
			
		||||
import * as parser_v4 from "../engine.io-parser"
 | 
			
		||||
import * as parser_v3 from "./parser-v3"
 | 
			
		||||
// import debugModule from "debug"
 | 
			
		||||
import { IncomingMessage } from "http"
 | 
			
		||||
import { Packet } from "../engine.io-parser"
 | 
			
		||||
 | 
			
		||||
// const debug = debugModule("engine:transport")
 | 
			
		||||
const debug = require('../debug')("engine:transport")
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Noop function.
 | 
			
		||||
 *
 | 
			
		||||
@@ -11,15 +18,28 @@ function noop() { }
 | 
			
		||||
 | 
			
		||||
export abstract class Transport extends EventEmitter {
 | 
			
		||||
    public sid: string
 | 
			
		||||
    public req /**http.IncomingMessage */
 | 
			
		||||
    public socket: WebSocketClient
 | 
			
		||||
    public writable: boolean
 | 
			
		||||
    public readyState: string
 | 
			
		||||
    public discarded: boolean
 | 
			
		||||
    public protocol: Number
 | 
			
		||||
    public parser: any
 | 
			
		||||
    public perMessageDeflate: any
 | 
			
		||||
    public supportsBinary: boolean = false
 | 
			
		||||
    public protocol: number
 | 
			
		||||
 | 
			
		||||
    protected _readyState: string
 | 
			
		||||
    protected discarded: boolean
 | 
			
		||||
    protected parser: any
 | 
			
		||||
    protected req: IncomingMessage & { cleanup: Function }
 | 
			
		||||
    protected supportsBinary: boolean
 | 
			
		||||
 | 
			
		||||
    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.
 | 
			
		||||
@@ -32,7 +52,7 @@ export abstract class Transport extends EventEmitter {
 | 
			
		||||
        this.readyState = "open"
 | 
			
		||||
        this.discarded = false
 | 
			
		||||
        this.protocol = req._query.EIO === "4" ? 4 : 3 // 3rd revision by default
 | 
			
		||||
        this.parser = parser_v4//= this.protocol === 4 ? parser_v4 : parser_v3
 | 
			
		||||
        this.parser = this.protocol === 4 ? parser_v4 : parser_v3
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -48,10 +68,10 @@ export abstract class Transport extends EventEmitter {
 | 
			
		||||
     * Called with an incoming HTTP request.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {http.IncomingMessage} request
 | 
			
		||||
     * @api private
 | 
			
		||||
     * @api protected
 | 
			
		||||
     */
 | 
			
		||||
    onRequest(req) {
 | 
			
		||||
        console.debug(`engine.io transport ${this.socket.id} setting request`, JSON.stringify(req))
 | 
			
		||||
    protected onRequest(req) {
 | 
			
		||||
        debug("setting request")
 | 
			
		||||
        this.req = req
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -72,16 +92,18 @@ export abstract class Transport extends EventEmitter {
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String} message error
 | 
			
		||||
     * @param {Object} error description
 | 
			
		||||
     * @api private
 | 
			
		||||
     * @api protected
 | 
			
		||||
     */
 | 
			
		||||
    onError(msg: string, desc?: string) {
 | 
			
		||||
    protected onError(msg: string, desc?) {
 | 
			
		||||
        if (this.listeners("error").length) {
 | 
			
		||||
            const err: any = new Error(msg)
 | 
			
		||||
            const err = new Error(msg)
 | 
			
		||||
            // @ts-ignore
 | 
			
		||||
            err.type = "TransportError"
 | 
			
		||||
            // @ts-ignore
 | 
			
		||||
            err.description = desc
 | 
			
		||||
            this.emit("error", err)
 | 
			
		||||
        } else {
 | 
			
		||||
            console.debug(`ignored transport error ${msg} (${desc})`)
 | 
			
		||||
            debug("ignored transport error %s (%s)", msg, desc)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -89,9 +111,9 @@ export abstract class Transport extends EventEmitter {
 | 
			
		||||
     * Called with parsed out a packets from the data stream.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Object} packet
 | 
			
		||||
     * @api private
 | 
			
		||||
     * @api protected
 | 
			
		||||
     */
 | 
			
		||||
    onPacket(packet) {
 | 
			
		||||
    protected onPacket(packet: Packet) {
 | 
			
		||||
        this.emit("packet", packet)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -99,23 +121,24 @@ export abstract class Transport extends EventEmitter {
 | 
			
		||||
     * Called with the encoded packet data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String} data
 | 
			
		||||
     * @api private
 | 
			
		||||
     * @api protected
 | 
			
		||||
     */
 | 
			
		||||
    onData(data) {
 | 
			
		||||
    protected onData(data) {
 | 
			
		||||
        this.onPacket(this.parser.decodePacket(data))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called upon transport close.
 | 
			
		||||
     *
 | 
			
		||||
     * @api private
 | 
			
		||||
     * @api protected
 | 
			
		||||
     */
 | 
			
		||||
    onClose() {
 | 
			
		||||
    protected onClose() {
 | 
			
		||||
        this.readyState = "closed"
 | 
			
		||||
        this.emit("close")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    abstract get supportsFraming()
 | 
			
		||||
    abstract get name()
 | 
			
		||||
    abstract send(...args: any[])
 | 
			
		||||
    abstract doClose(d: Function)
 | 
			
		||||
    abstract send(packets)
 | 
			
		||||
    abstract doClose(fn?)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,24 @@
 | 
			
		||||
// import { Polling as XHR } from "./polling"
 | 
			
		||||
// import { JSONP } from "./polling-jsonp"
 | 
			
		||||
import { WebSocket } from "./websocket"
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    websocket: require("./websocket").WebSocket
 | 
			
		||||
    // polling: polling,
 | 
			
		||||
    websocket: WebSocket
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// /**
 | 
			
		||||
//  * Polling polymorphic constructor.
 | 
			
		||||
//  *
 | 
			
		||||
//  * @api private
 | 
			
		||||
//  */
 | 
			
		||||
 | 
			
		||||
// function polling(req) {
 | 
			
		||||
//     if ("string" === typeof req._query.j) {
 | 
			
		||||
//         return new JSONP(req)
 | 
			
		||||
//     } else {
 | 
			
		||||
//         return new XHR(req)
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// polling.upgradesTo = ["websocket"]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,11 @@
 | 
			
		||||
import { Transport } from '../transport'
 | 
			
		||||
// const debug = require("debug")("engine:ws")
 | 
			
		||||
import { Transport } from "../transport"
 | 
			
		||||
// import debugModule from "debug";
 | 
			
		||||
 | 
			
		||||
const debug = require('../../debug')("engine:ws")
 | 
			
		||||
 | 
			
		||||
export class WebSocket extends Transport {
 | 
			
		||||
    public perMessageDeflate: any
 | 
			
		||||
    protected perMessageDeflate: any
 | 
			
		||||
    private socket: any
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * WebSocket transport
 | 
			
		||||
@@ -13,7 +16,11 @@ export class WebSocket extends Transport {
 | 
			
		||||
    constructor(req) {
 | 
			
		||||
        super(req)
 | 
			
		||||
        this.socket = req.websocket
 | 
			
		||||
        this.socket.on("message", this.onData.bind(this))
 | 
			
		||||
        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
 | 
			
		||||
@@ -21,10 +28,10 @@ export class WebSocket extends Transport {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Transport name
 | 
			
		||||
     *
 | 
			
		||||
     * @api public
 | 
			
		||||
     */
 | 
			
		||||
    * Transport name
 | 
			
		||||
    *
 | 
			
		||||
    * @api public
 | 
			
		||||
    */
 | 
			
		||||
    get name() {
 | 
			
		||||
        return "websocket"
 | 
			
		||||
    }
 | 
			
		||||
@@ -47,17 +54,6 @@ export class WebSocket extends Transport {
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Processes the incoming data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String} encoded packet
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    onData(data) {
 | 
			
		||||
        // debug('received "%s"', data)
 | 
			
		||||
        super.onData(data)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Writes a packet payload.
 | 
			
		||||
     *
 | 
			
		||||
@@ -65,7 +61,6 @@ export class WebSocket extends Transport {
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    send(packets) {
 | 
			
		||||
        // console.log('WebSocket send packets', JSON.stringify(packets))
 | 
			
		||||
        const packet = packets.shift()
 | 
			
		||||
        if (typeof packet === "undefined") {
 | 
			
		||||
            this.writable = true
 | 
			
		||||
@@ -74,7 +69,7 @@ export class WebSocket extends Transport {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // always creates a new object since ws modifies it
 | 
			
		||||
        const opts: any = {}
 | 
			
		||||
        const opts: { compress?: boolean } = {}
 | 
			
		||||
        if (packet.options) {
 | 
			
		||||
            opts.compress = packet.options.compress
 | 
			
		||||
        }
 | 
			
		||||
@@ -87,7 +82,7 @@ export class WebSocket extends Transport {
 | 
			
		||||
                    opts.compress = false
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            console.trace('writing', data)
 | 
			
		||||
            debug('writing "%s"', data)
 | 
			
		||||
            this.writable = false
 | 
			
		||||
 | 
			
		||||
            this.socket.send(data, opts, err => {
 | 
			
		||||
@@ -109,7 +104,7 @@ export class WebSocket extends Transport {
 | 
			
		||||
     * @api private
 | 
			
		||||
     */
 | 
			
		||||
    doClose(fn) {
 | 
			
		||||
        // debug("closing")
 | 
			
		||||
        debug("closing")
 | 
			
		||||
        this.socket.close()
 | 
			
		||||
        fn && fn()
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
import { EventEmitter } from "events"
 | 
			
		||||
 | 
			
		||||
export type SocketId = string
 | 
			
		||||
// we could extend the Room type to "string | number", but that would be a breaking change
 | 
			
		||||
// related: https://github.com/socketio/socket.io-redis-adapter/issues/418
 | 
			
		||||
export type Room = string
 | 
			
		||||
 | 
			
		||||
export interface BroadcastFlags {
 | 
			
		||||
@@ -9,11 +11,12 @@ export interface BroadcastFlags {
 | 
			
		||||
    local?: boolean
 | 
			
		||||
    broadcast?: boolean
 | 
			
		||||
    binary?: boolean
 | 
			
		||||
    timeout?: number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BroadcastOptions {
 | 
			
		||||
    rooms: Set<Room>
 | 
			
		||||
    except?: Set<SocketId>
 | 
			
		||||
    except?: Set<Room>
 | 
			
		||||
    flags?: BroadcastFlags
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -42,6 +45,15 @@ export class Adapter extends EventEmitter {
 | 
			
		||||
     */
 | 
			
		||||
    public close(): Promise<void> | void { }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the number of Socket.IO servers in the cluster
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public serverCount(): Promise<number> {
 | 
			
		||||
        return Promise.resolve(1)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a socket to a list of room.
 | 
			
		||||
     *
 | 
			
		||||
@@ -82,14 +94,14 @@ export class Adapter extends EventEmitter {
 | 
			
		||||
        this._del(room, id)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private _del(room, id) {
 | 
			
		||||
        if (this.rooms.has(room)) {
 | 
			
		||||
            const deleted = this.rooms.get(room).delete(id)
 | 
			
		||||
    private _del(room: Room, id: SocketId) {
 | 
			
		||||
        const _room = this.rooms.get(room)
 | 
			
		||||
        if (_room != null) {
 | 
			
		||||
            const deleted = _room.delete(id)
 | 
			
		||||
            if (deleted) {
 | 
			
		||||
                this.emit("leave-room", room, id)
 | 
			
		||||
            }
 | 
			
		||||
            if (this.rooms.get(room).size === 0) {
 | 
			
		||||
                this.rooms.delete(room)
 | 
			
		||||
            if (_room.size === 0 && this.rooms.delete(room)) {
 | 
			
		||||
                this.emit("delete-room", room)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -126,7 +138,7 @@ export class Adapter extends EventEmitter {
 | 
			
		||||
     */
 | 
			
		||||
    public broadcast(packet: any, opts: BroadcastOptions): void {
 | 
			
		||||
        const flags = opts.flags || {}
 | 
			
		||||
        const basePacketOpts = {
 | 
			
		||||
        const packetOpts = {
 | 
			
		||||
            preEncoded: true,
 | 
			
		||||
            volatile: flags.volatile,
 | 
			
		||||
            compress: flags.compress
 | 
			
		||||
@@ -135,22 +147,65 @@ export class Adapter extends EventEmitter {
 | 
			
		||||
        packet.nsp = this.nsp.name
 | 
			
		||||
        const encodedPackets = this.encoder.encode(packet)
 | 
			
		||||
 | 
			
		||||
        const packetOpts = encodedPackets.map(encodedPacket => {
 | 
			
		||||
            if (typeof encodedPacket === "string") {
 | 
			
		||||
                return {
 | 
			
		||||
                    ...basePacketOpts,
 | 
			
		||||
                    wsPreEncoded: "4" + encodedPacket // "4" being the "message" packet type in Engine.IO
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                return basePacketOpts
 | 
			
		||||
        this.apply(opts, socket => {
 | 
			
		||||
            if (typeof socket.notifyOutgoingListeners === "function") {
 | 
			
		||||
                socket.notifyOutgoingListeners(packet)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            socket.client.writeToEngine(encodedPackets, packetOpts)
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Broadcasts a packet and expects multiple acknowledgements.
 | 
			
		||||
     *
 | 
			
		||||
     * Options:
 | 
			
		||||
     *  - `flags` {Object} flags for this packet
 | 
			
		||||
     *  - `except` {Array} sids that should be excluded
 | 
			
		||||
     *  - `rooms` {Array} list of rooms to broadcast to
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Object} packet   the packet object
 | 
			
		||||
     * @param {Object} opts     the options
 | 
			
		||||
     * @param clientCountCallback - the number of clients that received the packet
 | 
			
		||||
     * @param ack                 - the callback that will be called for each client response
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public broadcastWithAck(
 | 
			
		||||
        packet: any,
 | 
			
		||||
        opts: BroadcastOptions,
 | 
			
		||||
        clientCountCallback: (clientCount: number) => void,
 | 
			
		||||
        ack: (...args: any[]) => void
 | 
			
		||||
    ) {
 | 
			
		||||
        const flags = opts.flags || {}
 | 
			
		||||
        const packetOpts = {
 | 
			
		||||
            preEncoded: true,
 | 
			
		||||
            volatile: flags.volatile,
 | 
			
		||||
            compress: flags.compress
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        packet.nsp = this.nsp.name
 | 
			
		||||
        // we can use the same id for each packet, since the _ids counter is common (no duplicate)
 | 
			
		||||
        packet.id = this.nsp._ids++
 | 
			
		||||
 | 
			
		||||
        const encodedPackets = this.encoder.encode(packet)
 | 
			
		||||
 | 
			
		||||
        let clientCount = 0
 | 
			
		||||
 | 
			
		||||
        this.apply(opts, socket => {
 | 
			
		||||
            for (let i = 0; i < encodedPackets.length; i++) {
 | 
			
		||||
                socket.client.writeToEngine(encodedPackets[i], packetOpts[i])
 | 
			
		||||
            // track the total number of acknowledgements that are expected
 | 
			
		||||
            clientCount++
 | 
			
		||||
            // call the ack callback for each client response
 | 
			
		||||
            socket.acks.set(packet.id, ack)
 | 
			
		||||
 | 
			
		||||
            if (typeof socket.notifyOutgoingListeners === "function") {
 | 
			
		||||
                socket.notifyOutgoingListeners(packet)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            socket.client.writeToEngine(encodedPackets, packetOpts)
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        clientCountCallback(clientCount)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -272,7 +327,7 @@ export class Adapter extends EventEmitter {
 | 
			
		||||
     * @param packet - an array of arguments, which may include an acknowledgement callback at the end
 | 
			
		||||
     */
 | 
			
		||||
    public serverSideEmit(packet: any[]): void {
 | 
			
		||||
        throw new Error(
 | 
			
		||||
        console.warn(
 | 
			
		||||
            "this adapter does not support the serverSideEmit() functionality"
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										77
									
								
								packages/websocket/src/socket.io-client/contrib/backo2.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								packages/websocket/src/socket.io-client/contrib/backo2.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Initialize backoff timer with `opts`.
 | 
			
		||||
 *
 | 
			
		||||
 * - `min` initial timeout in milliseconds [100]
 | 
			
		||||
 * - `max` max timeout [10000]
 | 
			
		||||
 * - `jitter` [0]
 | 
			
		||||
 * - `factor` [2]
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Object} opts
 | 
			
		||||
 * @api public
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export function Backoff(this: any, opts) {
 | 
			
		||||
    opts = opts || {}
 | 
			
		||||
    this.ms = opts.min || 100
 | 
			
		||||
    this.max = opts.max || 10000
 | 
			
		||||
    this.factor = opts.factor || 2
 | 
			
		||||
    this.jitter = opts.jitter > 0 && opts.jitter <= 1 ? opts.jitter : 0
 | 
			
		||||
    this.attempts = 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Return the backoff duration.
 | 
			
		||||
 *
 | 
			
		||||
 * @return {Number}
 | 
			
		||||
 * @api public
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
Backoff.prototype.duration = function () {
 | 
			
		||||
    var ms = this.ms * Math.pow(this.factor, this.attempts++)
 | 
			
		||||
    if (this.jitter) {
 | 
			
		||||
        var rand = Math.random()
 | 
			
		||||
        var deviation = Math.floor(rand * this.jitter * ms)
 | 
			
		||||
        ms = (Math.floor(rand * 10) & 1) == 0 ? ms - deviation : ms + deviation
 | 
			
		||||
    }
 | 
			
		||||
    return Math.min(ms, this.max) | 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Reset the number of attempts.
 | 
			
		||||
 *
 | 
			
		||||
 * @api public
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
Backoff.prototype.reset = function () {
 | 
			
		||||
    this.attempts = 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Set the minimum duration
 | 
			
		||||
 *
 | 
			
		||||
 * @api public
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
Backoff.prototype.setMin = function (min) {
 | 
			
		||||
    this.ms = min
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Set the maximum duration
 | 
			
		||||
 *
 | 
			
		||||
 * @api public
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
Backoff.prototype.setMax = function (max) {
 | 
			
		||||
    this.max = max
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Set the jitter
 | 
			
		||||
 *
 | 
			
		||||
 * @api public
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
Backoff.prototype.setJitter = function (jitter) {
 | 
			
		||||
    this.jitter = jitter
 | 
			
		||||
}
 | 
			
		||||
@@ -4,16 +4,10 @@ import { Socket, SocketOptions } from "./socket"
 | 
			
		||||
 | 
			
		||||
const debug = require("../debug")("socket.io-client")
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Module exports.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
module.exports = exports = lookup
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Managers cache.
 | 
			
		||||
 */
 | 
			
		||||
const cache: Record<string, Manager> = (exports.managers = {})
 | 
			
		||||
const cache: Record<string, Manager> = {}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Looks up an existing `Manager` for multiplexing.
 | 
			
		||||
@@ -76,6 +70,15 @@ function lookup(
 | 
			
		||||
    return io.socket(parsed.path, opts)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// so that "lookup" can be used both as a function (e.g. `io(...)`) and as a
 | 
			
		||||
// namespace (e.g. `io.connect(...)`), for backward compatibility
 | 
			
		||||
Object.assign(lookup, {
 | 
			
		||||
    Manager,
 | 
			
		||||
    Socket,
 | 
			
		||||
    io: lookup,
 | 
			
		||||
    connect: lookup,
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Protocol version.
 | 
			
		||||
 *
 | 
			
		||||
@@ -84,22 +87,18 @@ function lookup(
 | 
			
		||||
 | 
			
		||||
export { protocol } from "../socket.io-parser"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * `connect`.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {String} uri
 | 
			
		||||
 * @public
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
exports.connect = lookup
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Expose constructors for standalone build.
 | 
			
		||||
 *
 | 
			
		||||
 * @public
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export { Manager, ManagerOptions } from "./manager"
 | 
			
		||||
export { Socket } from "./socket"
 | 
			
		||||
export { lookup as io, SocketOptions }
 | 
			
		||||
export default lookup
 | 
			
		||||
export {
 | 
			
		||||
    Manager,
 | 
			
		||||
    ManagerOptions,
 | 
			
		||||
    Socket,
 | 
			
		||||
    SocketOptions,
 | 
			
		||||
    lookup as io,
 | 
			
		||||
    lookup as connect,
 | 
			
		||||
    lookup as default,
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,210 +1,26 @@
 | 
			
		||||
import eio from "../engine.io-client"
 | 
			
		||||
import { Socket, SocketOptions } from "./socket"
 | 
			
		||||
import {
 | 
			
		||||
    Socket as Engine,
 | 
			
		||||
    SocketOptions as EngineOptions,
 | 
			
		||||
    installTimerFunctions,
 | 
			
		||||
    nextTick,
 | 
			
		||||
} from "../engine.io-client"
 | 
			
		||||
import { Socket, SocketOptions, DisconnectDescription } from "./socket.js"
 | 
			
		||||
// import * as parser from "socket.io-parser"
 | 
			
		||||
import * as parser from "../socket.io-parser"
 | 
			
		||||
// import { Decoder, Encoder, Packet } from "socket.io-parser"
 | 
			
		||||
import { Decoder, Encoder, Packet } from "../socket.io-parser"
 | 
			
		||||
import { on } from "./on"
 | 
			
		||||
import * as Backoff from "backo2"
 | 
			
		||||
import { on } from "./on.js"
 | 
			
		||||
import { Backoff } from "./contrib/backo2"
 | 
			
		||||
import {
 | 
			
		||||
    DefaultEventsMap,
 | 
			
		||||
    EventsMap,
 | 
			
		||||
    StrictEventEmitter,
 | 
			
		||||
} from "./typed-events"
 | 
			
		||||
    Emitter,
 | 
			
		||||
} from "@socket.io/component-emitter"
 | 
			
		||||
// import debugModule from "debug" // debug()
 | 
			
		||||
 | 
			
		||||
// const debug = debugModule("socket.io-client:manager") // debug()
 | 
			
		||||
const debug = require("../debug")("socket.io-client")
 | 
			
		||||
 | 
			
		||||
interface EngineOptions {
 | 
			
		||||
    /**
 | 
			
		||||
     * The host that we're connecting to. Set from the URI passed when connecting
 | 
			
		||||
     */
 | 
			
		||||
    host: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The hostname for our connection. Set from the URI passed when connecting
 | 
			
		||||
     */
 | 
			
		||||
    hostname: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * If this is a secure connection. Set from the URI passed when connecting
 | 
			
		||||
     */
 | 
			
		||||
    secure: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The port for our connection. Set from the URI passed when connecting
 | 
			
		||||
     */
 | 
			
		||||
    port: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Any query parameters in our uri. Set from the URI passed when connecting
 | 
			
		||||
     */
 | 
			
		||||
    query: { [key: string]: string }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * `http.Agent` to use, defaults to `false` (NodeJS only)
 | 
			
		||||
     */
 | 
			
		||||
    agent: string | boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether the client should try to upgrade the transport from
 | 
			
		||||
     * long-polling to something better.
 | 
			
		||||
     * @default true
 | 
			
		||||
     */
 | 
			
		||||
    upgrade: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Forces JSONP for polling transport.
 | 
			
		||||
     */
 | 
			
		||||
    forceJSONP: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determines whether to use JSONP when necessary for polling. If
 | 
			
		||||
     * disabled (by settings to false) an error will be emitted (saying
 | 
			
		||||
     * "No transports available") if no other transports are available.
 | 
			
		||||
     * If another transport is available for opening a connection (e.g.
 | 
			
		||||
     * WebSocket) that transport will be used instead.
 | 
			
		||||
     * @default true
 | 
			
		||||
     */
 | 
			
		||||
    jsonp: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Forces base 64 encoding for polling transport even when XHR2
 | 
			
		||||
     * responseType is available and WebSocket even if the used standard
 | 
			
		||||
     * supports binary.
 | 
			
		||||
     */
 | 
			
		||||
    forceBase64: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Enables XDomainRequest for IE8 to avoid loading bar flashing with
 | 
			
		||||
     * click sound. default to `false` because XDomainRequest has a flaw
 | 
			
		||||
     * of not sending cookie.
 | 
			
		||||
     * @default false
 | 
			
		||||
     */
 | 
			
		||||
    enablesXDR: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The param name to use as our timestamp key
 | 
			
		||||
     * @default 't'
 | 
			
		||||
     */
 | 
			
		||||
    timestampParam: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether to add the timestamp with each transport request. Note: this
 | 
			
		||||
     * is ignored if the browser is IE or Android, in which case requests
 | 
			
		||||
     * are always stamped
 | 
			
		||||
     * @default false
 | 
			
		||||
     */
 | 
			
		||||
    timestampRequests: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A list of transports to try (in order). Engine.io always attempts to
 | 
			
		||||
     * connect directly with the first one, provided the feature detection test
 | 
			
		||||
     * for it passes.
 | 
			
		||||
     * @default ['polling','websocket']
 | 
			
		||||
     */
 | 
			
		||||
    transports: string[]
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The port the policy server listens on
 | 
			
		||||
     * @default 843
 | 
			
		||||
     */
 | 
			
		||||
    policyPost: number
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * If true and if the previous websocket connection to the server succeeded,
 | 
			
		||||
     * the connection attempt will bypass the normal upgrade process and will
 | 
			
		||||
     * initially try websocket. A connection attempt following a transport error
 | 
			
		||||
     * will use the normal upgrade process. It is recommended you turn this on
 | 
			
		||||
     * only when using SSL/TLS connections, or if you know that your network does
 | 
			
		||||
     * not block websockets.
 | 
			
		||||
     * @default false
 | 
			
		||||
     */
 | 
			
		||||
    rememberUpgrade: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Are we only interested in transports that support binary?
 | 
			
		||||
     */
 | 
			
		||||
    onlyBinaryUpgrades: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Timeout for xhr-polling requests in milliseconds (0) (only for polling transport)
 | 
			
		||||
     */
 | 
			
		||||
    requestTimeout: number
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Transport options for Node.js client (headers etc)
 | 
			
		||||
     */
 | 
			
		||||
    transportOptions: Object
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * (SSL) Certificate, Private key and CA certificates to use for SSL.
 | 
			
		||||
     * Can be used in Node.js client environment to manually specify
 | 
			
		||||
     * certificate information.
 | 
			
		||||
     */
 | 
			
		||||
    pfx: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * (SSL) Private key to use for SSL. Can be used in Node.js client
 | 
			
		||||
     * environment to manually specify certificate information.
 | 
			
		||||
     */
 | 
			
		||||
    key: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * (SSL) A string or passphrase for the private key or pfx. Can be
 | 
			
		||||
     * used in Node.js client environment to manually specify certificate
 | 
			
		||||
     * information.
 | 
			
		||||
     */
 | 
			
		||||
    passphrase: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * (SSL) Public x509 certificate to use. Can be used in Node.js client
 | 
			
		||||
     * environment to manually specify certificate information.
 | 
			
		||||
     */
 | 
			
		||||
    cert: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * (SSL) An authority certificate or array of authority certificates to
 | 
			
		||||
     * check the remote host against.. Can be used in Node.js client
 | 
			
		||||
     * environment to manually specify certificate information.
 | 
			
		||||
     */
 | 
			
		||||
    ca: string | string[]
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * (SSL) A string describing the ciphers to use or exclude. Consult the
 | 
			
		||||
     * [cipher format list]
 | 
			
		||||
     * (http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT) for
 | 
			
		||||
     * details on the format.. Can be used in Node.js client environment to
 | 
			
		||||
     * manually specify certificate information.
 | 
			
		||||
     */
 | 
			
		||||
    ciphers: string
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * (SSL) If true, the server certificate is verified against the list of
 | 
			
		||||
     * supplied CAs. An 'error' event is emitted if verification fails.
 | 
			
		||||
     * Verification happens at the connection level, before the HTTP request
 | 
			
		||||
     * is sent. Can be used in Node.js client environment to manually specify
 | 
			
		||||
     * certificate information.
 | 
			
		||||
     */
 | 
			
		||||
    rejectUnauthorized: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Headers that will be passed for each request to the server (via xhr-polling and via websockets).
 | 
			
		||||
     * These values then can be used during handshake or for special proxies.
 | 
			
		||||
     */
 | 
			
		||||
    extraHeaders?: { [header: string]: string }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether to include credentials (cookies, authorization headers, TLS
 | 
			
		||||
     * client certificates, etc.) with cross-origin XHR polling requests
 | 
			
		||||
     * @default false
 | 
			
		||||
     */
 | 
			
		||||
    withCredentials: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether to automatically close the connection whenever the beforeunload event is received.
 | 
			
		||||
     * @default true
 | 
			
		||||
     */
 | 
			
		||||
    closeOnBeforeunload: boolean
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ManagerOptions extends EngineOptions {
 | 
			
		||||
    /**
 | 
			
		||||
     * Should we force a new Manager for this connection?
 | 
			
		||||
@@ -267,13 +83,6 @@ export interface ManagerOptions extends EngineOptions {
 | 
			
		||||
     */
 | 
			
		||||
    autoConnect: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * weather we should unref the reconnect timer when it is
 | 
			
		||||
     * create automatically
 | 
			
		||||
     * @default false
 | 
			
		||||
     */
 | 
			
		||||
    autoUnref: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * the parser to use. Defaults to an instance of the Parser that ships with socket.io.
 | 
			
		||||
     */
 | 
			
		||||
@@ -285,7 +94,7 @@ interface ManagerReservedEvents {
 | 
			
		||||
    error: (err: Error) => void
 | 
			
		||||
    ping: () => void
 | 
			
		||||
    packet: (packet: Packet) => void
 | 
			
		||||
    close: (reason: string) => void
 | 
			
		||||
    close: (reason: string, description?: DisconnectDescription) => void
 | 
			
		||||
    reconnect_failed: () => void
 | 
			
		||||
    reconnect_attempt: (attempt: number) => void
 | 
			
		||||
    reconnect_error: (err: Error) => void
 | 
			
		||||
@@ -295,13 +104,13 @@ interface ManagerReservedEvents {
 | 
			
		||||
export class Manager<
 | 
			
		||||
    ListenEvents extends EventsMap = DefaultEventsMap,
 | 
			
		||||
    EmitEvents extends EventsMap = ListenEvents
 | 
			
		||||
    > extends StrictEventEmitter<{}, {}, ManagerReservedEvents> {
 | 
			
		||||
> extends Emitter<{}, {}, ManagerReservedEvents> {
 | 
			
		||||
    /**
 | 
			
		||||
     * The Engine.IO client instance
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public engine: any
 | 
			
		||||
    public engine: Engine
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
@@ -320,7 +129,9 @@ export class Manager<
 | 
			
		||||
 | 
			
		||||
    private nsps: Record<string, Socket> = {};
 | 
			
		||||
    private subs: Array<ReturnType<typeof on>> = [];
 | 
			
		||||
    // @ts-ignore
 | 
			
		||||
    private backoff: Backoff
 | 
			
		||||
    private setTimeoutFn: typeof setTimeout
 | 
			
		||||
    private _reconnection: boolean
 | 
			
		||||
    private _reconnectionAttempts: number
 | 
			
		||||
    private _reconnectionDelay: number
 | 
			
		||||
@@ -358,6 +169,7 @@ export class Manager<
 | 
			
		||||
 | 
			
		||||
        opts.path = opts.path || "/socket.io"
 | 
			
		||||
        this.opts = opts
 | 
			
		||||
        installTimerFunctions(this, opts)
 | 
			
		||||
        this.reconnection(opts.reconnection !== false)
 | 
			
		||||
        this.reconnectionAttempts(opts.reconnectionAttempts || Infinity)
 | 
			
		||||
        this.reconnectionDelay(opts.reconnectionDelay || 1000)
 | 
			
		||||
@@ -507,8 +319,7 @@ export class Manager<
 | 
			
		||||
        if (~this._readyState.indexOf("open")) return this
 | 
			
		||||
 | 
			
		||||
        debug("opening %s", this.uri)
 | 
			
		||||
        // @ts-ignore
 | 
			
		||||
        this.engine = eio(this.uri, this.opts)
 | 
			
		||||
        this.engine = new Engine(this.uri, this.opts)
 | 
			
		||||
        const socket = this.engine
 | 
			
		||||
        const self = this
 | 
			
		||||
        this._readyState = "opening"
 | 
			
		||||
@@ -543,10 +354,11 @@ export class Manager<
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // set timer
 | 
			
		||||
            const timer = setTimeout(() => {
 | 
			
		||||
            const timer = this.setTimeoutFn(() => {
 | 
			
		||||
                debug("connect attempt timed out after %d", timeout)
 | 
			
		||||
                openSubDestroy()
 | 
			
		||||
                socket.close()
 | 
			
		||||
                // @ts-ignore
 | 
			
		||||
                socket.emit("error", new Error("timeout"))
 | 
			
		||||
            }, timeout)
 | 
			
		||||
 | 
			
		||||
@@ -616,7 +428,11 @@ export class Manager<
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private ondata(data): void {
 | 
			
		||||
        this.decoder.add(data)
 | 
			
		||||
        try {
 | 
			
		||||
            this.decoder.add(data)
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            this.onclose("parse error", e as Error)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -625,7 +441,10 @@ export class Manager<
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private ondecoded(packet): void {
 | 
			
		||||
        this.emitReserved("packet", packet)
 | 
			
		||||
        // the nextTick call prevents an exception in a user-provided event listener from triggering a disconnection due to a "parse error"
 | 
			
		||||
        nextTick(() => {
 | 
			
		||||
            this.emitReserved("packet", packet)
 | 
			
		||||
        }, this.setTimeoutFn)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -713,13 +532,7 @@ export class Manager<
 | 
			
		||||
        debug("disconnect")
 | 
			
		||||
        this.skipReconnect = true
 | 
			
		||||
        this._reconnecting = false
 | 
			
		||||
        if ("opening" === this._readyState) {
 | 
			
		||||
            // `onclose` will not fire because
 | 
			
		||||
            // an open event never happened
 | 
			
		||||
            this.cleanup()
 | 
			
		||||
        }
 | 
			
		||||
        this.backoff.reset()
 | 
			
		||||
        this._readyState = "closed"
 | 
			
		||||
        this.onclose("forced close")
 | 
			
		||||
        if (this.engine) this.engine.close()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -737,13 +550,13 @@ export class Manager<
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private onclose(reason: string): void {
 | 
			
		||||
        debug("onclose")
 | 
			
		||||
    private onclose(reason: string, description?: DisconnectDescription): void {
 | 
			
		||||
        debug("closed due to %s", reason)
 | 
			
		||||
 | 
			
		||||
        this.cleanup()
 | 
			
		||||
        this.backoff.reset()
 | 
			
		||||
        this._readyState = "closed"
 | 
			
		||||
        this.emitReserved("close", reason)
 | 
			
		||||
        this.emitReserved("close", reason, description)
 | 
			
		||||
 | 
			
		||||
        if (this._reconnection && !this.skipReconnect) {
 | 
			
		||||
            this.reconnect()
 | 
			
		||||
@@ -770,7 +583,7 @@ export class Manager<
 | 
			
		||||
            debug("will wait %dms before reconnect attempt", delay)
 | 
			
		||||
 | 
			
		||||
            this._reconnecting = true
 | 
			
		||||
            const timer = setTimeout(() => {
 | 
			
		||||
            const timer = this.setTimeoutFn(() => {
 | 
			
		||||
                if (self.skipReconnect) return
 | 
			
		||||
 | 
			
		||||
                debug("attempting reconnect")
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,7 @@
 | 
			
		||||
// import type * as Emitter from "component-emitter";
 | 
			
		||||
import { EventEmitter } from "events"
 | 
			
		||||
import { StrictEventEmitter } from "./typed-events"
 | 
			
		||||
import { Emitter } from "@socket.io/component-emitter"
 | 
			
		||||
 | 
			
		||||
export function on(
 | 
			
		||||
    obj: EventEmitter | StrictEventEmitter<any, any>,
 | 
			
		||||
    obj: Emitter<any, any>,
 | 
			
		||||
    ev: string,
 | 
			
		||||
    fn: (err?: any) => any
 | 
			
		||||
): VoidFunction {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,17 @@
 | 
			
		||||
// import { Packet, PacketType } from "socket.io-parser"
 | 
			
		||||
import { Packet, PacketType } from "../socket.io-parser"
 | 
			
		||||
import { on } from "./on"
 | 
			
		||||
import { Manager } from "./manager"
 | 
			
		||||
import { on } from "./on.js"
 | 
			
		||||
import { Manager } from "./manager.js"
 | 
			
		||||
import {
 | 
			
		||||
    DefaultEventsMap,
 | 
			
		||||
    EventNames,
 | 
			
		||||
    EventParams,
 | 
			
		||||
    EventsMap,
 | 
			
		||||
    StrictEventEmitter,
 | 
			
		||||
} from "./typed-events"
 | 
			
		||||
    Emitter,
 | 
			
		||||
} from "@socket.io/component-emitter"
 | 
			
		||||
// import debugModule from "debug" // debug()
 | 
			
		||||
 | 
			
		||||
// const debug = debugModule("socket.io-client:socket") // debug()
 | 
			
		||||
const debug = require("../debug")("socket.io-client")
 | 
			
		||||
 | 
			
		||||
export interface SocketOptions {
 | 
			
		||||
@@ -35,26 +38,110 @@ const RESERVED_EVENTS = Object.freeze({
 | 
			
		||||
interface Flags {
 | 
			
		||||
    compress?: boolean
 | 
			
		||||
    volatile?: boolean
 | 
			
		||||
    timeout?: number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type DisconnectDescription =
 | 
			
		||||
    | Error
 | 
			
		||||
    | {
 | 
			
		||||
        description: string
 | 
			
		||||
        context?: CloseEvent | XMLHttpRequest
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
interface SocketReservedEvents {
 | 
			
		||||
    connect: () => void
 | 
			
		||||
    connect_error: (err: Error) => void
 | 
			
		||||
    disconnect: (reason: Socket.DisconnectReason) => void
 | 
			
		||||
    disconnect: (
 | 
			
		||||
        reason: Socket.DisconnectReason,
 | 
			
		||||
        description?: DisconnectDescription
 | 
			
		||||
    ) => void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A Socket is the fundamental class for interacting with the server.
 | 
			
		||||
 *
 | 
			
		||||
 * A Socket belongs to a certain Namespace (by default /) and uses an underlying {@link Manager} to communicate.
 | 
			
		||||
 *
 | 
			
		||||
 * @example
 | 
			
		||||
 * const socket = io();
 | 
			
		||||
 *
 | 
			
		||||
 * socket.on("connect", () => {
 | 
			
		||||
 *   console.log("connected");
 | 
			
		||||
 * });
 | 
			
		||||
 *
 | 
			
		||||
 * // send an event to the server
 | 
			
		||||
 * socket.emit("foo", "bar");
 | 
			
		||||
 *
 | 
			
		||||
 * socket.on("foobar", () => {
 | 
			
		||||
 *   // an event was received from the server
 | 
			
		||||
 * });
 | 
			
		||||
 *
 | 
			
		||||
 * // upon disconnection
 | 
			
		||||
 * socket.on("disconnect", (reason) => {
 | 
			
		||||
 *   console.log(`disconnected due to ${reason}`);
 | 
			
		||||
 * });
 | 
			
		||||
 */
 | 
			
		||||
export class Socket<
 | 
			
		||||
    ListenEvents extends EventsMap = DefaultEventsMap,
 | 
			
		||||
    EmitEvents extends EventsMap = ListenEvents
 | 
			
		||||
    > extends StrictEventEmitter<ListenEvents, EmitEvents, SocketReservedEvents> {
 | 
			
		||||
> extends Emitter<ListenEvents, EmitEvents, SocketReservedEvents> {
 | 
			
		||||
    public readonly io: Manager<ListenEvents, EmitEvents>
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A unique identifier for the session.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const socket = io();
 | 
			
		||||
     *
 | 
			
		||||
     * console.log(socket.id); // undefined
 | 
			
		||||
     *
 | 
			
		||||
     * socket.on("connect", () => {
 | 
			
		||||
     *   console.log(socket.id); // "G5p5..."
 | 
			
		||||
     * });
 | 
			
		||||
     */
 | 
			
		||||
    public id: string
 | 
			
		||||
    public connected: boolean
 | 
			
		||||
    public disconnected: boolean
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether the socket is currently connected to the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const socket = io();
 | 
			
		||||
     *
 | 
			
		||||
     * socket.on("connect", () => {
 | 
			
		||||
     *   console.log(socket.connected); // true
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * socket.on("disconnect", () => {
 | 
			
		||||
     *   console.log(socket.connected); // false
 | 
			
		||||
     * });
 | 
			
		||||
     */
 | 
			
		||||
    public connected: boolean = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Credentials that are sent when accessing a namespace.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const socket = io({
 | 
			
		||||
     *   auth: {
 | 
			
		||||
     *     token: "abcd"
 | 
			
		||||
     *   }
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * // or with a function
 | 
			
		||||
     * const socket = io({
 | 
			
		||||
     *   auth: (cb) => {
 | 
			
		||||
     *     cb({ token: localStorage.token })
 | 
			
		||||
     *   }
 | 
			
		||||
     * });
 | 
			
		||||
     */
 | 
			
		||||
    public auth: { [key: string]: any } | ((cb: (data: object) => void) => void)
 | 
			
		||||
    /**
 | 
			
		||||
     * Buffer for packets received before the CONNECT packet
 | 
			
		||||
     */
 | 
			
		||||
    public receiveBuffer: Array<ReadonlyArray<any>> = [];
 | 
			
		||||
    /**
 | 
			
		||||
     * Buffer for packets that will be sent once the socket is connected
 | 
			
		||||
     */
 | 
			
		||||
    public sendBuffer: Array<Packet> = [];
 | 
			
		||||
 | 
			
		||||
    private readonly nsp: string
 | 
			
		||||
@@ -64,29 +151,39 @@ export class Socket<
 | 
			
		||||
    private flags: Flags = {};
 | 
			
		||||
    private subs?: Array<VoidFunction>
 | 
			
		||||
    private _anyListeners: Array<(...args: any[]) => void>
 | 
			
		||||
    private _anyOutgoingListeners: Array<(...args: any[]) => void>
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * `Socket` constructor.
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    constructor(io: Manager, nsp: string, opts?: Partial<SocketOptions>) {
 | 
			
		||||
        super()
 | 
			
		||||
        this.io = io
 | 
			
		||||
        this.nsp = nsp
 | 
			
		||||
        this.ids = 0
 | 
			
		||||
        this.acks = {}
 | 
			
		||||
        this.receiveBuffer = []
 | 
			
		||||
        this.sendBuffer = []
 | 
			
		||||
        this.connected = false
 | 
			
		||||
        this.disconnected = true
 | 
			
		||||
        this.flags = {}
 | 
			
		||||
        if (opts && opts.auth) {
 | 
			
		||||
            this.auth = opts.auth
 | 
			
		||||
        }
 | 
			
		||||
        if (this.io._autoConnect) this.open()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether the socket is currently disconnected
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const socket = io();
 | 
			
		||||
     *
 | 
			
		||||
     * socket.on("connect", () => {
 | 
			
		||||
     *   console.log(socket.disconnected); // false
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * socket.on("disconnect", () => {
 | 
			
		||||
     *   console.log(socket.disconnected); // true
 | 
			
		||||
     * });
 | 
			
		||||
     */
 | 
			
		||||
    public get disconnected(): boolean {
 | 
			
		||||
        return !this.connected
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Subscribe to open, close and packet events
 | 
			
		||||
     *
 | 
			
		||||
@@ -105,7 +202,21 @@ export class Socket<
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether the Socket will try to reconnect when its Manager connects or reconnects
 | 
			
		||||
     * Whether the Socket will try to reconnect when its Manager connects or reconnects.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const socket = io();
 | 
			
		||||
     *
 | 
			
		||||
     * console.log(socket.active); // true
 | 
			
		||||
     *
 | 
			
		||||
     * socket.on("disconnect", (reason) => {
 | 
			
		||||
     *   if (reason === "io server disconnect") {
 | 
			
		||||
     *     // the disconnection was initiated by the server, you need to manually reconnect
 | 
			
		||||
     *     console.log(socket.active); // false
 | 
			
		||||
     *   }
 | 
			
		||||
     *   // else the socket will automatically try to reconnect
 | 
			
		||||
     *   console.log(socket.active); // true
 | 
			
		||||
     * });
 | 
			
		||||
     */
 | 
			
		||||
    public get active(): boolean {
 | 
			
		||||
        return !!this.subs
 | 
			
		||||
@@ -114,7 +225,12 @@ export class Socket<
 | 
			
		||||
    /**
 | 
			
		||||
     * "Opens" the socket.
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * const socket = io({
 | 
			
		||||
     *   autoConnect: false
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * socket.connect();
 | 
			
		||||
     */
 | 
			
		||||
    public connect(): this {
 | 
			
		||||
        if (this.connected) return this
 | 
			
		||||
@@ -126,7 +242,7 @@ export class Socket<
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Alias for connect()
 | 
			
		||||
     * Alias for {@link connect()}.
 | 
			
		||||
     */
 | 
			
		||||
    public open(): this {
 | 
			
		||||
        return this.connect()
 | 
			
		||||
@@ -135,8 +251,17 @@ export class Socket<
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a `message` event.
 | 
			
		||||
     *
 | 
			
		||||
     * This method mimics the WebSocket.send() method.
 | 
			
		||||
     *
 | 
			
		||||
     * @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * socket.send("hello");
 | 
			
		||||
     *
 | 
			
		||||
     * // this is equivalent to
 | 
			
		||||
     * socket.emit("message", "hello");
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public send(...args: any[]): this {
 | 
			
		||||
        args.unshift("message")
 | 
			
		||||
@@ -149,15 +274,25 @@ export class Socket<
 | 
			
		||||
     * Override `emit`.
 | 
			
		||||
     * If the event is in `events`, it's emitted normally.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * socket.emit("hello", "world");
 | 
			
		||||
     *
 | 
			
		||||
     * // all serializable datastructures are supported (no need to call JSON.stringify)
 | 
			
		||||
     * socket.emit("hello", 1, "2", { 3: ["4"], 5: Uint8Array.from([6]) });
 | 
			
		||||
     *
 | 
			
		||||
     * // with an acknowledgement from the server
 | 
			
		||||
     * socket.emit("hello", "world", (val) => {
 | 
			
		||||
     *   // ...
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public emit<Ev extends EventNames<EmitEvents>>(
 | 
			
		||||
        ev: Ev,
 | 
			
		||||
        ...args: EventParams<EmitEvents, Ev>
 | 
			
		||||
    ): this {
 | 
			
		||||
        if (RESERVED_EVENTS.hasOwnProperty(ev)) {
 | 
			
		||||
            throw new Error('"' + ev + '" is a reserved event name')
 | 
			
		||||
            throw new Error('"' + ev.toString() + '" is a reserved event name')
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        args.unshift(ev)
 | 
			
		||||
@@ -171,9 +306,12 @@ export class Socket<
 | 
			
		||||
 | 
			
		||||
        // event ack callback
 | 
			
		||||
        if ("function" === typeof args[args.length - 1]) {
 | 
			
		||||
            debug("emitting packet with ack id %d", this.ids)
 | 
			
		||||
            this.acks[this.ids] = args.pop()
 | 
			
		||||
            packet.id = this.ids++
 | 
			
		||||
            const id = this.ids++
 | 
			
		||||
            debug("emitting packet with ack id %d", id)
 | 
			
		||||
 | 
			
		||||
            const ack = args.pop() as Function
 | 
			
		||||
            this._registerAckCallback(id, ack)
 | 
			
		||||
            packet.id = id
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const isTransportWritable =
 | 
			
		||||
@@ -186,6 +324,7 @@ export class Socket<
 | 
			
		||||
        if (discardPacket) {
 | 
			
		||||
            debug("discard packet as the transport is not currently writable")
 | 
			
		||||
        } else if (this.connected) {
 | 
			
		||||
            this.notifyOutgoingListeners(packet)
 | 
			
		||||
            this.packet(packet)
 | 
			
		||||
        } else {
 | 
			
		||||
            this.sendBuffer.push(packet)
 | 
			
		||||
@@ -196,6 +335,36 @@ export class Socket<
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private _registerAckCallback(id: number, ack: Function) {
 | 
			
		||||
        const timeout = this.flags.timeout
 | 
			
		||||
        if (timeout === undefined) {
 | 
			
		||||
            this.acks[id] = ack
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // @ts-ignore
 | 
			
		||||
        const timer = this.io.setTimeoutFn(() => {
 | 
			
		||||
            delete this.acks[id]
 | 
			
		||||
            for (let i = 0; i < this.sendBuffer.length; i++) {
 | 
			
		||||
                if (this.sendBuffer[i].id === id) {
 | 
			
		||||
                    debug("removing packet with ack id %d from the buffer", id)
 | 
			
		||||
                    this.sendBuffer.splice(i, 1)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            debug("event with ack id %d has timed out after %d ms", id, timeout)
 | 
			
		||||
            ack.call(this, new Error("operation has timed out"))
 | 
			
		||||
        }, timeout)
 | 
			
		||||
 | 
			
		||||
        this.acks[id] = (...args) => {
 | 
			
		||||
            // @ts-ignore
 | 
			
		||||
            this.io.clearTimeoutFn(timer)
 | 
			
		||||
            ack.apply(this, [null, ...args])
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a packet.
 | 
			
		||||
     *
 | 
			
		||||
@@ -239,14 +408,17 @@ export class Socket<
 | 
			
		||||
     * Called upon engine `close`.
 | 
			
		||||
     *
 | 
			
		||||
     * @param reason
 | 
			
		||||
     * @param description
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private onclose(reason: Socket.DisconnectReason): void {
 | 
			
		||||
    private onclose(
 | 
			
		||||
        reason: Socket.DisconnectReason,
 | 
			
		||||
        description?: DisconnectDescription
 | 
			
		||||
    ): void {
 | 
			
		||||
        debug("close (%s)", reason)
 | 
			
		||||
        this.connected = false
 | 
			
		||||
        this.disconnected = true
 | 
			
		||||
        delete this.id
 | 
			
		||||
        this.emitReserved("disconnect", reason)
 | 
			
		||||
        this.emitReserved("disconnect", reason, description)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -276,17 +448,11 @@ export class Socket<
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
            case PacketType.EVENT:
 | 
			
		||||
                this.onevent(packet)
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
            case PacketType.BINARY_EVENT:
 | 
			
		||||
                this.onevent(packet)
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
            case PacketType.ACK:
 | 
			
		||||
                this.onack(packet)
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
            case PacketType.BINARY_ACK:
 | 
			
		||||
                this.onack(packet)
 | 
			
		||||
                break
 | 
			
		||||
@@ -296,6 +462,7 @@ export class Socket<
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
            case PacketType.CONNECT_ERROR:
 | 
			
		||||
                this.destroy()
 | 
			
		||||
                const err = new Error(packet.data.message)
 | 
			
		||||
                // @ts-ignore
 | 
			
		||||
                err.data = packet.data.data
 | 
			
		||||
@@ -386,7 +553,6 @@ export class Socket<
 | 
			
		||||
        debug("socket connected with id %s", id)
 | 
			
		||||
        this.id = id
 | 
			
		||||
        this.connected = true
 | 
			
		||||
        this.disconnected = false
 | 
			
		||||
        this.emitBuffered()
 | 
			
		||||
        this.emitReserved("connect")
 | 
			
		||||
    }
 | 
			
		||||
@@ -400,7 +566,10 @@ export class Socket<
 | 
			
		||||
        this.receiveBuffer.forEach((args) => this.emitEvent(args))
 | 
			
		||||
        this.receiveBuffer = []
 | 
			
		||||
 | 
			
		||||
        this.sendBuffer.forEach((packet) => this.packet(packet))
 | 
			
		||||
        this.sendBuffer.forEach((packet) => {
 | 
			
		||||
            this.notifyOutgoingListeners(packet)
 | 
			
		||||
            this.packet(packet)
 | 
			
		||||
        })
 | 
			
		||||
        this.sendBuffer = []
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -432,10 +601,20 @@ export class Socket<
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Disconnects the socket manually.
 | 
			
		||||
     * Disconnects the socket manually. In that case, the socket will not try to reconnect.
 | 
			
		||||
     *
 | 
			
		||||
     * If this is the last active Socket instance of the {@link Manager}, the low-level connection will be closed.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const socket = io();
 | 
			
		||||
     *
 | 
			
		||||
     * socket.on("disconnect", (reason) => {
 | 
			
		||||
     *   // console.log(reason); prints "io client disconnect"
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * socket.disconnect();
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public disconnect(): this {
 | 
			
		||||
        if (this.connected) {
 | 
			
		||||
@@ -454,10 +633,9 @@ export class Socket<
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Alias for disconnect()
 | 
			
		||||
     * Alias for {@link disconnect()}.
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public close(): this {
 | 
			
		||||
        return this.disconnect()
 | 
			
		||||
@@ -466,9 +644,11 @@ export class Socket<
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the compress flag.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * socket.compress(false).emit("hello");
 | 
			
		||||
     *
 | 
			
		||||
     * @param compress - if `true`, compresses the sending data
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public compress(compress: boolean): this {
 | 
			
		||||
        this.flags.compress = compress
 | 
			
		||||
@@ -479,20 +659,44 @@ export class Socket<
 | 
			
		||||
     * Sets a modifier for a subsequent event emission that the event message will be dropped when this socket is not
 | 
			
		||||
     * ready to send messages.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * socket.volatile.emit("hello"); // the server may or may not receive it
 | 
			
		||||
     *
 | 
			
		||||
     * @returns self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public get volatile(): this {
 | 
			
		||||
        this.flags.volatile = true
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets a modifier for a subsequent event emission that the callback will be called with an error when the
 | 
			
		||||
     * given number of milliseconds have elapsed without an acknowledgement from the server:
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * socket.timeout(5000).emit("my-event", (err) => {
 | 
			
		||||
     *   if (err) {
 | 
			
		||||
     *     // the server did not acknowledge the event in the given delay
 | 
			
		||||
     *   }
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @returns self
 | 
			
		||||
     */
 | 
			
		||||
    public timeout(timeout: number): this {
 | 
			
		||||
        this.flags.timeout = timeout
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
 | 
			
		||||
     * callback.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * socket.onAny((event, ...args) => {
 | 
			
		||||
     *   console.log(`got ${event}`);
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param listener
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public onAny(listener: (...args: any[]) => void): this {
 | 
			
		||||
        this._anyListeners = this._anyListeners || []
 | 
			
		||||
@@ -504,8 +708,12 @@ export class Socket<
 | 
			
		||||
     * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
 | 
			
		||||
     * callback. The listener is added to the beginning of the listeners array.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * socket.prependAny((event, ...args) => {
 | 
			
		||||
     *   console.log(`got event ${event}`);
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param listener
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public prependAny(listener: (...args: any[]) => void): this {
 | 
			
		||||
        this._anyListeners = this._anyListeners || []
 | 
			
		||||
@@ -516,8 +724,20 @@ export class Socket<
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes the listener that will be fired when any event is emitted.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const catchAllListener = (event, ...args) => {
 | 
			
		||||
     *   console.log(`got event ${event}`);
 | 
			
		||||
     * }
 | 
			
		||||
     *
 | 
			
		||||
     * socket.onAny(catchAllListener);
 | 
			
		||||
     *
 | 
			
		||||
     * // remove a specific listener
 | 
			
		||||
     * socket.offAny(catchAllListener);
 | 
			
		||||
     *
 | 
			
		||||
     * // or remove all listeners
 | 
			
		||||
     * socket.offAny();
 | 
			
		||||
     *
 | 
			
		||||
     * @param listener
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public offAny(listener?: (...args: any[]) => void): this {
 | 
			
		||||
        if (!this._anyListeners) {
 | 
			
		||||
@@ -540,12 +760,108 @@ export class Socket<
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,
 | 
			
		||||
     * e.g. to remove listeners.
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public listenersAny() {
 | 
			
		||||
        return this._anyListeners || []
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
 | 
			
		||||
     * callback.
 | 
			
		||||
     *
 | 
			
		||||
     * Note: acknowledgements sent to the server are not included.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * socket.onAnyOutgoing((event, ...args) => {
 | 
			
		||||
     *   console.log(`sent event ${event}`);
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param listener
 | 
			
		||||
     */
 | 
			
		||||
    public onAnyOutgoing(listener: (...args: any[]) => void): this {
 | 
			
		||||
        this._anyOutgoingListeners = this._anyOutgoingListeners || []
 | 
			
		||||
        this._anyOutgoingListeners.push(listener)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
 | 
			
		||||
     * callback. The listener is added to the beginning of the listeners array.
 | 
			
		||||
     *
 | 
			
		||||
     * Note: acknowledgements sent to the server are not included.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * socket.prependAnyOutgoing((event, ...args) => {
 | 
			
		||||
     *   console.log(`sent event ${event}`);
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param listener
 | 
			
		||||
     */
 | 
			
		||||
    public prependAnyOutgoing(listener: (...args: any[]) => void): this {
 | 
			
		||||
        this._anyOutgoingListeners = this._anyOutgoingListeners || []
 | 
			
		||||
        this._anyOutgoingListeners.unshift(listener)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes the listener that will be fired when any event is emitted.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const catchAllListener = (event, ...args) => {
 | 
			
		||||
     *   console.log(`sent event ${event}`);
 | 
			
		||||
     * }
 | 
			
		||||
     *
 | 
			
		||||
     * socket.onAnyOutgoing(catchAllListener);
 | 
			
		||||
     *
 | 
			
		||||
     * // remove a specific listener
 | 
			
		||||
     * socket.offAnyOutgoing(catchAllListener);
 | 
			
		||||
     *
 | 
			
		||||
     * // or remove all listeners
 | 
			
		||||
     * socket.offAnyOutgoing();
 | 
			
		||||
     *
 | 
			
		||||
     * @param [listener] - the catch-all listener (optional)
 | 
			
		||||
     */
 | 
			
		||||
    public offAnyOutgoing(listener?: (...args: any[]) => void): this {
 | 
			
		||||
        if (!this._anyOutgoingListeners) {
 | 
			
		||||
            return this
 | 
			
		||||
        }
 | 
			
		||||
        if (listener) {
 | 
			
		||||
            const listeners = this._anyOutgoingListeners
 | 
			
		||||
            for (let i = 0; i < listeners.length; i++) {
 | 
			
		||||
                if (listener === listeners[i]) {
 | 
			
		||||
                    listeners.splice(i, 1)
 | 
			
		||||
                    return this
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            this._anyOutgoingListeners = []
 | 
			
		||||
        }
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,
 | 
			
		||||
     * e.g. to remove listeners.
 | 
			
		||||
     */
 | 
			
		||||
    public listenersAnyOutgoing() {
 | 
			
		||||
        return this._anyOutgoingListeners || []
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Notify the listeners for each packet sent
 | 
			
		||||
     *
 | 
			
		||||
     * @param packet
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private notifyOutgoingListeners(packet: Packet) {
 | 
			
		||||
        if (this._anyOutgoingListeners && this._anyOutgoingListeners.length) {
 | 
			
		||||
            const listeners = this._anyOutgoingListeners.slice()
 | 
			
		||||
            for (const listener of listeners) {
 | 
			
		||||
                listener.apply(this, packet.data)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export namespace Socket {
 | 
			
		||||
@@ -555,4 +871,5 @@ export namespace Socket {
 | 
			
		||||
        | "ping timeout"
 | 
			
		||||
        | "transport close"
 | 
			
		||||
        | "transport error"
 | 
			
		||||
        | "parse error"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,157 +0,0 @@
 | 
			
		||||
import { EventEmitter } from "events"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An events map is an interface that maps event names to their value, which
 | 
			
		||||
 * represents the type of the `on` listener.
 | 
			
		||||
 */
 | 
			
		||||
export interface EventsMap {
 | 
			
		||||
    [event: string]: any
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The default events map, used if no EventsMap is given. Using this EventsMap
 | 
			
		||||
 * is equivalent to accepting all event names, and any data.
 | 
			
		||||
 */
 | 
			
		||||
export interface DefaultEventsMap {
 | 
			
		||||
    [event: string]: (...args: any[]) => void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns a union type containing all the keys of an event map.
 | 
			
		||||
 */
 | 
			
		||||
export type EventNames<Map extends EventsMap> = keyof Map & (string | symbol)
 | 
			
		||||
 | 
			
		||||
/** The tuple type representing the parameters of an event listener */
 | 
			
		||||
export type EventParams<
 | 
			
		||||
    Map extends EventsMap,
 | 
			
		||||
    Ev extends EventNames<Map>
 | 
			
		||||
    > = Parameters<Map[Ev]>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The event names that are either in ReservedEvents or in UserEvents
 | 
			
		||||
 */
 | 
			
		||||
export type ReservedOrUserEventNames<
 | 
			
		||||
    ReservedEventsMap extends EventsMap,
 | 
			
		||||
    UserEvents extends EventsMap
 | 
			
		||||
    > = EventNames<ReservedEventsMap> | EventNames<UserEvents>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Type of a listener of a user event or a reserved event. If `Ev` is in
 | 
			
		||||
 * `ReservedEvents`, the reserved event listener is returned.
 | 
			
		||||
 */
 | 
			
		||||
export type ReservedOrUserListener<
 | 
			
		||||
    ReservedEvents extends EventsMap,
 | 
			
		||||
    UserEvents extends EventsMap,
 | 
			
		||||
    Ev extends ReservedOrUserEventNames<ReservedEvents, UserEvents>
 | 
			
		||||
    > = FallbackToUntypedListener<
 | 
			
		||||
        Ev extends EventNames<ReservedEvents>
 | 
			
		||||
        ? ReservedEvents[Ev]
 | 
			
		||||
        : Ev extends EventNames<UserEvents>
 | 
			
		||||
        ? UserEvents[Ev]
 | 
			
		||||
        : never
 | 
			
		||||
    >
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns an untyped listener type if `T` is `never`; otherwise, returns `T`.
 | 
			
		||||
 *
 | 
			
		||||
 * This is a hack to mitigate https://github.com/socketio/socket.io/issues/3833.
 | 
			
		||||
 * Needed because of https://github.com/microsoft/TypeScript/issues/41778
 | 
			
		||||
 */
 | 
			
		||||
type FallbackToUntypedListener<T> = [T] extends [never]
 | 
			
		||||
    ? (...args: any[]) => void
 | 
			
		||||
    : T
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Strictly typed version of an `EventEmitter`. A `TypedEventEmitter` takes type
 | 
			
		||||
 * parameters for mappings of event names to event data types, and strictly
 | 
			
		||||
 * types method calls to the `EventEmitter` according to these event maps.
 | 
			
		||||
 *
 | 
			
		||||
 * @typeParam ListenEvents - `EventsMap` of user-defined events that can be
 | 
			
		||||
 * listened to with `on` or `once`
 | 
			
		||||
 * @typeParam EmitEvents - `EventsMap` of user-defined events that can be
 | 
			
		||||
 * emitted with `emit`
 | 
			
		||||
 * @typeParam ReservedEvents - `EventsMap` of reserved events, that can be
 | 
			
		||||
 * emitted by socket.io with `emitReserved`, and can be listened to with
 | 
			
		||||
 * `listen`.
 | 
			
		||||
 */
 | 
			
		||||
export abstract class StrictEventEmitter<
 | 
			
		||||
    ListenEvents extends EventsMap,
 | 
			
		||||
    EmitEvents extends EventsMap,
 | 
			
		||||
    ReservedEvents extends EventsMap = {}
 | 
			
		||||
    > extends EventEmitter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds the `listener` function as an event listener for `ev`.
 | 
			
		||||
     *
 | 
			
		||||
     * @param ev Name of the event
 | 
			
		||||
     * @param listener Callback function
 | 
			
		||||
     */
 | 
			
		||||
    on<Ev extends ReservedOrUserEventNames<ReservedEvents, ListenEvents>>(
 | 
			
		||||
        ev: Ev,
 | 
			
		||||
        listener: ReservedOrUserListener<ReservedEvents, ListenEvents, Ev>
 | 
			
		||||
    ): this {
 | 
			
		||||
        super.on(ev as string, listener)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a one-time `listener` function as an event listener for `ev`.
 | 
			
		||||
     *
 | 
			
		||||
     * @param ev Name of the event
 | 
			
		||||
     * @param listener Callback function
 | 
			
		||||
     */
 | 
			
		||||
    once<Ev extends ReservedOrUserEventNames<ReservedEvents, ListenEvents>>(
 | 
			
		||||
        ev: Ev,
 | 
			
		||||
        listener: ReservedOrUserListener<ReservedEvents, ListenEvents, Ev>
 | 
			
		||||
    ): this {
 | 
			
		||||
        super.once(ev as string, listener)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Emits an event.
 | 
			
		||||
     *
 | 
			
		||||
     * @param ev Name of the event
 | 
			
		||||
     * @param args Values to send to listeners of this event
 | 
			
		||||
     */
 | 
			
		||||
    // @ts-ignore
 | 
			
		||||
    emit<Ev extends EventNames<EmitEvents>>(
 | 
			
		||||
        ev: Ev,
 | 
			
		||||
        ...args: EventParams<EmitEvents, Ev>
 | 
			
		||||
    ): this {
 | 
			
		||||
        super.emit(ev as string, ...args)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Emits a reserved event.
 | 
			
		||||
     *
 | 
			
		||||
     * This method is `protected`, so that only a class extending
 | 
			
		||||
     * `StrictEventEmitter` can emit its own reserved events.
 | 
			
		||||
     *
 | 
			
		||||
     * @param ev Reserved event name
 | 
			
		||||
     * @param args Arguments to emit along with the event
 | 
			
		||||
     */
 | 
			
		||||
    protected emitReserved<Ev extends EventNames<ReservedEvents>>(
 | 
			
		||||
        ev: Ev,
 | 
			
		||||
        ...args: EventParams<ReservedEvents, Ev>
 | 
			
		||||
    ): this {
 | 
			
		||||
        super.emit(ev as string, ...args)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the listeners listening to an event.
 | 
			
		||||
     *
 | 
			
		||||
     * @param event Event name
 | 
			
		||||
     * @returns Array of listeners subscribed to `event`
 | 
			
		||||
     */
 | 
			
		||||
    listeners<Ev extends ReservedOrUserEventNames<ReservedEvents, ListenEvents>>(
 | 
			
		||||
        event: Ev
 | 
			
		||||
    ): ReservedOrUserListener<ReservedEvents, ListenEvents, Ev>[] {
 | 
			
		||||
        return super.listeners(event as string) as ReservedOrUserListener<
 | 
			
		||||
            ReservedEvents,
 | 
			
		||||
            ListenEvents,
 | 
			
		||||
            Ev
 | 
			
		||||
        >[]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,8 @@
 | 
			
		||||
import * as parseuri from "parseuri"
 | 
			
		||||
// import { parse } from "engine.io-client"
 | 
			
		||||
import { parse } from "../engine.io-client"
 | 
			
		||||
// import debugModule from "debug" // debug()
 | 
			
		||||
 | 
			
		||||
// const debug = debugModule("socket.io-client:url"); // debug()
 | 
			
		||||
const debug = require("../debug")("socket.io-client")
 | 
			
		||||
 | 
			
		||||
type ParsedUrl = {
 | 
			
		||||
@@ -67,7 +70,7 @@ export function url(
 | 
			
		||||
 | 
			
		||||
        // parse
 | 
			
		||||
        debug("parse %s", uri)
 | 
			
		||||
        obj = parseuri(uri) as ParsedUrl
 | 
			
		||||
        obj = parse(uri) as ParsedUrl
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // make sure we treat `localhost:80` and `localhost` equally
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { isBinary } from "./is-binary"
 | 
			
		||||
import { isBinary } from "./is-binary.js"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Replaces every Buffer | ArrayBuffer | Blob | File in packet with a numbered placeholder.
 | 
			
		||||
@@ -33,7 +33,7 @@ function _deconstructPacket(data, buffers) {
 | 
			
		||||
    } else if (typeof data === "object" && !(data instanceof Date)) {
 | 
			
		||||
        const newData = {}
 | 
			
		||||
        for (const key in data) {
 | 
			
		||||
            if (data.hasOwnProperty(key)) {
 | 
			
		||||
            if (Object.prototype.hasOwnProperty.call(data, key)) {
 | 
			
		||||
                newData[key] = _deconstructPacket(data[key], buffers)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -60,15 +60,23 @@ export function reconstructPacket(packet, buffers) {
 | 
			
		||||
function _reconstructPacket(data, buffers) {
 | 
			
		||||
    if (!data) return data
 | 
			
		||||
 | 
			
		||||
    if (data && data._placeholder) {
 | 
			
		||||
        return buffers[data.num] // appropriate buffer (should be natural order anyway)
 | 
			
		||||
    if (data && data._placeholder === true) {
 | 
			
		||||
        const isIndexValid =
 | 
			
		||||
            typeof data.num === "number" &&
 | 
			
		||||
            data.num >= 0 &&
 | 
			
		||||
            data.num < buffers.length
 | 
			
		||||
        if (isIndexValid) {
 | 
			
		||||
            return buffers[data.num] // appropriate buffer (should be natural order anyway)
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new Error("illegal attachments")
 | 
			
		||||
        }
 | 
			
		||||
    } else if (Array.isArray(data)) {
 | 
			
		||||
        for (let i = 0; i < data.length; i++) {
 | 
			
		||||
            data[i] = _reconstructPacket(data[i], buffers)
 | 
			
		||||
        }
 | 
			
		||||
    } else if (typeof data === "object") {
 | 
			
		||||
        for (const key in data) {
 | 
			
		||||
            if (data.hasOwnProperty(key)) {
 | 
			
		||||
            if (Object.prototype.hasOwnProperty.call(data, key)) {
 | 
			
		||||
                data[key] = _reconstructPacket(data[key], buffers)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,10 @@
 | 
			
		||||
import EventEmitter = require("events")
 | 
			
		||||
import { deconstructPacket, reconstructPacket } from "./binary"
 | 
			
		||||
import { isBinary, hasBinary } from "./is-binary"
 | 
			
		||||
import { Emitter } from "@socket.io/component-emitter"
 | 
			
		||||
import { deconstructPacket, reconstructPacket } from "./binary.js"
 | 
			
		||||
import { isBinary, hasBinary } from "./is-binary.js"
 | 
			
		||||
// import debugModule from "debug" // debug()
 | 
			
		||||
 | 
			
		||||
// const debug = require("debug")("socket.io-parser")
 | 
			
		||||
// const debug = debugModule("socket.io-parser") // debug()
 | 
			
		||||
const debug = require("../debug")("socket.io-client")
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Protocol version.
 | 
			
		||||
@@ -35,6 +37,12 @@ export interface Packet {
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export class Encoder {
 | 
			
		||||
    /**
 | 
			
		||||
     * Encoder constructor
 | 
			
		||||
     *
 | 
			
		||||
     * @param {function} replacer - custom replacer to pass down to JSON.parse
 | 
			
		||||
     */
 | 
			
		||||
    constructor(private replacer?: (this: any, key: string, value: any) => any) { }
 | 
			
		||||
    /**
 | 
			
		||||
     * Encode a packet as a single string if non-binary, or as a
 | 
			
		||||
     * buffer sequence, depending on packet type.
 | 
			
		||||
@@ -42,7 +50,7 @@ export class Encoder {
 | 
			
		||||
     * @param {Object} obj - packet object
 | 
			
		||||
     */
 | 
			
		||||
    public encode(obj: Packet) {
 | 
			
		||||
        console.trace("encoding packet", JSON.stringify(obj))
 | 
			
		||||
        debug("encoding packet %j", obj)
 | 
			
		||||
 | 
			
		||||
        if (obj.type === PacketType.EVENT || obj.type === PacketType.ACK) {
 | 
			
		||||
            if (hasBinary(obj)) {
 | 
			
		||||
@@ -85,10 +93,10 @@ export class Encoder {
 | 
			
		||||
 | 
			
		||||
        // json data
 | 
			
		||||
        if (null != obj.data) {
 | 
			
		||||
            str += JSON.stringify(obj.data)
 | 
			
		||||
            str += JSON.stringify(obj.data, this.replacer)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        console.trace("encoded", JSON.stringify(obj), "as", str)
 | 
			
		||||
        debug("encoded %j as %s", obj, str)
 | 
			
		||||
        return str
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -108,15 +116,24 @@ export class Encoder {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface DecoderReservedEvents {
 | 
			
		||||
    decoded: (packet: Packet) => void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A socket.io Decoder instance
 | 
			
		||||
 *
 | 
			
		||||
 * @return {Object} decoder
 | 
			
		||||
 */
 | 
			
		||||
export class Decoder extends EventEmitter {
 | 
			
		||||
export class Decoder extends Emitter<{}, {}, DecoderReservedEvents> {
 | 
			
		||||
    private reconstructor: BinaryReconstructor
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
    /**
 | 
			
		||||
     * Decoder constructor
 | 
			
		||||
     *
 | 
			
		||||
     * @param {function} reviver - custom reviver to pass down to JSON.stringify
 | 
			
		||||
     */
 | 
			
		||||
    constructor(private reviver?: (this: any, key: string, value: any) => any) {
 | 
			
		||||
        super()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -129,6 +146,9 @@ export class Decoder extends EventEmitter {
 | 
			
		||||
    public add(obj: any) {
 | 
			
		||||
        let packet
 | 
			
		||||
        if (typeof obj === "string") {
 | 
			
		||||
            if (this.reconstructor) {
 | 
			
		||||
                throw new Error("got plaintext data when reconstructing a packet")
 | 
			
		||||
            }
 | 
			
		||||
            packet = this.decodeString(obj)
 | 
			
		||||
            if (
 | 
			
		||||
                packet.type === PacketType.BINARY_EVENT ||
 | 
			
		||||
@@ -139,11 +159,11 @@ export class Decoder extends EventEmitter {
 | 
			
		||||
 | 
			
		||||
                // no attachments, labeled binary but no binary data to follow
 | 
			
		||||
                if (packet.attachments === 0) {
 | 
			
		||||
                    super.emit("decoded", packet)
 | 
			
		||||
                    super.emitReserved("decoded", packet)
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                // non-binary full packet
 | 
			
		||||
                super.emit("decoded", packet)
 | 
			
		||||
                super.emitReserved("decoded", packet)
 | 
			
		||||
            }
 | 
			
		||||
        } else if (isBinary(obj) || obj.base64) {
 | 
			
		||||
            // raw binary data
 | 
			
		||||
@@ -154,7 +174,7 @@ export class Decoder extends EventEmitter {
 | 
			
		||||
                if (packet) {
 | 
			
		||||
                    // received final buffer
 | 
			
		||||
                    this.reconstructor = null
 | 
			
		||||
                    super.emit("decoded", packet)
 | 
			
		||||
                    super.emitReserved("decoded", packet)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -223,7 +243,7 @@ export class Decoder extends EventEmitter {
 | 
			
		||||
 | 
			
		||||
        // look up json data
 | 
			
		||||
        if (str.charAt(++i)) {
 | 
			
		||||
            const payload = tryParse(str.substr(i))
 | 
			
		||||
            const payload = this.tryParse(str.substr(i))
 | 
			
		||||
            if (Decoder.isPayloadValid(p.type, payload)) {
 | 
			
		||||
                p.data = payload
 | 
			
		||||
            } else {
 | 
			
		||||
@@ -231,10 +251,18 @@ export class Decoder extends EventEmitter {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        console.trace("decoded", str, "as", p)
 | 
			
		||||
        debug("decoded %s as %j", str, p)
 | 
			
		||||
        return p
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private tryParse(str) {
 | 
			
		||||
        try {
 | 
			
		||||
            return JSON.parse(str, this.reviver)
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            return false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static isPayloadValid(type: PacketType, payload: any): boolean {
 | 
			
		||||
        switch (type) {
 | 
			
		||||
            case PacketType.CONNECT:
 | 
			
		||||
@@ -262,14 +290,6 @@ export class Decoder extends EventEmitter {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function tryParse(str) {
 | 
			
		||||
    try {
 | 
			
		||||
        return JSON.parse(str)
 | 
			
		||||
    } catch (error: any) {
 | 
			
		||||
        return false
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A manager of a binary event's 'buffer sequence'. Should
 | 
			
		||||
 * be constructed whenever a packet of type BINARY_EVENT is
 | 
			
		||||
 
 | 
			
		||||
@@ -7,14 +7,14 @@ const isView = (obj: any) => {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const toString = Object.prototype.toString
 | 
			
		||||
const withNativeBlob = false
 | 
			
		||||
// typeof Blob === "function" ||
 | 
			
		||||
// (typeof Blob !== "undefined" &&
 | 
			
		||||
//     toString.call(Blob) === "[object BlobConstructor]")
 | 
			
		||||
const withNativeFile = false
 | 
			
		||||
// typeof File === "function" ||
 | 
			
		||||
// (typeof File !== "undefined" &&
 | 
			
		||||
//     toString.call(File) === "[object FileConstructor]")
 | 
			
		||||
const withNativeBlob =
 | 
			
		||||
    typeof Blob === "function" ||
 | 
			
		||||
    (typeof Blob !== "undefined" &&
 | 
			
		||||
        toString.call(Blob) === "[object BlobConstructor]")
 | 
			
		||||
const withNativeFile =
 | 
			
		||||
    typeof File === "function" ||
 | 
			
		||||
    (typeof File !== "undefined" &&
 | 
			
		||||
        toString.call(File) === "[object FileConstructor]")
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns true if obj is a Buffer, an ArrayBuffer, a Blob or a File.
 | 
			
		||||
@@ -24,8 +24,9 @@ const withNativeFile = false
 | 
			
		||||
 | 
			
		||||
export function isBinary(obj: any) {
 | 
			
		||||
    return (
 | 
			
		||||
        (withNativeArrayBuffer && (obj instanceof ArrayBuffer || isView(obj)))
 | 
			
		||||
        // || (withNativeBlob && obj instanceof Blob) || (withNativeFile && obj instanceof File)
 | 
			
		||||
        (withNativeArrayBuffer && (obj instanceof ArrayBuffer || isView(obj))) ||
 | 
			
		||||
        (withNativeBlob && obj instanceof Blob) ||
 | 
			
		||||
        (withNativeFile && obj instanceof File)
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ import type {
 | 
			
		||||
    TypedEventBroadcaster,
 | 
			
		||||
} from "./typed-events"
 | 
			
		||||
 | 
			
		||||
export class BroadcastOperator<EmitEvents extends EventsMap>
 | 
			
		||||
export class BroadcastOperator<EmitEvents extends EventsMap, SocketData>
 | 
			
		||||
    implements TypedEventBroadcaster<EmitEvents>
 | 
			
		||||
{
 | 
			
		||||
    constructor(
 | 
			
		||||
@@ -25,18 +25,27 @@ export class BroadcastOperator<EmitEvents extends EventsMap>
 | 
			
		||||
    /**
 | 
			
		||||
     * Targets a room when emitting.
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @return a new BroadcastOperator instance
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * // the “foo” event will be broadcast to all connected clients in the “room-101” room
 | 
			
		||||
     * io.to("room-101").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * // with an array of rooms (a client will be notified at most once)
 | 
			
		||||
     * io.to(["room-101", "room-102"]).emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * // with multiple chained calls
 | 
			
		||||
     * io.to("room-101").to("room-102").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public to(room: Room | Room[]): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public to(room: Room | Room[]) {
 | 
			
		||||
        const rooms = new Set(this.rooms)
 | 
			
		||||
        if (Array.isArray(room)) {
 | 
			
		||||
            room.forEach((r) => rooms.add(r))
 | 
			
		||||
        } else {
 | 
			
		||||
            rooms.add(room)
 | 
			
		||||
        }
 | 
			
		||||
        return new BroadcastOperator(
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(
 | 
			
		||||
            this.adapter,
 | 
			
		||||
            rooms,
 | 
			
		||||
            this.exceptRooms,
 | 
			
		||||
@@ -45,31 +54,43 @@ export class BroadcastOperator<EmitEvents extends EventsMap>
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Targets a room when emitting.
 | 
			
		||||
     * Targets a room when emitting. Similar to `to()`, but might feel clearer in some cases:
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @return a new BroadcastOperator instance
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * // disconnect all clients in the "room-101" room
 | 
			
		||||
     * io.in("room-101").disconnectSockets();
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public in(room: Room | Room[]): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public in(room: Room | Room[]) {
 | 
			
		||||
        return this.to(room)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Excludes a room when emitting.
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @return a new BroadcastOperator instance
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * // the "foo" event will be broadcast to all connected clients, except the ones that are in the "room-101" room
 | 
			
		||||
     * io.except("room-101").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * // with an array of rooms
 | 
			
		||||
     * io.except(["room-101", "room-102"]).emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * // with multiple chained calls
 | 
			
		||||
     * io.except("room-101").except("room-102").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public except(room: Room | Room[]): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public except(room: Room | Room[]) {
 | 
			
		||||
        const exceptRooms = new Set(this.exceptRooms)
 | 
			
		||||
        if (Array.isArray(room)) {
 | 
			
		||||
            room.forEach((r) => exceptRooms.add(r))
 | 
			
		||||
        } else {
 | 
			
		||||
            exceptRooms.add(room)
 | 
			
		||||
        }
 | 
			
		||||
        return new BroadcastOperator(
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(
 | 
			
		||||
            this.adapter,
 | 
			
		||||
            this.rooms,
 | 
			
		||||
            exceptRooms,
 | 
			
		||||
@@ -80,13 +101,15 @@ export class BroadcastOperator<EmitEvents extends EventsMap>
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the compress flag.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.compress(false).emit("hello");
 | 
			
		||||
     *
 | 
			
		||||
     * @param compress - if `true`, compresses the sending data
 | 
			
		||||
     * @return a new BroadcastOperator instance
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public compress(compress: boolean): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public compress(compress: boolean) {
 | 
			
		||||
        const flags = Object.assign({}, this.flags, { compress })
 | 
			
		||||
        return new BroadcastOperator(
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(
 | 
			
		||||
            this.adapter,
 | 
			
		||||
            this.rooms,
 | 
			
		||||
            this.exceptRooms,
 | 
			
		||||
@@ -99,12 +122,14 @@ export class BroadcastOperator<EmitEvents extends EventsMap>
 | 
			
		||||
     * receive messages (because of network slowness or other issues, or because they’re connected through long polling
 | 
			
		||||
     * and is in the middle of a request-response cycle).
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.volatile.emit("hello"); // the clients may or may not receive it
 | 
			
		||||
     *
 | 
			
		||||
     * @return a new BroadcastOperator instance
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public get volatile(): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public get volatile() {
 | 
			
		||||
        const flags = Object.assign({}, this.flags, { volatile: true })
 | 
			
		||||
        return new BroadcastOperator(
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(
 | 
			
		||||
            this.adapter,
 | 
			
		||||
            this.rooms,
 | 
			
		||||
            this.exceptRooms,
 | 
			
		||||
@@ -115,12 +140,39 @@ export class BroadcastOperator<EmitEvents extends EventsMap>
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets a modifier for a subsequent event emission that the event data will only be broadcast to the current node.
 | 
			
		||||
     *
 | 
			
		||||
     * @return a new BroadcastOperator instance
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * // the “foo” event will be broadcast to all connected clients on this node
 | 
			
		||||
     * io.local.emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public get local(): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public get local() {
 | 
			
		||||
        const flags = Object.assign({}, this.flags, { local: true })
 | 
			
		||||
        return new BroadcastOperator(
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(
 | 
			
		||||
            this.adapter,
 | 
			
		||||
            this.rooms,
 | 
			
		||||
            this.exceptRooms,
 | 
			
		||||
            flags
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a timeout in milliseconds for the next operation
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.timeout(1000).emit("some-event", (err, responses) => {
 | 
			
		||||
     *   if (err) {
 | 
			
		||||
     *     // some clients did not acknowledge the event in the given delay
 | 
			
		||||
     *   } else {
 | 
			
		||||
     *     console.log(responses); // one response per client
 | 
			
		||||
     *   }
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param timeout
 | 
			
		||||
     */
 | 
			
		||||
    public timeout(timeout: number) {
 | 
			
		||||
        const flags = Object.assign({}, this.flags, { timeout })
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(
 | 
			
		||||
            this.adapter,
 | 
			
		||||
            this.rooms,
 | 
			
		||||
            this.exceptRooms,
 | 
			
		||||
@@ -131,15 +183,30 @@ export class BroadcastOperator<EmitEvents extends EventsMap>
 | 
			
		||||
    /**
 | 
			
		||||
     * Emits to all clients.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * // the “foo” event will be broadcast to all connected clients
 | 
			
		||||
     * io.emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * // the “foo” event will be broadcast to all connected clients in the “room-101” room
 | 
			
		||||
     * io.to("room-101").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * // with an acknowledgement expected from all connected clients
 | 
			
		||||
     * io.timeout(1000).emit("some-event", (err, responses) => {
 | 
			
		||||
     *   if (err) {
 | 
			
		||||
     *     // some clients did not acknowledge the event in the given delay
 | 
			
		||||
     *   } else {
 | 
			
		||||
     *     console.log(responses); // one response per client
 | 
			
		||||
     *   }
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @return Always true
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public emit<Ev extends EventNames<EmitEvents>>(
 | 
			
		||||
        ev: Ev,
 | 
			
		||||
        ...args: EventParams<EmitEvents, Ev>
 | 
			
		||||
    ): boolean {
 | 
			
		||||
        if (RESERVED_EVENTS.has(ev)) {
 | 
			
		||||
            throw new Error(`"${ev}" is a reserved event name`)
 | 
			
		||||
            throw new Error(`"${String(ev)}" is a reserved event name`)
 | 
			
		||||
        }
 | 
			
		||||
        // set up packet object
 | 
			
		||||
        const data = [ev, ...args]
 | 
			
		||||
@@ -148,14 +215,65 @@ export class BroadcastOperator<EmitEvents extends EventsMap>
 | 
			
		||||
            data: data,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ("function" == typeof data[data.length - 1]) {
 | 
			
		||||
            throw new Error("Callbacks are not supported when broadcasting")
 | 
			
		||||
        const withAck = typeof data[data.length - 1] === "function"
 | 
			
		||||
 | 
			
		||||
        if (!withAck) {
 | 
			
		||||
            this.adapter.broadcast(packet, {
 | 
			
		||||
                rooms: this.rooms,
 | 
			
		||||
                except: this.exceptRooms,
 | 
			
		||||
                flags: this.flags,
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
            return true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.adapter.broadcast(packet, {
 | 
			
		||||
            rooms: this.rooms,
 | 
			
		||||
            except: this.exceptRooms,
 | 
			
		||||
            flags: this.flags,
 | 
			
		||||
        const ack = data.pop() as (...args: any[]) => void
 | 
			
		||||
        let timedOut = false
 | 
			
		||||
        let responses: any[] = []
 | 
			
		||||
 | 
			
		||||
        const timer = setTimeout(() => {
 | 
			
		||||
            timedOut = true
 | 
			
		||||
            ack.apply(this, [new Error("operation has timed out"), responses])
 | 
			
		||||
        }, this.flags.timeout)
 | 
			
		||||
 | 
			
		||||
        let expectedServerCount = -1
 | 
			
		||||
        let actualServerCount = 0
 | 
			
		||||
        let expectedClientCount = 0
 | 
			
		||||
 | 
			
		||||
        const checkCompleteness = () => {
 | 
			
		||||
            if (
 | 
			
		||||
                !timedOut &&
 | 
			
		||||
                expectedServerCount === actualServerCount &&
 | 
			
		||||
                responses.length === expectedClientCount
 | 
			
		||||
            ) {
 | 
			
		||||
                clearTimeout(timer)
 | 
			
		||||
                ack.apply(this, [null, responses])
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.adapter.broadcastWithAck(
 | 
			
		||||
            packet,
 | 
			
		||||
            {
 | 
			
		||||
                rooms: this.rooms,
 | 
			
		||||
                except: this.exceptRooms,
 | 
			
		||||
                flags: this.flags,
 | 
			
		||||
            },
 | 
			
		||||
            (clientCount) => {
 | 
			
		||||
                // each Socket.IO server in the cluster sends the number of clients that were notified
 | 
			
		||||
                expectedClientCount += clientCount
 | 
			
		||||
                actualServerCount++
 | 
			
		||||
                checkCompleteness()
 | 
			
		||||
            },
 | 
			
		||||
            (clientResponse) => {
 | 
			
		||||
                // each client sends an acknowledgement
 | 
			
		||||
                responses.push(clientResponse)
 | 
			
		||||
                checkCompleteness()
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        this.adapter.serverCount().then((serverCount) => {
 | 
			
		||||
            expectedServerCount = serverCount
 | 
			
		||||
            checkCompleteness()
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        return true
 | 
			
		||||
@@ -164,7 +282,8 @@ export class BroadcastOperator<EmitEvents extends EventsMap>
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a list of clients.
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     * @deprecated this method will be removed in the next major release, please use {@link Server#serverSideEmit} or
 | 
			
		||||
     * {@link fetchSockets} instead.
 | 
			
		||||
     */
 | 
			
		||||
    public allSockets(): Promise<Set<SocketId>> {
 | 
			
		||||
        if (!this.adapter) {
 | 
			
		||||
@@ -176,71 +295,122 @@ export class BroadcastOperator<EmitEvents extends EventsMap>
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the matching socket instances
 | 
			
		||||
     * Returns the matching socket instances. This method works across a cluster of several Socket.IO servers.
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * // return all Socket instances
 | 
			
		||||
     * const sockets = await io.fetchSockets();
 | 
			
		||||
     *
 | 
			
		||||
     * // return all Socket instances in the "room1" room
 | 
			
		||||
     * const sockets = await io.in("room1").fetchSockets();
 | 
			
		||||
     *
 | 
			
		||||
     * for (const socket of sockets) {
 | 
			
		||||
     *   console.log(socket.id);
 | 
			
		||||
     *   console.log(socket.handshake);
 | 
			
		||||
     *   console.log(socket.rooms);
 | 
			
		||||
     *   console.log(socket.data);
 | 
			
		||||
     *
 | 
			
		||||
     *   socket.emit("hello");
 | 
			
		||||
     *   socket.join("room1");
 | 
			
		||||
     *   socket.leave("room2");
 | 
			
		||||
     *   socket.disconnect();
 | 
			
		||||
     * }
 | 
			
		||||
     */
 | 
			
		||||
    public fetchSockets(): Promise<RemoteSocket<EmitEvents>[]> {
 | 
			
		||||
    public fetchSockets(): Promise<RemoteSocket<EmitEvents, SocketData>[]> {
 | 
			
		||||
        return this.adapter
 | 
			
		||||
            .fetchSockets({
 | 
			
		||||
                rooms: this.rooms,
 | 
			
		||||
                except: this.exceptRooms,
 | 
			
		||||
                flags: this.flags,
 | 
			
		||||
            })
 | 
			
		||||
            .then((sockets) => {
 | 
			
		||||
                return sockets.map((socket) => {
 | 
			
		||||
                    if (socket instanceof Socket) {
 | 
			
		||||
                        // FIXME the TypeScript compiler complains about missing private properties
 | 
			
		||||
                        return socket as unknown as RemoteSocket<EmitEvents>
 | 
			
		||||
                        return socket as unknown as RemoteSocket<EmitEvents, SocketData>
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return new RemoteSocket(this.adapter, socket as SocketDetails)
 | 
			
		||||
                        return new RemoteSocket(
 | 
			
		||||
                            this.adapter,
 | 
			
		||||
                            socket as SocketDetails<SocketData>
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                })
 | 
			
		||||
            })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes the matching socket instances join the specified rooms
 | 
			
		||||
     * Makes the matching socket instances join the specified rooms.
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @public
 | 
			
		||||
     * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     *
 | 
			
		||||
     * // make all socket instances join the "room1" room
 | 
			
		||||
     * io.socketsJoin("room1");
 | 
			
		||||
     *
 | 
			
		||||
     * // make all socket instances in the "room1" room join the "room2" and "room3" rooms
 | 
			
		||||
     * io.in("room1").socketsJoin(["room2", "room3"]);
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     */
 | 
			
		||||
    public socketsJoin(room: Room | Room[]): void {
 | 
			
		||||
        this.adapter.addSockets(
 | 
			
		||||
            {
 | 
			
		||||
                rooms: this.rooms,
 | 
			
		||||
                except: this.exceptRooms,
 | 
			
		||||
                flags: this.flags,
 | 
			
		||||
            },
 | 
			
		||||
            Array.isArray(room) ? room : [room]
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes the matching socket instances leave the specified rooms
 | 
			
		||||
     * Makes the matching socket instances leave the specified rooms.
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @public
 | 
			
		||||
     * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * // make all socket instances leave the "room1" room
 | 
			
		||||
     * io.socketsLeave("room1");
 | 
			
		||||
     *
 | 
			
		||||
     * // make all socket instances in the "room1" room leave the "room2" and "room3" rooms
 | 
			
		||||
     * io.in("room1").socketsLeave(["room2", "room3"]);
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     */
 | 
			
		||||
    public socketsLeave(room: Room | Room[]): void {
 | 
			
		||||
        this.adapter.delSockets(
 | 
			
		||||
            {
 | 
			
		||||
                rooms: this.rooms,
 | 
			
		||||
                except: this.exceptRooms,
 | 
			
		||||
                flags: this.flags,
 | 
			
		||||
            },
 | 
			
		||||
            Array.isArray(room) ? room : [room]
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes the matching socket instances disconnect
 | 
			
		||||
     * Makes the matching socket instances disconnect.
 | 
			
		||||
     *
 | 
			
		||||
     * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * // make all socket instances disconnect (the connections might be kept alive for other namespaces)
 | 
			
		||||
     * io.disconnectSockets();
 | 
			
		||||
     *
 | 
			
		||||
     * // make all socket instances in the "room1" room disconnect and close the underlying connections
 | 
			
		||||
     * io.in("room1").disconnectSockets(true);
 | 
			
		||||
     *
 | 
			
		||||
     * @param close - whether to close the underlying connection
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public disconnectSockets(close: boolean = false): void {
 | 
			
		||||
        this.adapter.disconnectSockets(
 | 
			
		||||
            {
 | 
			
		||||
                rooms: this.rooms,
 | 
			
		||||
                except: this.exceptRooms,
 | 
			
		||||
                flags: this.flags,
 | 
			
		||||
            },
 | 
			
		||||
            close
 | 
			
		||||
        )
 | 
			
		||||
@@ -250,32 +420,35 @@ export class BroadcastOperator<EmitEvents extends EventsMap>
 | 
			
		||||
/**
 | 
			
		||||
 * Format of the data when the Socket instance exists on another Socket.IO server
 | 
			
		||||
 */
 | 
			
		||||
interface SocketDetails {
 | 
			
		||||
interface SocketDetails<SocketData> {
 | 
			
		||||
    id: SocketId
 | 
			
		||||
    handshake: Handshake
 | 
			
		||||
    rooms: Room[]
 | 
			
		||||
    data: any
 | 
			
		||||
    data: SocketData
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Expose of subset of the attributes and methods of the Socket class
 | 
			
		||||
 */
 | 
			
		||||
export class RemoteSocket<EmitEvents extends EventsMap>
 | 
			
		||||
export class RemoteSocket<EmitEvents extends EventsMap, SocketData>
 | 
			
		||||
    implements TypedEventBroadcaster<EmitEvents>
 | 
			
		||||
{
 | 
			
		||||
    public readonly id: SocketId
 | 
			
		||||
    public readonly handshake: Handshake
 | 
			
		||||
    public readonly rooms: Set<Room>
 | 
			
		||||
    public readonly data: any
 | 
			
		||||
    public readonly data: SocketData
 | 
			
		||||
 | 
			
		||||
    private readonly operator: BroadcastOperator<EmitEvents>
 | 
			
		||||
    private readonly operator: BroadcastOperator<EmitEvents, SocketData>
 | 
			
		||||
 | 
			
		||||
    constructor(adapter: Adapter, details: SocketDetails) {
 | 
			
		||||
    constructor(adapter: Adapter, details: SocketDetails<SocketData>) {
 | 
			
		||||
        this.id = details.id
 | 
			
		||||
        this.handshake = details.handshake
 | 
			
		||||
        this.rooms = new Set(details.rooms)
 | 
			
		||||
        this.data = details.data
 | 
			
		||||
        this.operator = new BroadcastOperator(adapter, new Set([this.id]))
 | 
			
		||||
        this.operator = new BroadcastOperator<EmitEvents, SocketData>(
 | 
			
		||||
            adapter,
 | 
			
		||||
            new Set([this.id])
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public emit<Ev extends EventNames<EmitEvents>>(
 | 
			
		||||
@@ -289,7 +462,6 @@ export class RemoteSocket<EmitEvents extends EventsMap>
 | 
			
		||||
     * Joins a room.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String|Array} room - room or array of rooms
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public join(room: Room | Room[]): void {
 | 
			
		||||
        return this.operator.socketsJoin(room)
 | 
			
		||||
@@ -299,7 +471,6 @@ export class RemoteSocket<EmitEvents extends EventsMap>
 | 
			
		||||
     * Leaves a room.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String} room
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public leave(room: Room): void {
 | 
			
		||||
        return this.operator.socketsLeave(room)
 | 
			
		||||
@@ -310,8 +481,6 @@ export class RemoteSocket<EmitEvents extends EventsMap>
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Boolean} close - if `true`, closes the underlying connection
 | 
			
		||||
     * @return {Socket} self
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public disconnect(close = false): this {
 | 
			
		||||
        this.operator.disconnectSockets(close)
 | 
			
		||||
 
 | 
			
		||||
@@ -9,9 +9,10 @@ import type { EventsMap } from "./typed-events"
 | 
			
		||||
import type { Socket } from "./socket"
 | 
			
		||||
// import type { SocketId } from "socket.io-adapter"
 | 
			
		||||
import type { SocketId } from "../socket.io-adapter"
 | 
			
		||||
import type { Socket as EngineIOSocket } from '../engine.io/socket'
 | 
			
		||||
import type { Socket as RawSocket } from '../engine.io/socket'
 | 
			
		||||
 | 
			
		||||
// const debug = debugModule("socket.io:client");
 | 
			
		||||
const debug = require('../debug')("socket.io:client")
 | 
			
		||||
 | 
			
		||||
interface WriteOptions {
 | 
			
		||||
    compress?: boolean
 | 
			
		||||
@@ -20,28 +21,39 @@ interface WriteOptions {
 | 
			
		||||
    wsPreEncoded?: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CloseReason =
 | 
			
		||||
    | "transport error"
 | 
			
		||||
    | "transport close"
 | 
			
		||||
    | "forced close"
 | 
			
		||||
    | "ping timeout"
 | 
			
		||||
    | "parse error"
 | 
			
		||||
 | 
			
		||||
export class Client<
 | 
			
		||||
    ListenEvents extends EventsMap,
 | 
			
		||||
    EmitEvents extends EventsMap,
 | 
			
		||||
    ServerSideEvents extends EventsMap
 | 
			
		||||
    > {
 | 
			
		||||
    public readonly conn: EngineIOSocket
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    readonly id: string
 | 
			
		||||
    private readonly server: Server<ListenEvents, EmitEvents, ServerSideEvents>
 | 
			
		||||
    ServerSideEvents extends EventsMap,
 | 
			
		||||
    SocketData = any
 | 
			
		||||
> {
 | 
			
		||||
    public readonly conn: RawSocket
 | 
			
		||||
 | 
			
		||||
    private readonly id: string
 | 
			
		||||
    private readonly server: Server<
 | 
			
		||||
        ListenEvents,
 | 
			
		||||
        EmitEvents,
 | 
			
		||||
        ServerSideEvents,
 | 
			
		||||
        SocketData
 | 
			
		||||
    >
 | 
			
		||||
    private readonly encoder: Encoder
 | 
			
		||||
    private readonly decoder: any
 | 
			
		||||
    private readonly decoder: Decoder
 | 
			
		||||
    private sockets: Map<
 | 
			
		||||
        SocketId,
 | 
			
		||||
        Socket<ListenEvents, EmitEvents, ServerSideEvents>
 | 
			
		||||
    > = new Map()
 | 
			
		||||
        Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
    > = new Map();
 | 
			
		||||
    private nsps: Map<
 | 
			
		||||
        string,
 | 
			
		||||
        Socket<ListenEvents, EmitEvents, ServerSideEvents>
 | 
			
		||||
    > = new Map()
 | 
			
		||||
    private connectTimeout: NodeJS.Timeout
 | 
			
		||||
        Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
    > = new Map();
 | 
			
		||||
    private connectTimeout?: NodeJS.Timeout
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Client constructor.
 | 
			
		||||
@@ -51,8 +63,8 @@ export class Client<
 | 
			
		||||
     * @package
 | 
			
		||||
     */
 | 
			
		||||
    constructor(
 | 
			
		||||
        server: Server<ListenEvents, EmitEvents, ServerSideEvents>,
 | 
			
		||||
        conn: EngineIOSocket
 | 
			
		||||
        server: Server<ListenEvents, EmitEvents, ServerSideEvents, SocketData>,
 | 
			
		||||
        conn: any
 | 
			
		||||
    ) {
 | 
			
		||||
        this.server = server
 | 
			
		||||
        this.conn = conn
 | 
			
		||||
@@ -67,7 +79,8 @@ export class Client<
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public get request(): any/** IncomingMessage */ {
 | 
			
		||||
    // public get request(): IncomingMessage {
 | 
			
		||||
    public get request(): any {
 | 
			
		||||
        return this.conn.request
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -77,7 +90,6 @@ export class Client<
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private setup() {
 | 
			
		||||
        console.debug(`socket.io client setup conn ${this.conn.id}`)
 | 
			
		||||
        this.onclose = this.onclose.bind(this)
 | 
			
		||||
        this.ondata = this.ondata.bind(this)
 | 
			
		||||
        this.onerror = this.onerror.bind(this)
 | 
			
		||||
@@ -91,10 +103,10 @@ export class Client<
 | 
			
		||||
 | 
			
		||||
        this.connectTimeout = setTimeout(() => {
 | 
			
		||||
            if (this.nsps.size === 0) {
 | 
			
		||||
                console.debug(`no namespace joined yet, close the client ${this.id}`)
 | 
			
		||||
                debug("no namespace joined yet, close the client")
 | 
			
		||||
                this.close()
 | 
			
		||||
            } else {
 | 
			
		||||
                console.debug(`the client ${this.id} has already joined a namespace, nothing to do`)
 | 
			
		||||
                debug("the client has already joined a namespace, nothing to do")
 | 
			
		||||
            }
 | 
			
		||||
        }, this.server._connectTimeout)
 | 
			
		||||
    }
 | 
			
		||||
@@ -108,7 +120,7 @@ export class Client<
 | 
			
		||||
     */
 | 
			
		||||
    private connect(name: string, auth: object = {}): void {
 | 
			
		||||
        if (this.server._nsps.has(name)) {
 | 
			
		||||
            console.debug(`socket.io client ${this.id} connecting to namespace ${name}`)
 | 
			
		||||
            debug("connecting to namespace %s", name)
 | 
			
		||||
            return this.doConnect(name, auth)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -117,14 +129,13 @@ export class Client<
 | 
			
		||||
            auth,
 | 
			
		||||
            (
 | 
			
		||||
                dynamicNspName:
 | 
			
		||||
                    | Namespace<ListenEvents, EmitEvents, ServerSideEvents>
 | 
			
		||||
                    | Namespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
                    | false
 | 
			
		||||
            ) => {
 | 
			
		||||
                if (dynamicNspName) {
 | 
			
		||||
                    console.debug(`dynamic namespace ${dynamicNspName} was created`)
 | 
			
		||||
                    this.doConnect(name, auth)
 | 
			
		||||
                } else {
 | 
			
		||||
                    console.debug(`creation of namespace ${name} was denied`)
 | 
			
		||||
                    debug("creation of namespace %s was denied", name)
 | 
			
		||||
                    this._packet({
 | 
			
		||||
                        type: PacketType.CONNECT_ERROR,
 | 
			
		||||
                        nsp: name,
 | 
			
		||||
@@ -178,20 +189,16 @@ export class Client<
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    _remove(socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>): void {
 | 
			
		||||
    _remove(
 | 
			
		||||
        socket: Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
    ): void {
 | 
			
		||||
        if (this.sockets.has(socket.id)) {
 | 
			
		||||
            const nsp = this.sockets.get(socket.id)!.nsp.name
 | 
			
		||||
            this.sockets.delete(socket.id)
 | 
			
		||||
            this.nsps.delete(nsp)
 | 
			
		||||
        } else {
 | 
			
		||||
            console.debug("ignoring remove for", socket.id)
 | 
			
		||||
            debug("ignoring remove for %s", socket.id)
 | 
			
		||||
        }
 | 
			
		||||
        // @java-patch  disconnect client when no live socket
 | 
			
		||||
        process.nextTick(() => {
 | 
			
		||||
            if (this.sockets.size == 0) {
 | 
			
		||||
                this.onclose('no live socket')
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -200,43 +207,47 @@ export class Client<
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private close(): void {
 | 
			
		||||
        console.debug(`client ${this.id} close - reason: forcing transport close`)
 | 
			
		||||
        if ("open" === this.conn.readyState) {
 | 
			
		||||
            console.debug("forcing transport close")
 | 
			
		||||
            debug("forcing transport close")
 | 
			
		||||
            this.conn.close()
 | 
			
		||||
            this.onclose("forced server close")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
   * Writes a packet to the transport.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {Object} packet object
 | 
			
		||||
   * @param {Object} opts
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
     * Writes a packet to the transport.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Object} packet object
 | 
			
		||||
     * @param {Object} opts
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    _packet(packet: Packet | any[], opts: WriteOptions = {}): void {
 | 
			
		||||
        if (this.conn.readyState !== "open") {
 | 
			
		||||
            console.debug(`client ${this.id} ignoring packet write ${JSON.stringify(packet)}`)
 | 
			
		||||
            debug("ignoring packet write %j", packet)
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        const encodedPackets = opts.preEncoded
 | 
			
		||||
            ? (packet as any[]) // previous versions of the adapter incorrectly used socket.packet() instead of writeToEngine()
 | 
			
		||||
            : this.encoder.encode(packet as Packet)
 | 
			
		||||
        for (const encodedPacket of encodedPackets) {
 | 
			
		||||
            this.writeToEngine(encodedPacket, opts)
 | 
			
		||||
        }
 | 
			
		||||
        this.writeToEngine(encodedPackets, opts)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private writeToEngine(
 | 
			
		||||
        encodedPacket: String | Buffer,
 | 
			
		||||
        encodedPackets: Array<String | Buffer>,
 | 
			
		||||
        opts: WriteOptions
 | 
			
		||||
    ): void {
 | 
			
		||||
        if (opts.volatile && !this.conn.transport.writable) {
 | 
			
		||||
            console.debug(`client ${this.id} volatile packet is discarded since the transport is not currently writable`)
 | 
			
		||||
            debug(
 | 
			
		||||
                "volatile packet is discarded since the transport is not currently writable"
 | 
			
		||||
            )
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        this.conn.write(encodedPacket, opts)
 | 
			
		||||
        const packets = Array.isArray(encodedPackets)
 | 
			
		||||
            ? encodedPackets
 | 
			
		||||
            : [encodedPackets]
 | 
			
		||||
        for (const encodedPacket of packets) {
 | 
			
		||||
            this.conn.write(encodedPacket, opts)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -248,8 +259,9 @@ export class Client<
 | 
			
		||||
        // try/catch is needed for protocol violations (GH-1880)
 | 
			
		||||
        try {
 | 
			
		||||
            this.decoder.add(data)
 | 
			
		||||
        } catch (error: any) {
 | 
			
		||||
            this.onerror(error)
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            debug("invalid packet format")
 | 
			
		||||
            this.onerror(e)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -259,22 +271,31 @@ export class Client<
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private ondecoded(packet: Packet): void {
 | 
			
		||||
        if (PacketType.CONNECT === packet.type) {
 | 
			
		||||
            if (this.conn.protocol === 3) {
 | 
			
		||||
                const parsed = url.parse(packet.nsp, true)
 | 
			
		||||
                this.connect(parsed.pathname!, parsed.query)
 | 
			
		||||
            } else {
 | 
			
		||||
                this.connect(packet.nsp, packet.data)
 | 
			
		||||
            }
 | 
			
		||||
        let namespace: string
 | 
			
		||||
        let authPayload
 | 
			
		||||
        if (this.conn.protocol === 3) {
 | 
			
		||||
            const parsed = url.parse(packet.nsp, true)
 | 
			
		||||
            namespace = parsed.pathname!
 | 
			
		||||
            authPayload = parsed.query
 | 
			
		||||
        } else {
 | 
			
		||||
            const socket = this.nsps.get(packet.nsp)
 | 
			
		||||
            if (socket) {
 | 
			
		||||
                process.nextTick(function () {
 | 
			
		||||
                    socket._onpacket(packet)
 | 
			
		||||
                })
 | 
			
		||||
            } else {
 | 
			
		||||
                console.debug(`client ${this.id} no socket for namespace ${packet.nsp}.`)
 | 
			
		||||
            }
 | 
			
		||||
            namespace = packet.nsp
 | 
			
		||||
            authPayload = packet.data
 | 
			
		||||
        }
 | 
			
		||||
        const socket = this.nsps.get(namespace)
 | 
			
		||||
 | 
			
		||||
        if (!socket && packet.type === PacketType.CONNECT) {
 | 
			
		||||
            this.connect(namespace, authPayload)
 | 
			
		||||
        } else if (
 | 
			
		||||
            socket &&
 | 
			
		||||
            packet.type !== PacketType.CONNECT &&
 | 
			
		||||
            packet.type !== PacketType.CONNECT_ERROR
 | 
			
		||||
        ) {
 | 
			
		||||
            process.nextTick(function () {
 | 
			
		||||
                socket._onpacket(packet)
 | 
			
		||||
            })
 | 
			
		||||
        } else {
 | 
			
		||||
            debug("invalid state (packet type: %s)", packet.type)
 | 
			
		||||
            this.close()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -297,8 +318,8 @@ export class Client<
 | 
			
		||||
     * @param reason
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private onclose(reason: string): void {
 | 
			
		||||
        console.debug(`client ${this.id} close with reason ${reason}`)
 | 
			
		||||
    private onclose(reason: CloseReason | "forced server close"): void {
 | 
			
		||||
        debug("client close with reason %s", reason)
 | 
			
		||||
 | 
			
		||||
        // ignore a potential subsequent `close` event
 | 
			
		||||
        this.destroy()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +1,30 @@
 | 
			
		||||
// import http = require("http");
 | 
			
		||||
// import type { Server as HTTPSServer } from "https";
 | 
			
		||||
// import type { Http2SecureServer } from "http2";
 | 
			
		||||
// import { createReadStream } from "fs";
 | 
			
		||||
// import { createDeflate, createGzip, createBrotliCompress } from "zlib";
 | 
			
		||||
// import accepts = require("accepts");
 | 
			
		||||
// import { pipeline } from "stream";
 | 
			
		||||
// import path = require("path");
 | 
			
		||||
import engine = require("../engine.io")
 | 
			
		||||
import { Client } from './client'
 | 
			
		||||
import { EventEmitter } from 'events'
 | 
			
		||||
import {
 | 
			
		||||
    attach,
 | 
			
		||||
    Server as Engine,
 | 
			
		||||
    ServerOptions as EngineOptions,
 | 
			
		||||
    AttachOptions,
 | 
			
		||||
    //   uServer,
 | 
			
		||||
} from "../engine.io"
 | 
			
		||||
import { Client } from "./client"
 | 
			
		||||
import { EventEmitter } from "events"
 | 
			
		||||
import { ExtendedError, Namespace, ServerReservedEventsMap } from "./namespace"
 | 
			
		||||
import { ParentNamespace } from './parent-namespace'
 | 
			
		||||
import { ParentNamespace } from "./parent-namespace"
 | 
			
		||||
// import { Adapter, Room, SocketId } from "socket.io-adapter"
 | 
			
		||||
import { Adapter, Room, SocketId } from "../socket.io-adapter"
 | 
			
		||||
// import * as parser from "socket.io-parser";
 | 
			
		||||
// import * as parser from "socket.io-parser"
 | 
			
		||||
import * as parser from "../socket.io-parser"
 | 
			
		||||
// import type { Encoder } from "socket.io-parser";
 | 
			
		||||
// import type { Encoder } from "socket.io-parser"
 | 
			
		||||
import type { Encoder } from "../socket.io-parser"
 | 
			
		||||
// import debugModule from "debug";
 | 
			
		||||
import { Socket } from './socket'
 | 
			
		||||
// import type { CookieSerializeOptions } from "cookie";
 | 
			
		||||
// import type { CorsOptions } from "cors";
 | 
			
		||||
// import debugModule from "debug"
 | 
			
		||||
import { Socket } from "./socket"
 | 
			
		||||
import type { BroadcastOperator, RemoteSocket } from "./broadcast-operator"
 | 
			
		||||
import {
 | 
			
		||||
    EventsMap,
 | 
			
		||||
@@ -27,13 +33,14 @@ import {
 | 
			
		||||
    StrictEventEmitter,
 | 
			
		||||
    EventNames,
 | 
			
		||||
} from "./typed-events"
 | 
			
		||||
// import { patchAdapter, restoreAdapter, serveFile } from "./uws"
 | 
			
		||||
 | 
			
		||||
import type { Socket as EngineIOSocket } from '../engine.io/socket'
 | 
			
		||||
// const debug = debugModule("socket.io:server")
 | 
			
		||||
const debug = require('../debug')("socket.io:server")
 | 
			
		||||
 | 
			
		||||
// const clientVersion = require("../package.json").version
 | 
			
		||||
// const dotMapRegex = /\.map/
 | 
			
		||||
 | 
			
		||||
// type Transport = "polling" | "websocket";
 | 
			
		||||
type ParentNspNameMatchFn = (
 | 
			
		||||
    name: string,
 | 
			
		||||
    auth: { [key: string]: any },
 | 
			
		||||
@@ -42,105 +49,7 @@ type ParentNspNameMatchFn = (
 | 
			
		||||
 | 
			
		||||
type AdapterConstructor = typeof Adapter | ((nsp: Namespace) => Adapter)
 | 
			
		||||
 | 
			
		||||
interface EngineOptions {
 | 
			
		||||
    /**
 | 
			
		||||
     * how many ms without a pong packet to consider the connection closed
 | 
			
		||||
     * @default 5000
 | 
			
		||||
     */
 | 
			
		||||
    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: http.IncomingMessage,
 | 
			
		||||
    //     fn: (err: string | null | undefined, success: boolean) => void
 | 
			
		||||
    // ) => void
 | 
			
		||||
    /**
 | 
			
		||||
     * the low-level transports that are enabled
 | 
			
		||||
     * @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). Default value is ws.
 | 
			
		||||
     * An alternative c++ addon is also available by installing uws module.
 | 
			
		||||
     */
 | 
			
		||||
    wsEngine: string
 | 
			
		||||
    /**
 | 
			
		||||
     * 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 | boolean
 | 
			
		||||
    /**
 | 
			
		||||
     * the options that will be forwarded to the cors module
 | 
			
		||||
     */
 | 
			
		||||
    // cors: CorsOptions
 | 
			
		||||
    /**
 | 
			
		||||
     * whether to enable compatibility with Socket.IO v2 clients
 | 
			
		||||
     * @default false
 | 
			
		||||
     */
 | 
			
		||||
    allowEIO3: boolean
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface EngineAttachOptions extends EngineOptions, AttachOptions { }
 | 
			
		||||
 | 
			
		||||
interface ServerOptions extends EngineAttachOptions {
 | 
			
		||||
interface ServerOptions extends EngineOptions, AttachOptions {
 | 
			
		||||
    /**
 | 
			
		||||
     * name of the path to capture
 | 
			
		||||
     * @default "/socket.io"
 | 
			
		||||
@@ -155,6 +64,7 @@ interface ServerOptions extends EngineAttachOptions {
 | 
			
		||||
     * the adapter to use
 | 
			
		||||
     * @default the in-memory adapter (https://github.com/socketio/socket.io-adapter)
 | 
			
		||||
     */
 | 
			
		||||
    // adapter: AdapterConstructor
 | 
			
		||||
    adapter: any
 | 
			
		||||
    /**
 | 
			
		||||
     * the parser to use
 | 
			
		||||
@@ -168,31 +78,62 @@ interface ServerOptions extends EngineAttachOptions {
 | 
			
		||||
    connectTimeout: number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a Socket.IO server.
 | 
			
		||||
 *
 | 
			
		||||
 * @example
 | 
			
		||||
 * import { Server } from "socket.io";
 | 
			
		||||
 *
 | 
			
		||||
 * const io = new Server();
 | 
			
		||||
 *
 | 
			
		||||
 * io.on("connection", (socket) => {
 | 
			
		||||
 *   console.log(`socket ${socket.id} connected`);
 | 
			
		||||
 *
 | 
			
		||||
 *   // send an event to the client
 | 
			
		||||
 *   socket.emit("foo", "bar");
 | 
			
		||||
 *
 | 
			
		||||
 *   socket.on("foobar", () => {
 | 
			
		||||
 *     // an event was received from the client
 | 
			
		||||
 *   });
 | 
			
		||||
 *
 | 
			
		||||
 *   // upon disconnection
 | 
			
		||||
 *   socket.on("disconnect", (reason) => {
 | 
			
		||||
 *     console.log(`socket ${socket.id} disconnected due to ${reason}`);
 | 
			
		||||
 *   });
 | 
			
		||||
 * });
 | 
			
		||||
 *
 | 
			
		||||
 * io.listen(3000);
 | 
			
		||||
 */
 | 
			
		||||
export class Server<
 | 
			
		||||
    ListenEvents extends EventsMap = DefaultEventsMap,
 | 
			
		||||
    EmitEvents extends EventsMap = ListenEvents,
 | 
			
		||||
    ServerSideEvents extends EventsMap = DefaultEventsMap
 | 
			
		||||
    > extends StrictEventEmitter<
 | 
			
		||||
    ServerSideEvents extends EventsMap = DefaultEventsMap,
 | 
			
		||||
    SocketData = any
 | 
			
		||||
> extends StrictEventEmitter<
 | 
			
		||||
    ServerSideEvents,
 | 
			
		||||
    EmitEvents,
 | 
			
		||||
    ServerReservedEventsMap<ListenEvents, EmitEvents, ServerSideEvents>
 | 
			
		||||
    > {
 | 
			
		||||
    ServerReservedEventsMap<
 | 
			
		||||
        ListenEvents,
 | 
			
		||||
        EmitEvents,
 | 
			
		||||
        ServerSideEvents,
 | 
			
		||||
        SocketData
 | 
			
		||||
    >
 | 
			
		||||
> {
 | 
			
		||||
    public readonly sockets: Namespace<
 | 
			
		||||
        ListenEvents,
 | 
			
		||||
        EmitEvents,
 | 
			
		||||
        ServerSideEvents
 | 
			
		||||
        ServerSideEvents,
 | 
			
		||||
        SocketData
 | 
			
		||||
    >
 | 
			
		||||
    /**
 | 
			
		||||
     * A reference to the underlying Engine.IO server.
 | 
			
		||||
     *
 | 
			
		||||
     * Example:
 | 
			
		||||
     *
 | 
			
		||||
     * <code>
 | 
			
		||||
     *   const clientsCount = io.engine.clientsCount;
 | 
			
		||||
     * </code>
 | 
			
		||||
     * @example
 | 
			
		||||
     * const clientsCount = io.engine.clientsCount;
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    public engine: any
 | 
			
		||||
 | 
			
		||||
    /** @private */
 | 
			
		||||
    readonly _parser: typeof parser
 | 
			
		||||
    /** @private */
 | 
			
		||||
@@ -201,28 +142,62 @@ export class Server<
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    _nsps: Map<string, Namespace<ListenEvents, EmitEvents, ServerSideEvents>> =
 | 
			
		||||
        new Map();
 | 
			
		||||
    _nsps: Map<
 | 
			
		||||
        string,
 | 
			
		||||
        Namespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
    > = new Map();
 | 
			
		||||
    private parentNsps: Map<
 | 
			
		||||
        ParentNspNameMatchFn,
 | 
			
		||||
        ParentNamespace<ListenEvents, EmitEvents, ServerSideEvents>
 | 
			
		||||
        ParentNamespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
    > = new Map();
 | 
			
		||||
    private _adapter?: AdapterConstructor
 | 
			
		||||
    private _serveClient: boolean
 | 
			
		||||
    private opts: Partial<EngineOptions>
 | 
			
		||||
    private eio
 | 
			
		||||
    private eio: Engine
 | 
			
		||||
    private _path: string
 | 
			
		||||
    private clientPathRegex: RegExp
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    _connectTimeout: number
 | 
			
		||||
    // private httpServer: http.Server | HTTPSServer | Http2SecureServer
 | 
			
		||||
 | 
			
		||||
    // private httpServer: http.Server
 | 
			
		||||
 | 
			
		||||
    constructor(srv: any, opts: Partial<ServerOptions> = {}) {
 | 
			
		||||
    /**
 | 
			
		||||
     * Server constructor.
 | 
			
		||||
     *
 | 
			
		||||
     * @param srv http server, port, or options
 | 
			
		||||
     * @param [opts]
 | 
			
		||||
     */
 | 
			
		||||
    constructor(opts?: Partial<ServerOptions>)
 | 
			
		||||
    constructor(
 | 
			
		||||
        // srv?: http.Server | HTTPSServer | Http2SecureServer | number,
 | 
			
		||||
        srv?: any,
 | 
			
		||||
        opts?: Partial<ServerOptions>
 | 
			
		||||
    )
 | 
			
		||||
    constructor(
 | 
			
		||||
        srv:
 | 
			
		||||
            // | undefined
 | 
			
		||||
            // | Partial<ServerOptions>
 | 
			
		||||
            // | http.Server
 | 
			
		||||
            // | HTTPSServer
 | 
			
		||||
            // | Http2SecureServer
 | 
			
		||||
            // | number,
 | 
			
		||||
            any,
 | 
			
		||||
        opts?: Partial<ServerOptions>
 | 
			
		||||
    )
 | 
			
		||||
    constructor(
 | 
			
		||||
        srv:
 | 
			
		||||
            // | undefined
 | 
			
		||||
            // | Partial<ServerOptions>
 | 
			
		||||
            // | http.Server
 | 
			
		||||
            // | HTTPSServer
 | 
			
		||||
            // | Http2SecureServer
 | 
			
		||||
            // | number,
 | 
			
		||||
            any,
 | 
			
		||||
        opts: Partial<ServerOptions> = {}
 | 
			
		||||
    ) {
 | 
			
		||||
        super()
 | 
			
		||||
        if (!srv) { throw new Error('srv can\'t be undefiend!') }
 | 
			
		||||
        // if (
 | 
			
		||||
        //     "object" === typeof srv &&
 | 
			
		||||
        //     srv instanceof Object &&
 | 
			
		||||
@@ -237,8 +212,12 @@ export class Server<
 | 
			
		||||
        this._parser = opts.parser || parser
 | 
			
		||||
        this.encoder = new this._parser.Encoder()
 | 
			
		||||
        this.adapter(opts.adapter || Adapter)
 | 
			
		||||
        this.sockets = this.of('/')
 | 
			
		||||
        // if (srv) this.attach(srv as http.Server);
 | 
			
		||||
        this.sockets = this.of("/")
 | 
			
		||||
        this.opts = opts
 | 
			
		||||
        // if (srv || typeof srv == "number")
 | 
			
		||||
        //     this.attach(
 | 
			
		||||
        //         srv as http.Server | HTTPSServer | Http2SecureServer | number
 | 
			
		||||
        //     )
 | 
			
		||||
        this.attach(srv, this.opts)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -247,7 +226,6 @@ export class Server<
 | 
			
		||||
     *
 | 
			
		||||
     * @param v - whether to serve client code
 | 
			
		||||
     * @return self when setting or value when getting
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public serveClient(v: boolean): this
 | 
			
		||||
    public serveClient(): boolean
 | 
			
		||||
@@ -271,7 +249,9 @@ export class Server<
 | 
			
		||||
        name: string,
 | 
			
		||||
        auth: { [key: string]: any },
 | 
			
		||||
        fn: (
 | 
			
		||||
            nsp: Namespace<ListenEvents, EmitEvents, ServerSideEvents> | false
 | 
			
		||||
            nsp:
 | 
			
		||||
                | Namespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
                | false
 | 
			
		||||
        ) => void
 | 
			
		||||
    ): void {
 | 
			
		||||
        if (this.parentNsps.size === 0) return fn(false)
 | 
			
		||||
@@ -285,15 +265,18 @@ export class Server<
 | 
			
		||||
            }
 | 
			
		||||
            nextFn.value(name, auth, (err, allow) => {
 | 
			
		||||
                if (err || !allow) {
 | 
			
		||||
                    run()
 | 
			
		||||
                } else {
 | 
			
		||||
                    const namespace = this.parentNsps
 | 
			
		||||
                        .get(nextFn.value)!
 | 
			
		||||
                        .createChild(name)
 | 
			
		||||
                    // @ts-ignore
 | 
			
		||||
                    this.sockets.emitReserved("new_namespace", namespace)
 | 
			
		||||
                    fn(namespace)
 | 
			
		||||
                    return run()
 | 
			
		||||
                }
 | 
			
		||||
                if (this._nsps.has(name)) {
 | 
			
		||||
                    // the namespace was created in the meantime
 | 
			
		||||
                    debug("dynamic namespace %s already exists", name)
 | 
			
		||||
                    return fn(this._nsps.get(name) as Namespace)
 | 
			
		||||
                }
 | 
			
		||||
                const namespace = this.parentNsps.get(nextFn.value)!.createChild(name)
 | 
			
		||||
                debug("dynamic namespace %s was created", name)
 | 
			
		||||
                // @ts-ignore
 | 
			
		||||
                this.sockets.emitReserved("new_namespace", namespace)
 | 
			
		||||
                fn(namespace)
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -305,7 +288,6 @@ export class Server<
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String} v pathname
 | 
			
		||||
     * @return {Server|String} self when setting or value when getting
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public path(v: string): this
 | 
			
		||||
    public path(): string
 | 
			
		||||
@@ -319,7 +301,7 @@ export class Server<
 | 
			
		||||
        this.clientPathRegex = new RegExp(
 | 
			
		||||
            "^" +
 | 
			
		||||
            escapedPath +
 | 
			
		||||
            "/socket\\.io(\\.min|\\.msgpack\\.min)?\\.js(\\.map)?$"
 | 
			
		||||
            "/socket\\.io(\\.msgpack|\\.esm)?(\\.min)?\\.js(\\.map)?(?:\\?|$)"
 | 
			
		||||
        )
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
@@ -327,7 +309,6 @@ export class Server<
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the delay after which a client without namespace is closed
 | 
			
		||||
     * @param v
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public connectTimeout(v: number): this
 | 
			
		||||
    public connectTimeout(): number
 | 
			
		||||
@@ -343,7 +324,6 @@ export class Server<
 | 
			
		||||
     *
 | 
			
		||||
     * @param v pathname
 | 
			
		||||
     * @return self when setting or value when getting
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public adapter(): AdapterConstructor | undefined
 | 
			
		||||
    public adapter(v: AdapterConstructor): this
 | 
			
		||||
@@ -364,14 +344,14 @@ export class Server<
 | 
			
		||||
     * @param srv - server or port
 | 
			
		||||
     * @param opts - options passed to engine.io
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public listen(
 | 
			
		||||
        srv: any,//http.Server | number,
 | 
			
		||||
        // srv: http.Server | HTTPSServer | Http2SecureServer | number,
 | 
			
		||||
        srv: any,
 | 
			
		||||
        opts: Partial<ServerOptions> = {}
 | 
			
		||||
    ): this {
 | 
			
		||||
        throw Error('Unsupport listen at MiaoScript Engine!')
 | 
			
		||||
        //return this.attach(srv, opts)
 | 
			
		||||
        // return this.attach(srv, opts)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -380,10 +360,10 @@ export class Server<
 | 
			
		||||
     * @param srv - server or port
 | 
			
		||||
     * @param opts - options passed to engine.io
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public attach(
 | 
			
		||||
        srv: any,//http.Server | number,
 | 
			
		||||
        // srv: http.Server | HTTPSServer | Http2SecureServer | number,
 | 
			
		||||
        srv: any,
 | 
			
		||||
        opts: Partial<ServerOptions> = {}
 | 
			
		||||
    ): this {
 | 
			
		||||
        // if ("function" == typeof srv) {
 | 
			
		||||
@@ -418,6 +398,69 @@ export class Server<
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // public attachApp(app /*: TemplatedApp */, opts: Partial<ServerOptions> = {}) {
 | 
			
		||||
    //     // merge the options passed to the Socket.IO server
 | 
			
		||||
    //     Object.assign(opts, this.opts)
 | 
			
		||||
    //     // set engine.io path to `/socket.io`
 | 
			
		||||
    //     opts.path = opts.path || this._path
 | 
			
		||||
 | 
			
		||||
    //     // initialize engine
 | 
			
		||||
    //     debug("creating uWebSockets.js-based engine with opts %j", opts)
 | 
			
		||||
    //     const engine = new uServer(opts)
 | 
			
		||||
 | 
			
		||||
    //     engine.attach(app, opts)
 | 
			
		||||
 | 
			
		||||
    //     // bind to engine events
 | 
			
		||||
    //     this.bind(engine)
 | 
			
		||||
 | 
			
		||||
    //     if (this._serveClient) {
 | 
			
		||||
    //         // attach static file serving
 | 
			
		||||
    //         app.get(`${this._path}/*`, (res, req) => {
 | 
			
		||||
    //             if (!this.clientPathRegex.test(req.getUrl())) {
 | 
			
		||||
    //                 req.setYield(true)
 | 
			
		||||
    //                 return
 | 
			
		||||
    //             }
 | 
			
		||||
 | 
			
		||||
    //             const filename = req
 | 
			
		||||
    //                 .getUrl()
 | 
			
		||||
    //                 .replace(this._path, "")
 | 
			
		||||
    //                 .replace(/\?.*$/, "")
 | 
			
		||||
    //                 .replace(/^\//, "")
 | 
			
		||||
    //             const isMap = dotMapRegex.test(filename)
 | 
			
		||||
    //             const type = isMap ? "map" : "source"
 | 
			
		||||
 | 
			
		||||
    //             // Per the standard, ETags must be quoted:
 | 
			
		||||
    //             // https://tools.ietf.org/html/rfc7232#section-2.3
 | 
			
		||||
    //             const expectedEtag = '"' + clientVersion + '"'
 | 
			
		||||
    //             const weakEtag = "W/" + expectedEtag
 | 
			
		||||
 | 
			
		||||
    //             const etag = req.getHeader("if-none-match")
 | 
			
		||||
    //             if (etag) {
 | 
			
		||||
    //                 if (expectedEtag === etag || weakEtag === etag) {
 | 
			
		||||
    //                     debug("serve client %s 304", type)
 | 
			
		||||
    //                     res.writeStatus("304 Not Modified")
 | 
			
		||||
    //                     res.end()
 | 
			
		||||
    //                     return
 | 
			
		||||
    //                 }
 | 
			
		||||
    //             }
 | 
			
		||||
 | 
			
		||||
    //             debug("serve client %s", type)
 | 
			
		||||
 | 
			
		||||
    //             res.writeHeader("cache-control", "public, max-age=0")
 | 
			
		||||
    //             res.writeHeader(
 | 
			
		||||
    //                 "content-type",
 | 
			
		||||
    //                 "application/" + (isMap ? "json" : "javascript")
 | 
			
		||||
    //             )
 | 
			
		||||
    //             res.writeHeader("etag", expectedEtag)
 | 
			
		||||
 | 
			
		||||
    //             const filepath = path.join(__dirname, "../client-dist/", filename)
 | 
			
		||||
    //             serveFile(res, filepath)
 | 
			
		||||
    //         })
 | 
			
		||||
    //     }
 | 
			
		||||
 | 
			
		||||
    //     patchAdapter(app)
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize engine
 | 
			
		||||
     *
 | 
			
		||||
@@ -425,10 +468,14 @@ export class Server<
 | 
			
		||||
     * @param opts - options passed to engine.io
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private initEngine(srv: any, opts: Partial<EngineAttachOptions>) {
 | 
			
		||||
        // // initialize engine
 | 
			
		||||
        console.debug("creating engine.io instance with opts", JSON.stringify(opts))
 | 
			
		||||
        this.eio = engine.attach(srv, opts)
 | 
			
		||||
    private initEngine(
 | 
			
		||||
        // srv: http.Server | HTTPSServer | Http2SecureServer,
 | 
			
		||||
        srv: any,
 | 
			
		||||
        opts: EngineOptions & AttachOptions
 | 
			
		||||
    ): void {
 | 
			
		||||
        // initialize engine
 | 
			
		||||
        debug("creating engine.io instance with opts %j", opts)
 | 
			
		||||
        this.eio = attach(srv, opts)
 | 
			
		||||
 | 
			
		||||
        // // attach static file serving
 | 
			
		||||
        // if (this._serveClient) this.attachServe(srv)
 | 
			
		||||
@@ -446,13 +493,15 @@ export class Server<
 | 
			
		||||
    //  * @param srv http server
 | 
			
		||||
    //  * @private
 | 
			
		||||
    //  */
 | 
			
		||||
    // private attachServe(srv: http.Server): void {
 | 
			
		||||
    // private attachServe(
 | 
			
		||||
    //     srv: http.Server | HTTPSServer | Http2SecureServer
 | 
			
		||||
    // ): void {
 | 
			
		||||
    //     debug("attaching client serving req handler")
 | 
			
		||||
 | 
			
		||||
    //     const evs = srv.listeners("request").slice(0)
 | 
			
		||||
    //     srv.removeAllListeners("request")
 | 
			
		||||
    //     srv.on("request", (req, res) => {
 | 
			
		||||
    //         if (this.clientPathRegex.test(req.url)) {
 | 
			
		||||
    //         if (this.clientPathRegex.test(req.url!)) {
 | 
			
		||||
    //             this.serve(req, res)
 | 
			
		||||
    //         } else {
 | 
			
		||||
    //             for (let i = 0; i < evs.length; i++) {
 | 
			
		||||
@@ -470,7 +519,7 @@ export class Server<
 | 
			
		||||
    //  * @private
 | 
			
		||||
    //  */
 | 
			
		||||
    // private serve(req: http.IncomingMessage, res: http.ServerResponse): void {
 | 
			
		||||
    //     const filename = req.url!.replace(this._path, "")
 | 
			
		||||
    //     const filename = req.url!.replace(this._path, "").replace(/\?.*$/, "")
 | 
			
		||||
    //     const isMap = dotMapRegex.test(filename)
 | 
			
		||||
    //     const type = isMap ? "map" : "source"
 | 
			
		||||
 | 
			
		||||
@@ -547,11 +596,9 @@ export class Server<
 | 
			
		||||
     * Binds socket.io to an engine.io instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {engine.Server} engine engine.io (or compatible) server
 | 
			
		||||
     * @return {Server} self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @return self
 | 
			
		||||
     */
 | 
			
		||||
    public bind(engine): Server {
 | 
			
		||||
        console.debug('engine.io', engine.constructor.name, 'bind to socket.io')
 | 
			
		||||
    public bind(engine): this {
 | 
			
		||||
        this.engine = engine
 | 
			
		||||
        this.engine.on("connection", this.onconnection.bind(this))
 | 
			
		||||
        return this
 | 
			
		||||
@@ -561,12 +608,12 @@ export class Server<
 | 
			
		||||
     * Called with each incoming transport connection.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {engine.Socket} conn
 | 
			
		||||
     * @return {Server} self
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private onconnection(conn: EngineIOSocket): Server {
 | 
			
		||||
        console.debug(`socket.io index incoming connection with id ${conn.id}`)
 | 
			
		||||
        let client = new Client(this, conn)
 | 
			
		||||
    private onconnection(conn): this {
 | 
			
		||||
        debug("incoming connection with id %s", conn.id)
 | 
			
		||||
        const client = new Client(this, conn)
 | 
			
		||||
        if (conn.protocol === 3) {
 | 
			
		||||
            // @ts-ignore
 | 
			
		||||
            client.connect("/")
 | 
			
		||||
@@ -577,17 +624,30 @@ export class Server<
 | 
			
		||||
    /**
 | 
			
		||||
     * Looks up a namespace.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String|RegExp|Function} name nsp name
 | 
			
		||||
     * @example
 | 
			
		||||
     * // with a simple string
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * // with a regex
 | 
			
		||||
     * const dynamicNsp = io.of(/^\/dynamic-\d+$/).on("connection", (socket) => {
 | 
			
		||||
     *   const namespace = socket.nsp; // newNamespace.name === "/dynamic-101"
 | 
			
		||||
     *
 | 
			
		||||
     *   // broadcast to all clients in the given sub-namespace
 | 
			
		||||
     *   namespace.emit("hello");
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param name - nsp name
 | 
			
		||||
     * @param fn optional, nsp `connection` ev handler
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public of(
 | 
			
		||||
        name: string | RegExp | ParentNspNameMatchFn,
 | 
			
		||||
        fn?: (socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>) => void
 | 
			
		||||
    ): Namespace<ListenEvents, EmitEvents, ServerSideEvents> {
 | 
			
		||||
        fn?: (
 | 
			
		||||
            socket: Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
        ) => void
 | 
			
		||||
    ): Namespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData> {
 | 
			
		||||
        if (typeof name === "function" || name instanceof RegExp) {
 | 
			
		||||
            const parentNsp = new ParentNamespace(this)
 | 
			
		||||
            console.debug(`initializing parent namespace ${parentNsp.name}`)
 | 
			
		||||
            debug("initializing parent namespace %s", parentNsp.name)
 | 
			
		||||
            if (typeof name === "function") {
 | 
			
		||||
                this.parentNsps.set(name, parentNsp)
 | 
			
		||||
            } else {
 | 
			
		||||
@@ -607,7 +667,7 @@ export class Server<
 | 
			
		||||
 | 
			
		||||
        let nsp = this._nsps.get(name)
 | 
			
		||||
        if (!nsp) {
 | 
			
		||||
            console.debug("initializing namespace", name)
 | 
			
		||||
            debug("initializing namespace %s", name)
 | 
			
		||||
            nsp = new Namespace(this, name)
 | 
			
		||||
            this._nsps.set(name, nsp)
 | 
			
		||||
            if (name !== "/") {
 | 
			
		||||
@@ -623,7 +683,6 @@ export class Server<
 | 
			
		||||
     * Closes server connection
 | 
			
		||||
     *
 | 
			
		||||
     * @param [fn] optional, called as `fn([err])` on error OR all conns closed
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public close(fn?: (err?: Error) => void): void {
 | 
			
		||||
        for (const socket of this.sockets.sockets.values()) {
 | 
			
		||||
@@ -632,6 +691,9 @@ export class Server<
 | 
			
		||||
 | 
			
		||||
        this.engine.close()
 | 
			
		||||
 | 
			
		||||
        // // restore the Adapter prototype
 | 
			
		||||
        // restoreAdapter()
 | 
			
		||||
 | 
			
		||||
        // if (this.httpServer) {
 | 
			
		||||
        //     this.httpServer.close(fn)
 | 
			
		||||
        // } else {
 | 
			
		||||
@@ -640,14 +702,19 @@ export class Server<
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets up namespace middleware.
 | 
			
		||||
     * Registers a middleware, which is a function that gets executed for every incoming {@link Socket}.
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.use((socket, next) => {
 | 
			
		||||
     *   // ...
 | 
			
		||||
     *   next();
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param fn - the middleware function
 | 
			
		||||
     */
 | 
			
		||||
    public use(
 | 
			
		||||
        fn: (
 | 
			
		||||
            socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>,
 | 
			
		||||
            socket: Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData>,
 | 
			
		||||
            next: (err?: ExtendedError) => void
 | 
			
		||||
        ) => void
 | 
			
		||||
    ): this {
 | 
			
		||||
@@ -658,41 +725,71 @@ export class Server<
 | 
			
		||||
    /**
 | 
			
		||||
     * Targets a room when emitting.
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * // the “foo” event will be broadcast to all connected clients in the “room-101” room
 | 
			
		||||
     * io.to("room-101").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * // with an array of rooms (a client will be notified at most once)
 | 
			
		||||
     * io.to(["room-101", "room-102"]).emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * // with multiple chained calls
 | 
			
		||||
     * io.to("room-101").to("room-102").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public to(room: Room | Room[]): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public to(room: Room | Room[]) {
 | 
			
		||||
        return this.sockets.to(room)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Targets a room when emitting.
 | 
			
		||||
     * Targets a room when emitting. Similar to `to()`, but might feel clearer in some cases:
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * // disconnect all clients in the "room-101" room
 | 
			
		||||
     * io.in("room-101").disconnectSockets();
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public in(room: Room | Room[]): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public in(room: Room | Room[]) {
 | 
			
		||||
        return this.sockets.in(room)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Excludes a room when emitting.
 | 
			
		||||
     *
 | 
			
		||||
     * @param name
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * // the "foo" event will be broadcast to all connected clients, except the ones that are in the "room-101" room
 | 
			
		||||
     * io.except("room-101").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * // with an array of rooms
 | 
			
		||||
     * io.except(["room-101", "room-102"]).emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * // with multiple chained calls
 | 
			
		||||
     * io.except("room-101").except("room-102").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public except(name: Room | Room[]): BroadcastOperator<EmitEvents> {
 | 
			
		||||
        return this.sockets.except(name)
 | 
			
		||||
    public except(room: Room | Room[]) {
 | 
			
		||||
        return this.sockets.except(room)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a `message` event to all clients.
 | 
			
		||||
     *
 | 
			
		||||
     * This method mimics the WebSocket.send() method.
 | 
			
		||||
     *
 | 
			
		||||
     * @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.send("hello");
 | 
			
		||||
     *
 | 
			
		||||
     * // this is equivalent to
 | 
			
		||||
     * io.emit("message", "hello");
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public send(...args: EventParams<EmitEvents, "message">): this {
 | 
			
		||||
        this.sockets.emit("message", ...args)
 | 
			
		||||
@@ -700,10 +797,9 @@ export class Server<
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a `message` event to all clients.
 | 
			
		||||
     * Sends a `message` event to all clients. Alias of {@link send}.
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public write(...args: EventParams<EmitEvents, "message">): this {
 | 
			
		||||
        this.sockets.emit("message", ...args)
 | 
			
		||||
@@ -711,11 +807,30 @@ export class Server<
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Emit a packet to other Socket.IO servers
 | 
			
		||||
     * Sends a message to the other Socket.IO servers of the cluster.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.serverSideEmit("hello", "world");
 | 
			
		||||
     *
 | 
			
		||||
     * io.on("hello", (arg1) => {
 | 
			
		||||
     *   console.log(arg1); // prints "world"
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * // acknowledgements (without binary content) are supported too:
 | 
			
		||||
     * io.serverSideEmit("ping", (err, responses) => {
 | 
			
		||||
     *  if (err) {
 | 
			
		||||
     *     // some clients did not acknowledge the event in the given delay
 | 
			
		||||
     *   } else {
 | 
			
		||||
     *     console.log(responses); // one response per client
 | 
			
		||||
     *   }
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * io.on("ping", (cb) => {
 | 
			
		||||
     *   cb("pong");
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param ev - the event name
 | 
			
		||||
     * @param args - an array of arguments, which may include an acknowledgement callback at the end
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public serverSideEmit<Ev extends EventNames<ServerSideEvents>>(
 | 
			
		||||
        ev: Ev,
 | 
			
		||||
@@ -727,7 +842,8 @@ export class Server<
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a list of socket ids.
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     * @deprecated this method will be removed in the next major release, please use {@link Server#serverSideEmit} or
 | 
			
		||||
     * {@link Server#fetchSockets} instead.
 | 
			
		||||
     */
 | 
			
		||||
    public allSockets(): Promise<Set<SocketId>> {
 | 
			
		||||
        return this.sockets.allSockets()
 | 
			
		||||
@@ -736,11 +852,13 @@ export class Server<
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the compress flag.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.compress(false).emit("hello");
 | 
			
		||||
     *
 | 
			
		||||
     * @param compress - if `true`, compresses the sending data
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public compress(compress: boolean): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public compress(compress: boolean) {
 | 
			
		||||
        return this.sockets.compress(compress)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -749,59 +867,126 @@ export class Server<
 | 
			
		||||
     * receive messages (because of network slowness or other issues, or because they’re connected through long polling
 | 
			
		||||
     * and is in the middle of a request-response cycle).
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.volatile.emit("hello"); // the clients may or may not receive it
 | 
			
		||||
     *
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public get volatile(): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public get volatile() {
 | 
			
		||||
        return this.sockets.volatile
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets a modifier for a subsequent event emission that the event data will only be broadcast to the current node.
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * // the “foo” event will be broadcast to all connected clients on this node
 | 
			
		||||
     * io.local.emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public get local(): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public get local() {
 | 
			
		||||
        return this.sockets.local
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the matching socket instances
 | 
			
		||||
     * Adds a timeout in milliseconds for the next operation.
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.timeout(1000).emit("some-event", (err, responses) => {
 | 
			
		||||
     *   if (err) {
 | 
			
		||||
     *     // some clients did not acknowledge the event in the given delay
 | 
			
		||||
     *   } else {
 | 
			
		||||
     *     console.log(responses); // one response per client
 | 
			
		||||
     *   }
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param timeout
 | 
			
		||||
     */
 | 
			
		||||
    public fetchSockets(): Promise<RemoteSocket<EmitEvents>[]> {
 | 
			
		||||
    public timeout(timeout: number) {
 | 
			
		||||
        return this.sockets.timeout(timeout)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the matching socket instances.
 | 
			
		||||
     *
 | 
			
		||||
     * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * // return all Socket instances
 | 
			
		||||
     * const sockets = await io.fetchSockets();
 | 
			
		||||
     *
 | 
			
		||||
     * // return all Socket instances in the "room1" room
 | 
			
		||||
     * const sockets = await io.in("room1").fetchSockets();
 | 
			
		||||
     *
 | 
			
		||||
     * for (const socket of sockets) {
 | 
			
		||||
     *   console.log(socket.id);
 | 
			
		||||
     *   console.log(socket.handshake);
 | 
			
		||||
     *   console.log(socket.rooms);
 | 
			
		||||
     *   console.log(socket.data);
 | 
			
		||||
     *
 | 
			
		||||
     *   socket.emit("hello");
 | 
			
		||||
     *   socket.join("room1");
 | 
			
		||||
     *   socket.leave("room2");
 | 
			
		||||
     *   socket.disconnect();
 | 
			
		||||
     * }
 | 
			
		||||
     */
 | 
			
		||||
    public fetchSockets(): Promise<RemoteSocket<EmitEvents, SocketData>[]> {
 | 
			
		||||
        return this.sockets.fetchSockets()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes the matching socket instances join the specified rooms
 | 
			
		||||
     * Makes the matching socket instances join the specified rooms.
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @public
 | 
			
		||||
     * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     *
 | 
			
		||||
     * // make all socket instances join the "room1" room
 | 
			
		||||
     * io.socketsJoin("room1");
 | 
			
		||||
     *
 | 
			
		||||
     * // make all socket instances in the "room1" room join the "room2" and "room3" rooms
 | 
			
		||||
     * io.in("room1").socketsJoin(["room2", "room3"]);
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     */
 | 
			
		||||
    public socketsJoin(room: Room | Room[]): void {
 | 
			
		||||
    public socketsJoin(room: Room | Room[]) {
 | 
			
		||||
        return this.sockets.socketsJoin(room)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes the matching socket instances leave the specified rooms
 | 
			
		||||
     * Makes the matching socket instances leave the specified rooms.
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @public
 | 
			
		||||
     * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * // make all socket instances leave the "room1" room
 | 
			
		||||
     * io.socketsLeave("room1");
 | 
			
		||||
     *
 | 
			
		||||
     * // make all socket instances in the "room1" room leave the "room2" and "room3" rooms
 | 
			
		||||
     * io.in("room1").socketsLeave(["room2", "room3"]);
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     */
 | 
			
		||||
    public socketsLeave(room: Room | Room[]): void {
 | 
			
		||||
    public socketsLeave(room: Room | Room[]) {
 | 
			
		||||
        return this.sockets.socketsLeave(room)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes the matching socket instances disconnect
 | 
			
		||||
     * Makes the matching socket instances disconnect.
 | 
			
		||||
     *
 | 
			
		||||
     * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * // make all socket instances disconnect (the connections might be kept alive for other namespaces)
 | 
			
		||||
     * io.disconnectSockets();
 | 
			
		||||
     *
 | 
			
		||||
     * // make all socket instances in the "room1" room disconnect and close the underlying connections
 | 
			
		||||
     * io.in("room1").disconnectSockets(true);
 | 
			
		||||
     *
 | 
			
		||||
     * @param close - whether to close the underlying connection
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public disconnectSockets(close: boolean = false): void {
 | 
			
		||||
    public disconnectSockets(close: boolean = false) {
 | 
			
		||||
        return this.sockets.disconnectSockets(close)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -822,4 +1007,10 @@ emitterMethods.forEach(function (fn) {
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
module.exports = (srv?, opts?) => new Server(srv, opts)
 | 
			
		||||
module.exports.Server = Server
 | 
			
		||||
module.exports.Namespace = Namespace
 | 
			
		||||
module.exports.Socket = Socket
 | 
			
		||||
 | 
			
		||||
export { Socket, ServerOptions, Namespace, BroadcastOperator, RemoteSocket }
 | 
			
		||||
export { Event } from "./socket"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
 | 
			
		||||
import { Socket } from "./socket"
 | 
			
		||||
import type { Server } from "./index"
 | 
			
		||||
import {
 | 
			
		||||
@@ -14,7 +13,8 @@ import type { Client } from "./client"
 | 
			
		||||
import type { Adapter, Room, SocketId } from "../socket.io-adapter"
 | 
			
		||||
import { BroadcastOperator, RemoteSocket } from "./broadcast-operator"
 | 
			
		||||
 | 
			
		||||
// const debug = debugModule("socket.io:namespace");
 | 
			
		||||
// const debug = debugModule("socket.io:namespace")
 | 
			
		||||
const debug = require('../debug')("socket.io:namespace")
 | 
			
		||||
 | 
			
		||||
export interface ExtendedError extends Error {
 | 
			
		||||
    data?: any
 | 
			
		||||
@@ -23,56 +23,125 @@ export interface ExtendedError extends Error {
 | 
			
		||||
export interface NamespaceReservedEventsMap<
 | 
			
		||||
    ListenEvents extends EventsMap,
 | 
			
		||||
    EmitEvents extends EventsMap,
 | 
			
		||||
    ServerSideEvents extends EventsMap
 | 
			
		||||
    > {
 | 
			
		||||
    connect: (socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>) => void
 | 
			
		||||
    ServerSideEvents extends EventsMap,
 | 
			
		||||
    SocketData
 | 
			
		||||
> {
 | 
			
		||||
    connect: (
 | 
			
		||||
        socket: Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
    ) => void
 | 
			
		||||
    connection: (
 | 
			
		||||
        socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>
 | 
			
		||||
        socket: Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
    ) => void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ServerReservedEventsMap<
 | 
			
		||||
    ListenEvents extends EventsMap,
 | 
			
		||||
    EmitEvents extends EventsMap,
 | 
			
		||||
    ServerSideEvents extends EventsMap,
 | 
			
		||||
    SocketData
 | 
			
		||||
> extends NamespaceReservedEventsMap<
 | 
			
		||||
    ListenEvents,
 | 
			
		||||
    EmitEvents,
 | 
			
		||||
    ServerSideEvents
 | 
			
		||||
    > extends NamespaceReservedEventsMap<
 | 
			
		||||
    ListenEvents,
 | 
			
		||||
    EmitEvents,
 | 
			
		||||
    ServerSideEvents
 | 
			
		||||
    > {
 | 
			
		||||
    ServerSideEvents,
 | 
			
		||||
    SocketData
 | 
			
		||||
> {
 | 
			
		||||
    new_namespace: (
 | 
			
		||||
        namespace: Namespace<ListenEvents, EmitEvents, ServerSideEvents>
 | 
			
		||||
        namespace: Namespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
    ) => void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const RESERVED_EVENTS: ReadonlySet<string | Symbol> = new Set<
 | 
			
		||||
    keyof ServerReservedEventsMap<never, never, never>
 | 
			
		||||
    keyof ServerReservedEventsMap<never, never, never, never>
 | 
			
		||||
>(<const>["connect", "connection", "new_namespace"])
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A Namespace is a communication channel that allows you to split the logic of your application over a single shared
 | 
			
		||||
 * connection.
 | 
			
		||||
 *
 | 
			
		||||
 * Each namespace has its own:
 | 
			
		||||
 *
 | 
			
		||||
 * - event handlers
 | 
			
		||||
 *
 | 
			
		||||
 * ```
 | 
			
		||||
 * io.of("/orders").on("connection", (socket) => {
 | 
			
		||||
 *   socket.on("order:list", () => {});
 | 
			
		||||
 *   socket.on("order:create", () => {});
 | 
			
		||||
 * });
 | 
			
		||||
 *
 | 
			
		||||
 * io.of("/users").on("connection", (socket) => {
 | 
			
		||||
 *   socket.on("user:list", () => {});
 | 
			
		||||
 * });
 | 
			
		||||
 * ```
 | 
			
		||||
 *
 | 
			
		||||
 * - rooms
 | 
			
		||||
 *
 | 
			
		||||
 * ```
 | 
			
		||||
 * const orderNamespace = io.of("/orders");
 | 
			
		||||
 *
 | 
			
		||||
 * orderNamespace.on("connection", (socket) => {
 | 
			
		||||
 *   socket.join("room1");
 | 
			
		||||
 *   orderNamespace.to("room1").emit("hello");
 | 
			
		||||
 * });
 | 
			
		||||
 *
 | 
			
		||||
 * const userNamespace = io.of("/users");
 | 
			
		||||
 *
 | 
			
		||||
 * userNamespace.on("connection", (socket) => {
 | 
			
		||||
 *   socket.join("room1"); // distinct from the room in the "orders" namespace
 | 
			
		||||
 *   userNamespace.to("room1").emit("holà");
 | 
			
		||||
 * });
 | 
			
		||||
 * ```
 | 
			
		||||
 *
 | 
			
		||||
 * - middlewares
 | 
			
		||||
 *
 | 
			
		||||
 * ```
 | 
			
		||||
 * const orderNamespace = io.of("/orders");
 | 
			
		||||
 *
 | 
			
		||||
 * orderNamespace.use((socket, next) => {
 | 
			
		||||
 *   // ensure the socket has access to the "orders" namespace
 | 
			
		||||
 * });
 | 
			
		||||
 *
 | 
			
		||||
 * const userNamespace = io.of("/users");
 | 
			
		||||
 *
 | 
			
		||||
 * userNamespace.use((socket, next) => {
 | 
			
		||||
 *   // ensure the socket has access to the "users" namespace
 | 
			
		||||
 * });
 | 
			
		||||
 * ```
 | 
			
		||||
 */
 | 
			
		||||
export class Namespace<
 | 
			
		||||
    ListenEvents extends EventsMap = DefaultEventsMap,
 | 
			
		||||
    EmitEvents extends EventsMap = ListenEvents,
 | 
			
		||||
    ServerSideEvents extends EventsMap = DefaultEventsMap
 | 
			
		||||
    > extends StrictEventEmitter<
 | 
			
		||||
    ServerSideEvents extends EventsMap = DefaultEventsMap,
 | 
			
		||||
    SocketData = any
 | 
			
		||||
> extends StrictEventEmitter<
 | 
			
		||||
    ServerSideEvents,
 | 
			
		||||
    EmitEvents,
 | 
			
		||||
    NamespaceReservedEventsMap<ListenEvents, EmitEvents, ServerSideEvents>
 | 
			
		||||
    > {
 | 
			
		||||
    NamespaceReservedEventsMap<
 | 
			
		||||
        ListenEvents,
 | 
			
		||||
        EmitEvents,
 | 
			
		||||
        ServerSideEvents,
 | 
			
		||||
        SocketData
 | 
			
		||||
    >
 | 
			
		||||
> {
 | 
			
		||||
    public readonly name: string
 | 
			
		||||
    public readonly sockets: Map<
 | 
			
		||||
        SocketId,
 | 
			
		||||
        Socket<ListenEvents, EmitEvents, ServerSideEvents>
 | 
			
		||||
        Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
    > = new Map();
 | 
			
		||||
 | 
			
		||||
    public adapter: Adapter
 | 
			
		||||
 | 
			
		||||
    /** @private */
 | 
			
		||||
    readonly server: Server<ListenEvents, EmitEvents, ServerSideEvents>
 | 
			
		||||
    readonly server: Server<
 | 
			
		||||
        ListenEvents,
 | 
			
		||||
        EmitEvents,
 | 
			
		||||
        ServerSideEvents,
 | 
			
		||||
        SocketData
 | 
			
		||||
    >
 | 
			
		||||
 | 
			
		||||
    /** @private */
 | 
			
		||||
    _fns: Array<
 | 
			
		||||
        (
 | 
			
		||||
            socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>,
 | 
			
		||||
            socket: Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData>,
 | 
			
		||||
            next: (err?: ExtendedError) => void
 | 
			
		||||
        ) => void
 | 
			
		||||
    > = [];
 | 
			
		||||
@@ -87,7 +156,7 @@ export class Namespace<
 | 
			
		||||
     * @param name
 | 
			
		||||
     */
 | 
			
		||||
    constructor(
 | 
			
		||||
        server: Server<ListenEvents, EmitEvents, ServerSideEvents>,
 | 
			
		||||
        server: Server<ListenEvents, EmitEvents, ServerSideEvents, SocketData>,
 | 
			
		||||
        name: string
 | 
			
		||||
    ) {
 | 
			
		||||
        super()
 | 
			
		||||
@@ -103,20 +172,27 @@ export class Namespace<
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    _initAdapter() {
 | 
			
		||||
    _initAdapter(): void {
 | 
			
		||||
        // @ts-ignore
 | 
			
		||||
        this.adapter = new (this.server.adapter()!)(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets up namespace middleware.
 | 
			
		||||
     * Registers a middleware, which is a function that gets executed for every incoming {@link Socket}.
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * myNamespace.use((socket, next) => {
 | 
			
		||||
     *   // ...
 | 
			
		||||
     *   next();
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param fn - the middleware function
 | 
			
		||||
     */
 | 
			
		||||
    public use(
 | 
			
		||||
        fn: (
 | 
			
		||||
            socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>,
 | 
			
		||||
            socket: Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData>,
 | 
			
		||||
            next: (err?: ExtendedError) => void
 | 
			
		||||
        ) => void
 | 
			
		||||
    ): this {
 | 
			
		||||
@@ -132,7 +208,7 @@ export class Namespace<
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private run(
 | 
			
		||||
        socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>,
 | 
			
		||||
        socket: Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData>,
 | 
			
		||||
        fn: (err: ExtendedError | null) => void
 | 
			
		||||
    ) {
 | 
			
		||||
        const fns = this._fns.slice(0)
 | 
			
		||||
@@ -157,34 +233,63 @@ export class Namespace<
 | 
			
		||||
    /**
 | 
			
		||||
     * Targets a room when emitting.
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * // the “foo” event will be broadcast to all connected clients in the “room-101” room
 | 
			
		||||
     * myNamespace.to("room-101").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * // with an array of rooms (a client will be notified at most once)
 | 
			
		||||
     * myNamespace.to(["room-101", "room-102"]).emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * // with multiple chained calls
 | 
			
		||||
     * myNamespace.to("room-101").to("room-102").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public to(room: Room | Room[]): BroadcastOperator<EmitEvents> {
 | 
			
		||||
        return new BroadcastOperator(this.adapter).to(room)
 | 
			
		||||
    public to(room: Room | Room[]) {
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(this.adapter).to(room)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Targets a room when emitting.
 | 
			
		||||
     * Targets a room when emitting. Similar to `to()`, but might feel clearer in some cases:
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * // disconnect all clients in the "room-101" room
 | 
			
		||||
     * myNamespace.in("room-101").disconnectSockets();
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public in(room: Room | Room[]): BroadcastOperator<EmitEvents> {
 | 
			
		||||
        return new BroadcastOperator(this.adapter).in(room)
 | 
			
		||||
    public in(room: Room | Room[]) {
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(this.adapter).in(room)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Excludes a room when emitting.
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * // the "foo" event will be broadcast to all connected clients, except the ones that are in the "room-101" room
 | 
			
		||||
     * myNamespace.except("room-101").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * // with an array of rooms
 | 
			
		||||
     * myNamespace.except(["room-101", "room-102"]).emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * // with multiple chained calls
 | 
			
		||||
     * myNamespace.except("room-101").except("room-102").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public except(room: Room | Room[]): BroadcastOperator<EmitEvents> {
 | 
			
		||||
        return new BroadcastOperator(this.adapter).except(room)
 | 
			
		||||
    public except(room: Room | Room[]) {
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(this.adapter).except(
 | 
			
		||||
            room
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -197,41 +302,45 @@ export class Namespace<
 | 
			
		||||
        client: Client<ListenEvents, EmitEvents, ServerSideEvents>,
 | 
			
		||||
        query,
 | 
			
		||||
        fn?: (socket: Socket) => void
 | 
			
		||||
    ): Socket<ListenEvents, EmitEvents, ServerSideEvents> {
 | 
			
		||||
        const socket = new Socket(this, client, query || {})
 | 
			
		||||
        console.debug(`socket.io namespace client ${client.id} adding socket ${socket.id} to nsp ${this.name}`)
 | 
			
		||||
        this.run(socket, err => {
 | 
			
		||||
    ): Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData> {
 | 
			
		||||
        debug("adding socket to nsp %s", this.name)
 | 
			
		||||
        const socket = new Socket(this, client, query)
 | 
			
		||||
        this.run(socket, (err) => {
 | 
			
		||||
            process.nextTick(() => {
 | 
			
		||||
                if ("open" == client.conn.readyState) {
 | 
			
		||||
                    if (err) {
 | 
			
		||||
                        if (client.conn.protocol === 3) {
 | 
			
		||||
                            return socket._error(err.data || err.message)
 | 
			
		||||
                        } else {
 | 
			
		||||
                            return socket._error({
 | 
			
		||||
                                message: err.message,
 | 
			
		||||
                                data: err.data,
 | 
			
		||||
                            })
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // track socket
 | 
			
		||||
                    this.sockets.set(socket.id, socket)
 | 
			
		||||
                    console.debug(`socket.io namespace ${this.name} track client ${client.id} socket ${socket.id}`)
 | 
			
		||||
 | 
			
		||||
                    // it's paramount that the internal `onconnect` logic
 | 
			
		||||
                    // fires before user-set events to prevent state order
 | 
			
		||||
                    // violations (such as a disconnection before the connection
 | 
			
		||||
                    // logic is complete)
 | 
			
		||||
                    socket._onconnect()
 | 
			
		||||
                    // @java-patch multi thread need direct callback socket
 | 
			
		||||
                    if (fn) fn(socket)
 | 
			
		||||
 | 
			
		||||
                    // fire user-set events
 | 
			
		||||
                    this.emitReserved("connect", socket)
 | 
			
		||||
                    this.emitReserved("connection", socket)
 | 
			
		||||
                } else {
 | 
			
		||||
                    console.debug(`next called after client ${client.id} was closed - ignoring socket`)
 | 
			
		||||
                if ("open" !== client.conn.readyState) {
 | 
			
		||||
                    debug("next called after client was closed - ignoring socket")
 | 
			
		||||
                    socket._cleanup()
 | 
			
		||||
                    return
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (err) {
 | 
			
		||||
                    debug("middleware error, sending CONNECT_ERROR packet to the client")
 | 
			
		||||
                    socket._cleanup()
 | 
			
		||||
                    if (client.conn.protocol === 3) {
 | 
			
		||||
                        return socket._error(err.data || err.message)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return socket._error({
 | 
			
		||||
                            message: err.message,
 | 
			
		||||
                            data: err.data,
 | 
			
		||||
                        })
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // track socket
 | 
			
		||||
                this.sockets.set(socket.id, socket)
 | 
			
		||||
 | 
			
		||||
                // it's paramount that the internal `onconnect` logic
 | 
			
		||||
                // fires before user-set events to prevent state order
 | 
			
		||||
                // violations (such as a disconnection before the connection
 | 
			
		||||
                // logic is complete)
 | 
			
		||||
                socket._onconnect()
 | 
			
		||||
                // if (fn) fn()
 | 
			
		||||
                // @java-patch multi thread need direct callback socket
 | 
			
		||||
                if (fn) fn(socket)
 | 
			
		||||
 | 
			
		||||
                // fire user-set events
 | 
			
		||||
                this.emitReserved("connect", socket)
 | 
			
		||||
                this.emitReserved("connection", socket)
 | 
			
		||||
            })
 | 
			
		||||
        })
 | 
			
		||||
        return socket
 | 
			
		||||
@@ -242,33 +351,64 @@ export class Namespace<
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    _remove(socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>): void {
 | 
			
		||||
    _remove(
 | 
			
		||||
        socket: Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
    ): void {
 | 
			
		||||
        if (this.sockets.has(socket.id)) {
 | 
			
		||||
            console.debug(`namespace ${this.name} remove socket ${socket.id}`)
 | 
			
		||||
            this.sockets.delete(socket.id)
 | 
			
		||||
        } else {
 | 
			
		||||
            console.debug(`namespace ${this.name} ignoring remove for ${socket.id}`)
 | 
			
		||||
            debug("ignoring remove for %s", socket.id)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Emits to all clients.
 | 
			
		||||
     * Emits to all connected clients.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * myNamespace.emit("hello", "world");
 | 
			
		||||
     *
 | 
			
		||||
     * // all serializable datastructures are supported (no need to call JSON.stringify)
 | 
			
		||||
     * myNamespace.emit("hello", 1, "2", { 3: ["4"], 5: Uint8Array.from([6]) });
 | 
			
		||||
     *
 | 
			
		||||
     * // with an acknowledgement from the clients
 | 
			
		||||
     * myNamespace.timeout(1000).emit("some-event", (err, responses) => {
 | 
			
		||||
     *   if (err) {
 | 
			
		||||
     *     // some clients did not acknowledge the event in the given delay
 | 
			
		||||
     *   } else {
 | 
			
		||||
     *     console.log(responses); // one response per client
 | 
			
		||||
     *   }
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @return Always true
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public emit<Ev extends EventNames<EmitEvents>>(
 | 
			
		||||
        ev: Ev,
 | 
			
		||||
        ...args: EventParams<EmitEvents, Ev>
 | 
			
		||||
    ): boolean {
 | 
			
		||||
        return new BroadcastOperator<EmitEvents>(this.adapter).emit(ev, ...args)
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(this.adapter).emit(
 | 
			
		||||
            ev,
 | 
			
		||||
            ...args
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a `message` event to all clients.
 | 
			
		||||
     *
 | 
			
		||||
     * This method mimics the WebSocket.send() method.
 | 
			
		||||
     *
 | 
			
		||||
     * @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * myNamespace.send("hello");
 | 
			
		||||
     *
 | 
			
		||||
     * // this is equivalent to
 | 
			
		||||
     * myNamespace.emit("message", "hello");
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public send(...args: EventParams<EmitEvents, "message">): this {
 | 
			
		||||
        this.emit("message", ...args)
 | 
			
		||||
@@ -276,10 +416,9 @@ export class Namespace<
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a `message` event to all clients.
 | 
			
		||||
     * Sends a `message` event to all clients. Sends a `message` event. Alias of {@link send}.
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public write(...args: EventParams<EmitEvents, "message">): this {
 | 
			
		||||
        this.emit("message", ...args)
 | 
			
		||||
@@ -287,18 +426,39 @@ export class Namespace<
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Emit a packet to other Socket.IO servers
 | 
			
		||||
     * Sends a message to the other Socket.IO servers of the cluster.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * myNamespace.serverSideEmit("hello", "world");
 | 
			
		||||
     *
 | 
			
		||||
     * myNamespace.on("hello", (arg1) => {
 | 
			
		||||
     *   console.log(arg1); // prints "world"
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * // acknowledgements (without binary content) are supported too:
 | 
			
		||||
     * myNamespace.serverSideEmit("ping", (err, responses) => {
 | 
			
		||||
     *  if (err) {
 | 
			
		||||
     *     // some clients did not acknowledge the event in the given delay
 | 
			
		||||
     *   } else {
 | 
			
		||||
     *     console.log(responses); // one response per client
 | 
			
		||||
     *   }
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * myNamespace.on("ping", (cb) => {
 | 
			
		||||
     *   cb("pong");
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param ev - the event name
 | 
			
		||||
     * @param args - an array of arguments, which may include an acknowledgement callback at the end
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public serverSideEmit<Ev extends EventNames<ServerSideEvents>>(
 | 
			
		||||
        ev: Ev,
 | 
			
		||||
        ...args: EventParams<ServerSideEvents, Ev>
 | 
			
		||||
    ): boolean {
 | 
			
		||||
        if (RESERVED_EVENTS.has(ev)) {
 | 
			
		||||
            throw new Error(`"${ev}" is a reserved event name`)
 | 
			
		||||
            throw new Error(`"${String(ev)}" is a reserved event name`)
 | 
			
		||||
        }
 | 
			
		||||
        args.unshift(ev)
 | 
			
		||||
        this.adapter.serverSideEmit(args)
 | 
			
		||||
@@ -319,22 +479,30 @@ export class Namespace<
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a list of clients.
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @deprecated this method will be removed in the next major release, please use {@link Namespace#serverSideEmit} or
 | 
			
		||||
     * {@link Namespace#fetchSockets} instead.
 | 
			
		||||
     */
 | 
			
		||||
    public allSockets(): Promise<Set<SocketId>> {
 | 
			
		||||
        return new BroadcastOperator(this.adapter).allSockets()
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(
 | 
			
		||||
            this.adapter
 | 
			
		||||
        ).allSockets()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
    * Sets the compress flag.
 | 
			
		||||
    *
 | 
			
		||||
    * @param compress - if `true`, compresses the sending data
 | 
			
		||||
    * @return self
 | 
			
		||||
    * @public
 | 
			
		||||
    */
 | 
			
		||||
    public compress(compress: boolean): BroadcastOperator<EmitEvents> {
 | 
			
		||||
        return new BroadcastOperator(this.adapter).compress(compress)
 | 
			
		||||
     * Sets the compress flag.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * myNamespace.compress(false).emit("hello");
 | 
			
		||||
     *
 | 
			
		||||
     * @param compress - if `true`, compresses the sending data
 | 
			
		||||
     * @return self
 | 
			
		||||
     */
 | 
			
		||||
    public compress(compress: boolean) {
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(this.adapter).compress(
 | 
			
		||||
            compress
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -342,62 +510,153 @@ export class Namespace<
 | 
			
		||||
     * receive messages (because of network slowness or other issues, or because they’re connected through long polling
 | 
			
		||||
     * and is in the middle of a request-response cycle).
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * myNamespace.volatile.emit("hello"); // the clients may or may not receive it
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public get volatile(): BroadcastOperator<EmitEvents> {
 | 
			
		||||
        return new BroadcastOperator(this.adapter).volatile
 | 
			
		||||
    public get volatile() {
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(this.adapter).volatile
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets a modifier for a subsequent event emission that the event data will only be broadcast to the current node.
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public get local(): BroadcastOperator<EmitEvents> {
 | 
			
		||||
        return new BroadcastOperator(this.adapter).local
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the matching socket instances
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public fetchSockets(): Promise<RemoteSocket<EmitEvents>[]> {
 | 
			
		||||
        return new BroadcastOperator(this.adapter).fetchSockets()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes the matching socket instances join the specified rooms
 | 
			
		||||
     * // the “foo” event will be broadcast to all connected clients on this node
 | 
			
		||||
     * myNamespace.local.emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @public
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public socketsJoin(room: Room | Room[]): void {
 | 
			
		||||
        return new BroadcastOperator(this.adapter).socketsJoin(room)
 | 
			
		||||
    public get local() {
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(this.adapter).local
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes the matching socket instances leave the specified rooms
 | 
			
		||||
     * Adds a timeout in milliseconds for the next operation.
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * myNamespace.timeout(1000).emit("some-event", (err, responses) => {
 | 
			
		||||
     *   if (err) {
 | 
			
		||||
     *     // some clients did not acknowledge the event in the given delay
 | 
			
		||||
     *   } else {
 | 
			
		||||
     *     console.log(responses); // one response per client
 | 
			
		||||
     *   }
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param timeout
 | 
			
		||||
     */
 | 
			
		||||
    public socketsLeave(room: Room | Room[]): void {
 | 
			
		||||
        return new BroadcastOperator(this.adapter).socketsLeave(room)
 | 
			
		||||
    public timeout(timeout: number) {
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(this.adapter).timeout(
 | 
			
		||||
            timeout
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes the matching socket instances disconnect
 | 
			
		||||
     * Returns the matching socket instances.
 | 
			
		||||
     *
 | 
			
		||||
     * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * // return all Socket instances
 | 
			
		||||
     * const sockets = await myNamespace.fetchSockets();
 | 
			
		||||
     *
 | 
			
		||||
     * // return all Socket instances in the "room1" room
 | 
			
		||||
     * const sockets = await myNamespace.in("room1").fetchSockets();
 | 
			
		||||
     *
 | 
			
		||||
     * for (const socket of sockets) {
 | 
			
		||||
     *   console.log(socket.id);
 | 
			
		||||
     *   console.log(socket.handshake);
 | 
			
		||||
     *   console.log(socket.rooms);
 | 
			
		||||
     *   console.log(socket.data);
 | 
			
		||||
     *
 | 
			
		||||
     *   socket.emit("hello");
 | 
			
		||||
     *   socket.join("room1");
 | 
			
		||||
     *   socket.leave("room2");
 | 
			
		||||
     *   socket.disconnect();
 | 
			
		||||
     * }
 | 
			
		||||
     */
 | 
			
		||||
    public fetchSockets() {
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(
 | 
			
		||||
            this.adapter
 | 
			
		||||
        ).fetchSockets()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes the matching socket instances join the specified rooms.
 | 
			
		||||
     *
 | 
			
		||||
     * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * // make all socket instances join the "room1" room
 | 
			
		||||
     * myNamespace.socketsJoin("room1");
 | 
			
		||||
     *
 | 
			
		||||
     * // make all socket instances in the "room1" room join the "room2" and "room3" rooms
 | 
			
		||||
     * myNamespace.in("room1").socketsJoin(["room2", "room3"]);
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     */
 | 
			
		||||
    public socketsJoin(room: Room | Room[]) {
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(
 | 
			
		||||
            this.adapter
 | 
			
		||||
        ).socketsJoin(room)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes the matching socket instances leave the specified rooms.
 | 
			
		||||
     *
 | 
			
		||||
     * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * // make all socket instances leave the "room1" room
 | 
			
		||||
     * myNamespace.socketsLeave("room1");
 | 
			
		||||
     *
 | 
			
		||||
     * // make all socket instances in the "room1" room leave the "room2" and "room3" rooms
 | 
			
		||||
     * myNamespace.in("room1").socketsLeave(["room2", "room3"]);
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     */
 | 
			
		||||
    public socketsLeave(room: Room | Room[]) {
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(
 | 
			
		||||
            this.adapter
 | 
			
		||||
        ).socketsLeave(room)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes the matching socket instances disconnect.
 | 
			
		||||
     *
 | 
			
		||||
     * Note: this method also works within a cluster of multiple Socket.IO servers, with a compatible {@link Adapter}.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * const myNamespace = io.of("/my-namespace");
 | 
			
		||||
     *
 | 
			
		||||
     * // make all socket instances disconnect (the connections might be kept alive for other namespaces)
 | 
			
		||||
     * myNamespace.disconnectSockets();
 | 
			
		||||
     *
 | 
			
		||||
     * // make all socket instances in the "room1" room disconnect and close the underlying connections
 | 
			
		||||
     * myNamespace.in("room1").disconnectSockets(true);
 | 
			
		||||
     *
 | 
			
		||||
     * @param close - whether to close the underlying connection
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public disconnectSockets(close: boolean = false): void {
 | 
			
		||||
        return new BroadcastOperator(this.adapter).disconnectSockets(close)
 | 
			
		||||
    public disconnectSockets(close: boolean = false) {
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(
 | 
			
		||||
            this.adapter
 | 
			
		||||
        ).disconnectSockets(close)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @java-patch
 | 
			
		||||
    public close() {
 | 
			
		||||
        RESERVED_EVENTS.forEach(event => this.removeAllListeners(event as any))
 | 
			
		||||
        this.server._nsps.delete(this.name)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import { Namespace } from "./namespace"
 | 
			
		||||
import type { Server } from "./index"
 | 
			
		||||
import type { Server, RemoteSocket } from "./index"
 | 
			
		||||
import type {
 | 
			
		||||
    EventParams,
 | 
			
		||||
    EventNames,
 | 
			
		||||
@@ -12,16 +12,24 @@ import type { BroadcastOptions } from "../socket.io-adapter"
 | 
			
		||||
export class ParentNamespace<
 | 
			
		||||
    ListenEvents extends EventsMap = DefaultEventsMap,
 | 
			
		||||
    EmitEvents extends EventsMap = ListenEvents,
 | 
			
		||||
    ServerSideEvents extends EventsMap = DefaultEventsMap
 | 
			
		||||
    > extends Namespace<ListenEvents, EmitEvents, ServerSideEvents> {
 | 
			
		||||
    ServerSideEvents extends EventsMap = DefaultEventsMap,
 | 
			
		||||
    SocketData = any
 | 
			
		||||
> extends Namespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData> {
 | 
			
		||||
    private static count: number = 0;
 | 
			
		||||
    private children: Set<Namespace<ListenEvents, EmitEvents, ServerSideEvents>> = new Set();
 | 
			
		||||
    private children: Set<
 | 
			
		||||
        Namespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
    > = new Set();
 | 
			
		||||
 | 
			
		||||
    constructor(server: Server<ListenEvents, EmitEvents, ServerSideEvents>) {
 | 
			
		||||
    constructor(
 | 
			
		||||
        server: Server<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
 | 
			
		||||
    ) {
 | 
			
		||||
        super(server, "/_" + ParentNamespace.count++)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _initAdapter() {
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    _initAdapter(): void {
 | 
			
		||||
        const broadcast = (packet: any, opts: BroadcastOptions) => {
 | 
			
		||||
            this.children.forEach((nsp) => {
 | 
			
		||||
                nsp.adapter.broadcast(packet, opts)
 | 
			
		||||
@@ -42,21 +50,9 @@ export class ParentNamespace<
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // public emit(...args: any[]): boolean {
 | 
			
		||||
    //     this.children.forEach(nsp => {
 | 
			
		||||
    //         nsp._rooms = this._rooms
 | 
			
		||||
    //         nsp._flags = this._flags
 | 
			
		||||
    //         nsp.emit.apply(nsp, args as any)
 | 
			
		||||
    //     })
 | 
			
		||||
    //     this._rooms.clear()
 | 
			
		||||
    //     this._flags = {}
 | 
			
		||||
 | 
			
		||||
    //     return true
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    createChild(
 | 
			
		||||
        name: string
 | 
			
		||||
    ): Namespace<ListenEvents, EmitEvents, ServerSideEvents> {
 | 
			
		||||
    ): Namespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData> {
 | 
			
		||||
        const namespace = new Namespace(this.server, name)
 | 
			
		||||
        namespace._fns = this._fns.slice(0)
 | 
			
		||||
        this.listeners("connect").forEach((listener) =>
 | 
			
		||||
@@ -69,4 +65,13 @@ export class ParentNamespace<
 | 
			
		||||
        this.server._nsps.set(name, namespace)
 | 
			
		||||
        return namespace
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fetchSockets(): Promise<RemoteSocket<EmitEvents, SocketData>[]> {
 | 
			
		||||
        // note: we could make the fetchSockets() method work for dynamic namespaces created with a regex (by sending the
 | 
			
		||||
        // regex to the other Socket.IO servers, and returning the sockets of each matching namespace for example), but
 | 
			
		||||
        // the behavior for namespaces created with a function is less clear
 | 
			
		||||
        // note²: we cannot loop over each children namespace, because with multiple Socket.IO servers, a given namespace
 | 
			
		||||
        // may exist on one node but not exist on another (since it is created upon client connection)
 | 
			
		||||
        throw new Error("fetchSockets() is not supported on parent namespaces")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
 | 
			
		||||
// import { Packet, PacketType } from "socket.io-parser"
 | 
			
		||||
import { Packet, PacketType } from "../socket.io-parser"
 | 
			
		||||
import url = require("url")
 | 
			
		||||
// import debugModule from "debug"
 | 
			
		||||
// import debugModule from "debug";
 | 
			
		||||
import type { Server } from "./index"
 | 
			
		||||
import {
 | 
			
		||||
    EventParams,
 | 
			
		||||
@@ -12,24 +11,41 @@ import {
 | 
			
		||||
} from "./typed-events"
 | 
			
		||||
import type { Client } from "./client"
 | 
			
		||||
import type { Namespace, NamespaceReservedEventsMap } from "./namespace"
 | 
			
		||||
// import type { IncomingMessage, IncomingHttpHeaders } from "http"
 | 
			
		||||
// import type { IncomingMessage, IncomingHttpHeaders } from "http";
 | 
			
		||||
import type {
 | 
			
		||||
    Adapter,
 | 
			
		||||
    BroadcastFlags,
 | 
			
		||||
    Room,
 | 
			
		||||
    SocketId,
 | 
			
		||||
} from "socket.io-adapter"
 | 
			
		||||
// import base64id from "base64id"
 | 
			
		||||
} from "../socket.io-adapter"
 | 
			
		||||
// import base64id from "base64id";
 | 
			
		||||
import type { ParsedUrlQuery } from "querystring"
 | 
			
		||||
import { BroadcastOperator } from "./broadcast-operator"
 | 
			
		||||
import * as url from "url"
 | 
			
		||||
 | 
			
		||||
// const debug = debugModule("socket.io:socket");
 | 
			
		||||
const debug = require('../debug')("socket.io:socket")
 | 
			
		||||
 | 
			
		||||
type ClientReservedEvents = "connect_error"
 | 
			
		||||
 | 
			
		||||
// TODO for next major release: cleanup disconnect reasons
 | 
			
		||||
export type DisconnectReason =
 | 
			
		||||
    // Engine.IO close reasons
 | 
			
		||||
    | "transport error"
 | 
			
		||||
    | "transport close"
 | 
			
		||||
    | "forced close"
 | 
			
		||||
    | "ping timeout"
 | 
			
		||||
    | "parse error"
 | 
			
		||||
    // Socket.IO disconnect reasons
 | 
			
		||||
    | "server shutting down"
 | 
			
		||||
    | "forced server close"
 | 
			
		||||
    | "client namespace disconnect"
 | 
			
		||||
    | "server namespace disconnect"
 | 
			
		||||
    | any
 | 
			
		||||
 | 
			
		||||
export interface SocketReservedEventsMap {
 | 
			
		||||
    disconnect: (reason: string) => void
 | 
			
		||||
    disconnecting: (reason: string) => void
 | 
			
		||||
    disconnect: (reason: DisconnectReason) => void
 | 
			
		||||
    disconnecting: (reason: DisconnectReason) => void
 | 
			
		||||
    error: (err: Error) => void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -47,7 +63,7 @@ export interface EventEmitterReservedEventsMap {
 | 
			
		||||
 | 
			
		||||
export const RESERVED_EVENTS: ReadonlySet<string | Symbol> = new Set<
 | 
			
		||||
    | ClientReservedEvents
 | 
			
		||||
    | keyof NamespaceReservedEventsMap<never, never, never>
 | 
			
		||||
    | keyof NamespaceReservedEventsMap<never, never, never, never>
 | 
			
		||||
    | keyof SocketReservedEventsMap
 | 
			
		||||
    | keyof EventEmitterReservedEventsMap
 | 
			
		||||
>(<const>[
 | 
			
		||||
@@ -66,7 +82,8 @@ export interface Handshake {
 | 
			
		||||
    /**
 | 
			
		||||
     * The headers sent as part of the handshake
 | 
			
		||||
     */
 | 
			
		||||
    headers: any//IncomingHttpHeaders
 | 
			
		||||
    // headers: IncomingHttpHeaders;
 | 
			
		||||
    headers: any
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The date of creation (as string)
 | 
			
		||||
@@ -109,33 +126,94 @@ export interface Handshake {
 | 
			
		||||
    auth: { [key: string]: any }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * `[eventName, ...args]`
 | 
			
		||||
 */
 | 
			
		||||
export type Event = [string, ...any[]]
 | 
			
		||||
 | 
			
		||||
function noop() { }
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is the main object for interacting with a client.
 | 
			
		||||
 *
 | 
			
		||||
 * A Socket belongs to a given {@link Namespace} and uses an underlying {@link Client} to communicate.
 | 
			
		||||
 *
 | 
			
		||||
 * Within each {@link Namespace}, you can also define arbitrary channels (called "rooms") that the {@link Socket} can
 | 
			
		||||
 * join and leave. That provides a convenient way to broadcast to a group of socket instances.
 | 
			
		||||
 *
 | 
			
		||||
 * @example
 | 
			
		||||
 * io.on("connection", (socket) => {
 | 
			
		||||
 *   console.log(`socket ${socket.id} connected`);
 | 
			
		||||
 *
 | 
			
		||||
 *   // send an event to the client
 | 
			
		||||
 *   socket.emit("foo", "bar");
 | 
			
		||||
 *
 | 
			
		||||
 *   socket.on("foobar", () => {
 | 
			
		||||
 *     // an event was received from the client
 | 
			
		||||
 *   });
 | 
			
		||||
 *
 | 
			
		||||
 *   // join the room named "room1"
 | 
			
		||||
 *   socket.join("room1");
 | 
			
		||||
 *
 | 
			
		||||
 *   // broadcast to everyone in the room named "room1"
 | 
			
		||||
 *   io.to("room1").emit("hello");
 | 
			
		||||
 *
 | 
			
		||||
 *   // upon disconnection
 | 
			
		||||
 *   socket.on("disconnect", (reason) => {
 | 
			
		||||
 *     console.log(`socket ${socket.id} disconnected due to ${reason}`);
 | 
			
		||||
 *   });
 | 
			
		||||
 * });
 | 
			
		||||
 */
 | 
			
		||||
export class Socket<
 | 
			
		||||
    ListenEvents extends EventsMap = DefaultEventsMap,
 | 
			
		||||
    EmitEvents extends EventsMap = ListenEvents,
 | 
			
		||||
    ServerSideEvents extends EventsMap = DefaultEventsMap
 | 
			
		||||
    > extends StrictEventEmitter<
 | 
			
		||||
    ServerSideEvents extends EventsMap = DefaultEventsMap,
 | 
			
		||||
    SocketData = any
 | 
			
		||||
> extends StrictEventEmitter<
 | 
			
		||||
    ListenEvents,
 | 
			
		||||
    EmitEvents,
 | 
			
		||||
    SocketReservedEventsMap
 | 
			
		||||
    > {
 | 
			
		||||
    public readonly id: SocketId
 | 
			
		||||
    public readonly handshake: Handshake
 | 
			
		||||
 | 
			
		||||
> {
 | 
			
		||||
    /**
 | 
			
		||||
     * Additional information that can be attached to the Socket instance and which will be used in the fetchSockets method
 | 
			
		||||
     * An unique identifier for the session.
 | 
			
		||||
     */
 | 
			
		||||
    public data: any = {};
 | 
			
		||||
    public readonly id: SocketId
 | 
			
		||||
    /**
 | 
			
		||||
     * The handshake details.
 | 
			
		||||
     */
 | 
			
		||||
    public readonly handshake: Handshake
 | 
			
		||||
    /**
 | 
			
		||||
     * Additional information that can be attached to the Socket instance and which will be used in the
 | 
			
		||||
     * {@link Server.fetchSockets()} method.
 | 
			
		||||
     */
 | 
			
		||||
    public data: Partial<SocketData> = {};
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether the socket is currently connected or not.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.use((socket, next) => {
 | 
			
		||||
     *   console.log(socket.connected); // false
 | 
			
		||||
     *   next();
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   console.log(socket.connected); // true
 | 
			
		||||
     * });
 | 
			
		||||
     */
 | 
			
		||||
    public connected: boolean = false;
 | 
			
		||||
 | 
			
		||||
    public connected: boolean
 | 
			
		||||
    public disconnected: boolean
 | 
			
		||||
 | 
			
		||||
    private readonly server: Server<ListenEvents, EmitEvents, ServerSideEvents>
 | 
			
		||||
    private readonly server: Server<
 | 
			
		||||
        ListenEvents,
 | 
			
		||||
        EmitEvents,
 | 
			
		||||
        ServerSideEvents,
 | 
			
		||||
        SocketData
 | 
			
		||||
    >
 | 
			
		||||
    private readonly adapter: Adapter
 | 
			
		||||
    private acks: Map<number, () => void> = new Map();
 | 
			
		||||
    private fns: Array<(event: Array<any>, next: (err?: Error) => void) => void> =
 | 
			
		||||
        [];
 | 
			
		||||
    private fns: Array<(event: Event, next: (err?: Error) => void) => void> = [];
 | 
			
		||||
    private flags: BroadcastFlags = {};
 | 
			
		||||
    private _anyListeners?: Array<(...args: any[]) => void>
 | 
			
		||||
    private _anyOutgoingListeners?: Array<(...args: any[]) => void>
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Interface to a `Client` for a given `Namespace`.
 | 
			
		||||
@@ -151,23 +229,23 @@ export class Socket<
 | 
			
		||||
        auth: object
 | 
			
		||||
    ) {
 | 
			
		||||
        super()
 | 
			
		||||
        this.nsp = nsp
 | 
			
		||||
        this.server = nsp.server
 | 
			
		||||
        this.adapter = this.nsp.adapter
 | 
			
		||||
        // if (client.conn.protocol === 3) {
 | 
			
		||||
        //     // @ts-ignore
 | 
			
		||||
        // @ts-ignore
 | 
			
		||||
        this.id = nsp.name !== "/" ? nsp.name + "#" + client.id : client.id
 | 
			
		||||
        // } else {
 | 
			
		||||
        //     this.id = base64id.generateId() // don't reuse the Engine.IO id because it's sensitive information
 | 
			
		||||
        // this.id = base64id.generateId() // don't reuse the Engine.IO id because it's sensitive information
 | 
			
		||||
        // }
 | 
			
		||||
        this.client = client
 | 
			
		||||
        this.acks = new Map()
 | 
			
		||||
        this.connected = true
 | 
			
		||||
        this.disconnected = false
 | 
			
		||||
        this.handshake = this.buildHandshake(auth)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    buildHandshake(auth): Handshake {
 | 
			
		||||
    /**
 | 
			
		||||
     * Builds the `handshake` BC object
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private buildHandshake(auth: object): Handshake {
 | 
			
		||||
        return {
 | 
			
		||||
            headers: this.request.headers,
 | 
			
		||||
            time: new Date() + "",
 | 
			
		||||
@@ -177,6 +255,7 @@ export class Socket<
 | 
			
		||||
            secure: !!this.request.connection.encrypted,
 | 
			
		||||
            issued: +new Date(),
 | 
			
		||||
            url: this.request.url!,
 | 
			
		||||
            // @ts-ignore
 | 
			
		||||
            query: url.parse(this.request.url!, true).query,
 | 
			
		||||
            auth,
 | 
			
		||||
        }
 | 
			
		||||
@@ -185,15 +264,27 @@ export class Socket<
 | 
			
		||||
    /**
 | 
			
		||||
     * Emits to this client.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   socket.emit("hello", "world");
 | 
			
		||||
     *
 | 
			
		||||
     *   // all serializable datastructures are supported (no need to call JSON.stringify)
 | 
			
		||||
     *   socket.emit("hello", 1, "2", { 3: ["4"], 5: Buffer.from([6]) });
 | 
			
		||||
     *
 | 
			
		||||
     *   // with an acknowledgement from the client
 | 
			
		||||
     *   socket.emit("hello", "world", (val) => {
 | 
			
		||||
     *     // ...
 | 
			
		||||
     *   });
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @return Always returns `true`.
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public emit<Ev extends EventNames<EmitEvents>>(
 | 
			
		||||
        ev: Ev,
 | 
			
		||||
        ...args: EventParams<EmitEvents, Ev>
 | 
			
		||||
    ): boolean {
 | 
			
		||||
        if (RESERVED_EVENTS.has(ev)) {
 | 
			
		||||
            throw new Error(`"${ev}" is a reserved event name`)
 | 
			
		||||
            throw new Error(`"${String(ev)}" is a reserved event name`)
 | 
			
		||||
        }
 | 
			
		||||
        const data: any[] = [ev, ...args]
 | 
			
		||||
        const packet: any = {
 | 
			
		||||
@@ -203,57 +294,124 @@ export class Socket<
 | 
			
		||||
 | 
			
		||||
        // access last argument to see if it's an ACK callback
 | 
			
		||||
        if (typeof data[data.length - 1] === "function") {
 | 
			
		||||
            console.trace("emitting packet with ack id %d", this.nsp._ids)
 | 
			
		||||
            this.acks.set(this.nsp._ids, data.pop())
 | 
			
		||||
            packet.id = this.nsp._ids++
 | 
			
		||||
            const id = this.nsp._ids++
 | 
			
		||||
            debug("emitting packet with ack id %d", id)
 | 
			
		||||
 | 
			
		||||
            this.registerAckCallback(id, data.pop())
 | 
			
		||||
            packet.id = id
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const flags = Object.assign({}, this.flags)
 | 
			
		||||
        this.flags = {}
 | 
			
		||||
 | 
			
		||||
        this.notifyOutgoingListeners(packet)
 | 
			
		||||
        this.packet(packet, flags)
 | 
			
		||||
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Targets a room when broadcasting.
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    public to(room: Room | Room[]): BroadcastOperator<EmitEvents> {
 | 
			
		||||
        return this.newBroadcastOperator().to(room)
 | 
			
		||||
    private registerAckCallback(id: number, ack: (...args: any[]) => void): void {
 | 
			
		||||
        const timeout = this.flags.timeout
 | 
			
		||||
        if (timeout === undefined) {
 | 
			
		||||
            this.acks.set(id, ack)
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const timer = setTimeout(() => {
 | 
			
		||||
            debug("event with ack id %d has timed out after %d ms", id, timeout)
 | 
			
		||||
            this.acks.delete(id)
 | 
			
		||||
            ack.call(this, new Error("operation has timed out"))
 | 
			
		||||
        }, timeout)
 | 
			
		||||
 | 
			
		||||
        this.acks.set(id, (...args) => {
 | 
			
		||||
            clearTimeout(timer)
 | 
			
		||||
            ack.apply(this, [null, ...args])
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Targets a room when broadcasting.
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   // the “foo” event will be broadcast to all connected clients in the “room-101” room, except this socket
 | 
			
		||||
     *   socket.to("room-101").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     *   // the code above is equivalent to:
 | 
			
		||||
     *   io.to("room-101").except(socket.id).emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     *   // with an array of rooms (a client will be notified at most once)
 | 
			
		||||
     *   socket.to(["room-101", "room-102"]).emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     *   // with multiple chained calls
 | 
			
		||||
     *   socket.to("room-101").to("room-102").emit("foo", "bar");
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public in(room: Room | Room[]): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public to(room: Room | Room[]) {
 | 
			
		||||
        return this.newBroadcastOperator().to(room)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Targets a room when broadcasting. Similar to `to()`, but might feel clearer in some cases:
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   // disconnect all clients in the "room-101" room, except this socket
 | 
			
		||||
     *   socket.in("room-101").disconnectSockets();
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public in(room: Room | Room[]) {
 | 
			
		||||
        return this.newBroadcastOperator().in(room)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Excludes a room when broadcasting.
 | 
			
		||||
     *
 | 
			
		||||
     * @param room
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   // the "foo" event will be broadcast to all connected clients, except the ones that are in the "room-101" room
 | 
			
		||||
     *   // and this socket
 | 
			
		||||
     *   socket.except("room-101").emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     *   // with an array of rooms
 | 
			
		||||
     *   socket.except(["room-101", "room-102"]).emit("foo", "bar");
 | 
			
		||||
     *
 | 
			
		||||
     *   // with multiple chained calls
 | 
			
		||||
     *   socket.except("room-101").except("room-102").emit("foo", "bar");
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param room - a room, or an array of rooms
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public except(room: Room | Room[]): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public except(room: Room | Room[]) {
 | 
			
		||||
        return this.newBroadcastOperator().except(room)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a `message` event.
 | 
			
		||||
     *
 | 
			
		||||
     * This method mimics the WebSocket.send() method.
 | 
			
		||||
     *
 | 
			
		||||
     * @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   socket.send("hello");
 | 
			
		||||
     *
 | 
			
		||||
     *   // this is equivalent to
 | 
			
		||||
     *   socket.emit("message", "hello");
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public send(...args: EventParams<EmitEvents, "message">): this {
 | 
			
		||||
        this.emit("message", ...args)
 | 
			
		||||
@@ -261,10 +419,9 @@ export class Socket<
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a `message` event.
 | 
			
		||||
     * Sends a `message` event. Alias of {@link send}.
 | 
			
		||||
     *
 | 
			
		||||
     * @return self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public write(...args: EventParams<EmitEvents, "message">): this {
 | 
			
		||||
        this.emit("message", ...args)
 | 
			
		||||
@@ -290,12 +447,20 @@ export class Socket<
 | 
			
		||||
    /**
 | 
			
		||||
     * Joins a room.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   // join a single room
 | 
			
		||||
     *   socket.join("room1");
 | 
			
		||||
     *
 | 
			
		||||
     *   // join multiple rooms
 | 
			
		||||
     *   socket.join(["room1", "room2"]);
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String|Array} rooms - room or array of rooms
 | 
			
		||||
     * @return a Promise or nothing, depending on the adapter
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public join(rooms: Room | Array<Room>): Promise<void> | void {
 | 
			
		||||
        console.debug(`join room ${rooms}`)
 | 
			
		||||
        debug("join room %s", rooms)
 | 
			
		||||
 | 
			
		||||
        return this.adapter.addAll(
 | 
			
		||||
            this.id,
 | 
			
		||||
@@ -306,12 +471,20 @@ export class Socket<
 | 
			
		||||
    /**
 | 
			
		||||
     * Leaves a room.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   // leave a single room
 | 
			
		||||
     *   socket.leave("room1");
 | 
			
		||||
     *
 | 
			
		||||
     *   // leave multiple rooms
 | 
			
		||||
     *   socket.leave("room1").leave("room2");
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param {String} room
 | 
			
		||||
     * @return a Promise or nothing, depending on the adapter
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public leave(room: string): Promise<void> | void {
 | 
			
		||||
        console.debug(`leave room ${room}`)
 | 
			
		||||
        debug("leave room %s", room)
 | 
			
		||||
 | 
			
		||||
        return this.adapter.del(this.id, room)
 | 
			
		||||
    }
 | 
			
		||||
@@ -334,7 +507,8 @@ export class Socket<
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    _onconnect(): void {
 | 
			
		||||
        console.debug(`socket ${this.id} connected - writing packet`)
 | 
			
		||||
        debug("socket connected - writing packet")
 | 
			
		||||
        this.connected = true
 | 
			
		||||
        this.join(this.id)
 | 
			
		||||
        if (this.conn.protocol === 3) {
 | 
			
		||||
            this.packet({ type: PacketType.CONNECT })
 | 
			
		||||
@@ -350,7 +524,7 @@ export class Socket<
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    _onpacket(packet: Packet): void {
 | 
			
		||||
        console.trace("got packet", JSON.stringify(packet))
 | 
			
		||||
        debug("got packet %j", packet)
 | 
			
		||||
        switch (packet.type) {
 | 
			
		||||
            case PacketType.EVENT:
 | 
			
		||||
                this.onevent(packet)
 | 
			
		||||
@@ -371,9 +545,6 @@ export class Socket<
 | 
			
		||||
            case PacketType.DISCONNECT:
 | 
			
		||||
                this.ondisconnect()
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
            case PacketType.CONNECT_ERROR:
 | 
			
		||||
                this._onerror(new Error(packet.data))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -385,10 +556,10 @@ export class Socket<
 | 
			
		||||
     */
 | 
			
		||||
    private onevent(packet: Packet): void {
 | 
			
		||||
        const args = packet.data || []
 | 
			
		||||
        console.trace("emitting event", JSON.stringify(args))
 | 
			
		||||
        debug("emitting event %j", args)
 | 
			
		||||
 | 
			
		||||
        if (null != packet.id) {
 | 
			
		||||
            console.trace("attaching ack callback to event")
 | 
			
		||||
            debug("attaching ack callback to event")
 | 
			
		||||
            args.push(this.ack(packet.id))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -414,7 +585,7 @@ export class Socket<
 | 
			
		||||
            // prevent double callbacks
 | 
			
		||||
            if (sent) return
 | 
			
		||||
            const args = Array.prototype.slice.call(arguments)
 | 
			
		||||
            console.trace("sending ack", JSON.stringify(args))
 | 
			
		||||
            debug("sending ack %j", args)
 | 
			
		||||
 | 
			
		||||
            self.packet({
 | 
			
		||||
                id: id,
 | 
			
		||||
@@ -434,11 +605,11 @@ export class Socket<
 | 
			
		||||
    private onack(packet: Packet): void {
 | 
			
		||||
        const ack = this.acks.get(packet.id!)
 | 
			
		||||
        if ("function" == typeof ack) {
 | 
			
		||||
            console.trace(`socket ${this.id} calling ack ${packet.id} with ${packet.data}`)
 | 
			
		||||
            debug("calling ack %s with %j", packet.id, packet.data)
 | 
			
		||||
            ack.apply(this, packet.data)
 | 
			
		||||
            this.acks.delete(packet.id!)
 | 
			
		||||
        } else {
 | 
			
		||||
            console.debug(`socket ${this.id} bad ack`, packet.id)
 | 
			
		||||
            debug("bad ack %s", packet.id)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -448,7 +619,7 @@ export class Socket<
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private ondisconnect(): void {
 | 
			
		||||
        console.debug(`socket ${this.id} got disconnect packet`)
 | 
			
		||||
        debug("got disconnect packet")
 | 
			
		||||
        this._onclose("client namespace disconnect")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -474,19 +645,28 @@ export class Socket<
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    _onclose(reason: string): this | undefined {
 | 
			
		||||
    _onclose(reason: DisconnectReason): this | undefined {
 | 
			
		||||
        if (!this.connected) return this
 | 
			
		||||
        console.debug(`closing socket ${this.id} - reason: ${reason}`)
 | 
			
		||||
        debug("closing socket - reason %s", reason)
 | 
			
		||||
        this.emitReserved("disconnecting", reason)
 | 
			
		||||
        this.leaveAll()
 | 
			
		||||
        this._cleanup()
 | 
			
		||||
        this.nsp._remove(this)
 | 
			
		||||
        this.client._remove(this)
 | 
			
		||||
        this.connected = false
 | 
			
		||||
        this.disconnected = true
 | 
			
		||||
        this.emitReserved("disconnect", reason)
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Makes the socket leave all the rooms it was part of and prevents it from joining any other room
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    _cleanup() {
 | 
			
		||||
        this.leaveAll()
 | 
			
		||||
        this.join = noop
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Produces an `error` packet.
 | 
			
		||||
     *
 | 
			
		||||
@@ -501,10 +681,17 @@ export class Socket<
 | 
			
		||||
    /**
 | 
			
		||||
     * Disconnects this client.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Boolean} close - if `true`, closes the underlying connection
 | 
			
		||||
     * @return {Socket} self
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   // disconnect this socket (the connection might be kept alive for other namespaces)
 | 
			
		||||
     *   socket.disconnect();
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     *   // disconnect this socket and close the underlying connection
 | 
			
		||||
     *   socket.disconnect(true);
 | 
			
		||||
     * })
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Boolean} close - if `true`, closes the underlying connection
 | 
			
		||||
     * @return self
 | 
			
		||||
     */
 | 
			
		||||
    public disconnect(close = false): this {
 | 
			
		||||
        if (!this.connected) return this
 | 
			
		||||
@@ -520,9 +707,13 @@ export class Socket<
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the compress flag.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   socket.compress(false).emit("hello");
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Boolean} compress - if `true`, compresses the sending data
 | 
			
		||||
     * @return {Socket} self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public compress(compress: boolean): this {
 | 
			
		||||
        this.flags.compress = compress
 | 
			
		||||
@@ -530,13 +721,17 @@ export class Socket<
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
   * Sets a modifier for a subsequent event emission that the event data may be lost if the client is not ready to
 | 
			
		||||
   * receive messages (because of network slowness or other issues, or because they’re connected through long polling
 | 
			
		||||
   * and is in the middle of a request-response cycle).
 | 
			
		||||
   *
 | 
			
		||||
   * @return {Socket} self
 | 
			
		||||
   * @public
 | 
			
		||||
   */
 | 
			
		||||
     * Sets a modifier for a subsequent event emission that the event data may be lost if the client is not ready to
 | 
			
		||||
     * receive messages (because of network slowness or other issues, or because they’re connected through long polling
 | 
			
		||||
     * and is in the middle of a request-response cycle).
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   socket.volatile.emit("hello"); // the client may or may not receive it
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @return {Socket} self
 | 
			
		||||
     */
 | 
			
		||||
    public get volatile(): this {
 | 
			
		||||
        this.flags.volatile = true
 | 
			
		||||
        return this
 | 
			
		||||
@@ -546,31 +741,61 @@ export class Socket<
 | 
			
		||||
     * Sets a modifier for a subsequent event emission that the event data will only be broadcast to every sockets but the
 | 
			
		||||
     * sender.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {Socket} self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   // the “foo” event will be broadcast to all connected clients, except this socket
 | 
			
		||||
     *   socket.broadcast.emit("foo", "bar");
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public get broadcast(): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public get broadcast() {
 | 
			
		||||
        return this.newBroadcastOperator()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets a modifier for a subsequent event emission that the event data will only be broadcast to the current node.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {Socket} self
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   // the “foo” event will be broadcast to all connected clients on this node, except this socket
 | 
			
		||||
     *   socket.local.emit("foo", "bar");
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @return a new {@link BroadcastOperator} instance for chaining
 | 
			
		||||
     */
 | 
			
		||||
    public get local(): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    public get local() {
 | 
			
		||||
        return this.newBroadcastOperator().local
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets a modifier for a subsequent event emission that the callback will be called with an error when the
 | 
			
		||||
     * given number of milliseconds have elapsed without an acknowledgement from the client:
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   socket.timeout(5000).emit("my-event", (err) => {
 | 
			
		||||
     *     if (err) {
 | 
			
		||||
     *       // the client did not acknowledge the event in the given delay
 | 
			
		||||
     *     }
 | 
			
		||||
     *   });
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @returns self
 | 
			
		||||
     */
 | 
			
		||||
    public timeout(timeout: number): this {
 | 
			
		||||
        this.flags.timeout = timeout
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Dispatch incoming event to socket listeners.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Array} event - event that will get emitted
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private dispatch(event: [eventName: string, ...args: any[]]): void {
 | 
			
		||||
        console.trace("dispatching an event", JSON.stringify(event))
 | 
			
		||||
    private dispatch(event: Event): void {
 | 
			
		||||
        debug("dispatching an event %j", event)
 | 
			
		||||
        this.run(event, (err) => {
 | 
			
		||||
            process.nextTick(() => {
 | 
			
		||||
                if (err) {
 | 
			
		||||
@@ -579,7 +804,7 @@ export class Socket<
 | 
			
		||||
                if (this.connected) {
 | 
			
		||||
                    super.emitUntyped.apply(this, event)
 | 
			
		||||
                } else {
 | 
			
		||||
                    console.debug("ignore packet received after disconnection")
 | 
			
		||||
                    debug("ignore packet received after disconnection")
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        })
 | 
			
		||||
@@ -588,13 +813,27 @@ export class Socket<
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets up socket middleware.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   socket.use(([event, ...args], next) => {
 | 
			
		||||
     *     if (isUnauthorized(event)) {
 | 
			
		||||
     *       return next(new Error("unauthorized event"));
 | 
			
		||||
     *     }
 | 
			
		||||
     *     // do not forget to call next
 | 
			
		||||
     *     next();
 | 
			
		||||
     *   });
 | 
			
		||||
     *
 | 
			
		||||
     *   socket.on("error", (err) => {
 | 
			
		||||
     *     if (err && err.message === "unauthorized event") {
 | 
			
		||||
     *       socket.disconnect();
 | 
			
		||||
     *     }
 | 
			
		||||
     *   });
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Function} fn - middleware function (event, next)
 | 
			
		||||
     * @return {Socket} self
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public use(
 | 
			
		||||
        fn: (event: Array<any>, next: (err?: Error) => void) => void
 | 
			
		||||
    ): this {
 | 
			
		||||
    public use(fn: (event: Event, next: (err?: Error) => void) => void): this {
 | 
			
		||||
        this.fns.push(fn)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
@@ -606,10 +845,7 @@ export class Socket<
 | 
			
		||||
     * @param {Function} fn - last fn call in the middleware
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private run(
 | 
			
		||||
        event: [eventName: string, ...args: any[]],
 | 
			
		||||
        fn: (err: Error | null) => void
 | 
			
		||||
    ): void {
 | 
			
		||||
    private run(event: Event, fn: (err: Error | null) => void): void {
 | 
			
		||||
        const fns = this.fns.slice(0)
 | 
			
		||||
        if (!fns.length) return fn(null)
 | 
			
		||||
 | 
			
		||||
@@ -629,10 +865,15 @@ export class Socket<
 | 
			
		||||
        run(0)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether the socket is currently disconnected
 | 
			
		||||
     */
 | 
			
		||||
    public get disconnected() {
 | 
			
		||||
        return !this.connected
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A reference to the request that originated the underlying Engine.IO Socket.
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public get request(): any /** IncomingMessage */ {
 | 
			
		||||
        return this.client.request
 | 
			
		||||
@@ -641,25 +882,47 @@ export class Socket<
 | 
			
		||||
    /**
 | 
			
		||||
     * A reference to the underlying Client transport connection (Engine.IO Socket object).
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   console.log(socket.conn.transport.name); // prints "polling" or "websocket"
 | 
			
		||||
     *
 | 
			
		||||
     *   socket.conn.once("upgrade", () => {
 | 
			
		||||
     *     console.log(socket.conn.transport.name); // prints "websocket"
 | 
			
		||||
     *   });
 | 
			
		||||
     * });
 | 
			
		||||
     */
 | 
			
		||||
    public get conn() {
 | 
			
		||||
        return this.client.conn
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @public
 | 
			
		||||
     * Returns the rooms the socket is currently in.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   console.log(socket.rooms); // Set { <socket.id> }
 | 
			
		||||
     *
 | 
			
		||||
     *   socket.join("room1");
 | 
			
		||||
     *
 | 
			
		||||
     *   console.log(socket.rooms); // Set { <socket.id>, "room1" }
 | 
			
		||||
     * });
 | 
			
		||||
     */
 | 
			
		||||
    public get rooms(): Set<Room> {
 | 
			
		||||
        return this.adapter.socketRooms(this.id) || new Set()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
 | 
			
		||||
     * callback.
 | 
			
		||||
     * Adds a listener that will be fired when any event is received. The event name is passed as the first argument to
 | 
			
		||||
     * the callback.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   socket.onAny((event, ...args) => {
 | 
			
		||||
     *     console.log(`got event ${event}`);
 | 
			
		||||
     *   });
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param listener
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public onAny(listener: (...args: any[]) => void): this {
 | 
			
		||||
        this._anyListeners = this._anyListeners || []
 | 
			
		||||
@@ -668,11 +931,10 @@ export class Socket<
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
 | 
			
		||||
     * callback. The listener is added to the beginning of the listeners array.
 | 
			
		||||
     * Adds a listener that will be fired when any event is received. The event name is passed as the first argument to
 | 
			
		||||
     * the callback. The listener is added to the beginning of the listeners array.
 | 
			
		||||
     *
 | 
			
		||||
     * @param listener
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public prependAny(listener: (...args: any[]) => void): this {
 | 
			
		||||
        this._anyListeners = this._anyListeners || []
 | 
			
		||||
@@ -681,10 +943,24 @@ export class Socket<
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes the listener that will be fired when any event is emitted.
 | 
			
		||||
     * Removes the listener that will be fired when any event is received.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   const catchAllListener = (event, ...args) => {
 | 
			
		||||
     *     console.log(`got event ${event}`);
 | 
			
		||||
     *   }
 | 
			
		||||
     *
 | 
			
		||||
     *   socket.onAny(catchAllListener);
 | 
			
		||||
     *
 | 
			
		||||
     *   // remove a specific listener
 | 
			
		||||
     *   socket.offAny(catchAllListener);
 | 
			
		||||
     *
 | 
			
		||||
     *   // or remove all listeners
 | 
			
		||||
     *   socket.offAny();
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param listener
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public offAny(listener?: (...args: any[]) => void): this {
 | 
			
		||||
        if (!this._anyListeners) {
 | 
			
		||||
@@ -707,17 +983,117 @@ export class Socket<
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,
 | 
			
		||||
     * e.g. to remove listeners.
 | 
			
		||||
     *
 | 
			
		||||
     * @public
 | 
			
		||||
     */
 | 
			
		||||
    public listenersAny() {
 | 
			
		||||
        return this._anyListeners || []
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private newBroadcastOperator(): BroadcastOperator<EmitEvents> {
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a listener that will be fired when any event is sent. The event name is passed as the first argument to
 | 
			
		||||
     * the callback.
 | 
			
		||||
     *
 | 
			
		||||
     * Note: acknowledgements sent to the client are not included.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   socket.onAnyOutgoing((event, ...args) => {
 | 
			
		||||
     *     console.log(`sent event ${event}`);
 | 
			
		||||
     *   });
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param listener
 | 
			
		||||
     */
 | 
			
		||||
    public onAnyOutgoing(listener: (...args: any[]) => void): this {
 | 
			
		||||
        this._anyOutgoingListeners = this._anyOutgoingListeners || []
 | 
			
		||||
        this._anyOutgoingListeners.push(listener)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the
 | 
			
		||||
     * callback. The listener is added to the beginning of the listeners array.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   socket.prependAnyOutgoing((event, ...args) => {
 | 
			
		||||
     *     console.log(`sent event ${event}`);
 | 
			
		||||
     *   });
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param listener
 | 
			
		||||
     */
 | 
			
		||||
    public prependAnyOutgoing(listener: (...args: any[]) => void): this {
 | 
			
		||||
        this._anyOutgoingListeners = this._anyOutgoingListeners || []
 | 
			
		||||
        this._anyOutgoingListeners.unshift(listener)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes the listener that will be fired when any event is sent.
 | 
			
		||||
     *
 | 
			
		||||
     * @example
 | 
			
		||||
     * io.on("connection", (socket) => {
 | 
			
		||||
     *   const catchAllListener = (event, ...args) => {
 | 
			
		||||
     *     console.log(`sent event ${event}`);
 | 
			
		||||
     *   }
 | 
			
		||||
     *
 | 
			
		||||
     *   socket.onAnyOutgoing(catchAllListener);
 | 
			
		||||
     *
 | 
			
		||||
     *   // remove a specific listener
 | 
			
		||||
     *   socket.offAnyOutgoing(catchAllListener);
 | 
			
		||||
     *
 | 
			
		||||
     *   // or remove all listeners
 | 
			
		||||
     *   socket.offAnyOutgoing();
 | 
			
		||||
     * });
 | 
			
		||||
     *
 | 
			
		||||
     * @param listener - the catch-all listener
 | 
			
		||||
     */
 | 
			
		||||
    public offAnyOutgoing(listener?: (...args: any[]) => void): this {
 | 
			
		||||
        if (!this._anyOutgoingListeners) {
 | 
			
		||||
            return this
 | 
			
		||||
        }
 | 
			
		||||
        if (listener) {
 | 
			
		||||
            const listeners = this._anyOutgoingListeners
 | 
			
		||||
            for (let i = 0; i < listeners.length; i++) {
 | 
			
		||||
                if (listener === listeners[i]) {
 | 
			
		||||
                    listeners.splice(i, 1)
 | 
			
		||||
                    return this
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            this._anyOutgoingListeners = []
 | 
			
		||||
        }
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,
 | 
			
		||||
     * e.g. to remove listeners.
 | 
			
		||||
     */
 | 
			
		||||
    public listenersAnyOutgoing() {
 | 
			
		||||
        return this._anyOutgoingListeners || []
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Notify the listeners for each packet sent (emit or broadcast)
 | 
			
		||||
     *
 | 
			
		||||
     * @param packet
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    private notifyOutgoingListeners(packet: Packet) {
 | 
			
		||||
        if (this._anyOutgoingListeners && this._anyOutgoingListeners.length) {
 | 
			
		||||
            const listeners = this._anyOutgoingListeners.slice()
 | 
			
		||||
            for (const listener of listeners) {
 | 
			
		||||
                listener.apply(this, packet.data)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private newBroadcastOperator() {
 | 
			
		||||
        const flags = Object.assign({}, this.flags)
 | 
			
		||||
        this.flags = {}
 | 
			
		||||
        return new BroadcastOperator(
 | 
			
		||||
        return new BroadcastOperator<EmitEvents, SocketData>(
 | 
			
		||||
            this.adapter,
 | 
			
		||||
            new Set<Room>(),
 | 
			
		||||
            new Set<Room>([this.id]),
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user