New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

tabex

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tabex - npm Package Compare versions

Comparing version

to
1.0.2

6

CHANGELOG.md

@@ -0,1 +1,7 @@

1.0.2 / 2015-06-11
------------------
- Added locks support.
1.0.1 / 2015-06-08

@@ -2,0 +8,0 @@ ------------------

176

dist/tabex.js

@@ -1,2 +0,2 @@

/*! tabex 1.0.1 https://github.com//nodeca/tabex @license MIT */(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.tabex = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/*! tabex 1.0.2 https://github.com//nodeca/tabex @license MIT */(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.tabex = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';

@@ -46,2 +46,34 @@

});
// Lock handlers
this.__lock_handlers__ = {};
// If client make lock request - store handler and remove it from message
this.filterOut(function (channel, message, callback) {
if (channel === '!sys.lock.request') {
var fn = message.data.fn;
var lockId = message.data.id;
delete message.data.fn;
// Wrap handler to pass unlock function into it
self.__lock_handlers__[message.id] = function () {
fn(function unlock() {
self.emit('!sys.lock.release', { id: lockId });
});
};
}
callback(channel, message);
});
// If lock acquired - execute handler
this.filterIn(function (channel, message, callback) {
if (channel === '!sys.lock.acquired' && self.__lock_handlers__[message.data.request_id]) {
self.__lock_handlers__[message.data.request_id]();
delete self.__lock_handlers__[message.data.request_id];
}
callback(channel, message);
});
}

@@ -114,2 +146,18 @@

// Try acquire lock and exec `fn` if success
//
// - id - lock identifier
// - timeout - optional, lock lifetime in ms, default `5000`
// - fn - handler will be executed if lock is acquired
//
Client.prototype.lock = function (id, timeout, fn) {
if (!fn) {
fn = timeout;
timeout = 5000;
}
this.emit('!sys.lock.request', { id: id, timeout: timeout, fn: fn });
};
// Filter input messages

@@ -315,3 +363,3 @@ //

/* global window */
/* global document, window */
var LocalStorage = require('./local_storage');

@@ -321,3 +369,5 @@ var $$ = require('./utils');

// Max lifetime of router record in storage
var TIMEOUT = 4000;
// Update router record frequency
var UPDATE_INTERVAL = TIMEOUT / 4;

@@ -341,5 +391,8 @@

this.__handlers__ = [];
this.__router_channels__ = {};
// Constants for convenience
this.__router_id_prefix__ = this.__namespace__ + 'router_';
this.__router_channels_prefix__ = this.__namespace__ + 'subscribed_';
this.__router_channels__ = {};
this.__lock_prefix__ = this.__namespace__ + 'lock_';

@@ -360,7 +413,12 @@ // IE broadcasts storage events also to the same window, we should filter that messages

$$.addEvent(window, 'storage', function (e) {
// In IE 9 without delay `e.newValue` will be broken
// http://stackoverflow.com/questions/9292576/localstorage-getitem-returns-old-data-in-ie-9
setTimeout(function () {
self.__on_changed__(e);
}, 1);
// IE needs kludge because event fire before data was saved
if ('onstoragecommit' in document) {
setTimeout(function () {
self.__on_changed__(e);
}, 1);
return;
}
self.__on_changed__(e);
});

@@ -384,2 +442,7 @@

}, UPDATE_INTERVAL);
// Remove outdated lock records
setInterval(function () {
self.__locks_cleanup__();
}, 1000);
}

@@ -412,2 +475,16 @@

