(function UMDish(name, context, definition, plugins) { context[name] = definition.call(context); for (var i = 0; i < plugins.length; i++) { plugins[i](context[name]) } if (typeof module !== "undefined" && module.exports) { module.exports = context[name]; } else if (typeof define === "function" && define.amd) { define(function reference() { return context[name]; }); } })("Primus", this || {}, function wrapper() { var define, module, exports , Primus = (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 10000 || !(match = regex.exec(ms))) return 0; amount = parseFloat(match[1]); switch (match[2].toLowerCase()) { case 'years': case 'year': case 'yrs': case 'yr': case 'y': return amount * year; case 'weeks': case 'week': case 'wks': case 'wk': case 'w': return amount * week; case 'days': case 'day': case 'd': return amount * day; case 'hours': case 'hour': case 'hrs': case 'hr': case 'h': return amount * hour; case 'minutes': case 'minute': case 'mins': case 'min': case 'm': return amount * minute; case 'seconds': case 'second': case 'secs': case 'sec': case 's': return amount * second; default: return amount; } }; },{}],6:[function(_dereq_,module,exports){ 'use strict'; /** * Wrap callbacks to prevent double execution. * * @param {Function} fn Function that should only be called once. * @returns {Function} A wrapped callback which prevents execution. * @api public */ module.exports = function one(fn) { var called = 0 , value; /** * The function that prevents double execution. * * @api private */ function onetime() { if (called) return value; called = 1; value = fn.apply(this, arguments); fn = null; return value; } // // To make debugging more easy we want to use the name of the supplied // function. So when you look at the functions that are assigned to event // listeners you don't see a load of `onetime` functions but actually the // names of the functions that this module will call. // onetime.displayName = fn.displayName || fn.name || onetime.displayName || onetime.name; return onetime; }; },{}],7:[function(_dereq_,module,exports){ // shim for using process in browser var process = module.exports = {}; // cached from whatever global is present so that test runners that stub it // don't break things. But we need to wrap it in a try catch in case it is // wrapped in strict mode code which doesn't define any globals. It's inside a // function because try/catches deoptimize in certain engines. var cachedSetTimeout; var cachedClearTimeout; function defaultSetTimout() { throw new Error('setTimeout has not been defined'); } function defaultClearTimeout () { throw new Error('clearTimeout has not been defined'); } (function () { try { if (typeof setTimeout === 'function') { cachedSetTimeout = setTimeout; } else { cachedSetTimeout = defaultSetTimout; } } catch (e) { cachedSetTimeout = defaultSetTimout; } try { if (typeof clearTimeout === 'function') { cachedClearTimeout = clearTimeout; } else { cachedClearTimeout = defaultClearTimeout; } } catch (e) { cachedClearTimeout = defaultClearTimeout; } } ()) function runTimeout(fun) { if (cachedSetTimeout === setTimeout) { //normal enviroments in sane situations return setTimeout(fun, 0); } // if setTimeout wasn't available but was latter defined if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { cachedSetTimeout = setTimeout; return setTimeout(fun, 0); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedSetTimeout(fun, 0); } catch(e){ try { // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally return cachedSetTimeout.call(null, fun, 0); } catch(e){ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error return cachedSetTimeout.call(this, fun, 0); } } } function runClearTimeout(marker) { if (cachedClearTimeout === clearTimeout) { //normal enviroments in sane situations return clearTimeout(marker); } // if clearTimeout wasn't available but was latter defined if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { cachedClearTimeout = clearTimeout; return clearTimeout(marker); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedClearTimeout(marker); } catch (e){ try { // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally return cachedClearTimeout.call(null, marker); } catch (e){ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. // Some versions of I.E. have different rules for clearTimeout vs setTimeout return cachedClearTimeout.call(this, marker); } } } var queue = []; var draining = false; var currentQueue; var queueIndex = -1; function cleanUpNextTick() { if (!draining || !currentQueue) { return; } draining = false; if (currentQueue.length) { queue = currentQueue.concat(queue); } else { queueIndex = -1; } if (queue.length) { drainQueue(); } } function drainQueue() { if (draining) { return; } var timeout = runTimeout(cleanUpNextTick); draining = true; var len = queue.length; while(len) { currentQueue = queue; queue = []; while (++queueIndex < len) { if (currentQueue) { currentQueue[queueIndex].run(); } } queueIndex = -1; len = queue.length; } currentQueue = null; draining = false; runClearTimeout(timeout); } process.nextTick = function (fun) { var args = new Array(arguments.length - 1); if (arguments.length > 1) { for (var i = 1; i < arguments.length; i++) { args[i - 1] = arguments[i]; } } queue.push(new Item(fun, args)); if (queue.length === 1 && !draining) { runTimeout(drainQueue); } }; // v8 likes predictible objects function Item(fun, array) { this.fun = fun; this.array = array; } Item.prototype.run = function () { this.fun.apply(null, this.array); }; process.title = 'browser'; process.browser = true; process.env = {}; process.argv = []; process.version = ''; // empty string to avoid regexp issues process.versions = {}; function noop() {} process.on = noop; process.addListener = noop; process.once = noop; process.off = noop; process.removeListener = noop; process.removeAllListeners = noop; process.emit = noop; process.prependListener = noop; process.prependOnceListener = noop; process.listeners = function (name) { return [] } process.binding = function (name) { throw new Error('process.binding is not supported'); }; process.cwd = function () { return '/' }; process.chdir = function (dir) { throw new Error('process.chdir is not supported'); }; process.umask = function() { return 0; }; },{}],8:[function(_dereq_,module,exports){ 'use strict'; var has = Object.prototype.hasOwnProperty , undef; /** * Decode a URI encoded string. * * @param {String} input The URI encoded string. * @returns {String|Null} The decoded string. * @api private */ function decode(input) { try { return decodeURIComponent(input.replace(/\+/g, ' ')); } catch (e) { return null; } } /** * Attempts to encode a given input. * * @param {String} input The string that needs to be encoded. * @returns {String|Null} The encoded string. * @api private */ function encode(input) { try { return encodeURIComponent(input); } catch (e) { return null; } } /** * Simple query string parser. * * @param {String} query The query string that needs to be parsed. * @returns {Object} * @api public */ function querystring(query) { var parser = /([^=?#&]+)=?([^&]*)/g , result = {} , part; while (part = parser.exec(query)) { var key = decode(part[1]) , value = decode(part[2]); // // Prevent overriding of existing properties. This ensures that build-in // methods like `toString` or __proto__ are not overriden by malicious // querystrings. // // In the case if failed decoding, we want to omit the key/value pairs // from the result. // if (key === null || value === null || key in result) continue; result[key] = value; } return result; } /** * Transform a query string to an object. * * @param {Object} obj Object that should be transformed. * @param {String} prefix Optional prefix. * @returns {String} * @api public */ function querystringify(obj, prefix) { prefix = prefix || ''; var pairs = [] , value , key; // // Optionally prefix with a '?' if needed // if ('string' !== typeof prefix) prefix = '?'; for (key in obj) { if (has.call(obj, key)) { value = obj[key]; // // Edge cases where we actually want to encode the value to an empty // string instead of the stringified value. // if (!value && (value === null || value === undef || isNaN(value))) { value = ''; } key = encode(key); value = encode(value); // // If we failed to encode the strings, we should bail out as we don't // want to add invalid strings to the query. // if (key === null || value === null) continue; pairs.push(key +'='+ value); } } return pairs.length ? prefix + pairs.join('&') : ''; } // // Expose the module. // exports.stringify = querystringify; exports.parse = querystring; },{}],9:[function(_dereq_,module,exports){ 'use strict'; var EventEmitter = _dereq_('eventemitter3') , millisecond = _dereq_('millisecond') , destroy = _dereq_('demolish') , Tick = _dereq_('tick-tock') , one = _dereq_('one-time'); /** * Returns sane defaults about a given value. * * @param {String} name Name of property we want. * @param {Recovery} selfie Recovery instance that got created. * @param {Object} opts User supplied options we want to check. * @returns {Number} Some default value. * @api private */ function defaults(name, selfie, opts) { return millisecond( name in opts ? opts[name] : (name in selfie ? selfie[name] : Recovery[name]) ); } /** * Attempt to recover your connection with reconnection attempt. * * @constructor * @param {Object} options Configuration * @api public */ function Recovery(options) { var recovery = this; if (!(recovery instanceof Recovery)) return new Recovery(options); options = options || {}; recovery.attempt = null; // Stores the current reconnect attempt. recovery._fn = null; // Stores the callback. recovery['reconnect timeout'] = defaults('reconnect timeout', recovery, options); recovery.retries = defaults('retries', recovery, options); recovery.factor = defaults('factor', recovery, options); recovery.max = defaults('max', recovery, options); recovery.min = defaults('min', recovery, options); recovery.timers = new Tick(recovery); } Recovery.prototype = new EventEmitter(); Recovery.prototype.constructor = Recovery; Recovery['reconnect timeout'] = '30 seconds'; // Maximum time to wait for an answer. Recovery.max = Infinity; // Maximum delay. Recovery.min = '500 ms'; // Minimum delay. Recovery.retries = 10; // Maximum amount of retries. Recovery.factor = 2; // Exponential back off factor. /** * Start a new reconnect procedure. * * @returns {Recovery} * @api public */ Recovery.prototype.reconnect = function reconnect() { var recovery = this; return recovery.backoff(function backedoff(err, opts) { opts.duration = (+new Date()) - opts.start; if (err) return recovery.emit('reconnect failed', err, opts); recovery.emit('reconnected', opts); }, recovery.attempt); }; /** * Exponential back off algorithm for retry operations. It uses a randomized * retry so we don't DDOS our server when it goes down under pressure. * * @param {Function} fn Callback to be called after the timeout. * @param {Object} opts Options for configuring the timeout. * @returns {Recovery} * @api private */ Recovery.prototype.backoff = function backoff(fn, opts) { var recovery = this; opts = opts || recovery.attempt || {}; // // Bailout when we already have a back off process running. We shouldn't call // the callback then. // if (opts.backoff) return recovery; opts['reconnect timeout'] = defaults('reconnect timeout', recovery, opts); opts.retries = defaults('retries', recovery, opts); opts.factor = defaults('factor', recovery, opts); opts.max = defaults('max', recovery, opts); opts.min = defaults('min', recovery, opts); opts.start = +opts.start || +new Date(); opts.duration = +opts.duration || 0; opts.attempt = +opts.attempt || 0; // // Bailout if we are about to make too much attempts. // if (opts.attempt === opts.retries) { fn.call(recovery, new Error('Unable to recover'), opts); return recovery; } // // Prevent duplicate back off attempts using the same options object and // increment our attempt as we're about to have another go at this thing. // opts.backoff = true; opts.attempt++; recovery.attempt = opts; // // Calculate the timeout, but make it randomly so we don't retry connections // at the same interval and defeat the purpose. This exponential back off is // based on the work of: // // http://dthain.blogspot.nl/2009/02/exponential-backoff-in-distributed.html // opts.scheduled = opts.attempt !== 1 ? Math.min(Math.round( (Math.random() + 1) * opts.min * Math.pow(opts.factor, opts.attempt - 1) ), opts.max) : opts.min; recovery.timers.setTimeout('reconnect', function delay() { opts.duration = (+new Date()) - opts.start; opts.backoff = false; recovery.timers.clear('reconnect, timeout'); // // Create a `one` function which can only be called once. So we can use the // same function for different types of invocations to create a much better // and usable API. // var connect = recovery._fn = one(function connect(err) { recovery.reset(); if (err) return recovery.backoff(fn, opts); fn.call(recovery, undefined, opts); }); recovery.emit('reconnect', opts, connect); recovery.timers.setTimeout('timeout', function timeout() { var err = new Error('Failed to reconnect in a timely manner'); opts.duration = (+new Date()) - opts.start; recovery.emit('reconnect timeout', err, opts); connect(err); }, opts['reconnect timeout']); }, opts.scheduled); // // Emit a `reconnecting` event with current reconnect options. This allows // them to update the UI and provide their users with feedback. // recovery.emit('reconnect scheduled', opts); return recovery; }; /** * Check if the reconnection process is currently reconnecting. * * @returns {Boolean} * @api public */ Recovery.prototype.reconnecting = function reconnecting() { return !!this.attempt; }; /** * Tell our reconnection procedure that we're passed. * * @param {Error} err Reconnection failed. * @returns {Recovery} * @api public */ Recovery.prototype.reconnected = function reconnected(err) { if (this._fn) this._fn(err); return this; }; /** * Reset the reconnection attempt so it can be re-used again. * * @returns {Recovery} * @api public */ Recovery.prototype.reset = function reset() { this._fn = this.attempt = null; this.timers.clear('reconnect, timeout'); return this; }; /** * Clean up the instance. * * @type {Function} * @returns {Boolean} * @api public */ Recovery.prototype.destroy = destroy('timers attempt _fn'); // // Expose the module. // module.exports = Recovery; },{"demolish":1,"eventemitter3":10,"millisecond":5,"one-time":6,"tick-tock":12}],10:[function(_dereq_,module,exports){ 'use strict'; // // We store our EE objects in a plain object whose properties are event names. // If `Object.create(null)` is not supported we prefix the event names with a // `~` to make sure that the built-in object properties are not overridden or // used as an attack vector. // We also assume that `Object.create(null)` is available when the event name // is an ES6 Symbol. // var prefix = typeof Object.create !== 'function' ? '~' : false; /** * Representation of a single EventEmitter function. * * @param {Function} fn Event handler to be called. * @param {Mixed} context Context for function execution. * @param {Boolean} once Only emit once * @api private */ function EE(fn, context, once) { this.fn = fn; this.context = context; this.once = once || false; } /** * Minimal EventEmitter interface that is molded against the Node.js * EventEmitter interface. * * @constructor * @api public */ function EventEmitter() { /* Nothing to set */ } /** * Holds the assigned EventEmitters by name. * * @type {Object} * @private */ EventEmitter.prototype._events = undefined; /** * Return a list of assigned event listeners. * * @param {String} event The events that should be listed. * @param {Boolean} exists We only need to know if there are listeners. * @returns {Array|Boolean} * @api public */ EventEmitter.prototype.listeners = function listeners(event, exists) { var evt = prefix ? prefix + event : event , available = this._events && this._events[evt]; if (exists) return !!available; if (!available) return []; if (available.fn) return [available.fn]; for (var i = 0, l = available.length, ee = new Array(l); i < l; i++) { ee[i] = available[i].fn; } return ee; }; /** * Emit an event to all registered event listeners. * * @param {String} event The name of the event. * @returns {Boolean} Indication if we've emitted an event. * @api public */ EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) { var evt = prefix ? prefix + event : event; if (!this._events || !this._events[evt]) return false; var listeners = this._events[evt] , len = arguments.length , args , i; if ('function' === typeof listeners.fn) { if (listeners.once) this.removeListener(event, listeners.fn, undefined, true); switch (len) { case 1: return listeners.fn.call(listeners.context), true; case 2: return listeners.fn.call(listeners.context, a1), true; case 3: return listeners.fn.call(listeners.context, a1, a2), true; case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true; case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true; case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true; } for (i = 1, args = new Array(len -1); i < len; i++) { args[i - 1] = arguments[i]; } listeners.fn.apply(listeners.context, args); } else { var length = listeners.length , j; for (i = 0; i < length; i++) { if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true); switch (len) { case 1: listeners[i].fn.call(listeners[i].context); break; case 2: listeners[i].fn.call(listeners[i].context, a1); break; case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break; default: if (!args) for (j = 1, args = new Array(len -1); j < len; j++) { args[j - 1] = arguments[j]; } listeners[i].fn.apply(listeners[i].context, args); } } } return true; }; /** * Register a new EventListener for the given event. * * @param {String} event Name of the event. * @param {Functon} fn Callback function. * @param {Mixed} context The context of the function. * @api public */ EventEmitter.prototype.on = function on(event, fn, context) { var listener = new EE(fn, context || this) , evt = prefix ? prefix + event : event; if (!this._events) this._events = prefix ? {} : Object.create(null); if (!this._events[evt]) this._events[evt] = listener; else { if (!this._events[evt].fn) this._events[evt].push(listener); else this._events[evt] = [ this._events[evt], listener ]; } return this; }; /** * Add an EventListener that's only called once. * * @param {String} event Name of the event. * @param {Function} fn Callback function. * @param {Mixed} context The context of the function. * @api public */ EventEmitter.prototype.once = function once(event, fn, context) { var listener = new EE(fn, context || this, true) , evt = prefix ? prefix + event : event; if (!this._events) this._events = prefix ? {} : Object.create(null); if (!this._events[evt]) this._events[evt] = listener; else { if (!this._events[evt].fn) this._events[evt].push(listener); else this._events[evt] = [ this._events[evt], listener ]; } return this; }; /** * Remove event listeners. * * @param {String} event The event we want to remove. * @param {Function} fn The listener that we need to find. * @param {Mixed} context Only remove listeners matching this context. * @param {Boolean} once Only remove once listeners. * @api public */ EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) { var evt = prefix ? prefix + event : event; if (!this._events || !this._events[evt]) return this; var listeners = this._events[evt] , events = []; if (fn) { if (listeners.fn) { if ( listeners.fn !== fn || (once && !listeners.once) || (context && listeners.context !== context) ) { events.push(listeners); } } else { for (var i = 0, length = listeners.length; i < length; i++) { if ( listeners[i].fn !== fn || (once && !listeners[i].once) || (context && listeners[i].context !== context) ) { events.push(listeners[i]); } } } } // // Reset the array, or remove it completely if we have no more listeners. // if (events.length) { this._events[evt] = events.length === 1 ? events[0] : events; } else { delete this._events[evt]; } return this; }; /** * Remove all listeners or only the listeners for the specified event. * * @param {String} event The event want to remove all listeners for. * @api public */ EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) { if (!this._events) return this; if (event) delete this._events[prefix ? prefix + event : event]; else this._events = prefix ? {} : Object.create(null); return this; }; // // Alias methods names because people roll like that. // EventEmitter.prototype.off = EventEmitter.prototype.removeListener; EventEmitter.prototype.addListener = EventEmitter.prototype.on; // // This function doesn't apply anymore. // EventEmitter.prototype.setMaxListeners = function setMaxListeners() { return this; }; // // Expose the prefix. // EventEmitter.prefixed = prefix; // // Expose the module. // if ('undefined' !== typeof module) { module.exports = EventEmitter; } },{}],11:[function(_dereq_,module,exports){ 'use strict'; /** * Check if we're required to add a port number. * * @see https://url.spec.whatwg.org/#default-port * @param {Number|String} port Port number we need to check * @param {String} protocol Protocol we need to check against. * @returns {Boolean} Is it a default port for the given protocol * @api private */ module.exports = function required(port, protocol) { protocol = protocol.split(':')[0]; port = +port; if (!port) return false; switch (protocol) { case 'http': case 'ws': return port !== 80; case 'https': case 'wss': return port !== 443; case 'ftp': return port !== 21; case 'gopher': return port !== 70; case 'file': return false; } return port !== 0; }; },{}],12:[function(_dereq_,module,exports){ (function (setImmediate,clearImmediate){(function (){ 'use strict'; var has = Object.prototype.hasOwnProperty , ms = _dereq_('millisecond'); /** * Timer instance. * * @constructor * @param {Object} timer New timer instance. * @param {Function} clear Clears the timer instance. * @param {Function} duration Duration of the timer. * @param {Function} fn The functions that need to be executed. * @api private */ function Timer(timer, clear, duration, fn) { this.start = +(new Date()); this.duration = duration; this.clear = clear; this.timer = timer; this.fns = [fn]; } /** * Calculate the time left for a given timer. * * @returns {Number} Time in milliseconds. * @api public */ Timer.prototype.remaining = function remaining() { return this.duration - this.taken(); }; /** * Calculate the amount of time it has taken since we've set the timer. * * @returns {Number} * @api public */ Timer.prototype.taken = function taken() { return +(new Date()) - this.start; }; /** * Custom wrappers for the various of clear{whatever} functions. We cannot * invoke them directly as this will cause thrown errors in Google Chrome with * an Illegal Invocation Error * * @see #2 * @type {Function} * @api private */ function unsetTimeout(id) { clearTimeout(id); } function unsetInterval(id) { clearInterval(id); } function unsetImmediate(id) { clearImmediate(id); } /** * Simple timer management. * * @constructor * @param {Mixed} context Context of the callbacks that we execute. * @api public */ function Tick(context) { if (!(this instanceof Tick)) return new Tick(context); this.timers = {}; this.context = context || this; } /** * Return a function which will just iterate over all assigned callbacks and * optionally clear the timers from memory if needed. * * @param {String} name Name of the timer we need to execute. * @param {Boolean} clear Also clear from memory. * @returns {Function} * @api private */ Tick.prototype.tock = function ticktock(name, clear) { var tock = this; return function tickedtock() { if (!(name in tock.timers)) return; var timer = tock.timers[name] , fns = timer.fns.slice() , l = fns.length , i = 0; if (clear) tock.clear(name); else tock.start = +new Date(); for (; i < l; i++) { fns[i].call(tock.context); } }; }; /** * Add a new timeout. * * @param {String} name Name of the timer. * @param {Function} fn Completion callback. * @param {Mixed} time Duration of the timer. * @returns {Tick} * @api public */ Tick.prototype.setTimeout = function timeout(name, fn, time) { var tick = this , tock; if (tick.timers[name]) { tick.timers[name].fns.push(fn); return tick; } tock = ms(time); tick.timers[name] = new Timer( setTimeout(tick.tock(name, true), ms(time)), unsetTimeout, tock, fn ); return tick; }; /** * Add a new interval. * * @param {String} name Name of the timer. * @param {Function} fn Completion callback. * @param {Mixed} time Interval of the timer. * @returns {Tick} * @api public */ Tick.prototype.setInterval = function interval(name, fn, time) { var tick = this , tock; if (tick.timers[name]) { tick.timers[name].fns.push(fn); return tick; } tock = ms(time); tick.timers[name] = new Timer( setInterval(tick.tock(name), ms(time)), unsetInterval, tock, fn ); return tick; }; /** * Add a new setImmediate. * * @param {String} name Name of the timer. * @param {Function} fn Completion callback. * @returns {Tick} * @api public */ Tick.prototype.setImmediate = function immediate(name, fn) { var tick = this; if ('function' !== typeof setImmediate) return tick.setTimeout(name, fn, 0); if (tick.timers[name]) { tick.timers[name].fns.push(fn); return tick; } tick.timers[name] = new Timer( setImmediate(tick.tock(name, true)), unsetImmediate, 0, fn ); return tick; }; /** * Check if we have a timer set. * * @param {String} name * @returns {Boolean} * @api public */ Tick.prototype.active = function active(name) { return name in this.timers; }; /** * Properly clean up all timeout references. If no arguments are supplied we * will attempt to clear every single timer that is present. * * @param {Arguments} ..args.. The names of the timeouts we need to clear * @returns {Tick} * @api public */ Tick.prototype.clear = function clear() { var args = arguments.length ? arguments : [] , tick = this , timer, i, l; if (args.length === 1 && 'string' === typeof args[0]) { args = args[0].split(/[, ]+/); } if (!args.length) { for (timer in tick.timers) { if (has.call(tick.timers, timer)) args.push(timer); } } for (i = 0, l = args.length; i < l; i++) { timer = tick.timers[args[i]]; if (!timer) continue; timer.clear(timer.timer); timer.fns = timer.timer = timer.clear = null; delete tick.timers[args[i]]; } return tick; }; /** * Adjust a timeout or interval to a new duration. * * @returns {Tick} * @api public */ Tick.prototype.adjust = function adjust(name, time) { var interval , tick = this , tock = ms(time) , timer = tick.timers[name]; if (!timer) return tick; interval = timer.clear === unsetInterval; timer.clear(timer.timer); timer.start = +(new Date()); timer.duration = tock; timer.timer = (interval ? setInterval : setTimeout)(tick.tock(name, !interval), tock); return tick; }; /** * We will no longer use this module, prepare your self for global cleanups. * * @returns {Boolean} * @api public */ Tick.prototype.end = Tick.prototype.destroy = function end() { if (!this.context) return false; this.clear(); this.context = this.timers = null; return true; }; // // Expose the timer factory. // Tick.Timer = Timer; module.exports = Tick; }).call(this)}).call(this,_dereq_("timers").setImmediate,_dereq_("timers").clearImmediate) },{"millisecond":5,"timers":13}],13:[function(_dereq_,module,exports){ (function (setImmediate,clearImmediate){(function (){ var nextTick = _dereq_('process/browser.js').nextTick; var apply = Function.prototype.apply; var slice = Array.prototype.slice; var immediateIds = {}; var nextImmediateId = 0; // DOM APIs, for completeness exports.setTimeout = function() { return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout); }; exports.setInterval = function() { return new Timeout(apply.call(setInterval, window, arguments), clearInterval); }; exports.clearTimeout = exports.clearInterval = function(timeout) { timeout.close(); }; function Timeout(id, clearFn) { this._id = id; this._clearFn = clearFn; } Timeout.prototype.unref = Timeout.prototype.ref = function() {}; Timeout.prototype.close = function() { this._clearFn.call(window, this._id); }; // Does not start the time, just sets up the members needed. exports.enroll = function(item, msecs) { clearTimeout(item._idleTimeoutId); item._idleTimeout = msecs; }; exports.unenroll = function(item) { clearTimeout(item._idleTimeoutId); item._idleTimeout = -1; }; exports._unrefActive = exports.active = function(item) { clearTimeout(item._idleTimeoutId); var msecs = item._idleTimeout; if (msecs >= 0) { item._idleTimeoutId = setTimeout(function onTimeout() { if (item._onTimeout) item._onTimeout(); }, msecs); } }; // That's not how node.js implements it but the exposed api is the same. exports.setImmediate = typeof setImmediate === "function" ? setImmediate : function(fn) { var id = nextImmediateId++; var args = arguments.length < 2 ? false : slice.call(arguments, 1); immediateIds[id] = true; nextTick(function onNextTick() { if (immediateIds[id]) { // fn.call() is faster so we optimize for the common use-case // @see http://jsperf.com/call-apply-segu if (args) { fn.apply(null, args); } else { fn.call(null); } // Prevent ids from leaking exports.clearImmediate(id); } }); return id; }; exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : function(id) { delete immediateIds[id]; }; }).call(this)}).call(this,_dereq_("timers").setImmediate,_dereq_("timers").clearImmediate) },{"process/browser.js":7,"timers":13}],14:[function(_dereq_,module,exports){ (function (global){(function (){ 'use strict'; var required = _dereq_('requires-port') , qs = _dereq_('querystringify') , controlOrWhitespace = /^[\x00-\x20\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/ , CRHTLF = /[\n\r\t]/g , slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\// , port = /:\d+$/ , protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\\/]+)?([\S\s]*)/i , windowsDriveLetter = /^[a-zA-Z]:/; /** * Remove control characters and whitespace from the beginning of a string. * * @param {Object|String} str String to trim. * @returns {String} A new string representing `str` stripped of control * characters and whitespace from its beginning. * @public */ function trimLeft(str) { return (str ? str : '').toString().replace(controlOrWhitespace, ''); } /** * These are the parse rules for the URL parser, it informs the parser * about: * * 0. The char it Needs to parse, if it's a string it should be done using * indexOf, RegExp using exec and NaN means set as current value. * 1. The property we should set when parsing this value. * 2. Indication if it's backwards or forward parsing, when set as number it's * the value of extra chars that should be split off. * 3. Inherit from location if non existing in the parser. * 4. `toLowerCase` the resulting value. */ var rules = [ ['#', 'hash'], // Extract from the back. ['?', 'query'], // Extract from the back. function sanitize(address, url) { // Sanitize what is left of the address return isSpecial(url.protocol) ? address.replace(/\\/g, '/') : address; }, ['/', 'pathname'], // Extract from the back. ['@', 'auth', 1], // Extract from the front. [NaN, 'host', undefined, 1, 1], // Set left over value. [/:(\d*)$/, 'port', undefined, 1], // RegExp the back. [NaN, 'hostname', undefined, 1, 1] // Set left over. ]; /** * These properties should not be copied or inherited from. This is only needed * for all non blob URL's as a blob URL does not include a hash, only the * origin. * * @type {Object} * @private */ var ignore = { hash: 1, query: 1 }; /** * The location object differs when your code is loaded through a normal page, * Worker or through a worker using a blob. And with the blobble begins the * trouble as the location object will contain the URL of the blob, not the * location of the page where our code is loaded in. The actual origin is * encoded in the `pathname` so we can thankfully generate a good "default" * location from it so we can generate proper relative URL's again. * * @param {Object|String} loc Optional default location object. * @returns {Object} lolcation object. * @public */ function lolcation(loc) { var globalVar; if (typeof window !== 'undefined') globalVar = window; else if (typeof global !== 'undefined') globalVar = global; else if (typeof self !== 'undefined') globalVar = self; else globalVar = {}; var location = globalVar.location || {}; loc = loc || location; var finaldestination = {} , type = typeof loc , key; if ('blob:' === loc.protocol) { finaldestination = new Url(unescape(loc.pathname), {}); } else if ('string' === type) { finaldestination = new Url(loc, {}); for (key in ignore) delete finaldestination[key]; } else if ('object' === type) { for (key in loc) { if (key in ignore) continue; finaldestination[key] = loc[key]; } if (finaldestination.slashes === undefined) { finaldestination.slashes = slashes.test(loc.href); } } return finaldestination; } /** * Check whether a protocol scheme is special. * * @param {String} The protocol scheme of the URL * @return {Boolean} `true` if the protocol scheme is special, else `false` * @private */ function isSpecial(scheme) { return ( scheme === 'file:' || scheme === 'ftp:' || scheme === 'http:' || scheme === 'https:' || scheme === 'ws:' || scheme === 'wss:' ); } /** * @typedef ProtocolExtract * @type Object * @property {String} protocol Protocol matched in the URL, in lowercase. * @property {Boolean} slashes `true` if protocol is followed by "//", else `false`. * @property {String} rest Rest of the URL that is not part of the protocol. */ /** * Extract protocol information from a URL with/without double slash ("//"). * * @param {String} address URL we want to extract from. * @param {Object} location * @return {ProtocolExtract} Extracted information. * @private */ function extractProtocol(address, location) { address = trimLeft(address); address = address.replace(CRHTLF, ''); location = location || {}; var match = protocolre.exec(address); var protocol = match[1] ? match[1].toLowerCase() : ''; var forwardSlashes = !!match[2]; var otherSlashes = !!match[3]; var slashesCount = 0; var rest; if (forwardSlashes) { if (otherSlashes) { rest = match[2] + match[3] + match[4]; slashesCount = match[2].length + match[3].length; } else { rest = match[2] + match[4]; slashesCount = match[2].length; } } else { if (otherSlashes) { rest = match[3] + match[4]; slashesCount = match[3].length; } else { rest = match[4] } } if (protocol === 'file:') { if (slashesCount >= 2) { rest = rest.slice(2); } } else if (isSpecial(protocol)) { rest = match[4]; } else if (protocol) { if (forwardSlashes) { rest = rest.slice(2); } } else if (slashesCount >= 2 && isSpecial(location.protocol)) { rest = match[4]; } return { protocol: protocol, slashes: forwardSlashes || isSpecial(protocol), slashesCount: slashesCount, rest: rest }; } /** * Resolve a relative URL pathname against a base URL pathname. * * @param {String} relative Pathname of the relative URL. * @param {String} base Pathname of the base URL. * @return {String} Resolved pathname. * @private */ function resolve(relative, base) { if (relative === '') return base; var path = (base || '/').split('/').slice(0, -1).concat(relative.split('/')) , i = path.length , last = path[i - 1] , unshift = false , up = 0; while (i--) { if (path[i] === '.') { path.splice(i, 1); } else if (path[i] === '..') { path.splice(i, 1); up++; } else if (up) { if (i === 0) unshift = true; path.splice(i, 1); up--; } } if (unshift) path.unshift(''); if (last === '.' || last === '..') path.push(''); return path.join('/'); } /** * The actual URL instance. Instead of returning an object we've opted-in to * create an actual constructor as it's much more memory efficient and * faster and it pleases my OCD. * * It is worth noting that we should not use `URL` as class name to prevent * clashes with the global URL instance that got introduced in browsers. * * @constructor * @param {String} address URL we want to parse. * @param {Object|String} [location] Location defaults for relative paths. * @param {Boolean|Function} [parser] Parser for the query string. * @private */ function Url(address, location, parser) { address = trimLeft(address); address = address.replace(CRHTLF, ''); if (!(this instanceof Url)) { return new Url(address, location, parser); } var relative, extracted, parse, instruction, index, key , instructions = rules.slice() , type = typeof location , url = this , i = 0; // // The following if statements allows this module two have compatibility with // 2 different API: // // 1. Node.js's `url.parse` api which accepts a URL, boolean as arguments // where the boolean indicates that the query string should also be parsed. // // 2. The `URL` interface of the browser which accepts a URL, object as // arguments. The supplied object will be used as default values / fall-back // for relative paths. // if ('object' !== type && 'string' !== type) { parser = location; location = null; } if (parser && 'function' !== typeof parser) parser = qs.parse; location = lolcation(location); // // Extract protocol information before running the instructions. // extracted = extractProtocol(address || '', location); relative = !extracted.protocol && !extracted.slashes; url.slashes = extracted.slashes || relative && location.slashes; url.protocol = extracted.protocol || location.protocol || ''; address = extracted.rest; // // When the authority component is absent the URL starts with a path // component. // if ( extracted.protocol === 'file:' && ( extracted.slashesCount !== 2 || windowsDriveLetter.test(address)) || (!extracted.slashes && (extracted.protocol || extracted.slashesCount < 2 || !isSpecial(url.protocol))) ) { instructions[3] = [/(.*)/, 'pathname']; } for (; i < instructions.length; i++) { instruction = instructions[i]; if (typeof instruction === 'function') { address = instruction(address, url); continue; } parse = instruction[0]; key = instruction[1]; if (parse !== parse) { url[key] = address; } else if ('string' === typeof parse) { index = parse === '@' ? address.lastIndexOf(parse) : address.indexOf(parse); if (~index) { if ('number' === typeof instruction[2]) { url[key] = address.slice(0, index); address = address.slice(index + instruction[2]); } else { url[key] = address.slice(index); address = address.slice(0, index); } } } else if ((index = parse.exec(address))) { url[key] = index[1]; address = address.slice(0, index.index); } url[key] = url[key] || ( relative && instruction[3] ? location[key] || '' : '' ); // // Hostname, host and protocol should be lowercased so they can be used to // create a proper `origin`. // if (instruction[4]) url[key] = url[key].toLowerCase(); } // // Also parse the supplied query string in to an object. If we're supplied // with a custom parser as function use that instead of the default build-in // parser. // if (parser) url.query = parser(url.query); // // If the URL is relative, resolve the pathname against the base URL. // if ( relative && location.slashes && url.pathname.charAt(0) !== '/' && (url.pathname !== '' || location.pathname !== '') ) { url.pathname = resolve(url.pathname, location.pathname); } // // Default to a / for pathname if none exists. This normalizes the URL // to always have a / // if (url.pathname.charAt(0) !== '/' && isSpecial(url.protocol)) { url.pathname = '/' + url.pathname; } // // We should not add port numbers if they are already the default port number // for a given protocol. As the host also contains the port number we're going // override it with the hostname which contains no port number. // if (!required(url.port, url.protocol)) { url.host = url.hostname; url.port = ''; } // // Parse down the `auth` for the username and password. // url.username = url.password = ''; if (url.auth) { index = url.auth.indexOf(':'); if (~index) { url.username = url.auth.slice(0, index); url.username = encodeURIComponent(decodeURIComponent(url.username)); url.password = url.auth.slice(index + 1); url.password = encodeURIComponent(decodeURIComponent(url.password)) } else { url.username = encodeURIComponent(decodeURIComponent(url.auth)); } url.auth = url.password ? url.username +':'+ url.password : url.username; } url.origin = url.protocol !== 'file:' && isSpecial(url.protocol) && url.host ? url.protocol +'//'+ url.host : 'null'; // // The href is just the compiled result. // url.href = url.toString(); } /** * This is convenience method for changing properties in the URL instance to * insure that they all propagate correctly. * * @param {String} part Property we need to adjust. * @param {Mixed} value The newly assigned value. * @param {Boolean|Function} fn When setting the query, it will be the function * used to parse the query. * When setting the protocol, double slash will be * removed from the final url if it is true. * @returns {URL} URL instance for chaining. * @public */ function set(part, value, fn) { var url = this; switch (part) { case 'query': if ('string' === typeof value && value.length) { value = (fn || qs.parse)(value); } url[part] = value; break; case 'port': url[part] = value; if (!required(value, url.protocol)) { url.host = url.hostname; url[part] = ''; } else if (value) { url.host = url.hostname +':'+ value; } break; case 'hostname': url[part] = value; if (url.port) value += ':'+ url.port; url.host = value; break; case 'host': url[part] = value; if (port.test(value)) { value = value.split(':'); url.port = value.pop(); url.hostname = value.join(':'); } else { url.hostname = value; url.port = ''; } break; case 'protocol': url.protocol = value.toLowerCase(); url.slashes = !fn; break; case 'pathname': case 'hash': if (value) { var char = part === 'pathname' ? '/' : '#'; url[part] = value.charAt(0) !== char ? char + value : value; } else { url[part] = value; } break; case 'username': case 'password': url[part] = encodeURIComponent(value); break; case 'auth': var index = value.indexOf(':'); if (~index) { url.username = value.slice(0, index); url.username = encodeURIComponent(decodeURIComponent(url.username)); url.password = value.slice(index + 1); url.password = encodeURIComponent(decodeURIComponent(url.password)); } else { url.username = encodeURIComponent(decodeURIComponent(value)); } } for (var i = 0; i < rules.length; i++) { var ins = rules[i]; if (ins[4]) url[ins[1]] = url[ins[1]].toLowerCase(); } url.auth = url.password ? url.username +':'+ url.password : url.username; url.origin = url.protocol !== 'file:' && isSpecial(url.protocol) && url.host ? url.protocol +'//'+ url.host : 'null'; url.href = url.toString(); return url; } /** * Transform the properties back in to a valid and full URL string. * * @param {Function} stringify Optional query stringify function. * @returns {String} Compiled version of the URL. * @public */ function toString(stringify) { if (!stringify || 'function' !== typeof stringify) stringify = qs.stringify; var query , url = this , host = url.host , protocol = url.protocol; if (protocol && protocol.charAt(protocol.length - 1) !== ':') protocol += ':'; var result = protocol + ((url.protocol && url.slashes) || isSpecial(url.protocol) ? '//' : ''); if (url.username) { result += url.username; if (url.password) result += ':'+ url.password; result += '@'; } else if (url.password) { result += ':'+ url.password; result += '@'; } else if ( url.protocol !== 'file:' && isSpecial(url.protocol) && !host && url.pathname !== '/' ) { // // Add back the empty userinfo, otherwise the original invalid URL // might be transformed into a valid one with `url.pathname` as host. // result += '@'; } // // Trailing colon is removed from `url.host` when it is parsed. If it still // ends with a colon, then add back the trailing colon that was removed. This // prevents an invalid URL from being transformed into a valid one. // if (host[host.length - 1] === ':' || (port.test(url.hostname) && !url.port)) { host += ':'; } result += host + url.pathname; query = 'object' === typeof url.query ? stringify(url.query) : url.query; if (query) result += '?' !== query.charAt(0) ? '?'+ query : query; if (url.hash) result += url.hash; return result; } Url.prototype = { set: set, toString: toString }; // // Expose the URL parser and some additional properties that might be useful for // others or testing. // Url.extractProtocol = extractProtocol; Url.location = lolcation; Url.trimLeft = trimLeft; Url.qs = qs; module.exports = Url; }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"querystringify":8,"requires-port":11}],15:[function(_dereq_,module,exports){ 'use strict'; var alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'.split('') , length = 64 , map = {} , 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 */ function encode(num) { var 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 */ function decode(str) { var 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 */ function yeast() { var 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; // // Expose the `yeast`, `encode` and `decode` functions. // yeast.encode = encode; yeast.decode = decode; module.exports = yeast; },{}],16:[function(_dereq_,module,exports){ /*globals require, define */ 'use strict'; var EventEmitter = _dereq_('eventemitter3') , TickTock = _dereq_('tick-tock') , Recovery = _dereq_('recovery') , qs = _dereq_('querystringify') , inherits = _dereq_('inherits') , destroy = _dereq_('demolish') , yeast = _dereq_('yeast') , u2028 = /\u2028/g , u2029 = /\u2029/g; /** * Context assertion, ensure that some of our public Primus methods are called * with the correct context to ensure that * * @param {Primus} self The context of the function. * @param {String} method The method name. * @api private */ function context(self, method) { if (self instanceof Primus) return; var failure = new Error('Primus#'+ method + '\'s context should called with a Primus instance'); if ('function' !== typeof self.listeners || !self.listeners('error').length) { throw failure; } self.emit('error', failure); } // // Sets the default connection URL, it uses the default origin of the browser // when supported but degrades for older browsers. In Node.js, we cannot guess // where the user wants to connect to, so we just default to localhost. // var defaultUrl; try { if (location.origin) { defaultUrl = location.origin; } else { defaultUrl = location.protocol +'//'+ location.host; } } catch (e) { defaultUrl = 'http://127.0.0.1'; } /** * Primus is a real-time library agnostic framework for establishing real-time * connections with servers. * * Options: * - reconnect, configuration for the reconnect process. * - manual, don't automatically call `.open` to start the connection. * - websockets, force the use of WebSockets, even when you should avoid them. * - timeout, connect timeout, server didn't respond in a timely manner. * - pingTimeout, The maximum amount of time to wait for the server to send a ping. * - network, Use network events as leading method for network connection drops. * - strategy, Reconnection strategies. * - transport, Transport options. * - url, uri, The URL to use connect with the server. * * @constructor * @param {String} url The URL of your server. * @param {Object} options The configuration. * @api public */ function Primus(url, options) { if (!(this instanceof Primus)) return new Primus(url, options); Primus.Stream.call(this); if ('function' !== typeof this.client) { return this.critical(new Error( 'The client library has not been compiled correctly, see '+ 'https://github.com/primus/primus#client-library for more details' )); } if ('object' === typeof url) { options = url; url = options.url || options.uri || defaultUrl; } else { options = options || {}; } if ('ping' in options || 'pong' in options) { return this.critical(new Error( 'The `ping` and `pong` options have been removed' )); } var primus = this; // The maximum number of messages that can be placed in queue. options.queueSize = 'queueSize' in options ? options.queueSize : Infinity; // Connection timeout duration. options.timeout = 'timeout' in options ? options.timeout : 10e3; // Stores the back off configuration. options.reconnect = 'reconnect' in options ? options.reconnect : {}; // Heartbeat ping interval. options.pingTimeout = 'pingTimeout' in options ? options.pingTimeout : 45000; // Reconnect strategies. options.strategy = 'strategy' in options ? options.strategy : []; // Custom transport options. options.transport = 'transport' in options ? options.transport : {}; primus.buffer = []; // Stores premature send data. primus.writable = true; // Silly stream compatibility. primus.readable = true; // Silly stream compatibility. primus.url = primus.parse(url || defaultUrl); // Parse the URL to a readable format. primus.readyState = Primus.CLOSED; // The readyState of the connection. primus.options = options; // Reference to the supplied options. primus.timers = new TickTock(this); // Contains all our timers. primus.socket = null; // Reference to the internal connection. primus.disconnect = false; // Did we receive a disconnect packet? primus.transport = options.transport; // Transport options. primus.transformers = { // Message transformers. outgoing: [], incoming: [] }; // // Create our reconnection instance. // primus.recovery = new Recovery(options.reconnect); // // Parse the reconnection strategy. It can have the following strategies: // // - timeout: Reconnect when we have a network timeout. // - disconnect: Reconnect when we have an unexpected disconnect. // - online: Reconnect when we're back online. // if ('string' === typeof options.strategy) { options.strategy = options.strategy.split(/\s?,\s?/g); } if (false === options.strategy) { // // Strategies are disabled, but we still need an empty array to join it in // to nothing. // options.strategy = []; } else if (!options.strategy.length) { options.strategy.push('disconnect', 'online'); // // Timeout based reconnection should only be enabled conditionally. When // authorization is enabled it could trigger. // if (!this.authorization) options.strategy.push('timeout'); } options.strategy = options.strategy.join(',').toLowerCase(); // // Force the use of WebSockets, even when we've detected some potential // broken WebSocket implementation. // if ('websockets' in options) { primus.AVOID_WEBSOCKETS = !options.websockets; } // // Force or disable the use of NETWORK events as leading client side // disconnection detection. // if ('network' in options) { primus.NETWORK_EVENTS = options.network; } // // Check if the user wants to manually initialise a connection. If they don't, // we want to do it after a really small timeout so we give the users enough // time to listen for `error` events etc. // if (!options.manual) primus.timers.setTimeout('open', function open() { primus.timers.clear('open'); primus.open(); }, 0); primus.initialise(options); } /** * Simple require wrapper to make browserify, node and require.js play nice. * * @param {String} name The module to require. * @returns {Object|Undefined} The module that we required. * @api private */ Primus.requires = Primus.require = function requires(name) { if ('function' !== typeof _dereq_) return undefined; return !('function' === typeof define && define.amd) ? _dereq_(name) : undefined; }; // // It's possible that we're running in Node.js or in a Node.js compatible // environment. In this cases we try to inherit from the Stream base class. // try { Primus.Stream = Primus.requires('stream'); } catch (e) { } if (!Primus.Stream) Primus.Stream = EventEmitter; inherits(Primus, Primus.Stream); /** * Primus readyStates, used internally to set the correct ready state. * * @type {Number} * @private */ Primus.OPENING = 1; // We're opening the connection. Primus.CLOSED = 2; // No active connection. Primus.OPEN = 3; // The connection is open. /** * Are we working with a potentially broken WebSockets implementation? This * boolean can be used by transformers to remove `WebSockets` from their * supported transports. * * @type {Boolean} * @private */ Primus.prototype.AVOID_WEBSOCKETS = false; /** * Some browsers support registering emitting `online` and `offline` events when * the connection has been dropped on the client. We're going to detect it in * a simple `try {} catch (e) {}` statement so we don't have to do complicated * feature detection. * * @type {Boolean} * @private */ Primus.prototype.NETWORK_EVENTS = false; Primus.prototype.online = true; try { if ( Primus.prototype.NETWORK_EVENTS = 'onLine' in navigator && (window.addEventListener || document.body.attachEvent) ) { if (!navigator.onLine) { Primus.prototype.online = false; } } } catch (e) { } /** * The Ark contains all our plugins definitions. It's namespaced by * name => plugin. * * @type {Object} * @private */ Primus.prototype.ark = {}; /** * Simple emit wrapper that returns a function that emits an event once it's * called. This makes it easier for transports to emit specific events. * * @returns {Function} A function that will emit the event when called. * @api public */ Primus.prototype.emits = _dereq_('emits'); /** * Return the given plugin. * * @param {String} name The name of the plugin. * @returns {Object|undefined} The plugin or undefined. * @api public */ Primus.prototype.plugin = function plugin(name) { context(this, 'plugin'); if (name) return this.ark[name]; var plugins = {}; for (name in this.ark) { plugins[name] = this.ark[name]; } return plugins; }; /** * Checks if the given event is an emitted event by Primus. * * @param {String} evt The event name. * @returns {Boolean} Indication of the event is reserved for internal use. * @api public */ Primus.prototype.reserved = function reserved(evt) { return (/^(incoming|outgoing)::/).test(evt) || evt in this.reserved.events; }; /** * The actual events that are used by the client. * * @type {Object} * @public */ Primus.prototype.reserved.events = { 'reconnect scheduled': 1, 'reconnect timeout': 1, 'readyStateChange': 1, 'reconnect failed': 1, 'reconnected': 1, 'reconnect': 1, 'offline': 1, 'timeout': 1, 'destroy': 1, 'online': 1, 'error': 1, 'close': 1, 'open': 1, 'data': 1, 'end': 1 }; /** * Initialise the Primus and setup all parsers and internal listeners. * * @param {Object} options The original options object. * @returns {Primus} * @api private */ Primus.prototype.initialise = function initialise(options) { var primus = this; primus.recovery .on('reconnected', primus.emits('reconnected')) .on('reconnect failed', primus.emits('reconnect failed', function failed(next) { primus.emit('end'); next(); })) .on('reconnect timeout', primus.emits('reconnect timeout')) .on('reconnect scheduled', primus.emits('reconnect scheduled')) .on('reconnect', primus.emits('reconnect', function reconnect(next) { primus.emit('outgoing::reconnect'); next(); })); primus.on('outgoing::open', function opening() { var readyState = primus.readyState; primus.readyState = Primus.OPENING; if (readyState !== primus.readyState) { primus.emit('readyStateChange', 'opening'); } }); primus.on('incoming::open', function opened() { var readyState = primus.readyState; if (primus.recovery.reconnecting()) { primus.recovery.reconnected(); } // // The connection has been opened so we should set our state to // (writ|read)able so our stream compatibility works as intended. // primus.writable = true; primus.readable = true; // // Make sure we are flagged as `online` as we've successfully opened the // connection. // if (!primus.online) { primus.online = true; primus.emit('online'); } primus.readyState = Primus.OPEN; if (readyState !== primus.readyState) { primus.emit('readyStateChange', 'open'); } primus.heartbeat(); if (primus.buffer.length) { var data = primus.buffer.slice() , length = data.length , i = 0; primus.buffer.length = 0; for (; i < length; i++) { primus._write(data[i]); } } primus.emit('open'); }); primus.on('incoming::ping', function ping(time) { primus.online = true; primus.heartbeat(); primus.emit('outgoing::pong', time); primus._write('primus::pong::'+ time); }); primus.on('incoming::error', function error(e) { var connect = primus.timers.active('connect') , err = e; // // When the error is not an Error instance we try to normalize it. // if ('string' === typeof e) { err = new Error(e); } else if (!(e instanceof Error) && 'object' === typeof e) { // // BrowserChannel and SockJS returns an object which contains some // details of the error. In order to have a proper error we "copy" the // details in an Error instance. // err = new Error(e.message || e.reason); for (var key in e) { if (Object.prototype.hasOwnProperty.call(e, key)) err[key] = e[key]; } } // // We're still doing a reconnect attempt, it could be that we failed to // connect because the server was down. Failing connect attempts should // always emit an `error` event instead of a `open` event. // // if (primus.recovery.reconnecting()) return primus.recovery.reconnected(err); if (primus.listeners('error').length) primus.emit('error', err); // // We received an error while connecting, this most likely the result of an // unauthorized access to the server. // if (connect) { if (~primus.options.strategy.indexOf('timeout')) { primus.recovery.reconnect(); } else { primus.end(); } } }); primus.on('incoming::data', function message(raw) { primus.decoder(raw, function decoding(err, data) { // // Do a "safe" emit('error') when we fail to parse a message. We don't // want to throw here as listening to errors should be optional. // if (err) return primus.listeners('error').length && primus.emit('error', err); // // Handle all "primus::" prefixed protocol messages. // if (primus.protocol(data)) return; primus.transforms(primus, primus, 'incoming', data, raw); }); }); primus.on('incoming::end', function end() { var readyState = primus.readyState; // // This `end` started with the receiving of a primus::server::close packet // which indicated that the user/developer on the server closed the // connection and it was not a result of a network disruption. So we should // kill the connection without doing a reconnect. // if (primus.disconnect) { primus.disconnect = false; return primus.end(); } // // Always set the readyState to closed, and if we're still connecting, close // the connection so we're sure that everything after this if statement block // is only executed because our readyState is set to `open`. // primus.readyState = Primus.CLOSED; if (readyState !== primus.readyState) { primus.emit('readyStateChange', 'end'); } if (primus.timers.active('connect')) primus.end(); if (readyState !== Primus.OPEN) { return primus.recovery.reconnecting() ? primus.recovery.reconnect() : false; } this.writable = false; this.readable = false; // // Clear all timers in case we're not going to reconnect. // this.timers.clear(); // // Fire the `close` event as an indication of connection disruption. // This is also fired by `primus#end` so it is emitted in all cases. // primus.emit('close'); // // The disconnect was unintentional, probably because the server has // shutdown, so if the reconnection is enabled start a reconnect procedure. // if (~primus.options.strategy.indexOf('disconnect')) { return primus.recovery.reconnect(); } primus.emit('outgoing::end'); primus.emit('end'); }); // // Setup the real-time client. // primus.client(); // // Process the potential plugins. // for (var plugin in primus.ark) { primus.ark[plugin].call(primus, primus, options); } // // NOTE: The following code is only required if we're supporting network // events as it requires access to browser globals. // if (!primus.NETWORK_EVENTS) return primus; /** * Handler for offline notifications. * * @api private */ primus.offlineHandler = function offline() { if (!primus.online) return; // Already or still offline, bailout. primus.online = false; primus.emit('offline'); primus.end(); // // It is certainly possible that we're in a reconnection loop and that the // user goes offline. In this case we want to kill the existing attempt so // when the user goes online, it will attempt to reconnect freshly again. // primus.recovery.reset(); }; /** * Handler for online notifications. * * @api private */ primus.onlineHandler = function online() { if (primus.online) return; // Already or still online, bailout. primus.online = true; primus.emit('online'); if (~primus.options.strategy.indexOf('online')) { primus.recovery.reconnect(); } }; if (window.addEventListener) { window.addEventListener('offline', primus.offlineHandler, false); window.addEventListener('online', primus.onlineHandler, false); } else if (document.body.attachEvent){ document.body.attachEvent('onoffline', primus.offlineHandler); document.body.attachEvent('ononline', primus.onlineHandler); } return primus; }; /** * Really dead simple protocol parser. We simply assume that every message that * is prefixed with `primus::` could be used as some sort of protocol definition * for Primus. * * @param {String} msg The data. * @returns {Boolean} Is a protocol message. * @api private */ Primus.prototype.protocol = function protocol(msg) { if ( 'string' !== typeof msg || msg.indexOf('primus::') !== 0 ) return false; var last = msg.indexOf(':', 8) , value = msg.slice(last + 2); switch (msg.slice(8, last)) { case 'ping': this.emit('incoming::ping', +value); break; case 'server': // // The server is closing the connection, forcefully disconnect so we don't // reconnect again. // if ('close' === value) { this.disconnect = true; } break; case 'id': this.emit('incoming::id', value); break; // // Unknown protocol, somebody is probably sending `primus::` prefixed // messages. // default: return false; } return true; }; /** * Execute the set of message transformers from Primus on the incoming or * outgoing message. * This function and it's content should be in sync with Spark#transforms in * spark.js. * * @param {Primus} primus Reference to the Primus instance with message transformers. * @param {Spark|Primus} connection Connection that receives or sends data. * @param {String} type The type of message, 'incoming' or 'outgoing'. * @param {Mixed} data The data to send or that has been received. * @param {String} raw The raw encoded data. * @returns {Primus} * @api public */ Primus.prototype.transforms = function transforms(primus, connection, type, data, raw) { var packet = { data: data } , fns = primus.transformers[type]; // // Iterate in series over the message transformers so we can allow optional // asynchronous execution of message transformers which could for example // retrieve additional data from the server, do extra decoding or even // message validation. // (function transform(index, done) { var transformer = fns[index++]; if (!transformer) return done(); if (1 === transformer.length) { if (false === transformer.call(connection, packet)) { // // When false is returned by an incoming transformer it means that's // being handled by the transformer and we should not emit the `data` // event. // return; } return transform(index, done); } transformer.call(connection, packet, function finished(err, arg) { if (err) return connection.emit('error', err); if (false === arg) return; transform(index, done); }); }(0, function done() { // // We always emit 2 arguments for the data event, the first argument is the // parsed data and the second argument is the raw string that we received. // This allows you, for example, to do some validation on the parsed data // and then save the raw string in your database without the stringify // overhead. // if ('incoming' === type) return connection.emit('data', packet.data, raw); connection._write(packet.data); })); return this; }; /** * Retrieve the current id from the server. * * @param {Function} fn Callback function. * @returns {Primus} * @api public */ Primus.prototype.id = function id(fn) { if (this.socket && this.socket.id) return fn(this.socket.id); this._write('primus::id::'); return this.once('incoming::id', fn); }; /** * Establish a connection with the server. When this function is called we * assume that we don't have any open connections. If you do call it when you * have a connection open, it could cause duplicate connections. * * @returns {Primus} * @api public */ Primus.prototype.open = function open() { context(this, 'open'); // // Only start a `connection timeout` procedure if we're not reconnecting as // that shouldn't count as an initial connection. This should be started // before the connection is opened to capture failing connections and kill the // timeout. // if (!this.recovery.reconnecting() && this.options.timeout) this.timeout(); this.emit('outgoing::open'); return this; }; /** * Send a new message. * * @param {Mixed} data The data that needs to be written. * @returns {Boolean} Always returns true as we don't support back pressure. * @api public */ Primus.prototype.write = function write(data) { context(this, 'write'); this.transforms(this, this, 'outgoing', data); return true; }; /** * The actual message writer. * * @param {Mixed} data The message that needs to be written. * @returns {Boolean} Successful write to the underlaying transport. * @api private */ Primus.prototype._write = function write(data) { var primus = this; // // The connection is closed, normally this would already be done in the // `spark.write` method, but as `_write` is used internally, we should also // add the same check here to prevent potential crashes by writing to a dead // socket. // if (Primus.OPEN !== primus.readyState) { // // If the buffer is at capacity, remove the first item. // if (this.buffer.length === this.options.queueSize) { this.buffer.splice(0, 1); } this.buffer.push(data); return false; } primus.encoder(data, function encoded(err, packet) { // // Do a "safe" emit('error') when we fail to parse a message. We don't // want to throw here as listening to errors should be optional. // if (err) return primus.listeners('error').length && primus.emit('error', err); // // Hack 1: \u2028 and \u2029 are allowed inside a JSON string, but JavaScript // defines them as newline separators. Unescaped control characters are not // allowed inside JSON strings, so this causes an error at parse time. We // work around this issue by escaping these characters. This can cause // errors with JSONP requests or if the string is just evaluated. // if ('string' === typeof packet) { if (~packet.indexOf('\u2028')) packet = packet.replace(u2028, '\\u2028'); if (~packet.indexOf('\u2029')) packet = packet.replace(u2029, '\\u2029'); } primus.emit('outgoing::data', packet); }); return true; }; /** * Set a timer that, upon expiration, closes the client. * * @returns {Primus} * @api private */ Primus.prototype.heartbeat = function heartbeat() { if (!this.options.pingTimeout) return this; this.timers.clear('heartbeat'); this.timers.setTimeout('heartbeat', function expired() { // // The network events already captured the offline event. // if (!this.online) return; this.online = false; this.emit('offline'); this.emit('incoming::end'); }, this.options.pingTimeout); return this; }; /** * Start a connection timeout. * * @returns {Primus} * @api private */ Primus.prototype.timeout = function timeout() { var primus = this; /** * Remove all references to the timeout listener as we've received an event * that can be used to determine state. * * @api private */ function remove() { primus.removeListener('error', remove) .removeListener('open', remove) .removeListener('end', remove) .timers.clear('connect'); } primus.timers.setTimeout('connect', function expired() { remove(); // Clean up old references. if (primus.readyState === Primus.OPEN || primus.recovery.reconnecting()) { return; } primus.emit('timeout'); // // We failed to connect to the server. // if (~primus.options.strategy.indexOf('timeout')) { primus.recovery.reconnect(); } else { primus.end(); } }, primus.options.timeout); return primus.on('error', remove) .on('open', remove) .on('end', remove); }; /** * Close the connection completely. * * @param {Mixed} data last packet of data. * @returns {Primus} * @api public */ Primus.prototype.end = function end(data) { context(this, 'end'); if ( this.readyState === Primus.CLOSED && !this.timers.active('connect') && !this.timers.active('open') ) { // // If we are reconnecting stop the reconnection procedure. // if (this.recovery.reconnecting()) { this.recovery.reset(); this.emit('end'); } return this; } if (data !== undefined) this.write(data); this.writable = false; this.readable = false; var readyState = this.readyState; this.readyState = Primus.CLOSED; if (readyState !== this.readyState) { this.emit('readyStateChange', 'end'); } this.timers.clear(); this.emit('outgoing::end'); this.emit('close'); this.emit('end'); return this; }; /** * Completely demolish the Primus instance and forcefully nuke all references. * * @returns {Boolean} * @api public */ Primus.prototype.destroy = destroy('url timers options recovery socket transport transformers', { before: 'end', after: ['removeAllListeners', function detach() { if (!this.NETWORK_EVENTS) return; if (window.addEventListener) { window.removeEventListener('offline', this.offlineHandler); window.removeEventListener('online', this.onlineHandler); } else if (document.body.attachEvent){ document.body.detachEvent('onoffline', this.offlineHandler); document.body.detachEvent('ononline', this.onlineHandler); } }] }); /** * Create a shallow clone of a given object. * * @param {Object} obj The object that needs to be cloned. * @returns {Object} Copy. * @api private */ Primus.prototype.clone = function clone(obj) { return this.merge({}, obj); }; /** * Merge different objects in to one target object. * * @param {Object} target The object where everything should be merged in. * @returns {Object} Original target with all merged objects. * @api private */ Primus.prototype.merge = function merge(target) { for (var i = 1, key, obj; i < arguments.length; i++) { obj = arguments[i]; for (key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) target[key] = obj[key]; } } return target; }; /** * Parse the connection string. * * @type {Function} * @param {String} url Connection URL. * @returns {Object} Parsed connection. * @api private */ Primus.prototype.parse = _dereq_('url-parse'); /** * Parse a query string. * * @param {String} query The query string that needs to be parsed. * @returns {Object} Parsed query string. * @api private */ Primus.prototype.querystring = qs.parse; /** * Transform a query string object back into string equiv. * * @param {Object} obj The query string object. * @returns {String} * @api private */ Primus.prototype.querystringify = qs.stringify; /** * Generates a connection URI. * * @param {String} protocol The protocol that should used to crate the URI. * @returns {String|options} The URL. * @api private */ Primus.prototype.uri = function uri(options) { var url = this.url , server = [] , qsa = false; // // Query strings are only allowed when we've received clearance for it. // if (options.query) qsa = true; options = options || {}; options.protocol = 'protocol' in options ? options.protocol : 'http:'; options.query = url.query && qsa ? url.query.slice(1) : false; options.secure = 'secure' in options ? options.secure : url.protocol === 'https:' || url.protocol === 'wss:'; options.auth = 'auth' in options ? options.auth : url.auth; options.pathname = 'pathname' in options ? options.pathname : this.pathname; options.port = 'port' in options ? +options.port : +url.port || (options.secure ? 443 : 80); // // We need to make sure that we create a unique connection URL every time to // prevent back forward cache from becoming an issue. We're doing this by // forcing an cache busting query string in to the URL. // var querystring = this.querystring(options.query || ''); querystring._primuscb = yeast(); options.query = this.querystringify(querystring); // // Allow transformation of the options before we construct a full URL from it. // this.emit('outgoing::url', options); // // Automatically suffix the protocol so we can supply `ws:` and `http:` and // it gets transformed correctly. // server.push(options.secure ? options.protocol.replace(':', 's:') : options.protocol, ''); server.push(options.auth ? options.auth +'@'+ url.host : url.host); // // Pathnames are optional as some Transformers would just use the pathname // directly. // if (options.pathname) server.push(options.pathname.slice(1)); // // Optionally add a search query. // if (qsa) server[server.length - 1] += '?'+ options.query; else delete options.query; if (options.object) return options; return server.join('/'); }; /** * Register a new message transformer. This allows you to easily manipulate incoming * and outgoing data which is particularity handy for plugins that want to send * meta data together with the messages. * * @param {String} type Incoming or outgoing * @param {Function} fn A new message transformer. * @returns {Primus} * @api public */ Primus.prototype.transform = function transform(type, fn) { context(this, 'transform'); if (!(type in this.transformers)) { return this.critical(new Error('Invalid transformer type')); } this.transformers[type].push(fn); return this; }; /** * A critical error has occurred, if we have an `error` listener, emit it there. * If not, throw it, so we get a stack trace + proper error message. * * @param {Error} err The critical error. * @returns {Primus} * @api private */ Primus.prototype.critical = function critical(err) { if (this.emit('error', err)) return this; throw err; }; /** * Syntax sugar, adopt a Socket.IO like API. * * @param {String} url The URL we want to connect to. * @param {Object} options Connection options. * @returns {Primus} * @api public */ Primus.connect = function connect(url, options) { return new Primus(url, options); }; // // Expose the EventEmitter so it can be re-used by wrapping libraries we're also // exposing the Stream interface. // Primus.EventEmitter = EventEmitter; // // These libraries are automatically inserted at the server-side using the // Primus#library method. // Primus.prototype.client = function client() { var onmessage = this.emits('incoming::data') , onerror = this.emits('incoming::error') , onopen = this.emits('incoming::open') , onclose = this.emits('incoming::end') , primus = this , socket; // // Select an available Engine.IO factory. // var factory = (function factory() { if ('undefined' !== typeof eio) return eio; try { var Socket = Primus.requires('engine.io-client').Socket; return function eio(options) { return new Socket(options); } } catch (e) {} return undefined; })(); if (!factory) return primus.critical(new Error( 'Missing required `engine.io-client` module. ' + 'Please run `npm install --save engine.io-client`' )); // // Connect to the given URL. // primus.on('outgoing::open', function opening() { primus.emit('outgoing::end'); primus.socket = socket = factory(primus.merge(primus.transport, primus.url, primus.uri({ protocol: 'http:', query: true, object: true }), { // // Never remember upgrades as switching from a WIFI to a 3G connection // could still get your connection blocked as 3G connections are usually // behind a reverse proxy so ISP's can optimize mobile traffic by // caching requests. // rememberUpgrade: false, // // Binary support in Engine.IO breaks a shit things. Turn it off for now. // forceBase64: true, // // Force timestamps on every single connection. Engine.IO only does this // for polling by default, but WebSockets require an explicit `true` // boolean. // timestampRequests: true, path: this.pathname, transports: !primus.AVOID_WEBSOCKETS ? ['polling', 'websocket'] : ['polling'] })); // // Setup the Event handlers. // socket.on('message', onmessage); socket.on('error', onerror); socket.on('close', onclose); socket.on('open', onopen); }); // // We need to write a new message to the socket. // primus.on('outgoing::data', function write(message) { if (socket) socket.send(message); }); // // Attempt to reconnect the socket. // primus.on('outgoing::reconnect', function reconnect() { primus.emit('outgoing::open'); }); // // We need to close the socket. // primus.on('outgoing::end', function close() { if (!socket) return; socket.removeListener('message', onmessage); socket.removeListener('error', onerror); socket.removeListener('close', onclose); socket.removeListener('open', onopen); socket.close(); socket = null; }); }; Primus.prototype.authorization = false; Primus.prototype.pathname = "/sugar"; Primus.prototype.encoder = function encoder(data, fn) { var err; try { data = JSON.stringify(data); } catch (e) { err = e; } fn(err, data); }; Primus.prototype.decoder = function decoder(data, fn) { var err; if ('string' !== typeof data) return fn(err, data); try { data = JSON.parse(data); } catch (e) { err = e; } fn(err, data); }; Primus.prototype.version = "8.0.9"; // // Expose the library. // module.exports = Primus; },{"demolish":1,"emits":2,"eventemitter3":3,"inherits":4,"querystringify":8,"recovery":9,"tick-tock":12,"url-parse":14,"yeast":15}]},{},[16])(16) ; return Primus; }, [ function (Primus) { (function (f) { var g; if (typeof window !== 'undefined') { g = window; } else if (typeof self !== 'undefined') { g = self; } g.eio = f(); })(function () { var eio = (function () { 'use strict'; function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _extends() { _extends = Object.assign ? Object.assign.bind() : 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; }; return _extends.apply(this, arguments); } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct.bind(); } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; } function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; } function _get() { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get.bind(); } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(arguments.length < 3 ? target : receiver); } return desc.value; }; } return _get.apply(this, arguments); } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } var PACKET_TYPES = Object.create(null); // no Map = no polyfill PACKET_TYPES["open"] = "0"; PACKET_TYPES["close"] = "1"; PACKET_TYPES["ping"] = "2"; PACKET_TYPES["pong"] = "3"; PACKET_TYPES["message"] = "4"; PACKET_TYPES["upgrade"] = "5"; PACKET_TYPES["noop"] = "6"; var PACKET_TYPES_REVERSE = Object.create(null); Object.keys(PACKET_TYPES).forEach(function (key) { PACKET_TYPES_REVERSE[PACKET_TYPES[key]] = key; }); var ERROR_PACKET = { type: "error", data: "parser error" }; var withNativeBlob = typeof Blob === "function" || typeof Blob !== "undefined" && Object.prototype.toString.call(Blob) === "[object BlobConstructor]"; var withNativeArrayBuffer$1 = typeof ArrayBuffer === "function"; // ArrayBuffer.isView method is not defined in IE10 var isView = function isView(obj) { return typeof ArrayBuffer.isView === "function" ? ArrayBuffer.isView(obj) : obj && obj.buffer instanceof ArrayBuffer; }; var encodePacket = function encodePacket(_ref, supportsBinary, callback) { var type = _ref.type, data = _ref.data; if (withNativeBlob && data instanceof Blob) { if (supportsBinary) { return callback(data); } else { return encodeBlobAsBase64(data, callback); } } else if (withNativeArrayBuffer$1 && (data instanceof ArrayBuffer || isView(data))) { if (supportsBinary) { return callback(data); } else { return encodeBlobAsBase64(new Blob([data]), callback); } } // plain string return callback(PACKET_TYPES[type] + (data || "")); }; var encodeBlobAsBase64 = function encodeBlobAsBase64(data, callback) { var fileReader = new FileReader(); fileReader.onload = function () { var content = fileReader.result.split(",")[1]; callback("b" + (content || "")); }; return fileReader.readAsDataURL(data); }; function toArray(data) { if (data instanceof Uint8Array) { return data; } else if (data instanceof ArrayBuffer) { return new Uint8Array(data); } else { return new Uint8Array(data.buffer, data.byteOffset, data.byteLength); } } var TEXT_ENCODER; function encodePacketToBinary(packet, callback) { if (withNativeBlob && packet.data instanceof Blob) { return packet.data.arrayBuffer().then(toArray).then(callback); } else if (withNativeArrayBuffer$1 && (packet.data instanceof ArrayBuffer || isView(packet.data))) { return callback(toArray(packet.data)); } encodePacket(packet, false, function (encoded) { if (!TEXT_ENCODER) { TEXT_ENCODER = new TextEncoder(); } callback(TEXT_ENCODER.encode(encoded)); }); } // imported from https://github.com/socketio/base64-arraybuffer var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; // Use a lookup table to find the index. var lookup = typeof Uint8Array === 'undefined' ? [] : new Uint8Array(256); for (var i$1 = 0; i$1 < chars.length; i$1++) { lookup[chars.charCodeAt(i$1)] = i$1; } var decode$1 = function decode(base64) { var bufferLength = base64.length * 0.75, len = base64.length, i, p = 0, encoded1, encoded2, encoded3, encoded4; if (base64[base64.length - 1] === '=') { bufferLength--; if (base64[base64.length - 2] === '=') { bufferLength--; } } var arraybuffer = new ArrayBuffer(bufferLength), bytes = new Uint8Array(arraybuffer); for (i = 0; i < len; i += 4) { encoded1 = lookup[base64.charCodeAt(i)]; encoded2 = lookup[base64.charCodeAt(i + 1)]; encoded3 = lookup[base64.charCodeAt(i + 2)]; encoded4 = lookup[base64.charCodeAt(i + 3)]; bytes[p++] = encoded1 << 2 | encoded2 >> 4; bytes[p++] = (encoded2 & 15) << 4 | encoded3 >> 2; bytes[p++] = (encoded3 & 3) << 6 | encoded4 & 63; } return arraybuffer; }; var withNativeArrayBuffer = typeof ArrayBuffer === "function"; var decodePacket = function decodePacket(encodedPacket, binaryType) { if (typeof encodedPacket !== "string") { return { type: "message", data: mapBinary(encodedPacket, binaryType) }; } var type = encodedPacket.charAt(0); if (type === "b") { return { type: "message", data: decodeBase64Packet(encodedPacket.substring(1), binaryType) }; } var packetType = PACKET_TYPES_REVERSE[type]; if (!packetType) { return ERROR_PACKET; } return encodedPacket.length > 1 ? { type: PACKET_TYPES_REVERSE[type], data: encodedPacket.substring(1) } : { type: PACKET_TYPES_REVERSE[type] }; }; var decodeBase64Packet = function decodeBase64Packet(data, binaryType) { if (withNativeArrayBuffer) { var decoded = decode$1(data); return mapBinary(decoded, binaryType); } else { return { base64: true, data: data }; // fallback for old browsers } }; var mapBinary = function mapBinary(data, binaryType) { switch (binaryType) { case "blob": if (data instanceof Blob) { // from WebSocket + binaryType "blob" return data; } else { // from HTTP long-polling or WebTransport return new Blob([data]); } case "arraybuffer": default: if (data instanceof ArrayBuffer) { // from HTTP long-polling (base64) or WebSocket + binaryType "arraybuffer" return data; } else { // from WebTransport (Uint8Array) return data.buffer; } } }; var SEPARATOR = String.fromCharCode(30); // see https://en.wikipedia.org/wiki/Delimiter#ASCII_delimited_text var encodePayload = function encodePayload(packets, callback) { // some packets may be added to the array while encoding, so the initial length must be saved var length = packets.length; var encodedPackets = new Array(length); var count = 0; packets.forEach(function (packet, i) { // force base64 encoding for binary packets encodePacket(packet, false, function (encodedPacket) { encodedPackets[i] = encodedPacket; if (++count === length) { callback(encodedPackets.join(SEPARATOR)); } }); }); }; var decodePayload = function decodePayload(encodedPayload, binaryType) { var encodedPackets = encodedPayload.split(SEPARATOR); var packets = []; for (var i = 0; i < encodedPackets.length; i++) { var decodedPacket = decodePacket(encodedPackets[i], binaryType); packets.push(decodedPacket); if (decodedPacket.type === "error") { break; } } return packets; }; var TEXT_DECODER; function decodePacketFromBinary(data, isBinary, binaryType) { if (!TEXT_DECODER) { // lazily created for compatibility with old browser platforms TEXT_DECODER = new TextDecoder(); } // 48 === "0".charCodeAt(0) (OPEN packet type) // 54 === "6".charCodeAt(0) (NOOP packet type) var isPlainBinary = isBinary || data[0] < 48 || data[0] > 54; return decodePacket(isPlainBinary ? data : TEXT_DECODER.decode(data), binaryType); } var protocol = 4; /** * Initialize a new `Emitter`. * * @api public */ function Emitter(obj) { if (obj) return mixin(obj); } /** * Mixin the emitter properties. * * @param {Object} obj * @return {Object} * @api private */ function mixin(obj) { for (var key in Emitter.prototype) { obj[key] = Emitter.prototype[key]; } return obj; } /** * Listen on the given `event` with `fn`. * * @param {String} event * @param {Function} fn * @return {Emitter} * @api public */ Emitter.prototype.on = Emitter.prototype.addEventListener = function (event, fn) { this._callbacks = this._callbacks || {}; (this._callbacks['$' + event] = this._callbacks['$' + event] || []).push(fn); return this; }; /** * Adds an `event` listener that will be invoked a single * time then automatically removed. * * @param {String} event * @param {Function} fn * @return {Emitter} * @api public */ Emitter.prototype.once = function (event, fn) { function on() { this.off(event, on); fn.apply(this, arguments); } on.fn = fn; this.on(event, on); return this; }; /** * Remove the given callback for `event` or all * registered callbacks. * * @param {String} event * @param {Function} fn * @return {Emitter} * @api public */ Emitter.prototype.off = Emitter.prototype.removeListener = Emitter.prototype.removeAllListeners = Emitter.prototype.removeEventListener = function (event, fn) { this._callbacks = this._callbacks || {}; // all if (0 == arguments.length) { this._callbacks = {}; return this; } // specific event var callbacks = this._callbacks['$' + event]; if (!callbacks) return this; // remove all handlers if (1 == arguments.length) { delete this._callbacks['$' + event]; return this; } // remove specific handler var cb; for (var i = 0; i < callbacks.length; i++) { cb = callbacks[i]; if (cb === fn || cb.fn === fn) { callbacks.splice(i, 1); break; } } // Remove event specific arrays for event types that no // one is subscribed for to avoid memory leak. if (callbacks.length === 0) { delete this._callbacks['$' + event]; } return this; }; /** * Emit `event` with the given args. * * @param {String} event * @param {Mixed} ... * @return {Emitter} */ Emitter.prototype.emit = function (event) { this._callbacks = this._callbacks || {}; var args = new Array(arguments.length - 1), callbacks = this._callbacks['$' + event]; for (var i = 1; i < arguments.length; i++) { args[i - 1] = arguments[i]; } if (callbacks) { callbacks = callbacks.slice(0); for (var i = 0, len = callbacks.length; i < len; ++i) { callbacks[i].apply(this, args); } } return this; }; // alias used for reserved events (protected method) Emitter.prototype.emitReserved = Emitter.prototype.emit; /** * Return array of callbacks for `event`. * * @param {String} event * @return {Array} * @api public */ Emitter.prototype.listeners = function (event) { this._callbacks = this._callbacks || {}; return this._callbacks['$' + event] || []; }; /** * Check if this emitter has `event` handlers. * * @param {String} event * @return {Boolean} * @api public */ Emitter.prototype.hasListeners = function (event) { return !!this.listeners(event).length; }; var globalThisShim = function () { if (typeof self !== "undefined") { return self; } else if (typeof window !== "undefined") { return window; } else { return Function("return this")(); } }(); function pick(obj) { for (var _len = arguments.length, attr = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { attr[_key - 1] = arguments[_key]; } return attr.reduce(function (acc, k) { if (obj.hasOwnProperty(k)) { acc[k] = obj[k]; } return acc; }, {}); } // Keep a reference to the real timeout functions so they can be used when overridden var NATIVE_SET_TIMEOUT = globalThisShim.setTimeout; var NATIVE_CLEAR_TIMEOUT = globalThisShim.clearTimeout; function installTimerFunctions(obj, opts) { if (opts.useNativeTimers) { obj.setTimeoutFn = NATIVE_SET_TIMEOUT.bind(globalThisShim); obj.clearTimeoutFn = NATIVE_CLEAR_TIMEOUT.bind(globalThisShim); } else { obj.setTimeoutFn = globalThisShim.setTimeout.bind(globalThisShim); obj.clearTimeoutFn = globalThisShim.clearTimeout.bind(globalThisShim); } } // base64 encoded buffers are about 33% bigger (https://en.wikipedia.org/wiki/Base64) var BASE64_OVERHEAD = 1.33; // we could also have used `new Blob([obj]).size`, but it isn't supported in IE9 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) { var c = 0, length = 0; for (var 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; } // imported from https://github.com/galkn/querystring /** * Compiles a querystring * Returns string representation of the object * * @param {Object} * @api private */ function encode$1(obj) { var str = ''; for (var 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 */ function decode(qs) { var qry = {}; var pairs = qs.split('&'); for (var i = 0, l = pairs.length; i < l; i++) { var pair = pairs[i].split('='); qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]); } return qry; } var TransportError = /*#__PURE__*/function (_Error) { _inherits(TransportError, _Error); var _super = _createSuper(TransportError); function TransportError(reason, description, context) { var _this; _classCallCheck(this, TransportError); _this = _super.call(this, reason); _this.description = description; _this.context = context; _this.type = "TransportError"; return _this; } return _createClass(TransportError); }( /*#__PURE__*/_wrapNativeSuper(Error)); var Transport = /*#__PURE__*/function (_Emitter) { _inherits(Transport, _Emitter); var _super2 = _createSuper(Transport); /** * Transport abstract constructor. * * @param {Object} opts - options * @protected */ function Transport(opts) { var _this2; _classCallCheck(this, Transport); _this2 = _super2.call(this); _this2.writable = false; installTimerFunctions(_assertThisInitialized(_this2), opts); _this2.opts = opts; _this2.query = opts.query; _this2.socket = opts.socket; return _this2; } /** * Emits an error. * * @param {String} reason * @param description * @param context - the error context * @return {Transport} for chaining * @protected */ _createClass(Transport, [{ key: "onError", value: function onError(reason, description, context) { _get(_getPrototypeOf(Transport.prototype), "emitReserved", this).call(this, "error", new TransportError(reason, description, context)); return this; } /** * Opens the transport. */ }, { key: "open", value: function open() { this.readyState = "opening"; this.doOpen(); return this; } /** * Closes the transport. */ }, { key: "close", value: function close() { if (this.readyState === "opening" || this.readyState === "open") { this.doClose(); this.onClose(); } return this; } /** * Sends multiple packets. * * @param {Array} packets */ }, { key: "send", value: function send(packets) { if (this.readyState === "open") { this.write(packets); } } /** * Called upon open * * @protected */ }, { key: "onOpen", value: function onOpen() { this.readyState = "open"; this.writable = true; _get(_getPrototypeOf(Transport.prototype), "emitReserved", this).call(this, "open"); } /** * Called with data. * * @param {String} data * @protected */ }, { key: "onData", value: function onData(data) { var packet = decodePacket(data, this.socket.binaryType); this.onPacket(packet); } /** * Called with a decoded packet. * * @protected */ }, { key: "onPacket", value: function onPacket(packet) { _get(_getPrototypeOf(Transport.prototype), "emitReserved", this).call(this, "packet", packet); } /** * Called upon close. * * @protected */ }, { key: "onClose", value: function onClose(details) { this.readyState = "closed"; _get(_getPrototypeOf(Transport.prototype), "emitReserved", this).call(this, "close", details); } /** * Pauses the transport, in order not to lose packets during an upgrade. * * @param onPause */ }, { key: "pause", value: function pause(onPause) {} }, { key: "createUri", value: function createUri(schema) { var query = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return schema + "://" + this._hostname() + this._port() + this.opts.path + this._query(query); } }, { key: "_hostname", value: function _hostname() { var hostname = this.opts.hostname; return hostname.indexOf(":") === -1 ? hostname : "[" + hostname + "]"; } }, { key: "_port", value: function _port() { if (this.opts.port && (this.opts.secure && Number(this.opts.port !== 443) || !this.opts.secure && Number(this.opts.port) !== 80)) { return ":" + this.opts.port; } else { return ""; } } }, { key: "_query", value: function _query(query) { var encodedQuery = encode$1(query); return encodedQuery.length ? "?" + encodedQuery : ""; } }]); return Transport; }(Emitter); // imported from https://github.com/unshiftio/yeast var alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'.split(''), length = 64, map = {}; var 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 */ function encode(num) { var encoded = ''; do { encoded = alphabet[num % length] + encoded; num = Math.floor(num / length); } while (num > 0); return encoded; } /** * Yeast: A tiny growing id generator. * * @returns {String} A unique id. * @api public */ function yeast() { var 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; // imported from https://github.com/component/has-cors var 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 } var hasCORS = value; // browser shim for xmlhttprequest module function XHR(opts) { var xdomain = opts.xdomain; // XMLHttpRequest can be disabled on IE try { if ("undefined" !== typeof XMLHttpRequest && (!xdomain || hasCORS)) { return new XMLHttpRequest(); } } catch (e) {} if (!xdomain) { try { return new globalThisShim[["Active"].concat("Object").join("X")]("Microsoft.XMLHTTP"); } catch (e) {} } } function createCookieJar() {} function empty() {} var hasXHR2 = function () { var xhr = new XHR({ xdomain: false }); return null != xhr.responseType; }(); var Polling = /*#__PURE__*/function (_Transport) { _inherits(Polling, _Transport); var _super = _createSuper(Polling); /** * XHR Polling constructor. * * @param {Object} opts * @package */ function Polling(opts) { var _this; _classCallCheck(this, Polling); _this = _super.call(this, opts); _this.polling = false; if (typeof location !== "undefined") { var isSSL = "https:" === location.protocol; var port = location.port; // some user agents have empty `location.port` if (!port) { port = isSSL ? "443" : "80"; } _this.xd = typeof location !== "undefined" && opts.hostname !== location.hostname || port !== opts.port; } /** * XHR supports binary */ var forceBase64 = opts && opts.forceBase64; _this.supportsBinary = hasXHR2 && !forceBase64; if (_this.opts.withCredentials) { _this.cookieJar = createCookieJar(); } return _this; } _createClass(Polling, [{ key: "name", get: function get() { return "polling"; } /** * Opens the socket (triggers polling). We write a PING message to determine * when the transport is open. * * @protected */ }, { key: "doOpen", value: function doOpen() { this.poll(); } /** * Pauses polling. * * @param {Function} onPause - callback upon buffers are flushed and transport is paused * @package */ }, { key: "pause", value: function pause(onPause) { var _this2 = this; this.readyState = "pausing"; var pause = function pause() { _this2.readyState = "paused"; onPause(); }; if (this.polling || !this.writable) { var total = 0; if (this.polling) { total++; this.once("pollComplete", function () { --total || pause(); }); } if (!this.writable) { total++; this.once("drain", function () { --total || pause(); }); } } else { pause(); } } /** * Starts polling cycle. * * @private */ }, { key: "poll", value: function poll() { this.polling = true; this.doPoll(); this.emitReserved("poll"); } /** * Overloads onData to detect payloads. * * @protected */ }, { key: "onData", value: function onData(data) { var _this3 = this; var callback = function callback(packet) { // if its the first message we consider the transport open if ("opening" === _this3.readyState && packet.type === "open") { _this3.onOpen(); } // if its a close packet, we close the ongoing requests if ("close" === packet.type) { _this3.onClose({ description: "transport closed by the server" }); return false; } // otherwise bypass onData and handle the message _this3.onPacket(packet); }; // decode payload decodePayload(data, this.socket.binaryType).forEach(callback); // if an event did not trigger closing if ("closed" !== this.readyState) { // if we got data we're not polling this.polling = false; this.emitReserved("pollComplete"); if ("open" === this.readyState) { this.poll(); } } } /** * For polling, send a close packet. * * @protected */ }, { key: "doClose", value: function doClose() { var _this4 = this; var close = function close() { _this4.write([{ type: "close" }]); }; if ("open" === this.readyState) { close(); } else { // in case we're trying to close while // handshaking is in progress (GH-164) this.once("open", close); } } /** * Writes a packets payload. * * @param {Array} packets - data packets * @protected */ }, { key: "write", value: function write(packets) { var _this5 = this; this.writable = false; encodePayload(packets, function (data) { _this5.doWrite(data, function () { _this5.writable = true; _this5.emitReserved("drain"); }); }); } /** * Generates uri for connection. * * @private */ }, { key: "uri", value: function uri() { var schema = this.opts.secure ? "https" : "http"; var query = this.query || {}; // cache busting is forced if (false !== this.opts.timestampRequests) { query[this.opts.timestampParam] = yeast(); } if (!this.supportsBinary && !query.sid) { query.b64 = 1; } return this.createUri(schema, query); } /** * Creates a request. * * @param {String} method * @private */ }, { key: "request", value: function request() { var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _extends(opts, { xd: this.xd, cookieJar: this.cookieJar }, this.opts); return new Request(this.uri(), opts); } /** * Sends data. * * @param {String} data to send. * @param {Function} called upon flush. * @private */ }, { key: "doWrite", value: function doWrite(data, fn) { var _this6 = this; var req = this.request({ method: "POST", data: data }); req.on("success", fn); req.on("error", function (xhrStatus, context) { _this6.onError("xhr post error", xhrStatus, context); }); } /** * Starts a poll cycle. * * @private */ }, { key: "doPoll", value: function doPoll() { var _this7 = this; var req = this.request(); req.on("data", this.onData.bind(this)); req.on("error", function (xhrStatus, context) { _this7.onError("xhr poll error", xhrStatus, context); }); this.pollXhr = req; } }]); return Polling; }(Transport); var Request = /*#__PURE__*/function (_Emitter) { _inherits(Request, _Emitter); var _super2 = _createSuper(Request); /** * Request constructor * * @param {Object} options * @package */ function Request(uri, opts) { var _this8; _classCallCheck(this, Request); _this8 = _super2.call(this); installTimerFunctions(_assertThisInitialized(_this8), opts); _this8.opts = opts; _this8.method = opts.method || "GET"; _this8.uri = uri; _this8.data = undefined !== opts.data ? opts.data : null; _this8.create(); return _this8; } /** * Creates the XHR object and sends the request. * * @private */ _createClass(Request, [{ key: "create", value: function create() { var _this9 = this; var _a; var opts = pick(this.opts, "agent", "pfx", "key", "passphrase", "cert", "ca", "ciphers", "rejectUnauthorized", "autoUnref"); opts.xdomain = !!this.opts.xd; var xhr = this.xhr = new XHR(opts); try { xhr.open(this.method, this.uri, true); try { if (this.opts.extraHeaders) { xhr.setDisableHeaderCheck && xhr.setDisableHeaderCheck(true); for (var i in this.opts.extraHeaders) { if (this.opts.extraHeaders.hasOwnProperty(i)) { xhr.setRequestHeader(i, this.opts.extraHeaders[i]); } } } } catch (e) {} if ("POST" === this.method) { try { xhr.setRequestHeader("Content-type", "text/plain;charset=UTF-8"); } catch (e) {} } try { xhr.setRequestHeader("Accept", "*/*"); } catch (e) {} (_a = this.opts.cookieJar) === null || _a === void 0 ? void 0 : _a.addCookies(xhr); // ie6 check if ("withCredentials" in xhr) { xhr.withCredentials = this.opts.withCredentials; } if (this.opts.requestTimeout) { xhr.timeout = this.opts.requestTimeout; } xhr.onreadystatechange = function () { var _a; if (xhr.readyState === 3) { (_a = _this9.opts.cookieJar) === null || _a === void 0 ? void 0 : _a.parseCookies(xhr); } if (4 !== xhr.readyState) return; if (200 === xhr.status || 1223 === xhr.status) { _this9.onLoad(); } else { // make sure the `error` event handler that's user-set // does not throw in the same tick and gets caught here _this9.setTimeoutFn(function () { _this9.onError(typeof xhr.status === "number" ? xhr.status : 0); }, 0); } }; xhr.send(this.data); } catch (e) { // Need to defer since .create() is called directly from the constructor // and thus the 'error' event can only be only bound *after* this exception // occurs. Therefore, also, we cannot throw here at all. this.setTimeoutFn(function () { _this9.onError(e); }, 0); return; } if (typeof document !== "undefined") { this.index = Request.requestsCount++; Request.requests[this.index] = this; } } /** * Called upon error. * * @private */ }, { key: "onError", value: function onError(err) { this.emitReserved("error", err, this.xhr); this.cleanup(true); } /** * Cleans up house. * * @private */ }, { key: "cleanup", value: function cleanup(fromError) { if ("undefined" === typeof this.xhr || null === this.xhr) { return; } this.xhr.onreadystatechange = empty; if (fromError) { try { this.xhr.abort(); } catch (e) {} } if (typeof document !== "undefined") { delete Request.requests[this.index]; } this.xhr = null; } /** * Called upon load. * * @private */ }, { key: "onLoad", value: function onLoad() { var data = this.xhr.responseText; if (data !== null) { this.emitReserved("data", data); this.emitReserved("success"); this.cleanup(); } } /** * Aborts the request. * * @package */ }, { key: "abort", value: function abort() { this.cleanup(); } }]); return Request; }(Emitter); Request.requestsCount = 0; Request.requests = {}; /** * Aborts pending requests when unloading the window. This is needed to prevent * memory leaks (e.g. when using IE) and to ensure that no spurious error is * emitted. */ if (typeof document !== "undefined") { // @ts-ignore if (typeof attachEvent === "function") { // @ts-ignore attachEvent("onunload", unloadHandler); } else if (typeof addEventListener === "function") { var terminationEvent = "onpagehide" in globalThisShim ? "pagehide" : "unload"; addEventListener(terminationEvent, unloadHandler, false); } } function unloadHandler() { for (var i in Request.requests) { if (Request.requests.hasOwnProperty(i)) { Request.requests[i].abort(); } } } var nextTick = function () { var isPromiseAvailable = typeof Promise === "function" && typeof Promise.resolve === "function"; if (isPromiseAvailable) { return function (cb) { return Promise.resolve().then(cb); }; } else { return function (cb, setTimeoutFn) { return setTimeoutFn(cb, 0); }; } }(); var WebSocket = globalThisShim.WebSocket || globalThisShim.MozWebSocket; var usingBrowserWebSocket = true; var defaultBinaryType = "arraybuffer"; // detect ReactNative environment var isReactNative = typeof navigator !== "undefined" && typeof navigator.product === "string" && navigator.product.toLowerCase() === "reactnative"; var WS = /*#__PURE__*/function (_Transport) { _inherits(WS, _Transport); var _super = _createSuper(WS); /** * WebSocket transport constructor. * * @param {Object} opts - connection options * @protected */ function WS(opts) { var _this; _classCallCheck(this, WS); _this = _super.call(this, opts); _this.supportsBinary = !opts.forceBase64; return _this; } _createClass(WS, [{ key: "name", get: function get() { return "websocket"; } }, { key: "doOpen", value: function doOpen() { if (!this.check()) { // let probe timeout return; } var uri = this.uri(); var protocols = this.opts.protocols; // React Native only supports the 'headers' option, and will print a warning if anything else is passed var opts = isReactNative ? {} : pick(this.opts, "agent", "perMessageDeflate", "pfx", "key", "passphrase", "cert", "ca", "ciphers", "rejectUnauthorized", "localAddress", "protocolVersion", "origin", "maxPayload", "family", "checkServerIdentity"); if (this.opts.extraHeaders) { opts.headers = this.opts.extraHeaders; } try { this.ws = usingBrowserWebSocket && !isReactNative ? protocols ? new WebSocket(uri, protocols) : new WebSocket(uri) : new WebSocket(uri, protocols, opts); } catch (err) { return this.emitReserved("error", err); } this.ws.binaryType = this.socket.binaryType || defaultBinaryType; this.addEventListeners(); } /** * Adds event listeners to the socket * * @private */ }, { key: "addEventListeners", value: function addEventListeners() { var _this2 = this; this.ws.onopen = function () { if (_this2.opts.autoUnref) { _this2.ws._socket.unref(); } _this2.onOpen(); }; this.ws.onclose = function (closeEvent) { return _this2.onClose({ description: "websocket connection closed", context: closeEvent }); }; this.ws.onmessage = function (ev) { return _this2.onData(ev.data); }; this.ws.onerror = function (e) { return _this2.onError("websocket error", e); }; } }, { key: "write", value: function write(packets) { var _this3 = this; this.writable = false; // encodePacket efficient as it uses WS framing // no need for encodePayload var _loop = function _loop() { var packet = packets[i]; var lastPacket = i === packets.length - 1; encodePacket(packet, _this3.supportsBinary, function (data) { // always create a new object (GH-437) var opts = {}; // Sometimes the websocket has already been closed but the browser didn't // have a chance of informing us about it yet, in that case send will // throw an error try { if (usingBrowserWebSocket) { // TypeError is thrown when passing the second argument on Safari _this3.ws.send(data); } } catch (e) {} if (lastPacket) { // fake drain // defer to next tick to allow Socket to clear writeBuffer nextTick(function () { _this3.writable = true; _this3.emitReserved("drain"); }, _this3.setTimeoutFn); } }); }; for (var i = 0; i < packets.length; i++) { _loop(); } } }, { key: "doClose", value: function doClose() { if (typeof this.ws !== "undefined") { this.ws.close(); this.ws = null; } } /** * Generates uri for connection. * * @private */ }, { key: "uri", value: function uri() { var schema = this.opts.secure ? "wss" : "ws"; var query = this.query || {}; // append timestamp to URI if (this.opts.timestampRequests) { query[this.opts.timestampParam] = yeast(); } // communicate binary support capabilities if (!this.supportsBinary) { query.b64 = 1; } return this.createUri(schema, query); } /** * Feature detection for WebSocket. * * @return {Boolean} whether this transport is available. * @private */ }, { key: "check", value: function check() { return !!WebSocket; } }]); return WS; }(Transport); function shouldIncludeBinaryHeader(packet, encoded) { // 48 === "0".charCodeAt(0) (OPEN packet type) // 54 === "6".charCodeAt(0) (NOOP packet type) return packet.type === "message" && typeof packet.data !== "string" && encoded[0] >= 48 && encoded[0] <= 54; } var WT = /*#__PURE__*/function (_Transport) { _inherits(WT, _Transport); var _super = _createSuper(WT); function WT() { _classCallCheck(this, WT); return _super.apply(this, arguments); } _createClass(WT, [{ key: "name", get: function get() { return "webtransport"; } }, { key: "doOpen", value: function doOpen() { var _this = this; // @ts-ignore if (typeof WebTransport !== "function") { return; } // @ts-ignore this.transport = new WebTransport(this.createUri("https"), this.opts.transportOptions[this.name]); this.transport.closed.then(function () { _this.onClose(); })["catch"](function (err) { _this.onError("webtransport error", err); }); // note: we could have used async/await, but that would require some additional polyfills this.transport.ready.then(function () { _this.transport.createBidirectionalStream().then(function (stream) { var reader = stream.readable.getReader(); _this.writer = stream.writable.getWriter(); var binaryFlag; var read = function read() { reader.read().then(function (_ref) { var done = _ref.done, value = _ref.value; if (done) { return; } if (!binaryFlag && value.byteLength === 1 && value[0] === 54) { binaryFlag = true; } else { // TODO expose binarytype _this.onPacket(decodePacketFromBinary(value, binaryFlag, "arraybuffer")); binaryFlag = false; } read(); })["catch"](function (err) {}); }; read(); var handshake = _this.query.sid ? "0{\"sid\":\"".concat(_this.query.sid, "\"}") : "0"; _this.writer.write(new TextEncoder().encode(handshake)).then(function () { return _this.onOpen(); }); }); }); } }, { key: "write", value: function write(packets) { var _this2 = this; this.writable = false; var _loop = function _loop() { var packet = packets[i]; var lastPacket = i === packets.length - 1; encodePacketToBinary(packet, function (data) { if (shouldIncludeBinaryHeader(packet, data)) { _this2.writer.write(Uint8Array.of(54)); } _this2.writer.write(data).then(function () { if (lastPacket) { nextTick(function () { _this2.writable = true; _this2.emitReserved("drain"); }, _this2.setTimeoutFn); } }); }); }; for (var i = 0; i < packets.length; i++) { _loop(); } } }, { key: "doClose", value: function doClose() { var _a; (_a = this.transport) === null || _a === void 0 ? void 0 : _a.close(); } }]); return WT; }(Transport); var transports = { websocket: WS, webtransport: WT, polling: Polling }; // imported from https://github.com/galkn/parseuri /** * Parses a URI * * Note: we could also have used the built-in URL object, but it isn't supported on all platforms. * * See: * - https://developer.mozilla.org/en-US/docs/Web/API/URL * - https://caniuse.com/url * - https://www.rfc-editor.org/rfc/rfc3986#appendix-B * * History of the parse() method: * - first commit: https://github.com/socketio/socket.io-client/commit/4ee1d5d94b3906a9c052b459f1a818b15f38f91c * - export into its own module: https://github.com/socketio/engine.io-client/commit/de2c561e4564efeb78f1bdb1ba39ef81b2822cb3 * - reimport: https://github.com/socketio/engine.io-client/commit/df32277c3f6d622eec5ed09f493cae3f3391d242 * * @author Steven Levithan (MIT license) * @api private */ var re = /^(?:(?![^:@\/?#]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@\/?#]*)(?::([^:@\/?#]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor']; function parse(str) { var 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); } var m = re.exec(str || ''), uri = {}, 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) { var 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) { var data = {}; query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g, function ($0, $1, $2) { if ($1) { data[$1] = $2; } }); return data; } var Socket = /*#__PURE__*/function (_Emitter) { _inherits(Socket, _Emitter); var _super = _createSuper(Socket); /** * Socket constructor. * * @param {String|Object} uri - uri or options * @param {Object} opts - options */ function Socket(uri) { var _this; var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classCallCheck(this, Socket); _this = _super.call(this); _this.writeBuffer = []; if (uri && "object" === _typeof(uri)) { opts = uri; uri = null; } if (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 = parse(opts.host).host; } installTimerFunctions(_assertThisInitialized(_this), opts); _this.secure = null != opts.secure ? opts.secure : typeof location !== "undefined" && "https:" === location.protocol; if (opts.hostname && !opts.port) { // if no port is specified manually, use the protocol default opts.port = _this.secure ? "443" : "80"; } _this.hostname = opts.hostname || (typeof location !== "undefined" ? location.hostname : "localhost"); _this.port = opts.port || (typeof location !== "undefined" && location.port ? location.port : _this.secure ? "443" : "80"); _this.transports = opts.transports || ["polling", "websocket", "webtransport"]; _this.writeBuffer = []; _this.prevBufferLen = 0; _this.opts = _extends({ path: "/engine.io", agent: false, withCredentials: false, upgrade: true, timestampParam: "t", rememberUpgrade: false, addTrailingSlash: true, rejectUnauthorized: true, perMessageDeflate: { threshold: 1024 }, transportOptions: {}, closeOnBeforeunload: false }, opts); _this.opts.path = _this.opts.path.replace(/\/$/, "") + (_this.opts.addTrailingSlash ? "/" : ""); if (typeof _this.opts.query === "string") { _this.opts.query = decode(_this.opts.query); } // set on handshake _this.id = null; _this.upgrades = null; _this.pingInterval = null; _this.pingTimeout = null; // set on heartbeat _this.pingTimeoutTimer = null; if (typeof addEventListener === "function") { if (_this.opts.closeOnBeforeunload) { // 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) _this.beforeunloadEventListener = function () { if (_this.transport) { // silently close the transport _this.transport.removeAllListeners(); _this.transport.close(); } }; addEventListener("beforeunload", _this.beforeunloadEventListener, false); } if (_this.hostname !== "localhost") { _this.offlineEventListener = function () { _this.onClose("transport close", { description: "network connection lost" }); }; addEventListener("offline", _this.offlineEventListener, false); } } _this.open(); return _this; } /** * Creates transport of the given type. * * @param {String} name - transport name * @return {Transport} * @private */ _createClass(Socket, [{ key: "createTransport", value: function createTransport(name) { var query = _extends({}, this.opts.query); // append engine.io protocol identifier query.EIO = protocol; // transport name query.transport = name; // session id if we already have one if (this.id) query.sid = this.id; var opts = _extends({}, this.opts, { query: query, socket: this, hostname: this.hostname, secure: this.secure, port: this.port }, this.opts.transportOptions[name]); return new transports[name](opts); } /** * Initializes transport to use and starts probe. * * @private */ }, { key: "open", value: function open() { var _this2 = this; var transport; if (this.opts.rememberUpgrade && Socket.priorWebsocketSuccess && this.transports.indexOf("websocket") !== -1) { transport = "websocket"; } else if (0 === this.transports.length) { // Emit error on next tick so it can be listened to this.setTimeoutFn(function () { _this2.emitReserved("error", "No transports available"); }, 0); return; } else { transport = this.transports[0]; } this.readyState = "opening"; // Retry with the next transport if the transport is disabled (jsonp: false) try { transport = this.createTransport(transport); } catch (e) { this.transports.shift(); this.open(); return; } transport.open(); this.setTransport(transport); } /** * Sets the current transport. Disables the existing one (if any). * * @private */ }, { key: "setTransport", value: function setTransport(transport) { var _this3 = this; if (this.transport) { this.transport.removeAllListeners(); } // set up transport this.transport = transport; // set up transport listeners transport.on("drain", this.onDrain.bind(this)).on("packet", this.onPacket.bind(this)).on("error", this.onError.bind(this)).on("close", function (reason) { return _this3.onClose("transport close", reason); }); } /** * Probes a transport. * * @param {String} name - transport name * @private */ }, { key: "probe", value: function probe(name) { var _this4 = this; var transport = this.createTransport(name); var failed = false; Socket.priorWebsocketSuccess = false; var onTransportOpen = function onTransportOpen() { if (failed) return; transport.send([{ type: "ping", data: "probe" }]); transport.once("packet", function (msg) { if (failed) return; if ("pong" === msg.type && "probe" === msg.data) { _this4.upgrading = true; _this4.emitReserved("upgrading", transport); if (!transport) return; Socket.priorWebsocketSuccess = "websocket" === transport.name; _this4.transport.pause(function () { if (failed) return; if ("closed" === _this4.readyState) return; cleanup(); _this4.setTransport(transport); transport.send([{ type: "upgrade" }]); _this4.emitReserved("upgrade", transport); transport = null; _this4.upgrading = false; _this4.flush(); }); } else { var err = new Error("probe error"); // @ts-ignore err.transport = transport.name; _this4.emitReserved("upgradeError", err); } }); }; function freezeTransport() { if (failed) return; // Any callback called by transport should be ignored since now failed = true; cleanup(); transport.close(); transport = null; } // Handle any error that happens while probing var onerror = function onerror(err) { var error = new Error("probe error: " + err); // @ts-ignore error.transport = transport.name; freezeTransport(); _this4.emitReserved("upgradeError", error); }; function onTransportClose() { onerror("transport closed"); } // When the socket is closed while we're probing function onclose() { onerror("socket closed"); } // When the socket is upgraded while we're probing function onupgrade(to) { if (transport && to.name !== transport.name) { freezeTransport(); } } // Remove all listeners on the transport and on self var cleanup = function cleanup() { transport.removeListener("open", onTransportOpen); transport.removeListener("error", onerror); transport.removeListener("close", onTransportClose); _this4.off("close", onclose); _this4.off("upgrading", onupgrade); }; transport.once("open", onTransportOpen); transport.once("error", onerror); transport.once("close", onTransportClose); this.once("close", onclose); this.once("upgrading", onupgrade); if (this.upgrades.indexOf("webtransport") !== -1 && name !== "webtransport") { // favor WebTransport this.setTimeoutFn(function () { if (!failed) { transport.open(); } }, 200); } else { transport.open(); } } /** * Called when connection is deemed open. * * @private */ }, { key: "onOpen", value: function onOpen() { this.readyState = "open"; Socket.priorWebsocketSuccess = "websocket" === this.transport.name; this.emitReserved("open"); this.flush(); // we check for `readyState` in case an `open` // listener already closed the socket if ("open" === this.readyState && this.opts.upgrade) { var i = 0; var l = this.upgrades.length; for (; i < l; i++) { this.probe(this.upgrades[i]); } } } /** * Handles a packet. * * @private */ }, { key: "onPacket", value: function onPacket(packet) { if ("opening" === this.readyState || "open" === this.readyState || "closing" === this.readyState) { this.emitReserved("packet", packet); // Socket is live - any packet counts this.emitReserved("heartbeat"); switch (packet.type) { case "open": this.onHandshake(JSON.parse(packet.data)); break; case "ping": this.resetPingTimeout(); this.sendPacket("pong"); this.emitReserved("ping"); this.emitReserved("pong"); break; case "error": var err = new Error("server error"); // @ts-ignore err.code = packet.data; this.onError(err); break; case "message": this.emitReserved("data", packet.data); this.emitReserved("message", packet.data); break; } } } /** * Called upon handshake completion. * * @param {Object} data - handshake obj * @private */ }, { key: "onHandshake", value: function 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; this.resetPingTimeout(); } /** * Sets and resets ping timeout timer based on server pings. * * @private */ }, { key: "resetPingTimeout", value: function resetPingTimeout() { var _this5 = this; this.clearTimeoutFn(this.pingTimeoutTimer); this.pingTimeoutTimer = this.setTimeoutFn(function () { _this5.onClose("ping timeout"); }, this.pingInterval + this.pingTimeout); if (this.opts.autoUnref) { this.pingTimeoutTimer.unref(); } } /** * Called on `drain` event * * @private */ }, { key: "onDrain", value: function onDrain() { this.writeBuffer.splice(0, this.prevBufferLen); // setting prevBufferLen = 0 is very important // for example, when upgrading, upgrade packet is sent over, // and a nonzero prevBufferLen could cause problems on `drain` this.prevBufferLen = 0; if (0 === this.writeBuffer.length) { this.emitReserved("drain"); } else { this.flush(); } } /** * Flush write buffers. * * @private */ }, { key: "flush", value: function flush() { if ("closed" !== this.readyState && this.transport.writable && !this.upgrading && this.writeBuffer.length) { var packets = this.getWritablePackets(); this.transport.send(packets); // keep track of current length of writeBuffer // splice writeBuffer and callbackBuffer on `drain` 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 */ }, { key: "getWritablePackets", value: function getWritablePackets() { var shouldCheckPayloadSize = this.maxPayload && this.transport.name === "polling" && this.writeBuffer.length > 1; if (!shouldCheckPayloadSize) { return this.writeBuffer; } var payloadSize = 1; // first packet type for (var i = 0; i < this.writeBuffer.length; i++) { var data = this.writeBuffer[i].data; if (data) { payloadSize += byteLength(data); } if (i > 0 && payloadSize > this.maxPayload) { return this.writeBuffer.slice(0, i); } payloadSize += 2; // separator + packet type } return this.writeBuffer; } /** * Sends a message. * * @param {String} msg - message. * @param {Object} options. * @param {Function} callback function. * @return {Socket} for chaining. */ }, { key: "write", value: function write(msg, options, fn) { this.sendPacket("message", msg, options, fn); return this; } }, { key: "send", value: function send(msg, options, fn) { this.sendPacket("message", msg, options, fn); return this; } /** * Sends a packet. * * @param {String} type: packet type. * @param {String} data. * @param {Object} options. * @param {Function} fn - callback function. * @private */ }, { key: "sendPacket", value: function sendPacket(type, data, options, fn) { if ("function" === typeof data) { fn = data; data = undefined; } if ("function" === typeof options) { fn = options; options = null; } if ("closing" === this.readyState || "closed" === this.readyState) { return; } options = options || {}; options.compress = false !== options.compress; var packet = { type: type, data: data, options: options }; this.emitReserved("packetCreate", packet); this.writeBuffer.push(packet); if (fn) this.once("flush", fn); this.flush(); } /** * Closes the connection. */ }, { key: "close", value: function close() { var _this6 = this; var close = function close() { _this6.onClose("forced close"); _this6.transport.close(); }; var cleanupAndClose = function cleanupAndClose() { _this6.off("upgrade", cleanupAndClose); _this6.off("upgradeError", cleanupAndClose); close(); }; var waitForUpgrade = function waitForUpgrade() { // wait for upgrade to finish since we can't send packets while pausing a transport _this6.once("upgrade", cleanupAndClose); _this6.once("upgradeError", cleanupAndClose); }; if ("opening" === this.readyState || "open" === this.readyState) { this.readyState = "closing"; if (this.writeBuffer.length) { this.once("drain", function () { if (_this6.upgrading) { waitForUpgrade(); } else { close(); } }); } else if (this.upgrading) { waitForUpgrade(); } else { close(); } } return this; } /** * Called upon transport error * * @private */ }, { key: "onError", value: function onError(err) { Socket.priorWebsocketSuccess = false; this.emitReserved("error", err); this.onClose("transport error", err); } /** * Called upon transport close. * * @private */ }, { key: "onClose", value: function onClose(reason, description) { if ("opening" === this.readyState || "open" === this.readyState || "closing" === this.readyState) { // clear timers this.clearTimeoutFn(this.pingTimeoutTimer); // stop event from firing again for transport this.transport.removeAllListeners("close"); // ensure transport won't stay open this.transport.close(); // ignore further transport communication this.transport.removeAllListeners(); if (typeof removeEventListener === "function") { removeEventListener("beforeunload", this.beforeunloadEventListener, false); removeEventListener("offline", this.offlineEventListener, false); } // set ready state this.readyState = "closed"; // clear session id this.id = null; // emit close event this.emitReserved("close", reason, description); // clean buffers after, so users can still // grab the buffers on `close` event this.writeBuffer = []; this.prevBufferLen = 0; } } /** * Filters upgrades, returning only those matching client transports. * * @param {Array} upgrades - server upgrades * @private */ }, { key: "filterUpgrades", value: function filterUpgrades(upgrades) { var filteredUpgrades = []; var i = 0; var j = upgrades.length; for (; i < j; i++) { if (~this.transports.indexOf(upgrades[i])) filteredUpgrades.push(upgrades[i]); } return filteredUpgrades; } }]); return Socket; }(Emitter); Socket.protocol = protocol; var browserEntrypoint = (function (uri, opts) { return new Socket(uri, opts); }); return browserEntrypoint; })(); return eio; }); } ]);