UNPKG

@adonisjs/websocket-client

Version:

Websocket client for AdonisJs

2,116 lines (1,802 loc) 58.8 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.adonis = global.adonis || {}, global.adonis.Ws = factory()); }(this, (function () { 'use strict'; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var asyncToGenerator = function (fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }; var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }; var possibleConstructorReturn = function (self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }; var toConsumableArray = function (arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }; var anyMap = new WeakMap(); var eventsMap = new WeakMap(); var resolvedPromise = Promise.resolve(); function assertEventName(eventName) { if (typeof eventName !== 'string') { throw new TypeError('eventName must be a string'); } } function assertListener(listener) { if (typeof listener !== 'function') { throw new TypeError('listener must be a function'); } } function getListeners(instance, eventName) { var events = eventsMap.get(instance); if (!events.has(eventName)) { events.set(eventName, new Set()); } return events.get(eventName); } var Emittery = function () { function Emittery() { classCallCheck(this, Emittery); anyMap.set(this, new Set()); eventsMap.set(this, new Map()); } createClass(Emittery, [{ key: 'on', value: function on(eventName, listener) { assertEventName(eventName); assertListener(listener); getListeners(this, eventName).add(listener); return this.off.bind(this, eventName, listener); } }, { key: 'off', value: function off(eventName, listener) { assertEventName(eventName); assertListener(listener); getListeners(this, eventName).delete(listener); } }, { key: 'once', value: function once(eventName) { var _this = this; return new Promise(function (resolve) { assertEventName(eventName); var off = _this.on(eventName, function (data) { off(); resolve(data); }); }); } }, { key: 'emit', value: function () { var _ref = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(eventName, eventData) { var _this2 = this; var listeners, anyListeners, staticListeners, staticAnyListeners; return regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: assertEventName(eventName); listeners = getListeners(this, eventName); anyListeners = anyMap.get(this); staticListeners = [].concat(toConsumableArray(listeners)); staticAnyListeners = [].concat(toConsumableArray(anyListeners)); _context3.next = 7; return resolvedPromise; case 7: return _context3.abrupt('return', Promise.all([].concat(toConsumableArray(staticListeners.map(function () { var _ref2 = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(listener) { return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: if (!listeners.has(listener)) { _context.next = 2; break; } return _context.abrupt('return', listener(eventData)); case 2: case 'end': return _context.stop(); } } }, _callee, _this2); })); return function (_x3) { return _ref2.apply(this, arguments); }; }())), toConsumableArray(staticAnyListeners.map(function () { var _ref3 = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(listener) { return regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: if (!anyListeners.has(listener)) { _context2.next = 2; break; } return _context2.abrupt('return', listener(eventName, eventData)); case 2: case 'end': return _context2.stop(); } } }, _callee2, _this2); })); return function (_x4) { return _ref3.apply(this, arguments); }; }()))))); case 8: case 'end': return _context3.stop(); } } }, _callee3, this); })); function emit(_x, _x2) { return _ref.apply(this, arguments); } return emit; }() }, { key: 'emitSerial', value: function () { var _ref4 = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4(eventName, eventData) { var listeners, anyListeners, staticListeners, staticAnyListeners, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, listener, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, _listener; return regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: assertEventName(eventName); listeners = getListeners(this, eventName); anyListeners = anyMap.get(this); staticListeners = [].concat(toConsumableArray(listeners)); staticAnyListeners = [].concat(toConsumableArray(anyListeners)); _context4.next = 7; return resolvedPromise; case 7: /* eslint-disable no-await-in-loop */ _iteratorNormalCompletion = true; _didIteratorError = false; _iteratorError = undefined; _context4.prev = 10; _iterator = staticListeners[Symbol.iterator](); case 12: if (_iteratorNormalCompletion = (_step = _iterator.next()).done) { _context4.next = 20; break; } listener = _step.value; if (!listeners.has(listener)) { _context4.next = 17; break; } _context4.next = 17; return listener(eventData); case 17: _iteratorNormalCompletion = true; _context4.next = 12; break; case 20: _context4.next = 26; break; case 22: _context4.prev = 22; _context4.t0 = _context4['catch'](10); _didIteratorError = true; _iteratorError = _context4.t0; case 26: _context4.prev = 26; _context4.prev = 27; if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } case 29: _context4.prev = 29; if (!_didIteratorError) { _context4.next = 32; break; } throw _iteratorError; case 32: return _context4.finish(29); case 33: return _context4.finish(26); case 34: _iteratorNormalCompletion2 = true; _didIteratorError2 = false; _iteratorError2 = undefined; _context4.prev = 37; _iterator2 = staticAnyListeners[Symbol.iterator](); case 39: if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) { _context4.next = 47; break; } _listener = _step2.value; if (!anyListeners.has(_listener)) { _context4.next = 44; break; } _context4.next = 44; return _listener(eventName, eventData); case 44: _iteratorNormalCompletion2 = true; _context4.next = 39; break; case 47: _context4.next = 53; break; case 49: _context4.prev = 49; _context4.t1 = _context4['catch'](37); _didIteratorError2 = true; _iteratorError2 = _context4.t1; case 53: _context4.prev = 53; _context4.prev = 54; if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } case 56: _context4.prev = 56; if (!_didIteratorError2) { _context4.next = 59; break; } throw _iteratorError2; case 59: return _context4.finish(56); case 60: return _context4.finish(53); case 61: case 'end': return _context4.stop(); } } }, _callee4, this, [[10, 22, 26, 34], [27,, 29, 33], [37, 49, 53, 61], [54,, 56, 60]]); })); function emitSerial(_x5, _x6) { return _ref4.apply(this, arguments); } return emitSerial; }() }, { key: 'onAny', value: function onAny(listener) { assertListener(listener); anyMap.get(this).add(listener); return this.offAny.bind(this, listener); } }, { key: 'offAny', value: function offAny(listener) { assertListener(listener); anyMap.get(this).delete(listener); } }, { key: 'clearListeners', value: function clearListeners(eventName) { if (typeof eventName === 'string') { getListeners(this, eventName).clear(); } else { anyMap.get(this).clear(); var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = eventsMap.get(this).values()[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var listeners = _step3.value; listeners.clear(); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } } } }, { key: 'listenerCount', value: function listenerCount(eventName) { if (typeof eventName === 'string') { return anyMap.get(this).size + getListeners(this, eventName).size; } if (typeof eventName !== 'undefined') { assertEventName(eventName); } var count = anyMap.get(this).size; var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = eventsMap.get(this).values()[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var value = _step4.value; count += value.size; } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } return count; } }]); return Emittery; }(); // Subclass used to encourage TS users to type their events. Emittery.Typed = function (_Emittery) { inherits(_class, _Emittery); function _class() { classCallCheck(this, _class); return possibleConstructorReturn(this, (_class.__proto__ || Object.getPrototypeOf(_class)).apply(this, arguments)); } return _class; }(Emittery); Object.defineProperty(Emittery.Typed, 'Typed', { enumerable: false, value: undefined }); var emittery = Emittery; var strictUriEncode = function strictUriEncode(str) { return encodeURIComponent(str).replace(/[!'()*]/g, function (x) { return '%' + x.charCodeAt(0).toString(16).toUpperCase(); }); }; function encoderForArrayFormat(options) { switch (options.arrayFormat) { case 'index': return function (key, value, index) { return value === null ? [encode(key, options), '[', index, ']'].join('') : [encode(key, options), '[', encode(index, options), ']=', encode(value, options)].join(''); }; case 'bracket': return function (key, value) { return value === null ? encode(key, options) : [encode(key, options), '[]=', encode(value, options)].join(''); }; default: return function (key, value) { return value === null ? encode(key, options) : [encode(key, options), '=', encode(value, options)].join(''); }; } } function encode(value, options) { if (options.encode) { return options.strict ? strictUriEncode(value) : encodeURIComponent(value); } return value; } var stringify = function stringify(obj, options) { var defaults$$1 = { encode: true, strict: true, arrayFormat: 'none' }; options = _extends(defaults$$1, options); if (options.sort === false) { options.sort = function () {}; } var formatter = encoderForArrayFormat(options); return obj ? Object.keys(obj).sort(options.sort).map(function (key) { var value = obj[key]; if (value === undefined) { return ''; } if (value === null) { return encode(key, options); } if (Array.isArray(value)) { var result = []; var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = value.slice()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var value2 = _step2.value; if (value2 === undefined) { continue; } result.push(formatter(key, value2, result.length)); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } return result.join('&'); } return encode(key, options) + '=' + encode(value, options); }).filter(function (x) { return x.length > 0; }).join('&') : ''; }; var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var wsp_browser = createCommonjsModule(function (module, exports) { !function (t, e) { module.exports = e(); }(commonjsGlobal, function () { var t = "function" == typeof Symbol && "symbol" == _typeof(Symbol.iterator) ? function (t) { return typeof t === 'undefined' ? 'undefined' : _typeof(t); } : function (t) { return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t === 'undefined' ? 'undefined' : _typeof(t); }, e = { OPEN: 0, JOIN: 1, LEAVE: 2, JOIN_ACK: 3, JOIN_ERROR: 4, LEAVE_ACK: 5, LEAVE_ERROR: 6, EVENT: 7, PING: 8, PONG: 9 };function o(t, e, o) { return o.forEach(function (t) { !function (t, e) { if (!t || "string" != typeof t) throw new Error(e); }(e[t], "expected " + t + " to be a valid string"); }), { t: t, d: e }; }var n = {};return Object.keys(e).forEach(function (o) { var i = o.toLowerCase().replace(/^\w|_(\w)/g, function (t, e) { return e ? e.toUpperCase() : t.toUpperCase(); });n["is" + i + "Packet"] = function (n) { return !(!n || "object" !== (void 0 === n ? "undefined" : t(n)) || n.t !== e[o]); }; }), n.hasTopic = function (t) { return !!(t && t.d && t.d.topic); }, n.isValidJoinPacket = n.hasTopic, n.isValidLeavePacket = n.hasTopic, n.isValidEventPacket = n.hasTopic, n.joinPacket = function (t) { return o(e.JOIN, { topic: t }, ["topic"]); }, n.leavePacket = function (t) { return o(e.LEAVE, { topic: t }, ["topic"]); }, n.joinAckPacket = function (t) { return o(e.JOIN_ACK, { topic: t }, ["topic"]); }, n.joinErrorPacket = function (t, n) { return o(e.JOIN_ERROR, { topic: t, message: n }, ["topic", "message"]); }, n.leaveAckPacket = function (t) { return o(e.LEAVE_ACK, { topic: t }, ["topic"]); }, n.leaveErrorPacket = function (t, n) { return o(e.LEAVE_ERROR, { topic: t, message: n }, ["topic", "message"]); }, n.eventPacket = function (t, n, i) { return o(e.EVENT, { topic: t, event: n, data: i = i || "" }, ["topic", "event"]); }, n.pingPacket = function () { return { t: e.PING }; }, n.pongPacket = function () { return { t: e.PONG }; }, _extends({ codes: e }, n); }); }); /** * Helpers. */ var s = 1000; var m = s * 60; var h = m * 60; var d = h * 24; var y = d * 365.25; /** * Parse or format the given `val`. * * Options: * * - `long` verbose formatting [false] * * @param {String|Number} val * @param {Object} [options] * @throws {Error} throw an error if val is not a non-empty string or a number * @return {String|Number} * @api public */ var ms = function ms(val, options) { options = options || {}; var type = typeof val === 'undefined' ? 'undefined' : _typeof(val); if (type === 'string' && val.length > 0) { return parse$1(val); } else if (type === 'number' && isNaN(val) === false) { return options.long ? fmtLong(val) : fmtShort(val); } throw new Error('val is not a non-empty string or a valid number. val=' + JSON.stringify(val)); }; /** * Parse the given `str` and return milliseconds. * * @param {String} str * @return {Number} * @api private */ function parse$1(str) { str = String(str); if (str.length > 100) { return; } var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str); if (!match) { return; } var n = parseFloat(match[1]); var type = (match[2] || 'ms').toLowerCase(); switch (type) { case 'years': case 'year': case 'yrs': case 'yr': case 'y': return n * y; case 'days': case 'day': case 'd': return n * d; case 'hours': case 'hour': case 'hrs': case 'hr': case 'h': return n * h; case 'minutes': case 'minute': case 'mins': case 'min': case 'm': return n * m; case 'seconds': case 'second': case 'secs': case 'sec': case 's': return n * s; case 'milliseconds': case 'millisecond': case 'msecs': case 'msec': case 'ms': return n; default: return undefined; } } /** * Short format for `ms`. * * @param {Number} ms * @return {String} * @api private */ function fmtShort(ms) { if (ms >= d) { return Math.round(ms / d) + 'd'; } if (ms >= h) { return Math.round(ms / h) + 'h'; } if (ms >= m) { return Math.round(ms / m) + 'm'; } if (ms >= s) { return Math.round(ms / s) + 's'; } return ms + 'ms'; } /** * Long format for `ms`. * * @param {Number} ms * @return {String} * @api private */ function fmtLong(ms) { return plural(ms, d, 'day') || plural(ms, h, 'hour') || plural(ms, m, 'minute') || plural(ms, s, 'second') || ms + ' ms'; } /** * Pluralization helper. */ function plural(ms, n, name) { if (ms < n) { return; } if (ms < n * 1.5) { return Math.floor(ms / n) + ' ' + name; } return Math.ceil(ms / n) + ' ' + name + 's'; } var debug = createCommonjsModule(function (module, exports) { /** * This is the common logic for both the Node.js and web browser * implementations of `debug()`. * * Expose `debug()` as the module. */ exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; exports.humanize = ms; /** * The currently active debug mode names, and names to skip. */ exports.names = []; exports.skips = []; /** * Map of special "%n" handling functions, for the debug "format" argument. * * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". */ exports.formatters = {}; /** * Previous log timestamp. */ var prevTime; /** * Select a color. * @param {String} namespace * @return {Number} * @api private */ function selectColor(namespace) { var hash = 0, i; for (i in namespace) { hash = (hash << 5) - hash + namespace.charCodeAt(i); hash |= 0; // Convert to 32bit integer } return exports.colors[Math.abs(hash) % exports.colors.length]; } /** * Create a debugger with the given `namespace`. * * @param {String} namespace * @return {Function} * @api public */ function createDebug(namespace) { function debug() { // disabled? if (!debug.enabled) return; var self = debug; // set `diff` timestamp var curr = +new Date(); var ms$$1 = curr - (prevTime || curr); self.diff = ms$$1; self.prev = prevTime; self.curr = curr; prevTime = curr; // turn the `arguments` into a proper Array var args = new Array(arguments.length); for (var i = 0; i < args.length; i++) { args[i] = arguments[i]; } args[0] = exports.coerce(args[0]); if ('string' !== typeof args[0]) { // anything else let's inspect with %O args.unshift('%O'); } // apply any `formatters` transformations var index = 0; args[0] = args[0].replace(/%([a-zA-Z%])/g, function (match, format) { // if we encounter an escaped % then don't increase the array index if (match === '%%') return match; index++; var formatter = exports.formatters[format]; if ('function' === typeof formatter) { var val = args[index]; match = formatter.call(self, val); // now we need to remove `args[index]` since it's inlined in the `format` args.splice(index, 1); index--; } return match; }); // apply env-specific formatting (colors, etc.) exports.formatArgs.call(self, args); var logFn = debug.log || exports.log || console.log.bind(console); logFn.apply(self, args); } debug.namespace = namespace; debug.enabled = exports.enabled(namespace); debug.useColors = exports.useColors(); debug.color = selectColor(namespace); // env-specific initialization logic for debug instances if ('function' === typeof exports.init) { exports.init(debug); } return debug; } /** * Enables a debug mode by namespaces. This can include modes * separated by a colon and wildcards. * * @param {String} namespaces * @api public */ function enable(namespaces) { exports.save(namespaces); exports.names = []; exports.skips = []; var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); var len = split.length; for (var i = 0; i < len; i++) { if (!split[i]) continue; // ignore empty strings namespaces = split[i].replace(/\*/g, '.*?'); if (namespaces[0] === '-') { exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); } else { exports.names.push(new RegExp('^' + namespaces + '$')); } } } /** * Disable debug output. * * @api public */ function disable() { exports.enable(''); } /** * Returns true if the given mode name is enabled, false otherwise. * * @param {String} name * @return {Boolean} * @api public */ function enabled(name) { var i, len; for (i = 0, len = exports.skips.length; i < len; i++) { if (exports.skips[i].test(name)) { return false; } } for (i = 0, len = exports.names.length; i < len; i++) { if (exports.names[i].test(name)) { return true; } } return false; } /** * Coerce `val`. * * @param {Mixed} val * @return {Mixed} * @api private */ function coerce(val) { if (val instanceof Error) return val.stack || val.message; return val; } }); var debug_1 = debug.coerce; var debug_2 = debug.disable; var debug_3 = debug.enable; var debug_4 = debug.enabled; var debug_5 = debug.humanize; var debug_6 = debug.names; var debug_7 = debug.skips; var debug_8 = debug.formatters; var browser = createCommonjsModule(function (module, exports) { /** * This is the web browser implementation of `debug()`. * * Expose `debug()` as the module. */ exports = module.exports = debug; exports.log = log; exports.formatArgs = formatArgs; exports.save = save; exports.load = load; exports.useColors = useColors; exports.storage = 'undefined' != typeof chrome && 'undefined' != typeof chrome.storage ? chrome.storage.local : localstorage(); /** * Colors. */ exports.colors = ['lightseagreen', 'forestgreen', 'goldenrod', 'dodgerblue', 'darkorchid', 'crimson']; /** * Currently only WebKit-based Web Inspectors, Firefox >= v31, * and the Firebug extension (any Firefox version) are known * to support "%c" CSS customizations. * * TODO: add a `localStorage` variable to explicitly enable/disable colors */ function useColors() { // NB: In an Electron preload script, document will be defined but not fully // initialized. Since we know we're in Chrome, we'll just detect this case // explicitly if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { return true; } // is webkit? http://stackoverflow.com/a/16459606/376773 // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 return typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance || // is firebug? http://stackoverflow.com/a/398120/376773 typeof window !== 'undefined' && window.console && (window.console.firebug || window.console.exception && window.console.table) || // is firefox >= v31? // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31 || // double check webkit in userAgent just in case we are in a worker typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/); } /** * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. */ exports.formatters.j = function (v) { try { return JSON.stringify(v); } catch (err) { return '[UnexpectedJSONParseError]: ' + err.message; } }; /** * Colorize log arguments if enabled. * * @api public */ function formatArgs(args) { var useColors = this.useColors; args[0] = (useColors ? '%c' : '') + this.namespace + (useColors ? ' %c' : ' ') + args[0] + (useColors ? '%c ' : ' ') + '+' + exports.humanize(this.diff); if (!useColors) return; var c = 'color: ' + this.color; args.splice(1, 0, c, 'color: inherit'); // the final "%c" is somewhat tricky, because there could be other // arguments passed either before or after the %c, so we need to // figure out the correct index to insert the CSS into var index = 0; var lastC = 0; args[0].replace(/%[a-zA-Z%]/g, function (match) { if ('%%' === match) return; index++; if ('%c' === match) { // we only are interested in the *last* %c // (the user may have provided their own) lastC = index; } }); args.splice(lastC, 0, c); } /** * Invokes `console.log()` when available. * No-op when `console.log` is not a "function". * * @api public */ function log() { // this hackery is required for IE8/9, where // the `console.log` function doesn't have 'apply' return 'object' === (typeof console === 'undefined' ? 'undefined' : _typeof(console)) && console.log && Function.prototype.apply.call(console.log, console, arguments); } /** * Save `namespaces`. * * @param {String} namespaces * @api private */ function save(namespaces) { try { if (null == namespaces) { exports.storage.removeItem('debug'); } else { exports.storage.debug = namespaces; } } catch (e) {} } /** * Load `namespaces`. * * @return {String} returns the previously persisted debug modes * @api private */ function load() { var r; try { r = exports.storage.debug; } catch (e) {} // If debug isn't set in LS, and we're in Electron, try to load $DEBUG if (!r && typeof process !== 'undefined' && 'env' in process) { r = process.env.DEBUG; } return r; } /** * Enable namespaces listed in `localStorage.debug` initially. */ exports.enable(load()); /** * Localstorage attempts to return the localstorage. * * This is necessary because safari throws * when a user disables cookies/localstorage * and you attempt to access it. * * @return {LocalStorage} * @api private */ function localstorage() { try { return window.localStorage; } catch (e) {} } }); var browser_1 = browser.log; var browser_2 = browser.formatArgs; var browser_3 = browser.save; var browser_4 = browser.load; var browser_5 = browser.useColors; var browser_6 = browser.storage; var browser_7 = browser.colors; var Debug = createCommonjsModule(function (module) { /* * adonis-websocket-client * * (c) Harminder Virk <virk@adonisjs.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ { var _Debug = browser; _Debug.enable('adonis:*'); module.exports = _Debug('adonis:websocket'); } }); /** * Socket class holds details for a single subscription. The instance * of this class can be used to exchange messages with the server * on a given topic. * * @class Socket */ var Socket = function () { function Socket(topic, connection) { classCallCheck(this, Socket); this.topic = topic; this.connection = connection; this.emitter = new emittery(); this._state = 'pending'; this._emitBuffer = []; } /** * Socket state * * @attribute state * * @return {String} */ createClass(Socket, [{ key: 'joinAck', /** * Called when subscription is confirmed by the * server * * @method joinAck * * @return {void} */ value: function joinAck() { var _this = this; this.state = 'open'; this.emitter.emit('ready', this); { Debug('clearing emit buffer for %s topic after subscription ack', this.topic); } /** * Process queued events */ this._emitBuffer.forEach(function (buf) { return _this.emit(buf.event, buf.data); }); this._emitBuffer = []; } /** * Called when subscription is rejected by the server * * @method joinError * * @param {Object} packet * * @return {void} */ }, { key: 'joinError', value: function joinError(packet) { this.state = 'error'; this.emitter.emit('error', packet); this.serverClose(); } /** * Called when subscription close is acknowledged * by the server * * @method leaveAck * * @return {void} */ }, { key: 'leaveAck', value: function leaveAck() { this.state = 'closed'; this.serverClose(); } /** * This method is invoked, when server rejects to close * the subscription. The state of the socket should not * change here * * @method leaveError * * @param {Object} packet * * @return {void} */ }, { key: 'leaveError', value: function leaveError(packet) { this.emitter.emit('leaveError', packet); } /* istanbul-ignore */ /** * Add an event listener * * @method on */ }, { key: 'on', value: function on() { var _emitter; (_emitter = this.emitter).on.apply(_emitter, arguments); } /* istanbul-ignore */ /** * Add an event listener for once only * * @method once */ }, { key: 'once', value: function once() { var _emitter2; (_emitter2 = this.emitter).once.apply(_emitter2, arguments); } /* istanbul-ignore */ /** * Remove event listener(s) * * @method off */ }, { key: 'off', value: function off() { var _emitter3; (_emitter3 = this.emitter).off.apply(_emitter3, arguments); } /** * Emit message on the subscription * * @method emit * * @param {String} event * @param {Mixed} data * * @return {void} */ }, { key: 'emit', value: function emit(event, data) { if (this.state === 'pending') { this._emitBuffer.push({ event: event, data: data }); return; } this.connection.sendEvent(this.topic, event, data); } /** * Closes the connection and removes all existing * listeners * * @method serverClose * * @return {Promise} */ }, { key: 'serverClose', value: function serverClose() { var _this2 = this; return this.emitter.emit('close', this).then(function () { _this2._emitBuffer = []; _this2.emitter.clearListeners(); }).catch(function () { _this2._emitBuffer = []; _this2.emitter.clearListeners(); }); } /** * Invoked when a new event is received from the server * * @method serverEvent * * @param {String} options.event * @param {Mixed} options.data * * @return {void} */ }, { key: 'serverEvent', value: function serverEvent(_ref) { var event = _ref.event, data = _ref.data; this.emitter.emit(event, data); } /** * Received error on connection * * @method serverError * * @return {void} */ }, { key: 'serverError', value: function serverError() { this.state = 'error'; } /** * Sends the request on server to close the subscription, we * have to wait for acknowledgment too * * @method close * * @return {void} */ }, { key: 'close', value: function close() { this.state = 'closing'; { Debug('closing subscription for %s topic with server', this.topic); } this.connection.sendPacket(wsp_browser.leavePacket(this.topic)); } /** * Forcefully terminating the subscription * * @method terminate * * @return {void} */ }, { key: 'terminate', value: function terminate() { this.leaveAck(); } }, { key: 'state', get: function get$$1() { return this._state; } /** * Update socket state */ , set: function set$$1(state) { if (!this.constructor.states.indexOf(state) === -1) { throw new Error(state + ' is not a valid socket state'); } this._state = state; } /** * A static array of internal states * * @method states * * @return {Array} */ }], [{ key: 'states', get: function get$$1() { return ['pending', 'open', 'closed', 'closing', 'error']; } }]); return Socket; }(); /** * adonis-websocket-client * * (c) Harminder Virk <virk@adonisjs.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * The default encoder to encode packets. */ var JsonEncoder = { name: 'json', /** * Encode a value by stringifying it * * @method encode * * @param {Object} payload * @param {Function} callback * * @return {void} */ encode: function encode(payload, callback) { var encoded = null; try { encoded = JSON.stringify(payload); } catch (error) { return callback(error); } callback(null, encoded); }, /** * Decode value by parsing it * * @method decode * * @param {String} payload * @param {Function} callback * * @return {void} */ decode: function decode(payload, callback) { var decoded = null; try { decoded = JSON.parse(payload); } catch (error) { return callback(error); } callback(null, decoded); } }; /** * Returns the ws protocol based upon HTTP or HTTPS * * @returns {String} * */ var wsProtocol = window.location.protocol === 'https:' ? 'wss' : 'ws'; /** * Connection class is used to make a TCP/Socket connection * with the server. It relies on Native Websocket browser * support. * * @class Connection * * @param {String} url * @param {Object} options */ var Connection = function (_Emitter) { inherits(Connection, _Emitter); function Connection(url, options) { classCallCheck(this, Connection); var _this = possibleConstructorReturn(this, (Connection.__proto__ || Object.getPrototypeOf(Connection)).call(this)); url = url || wsProtocol + '://' + window.location.host; /** * Connection options * * @type {Object} */ _this.options = _extends({ path: 'adonis-ws', reconnection: true, reconnectionAttempts: 10, reconnectionDelay: 1000, query: null, encoder: JsonEncoder }, options); { Debug('connection options %o', _this.options); } /** * The state connection is in * * @type {String} */ _this._connectionState = 'idle'; /** * Number of reconnection attempts being made * * @type {Number} */ _this._reconnectionAttempts = 0; /** * All packets are sent in sequence to the server. So we need to * maintain a queue and process one at a time * * @type {Array} */ _this._packetsQueue = []; /** * Whether or not the queue is in process * * @type {Boolean} */ _this._processingQueue = false; /** * As per Adonis protocol, the client must ping * the server after x interval * * @type {Timer} */ _this._pingTimer = null; /** * Extended query is merged with the query params * user pass * * @type {Object} */ _this._extendedQuery = {}; /** * Base URL for the websocket connection * * @type {String} */ _this._url = url.replace(/\/$/, '') + '/' + _this.options.path; /** * Subscriptions for a single connection * * @type {Object} */ _this.subscriptions = {}; /** * Handler called when `close` is emitted from the * subscription */ _this.removeSubscription = function (_ref) { var topic = _ref.topic; delete _this.subscriptions[topic]; }; return _this; } /** * Computed value to decide, whether or not to reconnect * * @method shouldReconnect * * @return {Boolean} */ createClass(Connection, [{ key: '_cleanup', /** * Clean references * * @method _cleanup * * @return {void} * * @private */ value: function _cleanup() { clearInterval(this._pingTimer); this.ws = null; this._pingTimer = null; } /** * Calls a callback passing subscription to it * * @method _subscriptionsIterator * * @param {Function} callback * * @return {void} * * @private */ }, { key: '_subscriptionsIterator', value: function _subscriptionsIterator(callback) { var _this2 = this; Object.keys(this.subscriptions).forEach(function (sub) { return callback(_this2.subscriptions[sub], sub); }); } /** * Calls the callback when there is a subscription for * the topic mentioned in the packet * * @method _ensureSubscription * * @param {Object} packet * @param {Function} cb * * @return {void} * * @private */ }, { key: '_ensureSubscription', value: function _ensureSubscription(packet, cb) { var socket = this.getSubscription(packet.d.topic); if (!socket) { { Debug('cannot consume packet since %s topic has no active subscription %j', packet.d.topic, packet); } return; } cb(socket, packet); } /** * Process the packets queue by sending one packet at a time * * @method _processQueue * * @return {void} * * @private */ }, { key: '_processQueue', value: function _processQueue() { var _this3 = this; if (this._processingQueue || !this._packetsQueue.length) { return; } /** * Turn on the processing flag * * @type {Boolean} */ this._processingQueue = true; this.options.encoder.encode(this._packetsQueue.shift(), function (error, payload) { if (error) { { Debug('encode error %j', error); } return; } _this3.write(payload); /** * Turn off the processing flag and re call the processQueue to send * the next message * * @type {Boolean} */ _this3._processingQueue = false; _this3._processQueue(); }); } /** * As soon as connection is ready, we start listening * for new message * * @method _onOpen * * @return {void} * * @private */ }, { key: '_onOpen', value: function _onOpen() { { Debug('opened'); } } /** * When received connection error * * @method _onError * * @param {Event} event * * @return {void} * * @private */ }, { key: '_onError', value: function _onError(event) { { Debug('error %O', event); } this._subscriptionsIterator(function (subscription) { return subscription.serverError(); }); this.emit('error', event); } /** * Initiates reconnect with the server by moving * all subscriptions to pending state * * @method _reconnect * * @return {void} * * @private */ }, { key: '_reconnect', value: function _reconnect() { var _this4 = this; this._reconnectionAttempts++; this.emit('reconnect', this._reconnectionAttempts); setTimeout(function () { _this4._connectionState = 'reconnect'; _this4.connect(); }, this.options.reconnectionDelay * this._reconnectionAttempts); } /** * When connection closes * * @method _onClose * * @param {Event} event * * @return {void} * * @private */ }, { key: '_onClose', value: function _onClose(event) { var _this5 = this; { Debug('closing from %s state', this._connectionState); } this._cleanup(); /** * Force subscriptions to terminate */ this._subscriptionsIterator(function (subscription) { return subscription.terminate(); }); this.emit('close', this).then(function () { _this5.shouldReconnect ? _this5._reconnect() : _this5.clearListeners(); }).catch(function () { _this5.shouldReconnect ? _this5._reconnect() : _this5.clearListeners(); }); } /** * When a new message was received * * @method _onMessage * * @param {Event} event * * @return {void} * * @private */ }, { key: '_onMessage', value: function _onMessage(event) { var _this6 = this; this.options.encoder.decode(event.data, function (decodeError, packet) { if (decodeError) { { Debug('packet dropped, decode error %o', decodeError); } return; } _this6._handleMessage(packet); }); } /** * Handles the message packet based upon it's type * * @method _handleMessage * * @param {Object} packet * * @return {void} * * @private */ }, { key: '_handleMessage', value: function _handleMessage(packet) { if (wsp_browser.isOpenPacket(packet)) { { Debug('open packet'); } this._handleOpen(packet); return; } if (wsp_browser.isJoinAckPacket(packet)) { { Debug('join ack packet'); } this._handleJoinAck(packet); return; } if (wsp_browser.isJoinErrorPacket(packet)) { { Debug('join error packet'); } this._handleJoinError(packet); return; } if (wsp_browser.isLeaveAckPacket(packet)) { { Debug('leave ack packet'); } this._handleLeaveAck(packet); return; } if (wsp_browser.isLeaveErrorPacket(packet)) { { Debug('leave error packet'); } this._handleLeaveError(packet); return; } if (wsp_browser.isLeavePacket(packet)) { { Debug('leave packet'); } this._handleServerLeave(packet); return; } if (wsp_browser.isEventPacket(packet)) { { Debug('event packet'); } this._handleEvent(packet); return; } if (wsp_browser.isPongPacket(packet)) { { Debug('pong packet'); } return; } { Debug('invalid packet type %d', packet.t); } } /** * Emits the open emit and send subscription packets * for pre-existing subscriptions * * @method _handleOpen * * @param {Object} packet * * @return {void} * * @private */ }, { key: '_handleOpen', value: function _handleOpen(packet) { var _this7 = this; this._connectionState = 'open'; this.emit('open', packet.d); /** * Setup a timer to ping the server, telling * client is awake */ this._pingTimer = setInterval(function () { _this7.sendPacket(wsp_browser.pingPacket()); }, packet.d.clientInterval); /** * Sending packets to make pending subscriptions */ { Debug('processing pre connection subscriptions %o', Object.keys(this.subscriptions)); } this._subscriptionsIterator(function (subscription) { _this7._sendSubscriptionPacket(subscription.topic); }); } /** * Handles the join acknowledgement for a subscription * * @method _handleJoinAck * * @param {Object} packet * * @return {void} * * @private */ }, { key: '_handleJoinAck', value: function _handleJoinAck(packet) { this._ensureSubscription(packet, function (socket) { return socket.joinAck(); }); } /** * Handles the join error for a subscription * * @method _handleJoinError *