Socket
Socket
Sign inDemoInstall

broadcast-channel

Package Overview
Dependencies
10
Maintainers
1
Versions
98
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.1 to 1.0.0

1

dist/es/browserify.index.js

@@ -1,4 +0,3 @@

require('babel-polyfill');
var BroadcastChannel = require('./index.js');
window['BroadcastChannel2'] = BroadcastChannel;

198

dist/es/index.js

@@ -1,5 +0,1 @@

import _regeneratorRuntime from 'babel-runtime/regenerator';
import _asyncToGenerator from 'babel-runtime/helpers/asyncToGenerator';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _createClass from 'babel-runtime/helpers/createClass';
import { isPromise } from './util.js';

@@ -11,8 +7,7 @@

var BroadcastChannel = function () {
function BroadcastChannel(name) {
module.exports = function () {
var BroadcastChannel = function BroadcastChannel(name) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, BroadcastChannel);
this.name = name;

@@ -24,129 +19,47 @@ this.options = fillOptionsWithDefaults(options);

this._prepare();
}
BroadcastChannel.prototype._prepare = function _prepare() {
var _this = this;
var maybePromise = this.method.create(this.name, this.options);
if (isPromise(maybePromise)) {
this._preparePromise = maybePromise;
maybePromise.then(function () {
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(s) {
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
// used in tests to simulate slow runtime
if (_this.options.prepareDelay) {
// await new Promise(res => setTimeout(res, this.options.prepareDelay));
}
_this._state = s;
case 2:
case 'end':
return _context.stop();
}
}
}, _callee, _this);
}));
return function (_x2) {
return _ref.apply(this, arguments);
};
}());
} else {
this._state = maybePromise;
}
};
BroadcastChannel.prototype.postMessage = function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(msg) {
var msgObj;
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
msgObj = {
time: new Date().getTime(),
data: msg
};
BroadcastChannel.prototype = {
_prepare: function _prepare() {
var _this = this;
if (!this.closed) {
_context2.next = 3;
break;
}
throw new Error('BroadcastChannel.postMessage(): ' + 'Cannot post message after channel has closed');
case 3:
if (!this._preparePromise) {
_context2.next = 6;
break;
}
_context2.next = 6;
return this._preparePromise;
case 6:
return _context2.abrupt('return', this.method.postMessage(this._state, msgObj));
case 7:
case 'end':
return _context2.stop();
var maybePromise = this.method.create(this.name, this.options);
if (isPromise(maybePromise)) {
this._preparePromise = maybePromise;
maybePromise.then(function (s) {
// used in tests to simulate slow runtime
if (_this.options.prepareDelay) {
// await new Promise(res => setTimeout(res, this.options.prepareDelay));
}
}
}, _callee2, this);
}));
_this._state = s;
});
} else {
this._state = maybePromise;
}
},
postMessage: function postMessage(msg) {
var _this2 = this;
function postMessage(_x3) {
return _ref2.apply(this, arguments);
}
var msgObj = {
time: new Date().getTime(),
data: msg
};
return postMessage;
}();
if (this.closed) {
throw new Error('BroadcastChannel.postMessage(): ' + 'Cannot post message after channel has closed');
}
BroadcastChannel.prototype.close = function () {
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
this.closed = true;
var awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve();
return awaitPrepare.then(function () {
return _this2.method.postMessage(_this2._state, msgObj);
});
},
if (!this._preparePromise) {
_context3.next = 4;
break;
}
set onmessage(fn) {
var _this3 = this;
_context3.next = 4;
return this._preparePromise;
case 4:
_context3.next = 6;
return this.method.close(this._state);
case 6:
case 'end':
return _context3.stop();
}
}
}, _callee3, this);
}));
function close() {
return _ref3.apply(this, arguments);
}
return close;
}();
_createClass(BroadcastChannel, [{
key: 'onmessage',
set: function set(fn) {
var _this2 = this;
var time = new Date().getTime() - 5;
if (this._preparePromise) {
this._preparePromise.then(function () {
_this2.method.onMessage(_this2._state, messageHandler(fn, time), time);
_this3.method.onMessage(_this3._state, messageHandler(fn, time), time);
});

@@ -156,24 +69,27 @@ } else {

}
}
}, {
key: 'type',
get: function get() {
return this.method.type;
}
}]);
},
close: function close() {
var _this4 = this;
return BroadcastChannel;
}();
this.closed = true;
var awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve();
return awaitPrepare.then(function () {
return _this4.method.close(_this4._state);
});
},
;
function messageHandler(fn, minTime) {
return function (msgObj) {
if (msgObj.time >= minTime) {
fn(msgObj.data);
get type() {
return this.method.type;
}
};
}
export default BroadcastChannel;
module.exports = BroadcastChannel;
function messageHandler(fn, minTime) {
return function (msgObj) {
if (msgObj.time >= minTime) {
fn(msgObj.data);
}
};
};
return BroadcastChannel;
}();

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

import _JSON$stringify from 'babel-runtime/core-js/json/stringify';
import isNode from 'detect-node';
var isNode = require('detect-node');
import * as NativeMethod from './methods/native.js';
import * as IndexeDbMethod from './methods/indexed-db.js';
import * as LocalstorageMethod from './methods/localstorage.js';
var NativeMethod = require('./methods/native.js');
var IndexeDbMethod = require('./methods/indexed-db.js');
var LocalstorageMethod = require('./methods/localstorage.js');

@@ -12,2 +11,4 @@ // order is important