// If it is system lock message - try acquire lock
if (channel === '!sys.lock.request') {
this.__lock__(message.data.id, message.id, message.data.timeout);
return;
}
// If it is system unlock message - remove lock data
if (channel === '!sys.lock.release') {
this.__ls__.removeItem(this.__lock_prefix__ + message.data.id);
return;
}
var serializedMessage = JSON.stringify({

@@ -458,2 +535,85 @@ channel: channel,

// Try acquire lock
//
// - lockId (String)
// - requestId (String)
// - timeout (Number)
//
Router.prototype.__lock__ = function (lockId, requestId, timeout) {
var self = this;
var lockKey = this.__lock_prefix__ + lockId;
var lockValue = this.__ls__.getItem(lockKey);
if (lockValue) {
try {
lockValue = JSON.parse(lockValue);
} catch (__) {
lockValue = null;
}
}
// If `expire` not in past - lock already acquired, exit here
if (lockValue && lockValue.expire > Date.now()) {
return;
}
// Try acquire lock
this.__ls__.setItem(lockKey, JSON.stringify({ expire: timeout + Date.now(), requestId: requestId }));
// Read lock value again to check `requestId` (race condition here - other tab may rewrite value in store)
lockValue = this.__ls__.getItem(lockKey);
if (lockValue) {
try {
lockValue = JSON.parse(lockValue);
} catch (__) {
lockValue = null;
}
}
// If `requestId` is not same - other tab acquire lock, exit here
if (!lockValue || lockValue.requestId !== requestId) {
return;
}
// Here lock acquired - send message to clients
this.__handlers__.forEach(function (handler) {
handler('!sys.lock.acquired', {
data: {
request_id: requestId
},
node_id: self.__node_id__,
id: self.__node_id__ + '_' + (self.__last_message_cnt__++)
});
});
};
// Remove outdated lock records from storage
//
Router.prototype.__locks_cleanup__ = function () {
for (var i = 0, key, val; i < this.__ls__.length; i++) {
key = this.__ls__.key(i);
// Filter localStorage records by prefix
if (key.indexOf(this.__lock_prefix__) !== 0) {
continue;
}
val = this.__ls__.getItem(key);
try {
val = JSON.parse(val);
} catch (__) {
val = null;
}
// If lock expire or record is broken - remove it
if (!val || val.expire < Date.now()) {
this.__ls__.removeItem(key);
}
}
};
// Update master id, if current tab is master - init connect and subscribe channels

@@ -460,0 +620,0 @@ //

4

dist/tabex.min.js

@@ -1,2 +0,2 @@

/*! tabex 1.0.1 https://github.com//nodeca/tabex @license MIT */
!function(_){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=_();else if("function"==typeof define&&define.amd)define([],_);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.tabex=_()}}(function(){return function _(e,t,n){function i(r,o){if(!t[r]){if(!e[r]){var a="function"==typeof require&&require;if(!o&&a)return a(r,!0);if(s)return s(r,!0);var h=new Error("Cannot find module '"+r+"'");throw h.code="MODULE_NOT_FOUND",h}var c=t[r]={exports:{}};e[r][0].call(c.exports,function(_){var t=e[r][1][_];return i(t?t:_)},c,c.exports,_,e,t,n)}return t[r].exports}for(var s="function"==typeof require&&require,r=0;r<n.length;r++)i(n[r]);return i}({1:[function(_,e){"use strict";e.exports=_("./lib")},{"./lib":3}],2:[function(_,e){"use strict";function t(_){var e=this;this.__filters_in__=[],this.__filters_out__=[],this.__subscriptions__=[],this.__node_id__=Math.floor(1e10*Math.random())+1,this.__last_message_cnt__=0,this.__ignore_list__={},this.__router__=_.router,this.__router__.onmessage(function(_,t){e.__onmessage__(_,t)})}var n=_("./utils");t.prototype.emit=function(_,e,t){var i=this,s={id:this.__node_id__+"_"+this.__last_message_cnt__++,node_id:this.__node_id__,data:e};t||(this.__ignore_list__[s.id]=!0),n.asyncEach(this.__filters_out__,_,s,function(_,e){i.__router__.broadcast(_,e)})},t.prototype.on=function(_,e){return this.__subscriptions__.push({channel:_,handler:e}),this.emit("!sys.channels.add",{channel:_}),this},t.prototype.off=function(_,e){var t=this;this.__subscriptions__=this.__subscriptions__.reduce(function(n,i){return i.channel!==_||e&&e!==i.handler?(n.push(i),n):(t.emit("!sys.channels.remove",{channel:_}),n)},[])},t.prototype.filterIn=function(_){return this.__filters_in__.push(_),this},t.prototype.filterOut=function(_){return this.__filters_out__.push(_),this},t.prototype.__onmessage__=function(_,e){var t=this;n.asyncEach(this.__filters_in__,_,e,function(_,e){t.__ignore_list__[e.id]||t.__subscriptions__.forEach(function(t){t.channel===_&&t.handler(e.data,_)})})},e.exports=t},{"./utils":7}],3:[function(_,e){"use strict";var t=_("./router"),n=_("./client"),i=_("./tunnel"),s={},r={_:{}};r._.Router=t,r._.Client=n,r._.Tunnel=i,r.client=function(_){_=_||{};var e,r=_.namespace||"tabex_default_";return _.iframe?e=new i.TunnelClient(_):(s[r]||(s[r]=new t({namespace:r})),e=s[r]),new n({router:e})},r.router=function(_){_=_||{};var e=_.namespace||"tabex_default_";return s[e]||(s[e]=new t({namespace:e})),new i.TunnelRouter({router:s[e],namespace:e,origin:_.origin}),s[e]},e.exports=r},{"./client":2,"./router":5,"./tunnel":6}],4:[function(_,e){"use strict";function t(){}var n=window.localStorage,i={},s=function(){if(document.documentMode&&document.documentMode<9)return!1;if(!n)return!1;try{n.setItem("live_local_storage_is_writable_test",""),n.removeItem("live_local_storage_is_writable_test")}catch(_){return!1}return!0}();Object.defineProperty(t.prototype,"length",{get:function(){return s?n.length:Object.keys(i).length}}),t.prototype.getItem=function(_){return s?n.getItem(_):i.hasOwnProperty(_)?i[_]:null},t.prototype.setItem=function(_,e){s?n.setItem(_,e):i[_]=e},t.prototype.removeItem=function(_){s?n.removeItem(_):i[_]=null},t.prototype.key=function(_){return s?n.key(_):Object.keys(i)[_]},e.exports=t},{}],5:[function(_,e){"use strict";function t(_){var e=this;_=_||{},this.__namespace__=_.namespace||"tabex_default_",this.__node_id__=Math.floor(1e10*Math.random())+1,this.__last_message_cnt__=0,this.__handlers__=[],this.__router_id_prefix__=this.__namespace__+"router_",this.__router_channels_prefix__=this.__namespace__+"subscribed_",this.__router_channels__={},this.__storage_events_filter__=[];for(var t=0;100>t;t++)this.__storage_events_filter__.push("");this.__ls__=new n,this.__master_id__=null,i.addEvent(window,"storage",function(_){setTimeout(function(){e.__on_changed__(_)},1)}),this.__destroyed__=!1,i.addEvent(window,"beforeunload",function(){e.__destroy__()}),i.addEvent(window,"unload",function(){e.__destroy__()}),this.__check_master__(),setInterval(function(){e.__check_master__()},r)}var n=_("./local_storage"),i=_("./utils"),s=4e3,r=s/4;t.prototype.broadcast=function(_,e){if("!sys.channels.add"===_)return this.__router_channels__[e.data.channel]=this.__router_channels__[e.data.channel]||0,this.__router_channels__[e.data.channel]++,void this.__update_channels_list__();if("!sys.channels.remove"===_)return this.__router_channels__[e.data.channel]=this.__router_channels__[e.data.channel]||0,this.__router_channels__[e.data.channel]--,void this.__update_channels_list__();var t=JSON.stringify({channel:_,message:e,random:Math.floor(1e10*Math.random())});this.__storage_events_filter__.shift(),this.__storage_events_filter__.push(this.__namespace__+"broadcast_"+t),this.__ls__.setItem(this.__namespace__+"broadcast",t),this.__handlers__.forEach(function(t){t(_,e)})},t.prototype.onmessage=function(_){var e=this;this.__handlers__.push(_),setTimeout(function(){_("!sys.master",{data:{node_id:e.__node_id__,master_id:e.__master_id__},node_id:e.__node_id__,id:e.__node_id__+"_"+e.__last_message_cnt__++}),e.__on_channels_list_changed__()},0)},t.prototype.__on_master_changed__=function(_){var e=this;return _?(this.__master_id__=+_,void this.__handlers__.forEach(function(_){_("!sys.master",{data:{node_id:e.__node_id__,master_id:e.__master_id__},node_id:e.__node_id__,id:e.__node_id__+"_"+e.__last_message_cnt__++})})):void(this.__get_alive_router_ids__().sort()[0]===this.__node_id__&&(this.__storage_events_filter__.pop(),this.__storage_events_filter__.push(this.__namespace__+"master_"+this.__node_id__),this.__ls__.setItem(this.__namespace__+"master",this.__node_id__),this.__on_master_changed__(this.__node_id__)))},t.prototype.__on_changed__=function(_){if(-1===this.__storage_events_filter__.indexOf(_.key+"_"+_.newValue)&&(_.key===this.__namespace__+"master"&&this.__on_master_changed__(_.newValue),0===_.key.indexOf(this.__router_channels_prefix__)&&this.__on_channels_list_changed__(),_.key===this.__namespace__+"broadcast")){var e=JSON.parse(_.newValue);this.__handlers__.forEach(function(_){_(e.channel,e.message)})}},t.prototype.__destroy__=function(){this.__destroyed__||(this.__destroyed__=!0,this.__ls__.removeItem(this.__router_id_prefix__+this.__node_id__),this.__ls__.removeItem(this.__router_channels_prefix__+this.__node_id__),this.__master_id__===this.__node_id__&&this.__ls__.removeItem(this.__namespace__+"master"))},t.prototype.__get_alive_router_ids__=function(){for(var _,e,t=Date.now()-s,n=[],i=0;i<this.__ls__.length;i++)e=this.__ls__.key(i),0===e.indexOf(this.__router_id_prefix__)&&(_=+e.substr(this.__router_id_prefix__.length),this.__ls__.getItem(e)<t?(this.__ls__.removeItem(e),this.__ls__.removeItem(this.__router_channels_prefix__+_)):n.push(_));return n},t.prototype.__update_channels_list__=function(){var _=this,e=[];Object.keys(this.__router_channels__).forEach(function(t){_.__router_channels__[t]>0&&e.push(t)});var t=JSON.stringify(e.sort());this.__ls__.getItem(this.__router_channels_prefix__+this.__node_id__)!==t&&(this.__storage_events_filter__.pop(),this.__storage_events_filter__.push(this.__router_channels_prefix__+this.__node_id__+"_"+t),this.__ls__.setItem(this.__router_channels_prefix__+this.__node_id__,t),this.__on_channels_list_changed__())},t.prototype.__on_channels_list_changed__=function(){for(var _,e=this,t=[],n=0;n<this.__ls__.length;n++)_=this.__ls__.key(n),0===_.indexOf(this.__router_channels_prefix__)&&(t=t.concat(JSON.parse(this.__ls__.getItem(_))));t=t.reduce(function(_,e){return-1===_.indexOf(e)&&_.push(e),_},[]),this.__handlers__.forEach(function(_){_("!sys.channels.refresh",{id:e.__node_id__+"_"+e.__last_message_cnt__++,node_id:e.__node_id__,data:{channels:t}})})},t.prototype.__check_master__=function(){this.__ls__.setItem(this.__router_id_prefix__+this.__node_id__,Date.now()),this.__master_id__=+this.__ls__.getItem(this.__namespace__+"master"),-1===this.__get_alive_router_ids__().indexOf(this.__master_id__)&&(this.__storage_events_filter__.pop(),this.__storage_events_filter__.push(this.__namespace__+"master_"+this.__node_id__),this.__ls__.setItem(this.__namespace__+"master",this.__node_id__),this.__on_master_changed__(this.__node_id__))},e.exports=t},{"./local_storage":4,"./utils":7}],6:[function(_,e,t){"use strict";function n(_){var e=this;this.__namespace__=_.namespace||"tabex_default_",this.__handlers__=[],this.__iframe_url__=_.iframe,this.__iframe_done__=!1,this.__pending__=[],this.__iframe__=document.createElement("iframe"),this.__iframe__.style.left="-1000px",this.__iframe__.style.position="absolute",this.__iframe__.onload=function(){e.__iframe__.contentWindow.postMessage(JSON.stringify({origin:window.location.origin||window.location.protocol+"//"+window.location.host,namespace:e.__namespace__}),e.__iframe_url__),e.__iframe_done__=!0,e.__pending__.forEach(function(_){e.__iframe__.contentWindow.postMessage(JSON.stringify(_),e.__iframe_url__)}),e.__pending__=null},s.addEvent(window,"message",function(_){if(0===e.__iframe_url__.indexOf(_.origin)){var t;try{t=JSON.parse(_.data)}catch(n){return}t.namespace===e.__namespace__&&e.__handlers__.forEach(function(_){_(t.channel,t.message)})}}),this.__iframe__.src=this.__iframe_url__,s.addEvent(document,"DOMContentLoaded",function(){document.querySelector("body").appendChild(e.__iframe__)})}function i(_){var e,t=this;for(this.__namespace__=_.namespace||"tabex_default_",this.__origin_first_check__=_.origin||window.location.origin||window.location.protocol+"//"+window.location.host,Array.isArray(this.__origin_first_check__)||(this.__origin_first_check__=[this.__origin_first_check__]),e=0;e<this.__origin_first_check__.length;e++)this.__origin_first_check__[e]=this.__origin_first_check__[e].replace(/[-\/\\^$+?.()|[\]{}]/g,"\\$&"),this.__origin_first_check__[e]=this.__origin_first_check__[e].replace(/[*]/g,".+?"),this.__origin_first_check__[e]=new RegExp(this.__origin_first_check__[e]);this.__origin__=null,this.__router__=_.router,s.addEvent(window,"message",function(_){var n=!1;if(!t.__origin__||t.__origin__!==_.origin){for(e=0;e<t.__origin_first_check__.length;e++)if(t.__origin_first_check__[e].test(_.origin)){n=!0;break}if(!n)return}var i;try{i=JSON.parse(_.data)}catch(s){return}if(i.namespace===t.__namespace__)return!t.__origin__&&i.origin?(t.__origin__=i.origin,void t.__router__.onmessage(function(_,e){window.parent.postMessage(JSON.stringify({channel:_,message:e,namespace:t.__namespace__}),t.__origin__)})):void t.__router__.broadcast(i.channel,i.message)})}var s=_("./utils");n.prototype.broadcast=function(_,e){this.__iframe_done__?this.__iframe__.contentWindow.postMessage(JSON.stringify({channel:_,message:e,namespace:this.__namespace__}),this.__iframe_url__):this.__pending__.push({channel:_,message:e,namespace:this.__namespace__})},n.prototype.onmessage=function(_){this.__handlers__.push(_)},t.TunnelClient=n,t.TunnelRouter=i},{"./utils":7}],7:[function(_,e,t){"use strict";t.asyncEach=function(_){function e(){if(0===_.length)return void t.apply(this,arguments);var n=_.shift();n.apply(this,Array.prototype.slice.call(arguments,0).concat(e))}_=_.slice(0);var t=arguments[arguments.length-1],n=Array.prototype.slice.call(arguments,1);n.pop(),e.apply(this,n)},t.addEvent=function(_,e,t){return document.addEventListener?void _.addEventListener(e,t):void _.attachEvent("on"+e,t)}},{}]},{},[1])(1)});
/*! tabex 1.0.2 https://github.com//nodeca/tabex @license MIT */
!function(_){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=_();else if("function"==typeof define&&define.amd)define([],_);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.tabex=_()}}(function(){return function _(e,t,i){function n(r,o){if(!t[r]){if(!e[r]){var a="function"==typeof require&&require;if(!o&&a)return a(r,!0);if(s)return s(r,!0);var h=new Error("Cannot find module '"+r+"'");throw h.code="MODULE_NOT_FOUND",h}var c=t[r]={exports:{}};e[r][0].call(c.exports,function(_){var t=e[r][1][_];return n(t?t:_)},c,c.exports,_,e,t,i)}return t[r].exports}for(var s="function"==typeof require&&require,r=0;r<i.length;r++)n(i[r]);return n}({1:[function(_,e){"use strict";e.exports=_("./lib")},{"./lib":3}],2:[function(_,e){"use strict";function t(_){var e=this;this.__filters_in__=[],this.__filters_out__=[],this.__subscriptions__=[],this.__node_id__=Math.floor(1e10*Math.random())+1,this.__last_message_cnt__=0,this.__ignore_list__={},this.__router__=_.router,this.__router__.onmessage(function(_,t){e.__onmessage__(_,t)}),this.__lock_handlers__={},this.filterOut(function(_,t,i){if("!sys.lock.request"===_){var n=t.data.fn,s=t.data.id;delete t.data.fn,e.__lock_handlers__[t.id]=function(){n(function(){e.emit("!sys.lock.release",{id:s})})}}i(_,t)}),this.filterIn(function(_,t,i){"!sys.lock.acquired"===_&&e.__lock_handlers__[t.data.request_id]&&(e.__lock_handlers__[t.data.request_id](),delete e.__lock_handlers__[t.data.request_id]),i(_,t)})}var i=_("./utils");t.prototype.emit=function(_,e,t){var n=this,s={id:this.__node_id__+"_"+this.__last_message_cnt__++,node_id:this.__node_id__,data:e};t||(this.__ignore_list__[s.id]=!0),i.asyncEach(this.__filters_out__,_,s,function(_,e){n.__router__.broadcast(_,e)})},t.prototype.on=function(_,e){return this.__subscriptions__.push({channel:_,handler:e}),this.emit("!sys.channels.add",{channel:_}),this},t.prototype.off=function(_,e){var t=this;this.__subscriptions__=this.__subscriptions__.reduce(function(i,n){return n.channel!==_||e&&e!==n.handler?(i.push(n),i):(t.emit("!sys.channels.remove",{channel:_}),i)},[])},t.prototype.lock=function(_,e,t){t||(t=e,e=5e3),this.emit("!sys.lock.request",{id:_,timeout:e,fn:t})},t.prototype.filterIn=function(_){return this.__filters_in__.push(_),this},t.prototype.filterOut=function(_){return this.__filters_out__.push(_),this},t.prototype.__onmessage__=function(_,e){var t=this;i.asyncEach(this.__filters_in__,_,e,function(_,e){t.__ignore_list__[e.id]||t.__subscriptions__.forEach(function(t){t.channel===_&&t.handler(e.data,_)})})},e.exports=t},{"./utils":7}],3:[function(_,e){"use strict";var t=_("./router"),i=_("./client"),n=_("./tunnel"),s={},r={_:{}};r._.Router=t,r._.Client=i,r._.Tunnel=n,r.client=function(_){_=_||{};var e,r=_.namespace||"tabex_default_";return _.iframe?e=new n.TunnelClient(_):(s[r]||(s[r]=new t({namespace:r})),e=s[r]),new i({router:e})},r.router=function(_){_=_||{};var e=_.namespace||"tabex_default_";return s[e]||(s[e]=new t({namespace:e})),new n.TunnelRouter({router:s[e],namespace:e,origin:_.origin}),s[e]},e.exports=r},{"./client":2,"./router":5,"./tunnel":6}],4:[function(_,e){"use strict";function t(){}var i=window.localStorage,n={},s=function(){if(document.documentMode&&document.documentMode<9)return!1;if(!i)return!1;try{i.setItem("live_local_storage_is_writable_test",""),i.removeItem("live_local_storage_is_writable_test")}catch(_){return!1}return!0}();Object.defineProperty(t.prototype,"length",{get:function(){return s?i.length:Object.keys(n).length}}),t.prototype.getItem=function(_){return s?i.getItem(_):n.hasOwnProperty(_)?n[_]:null},t.prototype.setItem=function(_,e){s?i.setItem(_,e):n[_]=e},t.prototype.removeItem=function(_){s?i.removeItem(_):n[_]=null},t.prototype.key=function(_){return s?i.key(_):Object.keys(n)[_]},e.exports=t},{}],5:[function(_,e){"use strict";function t(_){var e=this;_=_||{},this.__namespace__=_.namespace||"tabex_default_",this.__node_id__=Math.floor(1e10*Math.random())+1,this.__last_message_cnt__=0,this.__handlers__=[],this.__router_channels__={},this.__router_id_prefix__=this.__namespace__+"router_",this.__router_channels_prefix__=this.__namespace__+"subscribed_",this.__lock_prefix__=this.__namespace__+"lock_",this.__storage_events_filter__=[];for(var t=0;100>t;t++)this.__storage_events_filter__.push("");this.__ls__=new i,this.__master_id__=null,n.addEvent(window,"storage",function(_){return"onstoragecommit"in document?void setTimeout(function(){e.__on_changed__(_)},1):void e.__on_changed__(_)}),this.__destroyed__=!1,n.addEvent(window,"beforeunload",function(){e.__destroy__()}),n.addEvent(window,"unload",function(){e.__destroy__()}),this.__check_master__(),setInterval(function(){e.__check_master__()},r),setInterval(function(){e.__locks_cleanup__()},1e3)}var i=_("./local_storage"),n=_("./utils"),s=4e3,r=s/4;t.prototype.broadcast=function(_,e){if("!sys.channels.add"===_)return this.__router_channels__[e.data.channel]=this.__router_channels__[e.data.channel]||0,this.__router_channels__[e.data.channel]++,void this.__update_channels_list__();if("!sys.channels.remove"===_)return this.__router_channels__[e.data.channel]=this.__router_channels__[e.data.channel]||0,this.__router_channels__[e.data.channel]--,void this.__update_channels_list__();if("!sys.lock.request"===_)return void this.__lock__(e.data.id,e.id,e.data.timeout);if("!sys.lock.release"===_)return void this.__ls__.removeItem(this.__lock_prefix__+e.data.id);var t=JSON.stringify({channel:_,message:e,random:Math.floor(1e10*Math.random())});this.__storage_events_filter__.shift(),this.__storage_events_filter__.push(this.__namespace__+"broadcast_"+t),this.__ls__.setItem(this.__namespace__+"broadcast",t),this.__handlers__.forEach(function(t){t(_,e)})},t.prototype.onmessage=function(_){var e=this;this.__handlers__.push(_),setTimeout(function(){_("!sys.master",{data:{node_id:e.__node_id__,master_id:e.__master_id__},node_id:e.__node_id__,id:e.__node_id__+"_"+e.__last_message_cnt__++}),e.__on_channels_list_changed__()},0)},t.prototype.__lock__=function(_,e,t){var i=this,n=this.__lock_prefix__+_,s=this.__ls__.getItem(n);if(s)try{s=JSON.parse(s)}catch(r){s=null}if(!(s&&s.expire>Date.now())){if(this.__ls__.setItem(n,JSON.stringify({expire:t+Date.now(),requestId:e})),s=this.__ls__.getItem(n))try{s=JSON.parse(s)}catch(r){s=null}s&&s.requestId===e&&this.__handlers__.forEach(function(_){_("!sys.lock.acquired",{data:{request_id:e},node_id:i.__node_id__,id:i.__node_id__+"_"+i.__last_message_cnt__++})})}},t.prototype.__locks_cleanup__=function(){for(var _,e,t=0;t<this.__ls__.length;t++)if(_=this.__ls__.key(t),0===_.indexOf(this.__lock_prefix__)){e=this.__ls__.getItem(_);try{e=JSON.parse(e)}catch(i){e=null}(!e||e.expire<Date.now())&&this.__ls__.removeItem(_)}},t.prototype.__on_master_changed__=function(_){var e=this;return _?(this.__master_id__=+_,void this.__handlers__.forEach(function(_){_("!sys.master",{data:{node_id:e.__node_id__,master_id:e.__master_id__},node_id:e.__node_id__,id:e.__node_id__+"_"+e.__last_message_cnt__++})})):void(this.__get_alive_router_ids__().sort()[0]===this.__node_id__&&(this.__storage_events_filter__.pop(),this.__storage_events_filter__.push(this.__namespace__+"master_"+this.__node_id__),this.__ls__.setItem(this.__namespace__+"master",this.__node_id__),this.__on_master_changed__(this.__node_id__)))},t.prototype.__on_changed__=function(_){if(-1===this.__storage_events_filter__.indexOf(_.key+"_"+_.newValue)&&(_.key===this.__namespace__+"master"&&this.__on_master_changed__(_.newValue),0===_.key.indexOf(this.__router_channels_prefix__)&&this.__on_channels_list_changed__(),_.key===this.__namespace__+"broadcast")){var e=JSON.parse(_.newValue);this.__handlers__.forEach(function(_){_(e.channel,e.message)})}},t.prototype.__destroy__=function(){this.__destroyed__||(this.__destroyed__=!0,this.__ls__.removeItem(this.__router_id_prefix__+this.__node_id__),this.__ls__.removeItem(this.__router_channels_prefix__+this.__node_id__),this.__master_id__===this.__node_id__&&this.__ls__.removeItem(this.__namespace__+"master"))},t.prototype.__get_alive_router_ids__=function(){for(var _,e,t=Date.now()-s,i=[],n=0;n<this.__ls__.length;n++)e=this.__ls__.key(n),0===e.indexOf(this.__router_id_prefix__)&&(_=+e.substr(this.__router_id_prefix__.length),this.__ls__.getItem(e)<t?(this.__ls__.removeItem(e),this.__ls__.removeItem(this.__router_channels_prefix__+_)):i.push(_));return i},t.prototype.__update_channels_list__=function(){var _=this,e=[];Object.keys(this.__router_channels__).forEach(function(t){_.__router_channels__[t]>0&&e.push(t)});var t=JSON.stringify(e.sort());this.__ls__.getItem(this.__router_channels_prefix__+this.__node_id__)!==t&&(this.__storage_events_filter__.pop(),this.__storage_events_filter__.push(this.__router_channels_prefix__+this.__node_id__+"_"+t),this.__ls__.setItem(this.__router_channels_prefix__+this.__node_id__,t),this.__on_channels_list_changed__())},t.prototype.__on_channels_list_changed__=function(){for(var _,e=this,t=[],i=0;i<this.__ls__.length;i++)_=this.__ls__.key(i),0===_.indexOf(this.__router_channels_prefix__)&&(t=t.concat(JSON.parse(this.__ls__.getItem(_))));t=t.reduce(function(_,e){return-1===_.indexOf(e)&&_.push(e),_},[]),this.__handlers__.forEach(function(_){_("!sys.channels.refresh",{id:e.__node_id__+"_"+e.__last_message_cnt__++,node_id:e.__node_id__,data:{channels:t}})})},t.prototype.__check_master__=function(){this.__ls__.setItem(this.__router_id_prefix__+this.__node_id__,Date.now()),this.__master_id__=+this.__ls__.getItem(this.__namespace__+"master"),-1===this.__get_alive_router_ids__().indexOf(this.__master_id__)&&(this.__storage_events_filter__.pop(),this.__storage_events_filter__.push(this.__namespace__+"master_"+this.__node_id__),this.__ls__.setItem(this.__namespace__+"master",this.__node_id__),this.__on_master_changed__(this.__node_id__))},e.exports=t},{"./local_storage":4,"./utils":7}],6:[function(_,e,t){"use strict";function i(_){var e=this;this.__namespace__=_.namespace||"tabex_default_",this.__handlers__=[],this.__iframe_url__=_.iframe,this.__iframe_done__=!1,this.__pending__=[],this.__iframe__=document.createElement("iframe"),this.__iframe__.style.left="-1000px",this.__iframe__.style.position="absolute",this.__iframe__.onload=function(){e.__iframe__.contentWindow.postMessage(JSON.stringify({origin:window.location.origin||window.location.protocol+"//"+window.location.host,namespace:e.__namespace__}),e.__iframe_url__),e.__iframe_done__=!0,e.__pending__.forEach(function(_){e.__iframe__.contentWindow.postMessage(JSON.stringify(_),e.__iframe_url__)}),e.__pending__=null},s.addEvent(window,"message",function(_){if(0===e.__iframe_url__.indexOf(_.origin)){var t;try{t=JSON.parse(_.data)}catch(i){return}t.namespace===e.__namespace__&&e.__handlers__.forEach(function(_){_(t.channel,t.message)})}}),this.__iframe__.src=this.__iframe_url__,s.addEvent(document,"DOMContentLoaded",function(){document.querySelector("body").appendChild(e.__iframe__)})}function n(_){var e,t=this;for(this.__namespace__=_.namespace||"tabex_default_",this.__origin_first_check__=_.origin||window.location.origin||window.location.protocol+"//"+window.location.host,Array.isArray(this.__origin_first_check__)||(this.__origin_first_check__=[this.__origin_first_check__]),e=0;e<this.__origin_first_check__.length;e++)this.__origin_first_check__[e]=this.__origin_first_check__[e].replace(/[-\/\\^$+?.()|[\]{}]/g,"\\$&"),this.__origin_first_check__[e]=this.__origin_first_check__[e].replace(/[*]/g,".+?"),this.__origin_first_check__[e]=new RegExp(this.__origin_first_check__[e]);this.__origin__=null,this.__router__=_.router,s.addEvent(window,"message",function(_){var i=!1;if(!t.__origin__||t.__origin__!==_.origin){for(e=0;e<t.__origin_first_check__.length;e++)if(t.__origin_first_check__[e].test(_.origin)){i=!0;break}if(!i)return}var n;try{n=JSON.parse(_.data)}catch(s){return}if(n.namespace===t.__namespace__)return!t.__origin__&&n.origin?(t.__origin__=n.origin,void t.__router__.onmessage(function(_,e){window.parent.postMessage(JSON.stringify({channel:_,message:e,namespace:t.__namespace__}),t.__origin__)})):void t.__router__.broadcast(n.channel,n.message)})}var s=_("./utils");i.prototype.broadcast=function(_,e){this.__iframe_done__?this.__iframe__.contentWindow.postMessage(JSON.stringify({channel:_,message:e,namespace:this.__namespace__}),this.__iframe_url__):this.__pending__.push({channel:_,message:e,namespace:this.__namespace__})},i.prototype.onmessage=function(_){this.__handlers__.push(_)},t.TunnelClient=i,t.TunnelRouter=n},{"./utils":7}],7:[function(_,e,t){"use strict";t.asyncEach=function(_){function e(){if(0===_.length)return void t.apply(this,arguments);var i=_.shift();i.apply(this,Array.prototype.slice.call(arguments,0).concat(e))}_=_.slice(0);var t=arguments[arguments.length-1],i=Array.prototype.slice.call(arguments,1);i.pop(),e.apply(this,i)},t.addEvent=function(_,e,t){return document.addEventListener?void _.addEventListener(e,t):void _.attachEvent("on"+e,t)}},{}]},{},[1])(1)});

