@verdant-web/store 2.8.1 → 2.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,5 +13,5 @@ list should be an Array.`),a.length===0)return new b(0);if(a.length===1)return a
13
13
  - New indexes: ${Object.keys(o.addedIndexes).map(h=>o.addedIndexes[h].map(S=>`${h}.${S.name}`)).flatMap(h=>h).join(", ")}
14
14
  - Removed indexes: ${Object.keys(o.removedIndexes).map(h=>o.removedIndexes[h].map(S=>`${h}.${S.name}`)).flatMap(h=>h).join(", ")}
15
15
  `)}})}function rr({migration:i,meta:t,getMigrationNow:e,newOids:n}){return i.allCollections.reduce((r,o)=>(r[o]={put:async s=>{xe(i.newSchema.collections[o],s);let c=s[i.newSchema.collections[o].primaryKey],p=X(o,c);return n.push(p),await t.insertLocalOperation(De(s,p,e)),s},delete:async s=>{let c=X(o,s),p=await t.getAllDocumentRelatedOids(c);return t.insertLocalOperation(p.map(h=>({oid:h,timestamp:e(),data:{op:"delete"}})))}},r),{})}function fo({migration:i,context:t,meta:e}){return i.oldCollections.reduce((n,r)=>(n[r]={get:async o=>{let s=X(r,o);return await e.getDocumentSnapshot(s,{to:e.time.now(i.oldSchema.version)})},findOne:async o=>{let s=await qt({collection:r,index:o,context:t});return s?await e.getDocumentSnapshot(s,{to:e.time.now(i.oldSchema.version)}):null},findAll:async o=>{let s=await Wt({collection:r,index:o,context:t});return await Promise.all(s.map(p=>e.getDocumentSnapshot(p,{to:e.time.now(i.oldSchema.version)})))}},n),{})}function po({meta:i,migration:t,context:e}){function n(){return i.time.zero(t.version)}let r=new Array,o=fo({migration:t,context:e,meta:i}),s=rr({migration:t,getMigrationNow:n,newOids:r,meta:i}),c=async S=>{let E=await i.getAllCollectionRelatedOids(S);return i.insertLocalOperation(E.map(g=>({oid:g,timestamp:n(),data:{op:"delete"}})))},p=new Array;return{log:e.log,newOids:r,deleteCollection:c,migrate:async(S,E)=>{let g=await o[S].findAll();await Promise.all(g.filter(Boolean).map(async P=>{V(Ze(P),`Document is missing an OID: ${JSON.stringify(P)}`);let b=se(P),v=await E(P);if(v){Xe(b),Xe(v),Le(v);let C=et(b,v,n,void 0,[],{mergeUnknownObjects:!0});C.length>0&&await i.insertLocalOperation(C)}}))},queries:o,mutations:s,awaitables:p}}function ho({meta:i,migration:t,context:e}){function n(){return i.time.zero(t.version)}let r=new Array,o=new Proxy({},{get(){throw new Error("Queries are not available in initial migrations; there is no database yet!")}}),s=rr({migration:t,getMigrationNow:n,newOids:r,meta:i});return{log:e.log,newOids:r,deleteCollection:()=>{throw new Error("Calling deleteCollection() in initial migrations is not supported! Use initial migrations to seed initial data using mutations.")},migrate:()=>{throw new Error("Calling migrate() in initial migrations is not supported! Use initial migrations to seed initial data using mutations.")},queries:o,mutations:s,awaitables:[]}}async function mo(i){return new Promise((t,e)=>{let n=i.getAllKeys();n.onsuccess=r=>{t(n.result)},n.onerror=r=>{e(n.error)}})}async function yo(i,t){let e=i.delete(t);return new Promise((n,r)=>{e.onsuccess=o=>{n()},e.onerror=o=>{r(e.error)}})}async function go(i,t){let e=i.put(t);return new Promise((n,r)=>{e.onsuccess=o=>{n()},e.onerror=o=>{r(e.error)}})}async function bo({meta:i,currentVersion:t,newVersion:e}){let n=[];return await i.operations.iterateOverAllOperations(r=>n.push(r),{from:i.time.zero(t+1)}),Array.from(new Set(n.map(r=>K(r.oid))))}var st=class extends N{constructor(){super(...arguments);this._undoable=[];this._undone=[];this.undo=async()=>{let e=this._undoable.pop();return e?(this._undone.push(await e()),this.emit("change"),!0):!1};this.redo=async()=>{let e=this._undone.pop();return e?(this._undoable.push(await e()),this.emit("change"),!0):!1};this.addUndo=e=>{this._undoable.push(e),this._undone=[],this.emit("change")};this.addRedo=e=>{this._undone.push(e),this.emit("change")};this.clear=()=>{this._undoable=[],this._undone=[],this.emit("change")}}get canUndo(){return this._undoable.length>0}get canRedo(){return this._undone.length>0}};var Jt=class{constructor(t,e,n){this.meta=t;this.schema=e;this.entities=n;this.getOid=(t,e)=>{let n=this.schema.collections[t].primaryKey,r=e[n];return V(r,`Document must have a primary key: ${n.toString()} (got: ${JSON.stringify(e)})`),X(t,r)};this.addDefaults=(t,e)=>{let n=this.schema.collections[t];return xe(n,e)};this.create=async(t,e,n={})=>{let r=this.addDefaults(t,e),o=this.getOid(t,r);return this.entities.create(r,o,n)};this.delete=async(t,e,n={})=>{let r=X(t,e);return this.entities.delete(r,n)};this.deleteAll=async(t,e={})=>this.entities.deleteAll(t.map(([n,r])=>X(n,r)),e);this.deleteAllFromCollection=async(t,e,n={})=>this.entities.deleteAll(e.map(r=>X(t,r)),n)}};var Ue=Symbol("entity-file-update"),at=Symbol("entity-file-mark-failed"),wo,vo,Be=class extends N{constructor(e,{downloadRemote:n=!1}={}){super();this.id=e;this._objectUrl=null;this._fileData=null;this._loading=!0;this._failed=!1;this._disposed=!1;this._downloadRemote=!1;this[wo]=e=>{this._loading=!1,this._failed=!1,this._disposed=!1,this._fileData=e,e.file&&(this._objectUrl&&URL.revokeObjectURL(this._objectUrl),this._objectUrl=URL.createObjectURL(e.file)),this.emit("change")};this[vo]=()=>{this._failed=!0,this._loading=!1,this.emit("change")};this.dispose=()=>{this._objectUrl&&URL.revokeObjectURL(this._objectUrl),this._disposed=!0};this._downloadRemote=n}static{wo=Ue,vo=at}get downloadRemote(){return this._downloadRemote}get url(){return this.loading?null:this._objectUrl?this._objectUrl:this._fileData?.url??null}get name(){return this._fileData?.name??null}get type(){return this._fileData?.type??null}get loading(){return this._loading}get failed(){return this._failed}};var or=ft(mt(),1);function So(i){return{id:(0,or.default)(),file:i,url:void 0,remote:!1,name:i.name,type:i.type}}function Me(i,t){if(typeof window<"u"&&i instanceof File){let e=So(i);return t(e),Ei(e.id)}if(Array.isArray(i)){for(let e=0;e<i.length;e++)i[e]=Me(i[e],t);return i}if(typeof i=="object"){for(let e in i)i[e]=Me(i[e],t);return i}return i}function sr(i){return new Promise((t,e)=>{let n=new FileReader;n.onload=()=>{t(n.result)},n.onerror=e,n.readAsArrayBuffer(i)})}var Yt=class extends fe{constructor(){super(...arguments);this.addFile=async(e,{transaction:n,downloadRemote:r=!1}={})=>{let o=e.file?await sr(e.file):void 0;if(!o&&r&&e.url)try{o=await fetch(e.url,{method:"GET",credentials:"include"}).then(s=>s.arrayBuffer())}catch(s){console.error("Failed to download file to cache it locally. The file will still be available using its URL. Check the file server's CORS configuration.",s)}return this.run("files",s=>s.put({id:e.id,remote:e.remote?"true":"false",deletedAt:null,name:e.name,type:e.type,url:e.url,buffer:o}),"readwrite",n)};this.hydrateFileData=e=>{e.remote=e.remote==="true";let n=e.buffer;return delete e.buffer,e.file=n?xo(n,e.type):void 0,e};this.markUploaded=async(e,{transaction:n}={})=>{let r=await this.getFileRaw(e,{transaction:n});if(!r)throw new Error("File is not in local database");return this.run("files",o=>o.put({...r,remote:"true"}),"readwrite",n)};this.getFileRaw=async(e,{transaction:n}={})=>{let r=await this.run("files",o=>o.get(e),"readonly",n);if(r)return r};this.getFile=async(e,{transaction:n}={})=>{let r=await this.getFileRaw(e,{transaction:n});if(r)return this.hydrateFileData(r)};this.markPendingDelete=async(e,{transaction:n}={})=>{let r=await this.getFileRaw(e,{transaction:n});if(!r)throw new Error("File is not in local database");return this.run("files",o=>o.put({...r,deletedAt:Date.now()}),"readwrite",n)};this.listUnsynced=async()=>(await this.run("files",n=>n.index("remote").getAll("false"),"readonly")).map(this.hydrateFileData);this.iterateOverPendingDelete=(e,n)=>this.iterate("files",r=>r.index("deletedAt").openCursor(IDBKeyRange.lowerBound(0,!0)),(r,o)=>{e(this.hydrateFileData(r),o)},"readwrite",n)}deleteFile(e,{transaction:n}={}){return this.run("files",r=>r.delete(e),"readwrite",n)}};function xo(i,t){return new Blob([i],{type:t})}function Oo(i){return i.deletedAt!==null&&i.deletedAt<Date.now()-1e3*60*24*3}var Gt=class{constructor({db:t,sync:e,context:n,meta:r,config:o={}}){this.files=new Map;this.add=async t=>{let e=t;if(e.remote=!1,this.files.has(e.id))this.files.get(e.id)[Ue](e);else{let n=new Be(e.id);n[Ue](e),this.files.set(e.id,n)}await this.storage.addFile(e),e.file&&((await this.sync.uploadFile(e)).success?await this.storage.markUploaded(e.id):this.context.log("error","Failed to upload file"))};this.uploadFile=async(t,e=0)=>{let n=await this.sync.uploadFile(t);n.success?await this.storage.markUploaded(t.id):n.retry&&e<5?(this.context.log("error","Error uploading file, retrying..."),setTimeout(this.uploadFile,1e3,t,e+1)):this.context.log("error","Failed to upload file. Not retrying until next sync.")};this.get=t=>{if(this.files.has(t))return this.files.get(t);let e=new Be(t);return this.files.set(t,e),this.load(e),e};this.load=async(t,e=0)=>{if(e>5){t[at]();return}let n=await this.storage.getFile(t.id);if(n)t[Ue](n);else try{let r=await this.sync.getFile(t.id);r.success?(t[Ue](r.data),await this.storage.addFile(r.data,{downloadRemote:t.downloadRemote})):(t[at](),r.retry&&setTimeout(this.load,1e3,t,e+1))}catch(r){this.context.log("error","Failed to load file",r),t[at](),setTimeout(this.load,1e3,t,e+1)}};this.listUnsynced=async()=>this.storage.listUnsynced();this.onOnlineChange=async t=>{if(t){let e=await this.listUnsynced();await Promise.all(e.map(this.uploadFile))}};this.tryCleanupDeletedFiles=async()=>{let t=0,e=0;await this.storage.iterateOverPendingDelete((n,r)=>{this.config.canCleanupDeletedFile(n)?(t++,r.delete(n.id)):e++}),this.context.log("info",`Cleaned up ${t} files, skipped ${e} files`)};this.handleFileRefsDeleted=async t=>{let e=this.storage.createTransaction(["files"],"readwrite");await Promise.all(t.map(async n=>{try{await this.storage.markPendingDelete(n.id,{transaction:e})}catch(r){this.context.log("error","Failed to mark file for deletion",r)}})),this.context.log("info",`Marked ${t.length} files as pending delete`)};this.storage=new Yt(t),this.sync=e,this.context=n,this.meta=r,this.config={canCleanupDeletedFile:Oo,...o},this.sync.subscribe("onlineChange",this.onOnlineChange),this.meta.subscribe("filesDeleted",this.handleFileRefsDeleted),this.tryCleanupDeletedFiles()}};var ar="@@refresh",Xt="@@deepChange";function ct(i,t){return i[ar](t)}var Io,Do,ye=class i{constructor({oid:t,store:e,fieldSchema:n,cache:r,parent:o,onAllUnsubscribed:s,readonlyKeys:c=[],fieldPath:p=[]}){this._current=null;this._deleted=!1;this.cachedSnapshot=null;this.cachedDestructure=null;this.cachedDeepUpdatedAt=null;this._updatedAt=null;this[Io]=t=>{let{view:e,deleted:n,lastTimestamp:r}=this.cache.computeView(this.oid);this._current=e;let o=this._deleted&&!n;this._deleted=n,this.cachedDestructure=null,this._updatedAt=r||null,this.cachedDeepUpdatedAt=null,this._deleted?this.events.emit("delete",t):(this.events.emit("change",t),this[Xt](this,t)),o&&(this.cachedSnapshot=null,this.events.emit("restore",t))};this[Do]=(t,e)=>{this.cachedSnapshot=null,this.cachedDeepUpdatedAt=null,this.events.emit("changeDeep",t,e);let n=this.parent?.deref();n&&n[Xt](t,e)};this.getChildFieldSchema=t=>{if(this.fieldSchema.type==="object")return this.fieldSchema.properties[t];if(this.fieldSchema.type==="array")return this.fieldSchema.items;if(this.fieldSchema.type==="map")return this.fieldSchema.values;if(this.fieldSchema.type==="any")return this.fieldSchema;throw new Error("Invalid field schema")};this.dispose=()=>{this.events.dispose()};this.subscribe=(t,e)=>this.events.subscribe(t,e);this.addPatches=t=>{this.store.addLocalOperations(t)};this.cloneCurrent=()=>{if(this._current!==void 0)return se(this._current)};this.getSubObject=(t,e)=>{let n=this.getChildFieldSchema(e);return this.cache.getEntity({oid:t,fieldSchema:n,parent:this,fieldKey:e})};this.wrapValue=(t,e)=>{if(ne(t)){let n=t.id,r=this.getSubObject(n,e);if(r)return r;throw new Error(`CACHE MISS: Subobject ${n} does not exist on ${this.oid}`)}else if(oe(t)){let n=this.store.getFile(t.id);if(n)return n.subscribe("change",()=>{this[Xt](this,{isLocal:!1})}),n}return t};this.processInputValue=(t,e)=>{t instanceof File||(t=se(t,!1));let n=this.getChildFieldSchema(e);n&&_e(t,n);let r=tt(n,t,[...this.fieldPath,e]);if(r)throw new Error(r);return Me(t,this.store.addFile)};this.get=t=>{if(this.value===void 0||this.value===null)throw new Error("Cannot access deleted entity");let e=this.value[t];return this.wrapValue(e,t)};this.getAll=()=>{if(this.value===void 0||this.value===null)throw new Error("Cannot access deleted entity");if(this.cachedDestructure)return this.cachedDestructure;let t;if(Array.isArray(this.value))t=this.value.map((e,n)=>this.wrapValue(e,n));else{t={};for(let e in this.value)t[e]=this.get(e)}return this.cachedDestructure=t,t};this.getSnapshot=()=>{if(!this.value||this.deleted)return null;if(this.cachedSnapshot)return this.cachedSnapshot;let t;if(Array.isArray(this.value))t=this.value.map((e,n)=>ne(e)?this.getSubObject(e.id,n)?.getSnapshot():oe(e)?this.getFileSnapshot(e):e);else{t={...this.value};for(let[e,n]of Object.entries(t))ne(n)?t[e]=this.getSubObject(n.id,e)?.getSnapshot():oe(n)&&(t[e]=this.getFileSnapshot(n))}return $(t,this.oid),this.cachedSnapshot=t,t};this.keys=()=>Object.keys(this.value||{});this.entries=()=>Object.entries(this.getAll());this.values=()=>Object.values(this.getAll());this.set=(t,e)=>{if(this.readonlyKeys.includes(t))throw new Error(`Cannot set readonly key ${t.toString()}`);this.addPatches(this.store.patchCreator.createSet(this.oid,t,this.processInputValue(e,t)))};this.delete=t=>{if(Array.isArray(this.value))this.addPatches(this.store.patchCreator.createListDelete(this.oid,t,1));else{let e=this.getDeleteMode(t);if(!e)throw new Error(`Cannot delete key ${t} - the property is not marked as optional in the schema`);e==="delete"?this.addPatches(this.store.patchCreator.createRemove(this.oid,t)):this.addPatches(this.store.patchCreator.createSet(this.oid,t,null))}};this.getDeleteMode=t=>{if(this.readonlyKeys.includes(t))return!1;if(this.fieldSchema.type==="any"||this.fieldSchema.type==="map")return"delete";if(this.fieldSchema.type==="object"){let e=this.fieldSchema.properties[t];if(!e||e.type==="any")return"delete";if(e.type==="map")return!1;if(e.nullable)return"null"}return!1};this.remove=this.delete.bind(this);this.update=(t,{replaceSubObjects:e=!1,merge:n=!0}={replaceSubObjects:!1,merge:!0})=>{if(!n&&this.fieldSchema.type!=="any"&&this.fieldSchema.type!=="map")throw new Error('Cannot use .update without merge if the field has a strict schema type. merge: false is only available on "any" or "map" types.');for(let[o,s]of Object.entries(t)){if(this.readonlyKeys.includes(o))throw new Error(`Cannot set readonly key ${o.toString()}`);let c=this.getChildFieldSchema(o);c&&_e(s,c)}let r=Me(t,this.store.addFile);this.addPatches(this.store.patchCreator.createDiff(this.getSnapshot(),$(r,this.oid),{mergeUnknownObjects:!e,defaultUndefined:n}))};this.getItemRefValue=t=>{if(typeof t=="object"){let e=ce(t);if(!e||!this.cache.hasOid(e))throw new Error(`Cannot move object ${JSON.stringify(t)} which does not exist in this list`);return e}else return t};this.push=t=>{this.addPatches(this.store.patchCreator.createListPush(this.oid,this.processInputValue(t,this.value.length)))};this.insert=(t,e)=>{this.addPatches(this.store.patchCreator.createListInsert(this.oid,t,this.processInputValue(e,t)))};this.move=(t,e)=>{this.addPatches(this.store.patchCreator.createListMoveByIndex(this.oid,t,e))};this.moveItem=(t,e)=>{let n=this.getItemRefValue(t);if(ne(n))this.addPatches(this.store.patchCreator.createListMoveByRef(this.oid,n,e));else{let r=this.value.indexOf(n);this.addPatches(this.store.patchCreator.createListMoveByIndex(this.oid,r,e))}};this.removeAll=t=>{this.addPatches(this.store.patchCreator.createListRemove(this.oid,this.getItemRefValue(t)))};this.removeFirst=t=>{this.addPatches(this.store.patchCreator.createListRemove(this.oid,this.getItemRefValue(t),"first"))};this.removeLast=t=>{this.addPatches(this.store.patchCreator.createListRemove(this.oid,this.getItemRefValue(t),"last"))};this.add=t=>{this.addPatches(this.store.patchCreator.createListAdd(this.oid,this.processInputValue(t,this.value.length)))};this.has=t=>typeof t=="object"?this.value.some(e=>ne(e)?e.id===ce(t):(oe(e),!1)):this.value.includes(t);this.getAsWrapped=()=>{if(!this.isList)throw new Error("Cannot map items of a non-list");return this.value.map(this.wrapValue)};this.map=t=>this.getAsWrapped().map(t);this.filter=t=>this.getAsWrapped().filter((e,n)=>t(e,n));this.forEach=t=>{this.getAsWrapped().forEach(t)};this.some=t=>this.getAsWrapped().some(t);this.every=t=>this.getAsWrapped().every(t);this.find=t=>this.getAsWrapped().find(t);this.includes=t=>this.has(t);this.oid=t;let{collection:h}=ae(t);this.collection=h,this.store=e,this.fieldSchema=n,this.fieldPath=p,this.readonlyKeys=c,this.cache=r,this.parent=o&&this.cache.weakRef(o);let{view:S,deleted:E,lastTimestamp:g}=this.cache.computeView(t);if(this._current=S,this._deleted=E,this._updatedAt=g||null,this.cachedDeepUpdatedAt=null,this.events=new N(()=>{this.hasSubscribers||s?.()}),this.oid.includes(".")&&!this.parent)throw new Error("Parent must be provided for sub entities");V(!!n,"Field schema must be provided")}hasSubscribersToDeepChanges(){return this.events.subscriberCount("changeDeep")>0}get hasSubscribers(){if(this.events.totalSubscriberCount()>0)return!0;let t=this.parent?.deref();for(;t;){if(t.hasSubscribersToDeepChanges())return!0;t=t.parent?.deref()}return!1}get deleted(){return this._deleted}get value(){return this._current}get isList(){return Array.isArray(this._current)}get updatedAt(){return this._updatedAt}get deepUpdatedAt(){if(this.cachedDeepUpdatedAt)return this.cachedDeepUpdatedAt;let t=this._updatedAt;return this.isList?this.forEach(e=>{if(e instanceof i){let n=e.deepUpdatedAt;n&&(!t||n>t)&&(t=n)}}):this.values().forEach(e=>{if(e instanceof i){let n=e.deepUpdatedAt;n&&(!t||n>t)&&(t=n)}}),this.cachedDeepUpdatedAt=t,t}get uid(){return this.oid}getFileSnapshot(t){let e=this.store.getFile(t.id);return e.url?{id:t.id,url:e.url}:e.loading||e.failed?{id:t.id,url:void 0}:{id:t.id,url:null}}get length(){return this.value.length}[(Io=ar,Do=Xt,Symbol.iterator)](){let t=0;return{next:()=>t<this.value.length?{value:this.get(t++),done:!1}:{value:void 0,done:!0}}}};var Zt=class{constructor(){let t,e;this.promise=new Promise((n,r)=>{t=n,e=r}),this._resolve=t,this._reject=e}resolve(t){this._resolve(t)}reject(t){this._reject(t)}};var en=class extends N{constructor({oid:e,store:n,context:r}){super();this.entities=new Map;this._initialized=new Zt;this.setInitialized=()=>{this._initialized.resolve(!0)};this.insertLocalOperations=e=>{let n=new Set;for(let r of e){let{oid:o}=r;n.add(o);let s=this.localOperationsMap.get(o)||[];s.push(r),this.localOperationsMap.set(o,s)}for(let r of n){let s=this.entities.get(r)?.deref();s&&(ct(s,{isLocal:!0}),this.emit(`change:${r}`),this.emit("change:*",r))}};this.insertOperations=(e,n)=>{for(let r of e){let{oid:o}=r;n.affectedOids?.add(o);let s=this.operationsMap.get(o)||[],c=s.findIndex(h=>h.timestamp>=r.timestamp);if(c!==-1){if(s[c].timestamp===r.timestamp)continue;s.splice(c,0,r)}else s.push(r);this.operationsMap.set(o,s);let p=this.localOperationsMap.get(o);p&&this.localOperationsMap.set(o,p.filter(h=>h.timestamp!==r.timestamp))}};this.insertBaselines=(e,{affectedOids:n})=>{for(let r of e){let{oid:o}=r,s=this.baselinesMap.get(o);if(s?.timestamp&&s.timestamp>=r.timestamp)continue;n?.add(o),this.baselinesMap.set(o,r);let c=this.operationsMap.get(o)||[];for(;c[0]?.timestamp<r.timestamp;)c.shift()}};this.addData=({operations:e,baselines:n,reset:r,isLocal:o})=>{r&&(this.operationsMap.clear(),this.baselinesMap.clear());let s={isLocal:o||!1,affectedOids:new Set};if(this.insertBaselines(n,s),this.insertOperations(e,s),r)for(let c of this.entities.values()){let p=c.deref();p&&ct(p,s)}else for(let c of s.affectedOids){let h=this.entities.get(c)?.deref();h&&(ct(h,s),this.emit(`change:${c}`),this.emit("change:*",c))}};this.applyOperations=(e,n,r,o)=>{let s,c=this.storeTools.now;for(let p of r)if(!(o&&p.timestamp<=o)){if(Ci(p.timestamp,c)>0){s=p.timestamp;continue}p.data.op==="delete"?n=!0:(e=Pe(e,p.data),p.data.op==="initialize"&&(n=!1))}return s&&this.context.globalEvents.emit("futureSeen",s),{view:e,deleted:n,empty:!e&&!r.length}};this.computeView=e=>{if(this.baselinesMap.size===0&&this.operationsMap.size===0&&this.localOperationsMap.size===0)return this.context.log("debug",`Entity ${e} accessed with no data at all`),{view:null,deleted:!0,lastTimestamp:null};let n=this.computeConfirmedView(e),r=this.localOperationsMap.get(e)||[];if(n.empty&&!r.length)return this.context.log("debug",`Entity ${e} accessed with no local data at all`),{view:null,deleted:!0,lastTimestamp:null};let{view:o,deleted:s}=this.applyOperations(n.view,n.deleted,r);return o&&$(o,e),{view:o,deleted:s,lastTimestamp:this.getLastTimestamp(e)}};this.computeConfirmedView=e=>{let n=this.baselinesMap.get(e),r=this.operationsMap.get(e)||[],o=se(n?.snapshot||void 0),s=this.applyOperations(o,!o,r,n?.timestamp);return s.view&&$(s.view,e),s.empty&&this.context.log("debug",`Entity ${e} accessed with no confirmed data`),s};this.getLastTimestamp=e=>{let n=this.localOperationsMap.get(e);n?.length||(n=this.operationsMap.get(e)||[]);let r=null;return n.length?r=n[n.length-1]?.timestamp:r=this.baselinesMap.get(e)?.timestamp??null,r?this.storeTools.time.getWallClockTime(r):null};this.getEntity=({oid:e,fieldSchema:n,parent:r,readonlyKeys:o,fieldKey:s})=>{let p=this.entities.get(e)?.deref();return p||(p=new ye({oid:e,cache:this,fieldSchema:n,store:this.storeTools,parent:r,readonlyKeys:o,fieldPath:s?[...r?.fieldPath??[],s]:void 0}),this.entities.set(e,this.context.weakRef(p))),p};this.hasOid=e=>this.operationsMap.has(e)||this.baselinesMap.has(e);this.dispose=()=>{this.entities.forEach(e=>e.deref()?.dispose()),this.entities.clear()};this.reset=({operations:e,baselines:n,dropExistingUnconfirmed:r=!1,unconfirmedOperations:o,dropAll:s})=>{this.context.log("debug",`Resetting cache for ${this.oid} with ${e.length} ops and ${n.length} baselines, dropUnconfirmed=${r}`);let c={isLocal:!1,affectedOids:new Set};s&&this.baselinesMap.clear(),this.insertBaselines(n,c),s&&this.operationsMap.clear(),this.insertOperations(e,c),(o||r)&&(this.localOperationsMap.clear(),o&&this.insertLocalOperations(o));for(let p of this.entities.keys()){let S=this.entities.get(p)?.deref();S&&(ct(S,c),this.emit(`change:${p}`),this.emit("change:*",p))}};this.oid=e,this.operationsMap=new Map,this.localOperationsMap=new Map,this.baselinesMap=new Map,this.storeTools={addLocalOperations:n.addLocalOperations,patchCreator:n.meta.patchCreator,addFile:n.files.add,getFile:n.files.get,time:n.meta.time,now:n.meta.now},this.context=r}get initializedPromise(){return this._initialized.promise}get weakRef(){return this.context.weakRef}};var tn="@@default",nn=class{constructor({context:t,meta:e,batchTimeout:n=200,files:r}){this.documentFamilyCaches=new Map;this.unsubscribes=[];this._disposed=!1;this.currentBatchKey=tn;this.setContext=t=>{this.context=t};this.getDocumentSchema=t=>{let{collection:e}=ae(t);if(!this.schema.collections[e])return this.log("warn",`Missing schema for collection: ${e}`),{schema:null,readonlyKeys:[]};let n=this.schema.collections[e];return{readonlyKeys:[n.primaryKey],schema:{type:"object",properties:n.fields}}};this.refreshFamilyCache=async(t,e=!1,n=!1)=>{if(this._disposed){this.context.log("debug",`EntityStore is disposed, not refreshing ${t.oid} cache`);return}let r=this.meta.createTransaction(["baselines","operations"]),o=[],s=[];await Promise.all([this.meta.baselines.iterateOverAllForDocument(t.oid,c=>{o.push(c)},{transaction:r,mode:"readwrite"}),this.meta.operations.iterateOverAllOperationsForDocument(t.oid,c=>{c.confirmed=!0,s.push(c)},{transaction:r,mode:"readwrite"})]),t.reset({operations:s,baselines:o,dropExistingUnconfirmed:e,dropAll:n})};this.openFamilyCache=async t=>{let e=K(t),n=this.documentFamilyCaches.get(e);return n||(this.context.log("debug","opening family cache for",e),n=new en({oid:e,store:this,context:this.context}),this.documentFamilyCaches.set(e,n),await this.refreshFamilyCache(n),n.setInitialized()),await n.initializedPromise,n};this.onEntityChange=async t=>{};this.writeDocumentToStorage=async t=>{if(this._disposed){this.log("warn","EntityStore is disposed, not writing to storage");return}let e=K(t),{id:n,collection:r}=ae(e),o=await this.get(e);if(this._disposed){this.log("warn","EntityStore is disposed, not writing to storage");return}let s=o?.getSnapshot();if(s){let c=Rt(this.schema.collections[r],s);try{let h=this.db.transaction(r,"readwrite").objectStore(r);await W(h.put(c)),this.log("info","\u{1F4DD}","wrote",r,n,"to storage",c)}catch{this.log("\u26A0\uFE0F CRITICAL: possibly corrupt data couldn't be written to queryable storage. This is probably a bug in verdant! Please report at https://github.com/a-type/verdant/issues",`
16
- `,"Invalid data:",JSON.stringify(c))}}else try{let p=this.db.transaction(r,"readwrite").objectStore(r);await W(p.delete(n)),this.log("info","\u274C","deleted",r,n,"from storage")}catch(c){if(c instanceof Error)if(c instanceof DOMException&&c.message?.includes("not found"))this.log("debug","document not found in storage",t);else throw c}};this.get=async t=>{let e=await this.openFamilyCache(t),{schema:n,readonlyKeys:r}=this.getDocumentSchema(t);return n?e.getEntity({oid:t,fieldSchema:n,readonlyKeys:r}):null};this.getCached=t=>{let e=this.documentFamilyCaches.get(t);if(e){let{schema:n,readonlyKeys:r}=this.getDocumentSchema(t);return n?e.getEntity({oid:t,fieldSchema:n,readonlyKeys:r}):null}return null};this.create=async(t,e,n)=>{It(t);let r=Me(t,this.files.add);$(r,e);let o=this.meta.patchCreator.createInitialize(r,e),s=await this.openFamilyCache(e);s.insertLocalOperations(o),await this.submitOperations(o,n);let{schema:c,readonlyKeys:p}=this.getDocumentSchema(e);if(!c)throw new Error(`Cannot create a document in the ${ae(e).collection} collection; it is not defined in the current schema version.`);return s.getEntity({oid:e,fieldSchema:c,readonlyKeys:p})};this.addOperationsToOpenCaches=async(t,e)=>{let n=Vn(t);Object.keys(n).forEach(o=>{let s=this.documentFamilyCaches.get(o);s&&(this.log("adding",e.confirmed?"confirmed":"unconfirmed","operations to cache",o,n[o].length),e.isLocal?s.insertLocalOperations(n[o]):s.insertOperations(n[o],e))})};this.addBaselinesToOpenCaches=async(t,e)=>{let n=Nn(t);Object.keys(n).forEach(o=>{let s=this.documentFamilyCaches.get(o);s&&(this.log("adding","baselines to cache",o,n[o].length),s.insertBaselines(n[o],e))})};this.addDataToOpenCaches=({baselines:t,operations:e,reset:n,isLocal:r})=>{let o=Nn(t),s=Vn(e),c=Array.from(new Set(Object.keys(o).concat(Object.keys(s))));for(let p of c){let h=this.documentFamilyCaches.get(p);h?(h.addData({operations:s[p]||[],baselines:o[p]||[],reset:n,isLocal:r}),this.log("debug","Added data to cache for",p,s[p]?.length??0,"operations",o[p]?.length??0,"baselines")):this.log("debug","Could not add data to cache for",p,"because it is not open")}return c};this.addData=async({operations:t,baselines:e,reset:n})=>{if(this._disposed){this.log("warn","EntityStore is disposed, not adding data");return}let r=t;for(let c of r)c.confirmed=!1;let o=[];n?(this.log("Resetting local store to replicate remote synced data",e.length,"baselines, and",t.length,"operations"),await this.meta.reset(),await this.resetStoredDocuments(),o=Array.from(new Set(e.map(c=>K(c.oid)).concat(t.map(c=>K(c.oid)))))):o=this.addDataToOpenCaches({operations:r,baselines:e,reset:n}),await this.meta.insertRemoteBaselines(e),await this.meta.insertRemoteOperations(t),n&&await this.refreshAllCaches(!0,!0);for(let c of o)await this.writeDocumentToStorage(c);let s=Array.from(new Set(o.map(c=>ae(c).collection)));this.context.log("changes to collections",s),this.context.entityEvents.emit("collectionsChanged",s)};this.addLocalOperations=async t=>{this.log("Adding local operations",t.length),this.addOperationsToOpenCaches(t,{isLocal:!0,confirmed:!1}),this.operationBatcher.add({key:this.currentBatchKey,items:t})};this.batch=({undoable:t=!0,batchName:e=Ot(),max:n=null,timeout:r=this.defaultBatchTimeout}={})=>{let o=this.operationBatcher.add({key:e,max:n,timeout:r,items:[],userData:{undoable:t}}),s={run:c=>(this.currentBatchKey=e,c(),this.currentBatchKey=tn,s),flush:async()=>(await this.operationBatcher.flush(tn),o.flush()),discard:()=>{this.operationBatcher.discard(e)}};return s};this.flushPatches=async()=>{await this.operationBatcher.flush(this.currentBatchKey)};this.flushAllBatches=async()=>{await Promise.all(this.operationBatcher.flushAll())};this.flushOperations=async(t,e,n)=>{if(t.length){this.log("Flushing operations",t.length,"to storage / sync");for(let r of t)r.timestamp=this.meta.now;await this.submitOperations(t,n)}};this.submitOperations=async(t,{undoable:e=!0}={})=>{e&&this.undoHistory.addUndo(await this.createUndo(t)),await this.meta.insertLocalOperation(t),this.addDataToOpenCaches({operations:t,baselines:[]});let n=Array.from(new Set(t.map(o=>K(o.oid))));for(let o of n)await this.writeDocumentToStorage(o);let r=new Set(t.map(({oid:o})=>ae(o).collection));this.context.log("changes to collections",r),this.context.entityEvents.emit("collectionsChanged",Array.from(r))};this.getInverseOperations=async t=>{let e=Ki(t),n=[],r=()=>this.meta.now;for(let[o,s]of Object.entries(e)){let c=await this.openFamilyCache(o),{view:p,deleted:h}=c.computeConfirmedView(o),S=Qi(o,p,s,r);n.unshift(...S)}return n};this.createUndo=async t=>{let e=await this.getInverseOperations(t);return async()=>{let n=await this.createUndo(e);return await this.submitOperations(e.map(r=>(r.timestamp=this.meta.now,r)),{undoable:!1}),n}};this.delete=async(t,e)=>{V(t===K(t),"Only root documents may be deleted via client methods");let n=await this.meta.getAllDocumentRelatedOids(t),r=this.meta.patchCreator.createDeleteAll(n);await this.submitOperations(r,e)};this.deleteAll=async(t,e)=>{let n=await Promise.all(t.map(o=>this.meta.getAllDocumentRelatedOids(o))),r=this.meta.patchCreator.createDeleteAll(n.flat());await this.submitOperations(r,e)};this.reset=async()=>{this.context.log("warn","Resetting local database"),await this.resetStoredDocuments(),await this.refreshAllCaches(!0)};this.destroy=async()=>{this._disposed=!0;for(let t of this.unsubscribes)t();for(let t of this.documentFamilyCaches.values())t.dispose();this.documentFamilyCaches.clear(),await this.flushAllBatches()};this.handleRebase=t=>{this.log("debug","Reacting to rebases",t.length),this.addBaselinesToOpenCaches(t,{isLocal:!0})};this.resetStoredDocuments=async()=>{let t=this.db.transaction(Object.keys(this.schema.collections),"readwrite");for(let e of Object.keys(this.schema.collections)){let n=t.objectStore(e);await W(n.clear())}};this.refreshAllCaches=async(t=!1,e=!1)=>{for(let[n,r]of this.documentFamilyCaches)await this.refreshFamilyCache(r,t,e)};this.context=t,this.defaultBatchTimeout=n,this.meta=e,this.files=r,this.operationBatcher=new Ve(this.flushOperations),this.operationBatcher.add({key:tn,items:[],max:100,timeout:n,userData:{undoable:!0}}),this.unsubscribes.push(this.meta.subscribe("rebase",this.handleRebase))}get log(){return this.context.log}get db(){return this.context.documentDb}get undoHistory(){return this.context.undoHistory}get schema(){return this.context.schema}};var ei=Symbol("handleMessage"),Co,lt=class extends N{constructor({initialPresence:e,updateBatchTimeout:n=200,defaultProfile:r}){super();this._peers={};this._self={profile:{}};this._selfReplicaIds=new Set;this._peerIds=new Array;this.isSelf=(e,n)=>e.id===n.replicaId||this._selfReplicaIds.has(n.replicaId)||this._self.id===n.id;this[Co]=async(e,n)=>{let r=!1,o=new Set(this.peerIds);if(n.type==="presence-changed")this.isSelf(e,n.userInfo)?(this._self=n.userInfo,this._selfReplicaIds.add(n.userInfo.replicaId),this.emit("selfChanged",n.userInfo)):(o.add(n.userInfo.id),this._peers[n.userInfo.id]=n.userInfo,r=!0,this.emit("peerChanged",n.userInfo.id,n.userInfo));else if(n.type==="sync-resp"){this._peers={},o.clear();for(let[s,c]of Object.entries(n.peerPresence))this.isSelf(e,c)?(this._self=c,this._selfReplicaIds.add(c.replicaId),this.emit("selfChanged",c)):(r=!0,o.add(s),this._peers[s]=c,this.emit("peerChanged",s,c))}else if(n.type==="presence-offline"){o.delete(n.userId),this._selfReplicaIds.delete(n.replicaId);let s=this._peers[n.userId];delete this._peers[n.userId],r=!0,this.emit("peerLeft",n.userId,s)}r&&(this._peerIds=Array.from(o),this.emit("peersChanged",this._peers))};this.update=async e=>{this._updateBatch.update({items:[e]}),this.self.presence={...this.self.presence,...e},this.emit("selfChanged",this.self)};this.flushPresenceUpdates=e=>{let n=e.reduce((r,o)=>({...r,...o}),this.self.presence);this.emit("update",n)};this.self.presence=e,this.self.profile=r,this._updateBatcher=new Ve(this.flushPresenceUpdates),this._updateBatch=this._updateBatcher.add({max:25,timeout:n,items:[],key:"default"})}static{Co=ei}get self(){return this._self}get peers(){return this._peers}get peerIds(){return this._peerIds}get everyone(){let e={...this._peers};return e[this.self.id]=this.self,e}get selfReplicaIds(){return this._selfReplicaIds}};var rn=class{constructor({endpointProvider:t,log:e}){this.uploadFile=async t=>{let e=t.file;if(!e)throw new Error("Cannot upload a non-local file");let{files:n,token:r}=await this.endpointProvider.getEndpoints(),o=new window.FormData;o.append("file",e);try{let s=await fetch(n+`/${t.id}`,{method:"POST",body:o,credentials:"include",headers:{Authorization:`Bearer ${r}`}});return s.ok?{success:!0,retry:!1}:(this.log("error","File upload failed",s.status,await s.text()),{success:!1,retry:s.status>=500})}catch(s){return this.log("error","File upload failed",s),{success:!1,retry:!0}}};this.getFile=async t=>{let{files:e,token:n}=await this.endpointProvider.getEndpoints();try{let r=await fetch(e+`/${t}`,{method:"GET",credentials:"include",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`}});return r.ok?{success:!0,data:await r.json()}:(this.log("error","File information fetch failed",r.status,await r.text()),{success:!1,retry:r.status>=500||r.status===404})}catch(r){return this.log("error","File information fetch failed",r),{success:!1,retry:!0}}};this.endpointProvider=t,this.log=e}};var Ke=class extends N{constructor({interval:e=15*1e3,deadlineLength:n=3*1e3,restartOnTabFocus:r=!0}={}){super();this.nextBeat=null;this.deadline=null;this.keepAlive=()=>{this.deadline&&(clearTimeout(this.deadline),this.deadline=null,this.start())};this.start=(e=!1)=>{this.stop(),e?this.beat():this.nextBeat=setTimeout(this.beat,this._interval)};this.stop=()=>{this.nextBeat&&clearTimeout(this.nextBeat),this.deadline&&clearTimeout(this.deadline)};this.beat=async()=>{this.emit("beat"),this.deadline=setTimeout(this.onDeadline,this.deadlineLength)};this.onDeadline=()=>{this.deadline=null,this.emit("missed")};this.setInterval=e=>{this._interval=e};this._interval=e,this.deadlineLength=n,typeof window<"u"&&r&&(window.addEventListener("pageshow",()=>this.start(!0)),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&this.start(!0)}))}get interval(){return this._interval}};var on=class extends N{constructor({endpointProvider:e,meta:n,presence:r,interval:o=15*1e3,log:s=()=>{}}){super();this.mode="pull";this._isConnected=!1;this._status="paused";this._hasSynced=!1;this.setInterval=e=>{this.heartbeat.setInterval(e)};this.sendRequest=async e=>{this.log("Sending sync request",e);try{let{http:n,token:r}=await this.endpointProvider.getEndpoints(),o=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`},body:JSON.stringify({messages:e}),credentials:"include"});if(o.ok){this.heartbeat.keepAlive();let s=await o.json();for(let c of s.messages)this.handleServerMessage(c);this._isConnected||(this._isConnected=!0,this.emit("onlineChange",!0))}else this.log("Sync request failed",o.status,await o.text()),this._isConnected&&(this._isConnected=!1,this.emit("onlineChange",!1)),o.status>=500&&this.heartbeat.keepAlive()}catch(n){this._isConnected&&(this._isConnected=!1,this.emit("onlineChange",!1)),this.log(n),this.heartbeat.keepAlive()}};this.handleServerMessage=async e=>{e.type==="sync-resp"&&(e.ackThisNonce&&(this.log("Sending sync ack",e.ackThisNonce),this.sendRequest([await this.meta.messageCreator.createAck(e.ackThisNonce)])),this._hasSynced=!0),this.emit("message",e)};this.send=e=>{switch(e.type){case"presence-update":case"sync":case"heartbeat":return this.sendRequest([e]);case"op":if(this._hasSynced)return this.sendRequest([e]);break}};this.dispose=()=>{};this.onHeartbeat=async()=>{this.sendRequest([await this.meta.messageCreator.createPresenceUpdate(this.presence.self.presence),await this.meta.messageCreator.createSyncStep1()])};this.onHeartbeatMissed=async()=>{this.emit("onlineChange",!1),this.log("Missed heartbeat"),this._isConnected=!1};this.log=s,this.meta=n,this.presence=r,this.endpointProvider=e,this.heartbeat=new Ke({interval:o}),this.heartbeat.subscribe("beat",this.onHeartbeat),this.heartbeat.subscribe("missed",this.onHeartbeatMissed)}get interval(){return this.heartbeat.interval}start(){this.status!=="active"&&(this.heartbeat.start(!0),this._status="active")}stop(){this.heartbeat.stop(),this._status="paused"}reconnect(){this.heartbeat.start(!0)}get isConnected(){return this._isConnected}get status(){return this._status}};function ti(i){this.message=i}ti.prototype=new Error,ti.prototype.name="InvalidCharacterError";var cr=typeof window<"u"&&window.atob&&window.atob.bind(window)||function(i){var t=String(i).replace(/=+$/,"");if(t.length%4==1)throw new ti("'atob' failed: The string to be decoded is not correctly encoded.");for(var e,n,r=0,o=0,s="";n=t.charAt(o++);~n&&(e=r%4?64*e+n:n,r++%4)?s+=String.fromCharCode(255&e>>(-2*r&6)):0)n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(n);return s};function Eo(i){var t=i.replace(/-/g,"+").replace(/_/g,"/");switch(t.length%4){case 0:break;case 2:t+="==";break;case 3:t+="=";break;default:throw"Illegal base64url string!"}try{return function(e){return decodeURIComponent(cr(e).replace(/(.)/g,function(n,r){var o=r.charCodeAt(0).toString(16).toUpperCase();return o.length<2&&(o="0"+o),"%"+o}))}(t)}catch{return cr(t)}}function sn(i){this.message=i}function Po(i,t){if(typeof i!="string")throw new sn("Invalid token specified");var e=(t=t||{}).header===!0?0:1;try{return JSON.parse(Eo(i.split(".")[e]))}catch(n){throw new sn("Invalid token specified: "+n.message)}}sn.prototype=new Error,sn.prototype.name="InvalidTokenError";var lr=Po;var an=class{constructor(t){this.config=t;this.cached=null;this.type=0;this.getEndpoints=async()=>{if(this.cached)return this.cached;let t;this.config.fetchAuth?t=await this.config.fetchAuth():t=await fetch(this.config.authEndpoint,{credentials:"include"}).then(c=>{if(c.ok)return c.json();throw new Error(`Auth endpoint returned non-200 response: ${c.status}`)}),V(t.accessToken,"No access token provided from auth endpoint");let e=lr(t.accessToken);V(e.url,"No sync endpoint provided from auth endpoint"),V(e.type!==void 0,"No replica type provided from auth endpoint"),this.type=parseInt(e.type+"");let n=new URL(e.url);n.protocol=n.protocol.replace("ws","http");let r=n.toString();n.protocol=n.protocol.replace("http","ws");let o=n.toString(),s=e.file;if(!s){let c=new URL(r);c.pathname=c.pathname+"/files",s=c.toString()}return this.cached={http:r,websocket:o,files:s,token:t.accessToken},this.cached};if(!t.authEndpoint&&!t.fetchAuth)throw new Error("Either authEndpoint or fetchAuth must be provided to ServerSyncEndpointProvider")}};var cn=class extends N{constructor(e){super();this.timer=null;this.isScheduled=!1;this.next=()=>{this.isScheduled||(this.isScheduled=!0,this.timer=setTimeout(()=>{this.emit("trigger"),this.isScheduled=!1,this.backoff.next()},this.backoff.current))};this.reset=()=>{this.backoff.reset(),this.timer&&(clearTimeout(this.timer),this.timer=null)};this.backoff=e}},ln=class{constructor(t,e){this.current=0;this.next=()=>{this.current=Math.min(this.max,this.current*this.factor)};this.reset=()=>{this.current=0};this.max=t,this.factor=e}};var dn=class extends N{constructor({endpointProvider:e,meta:n,presence:r,log:o}){super();this.socket=null;this.connectQueue=[];this.syncQueue=[];this._status="paused";this.synced=!1;this.hasStartedSync=!1;this.mode="realtime";this.log=(...e)=>{};this.heartbeat=new Ke;this.reconnectScheduler=new cn(new ln(60*1e3,1.5));this.onOpen=()=>{if(!this.socket)throw new Error("Invalid sync state: online but socket is null");if(this.synced=!1,this.connectQueue.length){for(let e of this.connectQueue)this.log("Sending queued message",JSON.stringify(e,null,2)),this.socket.send(JSON.stringify(e));this.connectQueue=[]}this.log("Sync connected"),this.onOnlineChange(!0),this.reconnectScheduler.reset()};this.onOnlineChange=async e=>{this.log("Socket online change",e),e?(this.log("Starting sync"),this.hasStartedSync=!0,this.synced=!1,this.send(await this.meta.messageCreator.createPresenceUpdate(this.presence.self.presence)),this.send(await this.meta.messageCreator.createSyncStep1()),this.heartbeat.start()):(this.hasStartedSync=!1,this.synced=!1,this.heartbeat.stop()),this.emit("onlineChange",e)};this.onMessage=async e=>{let n=JSON.parse(e.data);switch(n.type){case"sync-resp":if(n.ackThisNonce&&this.send(await this.meta.messageCreator.createAck(n.ackThisNonce)),this.hasStartedSync=!0,this.synced=!0,this.syncQueue.length){for(let r of this.syncQueue)this.send(r);this.syncQueue=[]}case"need-since":case"presence-changed":case"presence-offline":this.emit("message",n);break;case"op-re":if(!this.hasStartedSync){this.log("Skipping op-re message because sync hasn't started yet",n);break}this.emit("message",n);break;case"heartbeat-response":this.heartbeat.keepAlive(),this.emit("message",n);break;default:this.synced&&this.emit("message",n);break}};this.onError=e=>{this.log(e),this.reconnectScheduler.next(),this.log("Attempting reconnect to websocket sync")};this.onClose=e=>{this.log("Sync disconnected"),this.onOnlineChange(!1),this.onError(e)};this.initializeSocket=async()=>{let e=await this.endpointProvider.getEndpoints();return this.socket=new WebSocket(e.websocket,["Bearer",e.token]),this.socket.addEventListener("message",this.onMessage),this.socket.addEventListener("open",this.onOpen),this.socket.addEventListener("error",this.onError),this.socket.addEventListener("close",this.onClose),this.socket};this.sendHeartbeat=async()=>{this.send(await this.meta.messageCreator.createHeartbeat())};this.reconnect=()=>{this.stop(),this.start()};this.canSkipSyncWait=e=>e.type==="sync"||e.type==="presence-update"||e.type==="sync-ack"||e.type==="heartbeat";this.send=e=>{this.status==="active"&&(!this.hasStartedSync&&!this.canSkipSyncWait(e)||(this.canSkipSyncWait(e)?this.socket?.readyState===WebSocket.OPEN?(this.log("Sending message",JSON.stringify(e,null,2)),this.socket.send(JSON.stringify(e))):(this.log("Enqueueing message until socket is open",JSON.stringify(e,null,2)),this.connectQueue.push(e)):this.synced?this.socket?.readyState===WebSocket.OPEN&&(this.log("Sending message",JSON.stringify(e,null,2)),this.socket.send(JSON.stringify(e))):this.hasStartedSync&&(this.log("Enqueueing message until synced",JSON.stringify(e,null,2)),this.syncQueue.push(e))))};this.dispose=()=>{this.socket?.removeEventListener("message",this.onMessage),this.socket?.removeEventListener("close",this.onClose),this.socket?.close()};this.start=()=>{this.socket||(this.initializeSocket(),this._status="active")};this.stop=()=>{this.dispose(),this.socket=null,this._status="paused"};this.log=o||this.log,this.endpointProvider=e,this.meta=n,this.presence=r,this.reconnectScheduler.subscribe("trigger",this.initializeSocket),this.heartbeat.subscribe("beat",this.sendHeartbeat)}get isConnected(){return this.socket?.readyState===WebSocket.OPEN}get status(){return this._status}};var un=class extends N{constructor(){super(...arguments);this.mode="pull";this.dispose=()=>{};this.isConnected=!1;this.status="paused";this.pullInterval=0;this.presence=new lt({initialPresence:{},defaultProfile:{}});this.uploadFile=async()=>({success:!1,retry:!1});this.getFile=async()=>({success:!1,retry:!1})}send(){}start(){}stop(){}reconnect(){}setMode(){}setPullInterval(){}},$e=class extends N{constructor({authEndpoint:e,fetchAuth:n,initialPresence:r,automaticTransportSelection:o=!0,autoStart:s,initialTransport:c,pullInterval:p,presenceUpdateBatchTimeout:h,defaultProfile:S,useBroadcastChannel:E},{meta:g,log:P,onData:b}){super();this.broadcastChannel=null;this._activelySyncing=!1;this.handleBroadcastChannelMessage=e=>{e.data.type==="sync"&&this.handleMessage(e.data.message)};this.handleMessage=async e=>{if(e.type==="op-re"||e.type==="sync-resp")for(let n of e.operations)this.meta.time.update(n.timestamp);switch(this.log("sync message",JSON.stringify(e,null,2)),e.type){case"op-re":await this.onData({operations:e.operations,baselines:e.baselines}),e.globalAckTimestamp&&await this.meta.setGlobalAck(e.globalAckTimestamp);break;case"global-ack":await this.meta.setGlobalAck(e.timestamp);break;case"sync-resp":this._activelySyncing=!0,this.emit("syncingChange",!0),await this.onData({operations:e.operations,baselines:e.baselines,reset:e.overwriteLocalData}),e.globalAckTimestamp&&await this.meta.setGlobalAck(e.globalAckTimestamp),await this.meta.updateLastSynced(e.ackedTimestamp),this._activelySyncing=!1,this.emit("syncingChange",!1);break;case"need-since":this.activeSync.send(await this.meta.messageCreator.createSyncStep1(e.since));break;case"server-ack":await this.meta.updateLastSynced(e.timestamp)}this.broadcastChannel?.postMessage({type:"sync",message:e}),this.presence[ei](await this.meta.localReplica.get(),e)};this.handleOnlineChange=e=>{this.emit("onlineChange",e)};this.handlePresenceUpdate=async e=>{this.send(await this.meta.messageCreator.createPresenceUpdate(e))};this.setMode=e=>{if(e==="realtime"&&!this.canDoRealtime)throw new Error("Cannot switch to realtime mode, because the current auth token does not allow it");let n;e==="realtime"?n=this.webSocketSync:n=this.pushPullSync,n!==this.activeSync&&(this.log("switching to",e,"mode"),this.activeSync.status==="active"&&n.start(),this.activeSync.stop(),this.activeSync=n)};this.setPullInterval=e=>{this.pushPullSync.setInterval(e)};this.send=e=>{if(this.activeSync.status==="active")return this.activeSync.send(e)};this.uploadFile=async e=>this.activeSync.status==="active"?this.fileSync.uploadFile(e):{success:!1,retry:!1};this.getFile=async e=>{if(this.activeSync.status==="active")return this.fileSync.getFile(e);throw new Error("Offline, cannot retrieve remote file details")};this.start=()=>this.activeSync.start();this.stop=()=>this.activeSync.stop();this.dispose=()=>{this.webSocketSync.dispose(),this.pushPullSync.dispose()};this.reconnect=()=>this.activeSync.reconnect();if(this.meta=g,this.onData=b,this.log=P||(()=>{}),this.presence=new lt({initialPresence:r,defaultProfile:S,updateBatchTimeout:h}),this.endpointProvider=new an({authEndpoint:e,fetchAuth:n}),this.webSocketSync=new dn({endpointProvider:this.endpointProvider,meta:g,presence:this.presence,log:this.log}),this.pushPullSync=new on({endpointProvider:this.endpointProvider,meta:g,presence:this.presence,log:this.log,interval:p}),this.fileSync=new rn({endpointProvider:this.endpointProvider,log:this.log}),E&&"BroadcastChannel"in window&&(this.broadcastChannel=new BroadcastChannel("verdant"),this.broadcastChannel.addEventListener("message",this.handleBroadcastChannelMessage)),c==="realtime"?this.activeSync=this.webSocketSync:this.activeSync=this.pushPullSync,this.presence.subscribe("update",this.handlePresenceUpdate),this.meta.subscribe("message",this.send),this.webSocketSync.subscribe("message",this.handleMessage),this.webSocketSync.subscribe("onlineChange",this.handleOnlineChange),this.pushPullSync.subscribe("message",this.handleMessage),this.pushPullSync.subscribe("onlineChange",this.handleOnlineChange),o&&this.canDoRealtime){let v=()=>{C&&clearTimeout(C);let O=Object.keys(this.presence.peers).length>0||o!=="peers-only"&&this.presence.selfReplicaIds.size>1;O&&this.mode==="pull"?this.setMode("realtime"):!O&&this.mode==="realtime"&&(C=setTimeout(()=>{Object.keys(this.presence.peers).length===0&&this.setMode("pull")},1e3))},C;this.presence.subscribe("peersChanged",v),o!=="peers-only"&&this.presence.subscribe("selfChanged",v)}s&&this.start()}get canDoRealtime(){return this.endpointProvider.type===0||this.endpointProvider.type===2||this.endpointProvider.type===5}get syncing(){return this._activelySyncing}get pullInterval(){return this.pushPullSync.interval}get isConnected(){return this.activeSync.isConnected}get status(){return this.activeSync.status}get mode(){return this.activeSync.mode}};var ze=class{constructor(){this._disposes=[];this.disposed=!1;this.dispose=()=>{this.disposed=!0,this._disposes.forEach(t=>t()),this._disposes=[]};this.addDispose=t=>{this._disposes.push(t)}}};function To(i){return i!==null}function ni(i){return Array.isArray(i)?i.map(ni).filter(To):i instanceof ye&&i.deleted?null:i}function Ce(i,t){return!i&&!t||i&&t&&Ie(i)===Ie(t)}var ii=Symbol("ON_ALL_UNSUBSCRIBED"),ue=Symbol("UPDATE"),Ao,pe=class extends ze{constructor({initial:e,context:n,collection:r,key:o,shouldUpdate:s}){super();this._internalUnsubscribes=[];this._status="initial";this._executionPromise=null;this.setValue=e=>{this._rawValue=e,this.subscribeToDeleteAndRestore(this._rawValue),this._value=ni(e),this._status="ready",this._events.emit("change",this._value)};this.refreshValue=()=>{this.setValue(this._rawValue)};this.subscribeToDeleteAndRestore=e=>{for(;this._internalUnsubscribes.length;)this._internalUnsubscribes.pop()?.();Array.isArray(e)?e.forEach(n=>{n instanceof ye&&(this._internalUnsubscribes.push(n.subscribe("delete",this.refreshValue)),this._internalUnsubscribes.push(n.subscribe("restore",this.refreshValue)))}):e instanceof ye&&(this._internalUnsubscribes.push(e.subscribe("delete",this.refreshValue)),this._internalUnsubscribes.push(e.subscribe("restore",()=>{this.refreshValue()})))};this.execute=()=>(this.context.log("debug","Executing query",this.key),this._status==="initial"?this._status="initializing":this._status==="ready"&&(this._status="revalidating"),this._executionPromise=this.run().then(()=>this._value).catch(e=>{if(e instanceof Error&&(e.name==="InvalidStateError"||e.name==="InvalidAccessError"))return this._value;throw e}),this._executionPromise);this[Ao]=e=>{this._allUnsubscribedHandler=e};this._rawValue=e,this._value=e,this._events=new N(p=>{p==="change"&&this._allUnsubscribedHandler?.(this)}),this.context=n,this.key=o,this.collection=r;let c=s||(p=>p.includes(r));this.addDispose(this.context.entityEvents.subscribe("collectionsChanged",p=>{c(p)&&(this.context.log("info","Updating query",this.key),this.execute())}))}static{Ao=ii}get current(){return this._value}get resolved(){return this.status==="ready"?Promise.resolve(this._value):this._executionPromise??this.execute()}get subscribed(){return this._events.totalSubscriberCount()>0}get status(){return this._status}subscribe(e,n){if(n===void 0&&typeof e=="function")return this.resolved,this._events.subscribe("change",e);if(e==="change"&&n!==void 0)return this.resolved,this._events.subscribe("change",n);if(e==="statusChange"&&typeof n=="function")return this._events.subscribe(e,n);throw new Error("Invalid invocation of Query.subscribe")}};var fn=class extends pe{constructor({id:e,hydrate:n,...r}){super({initial:null,...r});this.run=async()=>{let e=await this.hydrate(this.oid);this.setValue(e)};this.oid=X(r.collection,e),this.hydrate=n}};var Ro,pn=class extends pe{constructor({index:e,hydrate:n,...r}){super({initial:null,...r});this.run=async()=>{let e=await qt({collection:this.collection,index:this.index,context:this.context});this.setValue(e?await this.hydrate(e):null)};this[Ro]=e=>{Ce(this.index,e)||(this.index=e,this.execute())};this.index=e,this.hydrate=n}static{Ro=ue}};var ko,hn=class extends pe{constructor({index:e,hydrate:n,pageSize:r,page:o,...s}){super({initial:[],...s});this._hasNextPage=!1;this.run=async()=>{let{result:e,hasNextPage:n}=await rt({collection:this.collection,index:this.index,context:this.context,limit:this._pageSize,offset:this._page*this._pageSize});this._hasNextPage=n,this.setValue(await Promise.all(e.map(this.hydrate)))};this.nextPage=async()=>{this.hasNextPage&&(this._page++,await this.run())};this.previousPage=async()=>{this._page!==0&&(this._page--,await this.run())};this.setPage=async e=>{this._page=e,await this.run()};this[ko]=e=>{Ce(this.index,e)||(this.index=e,this.execute())};this.index=e,this.hydrate=n,this._pageSize=r,this._page=o}static{ko=ue}get pageSize(){return this._pageSize}get page(){return this._page}get hasNextPage(){return this._hasNextPage}get hasPreviousPage(){return this._page>0}};var Bo,mn=class extends pe{constructor({hydrate:e,pageSize:n,index:r,...o}){super({initial:[],...o});this._upToPage=1;this._hasNextPage=!1;this.run=async()=>{let{result:e,hasNextPage:n}=await rt({collection:this.collection,context:this.context,limit:this._pageSize*this._upToPage,offset:0,index:this.index});this._hasNextPage=n,this.setValue(await Promise.all(e.map(this.hydrate)))};this.loadMore=async()=>{let{result:e,hasNextPage:n}=await rt({collection:this.collection,context:this.context,limit:this._pageSize,offset:this._pageSize*this._upToPage,index:this.index});this._hasNextPage=n,this._upToPage++,this.setValue([...this.current,...await Promise.all(e.map(this.hydrate))])};this[Bo]=e=>{Ce(this.index,e)||(this.index=e,this.execute())};this.index=r,this.hydrate=e,this._pageSize=n}static{Bo=ue}get pageSize(){return this._pageSize}get hasMore(){return this._hasNextPage}};var Mo,yn=class extends pe{constructor({index:e,hydrate:n,...r}){super({initial:[],...r});this.run=async()=>{let e=await Wt({collection:this.collection,index:this.index,context:this.context});this.setValue(await Promise.all(e.map(this.hydrate)))};this[Mo]=e=>{Ce(this.index,e)||(this.index=e,this.execute())};this.index=e,this.hydrate=n}static{Mo=ue}};var gn=class{constructor({collection:t,cache:e,entities:n,context:r,documentManager:o}){this.serializeIndex=t=>t?Ie(t):"";this.get=t=>{let e=`get:${this.collection}:${t}`;return this.cache.getOrSet(e,()=>new fn({id:t,collection:this.collection,hydrate:this.hydrate,context:this.context,key:e}))};this.findOne=({index:t,key:e}={})=>{let n=e||`findOne:${this.collection}:${this.serializeIndex(t)}`;return this.cache.getOrSet(n,()=>new pn({index:t,collection:this.collection,hydrate:this.hydrate,context:this.context,key:n}),r=>{r[ue](t)})};this.findAll=({index:t,key:e}={})=>{let n=e||`findAll:${this.collection}:${this.serializeIndex(t)}`;return this.cache.getOrSet(n,()=>new yn({index:t,collection:this.collection,hydrate:this.hydrate,context:this.context,key:n}),r=>{r[ue](t)})};this.findPage=({index:t,pageSize:e,page:n,key:r})=>{let o=r||`findPage:${this.collection}:${this.serializeIndex(t)}:${e}`;return this.cache.getOrSet(o,()=>new hn({index:t,collection:this.collection,hydrate:this.hydrate,context:this.context,key:o,pageSize:e,page:n}),s=>{s[ue](t)})};this.findAllInfinite=({index:t,pageSize:e,key:n})=>{let r=n||`findAllInfinite:${this.collection}:${this.serializeIndex(t)}:${e}`;return this.cache.getOrSet(r,()=>new mn({index:t,collection:this.collection,hydrate:this.hydrate,context:this.context,key:r,pageSize:e}),o=>{o[ue](t)})};this.cache=e,this.collection=t,this.hydrate=n.get,this.context=r,this.documentManager=o,this.put=this.documentManager.create.bind(this.documentManager,this.collection),this.delete=this.documentManager.delete.bind(this.documentManager,this.collection),this.deleteAll=this.documentManager.deleteAllFromCollection.bind(this.documentManager,this.collection)}};var bn=class extends ze{constructor({evictionTime:e=5*1e3,context:n}){super();this._cache=new Map;this.onQueryUnsubscribed=e=>{setTimeout(()=>{e.subscribed||this._cache.get(e.key)===e&&this._cache.delete(e.key)},this._evictionTime)};this._evictionTime=e,this.context=n}get(e){return this._cache.get(e)||null}set(e){return this._cache.set(e.key,e),e[ii](this.onQueryUnsubscribed),e}getOrSet(e,n,r){let o=this.get(e);return o?(r?.(o),o):this.set(n())}};var Fe=class extends N{constructor(e,n,r){super();this.config=e;this.context=n;this.addData=e=>this._entities.addData(e);this.stats=async()=>{let e=Object.keys(this.schema.collections),n={};for(let h of e)n[h]=await nt(this.documentDb,h);let r=await this.meta.stats(),o=typeof navigator<"u"&&typeof navigator.storage<"u"&&"estimate"in navigator.storage?await navigator.storage.estimate():void 0,s=Object.values(n).reduce((h,{size:S})=>h+S,0),c=r.baselinesSize.size+r.operationsSize.size,p=c/s;return{collections:n,meta:r,storage:o,totalMetaSize:c,totalCollectionsSize:s,metaToDataRatio:p,quotaUsage:o?.usage&&o?.quota?o.usage/o.quota:void 0}};this.close=async()=>{this.sync.stop(),this.sync.dispose(),await this._entities.destroy(),this.meta.close(),await new Promise(async e=>{await Re(this.documentDb),await Re(this.metaDb),e()}),this.context.log?.("Client closed")};this.__dangerous__resetLocal=async()=>{this.sync.stop(),await Ft(this.namespace,indexedDB)};this.export=async()=>{let e=await this.meta.export();return Buffer.from(JSON.stringify(e))};this.import=async e=>{this.context.log("Importing data..."),await Re(this.context.documentDb);let n=JSON.parse(e.toString());await this.meta.resetFrom(n);let r=n.schema.version,o=indexedDB.deleteDatabase([this.namespace,"collections"].join("_"));await new Promise((c,p)=>{o.onsuccess=c,o.onerror=p});let s=this.context.schema;this.context.schema=n.schema,this.context.documentDb=await ot({meta:this.meta,migrations:this.config.migrations,context:this.context,version:r}),this.context.log("Re-initializing data from imported data..."),await this._entities.addData({operations:n.operations,baselines:n.baselines,reset:!0}),await Re(this.context.documentDb),this.context.log("Migrating up to latest schema..."),this.context.schema=s,this.context.documentDb=await ot({meta:this.meta,migrations:this.config.migrations,context:this.context,version:s.version})};this.meta=r.meta,this.collectionNames=Object.keys(n.schema.collections),this._sync=this.config.syncConfig&&!n.schema.wip?new $e(this.config.syncConfig,{meta:this.meta,onData:this.addData,log:this.context.log}):new un,n.schema.wip&&this.config.syncConfig&&n.log("warn","\u26A0\uFE0F\u26A0\uFE0F Sync is disabled for WIP schemas. Commit your schema changes to start syncing again. \u26A0\uFE0F\u26A0\uFE0F"),this._fileManager=new Gt({db:this.metaDb,sync:this.sync,context:this.context,config:this.config.files,meta:this.meta}),this._entities=new nn({context:this.context,meta:this.meta,files:this._fileManager}),this._queryCache=new bn({context:n}),this._documentManager=new Jt(this.meta,this.schema,this._entities);let o=ji(()=>{this.emit("futureSeen")},300);this.context.globalEvents.subscribe("futureSeen",o),this.documentDb.addEventListener("versionchange",()=>{this.context.log?.(`Another tab has requested a version change for ${this.namespace}`),this.documentDb.close(),typeof window<"u"&&window.location.reload()}),this.metaDb.addEventListener("versionchange",()=>{this.context.log?.(`Another tab has requested a version change for ${this.namespace}`),this.metaDb.close(),typeof window<"u"&&window.location.reload()});for(let[s,c]of Object.entries(n.schema.collections)){let p=s;this[p]=new gn({collection:p,cache:this._queryCache,context:this.context,entities:this.entities,documentManager:this.documentManager})}}get sync(){return this._sync}get entities(){return this._entities}get documentManager(){return this._documentManager}get documentDb(){return this.context.documentDb}get metaDb(){return this.context.metaDb}get schema(){return this.context.schema}get namespace(){return this.context.namespace}get undoHistory(){return this.context.undoHistory}get presence(){return this.sync.presence}get batch(){return this.entities.batch}};var dt=class{constructor(t){this.value=t}deref(){return this.value}};var dr=Symbol("metadataVersion");var wn=class{constructor(t){this.init=t;this._initializing=!1;this.initialize=async t=>{if(typeof window>"u"&&!t.indexedDb)throw new Error("A verdant client was initialized in an environment without IndexedDB. If you are using verdant in a server-rendered framework, you must enforce that all clients are initialized on the client-side, or you must provide some mock interface of IDBFactory to the ClientDescriptor options.");if(this._initializing||this._resolvedValue)return this._readyPromise;this._initializing=!0;try{let e;return t.schema.wip?e=await this.initializeWIPDatabases(t):(e=await this.initializeDatabases(t),this.cleanupWIPDatabases(t)),this.resolveReady(e),this._resolvedValue=e,e}catch(e){throw this.rejectReady(e),e}finally{this._initializing=!1}};this.initializeDatabases=async t=>{let e=t[dr],{db:n}=await $t({indexedDB:t.indexedDb,log:t.log,namespace:t.namespace,metadataVersion:e}),r={namespace:this._namespace,metaDb:n,schema:t.schema,log:t.log||(()=>{}),undoHistory:t.undoHistory||new st,entityEvents:new N,globalEvents:new N,weakRef:h=>t.EXPERIMENTAL_weakRefs?new WeakRef(h):new dt(h)},o=new it({context:r,disableRebasing:t.disableRebasing});await o.updateSchema(t.schema,t.overrideSchemaConflict);let s=await ot({context:r,version:t.schema.version,meta:o,migrations:t.migrations,indexedDB:t.indexedDb}),c=Object.assign(r,{documentDb:s});return new Fe({syncConfig:t.sync,migrations:t.migrations,files:t.files},c,{meta:o})};this.initializeWIPDatabases=async t=>{let e=Ie(t.schema);console.info(`WIP schema in use. Opening database with hash ${e}`);let n=`@@wip_${t.namespace}_${e}`,{db:r}=await Zi({indexedDB:t.indexedDb,log:t.log,namespace:t.namespace,wipNamespace:n}),o={namespace:this._namespace,metaDb:r,schema:t.schema,log:t.log||(()=>{}),undoHistory:t.undoHistory||new st,entityEvents:new N,globalEvents:new N,weakRef:S=>t.EXPERIMENTAL_weakRefs?new WeakRef(S):new dt(S)},s=new it({context:o,disableRebasing:t.disableRebasing});await s.updateSchema(t.schema,t.overrideSchemaConflict);let c=await ir({context:o,version:t.schema.version,meta:s,migrations:t.migrations,indexedDB:t.indexedDb,wipNamespace:n}),p=Object.assign(o,{documentDb:c});return new Fe({syncConfig:t.sync,migrations:t.migrations,files:t.files},p,{meta:s})};this.cleanupWIPDatabases=async t=>{let r=(await Gi(t.indexedDb)).filter(o=>o.name?.startsWith("@@wip_")).map(o=>o.name).filter(o=>!o.startsWith(`@@wip_${t.namespace}_${Ie(t.schema)}`));for(let o of r)await Yi(o,t.indexedDb)};this.open=()=>this.initialize(this.init);this.close=async()=>{this._resolvedValue&&this._resolvedValue.close(),this._initializing&&(await this._readyPromise).close()};this.__dangerous__resetLocal=async()=>{await Ft(this.namespace)};this._readyPromise=new Promise((e,n)=>{this.resolveReady=e,this.rejectReady=n}),this._namespace=t.namespace}get namespace(){return this._namespace}get current(){return this._resolvedValue}get readyPromise(){return this._readyPromise}get schema(){return this.init.schema}};window.Verdant=ri;
16
+ `,"Invalid data:",JSON.stringify(c))}}else try{let p=this.db.transaction(r,"readwrite").objectStore(r);await W(p.delete(n)),this.log("info","\u274C","deleted",r,n,"from storage")}catch(c){if(c instanceof Error)if(c instanceof DOMException&&c.message?.includes("not found"))this.log("debug","document not found in storage",t);else throw c}};this.get=async t=>{let e=await this.openFamilyCache(t),{schema:n,readonlyKeys:r}=this.getDocumentSchema(t);return n?e.getEntity({oid:t,fieldSchema:n,readonlyKeys:r}):null};this.getCached=t=>{let e=this.documentFamilyCaches.get(t);if(e){let{schema:n,readonlyKeys:r}=this.getDocumentSchema(t);return n?e.getEntity({oid:t,fieldSchema:n,readonlyKeys:r}):null}return null};this.create=async(t,e,n)=>{It(t);let r=Me(t,this.files.add);$(r,e);let o=this.meta.patchCreator.createInitialize(r,e),s=await this.openFamilyCache(e);s.insertLocalOperations(o),await this.submitOperations(o,n);let{schema:c,readonlyKeys:p}=this.getDocumentSchema(e);if(!c)throw new Error(`Cannot create a document in the ${ae(e).collection} collection; it is not defined in the current schema version.`);return s.getEntity({oid:e,fieldSchema:c,readonlyKeys:p})};this.addOperationsToOpenCaches=async(t,e)=>{let n=Vn(t);Object.keys(n).forEach(o=>{let s=this.documentFamilyCaches.get(o);s&&(this.log("adding",e.confirmed?"confirmed":"unconfirmed","operations to cache",o,n[o].length),e.isLocal?s.insertLocalOperations(n[o]):s.insertOperations(n[o],e))})};this.addBaselinesToOpenCaches=async(t,e)=>{let n=Nn(t);Object.keys(n).forEach(o=>{let s=this.documentFamilyCaches.get(o);s&&(this.log("adding","baselines to cache",o,n[o].length),s.insertBaselines(n[o],e))})};this.addDataToOpenCaches=({baselines:t,operations:e,reset:n,isLocal:r})=>{let o=Nn(t),s=Vn(e),c=Array.from(new Set(Object.keys(o).concat(Object.keys(s))));for(let p of c){let h=this.documentFamilyCaches.get(p);h?(h.addData({operations:s[p]||[],baselines:o[p]||[],reset:n,isLocal:r}),this.log("debug","Added data to cache for",p,s[p]?.length??0,"operations",o[p]?.length??0,"baselines")):this.log("debug","Could not add data to cache for",p,"because it is not open")}return c};this.addData=async({operations:t,baselines:e,reset:n})=>{if(this._disposed){this.log("warn","EntityStore is disposed, not adding data");return}let r=t;for(let c of r)c.confirmed=!1;let o=[];n?(this.log("Resetting local store to replicate remote synced data",e.length,"baselines, and",t.length,"operations"),await this.meta.reset(),await this.resetStoredDocuments(),o=Array.from(new Set(e.map(c=>K(c.oid)).concat(t.map(c=>K(c.oid)))))):o=this.addDataToOpenCaches({operations:r,baselines:e,reset:n}),await this.meta.insertRemoteBaselines(e),await this.meta.insertRemoteOperations(t),n&&await this.refreshAllCaches(!0,!0);for(let c of o)await this.writeDocumentToStorage(c);let s=Array.from(new Set(o.map(c=>ae(c).collection)));this.context.log("changes to collections",s),this.context.entityEvents.emit("collectionsChanged",s)};this.addLocalOperations=async t=>{this.log("Adding local operations",t.length),this.addOperationsToOpenCaches(t,{isLocal:!0,confirmed:!1}),this.operationBatcher.add({key:this.currentBatchKey,items:t})};this.batch=({undoable:t=!0,batchName:e=Ot(),max:n=null,timeout:r=this.defaultBatchTimeout}={})=>{let o=this.operationBatcher.add({key:e,max:n,timeout:r,items:[],userData:{undoable:t}}),s={run:c=>(this.currentBatchKey=e,c(),this.currentBatchKey=tn,s),flush:async()=>(await this.operationBatcher.flush(tn),o.flush()),discard:()=>{this.operationBatcher.discard(e)}};return s};this.flushPatches=async()=>{await this.operationBatcher.flush(this.currentBatchKey)};this.flushAllBatches=async()=>{await Promise.all(this.operationBatcher.flushAll())};this.flushOperations=async(t,e,n)=>{if(t.length){this.log("Flushing operations",t.length,"to storage / sync");for(let r of t)r.timestamp=this.meta.now;await this.submitOperations(t,n)}};this.submitOperations=async(t,{undoable:e=!0}={})=>{e&&this.undoHistory.addUndo(await this.createUndo(t)),await this.meta.insertLocalOperation(t),this.addDataToOpenCaches({operations:t,baselines:[]});let n=Array.from(new Set(t.map(o=>K(o.oid))));for(let o of n)await this.writeDocumentToStorage(o);let r=new Set(t.map(({oid:o})=>ae(o).collection));this.context.log("changes to collections",r),this.context.entityEvents.emit("collectionsChanged",Array.from(r))};this.getInverseOperations=async t=>{let e=Ki(t),n=[],r=()=>this.meta.now;for(let[o,s]of Object.entries(e)){let c=await this.openFamilyCache(o),{view:p,deleted:h}=c.computeConfirmedView(o),S=Qi(o,p,s,r);n.unshift(...S)}return n};this.createUndo=async t=>{let e=await this.getInverseOperations(t);return async()=>{let n=await this.createUndo(e);return await this.submitOperations(e.map(r=>(r.timestamp=this.meta.now,r)),{undoable:!1}),n}};this.delete=async(t,e)=>{V(t===K(t),"Only root documents may be deleted via client methods");let n=await this.meta.getAllDocumentRelatedOids(t),r=this.meta.patchCreator.createDeleteAll(n);await this.submitOperations(r,e)};this.deleteAll=async(t,e)=>{let n=await Promise.all(t.map(o=>this.meta.getAllDocumentRelatedOids(o))),r=this.meta.patchCreator.createDeleteAll(n.flat());await this.submitOperations(r,e)};this.reset=async()=>{this.context.log("warn","Resetting local database"),await this.resetStoredDocuments(),await this.refreshAllCaches(!0)};this.destroy=async()=>{this._disposed=!0;for(let t of this.unsubscribes)t();for(let t of this.documentFamilyCaches.values())t.dispose();this.documentFamilyCaches.clear(),await this.flushAllBatches()};this.handleRebase=t=>{this.log("debug","Reacting to rebases",t.length),this.addBaselinesToOpenCaches(t,{isLocal:!0})};this.resetStoredDocuments=async()=>{let t=this.db.transaction(Object.keys(this.schema.collections),"readwrite");for(let e of Object.keys(this.schema.collections)){let n=t.objectStore(e);await W(n.clear())}};this.refreshAllCaches=async(t=!1,e=!1)=>{for(let[n,r]of this.documentFamilyCaches)await this.refreshFamilyCache(r,t,e)};this.context=t,this.defaultBatchTimeout=n,this.meta=e,this.files=r,this.operationBatcher=new Ve(this.flushOperations),this.operationBatcher.add({key:tn,items:[],max:100,timeout:n,userData:{undoable:!0}}),this.unsubscribes.push(this.meta.subscribe("rebase",this.handleRebase))}get log(){return this.context.log}get db(){return this.context.documentDb}get undoHistory(){return this.context.undoHistory}get schema(){return this.context.schema}};var ei=Symbol("handleMessage"),Co,lt=class extends N{constructor({initialPresence:e,updateBatchTimeout:n=200,defaultProfile:r}){super();this._peers={};this._self={profile:{}};this._selfReplicaIds=new Set;this._peerIds=new Array;this.isSelf=(e,n)=>e.id===n.replicaId||this._selfReplicaIds.has(n.replicaId)||this._self.id===n.id;this[Co]=async(e,n)=>{let r=!1,o=new Set(this.peerIds);if(n.type==="presence-changed")this.isSelf(e,n.userInfo)?(this._self=n.userInfo,this._selfReplicaIds.add(n.userInfo.replicaId),this.emit("selfChanged",n.userInfo)):(o.add(n.userInfo.id),this._peers[n.userInfo.id]=n.userInfo,r=!0,this.emit("peerChanged",n.userInfo.id,n.userInfo));else if(n.type==="sync-resp"){this._peers={},o.clear();for(let[s,c]of Object.entries(n.peerPresence))this.isSelf(e,c)?(this._self=c,this._selfReplicaIds.add(c.replicaId),this.emit("selfChanged",c)):(r=!0,o.add(s),this._peers[s]=c,this.emit("peerChanged",s,c))}else if(n.type==="presence-offline"){o.delete(n.userId),this._selfReplicaIds.delete(n.replicaId);let s=this._peers[n.userId];delete this._peers[n.userId],r=!0,this.emit("peerLeft",n.userId,s)}r&&(this._peerIds=Array.from(o),this.emit("peersChanged",this._peers))};this.update=async e=>{this._updateBatch.update({items:[e]}),this.self.presence={...this.self.presence,...e},this.emit("selfChanged",this.self)};this.flushPresenceUpdates=e=>{let n=e.reduce((r,o)=>({...r,...o}),this.self.presence);this.emit("update",n)};this.self.presence=e,this.self.profile=r,this._updateBatcher=new Ve(this.flushPresenceUpdates),this._updateBatch=this._updateBatcher.add({max:25,timeout:n,items:[],key:"default"})}static{Co=ei}get self(){return this._self}get peers(){return this._peers}get peerIds(){return this._peerIds}get everyone(){let e={...this._peers};return e[this.self.id]=this.self,e}get selfReplicaIds(){return this._selfReplicaIds}};var rn=class{constructor({endpointProvider:t,log:e}){this.uploadFile=async t=>{let e=t.file;if(!e)throw new Error("Cannot upload a non-local file");let{files:n,token:r}=await this.endpointProvider.getEndpoints(),o=new window.FormData;o.append("file",e);try{let s=await fetch(n+`/${t.id}`,{method:"POST",body:o,credentials:"include",headers:{Authorization:`Bearer ${r}`}});return s.ok?{success:!0,retry:!1}:(this.log("error","File upload failed",s.status,await s.text()),{success:!1,retry:s.status>=500})}catch(s){return this.log("error","File upload failed",s),{success:!1,retry:!0}}};this.getFile=async t=>{let{files:e,token:n}=await this.endpointProvider.getEndpoints();try{let r=await fetch(e+`/${t}`,{method:"GET",credentials:"include",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`}});return r.ok?{success:!0,data:await r.json()}:(this.log("error","File information fetch failed",r.status,await r.text()),{success:!1,retry:r.status>=500||r.status===404})}catch(r){return this.log("error","File information fetch failed",r),{success:!1,retry:!0}}};this.endpointProvider=t,this.log=e}};var Ke=class extends N{constructor({interval:e=15*1e3,deadlineLength:n=3*1e3,restartOnTabFocus:r=!0}={}){super();this.nextBeat=null;this.deadline=null;this.keepAlive=()=>{this.deadline&&(clearTimeout(this.deadline),this.deadline=null,this.start())};this.start=(e=!1)=>{this.stop(),e?this.beat():this.nextBeat=setTimeout(this.beat,this._interval)};this.stop=()=>{this.nextBeat&&clearTimeout(this.nextBeat),this.deadline&&clearTimeout(this.deadline)};this.beat=async()=>{this.emit("beat"),this.deadline=setTimeout(this.onDeadline,this.deadlineLength)};this.onDeadline=()=>{this.deadline=null,this.emit("missed")};this.setInterval=e=>{this._interval=e};this._interval=e,this.deadlineLength=n,typeof window<"u"&&r&&(window.addEventListener("pageshow",()=>this.start(!0)),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&this.start(!0)}))}get interval(){return this._interval}};var on=class extends N{constructor({endpointProvider:e,meta:n,presence:r,interval:o=15*1e3,log:s=()=>{}}){super();this.mode="pull";this._isConnected=!1;this._status="paused";this._hasSynced=!1;this.setInterval=e=>{this.heartbeat.setInterval(e)};this.sendRequest=async e=>{this.log("Sending sync request",e);try{let{http:n,token:r}=await this.endpointProvider.getEndpoints(),o=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`},body:JSON.stringify({messages:e}),credentials:"include"});if(o.ok){this.heartbeat.keepAlive();let s=await o.json();for(let c of s.messages)this.handleServerMessage(c);this._isConnected||(this._isConnected=!0,this.emit("onlineChange",!0))}else this.log("Sync request failed",o.status,await o.text()),this._isConnected&&(this._isConnected=!1,this.emit("onlineChange",!1)),o.status>=500&&this.heartbeat.keepAlive()}catch(n){this._isConnected&&(this._isConnected=!1,this.emit("onlineChange",!1)),this.log(n),this.heartbeat.keepAlive()}};this.handleServerMessage=async e=>{e.type==="sync-resp"&&(e.ackThisNonce&&(this.log("Sending sync ack",e.ackThisNonce),this.sendRequest([await this.meta.messageCreator.createAck(e.ackThisNonce)])),this._hasSynced=!0),this.emit("message",e)};this.send=e=>{switch(e.type){case"presence-update":case"sync":case"heartbeat":return this.sendRequest([e]);case"op":if(this._hasSynced)return this.sendRequest([e]);break}};this.dispose=()=>{};this.onHeartbeat=async()=>{this.sendRequest([await this.meta.messageCreator.createPresenceUpdate(this.presence.self.presence),await this.meta.messageCreator.createSyncStep1()])};this.onHeartbeatMissed=async()=>{this.emit("onlineChange",!1),this.log("Missed heartbeat"),this._isConnected=!1};this.log=s,this.meta=n,this.presence=r,this.endpointProvider=e,this.heartbeat=new Ke({interval:o}),this.heartbeat.subscribe("beat",this.onHeartbeat),this.heartbeat.subscribe("missed",this.onHeartbeatMissed)}get interval(){return this.heartbeat.interval}start(){this.status!=="active"&&(this.heartbeat.start(!0),this._status="active")}stop(){this.heartbeat.stop(),this._status="paused"}reconnect(){this.heartbeat.start(!0)}get isConnected(){return this._isConnected}get status(){return this._status}};function ti(i){this.message=i}ti.prototype=new Error,ti.prototype.name="InvalidCharacterError";var cr=typeof window<"u"&&window.atob&&window.atob.bind(window)||function(i){var t=String(i).replace(/=+$/,"");if(t.length%4==1)throw new ti("'atob' failed: The string to be decoded is not correctly encoded.");for(var e,n,r=0,o=0,s="";n=t.charAt(o++);~n&&(e=r%4?64*e+n:n,r++%4)?s+=String.fromCharCode(255&e>>(-2*r&6)):0)n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(n);return s};function Eo(i){var t=i.replace(/-/g,"+").replace(/_/g,"/");switch(t.length%4){case 0:break;case 2:t+="==";break;case 3:t+="=";break;default:throw"Illegal base64url string!"}try{return function(e){return decodeURIComponent(cr(e).replace(/(.)/g,function(n,r){var o=r.charCodeAt(0).toString(16).toUpperCase();return o.length<2&&(o="0"+o),"%"+o}))}(t)}catch{return cr(t)}}function sn(i){this.message=i}function Po(i,t){if(typeof i!="string")throw new sn("Invalid token specified");var e=(t=t||{}).header===!0?0:1;try{return JSON.parse(Eo(i.split(".")[e]))}catch(n){throw new sn("Invalid token specified: "+n.message)}}sn.prototype=new Error,sn.prototype.name="InvalidTokenError";var lr=Po;var an=class{constructor(t){this.config=t;this.cached=null;this.type=0;this.getEndpoints=async()=>{if(this.cached)return this.cached;let t;this.config.fetchAuth?t=await this.config.fetchAuth():t=await fetch(this.config.authEndpoint,{credentials:"include"}).then(c=>{if(c.ok)return c.json();throw new Error(`Auth endpoint returned non-200 response: ${c.status}`)}),V(t.accessToken,"No access token provided from auth endpoint");let e=lr(t.accessToken);V(e.url,"No sync endpoint provided from auth endpoint"),V(e.type!==void 0,"No replica type provided from auth endpoint"),this.type=parseInt(e.type+"");let n=new URL(e.url);n.protocol=n.protocol.replace("ws","http");let r=n.toString();n.protocol=n.protocol.replace("http","ws");let o=n.toString(),s=e.file;if(!s){let c=new URL(r);c.pathname=c.pathname+"/files",s=c.toString()}return this.cached={http:r,websocket:o,files:s,token:t.accessToken},this.cached};if(!t.authEndpoint&&!t.fetchAuth)throw new Error("Either authEndpoint or fetchAuth must be provided to ServerSyncEndpointProvider")}};var cn=class extends N{constructor(e){super();this.timer=null;this.isScheduled=!1;this.next=()=>{this.isScheduled||(this.isScheduled=!0,this.timer=setTimeout(()=>{this.emit("trigger"),this.isScheduled=!1,this.backoff.next()},this.backoff.current))};this.reset=()=>{this.backoff.reset(),this.timer&&(clearTimeout(this.timer),this.timer=null)};this.backoff=e}},ln=class{constructor(t,e){this.current=0;this.next=()=>{this.current=Math.min(this.max,this.current*this.factor)};this.reset=()=>{this.current=0};this.max=t,this.factor=e}};var dn=class extends N{constructor({endpointProvider:e,meta:n,presence:r,log:o}){super();this.socket=null;this.connectQueue=[];this.syncQueue=[];this._status="paused";this.synced=!1;this.hasStartedSync=!1;this.mode="realtime";this.log=(...e)=>{};this.heartbeat=new Ke;this.reconnectScheduler=new cn(new ln(60*1e3,1.5));this.onOpen=()=>{if(!this.socket)throw new Error("Invalid sync state: online but socket is null");if(this.synced=!1,this.connectQueue.length){for(let e of this.connectQueue)this.log("Sending queued message",JSON.stringify(e,null,2)),this.socket.send(JSON.stringify(e));this.connectQueue=[]}this.log("Sync connected"),this.onOnlineChange(!0),this.reconnectScheduler.reset()};this.onOnlineChange=async e=>{this.log("Socket online change",e),e?(this.log("Starting sync"),this.hasStartedSync=!0,this.synced=!1,this.send(await this.meta.messageCreator.createPresenceUpdate(this.presence.self.presence)),this.send(await this.meta.messageCreator.createSyncStep1()),this.heartbeat.start()):(this.hasStartedSync=!1,this.synced=!1,this.heartbeat.stop()),this.emit("onlineChange",e)};this.onMessage=async e=>{let n=JSON.parse(e.data);switch(n.type){case"sync-resp":if(n.ackThisNonce&&this.send(await this.meta.messageCreator.createAck(n.ackThisNonce)),this.hasStartedSync=!0,this.synced=!0,this.syncQueue.length){for(let r of this.syncQueue)this.send(r);this.syncQueue=[]}case"need-since":case"presence-changed":case"presence-offline":this.emit("message",n);break;case"op-re":if(!this.hasStartedSync){this.log("Skipping op-re message because sync hasn't started yet",n);break}this.emit("message",n);break;case"heartbeat-response":this.heartbeat.keepAlive(),this.emit("message",n);break;default:this.synced&&this.emit("message",n);break}};this.onError=e=>{this.log(e),this.reconnectScheduler.next(),this.log("Attempting reconnect to websocket sync")};this.onClose=e=>{this.log("Sync disconnected"),this.onOnlineChange(!1),this.onError(e)};this.initializeSocket=async()=>{let e=await this.endpointProvider.getEndpoints();return this.socket=new WebSocket(e.websocket,["Bearer",e.token]),this.socket.addEventListener("message",this.onMessage),this.socket.addEventListener("open",this.onOpen),this.socket.addEventListener("error",this.onError),this.socket.addEventListener("close",this.onClose),this.socket};this.sendHeartbeat=async()=>{this.send(await this.meta.messageCreator.createHeartbeat())};this.reconnect=()=>{this.stop(),this.start()};this.canSkipSyncWait=e=>e.type==="sync"||e.type==="presence-update"||e.type==="sync-ack"||e.type==="heartbeat";this.send=e=>{this.status==="active"&&(!this.hasStartedSync&&!this.canSkipSyncWait(e)||(this.canSkipSyncWait(e)?this.socket?.readyState===WebSocket.OPEN?(this.log("Sending message",JSON.stringify(e,null,2)),this.socket.send(JSON.stringify(e))):(this.log("Enqueueing message until socket is open",JSON.stringify(e,null,2)),this.connectQueue.push(e)):this.synced?this.socket?.readyState===WebSocket.OPEN&&(this.log("Sending message",JSON.stringify(e,null,2)),this.socket.send(JSON.stringify(e))):this.hasStartedSync&&(this.log("Enqueueing message until synced",JSON.stringify(e,null,2)),this.syncQueue.push(e))))};this.dispose=()=>{this.socket?.removeEventListener("message",this.onMessage),this.socket?.removeEventListener("close",this.onClose),this.socket?.close()};this.start=()=>{this.socket||(this.initializeSocket(),this._status="active")};this.stop=()=>{this.dispose(),this.socket=null,this._status="paused"};this.log=o||this.log,this.endpointProvider=e,this.meta=n,this.presence=r,this.reconnectScheduler.subscribe("trigger",this.initializeSocket),this.heartbeat.subscribe("beat",this.sendHeartbeat)}get isConnected(){return this.socket?.readyState===WebSocket.OPEN}get status(){return this._status}};var un=class extends N{constructor(){super(...arguments);this.mode="pull";this.dispose=()=>{};this.isConnected=!1;this.status="paused";this.pullInterval=0;this.presence=new lt({initialPresence:{},defaultProfile:{}});this.uploadFile=async()=>({success:!1,retry:!1});this.getFile=async()=>({success:!1,retry:!1})}send(){}start(){}stop(){}reconnect(){}setMode(){}setPullInterval(){}},$e=class extends N{constructor({authEndpoint:e,fetchAuth:n,initialPresence:r,automaticTransportSelection:o=!0,autoStart:s,initialTransport:c,pullInterval:p,presenceUpdateBatchTimeout:h,defaultProfile:S,useBroadcastChannel:E},{meta:g,log:P,onData:b}){super();this.broadcastChannel=null;this._activelySyncing=!1;this.handleBroadcastChannelMessage=e=>{e.data.type==="sync"&&this.handleMessage(e.data.message,{source:"broadcastChannel"})};this.handleMessage=async(e,{source:n}={source:"network"})=>{if(e.type==="op-re"||e.type==="sync-resp")for(let r of e.operations)this.meta.time.update(r.timestamp);switch(this.log("sync message",JSON.stringify(e,null,2)),e.type){case"op-re":await this.onData({operations:e.operations,baselines:e.baselines}),e.globalAckTimestamp&&await this.meta.setGlobalAck(e.globalAckTimestamp);break;case"global-ack":await this.meta.setGlobalAck(e.timestamp);break;case"sync-resp":this._activelySyncing=!0,this.emit("syncingChange",!0),await this.onData({operations:e.operations,baselines:e.baselines,reset:e.overwriteLocalData}),e.globalAckTimestamp&&await this.meta.setGlobalAck(e.globalAckTimestamp),await this.meta.updateLastSynced(e.ackedTimestamp),this._activelySyncing=!1,this.emit("syncingChange",!1);break;case"need-since":this.activeSync.send(await this.meta.messageCreator.createSyncStep1(e.since));break;case"server-ack":await this.meta.updateLastSynced(e.timestamp)}n==="network"&&this.broadcastChannel?.postMessage({type:"sync",message:e}),this.presence[ei](await this.meta.localReplica.get(),e)};this.handleOnlineChange=e=>{this.emit("onlineChange",e)};this.handlePresenceUpdate=async e=>{this.send(await this.meta.messageCreator.createPresenceUpdate(e))};this.setMode=e=>{if(e==="realtime"&&!this.canDoRealtime)throw new Error("Cannot switch to realtime mode, because the current auth token does not allow it");let n;e==="realtime"?n=this.webSocketSync:n=this.pushPullSync,n!==this.activeSync&&(this.log("switching to",e,"mode"),this.activeSync.status==="active"&&n.start(),this.activeSync.stop(),this.activeSync=n)};this.setPullInterval=e=>{this.pushPullSync.setInterval(e)};this.send=e=>{if(this.activeSync.status==="active")return this.activeSync.send(e)};this.uploadFile=async e=>this.activeSync.status==="active"?this.fileSync.uploadFile(e):{success:!1,retry:!1};this.getFile=async e=>{if(this.activeSync.status==="active")return this.fileSync.getFile(e);throw new Error("Offline, cannot retrieve remote file details")};this.start=()=>this.activeSync.start();this.stop=()=>this.activeSync.stop();this.dispose=()=>{this.webSocketSync.dispose(),this.pushPullSync.dispose()};this.reconnect=()=>this.activeSync.reconnect();if(this.meta=g,this.onData=b,this.log=P||(()=>{}),this.presence=new lt({initialPresence:r,defaultProfile:S,updateBatchTimeout:h}),this.endpointProvider=new an({authEndpoint:e,fetchAuth:n}),this.webSocketSync=new dn({endpointProvider:this.endpointProvider,meta:g,presence:this.presence,log:this.log}),this.pushPullSync=new on({endpointProvider:this.endpointProvider,meta:g,presence:this.presence,log:this.log,interval:p}),this.fileSync=new rn({endpointProvider:this.endpointProvider,log:this.log}),E&&"BroadcastChannel"in window&&(this.broadcastChannel=new BroadcastChannel("verdant"),this.broadcastChannel.addEventListener("message",this.handleBroadcastChannelMessage)),c==="realtime"?this.activeSync=this.webSocketSync:this.activeSync=this.pushPullSync,this.presence.subscribe("update",this.handlePresenceUpdate),this.meta.subscribe("message",this.send),this.webSocketSync.subscribe("message",this.handleMessage),this.webSocketSync.subscribe("onlineChange",this.handleOnlineChange),this.pushPullSync.subscribe("message",this.handleMessage),this.pushPullSync.subscribe("onlineChange",this.handleOnlineChange),o&&this.canDoRealtime){let v=()=>{C&&clearTimeout(C);let O=Object.keys(this.presence.peers).length>0||o!=="peers-only"&&this.presence.selfReplicaIds.size>1;O&&this.mode==="pull"?this.setMode("realtime"):!O&&this.mode==="realtime"&&(C=setTimeout(()=>{Object.keys(this.presence.peers).length===0&&this.setMode("pull")},1e3))},C;this.presence.subscribe("peersChanged",v),o!=="peers-only"&&this.presence.subscribe("selfChanged",v)}s&&this.start()}get canDoRealtime(){return this.endpointProvider.type===0||this.endpointProvider.type===2||this.endpointProvider.type===5}get syncing(){return this._activelySyncing}get pullInterval(){return this.pushPullSync.interval}get isConnected(){return this.activeSync.isConnected}get status(){return this.activeSync.status}get mode(){return this.activeSync.mode}};var ze=class{constructor(){this._disposes=[];this.disposed=!1;this.dispose=()=>{this.disposed=!0,this._disposes.forEach(t=>t()),this._disposes=[]};this.addDispose=t=>{this._disposes.push(t)}}};function To(i){return i!==null}function ni(i){return Array.isArray(i)?i.map(ni).filter(To):i instanceof ye&&i.deleted?null:i}function Ce(i,t){return!i&&!t||i&&t&&Ie(i)===Ie(t)}var ii=Symbol("ON_ALL_UNSUBSCRIBED"),ue=Symbol("UPDATE"),Ao,pe=class extends ze{constructor({initial:e,context:n,collection:r,key:o,shouldUpdate:s}){super();this._internalUnsubscribes=[];this._status="initial";this._executionPromise=null;this.setValue=e=>{this._rawValue=e,this.subscribeToDeleteAndRestore(this._rawValue),this._value=ni(e),this._status="ready",this._events.emit("change",this._value)};this.refreshValue=()=>{this.setValue(this._rawValue)};this.subscribeToDeleteAndRestore=e=>{for(;this._internalUnsubscribes.length;)this._internalUnsubscribes.pop()?.();Array.isArray(e)?e.forEach(n=>{n instanceof ye&&(this._internalUnsubscribes.push(n.subscribe("delete",this.refreshValue)),this._internalUnsubscribes.push(n.subscribe("restore",this.refreshValue)))}):e instanceof ye&&(this._internalUnsubscribes.push(e.subscribe("delete",this.refreshValue)),this._internalUnsubscribes.push(e.subscribe("restore",()=>{this.refreshValue()})))};this.execute=()=>(this.context.log("debug","Executing query",this.key),this._status==="initial"?this._status="initializing":this._status==="ready"&&(this._status="revalidating"),this._executionPromise=this.run().then(()=>this._value).catch(e=>{if(e instanceof Error&&(e.name==="InvalidStateError"||e.name==="InvalidAccessError"))return this._value;throw e}),this._executionPromise);this[Ao]=e=>{this._allUnsubscribedHandler=e};this._rawValue=e,this._value=e,this._events=new N(p=>{p==="change"&&this._allUnsubscribedHandler?.(this)}),this.context=n,this.key=o,this.collection=r;let c=s||(p=>p.includes(r));this.addDispose(this.context.entityEvents.subscribe("collectionsChanged",p=>{c(p)&&(this.context.log("info","Updating query",this.key),this.execute())}))}static{Ao=ii}get current(){return this._value}get resolved(){return this.status==="ready"?Promise.resolve(this._value):this._executionPromise??this.execute()}get subscribed(){return this._events.totalSubscriberCount()>0}get status(){return this._status}subscribe(e,n){if(n===void 0&&typeof e=="function")return this.resolved,this._events.subscribe("change",e);if(e==="change"&&n!==void 0)return this.resolved,this._events.subscribe("change",n);if(e==="statusChange"&&typeof n=="function")return this._events.subscribe(e,n);throw new Error("Invalid invocation of Query.subscribe")}};var fn=class extends pe{constructor({id:e,hydrate:n,...r}){super({initial:null,...r});this.run=async()=>{let e=await this.hydrate(this.oid);this.setValue(e)};this.oid=X(r.collection,e),this.hydrate=n}};var Ro,pn=class extends pe{constructor({index:e,hydrate:n,...r}){super({initial:null,...r});this.run=async()=>{let e=await qt({collection:this.collection,index:this.index,context:this.context});this.setValue(e?await this.hydrate(e):null)};this[Ro]=e=>{Ce(this.index,e)||(this.index=e,this.execute())};this.index=e,this.hydrate=n}static{Ro=ue}};var ko,hn=class extends pe{constructor({index:e,hydrate:n,pageSize:r,page:o,...s}){super({initial:[],...s});this._hasNextPage=!1;this.run=async()=>{let{result:e,hasNextPage:n}=await rt({collection:this.collection,index:this.index,context:this.context,limit:this._pageSize,offset:this._page*this._pageSize});this._hasNextPage=n,this.setValue(await Promise.all(e.map(this.hydrate)))};this.nextPage=async()=>{this.hasNextPage&&(this._page++,await this.run())};this.previousPage=async()=>{this._page!==0&&(this._page--,await this.run())};this.setPage=async e=>{this._page=e,await this.run()};this[ko]=e=>{Ce(this.index,e)||(this.index=e,this.execute())};this.index=e,this.hydrate=n,this._pageSize=r,this._page=o}static{ko=ue}get pageSize(){return this._pageSize}get page(){return this._page}get hasNextPage(){return this._hasNextPage}get hasPreviousPage(){return this._page>0}};var Bo,mn=class extends pe{constructor({hydrate:e,pageSize:n,index:r,...o}){super({initial:[],...o});this._upToPage=1;this._hasNextPage=!1;this.run=async()=>{let{result:e,hasNextPage:n}=await rt({collection:this.collection,context:this.context,limit:this._pageSize*this._upToPage,offset:0,index:this.index});this._hasNextPage=n,this.setValue(await Promise.all(e.map(this.hydrate)))};this.loadMore=async()=>{let{result:e,hasNextPage:n}=await rt({collection:this.collection,context:this.context,limit:this._pageSize,offset:this._pageSize*this._upToPage,index:this.index});this._hasNextPage=n,this._upToPage++,this.setValue([...this.current,...await Promise.all(e.map(this.hydrate))])};this[Bo]=e=>{Ce(this.index,e)||(this.index=e,this.execute())};this.index=r,this.hydrate=e,this._pageSize=n}static{Bo=ue}get pageSize(){return this._pageSize}get hasMore(){return this._hasNextPage}};var Mo,yn=class extends pe{constructor({index:e,hydrate:n,...r}){super({initial:[],...r});this.run=async()=>{let e=await Wt({collection:this.collection,index:this.index,context:this.context});this.setValue(await Promise.all(e.map(this.hydrate)))};this[Mo]=e=>{Ce(this.index,e)||(this.index=e,this.execute())};this.index=e,this.hydrate=n}static{Mo=ue}};var gn=class{constructor({collection:t,cache:e,entities:n,context:r,documentManager:o}){this.serializeIndex=t=>t?Ie(t):"";this.get=t=>{let e=`get:${this.collection}:${t}`;return this.cache.getOrSet(e,()=>new fn({id:t,collection:this.collection,hydrate:this.hydrate,context:this.context,key:e}))};this.findOne=({index:t,key:e}={})=>{let n=e||`findOne:${this.collection}:${this.serializeIndex(t)}`;return this.cache.getOrSet(n,()=>new pn({index:t,collection:this.collection,hydrate:this.hydrate,context:this.context,key:n}),r=>{r[ue](t)})};this.findAll=({index:t,key:e}={})=>{let n=e||`findAll:${this.collection}:${this.serializeIndex(t)}`;return this.cache.getOrSet(n,()=>new yn({index:t,collection:this.collection,hydrate:this.hydrate,context:this.context,key:n}),r=>{r[ue](t)})};this.findPage=({index:t,pageSize:e,page:n,key:r})=>{let o=r||`findPage:${this.collection}:${this.serializeIndex(t)}:${e}`;return this.cache.getOrSet(o,()=>new hn({index:t,collection:this.collection,hydrate:this.hydrate,context:this.context,key:o,pageSize:e,page:n}),s=>{s[ue](t)})};this.findAllInfinite=({index:t,pageSize:e,key:n})=>{let r=n||`findAllInfinite:${this.collection}:${this.serializeIndex(t)}:${e}`;return this.cache.getOrSet(r,()=>new mn({index:t,collection:this.collection,hydrate:this.hydrate,context:this.context,key:r,pageSize:e}),o=>{o[ue](t)})};this.cache=e,this.collection=t,this.hydrate=n.get,this.context=r,this.documentManager=o,this.put=this.documentManager.create.bind(this.documentManager,this.collection),this.delete=this.documentManager.delete.bind(this.documentManager,this.collection),this.deleteAll=this.documentManager.deleteAllFromCollection.bind(this.documentManager,this.collection)}};var bn=class extends ze{constructor({evictionTime:e=5*1e3,context:n}){super();this._cache=new Map;this.onQueryUnsubscribed=e=>{setTimeout(()=>{e.subscribed||this._cache.get(e.key)===e&&this._cache.delete(e.key)},this._evictionTime)};this._evictionTime=e,this.context=n}get(e){return this._cache.get(e)||null}set(e){return this._cache.set(e.key,e),e[ii](this.onQueryUnsubscribed),e}getOrSet(e,n,r){let o=this.get(e);return o?(r?.(o),o):this.set(n())}};var Fe=class extends N{constructor(e,n,r){super();this.config=e;this.context=n;this.addData=e=>this._entities.addData(e);this.stats=async()=>{let e=Object.keys(this.schema.collections),n={};for(let h of e)n[h]=await nt(this.documentDb,h);let r=await this.meta.stats(),o=typeof navigator<"u"&&typeof navigator.storage<"u"&&"estimate"in navigator.storage?await navigator.storage.estimate():void 0,s=Object.values(n).reduce((h,{size:S})=>h+S,0),c=r.baselinesSize.size+r.operationsSize.size,p=c/s;return{collections:n,meta:r,storage:o,totalMetaSize:c,totalCollectionsSize:s,metaToDataRatio:p,quotaUsage:o?.usage&&o?.quota?o.usage/o.quota:void 0}};this.close=async()=>{this.sync.stop(),this.sync.dispose(),await this._entities.destroy(),this.meta.close(),await new Promise(async e=>{await Re(this.documentDb),await Re(this.metaDb),e()}),this.context.log?.("Client closed")};this.__dangerous__resetLocal=async()=>{this.sync.stop(),await Ft(this.namespace,indexedDB)};this.export=async()=>{let e=await this.meta.export();return Buffer.from(JSON.stringify(e))};this.import=async e=>{this.context.log("Importing data..."),await Re(this.context.documentDb);let n=JSON.parse(e.toString());await this.meta.resetFrom(n);let r=n.schema.version,o=indexedDB.deleteDatabase([this.namespace,"collections"].join("_"));await new Promise((c,p)=>{o.onsuccess=c,o.onerror=p});let s=this.context.schema;this.context.schema=n.schema,this.context.documentDb=await ot({meta:this.meta,migrations:this.config.migrations,context:this.context,version:r}),this.context.log("Re-initializing data from imported data..."),await this._entities.addData({operations:n.operations,baselines:n.baselines,reset:!0}),await Re(this.context.documentDb),this.context.log("Migrating up to latest schema..."),this.context.schema=s,this.context.documentDb=await ot({meta:this.meta,migrations:this.config.migrations,context:this.context,version:s.version})};this.meta=r.meta,this.collectionNames=Object.keys(n.schema.collections),this._sync=this.config.syncConfig&&!n.schema.wip?new $e(this.config.syncConfig,{meta:this.meta,onData:this.addData,log:this.context.log}):new un,n.schema.wip&&this.config.syncConfig&&n.log("warn","\u26A0\uFE0F\u26A0\uFE0F Sync is disabled for WIP schemas. Commit your schema changes to start syncing again. \u26A0\uFE0F\u26A0\uFE0F"),this._fileManager=new Gt({db:this.metaDb,sync:this.sync,context:this.context,config:this.config.files,meta:this.meta}),this._entities=new nn({context:this.context,meta:this.meta,files:this._fileManager}),this._queryCache=new bn({context:n}),this._documentManager=new Jt(this.meta,this.schema,this._entities);let o=ji(()=>{this.emit("futureSeen")},300);this.context.globalEvents.subscribe("futureSeen",o),this.documentDb.addEventListener("versionchange",()=>{this.context.log?.(`Another tab has requested a version change for ${this.namespace}`),this.documentDb.close(),typeof window<"u"&&window.location.reload()}),this.metaDb.addEventListener("versionchange",()=>{this.context.log?.(`Another tab has requested a version change for ${this.namespace}`),this.metaDb.close(),typeof window<"u"&&window.location.reload()});for(let[s,c]of Object.entries(n.schema.collections)){let p=s;this[p]=new gn({collection:p,cache:this._queryCache,context:this.context,entities:this.entities,documentManager:this.documentManager})}}get sync(){return this._sync}get entities(){return this._entities}get documentManager(){return this._documentManager}get documentDb(){return this.context.documentDb}get metaDb(){return this.context.metaDb}get schema(){return this.context.schema}get namespace(){return this.context.namespace}get undoHistory(){return this.context.undoHistory}get presence(){return this.sync.presence}get batch(){return this.entities.batch}};var dt=class{constructor(t){this.value=t}deref(){return this.value}};var dr=Symbol("metadataVersion");var wn=class{constructor(t){this.init=t;this._initializing=!1;this.initialize=async t=>{if(typeof window>"u"&&!t.indexedDb)throw new Error("A verdant client was initialized in an environment without IndexedDB. If you are using verdant in a server-rendered framework, you must enforce that all clients are initialized on the client-side, or you must provide some mock interface of IDBFactory to the ClientDescriptor options.");if(this._initializing||this._resolvedValue)return this._readyPromise;this._initializing=!0;try{let e;return t.schema.wip?e=await this.initializeWIPDatabases(t):(e=await this.initializeDatabases(t),this.cleanupWIPDatabases(t)),this.resolveReady(e),this._resolvedValue=e,e}catch(e){throw this.rejectReady(e),e}finally{this._initializing=!1}};this.initializeDatabases=async t=>{let e=t[dr],{db:n}=await $t({indexedDB:t.indexedDb,log:t.log,namespace:t.namespace,metadataVersion:e}),r={namespace:this._namespace,metaDb:n,schema:t.schema,log:t.log||(()=>{}),undoHistory:t.undoHistory||new st,entityEvents:new N,globalEvents:new N,weakRef:h=>t.EXPERIMENTAL_weakRefs?new WeakRef(h):new dt(h)},o=new it({context:r,disableRebasing:t.disableRebasing});await o.updateSchema(t.schema,t.overrideSchemaConflict);let s=await ot({context:r,version:t.schema.version,meta:o,migrations:t.migrations,indexedDB:t.indexedDb}),c=Object.assign(r,{documentDb:s});return new Fe({syncConfig:t.sync,migrations:t.migrations,files:t.files},c,{meta:o})};this.initializeWIPDatabases=async t=>{let e=Ie(t.schema);console.info(`WIP schema in use. Opening database with hash ${e}`);let n=`@@wip_${t.namespace}_${e}`,{db:r}=await Zi({indexedDB:t.indexedDb,log:t.log,namespace:t.namespace,wipNamespace:n}),o={namespace:this._namespace,metaDb:r,schema:t.schema,log:t.log||(()=>{}),undoHistory:t.undoHistory||new st,entityEvents:new N,globalEvents:new N,weakRef:S=>t.EXPERIMENTAL_weakRefs?new WeakRef(S):new dt(S)},s=new it({context:o,disableRebasing:t.disableRebasing});await s.updateSchema(t.schema,t.overrideSchemaConflict);let c=await ir({context:o,version:t.schema.version,meta:s,migrations:t.migrations,indexedDB:t.indexedDb,wipNamespace:n}),p=Object.assign(o,{documentDb:c});return new Fe({syncConfig:t.sync,migrations:t.migrations,files:t.files},p,{meta:s})};this.cleanupWIPDatabases=async t=>{let r=(await Gi(t.indexedDb)).filter(o=>o.name?.startsWith("@@wip_")).map(o=>o.name).filter(o=>!o.startsWith(`@@wip_${t.namespace}_${Ie(t.schema)}`));for(let o of r)await Yi(o,t.indexedDb)};this.open=()=>this.initialize(this.init);this.close=async()=>{this._resolvedValue&&this._resolvedValue.close(),this._initializing&&(await this._readyPromise).close()};this.__dangerous__resetLocal=async()=>{await Ft(this.namespace)};this._readyPromise=new Promise((e,n)=>{this.resolveReady=e,this.rejectReady=n}),this._namespace=t.namespace}get namespace(){return this._namespace}get current(){return this._resolvedValue}get readyPromise(){return this._readyPromise}get schema(){return this.init.schema}};window.Verdant=ri;
17
17
  //# sourceMappingURL=index.js.map