@live-state/sync 0.0.6-beta-2 → 0.0.6-beta-3
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.
- package/dist/client.js +1 -1
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {d,c,a,f,e,b as b$1}from'./chunk-AHF6GNMI.js';import {useSyncExternalStore,useEffect}from'react';import {xxHash32}from'js-xxhash';import {z as z$1}from'zod';import {stringify}from'qs';import ue from'fast-deep-equal';import {openDB}from'idb';var g=p=>xxHash32(JSON.stringify(p)).toString(32);var b=(p,e,t=false)=>Object.entries(e).every(([s,i])=>{if(s==="$and")return i.every(r=>b(p,r,t));if(s==="$or")return i.some(r=>b(p,r,t));let o=(i==null?void 0:i.$eq)!==void 0?i==null?void 0:i.$eq:i;if(typeof i=="object"&&i!==null&&(i==null?void 0:i.$eq)===void 0){if(i.$in!==void 0){let n=p[s];return n===void 0?false:t?!i.$in.includes(n):i.$in.includes(n)}if(i.$not!==void 0&&!t)return b(p,{[s]:i.$not},true);if(i.$gt!==void 0){let n=p[s];return typeof n!="number"?false:t?n<=i.$gt:n>i.$gt}if(i.$gte!==void 0){let n=p[s];return typeof n!="number"?false:t?n<i.$gte:n>=i.$gte}if(i.$lt!==void 0){let n=p[s];return typeof n!="number"?false:t?n>=i.$lt:n<i.$lt}if(i.$lte!==void 0){let n=p[s];return typeof n!="number"?false:t?n>i.$lte:n<=i.$lte}let r=p[s];return !r||typeof r!="object"&&!Array.isArray(r)?false:Array.isArray(r)?t?!r.some(n=>b(n,i,false)):r.some(n=>b(n,i,false)):b(r,i,t)}return t?p[s]!==o:p[s]===o}),v={CRITICAL:0,ERROR:1,WARN:2,INFO:3,DEBUG:4},L=class{level;prefix;constructor(e={}){this.level=e.level??v.INFO,this.prefix=e.prefix?`[${e.prefix}] `:"";}critical(...e){this.level>=v.CRITICAL&&console.error(`${this.prefix}[CRITICAL]`,...e);}error(...e){this.level>=v.ERROR&&console.error(`${this.prefix}[ERROR]`,...e);}warn(...e){this.level>=v.WARN&&console.warn(`${this.prefix}[WARN]`,...e);}info(...e){this.level>=v.INFO&&console.log(`${this.prefix}[INFO]`,...e);}debug(...e){this.level>=v.DEBUG&&console.log(`${this.prefix}[DEBUG]`,...e);}setLevel(e){this.level=e;}getLevel(){return this.level}},$=p=>new L(p);var x=class{subscriptions=new Map;getOrStoreSubscription(e){let t=g(e);return this.subscriptions.has(t)?this.subscriptions.get(t).subscribe:(this.subscriptions.set(t,{subscribe:s=>{var o;(o=this.subscriptions.get(t))==null||o.callbacks.add(s);let i=e.subscribe(()=>{var r;(r=this.subscriptions.get(t))==null||r.callbacks.forEach(n=>{n();});});return ()=>{var r;(r=this.subscriptions.get(t))==null||r.callbacks.delete(s),setTimeout(()=>{var n;((n=this.subscriptions.get(t))==null?void 0:n.callbacks.size)===0&&(this.subscriptions.delete(t),i());},10);}},callbacks:new Set}),this.subscriptions.get(t).subscribe)}},Z=new x,ye=p=>useSyncExternalStore(Z.getOrStoreSubscription(p),p.get),fe=(p,e)=>{useEffect(()=>{let t=p.load(e.buildQueryRequest());return ()=>{t();}},[e,p.load]);};var T=z$1.object({resource:z$1.string(),where:z$1.record(z$1.string(),z$1.any()).optional(),include:z$1.record(z$1.string(),z$1.any()).optional(),lastSyncedAt:z$1.string().optional(),limit:z$1.coerce.number().optional(),sort:z$1.array(z$1.object({key:z$1.string(),direction:z$1.enum(["asc","desc"])})).optional()}),I=z$1.record(z$1.string(),z$1.object({value:z$1.any().nullable(),_meta:z$1.object({timestamp:z$1.string().optional().nullable()}).optional()})),ee=I.superRefine((p,e)=>{p.id&&e.addIssue({code:z$1.ZodIssueCode.custom,message:"Payload cannot have an id"});}),Q=z$1.object({id:z$1.string().optional(),type:z$1.literal("MUTATE"),resource:z$1.string(),resourceId:z$1.string().optional()}),j=Q.extend({procedure:z$1.string(),payload:z$1.any().optional()}),k=Q.extend({procedure:z$1.enum(["INSERT","UPDATE"]),payload:ee});z$1.union([k,j]);var E=z$1.string(),te=T.extend({id:E,type:z$1.literal("SUBSCRIBE")}),ie=T.extend({id:E,type:z$1.literal("UNSUBSCRIBE")}),se=T.extend({id:E,type:z$1.literal("QUERY")}),G=k.extend({id:E}),ne=j.extend({id:E}),re=z$1.union([ne,G]);z$1.union([te,se,re,ie]);var oe=z$1.object({id:E,type:z$1.literal("REJECT"),resource:z$1.string(),message:z$1.string().optional()}),ae=z$1.object({id:E,type:z$1.literal("REPLY"),data:z$1.any()}),z=z$1.union([oe,ae,G]),q=z$1.object({resource:z$1.string(),data:z$1.array(I)});var R=class{ws=null;url;autoConnect;autoReconnect;reconnectTimeout;reconnectLimit;reconnectAttempts=0;eventListeners=new Map;reconnectTimer=null;intentionallyDisconnected=false;credentials;constructor(e){this.url=e.url,this.autoConnect=e.autoConnect??false,this.autoReconnect=e.autoReconnect??false,this.reconnectTimeout=e.reconnectTimeout??5e3,this.reconnectLimit=e.reconnectLimit,this.credentials=e.credentials,this.autoConnect&&this.connect();}connected(){var e;return ((e=this.ws)==null?void 0:e.readyState)===WebSocket.OPEN}async connect(){if(this.ws&&(this.ws.readyState===WebSocket.OPEN||this.ws.readyState===WebSocket.CONNECTING))return;this.intentionallyDisconnected=false;let e=await b$1(this.credentials);this.ws=new WebSocket(this.url+(e?`?${stringify(e)}`:"")),this.ws.addEventListener("open",this.handleOpen.bind(this)),this.ws.addEventListener("close",this.handleClose.bind(this)),this.ws.addEventListener("error",this.handleError.bind(this)),this.ws.addEventListener("message",this.handleMessage.bind(this));}disconnect(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.intentionallyDisconnected=true,this.ws&&(this.ws.close(),this.ws=null);}addEventListener(e,t){var s;this.eventListeners.has(e)||this.eventListeners.set(e,new Set),(s=this.eventListeners.get(e))==null||s.add(t);}removeEventListener(e,t){var s;this.eventListeners.has(e)&&((s=this.eventListeners.get(e))==null||s.delete(t));}send(e){if(this.ws&&this.ws.readyState===WebSocket.OPEN)this.ws.send(e);else throw new Error("WebSocket is not open")}handleOpen(e){this.reconnectAttempts=0,this.dispatchEvent("open",e),this.dispatchEvent("connectionChange",{open:true});}handleClose(e){this.dispatchEvent("close",e),this.dispatchEvent("connectionChange",{open:false}),this.autoReconnect&&!this.intentionallyDisconnected&&this.scheduleReconnect();}handleError(e){var t,s;this.dispatchEvent("error",e),this.dispatchEvent("connectionChange",{open:false}),(s=(t=e.error)==null?void 0:t.message)!=null&&s.includes("non-101")&&(this.ws&&(this.ws.close(),this.ws=null),this.autoReconnect&&!this.intentionallyDisconnected&&this.scheduleReconnect());}handleMessage(e){this.dispatchEvent("message",e);}scheduleReconnect(){this.reconnectLimit&&this.reconnectAttempts>=this.reconnectLimit||(this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{this.connect();},this.reconnectTimeout));}dispatchEvent(e,t){var s;(s=this.eventListeners.get(e))==null||s.forEach(i=>{i(t);});}};var O=class{constructor(e){this.logger=e;this.nodes=new Map;}nodes;createNode(e,t,s){if(this.nodes.has(e))throw new Error(`Node with id ${e} already exists`);let i={id:e,type:t,referencedBy:new Map(s.map(o=>[o,new Set])),references:new Map,subscriptions:new Set};return this.nodes.set(e,i),i}getNode(e){return this.nodes.get(e)}hasNode(e){return this.nodes.has(e)}createLink(e,t){let s=this.nodes.get(e),i=this.nodes.get(t);if(!s)throw new Error(`Source node with id ${e} does not exist`);if(!i)throw new Error(`Target node with id ${t} does not exist`);s.references.set(i.type,t);let o=i.referencedBy.get(s.type);o&&o instanceof Set?o.add(e):i.referencedBy.set(s.type,e),this.notifySubscribers(t);}removeLink(e,t){let s=this.nodes.get(e);if(!s)throw new Error(`Node with id ${e} does not exist`);let i=s.references.get(t);if(!i)return;s.references.delete(t);let o=this.nodes.get(i);if(!o)return;let r=o.referencedBy.get(s.type);r&&(r instanceof Set?r.delete(e):o.referencedBy.delete(s.type),this.notifySubscribers(i)),this.notifySubscribers(e);}subscribe(e,t){let s=this.nodes.get(e);if(!s)throw new Error(`Node with id ${e} does not exist`);return s.subscriptions.add(t),()=>{s.subscriptions.delete(t);}}removeNode(e){let t=this.nodes.get(e);t&&(Array.from(t.referencedBy.entries()).forEach(([s,i])=>{(i instanceof Set?Array.from(i.values()):[i]).forEach(r=>{let n=this.nodes.get(r);!n||!n.references.get(s)||(n.references.delete(s),this.notifySubscribers(r));});}),this.nodes.delete(e));}updateNode(e,t){let s=this.nodes.get(e);if(!s)throw new Error(`Node with id ${e} does not exist`);t(s),this.notifySubscribers(e);}notifySubscribers(e){let t=this.nodes.get(e);t&&Array.from(t.subscriptions).forEach(s=>{var i;try{s(e);}catch(o){(i=this.logger)==null||i.error(`Error in node subscription for node ${e}:`,o);}});}getAllNodes(){return Array.from(this.nodes.values())}};var D="__meta",C="databases",w=class{db;async init(e,t){var l,d;if(typeof window>"u")return;let i=((l=(await window.indexedDB.databases()).find(c=>c.name===t))==null?void 0:l.version)??1,o=await g(e),r=Object.fromEntries(await Promise.all(Object.entries(e).map(async([c,u])=>[c,await g(u)]))),n=await openDB("live-state-databases",1,{upgrade(c){c.objectStoreNames.contains(C)||c.createObjectStore(C);}}),a=(d=await this.getAll(n,C))==null?void 0:d[t];(a==null?void 0:a.schemaHash)!==o&&i++,this.db=await openDB(t,i,{async upgrade(c){[...Object.keys(e),D].forEach(u=>{(a==null?void 0:a.objectHashes[u])!==r[u]&&c.objectStoreNames.contains(u)&&c.deleteObjectStore(u),c.objectStoreNames.contains(u)||c.createObjectStore(u);}),await n.put(C,{schemaHash:o,objectHashes:r},t);},blocking(){window.location.reload();},blocked(){window.location.reload();}});}async get(e){return await this.getAll(this.db,e)??{}}getOne(e,t){return this.db?this.db.get(e,t):new Promise(s=>s(void 0))}set(e,t,s){var i;return (i=this.db)==null?void 0:i.put(e,s,t)}delete(e,t){var s;return (s=this.db)==null?void 0:s.delete(e,t)}getMeta(e){return this.db?this.db.get(D,e):new Promise(t=>t(void 0))}setMeta(e,t){var s;return (s=this.db)==null?void 0:s.put(D,t,e)}async getAll(e,t){if(!e)return;if(e.getAllRecords)return e.getAllRecords(t);let[s,i]=await Promise.all([e.getAll(t),e.getAllKeys(t)]);return Object.fromEntries(s.map((o,r)=>[i[r],o]))}};var A=class{constructor(e,t,s,i,o){this.schema=e;this.logger=s,this.optimisticObjGraph=new O(s),this.kvStorage=new w,t!==false&&this.kvStorage.init(this.schema,t.name).then(()=>{this.kvStorage.getMeta("mutationStack").then(r=>{!r||Object.keys(r).length===0||(this.optimisticMutationStack=r,i==null||i(this.optimisticMutationStack));}).then(()=>{Object.entries(this.schema).forEach(([r])=>{this.kvStorage.get(r).then(n=>{if(!n||Object.keys(n).length===0){o==null||o(r,0);return}let a=Object.values(n);o==null||o(r,a.length),this.loadConsolidatedState(r,a);});});}).catch(r=>{s.debug("Storage initialization failed (may not be available in this environment):",r);});});}rawObjPool={};optimisticMutationStack={};optimisticObjGraph;optimisticRawObjPool={};logger;collectionSubscriptions=new Map;querySnapshots={};kvStorage;get(e$1,t,s=false){var r;let i=t??g(e$1);if(this.querySnapshots[i]&&!s){let n=this.querySnapshots[i];if(n)return n}let o=((r=e$1.where)!=null&&r.id?[e$1.where.id]:Object.keys(this.optimisticRawObjPool[e$1.resource]??{})).flatMap(n=>{let a=f(this.materializeOneWithInclude(n,e$1.include));return a?[a]:[]});if(e$1.sort&&e$1.sort.length>0){let n=(a,l)=>{for(let d of e$1.sort){let c=a[d.key],u=l[d.key];if(c<u)return d.direction==="asc"?-1:1;if(c>u)return d.direction==="asc"?1:-1}return 0};o.sort(n);}if(e$1.where||e$1.limit){let n=e$1.where?a=>b(a,e$1.where):()=>true;o=e(o,n,e$1.limit);}return s||(this.querySnapshots[i]=o),o}subscribe(e,t){var o;let s=g(e);return this.collectionSubscriptions.get(s)||this.collectionSubscriptions.set(s,{callbacks:new Set,query:e,flatInclude:e.include?this.flattenIncludes(e.include,e.resource):void 0}),(o=this.collectionSubscriptions.get(s))==null||o.callbacks.add(t),()=>{var r,n;(r=this.collectionSubscriptions.get(s))==null||r.callbacks.delete(t),((n=this.collectionSubscriptions.get(s))==null?void 0:n.callbacks.size)===0&&(this.collectionSubscriptions.delete(s),delete this.querySnapshots[s]);}}addMutation(e,t,s=false){var r,n,a;let i=this.schema[e];if(this.logger.debug("Adding mutation",t),!i)throw new Error("Schema not found");let o=(r=this.optimisticRawObjPool[e])==null?void 0:r[t.resourceId];if(s)this.optimisticMutationStack[e]??=[],this.optimisticMutationStack[e].push(t);else {this.optimisticMutationStack[e]=((a=(n=this.optimisticMutationStack)==null?void 0:n[e])==null?void 0:a.filter(c=>c.id!==t.id))??[],this.rawObjPool[e]??={};let l={value:{...this.schema[e].mergeMutation("set",t.payload,this.rawObjPool[e][t.resourceId])[0].value,id:{value:t.resourceId}}};this.rawObjPool[e][t.resourceId]=l;let d=l.value;delete d.id,this.kvStorage.set(e,t.resourceId,d);}this.kvStorage.setMeta("mutationStack",this.optimisticMutationStack),this.updateRawObjPool(e,t.resourceId,t.payload,o);}undoMutation(e,t){var r,n;if(!this.optimisticMutationStack[e])return;let s=(r=this.optimisticMutationStack[e])==null?void 0:r.findIndex(a=>a.id===t);if(s===-1)return;let i=this.optimisticMutationStack[e][s];this.logger.debug("Removing mutation",i);let o=(n=this.optimisticRawObjPool[e])==null?void 0:n[i.resourceId];this.optimisticMutationStack[e].splice(s,1),this.kvStorage.setMeta("mutationStack",this.optimisticMutationStack),this.updateRawObjPool(e,i.resourceId,Object.fromEntries(Object.entries(i.payload).map(([a])=>[a,{value:null,_meta:{}}])),o);}loadConsolidatedState(e,t){t.forEach(s=>{var n;let i=(n=s.id)==null?void 0:n.value;if(!i)return;let{cleanedPayload:o,nestedMutations:r}=this.extractNestedRelations(e,s);r.forEach(a=>{this.addMutation(a.resource,a);}),this.addMutation(e,{id:i,type:"MUTATE",resource:e,resourceId:i,procedure:"INSERT",payload:o});});}extractNestedRelations(e,t){let s=this.schema[e],i={...t},o=[];return s!=null&&s.relations?(Object.entries(t).forEach(([r,n])=>{var c;let a=s.relations[r];if(!a)return;let l=a.entity.name,d=n==null?void 0:n.value;if(a.type==="one"){if(d&&typeof d=="object"&&!Array.isArray(d)&&((c=d.id)!=null&&c.value)){let u=d.id.value,f={...d},{cleanedPayload:m,nestedMutations:S}=this.extractNestedRelations(l,f);o.push(...S),o.push({id:u,type:"MUTATE",resource:l,resourceId:u,procedure:"INSERT",payload:m}),delete i[r];}}else a.type==="many"&&Array.isArray(d)&&(d.forEach(u=>{var f,m;if(u&&typeof u=="object"&&!Array.isArray(u)&&((m=(f=u.value)==null?void 0:f.id)!=null&&m.value)){let S=u.value.id.value,H={...u.value},{cleanedPayload:V,nestedMutations:J}=this.extractNestedRelations(l,H);o.push(...J),o.push({id:S,type:"MUTATE",resource:l,resourceId:S,procedure:"INSERT",payload:V});}}),delete i[r]);}),{cleanedPayload:i,nestedMutations:o}):{cleanedPayload:i,nestedMutations:o}}updateRawObjPool(e,t,s,i){var n;if(!this.schema[e])return;let o=(n=this.rawObjPool[e])==null?void 0:n[t],r=(this.optimisticMutationStack[e]??[]).reduce((a,l)=>l.resourceId!==t?a:this.schema[e].mergeMutation("set",l.payload,a)[0],o);if(this.optimisticRawObjPool[e]??={},r?this.optimisticRawObjPool[e][t]={value:{...r.value,id:{value:t}}}:delete this.optimisticRawObjPool[e][t],!(!this.optimisticObjGraph.hasNode(t)&&!r)){if(this.optimisticObjGraph.hasNode(t)||this.optimisticObjGraph.createNode(t,e,Object.values(this.schema[e].relations).flatMap(a=>a.type==="many"?[a.entity.name]:[])),Object.keys(this.schema[e].relations).length>0){let a=Object.fromEntries(Object.entries(this.schema[e].relations).flatMap(([l,d])=>d.type==="one"?[[d.relationalColumn,l]]:[]));Object.entries(s).forEach(([l,d])=>{let c=this.schema[e].relations[a[l]];if(!a[l])return;let u=i==null?void 0:i.value[l],[,f]=c.mergeMutation("set",d,u);if(f){if(!this.optimisticObjGraph.hasNode(f.value)){let m=c.entity.name;this.optimisticObjGraph.createNode(f.value,m,Object.values(this.schema[m].relations).flatMap(S=>S.type==="many"?[S.entity.name]:[]));}u!=null&&u.value&&this.optimisticObjGraph.removeLink(t,c.entity.name),this.optimisticObjGraph.createLink(t,f.value);}});}this.notifyCollectionSubscribers(e),this.optimisticObjGraph.notifySubscribers(t);}}materializeOneWithInclude(e,t={}){var a;if(!e)return;let s=this.optimisticObjGraph.getNode(e);if(!s)return;let i=s.type,o=(a=this.optimisticRawObjPool[i])==null?void 0:a[e];if(!o)return;let[r,n]=Object.entries(t).reduce((l,[d,c])=>{let u=this.schema[i].relations[d];return u&&(u.type==="one"?l[0].push([d,u.entity.name,c??true]):u.type==="many"&&l[1].push([d,u.entity.name,c??true])),l},[[],[]]);return {value:{...o.value,...Object.fromEntries(r.map(([l,d,c])=>[l,this.materializeOneWithInclude(s.references.get(d),typeof c=="object"&&c!==null?c:{})])),...Object.fromEntries(n.map(([l,d,c])=>{let u=s.referencedBy.get(d),f=u instanceof Set;return [l,f?{value:Array.from(u.values()).map(m=>this.materializeOneWithInclude(m,typeof c=="object"&&c!==null?c:{}))}:this.materializeOneWithInclude(u,typeof c=="object"&&c!==null?c:{})]}))}}}notifyCollectionSubscribers(e){this.collectionSubscriptions.forEach(t=>{if(t.query.resource===e||t.flatInclude&&t.flatInclude.includes(e)){let s=g(t.query),i=this.querySnapshots[s],o=this.get(t.query,void 0,true);if(ue(o,i))return;this.querySnapshots[s]=o,t.callbacks.forEach(r=>{r(o);});}});}flattenIncludes(e,t){let s=[];return Object.entries(e).forEach(([i,o])=>{var a;let r=(a=this.schema[t])==null?void 0:a.relations[i];if(!r)return;let n=r.entity.name;s.push(n),typeof o=="object"&&o!==null&&s.push(...this.flattenIncludes(o,n));}),Array.from(new Set(s))}};var P=class{url;ws;store;logger;remoteSubscriptions=new Map;eventListeners=new Set;replyHandlers={};constructor(e){var t,s,i,o;this.url=e.url,this.logger=$({level:e.logLevel??v.INFO}),this.store=new A(e.schema,e.storage,this.logger,r=>{var n,a;(a=(n=Object.values(r))==null?void 0:n.flat())==null||a.forEach(l=>{this.sendWsMessage(l);});},(r,n)=>{this.emitEvent({type:"CLIENT_STORAGE_LOADED",resource:r,itemCount:n});}),this.ws=new R({url:e.url,autoConnect:((t=e.connection)==null?void 0:t.autoConnect)??true,autoReconnect:((s=e.connection)==null?void 0:s.autoReconnect)??true,reconnectTimeout:((i=e.connection)==null?void 0:i.reconnectTimeout)??5e3,reconnectLimit:(o=e.connection)==null?void 0:o.maxReconnectAttempts,credentials:e.credentials}),this.ws.addEventListener("message",r=>{this.handleServerMessage(r.data);}),this.ws.addEventListener("connectionChange",r=>{this.emitEvent({type:"CONNECTION_STATE_CHANGE",open:r.open}),r.open&&(Array.from(this.remoteSubscriptions.values()).forEach(({query:n})=>{this.sendWsMessage({id:a(),type:"SUBSCRIBE",...n});}),Object.values(this.store.optimisticMutationStack).forEach(n=>{n&&n.forEach(a=>{this.emitEvent({type:"MUTATION_SENT",mutationId:a.id,resource:a.resource,resourceId:a.resourceId,procedure:a.procedure??"UNKNOWN",optimistic:true}),this.sendWsMessage(a);});}));});}get(e){let t=this.store.get(e);return this.emitEvent({type:"QUERY_EXECUTED",query:e,resultCount:Array.isArray(t)?t.length:t?1:0}),t}handleServerMessage(e){var t,s;try{this.logger.debug("Message received from the server:",e);let i=z.parse(JSON.parse(e));if(this.logger.debug("Parsed message:",i),this.emitEvent({type:"MESSAGE_RECEIVED",message:i}),i.type==="MUTATE"){let{resource:o,id:r,resourceId:n,procedure:a}=i;this.emitEvent({type:"MUTATION_RECEIVED",mutationId:r,resource:o,resourceId:n,procedure:a??"UNKNOWN"});try{this.store.addMutation(o,i);}catch(l){this.logger.error("Error merging mutation from the server:",l);}}else if(i.type==="REJECT"){let o=((t=this.store.optimisticMutationStack[i.resource])==null?void 0:t.length)??0,r=(s=this.store.optimisticMutationStack[i.resource])==null?void 0:s.find(n=>n.id===i.id);this.store.undoMutation(i.resource,i.id),this.emitEvent({type:"MUTATION_REJECTED",mutationId:i.id,resource:i.resource}),r&&this.emitEvent({type:"OPTIMISTIC_MUTATION_UNDONE",mutationId:i.id,resource:i.resource,resourceId:r.resourceId,pendingMutations:o-1});}else if(i.type==="REPLY"){let{id:o,data:r}=i;if(this.replyHandlers[o]){clearTimeout(this.replyHandlers[o].timeoutHandle),this.replyHandlers[o].handler(r);return}let n=q.parse(r);this.emitEvent({type:"DATA_LOAD_REPLY",resource:n.resource,itemCount:n.data.length}),this.store.loadConsolidatedState(n.resource,n.data),this.emitEvent({type:"STORE_STATE_UPDATED",resource:n.resource,itemCount:n.data.length});}}catch(i){this.logger.error("Error parsing message from the server:",i);}}load(e){let t=a(),s=g(e);this.emitEvent({type:"DATA_LOAD_REQUESTED",query:e,subscriptionId:t}),this.sendWsMessage({id:t,type:"SUBSCRIBE",...e});let i=!this.remoteSubscriptions.has(s);return this.remoteSubscriptions.has(s)?this.remoteSubscriptions.get(s).subCounter+=1:this.remoteSubscriptions.set(s,{query:e,subCounter:1}),i&&this.emitEvent({type:"SUBSCRIPTION_CREATED",query:e,subscriptionKey:s,subscriberCount:1}),()=>{if(this.remoteSubscriptions.has(s)){let o=this.remoteSubscriptions.get(s);o.subCounter-=1,this.remoteSubscriptions.get(s).subCounter<=0&&(this.remoteSubscriptions.delete(s),this.sendWsMessage({id:a(),type:"UNSUBSCRIBE",...e}),this.emitEvent({type:"SUBSCRIPTION_REMOVED",query:e,subscriptionKey:s}));}}}subscribe(e,t){return this.store.subscribe(e,t)}mutate(e,t,s,i){var n,a$1;let o={id:a(),type:"MUTATE",resource:e,payload:this.store.schema[e].encodeMutation("set",i,new Date().toISOString()),resourceId:t,procedure:s},r=(((n=this.store.optimisticMutationStack[e])==null?void 0:n.length)??0)+1;(a$1=this.store)==null||a$1.addMutation(e,o,true),this.emitEvent({type:"OPTIMISTIC_MUTATION_APPLIED",mutationId:o.id,resource:e,resourceId:t,procedure:s,pendingMutations:r}),this.emitEvent({type:"MUTATION_SENT",mutationId:o.id,resource:e,resourceId:t,procedure:s,optimistic:true}),this.sendWsMessage(o);}genericMutate(e,t,s){if(!this.ws||!this.ws.connected())throw new Error("WebSocket not connected");let i={id:a(),type:"MUTATE",resource:e,procedure:t,payload:s};return this.emitEvent({type:"MUTATION_SENT",mutationId:i.id,resource:e,resourceId:"",procedure:t,optimistic:false}),this.sendWsMessage(i),new Promise((o,r)=>{this.replyHandlers[i.id]={timeoutHandle:setTimeout(()=>{delete this.replyHandlers[i.id],r(new Error("Reply timeout"));},5e3),handler:n=>{delete this.replyHandlers[i.id],o(n);}};})}addEventListener(e){return this.eventListeners.add(e),()=>{this.eventListeners.delete(e);}}sendWsMessage(e){var t;(t=this.ws)!=null&&t.connected()&&this.ws.send(JSON.stringify(e));}emitEvent(e){this.eventListeners.forEach(t=>{t(e);});}},qe=p=>{let e=new P(p);return {client:{ws:e.ws,load:t=>e.load(t),addEventListener:t=>e.addEventListener(t)},store:{query:Object.entries(p.schema).reduce((t,[s,i])=>(t[s]=c._init(i,e),t),{}),mutate:d(()=>{},{apply:(t,s,i)=>{if(s.length<2)return;if(s.length>2)throw new Error("Trying to access an invalid path");let[o,r]=s;if(r==="insert"){let{id:n,...a}=i[0];return e.mutate(o,n,"INSERT",a)}if(r==="update"){let[n,a]=i;return e.mutate(o,n,"UPDATE",a)}return e.genericMutate(o,r,i[0])}})}}};export{qe as createClient,ye as useLiveQuery,fe as useLoadData};
|
|
1
|
+
import {d,c,a,f,e,b as b$1}from'./chunk-AHF6GNMI.js';import {useSyncExternalStore,useEffect}from'react';import {xxHash32}from'js-xxhash';import {z as z$1}from'zod';import {stringify}from'qs';import ue from'fast-deep-equal';import {openDB}from'idb';var g=d=>xxHash32(JSON.stringify(d)).toString(32);var b=(d,e,t=false)=>Object.entries(e).every(([s,i])=>{if(s==="$and")return i.every(r=>b(d,r,t));if(s==="$or")return i.some(r=>b(d,r,t));let o=(i==null?void 0:i.$eq)!==void 0?i==null?void 0:i.$eq:i;if(typeof i=="object"&&i!==null&&(i==null?void 0:i.$eq)===void 0){if(i.$in!==void 0){let n=d[s];return n===void 0?false:t?!i.$in.includes(n):i.$in.includes(n)}if(i.$not!==void 0&&!t)return b(d,{[s]:i.$not},true);if(i.$gt!==void 0){let n=d[s];return typeof n!="number"?false:t?n<=i.$gt:n>i.$gt}if(i.$gte!==void 0){let n=d[s];return typeof n!="number"?false:t?n<i.$gte:n>=i.$gte}if(i.$lt!==void 0){let n=d[s];return typeof n!="number"?false:t?n>=i.$lt:n<i.$lt}if(i.$lte!==void 0){let n=d[s];return typeof n!="number"?false:t?n>i.$lte:n<=i.$lte}let r=d[s];return !r||typeof r!="object"&&!Array.isArray(r)?false:Array.isArray(r)?t?!r.some(n=>b(n,i,false)):r.some(n=>b(n,i,false)):b(r,i,t)}return t?d[s]!==o:d[s]===o}),v={CRITICAL:0,ERROR:1,WARN:2,INFO:3,DEBUG:4},L=class{level;prefix;constructor(e={}){this.level=e.level??v.INFO,this.prefix=e.prefix?`[${e.prefix}] `:"";}critical(...e){this.level>=v.CRITICAL&&console.error(`${this.prefix}[CRITICAL]`,...e);}error(...e){this.level>=v.ERROR&&console.error(`${this.prefix}[ERROR]`,...e);}warn(...e){this.level>=v.WARN&&console.warn(`${this.prefix}[WARN]`,...e);}info(...e){this.level>=v.INFO&&console.log(`${this.prefix}[INFO]`,...e);}debug(...e){this.level>=v.DEBUG&&console.log(`${this.prefix}[DEBUG]`,...e);}setLevel(e){this.level=e;}getLevel(){return this.level}},$=d=>new L(d);var x=class{subscriptions=new Map;getOrStoreSubscription(e){let t=g(e);return this.subscriptions.has(t)?this.subscriptions.get(t).subscribe:(this.subscriptions.set(t,{subscribe:s=>{var o;(o=this.subscriptions.get(t))==null||o.callbacks.add(s);let i=e.subscribe(()=>{var r;(r=this.subscriptions.get(t))==null||r.callbacks.forEach(n=>{n();});});return ()=>{var r;(r=this.subscriptions.get(t))==null||r.callbacks.delete(s),setTimeout(()=>{var n;((n=this.subscriptions.get(t))==null?void 0:n.callbacks.size)===0&&(this.subscriptions.delete(t),i());},10);}},callbacks:new Set}),this.subscriptions.get(t).subscribe)}},Z=new x,ye=d=>useSyncExternalStore(Z.getOrStoreSubscription(d),d.get),fe=(d,e)=>{useEffect(()=>{let t=d.load(e.buildQueryRequest());return ()=>{t();}},[e,d.load]);};var T=z$1.object({resource:z$1.string(),where:z$1.record(z$1.string(),z$1.any()).optional(),include:z$1.record(z$1.string(),z$1.any()).optional(),lastSyncedAt:z$1.string().optional(),limit:z$1.coerce.number().optional(),sort:z$1.array(z$1.object({key:z$1.string(),direction:z$1.enum(["asc","desc"])})).optional()}),I=z$1.record(z$1.string(),z$1.object({value:z$1.any().nullable(),_meta:z$1.object({timestamp:z$1.string().optional().nullable()}).optional()})),ee=I.superRefine((d,e)=>{d.id&&e.addIssue({code:z$1.ZodIssueCode.custom,message:"Payload cannot have an id"});}),Q=z$1.object({id:z$1.string().optional(),type:z$1.literal("MUTATE"),resource:z$1.string(),resourceId:z$1.string().optional()}),j=Q.extend({procedure:z$1.string(),payload:z$1.any().optional()}),k=Q.extend({procedure:z$1.enum(["INSERT","UPDATE"]),payload:ee});z$1.union([k,j]);var E=z$1.string(),te=T.extend({id:E,type:z$1.literal("SUBSCRIBE")}),ie=T.extend({id:E,type:z$1.literal("UNSUBSCRIBE")}),se=T.extend({id:E,type:z$1.literal("QUERY")}),G=k.extend({id:E}),ne=j.extend({id:E}),re=z$1.union([ne,G]);z$1.union([te,se,re,ie]);var oe=z$1.object({id:E,type:z$1.literal("REJECT"),resource:z$1.string(),message:z$1.string().optional()}),ae=z$1.object({id:E,type:z$1.literal("REPLY"),data:z$1.any()}),z=z$1.union([oe,ae,G]),q=z$1.object({resource:z$1.string(),data:z$1.array(I)});var R=class{ws=null;url;autoConnect;autoReconnect;reconnectTimeout;reconnectLimit;reconnectAttempts=0;eventListeners=new Map;reconnectTimer=null;intentionallyDisconnected=false;credentials;constructor(e){this.url=e.url,this.autoConnect=e.autoConnect??false,this.autoReconnect=e.autoReconnect??false,this.reconnectTimeout=e.reconnectTimeout??5e3,this.reconnectLimit=e.reconnectLimit,this.credentials=e.credentials,this.autoConnect&&this.connect();}connected(){var e;return ((e=this.ws)==null?void 0:e.readyState)===WebSocket.OPEN}async connect(){if(this.ws&&(this.ws.readyState===WebSocket.OPEN||this.ws.readyState===WebSocket.CONNECTING))return;this.intentionallyDisconnected=false;let e=await b$1(this.credentials);this.ws=new WebSocket(this.url+(e?`?${stringify(e)}`:"")),this.ws.addEventListener("open",this.handleOpen.bind(this)),this.ws.addEventListener("close",this.handleClose.bind(this)),this.ws.addEventListener("error",this.handleError.bind(this)),this.ws.addEventListener("message",this.handleMessage.bind(this));}disconnect(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.intentionallyDisconnected=true,this.ws&&(this.ws.close(),this.ws=null);}addEventListener(e,t){var s;this.eventListeners.has(e)||this.eventListeners.set(e,new Set),(s=this.eventListeners.get(e))==null||s.add(t);}removeEventListener(e,t){var s;this.eventListeners.has(e)&&((s=this.eventListeners.get(e))==null||s.delete(t));}send(e){if(this.ws&&this.ws.readyState===WebSocket.OPEN)this.ws.send(e);else throw new Error("WebSocket is not open")}handleOpen(e){this.reconnectAttempts=0,this.dispatchEvent("open",e),this.dispatchEvent("connectionChange",{open:true});}handleClose(e){this.dispatchEvent("close",e),this.dispatchEvent("connectionChange",{open:false}),this.autoReconnect&&!this.intentionallyDisconnected&&this.scheduleReconnect();}handleError(e){var t,s;this.dispatchEvent("error",e),this.dispatchEvent("connectionChange",{open:false}),(s=(t=e.error)==null?void 0:t.message)!=null&&s.includes("non-101")&&(this.ws&&(this.ws.close(),this.ws=null),this.autoReconnect&&!this.intentionallyDisconnected&&this.scheduleReconnect());}handleMessage(e){this.dispatchEvent("message",e);}scheduleReconnect(){this.reconnectLimit&&this.reconnectAttempts>=this.reconnectLimit||(this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{this.connect();},this.reconnectTimeout));}dispatchEvent(e,t){var s;(s=this.eventListeners.get(e))==null||s.forEach(i=>{i(t);});}};var O=class{constructor(e){this.logger=e;this.nodes=new Map;}nodes;createNode(e,t,s){if(this.nodes.has(e))throw new Error(`Node with id ${e} already exists`);let i={id:e,type:t,referencedBy:new Map(s.map(o=>[o,new Set])),references:new Map,subscriptions:new Set};return this.nodes.set(e,i),i}getNode(e){return this.nodes.get(e)}hasNode(e){return this.nodes.has(e)}createLink(e,t){let s=this.nodes.get(e),i=this.nodes.get(t);if(!s)throw new Error(`Source node with id ${e} does not exist`);if(!i)throw new Error(`Target node with id ${t} does not exist`);s.references.set(i.type,t);let o=i.referencedBy.get(s.type);o&&o instanceof Set?o.add(e):i.referencedBy.set(s.type,e),this.notifySubscribers(t);}removeLink(e,t){let s=this.nodes.get(e);if(!s)throw new Error(`Node with id ${e} does not exist`);let i=s.references.get(t);if(!i)return;s.references.delete(t);let o=this.nodes.get(i);if(!o)return;let r=o.referencedBy.get(s.type);r&&(r instanceof Set?r.delete(e):o.referencedBy.delete(s.type),this.notifySubscribers(i)),this.notifySubscribers(e);}subscribe(e,t){let s=this.nodes.get(e);if(!s)throw new Error(`Node with id ${e} does not exist`);return s.subscriptions.add(t),()=>{s.subscriptions.delete(t);}}removeNode(e){let t=this.nodes.get(e);t&&(Array.from(t.referencedBy.entries()).forEach(([s,i])=>{(i instanceof Set?Array.from(i.values()):[i]).forEach(r=>{let n=this.nodes.get(r);!n||!n.references.get(s)||(n.references.delete(s),this.notifySubscribers(r));});}),this.nodes.delete(e));}updateNode(e,t){let s=this.nodes.get(e);if(!s)throw new Error(`Node with id ${e} does not exist`);t(s),this.notifySubscribers(e);}notifySubscribers(e){let t=this.nodes.get(e);t&&Array.from(t.subscriptions).forEach(s=>{var i;try{s(e);}catch(o){(i=this.logger)==null||i.error(`Error in node subscription for node ${e}:`,o);}});}getAllNodes(){return Array.from(this.nodes.values())}};var D="__meta",C="databases",w=class{db;async init(e,t){var u,p;if(typeof window>"u")return;let i=((u=(await window.indexedDB.databases()).find(c=>c.name===t))==null?void 0:u.version)??1,o=await g(e),r=Object.fromEntries(await Promise.all(Object.entries(e).map(async([c,l])=>[c,await g(l)]))),n=await openDB("live-state-databases",1,{upgrade(c){c.objectStoreNames.contains(C)||c.createObjectStore(C);}}),a=(p=await this.getAll(n,C))==null?void 0:p[t];(a==null?void 0:a.schemaHash)!==o&&i++,this.db=await openDB(t,i,{async upgrade(c){[...Object.keys(e),D].forEach(l=>{(a==null?void 0:a.objectHashes[l])!==r[l]&&c.objectStoreNames.contains(l)&&c.deleteObjectStore(l),c.objectStoreNames.contains(l)||c.createObjectStore(l);}),await n.put(C,{schemaHash:o,objectHashes:r},t);},blocking(){window.location.reload();},blocked(){window.location.reload();}});}async get(e){return await this.getAll(this.db,e)??{}}getOne(e,t){return this.db?this.db.get(e,t):new Promise(s=>s(void 0))}set(e,t,s){var i;return (i=this.db)==null?void 0:i.put(e,s,t)}delete(e,t){var s;return (s=this.db)==null?void 0:s.delete(e,t)}getMeta(e){return this.db?this.db.get(D,e):new Promise(t=>t(void 0))}setMeta(e,t){var s;return (s=this.db)==null?void 0:s.put(D,t,e)}async getAll(e,t){if(!e)return;if(e.getAllRecords)return e.getAllRecords(t);let[s,i]=await Promise.all([e.getAll(t),e.getAllKeys(t)]);return Object.fromEntries(s.map((o,r)=>[i[r],o]))}};var A=class{constructor(e,t,s,i,o){this.schema=e;this.logger=s,this.optimisticObjGraph=new O(s),this.kvStorage=new w,t!==false&&this.kvStorage.init(this.schema,t.name).then(()=>{this.kvStorage.getMeta("mutationStack").then(r=>{!r||Object.keys(r).length===0||(this.optimisticMutationStack=r,i==null||i(this.optimisticMutationStack));}).then(()=>{Object.entries(this.schema).forEach(([r])=>{this.kvStorage.get(r).then(n=>{if(!n||Object.keys(n).length===0){o==null||o(r,0);return}let a=Object.entries(n).map(([u,p])=>({...p,id:{value:u}}));o==null||o(r,a.length),this.loadConsolidatedState(r,a);});});}).catch(r=>{s.debug("Storage initialization failed (may not be available in this environment):",r);});});}rawObjPool={};optimisticMutationStack={};optimisticObjGraph;optimisticRawObjPool={};logger;collectionSubscriptions=new Map;querySnapshots={};kvStorage;get(e$1,t,s=false){var r;let i=t??g(e$1);if(this.querySnapshots[i]&&!s){let n=this.querySnapshots[i];if(n)return n}let o=((r=e$1.where)!=null&&r.id?[e$1.where.id]:Object.keys(this.optimisticRawObjPool[e$1.resource]??{})).flatMap(n=>{let a=f(this.materializeOneWithInclude(n,e$1.include));return a?[a]:[]});if(e$1.sort&&e$1.sort.length>0){let n=(a,u)=>{for(let p of e$1.sort){let c=a[p.key],l=u[p.key];if(c<l)return p.direction==="asc"?-1:1;if(c>l)return p.direction==="asc"?1:-1}return 0};o.sort(n);}if(e$1.where||e$1.limit){let n=e$1.where?a=>b(a,e$1.where):()=>true;o=e(o,n,e$1.limit);}return s||(this.querySnapshots[i]=o),o}subscribe(e,t){var o;let s=g(e);return this.collectionSubscriptions.get(s)||this.collectionSubscriptions.set(s,{callbacks:new Set,query:e,flatInclude:e.include?this.flattenIncludes(e.include,e.resource):void 0}),(o=this.collectionSubscriptions.get(s))==null||o.callbacks.add(t),()=>{var r,n;(r=this.collectionSubscriptions.get(s))==null||r.callbacks.delete(t),((n=this.collectionSubscriptions.get(s))==null?void 0:n.callbacks.size)===0&&(this.collectionSubscriptions.delete(s),delete this.querySnapshots[s]);}}addMutation(e,t,s=false){var r,n,a;let i=this.schema[e];if(this.logger.debug("Adding mutation",t),!i)throw new Error("Schema not found");let o=(r=this.optimisticRawObjPool[e])==null?void 0:r[t.resourceId];if(s)this.optimisticMutationStack[e]??=[],this.optimisticMutationStack[e].push(t);else {this.optimisticMutationStack[e]=((a=(n=this.optimisticMutationStack)==null?void 0:n[e])==null?void 0:a.filter(c=>c.id!==t.id))??[],this.rawObjPool[e]??={};let u={value:{...this.schema[e].mergeMutation("set",t.payload,this.rawObjPool[e][t.resourceId])[0].value,id:{value:t.resourceId}}};this.rawObjPool[e][t.resourceId]=u;let p=u.value;delete p.id,this.kvStorage.set(e,t.resourceId,p);}this.kvStorage.setMeta("mutationStack",this.optimisticMutationStack),this.updateRawObjPool(e,t.resourceId,t.payload,o);}undoMutation(e,t){var r,n;if(!this.optimisticMutationStack[e])return;let s=(r=this.optimisticMutationStack[e])==null?void 0:r.findIndex(a=>a.id===t);if(s===-1)return;let i=this.optimisticMutationStack[e][s];this.logger.debug("Removing mutation",i);let o=(n=this.optimisticRawObjPool[e])==null?void 0:n[i.resourceId];this.optimisticMutationStack[e].splice(s,1),this.kvStorage.setMeta("mutationStack",this.optimisticMutationStack),this.updateRawObjPool(e,i.resourceId,Object.fromEntries(Object.entries(i.payload).map(([a])=>[a,{value:null,_meta:{}}])),o);}loadConsolidatedState(e,t){t.forEach(s=>{var n;let i=(n=s.id)==null?void 0:n.value;if(!i)return;let{cleanedPayload:o,nestedMutations:r}=this.extractNestedRelations(e,s);r.forEach(a=>{this.addMutation(a.resource,a);}),this.addMutation(e,{id:i,type:"MUTATE",resource:e,resourceId:i,procedure:"INSERT",payload:o});});}extractNestedRelations(e,t){let s=this.schema[e],i={...t},o=[];return s!=null&&s.relations?(Object.entries(t).forEach(([r,n])=>{var c;let a=s.relations[r];if(!a)return;let u=a.entity.name,p=n==null?void 0:n.value;if(a.type==="one"){if(p&&typeof p=="object"&&!Array.isArray(p)&&((c=p.id)!=null&&c.value)){let l=p.id.value,f={...p},{cleanedPayload:m,nestedMutations:S}=this.extractNestedRelations(u,f);o.push(...S),o.push({id:l,type:"MUTATE",resource:u,resourceId:l,procedure:"INSERT",payload:m}),delete i[r];}}else a.type==="many"&&Array.isArray(p)&&(p.forEach(l=>{var f,m;if(l&&typeof l=="object"&&!Array.isArray(l)&&((m=(f=l.value)==null?void 0:f.id)!=null&&m.value)){let S=l.value.id.value,H={...l.value},{cleanedPayload:V,nestedMutations:J}=this.extractNestedRelations(u,H);o.push(...J),o.push({id:S,type:"MUTATE",resource:u,resourceId:S,procedure:"INSERT",payload:V});}}),delete i[r]);}),{cleanedPayload:i,nestedMutations:o}):{cleanedPayload:i,nestedMutations:o}}updateRawObjPool(e,t,s,i){var n;if(!this.schema[e])return;let o=(n=this.rawObjPool[e])==null?void 0:n[t],r=(this.optimisticMutationStack[e]??[]).reduce((a,u)=>u.resourceId!==t?a:this.schema[e].mergeMutation("set",u.payload,a)[0],o);if(this.optimisticRawObjPool[e]??={},r?this.optimisticRawObjPool[e][t]={value:{...r.value,id:{value:t}}}:delete this.optimisticRawObjPool[e][t],!(!this.optimisticObjGraph.hasNode(t)&&!r)){if(this.optimisticObjGraph.hasNode(t)||this.optimisticObjGraph.createNode(t,e,Object.values(this.schema[e].relations).flatMap(a=>a.type==="many"?[a.entity.name]:[])),Object.keys(this.schema[e].relations).length>0){let a=Object.fromEntries(Object.entries(this.schema[e].relations).flatMap(([u,p])=>p.type==="one"?[[p.relationalColumn,u]]:[]));Object.entries(s).forEach(([u,p])=>{let c=this.schema[e].relations[a[u]];if(!a[u])return;let l=i==null?void 0:i.value[u],[,f]=c.mergeMutation("set",p,l);if(f){if(!this.optimisticObjGraph.hasNode(f.value)){let m=c.entity.name;this.optimisticObjGraph.createNode(f.value,m,Object.values(this.schema[m].relations).flatMap(S=>S.type==="many"?[S.entity.name]:[]));}l!=null&&l.value&&this.optimisticObjGraph.removeLink(t,c.entity.name),this.optimisticObjGraph.createLink(t,f.value);}});}this.notifyCollectionSubscribers(e),this.optimisticObjGraph.notifySubscribers(t);}}materializeOneWithInclude(e,t={}){var a;if(!e)return;let s=this.optimisticObjGraph.getNode(e);if(!s)return;let i=s.type,o=(a=this.optimisticRawObjPool[i])==null?void 0:a[e];if(!o)return;let[r,n]=Object.entries(t).reduce((u,[p,c])=>{let l=this.schema[i].relations[p];return l&&(l.type==="one"?u[0].push([p,l.entity.name,c??true]):l.type==="many"&&u[1].push([p,l.entity.name,c??true])),u},[[],[]]);return {value:{...o.value,...Object.fromEntries(r.map(([u,p,c])=>[u,this.materializeOneWithInclude(s.references.get(p),typeof c=="object"&&c!==null?c:{})])),...Object.fromEntries(n.map(([u,p,c])=>{let l=s.referencedBy.get(p),f=l instanceof Set;return [u,f?{value:Array.from(l.values()).map(m=>this.materializeOneWithInclude(m,typeof c=="object"&&c!==null?c:{}))}:this.materializeOneWithInclude(l,typeof c=="object"&&c!==null?c:{})]}))}}}notifyCollectionSubscribers(e){this.collectionSubscriptions.forEach(t=>{if(t.query.resource===e||t.flatInclude&&t.flatInclude.includes(e)){let s=g(t.query),i=this.querySnapshots[s],o=this.get(t.query,void 0,true);if(ue(o,i))return;this.querySnapshots[s]=o,t.callbacks.forEach(r=>{r(o);});}});}flattenIncludes(e,t){let s=[];return Object.entries(e).forEach(([i,o])=>{var a;let r=(a=this.schema[t])==null?void 0:a.relations[i];if(!r)return;let n=r.entity.name;s.push(n),typeof o=="object"&&o!==null&&s.push(...this.flattenIncludes(o,n));}),Array.from(new Set(s))}};var P=class{url;ws;store;logger;remoteSubscriptions=new Map;eventListeners=new Set;replyHandlers={};constructor(e){var t,s,i,o;this.url=e.url,this.logger=$({level:e.logLevel??v.INFO}),this.store=new A(e.schema,e.storage,this.logger,r=>{var n,a;(a=(n=Object.values(r))==null?void 0:n.flat())==null||a.forEach(u=>{this.sendWsMessage(u);});},(r,n)=>{this.emitEvent({type:"CLIENT_STORAGE_LOADED",resource:r,itemCount:n});}),this.ws=new R({url:e.url,autoConnect:((t=e.connection)==null?void 0:t.autoConnect)??true,autoReconnect:((s=e.connection)==null?void 0:s.autoReconnect)??true,reconnectTimeout:((i=e.connection)==null?void 0:i.reconnectTimeout)??5e3,reconnectLimit:(o=e.connection)==null?void 0:o.maxReconnectAttempts,credentials:e.credentials}),this.ws.addEventListener("message",r=>{this.handleServerMessage(r.data);}),this.ws.addEventListener("connectionChange",r=>{this.emitEvent({type:"CONNECTION_STATE_CHANGE",open:r.open}),r.open&&(Array.from(this.remoteSubscriptions.values()).forEach(({query:n})=>{this.sendWsMessage({id:a(),type:"SUBSCRIBE",...n});}),Object.values(this.store.optimisticMutationStack).forEach(n=>{n&&n.forEach(a=>{this.emitEvent({type:"MUTATION_SENT",mutationId:a.id,resource:a.resource,resourceId:a.resourceId,procedure:a.procedure??"UNKNOWN",optimistic:true}),this.sendWsMessage(a);});}));});}get(e){let t=this.store.get(e);return this.emitEvent({type:"QUERY_EXECUTED",query:e,resultCount:Array.isArray(t)?t.length:t?1:0}),t}handleServerMessage(e){var t,s;try{this.logger.debug("Message received from the server:",e);let i=z.parse(JSON.parse(e));if(this.logger.debug("Parsed message:",i),this.emitEvent({type:"MESSAGE_RECEIVED",message:i}),i.type==="MUTATE"){let{resource:o,id:r,resourceId:n,procedure:a}=i;this.emitEvent({type:"MUTATION_RECEIVED",mutationId:r,resource:o,resourceId:n,procedure:a??"UNKNOWN"});try{this.store.addMutation(o,i);}catch(u){this.logger.error("Error merging mutation from the server:",u);}}else if(i.type==="REJECT"){let o=((t=this.store.optimisticMutationStack[i.resource])==null?void 0:t.length)??0,r=(s=this.store.optimisticMutationStack[i.resource])==null?void 0:s.find(n=>n.id===i.id);this.store.undoMutation(i.resource,i.id),this.emitEvent({type:"MUTATION_REJECTED",mutationId:i.id,resource:i.resource}),r&&this.emitEvent({type:"OPTIMISTIC_MUTATION_UNDONE",mutationId:i.id,resource:i.resource,resourceId:r.resourceId,pendingMutations:o-1});}else if(i.type==="REPLY"){let{id:o,data:r}=i;if(this.replyHandlers[o]){clearTimeout(this.replyHandlers[o].timeoutHandle),this.replyHandlers[o].handler(r);return}let n=q.parse(r);this.emitEvent({type:"DATA_LOAD_REPLY",resource:n.resource,itemCount:n.data.length}),this.store.loadConsolidatedState(n.resource,n.data),this.emitEvent({type:"STORE_STATE_UPDATED",resource:n.resource,itemCount:n.data.length});}}catch(i){this.logger.error("Error parsing message from the server:",i);}}load(e){let t=a(),s=g(e);this.emitEvent({type:"DATA_LOAD_REQUESTED",query:e,subscriptionId:t}),this.sendWsMessage({id:t,type:"SUBSCRIBE",...e});let i=!this.remoteSubscriptions.has(s);return this.remoteSubscriptions.has(s)?this.remoteSubscriptions.get(s).subCounter+=1:this.remoteSubscriptions.set(s,{query:e,subCounter:1}),i&&this.emitEvent({type:"SUBSCRIPTION_CREATED",query:e,subscriptionKey:s,subscriberCount:1}),()=>{if(this.remoteSubscriptions.has(s)){let o=this.remoteSubscriptions.get(s);o.subCounter-=1,this.remoteSubscriptions.get(s).subCounter<=0&&(this.remoteSubscriptions.delete(s),this.sendWsMessage({id:a(),type:"UNSUBSCRIBE",...e}),this.emitEvent({type:"SUBSCRIPTION_REMOVED",query:e,subscriptionKey:s}));}}}subscribe(e,t){return this.store.subscribe(e,t)}mutate(e,t,s,i){var n,a$1;let o={id:a(),type:"MUTATE",resource:e,payload:this.store.schema[e].encodeMutation("set",i,new Date().toISOString()),resourceId:t,procedure:s},r=(((n=this.store.optimisticMutationStack[e])==null?void 0:n.length)??0)+1;(a$1=this.store)==null||a$1.addMutation(e,o,true),this.emitEvent({type:"OPTIMISTIC_MUTATION_APPLIED",mutationId:o.id,resource:e,resourceId:t,procedure:s,pendingMutations:r}),this.emitEvent({type:"MUTATION_SENT",mutationId:o.id,resource:e,resourceId:t,procedure:s,optimistic:true}),this.sendWsMessage(o);}genericMutate(e,t,s){if(!this.ws||!this.ws.connected())throw new Error("WebSocket not connected");let i={id:a(),type:"MUTATE",resource:e,procedure:t,payload:s};return this.emitEvent({type:"MUTATION_SENT",mutationId:i.id,resource:e,resourceId:"",procedure:t,optimistic:false}),this.sendWsMessage(i),new Promise((o,r)=>{this.replyHandlers[i.id]={timeoutHandle:setTimeout(()=>{delete this.replyHandlers[i.id],r(new Error("Reply timeout"));},5e3),handler:n=>{delete this.replyHandlers[i.id],o(n);}};})}addEventListener(e){return this.eventListeners.add(e),()=>{this.eventListeners.delete(e);}}sendWsMessage(e){var t;(t=this.ws)!=null&&t.connected()&&this.ws.send(JSON.stringify(e));}emitEvent(e){this.eventListeners.forEach(t=>{t(e);});}},qe=d$1=>{let e=new P(d$1);return {client:{ws:e.ws,load:t=>e.load(t),addEventListener:t=>e.addEventListener(t)},store:{query:Object.entries(d$1.schema).reduce((t,[s,i])=>(t[s]=c._init(i,e),t),{}),mutate:d(()=>{},{apply:(t,s,i)=>{if(s.length<2)return;if(s.length>2)throw new Error("Trying to access an invalid path");let[o,r]=s;if(r==="insert"){let{id:n,...a}=i[0];return e.mutate(o,n,"INSERT",a)}if(r==="update"){let[n,a]=i;return e.mutate(o,n,"UPDATE",a)}return e.genericMutate(o,r,i[0])}})}}};export{qe as createClient,ye as useLiveQuery,fe as useLoadData};
|