This commit is contained in:
Iliyan Angelov
2025-09-14 23:24:25 +03:00
commit c67067a2a4
71311 changed files with 6800714 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
/**
* if you really need this method,
* implement it
*/
"use strict";

View File

@@ -0,0 +1,350 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getIdb = getIdb;
exports.createDatabase = createDatabase;
exports.writeMessage = writeMessage;
exports.getAllMessages = getAllMessages;
exports.getMessagesHigherThan = getMessagesHigherThan;
exports.removeMessageById = removeMessageById;
exports.getOldMessages = getOldMessages;
exports.cleanOldMessages = cleanOldMessages;
exports.create = create;
exports.close = close;
exports.postMessage = postMessage;
exports.onMessage = onMessage;
exports.canBeUsed = canBeUsed;
exports.averageResponseTime = averageResponseTime;
exports["default"] = exports.type = exports.microSeconds = void 0;
var _util = require("../util.js");
var _obliviousSet = require("oblivious-set");
var _options = require("../options");
/**
* this method uses indexeddb to store the messages
* There is currently no observerAPI for idb
* @link https://github.com/w3c/IndexedDB/issues/51
*/
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var DB_PREFIX = 'pubkey.broadcast-channel-0-';
var OBJECT_STORE_ID = 'messages';
var type = 'idb';
exports.type = type;
function getIdb() {
if (typeof indexedDB !== 'undefined') return indexedDB;
if (typeof window !== 'undefined') {
if (typeof window.mozIndexedDB !== 'undefined') return window.mozIndexedDB;
if (typeof window.webkitIndexedDB !== 'undefined') return window.webkitIndexedDB;
if (typeof window.msIndexedDB !== 'undefined') return window.msIndexedDB;
}
return false;
}
function createDatabase(channelName) {
var IndexedDB = getIdb(); // create table
var dbName = DB_PREFIX + channelName;
var openRequest = IndexedDB.open(dbName, 1);
openRequest.onupgradeneeded = function (ev) {
var db = ev.target.result;
db.createObjectStore(OBJECT_STORE_ID, {
keyPath: 'id',
autoIncrement: true
});
};
var dbPromise = new Promise(function (res, rej) {
openRequest.onerror = function (ev) {
return rej(ev);
};
openRequest.onsuccess = function () {
res(openRequest.result);
};
});
return dbPromise;
}
/**
* writes the new message to the database
* so other readers can find it
*/
function writeMessage(db, readerUuid, messageJson) {
var time = new Date().getTime();
var writeObject = {
uuid: readerUuid,
time: time,
data: messageJson
};
var transaction = db.transaction([OBJECT_STORE_ID], 'readwrite');
return new Promise(function (res, rej) {
transaction.oncomplete = function () {
return res();
};
transaction.onerror = function (ev) {
return rej(ev);
};
var objectStore = transaction.objectStore(OBJECT_STORE_ID);
objectStore.add(writeObject);
});
}
function getAllMessages(db) {
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
ret.push(cursor.value); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
res(ret);
}
};
});
}
function getMessagesHigherThan(db, lastCursorId) {
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
function openCursor() {
// Occasionally Safari will fail on IDBKeyRange.bound, this
// catches that error, having it open the cursor to the first
// item. When it gets data it will advance to the desired key.
try {
var keyRangeValue = IDBKeyRange.bound(lastCursorId + 1, Infinity);
return objectStore.openCursor(keyRangeValue);
} catch (e) {
return objectStore.openCursor();
}
}
return new Promise(function (res) {
openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
if (cursor.value.id < lastCursorId + 1) {
cursor["continue"](lastCursorId + 1);
} else {
ret.push(cursor.value);
cursor["continue"]();
}
} else {
res(ret);
}
};
});
}
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 getOldMessages(db, ttl) {
var olderThen = new Date().getTime() - ttl;
var objectStore = db.transaction(OBJECT_STORE_ID).objectStore(OBJECT_STORE_ID);
var ret = [];
return new Promise(function (res) {
objectStore.openCursor().onsuccess = function (ev) {
var cursor = ev.target.result;
if (cursor) {
var msgObk = cursor.value;
if (msgObk.time < olderThen) {
ret.push(msgObk); //alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor["continue"]();
} else {
// no more old messages,
res(ret);
return;
}
} else {
res(ret);
}
};
});
}
function cleanOldMessages(db, ttl) {
return getOldMessages(db, ttl).then(function (tooOld) {
return Promise.all(tooOld.map(function (msgObj) {
return removeMessageById(db, msgObj.id);
}));
});
}
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
return createDatabase(channelName).then(function (db) {
var state = {
closed: false,
lastCursorId: 0,
channelName: channelName,
options: options,
uuid: (0, _util.randomToken)(),
/**
* emittedMessagesIds
* contains all messages that have been emitted before
* @type {ObliviousSet}
*/
eMIs: new _obliviousSet.ObliviousSet(options.idb.ttl * 2),
// ensures we do not read messages in parrallel
writeBlockPromise: Promise.resolve(),
messagesCallback: null,
readQueuePromises: [],
db: db
};
/**
* Handle abrupt closes that do not originate from db.close().
* This could happen, for example, if the underlying storage is
* removed or if the user clears the database in the browser's
* history preferences.
*/
db.onclose = function () {
state.closed = true;
if (options.idb.onclose) options.idb.onclose();
};
/**
* if service-workers are used,
* we have no 'storage'-event if they post a message,
* therefore we also have to set an interval
*/
_readLoop(state);
return state;
});
}
function _readLoop(state) {
if (state.closed) return;
readNewMessages(state).then(function () {
return (0, _util.sleep)(state.options.idb.fallbackInterval);
}).then(function () {
return _readLoop(state);
});
}
function _filterMessage(msgObj, state) {
if (msgObj.uuid === state.uuid) return false; // send by own
if (state.eMIs.has(msgObj.id)) return false; // already emitted
if (msgObj.data.time < state.messagesCallbackTime) return false; // older then onMessageCallback
return true;
}
/**
* reads all new messages from the database and emits them
*/
function readNewMessages(state) {
// channel already closed
if (state.closed) return Promise.resolve(); // if no one is listening, we do not need to scan for new messages
if (!state.messagesCallback) return Promise.resolve();
return getMessagesHigherThan(state.db, state.lastCursorId).then(function (newerMessages) {
var useMessages = newerMessages
/**
* there is a bug in iOS where the msgObj can be undefined some times
* so we filter them out
* @link https://github.com/pubkey/broadcast-channel/issues/19
*/
.filter(function (msgObj) {
return !!msgObj;
}).map(function (msgObj) {
if (msgObj.id > state.lastCursorId) {
state.lastCursorId = msgObj.id;
}
return msgObj;
}).filter(function (msgObj) {
return _filterMessage(msgObj, state);
}).sort(function (msgObjA, msgObjB) {
return msgObjA.time - msgObjB.time;
}); // sort by time
useMessages.forEach(function (msgObj) {
if (state.messagesCallback) {
state.eMIs.add(msgObj.id);
state.messagesCallback(msgObj.data);
}
});
return Promise.resolve();
});
}
function close(channelState) {
channelState.closed = true;
channelState.db.close();
}
function postMessage(channelState, messageJson) {
channelState.writeBlockPromise = channelState.writeBlockPromise.then(function () {
return writeMessage(channelState.db, channelState.uuid, messageJson);
}).then(function () {
if ((0, _util.randomInt)(0, 10) === 0) {
/* await (do not await) */
cleanOldMessages(channelState.db, channelState.options.idb.ttl);
}
});
return channelState.writeBlockPromise;
}
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
readNewMessages(channelState);
}
function canBeUsed() {
if (_util.isNode) return false;
var idb = getIdb();
if (!idb) return false;
return true;
}
function averageResponseTime(options) {
return options.idb.fallbackInterval * 2;
}
var _default = {
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};
exports["default"] = _default;