var REQUIRE_FUN = require;
/**

@@ -18,3 +19,3 @@ * The NodeMethod is loaded lazy

if (isNode) {
var NodeMethod = require('./methods/node.js');
var NodeMethod = REQUIRE_FUN('./methods/node.js');
METHODS.push(NodeMethod);

@@ -43,5 +44,5 @@ }

});
if (!useMethod) throw new Error('No useable methode found:' + _JSON$stringify(METHODS.map(function (m) {
if (!useMethod) throw new Error('No useable methode found:' + JSON.stringify(METHODS.map(function (m) {
return m.type;
})));else return useMethod;
}

@@ -1,6 +0,1 @@

import _getIterator from 'babel-runtime/core-js/get-iterator';
import _Set from 'babel-runtime/core-js/set';
import _regeneratorRuntime from 'babel-runtime/regenerator';
import _Promise from 'babel-runtime/core-js/promise';
import _asyncToGenerator from 'babel-runtime/helpers/asyncToGenerator';
/**

@@ -14,7 +9,9 @@ * this method uses indexeddb to store the messages

import isNode from 'detect-node';
import randomToken from 'random-token';
import randomInt from 'random-int';
import IdleQueue from 'custom-idle-queue';
var isNode = require('detect-node');
var randomToken = require('random-token');
var randomInt = require('random-int');
var IdleQueue = require('custom-idle-queue');
import { sleep } from '../util.js';
import { fillOptionsWithDefaults } from '../options';

@@ -36,50 +33,28 @@

export var createDatabase = function () {
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(channelName) {
var IndexedDB, dbName, openRequest, db;
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
IndexedDB = getIdb();
export function createDatabase(channelName) {
var IndexedDB = getIdb();
// create table
// create table
var dbName = DB_PREFIX + channelName;
var openRequest = IndexedDB.open(dbName, 1);
dbName = DB_PREFIX + channelName;
openRequest = IndexedDB.open(dbName, 1);
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
keyPath: 'id',
autoIncrement: true
});
};
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
return dbPromise;
}
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
keyPath: 'id',
autoIncrement: true
});
};
_context.next = 6;
return new _Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
case 6:
db = _context.sent;
return _context.abrupt('return', db);
case 8:
case 'end':
return _context.stop();
}
}
}, _callee, this);
}));
return function createDatabase(_x) {
return _ref.apply(this, arguments);
};
}();
/**

@@ -89,298 +64,145 @@ * writes the new message to the database

*/
export var writeMessage = function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(db, readerUuid, messageJson) {
var time, writeObject, transaction;
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
time = new Date().getTime();
writeObject = {
uuid: readerUuid,
time: time,
data: messageJson
};
transaction = db.transaction([OBJECT_STORE_ID], 'readwrite');
return _context2.abrupt('return', new _Promise(function (res, rej) {
transaction.oncomplete = function () {
return res();
};
transaction.onerror = function (ev) {
return rej(ev);
};
var objectStore = transaction.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
}));
case 4:
case 'end':
return _context2.stop();
}
}
}, _callee2, this);
}));
return function writeMessage(_x2, _x3, _x4) {
return _ref2.apply(this, arguments);
export function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
uuid: readerUuid,
time: time,
data: messageJson
};
}();
export var getAllMessages = function () {
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(db) {
var objectStore, ret;
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
ret = [];
return _context3.abrupt('return', new _Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
ret.push(cursor.value);
//alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor['continue']();
} else {
res(ret);
}
};
}));
var transaction = db.transaction([OBJECT_STORE_ID], 'readwrite');
case 3:
case 'end':
return _context3.stop();
}
}
}, _callee3, this);
}));
return new Promise(function (res, rej) {
transaction.oncomplete = function () {
return res();
};
transaction.onerror = function (ev) {
return rej(ev);
};
return function getAllMessages(_x5) {
return _ref3.apply(this, arguments);
};
}();
var objectStore = transaction.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
});
}
export var getMessagesHigherThen = function () {
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(db, lastCursorId) {
var objectStore, ret, keyRangeValue;
return _regeneratorRuntime.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
ret = [];
keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
return _context4.abrupt('return', new _Promise(function (res) {
objectStore.openCursor(keyRangeValue).onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
ret.push(cursor.value);
//alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor['continue']();
} else {
res(ret);
}
};
}));
case 4:
case 'end':
return _context4.stop();
}
export function getAllMessages(db) {
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
ret.push(cursor.value);
//alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor['continue']();
} else {
res(ret);
}
}, _callee4, this);
}));
};
});
}
return function getMessagesHigherThen(_x6, _x7) {
return _ref4.apply(this, arguments);
};
}();
export var removeMessageById = function () {
var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5(db, id) {
var request;
return _regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
request = db.transaction([OBJECT_STORE_ID], 'readwrite').objectStore(OBJECT_STORE_ID)['delete'](id);
return _context5.abrupt('return', new _Promise(function (res) {
request.onsuccess = function () {
return res();
};
}));
case 2:
case 'end':
return _context5.stop();
}
export function getMessagesHigherThen(db, lastCursorId) {
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
return new Promise(function (res) {
objectStore.openCursor(keyRangeValue).onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
ret.push(cursor.value);
//alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor['continue']();
} else {
res(ret);
}
}, _callee5, this);
}));
};
});
}
return function removeMessageById(_x8, _x9) {
return _ref5.apply(this, arguments);
};
}();
export function removeMessageById(db, id) {
var request = db.transaction([OBJECT_STORE_ID], 'readwrite').objectStore(OBJECT_STORE_ID)['delete'](id);
return new Promise(function (res) {
request.onsuccess = function () {
return res();
};
});
}
export var getOldMessages = function () {
var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6(db, ttl) {
var olderThen, objectStore, ret;
return _regeneratorRuntime.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
olderThen = new Date().getTime() - ttl;
objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
ret = [];
return _context6.abrupt('return', new _Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
var msgObk = cursor.value;
if (msgObk.time < olderThen) {
ret.push(msgObk);
//alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor['continue']();
} else {
// no more old messages,
res(ret);
return;
}
} else {
res(ret);
}
};
}));
case 4:
case 'end':
return _context6.stop();
export function getOldMessages(db, ttl) {
var olderThen = new Date().getTime() - ttl;
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
var msgObk = cursor.value;
if (msgObk.time < olderThen) {
ret.push(msgObk);
//alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor['continue']();
} else {
// no more old messages,
res(ret);
return;
}
} else {
res(ret);
}
}, _callee6, this);
}));
};
});
}
return function getOldMessages(_x10, _x11) {
return _ref6.apply(this, arguments);
};
}();
export function cleanOldMessages(db, ttl) {
return getOldMessages(db, ttl).then(function (tooOld) {
return Promise.all(tooOld.map(function (msgObj) {
return removeMessageById(db, msgObj.id);
}));
});
}
export var cleanOldMessages = function () {
var _ref7 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee7(db, ttl) {
var tooOld;
return _regeneratorRuntime.wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
_context7.next = 2;
return getOldMessages(db, ttl);
export function create(channelName, options) {
options = fillOptionsWithDefaults(options);
case 2:
tooOld = _context7.sent;
return _context7.abrupt('return', _Promise.all(tooOld.map(function (msgObj) {
return removeMessageById(db, msgObj.id);
})));
var uuid = randomToken(10);
case 4:
case 'end':
return _context7.stop();
}
}
}, _callee7, this);
}));
// ensures we do not read messages in parrallel
var readQueue = new IdleQueue(1);
return function cleanOldMessages(_x12, _x13) {
return _ref7.apply(this, arguments);
};
}();
return createDatabase(channelName).then(function (db) {
var state = {
closed: false,
lastCursorId: 0,
channelName: channelName,
options: options,
uuid: uuid,
// contains all messages that have been emitted before
emittedMessagesIds: new Set(),
messagesCallback: null,
readQueue: readQueue,
db: db
};
export var create = function () {
var _ref8 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee9(channelName) {
var _this = this;
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
_readLoop(state);
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var uuid, readQueue, db, state;
return _regeneratorRuntime.wrap(function _callee9$(_context9) {
while (1) {
switch (_context9.prev = _context9.next) {
case 0:
options = fillOptionsWithDefaults(options);
return state;
});
}
uuid = randomToken(10);
function _readLoop(state) {
if (state.closed) return;
// ensures we do not read messages in parrallel
return handleMessagePing(state).then(function () {
return sleep(state.options.idb.fallbackInterval);
}).then(function () {
return _readLoop(state);
});
}
readQueue = new IdleQueue(1);
_context9.next = 5;
return createDatabase(channelName);
case 5:
db = _context9.sent;
state = {
closed: false,
lastCursorId: 0,
channelName: channelName,
options: options,
uuid: uuid,
// contains all messages that have been emitted before
emittedMessagesIds: new _Set(),
messagesCallback: null,
readQueue: readQueue,
db: db
};
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee8() {
return _regeneratorRuntime.wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
if (!(state.closed === false)) {
_context8.next = 7;
break;
}
_context8.next = 3;
return handleMessagePing(state);
case 3:
_context8.next = 5;
return new _Promise(function (res) {
return setTimeout(res, state.options.idb.fallbackInterval);
});
case 5:
_context8.next = 0;
break;
case 7:
case 'end':
return _context8.stop();
}
}
}, _callee8, _this);
}))();
return _context9.abrupt('return', state);
case 9:
case 'end':
return _context9.stop();
}
}
}, _callee9, this);
}));
return function create(_x14) {
return _ref8.apply(this, arguments);
};
}();
/**

@@ -390,119 +212,56 @@ * when the storage-event pings, so that we now new messages came,

*/
export var handleMessagePing = function () {
var _ref10 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee11(state) {
var _this2 = this;
export function handleMessagePing(state) {
/**
* when there are no listener, we do nothing
*/
if (!state.messagesCallback) return Promise.resolve();
return _regeneratorRuntime.wrap(function _callee11$(_context11) {
while (1) {
switch (_context11.prev = _context11.next) {
case 0:
if (state.messagesCallback) {
_context11.next = 2;
break;
}
/**
* if we have 2 or more read-tasks in the queue,
* we do not have to set more
*/
if (state.readQueue._idleCalls.size > 1) return Promise.resolve();
return _context11.abrupt('return');
return state.readQueue.requestIdlePromise().then(function () {
return state.readQueue.wrapCall(function () {
return _handleMessagePingInner(state);
});
});
}
case 2:
if (!(state.readQueue._idleCalls.size > 1)) {
_context11.next = 4;
break;
}
function _handleMessagePingInner(state) {
return getMessagesHigherThen(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages.map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
return msgObj;
}).filter(function (msgObj) {
return msgObj.uuid !== state.uuid;
}) // not send by own
.filter(function (msgObj) {
return !state.emittedMessagesIds.has(msgObj.id);
}) // not already emitted
.filter(function (msgObj) {
return msgObj.time >= state.messagesCallbackTime;
}) // not older then onMessageCallback
.sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
return _context11.abrupt('return');
case 4:
_context11.next = 6;
return state.readQueue.requestIdlePromise();
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.emittedMessagesIds.add(msgObj.id);
setTimeout(function () {
return state.emittedMessagesIds['delete'](msgObj.id);
}, state.options.idb.ttl * 2);
case 6:
_context11.next = 8;
return state.readQueue.wrapCall(_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee10() {
var newerMessages, useMessages, _loop, _iterator, _isArray, _i, _ref12, _ret;
return _regeneratorRuntime.wrap(function _callee10$(_context10) {
while (1) {
switch (_context10.prev = _context10.next) {
case 0:
_context10.next = 2;
return getMessagesHigherThen(state.db, state.lastCursorId);
case 2:
newerMessages = _context10.sent;
useMessages = newerMessages.map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
return msgObj;
}).filter(function (msgObj) {
return msgObj.uuid !== state.uuid;
}) // not send by own
.filter(function (msgObj) {
return !state.emittedMessagesIds.has(msgObj.id);
}) // not already emitted
.filter(function (msgObj) {
return msgObj.time >= state.messagesCallbackTime;
}) // not older then onMessageCallback
.sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
_loop = function _loop() {
if (_isArray) {
if (_i >= _iterator.length) return 'break';
_ref12 = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) return 'break';
_ref12 = _i.value;
}
var msgObj = _ref12;
if (state.messagesCallback) {
state.emittedMessagesIds.add(msgObj.id);
setTimeout(function () {
return state.emittedMessagesIds['delete'](msgObj.id);
}, state.options.idb.ttl * 2);
state.messagesCallback(msgObj.data);
}
};
_iterator = useMessages, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);
case 6:
_ret = _loop();
if (!(_ret === 'break')) {
_context10.next = 9;
break;
}
return _context10.abrupt('break', 11);
case 9:
_context10.next = 6;
break;
case 11:
case 'end':
return _context10.stop();
}
}
}, _callee10, _this2);
})));
case 8:
case 'end':
return _context11.stop();
}
state.messagesCallback(msgObj.data);
}
}, _callee11, this);
}));
});
return function handleMessagePing(_x16) {
return _ref10.apply(this, arguments);
};
}();
return Promise.resolve();
});
}

