spec/utils/javascripts/faye.js in faye-authentication-1.8.2 vs spec/utils/javascripts/faye.js in faye-authentication-1.9.0
- old
+ new
@@ -1,2639 +1,3046 @@
-(function() {
-'use strict';
+var Faye =
+/******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId])
+/******/ return installedModules[moduleId].exports;
+/******/
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ exports: {},
+/******/ id: moduleId,
+/******/ loaded: false
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ // Flag the module as loaded
+/******/ module.loaded = true;
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/******/
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+/******/
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+/******/
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "";
+/******/
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
-var Faye = {
- VERSION: '1.0.3',
+ 'use strict';
- BAYEUX_VERSION: '1.0',
- ID_LENGTH: 160,
- JSONP_CALLBACK: 'jsonpcallback',
- CONNECTION_TYPES: ['long-polling', 'cross-origin-long-polling', 'callback-polling', 'websocket', 'eventsource', 'in-process'],
+ var constants = __webpack_require__(1),
+ Logging = __webpack_require__(2);
- MANDATORY_CONNECTION_TYPES: ['long-polling', 'callback-polling', 'in-process'],
+ var Faye = {
+ VERSION: constants.VERSION,
- ENV: (typeof window !== 'undefined') ? window : global,
+ Client: __webpack_require__(4),
+ Scheduler: __webpack_require__(32)
+ };
- extend: function(dest, source, overwrite) {
- if (!source) return dest;
- for (var key in source) {
- if (!source.hasOwnProperty(key)) continue;
- if (dest.hasOwnProperty(key) && overwrite === false) continue;
- if (dest[key] !== source[key])
- dest[key] = source[key];
- }
- return dest;
- },
+ Logging.wrapper = Faye;
- random: function(bitlength) {
- bitlength = bitlength || this.ID_LENGTH;
- var maxLength = Math.ceil(bitlength * Math.log(2) / Math.log(36));
- var string = csprng(bitlength, 36);
- while (string.length < maxLength) string = '0' + string;
- return string;
- },
+ module.exports = Faye;
- clientIdFromMessages: function(messages) {
- var connect = this.filter([].concat(messages), function(message) {
- return message.channel === '/meta/connect';
- });
- return connect[0] && connect[0].clientId;
- },
- copyObject: function(object) {
- var clone, i, key;
- if (object instanceof Array) {
- clone = [];
- i = object.length;
- while (i--) clone[i] = Faye.copyObject(object[i]);
- return clone;
- } else if (typeof object === 'object') {
- clone = (object === null) ? null : {};
- for (key in object) clone[key] = Faye.copyObject(object[key]);
- return clone;
- } else {
- return object;
- }
- },
+/***/ },
+/* 1 */
+/***/ function(module, exports) {
- commonElement: function(lista, listb) {
- for (var i = 0, n = lista.length; i < n; i++) {
- if (this.indexOf(listb, lista[i]) !== -1)
- return lista[i];
- }
- return null;
- },
+ module.exports = {
+ VERSION: '1.2.4',
- indexOf: function(list, needle) {
- if (list.indexOf) return list.indexOf(needle);
+ BAYEUX_VERSION: '1.0',
+ ID_LENGTH: 160,
+ JSONP_CALLBACK: 'jsonpcallback',
+ CONNECTION_TYPES: ['long-polling', 'cross-origin-long-polling', 'callback-polling', 'websocket', 'eventsource', 'in-process'],
- for (var i = 0, n = list.length; i < n; i++) {
- if (list[i] === needle) return i;
- }
- return -1;
- },
+ MANDATORY_CONNECTION_TYPES: ['long-polling', 'callback-polling', 'in-process']
+ };
- map: function(object, callback, context) {
- if (object.map) return object.map(callback, context);
- var result = [];
- if (object instanceof Array) {
- for (var i = 0, n = object.length; i < n; i++) {
- result.push(callback.call(context || null, object[i], i));
- }
- } else {
- for (var key in object) {
- if (!object.hasOwnProperty(key)) continue;
- result.push(callback.call(context || null, key, object[key]));
- }
- }
- return result;
- },
+/***/ },
+/* 2 */
+/***/ function(module, exports, __webpack_require__) {
- filter: function(array, callback, context) {
- if (array.filter) return array.filter(callback, context);
- var result = [];
- for (var i = 0, n = array.length; i < n; i++) {
- if (callback.call(context || null, array[i], i))
- result.push(array[i]);
+ 'use strict';
+
+ var toJSON = __webpack_require__(3);
+
+ var Logging = {
+ LOG_LEVELS: {
+ fatal: 4,
+ error: 3,
+ warn: 2,
+ info: 1,
+ debug: 0
+ },
+
+ writeLog: function(messageArgs, level) {
+ var logger = Logging.logger || (Logging.wrapper || Logging).logger;
+ if (!logger) return;
+
+ var args = Array.prototype.slice.apply(messageArgs),
+ banner = '[Faye',
+ klass = this.className,
+
+ message = args.shift().replace(/\?/g, function() {
+ try {
+ return toJSON(args.shift());
+ } catch (error) {
+ return '[Object]';
+ }
+ });
+
+ if (klass) banner += '.' + klass;
+ banner += '] ';
+
+ if (typeof logger[level] === 'function')
+ logger[level](banner + message);
+ else if (typeof logger === 'function')
+ logger(banner + message);
}
- return result;
- },
+ };
- asyncEach: function(list, iterator, callback, context) {
- var n = list.length,
- i = -1,
- calls = 0,
- looping = false;
+ for (var key in Logging.LOG_LEVELS)
+ (function(level) {
+ Logging[level] = function() {
+ this.writeLog(arguments, level);
+ };
+ })(key);
- var iterate = function() {
- calls -= 1;
- i += 1;
- if (i === n) return callback && callback.call(context);
- iterator(list[i], resume);
- };
+ module.exports = Logging;
- var loop = function() {
- if (looping) return;
- looping = true;
- while (calls > 0) iterate();
- looping = false;
- };
- var resume = function() {
- calls += 1;
- loop();
- };
- resume();
- },
+/***/ },
+/* 3 */
+/***/ function(module, exports) {
+ 'use strict';
+
// http://assanka.net/content/tech/2009/09/02/json2-js-vs-prototype/
- toJSON: function(object) {
- if (!this.stringify) return JSON.stringify(object);
- return this.stringify(object, function(key, value) {
+ module.exports = function(object) {
+ return JSON.stringify(object, function(key, value) {
return (this[key] instanceof Array) ? this[key] : value;
});
- }
-};
+ };
-if (typeof module !== 'undefined')
- module.exports = Faye;
-else if (typeof window !== 'undefined')
- window.Faye = Faye;
-Faye.Class = function(parent, methods) {
- if (typeof parent !== 'function') {
- methods = parent;
- parent = Object;
- }
+/***/ },
+/* 4 */
+/***/ function(module, exports, __webpack_require__) {
- var klass = function() {
- if (!this.initialize) return this;
- return this.initialize.apply(this, arguments) || this;
- };
+ /* WEBPACK VAR INJECTION */(function(global) {'use strict';
- var bridge = function() {};
- bridge.prototype = parent.prototype;
+ var asap = __webpack_require__(5),
+ Class = __webpack_require__(7),
+ Promise = __webpack_require__(9),
+ URI = __webpack_require__(10),
+ array = __webpack_require__(11),
+ browser = __webpack_require__(12),
+ constants = __webpack_require__(1),
+ extend = __webpack_require__(8),
+ validateOptions = __webpack_require__(13),
+ Deferrable = __webpack_require__(14),
+ Logging = __webpack_require__(2),
+ Publisher = __webpack_require__(15),
+ Channel = __webpack_require__(17),
+ Dispatcher = __webpack_require__(19),
+ Error = __webpack_require__(33),
+ Extensible = __webpack_require__(34),
+ Publication = __webpack_require__(35),
+ Subscription = __webpack_require__(36);
- klass.prototype = new bridge();
- Faye.extend(klass.prototype, methods);
+ var Client = Class({ className: 'Client',
+ UNCONNECTED: 1,
+ CONNECTING: 2,
+ CONNECTED: 3,
+ DISCONNECTED: 4,
- return klass;
-};
+ HANDSHAKE: 'handshake',
+ RETRY: 'retry',
+ NONE: 'none',
-(function() {
-var EventEmitter = Faye.EventEmitter = function() {};
+ CONNECTION_TIMEOUT: 60,
-/*
-Copyright Joyent, Inc. and other Node contributors. All rights reserved.
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
+ DEFAULT_ENDPOINT: '/bayeux',
+ INTERVAL: 0,
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
+ initialize: function(endpoint, options) {
+ this.info('New client created for ?', endpoint);
+ options = options || {};
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
+ validateOptions(options, ['interval', 'timeout', 'endpoints', 'proxy', 'retry', 'scheduler', 'websocketExtensions', 'tls', 'ca']);
-var isArray = typeof Array.isArray === 'function'
- ? Array.isArray
- : function (xs) {
- return Object.prototype.toString.call(xs) === '[object Array]'
- }
-;
-function indexOf (xs, x) {
- if (xs.indexOf) return xs.indexOf(x);
- for (var i = 0; i < xs.length; i++) {
- if (x === xs[i]) return i;
- }
- return -1;
-}
+ this._channels = new Channel.Set();
+ this._dispatcher = Dispatcher.create(this, endpoint || this.DEFAULT_ENDPOINT, options);
+ this._messageId = 0;
+ this._state = this.UNCONNECTED;
-EventEmitter.prototype.emit = function(type) {
- // If there is no 'error' event listener then throw.
- if (type === 'error') {
- if (!this._events || !this._events.error ||
- (isArray(this._events.error) && !this._events.error.length))
- {
- if (arguments[1] instanceof Error) {
- throw arguments[1]; // Unhandled 'error' event
- } else {
- throw new Error("Uncaught, unspecified 'error' event.");
- }
- return false;
- }
- }
+ this._responseCallbacks = {};
- if (!this._events) return false;
- var handler = this._events[type];
- if (!handler) return false;
+ this._advice = {
+ reconnect: this.RETRY,
+ interval: 1000 * (options.interval || this.INTERVAL),
+ timeout: 1000 * (options.timeout || this.CONNECTION_TIMEOUT)
+ };
+ this._dispatcher.timeout = this._advice.timeout / 1000;
- if (typeof handler == 'function') {
- switch (arguments.length) {
- // fast cases
- case 1:
- handler.call(this);
- break;
- case 2:
- handler.call(this, arguments[1]);
- break;
- case 3:
- handler.call(this, arguments[1], arguments[2]);
- break;
- // slower
- default:
- var args = Array.prototype.slice.call(arguments, 1);
- handler.apply(this, args);
- }
- return true;
+ this._dispatcher.bind('message', this._receiveMessage, this);
- } else if (isArray(handler)) {
- var args = Array.prototype.slice.call(arguments, 1);
+ if (browser.Event && global.onbeforeunload !== undefined)
+ browser.Event.on(global, 'beforeunload', function() {
+ if (array.indexOf(this._dispatcher._disabled, 'autodisconnect') < 0)
+ this.disconnect();
+ }, this);
+ },
- var listeners = handler.slice();
- for (var i = 0, l = listeners.length; i < l; i++) {
- listeners[i].apply(this, args);
- }
- return true;
+ addWebsocketExtension: function(extension) {
+ return this._dispatcher.addWebsocketExtension(extension);
+ },
- } else {
- return false;
- }
-};
+ disable: function(feature) {
+ return this._dispatcher.disable(feature);
+ },
-// EventEmitter is defined in src/node_events.cc
-// EventEmitter.prototype.emit() is also defined there.
-EventEmitter.prototype.addListener = function(type, listener) {
- if ('function' !== typeof listener) {
- throw new Error('addListener only takes instances of Function');
- }
+ setHeader: function(name, value) {
+ return this._dispatcher.setHeader(name, value);
+ },
- if (!this._events) this._events = {};
+ // Request
+ // MUST include: * channel
+ // * version
+ // * supportedConnectionTypes
+ // MAY include: * minimumVersion
+ // * ext
+ // * id
+ //
+ // Success Response Failed Response
+ // MUST include: * channel MUST include: * channel
+ // * version * successful
+ // * supportedConnectionTypes * error
+ // * clientId MAY include: * supportedConnectionTypes
+ // * successful * advice
+ // MAY include: * minimumVersion * version
+ // * advice * minimumVersion
+ // * ext * ext
+ // * id * id
+ // * authSuccessful
+ handshake: function(callback, context) {
+ if (this._advice.reconnect === this.NONE) return;
+ if (this._state !== this.UNCONNECTED) return;
- // To avoid recursion in the case that type == "newListeners"! Before
- // adding it to the listeners, first emit "newListeners".
- this.emit('newListener', type, listener);
+ this._state = this.CONNECTING;
+ var self = this;
- if (!this._events[type]) {
- // Optimize the case of one listener. Don't need the extra array object.
- this._events[type] = listener;
- } else if (isArray(this._events[type])) {
- // If we've already got an array, just append.
- this._events[type].push(listener);
- } else {
- // Adding the second element, need to change to array.
- this._events[type] = [this._events[type], listener];
- }
+ this.info('Initiating handshake with ?', URI.stringify(this._dispatcher.endpoint));
+ this._dispatcher.selectTransport(constants.MANDATORY_CONNECTION_TYPES);
- return this;
-};
+ this._sendMessage({
+ channel: Channel.HANDSHAKE,
+ version: constants.BAYEUX_VERSION,
+ supportedConnectionTypes: this._dispatcher.getConnectionTypes()
-EventEmitter.prototype.on = EventEmitter.prototype.addListener;
+ }, {}, function(response) {
-EventEmitter.prototype.once = function(type, listener) {
- var self = this;
- self.on(type, function g() {
- self.removeListener(type, g);
- listener.apply(this, arguments);
- });
+ if (response.successful) {
+ this._state = this.CONNECTED;
+ this._dispatcher.clientId = response.clientId;
- return this;
-};
+ this._dispatcher.selectTransport(response.supportedConnectionTypes);
-EventEmitter.prototype.removeListener = function(type, listener) {
- if ('function' !== typeof listener) {
- throw new Error('removeListener only takes instances of Function');
- }
+ this.info('Handshake successful: ?', this._dispatcher.clientId);
- // does not use listeners(), so no side effect of creating _events[type]
- if (!this._events || !this._events[type]) return this;
+ this.subscribe(this._channels.getKeys(), true);
+ if (callback) asap(function() { callback.call(context) });
- var list = this._events[type];
+ } else {
+ this.info('Handshake unsuccessful');
+ global.setTimeout(function() { self.handshake(callback, context) }, this._dispatcher.retry * 1000);
+ this._state = this.UNCONNECTED;
+ }
+ }, this);
+ },
- if (isArray(list)) {
- var i = indexOf(list, listener);
- if (i < 0) return this;
- list.splice(i, 1);
- if (list.length == 0)
- delete this._events[type];
- } else if (this._events[type] === listener) {
- delete this._events[type];
- }
+ // Request Response
+ // MUST include: * channel MUST include: * channel
+ // * clientId * successful
+ // * connectionType * clientId
+ // MAY include: * ext MAY include: * error
+ // * id * advice
+ // * ext
+ // * id
+ // * timestamp
+ connect: function(callback, context) {
+ if (this._advice.reconnect === this.NONE) return;
+ if (this._state === this.DISCONNECTED) return;
- return this;
-};
+ if (this._state === this.UNCONNECTED)
+ return this.handshake(function() { this.connect(callback, context) }, this);
-EventEmitter.prototype.removeAllListeners = function(type) {
- if (arguments.length === 0) {
- this._events = {};
- return this;
- }
+ this.callback(callback, context);
+ if (this._state !== this.CONNECTED) return;
- // does not use listeners(), so no side effect of creating _events[type]
- if (type && this._events && this._events[type]) this._events[type] = null;
- return this;
-};
+ this.info('Calling deferred actions for ?', this._dispatcher.clientId);
+ this.setDeferredStatus('succeeded');
+ this.setDeferredStatus('unknown');
-EventEmitter.prototype.listeners = function(type) {
- if (!this._events) this._events = {};
- if (!this._events[type]) this._events[type] = [];
- if (!isArray(this._events[type])) {
- this._events[type] = [this._events[type]];
- }
- return this._events[type];
-};
+ if (this._connectRequest) return;
+ this._connectRequest = true;
-})();
+ this.info('Initiating connection for ?', this._dispatcher.clientId);
-Faye.Namespace = Faye.Class({
- initialize: function() {
- this._used = {};
- },
+ this._sendMessage({
+ channel: Channel.CONNECT,
+ clientId: this._dispatcher.clientId,
+ connectionType: this._dispatcher.connectionType
- exists: function(id) {
- return this._used.hasOwnProperty(id);
- },
+ }, {}, this._cycleConnection, this);
+ },
- generate: function() {
- var name = Faye.random();
- while (this._used.hasOwnProperty(name))
- name = Faye.random();
- return this._used[name] = name;
- },
+ // Request Response
+ // MUST include: * channel MUST include: * channel
+ // * clientId * successful
+ // MAY include: * ext * clientId
+ // * id MAY include: * error
+ // * ext
+ // * id
+ disconnect: function() {
+ if (this._state !== this.CONNECTED) return;
+ this._state = this.DISCONNECTED;
- release: function(id) {
- delete this._used[id];
- }
-});
+ this.info('Disconnecting ?', this._dispatcher.clientId);
+ var promise = new Publication();
-(function() {
-'use strict';
+ this._sendMessage({
+ channel: Channel.DISCONNECT,
+ clientId: this._dispatcher.clientId
-var timeout = setTimeout;
+ }, {}, function(response) {
+ if (response.successful) {
+ this._dispatcher.close();
+ promise.setDeferredStatus('succeeded');
+ } else {
+ promise.setDeferredStatus('failed', Error.parse(response.error));
+ }
+ }, this);
-var defer;
-if (typeof setImmediate === 'function')
- defer = function(fn) { setImmediate(fn) };
-else if (typeof process === 'object' && process.nextTick)
- defer = function(fn) { process.nextTick(fn) };
-else
- defer = function(fn) { timeout(fn, 0) };
+ this.info('Clearing channel listeners for ?', this._dispatcher.clientId);
+ this._channels = new Channel.Set();
-var PENDING = 0,
- FULFILLED = 1,
- REJECTED = 2;
+ return promise;
+ },
-var RETURN = function(x) { return x },
- THROW = function(x) { throw x };
+ // Request Response
+ // MUST include: * channel MUST include: * channel
+ // * clientId * successful
+ // * subscription * clientId
+ // MAY include: * ext * subscription
+ // * id MAY include: * error
+ // * advice
+ // * ext
+ // * id
+ // * timestamp
+ subscribe: function(channel, callback, context) {
+ if (channel instanceof Array)
+ return array.map(channel, function(c) {
+ return this.subscribe(c, callback, context);
+ }, this);
-var Promise = function(task) {
- this._state = PENDING;
- this._callbacks = [];
- this._errbacks = [];
+ var subscription = new Subscription(this, channel, callback, context),
+ force = (callback === true),
+ hasSubscribe = this._channels.hasSubscription(channel);
- if (typeof task !== 'function') return;
- var self = this;
+ if (hasSubscribe && !force) {
+ this._channels.subscribe([channel], subscription);
+ subscription.setDeferredStatus('succeeded');
+ return subscription;
+ }
- task(function(value) { fulfill(self, value) },
- function(reason) { reject(self, reason) });
-};
+ this.connect(function() {
+ this.info('Client ? attempting to subscribe to ?', this._dispatcher.clientId, channel);
+ if (!force) this._channels.subscribe([channel], subscription);
-Promise.prototype.then = function(callback, errback) {
- var next = {}, self = this;
+ this._sendMessage({
+ channel: Channel.SUBSCRIBE,
+ clientId: this._dispatcher.clientId,
+ subscription: channel
- next.promise = new Promise(function(fulfill, reject) {
- next.fulfill = fulfill;
- next.reject = reject;
+ }, {}, function(response) {
+ if (!response.successful) {
+ subscription.setDeferredStatus('failed', Error.parse(response.error));
+ return this._channels.unsubscribe(channel, subscription);
+ }
- registerCallback(self, callback, next);
- registerErrback(self, errback, next);
- });
- return next.promise;
-};
+ var channels = [].concat(response.subscription);
+ this.info('Subscription acknowledged for ? to ?', this._dispatcher.clientId, channels);
+ subscription.setDeferredStatus('succeeded');
+ }, this);
+ }, this);
-var registerCallback = function(promise, callback, next) {
- if (typeof callback !== 'function') callback = RETURN;
- var handler = function(value) { invoke(callback, value, next) };
- if (promise._state === PENDING) {
- promise._callbacks.push(handler);
- } else if (promise._state === FULFILLED) {
- handler(promise._value);
- }
-};
+ return subscription;
+ },
-var registerErrback = function(promise, errback, next) {
- if (typeof errback !== 'function') errback = THROW;
- var handler = function(reason) { invoke(errback, reason, next) };
- if (promise._state === PENDING) {
- promise._errbacks.push(handler);
- } else if (promise._state === REJECTED) {
- handler(promise._reason);
- }
-};
+ // Request Response
+ // MUST include: * channel MUST include: * channel
+ // * clientId * successful
+ // * subscription * clientId
+ // MAY include: * ext * subscription
+ // * id MAY include: * error
+ // * advice
+ // * ext
+ // * id
+ // * timestamp
+ unsubscribe: function(channel, subscription) {
+ if (channel instanceof Array)
+ return array.map(channel, function(c) {
+ return this.unsubscribe(c, subscription);
+ }, this);
-var invoke = function(fn, value, next) {
- defer(function() { _invoke(fn, value, next) });
-};
+ var dead = this._channels.unsubscribe(channel, subscription);
+ if (!dead) return;
-var _invoke = function(fn, value, next) {
- var called = false, outcome, type, then;
+ this.connect(function() {
+ this.info('Client ? attempting to unsubscribe from ?', this._dispatcher.clientId, channel);
- try {
- outcome = fn(value);
- type = typeof outcome;
- then = outcome !== null && (type === 'function' || type === 'object') && outcome.then;
+ this._sendMessage({
+ channel: Channel.UNSUBSCRIBE,
+ clientId: this._dispatcher.clientId,
+ subscription: channel
- if (outcome === next.promise)
- return next.reject(new TypeError('Recursive promise chain detected'));
+ }, {}, function(response) {
+ if (!response.successful) return;
- if (typeof then !== 'function') return next.fulfill(outcome);
+ var channels = [].concat(response.subscription);
+ this.info('Unsubscription acknowledged for ? from ?', this._dispatcher.clientId, channels);
+ }, this);
+ }, this);
+ },
- then.call(outcome, function(v) {
- if (called) return;
- called = true;
- _invoke(RETURN, v, next);
- }, function(r) {
- if (called) return;
- called = true;
- next.reject(r);
- });
+ // Request Response
+ // MUST include: * channel MUST include: * channel
+ // * data * successful
+ // MAY include: * clientId MAY include: * id
+ // * id * error
+ // * ext * ext
+ publish: function(channel, data, options) {
+ validateOptions(options || {}, ['attempts', 'deadline']);
+ var publication = new Publication();
- } catch (error) {
- if (called) return;
- called = true;
- next.reject(error);
- }
-};
+ this.connect(function() {
+ this.info('Client ? queueing published message to ?: ?', this._dispatcher.clientId, channel, data);
-var fulfill = Promise.fulfill = Promise.resolve = function(promise, value) {
- if (promise._state !== PENDING) return;
+ this._sendMessage({
+ channel: channel,
+ data: data,
+ clientId: this._dispatcher.clientId
- promise._state = FULFILLED;
- promise._value = value;
- promise._errbacks = [];
+ }, options, function(response) {
+ if (response.successful)
+ publication.setDeferredStatus('succeeded');
+ else
+ publication.setDeferredStatus('failed', Error.parse(response.error));
+ }, this);
+ }, this);
- var callbacks = promise._callbacks, cb;
- while (cb = callbacks.shift()) cb(value);
-};
+ return publication;
+ },
-var reject = Promise.reject = function(promise, reason) {
- if (promise._state !== PENDING) return;
+ _sendMessage: function(message, options, callback, context) {
+ message.id = this._generateMessageId();
- promise._state = REJECTED;
- promise._reason = reason;
- promise._callbacks = [];
+ var timeout = this._advice.timeout
+ ? 1.2 * this._advice.timeout / 1000
+ : 1.2 * this._dispatcher.retry;
- var errbacks = promise._errbacks, eb;
- while (eb = errbacks.shift()) eb(reason);
-};
+ this.pipeThroughExtensions('outgoing', message, null, function(message) {
+ if (!message) return;
+ if (callback) this._responseCallbacks[message.id] = [callback, context];
+ this._dispatcher.sendMessage(message, timeout, options || {});
+ }, this);
+ },
-Promise.defer = defer;
+ _generateMessageId: function() {
+ this._messageId += 1;
+ if (this._messageId >= Math.pow(2,32)) this._messageId = 0;
+ return this._messageId.toString(36);
+ },
-Promise.deferred = Promise.pending = function() {
- var tuple = {};
+ _receiveMessage: function(message) {
+ var id = message.id, callback;
- tuple.promise = new Promise(function(fulfill, reject) {
- tuple.fulfill = tuple.resolve = fulfill;
- tuple.reject = reject;
- });
- return tuple;
-};
+ if (message.successful !== undefined) {
+ callback = this._responseCallbacks[id];
+ delete this._responseCallbacks[id];
+ }
-Promise.fulfilled = Promise.resolved = function(value) {
- return new Promise(function(fulfill, reject) { fulfill(value) });
-};
+ this.pipeThroughExtensions('incoming', message, null, function(message) {
+ if (!message) return;
+ if (message.advice) this._handleAdvice(message.advice);
+ this._deliverMessage(message);
+ if (callback) callback[0].call(callback[1], message);
+ }, this);
+ },
-Promise.rejected = function(reason) {
- return new Promise(function(fulfill, reject) { reject(reason) });
-};
+ _handleAdvice: function(advice) {
+ extend(this._advice, advice);
+ this._dispatcher.timeout = this._advice.timeout / 1000;
-if (typeof Faye === 'undefined')
- module.exports = Promise;
-else
- Faye.Promise = Promise;
+ if (this._advice.reconnect === this.HANDSHAKE && this._state !== this.DISCONNECTED) {
+ this._state = this.UNCONNECTED;
+ this._dispatcher.clientId = null;
+ this._cycleConnection();
+ }
+ },
-})();
+ _deliverMessage: function(message) {
+ if (!message.channel || message.data === undefined) return;
+ this.info('Client ? calling listeners for ? with ?', this._dispatcher.clientId, message.channel, message.data);
+ this._channels.distributeMessage(message);
+ },
-Faye.Set = Faye.Class({
- initialize: function() {
- this._index = {};
- },
+ _cycleConnection: function() {
+ if (this._connectRequest) {
+ this._connectRequest = null;
+ this.info('Closed connection for ?', this._dispatcher.clientId);
+ }
+ var self = this;
+ global.setTimeout(function() { self.connect() }, this._advice.interval);
+ }
+ });
- add: function(item) {
- var key = (item.id !== undefined) ? item.id : item;
- if (this._index.hasOwnProperty(key)) return false;
- this._index[key] = item;
- return true;
- },
+ extend(Client.prototype, Deferrable);
+ extend(Client.prototype, Publisher);
+ extend(Client.prototype, Logging);
+ extend(Client.prototype, Extensible);
- forEach: function(block, context) {
- for (var key in this._index) {
- if (this._index.hasOwnProperty(key))
- block.call(context, this._index[key]);
- }
- },
+ module.exports = Client;
- isEmpty: function() {
- for (var key in this._index) {
- if (this._index.hasOwnProperty(key)) return false;
- }
- return true;
- },
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
- member: function(item) {
- for (var key in this._index) {
- if (this._index[key] === item) return true;
- }
- return false;
- },
+/***/ },
+/* 5 */
+/***/ function(module, exports, __webpack_require__) {
- remove: function(item) {
- var key = (item.id !== undefined) ? item.id : item;
- var removed = this._index[key];
- delete this._index[key];
- return removed;
- },
+ "use strict";
- toArray: function() {
- var array = [];
- this.forEach(function(item) { array.push(item) });
- return array;
+ // rawAsap provides everything we need except exception management.
+ var rawAsap = __webpack_require__(6);
+ // RawTasks are recycled to reduce GC churn.
+ var freeTasks = [];
+ // We queue errors to ensure they are thrown in right order (FIFO).
+ // Array-as-queue is good enough here, since we are just dealing with exceptions.
+ var pendingErrors = [];
+ var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError);
+
+ function throwFirstError() {
+ if (pendingErrors.length) {
+ throw pendingErrors.shift();
+ }
}
-});
-Faye.URI = {
- isURI: function(uri) {
- return uri && uri.protocol && uri.host && uri.path;
- },
+ /**
+ * Calls a task as soon as possible after returning, in its own event, with priority
+ * over other events like animation, reflow, and repaint. An error thrown from an
+ * event will not interrupt, nor even substantially slow down the processing of
+ * other events, but will be rather postponed to a lower priority event.
+ * @param {{call}} task A callable object, typically a function that takes no
+ * arguments.
+ */
+ module.exports = asap;
+ function asap(task) {
+ var rawTask;
+ if (freeTasks.length) {
+ rawTask = freeTasks.pop();
+ } else {
+ rawTask = new RawTask();
+ }
+ rawTask.task = task;
+ rawAsap(rawTask);
+ }
- isSameOrigin: function(uri) {
- var location = Faye.ENV.location;
- return uri.protocol === location.protocol &&
- uri.hostname === location.hostname &&
- uri.port === location.port;
- },
+ // We wrap tasks with recyclable task objects. A task object implements
+ // `call`, just like a function.
+ function RawTask() {
+ this.task = null;
+ }
- parse: function(url) {
- if (typeof url !== 'string') return url;
- var uri = {}, parts, query, pairs, i, n, data;
+ // The sole purpose of wrapping the task is to catch the exception and recycle
+ // the task object after its single use.
+ RawTask.prototype.call = function () {
+ try {
+ this.task.call();
+ } catch (error) {
+ if (asap.onerror) {
+ // This hook exists purely for testing purposes.
+ // Its name will be periodically randomized to break any code that
+ // depends on its existence.
+ asap.onerror(error);
+ } else {
+ // In a web browser, exceptions are not fatal. However, to avoid
+ // slowing down the queue of pending tasks, we rethrow the error in a
+ // lower priority turn.
+ pendingErrors.push(error);
+ requestErrorThrow();
+ }
+ } finally {
+ this.task = null;
+ freeTasks[freeTasks.length] = this;
+ }
+ };
- var consume = function(name, pattern) {
- url = url.replace(pattern, function(match) {
- uri[name] = match;
- return '';
- });
- uri[name] = uri[name] || '';
- };
- consume('protocol', /^[a-z]+\:/i);
- consume('host', /^\/\/[^\/\?#]+/);
+/***/ },
+/* 6 */
+/***/ function(module, exports) {
- if (!/^\//.test(url) && !uri.host)
- url = Faye.ENV.location.pathname.replace(/[^\/]*$/, '') + url;
+ /* WEBPACK VAR INJECTION */(function(global) {"use strict";
- consume('pathname', /^[^\?#]*/);
- consume('search', /^\?[^#]*/);
- consume('hash', /^#.*/);
+ // Use the fastest means possible to execute a task in its own turn, with
+ // priority over other events including IO, animation, reflow, and redraw
+ // events in browsers.
+ //
+ // An exception thrown by a task will permanently interrupt the processing of
+ // subsequent tasks. The higher level `asap` function ensures that if an
+ // exception is thrown by a task, that the task queue will continue flushing as
+ // soon as possible, but if you use `rawAsap` directly, you are responsible to
+ // either ensure that no exceptions are thrown from your task, or to manually
+ // call `rawAsap.requestFlush` if an exception is thrown.
+ module.exports = rawAsap;
+ function rawAsap(task) {
+ if (!queue.length) {
+ requestFlush();
+ flushing = true;
+ }
+ // Equivalent to push, but avoids a function call.
+ queue[queue.length] = task;
+ }
- uri.protocol = uri.protocol || Faye.ENV.location.protocol;
+ var queue = [];
+ // Once a flush has been requested, no further calls to `requestFlush` are
+ // necessary until the next `flush` completes.
+ var flushing = false;
+ // `requestFlush` is an implementation-specific method that attempts to kick
+ // off a `flush` event as quickly as possible. `flush` will attempt to exhaust
+ // the event queue before yielding to the browser's own event loop.
+ var requestFlush;
+ // The position of the next task to execute in the task queue. This is
+ // preserved between calls to `flush` so that it can be resumed if
+ // a task throws an exception.
+ var index = 0;
+ // If a task schedules additional tasks recursively, the task queue can grow
+ // unbounded. To prevent memory exhaustion, the task queue will periodically
+ // truncate already-completed tasks.
+ var capacity = 1024;
- if (uri.host) {
- uri.host = uri.host.substr(2);
- parts = uri.host.split(':');
- uri.hostname = parts[0];
- uri.port = parts[1] || '';
- } else {
- uri.host = Faye.ENV.location.host;
- uri.hostname = Faye.ENV.location.hostname;
- uri.port = Faye.ENV.location.port;
- }
+ // The flush function processes all tasks that have been scheduled with
+ // `rawAsap` unless and until one of those tasks throws an exception.
+ // If a task throws an exception, `flush` ensures that its state will remain
+ // consistent and will resume where it left off when called again.
+ // However, `flush` does not make any arrangements to be called again if an
+ // exception is thrown.
+ function flush() {
+ while (index < queue.length) {
+ var currentIndex = index;
+ // Advance the index before calling the task. This ensures that we will
+ // begin flushing on the next task the task throws an error.
+ index = index + 1;
+ queue[currentIndex].call();
+ // Prevent leaking memory for long chains of recursive calls to `asap`.
+ // If we call `asap` within tasks scheduled by `asap`, the queue will
+ // grow, but to avoid an O(n) walk for every task we execute, we don't
+ // shift tasks off the queue after they have been executed.
+ // Instead, we periodically shift 1024 tasks off the queue.
+ if (index > capacity) {
+ // Manually shift all values starting at the index back to the
+ // beginning of the queue.
+ for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
+ queue[scan] = queue[scan + index];
+ }
+ queue.length -= index;
+ index = 0;
+ }
+ }
+ queue.length = 0;
+ index = 0;
+ flushing = false;
+ }
- uri.pathname = uri.pathname || '/';
- uri.path = uri.pathname + uri.search;
+ // `requestFlush` is implemented using a strategy based on data collected from
+ // every available SauceLabs Selenium web driver worker at time of writing.
+ // https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593
- query = uri.search.replace(/^\?/, '');
- pairs = query ? query.split('&') : [];
- data = {};
+ // Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that
+ // have WebKitMutationObserver but not un-prefixed MutationObserver.
+ // Must use `global` or `self` instead of `window` to work in both frames and web
+ // workers. `global` is a provision of Browserify, Mr, Mrs, or Mop.
- for (i = 0, n = pairs.length; i < n; i++) {
- parts = pairs[i].split('=');
- data[decodeURIComponent(parts[0] || '')] = decodeURIComponent(parts[1] || '');
- }
+ /* globals self */
+ var scope = typeof global !== "undefined" ? global : self;
+ var BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver;
- uri.query = data;
+ // MutationObservers are desirable because they have high priority and work
+ // reliably everywhere they are implemented.
+ // They are implemented in all modern browsers.
+ //
+ // - Android 4-4.3
+ // - Chrome 26-34
+ // - Firefox 14-29
+ // - Internet Explorer 11
+ // - iPad Safari 6-7.1
+ // - iPhone Safari 7-7.1
+ // - Safari 6-7
+ if (typeof BrowserMutationObserver === "function") {
+ requestFlush = makeRequestCallFromMutationObserver(flush);
- uri.href = this.stringify(uri);
- return uri;
- },
+ // MessageChannels are desirable because they give direct access to the HTML
+ // task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera
+ // 11-12, and in web workers in many engines.
+ // Although message channels yield to any queued rendering and IO tasks, they
+ // would be better than imposing the 4ms delay of timers.
+ // However, they do not work reliably in Internet Explorer or Safari.
- stringify: function(uri) {
- var string = uri.protocol + '//' + uri.hostname;
- if (uri.port) string += ':' + uri.port;
- string += uri.pathname + this.queryString(uri.query) + (uri.hash || '');
- return string;
- },
+ // Internet Explorer 10 is the only browser that has setImmediate but does
+ // not have MutationObservers.
+ // Although setImmediate yields to the browser's renderer, it would be
+ // preferrable to falling back to setTimeout since it does not have
+ // the minimum 4ms penalty.
+ // Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (and
+ // Desktop to a lesser extent) that renders both setImmediate and
+ // MessageChannel useless for the purposes of ASAP.
+ // https://github.com/kriskowal/q/issues/396
- queryString: function(query) {
- var pairs = [];
- for (var key in query) {
- if (!query.hasOwnProperty(key)) continue;
- pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(query[key]));
- }
- if (pairs.length === 0) return '';
- return '?' + pairs.join('&');
+ // Timers are implemented universally.
+ // We fall back to timers in workers in most engines, and in foreground
+ // contexts in the following browsers.
+ // However, note that even this simple case requires nuances to operate in a
+ // broad spectrum of browsers.
+ //
+ // - Firefox 3-13
+ // - Internet Explorer 6-9
+ // - iPad Safari 4.3
+ // - Lynx 2.8.7
+ } else {
+ requestFlush = makeRequestCallFromTimer(flush);
}
-};
-Faye.Error = Faye.Class({
- initialize: function(code, params, message) {
- this.code = code;
- this.params = Array.prototype.slice.call(params);
- this.message = message;
- },
+ // `requestFlush` requests that the high priority event queue be flushed as
+ // soon as possible.
+ // This is useful to prevent an error thrown in a task from stalling the event
+ // queue if the exception handled by Node.js’s
+ // `process.on("uncaughtException")` or by a domain.
+ rawAsap.requestFlush = requestFlush;
- toString: function() {
- return this.code + ':' +
- this.params.join(',') + ':' +
- this.message;
+ // To request a high priority event, we induce a mutation observer by toggling
+ // the text of a text node between "1" and "-1".
+ function makeRequestCallFromMutationObserver(callback) {
+ var toggle = 1;
+ var observer = new BrowserMutationObserver(callback);
+ var node = document.createTextNode("");
+ observer.observe(node, {characterData: true});
+ return function requestCall() {
+ toggle = -toggle;
+ node.data = toggle;
+ };
}
-});
-Faye.Error.parse = function(message) {
- message = message || '';
- if (!Faye.Grammar.ERROR.test(message)) return new this(null, [], message);
+ // The message channel technique was discovered by Malte Ubl and was the
+ // original foundation for this library.
+ // http://www.nonblocking.io/2011/06/windownexttick.html
- var parts = message.split(':'),
- code = parseInt(parts[0]),
- params = parts[1].split(','),
- message = parts[2];
+ // Safari 6.0.5 (at least) intermittently fails to create message ports on a
+ // page's first load. Thankfully, this version of Safari supports
+ // MutationObservers, so we don't need to fall back in that case.
- return new this(code, params, message);
-};
+ // function makeRequestCallFromMessageChannel(callback) {
+ // var channel = new MessageChannel();
+ // channel.port1.onmessage = callback;
+ // return function requestCall() {
+ // channel.port2.postMessage(0);
+ // };
+ // }
+ // For reasons explained above, we are also unable to use `setImmediate`
+ // under any circumstances.
+ // Even if we were, there is another bug in Internet Explorer 10.
+ // It is not sufficient to assign `setImmediate` to `requestFlush` because
+ // `setImmediate` must be called *by name* and therefore must be wrapped in a
+ // closure.
+ // Never forget.
+ // function makeRequestCallFromSetImmediate(callback) {
+ // return function requestCall() {
+ // setImmediate(callback);
+ // };
+ // }
+ // Safari 6.0 has a problem where timers will get lost while the user is
+ // scrolling. This problem does not impact ASAP because Safari 6.0 supports
+ // mutation observers, so that implementation is used instead.
+ // However, if we ever elect to use timers in Safari, the prevalent work-around
+ // is to add a scroll event listener that calls for a flush.
-Faye.Error.versionMismatch = function() {
- return new this(300, arguments, 'Version mismatch').toString();
-};
+ // `setTimeout` does not call the passed callback if the delay is less than
+ // approximately 7 in web workers in Firefox 8 through 18, and sometimes not
+ // even then.
-Faye.Error.conntypeMismatch = function() {
- return new this(301, arguments, 'Connection types not supported').toString();
-};
+ function makeRequestCallFromTimer(callback) {
+ return function requestCall() {
+ // We dispatch a timeout with a specified delay of 0 for engines that
+ // can reliably accommodate that request. This will usually be snapped
+ // to a 4 milisecond delay, but once we're flushing, there's no delay
+ // between events.
+ var timeoutHandle = setTimeout(handleTimer, 0);
+ // However, since this timer gets frequently dropped in Firefox
+ // workers, we enlist an interval handle that will try to fire
+ // an event 20 times per second until it succeeds.
+ var intervalHandle = setInterval(handleTimer, 50);
-Faye.Error.extMismatch = function() {
- return new this(302, arguments, 'Extension mismatch').toString();
-};
+ function handleTimer() {
+ // Whichever timer succeeds will cancel both timers and
+ // execute the callback.
+ clearTimeout(timeoutHandle);
+ clearInterval(intervalHandle);
+ callback();
+ }
+ };
+ }
-Faye.Error.badRequest = function() {
- return new this(400, arguments, 'Bad request').toString();
-};
+ // This is for `asap.js` only.
+ // Its name will be periodically randomized to break any code that depends on
+ // its existence.
+ rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer;
-Faye.Error.clientUnknown = function() {
- return new this(401, arguments, 'Unknown client').toString();
-};
+ // ASAP was originally a nextTick shim included in Q. This was factored out
+ // into this ASAP package. It was later adapted to RSVP which made further
+ // amendments. These decisions, particularly to marginalize MessageChannel and
+ // to capture the MutationObserver implementation in a closure, were integrated
+ // back into ASAP proper.
+ // https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js
-Faye.Error.parameterMissing = function() {
- return new this(402, arguments, 'Missing required parameter').toString();
-};
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
-Faye.Error.channelForbidden = function() {
- return new this(403, arguments, 'Forbidden channel').toString();
-};
+/***/ },
+/* 7 */
+/***/ function(module, exports, __webpack_require__) {
-Faye.Error.channelUnknown = function() {
- return new this(404, arguments, 'Unknown channel').toString();
-};
+ 'use strict';
-Faye.Error.channelInvalid = function() {
- return new this(405, arguments, 'Invalid channel').toString();
-};
+ var extend = __webpack_require__(8);
-Faye.Error.extUnknown = function() {
- return new this(406, arguments, 'Unknown extension').toString();
-};
+ module.exports = function(parent, methods) {
+ if (typeof parent !== 'function') {
+ methods = parent;
+ parent = Object;
+ }
-Faye.Error.publishFailed = function() {
- return new this(407, arguments, 'Failed to publish').toString();
-};
+ var klass = function() {
+ if (!this.initialize) return this;
+ return this.initialize.apply(this, arguments) || this;
+ };
-Faye.Error.serverError = function() {
- return new this(500, arguments, 'Internal server error').toString();
-};
+ var bridge = function() {};
+ bridge.prototype = parent.prototype;
+ klass.prototype = new bridge();
+ extend(klass.prototype, methods);
-Faye.Deferrable = {
- then: function(callback, errback) {
- var self = this;
- if (!this._promise)
- this._promise = new Faye.Promise(function(fulfill, reject) {
- self._fulfill = fulfill;
- self._reject = reject;
- });
+ return klass;
+ };
- if (arguments.length === 0)
- return this._promise;
- else
- return this._promise.then(callback, errback);
- },
- callback: function(callback, context) {
- return this.then(function(value) { callback.call(context, value) });
- },
+/***/ },
+/* 8 */
+/***/ function(module, exports) {
- errback: function(callback, context) {
- return this.then(null, function(reason) { callback.call(context, reason) });
- },
+ 'use strict';
- timeout: function(seconds, message) {
- this.then();
- var self = this;
- this._timer = Faye.ENV.setTimeout(function() {
- self._reject(message);
- }, seconds * 1000);
- },
+ module.exports = function(dest, source, overwrite) {
+ if (!source) return dest;
+ for (var key in source) {
+ if (!source.hasOwnProperty(key)) continue;
+ if (dest.hasOwnProperty(key) && overwrite === false) continue;
+ if (dest[key] !== source[key])
+ dest[key] = source[key];
+ }
+ return dest;
+ };
- setDeferredStatus: function(status, value) {
- if (this._timer) Faye.ENV.clearTimeout(this._timer);
- this.then();
+/***/ },
+/* 9 */
+/***/ function(module, exports, __webpack_require__) {
- if (status === 'succeeded')
- this._fulfill(value);
- else if (status === 'failed')
- this._reject(value);
- else
- delete this._promise;
- }
-};
+ 'use strict';
-Faye.Publisher = {
- countListeners: function(eventType) {
- return this.listeners(eventType).length;
- },
+ var asap = __webpack_require__(5);
- bind: function(eventType, listener, context) {
- var slice = Array.prototype.slice,
- handler = function() { listener.apply(context, slice.call(arguments)) };
+ var PENDING = 0,
+ FULFILLED = 1,
+ REJECTED = 2;
- this._listeners = this._listeners || [];
- this._listeners.push([eventType, listener, context, handler]);
- return this.on(eventType, handler);
- },
+ var RETURN = function(x) { return x },
+ THROW = function(x) { throw x };
- unbind: function(eventType, listener, context) {
- this._listeners = this._listeners || [];
- var n = this._listeners.length, tuple;
+ var Promise = function(task) {
+ this._state = PENDING;
+ this._onFulfilled = [];
+ this._onRejected = [];
- while (n--) {
- tuple = this._listeners[n];
- if (tuple[0] !== eventType) continue;
- if (listener && (tuple[1] !== listener || tuple[2] !== context)) continue;
- this._listeners.splice(n, 1);
- this.removeListener(eventType, tuple[3]);
- }
- }
-};
+ if (typeof task !== 'function') return;
+ var self = this;
-Faye.extend(Faye.Publisher, Faye.EventEmitter.prototype);
-Faye.Publisher.trigger = Faye.Publisher.emit;
+ task(function(value) { resolve(self, value) },
+ function(reason) { reject(self, reason) });
+ };
-Faye.Timeouts = {
- addTimeout: function(name, delay, callback, context) {
- this._timeouts = this._timeouts || {};
- if (this._timeouts.hasOwnProperty(name)) return;
- var self = this;
- this._timeouts[name] = Faye.ENV.setTimeout(function() {
- delete self._timeouts[name];
- callback.call(context);
- }, 1000 * delay);
- },
+ Promise.prototype.then = function(onFulfilled, onRejected) {
+ var next = new Promise();
+ registerOnFulfilled(this, onFulfilled, next);
+ registerOnRejected(this, onRejected, next);
+ return next;
+ };
- removeTimeout: function(name) {
- this._timeouts = this._timeouts || {};
- var timeout = this._timeouts[name];
- if (!timeout) return;
- Faye.ENV.clearTimeout(timeout);
- delete this._timeouts[name];
- },
+ Promise.prototype['catch'] = function(onRejected) {
+ return this.then(null, onRejected);
+ };
- removeAllTimeouts: function() {
- this._timeouts = this._timeouts || {};
- for (var name in this._timeouts) this.removeTimeout(name);
- }
-};
+ var registerOnFulfilled = function(promise, onFulfilled, next) {
+ if (typeof onFulfilled !== 'function') onFulfilled = RETURN;
+ var handler = function(value) { invoke(onFulfilled, value, next) };
-Faye.Logging = {
- LOG_LEVELS: {
- fatal: 4,
- error: 3,
- warn: 2,
- info: 1,
- debug: 0
- },
+ if (promise._state === PENDING) {
+ promise._onFulfilled.push(handler);
+ } else if (promise._state === FULFILLED) {
+ handler(promise._value);
+ }
+ };
- writeLog: function(messageArgs, level) {
- if (!Faye.logger) return;
+ var registerOnRejected = function(promise, onRejected, next) {
+ if (typeof onRejected !== 'function') onRejected = THROW;
+ var handler = function(reason) { invoke(onRejected, reason, next) };
- var args = Array.prototype.slice.apply(messageArgs),
- banner = '[Faye',
- klass = this.className,
+ if (promise._state === PENDING) {
+ promise._onRejected.push(handler);
+ } else if (promise._state === REJECTED) {
+ handler(promise._reason);
+ }
+ };
- message = args.shift().replace(/\?/g, function() {
- try {
- return Faye.toJSON(args.shift());
- } catch (e) {
- return '[Object]';
- }
- });
+ var invoke = function(fn, value, next) {
+ asap(function() { _invoke(fn, value, next) });
+ };
- for (var key in Faye) {
- if (klass) continue;
- if (typeof Faye[key] !== 'function') continue;
- if (this instanceof Faye[key]) klass = key;
+ var _invoke = function(fn, value, next) {
+ var outcome;
+
+ try {
+ outcome = fn(value);
+ } catch (error) {
+ return reject(next, error);
}
- if (klass) banner += '.' + klass;
- banner += '] ';
- if (typeof Faye.logger[level] === 'function')
- Faye.logger[level](banner + message);
- else if (typeof Faye.logger === 'function')
- Faye.logger(banner + message);
- }
-};
+ if (outcome === next) {
+ reject(next, new TypeError('Recursive promise chain detected'));
+ } else {
+ resolve(next, outcome);
+ }
+ };
-(function() {
- for (var key in Faye.Logging.LOG_LEVELS)
- (function(level) {
- Faye.Logging[level] = function() {
- this.writeLog(arguments, level);
- };
- })(key);
-})();
+ var resolve = function(promise, value) {
+ var called = false, type, then;
-Faye.Grammar = {
- CHANNEL_NAME: /^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,
- CHANNEL_PATTERN: /^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,
- ERROR: /^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/,
- VERSION: /^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/
-};
+ try {
+ type = typeof value;
+ then = value !== null && (type === 'function' || type === 'object') && value.then;
-Faye.Extensible = {
- addExtension: function(extension) {
- this._extensions = this._extensions || [];
- this._extensions.push(extension);
- if (extension.added) extension.added(this);
- },
+ if (typeof then !== 'function') return fulfill(promise, value);
- removeExtension: function(extension) {
- if (!this._extensions) return;
- var i = this._extensions.length;
- while (i--) {
- if (this._extensions[i] !== extension) continue;
- this._extensions.splice(i,1);
- if (extension.removed) extension.removed(this);
+ then.call(value, function(v) {
+ if (!(called ^ (called = true))) return;
+ resolve(promise, v);
+ }, function(r) {
+ if (!(called ^ (called = true))) return;
+ reject(promise, r);
+ });
+ } catch (error) {
+ if (!(called ^ (called = true))) return;
+ reject(promise, error);
}
- },
+ };
- pipeThroughExtensions: function(stage, message, request, callback, context) {
- this.debug('Passing through ? extensions: ?', stage, message);
+ var fulfill = function(promise, value) {
+ if (promise._state !== PENDING) return;
- if (!this._extensions) return callback.call(context, message);
- var extensions = this._extensions.slice();
+ promise._state = FULFILLED;
+ promise._value = value;
+ promise._onRejected = [];
- var pipe = function(message) {
- if (!message) return callback.call(context, message);
+ var onFulfilled = promise._onFulfilled, fn;
+ while (fn = onFulfilled.shift()) fn(value);
+ };
- var extension = extensions.shift();
- if (!extension) return callback.call(context, message);
+ var reject = function(promise, reason) {
+ if (promise._state !== PENDING) return;
- var fn = extension[stage];
- if (!fn) return pipe(message);
+ promise._state = REJECTED;
+ promise._reason = reason;
+ promise._onFulfilled = [];
- if (fn.length >= 3) extension[stage](message, request, pipe);
- else extension[stage](message, pipe);
- };
- pipe(message);
- }
-};
+ var onRejected = promise._onRejected, fn;
+ while (fn = onRejected.shift()) fn(reason);
+ };
-Faye.extend(Faye.Extensible, Faye.Logging);
+ Promise.resolve = function(value) {
+ return new Promise(function(resolve, reject) { resolve(value) });
+ };
-Faye.Channel = Faye.Class({
- initialize: function(name) {
- this.id = this.name = name;
- },
+ Promise.reject = function(reason) {
+ return new Promise(function(resolve, reject) { reject(reason) });
+ };
- push: function(message) {
- this.trigger('message', message);
- },
+ Promise.all = function(promises) {
+ return new Promise(function(resolve, reject) {
+ var list = [], n = promises.length, i;
- isUnused: function() {
- return this.countListeners('message') === 0;
- }
-});
+ if (n === 0) return resolve(list);
-Faye.extend(Faye.Channel.prototype, Faye.Publisher);
+ for (i = 0; i < n; i++) (function(promise, i) {
+ Promise.resolve(promise).then(function(value) {
+ list[i] = value;
+ if (--n === 0) resolve(list);
+ }, reject);
+ })(promises[i], i);
+ });
+ };
-Faye.extend(Faye.Channel, {
- HANDSHAKE: '/meta/handshake',
- CONNECT: '/meta/connect',
- SUBSCRIBE: '/meta/subscribe',
- UNSUBSCRIBE: '/meta/unsubscribe',
- DISCONNECT: '/meta/disconnect',
+ Promise.race = function(promises) {
+ return new Promise(function(resolve, reject) {
+ for (var i = 0, n = promises.length; i < n; i++)
+ Promise.resolve(promises[i]).then(resolve, reject);
+ });
+ };
- META: 'meta',
- SERVICE: 'service',
+ Promise.deferred = Promise.pending = function() {
+ var tuple = {};
- expand: function(name) {
- var segments = this.parse(name),
- channels = ['/**', name];
+ tuple.promise = new Promise(function(resolve, reject) {
+ tuple.resolve = resolve;
+ tuple.reject = reject;
+ });
+ return tuple;
+ };
- var copy = segments.slice();
- copy[copy.length - 1] = '*';
- channels.push(this.unparse(copy));
+ module.exports = Promise;
- for (var i = 1, n = segments.length; i < n; i++) {
- copy = segments.slice(0, i);
- copy.push('**');
- channels.push(this.unparse(copy));
- }
- return channels;
- },
+/***/ },
+/* 10 */
+/***/ function(module, exports) {
- isValid: function(name) {
- return Faye.Grammar.CHANNEL_NAME.test(name) ||
- Faye.Grammar.CHANNEL_PATTERN.test(name);
- },
+ 'use strict';
- parse: function(name) {
- if (!this.isValid(name)) return null;
- return name.split('/').slice(1);
- },
+ module.exports = {
+ isURI: function(uri) {
+ return uri && uri.protocol && uri.host && uri.path;
+ },
- unparse: function(segments) {
- return '/' + segments.join('/');
- },
+ isSameOrigin: function(uri) {
+ return uri.protocol === location.protocol &&
+ uri.hostname === location.hostname &&
+ uri.port === location.port;
+ },
- isMeta: function(name) {
- var segments = this.parse(name);
- return segments ? (segments[0] === this.META) : null;
- },
+ parse: function(url) {
+ if (typeof url !== 'string') return url;
+ var uri = {}, parts, query, pairs, i, n, data;
- isService: function(name) {
- var segments = this.parse(name);
- return segments ? (segments[0] === this.SERVICE) : null;
- },
+ var consume = function(name, pattern) {
+ url = url.replace(pattern, function(match) {
+ uri[name] = match;
+ return '';
+ });
+ uri[name] = uri[name] || '';
+ };
- isSubscribable: function(name) {
- if (!this.isValid(name)) return null;
- return !this.isMeta(name) && !this.isService(name);
- },
+ consume('protocol', /^[a-z]+\:/i);
+ consume('host', /^\/\/[^\/\?#]+/);
- Set: Faye.Class({
- initialize: function() {
- this._channels = {};
- },
+ if (!/^\//.test(url) && !uri.host)
+ url = location.pathname.replace(/[^\/]*$/, '') + url;
- getKeys: function() {
- var keys = [];
- for (var key in this._channels) keys.push(key);
- return keys;
+ consume('pathname', /^[^\?#]*/);
+ consume('search', /^\?[^#]*/);
+ consume('hash', /^#.*/);
+
+ uri.protocol = uri.protocol || location.protocol;
+
+ if (uri.host) {
+ uri.host = uri.host.substr(2);
+ parts = uri.host.split(':');
+ uri.hostname = parts[0];
+ uri.port = parts[1] || '';
+ } else {
+ uri.host = location.host;
+ uri.hostname = location.hostname;
+ uri.port = location.port;
+ }
+
+ uri.pathname = uri.pathname || '/';
+ uri.path = uri.pathname + uri.search;
+
+ query = uri.search.replace(/^\?/, '');
+ pairs = query ? query.split('&') : [];
+ data = {};
+
+ for (i = 0, n = pairs.length; i < n; i++) {
+ parts = pairs[i].split('=');
+ data[decodeURIComponent(parts[0] || '')] = decodeURIComponent(parts[1] || '');
+ }
+
+ uri.query = data;
+
+ uri.href = this.stringify(uri);
+ return uri;
},
- remove: function(name) {
- delete this._channels[name];
+ stringify: function(uri) {
+ var string = uri.protocol + '//' + uri.hostname;
+ if (uri.port) string += ':' + uri.port;
+ string += uri.pathname + this.queryString(uri.query) + (uri.hash || '');
+ return string;
},
- hasSubscription: function(name) {
- return this._channels.hasOwnProperty(name);
+ queryString: function(query) {
+ var pairs = [];
+ for (var key in query) {
+ if (!query.hasOwnProperty(key)) continue;
+ pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(query[key]));
+ }
+ if (pairs.length === 0) return '';
+ return '?' + pairs.join('&');
+ }
+ };
+
+
+/***/ },
+/* 11 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ module.exports = {
+ commonElement: function(lista, listb) {
+ for (var i = 0, n = lista.length; i < n; i++) {
+ if (this.indexOf(listb, lista[i]) !== -1)
+ return lista[i];
+ }
+ return null;
},
- subscribe: function(names, callback, context) {
- var name;
- for (var i = 0, n = names.length; i < n; i++) {
- name = names[i];
- var channel = this._channels[name] = this._channels[name] || new Faye.Channel(name);
- if (callback) channel.bind('message', callback, context);
+ indexOf: function(list, needle) {
+ if (list.indexOf) return list.indexOf(needle);
+
+ for (var i = 0, n = list.length; i < n; i++) {
+ if (list[i] === needle) return i;
}
+ return -1;
},
- unsubscribe: function(name, callback, context) {
- var channel = this._channels[name];
- if (!channel) return false;
- channel.unbind('message', callback, context);
+ map: function(object, callback, context) {
+ if (object.map) return object.map(callback, context);
+ var result = [];
- if (channel.isUnused()) {
- this.remove(name);
- return true;
+ if (object instanceof Array) {
+ for (var i = 0, n = object.length; i < n; i++) {
+ result.push(callback.call(context || null, object[i], i));
+ }
} else {
- return false;
+ for (var key in object) {
+ if (!object.hasOwnProperty(key)) continue;
+ result.push(callback.call(context || null, key, object[key]));
+ }
}
+ return result;
},
- distributeMessage: function(message) {
- var channels = Faye.Channel.expand(message.channel);
-
- for (var i = 0, n = channels.length; i < n; i++) {
- var channel = this._channels[channels[i]];
- if (channel) channel.trigger('message', message.data);
+ filter: function(array, callback, context) {
+ if (array.filter) return array.filter(callback, context);
+ var result = [];
+ for (var i = 0, n = array.length; i < n; i++) {
+ if (callback.call(context || null, array[i], i))
+ result.push(array[i]);
}
- }
- })
-});
+ return result;
+ },
-Faye.Publication = Faye.Class(Faye.Deferrable);
+ asyncEach: function(list, iterator, callback, context) {
+ var n = list.length,
+ i = -1,
+ calls = 0,
+ looping = false;
-Faye.Subscription = Faye.Class({
- initialize: function(client, channels, callback, context) {
- this._client = client;
- this._channels = channels;
- this._callback = callback;
- this._context = context;
- this._cancelled = false;
- },
+ var iterate = function() {
+ calls -= 1;
+ i += 1;
+ if (i === n) return callback && callback.call(context);
+ iterator(list[i], resume);
+ };
- cancel: function() {
- if (this._cancelled) return;
- this._client.unsubscribe(this._channels, this._callback, this._context);
- this._cancelled = true;
- },
+ var loop = function() {
+ if (looping) return;
+ looping = true;
+ while (calls > 0) iterate();
+ looping = false;
+ };
- unsubscribe: function() {
- this.cancel();
- }
-});
+ var resume = function() {
+ calls += 1;
+ loop();
+ };
+ resume();
+ }
+ };
-Faye.extend(Faye.Subscription.prototype, Faye.Deferrable);
-Faye.Client = Faye.Class({
- UNCONNECTED: 1,
- CONNECTING: 2,
- CONNECTED: 3,
- DISCONNECTED: 4,
+/***/ },
+/* 12 */
+/***/ function(module, exports) {
- HANDSHAKE: 'handshake',
- RETRY: 'retry',
- NONE: 'none',
+ /* WEBPACK VAR INJECTION */(function(global) {'use strict';
- CONNECTION_TIMEOUT: 60,
+ var Event = {
+ _registry: [],
- DEFAULT_ENDPOINT: '/bayeux',
- INTERVAL: 0,
+ on: function(element, eventName, callback, context) {
+ var wrapped = function() { callback.call(context) };
- initialize: function(endpoint, options) {
- this.info('New client created for ?', endpoint);
- options = options || {};
+ if (element.addEventListener)
+ element.addEventListener(eventName, wrapped, false);
+ else
+ element.attachEvent('on' + eventName, wrapped);
- this._endpoint = endpoint || this.DEFAULT_ENDPOINT;
- this._channels = new Faye.Channel.Set();
- this._dispatcher = new Faye.Dispatcher(this, this._endpoint, options);
+ this._registry.push({
+ _element: element,
+ _type: eventName,
+ _callback: callback,
+ _context: context,
+ _handler: wrapped
+ });
+ },
- this._messageId = 0;
- this._state = this.UNCONNECTED;
+ detach: function(element, eventName, callback, context) {
+ var i = this._registry.length, register;
+ while (i--) {
+ register = this._registry[i];
- this._responseCallbacks = {};
+ if ((element && element !== register._element) ||
+ (eventName && eventName !== register._type) ||
+ (callback && callback !== register._callback) ||
+ (context && context !== register._context))
+ continue;
- this._advice = {
- reconnect: this.RETRY,
- interval: 1000 * (options.interval || this.INTERVAL),
- timeout: 1000 * (options.timeout || this.CONNECTION_TIMEOUT)
- };
- this._dispatcher.timeout = this._advice.timeout / 1000;
+ if (register._element.removeEventListener)
+ register._element.removeEventListener(register._type, register._handler, false);
+ else
+ register._element.detachEvent('on' + register._type, register._handler);
- this._dispatcher.bind('message', this._receiveMessage, this);
+ this._registry.splice(i,1);
+ register = null;
+ }
+ }
+ };
- if (Faye.Event && Faye.ENV.onbeforeunload !== undefined)
- Faye.Event.on(Faye.ENV, 'beforeunload', function() {
- if (Faye.indexOf(this._dispatcher._disabled, 'autodisconnect') < 0)
- this.disconnect();
- }, this);
- },
+ if (global.onunload !== undefined)
+ Event.on(global, 'unload', Event.detach, Event);
- disable: function(feature) {
- return this._dispatcher.disable(feature);
- },
+ module.exports = {
+ Event: Event
+ };
- setHeader: function(name, value) {
- return this._dispatcher.setHeader(name, value);
- },
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
- // Request
- // MUST include: * channel
- // * version
- // * supportedConnectionTypes
- // MAY include: * minimumVersion
- // * ext
- // * id
- //
- // Success Response Failed Response
- // MUST include: * channel MUST include: * channel
- // * version * successful
- // * supportedConnectionTypes * error
- // * clientId MAY include: * supportedConnectionTypes
- // * successful * advice
- // MAY include: * minimumVersion * version
- // * advice * minimumVersion
- // * ext * ext
- // * id * id
- // * authSuccessful
- handshake: function(callback, context) {
- if (this._advice.reconnect === this.NONE) return;
- if (this._state !== this.UNCONNECTED) return;
+/***/ },
+/* 13 */
+/***/ function(module, exports, __webpack_require__) {
- this._state = this.CONNECTING;
- var self = this;
+ 'use strict';
- this.info('Initiating handshake with ?', Faye.URI.stringify(this._endpoint));
- this._dispatcher.selectTransport(Faye.MANDATORY_CONNECTION_TYPES);
+ var array = __webpack_require__(11);
- this._sendMessage({
- channel: Faye.Channel.HANDSHAKE,
- version: Faye.BAYEUX_VERSION,
- supportedConnectionTypes: [this._dispatcher.connectionType]
+ module.exports = function(options, validKeys) {
+ for (var key in options) {
+ if (array.indexOf(validKeys, key) < 0)
+ throw new Error('Unrecognized option: ' + key);
+ }
+ };
- }, {}, function(response) {
- if (response.successful) {
- this._state = this.CONNECTED;
- this._dispatcher.clientId = response.clientId;
+/***/ },
+/* 14 */
+/***/ function(module, exports, __webpack_require__) {
- this._dispatcher.selectTransport(response.supportedConnectionTypes);
+ /* WEBPACK VAR INJECTION */(function(global) {'use strict';
- this.info('Handshake successful: ?', this._dispatcher.clientId);
+ var Promise = __webpack_require__(9);
- this.subscribe(this._channels.getKeys(), true);
- if (callback) Faye.Promise.defer(function() { callback.call(context) });
+ module.exports = {
+ then: function(callback, errback) {
+ var self = this;
+ if (!this._promise)
+ this._promise = new Promise(function(resolve, reject) {
+ self._resolve = resolve;
+ self._reject = reject;
+ });
- } else {
- this.info('Handshake unsuccessful');
- Faye.ENV.setTimeout(function() { self.handshake(callback, context) }, this._dispatcher.retry * 1000);
- this._state = this.UNCONNECTED;
- }
- }, this);
- },
+ if (arguments.length === 0)
+ return this._promise;
+ else
+ return this._promise.then(callback, errback);
+ },
- // Request Response
- // MUST include: * channel MUST include: * channel
- // * clientId * successful
- // * connectionType * clientId
- // MAY include: * ext MAY include: * error
- // * id * advice
- // * ext
- // * id
- // * timestamp
- connect: function(callback, context) {
- if (this._advice.reconnect === this.NONE) return;
- if (this._state === this.DISCONNECTED) return;
+ callback: function(callback, context) {
+ return this.then(function(value) { callback.call(context, value) });
+ },
- if (this._state === this.UNCONNECTED)
- return this.handshake(function() { this.connect(callback, context) }, this);
+ errback: function(callback, context) {
+ return this.then(null, function(reason) { callback.call(context, reason) });
+ },
- this.callback(callback, context);
- if (this._state !== this.CONNECTED) return;
+ timeout: function(seconds, message) {
+ this.then();
+ var self = this;
+ this._timer = global.setTimeout(function() {
+ self._reject(message);
+ }, seconds * 1000);
+ },
- this.info('Calling deferred actions for ?', this._dispatcher.clientId);
- this.setDeferredStatus('succeeded');
- this.setDeferredStatus('unknown');
+ setDeferredStatus: function(status, value) {
+ if (this._timer) global.clearTimeout(this._timer);
- if (this._connectRequest) return;
- this._connectRequest = true;
+ this.then();
- this.info('Initiating connection for ?', this._dispatcher.clientId);
+ if (status === 'succeeded')
+ this._resolve(value);
+ else if (status === 'failed')
+ this._reject(value);
+ else
+ delete this._promise;
+ }
+ };
- this._sendMessage({
- channel: Faye.Channel.CONNECT,
- clientId: this._dispatcher.clientId,
- connectionType: this._dispatcher.connectionType
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
- }, {}, this._cycleConnection, this);
- },
+/***/ },
+/* 15 */
+/***/ function(module, exports, __webpack_require__) {
- // Request Response
- // MUST include: * channel MUST include: * channel
- // * clientId * successful
- // MAY include: * ext * clientId
- // * id MAY include: * error
- // * ext
- // * id
- disconnect: function() {
- if (this._state !== this.CONNECTED) return;
- this._state = this.DISCONNECTED;
+ 'use strict';
- this.info('Disconnecting ?', this._dispatcher.clientId);
+ var extend = __webpack_require__(8),
+ EventEmitter = __webpack_require__(16);
- this._sendMessage({
- channel: Faye.Channel.DISCONNECT,
- clientId: this._dispatcher.clientId
+ var Publisher = {
+ countListeners: function(eventType) {
+ return this.listeners(eventType).length;
+ },
- }, {}, function(response) {
- if (response.successful) this._dispatcher.close();
- }, this);
+ bind: function(eventType, listener, context) {
+ var slice = Array.prototype.slice,
+ handler = function() { listener.apply(context, slice.call(arguments)) };
- this.info('Clearing channel listeners for ?', this._dispatcher.clientId);
- this._channels = new Faye.Channel.Set();
- },
+ this._listeners = this._listeners || [];
+ this._listeners.push([eventType, listener, context, handler]);
+ return this.on(eventType, handler);
+ },
- // Request Response
- // MUST include: * channel MUST include: * channel
- // * clientId * successful
- // * subscription * clientId
- // MAY include: * ext * subscription
- // * id MAY include: * error
- // * advice
- // * ext
- // * id
- // * timestamp
- subscribe: function(channel, callback, context) {
- if (channel instanceof Array)
- return Faye.map(channel, function(c) {
- return this.subscribe(c, callback, context);
- }, this);
+ unbind: function(eventType, listener, context) {
+ this._listeners = this._listeners || [];
+ var n = this._listeners.length, tuple;
- var subscription = new Faye.Subscription(this, channel, callback, context),
- force = (callback === true),
- hasSubscribe = this._channels.hasSubscription(channel);
-
- if (hasSubscribe && !force) {
- this._channels.subscribe([channel], callback, context);
- subscription.setDeferredStatus('succeeded');
- return subscription;
+ while (n--) {
+ tuple = this._listeners[n];
+ if (tuple[0] !== eventType) continue;
+ if (listener && (tuple[1] !== listener || tuple[2] !== context)) continue;
+ this._listeners.splice(n, 1);
+ this.removeListener(eventType, tuple[3]);
+ }
}
+ };
- this.connect(function() {
- this.info('Client ? attempting to subscribe to ?', this._dispatcher.clientId, channel);
- if (!force) this._channels.subscribe([channel], callback, context);
+ extend(Publisher, EventEmitter.prototype);
+ Publisher.trigger = Publisher.emit;
- this._sendMessage({
- channel: Faye.Channel.SUBSCRIBE,
- clientId: this._dispatcher.clientId,
- subscription: channel
+ module.exports = Publisher;
- }, {}, function(response) {
- if (!response.successful) {
- subscription.setDeferredStatus('failed', Faye.Error.parse(response.error));
- return this._channels.unsubscribe(channel, callback, context);
- }
- var channels = [].concat(response.subscription);
- this.info('Subscription acknowledged for ? to ?', this._dispatcher.clientId, channels);
- subscription.setDeferredStatus('succeeded');
- }, this);
- }, this);
+/***/ },
+/* 16 */
+/***/ function(module, exports) {
- return subscription;
- },
+ /*
+ Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
+ this software and associated documentation files (the "Software"), to deal in
+ the Software without restriction, including without limitation the rights to
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
- // Request Response
- // MUST include: * channel MUST include: * channel
- // * clientId * successful
- // * subscription * clientId
- // MAY include: * ext * subscription
- // * id MAY include: * error
- // * advice
- // * ext
- // * id
- // * timestamp
- unsubscribe: function(channel, callback, context) {
- if (channel instanceof Array)
- return Faye.map(channel, function(c) {
- return this.unsubscribe(c, callback, context);
- }, this);
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
- var dead = this._channels.unsubscribe(channel, callback, context);
- if (!dead) return;
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ */
- this.connect(function() {
- this.info('Client ? attempting to unsubscribe from ?', this._dispatcher.clientId, channel);
+ var isArray = typeof Array.isArray === 'function'
+ ? Array.isArray
+ : function (xs) {
+ return Object.prototype.toString.call(xs) === '[object Array]'
+ }
+ ;
+ function indexOf (xs, x) {
+ if (xs.indexOf) return xs.indexOf(x);
+ for (var i = 0; i < xs.length; i++) {
+ if (x === xs[i]) return i;
+ }
+ return -1;
+ }
- this._sendMessage({
- channel: Faye.Channel.UNSUBSCRIBE,
- clientId: this._dispatcher.clientId,
- subscription: channel
+ function EventEmitter() {}
+ module.exports = EventEmitter;
- }, {}, function(response) {
- if (!response.successful) return;
+ EventEmitter.prototype.emit = function(type) {
+ // If there is no 'error' event listener then throw.
+ if (type === 'error') {
+ if (!this._events || !this._events.error ||
+ (isArray(this._events.error) && !this._events.error.length))
+ {
+ if (arguments[1] instanceof Error) {
+ throw arguments[1]; // Unhandled 'error' event
+ } else {
+ throw new Error("Uncaught, unspecified 'error' event.");
+ }
+ return false;
+ }
+ }
- var channels = [].concat(response.subscription);
- this.info('Unsubscription acknowledged for ? from ?', this._dispatcher.clientId, channels);
- }, this);
- }, this);
- },
+ if (!this._events) return false;
+ var handler = this._events[type];
+ if (!handler) return false;
- // Request Response
- // MUST include: * channel MUST include: * channel
- // * data * successful
- // MAY include: * clientId MAY include: * id
- // * id * error
- // * ext * ext
- publish: function(channel, data, options) {
- var publication = new Faye.Publication();
+ if (typeof handler == 'function') {
+ switch (arguments.length) {
+ // fast cases
+ case 1:
+ handler.call(this);
+ break;
+ case 2:
+ handler.call(this, arguments[1]);
+ break;
+ case 3:
+ handler.call(this, arguments[1], arguments[2]);
+ break;
+ // slower
+ default:
+ var args = Array.prototype.slice.call(arguments, 1);
+ handler.apply(this, args);
+ }
+ return true;
- this.connect(function() {
- this.info('Client ? queueing published message to ?: ?', this._dispatcher.clientId, channel, data);
+ } else if (isArray(handler)) {
+ var args = Array.prototype.slice.call(arguments, 1);
- this._sendMessage({
- channel: channel,
- data: data,
- clientId: this._dispatcher.clientId
+ var listeners = handler.slice();
+ for (var i = 0, l = listeners.length; i < l; i++) {
+ listeners[i].apply(this, args);
+ }
+ return true;
- }, options, function(response) {
- if (response.successful)
- publication.setDeferredStatus('succeeded');
- else
- publication.setDeferredStatus('failed', Faye.Error.parse(response.error));
- }, this);
- }, this);
+ } else {
+ return false;
+ }
+ };
- return publication;
- },
+ // EventEmitter is defined in src/node_events.cc
+ // EventEmitter.prototype.emit() is also defined there.
+ EventEmitter.prototype.addListener = function(type, listener) {
+ if ('function' !== typeof listener) {
+ throw new Error('addListener only takes instances of Function');
+ }
- _sendMessage: function(message, options, callback, context) {
- message.id = this._generateMessageId();
+ if (!this._events) this._events = {};
- var timeout = this._advice.timeout
- ? 1.2 * this._advice.timeout / 1000
- : 1.2 * this._dispatcher.retry;
+ // To avoid recursion in the case that type == "newListeners"! Before
+ // adding it to the listeners, first emit "newListeners".
+ this.emit('newListener', type, listener);
- this.pipeThroughExtensions('outgoing', message, null, function(message) {
- if (!message) return;
- if (callback) this._responseCallbacks[message.id] = [callback, context];
- this._dispatcher.sendMessage(message, timeout, options || {});
- }, this);
- },
+ if (!this._events[type]) {
+ // Optimize the case of one listener. Don't need the extra array object.
+ this._events[type] = listener;
+ } else if (isArray(this._events[type])) {
+ // If we've already got an array, just append.
+ this._events[type].push(listener);
+ } else {
+ // Adding the second element, need to change to array.
+ this._events[type] = [this._events[type], listener];
+ }
- _generateMessageId: function() {
- this._messageId += 1;
- if (this._messageId >= Math.pow(2,32)) this._messageId = 0;
- return this._messageId.toString(36);
- },
+ return this;
+ };
- _receiveMessage: function(message) {
- var id = message.id, callback;
+ EventEmitter.prototype.on = EventEmitter.prototype.addListener;
- if (message.successful !== undefined) {
- callback = this._responseCallbacks[id];
- delete this._responseCallbacks[id];
+ EventEmitter.prototype.once = function(type, listener) {
+ var self = this;
+ self.on(type, function g() {
+ self.removeListener(type, g);
+ listener.apply(this, arguments);
+ });
+
+ return this;
+ };
+
+ EventEmitter.prototype.removeListener = function(type, listener) {
+ if ('function' !== typeof listener) {
+ throw new Error('removeListener only takes instances of Function');
}
- this.pipeThroughExtensions('incoming', message, null, function(message) {
- if (!message) return;
- if (message.advice) this._handleAdvice(message.advice);
- this._deliverMessage(message);
- if (callback) callback[0].call(callback[1], message);
- }, this);
- },
+ // does not use listeners(), so no side effect of creating _events[type]
+ if (!this._events || !this._events[type]) return this;
- _handleAdvice: function(advice) {
- Faye.extend(this._advice, advice);
- this._dispatcher.timeout = this._advice.timeout / 1000;
+ var list = this._events[type];
- if (this._advice.reconnect === this.HANDSHAKE && this._state !== this.DISCONNECTED) {
- this._state = this.UNCONNECTED;
- this._dispatcher.clientId = null;
- this._cycleConnection();
+ if (isArray(list)) {
+ var i = indexOf(list, listener);
+ if (i < 0) return this;
+ list.splice(i, 1);
+ if (list.length == 0)
+ delete this._events[type];
+ } else if (this._events[type] === listener) {
+ delete this._events[type];
}
- },
- _deliverMessage: function(message) {
- if (!message.channel || message.data === undefined) return;
- this.info('Client ? calling listeners for ? with ?', this._dispatcher.clientId, message.channel, message.data);
- this._channels.distributeMessage(message);
- },
+ return this;
+ };
- _cycleConnection: function() {
- if (this._connectRequest) {
- this._connectRequest = null;
- this.info('Closed connection for ?', this._dispatcher.clientId);
+ EventEmitter.prototype.removeAllListeners = function(type) {
+ if (arguments.length === 0) {
+ this._events = {};
+ return this;
}
- var self = this;
- Faye.ENV.setTimeout(function() { self.connect() }, this._advice.interval);
- }
-});
-Faye.extend(Faye.Client.prototype, Faye.Deferrable);
-Faye.extend(Faye.Client.prototype, Faye.Publisher);
-Faye.extend(Faye.Client.prototype, Faye.Logging);
-Faye.extend(Faye.Client.prototype, Faye.Extensible);
+ // does not use listeners(), so no side effect of creating _events[type]
+ if (type && this._events && this._events[type]) this._events[type] = null;
+ return this;
+ };
-Faye.Dispatcher = Faye.Class({
- MAX_REQUEST_SIZE: 2048,
- DEFAULT_RETRY: 5,
+ EventEmitter.prototype.listeners = function(type) {
+ if (!this._events) this._events = {};
+ if (!this._events[type]) this._events[type] = [];
+ if (!isArray(this._events[type])) {
+ this._events[type] = [this._events[type]];
+ }
+ return this._events[type];
+ };
- UP: 1,
- DOWN: 2,
- initialize: function(client, endpoint, options) {
- this._client = client;
- this.endpoint = Faye.URI.parse(endpoint);
- this._alternates = options.endpoints || {};
+/***/ },
+/* 17 */
+/***/ function(module, exports, __webpack_require__) {
- this.ca = options.ca;
- this.cookies = Faye.Cookies && new Faye.Cookies.CookieJar();
- this._disabled = [];
- this._envelopes = {};
- this.headers = {};
- this.retry = options.retry || this.DEFAULT_RETRY;
- this._state = 0;
- this.transports = {};
+ 'use strict';
- for (var type in this._alternates)
- this._alternates[type] = Faye.URI.parse(this._alternates[type]);
+ var Class = __webpack_require__(7),
+ extend = __webpack_require__(8),
+ Publisher = __webpack_require__(15),
+ Grammar = __webpack_require__(18);
- this.maxRequestSize = this.MAX_REQUEST_SIZE;
- },
+ var Channel = Class({
+ initialize: function(name) {
+ this.id = this.name = name;
+ },
- endpointFor: function(connectionType) {
- return this._alternates[connectionType] || this.endpoint;
- },
+ push: function(message) {
+ this.trigger('message', message);
+ },
- disable: function(feature) {
- this._disabled.push(feature);
- },
+ isUnused: function() {
+ return this.countListeners('message') === 0;
+ }
+ });
- setHeader: function(name, value) {
- this.headers[name] = value;
- },
+ extend(Channel.prototype, Publisher);
- close: function() {
- var transport = this._transport;
- delete this._transport;
- if (transport) transport.close();
- },
+ extend(Channel, {
+ HANDSHAKE: '/meta/handshake',
+ CONNECT: '/meta/connect',
+ SUBSCRIBE: '/meta/subscribe',
+ UNSUBSCRIBE: '/meta/unsubscribe',
+ DISCONNECT: '/meta/disconnect',
- selectTransport: function(transportTypes) {
- Faye.Transport.get(this, transportTypes, this._disabled, function(transport) {
- this.debug('Selected ? transport for ?', transport.connectionType, Faye.URI.stringify(transport.endpoint));
+ META: 'meta',
+ SERVICE: 'service',
- if (transport === this._transport) return;
- if (this._transport) this._transport.close();
+ expand: function(name) {
+ var segments = this.parse(name),
+ channels = ['/**', name];
- this._transport = transport;
- this.connectionType = transport.connectionType;
- }, this);
- },
+ var copy = segments.slice();
+ copy[copy.length - 1] = '*';
+ channels.push(this.unparse(copy));
- sendMessage: function(message, timeout, options) {
- if (!this._transport) return;
- options = options || {};
+ for (var i = 1, n = segments.length; i < n; i++) {
+ copy = segments.slice(0, i);
+ copy.push('**');
+ channels.push(this.unparse(copy));
+ }
- var self = this,
- id = message.id,
- attempts = options.attempts,
- deadline = options.deadline && new Date().getTime() + (options.deadline * 1000),
+ return channels;
+ },
- envelope = this._envelopes[id] = this._envelopes[id] ||
- {message: message, timeout: timeout, attempts: attempts, deadline: deadline};
+ isValid: function(name) {
+ return Grammar.CHANNEL_NAME.test(name) ||
+ Grammar.CHANNEL_PATTERN.test(name);
+ },
- if (envelope.request || envelope.timer) return;
+ parse: function(name) {
+ if (!this.isValid(name)) return null;
+ return name.split('/').slice(1);
+ },
- if (this._attemptsExhausted(envelope) || this._deadlinePassed(envelope)) {
- delete this._envelopes[id];
- return;
- }
+ unparse: function(segments) {
+ return '/' + segments.join('/');
+ },
- envelope.timer = Faye.ENV.setTimeout(function() {
- self.handleError(message);
- }, timeout * 1000);
+ isMeta: function(name) {
+ var segments = this.parse(name);
+ return segments ? (segments[0] === this.META) : null;
+ },
- envelope.request = this._transport.sendMessage(message);
- },
+ isService: function(name) {
+ var segments = this.parse(name);
+ return segments ? (segments[0] === this.SERVICE) : null;
+ },
- handleResponse: function(reply) {
- var envelope = this._envelopes[reply.id];
+ isSubscribable: function(name) {
+ if (!this.isValid(name)) return null;
+ return !this.isMeta(name) && !this.isService(name);
+ },
- if (reply.successful !== undefined && envelope) {
- delete this._envelopes[reply.id];
- Faye.ENV.clearTimeout(envelope.timer);
- }
+ Set: Class({
+ initialize: function() {
+ this._channels = {};
+ },
- this.trigger('message', reply);
+ getKeys: function() {
+ var keys = [];
+ for (var key in this._channels) keys.push(key);
+ return keys;
+ },
- if (this._state === this.UP) return;
- this._state = this.UP;
- this._client.trigger('transport:up');
- },
+ remove: function(name) {
+ delete this._channels[name];
+ },
- handleError: function(message, immediate) {
- var envelope = this._envelopes[message.id],
- request = envelope && envelope.request,
- self = this;
+ hasSubscription: function(name) {
+ return this._channels.hasOwnProperty(name);
+ },
- if (!request) return;
+ subscribe: function(names, subscription) {
+ var name;
+ for (var i = 0, n = names.length; i < n; i++) {
+ name = names[i];
+ var channel = this._channels[name] = this._channels[name] || new Channel(name);
+ channel.bind('message', subscription);
+ }
+ },
- request.then(function(req) {
- if (req && req.abort) req.abort();
- });
+ unsubscribe: function(name, subscription) {
+ var channel = this._channels[name];
+ if (!channel) return false;
+ channel.unbind('message', subscription);
- Faye.ENV.clearTimeout(envelope.timer);
- envelope.request = envelope.timer = null;
+ if (channel.isUnused()) {
+ this.remove(name);
+ return true;
+ } else {
+ return false;
+ }
+ },
- if (immediate) {
- this.sendMessage(envelope.message, envelope.timeout);
- } else {
- envelope.timer = Faye.ENV.setTimeout(function() {
- envelope.timer = null;
- self.sendMessage(envelope.message, envelope.timeout);
- }, this.retry * 1000);
- }
+ distributeMessage: function(message) {
+ var channels = Channel.expand(message.channel);
- if (this._state === this.DOWN) return;
- this._state = this.DOWN;
- this._client.trigger('transport:down');
- },
+ for (var i = 0, n = channels.length; i < n; i++) {
+ var channel = this._channels[channels[i]];
+ if (channel) channel.trigger('message', message);
+ }
+ }
+ })
+ });
- _attemptsExhausted: function(envelope) {
- if (envelope.attempts === undefined) return false;
- envelope.attempts -= 1;
- if (envelope.attempts >= 0) return false;
- return true;
- },
+ module.exports = Channel;
- _deadlinePassed: function(envelope) {
- var deadline = envelope.deadline;
- if (deadline === undefined) return false;
- if (new Date().getTime() <= deadline) return false;
- return true;
- }
-});
-Faye.extend(Faye.Dispatcher.prototype, Faye.Publisher);
-Faye.extend(Faye.Dispatcher.prototype, Faye.Logging);
+/***/ },
+/* 18 */
+/***/ function(module, exports) {
-Faye.Transport = Faye.extend(Faye.Class({
- MAX_DELAY: 0,
- batching: true,
+ 'use strict';
- initialize: function(dispatcher, endpoint) {
- this._dispatcher = dispatcher;
- this.endpoint = endpoint;
- this._outbox = [];
- },
+ module.exports = {
+ CHANNEL_NAME: /^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,
+ CHANNEL_PATTERN: /^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,
+ ERROR: /^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/,
+ VERSION: /^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/
+ };
- close: function() {},
- encode: function(messages) {
- return '';
- },
+/***/ },
+/* 19 */
+/***/ function(module, exports, __webpack_require__) {
- sendMessage: function(message) {
- this.debug('Client ? sending message to ?: ?',
- this._dispatcher.clientId, Faye.URI.stringify(this.endpoint), message);
+ /* WEBPACK VAR INJECTION */(function(global) {'use strict';
- if (!this.batching) return Faye.Promise.fulfilled(this.request([message]));
+ var Class = __webpack_require__(7),
+ URI = __webpack_require__(10),
+ cookies = __webpack_require__(20),
+ extend = __webpack_require__(8),
+ Logging = __webpack_require__(2),
+ Publisher = __webpack_require__(15),
+ Transport = __webpack_require__(21),
+ Scheduler = __webpack_require__(32);
- this._outbox.push(message);
- this._flushLargeBatch();
- this._promise = this._promise || new Faye.Promise();
+ var Dispatcher = Class({ className: 'Dispatcher',
+ MAX_REQUEST_SIZE: 2048,
+ DEFAULT_RETRY: 5,
- if (message.channel === Faye.Channel.HANDSHAKE) {
- this.addTimeout('publish', 0.01, this._flush, this);
- return this._promise;
- }
+ UP: 1,
+ DOWN: 2,
- if (message.channel === Faye.Channel.CONNECT)
- this._connectMessage = message;
+ initialize: function(client, endpoint, options) {
+ this._client = client;
+ this.endpoint = URI.parse(endpoint);
+ this._alternates = options.endpoints || {};
- this.addTimeout('publish', this.MAX_DELAY, this._flush, this);
- return this._promise;
- },
+ this.cookies = cookies.CookieJar && new cookies.CookieJar();
+ this._disabled = [];
+ this._envelopes = {};
+ this.headers = {};
+ this.retry = options.retry || this.DEFAULT_RETRY;
+ this._scheduler = options.scheduler || Scheduler;
+ this._state = 0;
+ this.transports = {};
+ this.wsExtensions = [];
- _flush: function() {
- this.removeTimeout('publish');
+ this.proxy = options.proxy || {};
+ if (typeof this._proxy === 'string') this._proxy = {origin: this._proxy};
- if (this._outbox.length > 1 && this._connectMessage)
- this._connectMessage.advice = {timeout: 0};
+ var exts = options.websocketExtensions;
+ if (exts) {
+ exts = [].concat(exts);
+ for (var i = 0, n = exts.length; i < n; i++)
+ this.addWebsocketExtension(exts[i]);
+ }
- Faye.Promise.fulfill(this._promise, this.request(this._outbox));
- delete this._promise;
+ this.tls = options.tls || {};
+ this.tls.ca = this.tls.ca || options.ca;
- this._connectMessage = null;
- this._outbox = [];
- },
+ for (var type in this._alternates)
+ this._alternates[type] = URI.parse(this._alternates[type]);
- _flushLargeBatch: function() {
- var string = this.encode(this._outbox);
- if (string.length < this._dispatcher.maxRequestSize) return;
- var last = this._outbox.pop();
- this._flush();
- if (last) this._outbox.push(last);
- },
+ this.maxRequestSize = this.MAX_REQUEST_SIZE;
+ },
- _receive: function(replies) {
- replies = [].concat(replies);
+ endpointFor: function(connectionType) {
+ return this._alternates[connectionType] || this.endpoint;
+ },
- this.debug('Client ? received from ? via ?: ?',
- this._dispatcher.clientId, Faye.URI.stringify(this.endpoint), this.connectionType, replies);
+ addWebsocketExtension: function(extension) {
+ this.wsExtensions.push(extension);
+ },
- for (var i = 0, n = replies.length; i < n; i++)
- this._dispatcher.handleResponse(replies[i]);
- },
+ disable: function(feature) {
+ this._disabled.push(feature);
+ },
- _handleError: function(messages, immediate) {
- messages = [].concat(messages);
+ setHeader: function(name, value) {
+ this.headers[name] = value;
+ },
- this.debug('Client ? failed to send to ? via ?: ?',
- this._dispatcher.clientId, Faye.URI.stringify(this.endpoint), this.connectionType, messages);
+ close: function() {
+ var transport = this._transport;
+ delete this._transport;
+ if (transport) transport.close();
+ },
- for (var i = 0, n = messages.length; i < n; i++)
- this._dispatcher.handleError(messages[i]);
- },
+ getConnectionTypes: function() {
+ return Transport.getConnectionTypes();
+ },
- _getCookies: function() {
- var cookies = this._dispatcher.cookies,
- url = Faye.URI.stringify(this.endpoint);
+ selectTransport: function(transportTypes) {
+ Transport.get(this, transportTypes, this._disabled, function(transport) {
+ this.debug('Selected ? transport for ?', transport.connectionType, URI.stringify(transport.endpoint));
- if (!cookies) return '';
+ if (transport === this._transport) return;
+ if (this._transport) this._transport.close();
- return Faye.map(cookies.getCookiesSync(url), function(cookie) {
- return cookie.cookieString();
- }).join('; ');
- },
+ this._transport = transport;
+ this.connectionType = transport.connectionType;
+ }, this);
+ },
- _storeCookies: function(setCookie) {
- var cookies = this._dispatcher.cookies,
- url = Faye.URI.stringify(this.endpoint),
- cookie;
+ sendMessage: function(message, timeout, options) {
+ options = options || {};
- if (!setCookie || !cookies) return;
- setCookie = [].concat(setCookie);
+ var id = message.id,
+ attempts = options.attempts,
+ deadline = options.deadline && new Date().getTime() + (options.deadline * 1000),
+ envelope = this._envelopes[id],
+ scheduler;
- for (var i = 0, n = setCookie.length; i < n; i++) {
- cookie = Faye.Cookies.Cookie.parse(setCookie[i]);
- cookies.setCookieSync(cookie, url);
- }
- }
+ if (!envelope) {
+ scheduler = new this._scheduler(message, {timeout: timeout, interval: this.retry, attempts: attempts, deadline: deadline});
+ envelope = this._envelopes[id] = {message: message, scheduler: scheduler};
+ }
-}), {
- get: function(dispatcher, allowed, disabled, callback, context) {
- var endpoint = dispatcher.endpoint;
+ this._sendEnvelope(envelope);
+ },
- Faye.asyncEach(this._transports, function(pair, resume) {
- var connType = pair[0], klass = pair[1],
- connEndpoint = dispatcher.endpointFor(connType);
+ _sendEnvelope: function(envelope) {
+ if (!this._transport) return;
+ if (envelope.request || envelope.timer) return;
- if (Faye.indexOf(disabled, connType) >= 0)
- return resume();
+ var message = envelope.message,
+ scheduler = envelope.scheduler,
+ self = this;
- if (Faye.indexOf(allowed, connType) < 0) {
- klass.isUsable(dispatcher, connEndpoint, function() {});
- return resume();
+ if (!scheduler.isDeliverable()) {
+ scheduler.abort();
+ delete this._envelopes[message.id];
+ return;
}
- klass.isUsable(dispatcher, connEndpoint, function(isUsable) {
- if (!isUsable) return resume();
- var transport = klass.hasOwnProperty('create') ? klass.create(dispatcher, connEndpoint) : new klass(dispatcher, connEndpoint);
- callback.call(context, transport);
- });
- }, function() {
- throw new Error('Could not find a usable connection type for ' + Faye.URI.stringify(endpoint));
- });
- },
+ envelope.timer = global.setTimeout(function() {
+ self.handleError(message);
+ }, scheduler.getTimeout() * 1000);
- register: function(type, klass) {
- this._transports.push([type, klass]);
- klass.prototype.connectionType = type;
- },
+ scheduler.send();
+ envelope.request = this._transport.sendMessage(message);
+ },
- _transports: []
-});
+ handleResponse: function(reply) {
+ var envelope = this._envelopes[reply.id];
-Faye.extend(Faye.Transport.prototype, Faye.Logging);
-Faye.extend(Faye.Transport.prototype, Faye.Timeouts);
+ if (reply.successful !== undefined && envelope) {
+ envelope.scheduler.succeed();
+ delete this._envelopes[reply.id];
+ global.clearTimeout(envelope.timer);
+ }
-Faye.Event = {
- _registry: [],
+ this.trigger('message', reply);
- on: function(element, eventName, callback, context) {
- var wrapped = function() { callback.call(context) };
+ if (this._state === this.UP) return;
+ this._state = this.UP;
+ this._client.trigger('transport:up');
+ },
- if (element.addEventListener)
- element.addEventListener(eventName, wrapped, false);
- else
- element.attachEvent('on' + eventName, wrapped);
+ handleError: function(message, immediate) {
+ var envelope = this._envelopes[message.id],
+ request = envelope && envelope.request,
+ self = this;
- this._registry.push({
- _element: element,
- _type: eventName,
- _callback: callback,
- _context: context,
- _handler: wrapped
- });
- },
+ if (!request) return;
- detach: function(element, eventName, callback, context) {
- var i = this._registry.length, register;
- while (i--) {
- register = this._registry[i];
+ request.then(function(req) {
+ if (req && req.abort) req.abort();
+ });
- if ((element && element !== register._element) ||
- (eventName && eventName !== register._type) ||
- (callback && callback !== register._callback) ||
- (context && context !== register._context))
- continue;
+ var scheduler = envelope.scheduler;
+ scheduler.fail();
- if (register._element.removeEventListener)
- register._element.removeEventListener(register._type, register._handler, false);
- else
- register._element.detachEvent('on' + register._type, register._handler);
+ global.clearTimeout(envelope.timer);
+ envelope.request = envelope.timer = null;
- this._registry.splice(i,1);
- register = null;
+ if (immediate) {
+ this._sendEnvelope(envelope);
+ } else {
+ envelope.timer = global.setTimeout(function() {
+ envelope.timer = null;
+ self._sendEnvelope(envelope);
+ }, scheduler.getInterval() * 1000);
+ }
+
+ if (this._state === this.DOWN) return;
+ this._state = this.DOWN;
+ this._client.trigger('transport:down');
}
- }
-};
+ });
-if (Faye.ENV.onunload !== undefined) Faye.Event.on(Faye.ENV, 'unload', Faye.Event.detach, Faye.Event);
+ Dispatcher.create = function(client, endpoint, options) {
+ return new Dispatcher(client, endpoint, options);
+ };
-/*
- json2.js
- 2013-05-26
+ extend(Dispatcher.prototype, Publisher);
+ extend(Dispatcher.prototype, Logging);
- Public Domain.
+ module.exports = Dispatcher;
- NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
- See http://www.JSON.org/js.html
+/***/ },
+/* 20 */
+/***/ function(module, exports) {
+ 'use strict';
- This code should be minified before deployment.
- See http://javascript.crockford.com/jsmin.html
+ module.exports = {};
- USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
- NOT CONTROL.
+/***/ },
+/* 21 */
+/***/ function(module, exports, __webpack_require__) {
- This file creates a global JSON object containing two methods: stringify
- and parse.
+ 'use strict';
- JSON.stringify(value, replacer, space)
- value any JavaScript value, usually an object or array.
+ var Transport = __webpack_require__(22);
- replacer an optional parameter that determines how object
- values are stringified for objects. It can be a
- function or an array of strings.
+ Transport.register('websocket', __webpack_require__(24));
+ Transport.register('eventsource', __webpack_require__(28));
+ Transport.register('long-polling', __webpack_require__(29));
+ Transport.register('cross-origin-long-polling', __webpack_require__(30));
+ Transport.register('callback-polling', __webpack_require__(31));
- space an optional parameter that specifies the indentation
- of nested structures. If it is omitted, the text will
- be packed without extra whitespace. If it is a number,
- it will specify the number of spaces to indent at each
- level. If it is a string (such as '\t' or ' '),
- it contains the characters used to indent at each level.
+ module.exports = Transport;
- This method produces a JSON text from a JavaScript value.
- When an object value is found, if the object contains a toJSON
- method, its toJSON method will be called and the result will be
- stringified. A toJSON method does not serialize: it returns the
- value represented by the name/value pair that should be serialized,
- or undefined if nothing should be serialized. The toJSON method
- will be passed the key associated with the value, and this will be
- bound to the value
+/***/ },
+/* 22 */
+/***/ function(module, exports, __webpack_require__) {
- For example, this would serialize Dates as ISO strings.
+ 'use strict';
- Date.prototype.toJSON = function (key) {
- function f(n) {
- // Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
- }
+ var Class = __webpack_require__(7),
+ Cookie = __webpack_require__(20).Cookie,
+ Promise = __webpack_require__(9),
+ URI = __webpack_require__(10),
+ array = __webpack_require__(11),
+ extend = __webpack_require__(8),
+ Logging = __webpack_require__(2),
+ Timeouts = __webpack_require__(23),
+ Channel = __webpack_require__(17);
- return this.getUTCFullYear() + '-' +
- f(this.getUTCMonth() + 1) + '-' +
- f(this.getUTCDate()) + 'T' +
- f(this.getUTCHours()) + ':' +
- f(this.getUTCMinutes()) + ':' +
- f(this.getUTCSeconds()) + 'Z';
- };
+ var Transport = extend(Class({ className: 'Transport',
+ DEFAULT_PORTS: {'http:': 80, 'https:': 443, 'ws:': 80, 'wss:': 443},
+ MAX_DELAY: 0,
- You can provide an optional replacer method. It will be passed the
- key and value of each member, with this bound to the containing
- object. The value that is returned from your method will be
- serialized. If your method returns undefined, then the member will
- be excluded from the serialization.
+ batching: true,
- If the replacer parameter is an array of strings, then it will be
- used to select the members to be serialized. It filters the results
- such that only members with keys listed in the replacer array are
- stringified.
+ initialize: function(dispatcher, endpoint) {
+ this._dispatcher = dispatcher;
+ this.endpoint = endpoint;
+ this._outbox = [];
+ this._proxy = extend({}, this._dispatcher.proxy);
- Values that do not have JSON representations, such as undefined or
- functions, will not be serialized. Such values in objects will be
- dropped; in arrays they will be replaced with null. You can use
- a replacer function to replace those with JSON values.
- JSON.stringify(undefined) returns undefined.
+ if (!this._proxy.origin)
+ this._proxy.origin = this._findProxy();
+ },
- The optional space parameter produces a stringification of the
- value that is filled with line breaks and indentation to make it
- easier to read.
+ close: function() {},
- If the space parameter is a non-empty string, then that string will
- be used for indentation. If the space parameter is a number, then
- the indentation will be that many spaces.
+ encode: function(messages) {
+ return '';
+ },
- Example:
+ sendMessage: function(message) {
+ this.debug('Client ? sending message to ?: ?',
+ this._dispatcher.clientId, URI.stringify(this.endpoint), message);
- text = JSON.stringify(['e', {pluribus: 'unum'}]);
- // text is '["e",{"pluribus":"unum"}]'
+ if (!this.batching) return Promise.resolve(this.request([message]));
+ this._outbox.push(message);
+ this._flushLargeBatch();
- text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
- // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+ if (message.channel === Channel.HANDSHAKE)
+ return this._publish(0.01);
- text = JSON.stringify([new Date()], function (key, value) {
- return this[key] instanceof Date ?
- 'Date(' + this[key] + ')' : value;
- });
- // text is '["Date(---current time---)"]'
+ if (message.channel === Channel.CONNECT)
+ this._connectMessage = message;
+ return this._publish(this.MAX_DELAY);
+ },
- JSON.parse(text, reviver)
- This method parses a JSON text to produce an object or array.
- It can throw a SyntaxError exception.
+ _makePromise: function() {
+ var self = this;
- The optional reviver parameter is a function that can filter and
- transform the results. It receives each of the keys and values,
- and its return value is used instead of the original value.
- If it returns what it received, then the structure is not modified.
- If it returns undefined then the member is deleted.
+ this._requestPromise = this._requestPromise || new Promise(function(resolve) {
+ self._resolvePromise = resolve;
+ });
+ },
- Example:
+ _publish: function(delay) {
+ this._makePromise();
- // Parse the text. Values that look like ISO date strings will
- // be converted to Date objects.
+ this.addTimeout('publish', delay, function() {
+ this._flush();
+ delete this._requestPromise;
+ }, this);
- myData = JSON.parse(text, function (key, value) {
- var a;
- if (typeof value === 'string') {
- a =
-/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
- if (a) {
- return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
- +a[5], +a[6]));
- }
- }
- return value;
- });
+ return this._requestPromise;
+ },
- myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
- var d;
- if (typeof value === 'string' &&
- value.slice(0, 5) === 'Date(' &&
- value.slice(-1) === ')') {
- d = new Date(value.slice(5, -1));
- if (d) {
- return d;
- }
- }
- return value;
- });
+ _flush: function() {
+ this.removeTimeout('publish');
+ if (this._outbox.length > 1 && this._connectMessage)
+ this._connectMessage.advice = {timeout: 0};
- This is a reference implementation. You are free to copy, modify, or
- redistribute.
-*/
+ this._resolvePromise(this.request(this._outbox));
-/*jslint evil: true, regexp: true */
+ this._connectMessage = null;
+ this._outbox = [];
+ },
-/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
- call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
- getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
- lastIndex, length, parse, prototype, push, replace, slice, stringify,
- test, toJSON, toString, valueOf
-*/
+ _flushLargeBatch: function() {
+ var string = this.encode(this._outbox);
+ if (string.length < this._dispatcher.maxRequestSize) return;
+ var last = this._outbox.pop();
+ this._makePromise();
+ this._flush();
-// Create a JSON object only if one does not already exist. We create the
-// methods in a closure to avoid creating global variables.
+ if (last) this._outbox.push(last);
+ },
-if (typeof JSON !== 'object') {
- JSON = {};
-}
+ _receive: function(replies) {
+ if (!replies) return;
+ replies = [].concat(replies);
-(function () {
- 'use strict';
+ this.debug('Client ? received from ? via ?: ?',
+ this._dispatcher.clientId, URI.stringify(this.endpoint), this.connectionType, replies);
- function f(n) {
- // Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
- }
+ for (var i = 0, n = replies.length; i < n; i++)
+ this._dispatcher.handleResponse(replies[i]);
+ },
- if (typeof Date.prototype.toJSON !== 'function') {
+ _handleError: function(messages, immediate) {
+ messages = [].concat(messages);
- Date.prototype.toJSON = function () {
+ this.debug('Client ? failed to send to ? via ?: ?',
+ this._dispatcher.clientId, URI.stringify(this.endpoint), this.connectionType, messages);
- return isFinite(this.valueOf())
- ? this.getUTCFullYear() + '-' +
- f(this.getUTCMonth() + 1) + '-' +
- f(this.getUTCDate()) + 'T' +
- f(this.getUTCHours()) + ':' +
- f(this.getUTCMinutes()) + ':' +
- f(this.getUTCSeconds()) + 'Z'
- : null;
- };
+ for (var i = 0, n = messages.length; i < n; i++)
+ this._dispatcher.handleError(messages[i]);
+ },
- String.prototype.toJSON =
- Number.prototype.toJSON =
- Boolean.prototype.toJSON = function () {
- return this.valueOf();
- };
- }
+ _getCookies: function() {
+ var cookies = this._dispatcher.cookies,
+ url = URI.stringify(this.endpoint);
- var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
- escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
- gap,
- indent,
- meta = { // table of character substitutions
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"' : '\\"',
- '\\': '\\\\'
- },
- rep;
+ if (!cookies) return '';
+ return array.map(cookies.getCookiesSync(url), function(cookie) {
+ return cookie.cookieString();
+ }).join('; ');
+ },
- function quote(string) {
+ _storeCookies: function(setCookie) {
+ var cookies = this._dispatcher.cookies,
+ url = URI.stringify(this.endpoint),
+ cookie;
-// If the string contains no control characters, no quote characters, and no
-// backslash characters, then we can safely slap some quotes around it.
-// Otherwise we must also replace the offending characters with safe escape
-// sequences.
+ if (!setCookie || !cookies) return;
+ setCookie = [].concat(setCookie);
- escapable.lastIndex = 0;
- return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
- var c = meta[a];
- return typeof c === 'string'
- ? c
- : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
- }) + '"' : '"' + string + '"';
- }
+ for (var i = 0, n = setCookie.length; i < n; i++) {
+ cookie = Cookie.parse(setCookie[i]);
+ cookies.setCookieSync(cookie, url);
+ }
+ },
+ _findProxy: function() {
+ if (typeof process === 'undefined') return undefined;
- function str(key, holder) {
+ var protocol = this.endpoint.protocol;
+ if (!protocol) return undefined;
-// Produce a string from holder[key].
+ var name = protocol.replace(/:$/, '').toLowerCase() + '_proxy',
+ upcase = name.toUpperCase(),
+ env = process.env,
+ keys, proxy;
- var i, // The loop counter.
- k, // The member key.
- v, // The member value.
- length,
- mind = gap,
- partial,
- value = holder[key];
+ if (name === 'http_proxy' && env.REQUEST_METHOD) {
+ keys = Object.keys(env).filter(function(k) { return /^http_proxy$/i.test(k) });
+ if (keys.length === 1) {
+ if (keys[0] === name && env[upcase] === undefined)
+ proxy = env[name];
+ } else if (keys.length > 1) {
+ proxy = env[name];
+ }
+ proxy = proxy || env['CGI_' + upcase];
+ } else {
+ proxy = env[name] || env[upcase];
+ if (proxy && !env[name])
+ console.warn('The environment variable ' + upcase +
+ ' is discouraged. Use ' + name + '.');
+ }
+ return proxy;
+ }
-// If the value has a toJSON method, call it to obtain a replacement value.
+ }), {
+ get: function(dispatcher, allowed, disabled, callback, context) {
+ var endpoint = dispatcher.endpoint;
- if (value && typeof value === 'object' &&
- typeof value.toJSON === 'function') {
- value = value.toJSON(key);
- }
+ array.asyncEach(this._transports, function(pair, resume) {
+ var connType = pair[0], klass = pair[1],
+ connEndpoint = dispatcher.endpointFor(connType);
-// If we were called with a replacer function, then call the replacer to
-// obtain a replacement value.
+ if (array.indexOf(disabled, connType) >= 0)
+ return resume();
- if (typeof rep === 'function') {
- value = rep.call(holder, key, value);
+ if (array.indexOf(allowed, connType) < 0) {
+ klass.isUsable(dispatcher, connEndpoint, function() {});
+ return resume();
}
-// What happens next depends on the value's type.
+ klass.isUsable(dispatcher, connEndpoint, function(isUsable) {
+ if (!isUsable) return resume();
+ var transport = klass.hasOwnProperty('create') ? klass.create(dispatcher, connEndpoint) : new klass(dispatcher, connEndpoint);
+ callback.call(context, transport);
+ });
+ }, function() {
+ throw new Error('Could not find a usable connection type for ' + URI.stringify(endpoint));
+ });
+ },
- switch (typeof value) {
- case 'string':
- return quote(value);
+ register: function(type, klass) {
+ this._transports.push([type, klass]);
+ klass.prototype.connectionType = type;
+ },
- case 'number':
+ getConnectionTypes: function() {
+ return array.map(this._transports, function(t) { return t[0] });
+ },
-// JSON numbers must be finite. Encode non-finite numbers as null.
+ _transports: []
+ });
- return isFinite(value) ? String(value) : 'null';
+ extend(Transport.prototype, Logging);
+ extend(Transport.prototype, Timeouts);
- case 'boolean':
- case 'null':
+ module.exports = Transport;
-// If the value is a boolean or null, convert it to a string. Note:
-// typeof null does not produce 'null'. The case is included here in
-// the remote chance that this gets fixed someday.
- return String(value);
+/***/ },
+/* 23 */
+/***/ function(module, exports) {
-// If the type is 'object', we might be dealing with an object or an array or
-// null.
+ /* WEBPACK VAR INJECTION */(function(global) {'use strict';
- case 'object':
+ module.exports = {
+ addTimeout: function(name, delay, callback, context) {
+ this._timeouts = this._timeouts || {};
+ if (this._timeouts.hasOwnProperty(name)) return;
+ var self = this;
+ this._timeouts[name] = global.setTimeout(function() {
+ delete self._timeouts[name];
+ callback.call(context);
+ }, 1000 * delay);
+ },
-// Due to a specification blunder in ECMAScript, typeof null is 'object',
-// so watch out for that case.
+ removeTimeout: function(name) {
+ this._timeouts = this._timeouts || {};
+ var timeout = this._timeouts[name];
+ if (!timeout) return;
+ global.clearTimeout(timeout);
+ delete this._timeouts[name];
+ },
- if (!value) {
- return 'null';
- }
+ removeAllTimeouts: function() {
+ this._timeouts = this._timeouts || {};
+ for (var name in this._timeouts) this.removeTimeout(name);
+ }
+ };
-// Make an array to hold the partial results of stringifying this object value.
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
- gap += indent;
- partial = [];
+/***/ },
+/* 24 */
+/***/ function(module, exports, __webpack_require__) {
-// Is the value an array?
+ /* WEBPACK VAR INJECTION */(function(global) {'use strict';
- if (Object.prototype.toString.apply(value) === '[object Array]') {
+ var Class = __webpack_require__(7),
+ Promise = __webpack_require__(9),
+ Set = __webpack_require__(25),
+ URI = __webpack_require__(10),
+ browser = __webpack_require__(12),
+ copyObject = __webpack_require__(26),
+ extend = __webpack_require__(8),
+ toJSON = __webpack_require__(3),
+ ws = __webpack_require__(27),
+ Deferrable = __webpack_require__(14),
+ Transport = __webpack_require__(22);
-// The value is an array. Stringify every element. Use null as a placeholder
-// for non-JSON values.
+ var WebSocket = extend(Class(Transport, {
+ UNCONNECTED: 1,
+ CONNECTING: 2,
+ CONNECTED: 3,
- length = value.length;
- for (i = 0; i < length; i += 1) {
- partial[i] = str(i, value) || 'null';
- }
+ batching: false,
-// Join all of the elements together, separated with commas, and wrap them in
-// brackets.
+ isUsable: function(callback, context) {
+ this.callback(function() { callback.call(context, true) });
+ this.errback(function() { callback.call(context, false) });
+ this.connect();
+ },
- v = partial.length === 0
- ? '[]'
- : gap
- ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
- : '[' + partial.join(',') + ']';
- gap = mind;
- return v;
- }
+ request: function(messages) {
+ this._pending = this._pending || new Set();
+ for (var i = 0, n = messages.length; i < n; i++) this._pending.add(messages[i]);
-// If the replacer is an array, use it to select the members to be stringified.
+ var self = this;
- if (rep && typeof rep === 'object') {
- length = rep.length;
- for (i = 0; i < length; i += 1) {
- if (typeof rep[i] === 'string') {
- k = rep[i];
- v = str(k, value);
- if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- } else {
+ var promise = new Promise(function(resolve, reject) {
+ self.callback(function(socket) {
+ if (!socket || socket.readyState !== 1) return;
+ socket.send(toJSON(messages));
+ resolve(socket);
+ });
-// Otherwise, iterate through all of the keys in the object.
+ self.connect();
+ });
- for (k in value) {
- if (Object.prototype.hasOwnProperty.call(value, k)) {
- v = str(k, value);
- if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- }
+ return {
+ abort: function() { promise.then(function(ws) { ws.close() }) }
+ };
+ },
-// Join all of the member texts together, separated with commas,
-// and wrap them in braces.
+ connect: function() {
+ if (WebSocket._unloaded) return;
- v = partial.length === 0
- ? '{}'
- : gap
- ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
- : '{' + partial.join(',') + '}';
- gap = mind;
- return v;
- }
- }
+ this._state = this._state || this.UNCONNECTED;
+ if (this._state !== this.UNCONNECTED) return;
+ this._state = this.CONNECTING;
-// If the JSON object does not yet have a stringify method, give it one.
+ var socket = this._createSocket();
+ if (!socket) return this.setDeferredStatus('failed');
- Faye.stringify = function (value, replacer, space) {
+ var self = this;
-// The stringify method takes a value and an optional replacer, and an optional
-// space parameter, and returns a JSON text. The replacer can be a function
-// that can replace values, or an array of strings that will select the keys.
-// A default replacer method can be provided. Use of the space parameter can
-// produce text that is more easily readable.
+ socket.onopen = function() {
+ if (socket.headers) self._storeCookies(socket.headers['set-cookie']);
+ self._socket = socket;
+ self._state = self.CONNECTED;
+ self._everConnected = true;
+ self._ping();
+ self.setDeferredStatus('succeeded', socket);
+ };
- var i;
- gap = '';
- indent = '';
+ var closed = false;
+ socket.onclose = socket.onerror = function() {
+ if (closed) return;
+ closed = true;
-// If the space parameter is a number, make an indent string containing that
-// many spaces.
+ var wasConnected = (self._state === self.CONNECTED);
+ socket.onopen = socket.onclose = socket.onerror = socket.onmessage = null;
- if (typeof space === 'number') {
- for (i = 0; i < space; i += 1) {
- indent += ' ';
- }
+ delete self._socket;
+ self._state = self.UNCONNECTED;
+ self.removeTimeout('ping');
-// If the space parameter is a string, it will be used as the indent string.
+ var pending = self._pending ? self._pending.toArray() : [];
+ delete self._pending;
- } else if (typeof space === 'string') {
- indent = space;
+ if (wasConnected || self._everConnected) {
+ self.setDeferredStatus('unknown');
+ self._handleError(pending, wasConnected);
+ } else {
+ self.setDeferredStatus('failed');
}
+ };
-// If there is a replacer, it must be a function or an array.
-// Otherwise, throw an error.
+ socket.onmessage = function(event) {
+ var replies;
+ try { replies = JSON.parse(event.data) } catch (error) {}
- rep = replacer;
- if (replacer && typeof replacer !== 'function' &&
- (typeof replacer !== 'object' ||
- typeof replacer.length !== 'number')) {
- throw new Error('JSON.stringify');
+ if (!replies) return;
+
+ replies = [].concat(replies);
+
+ for (var i = 0, n = replies.length; i < n; i++) {
+ if (replies[i].successful === undefined) continue;
+ self._pending.remove(replies[i]);
}
+ self._receive(replies);
+ };
+ },
-// Make a fake root object containing our value under the key of ''.
-// Return the result of stringifying the value.
+ close: function() {
+ if (!this._socket) return;
+ this._socket.close();
+ },
- return str('', {'': value});
- };
+ _createSocket: function() {
+ var url = WebSocket.getSocketUrl(this.endpoint),
+ headers = this._dispatcher.headers,
+ extensions = this._dispatcher.wsExtensions,
+ cookie = this._getCookies(),
+ tls = this._dispatcher.tls,
+ options = {extensions: extensions, headers: headers, proxy: this._proxy, tls: tls};
- if (typeof JSON.stringify !== 'function') {
- JSON.stringify = Faye.stringify;
- }
+ if (cookie !== '') options.headers['Cookie'] = cookie;
-// If the JSON object does not yet have a parse method, give it one.
+ return ws.create(url, [], options);
+ },
- if (typeof JSON.parse !== 'function') {
- JSON.parse = function (text, reviver) {
+ _ping: function() {
+ if (!this._socket || this._socket.readyState !== 1) return;
+ this._socket.send('[]');
+ this.addTimeout('ping', this._dispatcher.timeout / 2, this._ping, this);
+ }
-// The parse method takes a text and an optional reviver function, and returns
-// a JavaScript value if the text is a valid JSON text.
+ }), {
+ PROTOCOLS: {
+ 'http:': 'ws:',
+ 'https:': 'wss:'
+ },
- var j;
+ create: function(dispatcher, endpoint) {
+ var sockets = dispatcher.transports.websocket = dispatcher.transports.websocket || {};
+ sockets[endpoint.href] = sockets[endpoint.href] || new this(dispatcher, endpoint);
+ return sockets[endpoint.href];
+ },
- function walk(holder, key) {
+ getSocketUrl: function(endpoint) {
+ endpoint = copyObject(endpoint);
+ endpoint.protocol = this.PROTOCOLS[endpoint.protocol];
+ return URI.stringify(endpoint);
+ },
-// The walk method is used to recursively walk the resulting structure so
-// that modifications can be made.
+ isUsable: function(dispatcher, endpoint, callback, context) {
+ this.create(dispatcher, endpoint).isUsable(callback, context);
+ }
+ });
- var k, v, value = holder[key];
- if (value && typeof value === 'object') {
- for (k in value) {
- if (Object.prototype.hasOwnProperty.call(value, k)) {
- v = walk(value, k);
- if (v !== undefined) {
- value[k] = v;
- } else {
- delete value[k];
- }
- }
- }
- }
- return reviver.call(holder, key, value);
- }
+ extend(WebSocket.prototype, Deferrable);
+ if (browser.Event && global.onbeforeunload !== undefined)
+ browser.Event.on(global, 'beforeunload', function() { WebSocket._unloaded = true });
-// Parsing happens in four stages. In the first stage, we replace certain
-// Unicode characters with escape sequences. JavaScript handles many characters
-// incorrectly, either silently deleting them, or treating them as line endings.
+ module.exports = WebSocket;
- text = String(text);
- cx.lastIndex = 0;
- if (cx.test(text)) {
- text = text.replace(cx, function (a) {
- return '\\u' +
- ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
- });
- }
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
-// In the second stage, we run the text against regular expressions that look
-// for non-JSON patterns. We are especially concerned with '()' and 'new'
-// because they can cause invocation, and '=' because it can cause mutation.
-// But just to be safe, we want to reject all unexpected forms.
+/***/ },
+/* 25 */
+/***/ function(module, exports, __webpack_require__) {
-// We split the second stage into 4 regexp operations in order to work around
-// crippling inefficiencies in IE's and Safari's regexp engines. First we
-// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
-// replace all simple value tokens with ']' characters. Third, we delete all
-// open brackets that follow a colon or comma or that begin the text. Finally,
-// we look to see that the remaining characters are only whitespace or ']' or
-// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+ 'use strict';
- if (/^[\],:{}\s]*$/
- .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
- .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
- .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+ var Class = __webpack_require__(7);
-// In the third stage we use the eval function to compile the text into a
-// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
-// in JavaScript: it can begin a block or an object literal. We wrap the text
-// in parens to eliminate the ambiguity.
+ module.exports = Class({
+ initialize: function() {
+ this._index = {};
+ },
- j = eval('(' + text + ')');
+ add: function(item) {
+ var key = (item.id !== undefined) ? item.id : item;
+ if (this._index.hasOwnProperty(key)) return false;
+ this._index[key] = item;
+ return true;
+ },
-// In the optional fourth stage, we recursively walk the new structure, passing
-// each name/value pair to a reviver function for possible transformation.
+ forEach: function(block, context) {
+ for (var key in this._index) {
+ if (this._index.hasOwnProperty(key))
+ block.call(context, this._index[key]);
+ }
+ },
- return typeof reviver === 'function'
- ? walk({'': j}, '')
- : j;
- }
+ isEmpty: function() {
+ for (var key in this._index) {
+ if (this._index.hasOwnProperty(key)) return false;
+ }
+ return true;
+ },
-// If the text is not JSON parseable, then a SyntaxError is thrown.
+ member: function(item) {
+ for (var key in this._index) {
+ if (this._index[key] === item) return true;
+ }
+ return false;
+ },
- throw new SyntaxError('JSON.parse');
- };
+ remove: function(item) {
+ var key = (item.id !== undefined) ? item.id : item;
+ var removed = this._index[key];
+ delete this._index[key];
+ return removed;
+ },
+
+ toArray: function() {
+ var array = [];
+ this.forEach(function(item) { array.push(item) });
+ return array;
}
-}());
+ });
-Faye.Transport.WebSocket = Faye.extend(Faye.Class(Faye.Transport, {
- UNCONNECTED: 1,
- CONNECTING: 2,
- CONNECTED: 3,
- batching: false,
+/***/ },
+/* 26 */
+/***/ function(module, exports) {
- isUsable: function(callback, context) {
- this.callback(function() { callback.call(context, true) });
- this.errback(function() { callback.call(context, false) });
- this.connect();
- },
+ 'use strict';
- request: function(messages) {
- this._pending = this._pending || new Faye.Set();
- for (var i = 0, n = messages.length; i < n; i++) this._pending.add(messages[i]);
+ var copyObject = function(object) {
+ var clone, i, key;
+ if (object instanceof Array) {
+ clone = [];
+ i = object.length;
+ while (i--) clone[i] = copyObject(object[i]);
+ return clone;
+ } else if (typeof object === 'object') {
+ clone = (object === null) ? null : {};
+ for (key in object) clone[key] = copyObject(object[key]);
+ return clone;
+ } else {
+ return object;
+ }
+ };
- var promise = new Faye.Promise();
+ module.exports = copyObject;
- this.callback(function(socket) {
- if (!socket) return;
- socket.send(Faye.toJSON(messages));
- Faye.Promise.fulfill(promise, socket);
- }, this);
- this.connect();
+/***/ },
+/* 27 */
+/***/ function(module, exports) {
- return {
- abort: function() { promise.then(function(ws) { ws.close() }) }
- };
- },
+ /* WEBPACK VAR INJECTION */(function(global) {'use strict';
- connect: function() {
- if (Faye.Transport.WebSocket._unloaded) return;
+ var WS = global.MozWebSocket || global.WebSocket;
- this._state = this._state || this.UNCONNECTED;
- if (this._state !== this.UNCONNECTED) return;
- this._state = this.CONNECTING;
+ module.exports = {
+ create: function(url, protocols, options) {
+ if (typeof WS !== 'function') return null;
+ return new WS(url);
+ }
+ };
- var socket = this._createSocket();
- if (!socket) return this.setDeferredStatus('failed');
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
- var self = this;
+/***/ },
+/* 28 */
+/***/ function(module, exports, __webpack_require__) {
- socket.onopen = function() {
- if (socket.headers) self._storeCookies(socket.headers['set-cookie']);
- self._socket = socket;
- self._state = self.CONNECTED;
- self._everConnected = true;
- self._ping();
- self.setDeferredStatus('succeeded', socket);
- };
+ /* WEBPACK VAR INJECTION */(function(global) {'use strict';
- var closed = false;
- socket.onclose = socket.onerror = function() {
- if (closed) return;
- closed = true;
+ var Class = __webpack_require__(7),
+ URI = __webpack_require__(10),
+ copyObject = __webpack_require__(26),
+ extend = __webpack_require__(8),
+ Deferrable = __webpack_require__(14),
+ Transport = __webpack_require__(22),
+ XHR = __webpack_require__(29);
- var wasConnected = (self._state === self.CONNECTED);
- socket.onopen = socket.onclose = socket.onerror = socket.onmessage = null;
+ var EventSource = extend(Class(Transport, {
+ initialize: function(dispatcher, endpoint) {
+ Transport.prototype.initialize.call(this, dispatcher, endpoint);
+ if (!global.EventSource) return this.setDeferredStatus('failed');
- delete self._socket;
- self._state = self.UNCONNECTED;
- self.removeTimeout('ping');
- self.setDeferredStatus('unknown');
+ this._xhr = new XHR(dispatcher, endpoint);
- var pending = self._pending ? self._pending.toArray() : [];
- delete self._pending;
+ endpoint = copyObject(endpoint);
+ endpoint.pathname += '/' + dispatcher.clientId;
- if (wasConnected) {
- self._handleError(pending, true);
- } else if (self._everConnected) {
- self._handleError(pending);
- } else {
- self.setDeferredStatus('failed');
- }
- };
+ var socket = new global.EventSource(URI.stringify(endpoint)),
+ self = this;
- socket.onmessage = function(event) {
- var replies = JSON.parse(event.data);
- if (!replies) return;
+ socket.onopen = function() {
+ self._everConnected = true;
+ self.setDeferredStatus('succeeded');
+ };
- replies = [].concat(replies);
+ socket.onerror = function() {
+ if (self._everConnected) {
+ self._handleError([]);
+ } else {
+ self.setDeferredStatus('failed');
+ socket.close();
+ }
+ };
- for (var i = 0, n = replies.length; i < n; i++) {
- if (replies[i].successful === undefined) continue;
- self._pending.remove(replies[i]);
- }
- self._receive(replies);
- };
- },
+ socket.onmessage = function(event) {
+ var replies;
+ try { replies = JSON.parse(event.data) } catch (error) {}
- close: function() {
- if (!this._socket) return;
- this._socket.close();
- },
+ if (replies)
+ self._receive(replies);
+ else
+ self._handleError([]);
+ };
- _createSocket: function() {
- var url = Faye.Transport.WebSocket.getSocketUrl(this.endpoint),
- headers = Faye.copyObject(this._dispatcher.headers),
- options = {headers: headers, ca: this._dispatcher.ca};
+ this._socket = socket;
+ },
- options.headers['Cookie'] = this._getCookies();
+ close: function() {
+ if (!this._socket) return;
+ this._socket.onopen = this._socket.onerror = this._socket.onmessage = null;
+ this._socket.close();
+ delete this._socket;
+ },
- if (Faye.WebSocket) return new Faye.WebSocket.Client(url, [], options);
- if (Faye.ENV.MozWebSocket) return new MozWebSocket(url);
- if (Faye.ENV.WebSocket) return new WebSocket(url);
- },
+ isUsable: function(callback, context) {
+ this.callback(function() { callback.call(context, true) });
+ this.errback(function() { callback.call(context, false) });
+ },
- _ping: function() {
- if (!this._socket) return;
- this._socket.send('[]');
- this.addTimeout('ping', this._dispatcher.timeout / 2, this._ping, this);
- }
+ encode: function(messages) {
+ return this._xhr.encode(messages);
+ },
-}), {
- PROTOCOLS: {
- 'http:': 'ws:',
- 'https:': 'wss:'
- },
+ request: function(messages) {
+ return this._xhr.request(messages);
+ }
- create: function(dispatcher, endpoint) {
- var sockets = dispatcher.transports.websocket = dispatcher.transports.websocket || {};
- sockets[endpoint.href] = sockets[endpoint.href] || new this(dispatcher, endpoint);
- return sockets[endpoint.href];
- },
+ }), {
+ isUsable: function(dispatcher, endpoint, callback, context) {
+ var id = dispatcher.clientId;
+ if (!id) return callback.call(context, false);
- getSocketUrl: function(endpoint) {
- endpoint = Faye.copyObject(endpoint);
- endpoint.protocol = this.PROTOCOLS[endpoint.protocol];
- return Faye.URI.stringify(endpoint);
- },
+ XHR.isUsable(dispatcher, endpoint, function(usable) {
+ if (!usable) return callback.call(context, false);
+ this.create(dispatcher, endpoint).isUsable(callback, context);
+ }, this);
+ },
- isUsable: function(dispatcher, endpoint, callback, context) {
- this.create(dispatcher, endpoint).isUsable(callback, context);
- }
-});
+ create: function(dispatcher, endpoint) {
+ var sockets = dispatcher.transports.eventsource = dispatcher.transports.eventsource || {},
+ id = dispatcher.clientId;
-Faye.extend(Faye.Transport.WebSocket.prototype, Faye.Deferrable);
-Faye.Transport.register('websocket', Faye.Transport.WebSocket);
+ var url = copyObject(endpoint);
+ url.pathname += '/' + (id || '');
+ url = URI.stringify(url);
-if (Faye.Event && Faye.ENV.onbeforeunload !== undefined)
- Faye.Event.on(Faye.ENV, 'beforeunload', function() {
- Faye.Transport.WebSocket._unloaded = true;
+ sockets[url] = sockets[url] || new this(dispatcher, endpoint);
+ return sockets[url];
+ }
});
-Faye.Transport.EventSource = Faye.extend(Faye.Class(Faye.Transport, {
- initialize: function(dispatcher, endpoint) {
- Faye.Transport.prototype.initialize.call(this, dispatcher, endpoint);
- if (!Faye.ENV.EventSource) return this.setDeferredStatus('failed');
+ extend(EventSource.prototype, Deferrable);
- this._xhr = new Faye.Transport.XHR(dispatcher, endpoint);
+ module.exports = EventSource;
- endpoint = Faye.copyObject(endpoint);
- endpoint.pathname += '/' + dispatcher.clientId;
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
- var socket = new EventSource(Faye.URI.stringify(endpoint)),
- self = this;
+/***/ },
+/* 29 */
+/***/ function(module, exports, __webpack_require__) {
- socket.onopen = function() {
- self._everConnected = true;
- self.setDeferredStatus('succeeded');
- };
+ /* WEBPACK VAR INJECTION */(function(global) {'use strict';
- socket.onerror = function() {
- if (self._everConnected) {
- self._handleError([]);
+ var Class = __webpack_require__(7),
+ URI = __webpack_require__(10),
+ browser = __webpack_require__(12),
+ extend = __webpack_require__(8),
+ toJSON = __webpack_require__(3),
+ Transport = __webpack_require__(22);
+
+ var XHR = extend(Class(Transport, {
+ encode: function(messages) {
+ return toJSON(messages);
+ },
+
+ request: function(messages) {
+ var href = this.endpoint.href,
+ self = this,
+ xhr;
+
+ // Prefer XMLHttpRequest over ActiveXObject if they both exist
+ if (global.XMLHttpRequest) {
+ xhr = new XMLHttpRequest();
+ } else if (global.ActiveXObject) {
+ xhr = new ActiveXObject('Microsoft.XMLHTTP');
} else {
- self.setDeferredStatus('failed');
- socket.close();
+ return this._handleError(messages);
}
- };
- socket.onmessage = function(event) {
- self._receive(JSON.parse(event.data));
- };
+ xhr.open('POST', href, true);
+ xhr.setRequestHeader('Content-Type', 'application/json');
+ xhr.setRequestHeader('Pragma', 'no-cache');
+ xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
- this._socket = socket;
- },
+ var headers = this._dispatcher.headers;
+ for (var key in headers) {
+ if (!headers.hasOwnProperty(key)) continue;
+ xhr.setRequestHeader(key, headers[key]);
+ }
- close: function() {
- if (!this._socket) return;
- this._socket.onopen = this._socket.onerror = this._socket.onmessage = null;
- this._socket.close();
- delete this._socket;
- },
+ var abort = function() { xhr.abort() };
+ if (global.onbeforeunload !== undefined)
+ browser.Event.on(global, 'beforeunload', abort);
- isUsable: function(callback, context) {
- this.callback(function() { callback.call(context, true) });
- this.errback(function() { callback.call(context, false) });
- },
+ xhr.onreadystatechange = function() {
+ if (!xhr || xhr.readyState !== 4) return;
- encode: function(messages) {
- return this._xhr.encode(messages);
- },
+ var replies = null,
+ status = xhr.status,
+ text = xhr.responseText,
+ successful = (status >= 200 && status < 300) || status === 304 || status === 1223;
- request: function(messages) {
- return this._xhr.request(messages);
- }
+ if (global.onbeforeunload !== undefined)
+ browser.Event.detach(global, 'beforeunload', abort);
-}), {
- isUsable: function(dispatcher, endpoint, callback, context) {
- var id = dispatcher.clientId;
- if (!id) return callback.call(context, false);
+ xhr.onreadystatechange = function() {};
+ xhr = null;
- Faye.Transport.XHR.isUsable(dispatcher, endpoint, function(usable) {
- if (!usable) return callback.call(context, false);
- this.create(dispatcher, endpoint).isUsable(callback, context);
- }, this);
- },
+ if (!successful) return self._handleError(messages);
- create: function(dispatcher, endpoint) {
- var sockets = dispatcher.transports.eventsource = dispatcher.transports.eventsource || {},
- id = dispatcher.clientId;
+ try {
+ replies = JSON.parse(text);
+ } catch (error) {}
- endpoint = Faye.copyObject(endpoint);
- endpoint.pathname += '/' + (id || '');
- var url = Faye.URI.stringify(endpoint);
+ if (replies)
+ self._receive(replies);
+ else
+ self._handleError(messages);
+ };
- sockets[url] = sockets[url] || new this(dispatcher, endpoint);
- return sockets[url];
- }
-});
+ xhr.send(this.encode(messages));
+ return xhr;
+ }
+ }), {
+ isUsable: function(dispatcher, endpoint, callback, context) {
+ var usable = (navigator.product === 'ReactNative')
+ || URI.isSameOrigin(endpoint);
-Faye.extend(Faye.Transport.EventSource.prototype, Faye.Deferrable);
-Faye.Transport.register('eventsource', Faye.Transport.EventSource);
+ callback.call(context, usable);
+ }
+ });
-Faye.Transport.XHR = Faye.extend(Faye.Class(Faye.Transport, {
- encode: function(messages) {
- return Faye.toJSON(messages);
- },
+ module.exports = XHR;
- request: function(messages) {
- var href = this.endpoint.href,
- xhr = Faye.ENV.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest(),
- self = this;
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
- xhr.open('POST', href, true);
- xhr.setRequestHeader('Content-Type', 'application/json');
- xhr.setRequestHeader('Pragma', 'no-cache');
- xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+/***/ },
+/* 30 */
+/***/ function(module, exports, __webpack_require__) {
- var headers = this._dispatcher.headers;
- for (var key in headers) {
- if (!headers.hasOwnProperty(key)) continue;
- xhr.setRequestHeader(key, headers[key]);
- }
+ /* WEBPACK VAR INJECTION */(function(global) {'use strict';
- var abort = function() { xhr.abort() };
- if (Faye.ENV.onbeforeunload !== undefined) Faye.Event.on(Faye.ENV, 'beforeunload', abort);
+ var Class = __webpack_require__(7),
+ Set = __webpack_require__(25),
+ URI = __webpack_require__(10),
+ extend = __webpack_require__(8),
+ toJSON = __webpack_require__(3),
+ Transport = __webpack_require__(22);
- xhr.onreadystatechange = function() {
- if (!xhr || xhr.readyState !== 4) return;
+ var CORS = extend(Class(Transport, {
+ encode: function(messages) {
+ return 'message=' + encodeURIComponent(toJSON(messages));
+ },
- var replies = null,
- status = xhr.status,
- text = xhr.responseText,
- successful = (status >= 200 && status < 300) || status === 304 || status === 1223;
+ request: function(messages) {
+ var xhrClass = global.XDomainRequest ? XDomainRequest : XMLHttpRequest,
+ xhr = new xhrClass(),
+ id = ++CORS._id,
+ headers = this._dispatcher.headers,
+ self = this,
+ key;
- if (Faye.ENV.onbeforeunload !== undefined) Faye.Event.detach(Faye.ENV, 'beforeunload', abort);
- xhr.onreadystatechange = function() {};
- xhr = null;
+ xhr.open('POST', URI.stringify(this.endpoint), true);
- if (!successful) return self._handleError(messages);
+ if (xhr.setRequestHeader) {
+ xhr.setRequestHeader('Pragma', 'no-cache');
+ for (key in headers) {
+ if (!headers.hasOwnProperty(key)) continue;
+ xhr.setRequestHeader(key, headers[key]);
+ }
+ }
- try {
- replies = JSON.parse(text);
- } catch (e) {}
+ var cleanUp = function() {
+ if (!xhr) return false;
+ CORS._pending.remove(id);
+ xhr.onload = xhr.onerror = xhr.ontimeout = xhr.onprogress = null;
+ xhr = null;
+ };
- if (replies)
- self._receive(replies);
- else
+ xhr.onload = function() {
+ var replies;
+ try { replies = JSON.parse(xhr.responseText) } catch (error) {}
+
+ cleanUp();
+
+ if (replies)
+ self._receive(replies);
+ else
+ self._handleError(messages);
+ };
+
+ xhr.onerror = xhr.ontimeout = function() {
+ cleanUp();
self._handleError(messages);
- };
+ };
- xhr.send(this.encode(messages));
- return xhr;
- }
-}), {
- isUsable: function(dispatcher, endpoint, callback, context) {
- callback.call(context, Faye.URI.isSameOrigin(endpoint));
- }
-});
+ xhr.onprogress = function() {};
-Faye.Transport.register('long-polling', Faye.Transport.XHR);
+ if (xhrClass === global.XDomainRequest)
+ CORS._pending.add({id: id, xhr: xhr});
-Faye.Transport.CORS = Faye.extend(Faye.Class(Faye.Transport, {
- encode: function(messages) {
- return 'message=' + encodeURIComponent(Faye.toJSON(messages));
- },
+ xhr.send(this.encode(messages));
+ return xhr;
+ }
+ }), {
+ _id: 0,
+ _pending: new Set(),
- request: function(messages) {
- var xhrClass = Faye.ENV.XDomainRequest ? XDomainRequest : XMLHttpRequest,
- xhr = new xhrClass(),
- headers = this._dispatcher.headers,
- self = this,
- key;
+ isUsable: function(dispatcher, endpoint, callback, context) {
+ if (URI.isSameOrigin(endpoint))
+ return callback.call(context, false);
- xhr.open('POST', Faye.URI.stringify(this.endpoint), true);
+ if (global.XDomainRequest)
+ return callback.call(context, endpoint.protocol === location.protocol);
- if (xhr.setRequestHeader) {
- xhr.setRequestHeader('Pragma', 'no-cache');
- for (key in headers) {
- if (!headers.hasOwnProperty(key)) continue;
- xhr.setRequestHeader(key, headers[key]);
+ if (global.XMLHttpRequest) {
+ var xhr = new XMLHttpRequest();
+ return callback.call(context, xhr.withCredentials !== undefined);
}
+ return callback.call(context, false);
}
+ });
- var cleanUp = function() {
- if (!xhr) return false;
- xhr.onload = xhr.onerror = xhr.ontimeout = xhr.onprogress = null;
- xhr = null;
- };
+ module.exports = CORS;
- xhr.onload = function() {
- var replies = null;
- try {
- replies = JSON.parse(xhr.responseText);
- } catch (e) {}
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
- cleanUp();
+/***/ },
+/* 31 */
+/***/ function(module, exports, __webpack_require__) {
- if (replies)
+ /* WEBPACK VAR INJECTION */(function(global) {'use strict';
+
+ var Class = __webpack_require__(7),
+ URI = __webpack_require__(10),
+ copyObject = __webpack_require__(26),
+ extend = __webpack_require__(8),
+ toJSON = __webpack_require__(3),
+ Transport = __webpack_require__(22);
+
+ var JSONP = extend(Class(Transport, {
+ encode: function(messages) {
+ var url = copyObject(this.endpoint);
+ url.query.message = toJSON(messages);
+ url.query.jsonp = '__jsonp' + JSONP._cbCount + '__';
+ return URI.stringify(url);
+ },
+
+ request: function(messages) {
+ var head = document.getElementsByTagName('head')[0],
+ script = document.createElement('script'),
+ callbackName = JSONP.getCallbackName(),
+ endpoint = copyObject(this.endpoint),
+ self = this;
+
+ endpoint.query.message = toJSON(messages);
+ endpoint.query.jsonp = callbackName;
+
+ var cleanup = function() {
+ if (!global[callbackName]) return false;
+ global[callbackName] = undefined;
+ try { delete global[callbackName] } catch (error) {}
+ script.parentNode.removeChild(script);
+ };
+
+ global[callbackName] = function(replies) {
+ cleanup();
self._receive(replies);
- else
+ };
+
+ script.type = 'text/javascript';
+ script.src = URI.stringify(endpoint);
+ head.appendChild(script);
+
+ script.onerror = function() {
+ cleanup();
self._handleError(messages);
- };
+ };
- xhr.onerror = xhr.ontimeout = function() {
- cleanUp();
- self._handleError(messages);
- };
+ return {abort: cleanup};
+ }
+ }), {
+ _cbCount: 0,
- xhr.onprogress = function() {};
- xhr.send(this.encode(messages));
- return xhr;
- }
-}), {
- isUsable: function(dispatcher, endpoint, callback, context) {
- if (Faye.URI.isSameOrigin(endpoint))
- return callback.call(context, false);
+ getCallbackName: function() {
+ this._cbCount += 1;
+ return '__jsonp' + this._cbCount + '__';
+ },
- if (Faye.ENV.XDomainRequest)
- return callback.call(context, endpoint.protocol === Faye.ENV.location.protocol);
+ isUsable: function(dispatcher, endpoint, callback, context) {
+ callback.call(context, true);
+ }
+ });
- if (Faye.ENV.XMLHttpRequest) {
- var xhr = new Faye.ENV.XMLHttpRequest();
- return callback.call(context, xhr.withCredentials !== undefined);
+ module.exports = JSONP;
+
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
+
+/***/ },
+/* 32 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var extend = __webpack_require__(8);
+
+ var Scheduler = function(message, options) {
+ this.message = message;
+ this.options = options;
+ this.attempts = 0;
+ };
+
+ extend(Scheduler.prototype, {
+ getTimeout: function() {
+ return this.options.timeout;
+ },
+
+ getInterval: function() {
+ return this.options.interval;
+ },
+
+ isDeliverable: function() {
+ var attempts = this.options.attempts,
+ made = this.attempts,
+ deadline = this.options.deadline,
+ now = new Date().getTime();
+
+ if (attempts !== undefined && made >= attempts)
+ return false;
+
+ if (deadline !== undefined && now > deadline)
+ return false;
+
+ return true;
+ },
+
+ send: function() {
+ this.attempts += 1;
+ },
+
+ succeed: function() {},
+
+ fail: function() {},
+
+ abort: function() {}
+ });
+
+ module.exports = Scheduler;
+
+
+/***/ },
+/* 33 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var Class = __webpack_require__(7),
+ Grammar = __webpack_require__(18);
+
+ var Error = Class({
+ initialize: function(code, params, message) {
+ this.code = code;
+ this.params = Array.prototype.slice.call(params);
+ this.message = message;
+ },
+
+ toString: function() {
+ return this.code + ':' +
+ this.params.join(',') + ':' +
+ this.message;
}
- return callback.call(context, false);
- }
-});
+ });
-Faye.Transport.register('cross-origin-long-polling', Faye.Transport.CORS);
+ Error.parse = function(message) {
+ message = message || '';
+ if (!Grammar.ERROR.test(message)) return new Error(null, [], message);
-Faye.Transport.JSONP = Faye.extend(Faye.Class(Faye.Transport, {
- encode: function(messages) {
- var url = Faye.copyObject(this.endpoint);
- url.query.message = Faye.toJSON(messages);
- url.query.jsonp = '__jsonp' + Faye.Transport.JSONP._cbCount + '__';
- return Faye.URI.stringify(url);
- },
+ var parts = message.split(':'),
+ code = parseInt(parts[0]),
+ params = parts[1].split(','),
+ message = parts[2];
- request: function(messages) {
- var head = document.getElementsByTagName('head')[0],
- script = document.createElement('script'),
- callbackName = Faye.Transport.JSONP.getCallbackName(),
- endpoint = Faye.copyObject(this.endpoint),
- self = this;
+ return new Error(code, params, message);
+ };
- endpoint.query.message = Faye.toJSON(messages);
- endpoint.query.jsonp = callbackName;
+ // http://code.google.com/p/cometd/wiki/BayeuxCodes
+ var errors = {
+ versionMismatch: [300, 'Version mismatch'],
+ conntypeMismatch: [301, 'Connection types not supported'],
+ extMismatch: [302, 'Extension mismatch'],
+ badRequest: [400, 'Bad request'],
+ clientUnknown: [401, 'Unknown client'],
+ parameterMissing: [402, 'Missing required parameter'],
+ channelForbidden: [403, 'Forbidden channel'],
+ channelUnknown: [404, 'Unknown channel'],
+ channelInvalid: [405, 'Invalid channel'],
+ extUnknown: [406, 'Unknown extension'],
+ publishFailed: [407, 'Failed to publish'],
+ serverError: [500, 'Internal server error']
+ };
- var cleanup = function() {
- if (!Faye.ENV[callbackName]) return false;
- Faye.ENV[callbackName] = undefined;
- try { delete Faye.ENV[callbackName] } catch (e) {}
- script.parentNode.removeChild(script);
- };
+ for (var name in errors)
+ (function(name) {
+ Error[name] = function() {
+ return new Error(errors[name][0], arguments, errors[name][1]).toString();
+ };
+ })(name);
- Faye.ENV[callbackName] = function(replies) {
- cleanup();
- self._receive(replies);
- };
+ module.exports = Error;
- script.type = 'text/javascript';
- script.src = Faye.URI.stringify(endpoint);
- head.appendChild(script);
- script.onerror = function() {
- cleanup();
- self._handleError(messages);
- };
+/***/ },
+/* 34 */
+/***/ function(module, exports, __webpack_require__) {
- return {abort: cleanup};
- }
-}), {
- _cbCount: 0,
+ 'use strict';
- getCallbackName: function() {
- this._cbCount += 1;
- return '__jsonp' + this._cbCount + '__';
- },
+ var extend = __webpack_require__(8),
+ Logging = __webpack_require__(2);
- isUsable: function(dispatcher, endpoint, callback, context) {
- callback.call(context, true);
- }
-});
+ var Extensible = {
+ addExtension: function(extension) {
+ this._extensions = this._extensions || [];
+ this._extensions.push(extension);
+ if (extension.added) extension.added(this);
+ },
-Faye.Transport.register('callback-polling', Faye.Transport.JSONP);
+ removeExtension: function(extension) {
+ if (!this._extensions) return;
+ var i = this._extensions.length;
+ while (i--) {
+ if (this._extensions[i] !== extension) continue;
+ this._extensions.splice(i,1);
+ if (extension.removed) extension.removed(this);
+ }
+ },
-})();
\ No newline at end of file
+ pipeThroughExtensions: function(stage, message, request, callback, context) {
+ this.debug('Passing through ? extensions: ?', stage, message);
+
+ if (!this._extensions) return callback.call(context, message);
+ var extensions = this._extensions.slice();
+
+ var pipe = function(message) {
+ if (!message) return callback.call(context, message);
+
+ var extension = extensions.shift();
+ if (!extension) return callback.call(context, message);
+
+ var fn = extension[stage];
+ if (!fn) return pipe(message);
+
+ if (fn.length >= 3) extension[stage](message, request, pipe);
+ else extension[stage](message, pipe);
+ };
+ pipe(message);
+ }
+ };
+
+ extend(Extensible, Logging);
+
+ module.exports = Extensible;
+
+
+/***/ },
+/* 35 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var Class = __webpack_require__(7),
+ Deferrable = __webpack_require__(14);
+
+ module.exports = Class(Deferrable);
+
+
+/***/ },
+/* 36 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var Class = __webpack_require__(7),
+ extend = __webpack_require__(8),
+ Deferrable = __webpack_require__(14);
+
+ var Subscription = Class({
+ initialize: function(client, channels, callback, context) {
+ this._client = client;
+ this._channels = channels;
+ this._callback = callback;
+ this._context = context;
+ this._cancelled = false;
+ },
+
+ withChannel: function(callback, context) {
+ this._withChannel = [callback, context];
+ return this;
+ },
+
+ apply: function(context, args) {
+ var message = args[0];
+
+ if (this._callback)
+ this._callback.call(this._context, message.data);
+
+ if (this._withChannel)
+ this._withChannel[0].call(this._withChannel[1], message.channel, message.data);
+ },
+
+ cancel: function() {
+ if (this._cancelled) return;
+ this._client.unsubscribe(this._channels, this);
+ this._cancelled = true;
+ },
+
+ unsubscribe: function() {
+ this.cancel();
+ }
+ });
+
+ extend(Subscription.prototype, Deferrable);
+
+ module.exports = Subscription;
+
+
+/***/ }
+/******/ ]);
+//# sourceMappingURL=faye-browser.js.map