View File

@@ -0,0 +1,197 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getLocalStorage = getLocalStorage;
exports.storageKey = storageKey;
exports.postMessage = postMessage;
exports.addStorageEventListener = addStorageEventListener;
exports.removeStorageEventListener = removeStorageEventListener;
exports.create = create;
exports.close = close;
exports.onMessage = onMessage;
exports.canBeUsed = canBeUsed;
exports.averageResponseTime = averageResponseTime;
exports["default"] = exports.type = exports.microSeconds = void 0;
var _obliviousSet = require("oblivious-set");
var _options = require("../options");
var _util = require("../util");
/**
* A localStorage-only method which uses localstorage and its 'storage'-event
* This does not work inside of webworkers because they have no access to locastorage
* This is basically implemented to support IE9 or your grandmothers toaster.
* @link https://caniuse.com/#feat=namevalue-storage
* @link https://caniuse.com/#feat=indexeddb
*/
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var KEY_PREFIX = 'pubkey.broadcastChannel-';
var type = 'localstorage';
/**
* copied from crosstab
* @link https://github.com/tejacques/crosstab/blob/master/src/crosstab.js#L32
*/
exports.type = type;
function getLocalStorage() {
var localStorage;
if (typeof window === 'undefined') return null;
try {
localStorage = window.localStorage;
localStorage = window['ie8-eventlistener/storage'] || window.localStorage;
} catch (e) {// New versions of Firefox throw a Security exception
// if cookies are disabled. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
}
return localStorage;
}
function storageKey(channelName) {
return KEY_PREFIX + channelName;
}
/**
* writes the new message to the storage
* and fires the storage-event so other readers can find it
*/
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
(0, _util.sleep)().then(function () {
var key = storageKey(channelState.channelName);
var writeObj = {
token: (0, _util.randomToken)(),
time: new Date().getTime(),
data: messageJson,
uuid: channelState.uuid
};
var value = JSON.stringify(writeObj);
getLocalStorage().setItem(key, value);
/**
* StorageEvent does not fire the 'storage' event
* in the window that changes the state of the local storage.
* So we fire it manually
*/
var ev = document.createEvent('Event');
ev.initEvent('storage', true, true);
ev.key = key;
ev.newValue = value;
window.dispatchEvent(ev);
res();
});
});
}
function addStorageEventListener(channelName, fn) {
var key = storageKey(channelName);
var listener = function listener(ev) {
if (ev.key === key) {
fn(JSON.parse(ev.newValue));
}
};
window.addEventListener('storage', listener);
return listener;
}
function removeStorageEventListener(listener) {
window.removeEventListener('storage', listener);
}
function create(channelName, options) {
options = (0, _options.fillOptionsWithDefaults)(options);
if (!canBeUsed()) {
throw new Error('BroadcastChannel: localstorage cannot be used');
}
var uuid = (0, _util.randomToken)();
/**
* eMIs
* contains all messages that have been emitted before
* @type {ObliviousSet}
*/
var eMIs = new _obliviousSet.ObliviousSet(options.localstorage.removeTimeout);
var state = {
channelName: channelName,
uuid: uuid,
eMIs: eMIs // emittedMessagesIds
};
state.listener = addStorageEventListener(channelName, function (msgObj) {
if (!state.messagesCallback) return; // no listener
if (msgObj.uuid === uuid) return; // own message
if (!msgObj.token || eMIs.has(msgObj.token)) return; // already emitted
if (msgObj.data.time && msgObj.data.time < state.messagesCallbackTime) return; // too old
eMIs.add(msgObj.token);
state.messagesCallback(msgObj.data);
});
return state;
}
function close(channelState) {
removeStorageEventListener(channelState.listener);
}
function onMessage(channelState, fn, time) {
channelState.messagesCallbackTime = time;
channelState.messagesCallback = fn;
}
function canBeUsed() {
if (_util.isNode) return false;
var ls = getLocalStorage();
if (!ls) return false;
try {
var key = '__broadcastchannel_check';
ls.setItem(key, 'works');
ls.removeItem(key);
} catch (e) {
// Safari 10 in private mode will not allow write access to local
// storage and fail with a QuotaExceededError. See
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API#Private_Browsing_Incognito_modes
return false;
}
return true;
}
function averageResponseTime() {
var defaultTime = 120;
var userAgent = navigator.userAgent.toLowerCase();
if (userAgent.includes('safari') && !userAgent.includes('chrome')) {
// safari is much slower so this time is higher
return defaultTime * 2;
}
return defaultTime;
}
var _default = {
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};
exports["default"] = _default;