@@ -515,30 +274,10 @@ export function close(channelState) {

export var postMessage = function () {
var _ref13 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee12(channelState, messageJson) {
return _regeneratorRuntime.wrap(function _callee12$(_context12) {
while (1) {
switch (_context12.prev = _context12.next) {
case 0:
_context12.next = 2;
return writeMessage(channelState.db, channelState.uuid, messageJson);
export function postMessage(channelState, messageJson) {
return writeMessage(channelState.db, channelState.uuid, messageJson).then(function () {
if (randomInt(0, 10) === 0) {
/* await (do not await) */cleanOldMessages(channelState.db, channelState.options.idb.ttl);
}
});
}
case 2:
if (randomInt(0, 10) === 0) {
/* await (do not await) */cleanOldMessages(channelState.db, channelState.options.idb.ttl);
}
case 3:
case 'end':
return _context12.stop();
}
}
}, _callee12, this);
}));
return function postMessage(_x17, _x18) {
return _ref13.apply(this, arguments);
};
}();
export function onMessage(channelState, fn, time) {

@@ -545,0 +284,0 @@ channelState.messagesCallbackTime = time;

@@ -1,6 +0,1 @@

import _Set from 'babel-runtime/core-js/set';
import _regeneratorRuntime from 'babel-runtime/regenerator';
import _JSON$stringify from 'babel-runtime/core-js/json/stringify';
import _Promise from 'babel-runtime/core-js/promise';
import _asyncToGenerator from 'babel-runtime/helpers/asyncToGenerator';
/**

@@ -14,8 +9,9 @@ * A localStorage-only method which uses localstorage and its 'storage'-event

import isNode from 'detect-node';
import randomToken from 'random-token';
import IdleQueue from 'custom-idle-queue';
var isNode = require('detect-node');
var randomToken = require('random-token');
import { fillOptionsWithDefaults } from '../options';
import { sleep } from '../util';
var KEY_PREFIX = 'pubkey.broadcastChannel-';

@@ -50,51 +46,31 @@ export var type = 'localstorage';

*/
export var postMessage = function () {
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(channelState, messageJson) {
var key, writeObj, value, ev;
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return new _Promise(function (res) {
return setTimeout(res, 0);
});
export function postMessage(channelState, messageJson) {
return new Promise(function (res) {
sleep().then(function () {
var key = storageKey(channelState.channelName);
var writeObj = {
token: randomToken(10),
time: new Date().getTime(),
data: messageJson,
uuid: channelState.uuid
};
var value = JSON.stringify(writeObj);
localStorage.setItem(key, value);
case 2:
key = storageKey(channelState.channelName);
writeObj = {
token: randomToken(10),
time: new Date().getTime(),
data: messageJson,
uuid: channelState.uuid
};
value = _JSON$stringify(writeObj);
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
ev.newValue = value;
window.dispatchEvent(ev);
localStorage.setItem(key, value);
res();
});
});
}
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
ev.newValue = value;
window.dispatchEvent(ev);
case 11:
case 'end':
return _context.stop();
}
}
}, _callee, this);
}));
return function postMessage(_x, _x2) {
return _ref.apply(this, arguments);
};
}();
export function addStorageEventListener(channelName, fn) {

@@ -114,7 +90,3 @@ var key = storageKey(channelName);

export function create(channelName) {
var _this = this;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
export function create(channelName, options) {
options = fillOptionsWithDefaults(options);

@@ -129,6 +101,4 @@ if (!canBeUsed()) {

// contains all messages that have been emitted before
var emittedMessagesIds = new _Set();
var emittedMessagesIds = new Set();
var writeQueue = new IdleQueue(1);
var state = {

@@ -139,65 +109,18 @@ startTime: startTime,

uuid: uuid,
emittedMessagesIds: emittedMessagesIds,
writeQueue: writeQueue
emittedMessagesIds: emittedMessagesIds
};
state.listener = addStorageEventListener(channelName, function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(msgObj) {
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
if (state.messagesCallback) {
_context2.next = 2;
break;
}
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
if (msgObj.uuid === uuid) return; // own message
if (!msgObj.token || emittedMessagesIds.has(msgObj.token)) return; // already emitted
if (msgObj.time && msgObj.time < state.messagesCallbackTime) return; // too old
return _context2.abrupt('return');
emittedMessagesIds.add(msgObj.token);
setTimeout(function () {
return emittedMessagesIds['delete'](msgObj.token);
}, options.localstorage.removeTimeout);
state.messagesCallback(msgObj.data);
});
case 2:
if (!(msgObj.uuid === uuid)) {
_context2.next = 4;
break;
}
return _context2.abrupt('return');
case 4:
if (!(!msgObj.token || emittedMessagesIds.has(msgObj.token))) {
_context2.next = 6;
break;
}
return _context2.abrupt('return');
case 6:
if (!(msgObj.time && msgObj.time < state.messagesCallbackTime)) {
_context2.next = 8;
break;
}
return _context2.abrupt('return');
case 8:
// too old
emittedMessagesIds.add(msgObj.token);
setTimeout(function () {
return emittedMessagesIds['delete'](msgObj.token);
}, options.localstorage.removeTimeout);
state.messagesCallback(msgObj.data);
case 11:
case 'end':
return _context2.stop();
}
}
}, _callee2, _this);
}));
return function (_x4) {
return _ref2.apply(this, arguments);
};
}());
return state;

@@ -208,3 +131,2 @@ }

removeStorageEventListener(channelState.listener);
channelState.writeQueue.clear();
}

@@ -211,0 +133,0 @@

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

