@live-state/sync 0.0.7 → 1.0.0-canary-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-YPTDCIAN.js +1 -0
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/fetch-client.d.ts +1 -1
- package/dist/fetch-client.js +1 -1
- package/dist/{index-C0Qm5yHg.d.ts → index-DOU7wys1.d.ts} +113 -76
- package/dist/optimistic-client.d.ts +1 -1
- package/dist/server.cjs +5 -5
- package/dist/server.d.cts +202 -240
- package/dist/server.d.ts +202 -240
- package/dist/server.js +5 -5
- package/package.json +1 -1
- package/dist/chunk-LSAVBBUS.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var d="0123456789ABCDEFGHJKMNPQRSTVWXYZ";var a;(function(e){e.Base32IncorrectEncoding="B32_ENC_INVALID",e.DecodeTimeInvalidCharacter="DEC_TIME_CHAR",e.DecodeTimeValueMalformed="DEC_TIME_MALFORMED",e.EncodeTimeNegative="ENC_TIME_NEG",e.EncodeTimeSizeExceeded="ENC_TIME_SIZE_EXCEED",e.EncodeTimeValueMalformed="ENC_TIME_MALFORMED",e.PRNGDetectFailure="PRNG_DETECT",e.ULIDInvalid="ULID_INVALID",e.Unexpected="UNEXPECTED",e.UUIDInvalid="UUID_INVALID";})(a||(a={}));var c=class extends Error{constructor(t,n){super(`${n} (${t})`),this.name="ULIDError",this.code=t;}};function m(e){let t=Math.floor(e()*32);return t===32&&(t=31),d.charAt(t)}function E(e){let t=p(),n=t&&(t.crypto||t.msCrypto)||null;if(typeof(n==null?void 0:n.getRandomValues)=="function")return ()=>{let r=new Uint8Array(1);return n.getRandomValues(r),r[0]/255};if(typeof(n==null?void 0:n.randomBytes)=="function")return ()=>n.randomBytes(1).readUInt8()/255;throw new c(a.PRNGDetectFailure,"Failed to find a reliable PRNG")}function p(){return g()?self:typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:null}function N(e,t){let n="";for(;e>0;e--)n=m(t)+n;return n}function I(e,t=10){if(isNaN(e))throw new c(a.EncodeTimeValueMalformed,`Time must be a number: ${e}`);if(e>0xffffffffffff)throw new c(a.EncodeTimeSizeExceeded,`Cannot encode a time larger than ${0xffffffffffff}: ${e}`);if(e<0)throw new c(a.EncodeTimeNegative,`Time must be positive: ${e}`);if(Number.isInteger(e)===false)throw new c(a.EncodeTimeValueMalformed,`Time must be an integer: ${e}`);let n,r="";for(let o=t;o>0;o--)n=e%32,r=d.charAt(n)+r,e=(e-n)/32;return r}function g(){return typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope}function T(e,t){let n=E(),r=Date.now();return I(r,10)+N(16,n)}var b=()=>T().toLowerCase();var D=(e,t)=>typeof e=="function"?e(t):e;var _=(e,t,n=[])=>new Proxy(e,{get:(r,o)=>{var f,l;if(o==="__isProxy__")return true;let i=(f=t.get)==null?void 0:f.call(t,r,[...n,o]);if(i!==void 0)return i;let s=r,u=o;return (l=s[u])!=null&&l.__isProxy__||(s[u]=_(typeof s[u]=="object"?s[u]:()=>{},t,[...n,o])),s[u]},apply:(r,o,i)=>{var s;return (s=t.apply)==null?void 0:s.call(t,r,n,i)}}),M=(e,t,n)=>{let r=[],o=0;for(let i=0;i<e.length&&(n===void 0||o<n);i++)t(e[i],i)&&(r.push(e[i]),o++);return r};export{b as a,D as b,_ as c,M as d};
|
package/dist/client.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { B as BootstrapStatusChangeEvent, F as Client, A as ClientBootstrapStatus, E as ClientEvents, C as ClientOptions, a as ClientRouterConstraint, l as ClientState, p as ClientStorageLoadedEvent, o as ConnectionStateChangeEvent, q as DataLoadReplyEvent, D as DataLoadRequestedEvent, M as MessageReceivedEvent, s as MutationReceivedEvent, t as MutationRejectedEvent, r as MutationSentEvent, e as OptimisticHandlerContext, y as OptimisticMutationAppliedEvent, z as OptimisticMutationUndoneEvent, O as OptimisticMutationsConfig, c as OptimisticMutationsRegistry, g as OptimisticOperation, f as OptimisticStorageProxy, Q as QueryExecutedEvent, w as QuerySubscriptionTriggeredEvent, x as StoreStateUpdatedEvent, S as SubscriptionCreatedEvent, v as SubscriptionRemovedEvent, G as createClient, d as defineOptimisticMutations, m as useClientState, u as useLiveQuery, n as useLoadData } from './index-
|
|
1
|
+
export { B as BootstrapStatusChangeEvent, F as Client, A as ClientBootstrapStatus, E as ClientEvents, C as ClientOptions, a as ClientRouterConstraint, l as ClientState, p as ClientStorageLoadedEvent, o as ConnectionStateChangeEvent, q as DataLoadReplyEvent, D as DataLoadRequestedEvent, M as MessageReceivedEvent, s as MutationReceivedEvent, t as MutationRejectedEvent, r as MutationSentEvent, e as OptimisticHandlerContext, y as OptimisticMutationAppliedEvent, z as OptimisticMutationUndoneEvent, O as OptimisticMutationsConfig, c as OptimisticMutationsRegistry, g as OptimisticOperation, f as OptimisticStorageProxy, Q as QueryExecutedEvent, w as QuerySubscriptionTriggeredEvent, x as StoreStateUpdatedEvent, S as SubscriptionCreatedEvent, v as SubscriptionRemovedEvent, G as createClient, d as defineOptimisticMutations, m as useClientState, u as useLiveQuery, n as useLoadData } from './index-DOU7wys1.js';
|
|
2
2
|
import '@standard-schema/spec';
|
|
3
3
|
import 'zod';
|
package/dist/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {d,a,b as b$1,f,e,c}from'./chunk-LSAVBBUS.js';import {a as a$1}from'./chunk-RSSRYEM3.js';export{b as defineOptimisticMutations}from'./chunk-RSSRYEM3.js';import {useSyncExternalStore,useMemo,useEffect}from'react';import {xxHash32}from'js-xxhash';import {z}from'zod';import {stringify}from'qs';import Te from'fast-deep-equal';import {openDB}from'idb';var b=l=>xxHash32(JSON.stringify(l)).toString(32);var E=(l,e,t=false)=>Object.entries(e).every(([i,s])=>{if(i==="$and")return s.every(n=>E(l,n,t));if(i==="$or")return s.some(n=>E(l,n,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 r=l[i];return r===void 0?false:t?!s.$in.includes(r):s.$in.includes(r)}if(s.$not!==void 0&&!t)return E(l,{[i]:s.$not},true);if(s.$gt!==void 0){let r=l[i];return typeof r!="number"?false:t?r<=s.$gt:r>s.$gt}if(s.$gte!==void 0){let r=l[i];return typeof r!="number"?false:t?r<s.$gte:r>=s.$gte}if(s.$lt!==void 0){let r=l[i];return typeof r!="number"?false:t?r>=s.$lt:r<s.$lt}if(s.$lte!==void 0){let r=l[i];return typeof r!="number"?false:t?r>s.$lte:r<=s.$lte}let n=l[i];return !n||typeof n!="object"&&!Array.isArray(n)?false:Array.isArray(n)?t?!n.some(r=>E(r,s,false)):n.some(r=>E(r,s,false)):E(n,s,t)}return t?l[i]!==o:l[i]===o}),I=l=>{if(typeof l!="object"||l===null)return false;let e=l;return "where"in e||"limit"in e||"orderBy"in e||"include"in e},T={CRITICAL:0,ERROR:1,WARN:2,INFO:3,DEBUG:4},U=class{level;prefix;constructor(e={}){this.level=e.level??T.INFO,this.prefix=e.prefix?`[${e.prefix}] `:"";}critical(...e){this.level>=T.CRITICAL&&console.error(`${this.prefix}[CRITICAL]`,...e);}error(...e){this.level>=T.ERROR&&console.error(`${this.prefix}[ERROR]`,...e);}warn(...e){this.level>=T.WARN&&console.warn(`${this.prefix}[WARN]`,...e);}info(...e){this.level>=T.INFO&&console.log(`${this.prefix}[INFO]`,...e);}debug(...e){this.level>=T.DEBUG&&console.log(`${this.prefix}[DEBUG]`,...e);}setLevel(e){this.level=e;}getLevel(){return this.level}},F=l=>new U(l);var _=class{subscriptions=new Map;getOrStoreSubscription(e){let t=e.buildQueryRequest(),i=b(t);if(this.subscriptions.has(i))return this.subscriptions.get(i).subscribe;let s={subscribe:o=>{let n=this.subscriptions.get(i);return n.callbacks.add(o),n.unsubscribe||(n.unsubscribe=()=>{},n.unsubscribe=e.subscribe(()=>{n.callbacks.forEach(r=>{r();});})),()=>{var r;(r=this.subscriptions.get(i))==null||r.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}},pe=new _,we=l=>useSyncExternalStore(pe.getOrStoreSubscription(l),l.get),Ae=l=>{let{subscribe:e,getSnapshot:t}=useMemo(()=>{let i={bootstrapStatus:l.bootstrapStatus,connected:l.ws.connected()},s=()=>{let o={bootstrapStatus:l.bootstrapStatus,connected:l.ws.connected()};(o.bootstrapStatus!==i.bootstrapStatus||o.connected!==i.connected)&&(i=o);};return {subscribe:o=>l.addEventListener(n=>{(n.type==="BOOTSTRAP_STATUS_CHANGE"||n.type==="CONNECTION_STATE_CHANGE")&&(s(),o());}),getSnapshot:()=>i}},[l]);return useSyncExternalStore(e,t,t)},xe=(l,e)=>{useEffect(()=>{let t=l.load(e.buildQueryRequest());return ()=>{t();}},[e,l.load]);};var X=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()}),Q=z.record(z.string(),z.object({value:z.any().nullable(),_meta:z.object({timestamp:z.string().optional().nullable()}).optional()})),he=Q.superRefine((l,e)=>{l.id&&e.addIssue({code:z.ZodIssueCode.custom,message:"Payload cannot have an id"});}),Z=z.object({id:z.string().optional(),type:z.literal("MUTATE"),resource:z.string(),resourceId:z.string().optional()}),ee=z.object({timestamp:z.string().optional(),originMutationId:z.string().optional()}).optional(),N=Z.extend({procedure:z.string(),payload:z.any().optional(),meta:ee}),B=Z.extend({procedure:z.enum(["INSERT","UPDATE"]),payload:he,meta:ee});z.union([B,N]);var te=z.object({resource:z.string(),procedure:z.string(),input:z.any().optional()});var O=z.string(),W=z.union([te,X]),ye=z.object({id:O,type:z.literal("SUBSCRIBE")}).and(W),me=z.object({id:O,type:z.literal("UNSUBSCRIBE")}).and(W),ge=z.object({id:O,type:z.literal("QUERY")}).and(W),fe=z.object({id:O,type:z.literal("CUSTOM_QUERY"),resource:z.string(),procedure:z.string(),input:z.any().optional()}),ie=B.extend({id:O}),be=N.extend({id:O}),Me=z.union([be,ie]);z.union([ye,ge,fe,Me,me]);var Se=z.object({id:O,type:z.literal("REJECT"),resource:z.string(),message:z.string().optional()}),ve=z.object({id:O,type:z.literal("REPLY"),data:z.any()}),se=z.union([Se,ve,ie]),ne=z.object({resource:z.string(),data:z.array(Q)});var x=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 c(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 k=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 n=o.referencedBy.get(i.type);n&&(n instanceof Set?n.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(n=>{let r=this.nodes.get(n);!r||!r.references.get(i)||(r.references.delete(i),this.notifySubscribers(n));});}),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 q="__meta",L="databases",j=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 b(e),n=Object.fromEntries(await Promise.all(Object.entries(e).map(async([u,d])=>[u,await b(d)]))),r=await openDB("live-state-databases",1,{upgrade(u){u.objectStoreNames.contains(L)||u.createObjectStore(L);}}),a=(p=await this.getAll(r,L))==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),q].forEach(d=>{(a==null?void 0:a.objectHashes[d])!==n[d]&&u.objectStoreNames.contains(d)&&u.deleteObjectStore(d),u.objectStoreNames.contains(d)||u.createObjectStore(d);}),await r.put(L,{schemaHash:o,objectHashes:n},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(q,e):new Promise(t=>t(void 0))}setMeta(e,t){var i;return (i=this.db)==null?void 0:i.put(q,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,n)=>[s[n],o]))}};var P=class{constructor(e,t,i,s,o,n){this.schema=e;this.logger=i,this.optimisticObjGraph=new k(i),this.kvStorage=new j,this.onQuerySubscriptionTriggered=n,t!==false&&this.kvStorage.init(this.schema,t.name).then(()=>{Promise.all([this.kvStorage.getMeta("mutationStack"),this.kvStorage.getMeta("customMutationStack"),this.kvStorage.getMeta("customMutationIndex")]).then(([r,a,c])=>{r&&Object.keys(r).length>0&&(this.optimisticMutationStack=r),a&&a.length>0&&(this.customMutationStack=a),c&&Object.keys(c).length>0&&(this.customMutationIndex=c),s==null||s(this.optimisticMutationStack,this.customMutationStack,this.customMutationIndex);}).then(()=>{Object.entries(this.schema).forEach(([r])=>{this.kvStorage.get(r).then(a=>{if(!a||Object.keys(a).length===0){o==null||o(r,0);return}let c=Object.entries(a).map(([p,u])=>({...u,id:{value:p}}));o==null||o(r,c.length),this.loadConsolidatedState(r,c);});});}).catch(r=>{i.debug("Storage initialization failed (may not be available in this environment):",r);});});}rawObjPool={};optimisticMutationStack={};customMutationStack=[];optimisticObjGraph;optimisticRawObjPool={};logger;onQuerySubscriptionTriggered;customMutationIndex={};collectionSubscriptions=new Map;querySnapshots={};kvStorage;get(e$1,t,i=false){var a;let s=t??b(e$1);if(this.querySnapshots[s]&&!i){let c=this.querySnapshots[s];if(c)return c}let o,n=(a=e$1.where)==null?void 0:a.id;n===void 0?o=Object.keys(this.optimisticRawObjPool[e$1.resource]??{}):typeof n=="string"?o=[n]:typeof n=="object"&&n!==null?"$in"in n&&Array.isArray(n.$in)?o=n.$in:"$eq"in n&&typeof n.$eq=="string"?o=[n.$eq]:o=Object.keys(this.optimisticRawObjPool[e$1.resource]??{}):o=Object.keys(this.optimisticRawObjPool[e$1.resource]??{});let r=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 d of e$1.sort){let y=p[d.key],g=u[d.key];if(y<g)return d.direction==="asc"?-1:1;if(y>g)return d.direction==="asc"?1:-1}return 0};r.sort(c);}if(e$1.where||e$1.limit){let c=e$1.where?p=>E(p,e$1.where):()=>true;r=e(r,c,e$1.limit);}return !i&&this.collectionSubscriptions.has(s)&&(this.querySnapshots[s]=r),r}subscribe(e,t){var o;let i=b(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 n,r;(n=this.collectionSubscriptions.get(i))==null||n.callbacks.delete(t),((r=this.collectionSubscriptions.get(i))==null?void 0:r.callbacks.size)===0&&(this.collectionSubscriptions.delete(i),delete this.querySnapshots[i]);}}addMutation(e,t,i=false){var n,r,a,c,p,u,d;let s=this.schema[e];if(this.logger.debug("Adding mutation",t),!s)throw new Error("Schema not found");let o=(n=this.optimisticRawObjPool[e])==null?void 0:n[t.resourceId];if(i)this.optimisticMutationStack[e]??=[],this.optimisticMutationStack[e].push(t);else {this.optimisticMutationStack[e]=((a=(r=this.optimisticMutationStack)==null?void 0:r[e])==null?void 0:a.filter(M=>M.id!==t.id))??[];let y=(c=t.meta)==null?void 0:c.originMutationId;if(this.logger.debug("Broadcast mutation received",{mutationId:t.id,resource:e,resourceId:t.resourceId,procedure:t.procedure,originMutationId:y??"(none)",customMutationIndexKeys:Object.keys(this.customMutationIndex),optimisticStackSize:((p=this.optimisticMutationStack[e])==null?void 0:p.length)??0}),y&&this.customMutationIndex[y]){let w=this.customMutationIndex[y].filter(S=>S.resource===e),C=false;for(let S of w){let R=(u=this.optimisticMutationStack[e])==null?void 0:u.find(A=>A.id===S.mutationId);if(R&&R.resourceId===t.resourceId&&R.procedure===t.procedure){this.logger.debug("Removing optimistic mutation (resourceId match)",{optimisticMutationId:S.mutationId,resourceId:t.resourceId}),this.undoMutation(e,S.mutationId),C=true;break}}if(!C)for(let S of w){let R=(d=this.optimisticMutationStack[e])==null?void 0:d.find(A=>A.id===S.mutationId&&A.procedure===t.procedure);if(R){this.logger.debug("Removing optimistic mutation (resource+procedure fallback)",{optimisticMutationId:S.mutationId,optimisticResourceId:R.resourceId,broadcastResourceId:t.resourceId}),this.undoMutation(e,S.mutationId),C=true;break}}}this.rawObjPool[e]??={};let g={value:{...this.schema[e].mergeMutation("set",t.payload,this.rawObjPool[e][t.resourceId])[0].value,id:{value:t.resourceId}}};this.rawObjPool[e][t.resourceId]=g;let f=g.value;delete f.id,this.kvStorage.set(e,t.resourceId,f);}this.kvStorage.setMeta("mutationStack",this.optimisticMutationStack),this.updateRawObjPool(e,t.resourceId,t.payload,o);}undoMutation(e,t){var n,r;if(!this.optimisticMutationStack[e])return;let i=(n=this.optimisticMutationStack[e])==null?void 0:n.findIndex(a=>a.id===t);if(i===-1)return;let s=this.optimisticMutationStack[e][i];this.logger.debug("Removing mutation",s);let o=(r=this.optimisticRawObjPool[e])==null?void 0:r[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);}addCustomMutationMessage(e){this.customMutationStack.push(e),this.kvStorage.setMeta("customMutationStack",this.customMutationStack);}registerCustomMutation(e,t){this.customMutationIndex[e]=t,this.kvStorage.setMeta("customMutationIndex",this.customMutationIndex);}confirmCustomMutation(e){var i;let t=this.customMutationIndex[e];if(this.logger.debug("confirmCustomMutation called",{messageId:e,hasIndex:!!t,mutations:t??[]}),!!t){for(let{resource:s,mutationId:o}of t){let n=!!((i=this.optimisticMutationStack[s])!=null&&i.find(r=>r.id===o));this.logger.debug("confirmCustomMutation: undoing mutation",{resource:s,mutationId:o,stillInStack:n}),this.undoMutation(s,o);}delete this.customMutationIndex[e],this.kvStorage.setMeta("customMutationIndex",this.customMutationIndex),this.customMutationStack=this.customMutationStack.filter(s=>s.id!==e),this.kvStorage.setMeta("customMutationStack",this.customMutationStack);}}undoCustomMutation(e){var s;let t=this.customMutationIndex[e];if(!t)return [];let i=[];for(let{resource:o,mutationId:n}of t){let r=(s=this.optimisticMutationStack[o])==null?void 0:s.find(a=>a.id===n);this.undoMutation(o,n),r&&i.push({resource:o,mutationId:n,resourceId:r.resourceId});}return delete this.customMutationIndex[e],this.kvStorage.setMeta("customMutationIndex",this.customMutationIndex),this.customMutationStack=this.customMutationStack.filter(o=>o.id!==e),this.kvStorage.setMeta("customMutationStack",this.customMutationStack),i}getCustomMutationMutationIds(){let e=new Set;for(let t of Object.values(this.customMutationIndex))for(let{mutationId:i}of t)e.add(i);return e}loadConsolidatedState(e,t){t.forEach(i=>{var r;let s=(r=i.id)==null?void 0:r.value;if(!s)return;let{cleanedPayload:o,nestedMutations:n}=this.extractNestedRelations(e,i);n.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(([n,r])=>{var u;let a=i.relations[n];if(!a)return;let c=a.entity.name,p=r==null?void 0:r.value;if(a.type==="one"){if(p&&typeof p=="object"&&!Array.isArray(p)&&((u=p.id)!=null&&u.value)){let d=p.id.value,y={...p},{cleanedPayload:g,nestedMutations:f}=this.extractNestedRelations(c,y);o.push(...f),o.push({id:d,type:"MUTATE",resource:c,resourceId:d,procedure:"INSERT",payload:g}),delete s[n];}}else a.type==="many"&&Array.isArray(p)&&(p.forEach(d=>{var y,g;if(d&&typeof d=="object"&&!Array.isArray(d)&&((g=(y=d.value)==null?void 0:y.id)!=null&&g.value)){let f=d.value.id.value,M={...d.value},{cleanedPayload:w,nestedMutations:C}=this.extractNestedRelations(c,M);o.push(...C),o.push({id:f,type:"MUTATE",resource:c,resourceId:f,procedure:"INSERT",payload:w});}}),delete s[n]);}),{cleanedPayload:s,nestedMutations:o}):{cleanedPayload:s,nestedMutations:o}}updateRawObjPool(e,t,i,s){var r;if(!this.schema[e])return;let o=(r=this.rawObjPool[e])==null?void 0:r[t],n=(this.optimisticMutationStack[e]??[]).reduce((a,c)=>c.resourceId!==t?a:this.schema[e].mergeMutation("set",c.payload,a)[0],o);if(this.optimisticRawObjPool[e]??={},n?this.optimisticRawObjPool[e][t]={value:{...n.value,id:{value:t}}}:delete this.optimisticRawObjPool[e][t],!(!this.optimisticObjGraph.hasNode(t)&&!n)){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 d=s==null?void 0:s.value[c],[,y]=u.mergeMutation("set",p,d);if(y){if(!this.optimisticObjGraph.hasNode(y.value)){let g=u.entity.name;this.optimisticObjGraph.createNode(y.value,g,Object.values(this.schema[g].relations).flatMap(f=>f.type==="many"?[f.entity.name]:[]));}d!=null&&d.value&&this.optimisticObjGraph.removeLink(t,u.entity.name),this.optimisticObjGraph.createLink(t,y.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[n,r]=Object.entries(t).reduce((c,[p,u])=>{let d=this.schema[s].relations[p];return d&&(d.type==="one"?c[0].push([p,d.entity.name,u??true]):d.type==="many"&&c[1].push([p,d.entity.name,u??true])),c},[[],[]]);return {value:{...o.value,...Object.fromEntries(n.map(([c,p,u])=>[c,this.materializeOneWithInclude(i.references.get(p),I(u)?u.include??{}:typeof u=="object"&&u!==null?u:{})])),...Object.fromEntries(r.map(([c,p,u])=>{let d=i.referencedBy.get(p),y=d instanceof Set;return [c,y?{value:Array.from(d.values()).map(g=>this.materializeOneWithInclude(g,I(u)?u.include??{}:typeof u=="object"&&u!==null?u:{}))}:this.materializeOneWithInclude(d,I(u)?u.include??{}: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=b(t.query),n=this.querySnapshots[o],r=this.get(t.query,void 0,true);if(Te(r,n))return;this.querySnapshots[o]=r,(s=this.onQuerySubscriptionTriggered)==null||s.call(this,t.query),t.callbacks.forEach(a=>{a(r);});}});}flattenIncludes(e,t){let i=[];return Object.entries(e).forEach(([s,o])=>{var a;let n=(a=this.schema[t])==null?void 0:a.relations[s];if(!n)return;let r=n.entity.name;if(i.push(r),typeof o=="object"&&o!==null){let c=I(o)?o.include??{}:o;i.push(...this.flattenIncludes(c,r));}}),Array.from(new Set(i))}};var re=l=>{if(l instanceof Error&&l.message.includes("Unknown procedure"))return true;if(l instanceof Error&&typeof l.cause=="object"&&l.cause!==null&&"message"in l.cause){let e=l.cause.message;return typeof e=="string"&&e.includes("Unknown procedure")}return false},ae={pending:0,local:1,remote:2},D=class{constructor(e,t){this.client=e;this.query=t;}buildQueryRequest(){return this.query}then(e,t){return this.client.genericQuery(this.query.resource,this.query.procedure,this.query.input).then(e,t)}},$=class{url;ws;store;logger;optimisticMutations;remoteSubscriptions=new Map;eventListeners=new Set;replyHandlers={};_bootstrapStatus="pending";storageLoadedCount=0;expectedStorageLoads;constructor(e){var t,i,s,o;this.url=e.url,this.logger=F({level:e.logLevel??T.INFO}),this.optimisticMutations=e.optimisticMutations,this.expectedStorageLoads=e.storage===false?0:Object.keys(e.schema).length,this.store=new P(e.schema,e.storage,this.logger,(n,r,a)=>{var p,u;let c=new Set;if(a)for(let d of Object.values(a))for(let{mutationId:y}of d)c.add(y);(u=(p=Object.values(n))==null?void 0:p.flat())==null||u.forEach(d=>{c.has(d.id)||this.sendWsMessage(d);}),this.replayCustomMutationStack();},(n,r)=>{this.emitEvent({type:"CLIENT_STORAGE_LOADED",resource:n,itemCount:r}),this.storageLoadedCount+=1,this.expectedStorageLoads>0&&this.storageLoadedCount>=this.expectedStorageLoads&&this.setBootstrapStatus("local");},n=>{this.emitEvent({type:"QUERY_SUBSCRIPTION_TRIGGERED",query:n});}),this.ws=new x({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",n=>{this.handleServerMessage(n.data);}),this.ws.addEventListener("connectionChange",n=>{if(this.emitEvent({type:"CONNECTION_STATE_CHANGE",open:n.open}),n.open){Array.from(this.remoteSubscriptions.values()).forEach(({query:a})=>{this.sendWsMessage({id:b$1(),type:"SUBSCRIBE",...a});});let r=this.store.getCustomMutationMutationIds();Object.values(this.store.optimisticMutationStack).forEach(a=>{a&&a.forEach(c=>{r.has(c.id)||(this.emitEvent({type:"MUTATION_SENT",mutationId:c.id,resource:c.resource,resourceId:c.resourceId,procedure:c.procedure??"UNKNOWN",optimistic:true}),this.sendWsMessage(c));});}),this.replayCustomMutationStack();}});}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,s,o;try{this.logger.debug("Message received from the server:",e);let n=se.parse(JSON.parse(e));if(this.logger.debug("Parsed message:",n),this.emitEvent({type:"MESSAGE_RECEIVED",message:n}),n.type==="MUTATE"){let{resource:r,id:a,resourceId:c,procedure:p}=n;this.emitEvent({type:"MUTATION_RECEIVED",mutationId:a,resource:r,resourceId:c,procedure:p??"UNKNOWN"});try{this.store.addMutation(r,n);}catch(u){this.logger.error("Error merging mutation from the server:",u);}}else if(n.type==="REJECT"){if(this.replyHandlers[n.id]){clearTimeout(this.replyHandlers[n.id].timeoutHandle),this.emitUndoEvents(this.store.undoCustomMutation(n.id));let c=n.message??"Mutation rejected";(i=(t=this.replyHandlers[n.id]).reject)==null||i.call(t,new Error(c)),delete this.replyHandlers[n.id];}let r=((s=this.store.optimisticMutationStack[n.resource])==null?void 0:s.length)??0,a=(o=this.store.optimisticMutationStack[n.resource])==null?void 0:o.find(c=>c.id===n.id);this.store.undoMutation(n.resource,n.id),this.emitEvent({type:"MUTATION_REJECTED",mutationId:n.id,resource:n.resource}),a&&this.emitEvent({type:"OPTIMISTIC_MUTATION_UNDONE",mutationId:n.id,resource:n.resource,resourceId:a.resourceId,pendingMutations:r-1});}else if(n.type==="REPLY"){let{id:r,data:a}=n;if(this.replyHandlers[r]){clearTimeout(this.replyHandlers[r].timeoutHandle),this.replyHandlers[r].handler(a);return}let c=ne.parse(a);this.emitEvent({type:"DATA_LOAD_REPLY",resource:c.resource,itemCount:c.data.length}),this.store.loadConsolidatedState(c.resource,c.data),this.emitEvent({type:"STORE_STATE_UPDATED",resource:c.resource,itemCount:c.data.length}),this.setBootstrapStatus("remote");}}catch(n){this.logger.error("Error parsing message from the server:",n);}}load(e){let t=b$1(),i=b(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:b$1(),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 r,a;let o={id:b$1(),type:"MUTATE",resource:e,payload:this.store.schema[e].encodeMutation("set",s,new Date().toISOString()),resourceId:t,procedure:i},n=(((r=this.store.optimisticMutationStack[e])==null?void 0:r.length)??0)+1;(a=this.store)==null||a.addMutation(e,o,true),this.emitEvent({type:"OPTIMISTIC_MUTATION_APPLIED",mutationId:o.id,resource:e,resourceId:t,procedure:i,pendingMutations:n}),this.emitEvent({type:"MUTATION_SENT",mutationId:o.id,resource:e,resourceId:t,procedure:i,optimistic:true}),this.sendWsMessage(o);}genericMutate(e,t,i){var c,p,u,d;let s=(c=this.ws)==null?void 0:c.connected(),o=(p=this.optimisticMutations)==null?void 0:p.getHandler(e,t),r=(t==="insert"||t==="update")&&!o&&this.store.schema[e]?(()=>{let y=i??{},{id:g,...f}=y;if(typeof g=="string")try{let M=this.store.schema[e].encodeMutation("set",f,new Date().toISOString());return {id:g,input:f,encoded:M}}catch{return}})():void 0;if(!s&&!o&&!r)throw new Error("WebSocket not connected");let a={id:b$1(),type:"MUTATE",resource:e,procedure:t,payload:i,meta:{timestamp:new Date().toISOString()}};if(r){let y={id:a.id,type:"MUTATE",resource:e,resourceId:r.id,procedure:t==="insert"?"INSERT":"UPDATE",payload:r.encoded};(u=this.store)==null||u.addMutation(e,y,true),this.emitEvent({type:"OPTIMISTIC_MUTATION_APPLIED",mutationId:a.id,resource:e,resourceId:r.id,procedure:y.procedure,pendingMutations:((d=this.store.optimisticMutationStack[e])==null?void 0:d.length)??0}),this.emitEvent({type:"MUTATION_SENT",mutationId:a.id,resource:e,resourceId:r.id,procedure:t,optimistic:true});}else if(o)try{let{proxy:y,getOperations:g}=a$1(this.store,this.store.schema);o({input:i,storage:y});let f=g(),M=this.applyOptimisticOperations(f);this.store.registerCustomMutation(a.id,M),this.emitEvent({type:"MUTATION_SENT",mutationId:a.id,resource:e,resourceId:"",procedure:t,optimistic:!0});}catch(y){throw this.logger.error("Error executing optimistic handler:",y),this.emitUndoEvents(this.store.undoCustomMutation(a.id)),y}else this.emitEvent({type:"MUTATION_SENT",mutationId:a.id,resource:e,resourceId:"",procedure:t,optimistic:false});return s?(this.sendWsMessage(a),new Promise((y,g)=>{this.replyHandlers[a.id]={timeoutHandle:setTimeout(()=>{var f;if(delete this.replyHandlers[a.id],r){let M=((f=this.store.optimisticMutationStack[e])==null?void 0:f.length)??0;this.store.undoMutation(e,a.id),this.emitEvent({type:"OPTIMISTIC_MUTATION_UNDONE",mutationId:a.id,resource:e,resourceId:r.id,pendingMutations:Math.max(M-1,0)});}else this.emitUndoEvents(this.store.undoCustomMutation(a.id));g(new Error("Reply timeout"));},5e3),handler:f=>{delete this.replyHandlers[a.id],r||this.store.confirmCustomMutation(a.id),y(f);},reject:g};})):(this.store.addCustomMutationMessage(a),Promise.resolve(void 0))}applyOptimisticOperations(e){var i;let t=[];try{for(let s of e){let o=b$1(),n=new Date().toISOString(),r={id:o,type:"MUTATE",resource:s.resource,resourceId:s.id,procedure:s.type==="insert"?"INSERT":"UPDATE",payload:this.store.schema[s.resource].encodeMutation("set",s.data,n)},a=(((i=this.store.optimisticMutationStack[s.resource])==null?void 0:i.length)??0)+1;this.store.addMutation(s.resource,r,!0),t.push({resource:s.resource,mutationId:o}),this.emitEvent({type:"OPTIMISTIC_MUTATION_APPLIED",mutationId:o,resource:s.resource,resourceId:s.id,procedure:s.type==="insert"?"INSERT":"UPDATE",pendingMutations:a});}return t}catch(s){for(let{resource:o,mutationId:n}of t)this.store.undoMutation(o,n);throw s}}emitUndoEvents(e){var t;for(let{resource:i,mutationId:s,resourceId:o}of e){let n=((t=this.store.optimisticMutationStack[i])==null?void 0:t.length)??0;this.emitEvent({type:"OPTIMISTIC_MUTATION_UNDONE",mutationId:s,resource:i,resourceId:o,pendingMutations:n});}}genericQuery(e,t,i){if(!this.ws||!this.ws.connected())throw new Error("WebSocket not connected");let s={id:b$1(),type:"CUSTOM_QUERY",resource:e,procedure:t,input:i};return this.sendWsMessage(s),new Promise((o,n)=>{this.replyHandlers[s.id]={timeoutHandle:setTimeout(()=>{delete this.replyHandlers[s.id],n(new Error("Reply timeout"));},5e3),handler:r=>{delete this.replyHandlers[s.id],o(r);},reject:n};})}get bootstrapStatus(){return this._bootstrapStatus}setBootstrapStatus(e){ae[e]<=ae[this._bootstrapStatus]||(this._bootstrapStatus=e,this.emitEvent({type:"BOOTSTRAP_STATUS_CHANGE",bootstrapStatus:e}));}addEventListener(e){return this.eventListeners.add(e),()=>{this.eventListeners.delete(e);}}replayCustomMutationStack(){var e;if((e=this.ws)!=null&&e.connected())for(let t of this.store.customMutationStack)this.sendWsMessage(t),!this.replyHandlers[t.id]&&(this.replyHandlers[t.id]={timeoutHandle:setTimeout(()=>{delete this.replyHandlers[t.id],this.emitUndoEvents(this.store.undoCustomMutation(t.id));},5e3),handler:()=>{delete this.replyHandlers[t.id],this.store.confirmCustomMutation(t.id);}});}sendWsMessage(e){var t;(t=this.ws)!=null&&t.connected()&&this.ws.send(JSON.stringify(e));}emitEvent(e){this.eventListeners.forEach(t=>{t(e);});}},at=l=>{let e=new $(l),t=(i,s)=>new Proxy(s,{get(o,n,r){if(n in o)return Reflect.get(o,n,r);if(typeof n=="string")return a=>new D(e,{resource:i,procedure:n,input:a})}});return {client:{ws:e.ws,get bootstrapStatus(){return e.bootstrapStatus},load:i=>e.load(i),addEventListener:i=>e.addEventListener(i)},store:{query:new Proxy({},{get(i,s){if(typeof s=="string")return Object.hasOwn(l.schema,s)?t(s,a._init(l.schema[s],e)):new Proxy({},{get(o,n){if(typeof n=="string")return r=>new D(e,{resource:s,procedure:n,input:r})}})},has(i,s){return typeof s=="string"}}),mutate:d(()=>{},{apply:(i,s,o)=>{if(s.length<2)return;if(s.length>2)throw new Error("Trying to access an invalid path");let[n,r]=s;if(r==="insert")return e.genericMutate(n,r,o[0]).catch(a=>{if(!re(a))throw a;let{id:c,...p}=o[0]??{};return e.mutate(n,c,"INSERT",p)});if(r==="update"){let a=o.length>1&&typeof o[0]=="string"&&typeof o[1]=="object"&&o[1]!==null?{id:o[0],...o[1]}:o[0];return e.genericMutate(n,r,a).catch(c=>{var d;if(!re(c))throw c;let[p,u]=o.length>1?o:[(d=o[0])==null?void 0:d.id,o[0]];return e.mutate(n,p,"UPDATE",u)})}return e.genericMutate(n,r,o[0])}})}}};export{at as createClient,Ae as useClientState,we as useLiveQuery,xe as useLoadData};
|
|
1
|
+
import {c,a,d,b}from'./chunk-YPTDCIAN.js';import {a as a$1}from'./chunk-RSSRYEM3.js';export{b as defineOptimisticMutations}from'./chunk-RSSRYEM3.js';import {useSyncExternalStore,useMemo,useEffect}from'react';import {xxHash32}from'js-xxhash';import {z as z$1}from'zod';import {stringify}from'qs';import Ge from'fast-deep-equal';import {openDB}from'idb';var T=o=>xxHash32(JSON.stringify(o)).toString(32);var R=(o,e,t=false)=>Object.entries(e).every(([i,n])=>{if(i==="$and")return n.every(s=>R(o,s,t));if(i==="$or")return n.some(s=>R(o,s,t));let r=(n==null?void 0:n.$eq)!==void 0?n==null?void 0:n.$eq:n;if(typeof n=="object"&&n!==null&&(n==null?void 0:n.$eq)===void 0){if(n.$in!==void 0){let a=o[i];return a===void 0?false:t?!n.$in.includes(a):n.$in.includes(a)}if(n.$not!==void 0&&!t)return R(o,{[i]:n.$not},true);if(n.$gt!==void 0){let a=o[i];return typeof a!="number"?false:t?a<=n.$gt:a>n.$gt}if(n.$gte!==void 0){let a=o[i];return typeof a!="number"?false:t?a<n.$gte:a>=n.$gte}if(n.$lt!==void 0){let a=o[i];return typeof a!="number"?false:t?a>=n.$lt:a<n.$lt}if(n.$lte!==void 0){let a=o[i];return typeof a!="number"?false:t?a>n.$lte:a<=n.$lte}let s=o[i];return !s||typeof s!="object"&&!Array.isArray(s)?false:Array.isArray(s)?t?!s.some(a=>R(a,n,false)):s.some(a=>R(a,n,false)):R(s,n,t)}return t?o[i]!==r:o[i]===r}),j=o=>{if(typeof o!="object"||o===null)return false;let e=o;return "where"in e||"limit"in e||"orderBy"in e||"include"in e},C={CRITICAL:0,ERROR:1,WARN:2,INFO:3,DEBUG:4},J=class{level;prefix;constructor(e={}){this.level=e.level??C.INFO,this.prefix=e.prefix?`[${e.prefix}] `:"";}critical(...e){this.level>=C.CRITICAL&&console.error(`${this.prefix}[CRITICAL]`,...e);}error(...e){this.level>=C.ERROR&&console.error(`${this.prefix}[ERROR]`,...e);}warn(...e){this.level>=C.WARN&&console.warn(`${this.prefix}[WARN]`,...e);}info(...e){this.level>=C.INFO&&console.log(`${this.prefix}[INFO]`,...e);}debug(...e){this.level>=C.DEBUG&&console.log(`${this.prefix}[DEBUG]`,...e);}setLevel(e){this.level=e;}getLevel(){return this.level}},de=o=>new J(o);var Y=class{subscriptions=new Map;getOrStoreSubscription(e){let t=e.buildQueryRequest(),i=T(t);if(this.subscriptions.has(i))return this.subscriptions.get(i).subscribe;let n={subscribe:r=>{let s=this.subscriptions.get(i);return s.callbacks.add(r),s.unsubscribe||(s.unsubscribe=()=>{},s.unsubscribe=e.subscribe(()=>{s.callbacks.forEach(a=>{a();});})),()=>{var a;(a=this.subscriptions.get(i))==null||a.callbacks.delete(r),setTimeout(()=>{var u;let l=this.subscriptions.get(i);l&&l.callbacks.size===0&&((u=l.unsubscribe)==null||u.call(l),this.subscriptions.delete(i));},10);}},callbacks:new Set,unsubscribe:void 0};return this.subscriptions.set(i,n),this.subscriptions.get(i).subscribe}},Ce=new Y,Xe=o=>useSyncExternalStore(Ce.getOrStoreSubscription(o),o.get),Ze=o=>{let{subscribe:e,getSnapshot:t}=useMemo(()=>{let i={bootstrapStatus:o.bootstrapStatus,connected:o.ws.connected()},n=()=>{let r={bootstrapStatus:o.bootstrapStatus,connected:o.ws.connected()};(r.bootstrapStatus!==i.bootstrapStatus||r.connected!==i.connected)&&(i=r);};return {subscribe:r=>o.addEventListener(s=>{(s.type==="BOOTSTRAP_STATUS_CHANGE"||s.type==="CONNECTION_STATE_CHANGE")&&(n(),r());}),getSnapshot:()=>i}},[o]);return useSyncExternalStore(e,t,t)},et=(o,e)=>{useEffect(()=>{let t=o.load(e.buildQueryRequest());return ()=>{t();}},[e,o.load]);};var k=class o{_collection;_client;_where;_include;_limit;_single;_sort;_shouldAwait;constructor(e,t,i,n,r,s,a,l){this._collection=e,this._client=t,this._where=i??{},this._include=n??{},this._limit=r,this._single=s,this._sort=a,this._shouldAwait=l,this.get=this.get.bind(this),this.subscribe=this.subscribe.bind(this);}where(e){return new o(this._collection,this._client,{...this._where,...e},this._include,this._limit,this._single,this._sort,this._shouldAwait)}include(e){return new o(this._collection,this._client,this._where,{...this._include,...e},this._limit,this._single,this._sort,this._shouldAwait)}limit(e){return new o(this._collection,this._client,this._where,this._include,e,this._single,this._sort,this._shouldAwait)}one(e){return this.first({id:e})}first(e){return new o(this._collection,this._client,e??this._where,this._include,1,true,this._sort,this._shouldAwait)}orderBy(e,t="asc"){let i=[...this._sort??[],{key:e,direction:t}];return new o(this._collection,this._client,this._where,this._include,this._limit,this._single,i,this._shouldAwait)}toJSON(){return {resource:this._collection.name,where:this._where,include:this._include,limit:this._limit,sort:this._sort}}buildQueryRequest(){return {resource:this._collection.name,where:this._where,include:this._include,limit:this._limit,sort:this._sort}}get(){let e=this._client.get(this.buildQueryRequest());return this._shouldAwait?Promise.resolve(e).then(t=>this._single?t[0]:t):this._single?e[0]:e}subscribe(e){return this._client.subscribe(this.buildQueryRequest(),t=>{if(this._single)return e(t[0]);e(t);})}static _init(e,t,i){return new o(e,t,void 0,void 0,void 0,void 0,void 0,i??false)}};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(),limit:z$1.coerce.number().optional(),sort:z$1.array(z$1.object({key:z$1.string(),direction:z$1.enum(["asc","desc"])})).optional()});var 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()})),xe=X.superRefine((o,e)=>{o.id&&e.addIssue({code:z$1.ZodIssueCode.custom,message:"Payload cannot have an id"});}),Le=z$1.object({id:z$1.string().optional(),type:z$1.literal("MUTATE"),resource:z$1.string(),resourceId:z$1.string().optional()}),ye=z$1.object({timestamp:z$1.string().optional(),originMutationId:z$1.string().optional()}).optional(),he=Le.extend({procedure:z$1.string(),payload:z$1.any().optional(),meta:ye}),Z=z$1.object({id:z$1.string().optional(),type:z$1.literal("SYNC"),resource:z$1.string(),resourceId:z$1.string(),op:z$1.enum(["INSERT","UPDATE","DELETE"]),payload:xe,meta:ye}),ee=(o,e)=>{o.op==="DELETE"&&Object.keys(o.payload).length>0&&e.addIssue({code:z$1.ZodIssueCode.custom,message:"DELETE delta payload must be empty"});};Z.superRefine(ee);var me=z$1.object({resource:z$1.string(),procedure:z$1.string(),input:z$1.any().optional()});var x=z$1.string(),te=me,Ee=z$1.object({id:x,type:z$1.literal("SUBSCRIBE")}).and(te),Ie=z$1.object({id:x,type:z$1.literal("UNSUBSCRIBE")}).and(te),we=z$1.object({id:x,type:z$1.literal("QUERY")}).and(te),Ae=z$1.object({id:x,type:z$1.literal("CUSTOM_QUERY"),resource:z$1.string(),procedure:z$1.string(),input:z$1.any().optional()}),Oe=he.extend({id:x}),je=Oe;z$1.union([Ee,we,Ae,je,Ie]);var _e=z$1.object({id:x,type:z$1.literal("REJECT"),resource:z$1.string(),message:z$1.string().optional()}),De=z$1.object({id:x,type:z$1.literal("REPLY"),data:z$1.any()}),Ve=Z.extend({id:x}).superRefine(ee),fe=z$1.union([_e,De,Ve]),Te=z$1.object({resource:z$1.string(),data:z$1.array(X)});var N=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(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(n=>{n(t);});}};var ie=o=>typeof o=="object"&&o!==null&&"value"in o&&!Array.isArray(o),O=o=>o?Array.isArray(o.value)?o.value.map(t=>ie(t)?O(t):t):typeof o.value!="object"||o.value===null||o.value instanceof Date?o.value:Object.fromEntries(Object.entries(o.value).map(([t,i])=>Array.isArray(i)?[t,i.map(n=>ie(n)?O(n):n)]:ie(i)?[t,O(i)]:[t,i])):void 0;var B=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 n={id:e,type:t,referencedBy:new Map(i.map(r=>[r,new Set])),references:new Map,subscriptions:new Set};return this.nodes.set(e,n),n}getNode(e){return this.nodes.get(e)}hasNode(e){return this.nodes.has(e)}createLink(e,t){let i=this.nodes.get(e),n=this.nodes.get(t);if(!i)throw new Error(`Source node with id ${e} does not exist`);if(!n)throw new Error(`Target node with id ${t} does not exist`);i.references.set(n.type,t);let r=n.referencedBy.get(i.type);r&&r instanceof Set?r.add(e):n.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 n=i.references.get(t);if(!n)return;i.references.delete(t);let r=this.nodes.get(n);if(!r)return;let s=r.referencedBy.get(i.type);s&&(s instanceof Set?s.delete(e):r.referencedBy.delete(i.type),this.notifySubscribers(n)),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,n])=>{(n instanceof Set?Array.from(n.values()):[n]).forEach(s=>{let a=this.nodes.get(s);!a||!a.references.get(i)||(a.references.delete(i),this.notifySubscribers(s));});}),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 n;try{i(e);}catch(r){(n=this.logger)==null||n.error(`Error in node subscription for node ${e}:`,r);}});}getAllNodes(){return Array.from(this.nodes.values())}};var ne="__meta",W="databases",$=class{db;async init(e,t){var u,d;if(typeof window>"u")return;let n=((u=(await window.indexedDB.databases()).find(c=>c.name===t))==null?void 0:u.version)??1,r=await T(e),s=Object.fromEntries(await Promise.all(Object.entries(e).map(async([c,p])=>[c,await T(p)]))),a=await openDB("live-state-databases",1,{upgrade(c){c.objectStoreNames.contains(W)||c.createObjectStore(W);}}),l=(d=await this.getAll(a,W))==null?void 0:d[t];(l==null?void 0:l.schemaHash)!==r&&n++,this.db=await openDB(t,n,{async upgrade(c){[...Object.keys(e),ne].forEach(p=>{(l==null?void 0:l.objectHashes[p])!==s[p]&&c.objectStoreNames.contains(p)&&c.deleteObjectStore(p),c.objectStoreNames.contains(p)||c.createObjectStore(p);}),await a.put(W,{schemaHash:r,objectHashes:s},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 n;return (n=this.db)==null?void 0:n.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(ne,e):new Promise(t=>t(void 0))}setMeta(e,t){var i;return (i=this.db)==null?void 0:i.put(ne,t,e)}async getAll(e,t){if(!e)return;if(e.getAllRecords)return e.getAllRecords(t);let[i,n]=await Promise.all([e.getAll(t),e.getAllKeys(t)]);return Object.fromEntries(i.map((r,s)=>[n[s],r]))}};var G=class{constructor(e,t,i,n,r,s){this.schema=e;this.logger=i,this.optimisticObjGraph=new B(i),this.kvStorage=new $,this.onQuerySubscriptionTriggered=s,t!==false&&this.kvStorage.init(this.schema,t.name).then(()=>{Promise.all([this.kvStorage.getMeta("mutationStack"),this.kvStorage.getMeta("customMutationStack"),this.kvStorage.getMeta("customMutationIndex")]).then(([a,l,u])=>{a&&Object.keys(a).length>0&&(this.optimisticMutationStack=a),l&&l.length>0&&(this.customMutationStack=l),u&&Object.keys(u).length>0&&(this.customMutationIndex=u),n==null||n(this.optimisticMutationStack,this.customMutationStack,this.customMutationIndex);}).then(()=>{Object.entries(this.schema).forEach(([a])=>{this.kvStorage.get(a).then(l=>{if(!l||Object.keys(l).length===0){r==null||r(a,0);return}let u=Object.entries(l).map(([d,c])=>({...c,id:{value:d}}));r==null||r(a,u.length),this.loadConsolidatedState(a,u);});});}).catch(a=>{i.debug("Storage initialization failed (may not be available in this environment):",a);});});}rawObjPool={};optimisticMutationStack={};customMutationStack=[];optimisticObjGraph;optimisticRawObjPool={};logger;onQuerySubscriptionTriggered;customMutationIndex={};collectionSubscriptions=new Map;querySnapshots={};kvStorage;get(e,t,i=false){var l;let n=t??T(e);if(this.querySnapshots[n]&&!i){let u=this.querySnapshots[n];if(u)return u}let r,s=(l=e.where)==null?void 0:l.id;s===void 0?r=Object.keys(this.optimisticRawObjPool[e.resource]??{}):typeof s=="string"?r=[s]:typeof s=="object"&&s!==null?"$in"in s&&Array.isArray(s.$in)?r=s.$in:"$eq"in s&&typeof s.$eq=="string"?r=[s.$eq]:r=Object.keys(this.optimisticRawObjPool[e.resource]??{}):r=Object.keys(this.optimisticRawObjPool[e.resource]??{});let a=r.flatMap(u=>{let d=O(this.materializeOneWithInclude(u,e.include));return d?[d]:[]});if(e.sort&&e.sort.length>0){let u=(d,c)=>{for(let p of e.sort){let m=d[p.key],f=c[p.key];if(m<f)return p.direction==="asc"?-1:1;if(m>f)return p.direction==="asc"?1:-1}return 0};a.sort(u);}if(e.where||e.limit){let u=e.where?d=>R(d,e.where):()=>true;a=d(a,u,e.limit);}return !i&&this.collectionSubscriptions.has(n)&&(this.querySnapshots[n]=a),a}subscribe(e,t){var r;let i=T(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 s,a;(s=this.collectionSubscriptions.get(i))==null||s.callbacks.delete(t),((a=this.collectionSubscriptions.get(i))==null?void 0:a.callbacks.size)===0&&(this.collectionSubscriptions.delete(i),delete this.querySnapshots[i]);}}addMutation(e,t,i=false){var l,u,d,c,p,m,f,g;let n=this.schema[e];if(this.logger.debug("Adding mutation",t),!n)throw new Error("Schema not found");if(t.op==="DELETE"){this.removeFromPool(e,t.resourceId);return}let r=(l=this.optimisticRawObjPool[e])==null?void 0:l[t.resourceId],s=false;if(i)this.optimisticMutationStack[e]??=[],this.optimisticMutationStack[e].push(t);else {this.optimisticMutationStack[e]=((d=(u=this.optimisticMutationStack)==null?void 0:u[e])==null?void 0:d.filter(re=>re.id!==t.id))??[];let E=(c=t.meta)==null?void 0:c.originMutationId;if(this.logger.debug("Broadcast mutation received",{mutationId:t.id,resource:e,resourceId:t.resourceId,op:t.op,originMutationId:E??"(none)",customMutationIndexKeys:Object.keys(this.customMutationIndex),optimisticStackSize:((p=this.optimisticMutationStack[e])==null?void 0:p.length)??0}),E&&this.customMutationIndex[E]){let oe=this.customMutationIndex[E].filter(S=>S.resource===e),H=false;for(let S of oe){let I=(m=this.optimisticMutationStack[e])==null?void 0:m.find(V=>V.id===S.mutationId);if(I&&I.resourceId===t.resourceId&&I.op===t.op){this.logger.debug("Removing optimistic mutation (resourceId match)",{optimisticMutationId:S.mutationId,resourceId:t.resourceId}),this.undoMutation(e,S.mutationId),s=true,H=true;break}}if(!H)for(let S of oe){let I=(f=this.optimisticMutationStack[e])==null?void 0:f.find(V=>V.id===S.mutationId&&V.op===t.op);if(I){this.logger.debug("Removing optimistic mutation (resource+procedure fallback)",{optimisticMutationId:S.mutationId,optimisticResourceId:I.resourceId,broadcastResourceId:t.resourceId}),this.undoMutation(e,S.mutationId),s=true,H=true;break}}}this.rawObjPool[e]??={};let _={value:{...this.schema[e].mergeMutation("set",t.payload,this.rawObjPool[e][t.resourceId])[0].value,id:{value:t.resourceId}}};this.rawObjPool[e][t.resourceId]=_;let D=_.value;delete D.id,this.kvStorage.set(e,t.resourceId,D);}this.kvStorage.setMeta("mutationStack",this.optimisticMutationStack);let a=s?(g=this.optimisticRawObjPool[e])==null?void 0:g[t.resourceId]:r;this.updateRawObjPool(e,t.resourceId,t.payload,a);}undoMutation(e,t){var s,a;if(!this.optimisticMutationStack[e])return;let i=(s=this.optimisticMutationStack[e])==null?void 0:s.findIndex(l=>l.id===t);if(i===-1)return;let n=this.optimisticMutationStack[e][i];this.logger.debug("Removing mutation",n);let r=(a=this.optimisticRawObjPool[e])==null?void 0:a[n.resourceId];this.optimisticMutationStack[e].splice(i,1),this.kvStorage.setMeta("mutationStack",this.optimisticMutationStack),this.updateRawObjPool(e,n.resourceId,Object.fromEntries(Object.entries(n.payload).map(([l])=>[l,{value:null,_meta:{}}])),r);}addCustomMutationMessage(e){this.customMutationStack.push(e),this.kvStorage.setMeta("customMutationStack",this.customMutationStack);}registerCustomMutation(e,t){this.customMutationIndex[e]=t,this.kvStorage.setMeta("customMutationIndex",this.customMutationIndex);}confirmCustomMutation(e){var i;let t=this.customMutationIndex[e];if(this.logger.debug("confirmCustomMutation called",{messageId:e,hasIndex:!!t,mutations:t??[]}),!!t){for(let{resource:n,mutationId:r}of t){let s=!!((i=this.optimisticMutationStack[n])!=null&&i.find(a=>a.id===r));this.logger.debug("confirmCustomMutation: undoing mutation",{resource:n,mutationId:r,stillInStack:s}),this.undoMutation(n,r);}delete this.customMutationIndex[e],this.kvStorage.setMeta("customMutationIndex",this.customMutationIndex),this.customMutationStack=this.customMutationStack.filter(n=>n.id!==e),this.kvStorage.setMeta("customMutationStack",this.customMutationStack);}}undoCustomMutation(e){var n;let t=this.customMutationIndex[e];if(!t)return [];let i=[];for(let{resource:r,mutationId:s}of t){let a=(n=this.optimisticMutationStack[r])==null?void 0:n.find(l=>l.id===s);this.undoMutation(r,s),a&&i.push({resource:r,mutationId:s,resourceId:a.resourceId});}return delete this.customMutationIndex[e],this.kvStorage.setMeta("customMutationIndex",this.customMutationIndex),this.customMutationStack=this.customMutationStack.filter(r=>r.id!==e),this.kvStorage.setMeta("customMutationStack",this.customMutationStack),i}getCustomMutationMutationIds(){let e=new Set;for(let t of Object.values(this.customMutationIndex))for(let{mutationId:i}of t)e.add(i);return e}loadConsolidatedState(e,t){t.forEach(i=>{var a;let n=(a=i.id)==null?void 0:a.value;if(!n)return;let{cleanedPayload:r,nestedMutations:s}=this.extractNestedRelations(e,i);s.forEach(l=>{this.addMutation(l.resource,l);}),this.addMutation(e,{id:n,type:"SYNC",resource:e,resourceId:n,op:"INSERT",payload:r});});}extractNestedRelations(e,t){let i=this.schema[e],n={...t},r=[];return i!=null&&i.relations?(Object.entries(t).forEach(([s,a])=>{var c;let l=i.relations[s];if(!l)return;let u=l.entity.name,d=a==null?void 0:a.value;if(l.type==="one"){if(d&&typeof d=="object"&&!Array.isArray(d)&&((c=d.id)!=null&&c.value)){let p=d.id.value,m={...d},{cleanedPayload:f,nestedMutations:g}=this.extractNestedRelations(u,m);r.push(...g),r.push({id:p,type:"SYNC",resource:u,resourceId:p,op:"INSERT",payload:f}),delete n[s];}}else l.type==="many"&&Array.isArray(d)&&(d.forEach(p=>{var m,f;if(p&&typeof p=="object"&&!Array.isArray(p)&&((f=(m=p.value)==null?void 0:m.id)!=null&&f.value)){let g=p.value.id.value,E={...p.value},{cleanedPayload:_,nestedMutations:D}=this.extractNestedRelations(u,E);r.push(...D),r.push({id:g,type:"SYNC",resource:u,resourceId:g,op:"INSERT",payload:_});}}),delete n[s]);}),{cleanedPayload:n,nestedMutations:r}):{cleanedPayload:n,nestedMutations:r}}removeFromPool(e,t){var i,n;this.schema[e]&&((i=this.rawObjPool[e])==null||delete i[t],(n=this.optimisticRawObjPool[e])==null||delete n[t],this.kvStorage.delete(e,t),this.optimisticObjGraph.removeNode(t),this.notifyCollectionSubscribers(e),this.optimisticObjGraph.notifySubscribers(t));}updateRawObjPool(e,t,i,n){var a;if(!this.schema[e])return;let r=(a=this.rawObjPool[e])==null?void 0:a[t],s=(this.optimisticMutationStack[e]??[]).reduce((l,u)=>u.resourceId!==t?l:this.schema[e].mergeMutation("set",u.payload,l)[0],r);if(this.optimisticRawObjPool[e]??={},s?this.optimisticRawObjPool[e][t]={value:{...s.value,id:{value:t}}}:delete this.optimisticRawObjPool[e][t],!(!this.optimisticObjGraph.hasNode(t)&&!s)){if(this.optimisticObjGraph.hasNode(t)||this.optimisticObjGraph.createNode(t,e,Object.values(this.schema[e].relations).flatMap(l=>l.type==="many"?[l.entity.name]:[])),Object.keys(this.schema[e].relations).length>0){let l=Object.fromEntries(Object.entries(this.schema[e].relations).flatMap(([u,d])=>d.type==="one"?[[d.relationalColumn,u]]:[]));Object.entries(i).forEach(([u,d])=>{let c=this.schema[e].relations[l[u]];if(!l[u])return;let p=n==null?void 0:n.value[u],[,m]=c.mergeMutation("set",d,p);if(m){if(!this.optimisticObjGraph.hasNode(m.value)){let f=c.entity.name;this.optimisticObjGraph.createNode(m.value,f,Object.values(this.schema[f].relations).flatMap(g=>g.type==="many"?[g.entity.name]:[]));}p!=null&&p.value&&this.optimisticObjGraph.removeLink(t,c.entity.name),this.optimisticObjGraph.createLink(t,m.value);}});}this.notifyCollectionSubscribers(e),this.optimisticObjGraph.notifySubscribers(t);}}materializeOneWithInclude(e,t={}){var l;if(!e)return;let i=this.optimisticObjGraph.getNode(e);if(!i)return;let n=i.type,r=(l=this.optimisticRawObjPool[n])==null?void 0:l[e];if(!r)return;let[s,a]=Object.entries(t).reduce((u,[d,c])=>{let p=this.schema[n].relations[d];return p&&(p.type==="one"?u[0].push([d,p.entity.name,c??true]):p.type==="many"&&u[1].push([d,p.entity.name,c??true])),u},[[],[]]);return {value:{...r.value,...Object.fromEntries(s.map(([u,d,c])=>[u,this.materializeOneWithInclude(i.references.get(d),j(c)?c.include??{}:typeof c=="object"&&c!==null?c:{})])),...Object.fromEntries(a.map(([u,d,c])=>{let p=i.referencedBy.get(d),m=p instanceof Set;return [u,m?{value:Array.from(p.values()).map(f=>this.materializeOneWithInclude(f,j(c)?c.include??{}:typeof c=="object"&&c!==null?c:{}))}:this.materializeOneWithInclude(p,j(c)?c.include??{}:typeof c=="object"&&c!==null?c:{})]}))}}}notifyCollectionSubscribers(e){this.collectionSubscriptions.forEach(t=>{var i,n;if(t.query.resource===e||(i=t.flatInclude)!=null&&i.includes(e)){let r=T(t.query),s=this.querySnapshots[r],a=this.get(t.query,void 0,true);if(Ge(a,s))return;this.querySnapshots[r]=a,(n=this.onQuerySubscriptionTriggered)==null||n.call(this,t.query),t.callbacks.forEach(l=>{l(a);});}});}flattenIncludes(e,t){let i=[];return Object.entries(e).forEach(([n,r])=>{var l;let s=(l=this.schema[t])==null?void 0:l.relations[n];if(!s)return;let a=s.entity.name;if(i.push(a),typeof r=="object"&&r!==null){let u=j(r)?r.include??{}:r;i.push(...this.flattenIncludes(u,a));}}),Array.from(new Set(i))}};var ve={pending:0,local:1,remote:2},z=class{constructor(e,t){this.client=e;this.query=t;}buildQueryRequest(){return this.query}then(e,t){return this.client.genericQuery(this.query.resource,this.query.procedure,this.query.input).then(e,t)}},se=class{url;ws;store;logger;optimisticMutations;remoteSubscriptions=new Map;eventListeners=new Set;replyHandlers={};_bootstrapStatus="pending";storageLoadedCount=0;expectedStorageLoads;constructor(e){var t,i,n,r;this.url=e.url,this.logger=de({level:e.logLevel??C.INFO}),this.optimisticMutations=e.optimisticMutations,this.expectedStorageLoads=e.storage===false?0:Object.keys(e.schema).length,this.store=new G(e.schema,e.storage,this.logger,()=>{this.replayCustomMutationStack();},(s,a)=>{this.emitEvent({type:"CLIENT_STORAGE_LOADED",resource:s,itemCount:a}),this.storageLoadedCount+=1,this.expectedStorageLoads>0&&this.storageLoadedCount>=this.expectedStorageLoads&&this.setBootstrapStatus("local");},s=>{this.emitEvent({type:"QUERY_SUBSCRIPTION_TRIGGERED",query:s});}),this.ws=new N({url:e.url,autoConnect:((t=e.connection)==null?void 0:t.autoConnect)??true,autoReconnect:((i=e.connection)==null?void 0:i.autoReconnect)??true,reconnectTimeout:((n=e.connection)==null?void 0:n.reconnectTimeout)??5e3,reconnectLimit:(r=e.connection)==null?void 0:r.maxReconnectAttempts,credentials:e.credentials}),this.ws.addEventListener("message",s=>{this.handleServerMessage(s.data);}),this.ws.addEventListener("connectionChange",s=>{this.emitEvent({type:"CONNECTION_STATE_CHANGE",open:s.open}),s.open&&(Array.from(this.remoteSubscriptions.values()).forEach(({query:a$1})=>{this.sendWsMessage({id:a(),type:"SUBSCRIBE",...a$1});}),this.replayCustomMutationStack());});}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,n,r;try{this.logger.debug("Message received from the server:",e);let s=fe.parse(JSON.parse(e));if(this.logger.debug("Parsed message:",s),this.emitEvent({type:"MESSAGE_RECEIVED",message:s}),s.type==="SYNC"){let{resource:a,id:l,resourceId:u,op:d}=s;this.emitEvent({type:"MUTATION_RECEIVED",mutationId:l,resource:a,resourceId:u,procedure:d??"UNKNOWN"});try{this.store.addMutation(a,s);}catch(c){this.logger.error("Error merging sync delta from the server:",c);}}else if(s.type==="REJECT"){if(this.replyHandlers[s.id]){clearTimeout(this.replyHandlers[s.id].timeoutHandle),this.emitUndoEvents(this.store.undoCustomMutation(s.id));let u=s.message??"Mutation rejected";(i=(t=this.replyHandlers[s.id]).reject)==null||i.call(t,new Error(u)),delete this.replyHandlers[s.id];}let a=((n=this.store.optimisticMutationStack[s.resource])==null?void 0:n.length)??0,l=(r=this.store.optimisticMutationStack[s.resource])==null?void 0:r.find(u=>u.id===s.id);this.store.undoMutation(s.resource,s.id),this.emitEvent({type:"MUTATION_REJECTED",mutationId:s.id,resource:s.resource}),l&&this.emitEvent({type:"OPTIMISTIC_MUTATION_UNDONE",mutationId:s.id,resource:s.resource,resourceId:l.resourceId,pendingMutations:a-1});}else if(s.type==="REPLY"){let{id:a,data:l}=s;if(this.replyHandlers[a]){clearTimeout(this.replyHandlers[a].timeoutHandle),this.replyHandlers[a].handler(l);return}let u=Te.parse(l);this.emitEvent({type:"DATA_LOAD_REPLY",resource:u.resource,itemCount:u.data.length}),this.store.loadConsolidatedState(u.resource,u.data),this.emitEvent({type:"STORE_STATE_UPDATED",resource:u.resource,itemCount:u.data.length}),this.setBootstrapStatus("remote");}}catch(s){this.logger.error("Error parsing message from the server:",s);}}load(e){let t=a(),i=T(e);this.emitEvent({type:"DATA_LOAD_REQUESTED",query:e,subscriptionId:t}),this.sendWsMessage({id:t,type:"SUBSCRIBE",...e});let n=!this.remoteSubscriptions.has(i);return this.remoteSubscriptions.has(i)?this.remoteSubscriptions.get(i).subCounter+=1:this.remoteSubscriptions.set(i,{query:e,subCounter:1}),n&&this.emitEvent({type:"SUBSCRIPTION_CREATED",query:e,subscriptionKey:i,subscriberCount:1}),()=>{if(this.remoteSubscriptions.has(i)){let r=this.remoteSubscriptions.get(i);r.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)}genericMutate(e,t,i){var a$2,l;let n=(a$2=this.ws)==null?void 0:a$2.connected(),r=(l=this.optimisticMutations)==null?void 0:l.getHandler(e,t);if(!n&&!r)throw new Error("WebSocket not connected");let s={id:a(),type:"MUTATE",resource:e,procedure:t,payload:i,meta:{timestamp:new Date().toISOString()}};if(r)try{let{proxy:u,getOperations:d}=a$1(this.store,this.store.schema);r({input:i,storage:u});let c=d(),p=this.applyOptimisticOperations(c);this.store.registerCustomMutation(s.id,p),this.emitEvent({type:"MUTATION_SENT",mutationId:s.id,resource:e,resourceId:"",procedure:t,optimistic:!0});}catch(u){throw this.logger.error("Error executing optimistic handler:",u),this.emitUndoEvents(this.store.undoCustomMutation(s.id)),u}else this.emitEvent({type:"MUTATION_SENT",mutationId:s.id,resource:e,resourceId:"",procedure:t,optimistic:false});return n?(this.sendWsMessage(s),new Promise((u,d)=>{this.replyHandlers[s.id]={timeoutHandle:setTimeout(()=>{delete this.replyHandlers[s.id],this.emitUndoEvents(this.store.undoCustomMutation(s.id)),d(new Error("Reply timeout"));},5e3),handler:c=>{delete this.replyHandlers[s.id],this.store.confirmCustomMutation(s.id),u(c);},reject:d};})):(this.store.addCustomMutationMessage(s),Promise.resolve(void 0))}applyOptimisticOperations(e){var i;let t=[];try{for(let n of e){let r=a(),s=new Date().toISOString(),a$1={id:r,type:"SYNC",resource:n.resource,resourceId:n.id,op:n.type==="insert"?"INSERT":"UPDATE",payload:this.store.schema[n.resource].encodeMutation("set",n.data,s)},l=(((i=this.store.optimisticMutationStack[n.resource])==null?void 0:i.length)??0)+1;this.store.addMutation(n.resource,a$1,!0),t.push({resource:n.resource,mutationId:r}),this.emitEvent({type:"OPTIMISTIC_MUTATION_APPLIED",mutationId:r,resource:n.resource,resourceId:n.id,procedure:n.type==="insert"?"INSERT":"UPDATE",pendingMutations:l});}return t}catch(n){for(let{resource:r,mutationId:s}of t)this.store.undoMutation(r,s);throw n}}emitUndoEvents(e){var t;for(let{resource:i,mutationId:n,resourceId:r}of e){let s=((t=this.store.optimisticMutationStack[i])==null?void 0:t.length)??0;this.emitEvent({type:"OPTIMISTIC_MUTATION_UNDONE",mutationId:n,resource:i,resourceId:r,pendingMutations:s});}}genericQuery(e,t,i){if(!this.ws||!this.ws.connected())throw new Error("WebSocket not connected");let n={id:a(),type:"CUSTOM_QUERY",resource:e,procedure:t,input:i};return this.sendWsMessage(n),new Promise((r,s)=>{this.replyHandlers[n.id]={timeoutHandle:setTimeout(()=>{delete this.replyHandlers[n.id],s(new Error("Reply timeout"));},5e3),handler:a=>{delete this.replyHandlers[n.id],r(a);},reject:s};})}get bootstrapStatus(){return this._bootstrapStatus}setBootstrapStatus(e){ve[e]<=ve[this._bootstrapStatus]||(this._bootstrapStatus=e,this.emitEvent({type:"BOOTSTRAP_STATUS_CHANGE",bootstrapStatus:e}));}addEventListener(e){return this.eventListeners.add(e),()=>{this.eventListeners.delete(e);}}replayCustomMutationStack(){var e;if((e=this.ws)!=null&&e.connected())for(let t of this.store.customMutationStack)this.sendWsMessage(t),!this.replyHandlers[t.id]&&(this.replyHandlers[t.id]={timeoutHandle:setTimeout(()=>{delete this.replyHandlers[t.id],this.emitUndoEvents(this.store.undoCustomMutation(t.id));},5e3),handler:()=>{delete this.replyHandlers[t.id],this.store.confirmCustomMutation(t.id);}});}sendWsMessage(e){var t;(t=this.ws)!=null&&t.connected()&&this.ws.send(JSON.stringify(e));}emitEvent(e){this.eventListeners.forEach(t=>{t(e);});}},ei=o=>{let e=new se(o),t=(i,n)=>new Proxy(n,{get(r,s,a){if(s in r)return Reflect.get(r,s,a);if(typeof s=="string")return l=>new z(e,{resource:i,procedure:s,input:l})}});return {client:{ws:e.ws,get bootstrapStatus(){return e.bootstrapStatus},load:i=>e.load(i),addEventListener:i=>e.addEventListener(i)},store:{query:new Proxy({},{get(i,n){if(typeof n=="string")return Object.hasOwn(o.schema,n)?t(n,k._init(o.schema[n],e)):new Proxy({},{get(r,s){if(typeof s=="string")return a=>new z(e,{resource:n,procedure:s,input:a})}})},has(i,n){return typeof n=="string"}}),mutate:c(()=>{},{apply:(i,n,r)=>{if(n.length<2)return;if(n.length>2)throw new Error("Trying to access an invalid path");let[s,a]=n;return e.genericMutate(s,a,r[0])}})}}};export{ei as createClient,Ze as useClientState,Xe as useLiveQuery,et as useLoadData};
|
package/dist/fetch-client.d.ts
CHANGED
package/dist/fetch-client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {c,b}from'./chunk-YPTDCIAN.js';var y=async(r,n,i)=>{let t=s=>{if(!s)return {};if(s instanceof Headers){let f={};return s.forEach((g,m)=>{f[m]=g;}),f}return Array.isArray(s)?Object.fromEntries(s):s},c=t(i==null?void 0:i.headers),a=t(n==null?void 0:n.headers),o={...i,...n,headers:{...c,...a}},e=await fetch(r,o),u;try{u=await e.json();}catch{u=await e.text().catch(()=>{});}if(!e.ok)throw new Error(`Failed to fetch: ${e.status} ${e.statusText}`,{cause:u});return u},w=r=>{let n=r.url.replace(/\/+$/,"");return {query:new Proxy({},{get(i,t){if(typeof t=="string")return new Proxy({},{get(c,a){if(typeof a=="string")return async o=>{let e=await b(r.credentials)??{};return await y(`${n}/${t}/query/${a}`,{method:"POST",headers:{...e,"Content-Type":"application/json"},body:JSON.stringify({input:o})},r.fetchOptions)}}})},has(i,t){return typeof t=="string"}}),mutate:c(()=>{},{apply:async(i,t,c)=>{if(t.length<2)return;if(t.length>2)throw new Error("Trying to access an invalid path");let[a,o]=t,e=await b(r.credentials)??{};return await y(`${n}/${a}/${o}`,{method:"POST",headers:{...e,"Content-Type":"application/json"},body:JSON.stringify({payload:c[0],meta:{timestamp:new Date().toISOString()}})},r.fetchOptions)}})}};export{w as createClient};
|
|
@@ -471,11 +471,17 @@ type ConditionalPromise<T, P extends boolean> = P extends true ? Promise<T> : T;
|
|
|
471
471
|
type PromiseOrSync<T> = T | Promise<T>;
|
|
472
472
|
type Generatable<T, Arg = never> = T | ((arg: Arg) => T);
|
|
473
473
|
|
|
474
|
+
/**
|
|
475
|
+
* Internal Tracked Query representation. A Custom Query handler returns an
|
|
476
|
+
* unresolved query builder; the server mints a `RawQueryRequest` from it via
|
|
477
|
+
* `buildQueryRequest()`, which the query engine subscribes and resolves against
|
|
478
|
+
* storage. This is **not** an inbound client→server message — clients can only
|
|
479
|
+
* invoke named Custom Query procedures (see ADR-0002).
|
|
480
|
+
*/
|
|
474
481
|
declare const querySchema: z.ZodObject<{
|
|
475
482
|
resource: z.ZodString;
|
|
476
483
|
where: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
477
484
|
include: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
478
|
-
lastSyncedAt: z.ZodOptional<z.ZodString>;
|
|
479
485
|
limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
480
486
|
sort: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
481
487
|
key: z.ZodString;
|
|
@@ -496,7 +502,26 @@ type CustomQueryRequest = z.infer<typeof customQuerySchema>;
|
|
|
496
502
|
/** biome-ignore-all lint/complexity/noBannedTypes: <explanation> */
|
|
497
503
|
|
|
498
504
|
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>>[];
|
|
505
|
+
/**
|
|
506
|
+
* Type-only brand recording a {@link QueryBuilder}'s inferable parameters.
|
|
507
|
+
*
|
|
508
|
+
* `CustomQueryResult` (client entry point) has to recognise a query-builder
|
|
509
|
+
* value returned from a route handler whose type flows through the *server*
|
|
510
|
+
* entry point. The two entry points are emitted as separate `.d.ts` graphs, so
|
|
511
|
+
* each gets its own `declare class QueryBuilder`; because the class has
|
|
512
|
+
* `private` members, TypeScript compares those declarations *nominally* and any
|
|
513
|
+
* `extends QueryBuilder<...>` check across the boundary fails. Narrowing on this
|
|
514
|
+
* structural brand instead makes the check independent of class identity — and
|
|
515
|
+
* therefore also of duplicate installed package versions.
|
|
516
|
+
*/
|
|
517
|
+
interface QueryBuilderBrand<TCollection extends LiveObjectAny, TInclude extends IncludeClause<TCollection>, TSingle extends boolean> {
|
|
518
|
+
collection: TCollection;
|
|
519
|
+
include: TInclude;
|
|
520
|
+
single: TSingle;
|
|
521
|
+
}
|
|
499
522
|
declare class QueryBuilder<TCollection extends LiveObjectAny, TInclude extends IncludeClause<TCollection> = {}, TSingle extends boolean = false, TShouldAwait extends boolean = false> {
|
|
523
|
+
/** Never assigned at runtime; exists only to carry {@link QueryBuilderBrand}. */
|
|
524
|
+
readonly __queryBuilderBrand: QueryBuilderBrand<TCollection, TInclude, TSingle>;
|
|
500
525
|
private _collection;
|
|
501
526
|
private _client;
|
|
502
527
|
private _where;
|
|
@@ -532,7 +557,7 @@ declare class QueryBuilder<TCollection extends LiveObjectAny, TInclude extends I
|
|
|
532
557
|
* Supports Standard Schema (via ~standard property) and Zod schemas (via _output property for backward compatibility).
|
|
533
558
|
*/
|
|
534
559
|
type InferSchema$1<T> = T extends {
|
|
535
|
-
|
|
560
|
+
'~standard': {
|
|
536
561
|
types?: {
|
|
537
562
|
output: infer U;
|
|
538
563
|
};
|
|
@@ -553,49 +578,73 @@ type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
|
|
|
553
578
|
type CustomQueryLoadable<TOutput> = PromiseLike<TOutput> & {
|
|
554
579
|
buildQueryRequest: () => CustomQueryRequest;
|
|
555
580
|
};
|
|
556
|
-
|
|
581
|
+
/**
|
|
582
|
+
* Narrow a custom-query handler return type to its loadable client shape.
|
|
583
|
+
*
|
|
584
|
+
* The match keys off {@link QueryBuilderBrand} — a structural, type-only brand —
|
|
585
|
+
* rather than `extends QueryBuilder<...>`. `QueryBuilder` carries `private`
|
|
586
|
+
* members, so its class identity is nominal and the server- and client-bundle
|
|
587
|
+
* `.d.ts` graphs emit two incompatible declarations; a class-based check fails
|
|
588
|
+
* for published consumers who import the router from `@live-state/sync/server`
|
|
589
|
+
* and the client from `@live-state/sync/client`. The brand is compared by shape,
|
|
590
|
+
* so it survives that split (and duplicate installed versions).
|
|
591
|
+
*/
|
|
592
|
+
type CustomQueryResult<TOutput, TShouldAwait extends boolean = false> = UnwrapPromise<TOutput> extends {
|
|
593
|
+
readonly __queryBuilderBrand: {
|
|
594
|
+
collection: infer TCollection extends LiveObjectAny;
|
|
595
|
+
include: infer TInclude;
|
|
596
|
+
single: infer TSingle;
|
|
597
|
+
};
|
|
598
|
+
} ? // `TInclude` is inferred unconstrained; intersecting with its declared
|
|
599
|
+
TInclude & IncludeClause<TCollection> extends infer TInc extends IncludeClause<TCollection> ? TShouldAwait extends true ? TSingle extends true ? Promise<Simplify<InferLiveObject<TCollection, TInc>> | undefined> : Promise<Simplify<InferLiveObject<TCollection, TInc>>[]> : TSingle extends true ? CustomQueryLoadable<Simplify<InferLiveObject<TCollection, TInc>> | undefined> : CustomQueryLoadable<Simplify<InferLiveObject<TCollection, TInc>>[]> : never : Promisify<UnwrapPromise<TOutput>>;
|
|
557
600
|
type CustomQueryFunction<TInput, TOutput, TShouldAwait extends boolean = false> = [TInput] extends [never] | [undefined] ? () => CustomQueryResult<TOutput, TShouldAwait> : (input: TInput) => CustomQueryResult<TOutput, TShouldAwait>;
|
|
558
601
|
/**
|
|
559
|
-
* Simplified
|
|
560
|
-
*
|
|
561
|
-
*
|
|
602
|
+
* Simplified, client-safe view of a route. Routes are now procedure-only
|
|
603
|
+
* (decoupled from the schema, see ADR-0002); a resource is queryable by virtue
|
|
604
|
+
* of being in the `schema`, not because a route is declared for it.
|
|
562
605
|
*/
|
|
563
|
-
type
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
inputValidator: StandardSchemaV1<any, any>;
|
|
574
|
-
handler: (...args: any[]) => any;
|
|
575
|
-
}>;
|
|
606
|
+
type ClientRouteConstraint = {
|
|
607
|
+
customMutations: Record<string, {
|
|
608
|
+
_type: 'mutation';
|
|
609
|
+
inputValidator: StandardSchemaV1<any, any>;
|
|
610
|
+
handler: (...args: any[]) => any;
|
|
611
|
+
}>;
|
|
612
|
+
customQueries: Record<string, {
|
|
613
|
+
_type: 'query';
|
|
614
|
+
inputValidator: StandardSchemaV1<any, any>;
|
|
615
|
+
handler: (...args: any[]) => any;
|
|
576
616
|
}>;
|
|
577
617
|
};
|
|
578
|
-
type
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
[K2 in keyof TRoute["customQueries"]]: CustomQueryFunction<InferSchema$1<TRoute["customQueries"][K2]["inputValidator"]>, ReturnType<TRoute["customQueries"][K2]["handler"]>, TShouldAwait>;
|
|
618
|
+
type ClientRouterConstraint = {
|
|
619
|
+
schema: Record<string, LiveObjectAny>;
|
|
620
|
+
routes: Record<string, ClientRouteConstraint>;
|
|
582
621
|
};
|
|
583
|
-
type
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
622
|
+
type CustomQueryMethods<TRoute extends ClientRouteConstraint, TShouldAwait extends boolean> = {
|
|
623
|
+
[K2 in keyof TRoute['customQueries']]: CustomQueryFunction<InferSchema$1<TRoute['customQueries'][K2]['inputValidator']>, ReturnType<TRoute['customQueries'][K2]['handler']>, TShouldAwait>;
|
|
624
|
+
};
|
|
625
|
+
/**
|
|
626
|
+
* The client `store.query.<resource>` surface, asymmetric by client (ADR-0002):
|
|
627
|
+
*
|
|
628
|
+
* - **Websocket** (`TShouldAwait = false`): every resource in the `schema`
|
|
629
|
+
* exposes a `QueryBuilder` **Local Query** — `.where()/.get()/.subscribe()`
|
|
630
|
+
* read the optimistic store with no server round-trip (consumed by
|
|
631
|
+
* `useLiveQuery`) — merged with the declared **Custom Query** procedures of a
|
|
632
|
+
* route of the same name (if any).
|
|
633
|
+
* - **Fetch** (`TShouldAwait = true`): no optimistic store to back a Local
|
|
634
|
+
* Query, so only the declared Custom Query procedures are exposed.
|
|
635
|
+
*/
|
|
636
|
+
type WsQueryType<TRouter extends ClientRouterConstraint, K> = (K extends keyof TRouter['schema'] ? TRouter['schema'][K] extends LiveObjectAny ? QueryBuilder<TRouter['schema'][K], {}, false, false> : unknown : unknown) & (K extends keyof TRouter['routes'] ? CustomQueryMethods<TRouter['routes'][K], false> : unknown);
|
|
637
|
+
type CollectionMutateType<TRoute extends ClientRouteConstraint> = {
|
|
638
|
+
[K2 in keyof TRoute['customMutations']]: CustomMutationFunction<InferSchema$1<TRoute['customMutations'][K2]['inputValidator']>, ReturnType<TRoute['customMutations'][K2]['handler']>>;
|
|
592
639
|
};
|
|
593
640
|
type Client$1<TRouter extends ClientRouterConstraint, TShouldAwait extends boolean = false> = {
|
|
594
|
-
query: {
|
|
595
|
-
[K in keyof TRouter[
|
|
641
|
+
query: TShouldAwait extends true ? {
|
|
642
|
+
[K in keyof TRouter['routes']]: CustomQueryMethods<TRouter['routes'][K], true>;
|
|
643
|
+
} : {
|
|
644
|
+
[K in keyof TRouter['schema'] | keyof TRouter['routes']]: WsQueryType<TRouter, K>;
|
|
596
645
|
};
|
|
597
646
|
mutate: {
|
|
598
|
-
[K in keyof TRouter[
|
|
647
|
+
[K in keyof TRouter['routes']]: CollectionMutateType<TRouter['routes'][K]>;
|
|
599
648
|
};
|
|
600
649
|
};
|
|
601
650
|
|
|
@@ -691,30 +740,7 @@ type OptimisticMutationsRegistry<TSchema extends Schema<any>> = {
|
|
|
691
740
|
getHandler: (route: string, procedure: string) => OptimisticMutationHandler<TSchema, any> | undefined;
|
|
692
741
|
};
|
|
693
742
|
|
|
694
|
-
declare const
|
|
695
|
-
type: z.ZodLiteral<"MUTATE">;
|
|
696
|
-
resource: z.ZodString;
|
|
697
|
-
resourceId: z.ZodOptional<z.ZodString>;
|
|
698
|
-
procedure: z.ZodEnum<{
|
|
699
|
-
INSERT: "INSERT";
|
|
700
|
-
UPDATE: "UPDATE";
|
|
701
|
-
}>;
|
|
702
|
-
payload: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
703
|
-
value: z.ZodNullable<z.ZodAny>;
|
|
704
|
-
_meta: z.ZodOptional<z.ZodObject<{
|
|
705
|
-
timestamp: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
706
|
-
}, z.core.$strip>>;
|
|
707
|
-
}, z.core.$strip>>;
|
|
708
|
-
meta: z.ZodOptional<z.ZodObject<{
|
|
709
|
-
timestamp: z.ZodOptional<z.ZodString>;
|
|
710
|
-
originMutationId: z.ZodOptional<z.ZodString>;
|
|
711
|
-
}, z.core.$strip>>;
|
|
712
|
-
id: z.ZodString;
|
|
713
|
-
}, z.core.$strip>;
|
|
714
|
-
type DefaultMutationMessage = Omit<z.infer<typeof defaultMutationMsgSchema>, 'resourceId'> & {
|
|
715
|
-
resourceId: string;
|
|
716
|
-
};
|
|
717
|
-
declare const mutationMsgSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
743
|
+
declare const mutationMsgSchema: z.ZodObject<{
|
|
718
744
|
type: z.ZodLiteral<"MUTATE">;
|
|
719
745
|
resource: z.ZodString;
|
|
720
746
|
resourceId: z.ZodOptional<z.ZodString>;
|
|
@@ -725,13 +751,16 @@ declare const mutationMsgSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
725
751
|
originMutationId: z.ZodOptional<z.ZodString>;
|
|
726
752
|
}, z.core.$strip>>;
|
|
727
753
|
id: z.ZodString;
|
|
728
|
-
}, z.core.$strip
|
|
729
|
-
|
|
754
|
+
}, z.core.$strip>;
|
|
755
|
+
type MutationMessage = z.infer<typeof mutationMsgSchema>;
|
|
756
|
+
declare const syncDeltaMsgSchema: z.ZodObject<{
|
|
757
|
+
type: z.ZodLiteral<"SYNC">;
|
|
730
758
|
resource: z.ZodString;
|
|
731
|
-
resourceId: z.
|
|
732
|
-
|
|
759
|
+
resourceId: z.ZodString;
|
|
760
|
+
op: z.ZodEnum<{
|
|
733
761
|
INSERT: "INSERT";
|
|
734
762
|
UPDATE: "UPDATE";
|
|
763
|
+
DELETE: "DELETE";
|
|
735
764
|
}>;
|
|
736
765
|
payload: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
737
766
|
value: z.ZodNullable<z.ZodAny>;
|
|
@@ -744,8 +773,8 @@ declare const mutationMsgSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
744
773
|
originMutationId: z.ZodOptional<z.ZodString>;
|
|
745
774
|
}, z.core.$strip>>;
|
|
746
775
|
id: z.ZodString;
|
|
747
|
-
}, z.core.$strip
|
|
748
|
-
type
|
|
776
|
+
}, z.core.$strip>;
|
|
777
|
+
type SyncDeltaMessage = z.infer<typeof syncDeltaMsgSchema>;
|
|
749
778
|
declare const serverMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
750
779
|
id: z.ZodString;
|
|
751
780
|
type: z.ZodLiteral<"REJECT">;
|
|
@@ -756,12 +785,13 @@ declare const serverMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
756
785
|
type: z.ZodLiteral<"REPLY">;
|
|
757
786
|
data: z.ZodAny;
|
|
758
787
|
}, z.core.$strip>, z.ZodObject<{
|
|
759
|
-
type: z.ZodLiteral<"
|
|
788
|
+
type: z.ZodLiteral<"SYNC">;
|
|
760
789
|
resource: z.ZodString;
|
|
761
|
-
resourceId: z.
|
|
762
|
-
|
|
790
|
+
resourceId: z.ZodString;
|
|
791
|
+
op: z.ZodEnum<{
|
|
763
792
|
INSERT: "INSERT";
|
|
764
793
|
UPDATE: "UPDATE";
|
|
794
|
+
DELETE: "DELETE";
|
|
765
795
|
}>;
|
|
766
796
|
payload: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
767
797
|
value: z.ZodNullable<z.ZodAny>;
|
|
@@ -780,7 +810,7 @@ type ServerMessage = z.infer<typeof serverMessageSchema>;
|
|
|
780
810
|
declare class OptimisticStore {
|
|
781
811
|
readonly schema: Schema<any>;
|
|
782
812
|
private rawObjPool;
|
|
783
|
-
optimisticMutationStack: Record<string,
|
|
813
|
+
optimisticMutationStack: Record<string, SyncDeltaMessage[]>;
|
|
784
814
|
customMutationStack: MutationMessage[];
|
|
785
815
|
private optimisticObjGraph;
|
|
786
816
|
private optimisticRawObjPool;
|
|
@@ -796,7 +826,7 @@ declare class OptimisticStore {
|
|
|
796
826
|
constructor(schema: Schema<any>, storage: ClientOptions["storage"], logger: Logger, afterLoadMutations?: (stack: typeof this.optimisticMutationStack, customStack: MutationMessage[], customIndex: typeof this.customMutationIndex) => void, onStorageLoaded?: (resource: string, itemCount: number) => void, onQuerySubscriptionTriggered?: (query: RawQueryRequest) => void);
|
|
797
827
|
get(query: RawQueryRequest, _queryKey?: string, force?: boolean): any;
|
|
798
828
|
subscribe(query: RawQueryRequest, listener: (v: any[]) => void): () => void;
|
|
799
|
-
addMutation(routeName: string, mutation:
|
|
829
|
+
addMutation(routeName: string, mutation: SyncDeltaMessage, optimistic?: boolean): void;
|
|
800
830
|
undoMutation(routeName: string, mutationId: string): void;
|
|
801
831
|
addCustomMutationMessage(message: MutationMessage): void;
|
|
802
832
|
registerCustomMutation(messageId: string, mutations: Array<{
|
|
@@ -810,8 +840,15 @@ declare class OptimisticStore {
|
|
|
810
840
|
resourceId: string;
|
|
811
841
|
}>;
|
|
812
842
|
getCustomMutationMutationIds(): Set<string>;
|
|
813
|
-
loadConsolidatedState(resourceType: string, data:
|
|
843
|
+
loadConsolidatedState(resourceType: string, data: SyncDeltaMessage["payload"][]): void;
|
|
814
844
|
private extractNestedRelations;
|
|
845
|
+
/**
|
|
846
|
+
* Drop a row from every local store surface in response to a scope-out
|
|
847
|
+
* (`DELETE`) delta, then notify subscribers so windowed queries re-derive.
|
|
848
|
+
* Any pending optimistic mutation for the row is left untouched — it is
|
|
849
|
+
* reconciled through its own reply/reject path.
|
|
850
|
+
*/
|
|
851
|
+
private removeFromPool;
|
|
815
852
|
private updateRawObjPool;
|
|
816
853
|
private materializeOneWithInclude;
|
|
817
854
|
private notifyCollectionSubscribers;
|
|
@@ -920,7 +957,7 @@ type ClientStorageLoadedEvent = {
|
|
|
920
957
|
};
|
|
921
958
|
type DataLoadRequestedEvent = {
|
|
922
959
|
type: "DATA_LOAD_REQUESTED";
|
|
923
|
-
query:
|
|
960
|
+
query: CustomQueryRequest;
|
|
924
961
|
subscriptionId: string;
|
|
925
962
|
};
|
|
926
963
|
type DataLoadReplyEvent = {
|
|
@@ -951,13 +988,13 @@ type MutationRejectedEvent = {
|
|
|
951
988
|
};
|
|
952
989
|
type SubscriptionCreatedEvent = {
|
|
953
990
|
type: "SUBSCRIPTION_CREATED";
|
|
954
|
-
query:
|
|
991
|
+
query: CustomQueryRequest;
|
|
955
992
|
subscriptionKey: string;
|
|
956
993
|
subscriberCount: number;
|
|
957
994
|
};
|
|
958
995
|
type SubscriptionRemovedEvent = {
|
|
959
996
|
type: "SUBSCRIPTION_REMOVED";
|
|
960
|
-
query:
|
|
997
|
+
query: CustomQueryRequest;
|
|
961
998
|
subscriptionKey: string;
|
|
962
999
|
};
|
|
963
1000
|
type QueryExecutedEvent = {
|
|
@@ -1000,7 +1037,7 @@ type Client<TRouter extends ClientRouterConstraint> = {
|
|
|
1000
1037
|
ws: WebSocketClient;
|
|
1001
1038
|
readonly bootstrapStatus: ClientBootstrapStatus;
|
|
1002
1039
|
addEventListener: (listener: (event: ClientEvents) => void) => () => void;
|
|
1003
|
-
load: (query:
|
|
1040
|
+
load: (query: CustomQueryRequest) => () => void;
|
|
1004
1041
|
};
|
|
1005
1042
|
store: Client$1<TRouter>;
|
|
1006
1043
|
};
|
|
@@ -1016,7 +1053,7 @@ type ClientState = {
|
|
|
1016
1053
|
};
|
|
1017
1054
|
declare const useClientState: (client: Client<ClientRouterConstraint>["client"]) => ClientState;
|
|
1018
1055
|
declare const useLoadData: (client: Client<ClientRouterConstraint>["client"], query: {
|
|
1019
|
-
buildQueryRequest: () =>
|
|
1056
|
+
buildQueryRequest: () => CustomQueryRequest;
|
|
1020
1057
|
}) => void;
|
|
1021
1058
|
|
|
1022
1059
|
type ClientOptions<TSchema extends Schema<any> = Schema<any>> = {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { e as OptimisticHandlerContext, h as OptimisticInsertOperation, j as OptimisticMutationHandler, O as OptimisticMutationsConfig, c as OptimisticMutationsRegistry, g as OptimisticOperation, f as OptimisticStorageProxy, i as OptimisticUpdateOperation, k as createOptimisticStorageProxy, d as defineOptimisticMutations } from './index-
|
|
1
|
+
export { e as OptimisticHandlerContext, h as OptimisticInsertOperation, j as OptimisticMutationHandler, O as OptimisticMutationsConfig, c as OptimisticMutationsRegistry, g as OptimisticOperation, f as OptimisticStorageProxy, i as OptimisticUpdateOperation, k as createOptimisticStorageProxy, d as defineOptimisticMutations } from './index-DOU7wys1.js';
|
|
2
2
|
import '@standard-schema/spec';
|
|
3
3
|
import 'zod';
|