@live-state/sync 0.0.6-canary-14 → 0.0.6-pr-1
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.d.ts +2 -3
- package/dist/client.js +1 -1
- package/dist/fetch-client.d.ts +3 -4
- package/dist/fetch-client.js +1 -1
- package/dist/{index-DixUPrmV.d.ts → index-P-s1Yf1S.d.ts} +128 -184
- package/dist/server.cjs +6 -6
- package/dist/server.d.cts +53 -25
- package/dist/server.d.ts +53 -25
- package/dist/server.js +6 -6
- package/package.json +2 -1
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { o as Client, n as ClientEvents, C as ClientOptions, a as ClientRouterConstraint, e as ClientStorageLoadedEvent, d as ConnectionStateChangeEvent, f as DataLoadReplyEvent, D as DataLoadRequestedEvent, M as MessageReceivedEvent, h as MutationReceivedEvent, i as MutationRejectedEvent, g as MutationSentEvent, O as OptimisticMutationAppliedEvent, m as OptimisticMutationUndoneEvent, Q as QueryExecutedEvent, k as QuerySubscriptionTriggeredEvent, l as StoreStateUpdatedEvent, S as SubscriptionCreatedEvent, j as SubscriptionRemovedEvent, p as createClient, u as useLiveQuery, c as useLoadData } from './index-P-s1Yf1S.js';
|
|
2
2
|
import 'zod';
|
|
3
|
-
import '
|
|
4
|
-
import 'zod/v4/core';
|
|
3
|
+
import '@standard-schema/spec';
|
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}from'zod';import {stringify}from'qs';import le from'fast-deep-equal';import {openDB}from'idb';var g=u=>xxHash32(JSON.stringify(u)).toString(32);var b=(u,e,t=false)=>Object.entries(e).every(([i,s])=>{if(i==="$and")return s.every(o=>b(u,o,t));if(i==="$or")return s.some(o=>b(u,o,t));let r=(s==null?void 0:s.$eq)!==void 0?s==null?void 0:s.$eq:s;if(typeof s=="object"&&s!==null&&(s==null?void 0:s.$eq)===void 0){if(s.$in!==void 0){let n=u[i];return n===void 0?false:t?!s.$in.includes(n):s.$in.includes(n)}if(s.$not!==void 0&&!t)return b(u,{[i]:s.$not},true);if(s.$gt!==void 0){let n=u[i];return typeof n!="number"?false:t?n<=s.$gt:n>s.$gt}if(s.$gte!==void 0){let n=u[i];return typeof n!="number"?false:t?n<s.$gte:n>=s.$gte}if(s.$lt!==void 0){let n=u[i];return typeof n!="number"?false:t?n>=s.$lt:n<s.$lt}if(s.$lte!==void 0){let n=u[i];return typeof n!="number"?false:t?n>s.$lte:n<=s.$lte}let o=u[i];return !o||typeof o!="object"&&!Array.isArray(o)?false:Array.isArray(o)?t?!o.some(n=>b(n,s,false)):o.some(n=>b(n,s,false)):b(o,s,t)}return t?u[i]!==r:u[i]===r}),v={CRITICAL:0,ERROR:1,WARN:2,INFO:3,DEBUG:4},j=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}},G=u=>new j(u);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:i=>{var r;(r=this.subscriptions.get(t))==null||r.callbacks.add(i);let s=e.subscribe(()=>{var o;(o=this.subscriptions.get(t))==null||o.callbacks.forEach(n=>{n();});});return ()=>{var o;(o=this.subscriptions.get(t))==null||o.callbacks.delete(i),setTimeout(()=>{var n;((n=this.subscriptions.get(t))==null?void 0:n.callbacks.size)===0&&(this.subscriptions.delete(t),s());},10);}},callbacks:new Set}),this.subscriptions.get(t).subscribe)}},X=new x,ye=u=>useSyncExternalStore(X.getOrStoreSubscription(u),u.get),fe=(u,e)=>{useEffect(()=>{let t=u.load(e.buildQueryRequest());return ()=>{t();}},[e,u.load]);};var w=z.object({resource:z.string(),where:z.record(z.string(),z.any()).optional(),include:z.record(z.string(),z.any()).optional(),lastSyncedAt:z.string().optional(),limit:z.coerce.number().optional(),sort:z.array(z.object({key:z.string(),direction:z.enum(["asc","desc"])})).optional()}),A=z.record(z.string(),z.object({value:z.any().nullable(),_meta:z.object({timestamp:z.string().optional().nullable()}).optional()})),ee=A.superRefine((u,e)=>{u.id&&e.addIssue({code:z.ZodIssueCode.custom,message:"Payload cannot have an id"});}),U=z.object({id:z.string().optional(),type:z.literal("MUTATE"),resource:z.string(),resourceId:z.string().optional()}),k=U.extend({procedure:z.string(),payload:z.any().optional()}),P=U.extend({procedure:z.enum(["INSERT","UPDATE"]),payload:ee});z.union([P,k]);var M=z.string(),te=w.extend({id:M,type:z.literal("SUBSCRIBE")}),ie=w.extend({id:M,type:z.literal("UNSUBSCRIBE")}),se=w.extend({id:M,type:z.literal("QUERY")}),Q=P.extend({id:M}),ne=k.extend({id:M}),re=z.union([ne,Q]);z.union([te,se,re,ie]);var oe=z.object({id:M,type:z.literal("REJECT"),resource:z.string(),message:z.string().optional()}),ae=z.object({id:M,type:z.literal("REPLY"),data:z.any()}),H=z.union([oe,ae,Q]),q=z.object({resource:z.string(),data:z.array(A)});var O=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 i;this.eventListeners.has(e)||this.eventListeners.set(e,new Set),(i=this.eventListeners.get(e))==null||i.add(t);}removeEventListener(e,t){var i;this.eventListeners.has(e)&&((i=this.eventListeners.get(e))==null||i.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,i;this.dispatchEvent("error",e),this.dispatchEvent("connectionChange",{open:false}),(i=(t=e.error)==null?void 0:t.message)!=null&&i.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 i;(i=this.eventListeners.get(e))==null||i.forEach(s=>{s(t);});}};var R=class{constructor(e){this.logger=e;this.nodes=new Map;}nodes;createNode(e,t,i){if(this.nodes.has(e))throw new Error(`Node with id ${e} already exists`);let s={id:e,type:t,referencedBy:new Map(i.map(r=>[r,new Set])),references:new Map,subscriptions:new Set};return this.nodes.set(e,s),s}getNode(e){return this.nodes.get(e)}hasNode(e){return this.nodes.has(e)}createLink(e,t){let i=this.nodes.get(e),s=this.nodes.get(t);if(!i)throw new Error(`Source node with id ${e} does not exist`);if(!s)throw new Error(`Target node with id ${t} does not exist`);i.references.set(s.type,t);let r=s.referencedBy.get(i.type);r&&r instanceof Set?r.add(e):s.referencedBy.set(i.type,e),this.notifySubscribers(t);}removeLink(e,t){let i=this.nodes.get(e);if(!i)throw new Error(`Node with id ${e} does not exist`);let s=i.references.get(t);if(!s)return;i.references.delete(t);let r=this.nodes.get(s);if(!r)return;let o=r.referencedBy.get(i.type);o&&(o instanceof Set?o.delete(e):r.referencedBy.delete(i.type),this.notifySubscribers(s)),this.notifySubscribers(e);}subscribe(e,t){let i=this.nodes.get(e);if(!i)throw new Error(`Node with id ${e} does not exist`);return i.subscriptions.add(t),()=>{i.subscriptions.delete(t);}}removeNode(e){let t=this.nodes.get(e);t&&(Array.from(t.referencedBy.entries()).forEach(([i,s])=>{(s instanceof Set?Array.from(s.values()):[s]).forEach(o=>{let n=this.nodes.get(o);!n||!n.references.get(i)||(n.references.delete(i),this.notifySubscribers(o));});}),this.nodes.delete(e));}updateNode(e,t){let i=this.nodes.get(e);if(!i)throw new Error(`Node with id ${e} does not exist`);t(i),this.notifySubscribers(e);}notifySubscribers(e){let t=this.nodes.get(e);t&&Array.from(t.subscriptions).forEach(i=>{var s;try{i(e);}catch(r){(s=this.logger)==null||s.error(`Error in node subscription for node ${e}:`,r);}});}getAllNodes(){return Array.from(this.nodes.values())}};var W="__meta",L="databases",C=class{db;async init(e,t){var p,d;if(typeof window>"u")return;let s=((p=(await window.indexedDB.databases()).find(c=>c.name===t))==null?void 0:p.version)??1,r=await g(e),o=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(L)||c.createObjectStore(L);}}),a=(d=await this.getAll(n,L))==null?void 0:d[t];(a==null?void 0:a.schemaHash)!==r&&s++,this.db=await openDB(t,s,{async upgrade(c){[...Object.keys(e),W].forEach(l=>{(a==null?void 0:a.objectHashes[l])!==o[l]&&c.objectStoreNames.contains(l)&&c.deleteObjectStore(l),c.objectStoreNames.contains(l)||c.createObjectStore(l);}),await n.put(L,{schemaHash:r,objectHashes:o},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(i=>i(void 0))}set(e,t,i){var s;return (s=this.db)==null?void 0:s.put(e,i,t)}delete(e,t){var i;return (i=this.db)==null?void 0:i.delete(e,t)}getMeta(e){return this.db?this.db.get(W,e):new Promise(t=>t(void 0))}setMeta(e,t){var i;return (i=this.db)==null?void 0:i.put(W,t,e)}async getAll(e,t){if(!e)return;if(e.getAllRecords)return e.getAllRecords(t);let[i,s]=await Promise.all([e.getAll(t),e.getAllKeys(t)]);return Object.fromEntries(i.map((r,o)=>[s[o],r]))}};var T=class{constructor(e,t,i,s){this.schema=e;this.logger=i,this.optimisticObjGraph=new R(i),this.kvStorage=new C,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,s==null||s(this.optimisticMutationStack));}).then(()=>{Object.entries(this.schema).forEach(([r])=>{this.kvStorage.get(r).then(o=>{if(!o||Object.keys(o).length===0)return;let n=Object.values(o);this.loadConsolidatedState(r,n);});});}).catch(r=>{i.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,i=false){var o;let s=t??g(e$1);if(this.querySnapshots[s]&&!i){let n=this.querySnapshots[s];if(n)return n}let r=((o=e$1.where)!=null&&o.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,p)=>{for(let d of e$1.sort){let c=a[d.key],l=p[d.key];if(c<l)return d.direction==="asc"?-1:1;if(c>l)return d.direction==="asc"?1:-1}return 0};r.sort(n);}if(e$1.where||e$1.limit){let n=e$1.where?a=>b(a,e$1.where):()=>true;r=e(r,n,e$1.limit);}return i||(this.querySnapshots[s]=r),r}subscribe(e,t){var r;let i=g(e);return this.collectionSubscriptions.get(i)||this.collectionSubscriptions.set(i,{callbacks:new Set,query:e,flatInclude:e.include?this.flattenIncludes(e.include,e.resource):void 0}),(r=this.collectionSubscriptions.get(i))==null||r.callbacks.add(t),()=>{var o,n;(o=this.collectionSubscriptions.get(i))==null||o.callbacks.delete(t),((n=this.collectionSubscriptions.get(i))==null?void 0:n.callbacks.size)===0&&(this.collectionSubscriptions.delete(i),delete this.querySnapshots[i]);}}addMutation(e,t,i=false){var o,n,a;let s=this.schema[e];if(this.logger.debug("Adding mutation",t),!s)throw new Error("Schema not found");let r=(o=this.optimisticRawObjPool[e])==null?void 0:o[t.resourceId];if(i)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 p={value:{...this.schema[e].mergeMutation("set",t.payload,this.rawObjPool[e][t.resourceId])[0].value,id:{value:t.resourceId}}};this.rawObjPool[e][t.resourceId]=p;let d=p.value;delete d.id,this.kvStorage.set(e,t.resourceId,d);}this.kvStorage.setMeta("mutationStack",this.optimisticMutationStack),this.updateRawObjPool(e,t.resourceId,t.payload,r);}undoMutation(e,t){var o,n;if(!this.optimisticMutationStack[e])return;let i=(o=this.optimisticMutationStack[e])==null?void 0:o.findIndex(a=>a.id===t);if(i===-1)return;let s=this.optimisticMutationStack[e][i];this.logger.debug("Removing mutation",s);let r=(n=this.optimisticRawObjPool[e])==null?void 0:n[s.resourceId];this.optimisticMutationStack[e].splice(i,1),this.kvStorage.setMeta("mutationStack",this.optimisticMutationStack),this.updateRawObjPool(e,s.resourceId,Object.fromEntries(Object.entries(s.payload).map(([a])=>[a,{value:null,_meta:{}}])),r);}loadConsolidatedState(e,t){t.forEach(i=>{var n;let s=(n=i.id)==null?void 0:n.value;if(!s)return;let{cleanedPayload:r,nestedMutations:o}=this.extractNestedRelations(e,i);o.forEach(a=>{this.addMutation(a.resource,a);}),this.addMutation(e,{id:s,type:"MUTATE",resource:e,resourceId:s,procedure:"INSERT",payload:r});});}extractNestedRelations(e,t){let i=this.schema[e],s={...t},r=[];return i!=null&&i.relations?(Object.entries(t).forEach(([o,n])=>{var c;let a=i.relations[o];if(!a)return;let p=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 l=d.id.value,f={...d},{cleanedPayload:m,nestedMutations:S}=this.extractNestedRelations(p,f);r.push(...S),r.push({id:l,type:"MUTATE",resource:p,resourceId:l,procedure:"INSERT",payload:m}),delete s[o];}}else a.type==="many"&&Array.isArray(d)&&(d.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,_={...l.value},{cleanedPayload:F,nestedMutations:V}=this.extractNestedRelations(p,_);r.push(...V),r.push({id:S,type:"MUTATE",resource:p,resourceId:S,procedure:"INSERT",payload:F});}}),delete s[o]);}),{cleanedPayload:s,nestedMutations:r}):{cleanedPayload:s,nestedMutations:r}}updateRawObjPool(e,t,i,s){var n;if(!this.schema[e])return;let r=(n=this.rawObjPool[e])==null?void 0:n[t],o=(this.optimisticMutationStack[e]??[]).reduce((a,p)=>p.resourceId!==t?a:this.schema[e].mergeMutation("set",p.payload,a)[0],r);if(this.optimisticRawObjPool[e]??={},o?this.optimisticRawObjPool[e][t]={value:{...o.value,id:{value:t}}}:delete this.optimisticRawObjPool[e][t],!(!this.optimisticObjGraph.hasNode(t)&&!o)){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(([p,d])=>d.type==="one"?[[d.relationalColumn,p]]:[]));Object.entries(i).forEach(([p,d])=>{let c=this.schema[e].relations[a[p]];if(!a[p])return;let l=s==null?void 0:s.value[p],[,f]=c.mergeMutation("set",d,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 i=this.optimisticObjGraph.getNode(e);if(!i)return;let s=i.type,r=(a=this.optimisticRawObjPool[s])==null?void 0:a[e];if(!r)return;let[o,n]=Object.entries(t).reduce((p,[d,c])=>{let l=this.schema[s].relations[d];return l&&(l.type==="one"?p[0].push([d,l.entity.name,c??true]):l.type==="many"&&p[1].push([d,l.entity.name,c??true])),p},[[],[]]);return {value:{...r.value,...Object.fromEntries(o.map(([p,d,c])=>[p,this.materializeOneWithInclude(i.references.get(d),typeof c=="object"&&c!==null?c:{})])),...Object.fromEntries(n.map(([p,d,c])=>{let l=i.referencedBy.get(d),f=l instanceof Set;return [p,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 i=g(t.query),s=this.querySnapshots[i],r=this.get(t.query,void 0,true);if(le(r,s))return;this.querySnapshots[i]=r,t.callbacks.forEach(o=>{o(r);});}});}flattenIncludes(e,t){let i=[];return Object.entries(e).forEach(([s,r])=>{var a;let o=(a=this.schema[t])==null?void 0:a.relations[s];if(!o)return;let n=o.entity.name;i.push(n),typeof r=="object"&&r!==null&&i.push(...this.flattenIncludes(r,n));}),Array.from(new Set(i))}};var D=class{url;ws;store;logger;remoteSubscriptions=new Map;eventListeners=new Set;replyHandlers={};constructor(e){var t,i,s,r;this.url=e.url,this.logger=G({level:e.logLevel??v.INFO}),this.store=new T(e.schema,e.storage,this.logger,o=>{var n,a;(a=(n=Object.values(o))==null?void 0:n.flat())==null||a.forEach(p=>{this.sendWsMessage(p);});}),this.ws=new O({url:e.url,autoConnect:((t=e.connection)==null?void 0:t.autoConnect)??true,autoReconnect:((i=e.connection)==null?void 0:i.autoReconnect)??true,reconnectTimeout:((s=e.connection)==null?void 0:s.reconnectTimeout)??5e3,reconnectLimit:(r=e.connection)==null?void 0:r.maxReconnectAttempts,credentials:e.credentials}),this.ws.addEventListener("message",o=>{this.handleServerMessage(o.data);}),this.ws.addEventListener("connectionChange",o=>{this.emitEvent({type:"CONNECTION_STATE_CHANGE",open:o.open}),o.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.sendWsMessage(a);});}));});}get(e){return this.store.get(e)}handleServerMessage(e){try{this.logger.debug("Message received from the server:",e);let t=H.parse(JSON.parse(e));if(this.logger.debug("Parsed message:",t),this.emitEvent({type:"MESSAGE_RECEIVED",message:t}),t.type==="MUTATE"){let{resource:i}=t;try{this.store.addMutation(i,t);}catch(s){this.logger.error("Error merging mutation from the server:",s);}}else if(t.type==="REJECT")this.store.undoMutation(t.resource,t.id);else if(t.type==="REPLY"){let{id:i,data:s}=t;if(this.replyHandlers[i]){clearTimeout(this.replyHandlers[i].timeoutHandle),this.replyHandlers[i].handler(s);return}let r=q.parse(s);this.store.loadConsolidatedState(r.resource,r.data);}}catch(t){this.logger.error("Error parsing message from the server:",t);}}load(e){this.sendWsMessage({id:a(),type:"SUBSCRIBE",...e});let t=g(e);return this.remoteSubscriptions.has(t)?this.remoteSubscriptions.get(t).subCounter+=1:this.remoteSubscriptions.set(t,{query:e,subCounter:1}),()=>{this.remoteSubscriptions.has(t)&&(this.remoteSubscriptions.get(t).subCounter-=1,this.remoteSubscriptions.get(t).subCounter<=0&&(this.remoteSubscriptions.delete(t),this.sendWsMessage({id:a(),type:"UNSUBSCRIBE",...e})));}}subscribe(e,t){return this.store.subscribe(e,t)}mutate(e,t,i,s){var o;let r={id:a(),type:"MUTATE",resource:e,payload:this.store.schema[e].encodeMutation("set",s,new Date().toISOString()),resourceId:t,procedure:i};(o=this.store)==null||o.addMutation(e,r,true),this.sendWsMessage(r);}genericMutate(e,t,i){if(!this.ws||!this.ws.connected())throw new Error("WebSocket not connected");let s={id:a(),type:"MUTATE",resource:e,procedure:t,payload:i};return this.sendWsMessage(s),new Promise((r,o)=>{this.replyHandlers[s.id]={timeoutHandle:setTimeout(()=>{delete this.replyHandlers[s.id],o(new Error("Reply timeout"));},5e3),handler:n=>{delete this.replyHandlers[s.id],r(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=u=>{let e=new D(u);return {client:{ws:e.ws,load:t=>e.load(t),addEventListener:t=>e.addEventListener(t)},store:{query:Object.entries(u.schema).reduce((t,[i,s])=>(t[i]=c._init(s,e),t),{}),mutate:d(()=>{},{apply:(t,i,s)=>{if(i.length<2)return;if(i.length>2)throw new Error("Trying to access an invalid path");let[r,o]=i;if(o==="insert"){let{id:n,...a}=s[0];return e.mutate(r,n,"INSERT",a)}if(o==="update"){let[n,a]=s;return e.mutate(r,n,"UPDATE",a)}return e.genericMutate(r,o,s[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 m=d=>xxHash32(JSON.stringify(d)).toString(32);var b=(d,e,t=false)=>Object.entries(e).every(([i,s])=>{if(i==="$and")return s.every(r=>b(d,r,t));if(i==="$or")return s.some(r=>b(d,r,t));let o=(s==null?void 0:s.$eq)!==void 0?s==null?void 0:s.$eq:s;if(typeof s=="object"&&s!==null&&(s==null?void 0:s.$eq)===void 0){if(s.$in!==void 0){let n=d[i];return n===void 0?false:t?!s.$in.includes(n):s.$in.includes(n)}if(s.$not!==void 0&&!t)return b(d,{[i]:s.$not},true);if(s.$gt!==void 0){let n=d[i];return typeof n!="number"?false:t?n<=s.$gt:n>s.$gt}if(s.$gte!==void 0){let n=d[i];return typeof n!="number"?false:t?n<s.$gte:n>=s.$gte}if(s.$lt!==void 0){let n=d[i];return typeof n!="number"?false:t?n>=s.$lt:n<s.$lt}if(s.$lte!==void 0){let n=d[i];return typeof n!="number"?false:t?n>s.$lte:n<=s.$lte}let r=d[i];return !r||typeof r!="object"&&!Array.isArray(r)?false:Array.isArray(r)?t?!r.some(n=>b(n,s,false)):r.some(n=>b(n,s,false)):b(r,s,t)}return t?d[i]!==o:d[i]===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 I=class{subscriptions=new Map;getOrStoreSubscription(e){let t=e.buildQueryRequest(),i=m(t);if(this.subscriptions.has(i))return this.subscriptions.get(i).subscribe;let s={subscribe:o=>{let r=this.subscriptions.get(i);return r.callbacks.add(o),r.unsubscribe||(r.unsubscribe=()=>{},r.unsubscribe=e.subscribe(()=>{r.callbacks.forEach(n=>{n();});})),()=>{var n;(n=this.subscriptions.get(i))==null||n.callbacks.delete(o),setTimeout(()=>{var c;let a=this.subscriptions.get(i);a&&a.callbacks.size===0&&((c=a.unsubscribe)==null||c.call(a),this.subscriptions.delete(i));},10);}},callbacks:new Set,unsubscribe:void 0};return this.subscriptions.set(i,s),this.subscriptions.get(i).subscribe}},Z=new I,ye=d=>useSyncExternalStore(Z.getOrStoreSubscription(d),d.get),fe=(d,e)=>{useEffect(()=>{let t=d.load(e.buildQueryRequest());return ()=>{t();}},[e,d.load]);};var R=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()}),x=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=x.superRefine((d,e)=>{d.id&&e.addIssue({code:z$1.ZodIssueCode.custom,message:"Payload cannot have an id"});}),B=z$1.object({id:z$1.string().optional(),type:z$1.literal("MUTATE"),resource:z$1.string(),resourceId:z$1.string().optional()}),j=B.extend({procedure:z$1.string(),payload:z$1.any().optional()}),k=B.extend({procedure:z$1.enum(["INSERT","UPDATE"]),payload:ee});z$1.union([k,j]);var E=z$1.string(),te=R.extend({id:E,type:z$1.literal("SUBSCRIBE")}),ie=R.extend({id:E,type:z$1.literal("UNSUBSCRIBE")}),se=R.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()}),q=z$1.union([oe,ae,G]),z=z$1.object({resource:z$1.string(),data:z$1.array(x)});var T=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 i;this.eventListeners.has(e)||this.eventListeners.set(e,new Set),(i=this.eventListeners.get(e))==null||i.add(t);}removeEventListener(e,t){var i;this.eventListeners.has(e)&&((i=this.eventListeners.get(e))==null||i.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,i;this.dispatchEvent("error",e),this.dispatchEvent("connectionChange",{open:false}),(i=(t=e.error)==null?void 0:t.message)!=null&&i.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 i;(i=this.eventListeners.get(e))==null||i.forEach(s=>{s(t);});}};var O=class{constructor(e){this.logger=e;this.nodes=new Map;}nodes;createNode(e,t,i){if(this.nodes.has(e))throw new Error(`Node with id ${e} already exists`);let s={id:e,type:t,referencedBy:new Map(i.map(o=>[o,new Set])),references:new Map,subscriptions:new Set};return this.nodes.set(e,s),s}getNode(e){return this.nodes.get(e)}hasNode(e){return this.nodes.has(e)}createLink(e,t){let i=this.nodes.get(e),s=this.nodes.get(t);if(!i)throw new Error(`Source node with id ${e} does not exist`);if(!s)throw new Error(`Target node with id ${t} does not exist`);i.references.set(s.type,t);let o=s.referencedBy.get(i.type);o&&o instanceof Set?o.add(e):s.referencedBy.set(i.type,e),this.notifySubscribers(t);}removeLink(e,t){let i=this.nodes.get(e);if(!i)throw new Error(`Node with id ${e} does not exist`);let s=i.references.get(t);if(!s)return;i.references.delete(t);let o=this.nodes.get(s);if(!o)return;let r=o.referencedBy.get(i.type);r&&(r instanceof Set?r.delete(e):o.referencedBy.delete(i.type),this.notifySubscribers(s)),this.notifySubscribers(e);}subscribe(e,t){let i=this.nodes.get(e);if(!i)throw new Error(`Node with id ${e} does not exist`);return i.subscriptions.add(t),()=>{i.subscriptions.delete(t);}}removeNode(e){let t=this.nodes.get(e);t&&(Array.from(t.referencedBy.entries()).forEach(([i,s])=>{(s instanceof Set?Array.from(s.values()):[s]).forEach(r=>{let n=this.nodes.get(r);!n||!n.references.get(i)||(n.references.delete(i),this.notifySubscribers(r));});}),this.nodes.delete(e));}updateNode(e,t){let i=this.nodes.get(e);if(!i)throw new Error(`Node with id ${e} does not exist`);t(i),this.notifySubscribers(e);}notifySubscribers(e){let t=this.nodes.get(e);t&&Array.from(t.subscriptions).forEach(i=>{var s;try{i(e);}catch(o){(s=this.logger)==null||s.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 c,p;if(typeof window>"u")return;let s=((c=(await window.indexedDB.databases()).find(u=>u.name===t))==null?void 0:c.version)??1,o=await m(e),r=Object.fromEntries(await Promise.all(Object.entries(e).map(async([u,l])=>[u,await m(l)]))),n=await openDB("live-state-databases",1,{upgrade(u){u.objectStoreNames.contains(C)||u.createObjectStore(C);}}),a=(p=await this.getAll(n,C))==null?void 0:p[t];(a==null?void 0:a.schemaHash)!==o&&s++,this.db=await openDB(t,s,{async upgrade(u){[...Object.keys(e),D].forEach(l=>{(a==null?void 0:a.objectHashes[l])!==r[l]&&u.objectStoreNames.contains(l)&&u.deleteObjectStore(l),u.objectStoreNames.contains(l)||u.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(i=>i(void 0))}set(e,t,i){var s;return (s=this.db)==null?void 0:s.put(e,i,t)}delete(e,t){var i;return (i=this.db)==null?void 0:i.delete(e,t)}getMeta(e){return this.db?this.db.get(D,e):new Promise(t=>t(void 0))}setMeta(e,t){var i;return (i=this.db)==null?void 0:i.put(D,t,e)}async getAll(e,t){if(!e)return;if(e.getAllRecords)return e.getAllRecords(t);let[i,s]=await Promise.all([e.getAll(t),e.getAllKeys(t)]);return Object.fromEntries(i.map((o,r)=>[s[r],o]))}};var A=class{constructor(e,t,i,s,o,r){this.schema=e;this.logger=i,this.optimisticObjGraph=new O(i),this.kvStorage=new w,this.onQuerySubscriptionTriggered=r,t!==false&&this.kvStorage.init(this.schema,t.name).then(()=>{this.kvStorage.getMeta("mutationStack").then(n=>{!n||Object.keys(n).length===0||(this.optimisticMutationStack=n,s==null||s(this.optimisticMutationStack));}).then(()=>{Object.entries(this.schema).forEach(([n])=>{this.kvStorage.get(n).then(a=>{if(!a||Object.keys(a).length===0){o==null||o(n,0);return}let c=Object.entries(a).map(([p,u])=>({...u,id:{value:p}}));o==null||o(n,c.length),this.loadConsolidatedState(n,c);});});}).catch(n=>{i.debug("Storage initialization failed (may not be available in this environment):",n);});});}rawObjPool={};optimisticMutationStack={};optimisticObjGraph;optimisticRawObjPool={};logger;onQuerySubscriptionTriggered;collectionSubscriptions=new Map;querySnapshots={};kvStorage;get(e$1,t,i=false){var a;let s=t??m(e$1);if(this.querySnapshots[s]&&!i){let c=this.querySnapshots[s];if(c)return c}let o,r=(a=e$1.where)==null?void 0:a.id;r===void 0?o=Object.keys(this.optimisticRawObjPool[e$1.resource]??{}):typeof r=="string"?o=[r]:typeof r=="object"&&r!==null?"$in"in r&&Array.isArray(r.$in)?o=r.$in:"$eq"in r&&typeof r.$eq=="string"?o=[r.$eq]:o=Object.keys(this.optimisticRawObjPool[e$1.resource]??{}):o=Object.keys(this.optimisticRawObjPool[e$1.resource]??{});let n=o.flatMap(c=>{let p=f(this.materializeOneWithInclude(c,e$1.include));return p?[p]:[]});if(e$1.sort&&e$1.sort.length>0){let c=(p,u)=>{for(let l of e$1.sort){let f=p[l.key],g=u[l.key];if(f<g)return l.direction==="asc"?-1:1;if(f>g)return l.direction==="asc"?1:-1}return 0};n.sort(c);}if(e$1.where||e$1.limit){let c=e$1.where?p=>b(p,e$1.where):()=>true;n=e(n,c,e$1.limit);}return i||(this.querySnapshots[s]=n),n}subscribe(e,t){var o;let i=m(e);return this.collectionSubscriptions.get(i)||this.collectionSubscriptions.set(i,{callbacks:new Set,query:e,flatInclude:e.include?this.flattenIncludes(e.include,e.resource):void 0}),(o=this.collectionSubscriptions.get(i))==null||o.callbacks.add(t),()=>{var r,n;(r=this.collectionSubscriptions.get(i))==null||r.callbacks.delete(t),((n=this.collectionSubscriptions.get(i))==null?void 0:n.callbacks.size)===0&&(this.collectionSubscriptions.delete(i),delete this.querySnapshots[i]);}}addMutation(e,t,i=false){var r,n,a;let s=this.schema[e];if(this.logger.debug("Adding mutation",t),!s)throw new Error("Schema not found");let o=(r=this.optimisticRawObjPool[e])==null?void 0:r[t.resourceId];if(i)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(u=>u.id!==t.id))??[],this.rawObjPool[e]??={};let c={value:{...this.schema[e].mergeMutation("set",t.payload,this.rawObjPool[e][t.resourceId])[0].value,id:{value:t.resourceId}}};this.rawObjPool[e][t.resourceId]=c;let p=c.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 i=(r=this.optimisticMutationStack[e])==null?void 0:r.findIndex(a=>a.id===t);if(i===-1)return;let s=this.optimisticMutationStack[e][i];this.logger.debug("Removing mutation",s);let o=(n=this.optimisticRawObjPool[e])==null?void 0:n[s.resourceId];this.optimisticMutationStack[e].splice(i,1),this.kvStorage.setMeta("mutationStack",this.optimisticMutationStack),this.updateRawObjPool(e,s.resourceId,Object.fromEntries(Object.entries(s.payload).map(([a])=>[a,{value:null,_meta:{}}])),o);}loadConsolidatedState(e,t){t.forEach(i=>{var n;let s=(n=i.id)==null?void 0:n.value;if(!s)return;let{cleanedPayload:o,nestedMutations:r}=this.extractNestedRelations(e,i);r.forEach(a=>{this.addMutation(a.resource,a);}),this.addMutation(e,{id:s,type:"MUTATE",resource:e,resourceId:s,procedure:"INSERT",payload:o});});}extractNestedRelations(e,t){let i=this.schema[e],s={...t},o=[];return i!=null&&i.relations?(Object.entries(t).forEach(([r,n])=>{var u;let a=i.relations[r];if(!a)return;let c=a.entity.name,p=n==null?void 0:n.value;if(a.type==="one"){if(p&&typeof p=="object"&&!Array.isArray(p)&&((u=p.id)!=null&&u.value)){let l=p.id.value,f={...p},{cleanedPayload:g,nestedMutations:S}=this.extractNestedRelations(c,f);o.push(...S),o.push({id:l,type:"MUTATE",resource:c,resourceId:l,procedure:"INSERT",payload:g}),delete s[r];}}else a.type==="many"&&Array.isArray(p)&&(p.forEach(l=>{var f,g;if(l&&typeof l=="object"&&!Array.isArray(l)&&((g=(f=l.value)==null?void 0:f.id)!=null&&g.value)){let S=l.value.id.value,H={...l.value},{cleanedPayload:V,nestedMutations:Y}=this.extractNestedRelations(c,H);o.push(...Y),o.push({id:S,type:"MUTATE",resource:c,resourceId:S,procedure:"INSERT",payload:V});}}),delete s[r]);}),{cleanedPayload:s,nestedMutations:o}):{cleanedPayload:s,nestedMutations:o}}updateRawObjPool(e,t,i,s){var n;if(!this.schema[e])return;let o=(n=this.rawObjPool[e])==null?void 0:n[t],r=(this.optimisticMutationStack[e]??[]).reduce((a,c)=>c.resourceId!==t?a:this.schema[e].mergeMutation("set",c.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(([c,p])=>p.type==="one"?[[p.relationalColumn,c]]:[]));Object.entries(i).forEach(([c,p])=>{let u=this.schema[e].relations[a[c]];if(!a[c])return;let l=s==null?void 0:s.value[c],[,f]=u.mergeMutation("set",p,l);if(f){if(!this.optimisticObjGraph.hasNode(f.value)){let g=u.entity.name;this.optimisticObjGraph.createNode(f.value,g,Object.values(this.schema[g].relations).flatMap(S=>S.type==="many"?[S.entity.name]:[]));}l!=null&&l.value&&this.optimisticObjGraph.removeLink(t,u.entity.name),this.optimisticObjGraph.createLink(t,f.value);}});}this.notifyCollectionSubscribers(e),this.optimisticObjGraph.notifySubscribers(t);}}materializeOneWithInclude(e,t={}){var a;if(!e)return;let i=this.optimisticObjGraph.getNode(e);if(!i)return;let s=i.type,o=(a=this.optimisticRawObjPool[s])==null?void 0:a[e];if(!o)return;let[r,n]=Object.entries(t).reduce((c,[p,u])=>{let l=this.schema[s].relations[p];return l&&(l.type==="one"?c[0].push([p,l.entity.name,u??true]):l.type==="many"&&c[1].push([p,l.entity.name,u??true])),c},[[],[]]);return {value:{...o.value,...Object.fromEntries(r.map(([c,p,u])=>[c,this.materializeOneWithInclude(i.references.get(p),typeof u=="object"&&u!==null?u:{})])),...Object.fromEntries(n.map(([c,p,u])=>{let l=i.referencedBy.get(p),f=l instanceof Set;return [c,f?{value:Array.from(l.values()).map(g=>this.materializeOneWithInclude(g,typeof u=="object"&&u!==null?u:{}))}:this.materializeOneWithInclude(l,typeof u=="object"&&u!==null?u:{})]}))}}}notifyCollectionSubscribers(e){this.collectionSubscriptions.forEach(t=>{var i,s;if(t.query.resource===e||(i=t.flatInclude)!=null&&i.includes(e)){let o=m(t.query),r=this.querySnapshots[o],n=this.get(t.query,void 0,true);if(ue(n,r))return;this.querySnapshots[o]=n,(s=this.onQuerySubscriptionTriggered)==null||s.call(this,t.query),t.callbacks.forEach(a=>{a(n);});}});}flattenIncludes(e,t){let i=[];return Object.entries(e).forEach(([s,o])=>{var a;let r=(a=this.schema[t])==null?void 0:a.relations[s];if(!r)return;let n=r.entity.name;i.push(n),typeof o=="object"&&o!==null&&i.push(...this.flattenIncludes(o,n));}),Array.from(new Set(i))}};var P=class{url;ws;store;logger;remoteSubscriptions=new Map;eventListeners=new Set;replyHandlers={};constructor(e){var t,i,s,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(c=>{this.sendWsMessage(c);});},(r,n)=>{this.emitEvent({type:"CLIENT_STORAGE_LOADED",resource:r,itemCount:n});},r=>{this.emitEvent({type:"QUERY_SUBSCRIPTION_TRIGGERED",query:r});}),this.ws=new T({url:e.url,autoConnect:((t=e.connection)==null?void 0:t.autoConnect)??true,autoReconnect:((i=e.connection)==null?void 0:i.autoReconnect)??true,reconnectTimeout:((s=e.connection)==null?void 0:s.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,i;try{this.logger.debug("Message received from the server:",e);let s=q.parse(JSON.parse(e));if(this.logger.debug("Parsed message:",s),this.emitEvent({type:"MESSAGE_RECEIVED",message:s}),s.type==="MUTATE"){let{resource:o,id:r,resourceId:n,procedure:a}=s;this.emitEvent({type:"MUTATION_RECEIVED",mutationId:r,resource:o,resourceId:n,procedure:a??"UNKNOWN"});try{this.store.addMutation(o,s);}catch(c){this.logger.error("Error merging mutation from the server:",c);}}else if(s.type==="REJECT"){let o=((t=this.store.optimisticMutationStack[s.resource])==null?void 0:t.length)??0,r=(i=this.store.optimisticMutationStack[s.resource])==null?void 0:i.find(n=>n.id===s.id);this.store.undoMutation(s.resource,s.id),this.emitEvent({type:"MUTATION_REJECTED",mutationId:s.id,resource:s.resource}),r&&this.emitEvent({type:"OPTIMISTIC_MUTATION_UNDONE",mutationId:s.id,resource:s.resource,resourceId:r.resourceId,pendingMutations:o-1});}else if(s.type==="REPLY"){let{id:o,data:r}=s;if(this.replyHandlers[o]){clearTimeout(this.replyHandlers[o].timeoutHandle),this.replyHandlers[o].handler(r);return}let n=z.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(s){this.logger.error("Error parsing message from the server:",s);}}load(e){let t=a(),i=m(e);this.emitEvent({type:"DATA_LOAD_REQUESTED",query:e,subscriptionId:t}),this.sendWsMessage({id:t,type:"SUBSCRIBE",...e});let s=!this.remoteSubscriptions.has(i);return this.remoteSubscriptions.has(i)?this.remoteSubscriptions.get(i).subCounter+=1:this.remoteSubscriptions.set(i,{query:e,subCounter:1}),s&&this.emitEvent({type:"SUBSCRIPTION_CREATED",query:e,subscriptionKey:i,subscriberCount:1}),()=>{if(this.remoteSubscriptions.has(i)){let o=this.remoteSubscriptions.get(i);o.subCounter-=1,this.remoteSubscriptions.get(i).subCounter<=0&&(this.remoteSubscriptions.delete(i),this.sendWsMessage({id:a(),type:"UNSUBSCRIBE",...e}),this.emitEvent({type:"SUBSCRIPTION_REMOVED",query:e,subscriptionKey:i}));}}}subscribe(e,t){return this.store.subscribe(e,t)}mutate(e,t,i,s){var n,a$1;let o={id:a(),type:"MUTATE",resource:e,payload:this.store.schema[e].encodeMutation("set",s,new Date().toISOString()),resourceId:t,procedure:i},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:i,pendingMutations:r}),this.emitEvent({type:"MUTATION_SENT",mutationId:o.id,resource:e,resourceId:t,procedure:i,optimistic:true}),this.sendWsMessage(o);}genericMutate(e,t,i){if(!this.ws||!this.ws.connected())throw new Error("WebSocket not connected");let s={id:a(),type:"MUTATE",resource:e,procedure:t,payload:i};return this.emitEvent({type:"MUTATION_SENT",mutationId:s.id,resource:e,resourceId:"",procedure:t,optimistic:false}),this.sendWsMessage(s),new Promise((o,r)=>{this.replyHandlers[s.id]={timeoutHandle:setTimeout(()=>{delete this.replyHandlers[s.id],r(new Error("Reply timeout"));},5e3),handler:n=>{delete this.replyHandlers[s.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);});}},ze=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,[i,s])=>(t[i]=c._init(s,e),t),{}),mutate:d(()=>{},{apply:(t,i,s)=>{if(i.length<2)return;if(i.length>2)throw new Error("Trying to access an invalid path");let[o,r]=i;if(r==="insert"){let{id:n,...a}=s[0];return e.mutate(o,n,"INSERT",a)}if(r==="update"){let[n,a]=s;return e.mutate(o,n,"UPDATE",a)}return e.genericMutate(o,r,s[0])}})}}};export{ze as createClient,ye as useLiveQuery,fe as useLoadData};
|
package/dist/fetch-client.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { C as ClientOptions,
|
|
1
|
+
import { C as ClientOptions, a as ClientRouterConstraint, b as Client } from './index-P-s1Yf1S.js';
|
|
2
2
|
import 'zod';
|
|
3
|
-
import '
|
|
4
|
-
import 'zod/v4/core';
|
|
3
|
+
import '@standard-schema/spec';
|
|
5
4
|
|
|
6
5
|
type FetchClientOptions = Omit<ClientOptions, "storage"> & {
|
|
7
6
|
fetchOptions?: RequestInit;
|
|
8
7
|
};
|
|
9
|
-
declare const createClient: <TRouter extends
|
|
8
|
+
declare const createClient: <TRouter extends ClientRouterConstraint>(opts: FetchClientOptions) => Client<TRouter, true>;
|
|
10
9
|
|
|
11
10
|
export { type FetchClientOptions, createClient };
|
package/dist/fetch-client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {d,b,c,f as f$1}from'./chunk-AHF6GNMI.js';import {stringify}from'qs';var f=async(e,c,r)=>{let n=o=>{if(!o)return {};if(o instanceof Headers){let
|
|
1
|
+
import {d,b,c,f as f$1}from'./chunk-AHF6GNMI.js';import {stringify}from'qs';var f=async(e,c,r)=>{let n=o=>{if(!o)return {};if(o instanceof Headers){let d={};return o.forEach((y,b)=>{d[b]=y;}),d}return Array.isArray(o)?Object.fromEntries(o):o},s=n(r==null?void 0:r.headers),u=n(c==null?void 0:c.headers),a={...r,...c,headers:{...s,...u}},t=await fetch(e,a),i;try{i=await t.json();}catch{i=await t.text().catch(()=>{});}if(!t.ok)throw new Error(`Failed to fetch: ${t.status} ${t.statusText}`,{cause:i});return i},h=e=>{if(e===null)return "null";if(Array.isArray(e))return e.map(h);if(typeof e=="object"&&e!==null&&e.constructor===Object){let c={};for(let[r,n]of Object.entries(e))c[r]=h(n);return c}return e},$=e=>{let c$1={get:async r=>{let n=h(r),s=stringify(n),u=await b(e.credentials)??{},a=await f(`${e.url}/${r.resource}${s?`?${s}`:""}`,{headers:{...u,"Content-Type":"application/json"}},e.fetchOptions);return !a||typeof a!="object"?[]:Array.isArray(a)?a.map(t=>{var d,y;let i=f$1(t),o=((y=(d=t==null?void 0:t.value)==null?void 0:d.id)==null?void 0:y.value)??(t==null?void 0:t.id);return {...i,id:o}}):Object.entries(a).map(([t,i])=>({...f$1(i),id:t}))},subscribe:()=>{throw new Error("Fetch client does not support subscriptions")}};return {query:Object.entries(e.schema).reduce((r,[n,s])=>(r[n]=c._init(s,c$1,true),r),{}),mutate:d(()=>{},{apply:async(r,n,s)=>{if(n.length<2)return;if(n.length>2)throw new Error("Trying to access an invalid path");let[u,a]=n,t=await b(e.credentials)??{};if(a==="insert"){let{id:i,...o}=s[0];await f(`${e.url}/${u}/insert`,{method:"POST",headers:{...t,"Content-Type":"application/json"},body:JSON.stringify({resourceId:i,payload:e.schema[u].encodeMutation("set",o,new Date().toISOString())})},e.fetchOptions);return}if(a==="update"){let[i,o]=s,{id:d,...y}=o;await f(`${e.url}/${u}/update`,{method:"POST",headers:{...t,"Content-Type":"application/json"},body:JSON.stringify({resourceId:i,payload:e.schema[u].encodeMutation("set",y,new Date().toISOString())})},e.fetchOptions);return}return await f(`${e.url}/${u}/${a}`,{method:"POST",headers:{...t,"Content-Type":"application/json"},body:JSON.stringify({payload:s[0]})},e.fetchOptions)}})}};export{$ as createClient};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import
|
|
3
|
-
import * as z4 from 'zod/v4/core';
|
|
2
|
+
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
4
3
|
|
|
5
4
|
type LiveTypeMeta = {};
|
|
6
5
|
type MutationType = "set";
|
|
@@ -253,169 +252,6 @@ declare const querySchema: z.ZodObject<{
|
|
|
253
252
|
}, z.core.$strip>;
|
|
254
253
|
type RawQueryRequest = z.infer<typeof querySchema>;
|
|
255
254
|
|
|
256
|
-
/** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
|
|
257
|
-
/** biome-ignore-all lint/style/noNonNullAssertion: false positive */
|
|
258
|
-
|
|
259
|
-
type RouteRecord = Record<string, AnyRoute>;
|
|
260
|
-
declare class Router<TRoutes extends RouteRecord> {
|
|
261
|
-
readonly routes: TRoutes;
|
|
262
|
-
readonly hooksRegistry: Map<string, Hooks<any>>;
|
|
263
|
-
private constructor();
|
|
264
|
-
static create<TRoutes extends RouteRecord>(opts: {
|
|
265
|
-
routes: TRoutes;
|
|
266
|
-
}): Router<TRoutes>;
|
|
267
|
-
getHooks(resourceName: string): Hooks<any> | undefined;
|
|
268
|
-
}
|
|
269
|
-
type AnyRouter = Router<any>;
|
|
270
|
-
type Mutation<TInputValidator extends z3.ZodTypeAny | z4.$ZodType, // TODO use StandardSchema instead
|
|
271
|
-
TOutput> = {
|
|
272
|
-
inputValidator: TInputValidator;
|
|
273
|
-
handler: (opts: {
|
|
274
|
-
req: MutationRequest<z.infer<TInputValidator>>;
|
|
275
|
-
db: Storage;
|
|
276
|
-
}) => TOutput;
|
|
277
|
-
};
|
|
278
|
-
declare const mutationCreator: <TInputValidator extends z3.ZodTypeAny | z4.$ZodType>(validator?: TInputValidator) => {
|
|
279
|
-
handler: <THandler extends Mutation<TInputValidator, any>["handler"]>(handler: THandler) => Mutation<TInputValidator, ReturnType<THandler>>;
|
|
280
|
-
};
|
|
281
|
-
type ReadAuthorizationHandler<TShape extends LiveObjectAny> = (opts: {
|
|
282
|
-
ctx: BaseRequest["context"];
|
|
283
|
-
}) => WhereClause<TShape> | boolean;
|
|
284
|
-
type MutationAuthorizationHandler<TShape extends LiveObjectAny> = (opts: {
|
|
285
|
-
ctx: BaseRequest["context"];
|
|
286
|
-
value: Simplify<InferLiveObjectWithRelationalIds<TShape>>;
|
|
287
|
-
}) => WhereClause<TShape> | boolean;
|
|
288
|
-
type Authorization<TShape extends LiveObjectAny> = {
|
|
289
|
-
read?: ReadAuthorizationHandler<TShape>;
|
|
290
|
-
insert?: MutationAuthorizationHandler<TShape>;
|
|
291
|
-
update?: {
|
|
292
|
-
preMutation?: MutationAuthorizationHandler<TShape>;
|
|
293
|
-
postMutation?: MutationAuthorizationHandler<TShape>;
|
|
294
|
-
};
|
|
295
|
-
};
|
|
296
|
-
type BeforeInsertHook<TShape extends LiveObjectAny> = (opts: {
|
|
297
|
-
ctx?: Record<string, any>;
|
|
298
|
-
value: MaterializedLiveType<TShape>;
|
|
299
|
-
db: Storage;
|
|
300
|
-
}) => Promise<MaterializedLiveType<TShape> | void> | MaterializedLiveType<TShape> | void;
|
|
301
|
-
type AfterInsertHook<TShape extends LiveObjectAny> = (opts: {
|
|
302
|
-
ctx?: Record<string, any>;
|
|
303
|
-
value: MaterializedLiveType<TShape>;
|
|
304
|
-
db: Storage;
|
|
305
|
-
}) => Promise<void> | void;
|
|
306
|
-
type BeforeUpdateHook<TShape extends LiveObjectAny> = (opts: {
|
|
307
|
-
ctx?: Record<string, any>;
|
|
308
|
-
value: MaterializedLiveType<TShape>;
|
|
309
|
-
previousValue?: MaterializedLiveType<TShape>;
|
|
310
|
-
db: Storage;
|
|
311
|
-
}) => Promise<MaterializedLiveType<TShape> | void> | MaterializedLiveType<TShape> | void;
|
|
312
|
-
type AfterUpdateHook<TShape extends LiveObjectAny> = (opts: {
|
|
313
|
-
ctx?: Record<string, any>;
|
|
314
|
-
value: MaterializedLiveType<TShape>;
|
|
315
|
-
previousValue?: MaterializedLiveType<TShape>;
|
|
316
|
-
db: Storage;
|
|
317
|
-
}) => Promise<void> | void;
|
|
318
|
-
type Hooks<TShape extends LiveObjectAny> = {
|
|
319
|
-
beforeInsert?: BeforeInsertHook<TShape>;
|
|
320
|
-
afterInsert?: AfterInsertHook<TShape>;
|
|
321
|
-
beforeUpdate?: BeforeUpdateHook<TShape>;
|
|
322
|
-
afterUpdate?: AfterUpdateHook<TShape>;
|
|
323
|
-
};
|
|
324
|
-
declare class Route<TResourceSchema extends LiveObjectAny, TMiddleware extends Middleware<any>, TCustomMutations extends Record<string, Mutation<any, any>>> {
|
|
325
|
-
readonly resourceSchema: TResourceSchema;
|
|
326
|
-
readonly middlewares: Set<TMiddleware>;
|
|
327
|
-
readonly customMutations: TCustomMutations;
|
|
328
|
-
readonly authorization?: Authorization<TResourceSchema>;
|
|
329
|
-
readonly hooks?: Hooks<TResourceSchema>;
|
|
330
|
-
constructor(resourceSchema: TResourceSchema, customMutations?: TCustomMutations, authorization?: Authorization<TResourceSchema>, hooks?: Hooks<TResourceSchema>);
|
|
331
|
-
use(...middlewares: TMiddleware[]): this;
|
|
332
|
-
withMutations<T extends Record<string, Mutation<any, any>>>(mutationFactory: (opts: {
|
|
333
|
-
mutation: typeof mutationCreator;
|
|
334
|
-
}) => T): Route<TResourceSchema, TMiddleware, T>;
|
|
335
|
-
withHooks(hooks: Hooks<TResourceSchema>): Route<TResourceSchema, TMiddleware, TCustomMutations>;
|
|
336
|
-
getAuthorizationClause(req: QueryRequest): WhereClause<TResourceSchema> | undefined | boolean;
|
|
337
|
-
private handleSet;
|
|
338
|
-
private wrapInMiddlewares;
|
|
339
|
-
}
|
|
340
|
-
type AnyRoute = Route<LiveObjectAny, Middleware<any>, Record<string, any>>;
|
|
341
|
-
|
|
342
|
-
/** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
|
|
343
|
-
|
|
344
|
-
declare class Batcher {
|
|
345
|
-
private storage;
|
|
346
|
-
private queue;
|
|
347
|
-
private scheduled;
|
|
348
|
-
constructor(storage: Storage);
|
|
349
|
-
rawFind<T extends LiveObjectAny>({ resource, commonWhere, uniqueWhere, ...rest }: {
|
|
350
|
-
resource: string;
|
|
351
|
-
commonWhere?: Record<string, any>;
|
|
352
|
-
uniqueWhere?: Record<string, any>;
|
|
353
|
-
include?: Record<string, any>;
|
|
354
|
-
limit?: number;
|
|
355
|
-
sort?: {
|
|
356
|
-
key: string;
|
|
357
|
-
direction: "asc" | "desc";
|
|
358
|
-
}[];
|
|
359
|
-
}): Promise<MaterializedLiveType<T>[]>;
|
|
360
|
-
private getBatchKey;
|
|
361
|
-
private processBatch;
|
|
362
|
-
private executeBatchedRequests;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
interface DataSource {
|
|
366
|
-
get(query: RawQueryRequest, extra?: {
|
|
367
|
-
context?: any;
|
|
368
|
-
batcher?: Batcher;
|
|
369
|
-
}): PromiseOrSync<any[]>;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
/** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
|
|
373
|
-
|
|
374
|
-
declare abstract class Storage implements DataSource {
|
|
375
|
-
abstract findOne<T extends LiveObjectAny>(resource: T, id: string, options?: {
|
|
376
|
-
include?: IncludeClause<T>;
|
|
377
|
-
}): Promise<InferLiveObject<T> | undefined>;
|
|
378
|
-
abstract find<T extends LiveObjectAny>(resource: T, options?: {
|
|
379
|
-
where?: WhereClause<T>;
|
|
380
|
-
include?: IncludeClause<T>;
|
|
381
|
-
limit?: number;
|
|
382
|
-
sort?: {
|
|
383
|
-
key: string;
|
|
384
|
-
direction: "asc" | "desc";
|
|
385
|
-
}[];
|
|
386
|
-
}): Promise<InferLiveObject<T>[]>;
|
|
387
|
-
insert<T extends LiveObjectAny>(resource: T, value: Simplify<InferInsert<T>>): Promise<InferLiveObject<T>>;
|
|
388
|
-
update<T extends LiveObjectAny>(resource: T, resourceId: string, value: InferUpdate<T>): Promise<Partial<InferLiveObject<T>>>;
|
|
389
|
-
abstract transaction<T>(fn: (opts: {
|
|
390
|
-
trx: Storage;
|
|
391
|
-
commit: () => Promise<void>;
|
|
392
|
-
rollback: () => Promise<void>;
|
|
393
|
-
}) => Promise<T>): Promise<T>;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
interface BaseRequest {
|
|
397
|
-
headers: Record<string, string>;
|
|
398
|
-
cookies: Record<string, string>;
|
|
399
|
-
queryParams: Record<string, string>;
|
|
400
|
-
context: Record<string, any>;
|
|
401
|
-
}
|
|
402
|
-
interface QueryRequest extends BaseRequest, RawQueryRequest {
|
|
403
|
-
type: "QUERY";
|
|
404
|
-
}
|
|
405
|
-
interface MutationRequest<TInput = any> extends BaseRequest {
|
|
406
|
-
type: "MUTATE";
|
|
407
|
-
input: TInput;
|
|
408
|
-
resource: string;
|
|
409
|
-
resourceId?: string;
|
|
410
|
-
procedure: string;
|
|
411
|
-
}
|
|
412
|
-
type Request = QueryRequest | MutationRequest;
|
|
413
|
-
type NextFunction<O, R = Request> = (req: R) => PromiseOrSync<O>;
|
|
414
|
-
type Middleware<T = any> = (opts: {
|
|
415
|
-
req: Request;
|
|
416
|
-
next: NextFunction<T>;
|
|
417
|
-
}) => ReturnType<NextFunction<T>>;
|
|
418
|
-
|
|
419
255
|
/** biome-ignore-all lint/complexity/noBannedTypes: <explanation> */
|
|
420
256
|
|
|
421
257
|
type InferQueryResult<TCollection extends LiveObjectAny, TInclude extends IncludeClause<TCollection>, TSingle extends boolean = false> = TSingle extends true ? Simplify<InferLiveObject<TCollection, TInclude>> | undefined : Simplify<InferLiveObject<TCollection, TInclude>>[];
|
|
@@ -450,11 +286,57 @@ declare class QueryBuilder<TCollection extends LiveObjectAny, TInclude extends I
|
|
|
450
286
|
subscribe(callback: (value: InferQueryResult<TCollection, TInclude, TSingle>) => void): () => void;
|
|
451
287
|
}
|
|
452
288
|
|
|
289
|
+
/**
|
|
290
|
+
* Extracts the output type from a Standard Schema validator.
|
|
291
|
+
* Supports Standard Schema (via ~standard property) and Zod schemas (via _output property for backward compatibility).
|
|
292
|
+
*/
|
|
293
|
+
type InferSchema<T> = T extends {
|
|
294
|
+
"~standard": {
|
|
295
|
+
types?: {
|
|
296
|
+
output: infer U;
|
|
297
|
+
};
|
|
298
|
+
};
|
|
299
|
+
} ? U : T extends StandardSchemaV1<any, any> ? StandardSchemaV1.InferOutput<T> : T extends {
|
|
300
|
+
_output: infer U;
|
|
301
|
+
} ? U : never;
|
|
302
|
+
/**
|
|
303
|
+
* Helper type for custom mutation functions.
|
|
304
|
+
* When the input type is `never` or `undefined`, the function has no parameters.
|
|
305
|
+
*/
|
|
306
|
+
type CustomMutationFunction<TInput, TOutput> = [TInput] extends [never] | [undefined] ? () => Promisify<TOutput> : (input: TInput) => Promisify<TOutput>;
|
|
307
|
+
/**
|
|
308
|
+
* Simplified router constraint for client-side usage.
|
|
309
|
+
* This avoids importing server-internal types like Storage and Hooks,
|
|
310
|
+
* which can cause type incompatibilities when the package is bundled.
|
|
311
|
+
*/
|
|
312
|
+
type ClientRouterConstraint = {
|
|
313
|
+
routes: Record<string, {
|
|
314
|
+
resourceSchema: LiveObjectAny;
|
|
315
|
+
customMutations: Record<string, {
|
|
316
|
+
inputValidator: StandardSchemaV1<any, any>;
|
|
317
|
+
handler: (...args: any[]) => any;
|
|
318
|
+
}>;
|
|
319
|
+
}>;
|
|
320
|
+
};
|
|
321
|
+
type Client$1<TRouter extends ClientRouterConstraint, TShouldAwait extends boolean = false> = {
|
|
322
|
+
query: {
|
|
323
|
+
[K in keyof TRouter["routes"]]: QueryBuilder<TRouter["routes"][K]["resourceSchema"], {}, false, TShouldAwait>;
|
|
324
|
+
};
|
|
325
|
+
mutate: {
|
|
326
|
+
[K in keyof TRouter["routes"]]: {
|
|
327
|
+
insert: (input: Simplify<InferInsert<TRouter["routes"][K]["resourceSchema"]>>) => ConditionalPromise<void, TShouldAwait>;
|
|
328
|
+
update: (id: string, value: Simplify<InferUpdate<TRouter["routes"][K]["resourceSchema"]>>) => ConditionalPromise<void, TShouldAwait>;
|
|
329
|
+
} & {
|
|
330
|
+
[K2 in keyof TRouter["routes"][K]["customMutations"]]: CustomMutationFunction<InferSchema<TRouter["routes"][K]["customMutations"][K2]["inputValidator"]>, ReturnType<TRouter["routes"][K]["customMutations"][K2]["handler"]>>;
|
|
331
|
+
};
|
|
332
|
+
};
|
|
333
|
+
};
|
|
334
|
+
|
|
453
335
|
declare const useLiveQuery: <T extends {
|
|
454
336
|
get: () => U;
|
|
455
337
|
subscribe: (cb: (v: U) => void) => () => void;
|
|
456
338
|
}, U>(observable: T) => ReturnType<T["get"]>;
|
|
457
|
-
declare const useLoadData: (client: Client<
|
|
339
|
+
declare const useLoadData: (client: Client<ClientRouterConstraint>["client"], query: QueryBuilder<any, any>) => void;
|
|
458
340
|
|
|
459
341
|
declare const serverMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
460
342
|
id: z.ZodString;
|
|
@@ -483,20 +365,6 @@ declare const serverMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
483
365
|
}, z.core.$strip>]>;
|
|
484
366
|
type ServerMessage = z.infer<typeof serverMessageSchema>;
|
|
485
367
|
|
|
486
|
-
type Client$1<TRouter extends AnyRouter, TShouldAwait extends boolean = false> = {
|
|
487
|
-
query: {
|
|
488
|
-
[K in keyof TRouter["routes"]]: QueryBuilder<TRouter["routes"][K]["resourceSchema"], {}, false, TShouldAwait>;
|
|
489
|
-
};
|
|
490
|
-
mutate: {
|
|
491
|
-
[K in keyof TRouter["routes"]]: {
|
|
492
|
-
insert: (input: Simplify<InferInsert<TRouter["routes"][K]["resourceSchema"]>>) => ConditionalPromise<void, TShouldAwait>;
|
|
493
|
-
update: (id: string, value: Simplify<InferUpdate<TRouter["routes"][K]["resourceSchema"]>>) => ConditionalPromise<void, TShouldAwait>;
|
|
494
|
-
} & {
|
|
495
|
-
[K2 in keyof TRouter["routes"][K]["customMutations"]]: (input: z.infer<TRouter["routes"][K]["customMutations"][K2]["inputValidator"]>) => Promisify<ReturnType<TRouter["routes"][K]["customMutations"][K2]["handler"]>>;
|
|
496
|
-
};
|
|
497
|
-
};
|
|
498
|
-
};
|
|
499
|
-
|
|
500
368
|
type WebSocketClientEventMap = WebSocketEventMap & {
|
|
501
369
|
connectionChange: {
|
|
502
370
|
open: boolean;
|
|
@@ -552,8 +420,84 @@ type MessageReceivedEvent = {
|
|
|
552
420
|
type: "MESSAGE_RECEIVED";
|
|
553
421
|
message: ServerMessage;
|
|
554
422
|
};
|
|
555
|
-
type
|
|
556
|
-
type
|
|
423
|
+
type ClientStorageLoadedEvent = {
|
|
424
|
+
type: "CLIENT_STORAGE_LOADED";
|
|
425
|
+
resource: string;
|
|
426
|
+
itemCount: number;
|
|
427
|
+
};
|
|
428
|
+
type DataLoadRequestedEvent = {
|
|
429
|
+
type: "DATA_LOAD_REQUESTED";
|
|
430
|
+
query: RawQueryRequest;
|
|
431
|
+
subscriptionId: string;
|
|
432
|
+
};
|
|
433
|
+
type DataLoadReplyEvent = {
|
|
434
|
+
type: "DATA_LOAD_REPLY";
|
|
435
|
+
resource: string;
|
|
436
|
+
itemCount: number;
|
|
437
|
+
subscriptionId?: string;
|
|
438
|
+
};
|
|
439
|
+
type MutationSentEvent = {
|
|
440
|
+
type: "MUTATION_SENT";
|
|
441
|
+
mutationId: string;
|
|
442
|
+
resource: string;
|
|
443
|
+
resourceId: string;
|
|
444
|
+
procedure: string;
|
|
445
|
+
optimistic: boolean;
|
|
446
|
+
};
|
|
447
|
+
type MutationReceivedEvent = {
|
|
448
|
+
type: "MUTATION_RECEIVED";
|
|
449
|
+
mutationId: string;
|
|
450
|
+
resource: string;
|
|
451
|
+
resourceId: string;
|
|
452
|
+
procedure: string;
|
|
453
|
+
};
|
|
454
|
+
type MutationRejectedEvent = {
|
|
455
|
+
type: "MUTATION_REJECTED";
|
|
456
|
+
mutationId: string;
|
|
457
|
+
resource: string;
|
|
458
|
+
};
|
|
459
|
+
type SubscriptionCreatedEvent = {
|
|
460
|
+
type: "SUBSCRIPTION_CREATED";
|
|
461
|
+
query: RawQueryRequest;
|
|
462
|
+
subscriptionKey: string;
|
|
463
|
+
subscriberCount: number;
|
|
464
|
+
};
|
|
465
|
+
type SubscriptionRemovedEvent = {
|
|
466
|
+
type: "SUBSCRIPTION_REMOVED";
|
|
467
|
+
query: RawQueryRequest;
|
|
468
|
+
subscriptionKey: string;
|
|
469
|
+
};
|
|
470
|
+
type QueryExecutedEvent = {
|
|
471
|
+
type: "QUERY_EXECUTED";
|
|
472
|
+
query: RawQueryRequest;
|
|
473
|
+
resultCount: number;
|
|
474
|
+
};
|
|
475
|
+
type QuerySubscriptionTriggeredEvent = {
|
|
476
|
+
type: "QUERY_SUBSCRIPTION_TRIGGERED";
|
|
477
|
+
query: RawQueryRequest;
|
|
478
|
+
};
|
|
479
|
+
type StoreStateUpdatedEvent = {
|
|
480
|
+
type: "STORE_STATE_UPDATED";
|
|
481
|
+
resource: string;
|
|
482
|
+
itemCount: number;
|
|
483
|
+
};
|
|
484
|
+
type OptimisticMutationAppliedEvent = {
|
|
485
|
+
type: "OPTIMISTIC_MUTATION_APPLIED";
|
|
486
|
+
mutationId: string;
|
|
487
|
+
resource: string;
|
|
488
|
+
resourceId: string;
|
|
489
|
+
procedure: string;
|
|
490
|
+
pendingMutations: number;
|
|
491
|
+
};
|
|
492
|
+
type OptimisticMutationUndoneEvent = {
|
|
493
|
+
type: "OPTIMISTIC_MUTATION_UNDONE";
|
|
494
|
+
mutationId: string;
|
|
495
|
+
resource: string;
|
|
496
|
+
resourceId: string;
|
|
497
|
+
pendingMutations: number;
|
|
498
|
+
};
|
|
499
|
+
type ClientEvents = ConnectionStateChangeEvent | MessageReceivedEvent | ClientStorageLoadedEvent | DataLoadRequestedEvent | DataLoadReplyEvent | MutationSentEvent | MutationReceivedEvent | MutationRejectedEvent | SubscriptionCreatedEvent | SubscriptionRemovedEvent | QueryExecutedEvent | QuerySubscriptionTriggeredEvent | StoreStateUpdatedEvent | OptimisticMutationAppliedEvent | OptimisticMutationUndoneEvent;
|
|
500
|
+
type Client<TRouter extends ClientRouterConstraint> = {
|
|
557
501
|
client: {
|
|
558
502
|
ws: WebSocketClient;
|
|
559
503
|
addEventListener: (listener: (event: ClientEvents) => void) => () => void;
|
|
@@ -561,7 +505,7 @@ type Client<TRouter extends AnyRouter> = {
|
|
|
561
505
|
};
|
|
562
506
|
store: Client$1<TRouter>;
|
|
563
507
|
};
|
|
564
|
-
declare const createClient: <TRouter extends
|
|
508
|
+
declare const createClient: <TRouter extends ClientRouterConstraint>(opts: WebSocketClientOptions) => Client<TRouter>;
|
|
565
509
|
|
|
566
510
|
type ClientOptions = {
|
|
567
511
|
url: string;
|
|
@@ -573,4 +517,4 @@ type ClientOptions = {
|
|
|
573
517
|
logLevel?: LogLevel;
|
|
574
518
|
};
|
|
575
519
|
|
|
576
|
-
export { type
|
|
520
|
+
export { type ClientOptions as C, type DataLoadRequestedEvent as D, type MessageReceivedEvent as M, type OptimisticMutationAppliedEvent as O, type QueryExecutedEvent as Q, type SubscriptionCreatedEvent as S, type ClientRouterConstraint as a, type Client$1 as b, useLoadData as c, type ConnectionStateChangeEvent as d, type ClientStorageLoadedEvent as e, type DataLoadReplyEvent as f, type MutationSentEvent as g, type MutationReceivedEvent as h, type MutationRejectedEvent as i, type SubscriptionRemovedEvent as j, type QuerySubscriptionTriggeredEvent as k, type StoreStateUpdatedEvent as l, type OptimisticMutationUndoneEvent as m, type ClientEvents as n, type Client as o, createClient as p, useLiveQuery as u };
|