import isNode from 'detect-node';
var isNode = require('detect-node');
export var type = 'native';
export function create(channelName) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
export function create(channelName, options) {
if (!options) options = {};
var state = {

@@ -9,0 +8,0 @@ channelName: channelName,

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

import _Object$values from 'babel-runtime/core-js/object/values';
import _Object$keys from 'babel-runtime/core-js/object/keys';
import _getIterator from 'babel-runtime/core-js/get-iterator';
import _Set from 'babel-runtime/core-js/set';
import _JSON$stringify from 'babel-runtime/core-js/json/stringify';
import _regeneratorRuntime from 'babel-runtime/regenerator';
import _Promise from 'babel-runtime/core-js/promise';
import _asyncToGenerator from 'babel-runtime/helpers/asyncToGenerator';

@@ -75,3 +69,3 @@ /**

case 5:
_context.t0 = _Promise;
_context.t0 = Promise;
_context.next = 8;

@@ -139,3 +133,3 @@ return mkdir(paths.readers)['catch'](function () {

_context2.next = 5;
return writeFile(pathToFile, _JSON$stringify({
return writeFile(pathToFile, JSON.stringify({
time: new Date().getTime()

@@ -185,3 +179,3 @@ }));

_context3.next = 5;
return new _Promise(function (res) {
return new Promise(function (res) {
server.listen(pathToSocket, function () {

@@ -226,3 +220,3 @@ res();

_context4.next = 4;
return new _Promise(function (res) {
return new Promise(function (res) {
client.connect(pathToSocket, res);

@@ -268,3 +262,3 @@ });

_context5.next = 7;
return writeFile(msgPath, _JSON$stringify(writeObject));
return writeFile(msgPath, JSON.stringify(writeObject));

@@ -440,3 +434,3 @@ case 7:

_context10.next = 3;
return _Promise.all(messageObjects.filter(function (obj) {
return Promise.all(messageObjects.filter(function (obj) {
return obj.time < olderThen;

@@ -484,3 +478,3 @@ }).map(function (obj) {

_context12.next = 6;
return _Promise.all([getReadersUuids(channelName), createSocketEventEmitter(channelName, uuid), createSocketInfoFile(channelName, uuid)]);
return Promise.all([getReadersUuids(channelName), createSocketEventEmitter(channelName, uuid), createSocketInfoFile(channelName, uuid)]);

@@ -494,3 +488,3 @@ case 6:

_context12.next = 13;
return _Promise.all(otherReaderUuids.filter(function (readerUuid) {
return Promise.all(otherReaderUuids.filter(function (readerUuid) {
return readerUuid !== uuid;

@@ -538,3 +532,3 @@ }) // not own

// contains all messages that have been emitted before
emittedMessagesIds: new _Set(),
emittedMessagesIds: new Set(),
messagesCallbackTime: null,

@@ -708,3 +702,3 @@ messagesCallback: null,

});
_iterator = useMessages, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);
_iterator = useMessages, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();

@@ -766,3 +760,3 @@ case 12:

// remove subscriptions to closed readers
_Object$keys(channelState.otherReaderClients).filter(function (readerUuid) {
Object.keys(channelState.otherReaderClients).filter(function (readerUuid) {
return !otherReaders.includes(readerUuid);

@@ -775,3 +769,3 @@ }).forEach(function (readerUuid) {

_context17.next = 6;
return _Promise.all(otherReaders.filter(function (readerUuid) {
return Promise.all(otherReaders.filter(function (readerUuid) {
return readerUuid !== channelState.uuid;

@@ -863,4 +857,4 @@ }) // not own

_context18.next = 8;
return _Promise.all(_Object$values(channelState.otherReaderClients).map(function (client) {
return client.write(_JSON$stringify(pingObj));
return Promise.all(Object.values(channelState.otherReaderClients).map(function (client) {
return client.write(JSON.stringify(pingObj));
}));

@@ -932,3 +926,3 @@

_Object$values(channelState.otherReaderClients).forEach(function (client) {
Object.values(channelState.otherReaderClients).forEach(function (client) {
return client.destroy();

@@ -935,0 +929,0 @@ });

@@ -1,5 +0,4 @@

import clone from 'clone';
export function fillOptionsWithDefaults(options) {
options = clone(options);
if (!options) options = {};
options = JSON.parse(JSON.stringify(options));

@@ -6,0 +5,0 @@ // main

@@ -24,2 +24,9 @@ /**

}
};
};
export function sleep(time) {
if (!time) time = 0;
return new Promise(function (res) {
return setTimeout(res, time);
});
}
'use strict';
require('babel-polyfill');
var BroadcastChannel = require('./index.js');
window['BroadcastChannel2'] = BroadcastChannel;
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _regenerator = require('babel-runtime/regenerator');
var _regenerator2 = _interopRequireDefault(_regenerator);
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _util = require('./util.js');

@@ -29,8 +9,6 @@

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
module.exports = function () {
var BroadcastChannel = function () {
function BroadcastChannel(name) {
var BroadcastChannel = function BroadcastChannel(name) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
(0, _classCallCheck3['default'])(this, BroadcastChannel);

@@ -43,7 +21,6 @@ this.name = name;

this._prepare();
}
};
(0, _createClass3['default'])(BroadcastChannel, [{
key: '_prepare',
value: function _prepare() {
BroadcastChannel.prototype = {
_prepare: function _prepare() {
var _this = this;

@@ -54,122 +31,38 @@

this._preparePromise = maybePromise;
maybePromise.then(function () {
var _ref = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee(s) {
return _regenerator2['default'].wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
// used in tests to simulate slow runtime
if (_this.options.prepareDelay) {
// await new Promise(res => setTimeout(res, this.options.prepareDelay));
}
_this._state = s;
case 2:
case 'end':
return _context.stop();
}
}
}, _callee, _this);
}));
return function (_x2) {
return _ref.apply(this, arguments);
};
}());
maybePromise.then(function (s) {
// used in tests to simulate slow runtime
if (_this.options.prepareDelay) {
// await new Promise(res => setTimeout(res, this.options.prepareDelay));
}
_this._state = s;
});
} else {
this._state = maybePromise;
}
}
}, {
key: 'postMessage',
value: function () {
var _ref2 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee2(msg) {
var msgObj;
return _regenerator2['default'].wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
msgObj = {
time: new Date().getTime(),
data: msg
};
},
postMessage: function postMessage(msg) {
var _this2 = this;
if (!this.closed) {
_context2.next = 3;
break;
}
var msgObj = {
time: new Date().getTime(),
data: msg
};
throw new Error('BroadcastChannel.postMessage(): ' + 'Cannot post message after channel has closed');
case 3:
if (!this._preparePromise) {
_context2.next = 6;
break;
}
_context2.next = 6;
return this._preparePromise;
case 6:
return _context2.abrupt('return', this.method.postMessage(this._state, msgObj));
case 7:
case 'end':
return _context2.stop();
}
}
}, _callee2, this);
}));
function postMessage(_x3) {
return _ref2.apply(this, arguments);
if (this.closed) {
throw new Error('BroadcastChannel.postMessage(): ' + 'Cannot post message after channel has closed');
}
return postMessage;
}()
}, {
key: 'close',
value: function () {
var _ref3 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee3() {
return _regenerator2['default'].wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
this.closed = true;
var awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve();
return awaitPrepare.then(function () {
return _this2.method.postMessage(_this2._state, msgObj);
});
},
if (!this._preparePromise) {
_context3.next = 4;
break;
}
set onmessage(fn) {
var _this3 = this;
_context3.next = 4;
return this._preparePromise;
case 4:
_context3.next = 6;
return this.method.close(this._state);
case 6:
case 'end':
return _context3.stop();
}
}
}, _callee3, this);
}));
function close() {
return _ref3.apply(this, arguments);
}
return close;
}()
}, {
key: 'onmessage',
set: function set(fn) {
var _this2 = this;
var time = new Date().getTime() - 5;
if (this._preparePromise) {
this._preparePromise.then(function () {
_this2.method.onMessage(_this2._state, messageHandler(fn, time), time);
_this3.method.onMessage(_this3._state, messageHandler(fn, time), time);
});

@@ -179,24 +72,27 @@ } else {

}
}
}, {
key: 'type',
get: function get() {
return this.method.type;
}
}]);
return BroadcastChannel;
}();
},
close: function close() {
var _this4 = this;
;
this.closed = true;
var awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve();
return awaitPrepare.then(function () {
return _this4.method.close(_this4._state);
});
},
function messageHandler(fn, minTime) {
return function (msgObj) {
if (msgObj.time >= minTime) {
fn(msgObj.data);
get type() {
return this.method.type;
}
};
}
exports['default'] = BroadcastChannel;
function messageHandler(fn, minTime) {
return function (msgObj) {
if (msgObj.time >= minTime) {
fn(msgObj.data);
}
};
};
module.exports = BroadcastChannel;
return BroadcastChannel;
}();

@@ -6,29 +6,9 @@ 'use strict';

});
var _stringify = require('babel-runtime/core-js/json/stringify');
var _stringify2 = _interopRequireDefault(_stringify);
exports.chooseMethod = chooseMethod;
var isNode = require('detect-node');
var _detectNode = require('detect-node');
var NativeMethod = require('./methods/native.js');
var IndexeDbMethod = require('./methods/indexed-db.js');
var LocalstorageMethod = require('./methods/localstorage.js');
var _detectNode2 = _interopRequireDefault(_detectNode);
var _native = require('./methods/native.js');
var NativeMethod = _interopRequireWildcard(_native);
var _indexedDb = require('./methods/indexed-db.js');
var IndexeDbMethod = _interopRequireWildcard(_indexedDb);
var _localstorage = require('./methods/localstorage.js');
var LocalstorageMethod = _interopRequireWildcard(_localstorage);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
// order is important

@@ -38,2 +18,4 @@ var METHODS = [NativeMethod, // fastest

var REQUIRE_FUN = require;
/**

@@ -43,4 +25,4 @@ * The NodeMethod is loaded lazy

*/
if (_detectNode2['default']) {
var NodeMethod = require('./methods/node.js');
if (isNode) {
var NodeMethod = REQUIRE_FUN('./methods/node.js');
METHODS.push(NodeMethod);

@@ -59,3 +41,3 @@ }

var chooseMethods = METHODS;
if (!options.webWorkerSupport && !_detectNode2['default']) {
if (!options.webWorkerSupport && !isNode) {
// prefer localstorage over idb when no webworker-support needed

@@ -70,5 +52,5 @@ chooseMethods = METHODS.filter(function (m) {

});
if (!useMethod) throw new Error('No useable methode found:' + (0, _stringify2['default'])(METHODS.map(function (m) {
if (!useMethod) throw new Error('No useable methode found:' + JSON.stringify(METHODS.map(function (m) {
return m.type;
})));else return useMethod;
}

@@ -6,72 +6,75 @@ 'use strict';

});
exports.postMessage = exports.handleMessagePing = exports.create = exports.cleanOldMessages = exports.getOldMessages = exports.removeMessageById = exports.getMessagesHigherThen = exports.getAllMessages = exports.writeMessage = exports.createDatabase = exports.type = undefined;
exports.type = undefined;
exports.getIdb = getIdb;
exports.createDatabase = createDatabase;
exports.writeMessage = writeMessage;
exports.getAllMessages = getAllMessages;
exports.getMessagesHigherThen = getMessagesHigherThen;
exports.removeMessageById = removeMessageById;
exports.getOldMessages = getOldMessages;
exports.cleanOldMessages = cleanOldMessages;
exports.create = create;
exports.handleMessagePing = handleMessagePing;
exports.close = close;
exports.postMessage = postMessage;
exports.onMessage = onMessage;
exports.canBeUsed = canBeUsed;
var _getIterator2 = require('babel-runtime/core-js/get-iterator');
var _util = require('../util.js');
var _getIterator3 = _interopRequireDefault(_getIterator2);
var _options = require('../options');
var _set = require('babel-runtime/core-js/set');
/**
* this method uses indexeddb to store the messages
* There is currently no observerAPI for idb
* @link https://github.com/w3c/IndexedDB/issues/51
* So we use the localstorage 'storage'-event
* to ping other tabs when a message comes in
*/
var _set2 = _interopRequireDefault(_set);
var isNode = require('detect-node');
var randomToken = require('random-token');
var randomInt = require('random-int');
var IdleQueue = require('custom-idle-queue');
var _regenerator = require('babel-runtime/regenerator');
var DB_PREFIX = 'pubkey.broadcast-channel-0-';
var OBJECT_STORE_ID = 'messages';
var _regenerator2 = _interopRequireDefault(_regenerator);
var type = exports.type = 'idb';
var _promise = require('babel-runtime/core-js/promise');
function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
if (typeof mozIndexedDB !== 'undefined') return mozIndexedDB;
if (typeof webkitIndexedDB !== 'undefined') return webkitIndexedDB;
if (typeof msIndexedDB !== 'undefined') return msIndexedDB;
var _promise2 = _interopRequireDefault(_promise);
return false;
}
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
function createDatabase(channelName) {
var IndexedDB = getIdb();
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
// create table
var dbName = DB_PREFIX + channelName;
var openRequest = IndexedDB.open(dbName, 1);
var createDatabase = exports.createDatabase = function () {
var _ref = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee(channelName) {
var IndexedDB, dbName, openRequest, db;
return _regenerator2['default'].wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
IndexedDB = getIdb();
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
keyPath: 'id',
autoIncrement: true
});
};
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
// create table
return dbPromise;
}
dbName = DB_PREFIX + channelName;
openRequest = IndexedDB.open(dbName, 1);
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
keyPath: 'id',
autoIncrement: true
});
};
_context.next = 6;
return new _promise2['default'](function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
case 6:
db = _context.sent;
return _context.abrupt('return', db);
case 8:
case 'end':
return _context.stop();
}
}
}, _callee, this);
}));
return function createDatabase(_x) {
return _ref.apply(this, arguments);
};
}();
/**

@@ -81,300 +84,145 @@ * writes the new message to the database

*/
var writeMessage = exports.writeMessage = function () {
var _ref2 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee2(db, readerUuid, messageJson) {
var time, writeObject, transaction;
return _regenerator2['default'].wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
time = new Date().getTime();
writeObject = {
uuid: readerUuid,
time: time,
data: messageJson
};
transaction = db.transaction([OBJECT_STORE_ID], 'readwrite');
return _context2.abrupt('return', new _promise2['default'](function (res, rej) {
transaction.oncomplete = function () {
return res();
};
transaction.onerror = function (ev) {
return rej(ev);
};
var objectStore = transaction.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
}));
case 4:
case 'end':
return _context2.stop();
}
}
}, _callee2, this);
}));
return function writeMessage(_x2, _x3, _x4) {
return _ref2.apply(this, arguments);
function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
uuid: readerUuid,
time: time,
data: messageJson
};
}();
var getAllMessages = exports.getAllMessages = function () {
var _ref3 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee3(db) {
var objectStore, ret;
return _regenerator2['default'].wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
ret = [];
return _context3.abrupt('return', new _promise2['default'](function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
ret.push(cursor.value);
//alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor['continue']();
} else {
res(ret);
}
};
}));
var transaction = db.transaction([OBJECT_STORE_ID], 'readwrite');
case 3:
case 'end':
return _context3.stop();
}
}
}, _callee3, this);
}));
return new Promise(function (res, rej) {
transaction.oncomplete = function () {
return res();
};
transaction.onerror = function (ev) {
return rej(ev);
};
return function getAllMessages(_x5) {
return _ref3.apply(this, arguments);
};
}();
var objectStore = transaction.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
});
}
var getMessagesHigherThen = exports.getMessagesHigherThen = function () {
var _ref4 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee4(db, lastCursorId) {
var objectStore, ret, keyRangeValue;
return _regenerator2['default'].wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
ret = [];
keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
return _context4.abrupt('return', new _promise2['default'](function (res) {
objectStore.openCursor(keyRangeValue).onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
ret.push(cursor.value);
//alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor['continue']();
} else {
res(ret);
}
};
}));
case 4:
case 'end':
return _context4.stop();
}
function getAllMessages(db) {
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
ret.push(cursor.value);
//alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor['continue']();
} else {
res(ret);
}
}, _callee4, this);
}));
};
});
}
return function getMessagesHigherThen(_x6, _x7) {
return _ref4.apply(this, arguments);
};
}();
var removeMessageById = exports.removeMessageById = function () {
var _ref5 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee5(db, id) {
var request;
return _regenerator2['default'].wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
request = db.transaction([OBJECT_STORE_ID], 'readwrite').objectStore(OBJECT_STORE_ID)['delete'](id);
return _context5.abrupt('return', new _promise2['default'](function (res) {
request.onsuccess = function () {
return res();
};
}));
case 2:
case 'end':
return _context5.stop();
}
function getMessagesHigherThen(db, lastCursorId) {
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
return new Promise(function (res) {
objectStore.openCursor(keyRangeValue).onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
ret.push(cursor.value);
//alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor['continue']();
} else {
res(ret);
}
}, _callee5, this);
}));
};
});
}
return function removeMessageById(_x8, _x9) {
return _ref5.apply(this, arguments);
};
}();
function removeMessageById(db, id) {
var request = db.transaction([OBJECT_STORE_ID], 'readwrite').objectStore(OBJECT_STORE_ID)['delete'](id);
return new Promise(function (res) {
request.onsuccess = function () {
return res();
};
});
}
var getOldMessages = exports.getOldMessages = function () {
var _ref6 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee6(db, ttl) {
var olderThen, objectStore, ret;
return _regenerator2['default'].wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
olderThen = new Date().getTime() - ttl;
objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
ret = [];
return _context6.abrupt('return', new _promise2['default'](function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
var msgObk = cursor.value;
if (msgObk.time < olderThen) {
ret.push(msgObk);
//alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor['continue']();
} else {
// no more old messages,
res(ret);
return;
}
} else {
res(ret);
}
};
}));
case 4:
case 'end':
return _context6.stop();
function getOldMessages(db, ttl) {
var olderThen = new Date().getTime() - ttl;
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
var msgObk = cursor.value;
if (msgObk.time < olderThen) {
ret.push(msgObk);
//alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor['continue']();
} else {
// no more old messages,
res(ret);
return;
}
} else {
res(ret);
}
}, _callee6, this);
}));
};
});
}
return function getOldMessages(_x10, _x11) {
return _ref6.apply(this, arguments);
};
}();
function cleanOldMessages(db, ttl) {
return getOldMessages(db, ttl).then(function (tooOld) {
return Promise.all(tooOld.map(function (msgObj) {
return removeMessageById(db, msgObj.id);
}));
});
}
var cleanOldMessages = exports.cleanOldMessages = function () {
var _ref7 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee7(db, ttl) {
var tooOld;
return _regenerator2['default'].wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
_context7.next = 2;
return getOldMessages(db, ttl);
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
case 2:
tooOld = _context7.sent;
return _context7.abrupt('return', _promise2['default'].all(tooOld.map(function (msgObj) {
return removeMessageById(db, msgObj.id);
})));
var uuid = randomToken(10);
case 4:
case 'end':
return _context7.stop();
}
}
}, _callee7, this);
}));
// ensures we do not read messages in parrallel
var readQueue = new IdleQueue(1);
return function cleanOldMessages(_x12, _x13) {
return _ref7.apply(this, arguments);
};
}();
return createDatabase(channelName).then(function (db) {
var state = {
closed: false,
lastCursorId: 0,
channelName: channelName,
options: options,
uuid: uuid,
// contains all messages that have been emitted before
emittedMessagesIds: new Set(),
messagesCallback: null,
readQueue: readQueue,
db: db
};
var create = exports.create = function () {
var _ref8 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee9(channelName) {
var _this = this;
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
_readLoop(state);
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var uuid, readQueue, db, state;
return _regenerator2['default'].wrap(function _callee9$(_context9) {
while (1) {
switch (_context9.prev = _context9.next) {
case 0:
options = (0, _options.fillOptionsWithDefaults)(options);
return state;
});
}
uuid = (0, _randomToken2['default'])(10);
function _readLoop(state) {
if (state.closed) return;
// ensures we do not read messages in parrallel
return handleMessagePing(state).then(function () {
return (0, _util.sleep)(state.options.idb.fallbackInterval);
}).then(function () {
return _readLoop(state);
});
}
readQueue = new _customIdleQueue2['default'](1);
_context9.next = 5;
return createDatabase(channelName);
case 5:
db = _context9.sent;
state = {
closed: false,
lastCursorId: 0,
channelName: channelName,
options: options,
uuid: uuid,
// contains all messages that have been emitted before
emittedMessagesIds: new _set2['default'](),
messagesCallback: null,
readQueue: readQueue,
db: db
};
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
(0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee8() {
return _regenerator2['default'].wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
if (!(state.closed === false)) {
_context8.next = 7;
break;
}
_context8.next = 3;
return handleMessagePing(state);
case 3:
_context8.next = 5;
return new _promise2['default'](function (res) {
return setTimeout(res, state.options.idb.fallbackInterval);
});
case 5:
_context8.next = 0;
break;
case 7:
case 'end':
return _context8.stop();
}
}
}, _callee8, _this);
}))();
return _context9.abrupt('return', state);
case 9:
case 'end':
return _context9.stop();
}
}
}, _callee9, this);
}));
return function create(_x15) {
return _ref8.apply(this, arguments);
};
}();
/**

@@ -384,210 +232,55 @@ * when the storage-event pings, so that we now new messages came,

*/
function handleMessagePing(state) {
/**
* when there are no listener, we do nothing
*/
if (!state.messagesCallback) return Promise.resolve();
/**
* if we have 2 or more read-tasks in the queue,
* we do not have to set more
*/
if (state.readQueue._idleCalls.size > 1) return Promise.resolve();
var handleMessagePing = exports.handleMessagePing = function () {
var _ref10 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee11(state) {
var _this2 = this;
return state.readQueue.requestIdlePromise().then(function () {
return state.readQueue.wrapCall(function () {
return _handleMessagePingInner(state);
});
});
}
return _regenerator2['default'].wrap(function _callee11$(_context11) {
while (1) {
switch (_context11.prev = _context11.next) {
case 0:
if (state.messagesCallback) {
_context11.next = 2;
break;
}
return _context11.abrupt('return');
case 2:
if (!(state.readQueue._idleCalls.size > 1)) {
_context11.next = 4;
break;
}
return _context11.abrupt('return');
case 4:
_context11.next = 6;
return state.readQueue.requestIdlePromise();
case 6:
_context11.next = 8;
return state.readQueue.wrapCall((0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee10() {
var newerMessages, useMessages, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _loop, _iterator, _step;
return _regenerator2['default'].wrap(function _callee10$(_context10) {
while (1) {
switch (_context10.prev = _context10.next) {
case 0:
_context10.next = 2;
return getMessagesHigherThen(state.db, state.lastCursorId);
case 2:
newerMessages = _context10.sent;
useMessages = newerMessages.map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
return msgObj;
}).filter(function (msgObj) {
return msgObj.uuid !== state.uuid;
}) // not send by own
.filter(function (msgObj) {
return !state.emittedMessagesIds.has(msgObj.id);
}) // not already emitted
.filter(function (msgObj) {
return msgObj.time >= state.messagesCallbackTime;
}) // not older then onMessageCallback
.sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
_iteratorNormalCompletion = true;
_didIteratorError = false;
_iteratorError = undefined;
_context10.prev = 7;
_loop = function _loop() {
var msgObj = _step.value;
if (state.messagesCallback) {
state.emittedMessagesIds.add(msgObj.id);
setTimeout(function () {
return state.emittedMessagesIds['delete'](msgObj.id);
}, state.options.idb.ttl * 2);
state.messagesCallback(msgObj.data);
}
};
for (_iterator = (0, _getIterator3['default'])(useMessages); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
_loop();
}
_context10.next = 16;
break;
case 12:
_context10.prev = 12;
_context10.t0 = _context10['catch'](7);
_didIteratorError = true;
_iteratorError = _context10.t0;
case 16:
_context10.prev = 16;
_context10.prev = 17;
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
case 19:
_context10.prev = 19;
if (!_didIteratorError) {
_context10.next = 22;
break;
}
throw _iteratorError;
case 22:
return _context10.finish(19);
case 23:
return _context10.finish(16);
case 24:
case 'end':
return _context10.stop();
}
}
}, _callee10, _this2, [[7, 12, 16, 24], [17,, 19, 23]]);
})));
case 8:
case 'end':
return _context11.stop();
}
function _handleMessagePingInner(state) {
return getMessagesHigherThen(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages.map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
}, _callee11, this);
}));
return msgObj;
}).filter(function (msgObj) {
return msgObj.uuid !== state.uuid;
}) // not send by own
.filter(function (msgObj) {
return !state.emittedMessagesIds.has(msgObj.id);
}) // not already emitted
.filter(function (msgObj) {
return msgObj.time >= state.messagesCallbackTime;
}) // not older then onMessageCallback
.sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
return function handleMessagePing(_x16) {
return _ref10.apply(this, arguments);
};
}();
var postMessage = exports.postMessage = function () {
var _ref12 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee12(channelState, messageJson) {
return _regenerator2['default'].wrap(function _callee12$(_context12) {
while (1) {
switch (_context12.prev = _context12.next) {
case 0:
_context12.next = 2;
return writeMessage(channelState.db, channelState.uuid, messageJson);
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.emittedMessagesIds.add(msgObj.id);
setTimeout(function () {
return state.emittedMessagesIds['delete'](msgObj.id);
}, state.options.idb.ttl * 2);
case 2:
if ((0, _randomInt2['default'])(0, 10) === 0) {
/* await (do not await) */cleanOldMessages(channelState.db, channelState.options.idb.ttl);
}
case 3:
case 'end':
return _context12.stop();
}
state.messagesCallback(msgObj.data);
}
}, _callee12, this);
}));
});
return function postMessage(_x17, _x18) {
return _ref12.apply(this, arguments);
};
}();
exports.getIdb = getIdb;
exports.close = close;
exports.onMessage = onMessage;
exports.canBeUsed = canBeUsed;
var _detectNode = require('detect-node');
var _detectNode2 = _interopRequireDefault(_detectNode);
var _randomToken = require('random-token');
var _randomToken2 = _interopRequireDefault(_randomToken);
var _randomInt = require('random-int');
var _randomInt2 = _interopRequireDefault(_randomInt);
var _customIdleQueue = require('custom-idle-queue');
var _customIdleQueue2 = _interopRequireDefault(_customIdleQueue);
var _options = require('../options');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var DB_PREFIX = 'pubkey.broadcast-channel-0-'; /**
* this method uses indexeddb to store the messages
* There is currently no observerAPI for idb
* @link https://github.com/w3c/IndexedDB/issues/51
* So we use the localstorage 'storage'-event
* to ping other tabs when a message comes in
*/
var OBJECT_STORE_ID = 'messages';
var type = exports.type = 'idb';
function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
if (typeof mozIndexedDB !== 'undefined') return mozIndexedDB;
if (typeof webkitIndexedDB !== 'undefined') return webkitIndexedDB;
if (typeof msIndexedDB !== 'undefined') return msIndexedDB;
return false;
return Promise.resolve();
});
}