View File

@@ -0,0 +1,86 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.create = create;
exports.close = close;
exports.postMessage = postMessage;
exports.onMessage = onMessage;
exports.canBeUsed = canBeUsed;
exports.averageResponseTime = averageResponseTime;
exports["default"] = exports.type = exports.microSeconds = void 0;
var _util = require("../util");
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'native';
exports.type = type;
function create(channelName) {
var state = {
messagesCallback: null,
bc: new BroadcastChannel(channelName),
subFns: [] // subscriberFunctions
};
state.bc.onmessage = function (msg) {
if (state.messagesCallback) {
state.messagesCallback(msg.data);
}
};
return state;
}
function close(channelState) {
channelState.bc.close();
channelState.subFns = [];
}
function postMessage(channelState, messageJson) {
try {
channelState.bc.postMessage(messageJson, false);
return Promise.resolve();
} catch (err) {
return Promise.reject(err);
}
}
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
function canBeUsed() {
/**
* in the electron-renderer, isNode will be true even if we are in browser-context
* so we also check if window is undefined
*/
if (_util.isNode && typeof window === 'undefined') return false;
if (typeof BroadcastChannel === 'function') {
if (BroadcastChannel._pubkey) {
throw new Error('BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill');
}
return true;
} else return false;
}
function averageResponseTime() {
return 150;
}
var _default = {
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};
exports["default"] = _default;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.create = create;
exports.close = close;
exports.postMessage = postMessage;
exports.onMessage = onMessage;
exports.canBeUsed = canBeUsed;
exports.averageResponseTime = averageResponseTime;
exports["default"] = exports.type = exports.microSeconds = void 0;
var _util = require("../util");
var microSeconds = _util.microSeconds;
exports.microSeconds = microSeconds;
var type = 'simulate';
exports.type = type;
var SIMULATE_CHANNELS = new Set();
function create(channelName) {
var state = {
name: channelName,
messagesCallback: null
};
SIMULATE_CHANNELS.add(state);
return state;
}
function close(channelState) {
SIMULATE_CHANNELS["delete"](channelState);
}
function postMessage(channelState, messageJson) {
return new Promise(function (res) {
return setTimeout(function () {
var channelArray = Array.from(SIMULATE_CHANNELS);
channelArray.filter(function (channel) {
return channel.name === channelState.name;
}).filter(function (channel) {
return channel !== channelState;
}).filter(function (channel) {
return !!channel.messagesCallback;
}).forEach(function (channel) {
return channel.messagesCallback(messageJson);
});
res();
}, 5);
});
}
function onMessage(channelState, fn) {
channelState.messagesCallback = fn;
}
function canBeUsed() {
return true;
}
function averageResponseTime() {
return 5;
}
var _default = {
create: create,
close: close,
onMessage: onMessage,
postMessage: postMessage,
canBeUsed: canBeUsed,
type: type,
averageResponseTime: averageResponseTime,
microSeconds: microSeconds
};
exports["default"] = _default;