@@ -40,2 +40,34 @@ // Base client class

});
// Lock handlers
this.__lock_handlers__ = {};
// If client make lock request - store handler and remove it from message
this.filterOut(function (channel, message, callback) {
if (channel === '!sys.lock.request') {
var fn = message.data.fn;
var lockId = message.data.id;
delete message.data.fn;
// Wrap handler to pass unlock function into it
self.__lock_handlers__[message.id] = function () {
fn(function unlock() {
self.emit('!sys.lock.release', { id: lockId });
});
};
}
callback(channel, message);
});
// If lock acquired - execute handler
this.filterIn(function (channel, message, callback) {
if (channel === '!sys.lock.acquired' && self.__lock_handlers__[message.data.request_id]) {
self.__lock_handlers__[message.data.request_id]();
delete self.__lock_handlers__[message.data.request_id];
}
callback(channel, message);
});
}

@@ -108,2 +140,18 @@

// Try acquire lock and exec `fn` if success
//
// - id - lock identifier
// - timeout - optional, lock lifetime in ms, default `5000`
// - fn - handler will be executed if lock is acquired
//
Client.prototype.lock = function (id, timeout, fn) {
if (!fn) {
fn = timeout;
timeout = 5000;
}
this.emit('!sys.lock.request', { id: id, timeout: timeout, fn: fn });
};
// Filter input messages