@@ -601,2 +294,10 @@

function postMessage(channelState, messageJson) {
return writeMessage(channelState.db, channelState.uuid, messageJson).then(function () {
if (randomInt(0, 10) === 0) {
/* await (do not await) */cleanOldMessages(channelState.db, channelState.options.idb.ttl);
}
});
}
function onMessage(channelState, fn, time) {

@@ -609,3 +310,3 @@ channelState.messagesCallbackTime = time;

function canBeUsed() {
if (_detectNode2['default']) return false;
if (isNode) return false;
var idb = getIdb();

@@ -612,0 +313,0 @@

@@ -6,79 +6,6 @@ 'use strict';

});
exports.postMessage = exports.type = undefined;
var _set = require('babel-runtime/core-js/set');
var _set2 = _interopRequireDefault(_set);
var _regenerator = require('babel-runtime/regenerator');
var _regenerator2 = _interopRequireDefault(_regenerator);
var _stringify = require('babel-runtime/core-js/json/stringify');
var _stringify2 = _interopRequireDefault(_stringify);
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
/**
* writes the new message to the storage
* and fires the storage-event so other readers can find it
*/
var postMessage = exports.postMessage = function () {
var _ref = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee(channelState, messageJson) {
var key, writeObj, value, ev;
return _regenerator2['default'].wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return new _promise2['default'](function (res) {
return setTimeout(res, 0);
});
case 2:
key = storageKey(channelState.channelName);
writeObj = {
token: (0, _randomToken2['default'])(10),
time: new Date().getTime(),
data: messageJson,
uuid: channelState.uuid
};
value = (0, _stringify2['default'])(writeObj);
localStorage.setItem(key, value);
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
ev.newValue = value;
window.dispatchEvent(ev);
case 11:
case 'end':
return _context.stop();
}
}
}, _callee, this);
}));
return function postMessage(_x, _x2) {
return _ref.apply(this, arguments);
};
}();
exports.type = undefined;
exports.getLocalStorage = getLocalStorage;
exports.storageKey = storageKey;
exports.postMessage = postMessage;
exports.addStorageEventListener = addStorageEventListener;

