UNPKG

@blinkdotnew/sdk

Version:

Blink TypeScript SDK for client-side applications - Zero-boilerplate CRUD + auth + AI + analytics + notifications for modern SaaS/AI apps

1,559 lines (1,549 loc) 307 kB
'use strict'; var __getOwnPropNames = Object.getOwnPropertyNames; var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) { if (typeof require !== "undefined") return require.apply(this, arguments); throw Error('Dynamic require of "' + x + '" is not supported'); }); var __commonJS = (cb, mod) => function __require2() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; // ../../node_modules/async-limiter/index.js var require_async_limiter = __commonJS({ "../../node_modules/async-limiter/index.js"(exports, module) { function Queue(options) { if (!(this instanceof Queue)) { return new Queue(options); } options = options || {}; this.concurrency = options.concurrency || Infinity; this.pending = 0; this.jobs = []; this.cbs = []; this._done = done.bind(this); } var arrayAddMethods = [ "push", "unshift", "splice" ]; arrayAddMethods.forEach(function(method) { Queue.prototype[method] = function() { var methodResult = Array.prototype[method].apply(this.jobs, arguments); this._run(); return methodResult; }; }); Object.defineProperty(Queue.prototype, "length", { get: function() { return this.pending + this.jobs.length; } }); Queue.prototype._run = function() { if (this.pending === this.concurrency) { return; } if (this.jobs.length) { var job = this.jobs.shift(); this.pending++; job(this._done); this._run(); } if (this.pending === 0) { while (this.cbs.length !== 0) { var cb = this.cbs.pop(); process.nextTick(cb); } } }; Queue.prototype.onDone = function(cb) { if (typeof cb === "function") { this.cbs.push(cb); this._run(); } }; function done() { this.pending--; this._run(); } module.exports = Queue; } }); // ../../node_modules/ws/lib/constants.js var require_constants = __commonJS({ "../../node_modules/ws/lib/constants.js"(exports, module) { module.exports = { BINARY_TYPES: ["nodebuffer", "arraybuffer", "fragments"], GUID: "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", kStatusCode: Symbol("status-code"), kWebSocket: Symbol("websocket"), EMPTY_BUFFER: Buffer.alloc(0), NOOP: () => { } }; } }); // ../../node_modules/ws/lib/buffer-util.js var require_buffer_util = __commonJS({ "../../node_modules/ws/lib/buffer-util.js"(exports, module) { var { EMPTY_BUFFER } = require_constants(); function concat(list, totalLength) { if (list.length === 0) return EMPTY_BUFFER; if (list.length === 1) return list[0]; const target = Buffer.allocUnsafe(totalLength); var offset = 0; for (var i = 0; i < list.length; i++) { const buf = list[i]; buf.copy(target, offset); offset += buf.length; } return target; } function _mask(source, mask, output, offset, length) { for (var i = 0; i < length; i++) { output[offset + i] = source[i] ^ mask[i & 3]; } } function _unmask(buffer, mask) { const length = buffer.length; for (var i = 0; i < length; i++) { buffer[i] ^= mask[i & 3]; } } function toArrayBuffer(buf) { if (buf.byteLength === buf.buffer.byteLength) { return buf.buffer; } return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); } function toBuffer(data) { toBuffer.readOnly = true; if (Buffer.isBuffer(data)) return data; var buf; if (data instanceof ArrayBuffer) { buf = Buffer.from(data); } else if (ArrayBuffer.isView(data)) { buf = viewToBuffer(data); } else { buf = Buffer.from(data); toBuffer.readOnly = false; } return buf; } function viewToBuffer(view) { const buf = Buffer.from(view.buffer); if (view.byteLength !== view.buffer.byteLength) { return buf.slice(view.byteOffset, view.byteOffset + view.byteLength); } return buf; } try { const bufferUtil = __require("bufferutil"); const bu = bufferUtil.BufferUtil || bufferUtil; module.exports = { concat, mask(source, mask, output, offset, length) { if (length < 48) _mask(source, mask, output, offset, length); else bu.mask(source, mask, output, offset, length); }, toArrayBuffer, toBuffer, unmask(buffer, mask) { if (buffer.length < 32) _unmask(buffer, mask); else bu.unmask(buffer, mask); } }; } catch (e) { module.exports = { concat, mask: _mask, toArrayBuffer, toBuffer, unmask: _unmask }; } } }); // ../../node_modules/ws/lib/permessage-deflate.js var require_permessage_deflate = __commonJS({ "../../node_modules/ws/lib/permessage-deflate.js"(exports, module) { var Limiter = require_async_limiter(); var zlib = __require("zlib"); var bufferUtil = require_buffer_util(); var { kStatusCode, NOOP } = require_constants(); var TRAILER = Buffer.from([0, 0, 255, 255]); var EMPTY_BLOCK = Buffer.from([0]); var kPerMessageDeflate = Symbol("permessage-deflate"); var kTotalLength = Symbol("total-length"); var kCallback = Symbol("callback"); var kBuffers = Symbol("buffers"); var kError = Symbol("error"); var zlibLimiter; var PerMessageDeflate = class { /** * Creates a PerMessageDeflate instance. * * @param {Object} options Configuration options * @param {Boolean} options.serverNoContextTakeover Request/accept disabling * of server context takeover * @param {Boolean} options.clientNoContextTakeover Advertise/acknowledge * disabling of client context takeover * @param {(Boolean|Number)} options.serverMaxWindowBits Request/confirm the * use of a custom server window size * @param {(Boolean|Number)} options.clientMaxWindowBits Advertise support * for, or request, a custom client window size * @param {Object} options.zlibDeflateOptions Options to pass to zlib on deflate * @param {Object} options.zlibInflateOptions Options to pass to zlib on inflate * @param {Number} options.threshold Size (in bytes) below which messages * should not be compressed * @param {Number} options.concurrencyLimit The number of concurrent calls to * zlib * @param {Boolean} isServer Create the instance in either server or client * mode * @param {Number} maxPayload The maximum allowed message length */ constructor(options, isServer2, maxPayload) { this._maxPayload = maxPayload | 0; this._options = options || {}; this._threshold = this._options.threshold !== void 0 ? this._options.threshold : 1024; this._isServer = !!isServer2; this._deflate = null; this._inflate = null; this.params = null; if (!zlibLimiter) { const concurrency = this._options.concurrencyLimit !== void 0 ? this._options.concurrencyLimit : 10; zlibLimiter = new Limiter({ concurrency }); } } /** * @type {String} */ static get extensionName() { return "permessage-deflate"; } /** * Create an extension negotiation offer. * * @return {Object} Extension parameters * @public */ offer() { const params = {}; if (this._options.serverNoContextTakeover) { params.server_no_context_takeover = true; } if (this._options.clientNoContextTakeover) { params.client_no_context_takeover = true; } if (this._options.serverMaxWindowBits) { params.server_max_window_bits = this._options.serverMaxWindowBits; } if (this._options.clientMaxWindowBits) { params.client_max_window_bits = this._options.clientMaxWindowBits; } else if (this._options.clientMaxWindowBits == null) { params.client_max_window_bits = true; } return params; } /** * Accept an extension negotiation offer/response. * * @param {Array} configurations The extension negotiation offers/reponse * @return {Object} Accepted configuration * @public */ accept(configurations) { configurations = this.normalizeParams(configurations); this.params = this._isServer ? this.acceptAsServer(configurations) : this.acceptAsClient(configurations); return this.params; } /** * Releases all resources used by the extension. * * @public */ cleanup() { if (this._inflate) { this._inflate.close(); this._inflate = null; } if (this._deflate) { this._deflate.close(); this._deflate = null; } } /** * Accept an extension negotiation offer. * * @param {Array} offers The extension negotiation offers * @return {Object} Accepted configuration * @private */ acceptAsServer(offers) { const opts = this._options; const accepted = offers.find((params) => { if (opts.serverNoContextTakeover === false && params.server_no_context_takeover || params.server_max_window_bits && (opts.serverMaxWindowBits === false || typeof opts.serverMaxWindowBits === "number" && opts.serverMaxWindowBits > params.server_max_window_bits) || typeof opts.clientMaxWindowBits === "number" && !params.client_max_window_bits) { return false; } return true; }); if (!accepted) { throw new Error("None of the extension offers can be accepted"); } if (opts.serverNoContextTakeover) { accepted.server_no_context_takeover = true; } if (opts.clientNoContextTakeover) { accepted.client_no_context_takeover = true; } if (typeof opts.serverMaxWindowBits === "number") { accepted.server_max_window_bits = opts.serverMaxWindowBits; } if (typeof opts.clientMaxWindowBits === "number") { accepted.client_max_window_bits = opts.clientMaxWindowBits; } else if (accepted.client_max_window_bits === true || opts.clientMaxWindowBits === false) { delete accepted.client_max_window_bits; } return accepted; } /** * Accept the extension negotiation response. * * @param {Array} response The extension negotiation response * @return {Object} Accepted configuration * @private */ acceptAsClient(response) { const params = response[0]; if (this._options.clientNoContextTakeover === false && params.client_no_context_takeover) { throw new Error('Unexpected parameter "client_no_context_takeover"'); } if (!params.client_max_window_bits) { if (typeof this._options.clientMaxWindowBits === "number") { params.client_max_window_bits = this._options.clientMaxWindowBits; } } else if (this._options.clientMaxWindowBits === false || typeof this._options.clientMaxWindowBits === "number" && params.client_max_window_bits > this._options.clientMaxWindowBits) { throw new Error( 'Unexpected or invalid parameter "client_max_window_bits"' ); } return params; } /** * Normalize parameters. * * @param {Array} configurations The extension negotiation offers/reponse * @return {Array} The offers/response with normalized parameters * @private */ normalizeParams(configurations) { configurations.forEach((params) => { Object.keys(params).forEach((key) => { var value = params[key]; if (value.length > 1) { throw new Error(`Parameter "${key}" must have only a single value`); } value = value[0]; if (key === "client_max_window_bits") { if (value !== true) { const num = +value; if (!Number.isInteger(num) || num < 8 || num > 15) { throw new TypeError( `Invalid value for parameter "${key}": ${value}` ); } value = num; } else if (!this._isServer) { throw new TypeError( `Invalid value for parameter "${key}": ${value}` ); } } else if (key === "server_max_window_bits") { const num = +value; if (!Number.isInteger(num) || num < 8 || num > 15) { throw new TypeError( `Invalid value for parameter "${key}": ${value}` ); } value = num; } else if (key === "client_no_context_takeover" || key === "server_no_context_takeover") { if (value !== true) { throw new TypeError( `Invalid value for parameter "${key}": ${value}` ); } } else { throw new Error(`Unknown parameter "${key}"`); } params[key] = value; }); }); return configurations; } /** * Decompress data. Concurrency limited by async-limiter. * * @param {Buffer} data Compressed data * @param {Boolean} fin Specifies whether or not this is the last fragment * @param {Function} callback Callback * @public */ decompress(data, fin, callback) { zlibLimiter.push((done) => { this._decompress(data, fin, (err, result) => { done(); callback(err, result); }); }); } /** * Compress data. Concurrency limited by async-limiter. * * @param {Buffer} data Data to compress * @param {Boolean} fin Specifies whether or not this is the last fragment * @param {Function} callback Callback * @public */ compress(data, fin, callback) { zlibLimiter.push((done) => { this._compress(data, fin, (err, result) => { done(); callback(err, result); }); }); } /** * Decompress data. * * @param {Buffer} data Compressed data * @param {Boolean} fin Specifies whether or not this is the last fragment * @param {Function} callback Callback * @private */ _decompress(data, fin, callback) { const endpoint = this._isServer ? "client" : "server"; if (!this._inflate) { const key = `${endpoint}_max_window_bits`; const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key]; this._inflate = zlib.createInflateRaw( Object.assign({}, this._options.zlibInflateOptions, { windowBits }) ); this._inflate[kPerMessageDeflate] = this; this._inflate[kTotalLength] = 0; this._inflate[kBuffers] = []; this._inflate.on("error", inflateOnError); this._inflate.on("data", inflateOnData); } this._inflate[kCallback] = callback; this._inflate.write(data); if (fin) this._inflate.write(TRAILER); this._inflate.flush(() => { const err = this._inflate[kError]; if (err) { this._inflate.close(); this._inflate = null; callback(err); return; } const data2 = bufferUtil.concat( this._inflate[kBuffers], this._inflate[kTotalLength] ); if (fin && this.params[`${endpoint}_no_context_takeover`]) { this._inflate.close(); this._inflate = null; } else { this._inflate[kTotalLength] = 0; this._inflate[kBuffers] = []; } callback(null, data2); }); } /** * Compress data. * * @param {Buffer} data Data to compress * @param {Boolean} fin Specifies whether or not this is the last fragment * @param {Function} callback Callback * @private */ _compress(data, fin, callback) { if (!data || data.length === 0) { process.nextTick(callback, null, EMPTY_BLOCK); return; } const endpoint = this._isServer ? "server" : "client"; if (!this._deflate) { const key = `${endpoint}_max_window_bits`; const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key]; this._deflate = zlib.createDeflateRaw( Object.assign({}, this._options.zlibDeflateOptions, { windowBits }) ); this._deflate[kTotalLength] = 0; this._deflate[kBuffers] = []; this._deflate.on("error", NOOP); this._deflate.on("data", deflateOnData); } this._deflate.write(data); this._deflate.flush(zlib.Z_SYNC_FLUSH, () => { if (!this._deflate) { return; } var data2 = bufferUtil.concat( this._deflate[kBuffers], this._deflate[kTotalLength] ); if (fin) data2 = data2.slice(0, data2.length - 4); if (fin && this.params[`${endpoint}_no_context_takeover`]) { this._deflate.close(); this._deflate = null; } else { this._deflate[kTotalLength] = 0; this._deflate[kBuffers] = []; } callback(null, data2); }); } }; module.exports = PerMessageDeflate; function deflateOnData(chunk) { this[kBuffers].push(chunk); this[kTotalLength] += chunk.length; } function inflateOnData(chunk) { this[kTotalLength] += chunk.length; if (this[kPerMessageDeflate]._maxPayload < 1 || this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload) { this[kBuffers].push(chunk); return; } this[kError] = new RangeError("Max payload size exceeded"); this[kError][kStatusCode] = 1009; this.removeListener("data", inflateOnData); this.reset(); } function inflateOnError(err) { this[kPerMessageDeflate]._inflate = null; err[kStatusCode] = 1007; this[kCallback](err); } } }); // ../../node_modules/ws/lib/event-target.js var require_event_target = __commonJS({ "../../node_modules/ws/lib/event-target.js"(exports, module) { var Event = class { /** * Create a new `Event`. * * @param {String} type The name of the event * @param {Object} target A reference to the target to which the event was dispatched */ constructor(type, target) { this.target = target; this.type = type; } }; var MessageEvent = class extends Event { /** * Create a new `MessageEvent`. * * @param {(String|Buffer|ArrayBuffer|Buffer[])} data The received data * @param {WebSocket} target A reference to the target to which the event was dispatched */ constructor(data, target) { super("message", target); this.data = data; } }; var CloseEvent = class extends Event { /** * Create a new `CloseEvent`. * * @param {Number} code The status code explaining why the connection is being closed * @param {String} reason A human-readable string explaining why the connection is closing * @param {WebSocket} target A reference to the target to which the event was dispatched */ constructor(code, reason, target) { super("close", target); this.wasClean = target._closeFrameReceived && target._closeFrameSent; this.reason = reason; this.code = code; } }; var OpenEvent = class extends Event { /** * Create a new `OpenEvent`. * * @param {WebSocket} target A reference to the target to which the event was dispatched */ constructor(target) { super("open", target); } }; var ErrorEvent = class extends Event { /** * Create a new `ErrorEvent`. * * @param {Object} error The error that generated this event * @param {WebSocket} target A reference to the target to which the event was dispatched */ constructor(error, target) { super("error", target); this.message = error.message; this.error = error; } }; var EventTarget = { /** * Register an event listener. * * @param {String} method A string representing the event type to listen for * @param {Function} listener The listener to add * @public */ addEventListener(method, listener) { if (typeof listener !== "function") return; function onMessage(data) { listener.call(this, new MessageEvent(data, this)); } function onClose(code, message) { listener.call(this, new CloseEvent(code, message, this)); } function onError(error) { listener.call(this, new ErrorEvent(error, this)); } function onOpen() { listener.call(this, new OpenEvent(this)); } if (method === "message") { onMessage._listener = listener; this.on(method, onMessage); } else if (method === "close") { onClose._listener = listener; this.on(method, onClose); } else if (method === "error") { onError._listener = listener; this.on(method, onError); } else if (method === "open") { onOpen._listener = listener; this.on(method, onOpen); } else { this.on(method, listener); } }, /** * Remove an event listener. * * @param {String} method A string representing the event type to remove * @param {Function} listener The listener to remove * @public */ removeEventListener(method, listener) { const listeners = this.listeners(method); for (var i = 0; i < listeners.length; i++) { if (listeners[i] === listener || listeners[i]._listener === listener) { this.removeListener(method, listeners[i]); } } } }; module.exports = EventTarget; } }); // ../../node_modules/ws/lib/extension.js var require_extension = __commonJS({ "../../node_modules/ws/lib/extension.js"(exports, module) { var tokenChars = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127 ]; function push(dest, name, elem) { if (Object.prototype.hasOwnProperty.call(dest, name)) dest[name].push(elem); else dest[name] = [elem]; } function parse(header) { const offers = {}; if (header === void 0 || header === "") return offers; var params = {}; var mustUnescape = false; var isEscaping = false; var inQuotes = false; var extensionName; var paramName; var start = -1; var end = -1; for (var i = 0; i < header.length; i++) { const code = header.charCodeAt(i); if (extensionName === void 0) { if (end === -1 && tokenChars[code] === 1) { if (start === -1) start = i; } else if (code === 32 || code === 9) { if (end === -1 && start !== -1) end = i; } else if (code === 59 || code === 44) { if (start === -1) { throw new SyntaxError(`Unexpected character at index ${i}`); } if (end === -1) end = i; const name = header.slice(start, end); if (code === 44) { push(offers, name, params); params = {}; } else { extensionName = name; } start = end = -1; } else { throw new SyntaxError(`Unexpected character at index ${i}`); } } else if (paramName === void 0) { if (end === -1 && tokenChars[code] === 1) { if (start === -1) start = i; } else if (code === 32 || code === 9) { if (end === -1 && start !== -1) end = i; } else if (code === 59 || code === 44) { if (start === -1) { throw new SyntaxError(`Unexpected character at index ${i}`); } if (end === -1) end = i; push(params, header.slice(start, end), true); if (code === 44) { push(offers, extensionName, params); params = {}; extensionName = void 0; } start = end = -1; } else if (code === 61 && start !== -1 && end === -1) { paramName = header.slice(start, i); start = end = -1; } else { throw new SyntaxError(`Unexpected character at index ${i}`); } } else { if (isEscaping) { if (tokenChars[code] !== 1) { throw new SyntaxError(`Unexpected character at index ${i}`); } if (start === -1) start = i; else if (!mustUnescape) mustUnescape = true; isEscaping = false; } else if (inQuotes) { if (tokenChars[code] === 1) { if (start === -1) start = i; } else if (code === 34 && start !== -1) { inQuotes = false; end = i; } else if (code === 92) { isEscaping = true; } else { throw new SyntaxError(`Unexpected character at index ${i}`); } } else if (code === 34 && header.charCodeAt(i - 1) === 61) { inQuotes = true; } else if (end === -1 && tokenChars[code] === 1) { if (start === -1) start = i; } else if (start !== -1 && (code === 32 || code === 9)) { if (end === -1) end = i; } else if (code === 59 || code === 44) { if (start === -1) { throw new SyntaxError(`Unexpected character at index ${i}`); } if (end === -1) end = i; var value = header.slice(start, end); if (mustUnescape) { value = value.replace(/\\/g, ""); mustUnescape = false; } push(params, paramName, value); if (code === 44) { push(offers, extensionName, params); params = {}; extensionName = void 0; } paramName = void 0; start = end = -1; } else { throw new SyntaxError(`Unexpected character at index ${i}`); } } } if (start === -1 || inQuotes) { throw new SyntaxError("Unexpected end of input"); } if (end === -1) end = i; const token = header.slice(start, end); if (extensionName === void 0) { push(offers, token, {}); } else { if (paramName === void 0) { push(params, token, true); } else if (mustUnescape) { push(params, paramName, token.replace(/\\/g, "")); } else { push(params, paramName, token); } push(offers, extensionName, params); } return offers; } function format(extensions) { return Object.keys(extensions).map((extension) => { var configurations = extensions[extension]; if (!Array.isArray(configurations)) configurations = [configurations]; return configurations.map((params) => { return [extension].concat( Object.keys(params).map((k) => { var values = params[k]; if (!Array.isArray(values)) values = [values]; return values.map((v) => v === true ? k : `${k}=${v}`).join("; "); }) ).join("; "); }).join(", "); }).join(", "); } module.exports = { format, parse }; } }); // ../../node_modules/ws/lib/validation.js var require_validation = __commonJS({ "../../node_modules/ws/lib/validation.js"(exports) { try { const isValidUTF8 = __require("utf-8-validate"); exports.isValidUTF8 = typeof isValidUTF8 === "object" ? isValidUTF8.Validation.isValidUTF8 : isValidUTF8; } catch (e) { exports.isValidUTF8 = () => true; } exports.isValidStatusCode = (code) => { return code >= 1e3 && code <= 1013 && code !== 1004 && code !== 1005 && code !== 1006 || code >= 3e3 && code <= 4999; }; } }); // ../../node_modules/ws/lib/receiver.js var require_receiver = __commonJS({ "../../node_modules/ws/lib/receiver.js"(exports, module) { var { Writable } = __require("stream"); var PerMessageDeflate = require_permessage_deflate(); var { BINARY_TYPES, EMPTY_BUFFER, kStatusCode, kWebSocket } = require_constants(); var { concat, toArrayBuffer, unmask } = require_buffer_util(); var { isValidStatusCode, isValidUTF8 } = require_validation(); var GET_INFO = 0; var GET_PAYLOAD_LENGTH_16 = 1; var GET_PAYLOAD_LENGTH_64 = 2; var GET_MASK = 3; var GET_DATA = 4; var INFLATING = 5; var Receiver = class extends Writable { /** * Creates a Receiver instance. * * @param {String} binaryType The type for binary data * @param {Object} extensions An object containing the negotiated extensions * @param {Number} maxPayload The maximum allowed message length */ constructor(binaryType, extensions, maxPayload) { super(); this._binaryType = binaryType || BINARY_TYPES[0]; this[kWebSocket] = void 0; this._extensions = extensions || {}; this._maxPayload = maxPayload | 0; this._bufferedBytes = 0; this._buffers = []; this._compressed = false; this._payloadLength = 0; this._mask = void 0; this._fragmented = 0; this._masked = false; this._fin = false; this._opcode = 0; this._totalPayloadLength = 0; this._messageLength = 0; this._fragments = []; this._state = GET_INFO; this._loop = false; } /** * Implements `Writable.prototype._write()`. * * @param {Buffer} chunk The chunk of data to write * @param {String} encoding The character encoding of `chunk` * @param {Function} cb Callback */ _write(chunk, encoding, cb) { if (this._opcode === 8 && this._state == GET_INFO) return cb(); this._bufferedBytes += chunk.length; this._buffers.push(chunk); this.startLoop(cb); } /** * Consumes `n` bytes from the buffered data. * * @param {Number} n The number of bytes to consume * @return {Buffer} The consumed bytes * @private */ consume(n) { this._bufferedBytes -= n; if (n === this._buffers[0].length) return this._buffers.shift(); if (n < this._buffers[0].length) { const buf = this._buffers[0]; this._buffers[0] = buf.slice(n); return buf.slice(0, n); } const dst = Buffer.allocUnsafe(n); do { const buf = this._buffers[0]; if (n >= buf.length) { this._buffers.shift().copy(dst, dst.length - n); } else { buf.copy(dst, dst.length - n, 0, n); this._buffers[0] = buf.slice(n); } n -= buf.length; } while (n > 0); return dst; } /** * Starts the parsing loop. * * @param {Function} cb Callback * @private */ startLoop(cb) { var err; this._loop = true; do { switch (this._state) { case GET_INFO: err = this.getInfo(); break; case GET_PAYLOAD_LENGTH_16: err = this.getPayloadLength16(); break; case GET_PAYLOAD_LENGTH_64: err = this.getPayloadLength64(); break; case GET_MASK: this.getMask(); break; case GET_DATA: err = this.getData(cb); break; default: this._loop = false; return; } } while (this._loop); cb(err); } /** * Reads the first two bytes of a frame. * * @return {(RangeError|undefined)} A possible error * @private */ getInfo() { if (this._bufferedBytes < 2) { this._loop = false; return; } const buf = this.consume(2); if ((buf[0] & 48) !== 0) { this._loop = false; return error(RangeError, "RSV2 and RSV3 must be clear", true, 1002); } const compressed = (buf[0] & 64) === 64; if (compressed && !this._extensions[PerMessageDeflate.extensionName]) { this._loop = false; return error(RangeError, "RSV1 must be clear", true, 1002); } this._fin = (buf[0] & 128) === 128; this._opcode = buf[0] & 15; this._payloadLength = buf[1] & 127; if (this._opcode === 0) { if (compressed) { this._loop = false; return error(RangeError, "RSV1 must be clear", true, 1002); } if (!this._fragmented) { this._loop = false; return error(RangeError, "invalid opcode 0", true, 1002); } this._opcode = this._fragmented; } else if (this._opcode === 1 || this._opcode === 2) { if (this._fragmented) { this._loop = false; return error(RangeError, `invalid opcode ${this._opcode}`, true, 1002); } this._compressed = compressed; } else if (this._opcode > 7 && this._opcode < 11) { if (!this._fin) { this._loop = false; return error(RangeError, "FIN must be set", true, 1002); } if (compressed) { this._loop = false; return error(RangeError, "RSV1 must be clear", true, 1002); } if (this._payloadLength > 125) { this._loop = false; return error( RangeError, `invalid payload length ${this._payloadLength}`, true, 1002 ); } } else { this._loop = false; return error(RangeError, `invalid opcode ${this._opcode}`, true, 1002); } if (!this._fin && !this._fragmented) this._fragmented = this._opcode; this._masked = (buf[1] & 128) === 128; if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16; else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64; else return this.haveLength(); } /** * Gets extended payload length (7+16). * * @return {(RangeError|undefined)} A possible error * @private */ getPayloadLength16() { if (this._bufferedBytes < 2) { this._loop = false; return; } this._payloadLength = this.consume(2).readUInt16BE(0); return this.haveLength(); } /** * Gets extended payload length (7+64). * * @return {(RangeError|undefined)} A possible error * @private */ getPayloadLength64() { if (this._bufferedBytes < 8) { this._loop = false; return; } const buf = this.consume(8); const num = buf.readUInt32BE(0); if (num > Math.pow(2, 53 - 32) - 1) { this._loop = false; return error( RangeError, "Unsupported WebSocket frame: payload length > 2^53 - 1", false, 1009 ); } this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4); return this.haveLength(); } /** * Payload length has been read. * * @return {(RangeError|undefined)} A possible error * @private */ haveLength() { if (this._payloadLength && this._opcode < 8) { this._totalPayloadLength += this._payloadLength; if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) { this._loop = false; return error(RangeError, "Max payload size exceeded", false, 1009); } } if (this._masked) this._state = GET_MASK; else this._state = GET_DATA; } /** * Reads mask bytes. * * @private */ getMask() { if (this._bufferedBytes < 4) { this._loop = false; return; } this._mask = this.consume(4); this._state = GET_DATA; } /** * Reads data bytes. * * @param {Function} cb Callback * @return {(Error|RangeError|undefined)} A possible error * @private */ getData(cb) { var data = EMPTY_BUFFER; if (this._payloadLength) { if (this._bufferedBytes < this._payloadLength) { this._loop = false; return; } data = this.consume(this._payloadLength); if (this._masked) unmask(data, this._mask); } if (this._opcode > 7) return this.controlMessage(data); if (this._compressed) { this._state = INFLATING; this.decompress(data, cb); return; } if (data.length) { this._messageLength = this._totalPayloadLength; this._fragments.push(data); } return this.dataMessage(); } /** * Decompresses data. * * @param {Buffer} data Compressed data * @param {Function} cb Callback * @private */ decompress(data, cb) { const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; perMessageDeflate.decompress(data, this._fin, (err, buf) => { if (err) return cb(err); if (buf.length) { this._messageLength += buf.length; if (this._messageLength > this._maxPayload && this._maxPayload > 0) { return cb( error(RangeError, "Max payload size exceeded", false, 1009) ); } this._fragments.push(buf); } const er = this.dataMessage(); if (er) return cb(er); this.startLoop(cb); }); } /** * Handles a data message. * * @return {(Error|undefined)} A possible error * @private */ dataMessage() { if (this._fin) { const messageLength = this._messageLength; const fragments = this._fragments; this._totalPayloadLength = 0; this._messageLength = 0; this._fragmented = 0; this._fragments = []; if (this._opcode === 2) { var data; if (this._binaryType === "nodebuffer") { data = concat(fragments, messageLength); } else if (this._binaryType === "arraybuffer") { data = toArrayBuffer(concat(fragments, messageLength)); } else { data = fragments; } this.emit("message", data); } else { const buf = concat(fragments, messageLength); if (!isValidUTF8(buf)) { this._loop = false; return error(Error, "invalid UTF-8 sequence", true, 1007); } this.emit("message", buf.toString()); } } this._state = GET_INFO; } /** * Handles a control message. * * @param {Buffer} data Data to handle * @return {(Error|RangeError|undefined)} A possible error * @private */ controlMessage(data) { if (this._opcode === 8) { this._loop = false; if (data.length === 0) { this.emit("conclude", 1005, ""); this.end(); } else if (data.length === 1) { return error(RangeError, "invalid payload length 1", true, 1002); } else { const code = data.readUInt16BE(0); if (!isValidStatusCode(code)) { return error(RangeError, `invalid status code ${code}`, true, 1002); } const buf = data.slice(2); if (!isValidUTF8(buf)) { return error(Error, "invalid UTF-8 sequence", true, 1007); } this.emit("conclude", code, buf.toString()); this.end(); } } else if (this._opcode === 9) { this.emit("ping", data); } else { this.emit("pong", data); } this._state = GET_INFO; } }; module.exports = Receiver; function error(ErrorCtor, message, prefix, statusCode) { const err = new ErrorCtor( prefix ? `Invalid WebSocket frame: ${message}` : message ); Error.captureStackTrace(err, error); err[kStatusCode] = statusCode; return err; } } }); // ../../node_modules/ws/lib/sender.js var require_sender = __commonJS({ "../../node_modules/ws/lib/sender.js"(exports, module) { var { randomBytes } = __require("crypto"); var PerMessageDeflate = require_permessage_deflate(); var { EMPTY_BUFFER } = require_constants(); var { isValidStatusCode } = require_validation(); var { mask: applyMask, toBuffer } = require_buffer_util(); var Sender = class _Sender { /** * Creates a Sender instance. * * @param {net.Socket} socket The connection socket * @param {Object} extensions An object containing the negotiated extensions */ constructor(socket, extensions) { this._extensions = extensions || {}; this._socket = socket; this._firstFragment = true; this._compress = false; this._bufferedBytes = 0; this._deflating = false; this._queue = []; } /** * Frames a piece of data according to the HyBi WebSocket protocol. * * @param {Buffer} data The data to frame * @param {Object} options Options object * @param {Number} options.opcode The opcode * @param {Boolean} options.readOnly Specifies whether `data` can be modified * @param {Boolean} options.fin Specifies whether or not to set the FIN bit * @param {Boolean} options.mask Specifies whether or not to mask `data` * @param {Boolean} options.rsv1 Specifies whether or not to set the RSV1 bit * @return {Buffer[]} The framed data as a list of `Buffer` instances * @public */ static frame(data, options) { const merge = options.mask && options.readOnly; var offset = options.mask ? 6 : 2; var payloadLength = data.length; if (data.length >= 65536) { offset += 8; payloadLength = 127; } else if (data.length > 125) { offset += 2; payloadLength = 126; } const target = Buffer.allocUnsafe(merge ? data.length + offset : offset); target[0] = options.fin ? options.opcode | 128 : options.opcode; if (options.rsv1) target[0] |= 64; target[1] = payloadLength; if (payloadLength === 126) { target.writeUInt16BE(data.length, 2); } else if (payloadLength === 127) { target.writeUInt32BE(0, 2); target.writeUInt32BE(data.length, 6); } if (!options.mask) return [target, data]; const mask = randomBytes(4); target[1] |= 128; target[offset - 4] = mask[0]; target[offset - 3] = mask[1]; target[offset - 2] = mask[2]; target[offset - 1] = mask[3]; if (merge) { applyMask(data, mask, target, offset, data.length); return [target]; } applyMask(data, mask, data, 0, data.length); return [target, data]; } /** * Sends a close message to the other peer. * * @param {(Number|undefined)} code The status code component of the body * @param {String} data The message component of the body * @param {Boolean} mask Specifies whether or not to mask the message * @param {Function} cb Callback * @public */ close(code, data, mask, cb) { var buf; if (code === void 0) { buf = EMPTY_BUFFER; } else if (typeof code !== "number" || !isValidStatusCode(code)) { throw new TypeError("First argument must be a valid error code number"); } else if (data === void 0 || data === "") { buf = Buffer.allocUnsafe(2); buf.writeUInt16BE(code, 0); } else { buf = Buffer.allocUnsafe(2 + Buffer.byteLength(data)); buf.writeUInt16BE(code, 0); buf.write(data, 2); } if (this._deflating) { this.enqueue([this.doClose, buf, mask, cb]); } else { this.doClose(buf, mask, cb); } } /** * Frames and sends a close message. * * @param {Buffer} data The message to send * @param {Boolean} mask Specifies whether or not to mask `data` * @param {Function} cb Callback * @private */ doClose(data, mask, cb) { this.sendFrame( _Sender.frame(data, { fin: true, rsv1: false, opcode: 8, mask, readOnly: false }), cb ); } /** * Sends a ping message to the other peer. * * @param {*} data The message to send * @param {Boolean} mask Specifies whether or not to mask `data` * @param {Function} cb Callback * @public */ ping(data, mask, cb) { const buf = toBuffer(data); if (this._deflating) { this.enqueue([this.doPing, buf, mask, toBuffer.readOnly, cb]); } else { this.doPing(buf, mask, toBuffer.readOnly, cb); } } /** * Frames and sends a ping message. * * @param {*} data The message to send * @param {Boolean} mask Specifies whether or not to mask `data` * @param {Boolean} readOnly Specifies whether `data` can be modified * @param {Function} cb Callback * @private */ doPing(data, mask, readOnly, cb) { this.sendFrame( _Sender.frame(data, { fin: true, rsv1: false, opcode: 9, mask, readOnly }), cb ); } /** * Sends a pong message to the other peer. * * @param {*} data The message to send * @param {Boolean} mask Specifies whether or not to mask `data` * @param {Function} cb Callback * @public */ pong(data, mask, cb) { const buf = toBuffer(data); if (this._deflating) { this.enqueue([this.doPong, buf, mask, toBuffer.readOnly, cb]); } else { this.doPong(buf, mask, toBuffer.readOnly, cb); } } /** * Frames and sends a pong message. * * @param {*} data The message to send * @param {Boolean} mask Specifies whether or not to mask `data` * @param {Boolean} readOnly Specifies whether `data` can be modified * @param {Function} cb Callback * @private */ doPong(data, mask, readOnly, cb) { this.sendFrame( _Sender.frame(data, { fin: true, rsv1: false, opcode: 10, mask, readOnly }), cb ); } /** * Sends a data message to the other peer. * * @param {*} data The message to send * @param {Object} options Options object *