broadcast-channel
Advanced tools
Comparing version 4.10.0 to 4.11.0
@@ -10,3 +10,3 @@ | ||
<p align="center"> | ||
<strong>A BroadcastChannel to send data between different browser-tabs or nodejs-processes</strong> | ||
<strong>A BroadcastChannel to send data across multiple browser-tabs or nodejs-processes</strong> | ||
<br/> | ||
@@ -28,4 +28,4 @@ <span>+ LeaderElection over the channels</span><br /> | ||
- It works completely **client-side** and **offline**. | ||
- Tested on **old browsers**, **new browsers**, **WebWorkers**, **Iframes** and **NodeJs** | ||
- It works completely **client-side** and **offline**, | ||
- Tested on **old browsers**, **new browsers**, **WebWorkers**, **Iframes** and **NodeJs**. | ||
@@ -40,3 +40,3 @@ This behaves similar to the [BroadcastChannel-API](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API) which is currently only featured in [some browsers](https://caniuse.com/#feat=broadcastchannel). | ||
#### Create a channel in one tab/process and send a message. | ||
#### Create a channel in one tab/process and send a message | ||
@@ -49,3 +49,3 @@ ```ts | ||
#### Create a channel with the same name in another tab/process and recieve messages. | ||
#### Create a channel with the same name in another tab/process and recieve messages | ||
@@ -73,4 +73,4 @@ ```ts | ||
#### Close the channel if you do not need it anymore. | ||
Returns a `Promise` that resolved when everything is processed. | ||
#### Close the channel if you do not need it anymore | ||
Returns a `Promise` which is resolved when everything is processed. | ||
@@ -81,3 +81,3 @@ ```js | ||
#### Set options when creating a channel (optional): | ||
#### Set options when creating a channel (optional) | ||
@@ -92,3 +92,3 @@ ```js | ||
#### Create a typed channel in typescript: | ||
#### Create a typed channel in typescript | ||
@@ -106,3 +106,3 @@ ```typescript | ||
#### Enforce a options globally | ||
#### Enforce options globally | ||
@@ -124,6 +124,7 @@ When you use this module in a test-suite, it is recommended to enforce the fast `simulate` method on all channels so your tests run faster. You can do this with `enforceOptions()`. If you set this, all channels have the enforced options, no mather what options are given in the constructor. | ||
#### Clear tmp-folder: | ||
When used in NodeJs, the BroadcastChannel will communicate with other processes over filesystem based sockets. | ||
When you create a huge amount of channels, like you would do when running unit tests, you might get problems because there are too many folders in the tmp-directory. Calling `BroadcastChannel.clearNodeFolder()` will clear the tmp-folder and it is recommended to run this at the beginning of your test-suite. | ||
#### Clear tmp-folder | ||
When used in NodeJs, the BroadcastChannel will communicate with other processes over filesystem sockets. | ||
When you create a huge amount of channels, like you would do when running unit tests, you might get problems because there are too many folders in the tmp-directory. Calling `BroadcastChannel.clearNodeFolder()` will clear the tmp-folder. It is recommended to run this at the beginning of your test-suite. | ||
```typescript | ||
@@ -149,3 +150,3 @@ import { clearNodeFolder } from 'broadcast-channel'; | ||
IndexedDB databases can close unexpectedly for various reasons. This could happen, for example, if the underlying storage is removed or if the user clears the database in the browser's history preferences. Most often we have seen this happen in Mobile Safari. By default, we let the connection close and stop polling for changes. If you would like to continue listening you should close BroadcastChannel and create a new one. | ||
IndexedDB databases can close unexpectedly for various reasons. This could happen, for example, if the underlying storage is removed or if a user clears the database in the browser's history preferences. Most often we have seen this happen in Mobile Safari. By default, we let the connection close and stop polling for changes. If you would like to continue listening you should close BroadcastChannel and create a new one. | ||
@@ -178,3 +179,3 @@ Example of how you might do this: | ||
## Methods: | ||
## Methods | ||
@@ -195,3 +196,3 @@ Depending in which environment this is used, a proper method is automatically selected to ensure it always works. | ||
This module also comes with a leader-election which can be used so elect a leader between different BroadcastChannels. | ||
This module also comes with a leader-election which can be used to elect a leader between different BroadcastChannels. | ||
For example if you have a stable connection from the frontend to your server, you can use the LeaderElection to save server-side performance by only connecting once, even if the user has opened your website in multiple tabs. | ||
@@ -203,3 +204,3 @@ | ||
Create a channel and an elector. | ||
Create a channel and an elector: | ||
@@ -215,3 +216,3 @@ ```ts | ||
Wait until the elector becomes leader. | ||
Wait until the elector becomes leader: | ||
@@ -246,3 +247,3 @@ ```js | ||
Let the leader die. (automatically happens if the tab is closed or the process exits). | ||
Let the leader die. (automatically happens if a tab is closed or the process exits). | ||
@@ -256,3 +257,3 @@ ```js | ||
Duplicate leadership can happen on rare occurences like when the [CPU is on 100%](https://github.com/pubkey/broadcast-channel/issues/385) for longer time, or the browser [has throttled the javascript timers](https://github.com/pubkey/broadcast-channel/issues/414). | ||
Duplicate leadership can happen on rare occurences like when the [CPU is on 100%](https://web.archive.org/web/20201221051328/https://github.com/pubkey/broadcast-channel/issues/385) for longer time, or the browser [has throttled the javascript timers](https://web.archive.org/web/20201221051312/https://github.com/pubkey/broadcast-channel/issues/414). | ||
@@ -271,4 +272,4 @@ ```js | ||
- **low latency**: When you postMessage on one channel, it should take as low as possible time until other channels recieve the message. | ||
- **lossless**: When you send a message, it should be impossible that the message is lost before other channels recieved it | ||
- **low latency**: When you `postMessage` to a channel, it will be delivered to other channels as soon as possible, | ||
- **lossless**: When you send a message, it should be impossible that the message is lost before other channels recieved it, | ||
- **low idle workload**: During the time when no messages are send, there should be a low processor footprint. | ||
@@ -279,5 +280,5 @@ | ||
- This is not a polyfill. Do not set this module to `window.BroadcastChannel`. This implementation behaves similiar to the [BroadcastChannel-Standard](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API) with these limitations: | ||
- You can only send data that can be `JSON.stringify`-ed. | ||
- While the offical API emits [onmessage-events](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel/onmessage), this module directly emitts the data which was posted | ||
- This is not a replacement for a message queue. If you use this in NodeJs and want send more than 50 messages per second, you should use proper [IPC-Tooling](https://en.wikipedia.org/wiki/Message_queue) | ||
- You can only send data that can be `JSON.stringify`-ed, | ||
- While the offical API emits [onmessage-events](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel/onmessage), this module directly emitts the data which was posted. | ||
- This is not a replacement for a message queue. If you use this in NodeJs and want send more than 50 messages per second, you should use proper [IPC-Tooling](https://en.wikipedia.org/wiki/Message_queue). | ||
@@ -284,0 +285,0 @@ |
@@ -6,2 +6,7 @@ # CHANGELOG | ||
## 4.11.0 (12 April 2022) | ||
- Replaced `nano-time` with `microtime`. | ||
- Improve IndexedDB method performance. | ||
## 4.10.0 (3 February 2022) | ||
@@ -8,0 +13,0 @@ |
@@ -6,2 +6,3 @@ "use strict"; | ||
}); | ||
exports.TRANSACTION_SETTINGS = void 0; | ||
exports.averageResponseTime = averageResponseTime; | ||
@@ -11,2 +12,3 @@ exports.canBeUsed = canBeUsed; | ||
exports.close = close; | ||
exports.commitIndexedDBTransaction = commitIndexedDBTransaction; | ||
exports.create = create; | ||
@@ -22,3 +24,3 @@ exports.createDatabase = createDatabase; | ||
exports.postMessage = postMessage; | ||
exports.removeMessageById = removeMessageById; | ||
exports.removeMessagesById = removeMessagesById; | ||
exports.type = void 0; | ||
@@ -37,2 +39,5 @@ exports.writeMessage = writeMessage; | ||
* @link https://github.com/w3c/IndexedDB/issues/51 | ||
* | ||
* When working on this, ensure to use these performance optimizations: | ||
* @link https://rxdb.info/slow-indexeddb.html | ||
*/ | ||
@@ -43,2 +48,11 @@ var microSeconds = _util.microSeconds; | ||
var OBJECT_STORE_ID = 'messages'; | ||
/** | ||
* Use relaxed durability for faster performance on all transactions. | ||
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/ | ||
*/ | ||
var TRANSACTION_SETTINGS = { | ||
durability: 'relaxed' | ||
}; | ||
exports.TRANSACTION_SETTINGS = TRANSACTION_SETTINGS; | ||
var type = 'idb'; | ||
@@ -58,3 +72,15 @@ exports.type = type; | ||
} | ||
/** | ||
* If possible, we should explicitly commit IndexedDB transactions | ||
* for better performance. | ||
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/ | ||
*/ | ||
function commitIndexedDBTransaction(tx) { | ||
if (tx.commit) { | ||
tx.commit(); | ||
} | ||
} | ||
function createDatabase(channelName) { | ||
@@ -64,4 +90,10 @@ var IndexedDB = getIdb(); // create table | ||
var dbName = DB_PREFIX + channelName; | ||
var openRequest = IndexedDB.open(dbName, 1); | ||
/** | ||
* All IndexedDB databases are opened without version | ||
* because it is a bit faster, especially on firefox | ||
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version | ||
*/ | ||
var openRequest = IndexedDB.open(dbName); | ||
openRequest.onupgradeneeded = function (ev) { | ||
@@ -99,14 +131,15 @@ var db = ev.target.result; | ||
}; | ||
var transaction = db.transaction([OBJECT_STORE_ID], 'readwrite'); | ||
var tx = db.transaction([OBJECT_STORE_ID], 'readwrite', TRANSACTION_SETTINGS); | ||
return new Promise(function (res, rej) { | ||
transaction.oncomplete = function () { | ||
tx.oncomplete = function () { | ||
return res(); | ||
}; | ||
transaction.onerror = function (ev) { | ||
tx.onerror = function (ev) { | ||
return rej(ev); | ||
}; | ||
var objectStore = transaction.objectStore(OBJECT_STORE_ID); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
objectStore.add(writeObject); | ||
commitIndexedDBTransaction(tx); | ||
}); | ||
@@ -116,3 +149,4 @@ } | ||
function getAllMessages(db) { | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
@@ -128,2 +162,3 @@ return new Promise(function (res) { | ||
} else { | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -136,5 +171,25 @@ } | ||
function getMessagesHigherThan(db, lastCursorId) { | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
/** | ||
* Optimization shortcut, | ||
* if getAll() can be used, do not use a cursor. | ||
* @link https://rxdb.info/slow-indexeddb.html | ||
*/ | ||
if (objectStore.getAll) { | ||
var getAllRequest = objectStore.getAll(keyRangeValue); | ||
return new Promise(function (res, rej) { | ||
getAllRequest.onerror = function (err) { | ||
return rej(err); | ||
}; | ||
getAllRequest.onsuccess = function (e) { | ||
res(e.target.result); | ||
}; | ||
}); | ||
} | ||
function openCursor() { | ||
@@ -145,3 +200,3 @@ // Occasionally Safari will fail on IDBKeyRange.bound, this | ||
try { | ||
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
return objectStore.openCursor(keyRangeValue); | ||
@@ -153,4 +208,10 @@ } catch (e) { | ||
return new Promise(function (res) { | ||
openCursor().onsuccess = function (ev) { | ||
return new Promise(function (res, rej) { | ||
var openCursorRequest = openCursor(); | ||
openCursorRequest.onerror = function (err) { | ||
return rej(err); | ||
}; | ||
openCursorRequest.onsuccess = function (ev) { | ||
var cursor = ev.target.result; | ||
@@ -166,2 +227,3 @@ | ||
} else { | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -173,9 +235,13 @@ } | ||
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(); | ||
}; | ||
}); | ||
function removeMessagesById(db, ids) { | ||
var tx = db.transaction([OBJECT_STORE_ID], 'readwrite', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
return Promise.all(ids.map(function (id) { | ||
var deleteRequest = objectStore["delete"](id); | ||
return new Promise(function (res) { | ||
deleteRequest.onsuccess = function () { | ||
return res(); | ||
}; | ||
}); | ||
})); | ||
} | ||
@@ -185,3 +251,4 @@ | ||
var olderThen = new Date().getTime() - ttl; | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
@@ -201,2 +268,3 @@ return new Promise(function (res) { | ||
// no more old messages, | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -214,4 +282,4 @@ return; | ||
return getOldMessages(db, ttl).then(function (tooOld) { | ||
return Promise.all(tooOld.map(function (msgObj) { | ||
return removeMessageById(db, msgObj.id); | ||
return removeMessagesById(db, tooOld.map(function (msg) { | ||
return msg.id; | ||
})); | ||
@@ -218,0 +286,0 @@ }); |
@@ -57,3 +57,3 @@ "use strict"; | ||
var _nanoTime = _interopRequireDefault(require("nano-time")); | ||
var _microtime = _interopRequireDefault(require("microtime")); | ||
@@ -125,3 +125,3 @@ var _rimraf = _interopRequireDefault(require("rimraf")); | ||
/** | ||
* because the lenght of socket-paths is limited, we use only the first 20 chars | ||
* because the length of socket-paths is limited, we use only the first 20 chars | ||
* and also start with A to ensure we do not start with a number | ||
@@ -138,3 +138,3 @@ * @link https://serverfault.com/questions/641347/check-if-a-path-exceeds-maximum-for-unix-domain-socket | ||
var folderPathMessages = _path["default"].join(channelPathBase, 'messages'); | ||
var folderPathMessages = _path["default"].join(channelPathBase, 'msgs'); | ||
@@ -1188,3 +1188,3 @@ var ret = { | ||
function microSeconds() { | ||
return parseInt(_nanoTime["default"].microseconds()); | ||
return parseInt(_microtime["default"].now()); | ||
} |
@@ -5,2 +5,5 @@ /** | ||
* @link https://github.com/w3c/IndexedDB/issues/51 | ||
* | ||
* When working on this, ensure to use these performance optimizations: | ||
* @link https://rxdb.info/slow-indexeddb.html | ||
*/ | ||
@@ -13,2 +16,10 @@ import { sleep, randomInt, randomToken, microSeconds as micro, isNode, PROMISE_RESOLVED_VOID } from '../util.js'; | ||
var OBJECT_STORE_ID = 'messages'; | ||
/** | ||
* Use relaxed durability for faster performance on all transactions. | ||
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/ | ||
*/ | ||
export var TRANSACTION_SETTINGS = { | ||
durability: 'relaxed' | ||
}; | ||
export var type = 'idb'; | ||
@@ -26,2 +37,13 @@ export function getIdb() { | ||
} | ||
/** | ||
* If possible, we should explicitly commit IndexedDB transactions | ||
* for better performance. | ||
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/ | ||
*/ | ||
export function commitIndexedDBTransaction(tx) { | ||
if (tx.commit) { | ||
tx.commit(); | ||
} | ||
} | ||
export function createDatabase(channelName) { | ||
@@ -31,4 +53,10 @@ var IndexedDB = getIdb(); // create table | ||
var dbName = DB_PREFIX + channelName; | ||
var openRequest = IndexedDB.open(dbName, 1); | ||
/** | ||
* All IndexedDB databases are opened without version | ||
* because it is a bit faster, especially on firefox | ||
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version | ||
*/ | ||
var openRequest = IndexedDB.open(dbName); | ||
openRequest.onupgradeneeded = function (ev) { | ||
@@ -65,18 +93,20 @@ var db = ev.target.result; | ||
}; | ||
var transaction = db.transaction([OBJECT_STORE_ID], 'readwrite'); | ||
var tx = db.transaction([OBJECT_STORE_ID], 'readwrite', TRANSACTION_SETTINGS); | ||
return new Promise(function (res, rej) { | ||
transaction.oncomplete = function () { | ||
tx.oncomplete = function () { | ||
return res(); | ||
}; | ||
transaction.onerror = function (ev) { | ||
tx.onerror = function (ev) { | ||
return rej(ev); | ||
}; | ||
var objectStore = transaction.objectStore(OBJECT_STORE_ID); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
objectStore.add(writeObject); | ||
commitIndexedDBTransaction(tx); | ||
}); | ||
} | ||
export function getAllMessages(db) { | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
@@ -92,2 +122,3 @@ return new Promise(function (res) { | ||
} else { | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -99,5 +130,25 @@ } | ||
export function getMessagesHigherThan(db, lastCursorId) { | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
/** | ||
* Optimization shortcut, | ||
* if getAll() can be used, do not use a cursor. | ||
* @link https://rxdb.info/slow-indexeddb.html | ||
*/ | ||
if (objectStore.getAll) { | ||
var getAllRequest = objectStore.getAll(keyRangeValue); | ||
return new Promise(function (res, rej) { | ||
getAllRequest.onerror = function (err) { | ||
return rej(err); | ||
}; | ||
getAllRequest.onsuccess = function (e) { | ||
res(e.target.result); | ||
}; | ||
}); | ||
} | ||
function openCursor() { | ||
@@ -108,3 +159,3 @@ // Occasionally Safari will fail on IDBKeyRange.bound, this | ||
try { | ||
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
return objectStore.openCursor(keyRangeValue); | ||
@@ -116,4 +167,10 @@ } catch (e) { | ||
return new Promise(function (res) { | ||
openCursor().onsuccess = function (ev) { | ||
return new Promise(function (res, rej) { | ||
var openCursorRequest = openCursor(); | ||
openCursorRequest.onerror = function (err) { | ||
return rej(err); | ||
}; | ||
openCursorRequest.onsuccess = function (ev) { | ||
var cursor = ev.target.result; | ||
@@ -129,2 +186,3 @@ | ||
} else { | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -135,13 +193,18 @@ } | ||
} | ||
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 function removeMessagesById(db, ids) { | ||
var tx = db.transaction([OBJECT_STORE_ID], 'readwrite', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
return Promise.all(ids.map(function (id) { | ||
var deleteRequest = objectStore["delete"](id); | ||
return new Promise(function (res) { | ||
deleteRequest.onsuccess = function () { | ||
return res(); | ||
}; | ||
}); | ||
})); | ||
} | ||
export function getOldMessages(db, ttl) { | ||
var olderThen = new Date().getTime() - ttl; | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
@@ -161,2 +224,3 @@ return new Promise(function (res) { | ||
// no more old messages, | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -173,4 +237,4 @@ return; | ||
return getOldMessages(db, ttl).then(function (tooOld) { | ||
return Promise.all(tooOld.map(function (msgObj) { | ||
return removeMessageById(db, msgObj.id); | ||
return removeMessagesById(db, tooOld.map(function (msg) { | ||
return msg.id; | ||
})); | ||
@@ -177,0 +241,0 @@ }); |
@@ -15,3 +15,3 @@ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator"; | ||
import path from 'path'; | ||
import micro from 'nano-time'; | ||
import micro from 'microtime'; | ||
import rimraf from 'rimraf'; | ||
@@ -59,3 +59,3 @@ import isNode from 'detect-node'; | ||
/** | ||
* because the lenght of socket-paths is limited, we use only the first 20 chars | ||
* because the length of socket-paths is limited, we use only the first 20 chars | ||
* and also start with A to ensure we do not start with a number | ||
@@ -68,3 +68,3 @@ * @link https://serverfault.com/questions/641347/check-if-a-path-exceeds-maximum-for-unix-domain-socket | ||
var folderPathReaders = path.join(channelPathBase, 'rdrs'); | ||
var folderPathMessages = path.join(channelPathBase, 'messages'); | ||
var folderPathMessages = path.join(channelPathBase, 'msgs'); | ||
var ret = { | ||
@@ -1091,3 +1091,3 @@ channelBase: channelPathBase, | ||
export function microSeconds() { | ||
return parseInt(micro.microseconds()); | ||
return parseInt(micro.now()); | ||
} |
@@ -5,2 +5,5 @@ /** | ||
* @link https://github.com/w3c/IndexedDB/issues/51 | ||
* | ||
* When working on this, ensure to use these performance optimizations: | ||
* @link https://rxdb.info/slow-indexeddb.html | ||
*/ | ||
@@ -13,2 +16,10 @@ import { sleep, randomInt, randomToken, microSeconds as micro, isNode, PROMISE_RESOLVED_VOID } from '../util.js'; | ||
var OBJECT_STORE_ID = 'messages'; | ||
/** | ||
* Use relaxed durability for faster performance on all transactions. | ||
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/ | ||
*/ | ||
export var TRANSACTION_SETTINGS = { | ||
durability: 'relaxed' | ||
}; | ||
export var type = 'idb'; | ||
@@ -26,2 +37,13 @@ export function getIdb() { | ||
} | ||
/** | ||
* If possible, we should explicitly commit IndexedDB transactions | ||
* for better performance. | ||
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/ | ||
*/ | ||
export function commitIndexedDBTransaction(tx) { | ||
if (tx.commit) { | ||
tx.commit(); | ||
} | ||
} | ||
export function createDatabase(channelName) { | ||
@@ -31,4 +53,10 @@ var IndexedDB = getIdb(); // create table | ||
var dbName = DB_PREFIX + channelName; | ||
var openRequest = IndexedDB.open(dbName, 1); | ||
/** | ||
* All IndexedDB databases are opened without version | ||
* because it is a bit faster, especially on firefox | ||
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version | ||
*/ | ||
var openRequest = IndexedDB.open(dbName); | ||
openRequest.onupgradeneeded = function (ev) { | ||
@@ -65,18 +93,20 @@ var db = ev.target.result; | ||
}; | ||
var transaction = db.transaction([OBJECT_STORE_ID], 'readwrite'); | ||
var tx = db.transaction([OBJECT_STORE_ID], 'readwrite', TRANSACTION_SETTINGS); | ||
return new Promise(function (res, rej) { | ||
transaction.oncomplete = function () { | ||
tx.oncomplete = function () { | ||
return res(); | ||
}; | ||
transaction.onerror = function (ev) { | ||
tx.onerror = function (ev) { | ||
return rej(ev); | ||
}; | ||
var objectStore = transaction.objectStore(OBJECT_STORE_ID); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
objectStore.add(writeObject); | ||
commitIndexedDBTransaction(tx); | ||
}); | ||
} | ||
export function getAllMessages(db) { | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
@@ -92,2 +122,3 @@ return new Promise(function (res) { | ||
} else { | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -99,5 +130,25 @@ } | ||
export function getMessagesHigherThan(db, lastCursorId) { | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
/** | ||
* Optimization shortcut, | ||
* if getAll() can be used, do not use a cursor. | ||
* @link https://rxdb.info/slow-indexeddb.html | ||
*/ | ||
if (objectStore.getAll) { | ||
var getAllRequest = objectStore.getAll(keyRangeValue); | ||
return new Promise(function (res, rej) { | ||
getAllRequest.onerror = function (err) { | ||
return rej(err); | ||
}; | ||
getAllRequest.onsuccess = function (e) { | ||
res(e.target.result); | ||
}; | ||
}); | ||
} | ||
function openCursor() { | ||
@@ -108,3 +159,3 @@ // Occasionally Safari will fail on IDBKeyRange.bound, this | ||
try { | ||
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
return objectStore.openCursor(keyRangeValue); | ||
@@ -116,4 +167,10 @@ } catch (e) { | ||
return new Promise(function (res) { | ||
openCursor().onsuccess = function (ev) { | ||
return new Promise(function (res, rej) { | ||
var openCursorRequest = openCursor(); | ||
openCursorRequest.onerror = function (err) { | ||
return rej(err); | ||
}; | ||
openCursorRequest.onsuccess = function (ev) { | ||
var cursor = ev.target.result; | ||
@@ -129,2 +186,3 @@ | ||
} else { | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -135,13 +193,18 @@ } | ||
} | ||
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 function removeMessagesById(db, ids) { | ||
var tx = db.transaction([OBJECT_STORE_ID], 'readwrite', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
return Promise.all(ids.map(function (id) { | ||
var deleteRequest = objectStore["delete"](id); | ||
return new Promise(function (res) { | ||
deleteRequest.onsuccess = function () { | ||
return res(); | ||
}; | ||
}); | ||
})); | ||
} | ||
export function getOldMessages(db, ttl) { | ||
var olderThen = new Date().getTime() - ttl; | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
@@ -161,2 +224,3 @@ return new Promise(function (res) { | ||
// no more old messages, | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -173,4 +237,4 @@ return; | ||
return getOldMessages(db, ttl).then(function (tooOld) { | ||
return Promise.all(tooOld.map(function (msgObj) { | ||
return removeMessageById(db, msgObj.id); | ||
return removeMessagesById(db, tooOld.map(function (msg) { | ||
return msg.id; | ||
})); | ||
@@ -177,0 +241,0 @@ }); |
@@ -15,3 +15,3 @@ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator"; | ||
import path from 'path'; | ||
import micro from 'nano-time'; | ||
import micro from 'microtime'; | ||
import rimraf from 'rimraf'; | ||
@@ -59,3 +59,3 @@ import isNode from 'detect-node'; | ||
/** | ||
* because the lenght of socket-paths is limited, we use only the first 20 chars | ||
* because the length of socket-paths is limited, we use only the first 20 chars | ||
* and also start with A to ensure we do not start with a number | ||
@@ -68,3 +68,3 @@ * @link https://serverfault.com/questions/641347/check-if-a-path-exceeds-maximum-for-unix-domain-socket | ||
var folderPathReaders = path.join(channelPathBase, 'rdrs'); | ||
var folderPathMessages = path.join(channelPathBase, 'messages'); | ||
var folderPathMessages = path.join(channelPathBase, 'msgs'); | ||
var ret = { | ||
@@ -1091,3 +1091,3 @@ channelBase: channelPathBase, | ||
export function microSeconds() { | ||
return parseInt(micro.microseconds()); | ||
return parseInt(micro.now()); | ||
} |
@@ -853,2 +853,3 @@ (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ | ||
}); | ||
exports.TRANSACTION_SETTINGS = void 0; | ||
exports.averageResponseTime = averageResponseTime; | ||
@@ -858,2 +859,3 @@ exports.canBeUsed = canBeUsed; | ||
exports.close = close; | ||
exports.commitIndexedDBTransaction = commitIndexedDBTransaction; | ||
exports.create = create; | ||
@@ -869,3 +871,3 @@ exports.createDatabase = createDatabase; | ||
exports.postMessage = postMessage; | ||
exports.removeMessageById = removeMessageById; | ||
exports.removeMessagesById = removeMessagesById; | ||
exports.type = void 0; | ||
@@ -884,2 +886,5 @@ exports.writeMessage = writeMessage; | ||
* @link https://github.com/w3c/IndexedDB/issues/51 | ||
* | ||
* When working on this, ensure to use these performance optimizations: | ||
* @link https://rxdb.info/slow-indexeddb.html | ||
*/ | ||
@@ -890,2 +895,11 @@ var microSeconds = _util.microSeconds; | ||
var OBJECT_STORE_ID = 'messages'; | ||
/** | ||
* Use relaxed durability for faster performance on all transactions. | ||
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/ | ||
*/ | ||
var TRANSACTION_SETTINGS = { | ||
durability: 'relaxed' | ||
}; | ||
exports.TRANSACTION_SETTINGS = TRANSACTION_SETTINGS; | ||
var type = 'idb'; | ||
@@ -905,3 +919,15 @@ exports.type = type; | ||
} | ||
/** | ||
* If possible, we should explicitly commit IndexedDB transactions | ||
* for better performance. | ||
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/ | ||
*/ | ||
function commitIndexedDBTransaction(tx) { | ||
if (tx.commit) { | ||
tx.commit(); | ||
} | ||
} | ||
function createDatabase(channelName) { | ||
@@ -911,4 +937,10 @@ var IndexedDB = getIdb(); // create table | ||
var dbName = DB_PREFIX + channelName; | ||
var openRequest = IndexedDB.open(dbName, 1); | ||
/** | ||
* All IndexedDB databases are opened without version | ||
* because it is a bit faster, especially on firefox | ||
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version | ||
*/ | ||
var openRequest = IndexedDB.open(dbName); | ||
openRequest.onupgradeneeded = function (ev) { | ||
@@ -946,14 +978,15 @@ var db = ev.target.result; | ||
}; | ||
var transaction = db.transaction([OBJECT_STORE_ID], 'readwrite'); | ||
var tx = db.transaction([OBJECT_STORE_ID], 'readwrite', TRANSACTION_SETTINGS); | ||
return new Promise(function (res, rej) { | ||
transaction.oncomplete = function () { | ||
tx.oncomplete = function () { | ||
return res(); | ||
}; | ||
transaction.onerror = function (ev) { | ||
tx.onerror = function (ev) { | ||
return rej(ev); | ||
}; | ||
var objectStore = transaction.objectStore(OBJECT_STORE_ID); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
objectStore.add(writeObject); | ||
commitIndexedDBTransaction(tx); | ||
}); | ||
@@ -963,3 +996,4 @@ } | ||
function getAllMessages(db) { | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
@@ -975,2 +1009,3 @@ return new Promise(function (res) { | ||
} else { | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -983,5 +1018,25 @@ } | ||
function getMessagesHigherThan(db, lastCursorId) { | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
/** | ||
* Optimization shortcut, | ||
* if getAll() can be used, do not use a cursor. | ||
* @link https://rxdb.info/slow-indexeddb.html | ||
*/ | ||
if (objectStore.getAll) { | ||
var getAllRequest = objectStore.getAll(keyRangeValue); | ||
return new Promise(function (res, rej) { | ||
getAllRequest.onerror = function (err) { | ||
return rej(err); | ||
}; | ||
getAllRequest.onsuccess = function (e) { | ||
res(e.target.result); | ||
}; | ||
}); | ||
} | ||
function openCursor() { | ||
@@ -992,3 +1047,3 @@ // Occasionally Safari will fail on IDBKeyRange.bound, this | ||
try { | ||
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
return objectStore.openCursor(keyRangeValue); | ||
@@ -1000,4 +1055,10 @@ } catch (e) { | ||
return new Promise(function (res) { | ||
openCursor().onsuccess = function (ev) { | ||
return new Promise(function (res, rej) { | ||
var openCursorRequest = openCursor(); | ||
openCursorRequest.onerror = function (err) { | ||
return rej(err); | ||
}; | ||
openCursorRequest.onsuccess = function (ev) { | ||
var cursor = ev.target.result; | ||
@@ -1013,2 +1074,3 @@ | ||
} else { | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -1020,9 +1082,13 @@ } | ||
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(); | ||
}; | ||
}); | ||
function removeMessagesById(db, ids) { | ||
var tx = db.transaction([OBJECT_STORE_ID], 'readwrite', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
return Promise.all(ids.map(function (id) { | ||
var deleteRequest = objectStore["delete"](id); | ||
return new Promise(function (res) { | ||
deleteRequest.onsuccess = function () { | ||
return res(); | ||
}; | ||
}); | ||
})); | ||
} | ||
@@ -1032,3 +1098,4 @@ | ||
var olderThen = new Date().getTime() - ttl; | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
@@ -1048,2 +1115,3 @@ return new Promise(function (res) { | ||
// no more old messages, | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -1061,4 +1129,4 @@ return; | ||
return getOldMessages(db, ttl).then(function (tooOld) { | ||
return Promise.all(tooOld.map(function (msgObj) { | ||
return removeMessageById(db, msgObj.id); | ||
return removeMessagesById(db, tooOld.map(function (msg) { | ||
return msg.id; | ||
})); | ||
@@ -1065,0 +1133,0 @@ }); |
@@ -1,1 +0,1 @@ | ||
!function r(o,i,s){function a(t,e){if(!i[t]){if(!o[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(u)return u(t,!0);throw(e=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",e}n=i[t]={exports:{}},o[t][0].call(n.exports,function(e){return a(o[t][1][e]||e)},n,n.exports,r,o,i,s)}return i[t].exports}for(var u="function"==typeof require&&require,e=0;e<s.length;e++)a(s[e]);return a}({1:[function(e,l,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.OPEN_BROADCAST_CHANNELS=t.BroadcastChannel=void 0,t.clearNodeFolder=function(e){e=(0,s.fillOptionsWithDefaults)(e);e=(0,i.chooseMethod)(e);return"node"===e.type?e.clearNodeFolder().then(function(){return!0}):o.PROMISE_RESOLVED_FALSE},t.enforceOptions=function(e){r=e};function n(e,t){var n;this.id=d++,a.add(this),this.name=e,r&&(t=r),this.options=(0,s.fillOptionsWithDefaults)(t),this.method=(0,i.chooseMethod)(this.options),this._iL=!1,this._onML=null,this._addEL={message:[],internal:[]},this._uMP=new Set,this._befC=[],this._prepP=null,e=(n=this).method.create(n.name,n.options),(0,o.isPromise)(e)?(n._prepP=e).then(function(e){n._state=e}):n._state=e}var r,o=e("./util.js"),i=e("./method-chooser.js"),s=e("./options.js"),a=new Set,d=(t.OPEN_BROADCAST_CHANNELS=a,0);function u(t,e,n){var r={time:t.method.microSeconds(),type:e,data:n};return(t._prepP||o.PROMISE_RESOLVED_VOID).then(function(){var e=t.method.postMessage(t._state,r);return t._uMP.add(e),e.catch().then(function(){return t._uMP.delete(e)}),e})}function c(e){return 0<e._addEL.message.length||0<e._addEL.internal.length}function f(e,t,n){e._addEL[t].push(n);var r,o,i=e;!i._iL&&c(i)&&(r=function(n){i._addEL[n.type].forEach(function(e){var t=e.time-1e5;n.time>=t&&e.fn(n.data)})},o=i.method.microSeconds(),i._prepP?i._prepP.then(function(){i._iL=!0,i.method.onMessage(i._state,r,o)}):(i._iL=!0,i.method.onMessage(i._state,r,o)))}function h(e,t,n){e._addEL[t]=e._addEL[t].filter(function(e){return e!==n});t=e;t._iL&&!c(t)&&(t._iL=!1,e=t.method.microSeconds(),t.method.onMessage(t._state,null,e))}(t.BroadcastChannel=n)._pubkey=!0,n.prototype={postMessage:function(e){if(this.closed)throw new Error("BroadcastChannel.postMessage(): Cannot post message after channel has closed "+JSON.stringify(e));return u(this,"message",e)},postInternal:function(e){return u(this,"internal",e)},set onmessage(e){var t={time:this.method.microSeconds(),fn:e};h(this,"message",this._onML),e&&"function"==typeof e?(this._onML=t,f(this,"message",t)):this._onML=null},addEventListener:function(e,t){var n=this.method.microSeconds();f(this,e,{time:n,fn:t})},removeEventListener:function(e,t){var n=this._addEL[e].find(function(e){return e.fn===t});h(this,e,n)},close:function(){var e,t=this;if(!this.closed)return a.delete(this),this.closed=!0,e=this._prepP||o.PROMISE_RESOLVED_VOID,this._onML=null,this._addEL.message=[],e.then(function(){return Promise.all(Array.from(t._uMP))}).then(function(){return Promise.all(t._befC.map(function(e){return e()}))}).then(function(){return t.method.close(t._state)})},get type(){return this.method.type},get isClosed(){return this.closed}}},{"./method-chooser.js":6,"./options.js":11,"./util.js":12}],2:[function(e,t,n){"use strict";var e=e("./index.es5.js"),r=e.BroadcastChannel,e=e.createLeaderElection;window.BroadcastChannel2=r,window.createLeaderElection=e},{"./index.es5.js":3}],3:[function(e,t,n){"use strict";e=e("./index.js");t.exports={BroadcastChannel:e.BroadcastChannel,createLeaderElection:e.createLeaderElection,clearNodeFolder:e.clearNodeFolder,enforceOptions:e.enforceOptions,beLeader:e.beLeader}},{"./index.js":4}],4:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),Object.defineProperty(n,"BroadcastChannel",{enumerable:!0,get:function(){return r.BroadcastChannel}}),Object.defineProperty(n,"OPEN_BROADCAST_CHANNELS",{enumerable:!0,get:function(){return r.OPEN_BROADCAST_CHANNELS}}),Object.defineProperty(n,"beLeader",{enumerable:!0,get:function(){return o.beLeader}}),Object.defineProperty(n,"clearNodeFolder",{enumerable:!0,get:function(){return r.clearNodeFolder}}),Object.defineProperty(n,"createLeaderElection",{enumerable:!0,get:function(){return o.createLeaderElection}}),Object.defineProperty(n,"enforceOptions",{enumerable:!0,get:function(){return r.enforceOptions}});var r=e("./broadcast-channel"),o=e("./leader-election")},{"./broadcast-channel":1,"./leader-election":5}],5:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.beLeader=l,n.createLeaderElection=function(e,t){if(e._leaderElector)throw new Error("BroadcastChannel already has a leader-elector");t=function(e,t){e=e||{};(e=JSON.parse(JSON.stringify(e))).fallbackInterval||(e.fallbackInterval=3e3);e.responseTime||(e.responseTime=t.method.averageResponseTime(t.options));return e}(t,e);var n=new o(e,t);return e._befC.push(function(){return n.die()}),e._leaderElector=n};var u=e("./util.js"),r=e("unload"),o=function(e,t){function n(e){"leader"===e.context&&("death"===e.action&&(r.hasLeader=!1),"tell"===e.action&&(r.hasLeader=!0))}var r=this;this.broadcastChannel=e,this._options=t,this.isLeader=!1,this.hasLeader=!1,this.isDead=!1,this.token=(0,u.randomToken)(),this._aplQ=u.PROMISE_RESOLVED_VOID,this._aplQC=0,this._unl=[],this._lstns=[],this._dpL=function(){},this._dpLC=!1;this.broadcastChannel.addEventListener("internal",n),this._lstns.push(n)};function c(e,t){t={context:"leader",action:t,token:e.token};return e.broadcastChannel.postInternal(t)}function l(t){t.isLeader=!0,t.hasLeader=!0;function e(e){"leader"===e.context&&"apply"===e.action&&c(t,"tell"),"leader"!==e.context||"tell"!==e.action||t._dpLC||(t._dpLC=!0,t._dpL(),c(t,"tell"))}var n=(0,r.add)(function(){return t.die()});t._unl.push(n);return t.broadcastChannel.addEventListener("internal",e),t._lstns.push(e),c(t,"tell")}o.prototype={applyOnce:function(s){var a=this;if(this.isLeader)return(0,u.sleep)(0,!0);if(this.isDead)return(0,u.sleep)(0,!1);if(1<this._aplQC)return this._aplQ;function e(){if(a.isLeader)return u.PROMISE_RESOLVED_TRUE;function e(e){"leader"===e.context&&e.token!=a.token&&(o.push(e),"apply"===e.action&&e.token>a.token&&t(),"tell"===e.action&&(t(),a.hasLeader=!0))}var t,n=!1,r=new Promise(function(e){t=function(){n=!0,e()}}),o=[],i=(a.broadcastChannel.addEventListener("internal",e),s?4*a._options.responseTime:a._options.responseTime);return c(a,"apply").then(function(){return Promise.race([(0,u.sleep)(i),r.then(function(){return Promise.reject(new Error)})])}).then(function(){return c(a,"apply")}).then(function(){return Promise.race([(0,u.sleep)(i),r.then(function(){return Promise.reject(new Error)})])}).catch(function(){}).then(function(){return a.broadcastChannel.removeEventListener("internal",e),!n&&l(a).then(function(){return!0})})}return this._aplQC=this._aplQC+1,this._aplQ=this._aplQ.then(e).then(function(){a._aplQC=a._aplQC-1}),this._aplQ.then(function(){return a.isLeader})},awaitLeadership:function(){return this._aLP||(this._aLP=function(o){if(o.isLeader)return u.PROMISE_RESOLVED_VOID;return new Promise(function(e){var t=!1;function n(){t||(t=!0,o.broadcastChannel.removeEventListener("internal",r),e(!0))}o.applyOnce().then(function(){o.isLeader&&n()});(function e(){return(0,u.sleep)(o._options.fallbackInterval).then(function(){if(!o.isDead&&!t)return o.isLeader?void n():o.applyOnce(!0).then(function(){(o.isLeader?n:e)()})})})();var r=function(e){"leader"===e.context&&"death"===e.action&&(o.hasLeader=!1,o.applyOnce().then(function(){o.isLeader&&n()}))};o.broadcastChannel.addEventListener("internal",r),o._lstns.push(r)})}(this)),this._aLP},set onduplicate(e){this._dpL=e},die:function(){var t=this;return this._lstns.forEach(function(e){return t.broadcastChannel.removeEventListener("internal",e)}),this._lstns=[],this._unl.forEach(function(e){return e.remove()}),this._unl=[],this.isLeader&&(this.hasLeader=!1,this.isLeader=!1),this.isDead=!0,c(this,"death")}}},{"./util.js":12,unload:20}],6:[function(e,t,n){"use strict";var r=e("@babel/runtime/helpers/interopRequireDefault"),n=(e("@babel/runtime/helpers/typeof"),Object.defineProperty(n,"__esModule",{value:!0}),n.chooseMethod=function(t){var e=[].concat(t.methods,u).filter(Boolean);if(t.type){if("simulate"===t.type)return s.default;var n=e.find(function(e){return e.type===t.type});if(n)return n;throw new Error("method-type "+t.type+" not found")}t.webWorkerSupport||a.isNode||(e=e.filter(function(e){return"idb"!==e.type}));n=e.find(function(e){return e.canBeUsed()});{if(n)return n;throw new Error("No useable method found in "+JSON.stringify(u.map(function(e){return e.type})))}},r(e("./methods/native.js"))),o=r(e("./methods/indexed-db.js")),i=r(e("./methods/localstorage.js")),s=r(e("./methods/simulate.js")),a=e("./util");var u=[n.default,o.default,i.default]},{"./methods/indexed-db.js":7,"./methods/localstorage.js":8,"./methods/native.js":9,"./methods/simulate.js":10,"./util":12,"@babel/runtime/helpers/interopRequireDefault":13,"@babel/runtime/helpers/typeof":14}],7:[function(e,l,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.averageResponseTime=w,t.canBeUsed=y,t.cleanOldMessages=p,t.close=b,t.create=m,t.createDatabase=i,t.default=void 0,t.getAllMessages=function(e){var n=e.transaction(s).objectStore(s),r=[];return new Promise(function(t){n.openCursor().onsuccess=function(e){e=e.target.result;e?(r.push(e.value),e.continue()):t(r)}})},t.getIdb=r,t.getMessagesHigherThan=a,t.getOldMessages=c,t.microSeconds=void 0,t.onMessage=g,t.postMessage=_,t.removeMessageById=u,t.type=void 0,t.writeMessage=n;var o=e("../util.js"),d=e("oblivious-set"),f=e("../options"),e=o.microSeconds,h=(t.microSeconds=e,"pubkey.broadcast-channel-0-"),s="messages";function r(){if("undefined"!=typeof indexedDB)return indexedDB;if("undefined"!=typeof window){if(void 0!==window.mozIndexedDB)return window.mozIndexedDB;if(void 0!==window.webkitIndexedDB)return window.webkitIndexedDB;if(void 0!==window.msIndexedDB)return window.msIndexedDB}return!1}function i(e){var n=r().open(h+e,1);return n.onupgradeneeded=function(e){e.target.result.createObjectStore(s,{keyPath:"id",autoIncrement:!0})},new Promise(function(e,t){n.onerror=function(e){return t(e)},n.onsuccess=function(){e(n.result)}})}function n(e,t,n){var r={uuid:t,time:(new Date).getTime(),data:n},o=e.transaction([s],"readwrite");return new Promise(function(e,t){o.oncomplete=function(){return e()},o.onerror=function(e){return t(e)},o.objectStore(s).add(r)})}function a(e,n){var r=e.transaction(s).objectStore(s),o=[];return new Promise(function(t){(function(){try{var e=IDBKeyRange.bound(n+1,1/0);return r.openCursor(e)}catch(e){return r.openCursor()}})().onsuccess=function(e){e=e.target.result;e?e.value.id<n+1?e.continue(n+1):(o.push(e.value),e.continue()):t(o)}})}function u(e,t){var n=e.transaction([s],"readwrite").objectStore(s).delete(t);return new Promise(function(e){n.onsuccess=function(){return e()}})}function c(e,t){var r=(new Date).getTime()-t,o=e.transaction(s).objectStore(s),i=[];return new Promise(function(n){o.openCursor().onsuccess=function(e){var t,e=e.target.result;e&&(t=e.value).time<r?(i.push(t),e.continue()):n(i)}})}function p(t,e){return c(t,e).then(function(e){return Promise.all(e.map(function(e){return u(t,e.id)}))})}function m(n,r){return r=(0,f.fillOptionsWithDefaults)(r),i(n).then(function(e){var t={closed:!1,lastCursorId:0,channelName:n,options:r,uuid:(0,o.randomToken)(),eMIs:new d.ObliviousSet(2*r.idb.ttl),writeBlockPromise:o.PROMISE_RESOLVED_VOID,messagesCallback:null,readQueuePromises:[],db:e};return e.onclose=function(){t.closed=!0,r.idb.onclose&&r.idb.onclose()},function e(t){if(t.closed)return;v(t).then(function(){return(0,o.sleep)(t.options.idb.fallbackInterval)}).then(function(){return e(t)})}(t),t})}function v(n){return!n.closed&&n.messagesCallback?a(n.db,n.lastCursorId).then(function(e){return e.filter(function(e){return!!e}).map(function(e){return e.id>n.lastCursorId&&(n.lastCursorId=e.id),e}).filter(function(e){return t=n,(e=e).uuid!==t.uuid&&(!t.eMIs.has(e.id)&&!(e.data.time<t.messagesCallbackTime));var t}).sort(function(e,t){return e.time-t.time}).forEach(function(e){n.messagesCallback&&(n.eMIs.add(e.id),n.messagesCallback(e.data))}),o.PROMISE_RESOLVED_VOID}):o.PROMISE_RESOLVED_VOID}function b(e){e.closed=!0,e.db.close()}function _(e,t){return e.writeBlockPromise=e.writeBlockPromise.then(function(){return n(e.db,e.uuid,t)}).then(function(){0===(0,o.randomInt)(0,10)&&p(e.db,e.options.idb.ttl)}),e.writeBlockPromise}function g(e,t,n){e.messagesCallbackTime=n,e.messagesCallback=t,v(e)}function y(){return!o.isNode&&!!r()}function w(e){return 2*e.idb.fallbackInterval}t.type="idb",t.default={create:m,close:b,onMessage:g,postMessage:_,canBeUsed:y,type:"idb",averageResponseTime:w,microSeconds:e}},{"../options":11,"../util.js":12,"oblivious-set":17}],8:[function(e,l,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.addStorageEventListener=i,t.averageResponseTime=b,t.canBeUsed=c,t.close=m,t.create=p,t.default=void 0,t.getLocalStorage=a,t.microSeconds=void 0,t.onMessage=v,t.postMessage=r,t.removeStorageEventListener=h,t.storageKey=u,t.type=void 0;var d=e("oblivious-set"),f=e("../options"),s=e("../util"),e=s.microSeconds,o=(t.microSeconds=e,"pubkey.broadcastChannel-"),n="localstorage";function a(){var e;if("undefined"==typeof window)return null;try{e=window.localStorage,e=window["ie8-eventlistener/storage"]||window.localStorage}catch(e){}return e}function u(e){return o+e}function r(o,i){return new Promise(function(r){(0,s.sleep)().then(function(){var e=u(o.channelName),t={token:(0,s.randomToken)(),time:(new Date).getTime(),data:i,uuid:o.uuid},t=JSON.stringify(t),n=(a().setItem(e,t),document.createEvent("Event"));n.initEvent("storage",!0,!0),n.key=e,n.newValue=t,window.dispatchEvent(n),r()})})}function i(e,t){function n(e){e.key===r&&t(JSON.parse(e.newValue))}var r=o+e;return window.addEventListener("storage",n),n}function h(e){window.removeEventListener("storage",e)}function p(e,t){if(t=(0,f.fillOptionsWithDefaults)(t),!c())throw new Error("BroadcastChannel: localstorage cannot be used");var n=(0,s.randomToken)(),r=new d.ObliviousSet(t.localstorage.removeTimeout),o={channelName:e,uuid:n,eMIs:r};return o.listener=i(e,function(e){o.messagesCallback&&e.uuid!==n&&e.token&&!r.has(e.token)&&(e.data.time&&e.data.time<o.messagesCallbackTime||(r.add(e.token),o.messagesCallback(e.data)))}),o}function m(e){h(e.listener)}function v(e,t,n){e.messagesCallbackTime=n,e.messagesCallback=t}function c(){if(s.isNode)return!1;var e=a();if(!e)return!1;try{var t="__broadcastchannel_check";e.setItem(t,"works"),e.removeItem(t)}catch(e){return!1}return!0}function b(){var e=navigator.userAgent.toLowerCase();return e.includes("safari")&&!e.includes("chrome")?240:120}t.type=n,t.default={create:p,close:m,onMessage:v,postMessage:r,canBeUsed:c,type:n,averageResponseTime:b,microSeconds:e}},{"../options":11,"../util":12,"oblivious-set":17}],9:[function(e,c,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.averageResponseTime=u,t.canBeUsed=a,t.close=o,t.create=r,t.microSeconds=t.default=void 0,t.onMessage=s,t.postMessage=i,t.type=void 0;var n=e("../util"),e=n.microSeconds;t.microSeconds=e;function r(e){var t={messagesCallback:null,bc:new BroadcastChannel(e),subFns:[]};return t.bc.onmessage=function(e){t.messagesCallback&&t.messagesCallback(e.data)},t}function o(e){e.bc.close(),e.subFns=[]}function i(e,t){try{return e.bc.postMessage(t,!1),n.PROMISE_RESOLVED_VOID}catch(e){return Promise.reject(e)}}function s(e,t){e.messagesCallback=t}function a(){if(n.isNode&&"undefined"==typeof window)return!1;if("function"!=typeof BroadcastChannel)return!1;if(BroadcastChannel._pubkey)throw new Error("BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill");return!0}function u(){return 150}t.type="native",t.default={create:r,close:o,onMessage:s,postMessage:i,canBeUsed:a,type:"native",averageResponseTime:u,microSeconds:e}},{"../util":12}],10:[function(e,l,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.averageResponseTime=c,t.canBeUsed=u,t.close=i,t.create=o,t.microSeconds=t.default=void 0,t.onMessage=a,t.postMessage=s,t.type=void 0;var e=e("../util").microSeconds,n=(t.microSeconds=e,"simulate"),r=(t.type=n,new Set);function o(e){e={name:e,messagesCallback:null};return r.add(e),e}function i(e){r.delete(e)}function s(t,n){return new Promise(function(e){return setTimeout(function(){Array.from(r).filter(function(e){return e.name===t.name}).filter(function(e){return e!==t}).filter(function(e){return!!e.messagesCallback}).forEach(function(e){return e.messagesCallback(n)}),e()},5)})}function a(e,t){e.messagesCallback=t}function u(){return!0}function c(){return 5}t.default={create:o,close:i,onMessage:a,postMessage:s,canBeUsed:u,type:n,averageResponseTime:c,microSeconds:e}},{"../util":12}],11:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.fillOptionsWithDefaults=function(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},t=JSON.parse(JSON.stringify(e));void 0===t.webWorkerSupport&&(t.webWorkerSupport=!0);t.idb||(t.idb={});t.idb.ttl||(t.idb.ttl=45e3);t.idb.fallbackInterval||(t.idb.fallbackInterval=150);e.idb&&"function"==typeof e.idb.onclose&&(t.idb.onclose=e.idb.onclose);t.localstorage||(t.localstorage={});t.localstorage.removeTimeout||(t.localstorage.removeTimeout=6e4);e.methods&&(t.methods=e.methods);t.node||(t.node={});t.node.ttl||(t.node.ttl=12e4);t.node.maxParallelWrites||(t.node.maxParallelWrites=2048);void 0===t.node.useFastPath&&(t.node.useFastPath=!0);return t}},{}],12:[function(e,t,o){!function(r){!function(){"use strict";Object.defineProperty(o,"__esModule",{value:!0}),o.isNode=o.PROMISE_RESOLVED_VOID=o.PROMISE_RESOLVED_TRUE=o.PROMISE_RESOLVED_FALSE=void 0,o.isPromise=function(e){return!(!e||"function"!=typeof e.then)},o.microSeconds=function(){var e=(new Date).getTime();return e===t?1e3*e+ ++n:(n=0,1e3*(t=e))},o.randomInt=function(e,t){return Math.floor(Math.random()*(t-e+1)+e)},o.randomToken=function(){return Math.random().toString(36).substring(2)},o.sleep=function(t,n){t=t||0;return new Promise(function(e){return setTimeout(function(){return e(n)},t)})};var e=Promise.resolve(!1),e=(o.PROMISE_RESOLVED_FALSE=e,Promise.resolve(!0)),e=(o.PROMISE_RESOLVED_TRUE=e,Promise.resolve());o.PROMISE_RESOLVED_VOID=e;var t=0,n=0;e="[object process]"===Object.prototype.toString.call(void 0!==r?r:0);o.isNode=e}.call(this)}.call(this,e("_process"))},{_process:18}],13:[function(e,t,n){t.exports=function(e){return e&&e.__esModule?e:{default:e}},t.exports.__esModule=!0,t.exports.default=t.exports},{}],14:[function(e,t,n){function r(e){return t.exports=r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t.exports.__esModule=!0,t.exports.default=t.exports,r(e)}t.exports=r,t.exports.__esModule=!0,t.exports.default=t.exports},{}],15:[function(e,t,n){},{}],16:[function(e,t,n){t.exports=!1},{}],17:[function(e,t,n){"use strict";function r(e){this.ttl=e,this.set=new Set,this.timeMap=new Map}function o(e){for(var t=i()-e.ttl,n=e.set[Symbol.iterator]();;){var r=n.next().value;if(!r)return;if(!(e.timeMap.get(r)<t))return;e.timeMap.delete(r),e.set.delete(r)}}function i(){return(new Date).getTime()}Object.defineProperty(n,"__esModule",{value:!0}),n.now=n.removeTooOldValues=n.ObliviousSet=void 0,r.prototype.has=function(e){return this.set.has(e)},r.prototype.add=function(e){var t=this;this.timeMap.set(e,i()),this.set.add(e),setTimeout(function(){o(t)},0)},r.prototype.clear=function(){this.set.clear(),this.timeMap.clear()},n.ObliviousSet=r,n.removeTooOldValues=o,n.now=i},{}],18:[function(l,e,d){var n,r,e=e.exports={};function o(){throw new Error("setTimeout has not been defined")}function i(){throw new Error("clearTimeout has not been defined")}try{n="function"==typeof setTimeout?setTimeout:o}catch(e){n=o}try{r="function"==typeof clearTimeout?clearTimeout:i}catch(e){r=i}function f(t){if(n===setTimeout)return setTimeout(t,0);if((n===o||!n)&&setTimeout)return n=setTimeout,setTimeout(t,0);try{return n(t,0)}catch(e){try{return n.call(null,t,0)}catch(e){return n.call(this,t,0)}}}var s,a=[],u=!1,c=-1;function h(){u&&s&&(u=!1,s.length?a=s.concat(a):c=-1,a.length&&p())}function p(){if(!u){for(var e=f(h),t=(u=!0,a.length);t;){for(s=a,a=[];++c<t;)s&&s[c].run();c=-1,t=a.length}s=null,u=!1,function(t){if(r===clearTimeout)return clearTimeout(t);if((r===i||!r)&&clearTimeout)return r=clearTimeout,clearTimeout(t);try{r(t)}catch(e){try{return r.call(null,t)}catch(e){return r.call(this,t)}}}(e)}}function m(e,t){this.fun=e,this.array=t}function t(){}e.nextTick=function(e){var t=new Array(arguments.length-1);if(1<arguments.length)for(var n=1;n<arguments.length;n++)t[n-1]=arguments[n];a.push(new m(e,t)),1!==a.length||u||f(p)},m.prototype.run=function(){this.fun.apply(null,this.array)},e.title="browser",e.browser=!0,e.env={},e.argv=[],e.version="",e.versions={},e.on=t,e.addListener=t,e.once=t,e.off=t,e.removeListener=t,e.removeAllListeners=t,e.emit=t,e.prependListener=t,e.prependOnceListener=t,e.listeners=function(e){return[]},e.binding=function(e){throw new Error("process.binding is not supported")},e.cwd=function(){return"/"},e.chdir=function(e){throw new Error("process.chdir is not supported")},e.umask=function(){return 0}},{}],19:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.default=void 0,n.default={add:function(e){"function"==typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope||"function"==typeof window.addEventListener&&(window.addEventListener("beforeunload",function(){e()},!0),window.addEventListener("unload",function(){e()},!0))}}},{}],20:[function(e,t,n){"use strict";var r=e("@babel/runtime/helpers/interopRequireDefault"),n=(Object.defineProperty(n,"__esModule",{value:!0}),n.add=function(e){if(a||(a=!0,i.add(u)),"function"!=typeof e)throw new Error("Listener is no function");return s.add(e),{remove:function(){return s.delete(e)},run:function(){return s.delete(e),e()}}},n.getSize=function(){return s.size},n.removeAll=function(){s.clear()},n.runAll=u,r(e("detect-node"))),o=r(e("./browser.js")),r=r(e("./node.js")),i=(n.default?r:o).default,s=new Set,a=!1;function u(){var t=[];return s.forEach(function(e){t.push(e()),s.delete(e)}),Promise.all(t)}},{"./browser.js":19,"./node.js":15,"@babel/runtime/helpers/interopRequireDefault":13,"detect-node":16}]},{},[2]); | ||
!function r(o,i,s){function a(t,e){if(!i[t]){if(!o[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(u)return u(t,!0);throw(e=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",e}n=i[t]={exports:{}},o[t][0].call(n.exports,function(e){return a(o[t][1][e]||e)},n,n.exports,r,o,i,s)}return i[t].exports}for(var u="function"==typeof require&&require,e=0;e<s.length;e++)a(s[e]);return a}({1:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.OPEN_BROADCAST_CHANNELS=n.BroadcastChannel=void 0,n.clearNodeFolder=function(e){e=(0,a.fillOptionsWithDefaults)(e);e=(0,s.chooseMethod)(e);return"node"===e.type?e.clearNodeFolder().then(function(){return!0}):i.PROMISE_RESOLVED_FALSE},n.enforceOptions=function(e){o=e};function r(e,t){var n;this.id=c++,u.add(this),this.name=e,o&&(t=o),this.options=(0,a.fillOptionsWithDefaults)(t),this.method=(0,s.chooseMethod)(this.options),this._iL=!1,this._onML=null,this._addEL={message:[],internal:[]},this._uMP=new Set,this._befC=[],this._prepP=null,e=(n=this).method.create(n.name,n.options),(0,i.isPromise)(e)?(n._prepP=e).then(function(e){n._state=e}):n._state=e}var o,i=e("./util.js"),s=e("./method-chooser.js"),a=e("./options.js"),u=new Set,c=(n.OPEN_BROADCAST_CHANNELS=u,0);function l(t,e,n){var r={time:t.method.microSeconds(),type:e,data:n};return(t._prepP||i.PROMISE_RESOLVED_VOID).then(function(){var e=t.method.postMessage(t._state,r);return t._uMP.add(e),e.catch().then(function(){return t._uMP.delete(e)}),e})}function d(e){return 0<e._addEL.message.length||0<e._addEL.internal.length}function f(e,t,n){e._addEL[t].push(n);var r,o,i=e;!i._iL&&d(i)&&(r=function(n){i._addEL[n.type].forEach(function(e){var t=e.time-1e5;n.time>=t&&e.fn(n.data)})},o=i.method.microSeconds(),i._prepP?i._prepP.then(function(){i._iL=!0,i.method.onMessage(i._state,r,o)}):(i._iL=!0,i.method.onMessage(i._state,r,o)))}function h(e,t,n){e._addEL[t]=e._addEL[t].filter(function(e){return e!==n});t=e;t._iL&&!d(t)&&(t._iL=!1,e=t.method.microSeconds(),t.method.onMessage(t._state,null,e))}(n.BroadcastChannel=r)._pubkey=!0,r.prototype={postMessage:function(e){if(this.closed)throw new Error("BroadcastChannel.postMessage(): Cannot post message after channel has closed "+JSON.stringify(e));return l(this,"message",e)},postInternal:function(e){return l(this,"internal",e)},set onmessage(e){var t={time:this.method.microSeconds(),fn:e};h(this,"message",this._onML),e&&"function"==typeof e?(this._onML=t,f(this,"message",t)):this._onML=null},addEventListener:function(e,t){var n=this.method.microSeconds();f(this,e,{time:n,fn:t})},removeEventListener:function(e,t){var n=this._addEL[e].find(function(e){return e.fn===t});h(this,e,n)},close:function(){var e,t=this;if(!this.closed)return u.delete(this),this.closed=!0,e=this._prepP||i.PROMISE_RESOLVED_VOID,this._onML=null,this._addEL.message=[],e.then(function(){return Promise.all(Array.from(t._uMP))}).then(function(){return Promise.all(t._befC.map(function(e){return e()}))}).then(function(){return t.method.close(t._state)})},get type(){return this.method.type},get isClosed(){return this.closed}}},{"./method-chooser.js":6,"./options.js":11,"./util.js":12}],2:[function(e,t,n){"use strict";var e=e("./index.es5.js"),r=e.BroadcastChannel,e=e.createLeaderElection;window.BroadcastChannel2=r,window.createLeaderElection=e},{"./index.es5.js":3}],3:[function(e,t,n){"use strict";e=e("./index.js");t.exports={BroadcastChannel:e.BroadcastChannel,createLeaderElection:e.createLeaderElection,clearNodeFolder:e.clearNodeFolder,enforceOptions:e.enforceOptions,beLeader:e.beLeader}},{"./index.js":4}],4:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),Object.defineProperty(n,"BroadcastChannel",{enumerable:!0,get:function(){return r.BroadcastChannel}}),Object.defineProperty(n,"OPEN_BROADCAST_CHANNELS",{enumerable:!0,get:function(){return r.OPEN_BROADCAST_CHANNELS}}),Object.defineProperty(n,"beLeader",{enumerable:!0,get:function(){return o.beLeader}}),Object.defineProperty(n,"clearNodeFolder",{enumerable:!0,get:function(){return r.clearNodeFolder}}),Object.defineProperty(n,"createLeaderElection",{enumerable:!0,get:function(){return o.createLeaderElection}}),Object.defineProperty(n,"enforceOptions",{enumerable:!0,get:function(){return r.enforceOptions}});var r=e("./broadcast-channel"),o=e("./leader-election")},{"./broadcast-channel":1,"./leader-election":5}],5:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.beLeader=l,n.createLeaderElection=function(e,t){if(e._leaderElector)throw new Error("BroadcastChannel already has a leader-elector");t=function(e,t){e=e||{};(e=JSON.parse(JSON.stringify(e))).fallbackInterval||(e.fallbackInterval=3e3);e.responseTime||(e.responseTime=t.method.averageResponseTime(t.options));return e}(t,e);var n=new o(e,t);return e._befC.push(function(){return n.die()}),e._leaderElector=n};var u=e("./util.js"),r=e("unload"),o=function(e,t){function n(e){"leader"===e.context&&("death"===e.action&&(r.hasLeader=!1),"tell"===e.action&&(r.hasLeader=!0))}var r=this;this.broadcastChannel=e,this._options=t,this.isLeader=!1,this.hasLeader=!1,this.isDead=!1,this.token=(0,u.randomToken)(),this._aplQ=u.PROMISE_RESOLVED_VOID,this._aplQC=0,this._unl=[],this._lstns=[],this._dpL=function(){},this._dpLC=!1;this.broadcastChannel.addEventListener("internal",n),this._lstns.push(n)};function c(e,t){t={context:"leader",action:t,token:e.token};return e.broadcastChannel.postInternal(t)}function l(t){t.isLeader=!0,t.hasLeader=!0;function e(e){"leader"===e.context&&"apply"===e.action&&c(t,"tell"),"leader"!==e.context||"tell"!==e.action||t._dpLC||(t._dpLC=!0,t._dpL(),c(t,"tell"))}var n=(0,r.add)(function(){return t.die()});t._unl.push(n);return t.broadcastChannel.addEventListener("internal",e),t._lstns.push(e),c(t,"tell")}o.prototype={applyOnce:function(s){var a=this;if(this.isLeader)return(0,u.sleep)(0,!0);if(this.isDead)return(0,u.sleep)(0,!1);if(1<this._aplQC)return this._aplQ;function e(){if(a.isLeader)return u.PROMISE_RESOLVED_TRUE;function e(e){"leader"===e.context&&e.token!=a.token&&(o.push(e),"apply"===e.action&&e.token>a.token&&t(),"tell"===e.action&&(t(),a.hasLeader=!0))}var t,n=!1,r=new Promise(function(e){t=function(){n=!0,e()}}),o=[],i=(a.broadcastChannel.addEventListener("internal",e),s?4*a._options.responseTime:a._options.responseTime);return c(a,"apply").then(function(){return Promise.race([(0,u.sleep)(i),r.then(function(){return Promise.reject(new Error)})])}).then(function(){return c(a,"apply")}).then(function(){return Promise.race([(0,u.sleep)(i),r.then(function(){return Promise.reject(new Error)})])}).catch(function(){}).then(function(){return a.broadcastChannel.removeEventListener("internal",e),!n&&l(a).then(function(){return!0})})}return this._aplQC=this._aplQC+1,this._aplQ=this._aplQ.then(e).then(function(){a._aplQC=a._aplQC-1}),this._aplQ.then(function(){return a.isLeader})},awaitLeadership:function(){return this._aLP||(this._aLP=function(o){if(o.isLeader)return u.PROMISE_RESOLVED_VOID;return new Promise(function(e){var t=!1;function n(){t||(t=!0,o.broadcastChannel.removeEventListener("internal",r),e(!0))}o.applyOnce().then(function(){o.isLeader&&n()});(function e(){return(0,u.sleep)(o._options.fallbackInterval).then(function(){if(!o.isDead&&!t)return o.isLeader?void n():o.applyOnce(!0).then(function(){(o.isLeader?n:e)()})})})();var r=function(e){"leader"===e.context&&"death"===e.action&&(o.hasLeader=!1,o.applyOnce().then(function(){o.isLeader&&n()}))};o.broadcastChannel.addEventListener("internal",r),o._lstns.push(r)})}(this)),this._aLP},set onduplicate(e){this._dpL=e},die:function(){var t=this;return this._lstns.forEach(function(e){return t.broadcastChannel.removeEventListener("internal",e)}),this._lstns=[],this._unl.forEach(function(e){return e.remove()}),this._unl=[],this.isLeader&&(this.hasLeader=!1,this.isLeader=!1),this.isDead=!0,c(this,"death")}}},{"./util.js":12,unload:20}],6:[function(e,t,n){"use strict";var r=e("@babel/runtime/helpers/interopRequireDefault"),n=(e("@babel/runtime/helpers/typeof"),Object.defineProperty(n,"__esModule",{value:!0}),n.chooseMethod=function(t){var e=[].concat(t.methods,u).filter(Boolean);if(t.type){if("simulate"===t.type)return s.default;var n=e.find(function(e){return e.type===t.type});if(n)return n;throw new Error("method-type "+t.type+" not found")}t.webWorkerSupport||a.isNode||(e=e.filter(function(e){return"idb"!==e.type}));n=e.find(function(e){return e.canBeUsed()});{if(n)return n;throw new Error("No useable method found in "+JSON.stringify(u.map(function(e){return e.type})))}},r(e("./methods/native.js"))),o=r(e("./methods/indexed-db.js")),i=r(e("./methods/localstorage.js")),s=r(e("./methods/simulate.js")),a=e("./util");var u=[n.default,o.default,i.default]},{"./methods/indexed-db.js":7,"./methods/localstorage.js":8,"./methods/native.js":9,"./methods/simulate.js":10,"./util":12,"@babel/runtime/helpers/interopRequireDefault":13,"@babel/runtime/helpers/typeof":14}],7:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.TRANSACTION_SETTINGS=void 0,n.averageResponseTime=S,n.canBeUsed=E,n.cleanOldMessages=v,n.close=g,n.commitIndexedDBTransaction=d,n.create=b,n.createDatabase=u,n.default=void 0,n.getAllMessages=function(e){var n=e.transaction(c,"readonly",l),r=n.objectStore(c),o=[];return new Promise(function(t){r.openCursor().onsuccess=function(e){e=e.target.result;e?(o.push(e.value),e.continue()):(d(n),t(o))}})},n.getIdb=a,n.getMessagesHigherThan=h,n.getOldMessages=m,n.microSeconds=void 0,n.onMessage=w,n.postMessage=y,n.removeMessagesById=p,n.type=void 0,n.writeMessage=f;var o=e("../util.js"),i=e("oblivious-set"),s=e("../options"),e=o.microSeconds,r=(n.microSeconds=e,"pubkey.broadcast-channel-0-"),c="messages",l={durability:"relaxed"};n.TRANSACTION_SETTINGS=l;function a(){if("undefined"!=typeof indexedDB)return indexedDB;if("undefined"!=typeof window){if(void 0!==window.mozIndexedDB)return window.mozIndexedDB;if(void 0!==window.webkitIndexedDB)return window.webkitIndexedDB;if(void 0!==window.msIndexedDB)return window.msIndexedDB}return!1}function d(e){e.commit&&e.commit()}function u(e){var n=a().open(r+e);return n.onupgradeneeded=function(e){e.target.result.createObjectStore(c,{keyPath:"id",autoIncrement:!0})},new Promise(function(e,t){n.onerror=function(e){return t(e)},n.onsuccess=function(){e(n.result)}})}function f(e,t,n){var r={uuid:t,time:(new Date).getTime(),data:n},o=e.transaction([c],"readwrite",l);return new Promise(function(e,t){o.oncomplete=function(){return e()},o.onerror=function(e){return t(e)},o.objectStore(c).add(r),d(o)})}function h(e,r){var o,i=e.transaction(c,"readonly",l),s=i.objectStore(c),a=[],u=IDBKeyRange.bound(r+1,1/0);return s.getAll?(o=s.getAll(u),new Promise(function(t,n){o.onerror=function(e){return n(e)},o.onsuccess=function(e){t(e.target.result)}})):new Promise(function(t,n){var e=function(){try{return u=IDBKeyRange.bound(r+1,1/0),s.openCursor(u)}catch(e){return s.openCursor()}}();e.onerror=function(e){return n(e)},e.onsuccess=function(e){e=e.target.result;e?e.value.id<r+1?e.continue(r+1):(a.push(e.value),e.continue()):(d(i),t(a))}})}function p(e,t){var n=e.transaction([c],"readwrite",l).objectStore(c);return Promise.all(t.map(function(e){var t=n.delete(e);return new Promise(function(e){t.onsuccess=function(){return e()}})}))}function m(e,t){var r=(new Date).getTime()-t,o=e.transaction(c,"readonly",l),i=o.objectStore(c),s=[];return new Promise(function(n){i.openCursor().onsuccess=function(e){var t,e=e.target.result;e?(t=e.value).time<r?(s.push(t),e.continue()):(d(o),n(s)):n(s)}})}function v(t,e){return m(t,e).then(function(e){return p(t,e.map(function(e){return e.id}))})}function b(n,r){return r=(0,s.fillOptionsWithDefaults)(r),u(n).then(function(e){var t={closed:!1,lastCursorId:0,channelName:n,options:r,uuid:(0,o.randomToken)(),eMIs:new i.ObliviousSet(2*r.idb.ttl),writeBlockPromise:o.PROMISE_RESOLVED_VOID,messagesCallback:null,readQueuePromises:[],db:e};return e.onclose=function(){t.closed=!0,r.idb.onclose&&r.idb.onclose()},function e(t){if(t.closed)return;_(t).then(function(){return(0,o.sleep)(t.options.idb.fallbackInterval)}).then(function(){return e(t)})}(t),t})}function _(n){return!n.closed&&n.messagesCallback?h(n.db,n.lastCursorId).then(function(e){return e.filter(function(e){return!!e}).map(function(e){return e.id>n.lastCursorId&&(n.lastCursorId=e.id),e}).filter(function(e){return t=n,(e=e).uuid!==t.uuid&&(!t.eMIs.has(e.id)&&!(e.data.time<t.messagesCallbackTime));var t}).sort(function(e,t){return e.time-t.time}).forEach(function(e){n.messagesCallback&&(n.eMIs.add(e.id),n.messagesCallback(e.data))}),o.PROMISE_RESOLVED_VOID}):o.PROMISE_RESOLVED_VOID}function g(e){e.closed=!0,e.db.close()}function y(e,t){return e.writeBlockPromise=e.writeBlockPromise.then(function(){return f(e.db,e.uuid,t)}).then(function(){0===(0,o.randomInt)(0,10)&&v(e.db,e.options.idb.ttl)}),e.writeBlockPromise}function w(e,t,n){e.messagesCallbackTime=n,e.messagesCallback=t,_(e)}function E(){return!o.isNode&&!!a()}function S(e){return 2*e.idb.fallbackInterval}n.type="idb",n.default={create:b,close:g,onMessage:w,postMessage:y,canBeUsed:E,type:"idb",averageResponseTime:S,microSeconds:e}},{"../options":11,"../util.js":12,"oblivious-set":17}],8:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.addStorageEventListener=d,n.averageResponseTime=b,n.canBeUsed=v,n.close=p,n.create=h,n.default=void 0,n.getLocalStorage=u,n.microSeconds=void 0,n.onMessage=m,n.postMessage=l,n.removeStorageEventListener=f,n.storageKey=c,n.type=void 0;var i=e("oblivious-set"),s=e("../options"),a=e("../util"),e=a.microSeconds,o=(n.microSeconds=e,"pubkey.broadcastChannel-"),r="localstorage";function u(){var e;if("undefined"==typeof window)return null;try{e=window.localStorage,e=window["ie8-eventlistener/storage"]||window.localStorage}catch(e){}return e}function c(e){return o+e}function l(o,i){return new Promise(function(r){(0,a.sleep)().then(function(){var e=c(o.channelName),t={token:(0,a.randomToken)(),time:(new Date).getTime(),data:i,uuid:o.uuid},t=JSON.stringify(t),n=(u().setItem(e,t),document.createEvent("Event"));n.initEvent("storage",!0,!0),n.key=e,n.newValue=t,window.dispatchEvent(n),r()})})}function d(e,t){function n(e){e.key===r&&t(JSON.parse(e.newValue))}var r=o+e;return window.addEventListener("storage",n),n}function f(e){window.removeEventListener("storage",e)}function h(e,t){if(t=(0,s.fillOptionsWithDefaults)(t),!v())throw new Error("BroadcastChannel: localstorage cannot be used");var n=(0,a.randomToken)(),r=new i.ObliviousSet(t.localstorage.removeTimeout),o={channelName:e,uuid:n,eMIs:r};return o.listener=d(e,function(e){!o.messagesCallback||e.uuid===n||!e.token||r.has(e.token)||e.data.time&&e.data.time<o.messagesCallbackTime||(r.add(e.token),o.messagesCallback(e.data))}),o}function p(e){f(e.listener)}function m(e,t,n){e.messagesCallbackTime=n,e.messagesCallback=t}function v(){if(a.isNode)return!1;var e=u();if(!e)return!1;try{var t="__broadcastchannel_check";e.setItem(t,"works"),e.removeItem(t)}catch(e){return!1}return!0}function b(){var e=navigator.userAgent.toLowerCase();return e.includes("safari")&&!e.includes("chrome")?240:120}n.type=r,n.default={create:h,close:p,onMessage:m,postMessage:l,canBeUsed:v,type:r,averageResponseTime:b,microSeconds:e}},{"../options":11,"../util":12,"oblivious-set":17}],9:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.averageResponseTime=c,n.canBeUsed=u,n.close=i,n.create=o,n.microSeconds=n.default=void 0,n.onMessage=a,n.postMessage=s,n.type=void 0;var r=e("../util"),e=r.microSeconds;n.microSeconds=e;function o(e){var t={messagesCallback:null,bc:new BroadcastChannel(e),subFns:[]};return t.bc.onmessage=function(e){t.messagesCallback&&t.messagesCallback(e.data)},t}function i(e){e.bc.close(),e.subFns=[]}function s(e,t){try{return e.bc.postMessage(t,!1),r.PROMISE_RESOLVED_VOID}catch(e){return Promise.reject(e)}}function a(e,t){e.messagesCallback=t}function u(){if(r.isNode&&"undefined"==typeof window)return!1;if("function"!=typeof BroadcastChannel)return!1;if(BroadcastChannel._pubkey)throw new Error("BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill");return!0}function c(){return 150}n.type="native",n.default={create:o,close:i,onMessage:a,postMessage:s,canBeUsed:u,type:"native",averageResponseTime:c,microSeconds:e}},{"../util":12}],10:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.averageResponseTime=l,n.canBeUsed=c,n.close=s,n.create=i,n.microSeconds=n.default=void 0,n.onMessage=u,n.postMessage=a,n.type=void 0;var e=e("../util").microSeconds,r=(n.microSeconds=e,"simulate"),o=(n.type=r,new Set);function i(e){e={name:e,messagesCallback:null};return o.add(e),e}function s(e){o.delete(e)}function a(t,n){return new Promise(function(e){return setTimeout(function(){Array.from(o).filter(function(e){return e.name===t.name}).filter(function(e){return e!==t}).filter(function(e){return!!e.messagesCallback}).forEach(function(e){return e.messagesCallback(n)}),e()},5)})}function u(e,t){e.messagesCallback=t}function c(){return!0}function l(){return 5}n.default={create:i,close:s,onMessage:u,postMessage:a,canBeUsed:c,type:r,averageResponseTime:l,microSeconds:e}},{"../util":12}],11:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.fillOptionsWithDefaults=function(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},t=JSON.parse(JSON.stringify(e));void 0===t.webWorkerSupport&&(t.webWorkerSupport=!0);t.idb||(t.idb={});t.idb.ttl||(t.idb.ttl=45e3);t.idb.fallbackInterval||(t.idb.fallbackInterval=150);e.idb&&"function"==typeof e.idb.onclose&&(t.idb.onclose=e.idb.onclose);t.localstorage||(t.localstorage={});t.localstorage.removeTimeout||(t.localstorage.removeTimeout=6e4);e.methods&&(t.methods=e.methods);t.node||(t.node={});t.node.ttl||(t.node.ttl=12e4);t.node.maxParallelWrites||(t.node.maxParallelWrites=2048);void 0===t.node.useFastPath&&(t.node.useFastPath=!0);return t}},{}],12:[function(e,t,o){!function(r){!function(){"use strict";Object.defineProperty(o,"__esModule",{value:!0}),o.isNode=o.PROMISE_RESOLVED_VOID=o.PROMISE_RESOLVED_TRUE=o.PROMISE_RESOLVED_FALSE=void 0,o.isPromise=function(e){return!(!e||"function"!=typeof e.then)},o.microSeconds=function(){var e=(new Date).getTime();return e===t?1e3*e+ ++n:(n=0,1e3*(t=e))},o.randomInt=function(e,t){return Math.floor(Math.random()*(t-e+1)+e)},o.randomToken=function(){return Math.random().toString(36).substring(2)},o.sleep=function(t,n){t=t||0;return new Promise(function(e){return setTimeout(function(){return e(n)},t)})};var e=Promise.resolve(!1),e=(o.PROMISE_RESOLVED_FALSE=e,Promise.resolve(!0)),e=(o.PROMISE_RESOLVED_TRUE=e,Promise.resolve());o.PROMISE_RESOLVED_VOID=e;var t=0,n=0;e="[object process]"===Object.prototype.toString.call(void 0!==r?r:0);o.isNode=e}.call(this)}.call(this,e("_process"))},{_process:18}],13:[function(e,t,n){t.exports=function(e){return e&&e.__esModule?e:{default:e}},t.exports.__esModule=!0,t.exports.default=t.exports},{}],14:[function(e,t,n){function r(e){return t.exports=r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t.exports.__esModule=!0,t.exports.default=t.exports,r(e)}t.exports=r,t.exports.__esModule=!0,t.exports.default=t.exports},{}],15:[function(e,t,n){},{}],16:[function(e,t,n){t.exports=!1},{}],17:[function(e,t,n){"use strict";function r(e){this.ttl=e,this.set=new Set,this.timeMap=new Map}function o(e){for(var t=i()-e.ttl,n=e.set[Symbol.iterator]();;){var r=n.next().value;if(!r)return;if(!(e.timeMap.get(r)<t))return;e.timeMap.delete(r),e.set.delete(r)}}function i(){return(new Date).getTime()}Object.defineProperty(n,"__esModule",{value:!0}),n.now=n.removeTooOldValues=n.ObliviousSet=void 0,r.prototype.has=function(e){return this.set.has(e)},r.prototype.add=function(e){var t=this;this.timeMap.set(e,i()),this.set.add(e),setTimeout(function(){o(t)},0)},r.prototype.clear=function(){this.set.clear(),this.timeMap.clear()},n.ObliviousSet=r,n.removeTooOldValues=o,n.now=i},{}],18:[function(e,t,n){var r,o,t=t.exports={};function i(){throw new Error("setTimeout has not been defined")}function s(){throw new Error("clearTimeout has not been defined")}try{r="function"==typeof setTimeout?setTimeout:i}catch(e){r=i}try{o="function"==typeof clearTimeout?clearTimeout:s}catch(e){o=s}function a(t){if(r===setTimeout)return setTimeout(t,0);if((r===i||!r)&&setTimeout)return(r=setTimeout)(t,0);try{return r(t,0)}catch(e){try{return r.call(null,t,0)}catch(e){return r.call(this,t,0)}}}var u,c=[],l=!1,d=-1;function f(){l&&u&&(l=!1,u.length?c=u.concat(c):d=-1,c.length&&h())}function h(){if(!l){for(var e=a(f),t=(l=!0,c.length);t;){for(u=c,c=[];++d<t;)u&&u[d].run();d=-1,t=c.length}u=null,l=!1,!function(t){if(o===clearTimeout)return clearTimeout(t);if((o===s||!o)&&clearTimeout)return(o=clearTimeout)(t);try{o(t)}catch(e){try{return o.call(null,t)}catch(e){return o.call(this,t)}}}(e)}}function p(e,t){this.fun=e,this.array=t}function m(){}t.nextTick=function(e){var t=new Array(arguments.length-1);if(1<arguments.length)for(var n=1;n<arguments.length;n++)t[n-1]=arguments[n];c.push(new p(e,t)),1!==c.length||l||a(h)},p.prototype.run=function(){this.fun.apply(null,this.array)},t.title="browser",t.browser=!0,t.env={},t.argv=[],t.version="",t.versions={},t.on=m,t.addListener=m,t.once=m,t.off=m,t.removeListener=m,t.removeAllListeners=m,t.emit=m,t.prependListener=m,t.prependOnceListener=m,t.listeners=function(e){return[]},t.binding=function(e){throw new Error("process.binding is not supported")},t.cwd=function(){return"/"},t.chdir=function(e){throw new Error("process.chdir is not supported")},t.umask=function(){return 0}},{}],19:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.default=void 0,n.default={add:function(e){"function"==typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope||"function"==typeof window.addEventListener&&(window.addEventListener("beforeunload",function(){e()},!0),window.addEventListener("unload",function(){e()},!0))}}},{}],20:[function(e,t,n){"use strict";var r=e("@babel/runtime/helpers/interopRequireDefault"),n=(Object.defineProperty(n,"__esModule",{value:!0}),n.add=function(e){if(a||(a=!0,i.add(u)),"function"!=typeof e)throw new Error("Listener is no function");return s.add(e),{remove:function(){return s.delete(e)},run:function(){return s.delete(e),e()}}},n.getSize=function(){return s.size},n.removeAll=function(){s.clear()},n.runAll=u,r(e("detect-node"))),o=r(e("./browser.js")),r=r(e("./node.js")),i=(n.default?r:o).default,s=new Set,a=!1;function u(){var t=[];return s.forEach(function(e){t.push(e()),s.delete(e)}),Promise.all(t)}},{"./browser.js":19,"./node.js":15,"@babel/runtime/helpers/interopRequireDefault":13,"detect-node":16}]},{},[2]); |
@@ -6,2 +6,3 @@ "use strict"; | ||
}); | ||
exports.TRANSACTION_SETTINGS = void 0; | ||
exports.averageResponseTime = averageResponseTime; | ||
@@ -11,2 +12,3 @@ exports.canBeUsed = canBeUsed; | ||
exports.close = close; | ||
exports.commitIndexedDBTransaction = commitIndexedDBTransaction; | ||
exports.create = create; | ||
@@ -22,3 +24,3 @@ exports.createDatabase = createDatabase; | ||
exports.postMessage = postMessage; | ||
exports.removeMessageById = removeMessageById; | ||
exports.removeMessagesById = removeMessagesById; | ||
exports.type = void 0; | ||
@@ -37,2 +39,5 @@ exports.writeMessage = writeMessage; | ||
* @link https://github.com/w3c/IndexedDB/issues/51 | ||
* | ||
* When working on this, ensure to use these performance optimizations: | ||
* @link https://rxdb.info/slow-indexeddb.html | ||
*/ | ||
@@ -43,2 +48,11 @@ var microSeconds = _util.microSeconds; | ||
var OBJECT_STORE_ID = 'messages'; | ||
/** | ||
* Use relaxed durability for faster performance on all transactions. | ||
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/ | ||
*/ | ||
var TRANSACTION_SETTINGS = { | ||
durability: 'relaxed' | ||
}; | ||
exports.TRANSACTION_SETTINGS = TRANSACTION_SETTINGS; | ||
var type = 'idb'; | ||
@@ -58,3 +72,15 @@ exports.type = type; | ||
} | ||
/** | ||
* If possible, we should explicitly commit IndexedDB transactions | ||
* for better performance. | ||
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/ | ||
*/ | ||
function commitIndexedDBTransaction(tx) { | ||
if (tx.commit) { | ||
tx.commit(); | ||
} | ||
} | ||
function createDatabase(channelName) { | ||
@@ -64,4 +90,10 @@ var IndexedDB = getIdb(); // create table | ||
var dbName = DB_PREFIX + channelName; | ||
var openRequest = IndexedDB.open(dbName, 1); | ||
/** | ||
* All IndexedDB databases are opened without version | ||
* because it is a bit faster, especially on firefox | ||
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version | ||
*/ | ||
var openRequest = IndexedDB.open(dbName); | ||
openRequest.onupgradeneeded = function (ev) { | ||
@@ -99,14 +131,15 @@ var db = ev.target.result; | ||
}; | ||
var transaction = db.transaction([OBJECT_STORE_ID], 'readwrite'); | ||
var tx = db.transaction([OBJECT_STORE_ID], 'readwrite', TRANSACTION_SETTINGS); | ||
return new Promise(function (res, rej) { | ||
transaction.oncomplete = function () { | ||
tx.oncomplete = function () { | ||
return res(); | ||
}; | ||
transaction.onerror = function (ev) { | ||
tx.onerror = function (ev) { | ||
return rej(ev); | ||
}; | ||
var objectStore = transaction.objectStore(OBJECT_STORE_ID); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
objectStore.add(writeObject); | ||
commitIndexedDBTransaction(tx); | ||
}); | ||
@@ -116,3 +149,4 @@ } | ||
function getAllMessages(db) { | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
@@ -128,2 +162,3 @@ return new Promise(function (res) { | ||
} else { | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -136,5 +171,25 @@ } | ||
function getMessagesHigherThan(db, lastCursorId) { | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
/** | ||
* Optimization shortcut, | ||
* if getAll() can be used, do not use a cursor. | ||
* @link https://rxdb.info/slow-indexeddb.html | ||
*/ | ||
if (objectStore.getAll) { | ||
var getAllRequest = objectStore.getAll(keyRangeValue); | ||
return new Promise(function (res, rej) { | ||
getAllRequest.onerror = function (err) { | ||
return rej(err); | ||
}; | ||
getAllRequest.onsuccess = function (e) { | ||
res(e.target.result); | ||
}; | ||
}); | ||
} | ||
function openCursor() { | ||
@@ -145,3 +200,3 @@ // Occasionally Safari will fail on IDBKeyRange.bound, this | ||
try { | ||
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
return objectStore.openCursor(keyRangeValue); | ||
@@ -153,4 +208,10 @@ } catch (e) { | ||
return new Promise(function (res) { | ||
openCursor().onsuccess = function (ev) { | ||
return new Promise(function (res, rej) { | ||
var openCursorRequest = openCursor(); | ||
openCursorRequest.onerror = function (err) { | ||
return rej(err); | ||
}; | ||
openCursorRequest.onsuccess = function (ev) { | ||
var cursor = ev.target.result; | ||
@@ -166,2 +227,3 @@ | ||
} else { | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -173,9 +235,13 @@ } | ||
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(); | ||
}; | ||
}); | ||
function removeMessagesById(db, ids) { | ||
var tx = db.transaction([OBJECT_STORE_ID], 'readwrite', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
return Promise.all(ids.map(function (id) { | ||
var deleteRequest = objectStore["delete"](id); | ||
return new Promise(function (res) { | ||
deleteRequest.onsuccess = function () { | ||
return res(); | ||
}; | ||
}); | ||
})); | ||
} | ||
@@ -185,3 +251,4 @@ | ||
var olderThen = new Date().getTime() - ttl; | ||
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
var tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
var objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
var ret = []; | ||
@@ -201,2 +268,3 @@ return new Promise(function (res) { | ||
// no more old messages, | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -214,4 +282,4 @@ return; | ||
return getOldMessages(db, ttl).then(function (tooOld) { | ||
return Promise.all(tooOld.map(function (msgObj) { | ||
return removeMessageById(db, msgObj.id); | ||
return removeMessagesById(db, tooOld.map(function (msg) { | ||
return msg.id; | ||
})); | ||
@@ -218,0 +286,0 @@ }); |
@@ -57,3 +57,3 @@ "use strict"; | ||
var _nanoTime = _interopRequireDefault(require("nano-time")); | ||
var _microtime = _interopRequireDefault(require("microtime")); | ||
@@ -125,3 +125,3 @@ var _rimraf = _interopRequireDefault(require("rimraf")); | ||
/** | ||
* because the lenght of socket-paths is limited, we use only the first 20 chars | ||
* because the length of socket-paths is limited, we use only the first 20 chars | ||
* and also start with A to ensure we do not start with a number | ||
@@ -138,3 +138,3 @@ * @link https://serverfault.com/questions/641347/check-if-a-path-exceeds-maximum-for-unix-domain-socket | ||
var folderPathMessages = _path["default"].join(channelPathBase, 'messages'); | ||
var folderPathMessages = _path["default"].join(channelPathBase, 'msgs'); | ||
@@ -1188,3 +1188,3 @@ var ret = { | ||
function microSeconds() { | ||
return parseInt(_nanoTime["default"].microseconds()); | ||
return parseInt(_microtime["default"].now()); | ||
} |
{ | ||
"name": "broadcast-channel", | ||
"version": "4.10.0", | ||
"version": "4.11.0", | ||
"description": "A BroadcastChannel that works in New Browsers, Old Browsers, WebWorkers and NodeJs", | ||
@@ -84,4 +84,3 @@ "exports": { | ||
"detect-node": "^2.1.0", | ||
"microseconds": "0.2.0", | ||
"nano-time": "1.0.0", | ||
"microtime": "3.0.0", | ||
"oblivious-set": "1.0.0", | ||
@@ -93,5 +92,5 @@ "p-queue": "6.6.2", | ||
"devDependencies": { | ||
"@babel/cli": "7.17.0", | ||
"@babel/core": "7.17.0", | ||
"@babel/plugin-proposal-object-rest-spread": "7.16.7", | ||
"@babel/cli": "7.17.6", | ||
"@babel/core": "7.17.9", | ||
"@babel/plugin-proposal-object-rest-spread": "7.17.3", | ||
"@babel/plugin-transform-member-expression-literals": "7.16.7", | ||
@@ -103,3 +102,3 @@ "@babel/plugin-transform-property-literals": "7.16.7", | ||
"@babel/types": "7.17.0", | ||
"@rollup/plugin-node-resolve": "13.1.3", | ||
"@rollup/plugin-node-resolve": "13.2.0", | ||
"@types/core-js": "2.5.5", | ||
@@ -111,15 +110,15 @@ "assert": "2.0.0", | ||
"clone": "2.1.2", | ||
"concurrently": "7.0.0", | ||
"concurrently": "7.1.0", | ||
"convert-hrtime": "5.0.0", | ||
"copyfiles": "2.4.1", | ||
"cross-env": "7.0.3", | ||
"eslint": "8.8.0", | ||
"eslint": "8.13.0", | ||
"gzip-size-cli": "5.1.0", | ||
"http-server": "14.1.0", | ||
"jest": "27.4.7", | ||
"karma": "6.3.13", | ||
"jest": "27.5.1", | ||
"karma": "6.3.17", | ||
"karma-babel-preprocessor": "8.0.2", | ||
"karma-browserify": "8.1.0", | ||
"karma-chrome-launcher": "3.1.0", | ||
"karma-coverage": "2.1.0", | ||
"karma-chrome-launcher": "3.1.1", | ||
"karma-coverage": "2.2.0", | ||
"karma-detect-browsers": "2.3.3", | ||
@@ -132,16 +131,16 @@ "karma-edge-launcher": "0.4.2", | ||
"karma-safari-launcher": "1.0.0", | ||
"mocha": "9.2.0", | ||
"mocha": "9.2.2", | ||
"pre-commit": "1.2.2", | ||
"random-int": "3.0.0", | ||
"random-token": "0.0.8", | ||
"rollup": "2.67.0", | ||
"rollup": "2.70.1", | ||
"rollup-plugin-terser": "7.0.2", | ||
"testcafe": "1.18.3", | ||
"ts-node": "10.4.0", | ||
"typescript": "4.5.5", | ||
"uglify-js": "3.15.0", | ||
"testcafe": "1.18.5", | ||
"ts-node": "10.7.0", | ||
"typescript": "4.6.3", | ||
"uglify-js": "3.15.4", | ||
"watchify": "4.0.0", | ||
"webpack": "5.68.0", | ||
"webpack": "5.72.0", | ||
"webpack-cli": "4.9.2" | ||
} | ||
} |
@@ -6,7 +6,5 @@ import { | ||
} from './util.js'; | ||
import { | ||
chooseMethod | ||
} from './method-chooser.js'; | ||
import { | ||
@@ -21,3 +19,2 @@ fillOptionsWithDefaults | ||
export const OPEN_BROADCAST_CHANNELS = new Set(); | ||
let lastId = 0; | ||
@@ -24,0 +21,0 @@ |
@@ -5,2 +5,5 @@ /** | ||
* @link https://github.com/w3c/IndexedDB/issues/51 | ||
* | ||
* When working on this, ensure to use these performance optimizations: | ||
* @link https://rxdb.info/slow-indexeddb.html | ||
*/ | ||
@@ -27,2 +30,8 @@ | ||
/** | ||
* Use relaxed durability for faster performance on all transactions. | ||
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/ | ||
*/ | ||
export const TRANSACTION_SETTINGS = { durability: 'relaxed' }; | ||
export const type = 'idb'; | ||
@@ -41,2 +50,15 @@ | ||
/** | ||
* If possible, we should explicitly commit IndexedDB transactions | ||
* for better performance. | ||
* @link https://nolanlawson.com/2021/08/22/speeding-up-indexeddb-reads-and-writes/ | ||
*/ | ||
export function commitIndexedDBTransaction(tx) { | ||
if (tx.commit) { | ||
tx.commit(); | ||
} | ||
} | ||
export function createDatabase(channelName) { | ||
@@ -47,4 +69,10 @@ const IndexedDB = getIdb(); | ||
const dbName = DB_PREFIX + channelName; | ||
const openRequest = IndexedDB.open(dbName, 1); | ||
/** | ||
* All IndexedDB databases are opened without version | ||
* because it is a bit faster, especially on firefox | ||
* @link http://nparashuram.com/IndexedDB/perf/#Open%20Database%20with%20version | ||
*/ | ||
const openRequest = IndexedDB.open(dbName); | ||
openRequest.onupgradeneeded = ev => { | ||
@@ -79,10 +107,11 @@ const db = ev.target.result; | ||
const transaction = db.transaction([OBJECT_STORE_ID], 'readwrite'); | ||
const tx = db.transaction([OBJECT_STORE_ID], 'readwrite', TRANSACTION_SETTINGS); | ||
return new Promise((res, rej) => { | ||
transaction.oncomplete = () => res(); | ||
transaction.onerror = ev => rej(ev); | ||
tx.oncomplete = () => res(); | ||
tx.onerror = ev => rej(ev); | ||
const objectStore = transaction.objectStore(OBJECT_STORE_ID); | ||
const objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
objectStore.add(writeObject); | ||
commitIndexedDBTransaction(tx); | ||
}); | ||
@@ -92,3 +121,5 @@ } | ||
export function getAllMessages(db) { | ||
const objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
const tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
const objectStore = tx | ||
.objectStore(OBJECT_STORE_ID); | ||
const ret = []; | ||
@@ -103,2 +134,3 @@ return new Promise(res => { | ||
} else { | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -111,5 +143,24 @@ } | ||
export function getMessagesHigherThan(db, lastCursorId) { | ||
const objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
const tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
const objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
const ret = []; | ||
let keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
/** | ||
* Optimization shortcut, | ||
* if getAll() can be used, do not use a cursor. | ||
* @link https://rxdb.info/slow-indexeddb.html | ||
*/ | ||
if (objectStore.getAll) { | ||
const getAllRequest = objectStore.getAll(keyRangeValue); | ||
return new Promise((res, rej) => { | ||
getAllRequest.onerror = err => rej(err); | ||
getAllRequest.onsuccess = function (e) { | ||
res(e.target.result); | ||
}; | ||
}); | ||
} | ||
function openCursor() { | ||
@@ -120,3 +171,3 @@ // Occasionally Safari will fail on IDBKeyRange.bound, this | ||
try { | ||
const keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity); | ||
return objectStore.openCursor(keyRangeValue); | ||
@@ -128,4 +179,6 @@ } catch (e) { | ||
return new Promise(res => { | ||
openCursor().onsuccess = ev => { | ||
return new Promise((res, rej) => { | ||
const openCursorRequest = openCursor(); | ||
openCursorRequest.onerror = err => rej(err); | ||
openCursorRequest.onsuccess = ev => { | ||
const cursor = ev.target.result; | ||
@@ -140,2 +193,3 @@ if (cursor) { | ||
} else { | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -147,9 +201,14 @@ } | ||
export function removeMessageById(db, id) { | ||
const request = db.transaction([OBJECT_STORE_ID], 'readwrite') | ||
.objectStore(OBJECT_STORE_ID) | ||
.delete(id); | ||
return new Promise(res => { | ||
request.onsuccess = () => res(); | ||
}); | ||
export function removeMessagesById(db, ids) { | ||
const tx = db.transaction([OBJECT_STORE_ID], 'readwrite', TRANSACTION_SETTINGS); | ||
const objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
return Promise.all( | ||
ids.map(id => { | ||
const deleteRequest = objectStore.delete(id); | ||
return new Promise(res => { | ||
deleteRequest.onsuccess = () => res(); | ||
}); | ||
}) | ||
); | ||
} | ||
@@ -159,3 +218,4 @@ | ||
const olderThen = new Date().getTime() - ttl; | ||
const objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID); | ||
const tx = db.transaction(OBJECT_STORE_ID, 'readonly', TRANSACTION_SETTINGS); | ||
const objectStore = tx.objectStore(OBJECT_STORE_ID); | ||
const ret = []; | ||
@@ -173,2 +233,3 @@ return new Promise(res => { | ||
// no more old messages, | ||
commitIndexedDBTransaction(tx); | ||
res(ret); | ||
@@ -187,4 +248,5 @@ return; | ||
.then(tooOld => { | ||
return Promise.all( | ||
tooOld.map(msgObj => removeMessageById(db, msgObj.id)) | ||
return removeMessagesById( | ||
db, | ||
tooOld.map(msg => msg.id) | ||
); | ||
@@ -191,0 +253,0 @@ }); |
@@ -13,3 +13,3 @@ /** | ||
import path from 'path'; | ||
import micro from 'nano-time'; | ||
import micro from 'microtime'; | ||
import rimraf from 'rimraf'; | ||
@@ -74,3 +74,3 @@ import isNode from 'detect-node'; | ||
/** | ||
* because the lenght of socket-paths is limited, we use only the first 20 chars | ||
* because the length of socket-paths is limited, we use only the first 20 chars | ||
* and also start with A to ensure we do not start with a number | ||
@@ -91,3 +91,3 @@ * @link https://serverfault.com/questions/641347/check-if-a-path-exceeds-maximum-for-unix-domain-socket | ||
channelPathBase, | ||
'messages' | ||
'msgs' | ||
); | ||
@@ -687,3 +687,3 @@ | ||
export function microSeconds() { | ||
return parseInt(micro.microseconds()); | ||
return parseInt(micro.now()); | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
507867
7
13169
+ Addedmicrotime@3.0.0
+ Addedmicrotime@3.0.0(transitive)
+ Addednode-addon-api@1.7.2(transitive)
+ Addednode-gyp-build@3.9.0(transitive)
- Removedmicroseconds@0.2.0
- Removednano-time@1.0.0
- Removedbig-integer@1.6.52(transitive)
- Removedmicroseconds@0.2.0(transitive)
- Removednano-time@1.0.0(transitive)