@@ -110,0 +158,0 @@ //

@@ -6,3 +6,3 @@ // LocalStorage router

/* global window */
/* global document, window */
var LocalStorage = require('./local_storage');

@@ -12,3 +12,5 @@ var $$ = require('./utils');

// Max lifetime of router record in storage
var TIMEOUT = 4000;
// Update router record frequency
var UPDATE_INTERVAL = TIMEOUT / 4;

@@ -32,5 +34,8 @@

this.__handlers__ = [];
this.__router_channels__ = {};
// Constants for convenience
this.__router_id_prefix__ = this.__namespace__ + 'router_';
this.__router_channels_prefix__ = this.__namespace__ + 'subscribed_';
this.__router_channels__ = {};
this.__lock_prefix__ = this.__namespace__ + 'lock_';

@@ -51,7 +56,12 @@ // IE broadcasts storage events also to the same window, we should filter that messages

$$.addEvent(window, 'storage', function (e) {
// In IE 9 without delay `e.newValue` will be broken
// http://stackoverflow.com/questions/9292576/localstorage-getitem-returns-old-data-in-ie-9
setTimeout(function () {
self.__on_changed__(e);
}, 1);
// IE needs kludge because event fire before data was saved
if ('onstoragecommit' in document) {
setTimeout(function () {
self.__on_changed__(e);
}, 1);
return;
}
self.__on_changed__(e);
});

@@ -75,2 +85,7 @@

}, UPDATE_INTERVAL);
// Remove outdated lock records
setInterval(function () {
self.__locks_cleanup__();
}, 1000);
}

@@ -103,2 +118,16 @@

// If it is system lock message - try acquire lock
if (channel === '!sys.lock.request') {
this.__lock__(message.data.id, message.id, message.data.timeout);
return;
}
// If it is system unlock message - remove lock data
if (channel === '!sys.lock.release') {
this.__ls__.removeItem(this.__lock_prefix__ + message.data.id);
return;
}
var serializedMessage = JSON.stringify({

@@ -149,2 +178,85 @@ channel: channel,

// Try acquire lock
//
// - lockId (String)
// - requestId (String)
// - timeout (Number)
//
Router.prototype.__lock__ = function (lockId, requestId, timeout) {
var self = this;
var lockKey = this.__lock_prefix__ + lockId;
var lockValue = this.__ls__.getItem(lockKey);
if (lockValue) {
try {
lockValue = JSON.parse(lockValue);
} catch (__) {
lockValue = null;
}
}
// If `expire` not in past - lock already acquired, exit here
if (lockValue && lockValue.expire > Date.now()) {
return;
}
// Try acquire lock
this.__ls__.setItem(lockKey, JSON.stringify({ expire: timeout + Date.now(), requestId: requestId }));
// Read lock value again to check `requestId` (race condition here - other tab may rewrite value in store)
lockValue = this.__ls__.getItem(lockKey);
if (lockValue) {
try {
lockValue = JSON.parse(lockValue);
} catch (__) {
lockValue = null;
}
}
// If `requestId` is not same - other tab acquire lock, exit here
if (!lockValue || lockValue.requestId !== requestId) {
return;
}
// Here lock acquired - send message to clients
this.__handlers__.forEach(function (handler) {
handler('!sys.lock.acquired', {
data: {
request_id: requestId
},
node_id: self.__node_id__,
id: self.__node_id__ + '_' + (self.__last_message_cnt__++)
});
});
};
// Remove outdated lock records from storage
//
Router.prototype.__locks_cleanup__ = function () {
for (var i = 0, key, val; i < this.__ls__.length; i++) {
key = this.__ls__.key(i);
// Filter localStorage records by prefix
if (key.indexOf(this.__lock_prefix__) !== 0) {
continue;
}
val = this.__ls__.getItem(key);
try {
val = JSON.parse(val);
} catch (__) {
val = null;
}
// If lock expire or record is broken - remove it
if (!val || val.expire < Date.now()) {
this.__ls__.removeItem(key);
}
}
};
// Update master id, if current tab is master - init connect and subscribe channels

@@ -151,0 +263,0 @@ //

{
"name": "tabex",
"version": "1.0.1",
"version": "1.0.2",
"description": "Cross-tab message bus for browsers.",

@@ -5,0 +5,0 @@ "keywords": [

@@ -114,2 +114,10 @@ tabex

#### client.lock(id, [timeout, ] fn):
- __id__ - lock identifier
- __timeout__ - optional, lock lifetime in ms, default 5000
- __fn(unlock)__ - handler will be executed if lock is acquired
- __unlock__ - function to release acquired lock
#### client.filterIn(fn), client.filterOut(fn)

@@ -199,5 +207,12 @@

- `channel` - channel name
- __!sys.lock.request__ - emitted by `tabex.client` to try acquire lock. Message data:
- __id__ - lock identifier
- __timeout__ - lock lifetime in ms
- __!sys.lock.acquired__ - emitted when router acquire lock for client
- __request_id__ - request message id
- __!sys.lock.release__ - emitted by `tabex.client` to release already acquired
lock. Message data:
- __id__ - lock identifier
- __!sys.error__ - emitted on internal errors, for debug.
- __!sys.master__ - sepecific for localStorage-based router. Emitted when tab
become master. Message data:
- __!sys.master__ - sepecific for localStorage-based router. Message data:
- `node_id` - id of "local" router node

@@ -207,3 +222,4 @@ - `master_id` - id of node that become master

__Note.__ `!sys.master` event is broadcasted only when `localStorage` router
used. You should NOT rely on it in your general application logic.
used. You should NOT rely on it in your general application logic. Use locks
instead to filter single handler on broadcasts.

@@ -210,0 +226,0 @@