diff --git a/clients/browser/tokensockjs.js b/clients/browser/tokensockjs.js index 90c4083..652802a 100644 --- a/clients/browser/tokensockjs.js +++ b/clients/browser/tokensockjs.js @@ -1,419 +1,431 @@ -;(function(global){ - - var MAX_DELAY = 5 * 1000, - MIN_DELAY = 10, - dt = 5; - - var emitterFunctions = ["on", "addListener", "removeListener", "removeAllListeners"]; - - var noop = function(){}; - - var nextDelay = function(last){ - return Math.min(last * dt, MAX_DELAY); - }; - - var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - var uuid = function(){ - var i, out = ""; - for(i = 0; i < 10; i++) - out += chars.charAt(Math.random() * chars.length | 0); - return out; - }; - - Object.size = function(obj){ - var size = 0, key; - for(key in obj){ - if(obj.hasOwnProperty(key)) size++; - } - return size; - }; - - Object.shallowCopy = function(obj){ - var key, copy = {}; - for(key in obj){ - if(obj.hasOwnProperty(key)) - copy[key] = obj[key]; - } - return copy; - }; - - // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys - if (!Object.keys) { - Object.keys = (function() { - 'use strict'; - var hasOwnProperty = Object.prototype.hasOwnProperty, - hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'), - dontEnums = [ - 'toString', - 'toLocaleString', - 'valueOf', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'constructor' - ], - dontEnumsLength = dontEnums.length; - - return function(obj) { - if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { - throw new TypeError('Object.keys called on non-object'); - } - - var result = [], prop, i; - - for (prop in obj) { - if (hasOwnProperty.call(obj, prop)) { - result.push(prop); - } - } - - if (hasDontEnumBug) { - for (i = 0; i < dontEnumsLength; i++) { - if (hasOwnProperty.call(obj, dontEnums[i])) { - result.push(dontEnums[i]); - } - } - } - return result; - }; - }()); - } - - var Monitor = function(socket, emitter){ - this._socket = socket; - this._inTransit = {}; - this._emitter = emitter; - }; - - Monitor.prototype.sendMessage = function(data, callback){ - if(typeof data === "string") - data = JSON.parse(data); - data.uuid = uuid(); - if(!this._inTransit[data.rpc]) - this._inTransit[data.rpc] = {}; - this._inTransit[data.rpc][data.uuid] = callback || noop; - this._socket.send(JSON.stringify(data)); - }; - - Monitor.prototype.handleResponse = function(data){ - var fn = null; - if(data.rpc && data.uuid) - fn = this._inTransit[data.rpc][data.uuid]; - if(fn && typeof fn === "function"){ - if(data.error) - fn(data.error); - else - fn(null, data.resp); - delete this._inTransit[data.rpc][data.uuid]; - if(Object.size(this._inTransit[data.rpc]) === 0) - delete this._inTransit[data.rpc]; - }if(data.channel){ - this._emitter.emit("message", data.channel, data.message); - } - }; - - var rpcResponse = function(error, resp, instance, data){ - var res = {}; - if(error) - res.error = error.message || error; - else - res.data = resp; - var out = { - rpc: "_rpc", - fid: data.fid, - resp: res - }; - instance._socket.send(JSON.stringify(out)); - }; - - var handleInternal = function(instance, command, data){ - if(command === "subscribe"){ - instance._channels[data.channel] = true; - }else if(command === "unsubscribe"){ - delete instance._channels[data.channel]; - }else if(command === "rpc"){ - var fn = instance._actions; - data.command.split(".").forEach(function(s){ - fn = fn && fn[s] ? fn[s] : null; - }); - if(fn && typeof fn === "function"){ - fn(data.args, function(error, resp){ - rpcResponse(error, resp, instance, data); - }); - } - } - }; - - var attemptReconnect = function(tokenSocket){ - tokenSocket._connectTimer = setTimeout(function(instance){ - resetConnection(instance, function(error){ - if(error){ - instance._emitter.emit("reconnect", error); - attemptReconnect(instance); - }else{ - instance._emitter.emit("reconnect"); - } - }); - }, tokenSocket._connectDelay, tokenSocket); - tokenSocket._connectDelay = nextDelay(tokenSocket._connectDelay); - }; - - var formEncode = function(obj, prefix) { - var prop, out = []; - for(prop in obj){ - if(!obj.hasOwnProperty(prop) || (typeof obj[prop] === "string" && obj[prop].length < 1)) - continue; - var key = prefix ? prefix + "[" + prop + "]" : prop, - val = obj[prop]; - out.push(typeof val == "object" ? formEncode(val, key) : encodeURIComponent(key) + "=" + encodeURIComponent(val)); - } - return out.join("&"); - }; - - var request = function(options, data, callback){ - options = Object.shallowCopy(options); - if(options.dataType && options.dataType.toLowerCase() === "jsonp"){ - var callbackKey = "token_callback_" + new Date().getTime() + "_" + (Math.round(Math.random() * 1e16)).toString(36); - var script = global.document.createElement("script"); - global[callbackKey] = function(resp) { - global.document.body.removeChild(script); - delete global[callbackKey]; - if(typeof resp === "string"){ - try{ - resp = JSON.parse(resp); - }catch(e){ - return callback(new Error(resp || "Error making jsonp request!")); - } - } - callback(resp && resp.error ? resp.error : null, resp); - }; - script.onerror = function(e){ - global.document.body.removeChild(script); - delete global[callbackKey]; - callback(new Error("Error making jsonp request!")); - return false; - }; - script.onload = function(e){ - return false; - }; - script.src = options.url + (options.url.indexOf("?") > 0 ? "&" : "?") + "callback=" + callbackKey + "&" + formEncode(data || {}); - global.document.body.appendChild(script); - }else{ - var xhr = new global.XMLHttpRequest(); - options.url += (data && options.url.indexOf("?") > 0 ? "&" : "?") + formEncode(data || {}); - xhr.open(options.method, options.url, true); - xhr.onreadystatechange = function(){ - if(xhr.readyState === 4){ - var msg = xhr.target ? xhr.target.responseText : xhr.responseText; - try{ - msg = JSON.parse(msg); - }catch(ev){} - - if(xhr.status >= 200 && xhr.status < 300) - callback(null, msg); - else - callback(msg && msg.error ? new Error(msg.error) : msg instanceof Error ? msg : new Error(msg || "Error making HTTP request")); - } - }; - xhr.setRequestHeader("Accept", "application/json"); - xhr.send(); - } - }; - - var resetConnection = function(tokenSocket, callback){ - request(tokenSocket._opts, tokenSocket._authentication, function(error, resp){ - if(error || !resp || !resp.token){ - error = error || new Error("No token found!"); - return typeof callback === "string" - ? tokenSocket._emitter.emit(callback, error) - : callback(error); - } - - tokenSocket._token = resp.token; - tokenSocket._socket = new global.SockJS(tokenSocket._apiRoute + tokenSocket._socketPrefix, null, tokenSocket._sockjs); - tokenSocket._socket.onopen = function(){ - tokenSocket._monitor.sendMessage({ - rpc: "auth", - token: tokenSocket._token - }, function(error, resp){ - callback = typeof callback === "string" ? tokenSocket._emitter.emit.bind(tokenSocket._emitter, callback) : callback; - if(error){ - callback(error); - }else{ - delete tokenSocket._closed; - clearInterval(tokenSocket._connectTimer); - delete tokenSocket._connectTimer; - tokenSocket._connectDelay = MIN_DELAY; - replay(tokenSocket); - callback(); - } - }); - }; - tokenSocket._monitor = new Monitor(tokenSocket._socket, tokenSocket._emitter); - tokenSocket._socket.onmessage = function(e){ - try{ - e.data = JSON.parse(e.data); - }catch(ev){ return; } - if(e.data.internal) - handleInternal(tokenSocket, e.data.command, e.data.data); - else - tokenSocket._monitor.handleResponse(e.data); - }; - tokenSocket._socket.onclose = function(){ - tokenSocket._closed = true; - if(tokenSocket._reconnect) - attemptReconnect(tokenSocket); - }; - }); - }; - - var checkAndUseConnection = function(tokenSocket, callback){ - if(tokenSocket._closed) - tokenSocket._queue.push({ fn: callback }); - else - callback(); - }; - - var replay = function(tokenSocket){ - for(var channel in tokenSocket._channels) - tokenSocket.subscribe(channel); - tokenSocket._queue.forEach(function(curr){ - if(curr.fn && typeof curr.fn === "function") - curr.fn(); - }); - tokenSocket._queue = []; - }; - - var TokenSocket = function(options, actions){ - var self = this; - self._emitter = new EventEmitter(); - - emitterFunctions.forEach(function(fn){ - self[fn] = self._emitter[fn]; - }); - - self._closed = true; - if(!options) - options = {}; - if(!self._ready && typeof options.ready === "function") - self.ready(options.ready); - if(!self._onreconnect && typeof options.onreconnect === "function") - self.onreconnect(options.onreconnect); - if(!options.host) - options.host = global.location.host; - self._reconnect = typeof options.reconnect === "undefined" ? true : options.reconnect; - self._channels = {}; - self._ping = options.ping || false; - self._sockjs = options.sockjs || {}; - self._apiRoute = options.host.indexOf("http") < 0 ? global.location.protocol + "//" + options.host : options.host; - self._socketPrefix = options.socketPrefix || "/sockets"; - self._tokenPath = options.tokenPath || "/socket/token"; - self._actions = typeof actions === "object" ? actions : {}; - self._authentication = options.authentication || {}; - self._queue = []; - self._connectDelay = MIN_DELAY; - self._connectTimer = null; - self._opts = { - method: "GET", - url: self._apiRoute + self._tokenPath, - dataType: options.host !== global.location.host ? "jsonp" : "json" - }; - - if(self._ping && self._ping > 0){ - self._pingTimer = setInterval(function(){ - if(!self._closed) - self.rpc("_ping", {}); - }, self._ping); - } - - resetConnection(self, "ready"); - }; - - TokenSocket.prototype.ready = function(callback){ - this._emitter.on("ready", callback); - }; - - TokenSocket.prototype.onreconnect = function(callback){ - this._emitter.on("reconnect", callback); - }; - - TokenSocket.prototype.channels = function(){ - return Object.keys(this._channels); - }; - - // @rpc is the controller action - TokenSocket.prototype.rpc = function(rpc, data, callback){ - var self = this; - checkAndUseConnection(self, function(){ - self._monitor.sendMessage({ - rpc: rpc, - req: data - }, callback); - }); - }; - - TokenSocket.prototype.register = function(actions){ - this._actions = actions; - }; - - TokenSocket.prototype.subscribe = function(channel, callback){ - var self = this; - checkAndUseConnection(self, function(){ - self._channels[channel] = true; - self._monitor.sendMessage({ - rpc: "_subscribe", - req: { channel: channel } - }, callback); - }); - }; - - TokenSocket.prototype.unsubscribe = function(channel, callback){ - var self = this; - checkAndUseConnection(self, function(){ - delete self._channels[channel]; - self._monitor.sendMessage({ - rpc: "_unsubscribe", - req: { channel: channel } - }, callback); - }); - }; - - TokenSocket.prototype.publish = function(channel, data, callback){ - var self = this; - checkAndUseConnection(self, function(){ - self._monitor.sendMessage({ - rpc: "_publish", - req: { - channel: channel, - data: data - } - }, callback); - }); - }; - - TokenSocket.prototype.broadcast = function(data, callback){ - var self = this; - checkAndUseConnection(self, function(){ - self._monitor.sendMessage({ - rpc: "_broadcast", - req: { data: data } - }, callback); - }); - }; - - TokenSocket.prototype.onmessage = function(callback){ - this._emitter.on("message", callback); - }; - - TokenSocket.prototype.end = function(callback){ - this._emitter.removeAllListeners("ready"); - this._emitter.removeAllListeners("reconnect"); - this._emitter.removeAllListeners("message"); - this._closed = true; - this._socket.onclose = callback; - this._socket.close(); - }; - - global.TokenSocket = TokenSocket; - -}(typeof window === "undefined" ? {} : window)); +(function (root, factory) { + 'use strict'; + + module.exports = factory( + root, + exports, + require('events').EventEmitter, + require('sockjs-client') + ); +}(typeof window === "undefined" ? {} : window, function (root, Module, EventEmitter, SockJS) { + 'use strict'; + + var MAX_DELAY = 5 * 1000, + MIN_DELAY = 10, + dt = 5; + + var emitterFunctions = ["on", "addListener", "removeListener", "removeAllListeners"]; + + var noop = function(){}; + + var nextDelay = function(last){ + return Math.min(last * dt, MAX_DELAY); + }; + + var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + var uuid = function(){ + var i, out = ""; + for(i = 0; i < 10; i++) + out += chars.charAt(Math.random() * chars.length | 0); + return out; + }; + + Object.size = function(obj){ + var size = 0, key; + for(key in obj){ + if(obj.hasOwnProperty(key)) size++; + } + return size; + }; + + Object.shallowCopy = function(obj){ + var key, copy = {}; + for(key in obj){ + if(obj.hasOwnProperty(key)) + copy[key] = obj[key]; + } + return copy; + }; + + // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys + if (!Object.keys) { + Object.keys = (function() { + 'use strict'; + var hasOwnProperty = Object.prototype.hasOwnProperty, + hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'), + dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + dontEnumsLength = dontEnums.length; + + return function(obj) { + if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { + throw new TypeError('Object.keys called on non-object'); + } + + var result = [], prop, i; + + for (prop in obj) { + if (hasOwnProperty.call(obj, prop)) { + result.push(prop); + } + } + + if (hasDontEnumBug) { + for (i = 0; i < dontEnumsLength; i++) { + if (hasOwnProperty.call(obj, dontEnums[i])) { + result.push(dontEnums[i]); + } + } + } + return result; + }; + }()); + } + + var Monitor = function(socket, emitter){ + this._socket = socket; + this._inTransit = {}; + this._emitter = emitter; + }; + + Monitor.prototype.sendMessage = function(data, callback){ + if(typeof data === "string") + data = JSON.parse(data); + data.uuid = uuid(); + if(!this._inTransit[data.rpc]) + this._inTransit[data.rpc] = {}; + this._inTransit[data.rpc][data.uuid] = callback || noop; + this._socket.send(JSON.stringify(data)); + }; + + Monitor.prototype.handleResponse = function(data){ + var fn = null; + if(data.rpc && data.uuid) + fn = this._inTransit[data.rpc][data.uuid]; + if(fn && typeof fn === "function"){ + if(data.error) + fn(data.error); + else + fn(null, data.resp); + delete this._inTransit[data.rpc][data.uuid]; + if(Object.size(this._inTransit[data.rpc]) === 0) + delete this._inTransit[data.rpc]; + }if(data.channel){ + this._emitter.emit("message", data.channel, data.message); + } + }; + + var rpcResponse = function(error, resp, instance, data){ + var res = {}; + if(error) + res.error = error.message || error; + else + res.data = resp; + var out = { + rpc: "_rpc", + fid: data.fid, + resp: res + }; + instance._socket.send(JSON.stringify(out)); + }; + + var handleInternal = function(instance, command, data){ + if(command === "subscribe"){ + instance._channels[data.channel] = true; + }else if(command === "unsubscribe"){ + delete instance._channels[data.channel]; + }else if(command === "rpc"){ + var fn = instance._actions; + data.command.split(".").forEach(function(s){ + fn = fn && fn[s] ? fn[s] : null; + }); + if(fn && typeof fn === "function"){ + fn(data.args, function(error, resp){ + rpcResponse(error, resp, instance, data); + }); + } + } + }; + + var attemptReconnect = function(tokenSocket){ + tokenSocket._connectTimer = setTimeout(function(instance){ + resetConnection(instance, function(error){ + if(error){ + instance._emitter.emit("reconnect", error); + attemptReconnect(instance); + }else{ + instance._emitter.emit("reconnect"); + } + }); + }, tokenSocket._connectDelay, tokenSocket); + tokenSocket._connectDelay = nextDelay(tokenSocket._connectDelay); + }; + + var formEncode = function(obj, prefix) { + var prop, out = []; + for(prop in obj){ + if(!obj.hasOwnProperty(prop) || (typeof obj[prop] === "string" && obj[prop].length < 1)) + continue; + var key = prefix ? prefix + "[" + prop + "]" : prop, + val = obj[prop]; + out.push(typeof val == "object" ? formEncode(val, key) : encodeURIComponent(key) + "=" + encodeURIComponent(val)); + } + return out.join("&"); + }; + + var request = function(options, data, callback){ + options = Object.shallowCopy(options); + if(options.dataType && options.dataType.toLowerCase() === "jsonp"){ + var callbackKey = "token_callback_" + new Date().getTime() + "_" + (Math.round(Math.random() * 1e16)).toString(36); + var script = global.document.createElement("script"); + global[callbackKey] = function(resp) { + global.document.body.removeChild(script); + delete global[callbackKey]; + if(typeof resp === "string"){ + try{ + resp = JSON.parse(resp); + }catch(e){ + return callback(new Error(resp || "Error making jsonp request!")); + } + } + callback(resp && resp.error ? resp.error : null, resp); + }; + script.onerror = function(e){ + global.document.body.removeChild(script); + delete global[callbackKey]; + callback(new Error("Error making jsonp request!")); + return false; + }; + script.onload = function(e){ + return false; + }; + script.src = options.url + (options.url.indexOf("?") > 0 ? "&" : "?") + "callback=" + callbackKey + "&" + formEncode(data || {}); + global.document.body.appendChild(script); + }else{ + var xhr = new global.XMLHttpRequest(); + options.url += (data && options.url.indexOf("?") > 0 ? "&" : "?") + formEncode(data || {}); + xhr.open(options.method, options.url, true); + xhr.onreadystatechange = function(){ + if(xhr.readyState === 4){ + var msg = xhr.target ? xhr.target.responseText : xhr.responseText; + try{ + msg = JSON.parse(msg); + }catch(ev){} + + if(xhr.status >= 200 && xhr.status < 300) + callback(null, msg); + else + callback(msg && msg.error ? new Error(msg.error) : msg instanceof Error ? msg : new Error(msg || "Error making HTTP request")); + } + }; + xhr.setRequestHeader("Accept", "application/json"); + xhr.send(); + } + }; + + var resetConnection = function(tokenSocket, callback){ + request(tokenSocket._opts, tokenSocket._authentication, function(error, resp){ + if(error || !resp || !resp.token){ + error = error || new Error("No token found!"); + return typeof callback === "string" + ? tokenSocket._emitter.emit(callback, error) + : callback(error); + } + + tokenSocket._token = resp.token; + tokenSocket._socket = new SockJS(tokenSocket._apiRoute + tokenSocket._socketPrefix, null, tokenSocket._sockjs); + tokenSocket._socket.onopen = function(){ + tokenSocket._monitor.sendMessage({ + rpc: "auth", + token: tokenSocket._token + }, function(error, resp){ + callback = typeof callback === "string" ? tokenSocket._emitter.emit.bind(tokenSocket._emitter, callback) : callback; + if(error){ + callback(error); + }else{ + delete tokenSocket._closed; + clearInterval(tokenSocket._connectTimer); + delete tokenSocket._connectTimer; + tokenSocket._connectDelay = MIN_DELAY; + replay(tokenSocket); + callback(); + } + }); + }; + tokenSocket._monitor = new Monitor(tokenSocket._socket, tokenSocket._emitter); + tokenSocket._socket.onmessage = function(e){ + try{ + e.data = JSON.parse(e.data); + }catch(ev){ return; } + if(e.data.internal) + handleInternal(tokenSocket, e.data.command, e.data.data); + else + tokenSocket._monitor.handleResponse(e.data); + }; + tokenSocket._socket.onclose = function(){ + tokenSocket._closed = true; + if(tokenSocket._reconnect) + attemptReconnect(tokenSocket); + }; + }); + }; + + var checkAndUseConnection = function(tokenSocket, callback){ + if(tokenSocket._closed) + tokenSocket._queue.push({ fn: callback }); + else + callback(); + }; + + var replay = function(tokenSocket){ + for(var channel in tokenSocket._channels) + tokenSocket.subscribe(channel); + tokenSocket._queue.forEach(function(curr){ + if(curr.fn && typeof curr.fn === "function") + curr.fn(); + }); + tokenSocket._queue = []; + }; + + var TokenSocket = function(options, actions){ + var self = this; + self._emitter = new EventEmitter(); + + emitterFunctions.forEach(function(fn){ + self[fn] = self._emitter[fn]; + }); + + self._closed = true; + if(!options) + options = {}; + if(!self._ready && typeof options.ready === "function") + self.ready(options.ready); + if(!self._onreconnect && typeof options.onreconnect === "function") + self.onreconnect(options.onreconnect); + if(!options.host) + options.host = global.location.host; + self._reconnect = typeof options.reconnect === "undefined" ? true : options.reconnect; + self._channels = {}; + self._ping = options.ping || false; + self._sockjs = options.sockjs || {}; + self._apiRoute = options.host.indexOf("http") < 0 ? global.location.protocol + "//" + options.host : options.host; + self._socketPrefix = options.socketPrefix || "/sockets"; + self._tokenPath = options.tokenPath || "/socket/token"; + self._actions = typeof actions === "object" ? actions : {}; + self._authentication = options.authentication || {}; + self._queue = []; + self._connectDelay = MIN_DELAY; + self._connectTimer = null; + self._opts = { + method: "GET", + url: self._apiRoute + self._tokenPath, + dataType: options.host !== global.location.host ? "jsonp" : "json" + }; + + if(self._ping && self._ping > 0){ + self._pingTimer = setInterval(function(){ + if(!self._closed) + self.rpc("_ping", {}); + }, self._ping); + } + + resetConnection(self, "ready"); + }; + + TokenSocket.prototype.ready = function(callback){ + this._emitter.on("ready", callback); + }; + + TokenSocket.prototype.onreconnect = function(callback){ + this._emitter.on("reconnect", callback); + }; + + TokenSocket.prototype.channels = function(){ + return Object.keys(this._channels); + }; + + // @rpc is the controller action + TokenSocket.prototype.rpc = function(rpc, data, callback){ + var self = this; + checkAndUseConnection(self, function(){ + self._monitor.sendMessage({ + rpc: rpc, + req: data + }, callback); + }); + }; + + TokenSocket.prototype.register = function(actions){ + this._actions = actions; + }; + + TokenSocket.prototype.subscribe = function(channel, callback){ + var self = this; + checkAndUseConnection(self, function(){ + self._channels[channel] = true; + self._monitor.sendMessage({ + rpc: "_subscribe", + req: { channel: channel } + }, callback); + }); + }; + + TokenSocket.prototype.unsubscribe = function(channel, callback){ + var self = this; + checkAndUseConnection(self, function(){ + delete self._channels[channel]; + self._monitor.sendMessage({ + rpc: "_unsubscribe", + req: { channel: channel } + }, callback); + }); + }; + + TokenSocket.prototype.publish = function(channel, data, callback){ + var self = this; + checkAndUseConnection(self, function(){ + self._monitor.sendMessage({ + rpc: "_publish", + req: { + channel: channel, + data: data + } + }, callback); + }); + }; + + TokenSocket.prototype.broadcast = function(data, callback){ + var self = this; + checkAndUseConnection(self, function(){ + self._monitor.sendMessage({ + rpc: "_broadcast", + req: { data: data } + }, callback); + }); + }; + + TokenSocket.prototype.onmessage = function(callback){ + this._emitter.on("message", callback); + }; + + TokenSocket.prototype.end = function(callback){ + this._emitter.removeAllListeners("ready"); + this._emitter.removeAllListeners("reconnect"); + this._emitter.removeAllListeners("message"); + this._closed = true; + this._socket.onclose = callback; + this._socket.close(); + }; + + Module = TokenSocket; + root.TokenSocket = Module; + return Module; +})); + diff --git a/package.json b/package.json index ecf6236..9a63158 100644 --- a/package.json +++ b/package.json @@ -45,9 +45,11 @@ }, "dependencies": { "async": "^1.5.2", + "events": "^1.1.0", "lodash": "^4.0.0", "node-uuid": "^1.4.1", "restjs": "azuqua/restjs", + "sockjs-client": "^1.1.0", "sockjs-client-ws": "^0.1.0" } }