@@ -91,17 +18,5 @@ exports.removeStorageEventListener = removeStorageEventListener;

var _detectNode = require('detect-node');
var _detectNode2 = _interopRequireDefault(_detectNode);
var _randomToken = require('random-token');
var _randomToken2 = _interopRequireDefault(_randomToken);
var _customIdleQueue = require('custom-idle-queue');
var _customIdleQueue2 = _interopRequireDefault(_customIdleQueue);
var _options = require('../options');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _util = require('../util');

@@ -116,2 +31,5 @@ /**

var isNode = require('detect-node');
var randomToken = require('random-token');
var KEY_PREFIX = 'pubkey.broadcastChannel-';

@@ -140,3 +58,38 @@ var type = exports.type = 'localstorage';

return KEY_PREFIX + channelName;
}function addStorageEventListener(channelName, fn) {
}
/**
* writes the new message to the storage
* and fires the storage-event so other readers can find it
*/
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
(0, _util.sleep)().then(function () {
var key = storageKey(channelState.channelName);
var writeObj = {
token: randomToken(10),
time: new Date().getTime(),
data: messageJson,
uuid: channelState.uuid
};
var value = JSON.stringify(writeObj);
localStorage.setItem(key, value);
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
ev.newValue = value;
window.dispatchEvent(ev);
res();
});
});
}
function addStorageEventListener(channelName, fn) {
var key = storageKey(channelName);

@@ -155,7 +108,3 @@ var listener = function listener(ev) {

function create(channelName) {
var _this = this;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);

@@ -167,9 +116,7 @@ if (!canBeUsed()) {

var startTime = new Date().getTime();
var uuid = (0, _randomToken2['default'])(10);
var uuid = randomToken(10);
// contains all messages that have been emitted before
var emittedMessagesIds = new _set2['default']();
var emittedMessagesIds = new Set();
var writeQueue = new _customIdleQueue2['default'](1);
var state = {

@@ -180,65 +127,18 @@ startTime: startTime,

uuid: uuid,
emittedMessagesIds: emittedMessagesIds,
writeQueue: writeQueue
emittedMessagesIds: emittedMessagesIds
};
state.listener = addStorageEventListener(channelName, function () {
var _ref2 = (0, _asyncToGenerator3['default'])( /*#__PURE__*/_regenerator2['default'].mark(function _callee2(msgObj) {
return _regenerator2['default'].wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
if (state.messagesCallback) {
_context2.next = 2;
break;
}
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
if (msgObj.uuid === uuid) return; // own message
if (!msgObj.token || emittedMessagesIds.has(msgObj.token)) return; // already emitted
if (msgObj.time && msgObj.time < state.messagesCallbackTime) return; // too old
return _context2.abrupt('return');
emittedMessagesIds.add(msgObj.token);
setTimeout(function () {
return emittedMessagesIds['delete'](msgObj.token);
}, options.localstorage.removeTimeout);
state.messagesCallback(msgObj.data);
});
case 2:
if (!(msgObj.uuid === uuid)) {
_context2.next = 4;
break;
}
return _context2.abrupt('return');
case 4:
if (!(!msgObj.token || emittedMessagesIds.has(msgObj.token))) {
_context2.next = 6;
break;
}
return _context2.abrupt('return');
case 6:
if (!(msgObj.time && msgObj.time < state.messagesCallbackTime)) {
_context2.next = 8;
break;
}
return _context2.abrupt('return');
case 8:
// too old
emittedMessagesIds.add(msgObj.token);
setTimeout(function () {
return emittedMessagesIds['delete'](msgObj.token);
}, options.localstorage.removeTimeout);
state.messagesCallback(msgObj.data);
case 11:
case 'end':
return _context2.stop();
}
}
}, _callee2, _this);
}));
return function (_x4) {
return _ref2.apply(this, arguments);
};
}());
return state;

@@ -249,3 +149,2 @@ }

removeStorageEventListener(channelState.listener);
channelState.writeQueue.clear();
}

@@ -259,3 +158,3 @@

function canBeUsed() {
if (_detectNode2['default']) return false;
if (isNode) return false;
var ls = getLocalStorage();

@@ -262,0 +161,0 @@

@@ -6,3 +6,2 @@ 'use strict';

});
exports.type = undefined;
exports.create = create;

@@ -13,14 +12,8 @@ exports.close = close;

