dexie-observable
Version:
Addon to Dexie that makes it possible to observe database changes no matter if they occur on other db instance or other window.
1 lines • 13.4 kB
JavaScript
(function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n(require("dexie")):"function"==typeof define&&define.amd?define(["dexie"],n):((e="undefined"!=typeof globalThis?globalThis:e||self).Dexie=e.Dexie||{},e.Dexie.Observable=n(e.Dexie))})(this,function(e){"use strict";function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var j=n(e);function B(){}function C(o,i){return o===B?i:function(){var e,n,t=o.apply(this,arguments);return t&&"function"==typeof t.then?(e=this,n=arguments,t.then(function(){return i.apply(e,n)})):i.apply(this,arguments)}}var l=1,m=2,u=3;function k(t){return function(e){var n,a,s,d,f,i,r;e.hook._observing||(e.hook._observing=!0,n=e.name,e.hook("creating").subscribe((a=t,s=e,function(n,e,t){var o=void 0,i=(void 0===n&&s.schema.primKey.uuid&&(n=o=j.default.Observable.createUUID(),s.schema.primKey.keyPath&&j.default.setByKeyPath(e,s.schema.primKey.keyPath,n)),{source:t.source||null,table:s.name,key:void 0===n?null:n,type:l,obj:e}),r=a._changes.add(i).then(function(e){return t._lastWrittenRevision=Math.max(t._lastWrittenRevision,e),e});return this.onsuccess=function(e){n!=e&&r._then(function(){i.key=e,a._changes.put(i)})},this.onerror=function(){r._then(function(e){a._changes.delete(e)})},o})),e.hook("updating").subscribe((d=t,f=n,function(e,n,t,o){var i,r,a={},s=!1,l=j.default.deepClone(t);for(i in e){var u,c=e[i];void 0===c?(j.default.delByKeyPath(l,i),s=!(a[i]=null)):c!==(u=j.default.getByKeyPath(t,i))&&JSON.stringify(c)!==JSON.stringify(u)&&(j.default.setByKeyPath(l,i,c),a[i]=c,s=!0)}s&&(n={source:o.source||null,table:f,key:n,type:m,mods:a,oldObj:t,obj:l},r=d._changes.add(n),this.onsuccess=function(){r._then(function(e){o._lastWrittenRevision=Math.max(o._lastWrittenRevision,e)})},this.onerror=function(){r._then(function(e){d._changes.delete(e)})})})),e.hook("deleting").subscribe((i=t,r=n,function(e,n,t){var o=i._changes.add({source:t.source||null,table:r,key:e,type:u,oldObj:n}).then(function(e){return t._lastWrittenRevision=Math.max(t._lastWrittenRevision,e),e}).catch(function(e){console.log(n),console.log(e.stack)});this.onerror=function(){o._then(function(e){i._changes.delete(e)})}})))}}var c=j.default.Promise;function E(r,a,e,s,l){var u={};function n(){return s.node?j.default.ignoreTransaction(function(){return r.transaction("rw","_intercomm",function(){return r._intercomm.where({destinationNode:s.node.id}).toArray(function(e){return e.forEach(function(e){var n=e;"response"===n.type?(e=u[n.requestId.toString()])&&(n.isFailure?e.reject(n.message.error):e.resolve(n.message.result),delete u[n.requestId.toString()]):(n.resolve=function(e){r.observable.sendMessage("response",{result:e},n.sender,{requestId:n.id})},n.reject=function(e){r.observable.sendMessage("response",{error:e.toString()},n.sender,{isFailure:!0,requestId:n.id})},r.on.message.fire(n))}),r._intercomm.where("id").anyOf(e.map(function(e){return e.id})).delete()})})}):c.reject(new j.default.DatabaseClosedError)}return r.observable.sendMessage=function(e,n,t,o){var i;return o=o||{},s.node?(i={message:n,destinationNode:t,sender:s.node.id,type:e},j.default.extend(i,o),j.default.ignoreTransaction(function(){var e=["_intercomm"],e=(o.wantReply&&e.push("_syncNodes"),r.transaction("rw",e,function(){return o.wantReply?r._syncNodes.where("id").equals(t).count(function(e){return e?r._intercomm.add(i):r._syncNodes.where("isMaster").above(0).first(function(e){return i.destinationNode=e.id,r._intercomm.add(i)})}):r._intercomm.add(i)}).then(function(t){var e=null;return o.wantReply&&(e=new c(function(e,n){u[t.toString()]={resolve:e,reject:n}})),l&&l.setItem("Dexie.Observable/intercomm/"+r.name,t.toString()),a.on.intercomm.fire(r.name),e}));if(o.wantReply)return e;e.catch(function(){})})):o.wantReply?c.reject(new j.default.DatabaseClosedError):c.resolve()},r.observable.broadcastMessage=function(n,t,o){var i;s.node&&(i=s.node.id,j.default.ignoreTransaction(function(){r._syncNodes.toArray(function(e){return c.all(e.filter(function(e){return"local"===e.type&&(o||e.id!==i)}).map(function(e){return r.observable.sendMessage(n,t,e.id)}))}).catch(function(){})}))},{onIntercomm:function(e){e===r.name&&n().catch("DatabaseClosedError",function(){})},consumeIntercommMessages:n}}function H(t){return function(e,n){e._changes="++rev",e._syncNodes="++id,myRevision,lastHeartBeat,&url,isMaster,type,status",e._intercomm="++id,destinationNode",e._uncommittedChanges="++id,node",t.call(this,e,n),Object.keys(n).forEach(function(e){e=n[e];0===e.primKey.name.indexOf("$$")&&(e.primKey.uuid=!0,e.primKey.name=e.primKey.name.substr(2),e.primKey.keyPath=e.primKey.keyPath.substr(2))}),Object.keys(n).forEach(function(e){0!==e.indexOf("_")&&0!==e.indexOf("$")&&(n[e].observable=!0)})}}var r,K=self,P=j.default.defineClass({rev:Number,source:String,table:String,key:Object,type:Number,obj:Object,mods:Object,oldObj:Object}),W=j.default.override,U=j.default.Promise,q=!1;function V(a){if(!/^(3|4)\./.test(j.default.version))throw new Error("Missing dexie version 3.x or 4.x");if(a.observable){if("4.0.1-beta.13"!==a.observable.version)throw new Error("Mixed versions of dexie-observable")}else var n,t,o,s,l,i,r,u,c=2e4,d=2e4,f=c-5e3,m=V.localStorageImpl,v=j.default.defineClass({myRevision:Number,type:String,lastHeartBeat:Number,deleteTimeStamp:Number,url:String,isMaster:Number,syncProtocol:String,syncContext:null,syncOptions:Object,connected:!1,status:Number,appliedRemoteRevision:null,remoteBaseRevisions:[{local:Number,remote:null}],dbUploadState:{tablesToUpload:[String],currentTable:String,currentKey:null,localBaseRevision:Number}}),y=(a.observable={version:"4.0.1-beta.13"},a.observable.SyncNode=v,function(e){t.latestRevision[n.name]<e&&(t.latestRevision[n.name]=e,j.default.ignoreTransaction(function(){t.on("latestRevisionIncremented").fire(n.name,e)}),o&&o.setItem("Dexie.Observable/latestRevision/"+n.name,e))}),e=(l=y,function(a){return function(e,n,t,o){var i,r;return s.dynamicallyOpened()?a.apply(this,arguments):(i=!1,"readwrite"===e&&n.some(function(e){return t[e]&&t[e].observable})&&(i=!0,-1===(n=n.slice(0)).indexOf("_changes")&&n.push("_changes")),r=a.call(this,e,n,t,o),i&&(r._lastWrittenRevision=0,r.on("complete",function(){var e;r._lastWrittenRevision&&(o?(e=function e(n){return n.parent?e(n.parent):n}(o))._lastWrittenRevision=Math.max(r._lastWrittenRevision,e.lastWrittenRevision||0):(l.timeoutHandle&&clearTimeout(l.timeoutHandle),l.timeoutHandle=setTimeout(function(){delete l.timeoutHandle,l(r._lastWrittenRevision)},25)))}),r.parent&&r.parent.source&&(r.source=r.parent.source)),r)}}),b=k(s=n=a),b=(r=v,u=b,function(e){return function(){return Object.keys(i._allTables).forEach(function(e){e=i._allTables[e];e.schema.observable&&u(e),"_syncNodes"===e.name&&e.mapToClass(r)}),e.apply(this,arguments)}}),p={node:null},h=E(i=a,t=V,0,p,o=m),g=h.onIntercomm,_=h.consumeIntercommMessages,x=(Object.defineProperty(a,"_localSyncNode",{get:function(){return p.node}}),null),R=null,w=(j.default.fake&&(a.version(1).stores({_syncNodes:"++id,myRevision,lastHeartBeat",_changes:"++rev",_intercomm:"++id,destinationNode",_uncommittedChanges:"++id,node"}),a._syncNodes.mapToClass(v),a._changes.mapToClass(P),p.node=new v({myRevision:0,type:"local",lastHeartBeat:Date.now(),deleteTimeStamp:null})),a.Version.prototype._parseStoresSpec=W(a.Version.prototype._parseStoresSpec,H),a.on.addEventType({changes:"asap",cleanup:[C,B],message:"asap"}),a._createTransaction=W(a._createTransaction,e),V.latestRevision[a.name]=V.latestRevision[a.name]||0,a.open=W(a.open,b),a.close=W(a.close,function(e){return function(){return a.dynamicallyOpened()||(y.timeoutHandle&&(clearTimeout(y.timeoutHandle),delete y.timeoutHandle),V.on("latestRevisionIncremented").unsubscribe(O),V.on("suicideNurseCall").unsubscribe(I),V.on("intercomm").unsubscribe(g),V.on("beforeunload").unsubscribe(M),p.node&&p.node.id&&(V.on.suicideNurseCall.fire(a.name,p.node.id),m&&m.setItem("Dexie.Observable/deadnode:"+p.node.id.toString()+"/"+a.name,"dead"),p.node.deleteTimeStamp=1,p.node.lastHeartBeat=0,a._syncNodes.put(p.node),p.node=null),x&&clearTimeout(x),x=null,R&&clearTimeout(R),R=null),e.apply(this,arguments)}}),a.delete=W(a.delete,function(e){return function(){return e.apply(this,arguments).then(function(e){return V.latestRevision[a.name]=0,e})}}),a.on("ready",function(){return a.dynamicallyOpened()?a:a.table("_changes").orderBy("rev").last(function(e){var n=e?e.rev:0;return p.node=new v({myRevision:n,type:"local",lastHeartBeat:Date.now(),deleteTimeStamp:null,isMaster:0}),V.latestRevision[a.name]<n&&(V.latestRevision[a.name]=n,j.default.ignoreTransaction(function(){V.on.latestRevisionIncremented.fire(n)})),a._syncNodes.put(p.node).then(j.default.ignoreTransaction(function(){var n=1;return a._syncNodes.orderBy("isMaster").reverse().modify(function(e){e.isMaster&&(e.lastHeartBeat<Date.now()-c?e.isMaster=0:n=0),p.node&&e.id===p.node.id&&(e.isMaster=p.node.isMaster=n)})})).then(function(){V.on("latestRevisionIncremented",O),V.on("beforeunload",M),V.on("suicideNurseCall",I),V.on("intercomm",g),x=setTimeout(S,500),R=setTimeout(T,f)}).then(function(){D()})})},!0),0);function O(e,n){e!==a.name||n<=w||(w=n,j.default.vip(function(){N().catch("DatabaseClosedError",function(){})}))}function N(e,n,o){var i,r,t;return!n&&N.ongoingOperation?N.ongoingOperation:(i=!1,(r=p.node)?(t=a._changes.where("rev").above(r.myRevision).limit(1e3).toArray(function(e){0<e.length?(n=e[e.length-1],i=1e3===e.length,a.on("changes").fire(e,i),r.myRevision=n.rev):o&&a.on("changes").fire([],!1);var n,t=!1;return a._syncNodes.where(":id").equals(r.id).modify(function(e){t=!0,e.lastHeartBeat=Date.now(),e.deleteTimeStamp=null,e.myRevision=Math.max(e.myRevision,r.myRevision)}).then(function(){return t})}).then(function(e){if(!e)throw q?new Error("Browser is shutting down"):(a.close(),console.error("Out of sync"),K.location&&K.location.reload(!0),new Error("Out of sync"));if(i||V.latestRevision[a.name]>r.myRevision)return N(V.latestRevision[a.name],(n||0)+1,i)}).finally(function(){delete N.ongoingOperation}),n||(N.ongoingOperation=t),t):U.reject(new j.default.DatabaseClosedError))}function T(){R=null;var e=p.node&&p.node.id;e&&a.transaction("rw!",a._syncNodes,function(){a._syncNodes.where({id:e}).first(function(e){if(e)return e.lastHeartBeat=Date.now(),e.deleteTimeStamp=null,a._syncNodes.put(e);a.isOpen()&&a.close()})}).catch("DatabaseClosedError",function(){}).finally(function(){p.node&&p.node.id===e&&a.isOpen()&&(R=setTimeout(T,f))})}function S(){x=null;var e=p.node&&p.node.id;e&&j.default.vip(function(){N(V.latestRevision[a.name]).then(D).then(_).catch("DatabaseClosedError",function(){}).finally(function(){p.node&&p.node.id===e&&a.isOpen()&&(x=setTimeout(S,500))})})}function D(){var t=p.node;return t?a.transaction("rw","_syncNodes","_changes","_intercomm",function(){var n=!1;a._syncNodes.where("lastHeartBeat").below(Date.now()-c).filter(function(e){return"local"===e.type}).modify(function(e){e.deleteTimeStamp&&e.deleteTimeStamp<Date.now()?(delete this.value,m&&m.removeItem("Dexie.Observable/deadnode:"+e.id+"/"+a.name),e.isMaster&&(a._syncNodes.update(t,{isMaster:1}),n=!0),a._intercomm.where({destinationNode:e.id}).modify(function(e){e.wantReply?e.destinationNode=t.id:delete this.value})):e.deleteTimeStamp||(e.deleteTimeStamp=Date.now()+d)}).then(function(){return V.deleteOldChanges(a),a.on("cleanup").fire(n)})}):U.reject(new j.default.DatabaseClosedError)}function M(){p.node&&(q=!0,p.node.deleteTimeStamp=1,p.node.lastHeartBeat=0,a._syncNodes.put(p.node),V.wereTheOneDying=!0,m&&m.setItem("Dexie.Observable/deadnode:"+p.node.id.toString()+"/"+a.name,"dead"))}function I(e,n){e!==a.name||V.wereTheOneDying||j.default.vip(function(){a._syncNodes.update(n,{deleteTimeStamp:1,lastHeartBeat:0}).then(D)})}}V.version="4.0.1-beta.13",V.latestRevision={},V.on=j.default.Events(null,"latestRevisionIncremented","suicideNurseCall","intercomm","beforeunload"),V.createUUID=function(){var t=Date.now();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){var n=(t+16*Math.random())%16|0;return t=Math.floor(t/16),("x"===e?n:7&n|8).toString(16)})},V.deleteOldChanges=function n(t){j.default.ignoreTransaction(function(){return t._syncNodes.orderBy("myRevision").first(function(e){return t._changes.where("rev").below(e.myRevision).limit(100).primaryKeys()}).then(function(e){if(0!==e.length)return t._changes.bulkDelete(e).then(function(){100===e.length&&setTimeout(function(){return t.isOpen()&&n(t)},500)})})}).catch(function(){})},V._onStorage=(r=V,function(e){var n,t,o,i;e.key&&0===e.key.indexOf("Dexie.Observable/")&&(n=(i=e.key.split("/"))[1],t=i[2],"latestRevision"===n?(o=parseInt(e.newValue,10),!isNaN(o)&&o>r.latestRevision[t]&&(r.latestRevision[t]=o,j.default.ignoreTransaction(function(){r.on("latestRevisionIncremented").fire(t,o)}))):0===n.indexOf("deadnode:")?(i=parseInt(n.split(":")[1],10),e.newValue&&r.on.suicideNurseCall.fire(t,i)):"intercomm"===n&&e.newValue&&r.on.intercomm.fire(t))}),V._onBeforeUnload=function(){V.on.beforeunload.fire()};try{V.localStorageImpl=K.localStorage}catch(e){}if(null!=K&&K.addEventListener&&(K.addEventListener("storage",V._onStorage),K.addEventListener("beforeunload",V._onBeforeUnload)),j.default.Observable){if("4.0.1-beta.13"!==j.default.Observable.version)throw new Error("Mixed versions of dexie-observable")}else j.default.Observable=V,j.default.addons.push(V);return j.default.Observable});