Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
Observable._onStorage = function onStorage(event) {
// We use the onstorage event to trigger onLatestRevisionIncremented since we will wake up when other windows modify the DB as well!
if (event.key.indexOf("Dexie.Observable/") === 0) { // For example "Dexie.Observable/latestRevision/FriendsDB"
var parts = event.key.split('/');
var prop = parts[1];
var dbname = parts[2];
if (prop === 'latestRevision') {
var rev = parseInt(event.newValue, 10);
if (!isNaN(rev) && rev > Observable.latestRevision[dbname]) {
Observable.latestRevision[dbname] = rev;
Dexie.ignoreTransaction(function() {
Observable.on('latestRevisionIncremented').fire(dbname, rev);
});
}
} else if (prop.indexOf("deadnode:") === 0) {
var nodeID = parseInt(prop.split(':')[1], 10);
if (event.newValue) {
Observable.on.suicideNurseCall.fire(dbname, nodeID);
}
} else if (prop === 'intercomm') {
if (event.newValue) {
Observable.on.intercomm.fire(dbname);
}
}
}
};
Observable._onStorage = function onStorage(event) {
// We use the onstorage event to trigger onLatestRevisionIncremented since we will wake up when other windows modify the DB as well!
if (event.key.indexOf("Dexie.Observable/") === 0) {
// For example "Dexie.Observable/latestRevision/FriendsDB"
var parts = event.key.split('/');
var prop = parts[1];
var dbname = parts[2];
if (prop === 'latestRevision') {
var rev = parseInt(event.newValue, 10);
if (!isNaN(rev) && rev > Observable.latestRevision[dbname]) {
Observable.latestRevision[dbname] = rev;
Dexie.ignoreTransaction(function () {
Observable.on('latestRevisionIncremented').fire(dbname, rev);
});
}
} else if (prop.indexOf("deadnode:") === 0) {
var nodeID = parseInt(prop.split(':')[1], 10);
if (event.newValue) {
Observable.on.suicideNurseCall.fire(dbname, nodeID);
}
} else if (prop === 'intercomm') {
if (event.newValue) {
Observable.on.intercomm.fire(dbname);
}
}
}
};
db.on('cleanup', function(weBecameMaster) {
// A cleanup (done in Dexie.Observable) may result in that a master node is removed and we become master.
if (weBecameMaster) {
// We took over the master role in Observable's cleanup method.
// We should connect to remote servers now.
// At this point, also reconnect servers with status ERROR_WILL_RETRY as well as plain ERROR.
// Reason to reconnect to those with plain "ERROR" is that the ERROR state may occur when a database
// connection has been closed. The new master would then be expected to reconnect.
// Also, this is not an infinite poll(). This is rare event that a new browser tab takes over from
// an old closed one.
Dexie.ignoreTransaction(()=>Dexie.vip(()=>{
return db._syncNodes.where({type: 'remote'})
.filter(node => node.status !== Statuses.OFFLINE)
.toArray(connectedRemoteNodes => Promise.all(connectedRemoteNodes.map(node =>
db.syncable.connect(node.syncProtocol, node.url, node.syncOptions).catch(e => {
console.warn(`Dexie.Syncable: Could not connect to ${node.url}. ${e.stack || e}`);
})
)));
})).catch('DatabaseClosedError', ()=>{});
}
});
if (!options!.acceptVersionDiff && db.verno !== dbExport.databaseVersion) {
// Possible feature: Call upgraders in some isolated way if this happens... ?
throw new Error(`Database version differs. Current database is in version ${db.verno} but export is ${dbExport.databaseVersion}`);
}
const { progressCallback } = options;
const progress: ImportProgress = {
done: false,
completedRows: 0,
completedTables: 0,
totalRows: dbExport.tables.reduce((p, c) => p + c.rowCount, 0),
totalTables: dbExport.tables.length
};
if (progressCallback) {
// Keep ongoing transaction private
Dexie.ignoreTransaction(()=>progressCallback(progress));
}
if (options.noTransaction) {
await importAll();
} else {
await db.transaction('rw', db.tables, importAll);
}
async function importAll () {
do {
for (const tableExport of dbExport.data) {
if (!tableExport.rows) break; // Need to pull more!
if ((tableExport.rows as any).complete && tableExport.rows.length === 0)
continue;
if (progressCallback) {
return db.table("_changes").orderBy("rev").last(function (lastChange) {
// Since startObserving() is called before database open() method, this will be the first database operation enqueued to db.
// Therefore we know that the retrieved value will be This query will
var latestRevision = lastChange ? lastChange.rev : 0;
mySyncNode = new SyncNode({
myRevision: latestRevision,
type: "local",
lastHeartBeat: Date.now(),
deleteTimeStamp: null,
isMaster: 0
});
if (Observable.latestRevision[db.name] < latestRevision) {
// Side track . For correctness whenever setting Observable.latestRevision[db.name] we must make sure the event is fired if increased:
// There are other db instances in same window that hasnt yet been informed about a new revision
Observable.latestRevision[db.name] = latestRevision;
Dexie.ignoreTransaction(function () {
Observable.on.latestRevisionIncremented.fire(latestRevision);
});
}
// Add new sync node or if this is a reopening of the database after a close() call, update it.
return db.transaction('rw', '_syncNodes', function () {
db._syncNodes.where('isMaster').equals(1).count(function (anyMasterNode) {
if (!anyMasterNode) {
// There's no master node. Let's take that role then.
mySyncNode.isMaster = 1;
}
// Add our node to DB and start subscribing to events
db._syncNodes.add(mySyncNode).then(function () {
Observable.on('latestRevisionIncremented', onLatestRevisionIncremented); // Wakeup when a new revision is available.
Observable.on('beforeunload', onBeforeUnload);
Observable.on('suicideNurseCall', onSuicide);
Observable.on('intercomm', onIntercomm);
.each(function(connectedRemoteNode) {
// There are connected remote nodes that we must take over
// Since we may be in the on(ready) event, we must get VIPed to continue
Dexie.ignoreTransaction(function() {
Dexie.vip(function() {
db.syncable.connect(connectedRemoteNode.syncProtocol, connectedRemoteNode.url, connectedRemoteNode.syncOptions);
});
});
});
}
function wakeupObservers(lastWrittenRevision) {
// Make sure Observable.latestRevision[db.name] is still below our value, now when some time has elapsed and other db instances in same window possibly could have made changes too.
if (Observable.latestRevision[db.name] < lastWrittenRevision) {
// Set the static property lastRevision[db.name] to the revision of the last written change.
Observable.latestRevision[db.name] = lastWrittenRevision;
// Wakeup ourselves, and any other db instances on this window:
Dexie.ignoreTransaction(function() {
Observable.on('latestRevisionIncremented').fire(db.name, lastWrittenRevision);
});
// Observable.on.latestRevisionIncremented will only wakeup db's in current window.
// We need a storage event to wakeup other windwos.
// Since indexedDB lacks storage events, let's use the storage event from WebStorage just for
// the purpose to wakeup db instances in other windows.
localStorage.setItem('Dexie.Observable/latestRevision/' + db.name, lastWrittenRevision); // In IE, this will also wakeup our own window. However, onLatestRevisionIncremented will work around this by only running once per revision id.
}
}
return db.table('_intercomm').where("destinationNode").equals(mySyncNode.id).modify(function(msg) {
// For each message, fire the event and remove message.
delete this.value;
Dexie.ignoreTransaction(function() {
consumeMessage(msg);
});
});
}
function _enque() {
if (!context.ongoingOperation) {
context.ongoingOperation = Dexie.ignoreTransaction(function() {
return Dexie.vip(function() {
return fn();
});
}).then(function(res) {
delete context.ongoingOperation;
return res;
});
} else {
context.ongoingOperation = context.ongoingOperation.then(function() {
return enque(context, fn, instanceID);
});
}
return context.ongoingOperation;
}
return new Promise((resolve, reject) => {
Dexie.ignoreTransaction(() => {
callback()
.then(resolve)
.catch(reject);
});
});
}