exports.canBeUsed = canBeUsed;
var isNode = require('detect-node');
var _detectNode = require('detect-node');
var _detectNode2 = _interopRequireDefault(_detectNode);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var type = exports.type = 'native';
function create(channelName) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
function create(channelName, options) {
if (!options) options = {};
var state = {

@@ -58,5 +51,5 @@ channelName: channelName,

function canBeUsed() {
if (_detectNode2['default']) return false;
if (isNode) return false;
if (typeof BroadcastChannel === 'function') return true;
};

@@ -8,18 +8,2 @@ 'use strict';

var _values = require('babel-runtime/core-js/object/values');
var _values2 = _interopRequireDefault(_values);
var _keys = require('babel-runtime/core-js/object/keys');
var _keys2 = _interopRequireDefault(_keys);
var _getIterator2 = require('babel-runtime/core-js/get-iterator');
var _getIterator3 = _interopRequireDefault(_getIterator2);
var _set = require('babel-runtime/core-js/set');
var _set2 = _interopRequireDefault(_set);
var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray');

@@ -29,6 +13,2 @@

var _stringify = require('babel-runtime/core-js/json/stringify');
var _stringify2 = _interopRequireDefault(_stringify);
var _regenerator = require('babel-runtime/regenerator');

@@ -38,6 +18,2 @@

var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');

@@ -67,3 +43,3 @@

case 5:
_context.t0 = _promise2['default'];
_context.t0 = Promise;
_context.next = 8;

@@ -118,3 +94,3 @@ return mkdir(paths.readers)['catch'](function () {

_context2.next = 5;
return writeFile(pathToFile, (0, _stringify2['default'])({
return writeFile(pathToFile, JSON.stringify({
time: new Date().getTime()

@@ -166,3 +142,3 @@ }));

_context3.next = 5;
return new _promise2['default'](function (res) {
return new Promise(function (res) {
server.listen(pathToSocket, function () {

@@ -207,3 +183,3 @@ res();

_context4.next = 4;
return new _promise2['default'](function (res) {
return new Promise(function (res) {
client.connect(pathToSocket, res);

@@ -251,3 +227,3 @@ });

_context5.next = 7;
return writeFile(msgPath, (0, _stringify2['default'])(writeObject));
return writeFile(msgPath, JSON.stringify(writeObject));

@@ -414,3 +390,3 @@ case 7:

_context10.next = 3;
return _promise2['default'].all(messageObjects.filter(function (obj) {
return Promise.all(messageObjects.filter(function (obj) {
return obj.time < olderThen;

@@ -456,3 +432,3 @@ }).map(function (obj) {

_context12.next = 6;
return _promise2['default'].all([getReadersUuids(channelName), createSocketEventEmitter(channelName, uuid), createSocketInfoFile(channelName, uuid)]);
return Promise.all([getReadersUuids(channelName), createSocketEventEmitter(channelName, uuid), createSocketInfoFile(channelName, uuid)]);

@@ -467,3 +443,3 @@ case 6:

_context12.next = 14;
return _promise2['default'].all(otherReaderUuids.filter(function (readerUuid) {
return Promise.all(otherReaderUuids.filter(function (readerUuid) {
return readerUuid !== uuid;

@@ -511,3 +487,3 @@ }) // not own

// contains all messages that have been emitted before
emittedMessagesIds: new _set2['default'](),
emittedMessagesIds: new Set(),
messagesCallbackTime: null,

@@ -656,3 +632,3 @@ messagesCallback: null,

});
_iterator = (0, _getIterator3['default'])(useMessages);
_iterator = useMessages[Symbol.iterator]();

@@ -744,3 +720,3 @@ case 16:

// remove subscriptions to closed readers
(0, _keys2['default'])(channelState.otherReaderClients).filter(function (readerUuid) {
Object.keys(channelState.otherReaderClients).filter(function (readerUuid) {
return !otherReaders.includes(readerUuid);

@@ -753,3 +729,3 @@ }).forEach(function (readerUuid) {

_context17.next = 6;
return _promise2['default'].all(otherReaders.filter(function (readerUuid) {
return Promise.all(otherReaders.filter(function (readerUuid) {
return readerUuid !== channelState.uuid;

@@ -841,4 +817,4 @@ }) // not own

_context18.next = 8;
return _promise2['default'].all((0, _values2['default'])(channelState.otherReaderClients).map(function (client) {
return client.write((0, _stringify2['default'])(pingObj));
return Promise.all(Object.values(channelState.otherReaderClients).map(function (client) {
return client.write(JSON.stringify(pingObj));
}));

@@ -902,3 +878,3 @@

(0, _values2['default'])(channelState.otherReaderClients).forEach(function (client) {
Object.values(channelState.otherReaderClients).forEach(function (client) {
return client.destroy();

@@ -905,0 +881,0 @@ });

@@ -7,11 +7,5 @@ 'use strict';

exports.fillOptionsWithDefaults = fillOptionsWithDefaults;
var _clone = require('clone');
var _clone2 = _interopRequireDefault(_clone);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function fillOptionsWithDefaults(options) {
options = (0, _clone2['default'])(options);
if (!options) options = {};
options = JSON.parse(JSON.stringify(options));

@@ -18,0 +12,0 @@ // main

@@ -8,2 +8,3 @@ 'use strict';

exports.cleanPipeName = cleanPipeName;
exports.sleep = sleep;
/**

@@ -32,2 +33,9 @@ * returns true if the given object is a promise

}
};
};
function sleep(time) {
if (!time) time = 0;
return new Promise(function (res) {
return setTimeout(res, time);
});
}
{
"name": "broadcast-channel",
"version": "0.0.1",
"version": "1.0.0",
"description": "A BroadcastChannel implementation that works with new browsers, older browsers and Node.js",
"homepage": "https://pubkey.github.io/broadcast-channel/",
"homepage": "https://github.com/pubkey/broadcast-channel#readme",
"keywords": [

@@ -26,3 +26,2 @@ "broadcast-channel",

},
"homepage": "https://github.com/pubkey/broadcast-channel#readme",
"main": "./dist/lib/index.js",

@@ -38,2 +37,3 @@ "jsnext:main": "./dist/es/index.js",

"test:typings": "npm run build && mocha ./test/typings.test.js -b --timeout 12000 --exit",
"test:size": "npm run build && rimraf test_tmp/browserify.js && browserify --no-builtins dist/lib/browserify.index.js > test_tmp/browserify.js && uglifyjs --compress --mangle --output test_tmp/browserify.min.js -- test_tmp/browserify.js && echo \"Build-Size (minified+gzip):\" && gzip-size --raw test_tmp/browserify.min.js",
"lint": "eslint --ignore-path ./config/.eslintignore src test config scripts",

@@ -48,2 +48,3 @@ "clear": "rimraf -rf ./dist && rimraf -rf ./gen",

"build": "npm run clear && concurrently \"npm run build:es6\" \"npm run build:es5\" \"npm run build:test\" && concurrently \"npm run build:browser\" \"npm run build:worker\" \"npm run build:iframe\"",
"build:min": "uglifyjs --compress --mangle --output dist/lib/browserify.min.js -- dist/lib/browserify.index.js",
"docs:only": "http-server ./docs",

@@ -58,3 +59,2 @@ "docs:serve": "npm run build && npm run docs:only"

"babel-runtime": "6.26.0",
"clone": "2.1.1",
"custom-idle-queue": "2.0.1",

@@ -93,2 +93,3 @@ "detect-node": "2.0.3",

"child-process-promise": "^2.2.1",
"clone": "2.1.1",
"concurrently": "3.5.1",

@@ -99,2 +100,3 @@ "convert-hrtime": "2.0.0",

"eslint": "4.19.1",
"gzip-size-cli": "^2.1.0",
"http-server": "0.11.1",

@@ -101,0 +103,0 @@ "karma": "2.0.2",

@@ -51,2 +51,9 @@ BEFORE:

=> sending localstorage-pings is slower
=> sending localstorage-pings is slower
====== build-size
BEFORE: 37251
AFTER: 4077

@@ -16,3 +16,3 @@

<img src="https://travis-ci.org/pubkey/broadcast-channel.svg?branch=master" /></a>
<a href="https://twitter.com/intent/follow?screen_name=pubkeypubkey">
<a href="https://twitter.com/pubkeypubkey">
<img src="https://img.shields.io/twitter/follow/pubkeypubkey.svg?style=social&logo=twitter"

@@ -26,4 +26,2 @@ alt="follow on Twitter"></a>

# BroadcastChannel
A BroadcastChannel allows simple communication between browsing contexts with the same origin or different NodeJs processes.

@@ -30,0 +28,0 @@

@@ -1,4 +0,3 @@

require('babel-polyfill');
const BroadcastChannel = require('./index.js');
window['BroadcastChannel2'] = BroadcastChannel;

@@ -13,4 +13,7 @@ import {

class BroadcastChannel {
constructor(name, options = {}) {
module.exports = (() => {
const BroadcastChannel = function (name, options = {}) {
this.name = name;

@@ -22,40 +25,52 @@ this.options = fillOptionsWithDefaults(options);

this._prepare();
}
_prepare() {
const maybePromise = this.method.create(this.name, this.options);
if (isPromise(maybePromise)) {
this._preparePromise = maybePromise;
maybePromise.then(async (s) => {
// used in tests to simulate slow runtime
if (this.options.prepareDelay) {
// await new Promise(res => setTimeout(res, this.options.prepareDelay));
}
this._state = s;
};
BroadcastChannel.prototype = {
_prepare() {
const maybePromise = this.method.create(this.name, this.options);
if (isPromise(maybePromise)) {
this._preparePromise = maybePromise;
maybePromise.then(s => {
// used in tests to simulate slow runtime
if (this.options.prepareDelay) {
// await new Promise(res => setTimeout(res, this.options.prepareDelay));
}
this._state = s;
});
} else {
this._state = maybePromise;
}
},
postMessage(msg) {
const msgObj = {
time: new Date().getTime(),
data: msg
};
if (this.closed) {
throw new Error(
'BroadcastChannel.postMessage(): ' +
'Cannot post message after channel has closed'
);
}
const awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve();
return awaitPrepare.then(() => {
return this.method.postMessage(
this._state,
msgObj
);
});
} else {
this._state = maybePromise;
}
}
async postMessage(msg) {
const msgObj = {
time: new Date().getTime(),
data: msg
};
if (this.closed) {
throw new Error(
'BroadcastChannel.postMessage(): ' +
'Cannot post message after channel has closed'
);
}
if (this._preparePromise) await this._preparePromise;
return this.method.postMessage(
this._state,
msgObj
);
}
set onmessage(fn) {
const time = new Date().getTime() - 5;
if (this._preparePromise) {
this._preparePromise.then(() => {
},
set onmessage(fn) {
const time = new Date().getTime() - 5;
if (this._preparePromise) {
this._preparePromise.then(() => {
this.method.onMessage(
this._state,
messageHandler(fn, time),
time
);
});
} else {
this.method.onMessage(

@@ -66,32 +81,29 @@ this._state,

);
}
},
close() {
this.closed = true;
const awaitPrepare = this._preparePromise ? this._preparePromise : Promise.resolve();
return awaitPrepare.then(() => {
return this.method.close(
this._state
);
});
} else {
this.method.onMessage(
this._state,
messageHandler(fn, time),
time
);
},
get type() {
return this.method.type;
}
}
async close() {
this.closed = true;
if (this._preparePromise) await this._preparePromise;
await this.method.close(
this._state
);
}
get type() {
return this.method.type;
}
};
};
function messageHandler(fn, minTime) {
return msgObj => {
if (msgObj.time >= minTime) {
fn(msgObj.data);
}
function messageHandler(fn, minTime) {
return msgObj => {
if (msgObj.time >= minTime) {
fn(msgObj.data);
}
};
};
}
export default BroadcastChannel;
module.exports = BroadcastChannel;
return BroadcastChannel;
})();

@@ -1,6 +0,6 @@

import isNode from 'detect-node';
const isNode = require('detect-node');
import * as NativeMethod from './methods/native.js';
import * as IndexeDbMethod from './methods/indexed-db.js';
import * as LocalstorageMethod from './methods/localstorage.js';
const NativeMethod = require('./methods/native.js');
const IndexeDbMethod = require('./methods/indexed-db.js');
const LocalstorageMethod = require('./methods/localstorage.js');

@@ -14,2 +14,4 @@ // order is important

const REQUIRE_FUN = require;
/**

@@ -20,3 +22,3 @@ * The NodeMethod is loaded lazy

if (isNode) {
const NodeMethod = require('./methods/node.js');
const NodeMethod = REQUIRE_FUN('./methods/node.js');
METHODS.push(NodeMethod);

@@ -23,0 +25,0 @@ }

@@ -9,8 +9,12 @@ /**

import isNode from 'detect-node';
import randomToken from 'random-token';
import randomInt from 'random-int';
import IdleQueue from 'custom-idle-queue';
const isNode = require('detect-node');
const randomToken = require('random-token');
const randomInt = require('random-int');
const IdleQueue = require('custom-idle-queue');
import {
sleep
} from '../util.js';
import {
fillOptionsWithDefaults

@@ -33,3 +37,3 @@ } from '../options';

export async function createDatabase(channelName) {
export function createDatabase(channelName) {
const IndexedDB = getIdb();

@@ -48,3 +52,3 @@

};
const db = await new Promise((res, rej) => {
const dbPromise = new Promise((res, rej) => {
openRequest.onerror = ev => rej(ev);

@@ -56,4 +60,5 @@ openRequest.onsuccess = () => {

return db;
return dbPromise;
}
/**

@@ -63,3 +68,3 @@ * writes the new message to the database

*/
export async function writeMessage(db, readerUuid, messageJson) {
export function writeMessage(db, readerUuid, messageJson) {
const time = new Date().getTime();

@@ -83,3 +88,3 @@ const writeObject = {

export async function getAllMessages(db) {
export function getAllMessages(db) {
const objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);

@@ -101,3 +106,3 @@ const ret = [];

export async function getMessagesHigherThen(db, lastCursorId) {
export function getMessagesHigherThen(db, lastCursorId) {
const objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);

@@ -120,3 +125,3 @@ const ret = [];

export async function removeMessageById(db, id) {
export function removeMessageById(db, id) {
const request = db.transaction([OBJECT_STORE_ID], 'readwrite')

@@ -130,3 +135,3 @@ .objectStore(OBJECT_STORE_ID)

export async function getOldMessages(db, ttl) {
export function getOldMessages(db, ttl) {
const olderThen = new Date().getTime() - ttl;

@@ -156,10 +161,12 @@ const objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);

export async function cleanOldMessages(db, ttl) {
const tooOld = await getOldMessages(db, ttl);
return Promise.all(
tooOld.map(msgObj => removeMessageById(db, msgObj.id))
);
export function cleanOldMessages(db, ttl) {
return getOldMessages(db, ttl)
.then(tooOld => {
return Promise.all(
tooOld.map(msgObj => removeMessageById(db, msgObj.id))
);
});
}
export async function create(channelName, options = {}) {
export function create(channelName, options) {
options = fillOptionsWithDefaults(options);

@@ -172,31 +179,37 @@

const db = await createDatabase(channelName);
const state = {
closed: false,
lastCursorId: 0,
channelName,
options,
uuid,
// contains all messages that have been emitted before
emittedMessagesIds: new Set(),
messagesCallback: null,
readQueue,
db
};
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
(async () => {
while (state.closed === false) {
await handleMessagePing(state);
await new Promise(res => setTimeout(res, state.options.idb.fallbackInterval));
}
})();
return createDatabase(channelName).then(db => {
const state = {
closed: false,
lastCursorId: 0,
channelName,
options,
uuid,
// contains all messages that have been emitted before
emittedMessagesIds: new Set(),
messagesCallback: null,
readQueue,
db
};
return state;
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
_readLoop(state);
return state;
});
}
function _readLoop(state) {
if (state.closed) return;
return handleMessagePing(state)
.then(() => sleep(state.options.idb.fallbackInterval))
.then(() => _readLoop(state));
}
/**

@@ -206,7 +219,7 @@ * when the storage-event pings, so that we now new messages came,

*/
export async function handleMessagePing(state) {
export function handleMessagePing(state) {
/**
* when there are no listener, we do nothing
*/
if (!state.messagesCallback) return;
if (!state.messagesCallback) return Promise.resolve();

@@ -217,8 +230,13 @@ /**

*/
if (state.readQueue._idleCalls.size > 1) return;
if (state.readQueue._idleCalls.size > 1) return Promise.resolve();
await state.readQueue.requestIdlePromise();
await state.readQueue.wrapCall(
async () => {
const newerMessages = await getMessagesHigherThen(state.db, state.lastCursorId);
return state.readQueue.requestIdlePromise()
.then(() => state.readQueue.wrapCall(
() => _handleMessagePingInner(state)
));
}
function _handleMessagePingInner(state) {
return getMessagesHigherThen(state.db, state.lastCursorId)
.then(newerMessages => {
const useMessages = newerMessages

@@ -236,3 +254,4 @@ .map(msgObj => {

for (const msgObj of useMessages) {
useMessages.forEach(msgObj => {
if (state.messagesCallback) {

@@ -247,5 +266,6 @@ state.emittedMessagesIds.add(msgObj.id);

}
}
}
);
});
return Promise.resolve();
});
}

@@ -259,15 +279,15 @@

export async function postMessage(channelState, messageJson) {
await writeMessage(
export function postMessage(channelState, messageJson) {
return writeMessage(
channelState.db,
channelState.uuid,
messageJson
);
if (randomInt(0, 10) === 0) {
/* await (do not await) */ cleanOldMessages(
channelState.db,
channelState.options.idb.ttl
);
}
).then(() => {
if (randomInt(0, 10) === 0) {
/* await (do not await) */ cleanOldMessages(
channelState.db,
channelState.options.idb.ttl
);
}
});
}

@@ -274,0 +294,0 @@

@@ -9,5 +9,4 @@ /**

import isNode from 'detect-node';
import randomToken from 'random-token';
import IdleQueue from 'custom-idle-queue';
const isNode = require('detect-node');
const randomToken = require('random-token');

@@ -18,2 +17,6 @@ import {

import {
sleep
} from '../util';
const KEY_PREFIX = 'pubkey.broadcastChannel-';

@@ -49,25 +52,29 @@ export const type = 'localstorage';

*/
export async function postMessage(channelState, messageJson) {
await new Promise(res => setTimeout(res, 0));
export function postMessage(channelState, messageJson) {
return new Promise(res => {
sleep().then(() => {
const key = storageKey(channelState.channelName);
const writeObj = {
token: randomToken(10),
time: new Date().getTime(),
data: messageJson,
uuid: channelState.uuid
};
const value = JSON.stringify(writeObj);
localStorage.setItem(key, value);
const key = storageKey(channelState.channelName);
const writeObj = {
token: randomToken(10),
time: new Date().getTime(),
data: messageJson,
uuid: channelState.uuid
};
const value = JSON.stringify(writeObj);
localStorage.setItem(key, value);
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
const ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
ev.newValue = value;
window.dispatchEvent(ev);
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
const ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
ev.newValue = value;
window.dispatchEvent(ev);
res();
});
});
}

@@ -89,5 +96,5 @@

export function create(channelName, options = {}) {
export function create(channelName, options) {
options = fillOptionsWithDefaults(options);
if(!canBeUsed()){
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');

@@ -102,4 +109,2 @@ }

const writeQueue = new IdleQueue(1);
const state = {

@@ -110,4 +115,3 @@ startTime,

uuid,
emittedMessagesIds,
writeQueue
emittedMessagesIds
};

@@ -118,3 +122,3 @@

channelName,
async (msgObj) => {
(msgObj) => {
if (!state.messagesCallback) return; // no listener

@@ -140,3 +144,2 @@ if (msgObj.uuid === uuid) return; // own message

removeStorageEventListener(channelState.listener);
channelState.writeQueue.clear();
}

@@ -143,0 +146,0 @@

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

import isNode from 'detect-node';
const isNode = require('detect-node');
export const type = 'native';
export function create(channelName, options = {}) {
export function create(channelName, options) {
if(!options) options = {};
const state = {

@@ -8,0 +8,0 @@ channelName,

@@ -1,5 +0,4 @@

import clone from 'clone';
export function fillOptionsWithDefaults(options) {
options = clone(options);
if(!options) options = {};
options = JSON.parse(JSON.stringify(options));

@@ -6,0 +5,0 @@ // main

@@ -29,1 +29,6 @@ /**

};
export function sleep(time) {
if (!time) time = 0;
return new Promise(res => setTimeout(res, time));
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc