@live-state/sync 0.0.6-canary-12 → 0.0.6-canary-13

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 CHANGED
@@ -1,4 +1,4 @@
1
- export { e as Client, d as ClientEvents, C as ClientOptions, c as ConnectionStateChangeEvent, M as MessageReceivedEvent, f as createClient, u as useLiveQuery, b as useLoadData } from './index-B8lFpK0h.js';
1
+ export { e as Client, d as ClientEvents, C as ClientOptions, c as ConnectionStateChangeEvent, M as MessageReceivedEvent, f as createClient, u as useLiveQuery, b as useLoadData } from './index-BiZR-P7f.js';
2
2
  import 'zod';
3
3
  import 'zod/v3';
4
4
  import 'zod/v4/core';
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 ue from'fast-deep-equal';import {openDB}from'idb';var g=l=>xxHash32(JSON.stringify(l)).toString(32);var b=(l,e,t=false)=>Object.entries(e).every(([i,s])=>{if(i==="$and")return s.every(o=>b(l,o,t));if(i==="$or")return s.some(o=>b(l,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=l[i];return n===void 0?false:t?!s.$in.includes(n):s.$in.includes(n)}if(s.$not!==void 0&&!t)return b(l,{[i]:s.$not},true);if(s.$gt!==void 0){let n=l[i];return typeof n!="number"?false:t?n<=s.$gt:n>s.$gt}if(s.$gte!==void 0){let n=l[i];return typeof n!="number"?false:t?n<s.$gte:n>=s.$gte}if(s.$lt!==void 0){let n=l[i];return typeof n!="number"?false:t?n>=s.$lt:n<s.$lt}if(s.$lte!==void 0){let n=l[i];return typeof n!="number"?false:t?n>s.$lte:n<=s.$lte}let o=l[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?l[i]!==r:l[i]===r}),v={CRITICAL:0,ERROR:1,WARN:2,INFO:3,DEBUG:4},x=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}},U=l=>new x(l);var A=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)}},ee=new A,fe=l=>useSyncExternalStore(ee.getOrStoreSubscription(l),l.get),ge=(l,e)=>{useEffect(()=>{let t=l.load(e.buildQueryRequest());return ()=>{t();}},[e,l.load]);};var O=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()}),k=z.record(z.string(),z.object({value:z.any().nullable(),_meta:z.object({timestamp:z.string().optional().nullable()}).optional()})),te=k.superRefine((l,e)=>{l.id&&e.addIssue({code:z.ZodIssueCode.custom,message:"Payload cannot have an id"});}),Q=z.object({id:z.string().optional(),type:z.literal("MUTATE"),resource:z.string(),resourceId:z.string().optional()}),P=Q.extend({procedure:z.string(),payload:z.any().optional()}),W=Q.extend({procedure:z.enum(["INSERT","UPDATE"]),payload:te});z.union([W,P]);var M=z.string(),ie=O.extend({id:M,type:z.literal("SUBSCRIBE")}),se=O.extend({id:M,type:z.literal("UNSUBSCRIBE")}),ne=O.extend({id:M,type:z.literal("QUERY")}),H=W.extend({id:M}),re=P.extend({id:M}),oe=z.union([re,H]);z.union([ie,ne,oe,se]);var ae=z.object({id:M,type:z.literal("REJECT"),resource:z.string(),message:z.string().optional()}),ce=z.object({id:M,type:z.literal("REPLY"),data:z.any()}),q=z.union([ae,ce,H]),K=z.object({resource:z.string(),data:z.array(k)});var R=class{ws=null;url;autoConnect;autoReconnect;reconnectTimeout;reconnectLimit;reconnectAttempts=0;eventListeners=new Map;reconnectTimer=null;intentionallyDisconnected=false;credentials;constructor(e){this.url=e.url,this.autoConnect=e.autoConnect??false,this.autoReconnect=e.autoReconnect??false,this.reconnectTimeout=e.reconnectTimeout??5e3,this.reconnectLimit=e.reconnectLimit,this.credentials=e.credentials,this.autoConnect&&this.connect();}connected(){var e;return ((e=this.ws)==null?void 0:e.readyState)===WebSocket.OPEN}async connect(){if(this.ws&&(this.ws.readyState===WebSocket.OPEN||this.ws.readyState===WebSocket.CONNECTING))return;this.intentionallyDisconnected=false;let e=await b$1(this.credentials);this.ws=new WebSocket(this.url+(e?`?${stringify(e)}`:"")),this.ws.addEventListener("open",this.handleOpen.bind(this)),this.ws.addEventListener("close",this.handleClose.bind(this)),this.ws.addEventListener("error",this.handleError.bind(this)),this.ws.addEventListener("message",this.handleMessage.bind(this));}disconnect(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.intentionallyDisconnected=true,this.ws&&(this.ws.close(),this.ws=null);}addEventListener(e,t){var 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 L=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 D="__meta",C="databases",T=class{db;async init(e,t){var u,p;if(typeof window>"u")return;let s=((u=(await window.indexedDB.databases()).find(c=>c.name===t))==null?void 0:u.version)??1,r=await g(e),o=Object.fromEntries(await Promise.all(Object.entries(e).map(async([c,h])=>[c,await g(h)]))),n=await openDB("live-state-databases",1,{upgrade(c){c.objectStoreNames.contains(C)||c.createObjectStore(C);}}),a=(p=await this.getAll(n,C))==null?void 0:p[t];(a==null?void 0:a.schemaHash)!==r&&s++,this.db=await openDB(t,s,{async upgrade(c){[...Object.keys(e),D].forEach(h=>{(a==null?void 0:a.objectHashes[h])!==o[h]&&c.objectStoreNames.contains(h)&&c.deleteObjectStore(h),c.objectStoreNames.contains(h)||c.createObjectStore(h);}),await n.put(C,{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(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((r,o)=>[s[o],r]))}};var j=class{constructor(e,t,i,s){this.schema=e;this.logger=i,this.optimisticObjGraph=new L(i),this.kvStorage=new T,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,u)=>{for(let p of e$1.sort){let c=a[p.key],h=u[p.key];if(c<h)return p.direction==="asc"?-1:1;if(c>h)return p.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 u={value:{...this.schema[e].mergeMutation("set",t.payload,this.rawObjPool[e][t.resourceId])[0].value,id:{value:t.resourceId}}};this.rawObjPool[e][t.resourceId]=u;let p=u.value;delete p.id,this.kvStorage.set(e,t.resourceId,p);}this.kvStorage.setMeta("mutationStack",this.optimisticMutationStack),this.updateRawObjPool(e,t.resourceId,t.payload,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,h;let a=i.relations[o];if(!a)return;let u=a.entity.name,p=n==null?void 0:n.value;if(a.type==="one"){if(p&&typeof p=="object"&&!Array.isArray(p)&&((h=(c=p.value)==null?void 0:c.id)!=null&&h.value)){let f=p.value.id.value,m={...p.value},{cleanedPayload:S,nestedMutations:w}=this.extractNestedRelations(u,m);r.push(...w),r.push({id:f,type:"MUTATE",resource:u,resourceId:f,procedure:"INSERT",payload:S}),delete s[o];}}else a.type==="many"&&Array.isArray(p)&&(p.forEach(f=>{var m,S;if(f&&typeof f=="object"&&!Array.isArray(f)&&((S=(m=f.value)==null?void 0:m.id)!=null&&S.value)){let w=f.value.id.value,F={...f.value},{cleanedPayload:V,nestedMutations:J}=this.extractNestedRelations(u,F);r.push(...J),r.push({id:w,type:"MUTATE",resource:u,resourceId:w,procedure:"INSERT",payload:V});}}),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,u)=>u.resourceId!==t?a:this.schema[e].mergeMutation("set",u.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(([u,p])=>p.type==="one"?[[p.relationalColumn,u]]:[]));Object.entries(i).forEach(([u,p])=>{let c=this.schema[e].relations[a[u]];if(!a[u])return;let h=s==null?void 0:s.value[u],[,f]=c.mergeMutation("set",p,h);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]:[]));}h!=null&&h.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((u,[p,c])=>{let h=this.schema[s].relations[p];return h&&(h.type==="one"?u[0].push([p,h.entity.name,c??true]):h.type==="many"&&u[1].push([p,h.entity.name,c??true])),u},[[],[]]);return {value:{...r.value,...Object.fromEntries(o.map(([u,p,c])=>[u,this.materializeOneWithInclude(i.references.get(p),typeof c=="object"&&c!==null?c:{})])),...Object.fromEntries(n.map(([u,p,c])=>{let h=i.referencedBy.get(p),f=h instanceof Set;return [u,f?{value:Array.from(h.values()).map(m=>this.materializeOneWithInclude(m,typeof c=="object"&&c!==null?c:{}))}:this.materializeOneWithInclude(h,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(ue(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 I=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=U({level:e.logLevel??v.INFO}),this.store=new j(e.schema,e.storage,this.logger,o=>{var n,a;(a=(n=Object.values(o))==null?void 0:n.flat())==null||a.forEach(u=>{this.sendWsMessage(u);});}),this.ws=new R({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=q.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=K.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);});}},Ke=l=>{let e=new I(l);return {client:{ws:e.ws,load:t=>e.load(t),addEventListener:t=>e.addEventListener(t)},store:{query:Object.entries(l.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{Ke as createClient,fe as useLiveQuery,ge 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}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,4 +1,4 @@
1
- import { C as ClientOptions, A as AnyRouter, a as Client } from './index-B8lFpK0h.js';
1
+ import { C as ClientOptions, A as AnyRouter, a as Client } from './index-BiZR-P7f.js';
2
2
  import 'zod';
3
3
  import 'zod/v3';
4
4
  import 'zod/v4/core';
@@ -259,10 +259,12 @@ type RawQueryRequest = z.infer<typeof querySchema>;
259
259
  type RouteRecord = Record<string, AnyRoute>;
260
260
  declare class Router<TRoutes extends RouteRecord> {
261
261
  readonly routes: TRoutes;
262
+ private readonly hooksRegistry;
262
263
  private constructor();
263
264
  static create<TRoutes extends RouteRecord>(opts: {
264
265
  routes: TRoutes;
265
266
  }): Router<TRoutes>;
267
+ getHooks(resourceName: string): Hooks<any> | undefined;
266
268
  }
267
269
  type AnyRouter = Router<any>;
268
270
  type Mutation<TInputValidator extends z3.ZodTypeAny | z4.$ZodType, // TODO use StandardSchema instead
@@ -291,16 +293,46 @@ type Authorization<TShape extends LiveObjectAny> = {
291
293
  postMutation?: MutationAuthorizationHandler<TShape>;
292
294
  };
293
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
+ };
294
324
  declare class Route<TResourceSchema extends LiveObjectAny, TMiddleware extends Middleware<any>, TCustomMutations extends Record<string, Mutation<any, any>>> {
295
325
  readonly resourceSchema: TResourceSchema;
296
326
  readonly middlewares: Set<TMiddleware>;
297
327
  readonly customMutations: TCustomMutations;
298
328
  readonly authorization?: Authorization<TResourceSchema>;
299
- constructor(resourceSchema: TResourceSchema, customMutations?: TCustomMutations, authorization?: Authorization<TResourceSchema>);
329
+ readonly hooks?: Hooks<TResourceSchema>;
330
+ constructor(resourceSchema: TResourceSchema, customMutations?: TCustomMutations, authorization?: Authorization<TResourceSchema>, hooks?: Hooks<TResourceSchema>);
300
331
  use(...middlewares: TMiddleware[]): this;
301
332
  withMutations<T extends Record<string, Mutation<any, any>>>(mutationFactory: (opts: {
302
333
  mutation: typeof mutationCreator;
303
334
  }) => T): Route<TResourceSchema, TMiddleware, T>;
335
+ withHooks(hooks: Hooks<TResourceSchema>): Route<TResourceSchema, TMiddleware, TCustomMutations>;
304
336
  getAuthorizationClause(req: QueryRequest): WhereClause<TResourceSchema> | undefined | boolean;
305
337
  private handleSet;
306
338
  private wrapInMiddlewares;
@@ -353,7 +385,7 @@ declare abstract class Storage implements DataSource {
353
385
  }[];
354
386
  }): Promise<InferLiveObject<T>[]>;
355
387
  insert<T extends LiveObjectAny>(resource: T, value: Simplify<InferInsert<T>>): Promise<InferLiveObject<T>>;
356
- update<T extends LiveObjectAny>(resource: T, resourceId: string, value: InferUpdate<T>): Promise<InferLiveObject<T>>;
388
+ update<T extends LiveObjectAny>(resource: T, resourceId: string, value: InferUpdate<T>): Promise<Partial<InferLiveObject<T>>>;
357
389
  abstract transaction<T>(fn: (opts: {
358
390
  trx: Storage;
359
391
  commit: () => Promise<void>;
@@ -413,6 +445,7 @@ declare class QueryBuilder<TCollection extends LiveObjectAny, TInclude extends I
413
445
  direction: "asc" | "desc";
414
446
  }[] | undefined;
415
447
  };
448
+ buildQueryRequest(): RawQueryRequest;
416
449
  get(): ConditionalPromise<InferQueryResult<TCollection, TInclude, TSingle>, TShouldAwait>;
417
450
  subscribe(callback: (value: InferQueryResult<TCollection, TInclude, TSingle>) => void): () => void;
418
451
  }
package/dist/server.cjs CHANGED
@@ -1,2 +1,6 @@
1
- 'use strict';var V=require('crypto'),jsXxhash=require('js-xxhash'),dt=require('qs'),zod=require('zod'),kysely=require('kysely'),postgres=require('kysely/helpers/postgres');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var V__default=/*#__PURE__*/_interopDefault(V);var dt__default=/*#__PURE__*/_interopDefault(dt);var ke=Object.create;var me=Object.defineProperty;var ze=Object.getOwnPropertyDescriptor;var De=Object.getOwnPropertyNames;var _e=Object.getPrototypeOf,Ve=Object.prototype.hasOwnProperty;var Fe=(i,e)=>()=>(e||i((e={exports:{}}).exports,e),e.exports);var Ke=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of De(e))!Ve.call(i,r)&&r!==t&&me(i,r,{get:()=>e[r],enumerable:!(n=ze(e,r))||n.enumerable});return i};var ge=(i,e,t)=>(t=i!=null?ke(_e(i)):{},Ke(me(t,"default",{value:i,enumerable:true}),i));var se=Fe(U=>{Object.defineProperty(U,"__esModule",{value:true});U.parse=st;U.serialize=at;var Xe=/^[\u0021-\u003A\u003C\u003E-\u007E]+$/,et=/^[\u0021-\u003A\u003C-\u007E]*$/,tt=/^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i,rt=/^[\u0020-\u003A\u003D-\u007E]*$/,nt=Object.prototype.toString,it=(()=>{let i=function(){};return i.prototype=Object.create(null),i})();function st(i,e){let t=new it,n=i.length;if(n<2)return t;let r=(e==null?void 0:e.decode)||ot,s=0;do{let o=i.indexOf("=",s);if(o===-1)break;let a=i.indexOf(";",s),u=a===-1?n:a;if(o>u){s=i.lastIndexOf(";",o-1)+1;continue}let l=Se(i,s,o),p=we(i,o,l),c=i.slice(l,p);if(t[c]===void 0){let y=Se(i,o+1,u),d=we(i,u,y),f=r(i.slice(y,d));t[c]=f;}s=u+1;}while(s<n);return t}function Se(i,e,t){do{let n=i.charCodeAt(e);if(n!==32&&n!==9)return e}while(++e<t);return t}function we(i,e,t){for(;e>t;){let n=i.charCodeAt(--e);if(n!==32&&n!==9)return e+1}return t}function at(i,e,t){let n=(t==null?void 0:t.encode)||encodeURIComponent;if(!Xe.test(i))throw new TypeError(`argument name is invalid: ${i}`);let r=n(e);if(!et.test(r))throw new TypeError(`argument val is invalid: ${e}`);let s=i+"="+r;if(!t)return s;if(t.maxAge!==void 0){if(!Number.isInteger(t.maxAge))throw new TypeError(`option maxAge is invalid: ${t.maxAge}`);s+="; Max-Age="+t.maxAge;}if(t.domain){if(!tt.test(t.domain))throw new TypeError(`option domain is invalid: ${t.domain}`);s+="; Domain="+t.domain;}if(t.path){if(!rt.test(t.path))throw new TypeError(`option path is invalid: ${t.path}`);s+="; Path="+t.path;}if(t.expires){if(!ut(t.expires)||!Number.isFinite(t.expires.valueOf()))throw new TypeError(`option expires is invalid: ${t.expires}`);s+="; Expires="+t.expires.toUTCString();}if(t.httpOnly&&(s+="; HttpOnly"),t.secure&&(s+="; Secure"),t.partitioned&&(s+="; Partitioned"),t.priority)switch(typeof t.priority=="string"?t.priority.toLowerCase():void 0){case "low":s+="; Priority=Low";break;case "medium":s+="; Priority=Medium";break;case "high":s+="; Priority=High";break;default:throw new TypeError(`option priority is invalid: ${t.priority}`)}if(t.sameSite)switch(typeof t.sameSite=="string"?t.sameSite.toLowerCase():t.sameSite){case true:case "strict":s+="; SameSite=Strict";break;case "lax":s+="; SameSite=Lax";break;case "none":s+="; SameSite=None";break;default:throw new TypeError(`option sameSite is invalid: ${t.sameSite}`)}return s}function ot(i){if(i.indexOf("%")===-1)return i;try{return decodeURIComponent(i)}catch{return i}}function ut(i){return nt.call(i)==="[object Date]"}});var S=i=>i?Array.isArray(i.value)?i.value.map(t=>S(t)):typeof i.value!="object"||i.value===null||i.value instanceof Date?i.value:Object.fromEntries(Object.entries(i.value).map(([t,n])=>Array.isArray(n)?[t,n.map(r=>S(r))]:[t,S(n)])):void 0;var be="0123456789ABCDEFGHJKMNPQRSTVWXYZ",k=32;var We=16,Re=10,Te=0xffffffffffff;var A;(function(i){i.Base32IncorrectEncoding="B32_ENC_INVALID",i.DecodeTimeInvalidCharacter="DEC_TIME_CHAR",i.DecodeTimeValueMalformed="DEC_TIME_MALFORMED",i.EncodeTimeNegative="ENC_TIME_NEG",i.EncodeTimeSizeExceeded="ENC_TIME_SIZE_EXCEED",i.EncodeTimeValueMalformed="ENC_TIME_MALFORMED",i.PRNGDetectFailure="PRNG_DETECT",i.ULIDInvalid="ULID_INVALID",i.Unexpected="UNEXPECTED",i.UUIDInvalid="UUID_INVALID";})(A||(A={}));var E=class extends Error{constructor(e,t){super(`${t} (${e})`),this.name="ULIDError",this.code=e;}};function Be(i){let e=Math.floor(i()*k);return e===k&&(e=k-1),be.charAt(e)}function Ue(i){var n;let e=He(),t=e&&(e.crypto||e.msCrypto)||(typeof V__default.default<"u"?V__default.default:null);if(typeof(t==null?void 0:t.getRandomValues)=="function")return ()=>{let r=new Uint8Array(1);return t.getRandomValues(r),r[0]/255};if(typeof(t==null?void 0:t.randomBytes)=="function")return ()=>t.randomBytes(1).readUInt8()/255;if((n=V__default.default)!=null&&n.randomBytes)return ()=>V__default.default.randomBytes(1).readUInt8()/255;throw new E(A.PRNGDetectFailure,"Failed to find a reliable PRNG")}function He(){return Je()?self:typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:null}function Ge(i,e){let t="";for(;i>0;i--)t=Be(e)+t;return t}function Ze(i,e=Re){if(isNaN(i))throw new E(A.EncodeTimeValueMalformed,`Time must be a number: ${i}`);if(i>Te)throw new E(A.EncodeTimeSizeExceeded,`Cannot encode a time larger than ${Te}: ${i}`);if(i<0)throw new E(A.EncodeTimeNegative,`Time must be positive: ${i}`);if(Number.isInteger(i)===false)throw new E(A.EncodeTimeValueMalformed,`Time must be an integer: ${i}`);let t,n="";for(let r=e;r>0;r--)t=i%k,n=be.charAt(t)+n,i=(i-t)/k;return n}function Je(){return typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope}function ve(i,e){let t=Ue(),n=Date.now();return Ze(n,Re)+Ge(We,t)}var K=()=>ve().toLowerCase(),F=i=>({then(e,t){try{if(e){let n=e(i);return n instanceof Promise?n:F(n)}return F(i)}catch(n){if(t){let r=t(n);return r instanceof Promise?r:F(r)}throw n}}}),re=i=>i instanceof Promise?i:F(i);var P=(...i)=>{let e=i.filter(t=>!!t);return e.length===0?{}:e.length===1?e[0]:{$and:e}};var W=class{storage;queue=new Map;scheduled=false;constructor(e){this.storage=e;}async rawFind({resource:e,commonWhere:t,uniqueWhere:n,...r}){return new Promise((s,o)=>{let a=this.getBatchKey({resource:e,commonWhere:t,...r}),u={resource:e,commonWhere:t,uniqueWhere:n,...r,resolve:s,reject:o};this.queue.has(a)||this.queue.set(a,[]);let l=this.queue.get(a);l&&l.push(u),this.scheduled||(this.scheduled=true,setImmediate(()=>{this.processBatch();}));})}getBatchKey(e){let{resource:t,commonWhere:n,...r}=e;return `${t}:${JSON.stringify(n??{})}:${JSON.stringify(r??{})}`}async processBatch(){this.scheduled=false;let e=Array.from(this.queue.entries());this.queue.clear();for(let[,t]of e)try{await this.executeBatchedRequests(t);}catch(n){t.forEach(r=>{r.reject(n);});}}async executeBatchedRequests(e){var y;if(e.length===0)return;let t=e[0],{resource:n,commonWhere:r,include:s,sort:o}=t,a=e.length===1?t.limit:void 0,u=e.map(d=>d.uniqueWhere).filter(d=>d!==void 0),l=r,p=(y=Object.entries(u[0]??{})[0])==null?void 0:y[0];if(u.length>0){let d=u.map(f=>f[p]).filter(f=>f!=null);d.length>0&&(l=P(r,{[p]:{$in:d}}));}let c=await this.storage.get({resource:n,where:l,include:s,sort:o,limit:a});for(let d of e){let f=c;if(d.uniqueWhere){let[m,g]=Object.entries(d.uniqueWhere)[0];f=c.filter(h=>{var T;return ((T=h.value[m])==null?void 0:T.value)===g});}d.resolve(f);}}};var j=i=>jsXxhash.xxHash32(JSON.stringify(i)).toString(32),N=(i,e,t)=>{let n={},r=t[e];if(!r)return n;let s=o=>{o.$and?o.$and.forEach(s):o.$or?o.$or.forEach(s):Object.entries(o).forEach(([a,u])=>{var l;if((l=r.relations)!=null&&l[a]&&(n[a]=true,typeof u=="object"&&u!==null&&!Array.isArray(u))){let p=N(u,r.relations[a].entity.name,t);Object.keys(p).length>0&&(n[a]=p);}});};return s(i),n},I=(i,e,t=false)=>Object.entries(e).every(([n,r])=>{if(n==="$and")return r.every(o=>I(i,o,t));if(n==="$or")return r.some(o=>I(i,o,t));let s=(r==null?void 0:r.$eq)!==void 0?r==null?void 0:r.$eq:r;if(typeof r=="object"&&r!==null&&(r==null?void 0:r.$eq)===void 0){if(r.$in!==void 0){let a=i[n];return a===void 0?false:t?!r.$in.includes(a):r.$in.includes(a)}if(r.$not!==void 0&&!t)return I(i,{[n]:r.$not},true);if(r.$gt!==void 0){let a=i[n];return typeof a!="number"?false:t?a<=r.$gt:a>r.$gt}if(r.$gte!==void 0){let a=i[n];return typeof a!="number"?false:t?a<r.$gte:a>=r.$gte}if(r.$lt!==void 0){let a=i[n];return typeof a!="number"?false:t?a>=r.$lt:a<r.$lt}if(r.$lte!==void 0){let a=i[n];return typeof a!="number"?false:t?a>r.$lte:a<=r.$lte}let o=i[n];return !o||typeof o!="object"&&!Array.isArray(o)?false:Array.isArray(o)?t?!o.some(a=>I(a,r,false)):o.some(a=>I(a,r,false)):I(o,r,t)}return t?i[n]!==s:i[n]===s}),L={CRITICAL:0,ERROR:1,WARN:2,INFO:3,DEBUG:4},ne=class{level;prefix;constructor(e={}){this.level=e.level??L.INFO,this.prefix=e.prefix?`[${e.prefix}] `:"";}critical(...e){this.level>=L.CRITICAL&&console.error(`${this.prefix}[CRITICAL]`,...e);}error(...e){this.level>=L.ERROR&&console.error(`${this.prefix}[ERROR]`,...e);}warn(...e){this.level>=L.WARN&&console.warn(`${this.prefix}[WARN]`,...e);}info(...e){this.level>=L.INFO&&console.log(`${this.prefix}[INFO]`,...e);}debug(...e){this.level>=L.DEBUG&&console.log(`${this.prefix}[DEBUG]`,...e);}setLevel(e){this.level=e;}getLevel(){return this.level}},xe=i=>new ne(i);function ie(i){return j({resource:i.query.resource,where:i.query.where,include:i.query.include,stepPath:i.stepPath,isMany:i.isMany,relationName:i.relationName})}var B=class{router;storage;schema;logger;queryNodes=new Map;objectNodes=new Map;constructor(e){this.router=e.router,this.storage=e.storage,this.schema=e.schema,this.logger=e.logger;}getRelationalColumns(e){let t=new Map,n=this.schema[e];if(!(n!=null&&n.relations))return t;for(let[r,s]of Object.entries(n.relations))s.type==="one"&&s.relationalColumn&&t.set(String(s.relationalColumn),{relationName:r,targetResource:s.entity.name});return t}ensureObjectNode(e,t,n){let r=this.objectNodes.get(e);return r?n&&r.matchedQueries.add(n):(r={id:e,type:t,matchedQueries:new Set(n?[n]:[]),referencesObjects:new Map,referencedByObjects:new Map},this.objectNodes.set(e,r)),r}storeRelation(e,t,n,r){let s=this.objectNodes.get(e),o=this.objectNodes.get(t);if(s&&s.referencesObjects.set(n,t),o&&r){let a=o.referencedByObjects.get(r);a||(a=new Set,o.referencedByObjects.set(r,a)),a.add(e);}}removeRelation(e,t,n,r){let s=this.objectNodes.get(e),o=this.objectNodes.get(t);if(s&&s.referencesObjects.delete(n),o&&r){let a=o.referencedByObjects.get(r);a&&(a.delete(e),a.size===0&&o.referencedByObjects.delete(r));}}getInverseRelationName(e,t,n){let r=this.schema[e];if(!(r!=null&&r.relations))return;let s=r.relations[n];if(!s)return;let o=this.schema[t];if(o!=null&&o.relations){if(s.type==="many"&&s.foreignColumn){for(let[a,u]of Object.entries(o.relations))if(u.entity.name===e&&u.type==="one"&&u.relationalColumn===s.foreignColumn)return a}if(s.type==="one"&&s.relationalColumn){for(let[a,u]of Object.entries(o.relations))if(u.entity.name===e&&u.type==="many"&&u.foreignColumn===s.relationalColumn)return a}}}updateRelationsFromMutation(e,t,n,r){let s=this.getRelationalColumns(e),o=this.objectNodes.get(t);if(o)for(let[a,{relationName:u,targetResource:l}]of Array.from(s)){if(!(r&&a in r))continue;let c=this.getInverseRelationName(e,l,u),y=o.referencesObjects.get(u),d=n[a];y!==d&&(y&&this.removeRelation(t,y,u,c),d&&(this.ensureObjectNode(d,l),this.storeRelation(t,d,u,c)));}}get(e,t){let n=this.breakdownQuery({query:e,context:(t==null?void 0:t.context)??{}});return this.resolveQuery(n,{context:(t==null?void 0:t.context)??{},batcher:(t==null?void 0:t.batcher)??new W(this.storage)})}subscribe(e,t,n={}){let r=this.breakdownQuery({query:e,context:n}),s={},o=[];for(let a of r){this.logger.debug("[QueryEngine] Subscribing to step",a.stepPath.join("."));let u=ie(a),l=s[a.stepPath.at(-2)??""],p=a.stepPath.at(-1)??"",c=this.queryNodes.get(u);if(c)c.subscriptions.add(t);else if(c={hash:u,queryStep:a,relationName:p,trackedObjects:new Set,subscriptions:new Set([t]),parentQuery:l,childQueries:new Set},this.queryNodes.set(c.hash,c),l){let y=this.queryNodes.get(l);y&&y.childQueries.add(c.hash);}s[p]=u,o.push(()=>{let y=this.queryNodes.get(u);y&&(y.subscriptions.delete(t),y.subscriptions.size===0&&this.queryNodes.delete(u));});}return ()=>{for(let a of o)a();}}breakdownQuery(e){var g;let{query:t,stepPath:n=[],context:r={},parentResource:s}=e,{include:o}=t,a=n.length===0,u=n.at(-1),l,p,c;if(!a&&s&&u){let h=this.schema[s],T=(g=h==null?void 0:h.relations)==null?void 0:g[u];T&&(c=T.type==="many",T.type==="one"?(l=b=>({id:b}),p=b=>b.map(v=>{var x,M;return (M=(x=v.value)==null?void 0:x[T.relationalColumn])==null?void 0:M.value}).filter(v=>v!==void 0)):(l=b=>({[T.foreignColumn]:b}),p=b=>b.map(v=>{var x,M;return (M=(x=v.value)==null?void 0:x.id)==null?void 0:M.value}).filter(v=>v!==void 0)));}let{include:y,...d}=t,m=[this.router.incrementQueryStep({query:d,stepPath:[...n],getWhere:l,referenceGetter:p,isMany:c,relationName:u},r)];if(o&&typeof o=="object"&&Object.keys(o).length>0){let h=this.schema[t.resource];if(!h)throw new Error(`Resource ${t.resource} not found`);m.push(...Object.entries(o).flatMap(([T,b])=>{let v=h.relations[T];if(!v)throw new Error(`Relation ${T} not found for resource ${t.resource}`);let x=v.entity.name;return this.breakdownQuery({query:{resource:x,include:typeof b=="object"?b:void 0},stepPath:[...n,T],context:r,parentResource:t.resource})}));}return m}resolveQuery(e,t){this.logger.debug("[QueryEngine] Resolving query",e.map(s=>s.stepPath.join(".")).join(" -> "));let n={},r=this.resolveStep(e[0],t).then(s=>{this.logger.debug("[QueryEngine] Resolved step",e[0].stepPath.join("."),"with results count:",s.length),n[e[0].stepPath.join(".")]=[{data:s}];});for(let s=1;s<e.length;s++){let o=e[s],a=o.stepPath.slice(0,-1).join(".");r=r.then(async()=>{var l,p;let u=n[a];if(!u){n[o.stepPath.join(".")]=[];return}if(o.referenceGetter&&o.getWhere){let c=new Map;for(let f of u)for(let m of f.data){let g=(p=(l=m==null?void 0:m.value)==null?void 0:l.id)==null?void 0:p.value;if(!g)continue;let T=o.referenceGetter([m])[0];if(T){c.has(T)||c.set(T,new Set);let b=c.get(T);b&&b.add(g);}}let y=Array.from(c.keys());if(y.length===0){n[o.stepPath.join(".")]=[];return}let d=[];for(let f of y){let m=o.getWhere(f),g={...o,relationalWhere:m},h=await this.resolveStep(g,t),T=c.get(f);if(T)for(let b of Array.from(T))d.push({includedBy:b,data:h});}this.logger.debug("[QueryEngine] Resolved step",o.stepPath.join("."),"with results count:",d.reduce((f,m)=>f+m.data.length,0)),n[o.stepPath.join(".")]=d;}else {let c=await this.resolveStep(o,t);n[o.stepPath.join(".")]=[{data:c}];}});}return r=r.then((()=>(this.logger.debug("[QueryEngine] Assembling results"),this.assembleResults(e,n)))),r}assembleResults(e,t){var o,a,u,l,p;this.logger.debug("[QueryEngine] assembleResults: Starting assembly"),this.logger.debug("[QueryEngine] assembleResults: Plan steps:",e.length),this.logger.debug("[QueryEngine] assembleResults: Step results keys:",Object.keys(t));let n=new Map;for(let c of e){let y=c.stepPath.join("."),d=t[y]??[],f=Object.keys(c.query.include??{});this.logger.debug(`[QueryEngine] assembleResults: Processing step "${y}"`,{resource:c.query.resource,includedRelations:f,resultGroups:d.length,isMany:c.isMany,relationName:c.relationName});for(let m of d){this.logger.debug(`[QueryEngine] assembleResults: Processing result group for "${y}"`,{dataCount:m.data.length,includedBy:m.includedBy});for(let g of m.data){let h=(a=(o=g==null?void 0:g.value)==null?void 0:o.id)==null?void 0:a.value;if(!h){this.logger.debug(`[QueryEngine] assembleResults: Skipping data without id in step "${y}"`);continue}let T=y?`${y}.${h}`:h,b=[];if(c.stepPath.length>0&&m.includedBy){let x=c.stepPath.slice(0,-1).join(".");b=[x?`${x}.${m.includedBy}`:m.includedBy],this.logger.debug(`[QueryEngine] assembleResults: Child entity "${T}" has parent keys:`,b,{stepPath:y,parentStepPath:x,includedBy:m.includedBy});}else this.logger.debug(`[QueryEngine] assembleResults: Root entity "${T}" (no parent)`);let v=n.get(T);if(v){this.logger.debug(`[QueryEngine] assembleResults: Entity "${T}" already exists, adding parent keys:`,b);for(let x of b)v.includedBy.add(x);}else this.logger.debug(`[QueryEngine] assembleResults: Adding new entity "${T}"`,{resource:c.query.resource,path:c.stepPath.at(-1)??"",isMany:c.isMany??false,relationName:c.relationName,includedRelations:f,parentKeys:b}),n.set(T,{data:g,includedBy:new Set(b),path:c.stepPath.at(-1)??"",isMany:c.isMany??false,relationName:c.relationName,resourceName:c.query.resource,includedRelations:f});}}}this.logger.debug(`[QueryEngine] assembleResults: Built entriesMap with ${n.size} entries`),this.logger.debug("[QueryEngine] assembleResults: EntriesMap keys:",Array.from(n.keys()));let r=Array.from(n.entries()),s=[];this.logger.debug(`[QueryEngine] assembleResults: Starting assembly phase with ${r.length} entries`);for(let c=r.length-1;c>=0;c--){let[y,d]=r[c],f=this.schema[d.resourceName];this.logger.debug(`[QueryEngine] assembleResults: Processing entry "${y}"`,{resource:d.resourceName,path:d.path,isMany:d.isMany,relationName:d.relationName,includedRelations:d.includedRelations,parentKeys:Array.from(d.includedBy)});for(let m of d.includedRelations){let g=(l=(u=f==null?void 0:f.relations)==null?void 0:u[m])==null?void 0:l.type,h=!!d.data.value[m];if(this.logger.debug(`[QueryEngine] assembleResults: Checking included relation "${m}" for "${y}"`,{relationType:g,hasRelation:h,resourceHasRelation:!!((p=f==null?void 0:f.relations)!=null&&p[m])}),d.data.value[m])this.logger.debug(`[QueryEngine] assembleResults: Relation "${m}" already exists for "${y}"`,d.data.value[m]);else {let T=g==="many"?{value:[]}:{value:null};d.data.value[m]=T,this.logger.debug(`[QueryEngine] assembleResults: Initialized relation "${m}" for "${y}" with`,T);}}if(d.path===""){this.logger.debug(`[QueryEngine] assembleResults: Adding root entity "${y}" to resultData`),s.push(d.data);continue}this.logger.debug(`[QueryEngine] assembleResults: Attaching "${y}" to ${d.includedBy.size} parent(s)`);for(let m of Array.from(d.includedBy)){let g=n.get(m);if(!g){this.logger.warn(`[QueryEngine] assembleResults: WARNING - Parent "${m}" not found in entriesMap for child "${y}"`);continue}let h=d.relationName??d.path;this.logger.debug(`[QueryEngine] assembleResults: Attaching "${y}" to parent "${m}" via relation "${h}"`,{isMany:d.isMany,parentHasRelation:!!g.data.value[h]}),d.isMany?(g.data.value[h]??={value:[]},g.data.value[h].value.push(d.data),this.logger.debug(`[QueryEngine] assembleResults: Added "${y}" to many relation "${h}" on parent "${m}"`,{arrayLength:g.data.value[h].value.length})):(g.data.value[h]=d.data,this.logger.debug(`[QueryEngine] assembleResults: Set one relation "${h}" on parent "${m}" to "${y}"`));}}return this.logger.debug(`[QueryEngine] assembleResults: Assembly complete. Returning ${s.length} root items`),s}resolveStep(e,t){this.logger.debug("[QueryEngine] Resolving step",e.stepPath.join("."),"with query",JSON.stringify(e.query,null,2),"relationalWhere",JSON.stringify(e.relationalWhere,null,2));let{query:n,relationalWhere:r}=e,s=n.where&&r?P(n.where,r):r??n.where,o=s?{...n,where:s}:n;return re(this.router.get(o,t)).then(a=>(this.loadStepResults(e,a),a))}loadStepResults(e,t){this.logger.debug("[QueryEngine] Loading step results",e.stepPath.join("."),"with results",JSON.stringify(t,null,2));let n=ie(e),r=this.queryNodes.get(n),s=e.query.resource;if(!r)return;let o=this.getRelationalColumns(s);for(let a of t){let u=S(a),l=u.id;this.ensureObjectNode(l,s,n),r.trackedObjects.add(l);for(let[p,{relationName:c,targetResource:y}]of Array.from(o)){let d=u[p];if(d){this.ensureObjectNode(d,y);let f=this.getInverseRelationName(s,y,c);this.storeRelation(l,d,c,f);}}this.loadNestedRelations(s,l,u),this.logger.debug("[QueryEngine] Loaded nested relations for",l);}}loadNestedRelations(e,t,n){let r=this.schema[e];if(r!=null&&r.relations)for(let[s,o]of Object.entries(r.relations)){let a=n[s];if(!a)continue;let u=o.entity.name,l=this.getInverseRelationName(e,u,s);if(o.type==="one")a&&typeof a=="object"&&a.id&&(this.ensureObjectNode(a.id,u),this.storeRelation(t,a.id,s,l),this.loadNestedRelations(u,a.id,a));else if(o.type==="many"&&Array.isArray(a)){for(let p of a)if(p&&typeof p=="object"&&p.id){this.ensureObjectNode(p.id,u);let c=this.getInverseRelationName(u,e,s);c&&this.storeRelation(p.id,t,c,s),this.loadNestedRelations(u,p.id,p);}}}}buildIncludeFromChildQueries(e){let t=this.queryNodes.get(e);if(!t||t.childQueries.size===0)return {};let n={};for(let r of Array.from(t.childQueries)){let s=this.queryNodes.get(r);if(!s||!s.relationName)continue;let o=this.buildIncludeFromChildQueries(r);n[s.relationName]=Object.keys(o).length>0?o:true;}return n}sendInsertsForTree(e,t,n){var a,u;let r=(u=(a=t==null?void 0:t.value)==null?void 0:a.id)==null?void 0:u.value;if(!r)return;let s={procedure:"INSERT",resource:n,resourceId:r,type:"MUTATE",payload:t.value};for(let l of Array.from(e.subscriptions))try{l(s);}catch(p){this.logger.error("[QueryEngine] Error in subscription callback during sendInsertsForTree",{error:p,queryHash:e.hash,resource:n,resourceId:r,stepPath:e.queryStep.stepPath.join(".")});}e.trackedObjects.add(r),this.ensureObjectNode(r,n,e.hash).matchedQueries.add(e.hash);for(let l of Array.from(e.childQueries)){let p=this.queryNodes.get(l);if(!p||!p.relationName)continue;let c=p.relationName,y=p.queryStep.query.resource,d=t.value[c];if(!d)continue;let f=d.value;if(Array.isArray(f))for(let m of f)this.sendInsertsForTree(p,m,y);else f&&typeof f=="object"&&this.sendInsertsForTree(p,f,y);}}handleMutation(e,t){if(e.procedure==="INSERT"){if(this.objectNodes.has(e.resourceId))return;let n=S(t);if(!n)return;let r={id:e.resourceId,type:e.resource,matchedQueries:new Set,referencesObjects:new Map,referencedByObjects:new Map};this.objectNodes.set(e.resourceId,r);let s=this.getRelationalColumns(e.resource);for(let[a,{relationName:u,targetResource:l}]of Array.from(s)){let p=n[a];if(p){this.ensureObjectNode(p,l);let c=this.getInverseRelationName(e.resource,l,u);this.storeRelation(e.resourceId,p,u,c);}}let o=this.objectNodes.get(e.resourceId);this.getMatchingQueries(e,n).then(a=>{for(let u of a){let l=this.queryNodes.get(u);if(l){l.trackedObjects.add(e.resourceId),o&&o.matchedQueries.add(u);for(let p of Array.from(l.subscriptions))try{p(e);}catch(c){this.logger.error("[QueryEngine] Error in subscription callback during INSERT mutation",{error:c,queryHash:l.hash,resource:e.resource,resourceId:e.resourceId,stepPath:l.queryStep.stepPath.join(".")});}}}});return}if(e.procedure==="UPDATE"){let n=S(t);if(!n)return;let r=this.objectNodes.get(e.resourceId),s=new Set((r==null?void 0:r.matchedQueries)??[]);r||(r={id:e.resourceId,type:e.resource,matchedQueries:new Set,referencesObjects:new Map,referencedByObjects:new Map},this.objectNodes.set(e.resourceId,r)),this.updateRelationsFromMutation(e.resource,e.resourceId,n,e.payload),this.getMatchingQueries(e,n).then(o=>{let a=new Set(o),u=[],l=[],p=[];for(let y of o)s.has(y)?p.push(y):u.push(y);for(let y of Array.from(s))a.has(y)||l.push(y);for(let y of u){let d=this.queryNodes.get(y);d&&d.trackedObjects.add(e.resourceId);}for(let y of l){let d=this.queryNodes.get(y);d&&d.trackedObjects.delete(e.resourceId);}let c=this.objectNodes.get(e.resourceId);if(c){for(let y of u)c.matchedQueries.add(y);for(let y of l)c.matchedQueries.delete(y);}for(let y of [...l,...p]){let d=this.queryNodes.get(y);if(d)for(let f of Array.from(d.subscriptions))try{f(e);}catch(m){this.logger.error("[QueryEngine] Error in subscription callback during UPDATE mutation",{error:m,queryHash:d.hash,resource:e.resource,resourceId:e.resourceId,stepPath:d.queryStep.stepPath.join(".")});}}if(u.length>0)for(let y of u){let d=this.queryNodes.get(y);if(!d)continue;let f=this.buildIncludeFromChildQueries(y);this.get({resource:e.resource,where:{id:e.resourceId},include:Object.keys(f).length>0?f:void 0}).then(m=>{!m||m.length===0||this.sendInsertsForTree(d,m[0],e.resource);});}});return}}getMatchingQueries(e,t){let n=[];for(let r of Array.from(this.queryNodes.values()))r.queryStep.query.resource===e.resource&&n.push(r);return n.length===0?re([]):Promise.all(n.map(async r=>{let s=r.queryStep.query.where,o=r.queryStep.query.resource,a=e.resourceId,u=this.objectNodes.get(a);if(!u)return {hash:r.hash,matches:false};if(r.relationName){let d=r.parentQuery?this.queryNodes.get(r.parentQuery):void 0,f=d==null?void 0:d.queryStep.query.resource,m=f?this.getInverseRelationName(f,o,r.relationName):void 0,g=m?u.referencesObjects.get(m):void 0;if(!g)return {hash:r.hash,matches:false};let h=this.objectNodes.get(g);return !h||!d||!h.matchedQueries.has(d.hash)?{hash:r.hash,matches:false}:{hash:r.hash,matches:true}}if(!s)return {hash:r.hash,matches:true};let l=N(s,o,this.schema),p=Object.keys(l).length>0;if(!p&&t!==void 0)return {hash:r.hash,matches:I(t,s)};let c=await this.storage.get({resource:o,where:{id:a},include:p?l:void 0});if(!c||c.length===0)return {hash:r.hash,matches:false};let y=S(c[0]);return y?{hash:r.hash,matches:I(y,s)}:{hash:r.hash,matches:false}})).then(r=>r.filter(s=>s.matches).map(s=>s.hash))}};var Le=ge(se());var q=zod.z.object({resource:zod.z.string(),where:zod.z.record(zod.z.string(),zod.z.any()).optional(),include:zod.z.record(zod.z.string(),zod.z.any()).optional(),lastSyncedAt:zod.z.string().optional(),limit:zod.z.coerce.number().optional(),sort:zod.z.array(zod.z.object({key:zod.z.string(),direction:zod.z.enum(["asc","desc"])})).optional()}),ae=zod.z.record(zod.z.string(),zod.z.object({value:zod.z.any().nullable(),_meta:zod.z.object({timestamp:zod.z.string().optional().nullable()}).optional()})),ct=ae.superRefine((i,e)=>{i.id&&e.addIssue({code:zod.z.ZodIssueCode.custom,message:"Payload cannot have an id"});}),Ie=zod.z.object({id:zod.z.string().optional(),type:zod.z.literal("MUTATE"),resource:zod.z.string(),resourceId:zod.z.string().optional()}),z=Ie.extend({procedure:zod.z.string(),payload:zod.z.any().optional()}),D=Ie.extend({procedure:zod.z.enum(["INSERT","UPDATE"]),payload:ct});zod.z.union([D,z]);var Me=q.omit({resource:true}),oe=z.omit({id:true,type:true,resource:true,procedure:true}),ue=D.omit({id:true,type:true,resource:true,procedure:true});zod.z.union([ue,oe]);var ce=i=>{if(i==null)return i;if(i==="null")return null;if(Array.isArray(i))return i.map(ce);if(typeof i=="object"&&i.constructor===Object){let e={};for(let[t,n]of Object.entries(i))e[t]=ce(n);return e}return i},je=i=>{let e=i.logger;return async t=>{var n;try{let r=typeof t.headers.getSetCookie=="function"?Object.fromEntries(t.headers):t.headers,s={headers:r,cookies:r.cookie?Le.default.parse(r.cookie):{}},o=new URL(t.url),a=o.pathname.split("/"),u=o.searchParams,l=ce(dt__default.default.parse(u.toString())),p=await((n=i.contextProvider)==null?void 0:n.call(i,{transport:"HTTP",headers:s.headers,cookies:s.cookies,queryParams:l}))??{};if(t.method==="GET"){let c=a[a.length-1],{success:y,data:d,error:f}=Me.safeParse(l);if(!y)return Response.json({message:"Invalid query",code:"INVALID_QUERY",details:f},{status:400});let m=await i.handleQuery({req:{...s,...d,type:"QUERY",resource:c,context:p,queryParams:l}});return !m||!m.data?Response.json({message:"Invalid resource",code:"INVALID_RESOURCE"},{status:400}):Response.json(m.data)}if(t.method==="POST")try{let c=a[a.length-1],y=a[a.length-2],d=t.body?await t.json():{},f;if(c==="insert"||c==="update"){let{success:g,data:h,error:T}=ue.safeParse(d);if(!g)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:T},{status:400});f=h;}else {let{success:g,data:h,error:T}=oe.safeParse(d);if(!g)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:T},{status:400});f=h;}let m=await i.handleMutation({req:{...s,type:"MUTATE",resource:y,input:f.payload,context:p,resourceId:f.resourceId,procedure:c==="insert"||c==="update"?c.toUpperCase():c,queryParams:{}}});return Response.json(m)}catch(c){return e.error("Error parsing mutation from the client:",c),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}return Response.json({message:"Not found",code:"NOT_FOUND"},{status:404})}catch(r){return e.error("Unexpected error:",r),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}}};var Ee=ge(se());var $=zod.z.string(),yt=q.extend({id:$,type:zod.z.literal("SUBSCRIBE")}),pt=q.extend({id:$,type:zod.z.literal("UNSUBSCRIBE")}),ft=q.extend({id:$,type:zod.z.literal("QUERY")}),Oe=D.extend({id:$}),ht=z.extend({id:$}),mt=zod.z.union([ht,Oe]),Ae=zod.z.union([yt,ft,mt,pt]),gt=zod.z.object({id:$,type:zod.z.literal("REJECT"),resource:zod.z.string(),message:zod.z.string().optional()}),Tt=zod.z.object({id:$,type:zod.z.literal("REPLY"),data:zod.z.any()});zod.z.union([gt,Tt,Oe]);zod.z.object({resource:zod.z.string(),data:zod.z.array(ae)});var Ne=i=>{let e={},t=i.logger;return (n,r)=>{var c;let s=y=>{n.send(JSON.stringify(y));},o=K(),a=new Map,u={headers:r.headers,cookies:typeof r.headers.cookie=="string"?Ee.default.parse(r.headers.cookie):{}},l=dt.parse(r.url.split("?")[1]),p=(c=i.contextProvider)==null?void 0:c.call(i,{transport:"WEBSOCKET",headers:u.headers,cookies:u.cookies,queryParams:l});e[o]=n,t.info("Client connected:",o),n.on("message",async y=>{try{t.debug("Message received from the client:",y);let d=Ae.parse(JSON.parse(y.toString()));if(d.type==="SUBSCRIBE"||d.type==="QUERY"){let{type:f,id:m,...g}=d,h=f==="SUBSCRIBE",T=await i.handleQuery({req:{...u,...g,type:"QUERY",context:await p??{},queryParams:l},subscription:h?b=>{var v;!b.resourceId||!b.payload||!Object.keys(b.payload).length||(v=e[o])==null||v.send(JSON.stringify(b));}:void 0});if(!T||!T.data)throw new Error("Invalid resource");h&&T.unsubscribe&&a.set(j(g),T.unsubscribe),s({id:m,type:"REPLY",data:{resource:g.resource,data:(T.data??[]).map(b=>b.value)}});}else if(d.type==="UNSUBSCRIBE"){let{type:f,id:m,...g}=d,h=a.get(j(g));h&&(h(),a.delete(j(g)));}else if(d.type==="MUTATE"){let{resource:f}=d;t.debug("Received mutation from client:",d);try{let m=await i.handleMutation({req:{...u,type:"MUTATE",resource:f,input:d.payload,context:{messageId:d.id,...await p??{}},resourceId:d.resourceId,procedure:d.procedure,queryParams:l}});d.procedure&&d.procedure!=="INSERT"&&d.procedure!=="UPDATE"&&s({id:d.id,type:"REPLY",data:m});}catch(m){s({id:d.id,type:"REJECT",resource:f,message:m.message}),t.error("Error parsing mutation from the client:",m);}}}catch(d){t.error("Error handling message from the client:",d);}}),n.on("close",()=>{t.info("Connection closed",o),delete e[o];for(let y of Array.from(a.values()))y();});}};function $e(i){let e=`${i.protocol}://${i.hostname}${i.url}`,t=new Headers;return Object.entries(i.headers).forEach(([n,r])=>{r&&t.set(n,Array.isArray(r)?r.join(","):r);}),new Request(e,{method:i.method,headers:t,body:i.body&&i.method!=="GET"?JSON.stringify(i.body):void 0})}var Lr=(i,e,t)=>{i.ws(`${(t==null?void 0:t.basePath)??""}/ws`,Ne(e)),i.use(`${(t==null?void 0:t.basePath)??""}/`,(n,r)=>{je(e)($e(n)).then(o=>o.json().then(a=>r.status(o.status).send(a)));});};var le=class i{routes;constructor(e){this.routes=e.routes;}static create(e){return new i(e)}},Nr=i=>le.create({...i}),vt=i=>({handler:e=>({inputValidator:i??zod.z.undefined(),handler:e})}),de=class i{resourceSchema;middlewares;customMutations;authorization;constructor(e,t,n){this.resourceSchema=e,this.middlewares=new Set,this.customMutations=t??{},this.authorization=n;}use(...e){for(let t of e)this.middlewares.add(t);return this}withMutations(e){return new i(this.resourceSchema,e({mutation:vt}),this.authorization)}handleQuery=async({req:e,batcher:t})=>await this.wrapInMiddlewares(async n=>{let r={resource:n.resource,where:n.where,include:n.include,lastSyncedAt:n.lastSyncedAt,limit:n.limit,sort:n.sort},s=j(r);return {data:await t.rawFind({resource:n.resource,commonWhere:n.where,uniqueWhere:n.relationalWhere,include:n.include,limit:n.limit,sort:n.sort}),unsubscribe:void 0,queryHash:s}})(e);handleMutation=async({req:e,db:t,schema:n})=>await this.wrapInMiddlewares(async r=>{if(!r.procedure)throw new Error("Procedure is required for mutations");let s=this.customMutations[r.procedure];if(s){let o=s.inputValidator.parse(r.input);return r.input=o,s.handler({req:r,db:t})}else {if(r.procedure==="INSERT"||r.procedure==="UPDATE")return this.handleSet({req:r,db:t,operation:r.procedure,schema:n});throw new Error(`Unknown procedure: ${r.procedure}`)}})(e);getAuthorizationClause(e){var t,n;return (n=(t=this.authorization)==null?void 0:t.read)==null?void 0:n.call(t,{ctx:e.context})}handleSet=async({req:e,db:t,operation:n,schema:r})=>{if(!e.input)throw new Error("Payload is required");if(!e.resourceId)throw new Error("ResourceId is required");let s=await t.rawFindById(e.resource,e.resourceId);if(n==="INSERT"&&s)throw new Error("Resource already exists");if(n==="UPDATE"&&!s)throw new Error("Resource not found");return t.transaction(async({trx:o})=>{var p,c,y,d,f,m,g;let[a,u]=this.resourceSchema.mergeMutation("set",e.input,s);if(!u)throw new Error("Mutation rejected");if(n==="INSERT"){let h=await o.rawInsert(e.resource,e.resourceId,a,(p=e.context)==null?void 0:p.messageId),T=S(h);if(T.id=T.id??e.resourceId,(c=this.authorization)!=null&&c.insert){let b=this.authorization.insert({ctx:e.context,value:T});if(typeof b=="boolean"){if(!b)throw new Error("Not authorized")}else {let v=N(b,e.resource,r),x=Object.keys(v).length>0?await o.rawFindById(e.resource,e.resourceId,v):h,M=S(x);if(M.id=M.id??e.resourceId,!I(M,b))throw new Error("Not authorized")}}return {data:h,acceptedValues:u}}if((d=(y=this.authorization)==null?void 0:y.update)!=null&&d.preMutation){let h=S(s);h.id=h.id??e.resourceId;let T=this.authorization.update.preMutation({ctx:e.context,value:h});if(typeof T=="boolean"){if(!T)throw new Error("Not authorized")}else {let b=N(T,e.resource,r),v=Object.keys(b).length>0?await o.rawFindById(e.resource,e.resourceId,b):s,x=S(v);if(x.id=x.id??e.resourceId,!I(x,T))throw new Error("Not authorized")}}let l=await o.rawUpdate(e.resource,e.resourceId,a,(f=e.context)==null?void 0:f.messageId);if((g=(m=this.authorization)==null?void 0:m.update)!=null&&g.postMutation){let h=S(l);h.id=h.id??e.resourceId;let T=this.authorization.update.postMutation({ctx:e.context,value:h});if(typeof T=="boolean"){if(!T)throw new Error("Not authorized")}else {let b=N(T,e.resource,r),v=Object.keys(b).length>0?await o.rawFindById(e.resource,e.resourceId,b):l,x=S(v);if(x.id=x.id??e.resourceId,!I(x,T))throw new Error("Not authorized")}}return {data:l,acceptedValues:u}})};wrapInMiddlewares(e){return t=>Array.from(this.middlewares.values()).reduceRight((n,r)=>s=>r({req:s,next:n}),e)(t)}},ye=class i{middlewares;constructor(e=[]){this.middlewares=e;}collectionRoute(e,t){return new de(e,void 0,t).use(...this.middlewares)}use(...e){return new i([...this.middlewares,...e])}static create(){return new i}},$r=ye.create;var _=class{async insert(e,t){let n=new Date().toISOString();return S(await this.rawInsert(e.name,t.id,{value:Object.fromEntries(Object.entries(t).map(([r,s])=>[r,{value:s,_meta:{timestamp:n}}]))}))}async update(e,t,n){let r=new Date().toISOString(),{id:s,...o}=n;return S(await this.rawUpdate(e.name,t,{value:Object.fromEntries(Object.entries(o).map(([a,u])=>[a,{value:u,_meta:{timestamp:r}}]))}))}};function H(i,e,t,n){if(!i)throw new Error("Schema not initialized");let r=i[e];if(!r)throw new Error("Resource not found");let s=n.$or,o=n.$and;return (s?t.or:t.and)(s?n.$or.map(a=>H(i,e,t,a)):o?n.$and.map(a=>H(i,e,t,a)):Object.entries(n).map(([a,u])=>{var l,p;if(r.fields[a])return (u==null?void 0:u.$eq)!==void 0?t(`${e}.${a}`,u.$eq===null?"is":"=",u.$eq):(u==null?void 0:u.$in)!==void 0?t(`${e}.${a}`,"in",u.$in):(u==null?void 0:u.$not)!==void 0?((l=u==null?void 0:u.$not)==null?void 0:l.$in)!==void 0?t(`${e}.${a}`,"not in",u.$not.$in):((p=u==null?void 0:u.$not)==null?void 0:p.$eq)!==void 0?t(`${e}.${a}`,u.$not.$eq===null?"is not":"!=",u.$not.$eq):t(`${e}.${a}`,u.$not===null?"is not":"!=",u.$not):(u==null?void 0:u.$gt)!==void 0?t(`${e}.${a}`,">",u.$gt):(u==null?void 0:u.$gte)!==void 0?t(`${e}.${a}`,">=",u.$gte):(u==null?void 0:u.$lt)!==void 0?t(`${e}.${a}`,"<",u.$lt):(u==null?void 0:u.$lte)!==void 0?t(`${e}.${a}`,"<=",u.$lte):t(`${e}.${a}`,u===null?"is":"=",u);if(r.relations[a]){let c=r.relations[a],y=c.entity.name;return c.type==="many"?t.exists(pe(i,y,t.selectFrom(y).select("id").whereRef(c.foreignColumn,"=",`${e}.id`),u)):H(i,y,t,u)}return null}).filter(Boolean))}function G(i,e,t,n){let r=i[e];if(!r)throw new Error("Resource not found");if(!n)return t;if(n.$and){for(let s of n.$and)t=G(i,e,t,s);return t}else if(n.$or){for(let s of n.$or)t=G(i,e,t,s);return t}for(let[s,o]of Object.entries(n)){if(!r.relations[s])continue;let a=r.relations[s],u=a.entity.name,l=a.type==="one"?"id":a.foreignColumn,p=a.type==="one"?a.relationalColumn:"id";t=t.leftJoin(u,`${u}.${l}`,`${e}.${p}`),o instanceof Object&&!Array.isArray(o)&&o!==null&&(t=G(i,u,t,o));}return t}function pe(i,e,t,n){return !n||Object.keys(n).length===0?t:(t=G(i,e,t,n),t.where(r=>H(i,e,r,n)))}function Z(i,e,t,n){if(!n)return t;if(!i)throw new Error("Schema not initialized");let r=i[e];if(!r)throw new Error(`Resource not found: ${e}`);for(let s of Object.keys(n)){if(!r.relations[s])throw new Error(`Relation ${s} not found in resource ${e}`);let o=r.relations[s],a=o.entity.name,u=n[s],l=o.type==="one"?"id":o.foreignColumn,p=o.type==="one"?o.relationalColumn:"id",c=o.type==="one"?postgres.jsonObjectFrom:postgres.jsonArrayFrom,y=typeof u=="object"&&u!==null;t=t.select(d=>{let f=d.selectFrom(a).selectAll(a).whereRef(`${a}.${l}`,"=",`${e}.${p}`).select(m=>postgres.jsonObjectFrom(m.selectFrom(`${a}_meta`).selectAll(`${a}_meta`).whereRef(`${a}_meta.id`,"=",`${a}.id`)).as("_meta"));return y&&(f=Z(i,a,f,u)),c(f).as(s)});}return t}var Qe="42701",fe=class i extends _{db;schema;logger;server;mutationStack=[];constructor(e,t,n,r){super(),this.isKyselyLike(e)?this.db=e:this.db=new kysely.Kysely({dialect:new kysely.PostgresDialect({pool:e})}),this.schema=t,this.logger=n,this.server=r,this.rawInsert=this.rawInsert.bind(this),this.rawUpdate=this.rawUpdate.bind(this);}async init(e,t,n){var s;this.schema=e,this.logger=t,this.server=n;let r=await this.db.introspection.getTables();for(let[o,a]of Object.entries(e)){let u=r.find(c=>c.name===o);u||await this.db.schema.createTable(o).ifNotExists().execute();let l=`${o}_meta`,p=r.find(c=>c.name===l);p||await this.db.schema.createTable(l).ifNotExists().execute();for(let[c,y]of Object.entries(a.fields)){let d=u==null?void 0:u.columns.find(g=>g.name===c),f=y.getStorageFieldType();d?d.dataType!==f.type&&((s=this.logger)==null||s.warn("Column type mismatch:",c,"expected to have type:",f.type,"but has type:",d.dataType)):(await this.db.schema.alterTable(o).addColumn(c,f.type,g=>{let h=g;return f.unique&&(h=h.unique()),f.nullable||(h=h.notNull()),f.references&&(h=h.references(f.references)),f.primary&&(h=h.primaryKey()),f.default!==void 0&&(h=h.defaultTo(f.default)),h}).execute().catch(g=>{var h;if(g.code!==Qe)throw (h=this.logger)==null||h.error("Error adding column",c,g),g}),f.index&&await this.db.schema.createIndex(`${o}_${c}_index`).on(o).column(c).execute().catch(()=>{})),p!=null&&p.columns.find(g=>g.name===c)||await this.db.schema.alterTable(l).addColumn(c,"varchar",g=>{let h=g;return f.primary&&(h=h.primaryKey().references(`${o}.${c}`)),h}).execute().catch(g=>{var h;if(g.code!==Qe)throw (h=this.logger)==null||h.error("Error adding meta column",c,g),g});}}}async rawFindById(e,t,n){if(!this.schema)throw new Error("Schema not initialized");let r=await this.db.selectFrom(e).where("id","=",t).selectAll(e).select(o=>postgres.jsonObjectFrom(o.selectFrom(`${e}_meta`).selectAll(`${e}_meta`).whereRef(`${e}_meta.id`,"=",`${e}.id`)).as("_meta"));r=Z(this.schema,e,r,n);let s=await r.executeTakeFirst();if(s)return this.convertToMaterializedLiveType(s)}async findOne(e,t,n){let r=await this.rawFindById(e.name,t,n==null?void 0:n.include);if(r)return S(r)}async get(e){if(!this.schema)throw new Error("Schema not initialized");let{resource:t,where:n,include:r,limit:s,sort:o}=e,a=this.db.selectFrom(t).selectAll(t).select(l=>postgres.jsonObjectFrom(l.selectFrom(`${t}_meta`).selectAll(`${t}_meta`).whereRef(`${t}_meta.id`,"=",`${t}.id`)).as("_meta"));a=pe(this.schema,t,a,n),a=Z(this.schema,t,a,r),s!==void 0&&(a=a.limit(s)),o!==void 0&&o.forEach(l=>{a=a.orderBy(l.key,l.direction);});let u=await a.execute();return u.length===0?[]:u.map(l=>this.convertToMaterializedLiveType(l))}async find(e,t){return (await this.get({resource:e.name,where:t==null?void 0:t.where,include:t==null?void 0:t.include,limit:t==null?void 0:t.limit,sort:t==null?void 0:t.sort})).map(r=>S(r))}async rawInsert(e,t,n,r){var u;let s={},o={};for(let[l,p]of Object.entries(n.value)){let c=(u=p._meta)==null?void 0:u.timestamp;c&&(s[l]=p.value,o[l]=c);}await this.db.insertInto(e).values({...s,id:t}).execute().then(()=>{this.db.insertInto(`${e}_meta`).values({...o,id:t}).execute();});let a=this.buildMutation(e,t,"INSERT",n,r);return a&&this.trackMutation(a,n),n}async rawUpdate(e,t,n,r){var u;let s={},o={};for(let[l,p]of Object.entries(n.value)){let c=(u=p._meta)==null?void 0:u.timestamp;c&&(s[l]=p.value,o[l]=c);}await Promise.all([this.db.updateTable(e).set(s).where("id","=",t).execute(),this.db.insertInto(`${e}_meta`).values({...o,id:t}).onConflict(l=>l.column("id").doUpdateSet(o)).execute()]);let a=this.buildMutation(e,t,"UPDATE",n,r);if(a){let l=await this.rawFindById(e,t);l&&this.trackMutation(a,l);}return n}async transaction(e){if(!this.schema)throw new Error("Schema not initialized");if(this.db.isTransaction){let s=Math.random().toString(36).substring(2,15),o=this.mutationStack,a=[];this.mutationStack=a;let u=await this.db.savepoint(s).execute();try{return await e({trx:this,commit:async()=>{await u.releaseSavepoint(s).execute(),o.push(...a);},rollback:async()=>{await u.rollbackToSavepoint(s).execute(),a.length=0;}}).then(l=>u.isCommitted||u.isRolledBack?l:u.releaseSavepoint(s).execute().then(()=>(o.push(...a),l)))}catch(l){throw await u.rollbackToSavepoint(s).execute().catch(()=>{}),a.length=0,l}finally{this.mutationStack=o;}}let t=[],n=this.mutationStack;this.mutationStack=t;let r=await this.db.startTransaction().execute();try{let s=new i(r,this.schema,this.logger,this.server);return s.mutationStack=t,await e({trx:s,commit:async()=>{await r.commit().execute(),this.notifyMutations(t);},rollback:async()=>{await r.rollback().execute(),t.length=0;}}).then(o=>r.isCommitted||r.isRolledBack?o:r.commit().execute().then(()=>(this.notifyMutations(t),o)))}catch(s){throw await r.rollback().execute(),t.length=0,s}finally{this.mutationStack=n;}}get internalDB(){return this.db}convertToMaterializedLiveType(e){return {value:Object.entries(e).reduce((t,[n,r])=>{var s,o,a;return n==="_meta"||(n==="id"?t[n]={value:r}:Array.isArray(r)?t[n]={value:r.map(u=>this.convertToMaterializedLiveType(u)),_meta:{timestamp:(s=e==null?void 0:e._meta)==null?void 0:s[n]}}:typeof r=="object"&&r!==null&&!(r instanceof Date)?t[n]={...this.convertToMaterializedLiveType(r),_meta:{timestamp:(o=e==null?void 0:e._meta)==null?void 0:o[n]}}:t[n]={value:r,_meta:{timestamp:(a=e==null?void 0:e._meta)==null?void 0:a[n]}}),t},{})}}isKyselyLike(e){if(e instanceof kysely.Kysely)return true;if(!e||typeof e!="object")return false;let t=e,n=typeof t.selectFrom=="function",r=typeof t.startTransaction=="function",s=typeof t.savepoint=="function",o=typeof t.isTransaction=="boolean"||typeof t.isTransaction=="function";return n&&r||s&&o}buildMutation(e,t,n,r,s){var a;let o={};for(let[u,l]of Object.entries(r.value)){if(u==="id")continue;let p=(a=l._meta)==null?void 0:a.timestamp;p&&(o[u]={value:l.value,_meta:{timestamp:p}});}return Object.keys(o).length===0?null:{id:s??K(),type:"MUTATE",resource:e,resourceId:t,procedure:n,payload:o}}trackMutation(e,t){this.db.isTransaction?this.mutationStack.push({mutation:e,entityData:t}):this.notifyMutations([e],t);}notifyMutations(e,t){if(this.server)if(t!==void 0){let n=e;for(let r of n)this.server.notifySubscribers(r,t);}else {let n=e;for(let{mutation:r,entityData:s}of n)this.server.notifySubscribers(r,s);}}};var he=class i{router;storage;schema;middlewares=new Set;logger;contextProvider;queryEngine;constructor(e){var t;this.router=e.router,this.storage=e.storage,this.schema=e.schema,this.logger=xe({level:e.logLevel??L.INFO}),(t=e.middlewares)==null||t.forEach(n=>{this.middlewares.add(n);}),this.storage.init(this.schema,this.logger,this),this.contextProvider=e.contextProvider,this.queryEngine=new B({router:{get:async(n,r)=>{var c;let{headers:s,cookies:o,queryParams:a,context:u}=(r==null?void 0:r.context)??{};if(!(r!=null&&r.batcher))throw new Error("Batcher is required");let l={...n,type:"QUERY",headers:s,cookies:o,queryParams:a,context:u},p=await((c=this.router.routes[n.resource])==null?void 0:c.handleQuery({req:l,batcher:r.batcher}));return (p==null?void 0:p.data)??[]},incrementQueryStep:(n,r={})=>{var a;let s=(a=this.router.routes[n.query.resource])==null?void 0:a.getAuthorizationClause({...n.query,type:"QUERY",headers:r.headers,cookies:r.cookies,queryParams:r.queryParams,context:r.context});if(typeof s=="boolean"&&!s)throw new Error("Not authorized");let o=P(n.query.where,typeof s=="object"?s:void 0);return {...n,query:{...n.query,where:o}}}},storage:this.storage,schema:this.schema,logger:this.logger});}static create(e){return new i(e)}handleQuery(e){return this.wrapInMiddlewares(async t=>{let{headers:n,cookies:r,queryParams:s,context:o,...a}=t,u={headers:n,cookies:r,queryParams:s,context:o},l=e.subscription?this.queryEngine.subscribe(a,c=>{var y;(y=e.subscription)==null||y.call(e,c);},u):void 0;return {data:await this.queryEngine.get(a,{context:u}),unsubscribe:l}})(e.req)}async handleMutation(e){return await this.wrapInMiddlewares(async n=>{let r=this.router.routes[n.resource];if(!r)throw new Error("Invalid resource");return r.handleMutation({req:n,db:this.storage,schema:this.schema})})(e.req)}use(e){return this.middlewares.add(e),this}context(e){return this.contextProvider=e,this}notifySubscribers(e,t){this.queryEngine.handleMutation(e,t);}wrapInMiddlewares(e){return t=>Array.from(this.middlewares.values()).reduceRight((n,r)=>s=>r({req:s,next:n}),e)(t)}},Yr=he.create;
2
- exports.Route=de;exports.RouteFactory=ye;exports.Router=le;exports.SQLStorage=fe;exports.Server=he;exports.Storage=_;exports.expressAdapter=Lr;exports.routeFactory=$r;exports.router=Nr;exports.server=Yr;
1
+ 'use strict';var W=require('crypto'),jsXxhash=require('js-xxhash'),gt=require('qs'),zod=require('zod'),kysely=require('kysely'),mysql=require('kysely/helpers/mysql'),postgres=require('kysely/helpers/postgres'),sqlite=require('kysely/helpers/sqlite');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var W__default=/*#__PURE__*/_interopDefault(W);var gt__default=/*#__PURE__*/_interopDefault(gt);var _e=Object.create;var ve=Object.defineProperty;var Be=Object.getOwnPropertyDescriptor;var We=Object.getOwnPropertyNames;var Ue=Object.getPrototypeOf,He=Object.prototype.hasOwnProperty;var Ge=(i,e)=>()=>(e||i((e={exports:{}}).exports,e),e.exports);var Je=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of We(e))!He.call(i,r)&&r!==t&&ve(i,r,{get:()=>e[r],enumerable:!(n=Be(e,r))||n.enumerable});return i};var Se=(i,e,t)=>(t=i!=null?_e(Ue(i)):{},Je(ve(t,"default",{value:i,enumerable:true}),i));var ue=Ge(Z=>{Object.defineProperty(Z,"__esModule",{value:true});Z.parse=dt;Z.serialize=yt;var st=/^[\u0021-\u003A\u003C\u003E-\u007E]+$/,at=/^[\u0021-\u003A\u003C-\u007E]*$/,ot=/^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i,ct=/^[\u0020-\u003A\u003D-\u007E]*$/,ut=Object.prototype.toString,lt=(()=>{let i=function(){};return i.prototype=Object.create(null),i})();function dt(i,e){let t=new lt,n=i.length;if(n<2)return t;let r=(e==null?void 0:e.decode)||pt,a=0;do{let c=i.indexOf("=",a);if(c===-1)break;let o=i.indexOf(";",a),s=o===-1?n:o;if(c>s){a=i.lastIndexOf(";",c-1)+1;continue}let u=je(i,a,c),d=Oe(i,c,u),l=i.slice(u,d);if(t[l]===void 0){let p=je(i,c+1,s),y=Oe(i,s,p),h=r(i.slice(p,y));t[l]=h;}a=s+1;}while(a<n);return t}function je(i,e,t){do{let n=i.charCodeAt(e);if(n!==32&&n!==9)return e}while(++e<t);return t}function Oe(i,e,t){for(;e>t;){let n=i.charCodeAt(--e);if(n!==32&&n!==9)return e+1}return t}function yt(i,e,t){let n=(t==null?void 0:t.encode)||encodeURIComponent;if(!st.test(i))throw new TypeError(`argument name is invalid: ${i}`);let r=n(e);if(!at.test(r))throw new TypeError(`argument val is invalid: ${e}`);let a=i+"="+r;if(!t)return a;if(t.maxAge!==void 0){if(!Number.isInteger(t.maxAge))throw new TypeError(`option maxAge is invalid: ${t.maxAge}`);a+="; Max-Age="+t.maxAge;}if(t.domain){if(!ot.test(t.domain))throw new TypeError(`option domain is invalid: ${t.domain}`);a+="; Domain="+t.domain;}if(t.path){if(!ct.test(t.path))throw new TypeError(`option path is invalid: ${t.path}`);a+="; Path="+t.path;}if(t.expires){if(!ft(t.expires)||!Number.isFinite(t.expires.valueOf()))throw new TypeError(`option expires is invalid: ${t.expires}`);a+="; Expires="+t.expires.toUTCString();}if(t.httpOnly&&(a+="; HttpOnly"),t.secure&&(a+="; Secure"),t.partitioned&&(a+="; Partitioned"),t.priority)switch(typeof t.priority=="string"?t.priority.toLowerCase():void 0){case "low":a+="; Priority=Low";break;case "medium":a+="; Priority=Medium";break;case "high":a+="; Priority=High";break;default:throw new TypeError(`option priority is invalid: ${t.priority}`)}if(t.sameSite)switch(typeof t.sameSite=="string"?t.sameSite.toLowerCase():t.sameSite){case true:case "strict":a+="; SameSite=Strict";break;case "lax":a+="; SameSite=Lax";break;case "none":a+="; SameSite=None";break;default:throw new TypeError(`option sameSite is invalid: ${t.sameSite}`)}return a}function pt(i){if(i.indexOf("%")===-1)return i;try{return decodeURIComponent(i)}catch{return i}}function ft(i){return ut.call(i)==="[object Date]"}});var x=i=>i?Array.isArray(i.value)?i.value.map(t=>x(t)):typeof i.value!="object"||i.value===null||i.value instanceof Date?i.value:Object.fromEntries(Object.entries(i.value).map(([t,n])=>Array.isArray(n)?[t,n.map(r=>x(r))]:[t,x(n)])):void 0;var we="0123456789ABCDEFGHJKMNPQRSTVWXYZ",z=32;var Ze=16,Ie=10,xe=0xffffffffffff;var A;(function(i){i.Base32IncorrectEncoding="B32_ENC_INVALID",i.DecodeTimeInvalidCharacter="DEC_TIME_CHAR",i.DecodeTimeValueMalformed="DEC_TIME_MALFORMED",i.EncodeTimeNegative="ENC_TIME_NEG",i.EncodeTimeSizeExceeded="ENC_TIME_SIZE_EXCEED",i.EncodeTimeValueMalformed="ENC_TIME_MALFORMED",i.PRNGDetectFailure="PRNG_DETECT",i.ULIDInvalid="ULID_INVALID",i.Unexpected="UNEXPECTED",i.UUIDInvalid="UUID_INVALID";})(A||(A={}));var E=class extends Error{constructor(e,t){super(`${t} (${e})`),this.name="ULIDError",this.code=e;}};function Ye(i){let e=Math.floor(i()*z);return e===z&&(e=z-1),we.charAt(e)}function Xe(i){var n;let e=et(),t=e&&(e.crypto||e.msCrypto)||(typeof W__default.default<"u"?W__default.default:null);if(typeof(t==null?void 0:t.getRandomValues)=="function")return ()=>{let r=new Uint8Array(1);return t.getRandomValues(r),r[0]/255};if(typeof(t==null?void 0:t.randomBytes)=="function")return ()=>t.randomBytes(1).readUInt8()/255;if((n=W__default.default)!=null&&n.randomBytes)return ()=>W__default.default.randomBytes(1).readUInt8()/255;throw new E(A.PRNGDetectFailure,"Failed to find a reliable PRNG")}function et(){return nt()?self:typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:null}function tt(i,e){let t="";for(;i>0;i--)t=Ye(e)+t;return t}function rt(i,e=Ie){if(isNaN(i))throw new E(A.EncodeTimeValueMalformed,`Time must be a number: ${i}`);if(i>xe)throw new E(A.EncodeTimeSizeExceeded,`Cannot encode a time larger than ${xe}: ${i}`);if(i<0)throw new E(A.EncodeTimeNegative,`Time must be positive: ${i}`);if(Number.isInteger(i)===false)throw new E(A.EncodeTimeValueMalformed,`Time must be an integer: ${i}`);let t,n="";for(let r=e;r>0;r--)t=i%z,n=we.charAt(t)+n,i=(i-t)/z;return n}function nt(){return typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope}function Me(i,e){let t=Xe(),n=Date.now();return rt(n,Ie)+tt(Ze,t)}var H=()=>Me().toLowerCase(),U=i=>({then(e,t){try{if(e){let n=e(i);return n instanceof Promise?n:U(n)}return U(i)}catch(n){if(t){let r=t(n);return r instanceof Promise?r:U(r)}throw n}}}),ae=i=>i instanceof Promise?i:U(i);var q=(...i)=>{let e=i.filter(t=>!!t);return e.length===0?{}:e.length===1?e[0]:{$and:e}};var G=class{storage;queue=new Map;scheduled=false;constructor(e){this.storage=e;}async rawFind({resource:e,commonWhere:t,uniqueWhere:n,...r}){return new Promise((a,c)=>{let o=this.getBatchKey({resource:e,commonWhere:t,...r}),s={resource:e,commonWhere:t,uniqueWhere:n,...r,resolve:a,reject:c};this.queue.has(o)||this.queue.set(o,[]);let u=this.queue.get(o);u&&u.push(s),this.scheduled||(this.scheduled=true,setImmediate(()=>{this.processBatch();}));})}getBatchKey(e){let{resource:t,commonWhere:n,...r}=e;return `${t}:${JSON.stringify(n??{})}:${JSON.stringify(r??{})}`}async processBatch(){this.scheduled=false;let e=Array.from(this.queue.entries());this.queue.clear();for(let[,t]of e)try{await this.executeBatchedRequests(t);}catch(n){t.forEach(r=>{r.reject(n);});}}async executeBatchedRequests(e){var p;if(e.length===0)return;let t=e[0],{resource:n,commonWhere:r,include:a,sort:c}=t,o=e.length===1?t.limit:void 0,s=e.map(y=>y.uniqueWhere).filter(y=>y!==void 0),u=r,d=(p=Object.entries(s[0]??{})[0])==null?void 0:p[0];if(s.length>0){let y=s.map(h=>h[d]).filter(h=>h!=null);y.length>0&&(u=q(r,{[d]:{$in:y}}));}let l=await this.storage.get({resource:n,where:u,include:a,sort:c,limit:o});for(let y of e){let h=l;if(y.uniqueWhere){let[f,T]=Object.entries(y.uniqueWhere)[0];h=l.filter(g=>{var m;return ((m=g.value[f])==null?void 0:m.value)===T});}y.resolve(h);}}};var j=i=>jsXxhash.xxHash32(JSON.stringify(i)).toString(32),C=(i,e,t)=>{let n={},r=t[e];if(!r)return n;let a=c=>{c.$and?c.$and.forEach(a):c.$or?c.$or.forEach(a):Object.entries(c).forEach(([o,s])=>{var u;if((u=r.relations)!=null&&u[o]&&(n[o]=true,typeof s=="object"&&s!==null&&!Array.isArray(s))){let d=C(s,r.relations[o].entity.name,t);Object.keys(d).length>0&&(n[o]=d);}});};return a(i),n},I=(i,e,t=false)=>Object.entries(e).every(([n,r])=>{if(n==="$and")return r.every(c=>I(i,c,t));if(n==="$or")return r.some(c=>I(i,c,t));let a=(r==null?void 0:r.$eq)!==void 0?r==null?void 0:r.$eq:r;if(typeof r=="object"&&r!==null&&(r==null?void 0:r.$eq)===void 0){if(r.$in!==void 0){let o=i[n];return o===void 0?false:t?!r.$in.includes(o):r.$in.includes(o)}if(r.$not!==void 0&&!t)return I(i,{[n]:r.$not},true);if(r.$gt!==void 0){let o=i[n];return typeof o!="number"?false:t?o<=r.$gt:o>r.$gt}if(r.$gte!==void 0){let o=i[n];return typeof o!="number"?false:t?o<r.$gte:o>=r.$gte}if(r.$lt!==void 0){let o=i[n];return typeof o!="number"?false:t?o>=r.$lt:o<r.$lt}if(r.$lte!==void 0){let o=i[n];return typeof o!="number"?false:t?o>r.$lte:o<=r.$lte}let c=i[n];return !c||typeof c!="object"&&!Array.isArray(c)?false:Array.isArray(c)?t?!c.some(o=>I(o,r,false)):c.some(o=>I(o,r,false)):I(c,r,t)}return t?i[n]!==a:i[n]===a}),L={CRITICAL:0,ERROR:1,WARN:2,INFO:3,DEBUG:4},oe=class{level;prefix;constructor(e={}){this.level=e.level??L.INFO,this.prefix=e.prefix?`[${e.prefix}] `:"";}critical(...e){this.level>=L.CRITICAL&&console.error(`${this.prefix}[CRITICAL]`,...e);}error(...e){this.level>=L.ERROR&&console.error(`${this.prefix}[ERROR]`,...e);}warn(...e){this.level>=L.WARN&&console.warn(`${this.prefix}[WARN]`,...e);}info(...e){this.level>=L.INFO&&console.log(`${this.prefix}[INFO]`,...e);}debug(...e){this.level>=L.DEBUG&&console.log(`${this.prefix}[DEBUG]`,...e);}setLevel(e){this.level=e;}getLevel(){return this.level}},Le=i=>new oe(i);function ce(i){return j({resource:i.query.resource,where:i.query.where,include:i.query.include,stepPath:i.stepPath,isMany:i.isMany,relationName:i.relationName})}var J=class{router;storage;schema;logger;queryNodes=new Map;objectNodes=new Map;constructor(e){this.router=e.router,this.storage=e.storage,this.schema=e.schema,this.logger=e.logger;}getRelationalColumns(e){let t=new Map,n=this.schema[e];if(!(n!=null&&n.relations))return t;for(let[r,a]of Object.entries(n.relations))a.type==="one"&&a.relationalColumn&&t.set(String(a.relationalColumn),{relationName:r,targetResource:a.entity.name});return t}ensureObjectNode(e,t,n){let r=this.objectNodes.get(e);return r?n&&r.matchedQueries.add(n):(r={id:e,type:t,matchedQueries:new Set(n?[n]:[]),referencesObjects:new Map,referencedByObjects:new Map},this.objectNodes.set(e,r)),r}storeRelation(e,t,n,r){let a=this.objectNodes.get(e),c=this.objectNodes.get(t);if(a&&a.referencesObjects.set(n,t),c&&r){let o=c.referencedByObjects.get(r);o||(o=new Set,c.referencedByObjects.set(r,o)),o.add(e);}}removeRelation(e,t,n,r){let a=this.objectNodes.get(e),c=this.objectNodes.get(t);if(a&&a.referencesObjects.delete(n),c&&r){let o=c.referencedByObjects.get(r);o&&(o.delete(e),o.size===0&&c.referencedByObjects.delete(r));}}getInverseRelationName(e,t,n){let r=this.schema[e];if(!(r!=null&&r.relations))return;let a=r.relations[n];if(!a)return;let c=this.schema[t];if(c!=null&&c.relations){if(a.type==="many"&&a.foreignColumn){for(let[o,s]of Object.entries(c.relations))if(s.entity.name===e&&s.type==="one"&&s.relationalColumn===a.foreignColumn)return o}if(a.type==="one"&&a.relationalColumn){for(let[o,s]of Object.entries(c.relations))if(s.entity.name===e&&s.type==="many"&&s.foreignColumn===a.relationalColumn)return o}}}updateRelationsFromMutation(e,t,n,r){let a=this.getRelationalColumns(e),c=this.objectNodes.get(t);if(c)for(let[o,{relationName:s,targetResource:u}]of Array.from(a)){if(!(r&&o in r))continue;let l=this.getInverseRelationName(e,u,s),p=c.referencesObjects.get(s),y=n[o];p!==y&&(p&&this.removeRelation(t,p,s,l),y&&(this.ensureObjectNode(y,u),this.storeRelation(t,y,s,l)));}}get(e,t){let n=this.breakdownQuery({query:e,context:(t==null?void 0:t.context)??{}});return this.resolveQuery(n,{context:(t==null?void 0:t.context)??{},batcher:(t==null?void 0:t.batcher)??new G(this.storage)})}subscribe(e,t,n={}){let r=this.breakdownQuery({query:e,context:n}),a={},c=[];for(let o of r){this.logger.debug("[QueryEngine] Subscribing to step",o.stepPath.join("."));let s=ce(o),u=a[o.stepPath.at(-2)??""],d=o.stepPath.at(-1)??"",l=this.queryNodes.get(s);if(l)l.subscriptions.add(t);else if(l={hash:s,queryStep:o,relationName:d,trackedObjects:new Set,subscriptions:new Set([t]),parentQuery:u,childQueries:new Set},this.queryNodes.set(l.hash,l),u){let p=this.queryNodes.get(u);p&&p.childQueries.add(l.hash);}a[d]=s,c.push(()=>{let p=this.queryNodes.get(s);p&&(p.subscriptions.delete(t),p.subscriptions.size===0&&this.queryNodes.delete(s));});}return ()=>{for(let o of c)o();}}breakdownQuery(e){var T;let{query:t,stepPath:n=[],context:r={},parentResource:a}=e,{include:c}=t,o=n.length===0,s=n.at(-1),u,d,l;if(!o&&a&&s){let g=this.schema[a],m=(T=g==null?void 0:g.relations)==null?void 0:T[s];m&&(l=m.type==="many",m.type==="one"?(u=b=>({id:b}),d=b=>b.map(v=>{var S,M;return (M=(S=v.value)==null?void 0:S[m.relationalColumn])==null?void 0:M.value}).filter(v=>v!==void 0)):(u=b=>({[m.foreignColumn]:b}),d=b=>b.map(v=>{var S,M;return (M=(S=v.value)==null?void 0:S.id)==null?void 0:M.value}).filter(v=>v!==void 0)));}let{include:p,...y}=t,f=[this.router.incrementQueryStep({query:y,stepPath:[...n],getWhere:u,referenceGetter:d,isMany:l,relationName:s},r)];if(c&&typeof c=="object"&&Object.keys(c).length>0){let g=this.schema[t.resource];if(!g)throw new Error(`Resource ${t.resource} not found`);f.push(...Object.entries(c).flatMap(([m,b])=>{let v=g.relations[m];if(!v)throw new Error(`Relation ${m} not found for resource ${t.resource}`);let S=v.entity.name;return this.breakdownQuery({query:{resource:S,include:typeof b=="object"?b:void 0},stepPath:[...n,m],context:r,parentResource:t.resource})}));}return f}resolveQuery(e,t){this.logger.debug("[QueryEngine] Resolving query",e.map(a=>a.stepPath.join(".")).join(" -> "));let n={},r=this.resolveStep(e[0],t).then(a=>{this.logger.debug("[QueryEngine] Resolved step",e[0].stepPath.join("."),"with results count:",a.length),n[e[0].stepPath.join(".")]=[{data:a}];});for(let a=1;a<e.length;a++){let c=e[a],o=c.stepPath.slice(0,-1).join(".");r=r.then(async()=>{var u,d;let s=n[o];if(!s){n[c.stepPath.join(".")]=[];return}if(c.referenceGetter&&c.getWhere){let l=new Map;for(let h of s)for(let f of h.data){let T=(d=(u=f==null?void 0:f.value)==null?void 0:u.id)==null?void 0:d.value;if(!T)continue;let m=c.referenceGetter([f])[0];if(m){l.has(m)||l.set(m,new Set);let b=l.get(m);b&&b.add(T);}}let p=Array.from(l.keys());if(p.length===0){n[c.stepPath.join(".")]=[];return}let y=[];for(let h of p){let f=c.getWhere(h),T={...c,relationalWhere:f},g=await this.resolveStep(T,t),m=l.get(h);if(m)for(let b of Array.from(m))y.push({includedBy:b,data:g});}this.logger.debug("[QueryEngine] Resolved step",c.stepPath.join("."),"with results count:",y.reduce((h,f)=>h+f.data.length,0)),n[c.stepPath.join(".")]=y;}else {let l=await this.resolveStep(c,t);n[c.stepPath.join(".")]=[{data:l}];}});}return r=r.then((()=>(this.logger.debug("[QueryEngine] Assembling results"),this.assembleResults(e,n)))),r}assembleResults(e,t){var c,o,s,u,d;this.logger.debug("[QueryEngine] assembleResults: Starting assembly"),this.logger.debug("[QueryEngine] assembleResults: Plan steps:",e.length),this.logger.debug("[QueryEngine] assembleResults: Step results keys:",Object.keys(t));let n=new Map;for(let l of e){let p=l.stepPath.join("."),y=t[p]??[],h=Object.keys(l.query.include??{});this.logger.debug(`[QueryEngine] assembleResults: Processing step "${p}"`,{resource:l.query.resource,includedRelations:h,resultGroups:y.length,isMany:l.isMany,relationName:l.relationName});for(let f of y){this.logger.debug(`[QueryEngine] assembleResults: Processing result group for "${p}"`,{dataCount:f.data.length,includedBy:f.includedBy});for(let T of f.data){let g=(o=(c=T==null?void 0:T.value)==null?void 0:c.id)==null?void 0:o.value;if(!g){this.logger.debug(`[QueryEngine] assembleResults: Skipping data without id in step "${p}"`);continue}let m=p?`${p}.${g}`:g,b=[];if(l.stepPath.length>0&&f.includedBy){let S=l.stepPath.slice(0,-1).join(".");b=[S?`${S}.${f.includedBy}`:f.includedBy],this.logger.debug(`[QueryEngine] assembleResults: Child entity "${m}" has parent keys:`,b,{stepPath:p,parentStepPath:S,includedBy:f.includedBy});}else this.logger.debug(`[QueryEngine] assembleResults: Root entity "${m}" (no parent)`);let v=n.get(m);if(v){this.logger.debug(`[QueryEngine] assembleResults: Entity "${m}" already exists, adding parent keys:`,b);for(let S of b)v.includedBy.add(S);}else this.logger.debug(`[QueryEngine] assembleResults: Adding new entity "${m}"`,{resource:l.query.resource,path:l.stepPath.at(-1)??"",isMany:l.isMany??false,relationName:l.relationName,includedRelations:h,parentKeys:b}),n.set(m,{data:T,includedBy:new Set(b),path:l.stepPath.at(-1)??"",isMany:l.isMany??false,relationName:l.relationName,resourceName:l.query.resource,includedRelations:h});}}}this.logger.debug(`[QueryEngine] assembleResults: Built entriesMap with ${n.size} entries`),this.logger.debug("[QueryEngine] assembleResults: EntriesMap keys:",Array.from(n.keys()));let r=Array.from(n.entries()),a=[];this.logger.debug(`[QueryEngine] assembleResults: Starting assembly phase with ${r.length} entries`);for(let l=r.length-1;l>=0;l--){let[p,y]=r[l],h=this.schema[y.resourceName];this.logger.debug(`[QueryEngine] assembleResults: Processing entry "${p}"`,{resource:y.resourceName,path:y.path,isMany:y.isMany,relationName:y.relationName,includedRelations:y.includedRelations,parentKeys:Array.from(y.includedBy)});for(let f of y.includedRelations){let T=(u=(s=h==null?void 0:h.relations)==null?void 0:s[f])==null?void 0:u.type,g=!!y.data.value[f];if(this.logger.debug(`[QueryEngine] assembleResults: Checking included relation "${f}" for "${p}"`,{relationType:T,hasRelation:g,resourceHasRelation:!!((d=h==null?void 0:h.relations)!=null&&d[f])}),y.data.value[f])this.logger.debug(`[QueryEngine] assembleResults: Relation "${f}" already exists for "${p}"`,y.data.value[f]);else {let m=T==="many"?{value:[]}:{value:null};y.data.value[f]=m,this.logger.debug(`[QueryEngine] assembleResults: Initialized relation "${f}" for "${p}" with`,m);}}if(y.path===""){this.logger.debug(`[QueryEngine] assembleResults: Adding root entity "${p}" to resultData`),a.push(y.data);continue}this.logger.debug(`[QueryEngine] assembleResults: Attaching "${p}" to ${y.includedBy.size} parent(s)`);for(let f of Array.from(y.includedBy)){let T=n.get(f);if(!T){this.logger.warn(`[QueryEngine] assembleResults: WARNING - Parent "${f}" not found in entriesMap for child "${p}"`);continue}let g=y.relationName??y.path;this.logger.debug(`[QueryEngine] assembleResults: Attaching "${p}" to parent "${f}" via relation "${g}"`,{isMany:y.isMany,parentHasRelation:!!T.data.value[g]}),y.isMany?(T.data.value[g]??={value:[]},T.data.value[g].value.push(y.data),this.logger.debug(`[QueryEngine] assembleResults: Added "${p}" to many relation "${g}" on parent "${f}"`,{arrayLength:T.data.value[g].value.length})):(T.data.value[g]=y.data,this.logger.debug(`[QueryEngine] assembleResults: Set one relation "${g}" on parent "${f}" to "${p}"`));}}return this.logger.debug(`[QueryEngine] assembleResults: Assembly complete. Returning ${a.length} root items`),a}resolveStep(e,t){this.logger.debug("[QueryEngine] Resolving step",e.stepPath.join("."),"with query",JSON.stringify(e.query,null,2),"relationalWhere",JSON.stringify(e.relationalWhere,null,2));let{query:n,relationalWhere:r}=e,a=n.where&&r?q(n.where,r):r??n.where,c=a?{...n,where:a}:n;return ae(this.router.get(c,t)).then(o=>(this.loadStepResults(e,o),o))}loadStepResults(e,t){this.logger.debug("[QueryEngine] Loading step results",e.stepPath.join("."),"with results",JSON.stringify(t,null,2));let n=ce(e),r=this.queryNodes.get(n),a=e.query.resource;if(!r)return;let c=this.getRelationalColumns(a);for(let o of t){let s=x(o),u=s.id;this.ensureObjectNode(u,a,n),r.trackedObjects.add(u);for(let[d,{relationName:l,targetResource:p}]of Array.from(c)){let y=s[d];if(y){this.ensureObjectNode(y,p);let h=this.getInverseRelationName(a,p,l);this.storeRelation(u,y,l,h);}}this.loadNestedRelations(a,u,s),this.logger.debug("[QueryEngine] Loaded nested relations for",u);}}loadNestedRelations(e,t,n){let r=this.schema[e];if(r!=null&&r.relations)for(let[a,c]of Object.entries(r.relations)){let o=n[a];if(!o)continue;let s=c.entity.name,u=this.getInverseRelationName(e,s,a);if(c.type==="one")o&&typeof o=="object"&&o.id&&(this.ensureObjectNode(o.id,s),this.storeRelation(t,o.id,a,u),this.loadNestedRelations(s,o.id,o));else if(c.type==="many"&&Array.isArray(o)){for(let d of o)if(d&&typeof d=="object"&&d.id){this.ensureObjectNode(d.id,s);let l=this.getInverseRelationName(s,e,a);l&&this.storeRelation(d.id,t,l,a),this.loadNestedRelations(s,d.id,d);}}}}buildIncludeFromChildQueries(e){let t=this.queryNodes.get(e);if(!t||t.childQueries.size===0)return {};let n={};for(let r of Array.from(t.childQueries)){let a=this.queryNodes.get(r);if(!a||!a.relationName)continue;let c=this.buildIncludeFromChildQueries(r);n[a.relationName]=Object.keys(c).length>0?c:true;}return n}sendInsertsForTree(e,t,n){var o,s;let r=(s=(o=t==null?void 0:t.value)==null?void 0:o.id)==null?void 0:s.value;if(!r)return;let a={procedure:"INSERT",resource:n,resourceId:r,type:"MUTATE",payload:t.value};for(let u of Array.from(e.subscriptions))try{u(a);}catch(d){this.logger.error("[QueryEngine] Error in subscription callback during sendInsertsForTree",{error:d,queryHash:e.hash,resource:n,resourceId:r,stepPath:e.queryStep.stepPath.join(".")});}e.trackedObjects.add(r),this.ensureObjectNode(r,n,e.hash).matchedQueries.add(e.hash);for(let u of Array.from(e.childQueries)){let d=this.queryNodes.get(u);if(!d||!d.relationName)continue;let l=d.relationName,p=d.queryStep.query.resource,y=t.value[l];if(!y)continue;let h=y.value;if(Array.isArray(h))for(let f of h)this.sendInsertsForTree(d,f,p);else h&&typeof h=="object"&&this.sendInsertsForTree(d,h,p);}}handleMutation(e,t){if(e.procedure==="INSERT"){if(this.objectNodes.has(e.resourceId))return;let n=x(t);if(!n)return;let r={id:e.resourceId,type:e.resource,matchedQueries:new Set,referencesObjects:new Map,referencedByObjects:new Map};this.objectNodes.set(e.resourceId,r);let a=this.getRelationalColumns(e.resource);for(let[o,{relationName:s,targetResource:u}]of Array.from(a)){let d=n[o];if(d){this.ensureObjectNode(d,u);let l=this.getInverseRelationName(e.resource,u,s);this.storeRelation(e.resourceId,d,s,l);}}let c=this.objectNodes.get(e.resourceId);this.getMatchingQueries(e,n).then(o=>{for(let s of o){let u=this.queryNodes.get(s);if(u){u.trackedObjects.add(e.resourceId),c&&c.matchedQueries.add(s);for(let d of Array.from(u.subscriptions))try{d(e);}catch(l){this.logger.error("[QueryEngine] Error in subscription callback during INSERT mutation",{error:l,queryHash:u.hash,resource:e.resource,resourceId:e.resourceId,stepPath:u.queryStep.stepPath.join(".")});}}}});return}if(e.procedure==="UPDATE"){let n=x(t);if(!n)return;let r=this.objectNodes.get(e.resourceId),a=new Set((r==null?void 0:r.matchedQueries)??[]);r||(r={id:e.resourceId,type:e.resource,matchedQueries:new Set,referencesObjects:new Map,referencedByObjects:new Map},this.objectNodes.set(e.resourceId,r)),this.updateRelationsFromMutation(e.resource,e.resourceId,n,e.payload),this.getMatchingQueries(e,n).then(c=>{let o=new Set(c),s=[],u=[],d=[];for(let p of c)a.has(p)?d.push(p):s.push(p);for(let p of Array.from(a))o.has(p)||u.push(p);for(let p of s){let y=this.queryNodes.get(p);y&&y.trackedObjects.add(e.resourceId);}for(let p of u){let y=this.queryNodes.get(p);y&&y.trackedObjects.delete(e.resourceId);}let l=this.objectNodes.get(e.resourceId);if(l){for(let p of s)l.matchedQueries.add(p);for(let p of u)l.matchedQueries.delete(p);}for(let p of [...u,...d]){let y=this.queryNodes.get(p);if(y)for(let h of Array.from(y.subscriptions))try{h(e);}catch(f){this.logger.error("[QueryEngine] Error in subscription callback during UPDATE mutation",{error:f,queryHash:y.hash,resource:e.resource,resourceId:e.resourceId,stepPath:y.queryStep.stepPath.join(".")});}}if(s.length>0)for(let p of s){let y=this.queryNodes.get(p);if(!y)continue;let h=this.buildIncludeFromChildQueries(p);this.get({resource:e.resource,where:{id:e.resourceId},include:Object.keys(h).length>0?h:void 0}).then(f=>{!f||f.length===0||this.sendInsertsForTree(y,f[0],e.resource);});}});return}}getMatchingQueries(e,t){let n=[];for(let r of Array.from(this.queryNodes.values()))r.queryStep.query.resource===e.resource&&n.push(r);return n.length===0?ae([]):Promise.all(n.map(async r=>{let a=r.queryStep.query.where,c=r.queryStep.query.resource,o=e.resourceId,s=this.objectNodes.get(o);if(!s)return {hash:r.hash,matches:false};if(r.relationName){let y=r.parentQuery?this.queryNodes.get(r.parentQuery):void 0,h=y==null?void 0:y.queryStep.query.resource,f=h?this.getInverseRelationName(h,c,r.relationName):void 0,T=f?s.referencesObjects.get(f):void 0;if(!T)return {hash:r.hash,matches:false};let g=this.objectNodes.get(T);return !g||!y||!g.matchedQueries.has(y.hash)?{hash:r.hash,matches:false}:{hash:r.hash,matches:true}}if(!a)return {hash:r.hash,matches:true};let u=C(a,c,this.schema),d=Object.keys(u).length>0;if(!d&&t!==void 0)return {hash:r.hash,matches:I(t,a)};let l=await this.storage.get({resource:c,where:{id:o},include:d?u:void 0});if(!l||l.length===0)return {hash:r.hash,matches:false};let p=x(l[0]);return p?{hash:r.hash,matches:I(p,a)}:{hash:r.hash,matches:false}})).then(r=>r.filter(a=>a.matches).map(a=>a.hash))}};var Ce=Se(ue());var F=zod.z.object({resource:zod.z.string(),where:zod.z.record(zod.z.string(),zod.z.any()).optional(),include:zod.z.record(zod.z.string(),zod.z.any()).optional(),lastSyncedAt:zod.z.string().optional(),limit:zod.z.coerce.number().optional(),sort:zod.z.array(zod.z.object({key:zod.z.string(),direction:zod.z.enum(["asc","desc"])})).optional()}),le=zod.z.record(zod.z.string(),zod.z.object({value:zod.z.any().nullable(),_meta:zod.z.object({timestamp:zod.z.string().optional().nullable()}).optional()})),ht=le.superRefine((i,e)=>{i.id&&e.addIssue({code:zod.z.ZodIssueCode.custom,message:"Payload cannot have an id"});}),Ae=zod.z.object({id:zod.z.string().optional(),type:zod.z.literal("MUTATE"),resource:zod.z.string(),resourceId:zod.z.string().optional()}),Q=Ae.extend({procedure:zod.z.string(),payload:zod.z.any().optional()}),K=Ae.extend({procedure:zod.z.enum(["INSERT","UPDATE"]),payload:ht});zod.z.union([K,Q]);var Ee=F.omit({resource:true}),de=Q.omit({id:true,type:true,resource:true,procedure:true}),ye=K.omit({id:true,type:true,resource:true,procedure:true});zod.z.union([ye,de]);var pe=i=>{if(i==null)return i;if(i==="null")return null;if(Array.isArray(i))return i.map(pe);if(typeof i=="object"&&i.constructor===Object){let e={};for(let[t,n]of Object.entries(i))e[t]=pe(n);return e}return i},Ne=i=>{let e=i.logger;return async t=>{var n;try{let r=typeof t.headers.getSetCookie=="function"?Object.fromEntries(t.headers):t.headers,a={headers:r,cookies:r.cookie?Ce.default.parse(r.cookie):{}},c=new URL(t.url),o=c.pathname.split("/"),s=c.searchParams,u=pe(gt__default.default.parse(s.toString())),d=await((n=i.contextProvider)==null?void 0:n.call(i,{transport:"HTTP",headers:a.headers,cookies:a.cookies,queryParams:u}))??{};if(t.method==="GET"){let l=o[o.length-1],{success:p,data:y,error:h}=Ee.safeParse(u);if(!p)return Response.json({message:"Invalid query",code:"INVALID_QUERY",details:h},{status:400});let f=await i.handleQuery({req:{...a,...y,type:"QUERY",resource:l,context:d,queryParams:u}});return !f||!f.data?Response.json({message:"Invalid resource",code:"INVALID_RESOURCE"},{status:400}):Response.json(f.data)}if(t.method==="POST")try{let l=o[o.length-1],p=o[o.length-2],y=t.body?await t.json():{},h;if(l==="insert"||l==="update"){let{success:T,data:g,error:m}=ye.safeParse(y);if(!T)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:m},{status:400});h=g;}else {let{success:T,data:g,error:m}=de.safeParse(y);if(!T)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:m},{status:400});h=g;}let f=await i.handleMutation({req:{...a,type:"MUTATE",resource:p,input:h.payload,context:d,resourceId:h.resourceId,procedure:l==="insert"||l==="update"?l.toUpperCase():l,queryParams:{}}});return Response.json(f)}catch(l){return e.error("Error parsing mutation from the client:",l),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}return Response.json({message:"Not found",code:"NOT_FOUND"},{status:404})}catch(r){return e.error("Unexpected error:",r),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}}};var qe=Se(ue());var N=zod.z.string(),Tt=F.extend({id:N,type:zod.z.literal("SUBSCRIBE")}),bt=F.extend({id:N,type:zod.z.literal("UNSUBSCRIBE")}),Rt=F.extend({id:N,type:zod.z.literal("QUERY")}),$e=K.extend({id:N}),vt=Q.extend({id:N}),St=zod.z.union([vt,$e]),Pe=zod.z.union([Tt,Rt,St,bt]),xt=zod.z.object({id:N,type:zod.z.literal("REJECT"),resource:zod.z.string(),message:zod.z.string().optional()}),wt=zod.z.object({id:N,type:zod.z.literal("REPLY"),data:zod.z.any()});zod.z.union([xt,wt,$e]);zod.z.object({resource:zod.z.string(),data:zod.z.array(le)});var Fe=i=>{let e={},t=i.logger;return (n,r)=>{var l;let a=p=>{n.send(JSON.stringify(p));},c=H(),o=new Map,s={headers:r.headers,cookies:typeof r.headers.cookie=="string"?qe.default.parse(r.headers.cookie):{}},u=gt.parse(r.url.split("?")[1]),d=(l=i.contextProvider)==null?void 0:l.call(i,{transport:"WEBSOCKET",headers:s.headers,cookies:s.cookies,queryParams:u});e[c]=n,t.info("Client connected:",c),n.on("message",async p=>{try{t.debug("Message received from the client:",p);let y=Pe.parse(JSON.parse(p.toString()));if(y.type==="SUBSCRIBE"||y.type==="QUERY"){let{type:h,id:f,...T}=y,g=h==="SUBSCRIBE",m=await i.handleQuery({req:{...s,...T,type:"QUERY",context:await d??{},queryParams:u},subscription:g?b=>{var v;!b.resourceId||!b.payload||!Object.keys(b.payload).length||(v=e[c])==null||v.send(JSON.stringify(b));}:void 0});if(!m||!m.data)throw new Error("Invalid resource");g&&m.unsubscribe&&o.set(j(T),m.unsubscribe),a({id:f,type:"REPLY",data:{resource:T.resource,data:(m.data??[]).map(b=>b.value)}});}else if(y.type==="UNSUBSCRIBE"){let{type:h,id:f,...T}=y,g=o.get(j(T));g&&(g(),o.delete(j(T)));}else if(y.type==="MUTATE"){let{resource:h}=y;t.debug("Received mutation from client:",y);try{let f=await i.handleMutation({req:{...s,type:"MUTATE",resource:h,input:y.payload,context:{messageId:y.id,...await d??{}},resourceId:y.resourceId,procedure:y.procedure,queryParams:u}});y.procedure&&y.procedure!=="INSERT"&&y.procedure!=="UPDATE"&&a({id:y.id,type:"REPLY",data:f});}catch(f){a({id:y.id,type:"REJECT",resource:h,message:f.message}),t.error("Error parsing mutation from the client:",f);}}}catch(y){t.error("Error handling message from the client:",y);}}),n.on("close",()=>{t.info("Connection closed",c),delete e[c];for(let p of Array.from(o.values()))p();});}};function ke(i){let e=`${i.protocol}://${i.hostname}${i.url}`,t=new Headers;return Object.entries(i.headers).forEach(([n,r])=>{r&&t.set(n,Array.isArray(r)?r.join(","):r);}),new Request(e,{method:i.method,headers:t,body:i.body&&i.method!=="GET"?JSON.stringify(i.body):void 0})}var Gr=(i,e,t)=>{i.ws(`${(t==null?void 0:t.basePath)??""}/ws`,Fe(e)),i.use(`${(t==null?void 0:t.basePath)??""}/`,(n,r)=>{Ne(e)(ke(n)).then(c=>c.json().then(o=>r.status(c.status).send(o)));});};var fe=class i{routes;hooksRegistry=new Map;constructor(e){this.routes=e.routes;for(let t of Object.values(e.routes)){let n=t;n.hooks&&this.hooksRegistry.set(n.resourceSchema.name,n.hooks);}}static create(e){return new i(e)}getHooks(e){return this.hooksRegistry.get(e)}},en=i=>fe.create({...i}),Lt=i=>({handler:e=>({inputValidator:i??zod.z.undefined(),handler:e})}),he=class i{resourceSchema;middlewares;customMutations;authorization;hooks;constructor(e,t,n,r){this.resourceSchema=e,this.middlewares=new Set,this.customMutations=t??{},this.authorization=n,this.hooks=r;}use(...e){for(let t of e)this.middlewares.add(t);return this}withMutations(e){return new i(this.resourceSchema,e({mutation:Lt}),this.authorization,this.hooks)}withHooks(e){return new i(this.resourceSchema,this.customMutations,this.authorization,e)}handleQuery=async({req:e,batcher:t})=>await this.wrapInMiddlewares(async n=>{let r={resource:n.resource,where:n.where,include:n.include,lastSyncedAt:n.lastSyncedAt,limit:n.limit,sort:n.sort},a=j(r);return {data:await t.rawFind({resource:n.resource,commonWhere:n.where,uniqueWhere:n.relationalWhere,include:n.include,limit:n.limit,sort:n.sort}),unsubscribe:void 0,queryHash:a}})(e);handleMutation=async({req:e,db:t,schema:n})=>await this.wrapInMiddlewares(async r=>{if(!r.procedure)throw new Error("Procedure is required for mutations");let a=this.customMutations[r.procedure];if(a){let c=a.inputValidator.parse(r.input);return r.input=c,a.handler({req:r,db:t})}else {if(r.procedure==="INSERT"||r.procedure==="UPDATE")return this.handleSet({req:r,db:t,operation:r.procedure,schema:n});throw new Error(`Unknown procedure: ${r.procedure}`)}})(e);getAuthorizationClause(e){var t,n;return (n=(t=this.authorization)==null?void 0:t.read)==null?void 0:n.call(t,{ctx:e.context})}handleSet=async({req:e,db:t,operation:n,schema:r})=>{if(!e.input)throw new Error("Payload is required");if(!e.resourceId)throw new Error("ResourceId is required");let a=await t.rawFindById(e.resource,e.resourceId);if(n==="INSERT"&&a)throw new Error("Resource already exists");if(n==="UPDATE"&&!a)throw new Error("Resource not found");return t.transaction(async({trx:c})=>{var d,l,p,y,h,f,T;let[o,s]=this.resourceSchema.mergeMutation("set",e.input,a);if(!s)throw new Error("Mutation rejected");if(n==="INSERT"){let g=await c.rawInsert(e.resource,e.resourceId,o,(d=e.context)==null?void 0:d.messageId,e.context),m=x(g);if(m.id=m.id??e.resourceId,(l=this.authorization)!=null&&l.insert){let b=this.authorization.insert({ctx:e.context,value:m});if(typeof b=="boolean"){if(!b)throw new Error("Not authorized")}else {let v=C(b,e.resource,r),S=Object.keys(v).length>0?await c.rawFindById(e.resource,e.resourceId,v):g,M=x(S);if(M.id=M.id??e.resourceId,!I(M,b))throw new Error("Not authorized")}}return {data:g,acceptedValues:s}}if((y=(p=this.authorization)==null?void 0:p.update)!=null&&y.preMutation){let g=x(a);g.id=g.id??e.resourceId;let m=this.authorization.update.preMutation({ctx:e.context,value:g});if(typeof m=="boolean"){if(!m)throw new Error("Not authorized")}else {let b=C(m,e.resource,r),v=Object.keys(b).length>0?await c.rawFindById(e.resource,e.resourceId,b):a,S=x(v);if(S.id=S.id??e.resourceId,!I(S,m))throw new Error("Not authorized")}}let u=await c.rawUpdate(e.resource,e.resourceId,o,(h=e.context)==null?void 0:h.messageId,e.context);if((T=(f=this.authorization)==null?void 0:f.update)!=null&&T.postMutation){let g=x(u);g.id=g.id??e.resourceId;let m=this.authorization.update.postMutation({ctx:e.context,value:g});if(typeof m=="boolean"){if(!m)throw new Error("Not authorized")}else {let b=C(m,e.resource,r),v=Object.keys(b).length>0?await c.rawFindById(e.resource,e.resourceId,b):u,S=x(v);if(S.id=S.id??e.resourceId,!I(S,m))throw new Error("Not authorized")}}return {data:u,acceptedValues:s}})};wrapInMiddlewares(e){return t=>Array.from(this.middlewares.values()).reduceRight((n,r)=>a=>r({req:a,next:n}),e)(t)}},me=class i{middlewares;constructor(e=[]){this.middlewares=e;}collectionRoute(e,t){return new he(e,void 0,t,void 0).use(...this.middlewares)}use(...e){return new i([...this.middlewares,...e])}static create(){return new i}},tn=me.create;var V=class{async insert(e,t){let n=new Date().toISOString();return x(await this.rawInsert(e.name,t.id,{value:Object.fromEntries(Object.entries(t).map(([r,a])=>[r,{value:a,_meta:{timestamp:n}}]))}))}async update(e,t,n){let r=new Date().toISOString(),{id:a,...c}=n;return x(await this.rawUpdate(e.name,t,{value:Object.fromEntries(Object.entries(c).map(([o,s])=>[o,{value:s,_meta:{timestamp:r}}]))}))}};var $t={postgres:{jsonObjectFrom:postgres.jsonObjectFrom,jsonArrayFrom:postgres.jsonArrayFrom},mysql:{jsonObjectFrom:mysql.jsonObjectFrom,jsonArrayFrom:mysql.jsonArrayFrom},sqlite:{jsonObjectFrom:sqlite.jsonObjectFrom,jsonArrayFrom:sqlite.jsonArrayFrom}};function $(i){var r,a,c;let e=(r=i.getExecutor)==null?void 0:r.call(i),t=e==null?void 0:e.adapter;if(!t)return "postgres";let n=((c=(a=t.constructor)==null?void 0:a.name)==null?void 0:c.toLowerCase())??"";return n.includes("postgres")?"postgres":n.includes("mysql")?"mysql":n.includes("sqlite")?"sqlite":"postgres"}function De(i){let e=$(i);return $t[e]}var Pt="42701";function _(i){var t;if(i.code===Pt)return true;let e=((t=i.message)==null?void 0:t.toLowerCase())||"";return e.includes("already exists")||e.includes("duplicate")||e.includes("already defined")}function B(i,e){return i.some(t=>t.name===e)}function qt(i,e){return (i==null?void 0:i.columns.some(t=>t.name===e))??false}function ge(i,e){let[t]=e.split(".");return B(i,t)}function ze(i,e,t,n=false){let r=i;return e.unique&&(r=r.unique()),e.nullable||(r=r.notNull()),e.primary&&(r=r.primaryKey()),e.default!==void 0&&(r=r.defaultTo(e.default)),!n&&e.references&&ge(t,e.references)&&(r=r.references(e.references)),r}function Ft(i,e,t,n,r){let a=[];for(let[c,o]of Object.entries(i.fields)){let s=e==null?void 0:e.columns.find(d=>d.name===c),u=o.getStorageFieldType();s?(s.dataType,u.type):(a.push({name:c,storageFieldType:u}),u.references&&!ge(t,u.references)&&n.push({tableName:r,columnName:c,references:u.references}));}return a}async function kt(i,e,t,n,r){if(t.length===0)return;let a=i.schema.createTable(e);for(let{name:c,storageFieldType:o}of t)a=a.addColumn(c,o.type,s=>ze(s,o,n));await a.execute().catch(c=>{if(!_(c))throw r==null||r.error("Error creating table",e,c),c});}async function Dt(i,e,t,n,r,a){for(let{name:c,storageFieldType:o}of t){let s=o.references?ge(n,o.references):false;await i.schema.alterTable(e).addColumn(c,o.type,u=>ze(u,o,n,!s)).execute().catch(u=>{if(!_(u))throw a==null||a.error("Error adding column",c,u),u}),o.references&&!s&&!r.some(u=>u.tableName===e&&u.columnName===c)&&r.push({tableName:e,columnName:c,references:o.references}),o.index&&await i.schema.createIndex(`${e}_${c}_index`).on(e).column(c).execute().catch(()=>{});}}async function zt(i,e,t,n,r,a){let c=`${e}_meta`,o=[];for(let[s,u]of Object.entries(t.fields)){let d=u.getStorageFieldType();qt(n,s)||o.push({name:s,storageFieldType:d});}if(!n&&o.length>0){let s=i.schema.createTable(c);for(let{name:u,storageFieldType:d}of o)s=s.addColumn(u,"varchar",l=>{let p=l;return d.primary&&(p=p.primaryKey(),B(r,e)&&(p=p.references(`${e}.${u}`))),p});await s.execute().catch(u=>{if(!_(u))throw a==null||a.error("Error creating meta table",c,u),u});}else if(n)for(let{name:s,storageFieldType:u}of o)await i.schema.alterTable(c).addColumn(s,"varchar",d=>{let l=d;return u.primary&&(l=l.primaryKey(),B(r,e)&&(l=l.references(`${e}.${s}`))),l}).execute().catch(d=>{if(!_(d))throw a==null||a.error("Error adding meta column",s,d),d});}async function Qe(i,e,t,n,r){let[a,c]=n.split("."),o=`${e}_${t}_fk`;try{await kysely.sql`
2
+ ALTER TABLE ${kysely.sql.raw(e)}
3
+ ADD CONSTRAINT ${kysely.sql.raw(o)}
4
+ FOREIGN KEY (${kysely.sql.raw(t)})
5
+ REFERENCES ${kysely.sql.raw(a)} (${kysely.sql.raw(c)})
6
+ `.execute(i);}catch(s){_(s)||r==null||r.warn("Could not add foreign key constraint",e,t,n,s);}}async function Qt(i,e,t,n){for(let{tableName:r,columnName:a,references:c}of e){let o=t.find(d=>d.name===r),s=o==null?void 0:o.columns.find(d=>d.name===a),[u]=c.split(".");o&&s&&B(t,u)&&await Qe(i,r,a,c,n);}}async function Kt(i,e,t,n){for(let[r,a]of Object.entries(e)){let c=`${r}_meta`,o=t.find(s=>s.name===c);if(o)for(let[s,u]of Object.entries(a.fields)){let d=u.getStorageFieldType(),l=o.columns.find(p=>p.name===s);d.primary&&l&&B(t,r)&&await Qe(i,c,s,`${r}.${s}`,n);}}}async function Ke(i,e,t){let n=await i.introspection.getTables(),r=[];for(let[c,o]of Object.entries(e)){let s=n.find(l=>l.name===c),u=n.find(l=>l.name===`${c}_meta`),d=Ft(o,s,n,r,c);if(s)for(let[l,p]of Object.entries(o.fields)){let y=s.columns.find(f=>f.name===l),h=p.getStorageFieldType();y&&y.dataType!==h.type&&(t==null||t.warn("Column type mismatch:",l,"expected to have type:",h.type,"but has type:",y.dataType));}!s&&d.length>0?await kt(i,c,d,n,t):s&&await Dt(i,c,d,n,r,t),await zt(i,c,o,u,n,t);}let a=await i.introspection.getTables();await Qt(i,r,a,t),await Kt(i,e,a,t);}function Y(i,e,t,n){if(!i)throw new Error("Schema not initialized");let r=i[e];if(!r)throw new Error("Resource not found");let a=n.$or,c=n.$and;return (a?t.or:t.and)(a?n.$or.map(o=>Y(i,e,t,o)):c?n.$and.map(o=>Y(i,e,t,o)):Object.entries(n).map(([o,s])=>{var u,d;if(r.fields[o])return (s==null?void 0:s.$eq)!==void 0?t(`${e}.${o}`,s.$eq===null?"is":"=",s.$eq):(s==null?void 0:s.$in)!==void 0?t(`${e}.${o}`,"in",s.$in):(s==null?void 0:s.$not)!==void 0?((u=s==null?void 0:s.$not)==null?void 0:u.$in)!==void 0?t(`${e}.${o}`,"not in",s.$not.$in):((d=s==null?void 0:s.$not)==null?void 0:d.$eq)!==void 0?t(`${e}.${o}`,s.$not.$eq===null?"is not":"!=",s.$not.$eq):t(`${e}.${o}`,s.$not===null?"is not":"!=",s.$not):(s==null?void 0:s.$gt)!==void 0?t(`${e}.${o}`,">",s.$gt):(s==null?void 0:s.$gte)!==void 0?t(`${e}.${o}`,">=",s.$gte):(s==null?void 0:s.$lt)!==void 0?t(`${e}.${o}`,"<",s.$lt):(s==null?void 0:s.$lte)!==void 0?t(`${e}.${o}`,"<=",s.$lte):t(`${e}.${o}`,s===null?"is":"=",s);if(r.relations[o]){let l=r.relations[o],p=l.entity.name;return l.type==="many"?t.exists(Te(i,p,t.selectFrom(p).select("id").whereRef(l.foreignColumn,"=",`${e}.id`),s)):Y(i,p,t,s)}return null}).filter(Boolean))}function X(i,e,t,n){let r=i[e];if(!r)throw new Error("Resource not found");if(!n)return t;if(n.$and){for(let a of n.$and)t=X(i,e,t,a);return t}else if(n.$or){for(let a of n.$or)t=X(i,e,t,a);return t}for(let[a,c]of Object.entries(n)){if(!r.relations[a])continue;let o=r.relations[a],s=o.entity.name,u=o.type==="one"?"id":o.foreignColumn,d=o.type==="one"?o.relationalColumn:"id";t=t.leftJoin(s,`${s}.${u}`,`${e}.${d}`),c instanceof Object&&!Array.isArray(c)&&c!==null&&(t=X(i,s,t,c));}return t}function Te(i,e,t,n){return !n||Object.keys(n).length===0?t:(t=X(i,e,t,n),t.where(r=>Y(i,e,r,n)))}function Vt(i,e,t,n,r){let a=$(r),c=e[t];if(a==="sqlite"&&(c!=null&&c.fields)){let o=Object.keys(c.fields),s=i.selectFrom(n);for(let u of o)s=s.select(`${n}.${u}`);return s}return i.selectFrom(n).selectAll(n)}function _t(i,e,t,n,r){let a=$(r),c=e[t];if(a==="sqlite"&&(c!=null&&c.fields)){let o=Object.keys(c.fields),s=i.selectFrom(n);for(let u of o)s=s.select(`${n}.${u}`);return s}return i.selectFrom(n).selectAll(n)}function ee(i,e,t,n,r,a){if(!n)return t;if(!i)throw new Error("Schema not initialized");let c=i[e];if(!c)throw new Error(`Resource not found: ${e}`);let{jsonObjectFrom:o,jsonArrayFrom:s}=r;for(let u of Object.keys(n)){if(!c.relations[u])throw new Error(`Relation ${u} not found in resource ${e}`);let d=c.relations[u],l=d.entity.name,p=n[u],y=d.type==="one"?"id":d.foreignColumn,h=d.type==="one"?d.relationalColumn:"id",f=d.type==="one"?o:s,T=typeof p=="object"&&p!==null;t=t.select(g=>{let m=`${l}_meta`,b=_t(g,i,l,l,a).whereRef(`${l}.${y}`,"=",`${e}.${h}`).select(v=>o(Vt(v,i,l,m,a).whereRef(`${m}.id`,"=",`${l}.id`)).as("_meta"));return T&&(b=ee(i,l,b,p,r,a)),f(b).as(u)});}return t}var be=class i extends V{db;dialectHelpers;schema;logger;server;mutationStack=[];constructor(e,t,n,r){super(),this.isKyselyLike(e)?this.db=e:this.db=new kysely.Kysely({dialect:new kysely.PostgresDialect({pool:e})}),this.dialectHelpers=De(this.db),this.schema=t,this.logger=n,this.server=r,this.rawInsert=this.rawInsert.bind(this),this.rawUpdate=this.rawUpdate.bind(this);}async init(e,t,n){this.schema=e,this.logger=t,this.server=n,await Ke(this.db,e,t);}selectMetaColumns(e,t,n){var c;let r=$(this.db),a=(c=this.schema)==null?void 0:c[t];if(r==="sqlite"&&(a!=null&&a.fields)){let o=Object.keys(a.fields),s=e.selectFrom(n);for(let u of o)s=s.select(`${n}.${u}`);return s}return e.selectFrom(n).selectAll(n)}async rawFindById(e,t,n){if(!this.schema)throw new Error("Schema not initialized");let r=`${e}_meta`,a=await this.db.selectFrom(e).where("id","=",t).selectAll(e).select(s=>this.dialectHelpers.jsonObjectFrom(this.selectMetaColumns(s,e,r).whereRef(`${r}.id`,"=",`${e}.id`)).as("_meta"));a=ee(this.schema,e,a,n,this.dialectHelpers,this.db);let c=await a.executeTakeFirst();if(!c)return;let o=this.parseRelationalJsonStrings(c,e);return this.convertToMaterializedLiveType(o)}async findOne(e,t,n){let r=await this.rawFindById(e.name,t,n==null?void 0:n.include);if(r)return x(r)}async get(e){if(!this.schema)throw new Error("Schema not initialized");let{resource:t,where:n,include:r,limit:a,sort:c}=e,o=`${t}_meta`,s=this.db.selectFrom(t).selectAll(t).select(d=>this.dialectHelpers.jsonObjectFrom(this.selectMetaColumns(d,t,o).whereRef(`${o}.id`,"=",`${t}.id`)).as("_meta"));s=Te(this.schema,t,s,n),s=ee(this.schema,t,s,r,this.dialectHelpers,this.db),a!==void 0&&(s=s.limit(a)),c!==void 0&&c.forEach(d=>{s=s.orderBy(d.key,d.direction);});let u=await s.execute();return u.length===0?[]:u.map(d=>{let l=this.parseRelationalJsonStrings(d,t);return this.convertToMaterializedLiveType(l)})}async find(e,t){return (await this.get({resource:e.name,where:t==null?void 0:t.where,include:t==null?void 0:t.include,limit:t==null?void 0:t.limit,sort:t==null?void 0:t.sort})).map(r=>x(r))}async rawInsert(e,t,n,r,a){var l,p,y;let c=(p=(l=this.server)==null?void 0:l.router)==null?void 0:p.getHooks(e),o=n;if(c!=null&&c.beforeInsert){let h=await c.beforeInsert({ctx:a,value:o,db:this});h&&(o=h);}let s={},u={};for(let[h,f]of Object.entries(o.value)){let T=(y=f._meta)==null?void 0:y.timestamp;T&&(s[h]=f.value,u[h]=T);}await this.db.insertInto(e).values({...s,id:t}).execute().then(()=>{this.db.insertInto(`${e}_meta`).values({...u,id:t}).execute();});let d=this.buildMutation(e,t,"INSERT",o,r);return d&&this.trackMutation(d,o),c!=null&&c.afterInsert&&await c.afterInsert({ctx:a,value:o,db:this}),o}async rawUpdate(e,t,n,r,a){var p,y,h;let c=(y=(p=this.server)==null?void 0:p.router)==null?void 0:y.getHooks(e),o;(c!=null&&c.beforeUpdate||c!=null&&c.afterUpdate)&&(o=await this.rawFindById(e,t));let s=n;if(c!=null&&c.beforeUpdate){let f=await c.beforeUpdate({ctx:a,value:s,previousValue:o,db:this});f&&(s=f);}let u={},d={};for(let[f,T]of Object.entries(s.value)){let g=(h=T._meta)==null?void 0:h.timestamp;g&&(u[f]=T.value,d[f]=g);}await Promise.all([this.db.updateTable(e).set(u).where("id","=",t).execute(),this.db.insertInto(`${e}_meta`).values({...d,id:t}).onConflict(f=>f.column("id").doUpdateSet(d)).execute()]);let l=this.buildMutation(e,t,"UPDATE",s,r);if(l){let f=await this.rawFindById(e,t);f&&this.trackMutation(l,f);}if(c!=null&&c.afterUpdate){let f=await this.rawFindById(e,t);f&&await c.afterUpdate({ctx:a,value:f,previousValue:o,db:this});}return s}async transaction(e){if(!this.schema)throw new Error("Schema not initialized");if(this.db.isTransaction){let a=Math.random().toString(36).substring(2,15),c=this.mutationStack,o=[];this.mutationStack=o;let s=await this.db.savepoint(a).execute(),u=false,d=false;try{return await e({trx:this,commit:async()=>{await s.releaseSavepoint(a).execute(),u=!0,c.push(...o);},rollback:async()=>{await s.rollbackToSavepoint(a).execute(),d=!0,o.length=0;}}).then(l=>s.isCommitted||s.isRolledBack||u||d?l:s.releaseSavepoint(a).execute().then(()=>(c.push(...o),l)))}catch(l){throw d||await s.rollbackToSavepoint(a).execute().catch(()=>{}),o.length=0,l}finally{this.mutationStack=c;}}let t=[],n=this.mutationStack;this.mutationStack=t;let r=await this.db.startTransaction().execute();try{let a=new i(r,this.schema,this.logger,this.server);return a.mutationStack=t,await e({trx:a,commit:async()=>{await r.commit().execute(),this.notifyMutations(t);},rollback:async()=>{await r.rollback().execute(),t.length=0;}}).then(c=>r.isCommitted||r.isRolledBack?c:r.commit().execute().then(()=>(this.notifyMutations(t),c)))}catch(a){throw await r.rollback().execute(),t.length=0,a}finally{this.mutationStack=n;}}get internalDB(){return this.db}isRelationalField(e,t){var r;if(!this.schema)return false;let n=this.schema[e];return !!((r=n==null?void 0:n.relations)!=null&&r[t])}parseRelationalJsonStrings(e,t){var a,c;if($(this.db)!=="sqlite"||typeof e!="object"||e===null||e instanceof Date)return e;if(Array.isArray(e))return e.map(o=>this.parseRelationalJsonStrings(o,t));let r={};for(let[o,s]of Object.entries(e))if(o==="_meta"&&typeof s=="string")if(s.startsWith("{")&&s.endsWith("}")||s.startsWith("[")&&s.endsWith("]"))try{r[o]=JSON.parse(s);}catch{r[o]=s;}else r[o]=s;else if(this.isRelationalField(t,o))if(typeof s=="string")if(s.startsWith("{")&&s.endsWith("}")||s.startsWith("[")&&s.endsWith("]"))try{let u=JSON.parse(s);if(this.schema){let d=this.schema[t],l=(a=d==null?void 0:d.relations)==null?void 0:a[o];if(l){let p=l.entity.name;r[o]=this.parseRelationalJsonStrings(u,p);}else r[o]=u;}else r[o]=u;}catch{r[o]=s;}else r[o]=s;else if(typeof s=="object"&&s!==null&&!Array.isArray(s))if(this.schema){let u=this.schema[t],d=(c=u==null?void 0:u.relations)==null?void 0:c[o];if(d){let l=d.entity.name;r[o]=this.parseRelationalJsonStrings(s,l);}else r[o]=s;}else r[o]=s;else Array.isArray(s)?r[o]=s.map(u=>{var d,l;if(typeof u=="string")try{let p=JSON.parse(u);if(this.schema){let y=this.schema[t],h=(d=y==null?void 0:y.relations)==null?void 0:d[o];if(h){let f=h.entity.name;return this.parseRelationalJsonStrings(p,f)}}return p}catch{return u}if(typeof u=="object"&&u!==null&&this.schema){let p=this.schema[t],y=(l=p==null?void 0:p.relations)==null?void 0:l[o];if(y){let h=y.entity.name;return this.parseRelationalJsonStrings(u,h)}}return u}):r[o]=s;else r[o]=s;return r}convertToMaterializedLiveType(e){return {value:Object.entries(e).reduce((t,[n,r])=>{var a,c,o;return n==="_meta"||(n==="id"?t[n]={value:r}:Array.isArray(r)?t[n]={value:r.map(s=>this.convertToMaterializedLiveType(s)),_meta:{timestamp:(a=e==null?void 0:e._meta)==null?void 0:a[n]}}:typeof r=="object"&&r!==null&&!(r instanceof Date)?t[n]={...this.convertToMaterializedLiveType(r),_meta:{timestamp:(c=e==null?void 0:e._meta)==null?void 0:c[n]}}:t[n]={value:r,_meta:{timestamp:(o=e==null?void 0:e._meta)==null?void 0:o[n]}}),t},{})}}isKyselyLike(e){if(e instanceof kysely.Kysely)return true;if(!e||typeof e!="object")return false;let t=e,n=typeof t.selectFrom=="function",r=typeof t.startTransaction=="function",a=typeof t.savepoint=="function",c=typeof t.isTransaction=="boolean"||typeof t.isTransaction=="function";return n&&r||a&&c}buildMutation(e,t,n,r,a){var o;let c={};for(let[s,u]of Object.entries(r.value)){if(s==="id")continue;let d=(o=u._meta)==null?void 0:o.timestamp;d&&(c[s]={value:u.value,_meta:{timestamp:d}});}return Object.keys(c).length===0?null:{id:a??H(),type:"MUTATE",resource:e,resourceId:t,procedure:n,payload:c}}trackMutation(e,t){this.db.isTransaction?this.mutationStack.push({mutation:e,entityData:t}):this.notifyMutations([e],t);}notifyMutations(e,t){if(this.server)if(t!==void 0){let n=e;for(let r of n)this.server.notifySubscribers(r,t);}else {let n=e;for(let{mutation:r,entityData:a}of n)this.server.notifySubscribers(r,a);}}};var Re=class i{router;storage;schema;middlewares=new Set;logger;contextProvider;queryEngine;constructor(e){var t;this.router=e.router,this.storage=e.storage,this.schema=e.schema,this.logger=Le({level:e.logLevel??L.INFO}),(t=e.middlewares)==null||t.forEach(n=>{this.middlewares.add(n);}),this.storage.init(this.schema,this.logger,this),this.contextProvider=e.contextProvider,this.queryEngine=new J({router:{get:async(n,r)=>{var l;let{headers:a,cookies:c,queryParams:o,context:s}=(r==null?void 0:r.context)??{};if(!(r!=null&&r.batcher))throw new Error("Batcher is required");let u={...n,type:"QUERY",headers:a,cookies:c,queryParams:o,context:s},d=await((l=this.router.routes[n.resource])==null?void 0:l.handleQuery({req:u,batcher:r.batcher}));return (d==null?void 0:d.data)??[]},incrementQueryStep:(n,r={})=>{var o;let a=(o=this.router.routes[n.query.resource])==null?void 0:o.getAuthorizationClause({...n.query,type:"QUERY",headers:r.headers,cookies:r.cookies,queryParams:r.queryParams,context:r.context});if(typeof a=="boolean"&&!a)throw new Error("Not authorized");let c=q(n.query.where,typeof a=="object"?a:void 0);return {...n,query:{...n.query,where:c}}}},storage:this.storage,schema:this.schema,logger:this.logger});}static create(e){return new i(e)}handleQuery(e){return this.wrapInMiddlewares(async t=>{let{headers:n,cookies:r,queryParams:a,context:c,...o}=t,s={headers:n,cookies:r,queryParams:a,context:c},u=e.subscription?this.queryEngine.subscribe(o,l=>{var p;(p=e.subscription)==null||p.call(e,l);},s):void 0;return {data:await this.queryEngine.get(o,{context:s}),unsubscribe:u}})(e.req)}async handleMutation(e){return await this.wrapInMiddlewares(async n=>{let r=this.router.routes[n.resource];if(!r)throw new Error("Invalid resource");return r.handleMutation({req:n,db:this.storage,schema:this.schema})})(e.req)}use(e){return this.middlewares.add(e),this}context(e){return this.contextProvider=e,this}notifySubscribers(e,t){this.queryEngine.handleMutation(e,t);}wrapInMiddlewares(e){return t=>Array.from(this.middlewares.values()).reduceRight((n,r)=>a=>r({req:a,next:n}),e)(t)}},jn=Re.create;exports.Route=he;exports.RouteFactory=me;exports.Router=fe;exports.SQLStorage=be;exports.Server=Re;exports.Storage=V;exports.expressAdapter=Gr;exports.routeFactory=tn;exports.router=en;exports.server=jn;
package/dist/server.d.cts CHANGED
@@ -48,10 +48,12 @@ type PromiseOrSync<T> = T | Promise<T>;
48
48
  type RouteRecord = Record<string, AnyRoute>;
49
49
  declare class Router<TRoutes extends RouteRecord> {
50
50
  readonly routes: TRoutes;
51
+ private readonly hooksRegistry;
51
52
  private constructor();
52
53
  static create<TRoutes extends RouteRecord>(opts: {
53
54
  routes: TRoutes;
54
55
  }): Router<TRoutes>;
56
+ getHooks(resourceName: string): Hooks<any> | undefined;
55
57
  }
56
58
  declare const router: <TSchema extends Schema<any>, TRoutes extends Record<keyof TSchema, Route<any, any, any>>>(opts: {
57
59
  schema: TSchema;
@@ -92,16 +94,46 @@ type Authorization<TShape extends LiveObjectAny> = {
92
94
  postMutation?: MutationAuthorizationHandler<TShape>;
93
95
  };
94
96
  };
97
+ type BeforeInsertHook<TShape extends LiveObjectAny> = (opts: {
98
+ ctx?: Record<string, any>;
99
+ value: MaterializedLiveType<TShape>;
100
+ db: Storage;
101
+ }) => Promise<MaterializedLiveType<TShape> | void> | MaterializedLiveType<TShape> | void;
102
+ type AfterInsertHook<TShape extends LiveObjectAny> = (opts: {
103
+ ctx?: Record<string, any>;
104
+ value: MaterializedLiveType<TShape>;
105
+ db: Storage;
106
+ }) => Promise<void> | void;
107
+ type BeforeUpdateHook<TShape extends LiveObjectAny> = (opts: {
108
+ ctx?: Record<string, any>;
109
+ value: MaterializedLiveType<TShape>;
110
+ previousValue?: MaterializedLiveType<TShape>;
111
+ db: Storage;
112
+ }) => Promise<MaterializedLiveType<TShape> | void> | MaterializedLiveType<TShape> | void;
113
+ type AfterUpdateHook<TShape extends LiveObjectAny> = (opts: {
114
+ ctx?: Record<string, any>;
115
+ value: MaterializedLiveType<TShape>;
116
+ previousValue?: MaterializedLiveType<TShape>;
117
+ db: Storage;
118
+ }) => Promise<void> | void;
119
+ type Hooks<TShape extends LiveObjectAny> = {
120
+ beforeInsert?: BeforeInsertHook<TShape>;
121
+ afterInsert?: AfterInsertHook<TShape>;
122
+ beforeUpdate?: BeforeUpdateHook<TShape>;
123
+ afterUpdate?: AfterUpdateHook<TShape>;
124
+ };
95
125
  declare class Route<TResourceSchema extends LiveObjectAny, TMiddleware extends Middleware<any>, TCustomMutations extends Record<string, Mutation<any, any>>> {
96
126
  readonly resourceSchema: TResourceSchema;
97
127
  readonly middlewares: Set<TMiddleware>;
98
128
  readonly customMutations: TCustomMutations;
99
129
  readonly authorization?: Authorization<TResourceSchema>;
100
- constructor(resourceSchema: TResourceSchema, customMutations?: TCustomMutations, authorization?: Authorization<TResourceSchema>);
130
+ readonly hooks?: Hooks<TResourceSchema>;
131
+ constructor(resourceSchema: TResourceSchema, customMutations?: TCustomMutations, authorization?: Authorization<TResourceSchema>, hooks?: Hooks<TResourceSchema>);
101
132
  use(...middlewares: TMiddleware[]): this;
102
133
  withMutations<T extends Record<string, Mutation<any, any>>>(mutationFactory: (opts: {
103
134
  mutation: typeof mutationCreator;
104
135
  }) => T): Route<TResourceSchema, TMiddleware, T>;
136
+ withHooks(hooks: Hooks<TResourceSchema>): Route<TResourceSchema, TMiddleware, TCustomMutations>;
105
137
  getAuthorizationClause(req: QueryRequest): WhereClause<TResourceSchema> | undefined | boolean;
106
138
  private handleSet;
107
139
  private wrapInMiddlewares;
@@ -162,7 +194,7 @@ declare abstract class Storage implements DataSource {
162
194
  }[];
163
195
  }): Promise<InferLiveObject<T>[]>;
164
196
  insert<T extends LiveObjectAny>(resource: T, value: Simplify<InferInsert<T>>): Promise<InferLiveObject<T>>;
165
- update<T extends LiveObjectAny>(resource: T, resourceId: string, value: InferUpdate<T>): Promise<InferLiveObject<T>>;
197
+ update<T extends LiveObjectAny>(resource: T, resourceId: string, value: InferUpdate<T>): Promise<Partial<InferLiveObject<T>>>;
166
198
  abstract transaction<T>(fn: (opts: {
167
199
  trx: Storage;
168
200
  commit: () => Promise<void>;
@@ -174,11 +206,13 @@ declare abstract class Storage implements DataSource {
174
206
 
175
207
  declare class SQLStorage extends Storage {
176
208
  private readonly db;
209
+ private readonly dialectHelpers;
177
210
  private schema?;
178
211
  private logger?;
179
212
  private server?;
180
213
  private mutationStack;
181
214
  constructor(pool: PostgresPool);
215
+ private selectMetaColumns;
182
216
  findOne<T extends LiveObjectAny>(resource: T, id: string, options?: {
183
217
  include?: IncludeClause<T>;
184
218
  }): Promise<InferLiveObject<T> | undefined>;
@@ -210,6 +244,8 @@ declare class SQLStorage extends Storage {
210
244
  [x: string]: any;
211
245
  };
212
246
  }>;
247
+ private isRelationalField;
248
+ private parseRelationalJsonStrings;
213
249
  private convertToMaterializedLiveType;
214
250
  private isKyselyLike;
215
251
  private buildMutation;
@@ -275,4 +311,4 @@ declare class Server<TRouter extends AnyRouter> {
275
311
  }
276
312
  declare const server: typeof Server.create;
277
313
 
278
- export { type AnyRoute, type AnyRouter, type Authorization, type BaseRequest, type ContextProvider, type Middleware, type Mutation, type MutationAuthorizationHandler, type MutationRequest, type MutationResult, type NextFunction, type QueryRequest, type QueryResult, type ReadAuthorizationHandler, type Request, Route, RouteFactory, type RouteRecord, Router, SQLStorage, Server, Storage, expressAdapter, routeFactory, router, server };
314
+ export { type AfterInsertHook, type AfterUpdateHook, type AnyRoute, type AnyRouter, type Authorization, type BaseRequest, type BeforeInsertHook, type BeforeUpdateHook, type ContextProvider, type Hooks, type Middleware, type Mutation, type MutationAuthorizationHandler, type MutationRequest, type MutationResult, type NextFunction, type QueryRequest, type QueryResult, type ReadAuthorizationHandler, type Request, Route, RouteFactory, type RouteRecord, Router, SQLStorage, Server, Storage, expressAdapter, routeFactory, router, server };
package/dist/server.d.ts CHANGED
@@ -48,10 +48,12 @@ type PromiseOrSync<T> = T | Promise<T>;
48
48
  type RouteRecord = Record<string, AnyRoute>;
49
49
  declare class Router<TRoutes extends RouteRecord> {
50
50
  readonly routes: TRoutes;
51
+ private readonly hooksRegistry;
51
52
  private constructor();
52
53
  static create<TRoutes extends RouteRecord>(opts: {
53
54
  routes: TRoutes;
54
55
  }): Router<TRoutes>;
56
+ getHooks(resourceName: string): Hooks<any> | undefined;
55
57
  }
56
58
  declare const router: <TSchema extends Schema<any>, TRoutes extends Record<keyof TSchema, Route<any, any, any>>>(opts: {
57
59
  schema: TSchema;
@@ -92,16 +94,46 @@ type Authorization<TShape extends LiveObjectAny> = {
92
94
  postMutation?: MutationAuthorizationHandler<TShape>;
93
95
  };
94
96
  };
97
+ type BeforeInsertHook<TShape extends LiveObjectAny> = (opts: {
98
+ ctx?: Record<string, any>;
99
+ value: MaterializedLiveType<TShape>;
100
+ db: Storage;
101
+ }) => Promise<MaterializedLiveType<TShape> | void> | MaterializedLiveType<TShape> | void;
102
+ type AfterInsertHook<TShape extends LiveObjectAny> = (opts: {
103
+ ctx?: Record<string, any>;
104
+ value: MaterializedLiveType<TShape>;
105
+ db: Storage;
106
+ }) => Promise<void> | void;
107
+ type BeforeUpdateHook<TShape extends LiveObjectAny> = (opts: {
108
+ ctx?: Record<string, any>;
109
+ value: MaterializedLiveType<TShape>;
110
+ previousValue?: MaterializedLiveType<TShape>;
111
+ db: Storage;
112
+ }) => Promise<MaterializedLiveType<TShape> | void> | MaterializedLiveType<TShape> | void;
113
+ type AfterUpdateHook<TShape extends LiveObjectAny> = (opts: {
114
+ ctx?: Record<string, any>;
115
+ value: MaterializedLiveType<TShape>;
116
+ previousValue?: MaterializedLiveType<TShape>;
117
+ db: Storage;
118
+ }) => Promise<void> | void;
119
+ type Hooks<TShape extends LiveObjectAny> = {
120
+ beforeInsert?: BeforeInsertHook<TShape>;
121
+ afterInsert?: AfterInsertHook<TShape>;
122
+ beforeUpdate?: BeforeUpdateHook<TShape>;
123
+ afterUpdate?: AfterUpdateHook<TShape>;
124
+ };
95
125
  declare class Route<TResourceSchema extends LiveObjectAny, TMiddleware extends Middleware<any>, TCustomMutations extends Record<string, Mutation<any, any>>> {
96
126
  readonly resourceSchema: TResourceSchema;
97
127
  readonly middlewares: Set<TMiddleware>;
98
128
  readonly customMutations: TCustomMutations;
99
129
  readonly authorization?: Authorization<TResourceSchema>;
100
- constructor(resourceSchema: TResourceSchema, customMutations?: TCustomMutations, authorization?: Authorization<TResourceSchema>);
130
+ readonly hooks?: Hooks<TResourceSchema>;
131
+ constructor(resourceSchema: TResourceSchema, customMutations?: TCustomMutations, authorization?: Authorization<TResourceSchema>, hooks?: Hooks<TResourceSchema>);
101
132
  use(...middlewares: TMiddleware[]): this;
102
133
  withMutations<T extends Record<string, Mutation<any, any>>>(mutationFactory: (opts: {
103
134
  mutation: typeof mutationCreator;
104
135
  }) => T): Route<TResourceSchema, TMiddleware, T>;
136
+ withHooks(hooks: Hooks<TResourceSchema>): Route<TResourceSchema, TMiddleware, TCustomMutations>;
105
137
  getAuthorizationClause(req: QueryRequest): WhereClause<TResourceSchema> | undefined | boolean;
106
138
  private handleSet;
107
139
  private wrapInMiddlewares;
@@ -162,7 +194,7 @@ declare abstract class Storage implements DataSource {
162
194
  }[];
163
195
  }): Promise<InferLiveObject<T>[]>;
164
196
  insert<T extends LiveObjectAny>(resource: T, value: Simplify<InferInsert<T>>): Promise<InferLiveObject<T>>;
165
- update<T extends LiveObjectAny>(resource: T, resourceId: string, value: InferUpdate<T>): Promise<InferLiveObject<T>>;
197
+ update<T extends LiveObjectAny>(resource: T, resourceId: string, value: InferUpdate<T>): Promise<Partial<InferLiveObject<T>>>;
166
198
  abstract transaction<T>(fn: (opts: {
167
199
  trx: Storage;
168
200
  commit: () => Promise<void>;
@@ -174,11 +206,13 @@ declare abstract class Storage implements DataSource {
174
206
 
175
207
  declare class SQLStorage extends Storage {
176
208
  private readonly db;
209
+ private readonly dialectHelpers;
177
210
  private schema?;
178
211
  private logger?;
179
212
  private server?;
180
213
  private mutationStack;
181
214
  constructor(pool: PostgresPool);
215
+ private selectMetaColumns;
182
216
  findOne<T extends LiveObjectAny>(resource: T, id: string, options?: {
183
217
  include?: IncludeClause<T>;
184
218
  }): Promise<InferLiveObject<T> | undefined>;
@@ -210,6 +244,8 @@ declare class SQLStorage extends Storage {
210
244
  [x: string]: any;
211
245
  };
212
246
  }>;
247
+ private isRelationalField;
248
+ private parseRelationalJsonStrings;
213
249
  private convertToMaterializedLiveType;
214
250
  private isKyselyLike;
215
251
  private buildMutation;
@@ -275,4 +311,4 @@ declare class Server<TRouter extends AnyRouter> {
275
311
  }
276
312
  declare const server: typeof Server.create;
277
313
 
278
- export { type AnyRoute, type AnyRouter, type Authorization, type BaseRequest, type ContextProvider, type Middleware, type Mutation, type MutationAuthorizationHandler, type MutationRequest, type MutationResult, type NextFunction, type QueryRequest, type QueryResult, type ReadAuthorizationHandler, type Request, Route, RouteFactory, type RouteRecord, Router, SQLStorage, Server, Storage, expressAdapter, routeFactory, router, server };
314
+ export { type AfterInsertHook, type AfterUpdateHook, type AnyRoute, type AnyRouter, type Authorization, type BaseRequest, type BeforeInsertHook, type BeforeUpdateHook, type ContextProvider, type Hooks, type Middleware, type Mutation, type MutationAuthorizationHandler, type MutationRequest, type MutationResult, type NextFunction, type QueryRequest, type QueryResult, type ReadAuthorizationHandler, type Request, Route, RouteFactory, type RouteRecord, Router, SQLStorage, Server, Storage, expressAdapter, routeFactory, router, server };
package/dist/server.js CHANGED
@@ -1,2 +1,6 @@
1
- import {a,b,v,t,w,x,z as z$2,y}from'./chunk-IT5UC7TA.js';import k from'crypto';import Ge,{parse}from'qs';import {z as z$1}from'zod';import {Kysely,PostgresDialect}from'kysely';import {jsonObjectFrom,jsonArrayFrom}from'kysely/helpers/postgres';var Z=a(W=>{Object.defineProperty(W,"__esModule",{value:true});W.parse=Ue;W.serialize=We;var Qe=/^[\u0021-\u003A\u003C\u003E-\u007E]+$/,ze=/^[\u0021-\u003A\u003C-\u007E]*$/,ke=/^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i,qe=/^[\u0020-\u003A\u003D-\u007E]*$/,De=Object.prototype.toString,Be=(()=>{let a=function(){};return a.prototype=Object.create(null),a})();function Ue(a,e){let t=new Be,n=a.length;if(n<2)return t;let r=(e==null?void 0:e.decode)||Fe,i=0;do{let c=a.indexOf("=",i);if(c===-1)break;let o=a.indexOf(";",i),s=o===-1?n:o;if(c>s){i=a.lastIndexOf(";",c-1)+1;continue}let l=ye(a,i,c),y=pe(a,c,l),u=a.slice(l,y);if(t[u]===void 0){let h=ye(a,c+1,s),d=pe(a,s,h),p=r(a.slice(h,d));t[u]=p;}i=s+1;}while(i<n);return t}function ye(a,e,t){do{let n=a.charCodeAt(e);if(n!==32&&n!==9)return e}while(++e<t);return t}function pe(a,e,t){for(;e>t;){let n=a.charCodeAt(--e);if(n!==32&&n!==9)return e+1}return t}function We(a,e,t){let n=(t==null?void 0:t.encode)||encodeURIComponent;if(!Qe.test(a))throw new TypeError(`argument name is invalid: ${a}`);let r=n(e);if(!ze.test(r))throw new TypeError(`argument val is invalid: ${e}`);let i=a+"="+r;if(!t)return i;if(t.maxAge!==void 0){if(!Number.isInteger(t.maxAge))throw new TypeError(`option maxAge is invalid: ${t.maxAge}`);i+="; Max-Age="+t.maxAge;}if(t.domain){if(!ke.test(t.domain))throw new TypeError(`option domain is invalid: ${t.domain}`);i+="; Domain="+t.domain;}if(t.path){if(!qe.test(t.path))throw new TypeError(`option path is invalid: ${t.path}`);i+="; Path="+t.path;}if(t.expires){if(!_e(t.expires)||!Number.isFinite(t.expires.valueOf()))throw new TypeError(`option expires is invalid: ${t.expires}`);i+="; Expires="+t.expires.toUTCString();}if(t.httpOnly&&(i+="; HttpOnly"),t.secure&&(i+="; Secure"),t.partitioned&&(i+="; Partitioned"),t.priority)switch(typeof t.priority=="string"?t.priority.toLowerCase():void 0){case "low":i+="; Priority=Low";break;case "medium":i+="; Priority=Medium";break;case "high":i+="; Priority=High";break;default:throw new TypeError(`option priority is invalid: ${t.priority}`)}if(t.sameSite)switch(typeof t.sameSite=="string"?t.sameSite.toLowerCase():t.sameSite){case true:case "strict":i+="; SameSite=Strict";break;case "lax":i+="; SameSite=Lax";break;case "none":i+="; SameSite=None";break;default:throw new TypeError(`option sameSite is invalid: ${t.sameSite}`)}return i}function Fe(a){if(a.indexOf("%")===-1)return a;try{return decodeURIComponent(a)}catch{return a}}function _e(a){return De.call(a)==="[object Date]"}});var de="0123456789ABCDEFGHJKMNPQRSTVWXYZ",$=32;var Ae=16,le=10,ue=0xffffffffffff;var E;(function(a){a.Base32IncorrectEncoding="B32_ENC_INVALID",a.DecodeTimeInvalidCharacter="DEC_TIME_CHAR",a.DecodeTimeValueMalformed="DEC_TIME_MALFORMED",a.EncodeTimeNegative="ENC_TIME_NEG",a.EncodeTimeSizeExceeded="ENC_TIME_SIZE_EXCEED",a.EncodeTimeValueMalformed="ENC_TIME_MALFORMED",a.PRNGDetectFailure="PRNG_DETECT",a.ULIDInvalid="ULID_INVALID",a.Unexpected="UNEXPECTED",a.UUIDInvalid="UUID_INVALID";})(E||(E={}));var A=class extends Error{constructor(e,t){super(`${t} (${e})`),this.name="ULIDError",this.code=e;}};function Oe(a){let e=Math.floor(a()*$);return e===$&&(e=$-1),de.charAt(e)}function Ne(a){var n;let e=Pe(),t=e&&(e.crypto||e.msCrypto)||(typeof k<"u"?k:null);if(typeof(t==null?void 0:t.getRandomValues)=="function")return ()=>{let r=new Uint8Array(1);return t.getRandomValues(r),r[0]/255};if(typeof(t==null?void 0:t.randomBytes)=="function")return ()=>t.randomBytes(1).readUInt8()/255;if((n=k)!=null&&n.randomBytes)return ()=>k.randomBytes(1).readUInt8()/255;throw new A(E.PRNGDetectFailure,"Failed to find a reliable PRNG")}function Pe(){return Ce()?self:typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:null}function Le(a,e){let t="";for(;a>0;a--)t=Oe(e)+t;return t}function $e(a,e=le){if(isNaN(a))throw new A(E.EncodeTimeValueMalformed,`Time must be a number: ${a}`);if(a>ue)throw new A(E.EncodeTimeSizeExceeded,`Cannot encode a time larger than ${ue}: ${a}`);if(a<0)throw new A(E.EncodeTimeNegative,`Time must be positive: ${a}`);if(Number.isInteger(a)===false)throw new A(E.EncodeTimeValueMalformed,`Time must be an integer: ${a}`);let t,n="";for(let r=e;r>0;r--)t=a%$,n=de.charAt(t)+n,a=(a-t)/$;return n}function Ce(){return typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope}function he(a,e){let t=Ne(),n=Date.now();return $e(n,le)+Le(Ae,t)}var D=()=>he().toLowerCase(),q=a=>({then(e,t){try{if(e){let n=e(a);return n instanceof Promise?n:q(n)}return q(a)}catch(n){if(t){let r=t(n);return r instanceof Promise?r:q(r)}throw n}}}),H=a=>a instanceof Promise?a:q(a);var P=(...a)=>{let e=a.filter(t=>!!t);return e.length===0?{}:e.length===1?e[0]:{$and:e}};var B=class{storage;queue=new Map;scheduled=false;constructor(e){this.storage=e;}async rawFind({resource:e,commonWhere:t,uniqueWhere:n,...r}){return new Promise((i,c)=>{let o=this.getBatchKey({resource:e,commonWhere:t,...r}),s={resource:e,commonWhere:t,uniqueWhere:n,...r,resolve:i,reject:c};this.queue.has(o)||this.queue.set(o,[]);let l=this.queue.get(o);l&&l.push(s),this.scheduled||(this.scheduled=true,setImmediate(()=>{this.processBatch();}));})}getBatchKey(e){let{resource:t,commonWhere:n,...r}=e;return `${t}:${JSON.stringify(n??{})}:${JSON.stringify(r??{})}`}async processBatch(){this.scheduled=false;let e=Array.from(this.queue.entries());this.queue.clear();for(let[,t]of e)try{await this.executeBatchedRequests(t);}catch(n){t.forEach(r=>{r.reject(n);});}}async executeBatchedRequests(e){var h;if(e.length===0)return;let t=e[0],{resource:n,commonWhere:r,include:i,sort:c}=t,o=e.length===1?t.limit:void 0,s=e.map(d=>d.uniqueWhere).filter(d=>d!==void 0),l=r,y=(h=Object.entries(s[0]??{})[0])==null?void 0:h[0];if(s.length>0){let d=s.map(p=>p[y]).filter(p=>p!=null);d.length>0&&(l=P(r,{[y]:{$in:d}}));}let u=await this.storage.get({resource:n,where:l,include:i,sort:c,limit:o});for(let d of e){let p=u;if(d.uniqueWhere){let[m,g]=Object.entries(d.uniqueWhere)[0];p=u.filter(f=>{var b;return ((b=f.value[m])==null?void 0:b.value)===g});}d.resolve(p);}}};function G(a){return v({resource:a.query.resource,where:a.query.where,include:a.query.include,stepPath:a.stepPath,isMany:a.isMany,relationName:a.relationName})}var U=class{router;storage;schema;logger;queryNodes=new Map;objectNodes=new Map;constructor(e){this.router=e.router,this.storage=e.storage,this.schema=e.schema,this.logger=e.logger;}getRelationalColumns(e){let t=new Map,n=this.schema[e];if(!(n!=null&&n.relations))return t;for(let[r,i]of Object.entries(n.relations))i.type==="one"&&i.relationalColumn&&t.set(String(i.relationalColumn),{relationName:r,targetResource:i.entity.name});return t}ensureObjectNode(e,t,n){let r=this.objectNodes.get(e);return r?n&&r.matchedQueries.add(n):(r={id:e,type:t,matchedQueries:new Set(n?[n]:[]),referencesObjects:new Map,referencedByObjects:new Map},this.objectNodes.set(e,r)),r}storeRelation(e,t,n,r){let i=this.objectNodes.get(e),c=this.objectNodes.get(t);if(i&&i.referencesObjects.set(n,t),c&&r){let o=c.referencedByObjects.get(r);o||(o=new Set,c.referencedByObjects.set(r,o)),o.add(e);}}removeRelation(e,t,n,r){let i=this.objectNodes.get(e),c=this.objectNodes.get(t);if(i&&i.referencesObjects.delete(n),c&&r){let o=c.referencedByObjects.get(r);o&&(o.delete(e),o.size===0&&c.referencedByObjects.delete(r));}}getInverseRelationName(e,t,n){let r=this.schema[e];if(!(r!=null&&r.relations))return;let i=r.relations[n];if(!i)return;let c=this.schema[t];if(c!=null&&c.relations){if(i.type==="many"&&i.foreignColumn){for(let[o,s]of Object.entries(c.relations))if(s.entity.name===e&&s.type==="one"&&s.relationalColumn===i.foreignColumn)return o}if(i.type==="one"&&i.relationalColumn){for(let[o,s]of Object.entries(c.relations))if(s.entity.name===e&&s.type==="many"&&s.foreignColumn===i.relationalColumn)return o}}}updateRelationsFromMutation(e,t,n,r){let i=this.getRelationalColumns(e),c=this.objectNodes.get(t);if(c)for(let[o,{relationName:s,targetResource:l}]of Array.from(i)){if(!(r&&o in r))continue;let u=this.getInverseRelationName(e,l,s),h=c.referencesObjects.get(s),d=n[o];h!==d&&(h&&this.removeRelation(t,h,s,u),d&&(this.ensureObjectNode(d,l),this.storeRelation(t,d,s,u)));}}get(e,t){let n=this.breakdownQuery({query:e,context:(t==null?void 0:t.context)??{}});return this.resolveQuery(n,{context:(t==null?void 0:t.context)??{},batcher:(t==null?void 0:t.batcher)??new B(this.storage)})}subscribe(e,t,n={}){let r=this.breakdownQuery({query:e,context:n}),i={},c=[];for(let o of r){this.logger.debug("[QueryEngine] Subscribing to step",o.stepPath.join("."));let s=G(o),l=i[o.stepPath.at(-2)??""],y=o.stepPath.at(-1)??"",u=this.queryNodes.get(s);if(u)u.subscriptions.add(t);else if(u={hash:s,queryStep:o,relationName:y,trackedObjects:new Set,subscriptions:new Set([t]),parentQuery:l,childQueries:new Set},this.queryNodes.set(u.hash,u),l){let h=this.queryNodes.get(l);h&&h.childQueries.add(u.hash);}i[y]=s,c.push(()=>{let h=this.queryNodes.get(s);h&&(h.subscriptions.delete(t),h.subscriptions.size===0&&this.queryNodes.delete(s));});}return ()=>{for(let o of c)o();}}breakdownQuery(e){var g;let{query:t,stepPath:n=[],context:r={},parentResource:i}=e,{include:c}=t,o=n.length===0,s=n.at(-1),l,y,u;if(!o&&i&&s){let f=this.schema[i],b=(g=f==null?void 0:f.relations)==null?void 0:g[s];b&&(u=b.type==="many",b.type==="one"?(l=R=>({id:R}),y=R=>R.map(w=>{var S,x;return (x=(S=w.value)==null?void 0:S[b.relationalColumn])==null?void 0:x.value}).filter(w=>w!==void 0)):(l=R=>({[b.foreignColumn]:R}),y=R=>R.map(w=>{var S,x;return (x=(S=w.value)==null?void 0:S.id)==null?void 0:x.value}).filter(w=>w!==void 0)));}let{include:h,...d}=t,m=[this.router.incrementQueryStep({query:d,stepPath:[...n],getWhere:l,referenceGetter:y,isMany:u,relationName:s},r)];if(c&&typeof c=="object"&&Object.keys(c).length>0){let f=this.schema[t.resource];if(!f)throw new Error(`Resource ${t.resource} not found`);m.push(...Object.entries(c).flatMap(([b,R])=>{let w=f.relations[b];if(!w)throw new Error(`Relation ${b} not found for resource ${t.resource}`);let S=w.entity.name;return this.breakdownQuery({query:{resource:S,include:typeof R=="object"?R:void 0},stepPath:[...n,b],context:r,parentResource:t.resource})}));}return m}resolveQuery(e,t){this.logger.debug("[QueryEngine] Resolving query",e.map(i=>i.stepPath.join(".")).join(" -> "));let n={},r=this.resolveStep(e[0],t).then(i=>{this.logger.debug("[QueryEngine] Resolved step",e[0].stepPath.join("."),"with results count:",i.length),n[e[0].stepPath.join(".")]=[{data:i}];});for(let i=1;i<e.length;i++){let c=e[i],o=c.stepPath.slice(0,-1).join(".");r=r.then(async()=>{var l,y;let s=n[o];if(!s){n[c.stepPath.join(".")]=[];return}if(c.referenceGetter&&c.getWhere){let u=new Map;for(let p of s)for(let m of p.data){let g=(y=(l=m==null?void 0:m.value)==null?void 0:l.id)==null?void 0:y.value;if(!g)continue;let b=c.referenceGetter([m])[0];if(b){u.has(b)||u.set(b,new Set);let R=u.get(b);R&&R.add(g);}}let h=Array.from(u.keys());if(h.length===0){n[c.stepPath.join(".")]=[];return}let d=[];for(let p of h){let m=c.getWhere(p),g={...c,relationalWhere:m},f=await this.resolveStep(g,t),b=u.get(p);if(b)for(let R of Array.from(b))d.push({includedBy:R,data:f});}this.logger.debug("[QueryEngine] Resolved step",c.stepPath.join("."),"with results count:",d.reduce((p,m)=>p+m.data.length,0)),n[c.stepPath.join(".")]=d;}else {let u=await this.resolveStep(c,t);n[c.stepPath.join(".")]=[{data:u}];}});}return r=r.then((()=>(this.logger.debug("[QueryEngine] Assembling results"),this.assembleResults(e,n)))),r}assembleResults(e,t){var c,o,s,l,y;this.logger.debug("[QueryEngine] assembleResults: Starting assembly"),this.logger.debug("[QueryEngine] assembleResults: Plan steps:",e.length),this.logger.debug("[QueryEngine] assembleResults: Step results keys:",Object.keys(t));let n=new Map;for(let u of e){let h=u.stepPath.join("."),d=t[h]??[],p=Object.keys(u.query.include??{});this.logger.debug(`[QueryEngine] assembleResults: Processing step "${h}"`,{resource:u.query.resource,includedRelations:p,resultGroups:d.length,isMany:u.isMany,relationName:u.relationName});for(let m of d){this.logger.debug(`[QueryEngine] assembleResults: Processing result group for "${h}"`,{dataCount:m.data.length,includedBy:m.includedBy});for(let g of m.data){let f=(o=(c=g==null?void 0:g.value)==null?void 0:c.id)==null?void 0:o.value;if(!f){this.logger.debug(`[QueryEngine] assembleResults: Skipping data without id in step "${h}"`);continue}let b=h?`${h}.${f}`:f,R=[];if(u.stepPath.length>0&&m.includedBy){let S=u.stepPath.slice(0,-1).join(".");R=[S?`${S}.${m.includedBy}`:m.includedBy],this.logger.debug(`[QueryEngine] assembleResults: Child entity "${b}" has parent keys:`,R,{stepPath:h,parentStepPath:S,includedBy:m.includedBy});}else this.logger.debug(`[QueryEngine] assembleResults: Root entity "${b}" (no parent)`);let w=n.get(b);if(w){this.logger.debug(`[QueryEngine] assembleResults: Entity "${b}" already exists, adding parent keys:`,R);for(let S of R)w.includedBy.add(S);}else this.logger.debug(`[QueryEngine] assembleResults: Adding new entity "${b}"`,{resource:u.query.resource,path:u.stepPath.at(-1)??"",isMany:u.isMany??false,relationName:u.relationName,includedRelations:p,parentKeys:R}),n.set(b,{data:g,includedBy:new Set(R),path:u.stepPath.at(-1)??"",isMany:u.isMany??false,relationName:u.relationName,resourceName:u.query.resource,includedRelations:p});}}}this.logger.debug(`[QueryEngine] assembleResults: Built entriesMap with ${n.size} entries`),this.logger.debug("[QueryEngine] assembleResults: EntriesMap keys:",Array.from(n.keys()));let r=Array.from(n.entries()),i=[];this.logger.debug(`[QueryEngine] assembleResults: Starting assembly phase with ${r.length} entries`);for(let u=r.length-1;u>=0;u--){let[h,d]=r[u],p=this.schema[d.resourceName];this.logger.debug(`[QueryEngine] assembleResults: Processing entry "${h}"`,{resource:d.resourceName,path:d.path,isMany:d.isMany,relationName:d.relationName,includedRelations:d.includedRelations,parentKeys:Array.from(d.includedBy)});for(let m of d.includedRelations){let g=(l=(s=p==null?void 0:p.relations)==null?void 0:s[m])==null?void 0:l.type,f=!!d.data.value[m];if(this.logger.debug(`[QueryEngine] assembleResults: Checking included relation "${m}" for "${h}"`,{relationType:g,hasRelation:f,resourceHasRelation:!!((y=p==null?void 0:p.relations)!=null&&y[m])}),d.data.value[m])this.logger.debug(`[QueryEngine] assembleResults: Relation "${m}" already exists for "${h}"`,d.data.value[m]);else {let b=g==="many"?{value:[]}:{value:null};d.data.value[m]=b,this.logger.debug(`[QueryEngine] assembleResults: Initialized relation "${m}" for "${h}" with`,b);}}if(d.path===""){this.logger.debug(`[QueryEngine] assembleResults: Adding root entity "${h}" to resultData`),i.push(d.data);continue}this.logger.debug(`[QueryEngine] assembleResults: Attaching "${h}" to ${d.includedBy.size} parent(s)`);for(let m of Array.from(d.includedBy)){let g=n.get(m);if(!g){this.logger.warn(`[QueryEngine] assembleResults: WARNING - Parent "${m}" not found in entriesMap for child "${h}"`);continue}let f=d.relationName??d.path;this.logger.debug(`[QueryEngine] assembleResults: Attaching "${h}" to parent "${m}" via relation "${f}"`,{isMany:d.isMany,parentHasRelation:!!g.data.value[f]}),d.isMany?(g.data.value[f]??={value:[]},g.data.value[f].value.push(d.data),this.logger.debug(`[QueryEngine] assembleResults: Added "${h}" to many relation "${f}" on parent "${m}"`,{arrayLength:g.data.value[f].value.length})):(g.data.value[f]=d.data,this.logger.debug(`[QueryEngine] assembleResults: Set one relation "${f}" on parent "${m}" to "${h}"`));}}return this.logger.debug(`[QueryEngine] assembleResults: Assembly complete. Returning ${i.length} root items`),i}resolveStep(e,t){this.logger.debug("[QueryEngine] Resolving step",e.stepPath.join("."),"with query",JSON.stringify(e.query,null,2),"relationalWhere",JSON.stringify(e.relationalWhere,null,2));let{query:n,relationalWhere:r}=e,i=n.where&&r?P(n.where,r):r??n.where,c=i?{...n,where:i}:n;return H(this.router.get(c,t)).then(o=>(this.loadStepResults(e,o),o))}loadStepResults(e,t$1){this.logger.debug("[QueryEngine] Loading step results",e.stepPath.join("."),"with results",JSON.stringify(t$1,null,2));let n=G(e),r=this.queryNodes.get(n),i=e.query.resource;if(!r)return;let c=this.getRelationalColumns(i);for(let o of t$1){let s=t(o),l=s.id;this.ensureObjectNode(l,i,n),r.trackedObjects.add(l);for(let[y,{relationName:u,targetResource:h}]of Array.from(c)){let d=s[y];if(d){this.ensureObjectNode(d,h);let p=this.getInverseRelationName(i,h,u);this.storeRelation(l,d,u,p);}}this.loadNestedRelations(i,l,s),this.logger.debug("[QueryEngine] Loaded nested relations for",l);}}loadNestedRelations(e,t,n){let r=this.schema[e];if(r!=null&&r.relations)for(let[i,c]of Object.entries(r.relations)){let o=n[i];if(!o)continue;let s=c.entity.name,l=this.getInverseRelationName(e,s,i);if(c.type==="one")o&&typeof o=="object"&&o.id&&(this.ensureObjectNode(o.id,s),this.storeRelation(t,o.id,i,l),this.loadNestedRelations(s,o.id,o));else if(c.type==="many"&&Array.isArray(o)){for(let y of o)if(y&&typeof y=="object"&&y.id){this.ensureObjectNode(y.id,s);let u=this.getInverseRelationName(s,e,i);u&&this.storeRelation(y.id,t,u,i),this.loadNestedRelations(s,y.id,y);}}}}buildIncludeFromChildQueries(e){let t=this.queryNodes.get(e);if(!t||t.childQueries.size===0)return {};let n={};for(let r of Array.from(t.childQueries)){let i=this.queryNodes.get(r);if(!i||!i.relationName)continue;let c=this.buildIncludeFromChildQueries(r);n[i.relationName]=Object.keys(c).length>0?c:true;}return n}sendInsertsForTree(e,t,n){var o,s;let r=(s=(o=t==null?void 0:t.value)==null?void 0:o.id)==null?void 0:s.value;if(!r)return;let i={procedure:"INSERT",resource:n,resourceId:r,type:"MUTATE",payload:t.value};for(let l of Array.from(e.subscriptions))try{l(i);}catch(y){this.logger.error("[QueryEngine] Error in subscription callback during sendInsertsForTree",{error:y,queryHash:e.hash,resource:n,resourceId:r,stepPath:e.queryStep.stepPath.join(".")});}e.trackedObjects.add(r),this.ensureObjectNode(r,n,e.hash).matchedQueries.add(e.hash);for(let l of Array.from(e.childQueries)){let y=this.queryNodes.get(l);if(!y||!y.relationName)continue;let u=y.relationName,h=y.queryStep.query.resource,d=t.value[u];if(!d)continue;let p=d.value;if(Array.isArray(p))for(let m of p)this.sendInsertsForTree(y,m,h);else p&&typeof p=="object"&&this.sendInsertsForTree(y,p,h);}}handleMutation(e,t$1){if(e.procedure==="INSERT"){if(this.objectNodes.has(e.resourceId))return;let n=t(t$1);if(!n)return;let r={id:e.resourceId,type:e.resource,matchedQueries:new Set,referencesObjects:new Map,referencedByObjects:new Map};this.objectNodes.set(e.resourceId,r);let i=this.getRelationalColumns(e.resource);for(let[o,{relationName:s,targetResource:l}]of Array.from(i)){let y=n[o];if(y){this.ensureObjectNode(y,l);let u=this.getInverseRelationName(e.resource,l,s);this.storeRelation(e.resourceId,y,s,u);}}let c=this.objectNodes.get(e.resourceId);this.getMatchingQueries(e,n).then(o=>{for(let s of o){let l=this.queryNodes.get(s);if(l){l.trackedObjects.add(e.resourceId),c&&c.matchedQueries.add(s);for(let y of Array.from(l.subscriptions))try{y(e);}catch(u){this.logger.error("[QueryEngine] Error in subscription callback during INSERT mutation",{error:u,queryHash:l.hash,resource:e.resource,resourceId:e.resourceId,stepPath:l.queryStep.stepPath.join(".")});}}}});return}if(e.procedure==="UPDATE"){let n=t(t$1);if(!n)return;let r=this.objectNodes.get(e.resourceId),i=new Set((r==null?void 0:r.matchedQueries)??[]);r||(r={id:e.resourceId,type:e.resource,matchedQueries:new Set,referencesObjects:new Map,referencedByObjects:new Map},this.objectNodes.set(e.resourceId,r)),this.updateRelationsFromMutation(e.resource,e.resourceId,n,e.payload),this.getMatchingQueries(e,n).then(c=>{let o=new Set(c),s=[],l=[],y=[];for(let h of c)i.has(h)?y.push(h):s.push(h);for(let h of Array.from(i))o.has(h)||l.push(h);for(let h of s){let d=this.queryNodes.get(h);d&&d.trackedObjects.add(e.resourceId);}for(let h of l){let d=this.queryNodes.get(h);d&&d.trackedObjects.delete(e.resourceId);}let u=this.objectNodes.get(e.resourceId);if(u){for(let h of s)u.matchedQueries.add(h);for(let h of l)u.matchedQueries.delete(h);}for(let h of [...l,...y]){let d=this.queryNodes.get(h);if(d)for(let p of Array.from(d.subscriptions))try{p(e);}catch(m){this.logger.error("[QueryEngine] Error in subscription callback during UPDATE mutation",{error:m,queryHash:d.hash,resource:e.resource,resourceId:e.resourceId,stepPath:d.queryStep.stepPath.join(".")});}}if(s.length>0)for(let h of s){let d=this.queryNodes.get(h);if(!d)continue;let p=this.buildIncludeFromChildQueries(h);this.get({resource:e.resource,where:{id:e.resourceId},include:Object.keys(p).length>0?p:void 0}).then(m=>{!m||m.length===0||this.sendInsertsForTree(d,m[0],e.resource);});}});return}}getMatchingQueries(e,t$1){let n=[];for(let r of Array.from(this.queryNodes.values()))r.queryStep.query.resource===e.resource&&n.push(r);return n.length===0?H([]):Promise.all(n.map(async r=>{let i=r.queryStep.query.where,c=r.queryStep.query.resource,o=e.resourceId,s=this.objectNodes.get(o);if(!s)return {hash:r.hash,matches:false};if(r.relationName){let d=r.parentQuery?this.queryNodes.get(r.parentQuery):void 0,p=d==null?void 0:d.queryStep.query.resource,m=p?this.getInverseRelationName(p,c,r.relationName):void 0,g=m?s.referencesObjects.get(m):void 0;if(!g)return {hash:r.hash,matches:false};let f=this.objectNodes.get(g);return !f||!d||!f.matchedQueries.has(d.hash)?{hash:r.hash,matches:false}:{hash:r.hash,matches:true}}if(!i)return {hash:r.hash,matches:true};let l=w(i,c,this.schema),y=Object.keys(l).length>0;if(!y&&t$1!==void 0)return {hash:r.hash,matches:x(t$1,i)};let u=await this.storage.get({resource:c,where:{id:o},include:y?l:void 0});if(!u||u.length===0)return {hash:r.hash,matches:false};let h=t(u[0]);return h?{hash:r.hash,matches:x(h,i)}:{hash:r.hash,matches:false}})).then(r=>r.filter(i=>i.matches).map(i=>i.hash))}};var ge=b(Z(),1);var L=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()}),K=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()})),Ve=K.superRefine((a,e)=>{a.id&&e.addIssue({code:z$1.ZodIssueCode.custom,message:"Payload cannot have an id"});}),fe=z$1.object({id:z$1.string().optional(),type:z$1.literal("MUTATE"),resource:z$1.string(),resourceId:z$1.string().optional()}),C=fe.extend({procedure:z$1.string(),payload:z$1.any().optional()}),Q=fe.extend({procedure:z$1.enum(["INSERT","UPDATE"]),payload:Ve});z$1.union([Q,C]);var me=L.omit({resource:true}),J=C.omit({id:true,type:true,resource:true,procedure:true}),Y=Q.omit({id:true,type:true,resource:true,procedure:true});z$1.union([Y,J]);var X=a=>{if(a==null)return a;if(a==="null")return null;if(Array.isArray(a))return a.map(X);if(typeof a=="object"&&a.constructor===Object){let e={};for(let[t,n]of Object.entries(a))e[t]=X(n);return e}return a},be=a=>{let e=a.logger;return async t=>{var n;try{let r=typeof t.headers.getSetCookie=="function"?Object.fromEntries(t.headers):t.headers,i={headers:r,cookies:r.cookie?ge.default.parse(r.cookie):{}},c=new URL(t.url),o=c.pathname.split("/"),s=c.searchParams,l=X(Ge.parse(s.toString())),y=await((n=a.contextProvider)==null?void 0:n.call(a,{transport:"HTTP",headers:i.headers,cookies:i.cookies,queryParams:l}))??{};if(t.method==="GET"){let u=o[o.length-1],{success:h,data:d,error:p}=me.safeParse(l);if(!h)return Response.json({message:"Invalid query",code:"INVALID_QUERY",details:p},{status:400});let m=await a.handleQuery({req:{...i,...d,type:"QUERY",resource:u,context:y,queryParams:l}});return !m||!m.data?Response.json({message:"Invalid resource",code:"INVALID_RESOURCE"},{status:400}):Response.json(m.data)}if(t.method==="POST")try{let u=o[o.length-1],h=o[o.length-2],d=t.body?await t.json():{},p;if(u==="insert"||u==="update"){let{success:g,data:f,error:b}=Y.safeParse(d);if(!g)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:b},{status:400});p=f;}else {let{success:g,data:f,error:b}=J.safeParse(d);if(!g)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:b},{status:400});p=f;}let m=await a.handleMutation({req:{...i,type:"MUTATE",resource:h,input:p.payload,context:y,resourceId:p.resourceId,procedure:u==="insert"||u==="update"?u.toUpperCase():u,queryParams:{}}});return Response.json(m)}catch(u){return e.error("Error parsing mutation from the client:",u),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}return Response.json({message:"Not found",code:"NOT_FOUND"},{status:404})}catch(r){return e.error("Unexpected error:",r),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}}};var we=b(Z(),1);var O=z$1.string(),Ze=L.extend({id:O,type:z$1.literal("SUBSCRIBE")}),Ke=L.extend({id:O,type:z$1.literal("UNSUBSCRIBE")}),Je=L.extend({id:O,type:z$1.literal("QUERY")}),Re=Q.extend({id:O}),Ye=C.extend({id:O}),Xe=z$1.union([Ye,Re]),Te=z$1.union([Ze,Je,Xe,Ke]),et=z$1.object({id:O,type:z$1.literal("REJECT"),resource:z$1.string(),message:z$1.string().optional()}),tt=z$1.object({id:O,type:z$1.literal("REPLY"),data:z$1.any()});z$1.union([et,tt,Re]);z$1.object({resource:z$1.string(),data:z$1.array(K)});var Se=a=>{let e={},t=a.logger;return (n,r)=>{var u;let i=h=>{n.send(JSON.stringify(h));},c=D(),o=new Map,s={headers:r.headers,cookies:typeof r.headers.cookie=="string"?we.default.parse(r.headers.cookie):{}},l=parse(r.url.split("?")[1]),y=(u=a.contextProvider)==null?void 0:u.call(a,{transport:"WEBSOCKET",headers:s.headers,cookies:s.cookies,queryParams:l});e[c]=n,t.info("Client connected:",c),n.on("message",async h=>{try{t.debug("Message received from the client:",h);let d=Te.parse(JSON.parse(h.toString()));if(d.type==="SUBSCRIBE"||d.type==="QUERY"){let{type:p,id:m,...g}=d,f=p==="SUBSCRIBE",b=await a.handleQuery({req:{...s,...g,type:"QUERY",context:await y??{},queryParams:l},subscription:f?R=>{var w;!R.resourceId||!R.payload||!Object.keys(R.payload).length||(w=e[c])==null||w.send(JSON.stringify(R));}:void 0});if(!b||!b.data)throw new Error("Invalid resource");f&&b.unsubscribe&&o.set(v(g),b.unsubscribe),i({id:m,type:"REPLY",data:{resource:g.resource,data:(b.data??[]).map(R=>R.value)}});}else if(d.type==="UNSUBSCRIBE"){let{type:p,id:m,...g}=d,f=o.get(v(g));f&&(f(),o.delete(v(g)));}else if(d.type==="MUTATE"){let{resource:p}=d;t.debug("Received mutation from client:",d);try{let m=await a.handleMutation({req:{...s,type:"MUTATE",resource:p,input:d.payload,context:{messageId:d.id,...await y??{}},resourceId:d.resourceId,procedure:d.procedure,queryParams:l}});d.procedure&&d.procedure!=="INSERT"&&d.procedure!=="UPDATE"&&i({id:d.id,type:"REPLY",data:m});}catch(m){i({id:d.id,type:"REJECT",resource:p,message:m.message}),t.error("Error parsing mutation from the client:",m);}}}catch(d){t.error("Error handling message from the client:",d);}}),n.on("close",()=>{t.info("Connection closed",c),delete e[c];for(let h of Array.from(o.values()))h();});}};function Me(a){let e=`${a.protocol}://${a.hostname}${a.url}`,t=new Headers;return Object.entries(a.headers).forEach(([n,r])=>{r&&t.set(n,Array.isArray(r)?r.join(","):r);}),new Request(e,{method:a.method,headers:t,body:a.body&&a.method!=="GET"?JSON.stringify(a.body):void 0})}var Ht=(a,e,t)=>{a.ws(`${(t==null?void 0:t.basePath)??""}/ws`,Se(e)),a.use(`${(t==null?void 0:t.basePath)??""}/`,(n,r)=>{be(e)(Me(n)).then(c=>c.json().then(o=>r.status(c.status).send(o)));});};var ee=class a{routes;constructor(e){this.routes=e.routes;}static create(e){return new a(e)}},Yt=a=>ee.create({...a}),it=a=>({handler:e=>({inputValidator:a??z$1.undefined(),handler:e})}),te=class a{resourceSchema;middlewares;customMutations;authorization;constructor(e,t,n){this.resourceSchema=e,this.middlewares=new Set,this.customMutations=t??{},this.authorization=n;}use(...e){for(let t of e)this.middlewares.add(t);return this}withMutations(e){return new a(this.resourceSchema,e({mutation:it}),this.authorization)}handleQuery=async({req:e,batcher:t})=>await this.wrapInMiddlewares(async n=>{let r={resource:n.resource,where:n.where,include:n.include,lastSyncedAt:n.lastSyncedAt,limit:n.limit,sort:n.sort},i=v(r);return {data:await t.rawFind({resource:n.resource,commonWhere:n.where,uniqueWhere:n.relationalWhere,include:n.include,limit:n.limit,sort:n.sort}),unsubscribe:void 0,queryHash:i}})(e);handleMutation=async({req:e,db:t,schema:n})=>await this.wrapInMiddlewares(async r=>{if(!r.procedure)throw new Error("Procedure is required for mutations");let i=this.customMutations[r.procedure];if(i){let c=i.inputValidator.parse(r.input);return r.input=c,i.handler({req:r,db:t})}else {if(r.procedure==="INSERT"||r.procedure==="UPDATE")return this.handleSet({req:r,db:t,operation:r.procedure,schema:n});throw new Error(`Unknown procedure: ${r.procedure}`)}})(e);getAuthorizationClause(e){var t,n;return (n=(t=this.authorization)==null?void 0:t.read)==null?void 0:n.call(t,{ctx:e.context})}handleSet=async({req:e,db:t$1,operation:n,schema:r})=>{if(!e.input)throw new Error("Payload is required");if(!e.resourceId)throw new Error("ResourceId is required");let i=await t$1.rawFindById(e.resource,e.resourceId);if(n==="INSERT"&&i)throw new Error("Resource already exists");if(n==="UPDATE"&&!i)throw new Error("Resource not found");return t$1.transaction(async({trx:c})=>{var y,u,h,d,p,m,g;let[o,s]=this.resourceSchema.mergeMutation("set",e.input,i);if(!s)throw new Error("Mutation rejected");if(n==="INSERT"){let f=await c.rawInsert(e.resource,e.resourceId,o,(y=e.context)==null?void 0:y.messageId),b=t(f);if(b.id=b.id??e.resourceId,(u=this.authorization)!=null&&u.insert){let R=this.authorization.insert({ctx:e.context,value:b});if(typeof R=="boolean"){if(!R)throw new Error("Not authorized")}else {let w$1=w(R,e.resource,r),S=Object.keys(w$1).length>0?await c.rawFindById(e.resource,e.resourceId,w$1):f,x$1=t(S);if(x$1.id=x$1.id??e.resourceId,!x(x$1,R))throw new Error("Not authorized")}}return {data:f,acceptedValues:s}}if((d=(h=this.authorization)==null?void 0:h.update)!=null&&d.preMutation){let f=t(i);f.id=f.id??e.resourceId;let b=this.authorization.update.preMutation({ctx:e.context,value:f});if(typeof b=="boolean"){if(!b)throw new Error("Not authorized")}else {let R=w(b,e.resource,r),w$1=Object.keys(R).length>0?await c.rawFindById(e.resource,e.resourceId,R):i,S=t(w$1);if(S.id=S.id??e.resourceId,!x(S,b))throw new Error("Not authorized")}}let l=await c.rawUpdate(e.resource,e.resourceId,o,(p=e.context)==null?void 0:p.messageId);if((g=(m=this.authorization)==null?void 0:m.update)!=null&&g.postMutation){let f=t(l);f.id=f.id??e.resourceId;let b=this.authorization.update.postMutation({ctx:e.context,value:f});if(typeof b=="boolean"){if(!b)throw new Error("Not authorized")}else {let R=w(b,e.resource,r),w$1=Object.keys(R).length>0?await c.rawFindById(e.resource,e.resourceId,R):l,S=t(w$1);if(S.id=S.id??e.resourceId,!x(S,b))throw new Error("Not authorized")}}return {data:l,acceptedValues:s}})};wrapInMiddlewares(e){return t=>Array.from(this.middlewares.values()).reduceRight((n,r)=>i=>r({req:i,next:n}),e)(t)}},re=class a{middlewares;constructor(e=[]){this.middlewares=e;}collectionRoute(e,t){return new te(e,void 0,t).use(...this.middlewares)}use(...e){return new a([...this.middlewares,...e])}static create(){return new a}},Xt=re.create;var z=class{async insert(e,t$1){let n=new Date().toISOString();return t(await this.rawInsert(e.name,t$1.id,{value:Object.fromEntries(Object.entries(t$1).map(([r,i])=>[r,{value:i,_meta:{timestamp:n}}]))}))}async update(e,t$1,n){let r=new Date().toISOString(),{id:i,...c}=n;return t(await this.rawUpdate(e.name,t$1,{value:Object.fromEntries(Object.entries(c).map(([o,s])=>[o,{value:s,_meta:{timestamp:r}}]))}))}};function F(a,e,t,n){if(!a)throw new Error("Schema not initialized");let r=a[e];if(!r)throw new Error("Resource not found");let i=n.$or,c=n.$and;return (i?t.or:t.and)(i?n.$or.map(o=>F(a,e,t,o)):c?n.$and.map(o=>F(a,e,t,o)):Object.entries(n).map(([o,s])=>{var l,y;if(r.fields[o])return (s==null?void 0:s.$eq)!==void 0?t(`${e}.${o}`,s.$eq===null?"is":"=",s.$eq):(s==null?void 0:s.$in)!==void 0?t(`${e}.${o}`,"in",s.$in):(s==null?void 0:s.$not)!==void 0?((l=s==null?void 0:s.$not)==null?void 0:l.$in)!==void 0?t(`${e}.${o}`,"not in",s.$not.$in):((y=s==null?void 0:s.$not)==null?void 0:y.$eq)!==void 0?t(`${e}.${o}`,s.$not.$eq===null?"is not":"!=",s.$not.$eq):t(`${e}.${o}`,s.$not===null?"is not":"!=",s.$not):(s==null?void 0:s.$gt)!==void 0?t(`${e}.${o}`,">",s.$gt):(s==null?void 0:s.$gte)!==void 0?t(`${e}.${o}`,">=",s.$gte):(s==null?void 0:s.$lt)!==void 0?t(`${e}.${o}`,"<",s.$lt):(s==null?void 0:s.$lte)!==void 0?t(`${e}.${o}`,"<=",s.$lte):t(`${e}.${o}`,s===null?"is":"=",s);if(r.relations[o]){let u=r.relations[o],h=u.entity.name;return u.type==="many"?t.exists(ne(a,h,t.selectFrom(h).select("id").whereRef(u.foreignColumn,"=",`${e}.id`),s)):F(a,h,t,s)}return null}).filter(Boolean))}function _(a,e,t,n){let r=a[e];if(!r)throw new Error("Resource not found");if(!n)return t;if(n.$and){for(let i of n.$and)t=_(a,e,t,i);return t}else if(n.$or){for(let i of n.$or)t=_(a,e,t,i);return t}for(let[i,c]of Object.entries(n)){if(!r.relations[i])continue;let o=r.relations[i],s=o.entity.name,l=o.type==="one"?"id":o.foreignColumn,y=o.type==="one"?o.relationalColumn:"id";t=t.leftJoin(s,`${s}.${l}`,`${e}.${y}`),c instanceof Object&&!Array.isArray(c)&&c!==null&&(t=_(a,s,t,c));}return t}function ne(a,e,t,n){return !n||Object.keys(n).length===0?t:(t=_(a,e,t,n),t.where(r=>F(a,e,r,n)))}function V(a,e,t,n){if(!n)return t;if(!a)throw new Error("Schema not initialized");let r=a[e];if(!r)throw new Error(`Resource not found: ${e}`);for(let i of Object.keys(n)){if(!r.relations[i])throw new Error(`Relation ${i} not found in resource ${e}`);let c=r.relations[i],o=c.entity.name,s=n[i],l=c.type==="one"?"id":c.foreignColumn,y=c.type==="one"?c.relationalColumn:"id",u=c.type==="one"?jsonObjectFrom:jsonArrayFrom,h=typeof s=="object"&&s!==null;t=t.select(d=>{let p=d.selectFrom(o).selectAll(o).whereRef(`${o}.${l}`,"=",`${e}.${y}`).select(m=>jsonObjectFrom(m.selectFrom(`${o}_meta`).selectAll(`${o}_meta`).whereRef(`${o}_meta.id`,"=",`${o}.id`)).as("_meta"));return h&&(p=V(a,o,p,s)),u(p).as(i)});}return t}var je="42701",ie=class a extends z{db;schema;logger;server;mutationStack=[];constructor(e,t,n,r){super(),this.isKyselyLike(e)?this.db=e:this.db=new Kysely({dialect:new PostgresDialect({pool:e})}),this.schema=t,this.logger=n,this.server=r,this.rawInsert=this.rawInsert.bind(this),this.rawUpdate=this.rawUpdate.bind(this);}async init(e,t,n){var i;this.schema=e,this.logger=t,this.server=n;let r=await this.db.introspection.getTables();for(let[c,o]of Object.entries(e)){let s=r.find(u=>u.name===c);s||await this.db.schema.createTable(c).ifNotExists().execute();let l=`${c}_meta`,y=r.find(u=>u.name===l);y||await this.db.schema.createTable(l).ifNotExists().execute();for(let[u,h]of Object.entries(o.fields)){let d=s==null?void 0:s.columns.find(g=>g.name===u),p=h.getStorageFieldType();d?d.dataType!==p.type&&((i=this.logger)==null||i.warn("Column type mismatch:",u,"expected to have type:",p.type,"but has type:",d.dataType)):(await this.db.schema.alterTable(c).addColumn(u,p.type,g=>{let f=g;return p.unique&&(f=f.unique()),p.nullable||(f=f.notNull()),p.references&&(f=f.references(p.references)),p.primary&&(f=f.primaryKey()),p.default!==void 0&&(f=f.defaultTo(p.default)),f}).execute().catch(g=>{var f;if(g.code!==je)throw (f=this.logger)==null||f.error("Error adding column",u,g),g}),p.index&&await this.db.schema.createIndex(`${c}_${u}_index`).on(c).column(u).execute().catch(()=>{})),y!=null&&y.columns.find(g=>g.name===u)||await this.db.schema.alterTable(l).addColumn(u,"varchar",g=>{let f=g;return p.primary&&(f=f.primaryKey().references(`${c}.${u}`)),f}).execute().catch(g=>{var f;if(g.code!==je)throw (f=this.logger)==null||f.error("Error adding meta column",u,g),g});}}}async rawFindById(e,t,n){if(!this.schema)throw new Error("Schema not initialized");let r=await this.db.selectFrom(e).where("id","=",t).selectAll(e).select(c=>jsonObjectFrom(c.selectFrom(`${e}_meta`).selectAll(`${e}_meta`).whereRef(`${e}_meta.id`,"=",`${e}.id`)).as("_meta"));r=V(this.schema,e,r,n);let i=await r.executeTakeFirst();if(i)return this.convertToMaterializedLiveType(i)}async findOne(e,t$1,n){let r=await this.rawFindById(e.name,t$1,n==null?void 0:n.include);if(r)return t(r)}async get(e){if(!this.schema)throw new Error("Schema not initialized");let{resource:t,where:n,include:r,limit:i,sort:c}=e,o=this.db.selectFrom(t).selectAll(t).select(l=>jsonObjectFrom(l.selectFrom(`${t}_meta`).selectAll(`${t}_meta`).whereRef(`${t}_meta.id`,"=",`${t}.id`)).as("_meta"));o=ne(this.schema,t,o,n),o=V(this.schema,t,o,r),i!==void 0&&(o=o.limit(i)),c!==void 0&&c.forEach(l=>{o=o.orderBy(l.key,l.direction);});let s=await o.execute();return s.length===0?[]:s.map(l=>this.convertToMaterializedLiveType(l))}async find(e,t$1){return (await this.get({resource:e.name,where:t$1==null?void 0:t$1.where,include:t$1==null?void 0:t$1.include,limit:t$1==null?void 0:t$1.limit,sort:t$1==null?void 0:t$1.sort})).map(r=>t(r))}async rawInsert(e,t,n,r){var s;let i={},c={};for(let[l,y]of Object.entries(n.value)){let u=(s=y._meta)==null?void 0:s.timestamp;u&&(i[l]=y.value,c[l]=u);}await this.db.insertInto(e).values({...i,id:t}).execute().then(()=>{this.db.insertInto(`${e}_meta`).values({...c,id:t}).execute();});let o=this.buildMutation(e,t,"INSERT",n,r);return o&&this.trackMutation(o,n),n}async rawUpdate(e,t,n,r){var s;let i={},c={};for(let[l,y]of Object.entries(n.value)){let u=(s=y._meta)==null?void 0:s.timestamp;u&&(i[l]=y.value,c[l]=u);}await Promise.all([this.db.updateTable(e).set(i).where("id","=",t).execute(),this.db.insertInto(`${e}_meta`).values({...c,id:t}).onConflict(l=>l.column("id").doUpdateSet(c)).execute()]);let o=this.buildMutation(e,t,"UPDATE",n,r);if(o){let l=await this.rawFindById(e,t);l&&this.trackMutation(o,l);}return n}async transaction(e){if(!this.schema)throw new Error("Schema not initialized");if(this.db.isTransaction){let i=Math.random().toString(36).substring(2,15),c=this.mutationStack,o=[];this.mutationStack=o;let s=await this.db.savepoint(i).execute();try{return await e({trx:this,commit:async()=>{await s.releaseSavepoint(i).execute(),c.push(...o);},rollback:async()=>{await s.rollbackToSavepoint(i).execute(),o.length=0;}}).then(l=>s.isCommitted||s.isRolledBack?l:s.releaseSavepoint(i).execute().then(()=>(c.push(...o),l)))}catch(l){throw await s.rollbackToSavepoint(i).execute().catch(()=>{}),o.length=0,l}finally{this.mutationStack=c;}}let t=[],n=this.mutationStack;this.mutationStack=t;let r=await this.db.startTransaction().execute();try{let i=new a(r,this.schema,this.logger,this.server);return i.mutationStack=t,await e({trx:i,commit:async()=>{await r.commit().execute(),this.notifyMutations(t);},rollback:async()=>{await r.rollback().execute(),t.length=0;}}).then(c=>r.isCommitted||r.isRolledBack?c:r.commit().execute().then(()=>(this.notifyMutations(t),c)))}catch(i){throw await r.rollback().execute(),t.length=0,i}finally{this.mutationStack=n;}}get internalDB(){return this.db}convertToMaterializedLiveType(e){return {value:Object.entries(e).reduce((t,[n,r])=>{var i,c,o;return n==="_meta"||(n==="id"?t[n]={value:r}:Array.isArray(r)?t[n]={value:r.map(s=>this.convertToMaterializedLiveType(s)),_meta:{timestamp:(i=e==null?void 0:e._meta)==null?void 0:i[n]}}:typeof r=="object"&&r!==null&&!(r instanceof Date)?t[n]={...this.convertToMaterializedLiveType(r),_meta:{timestamp:(c=e==null?void 0:e._meta)==null?void 0:c[n]}}:t[n]={value:r,_meta:{timestamp:(o=e==null?void 0:e._meta)==null?void 0:o[n]}}),t},{})}}isKyselyLike(e){if(e instanceof Kysely)return true;if(!e||typeof e!="object")return false;let t=e,n=typeof t.selectFrom=="function",r=typeof t.startTransaction=="function",i=typeof t.savepoint=="function",c=typeof t.isTransaction=="boolean"||typeof t.isTransaction=="function";return n&&r||i&&c}buildMutation(e,t,n,r,i){var o;let c={};for(let[s,l]of Object.entries(r.value)){if(s==="id")continue;let y=(o=l._meta)==null?void 0:o.timestamp;y&&(c[s]={value:l.value,_meta:{timestamp:y}});}return Object.keys(c).length===0?null:{id:i??D(),type:"MUTATE",resource:e,resourceId:t,procedure:n,payload:c}}trackMutation(e,t){this.db.isTransaction?this.mutationStack.push({mutation:e,entityData:t}):this.notifyMutations([e],t);}notifyMutations(e,t){if(this.server)if(t!==void 0){let n=e;for(let r of n)this.server.notifySubscribers(r,t);}else {let n=e;for(let{mutation:r,entityData:i}of n)this.server.notifySubscribers(r,i);}}};var se=class a{router;storage;schema;middlewares=new Set;logger;contextProvider;queryEngine;constructor(e){var t;this.router=e.router,this.storage=e.storage,this.schema=e.schema,this.logger=z$2({level:e.logLevel??y.INFO}),(t=e.middlewares)==null||t.forEach(n=>{this.middlewares.add(n);}),this.storage.init(this.schema,this.logger,this),this.contextProvider=e.contextProvider,this.queryEngine=new U({router:{get:async(n,r)=>{var u;let{headers:i,cookies:c,queryParams:o,context:s}=(r==null?void 0:r.context)??{};if(!(r!=null&&r.batcher))throw new Error("Batcher is required");let l={...n,type:"QUERY",headers:i,cookies:c,queryParams:o,context:s},y=await((u=this.router.routes[n.resource])==null?void 0:u.handleQuery({req:l,batcher:r.batcher}));return (y==null?void 0:y.data)??[]},incrementQueryStep:(n,r={})=>{var o;let i=(o=this.router.routes[n.query.resource])==null?void 0:o.getAuthorizationClause({...n.query,type:"QUERY",headers:r.headers,cookies:r.cookies,queryParams:r.queryParams,context:r.context});if(typeof i=="boolean"&&!i)throw new Error("Not authorized");let c=P(n.query.where,typeof i=="object"?i:void 0);return {...n,query:{...n.query,where:c}}}},storage:this.storage,schema:this.schema,logger:this.logger});}static create(e){return new a(e)}handleQuery(e){return this.wrapInMiddlewares(async t=>{let{headers:n,cookies:r,queryParams:i,context:c,...o}=t,s={headers:n,cookies:r,queryParams:i,context:c},l=e.subscription?this.queryEngine.subscribe(o,u=>{var h;(h=e.subscription)==null||h.call(e,u);},s):void 0;return {data:await this.queryEngine.get(o,{context:s}),unsubscribe:l}})(e.req)}async handleMutation(e){return await this.wrapInMiddlewares(async n=>{let r=this.router.routes[n.resource];if(!r)throw new Error("Invalid resource");return r.handleMutation({req:n,db:this.storage,schema:this.schema})})(e.req)}use(e){return this.middlewares.add(e),this}context(e){return this.contextProvider=e,this}notifySubscribers(e,t){this.queryEngine.handleMutation(e,t);}wrapInMiddlewares(e){return t=>Array.from(this.middlewares.values()).reduceRight((n,r)=>i=>r({req:i,next:n}),e)(t)}},br=se.create;
2
- export{te as Route,re as RouteFactory,ee as Router,ie as SQLStorage,se as Server,z as Storage,Ht as expressAdapter,Xt as routeFactory,Yt as router,br as server};
1
+ import {a,b,v,t,w,x,z as z$2,y}from'./chunk-IT5UC7TA.js';import B from'crypto';import et,{parse}from'qs';import {z as z$1}from'zod';import {Kysely,PostgresDialect,sql}from'kysely';import {jsonArrayFrom as jsonArrayFrom$1,jsonObjectFrom as jsonObjectFrom$1}from'kysely/helpers/mysql';import {jsonArrayFrom as jsonArrayFrom$2,jsonObjectFrom as jsonObjectFrom$2}from'kysely/helpers/postgres';import {jsonArrayFrom,jsonObjectFrom}from'kysely/helpers/sqlite';var X=a(_=>{Object.defineProperty(_,"__esModule",{value:true});_.parse=Ke;_.serialize=Je;var Be=/^[\u0021-\u003A\u003C\u003E-\u007E]+$/,Ue=/^[\u0021-\u003A\u003C-\u007E]*$/,We=/^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i,He=/^[\u0020-\u003A\u003D-\u007E]*$/,Ve=Object.prototype.toString,_e=(()=>{let c=function(){};return c.prototype=Object.create(null),c})();function Ke(c,e){let t=new _e,n=c.length;if(n<2)return t;let r=(e==null?void 0:e.decode)||Ge,i=0;do{let o=c.indexOf("=",i);if(o===-1)break;let a=c.indexOf(";",i),s=a===-1?n:a;if(o>s){i=c.lastIndexOf(";",o-1)+1;continue}let u=be(c,i,o),d=Te(c,o,u),l=c.slice(u,d);if(t[l]===void 0){let h=be(c,o+1,s),y=Te(c,s,h),p=r(c.slice(h,y));t[l]=p;}i=s+1;}while(i<n);return t}function be(c,e,t){do{let n=c.charCodeAt(e);if(n!==32&&n!==9)return e}while(++e<t);return t}function Te(c,e,t){for(;e>t;){let n=c.charCodeAt(--e);if(n!==32&&n!==9)return e+1}return t}function Je(c,e,t){let n=(t==null?void 0:t.encode)||encodeURIComponent;if(!Be.test(c))throw new TypeError(`argument name is invalid: ${c}`);let r=n(e);if(!Ue.test(r))throw new TypeError(`argument val is invalid: ${e}`);let i=c+"="+r;if(!t)return i;if(t.maxAge!==void 0){if(!Number.isInteger(t.maxAge))throw new TypeError(`option maxAge is invalid: ${t.maxAge}`);i+="; Max-Age="+t.maxAge;}if(t.domain){if(!We.test(t.domain))throw new TypeError(`option domain is invalid: ${t.domain}`);i+="; Domain="+t.domain;}if(t.path){if(!He.test(t.path))throw new TypeError(`option path is invalid: ${t.path}`);i+="; Path="+t.path;}if(t.expires){if(!Ze(t.expires)||!Number.isFinite(t.expires.valueOf()))throw new TypeError(`option expires is invalid: ${t.expires}`);i+="; Expires="+t.expires.toUTCString();}if(t.httpOnly&&(i+="; HttpOnly"),t.secure&&(i+="; Secure"),t.partitioned&&(i+="; Partitioned"),t.priority)switch(typeof t.priority=="string"?t.priority.toLowerCase():void 0){case "low":i+="; Priority=Low";break;case "medium":i+="; Priority=Medium";break;case "high":i+="; Priority=High";break;default:throw new TypeError(`option priority is invalid: ${t.priority}`)}if(t.sameSite)switch(typeof t.sameSite=="string"?t.sameSite.toLowerCase():t.sameSite){case true:case "strict":i+="; SameSite=Strict";break;case "lax":i+="; SameSite=Lax";break;case "none":i+="; SameSite=None";break;default:throw new TypeError(`option sameSite is invalid: ${t.sameSite}`)}return i}function Ge(c){if(c.indexOf("%")===-1)return c;try{return decodeURIComponent(c)}catch{return c}}function Ze(c){return Ve.call(c)==="[object Date]"}});var pe="0123456789ABCDEFGHJKMNPQRSTVWXYZ",k=32;var $e=16,me=10,fe=0xffffffffffff;var A;(function(c){c.Base32IncorrectEncoding="B32_ENC_INVALID",c.DecodeTimeInvalidCharacter="DEC_TIME_CHAR",c.DecodeTimeValueMalformed="DEC_TIME_MALFORMED",c.EncodeTimeNegative="ENC_TIME_NEG",c.EncodeTimeSizeExceeded="ENC_TIME_SIZE_EXCEED",c.EncodeTimeValueMalformed="ENC_TIME_MALFORMED",c.PRNGDetectFailure="PRNG_DETECT",c.ULIDInvalid="ULID_INVALID",c.Unexpected="UNEXPECTED",c.UUIDInvalid="UUID_INVALID";})(A||(A={}));var O=class extends Error{constructor(e,t){super(`${t} (${e})`),this.name="ULIDError",this.code=e;}};function ke(c){let e=Math.floor(c()*k);return e===k&&(e=k-1),pe.charAt(e)}function ze(c){var n;let e=Qe(),t=e&&(e.crypto||e.msCrypto)||(typeof B<"u"?B:null);if(typeof(t==null?void 0:t.getRandomValues)=="function")return ()=>{let r=new Uint8Array(1);return t.getRandomValues(r),r[0]/255};if(typeof(t==null?void 0:t.randomBytes)=="function")return ()=>t.randomBytes(1).readUInt8()/255;if((n=B)!=null&&n.randomBytes)return ()=>B.randomBytes(1).readUInt8()/255;throw new O(A.PRNGDetectFailure,"Failed to find a reliable PRNG")}function Qe(){return De()?self:typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:null}function qe(c,e){let t="";for(;c>0;c--)t=ke(e)+t;return t}function Fe(c,e=me){if(isNaN(c))throw new O(A.EncodeTimeValueMalformed,`Time must be a number: ${c}`);if(c>fe)throw new O(A.EncodeTimeSizeExceeded,`Cannot encode a time larger than ${fe}: ${c}`);if(c<0)throw new O(A.EncodeTimeNegative,`Time must be positive: ${c}`);if(Number.isInteger(c)===false)throw new O(A.EncodeTimeValueMalformed,`Time must be an integer: ${c}`);let t,n="";for(let r=e;r>0;r--)t=c%k,n=pe.charAt(t)+n,c=(c-t)/k;return n}function De(){return typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope}function ge(c,e){let t=ze(),n=Date.now();return Fe(n,me)+qe($e,t)}var W=()=>ge().toLowerCase(),U=c=>({then(e,t){try{if(e){let n=e(c);return n instanceof Promise?n:U(n)}return U(c)}catch(n){if(t){let r=t(n);return r instanceof Promise?r:U(r)}throw n}}}),Z=c=>c instanceof Promise?c:U(c);var N=(...c)=>{let e=c.filter(t=>!!t);return e.length===0?{}:e.length===1?e[0]:{$and:e}};var H=class{storage;queue=new Map;scheduled=false;constructor(e){this.storage=e;}async rawFind({resource:e,commonWhere:t,uniqueWhere:n,...r}){return new Promise((i,o)=>{let a=this.getBatchKey({resource:e,commonWhere:t,...r}),s={resource:e,commonWhere:t,uniqueWhere:n,...r,resolve:i,reject:o};this.queue.has(a)||this.queue.set(a,[]);let u=this.queue.get(a);u&&u.push(s),this.scheduled||(this.scheduled=true,setImmediate(()=>{this.processBatch();}));})}getBatchKey(e){let{resource:t,commonWhere:n,...r}=e;return `${t}:${JSON.stringify(n??{})}:${JSON.stringify(r??{})}`}async processBatch(){this.scheduled=false;let e=Array.from(this.queue.entries());this.queue.clear();for(let[,t]of e)try{await this.executeBatchedRequests(t);}catch(n){t.forEach(r=>{r.reject(n);});}}async executeBatchedRequests(e){var h;if(e.length===0)return;let t=e[0],{resource:n,commonWhere:r,include:i,sort:o}=t,a=e.length===1?t.limit:void 0,s=e.map(y=>y.uniqueWhere).filter(y=>y!==void 0),u=r,d=(h=Object.entries(s[0]??{})[0])==null?void 0:h[0];if(s.length>0){let y=s.map(p=>p[d]).filter(p=>p!=null);y.length>0&&(u=N(r,{[d]:{$in:y}}));}let l=await this.storage.get({resource:n,where:u,include:i,sort:o,limit:a});for(let y of e){let p=l;if(y.uniqueWhere){let[f,b]=Object.entries(y.uniqueWhere)[0];p=l.filter(g=>{var m;return ((m=g.value[f])==null?void 0:m.value)===b});}y.resolve(p);}}};function Y(c){return v({resource:c.query.resource,where:c.query.where,include:c.query.include,stepPath:c.stepPath,isMany:c.isMany,relationName:c.relationName})}var V=class{router;storage;schema;logger;queryNodes=new Map;objectNodes=new Map;constructor(e){this.router=e.router,this.storage=e.storage,this.schema=e.schema,this.logger=e.logger;}getRelationalColumns(e){let t=new Map,n=this.schema[e];if(!(n!=null&&n.relations))return t;for(let[r,i]of Object.entries(n.relations))i.type==="one"&&i.relationalColumn&&t.set(String(i.relationalColumn),{relationName:r,targetResource:i.entity.name});return t}ensureObjectNode(e,t,n){let r=this.objectNodes.get(e);return r?n&&r.matchedQueries.add(n):(r={id:e,type:t,matchedQueries:new Set(n?[n]:[]),referencesObjects:new Map,referencedByObjects:new Map},this.objectNodes.set(e,r)),r}storeRelation(e,t,n,r){let i=this.objectNodes.get(e),o=this.objectNodes.get(t);if(i&&i.referencesObjects.set(n,t),o&&r){let a=o.referencedByObjects.get(r);a||(a=new Set,o.referencedByObjects.set(r,a)),a.add(e);}}removeRelation(e,t,n,r){let i=this.objectNodes.get(e),o=this.objectNodes.get(t);if(i&&i.referencesObjects.delete(n),o&&r){let a=o.referencedByObjects.get(r);a&&(a.delete(e),a.size===0&&o.referencedByObjects.delete(r));}}getInverseRelationName(e,t,n){let r=this.schema[e];if(!(r!=null&&r.relations))return;let i=r.relations[n];if(!i)return;let o=this.schema[t];if(o!=null&&o.relations){if(i.type==="many"&&i.foreignColumn){for(let[a,s]of Object.entries(o.relations))if(s.entity.name===e&&s.type==="one"&&s.relationalColumn===i.foreignColumn)return a}if(i.type==="one"&&i.relationalColumn){for(let[a,s]of Object.entries(o.relations))if(s.entity.name===e&&s.type==="many"&&s.foreignColumn===i.relationalColumn)return a}}}updateRelationsFromMutation(e,t,n,r){let i=this.getRelationalColumns(e),o=this.objectNodes.get(t);if(o)for(let[a,{relationName:s,targetResource:u}]of Array.from(i)){if(!(r&&a in r))continue;let l=this.getInverseRelationName(e,u,s),h=o.referencesObjects.get(s),y=n[a];h!==y&&(h&&this.removeRelation(t,h,s,l),y&&(this.ensureObjectNode(y,u),this.storeRelation(t,y,s,l)));}}get(e,t){let n=this.breakdownQuery({query:e,context:(t==null?void 0:t.context)??{}});return this.resolveQuery(n,{context:(t==null?void 0:t.context)??{},batcher:(t==null?void 0:t.batcher)??new H(this.storage)})}subscribe(e,t,n={}){let r=this.breakdownQuery({query:e,context:n}),i={},o=[];for(let a of r){this.logger.debug("[QueryEngine] Subscribing to step",a.stepPath.join("."));let s=Y(a),u=i[a.stepPath.at(-2)??""],d=a.stepPath.at(-1)??"",l=this.queryNodes.get(s);if(l)l.subscriptions.add(t);else if(l={hash:s,queryStep:a,relationName:d,trackedObjects:new Set,subscriptions:new Set([t]),parentQuery:u,childQueries:new Set},this.queryNodes.set(l.hash,l),u){let h=this.queryNodes.get(u);h&&h.childQueries.add(l.hash);}i[d]=s,o.push(()=>{let h=this.queryNodes.get(s);h&&(h.subscriptions.delete(t),h.subscriptions.size===0&&this.queryNodes.delete(s));});}return ()=>{for(let a of o)a();}}breakdownQuery(e){var b;let{query:t,stepPath:n=[],context:r={},parentResource:i}=e,{include:o}=t,a=n.length===0,s=n.at(-1),u,d,l;if(!a&&i&&s){let g=this.schema[i],m=(b=g==null?void 0:g.relations)==null?void 0:b[s];m&&(l=m.type==="many",m.type==="one"?(u=T=>({id:T}),d=T=>T.map(S=>{var w,M;return (M=(w=S.value)==null?void 0:w[m.relationalColumn])==null?void 0:M.value}).filter(S=>S!==void 0)):(u=T=>({[m.foreignColumn]:T}),d=T=>T.map(S=>{var w,M;return (M=(w=S.value)==null?void 0:w.id)==null?void 0:M.value}).filter(S=>S!==void 0)));}let{include:h,...y}=t,f=[this.router.incrementQueryStep({query:y,stepPath:[...n],getWhere:u,referenceGetter:d,isMany:l,relationName:s},r)];if(o&&typeof o=="object"&&Object.keys(o).length>0){let g=this.schema[t.resource];if(!g)throw new Error(`Resource ${t.resource} not found`);f.push(...Object.entries(o).flatMap(([m,T])=>{let S=g.relations[m];if(!S)throw new Error(`Relation ${m} not found for resource ${t.resource}`);let w=S.entity.name;return this.breakdownQuery({query:{resource:w,include:typeof T=="object"?T:void 0},stepPath:[...n,m],context:r,parentResource:t.resource})}));}return f}resolveQuery(e,t){this.logger.debug("[QueryEngine] Resolving query",e.map(i=>i.stepPath.join(".")).join(" -> "));let n={},r=this.resolveStep(e[0],t).then(i=>{this.logger.debug("[QueryEngine] Resolved step",e[0].stepPath.join("."),"with results count:",i.length),n[e[0].stepPath.join(".")]=[{data:i}];});for(let i=1;i<e.length;i++){let o=e[i],a=o.stepPath.slice(0,-1).join(".");r=r.then(async()=>{var u,d;let s=n[a];if(!s){n[o.stepPath.join(".")]=[];return}if(o.referenceGetter&&o.getWhere){let l=new Map;for(let p of s)for(let f of p.data){let b=(d=(u=f==null?void 0:f.value)==null?void 0:u.id)==null?void 0:d.value;if(!b)continue;let m=o.referenceGetter([f])[0];if(m){l.has(m)||l.set(m,new Set);let T=l.get(m);T&&T.add(b);}}let h=Array.from(l.keys());if(h.length===0){n[o.stepPath.join(".")]=[];return}let y=[];for(let p of h){let f=o.getWhere(p),b={...o,relationalWhere:f},g=await this.resolveStep(b,t),m=l.get(p);if(m)for(let T of Array.from(m))y.push({includedBy:T,data:g});}this.logger.debug("[QueryEngine] Resolved step",o.stepPath.join("."),"with results count:",y.reduce((p,f)=>p+f.data.length,0)),n[o.stepPath.join(".")]=y;}else {let l=await this.resolveStep(o,t);n[o.stepPath.join(".")]=[{data:l}];}});}return r=r.then((()=>(this.logger.debug("[QueryEngine] Assembling results"),this.assembleResults(e,n)))),r}assembleResults(e,t){var o,a,s,u,d;this.logger.debug("[QueryEngine] assembleResults: Starting assembly"),this.logger.debug("[QueryEngine] assembleResults: Plan steps:",e.length),this.logger.debug("[QueryEngine] assembleResults: Step results keys:",Object.keys(t));let n=new Map;for(let l of e){let h=l.stepPath.join("."),y=t[h]??[],p=Object.keys(l.query.include??{});this.logger.debug(`[QueryEngine] assembleResults: Processing step "${h}"`,{resource:l.query.resource,includedRelations:p,resultGroups:y.length,isMany:l.isMany,relationName:l.relationName});for(let f of y){this.logger.debug(`[QueryEngine] assembleResults: Processing result group for "${h}"`,{dataCount:f.data.length,includedBy:f.includedBy});for(let b of f.data){let g=(a=(o=b==null?void 0:b.value)==null?void 0:o.id)==null?void 0:a.value;if(!g){this.logger.debug(`[QueryEngine] assembleResults: Skipping data without id in step "${h}"`);continue}let m=h?`${h}.${g}`:g,T=[];if(l.stepPath.length>0&&f.includedBy){let w=l.stepPath.slice(0,-1).join(".");T=[w?`${w}.${f.includedBy}`:f.includedBy],this.logger.debug(`[QueryEngine] assembleResults: Child entity "${m}" has parent keys:`,T,{stepPath:h,parentStepPath:w,includedBy:f.includedBy});}else this.logger.debug(`[QueryEngine] assembleResults: Root entity "${m}" (no parent)`);let S=n.get(m);if(S){this.logger.debug(`[QueryEngine] assembleResults: Entity "${m}" already exists, adding parent keys:`,T);for(let w of T)S.includedBy.add(w);}else this.logger.debug(`[QueryEngine] assembleResults: Adding new entity "${m}"`,{resource:l.query.resource,path:l.stepPath.at(-1)??"",isMany:l.isMany??false,relationName:l.relationName,includedRelations:p,parentKeys:T}),n.set(m,{data:b,includedBy:new Set(T),path:l.stepPath.at(-1)??"",isMany:l.isMany??false,relationName:l.relationName,resourceName:l.query.resource,includedRelations:p});}}}this.logger.debug(`[QueryEngine] assembleResults: Built entriesMap with ${n.size} entries`),this.logger.debug("[QueryEngine] assembleResults: EntriesMap keys:",Array.from(n.keys()));let r=Array.from(n.entries()),i=[];this.logger.debug(`[QueryEngine] assembleResults: Starting assembly phase with ${r.length} entries`);for(let l=r.length-1;l>=0;l--){let[h,y]=r[l],p=this.schema[y.resourceName];this.logger.debug(`[QueryEngine] assembleResults: Processing entry "${h}"`,{resource:y.resourceName,path:y.path,isMany:y.isMany,relationName:y.relationName,includedRelations:y.includedRelations,parentKeys:Array.from(y.includedBy)});for(let f of y.includedRelations){let b=(u=(s=p==null?void 0:p.relations)==null?void 0:s[f])==null?void 0:u.type,g=!!y.data.value[f];if(this.logger.debug(`[QueryEngine] assembleResults: Checking included relation "${f}" for "${h}"`,{relationType:b,hasRelation:g,resourceHasRelation:!!((d=p==null?void 0:p.relations)!=null&&d[f])}),y.data.value[f])this.logger.debug(`[QueryEngine] assembleResults: Relation "${f}" already exists for "${h}"`,y.data.value[f]);else {let m=b==="many"?{value:[]}:{value:null};y.data.value[f]=m,this.logger.debug(`[QueryEngine] assembleResults: Initialized relation "${f}" for "${h}" with`,m);}}if(y.path===""){this.logger.debug(`[QueryEngine] assembleResults: Adding root entity "${h}" to resultData`),i.push(y.data);continue}this.logger.debug(`[QueryEngine] assembleResults: Attaching "${h}" to ${y.includedBy.size} parent(s)`);for(let f of Array.from(y.includedBy)){let b=n.get(f);if(!b){this.logger.warn(`[QueryEngine] assembleResults: WARNING - Parent "${f}" not found in entriesMap for child "${h}"`);continue}let g=y.relationName??y.path;this.logger.debug(`[QueryEngine] assembleResults: Attaching "${h}" to parent "${f}" via relation "${g}"`,{isMany:y.isMany,parentHasRelation:!!b.data.value[g]}),y.isMany?(b.data.value[g]??={value:[]},b.data.value[g].value.push(y.data),this.logger.debug(`[QueryEngine] assembleResults: Added "${h}" to many relation "${g}" on parent "${f}"`,{arrayLength:b.data.value[g].value.length})):(b.data.value[g]=y.data,this.logger.debug(`[QueryEngine] assembleResults: Set one relation "${g}" on parent "${f}" to "${h}"`));}}return this.logger.debug(`[QueryEngine] assembleResults: Assembly complete. Returning ${i.length} root items`),i}resolveStep(e,t){this.logger.debug("[QueryEngine] Resolving step",e.stepPath.join("."),"with query",JSON.stringify(e.query,null,2),"relationalWhere",JSON.stringify(e.relationalWhere,null,2));let{query:n,relationalWhere:r}=e,i=n.where&&r?N(n.where,r):r??n.where,o=i?{...n,where:i}:n;return Z(this.router.get(o,t)).then(a=>(this.loadStepResults(e,a),a))}loadStepResults(e,t$1){this.logger.debug("[QueryEngine] Loading step results",e.stepPath.join("."),"with results",JSON.stringify(t$1,null,2));let n=Y(e),r=this.queryNodes.get(n),i=e.query.resource;if(!r)return;let o=this.getRelationalColumns(i);for(let a of t$1){let s=t(a),u=s.id;this.ensureObjectNode(u,i,n),r.trackedObjects.add(u);for(let[d,{relationName:l,targetResource:h}]of Array.from(o)){let y=s[d];if(y){this.ensureObjectNode(y,h);let p=this.getInverseRelationName(i,h,l);this.storeRelation(u,y,l,p);}}this.loadNestedRelations(i,u,s),this.logger.debug("[QueryEngine] Loaded nested relations for",u);}}loadNestedRelations(e,t,n){let r=this.schema[e];if(r!=null&&r.relations)for(let[i,o]of Object.entries(r.relations)){let a=n[i];if(!a)continue;let s=o.entity.name,u=this.getInverseRelationName(e,s,i);if(o.type==="one")a&&typeof a=="object"&&a.id&&(this.ensureObjectNode(a.id,s),this.storeRelation(t,a.id,i,u),this.loadNestedRelations(s,a.id,a));else if(o.type==="many"&&Array.isArray(a)){for(let d of a)if(d&&typeof d=="object"&&d.id){this.ensureObjectNode(d.id,s);let l=this.getInverseRelationName(s,e,i);l&&this.storeRelation(d.id,t,l,i),this.loadNestedRelations(s,d.id,d);}}}}buildIncludeFromChildQueries(e){let t=this.queryNodes.get(e);if(!t||t.childQueries.size===0)return {};let n={};for(let r of Array.from(t.childQueries)){let i=this.queryNodes.get(r);if(!i||!i.relationName)continue;let o=this.buildIncludeFromChildQueries(r);n[i.relationName]=Object.keys(o).length>0?o:true;}return n}sendInsertsForTree(e,t,n){var a,s;let r=(s=(a=t==null?void 0:t.value)==null?void 0:a.id)==null?void 0:s.value;if(!r)return;let i={procedure:"INSERT",resource:n,resourceId:r,type:"MUTATE",payload:t.value};for(let u of Array.from(e.subscriptions))try{u(i);}catch(d){this.logger.error("[QueryEngine] Error in subscription callback during sendInsertsForTree",{error:d,queryHash:e.hash,resource:n,resourceId:r,stepPath:e.queryStep.stepPath.join(".")});}e.trackedObjects.add(r),this.ensureObjectNode(r,n,e.hash).matchedQueries.add(e.hash);for(let u of Array.from(e.childQueries)){let d=this.queryNodes.get(u);if(!d||!d.relationName)continue;let l=d.relationName,h=d.queryStep.query.resource,y=t.value[l];if(!y)continue;let p=y.value;if(Array.isArray(p))for(let f of p)this.sendInsertsForTree(d,f,h);else p&&typeof p=="object"&&this.sendInsertsForTree(d,p,h);}}handleMutation(e,t$1){if(e.procedure==="INSERT"){if(this.objectNodes.has(e.resourceId))return;let n=t(t$1);if(!n)return;let r={id:e.resourceId,type:e.resource,matchedQueries:new Set,referencesObjects:new Map,referencedByObjects:new Map};this.objectNodes.set(e.resourceId,r);let i=this.getRelationalColumns(e.resource);for(let[a,{relationName:s,targetResource:u}]of Array.from(i)){let d=n[a];if(d){this.ensureObjectNode(d,u);let l=this.getInverseRelationName(e.resource,u,s);this.storeRelation(e.resourceId,d,s,l);}}let o=this.objectNodes.get(e.resourceId);this.getMatchingQueries(e,n).then(a=>{for(let s of a){let u=this.queryNodes.get(s);if(u){u.trackedObjects.add(e.resourceId),o&&o.matchedQueries.add(s);for(let d of Array.from(u.subscriptions))try{d(e);}catch(l){this.logger.error("[QueryEngine] Error in subscription callback during INSERT mutation",{error:l,queryHash:u.hash,resource:e.resource,resourceId:e.resourceId,stepPath:u.queryStep.stepPath.join(".")});}}}});return}if(e.procedure==="UPDATE"){let n=t(t$1);if(!n)return;let r=this.objectNodes.get(e.resourceId),i=new Set((r==null?void 0:r.matchedQueries)??[]);r||(r={id:e.resourceId,type:e.resource,matchedQueries:new Set,referencesObjects:new Map,referencedByObjects:new Map},this.objectNodes.set(e.resourceId,r)),this.updateRelationsFromMutation(e.resource,e.resourceId,n,e.payload),this.getMatchingQueries(e,n).then(o=>{let a=new Set(o),s=[],u=[],d=[];for(let h of o)i.has(h)?d.push(h):s.push(h);for(let h of Array.from(i))a.has(h)||u.push(h);for(let h of s){let y=this.queryNodes.get(h);y&&y.trackedObjects.add(e.resourceId);}for(let h of u){let y=this.queryNodes.get(h);y&&y.trackedObjects.delete(e.resourceId);}let l=this.objectNodes.get(e.resourceId);if(l){for(let h of s)l.matchedQueries.add(h);for(let h of u)l.matchedQueries.delete(h);}for(let h of [...u,...d]){let y=this.queryNodes.get(h);if(y)for(let p of Array.from(y.subscriptions))try{p(e);}catch(f){this.logger.error("[QueryEngine] Error in subscription callback during UPDATE mutation",{error:f,queryHash:y.hash,resource:e.resource,resourceId:e.resourceId,stepPath:y.queryStep.stepPath.join(".")});}}if(s.length>0)for(let h of s){let y=this.queryNodes.get(h);if(!y)continue;let p=this.buildIncludeFromChildQueries(h);this.get({resource:e.resource,where:{id:e.resourceId},include:Object.keys(p).length>0?p:void 0}).then(f=>{!f||f.length===0||this.sendInsertsForTree(y,f[0],e.resource);});}});return}}getMatchingQueries(e,t$1){let n=[];for(let r of Array.from(this.queryNodes.values()))r.queryStep.query.resource===e.resource&&n.push(r);return n.length===0?Z([]):Promise.all(n.map(async r=>{let i=r.queryStep.query.where,o=r.queryStep.query.resource,a=e.resourceId,s=this.objectNodes.get(a);if(!s)return {hash:r.hash,matches:false};if(r.relationName){let y=r.parentQuery?this.queryNodes.get(r.parentQuery):void 0,p=y==null?void 0:y.queryStep.query.resource,f=p?this.getInverseRelationName(p,o,r.relationName):void 0,b=f?s.referencesObjects.get(f):void 0;if(!b)return {hash:r.hash,matches:false};let g=this.objectNodes.get(b);return !g||!y||!g.matchedQueries.has(y.hash)?{hash:r.hash,matches:false}:{hash:r.hash,matches:true}}if(!i)return {hash:r.hash,matches:true};let u=w(i,o,this.schema),d=Object.keys(u).length>0;if(!d&&t$1!==void 0)return {hash:r.hash,matches:x(t$1,i)};let l=await this.storage.get({resource:o,where:{id:a},include:d?u:void 0});if(!l||l.length===0)return {hash:r.hash,matches:false};let h=t(l[0]);return h?{hash:r.hash,matches:x(h,i)}:{hash:r.hash,matches:false}})).then(r=>r.filter(i=>i.matches).map(i=>i.hash))}};var we=b(X(),1);var C=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()}),ee=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()})),Ye=ee.superRefine((c,e)=>{c.id&&e.addIssue({code:z$1.ZodIssueCode.custom,message:"Payload cannot have an id"});}),Re=z$1.object({id:z$1.string().optional(),type:z$1.literal("MUTATE"),resource:z$1.string(),resourceId:z$1.string().optional()}),z=Re.extend({procedure:z$1.string(),payload:z$1.any().optional()}),Q=Re.extend({procedure:z$1.enum(["INSERT","UPDATE"]),payload:Ye});z$1.union([Q,z]);var Se=C.omit({resource:true}),te=z.omit({id:true,type:true,resource:true,procedure:true}),re=Q.omit({id:true,type:true,resource:true,procedure:true});z$1.union([re,te]);var ne=c=>{if(c==null)return c;if(c==="null")return null;if(Array.isArray(c))return c.map(ne);if(typeof c=="object"&&c.constructor===Object){let e={};for(let[t,n]of Object.entries(c))e[t]=ne(n);return e}return c},ve=c=>{let e=c.logger;return async t=>{var n;try{let r=typeof t.headers.getSetCookie=="function"?Object.fromEntries(t.headers):t.headers,i={headers:r,cookies:r.cookie?we.default.parse(r.cookie):{}},o=new URL(t.url),a=o.pathname.split("/"),s=o.searchParams,u=ne(et.parse(s.toString())),d=await((n=c.contextProvider)==null?void 0:n.call(c,{transport:"HTTP",headers:i.headers,cookies:i.cookies,queryParams:u}))??{};if(t.method==="GET"){let l=a[a.length-1],{success:h,data:y,error:p}=Se.safeParse(u);if(!h)return Response.json({message:"Invalid query",code:"INVALID_QUERY",details:p},{status:400});let f=await c.handleQuery({req:{...i,...y,type:"QUERY",resource:l,context:d,queryParams:u}});return !f||!f.data?Response.json({message:"Invalid resource",code:"INVALID_RESOURCE"},{status:400}):Response.json(f.data)}if(t.method==="POST")try{let l=a[a.length-1],h=a[a.length-2],y=t.body?await t.json():{},p;if(l==="insert"||l==="update"){let{success:b,data:g,error:m}=re.safeParse(y);if(!b)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:m},{status:400});p=g;}else {let{success:b,data:g,error:m}=te.safeParse(y);if(!b)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:m},{status:400});p=g;}let f=await c.handleMutation({req:{...i,type:"MUTATE",resource:h,input:p.payload,context:d,resourceId:p.resourceId,procedure:l==="insert"||l==="update"?l.toUpperCase():l,queryParams:{}}});return Response.json(f)}catch(l){return e.error("Error parsing mutation from the client:",l),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}return Response.json({message:"Not found",code:"NOT_FOUND"},{status:404})}catch(r){return e.error("Unexpected error:",r),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}}};var Ie=b(X(),1);var E=z$1.string(),tt=C.extend({id:E,type:z$1.literal("SUBSCRIBE")}),rt=C.extend({id:E,type:z$1.literal("UNSUBSCRIBE")}),nt=C.extend({id:E,type:z$1.literal("QUERY")}),xe=Q.extend({id:E}),st=z.extend({id:E}),it=z$1.union([st,xe]),Me=z$1.union([tt,nt,it,rt]),ot=z$1.object({id:E,type:z$1.literal("REJECT"),resource:z$1.string(),message:z$1.string().optional()}),at=z$1.object({id:E,type:z$1.literal("REPLY"),data:z$1.any()});z$1.union([ot,at,xe]);z$1.object({resource:z$1.string(),data:z$1.array(ee)});var je=c=>{let e={},t=c.logger;return (n,r)=>{var l;let i=h=>{n.send(JSON.stringify(h));},o=W(),a=new Map,s={headers:r.headers,cookies:typeof r.headers.cookie=="string"?Ie.default.parse(r.headers.cookie):{}},u=parse(r.url.split("?")[1]),d=(l=c.contextProvider)==null?void 0:l.call(c,{transport:"WEBSOCKET",headers:s.headers,cookies:s.cookies,queryParams:u});e[o]=n,t.info("Client connected:",o),n.on("message",async h=>{try{t.debug("Message received from the client:",h);let y=Me.parse(JSON.parse(h.toString()));if(y.type==="SUBSCRIBE"||y.type==="QUERY"){let{type:p,id:f,...b}=y,g=p==="SUBSCRIBE",m=await c.handleQuery({req:{...s,...b,type:"QUERY",context:await d??{},queryParams:u},subscription:g?T=>{var S;!T.resourceId||!T.payload||!Object.keys(T.payload).length||(S=e[o])==null||S.send(JSON.stringify(T));}:void 0});if(!m||!m.data)throw new Error("Invalid resource");g&&m.unsubscribe&&a.set(v(b),m.unsubscribe),i({id:f,type:"REPLY",data:{resource:b.resource,data:(m.data??[]).map(T=>T.value)}});}else if(y.type==="UNSUBSCRIBE"){let{type:p,id:f,...b}=y,g=a.get(v(b));g&&(g(),a.delete(v(b)));}else if(y.type==="MUTATE"){let{resource:p}=y;t.debug("Received mutation from client:",y);try{let f=await c.handleMutation({req:{...s,type:"MUTATE",resource:p,input:y.payload,context:{messageId:y.id,...await d??{}},resourceId:y.resourceId,procedure:y.procedure,queryParams:u}});y.procedure&&y.procedure!=="INSERT"&&y.procedure!=="UPDATE"&&i({id:y.id,type:"REPLY",data:f});}catch(f){i({id:y.id,type:"REJECT",resource:p,message:f.message}),t.error("Error parsing mutation from the client:",f);}}}catch(y){t.error("Error handling message from the client:",y);}}),n.on("close",()=>{t.info("Connection closed",o),delete e[o];for(let h of Array.from(a.values()))h();});}};function Ae(c){let e=`${c.protocol}://${c.hostname}${c.url}`,t=new Headers;return Object.entries(c.headers).forEach(([n,r])=>{r&&t.set(n,Array.isArray(r)?r.join(","):r);}),new Request(e,{method:c.method,headers:t,body:c.body&&c.method!=="GET"?JSON.stringify(c.body):void 0})}var pr=(c,e,t)=>{c.ws(`${(t==null?void 0:t.basePath)??""}/ws`,je(e)),c.use(`${(t==null?void 0:t.basePath)??""}/`,(n,r)=>{ve(e)(Ae(n)).then(o=>o.json().then(a=>r.status(o.status).send(a)));});};var se=class c{routes;hooksRegistry=new Map;constructor(e){this.routes=e.routes;for(let t of Object.values(e.routes)){let n=t;n.hooks&&this.hooksRegistry.set(n.resourceSchema.name,n.hooks);}}static create(e){return new c(e)}getHooks(e){return this.hooksRegistry.get(e)}},Rr=c=>se.create({...c}),lt=c=>({handler:e=>({inputValidator:c??z$1.undefined(),handler:e})}),ie=class c{resourceSchema;middlewares;customMutations;authorization;hooks;constructor(e,t,n,r){this.resourceSchema=e,this.middlewares=new Set,this.customMutations=t??{},this.authorization=n,this.hooks=r;}use(...e){for(let t of e)this.middlewares.add(t);return this}withMutations(e){return new c(this.resourceSchema,e({mutation:lt}),this.authorization,this.hooks)}withHooks(e){return new c(this.resourceSchema,this.customMutations,this.authorization,e)}handleQuery=async({req:e,batcher:t})=>await this.wrapInMiddlewares(async n=>{let r={resource:n.resource,where:n.where,include:n.include,lastSyncedAt:n.lastSyncedAt,limit:n.limit,sort:n.sort},i=v(r);return {data:await t.rawFind({resource:n.resource,commonWhere:n.where,uniqueWhere:n.relationalWhere,include:n.include,limit:n.limit,sort:n.sort}),unsubscribe:void 0,queryHash:i}})(e);handleMutation=async({req:e,db:t,schema:n})=>await this.wrapInMiddlewares(async r=>{if(!r.procedure)throw new Error("Procedure is required for mutations");let i=this.customMutations[r.procedure];if(i){let o=i.inputValidator.parse(r.input);return r.input=o,i.handler({req:r,db:t})}else {if(r.procedure==="INSERT"||r.procedure==="UPDATE")return this.handleSet({req:r,db:t,operation:r.procedure,schema:n});throw new Error(`Unknown procedure: ${r.procedure}`)}})(e);getAuthorizationClause(e){var t,n;return (n=(t=this.authorization)==null?void 0:t.read)==null?void 0:n.call(t,{ctx:e.context})}handleSet=async({req:e,db:t$1,operation:n,schema:r})=>{if(!e.input)throw new Error("Payload is required");if(!e.resourceId)throw new Error("ResourceId is required");let i=await t$1.rawFindById(e.resource,e.resourceId);if(n==="INSERT"&&i)throw new Error("Resource already exists");if(n==="UPDATE"&&!i)throw new Error("Resource not found");return t$1.transaction(async({trx:o})=>{var d,l,h,y,p,f,b;let[a,s]=this.resourceSchema.mergeMutation("set",e.input,i);if(!s)throw new Error("Mutation rejected");if(n==="INSERT"){let g=await o.rawInsert(e.resource,e.resourceId,a,(d=e.context)==null?void 0:d.messageId,e.context),m=t(g);if(m.id=m.id??e.resourceId,(l=this.authorization)!=null&&l.insert){let T=this.authorization.insert({ctx:e.context,value:m});if(typeof T=="boolean"){if(!T)throw new Error("Not authorized")}else {let S=w(T,e.resource,r),w$1=Object.keys(S).length>0?await o.rawFindById(e.resource,e.resourceId,S):g,M=t(w$1);if(M.id=M.id??e.resourceId,!x(M,T))throw new Error("Not authorized")}}return {data:g,acceptedValues:s}}if((y=(h=this.authorization)==null?void 0:h.update)!=null&&y.preMutation){let g=t(i);g.id=g.id??e.resourceId;let m=this.authorization.update.preMutation({ctx:e.context,value:g});if(typeof m=="boolean"){if(!m)throw new Error("Not authorized")}else {let T=w(m,e.resource,r),S=Object.keys(T).length>0?await o.rawFindById(e.resource,e.resourceId,T):i,w$1=t(S);if(w$1.id=w$1.id??e.resourceId,!x(w$1,m))throw new Error("Not authorized")}}let u=await o.rawUpdate(e.resource,e.resourceId,a,(p=e.context)==null?void 0:p.messageId,e.context);if((b=(f=this.authorization)==null?void 0:f.update)!=null&&b.postMutation){let g=t(u);g.id=g.id??e.resourceId;let m=this.authorization.update.postMutation({ctx:e.context,value:g});if(typeof m=="boolean"){if(!m)throw new Error("Not authorized")}else {let T=w(m,e.resource,r),S=Object.keys(T).length>0?await o.rawFindById(e.resource,e.resourceId,T):u,w$1=t(S);if(w$1.id=w$1.id??e.resourceId,!x(w$1,m))throw new Error("Not authorized")}}return {data:u,acceptedValues:s}})};wrapInMiddlewares(e){return t=>Array.from(this.middlewares.values()).reduceRight((n,r)=>i=>r({req:i,next:n}),e)(t)}},oe=class c{middlewares;constructor(e=[]){this.middlewares=e;}collectionRoute(e,t){return new ie(e,void 0,t,void 0).use(...this.middlewares)}use(...e){return new c([...this.middlewares,...e])}static create(){return new c}},Sr=oe.create;var q=class{async insert(e,t$1){let n=new Date().toISOString();return t(await this.rawInsert(e.name,t$1.id,{value:Object.fromEntries(Object.entries(t$1).map(([r,i])=>[r,{value:i,_meta:{timestamp:n}}]))}))}async update(e,t$1,n){let r=new Date().toISOString(),{id:i,...o}=n;return t(await this.rawUpdate(e.name,t$1,{value:Object.fromEntries(Object.entries(o).map(([a,s])=>[a,{value:s,_meta:{timestamp:r}}]))}))}};var gt={postgres:{jsonObjectFrom:jsonObjectFrom$2,jsonArrayFrom:jsonArrayFrom$2},mysql:{jsonObjectFrom:jsonObjectFrom$1,jsonArrayFrom:jsonArrayFrom$1},sqlite:{jsonObjectFrom:jsonObjectFrom,jsonArrayFrom:jsonArrayFrom}};function L(c){var r,i,o;let e=(r=c.getExecutor)==null?void 0:r.call(c),t=e==null?void 0:e.adapter;if(!t)return "postgres";let n=((o=(i=t.constructor)==null?void 0:i.name)==null?void 0:o.toLowerCase())??"";return n.includes("postgres")?"postgres":n.includes("mysql")?"mysql":n.includes("sqlite")?"sqlite":"postgres"}function Oe(c){let e=L(c);return gt[e]}var bt="42701";function F(c){var t;if(c.code===bt)return true;let e=((t=c.message)==null?void 0:t.toLowerCase())||"";return e.includes("already exists")||e.includes("duplicate")||e.includes("already defined")}function D(c,e){return c.some(t=>t.name===e)}function Tt(c,e){return (c==null?void 0:c.columns.some(t=>t.name===e))??false}function ae(c,e){let[t]=e.split(".");return D(c,t)}function Ee(c,e,t,n=false){let r=c;return e.unique&&(r=r.unique()),e.nullable||(r=r.notNull()),e.primary&&(r=r.primaryKey()),e.default!==void 0&&(r=r.defaultTo(e.default)),!n&&e.references&&ae(t,e.references)&&(r=r.references(e.references)),r}function Rt(c,e,t,n,r){let i=[];for(let[o,a]of Object.entries(c.fields)){let s=e==null?void 0:e.columns.find(d=>d.name===o),u=a.getStorageFieldType();s?(s.dataType,u.type):(i.push({name:o,storageFieldType:u}),u.references&&!ae(t,u.references)&&n.push({tableName:r,columnName:o,references:u.references}));}return i}async function St(c,e,t,n,r){if(t.length===0)return;let i=c.schema.createTable(e);for(let{name:o,storageFieldType:a}of t)i=i.addColumn(o,a.type,s=>Ee(s,a,n));await i.execute().catch(o=>{if(!F(o))throw r==null||r.error("Error creating table",e,o),o});}async function wt(c,e,t,n,r,i){for(let{name:o,storageFieldType:a}of t){let s=a.references?ae(n,a.references):false;await c.schema.alterTable(e).addColumn(o,a.type,u=>Ee(u,a,n,!s)).execute().catch(u=>{if(!F(u))throw i==null||i.error("Error adding column",o,u),u}),a.references&&!s&&!r.some(u=>u.tableName===e&&u.columnName===o)&&r.push({tableName:e,columnName:o,references:a.references}),a.index&&await c.schema.createIndex(`${e}_${o}_index`).on(e).column(o).execute().catch(()=>{});}}async function vt(c,e,t,n,r,i){let o=`${e}_meta`,a=[];for(let[s,u]of Object.entries(t.fields)){let d=u.getStorageFieldType();Tt(n,s)||a.push({name:s,storageFieldType:d});}if(!n&&a.length>0){let s=c.schema.createTable(o);for(let{name:u,storageFieldType:d}of a)s=s.addColumn(u,"varchar",l=>{let h=l;return d.primary&&(h=h.primaryKey(),D(r,e)&&(h=h.references(`${e}.${u}`))),h});await s.execute().catch(u=>{if(!F(u))throw i==null||i.error("Error creating meta table",o,u),u});}else if(n)for(let{name:s,storageFieldType:u}of a)await c.schema.alterTable(o).addColumn(s,"varchar",d=>{let l=d;return u.primary&&(l=l.primaryKey(),D(r,e)&&(l=l.references(`${e}.${s}`))),l}).execute().catch(d=>{if(!F(d))throw i==null||i.error("Error adding meta column",s,d),d});}async function Le(c,e,t,n,r){let[i,o]=n.split("."),a=`${e}_${t}_fk`;try{await sql`
2
+ ALTER TABLE ${sql.raw(e)}
3
+ ADD CONSTRAINT ${sql.raw(a)}
4
+ FOREIGN KEY (${sql.raw(t)})
5
+ REFERENCES ${sql.raw(i)} (${sql.raw(o)})
6
+ `.execute(c);}catch(s){F(s)||r==null||r.warn("Could not add foreign key constraint",e,t,n,s);}}async function xt(c,e,t,n){for(let{tableName:r,columnName:i,references:o}of e){let a=t.find(d=>d.name===r),s=a==null?void 0:a.columns.find(d=>d.name===i),[u]=o.split(".");a&&s&&D(t,u)&&await Le(c,r,i,o,n);}}async function Mt(c,e,t,n){for(let[r,i]of Object.entries(e)){let o=`${r}_meta`,a=t.find(s=>s.name===o);if(a)for(let[s,u]of Object.entries(i.fields)){let d=u.getStorageFieldType(),l=a.columns.find(h=>h.name===s);d.primary&&l&&D(t,r)&&await Le(c,o,s,`${r}.${s}`,n);}}}async function Pe(c,e,t){let n=await c.introspection.getTables(),r=[];for(let[o,a]of Object.entries(e)){let s=n.find(l=>l.name===o),u=n.find(l=>l.name===`${o}_meta`),d=Rt(a,s,n,r,o);if(s)for(let[l,h]of Object.entries(a.fields)){let y=s.columns.find(f=>f.name===l),p=h.getStorageFieldType();y&&y.dataType!==p.type&&(t==null||t.warn("Column type mismatch:",l,"expected to have type:",p.type,"but has type:",y.dataType));}!s&&d.length>0?await St(c,o,d,n,t):s&&await wt(c,o,d,n,r,t),await vt(c,o,a,u,n,t);}let i=await c.introspection.getTables();await xt(c,r,i,t),await Mt(c,e,i,t);}function K(c,e,t,n){if(!c)throw new Error("Schema not initialized");let r=c[e];if(!r)throw new Error("Resource not found");let i=n.$or,o=n.$and;return (i?t.or:t.and)(i?n.$or.map(a=>K(c,e,t,a)):o?n.$and.map(a=>K(c,e,t,a)):Object.entries(n).map(([a,s])=>{var u,d;if(r.fields[a])return (s==null?void 0:s.$eq)!==void 0?t(`${e}.${a}`,s.$eq===null?"is":"=",s.$eq):(s==null?void 0:s.$in)!==void 0?t(`${e}.${a}`,"in",s.$in):(s==null?void 0:s.$not)!==void 0?((u=s==null?void 0:s.$not)==null?void 0:u.$in)!==void 0?t(`${e}.${a}`,"not in",s.$not.$in):((d=s==null?void 0:s.$not)==null?void 0:d.$eq)!==void 0?t(`${e}.${a}`,s.$not.$eq===null?"is not":"!=",s.$not.$eq):t(`${e}.${a}`,s.$not===null?"is not":"!=",s.$not):(s==null?void 0:s.$gt)!==void 0?t(`${e}.${a}`,">",s.$gt):(s==null?void 0:s.$gte)!==void 0?t(`${e}.${a}`,">=",s.$gte):(s==null?void 0:s.$lt)!==void 0?t(`${e}.${a}`,"<",s.$lt):(s==null?void 0:s.$lte)!==void 0?t(`${e}.${a}`,"<=",s.$lte):t(`${e}.${a}`,s===null?"is":"=",s);if(r.relations[a]){let l=r.relations[a],h=l.entity.name;return l.type==="many"?t.exists(ce(c,h,t.selectFrom(h).select("id").whereRef(l.foreignColumn,"=",`${e}.id`),s)):K(c,h,t,s)}return null}).filter(Boolean))}function J(c,e,t,n){let r=c[e];if(!r)throw new Error("Resource not found");if(!n)return t;if(n.$and){for(let i of n.$and)t=J(c,e,t,i);return t}else if(n.$or){for(let i of n.$or)t=J(c,e,t,i);return t}for(let[i,o]of Object.entries(n)){if(!r.relations[i])continue;let a=r.relations[i],s=a.entity.name,u=a.type==="one"?"id":a.foreignColumn,d=a.type==="one"?a.relationalColumn:"id";t=t.leftJoin(s,`${s}.${u}`,`${e}.${d}`),o instanceof Object&&!Array.isArray(o)&&o!==null&&(t=J(c,s,t,o));}return t}function ce(c,e,t,n){return !n||Object.keys(n).length===0?t:(t=J(c,e,t,n),t.where(r=>K(c,e,r,n)))}function It(c,e,t,n,r){let i=L(r),o=e[t];if(i==="sqlite"&&(o!=null&&o.fields)){let a=Object.keys(o.fields),s=c.selectFrom(n);for(let u of a)s=s.select(`${n}.${u}`);return s}return c.selectFrom(n).selectAll(n)}function jt(c,e,t,n,r){let i=L(r),o=e[t];if(i==="sqlite"&&(o!=null&&o.fields)){let a=Object.keys(o.fields),s=c.selectFrom(n);for(let u of a)s=s.select(`${n}.${u}`);return s}return c.selectFrom(n).selectAll(n)}function G(c,e,t,n,r,i){if(!n)return t;if(!c)throw new Error("Schema not initialized");let o=c[e];if(!o)throw new Error(`Resource not found: ${e}`);let{jsonObjectFrom:a,jsonArrayFrom:s}=r;for(let u of Object.keys(n)){if(!o.relations[u])throw new Error(`Relation ${u} not found in resource ${e}`);let d=o.relations[u],l=d.entity.name,h=n[u],y=d.type==="one"?"id":d.foreignColumn,p=d.type==="one"?d.relationalColumn:"id",f=d.type==="one"?a:s,b=typeof h=="object"&&h!==null;t=t.select(g=>{let m=`${l}_meta`,T=jt(g,c,l,l,i).whereRef(`${l}.${y}`,"=",`${e}.${p}`).select(S=>a(It(S,c,l,m,i).whereRef(`${m}.id`,"=",`${l}.id`)).as("_meta"));return b&&(T=G(c,l,T,h,r,i)),f(T).as(u)});}return t}var ue=class c extends q{db;dialectHelpers;schema;logger;server;mutationStack=[];constructor(e,t,n,r){super(),this.isKyselyLike(e)?this.db=e:this.db=new Kysely({dialect:new PostgresDialect({pool:e})}),this.dialectHelpers=Oe(this.db),this.schema=t,this.logger=n,this.server=r,this.rawInsert=this.rawInsert.bind(this),this.rawUpdate=this.rawUpdate.bind(this);}async init(e,t,n){this.schema=e,this.logger=t,this.server=n,await Pe(this.db,e,t);}selectMetaColumns(e,t,n){var o;let r=L(this.db),i=(o=this.schema)==null?void 0:o[t];if(r==="sqlite"&&(i!=null&&i.fields)){let a=Object.keys(i.fields),s=e.selectFrom(n);for(let u of a)s=s.select(`${n}.${u}`);return s}return e.selectFrom(n).selectAll(n)}async rawFindById(e,t,n){if(!this.schema)throw new Error("Schema not initialized");let r=`${e}_meta`,i=await this.db.selectFrom(e).where("id","=",t).selectAll(e).select(s=>this.dialectHelpers.jsonObjectFrom(this.selectMetaColumns(s,e,r).whereRef(`${r}.id`,"=",`${e}.id`)).as("_meta"));i=G(this.schema,e,i,n,this.dialectHelpers,this.db);let o=await i.executeTakeFirst();if(!o)return;let a=this.parseRelationalJsonStrings(o,e);return this.convertToMaterializedLiveType(a)}async findOne(e,t$1,n){let r=await this.rawFindById(e.name,t$1,n==null?void 0:n.include);if(r)return t(r)}async get(e){if(!this.schema)throw new Error("Schema not initialized");let{resource:t,where:n,include:r,limit:i,sort:o}=e,a=`${t}_meta`,s=this.db.selectFrom(t).selectAll(t).select(d=>this.dialectHelpers.jsonObjectFrom(this.selectMetaColumns(d,t,a).whereRef(`${a}.id`,"=",`${t}.id`)).as("_meta"));s=ce(this.schema,t,s,n),s=G(this.schema,t,s,r,this.dialectHelpers,this.db),i!==void 0&&(s=s.limit(i)),o!==void 0&&o.forEach(d=>{s=s.orderBy(d.key,d.direction);});let u=await s.execute();return u.length===0?[]:u.map(d=>{let l=this.parseRelationalJsonStrings(d,t);return this.convertToMaterializedLiveType(l)})}async find(e,t$1){return (await this.get({resource:e.name,where:t$1==null?void 0:t$1.where,include:t$1==null?void 0:t$1.include,limit:t$1==null?void 0:t$1.limit,sort:t$1==null?void 0:t$1.sort})).map(r=>t(r))}async rawInsert(e,t,n,r,i){var l,h,y;let o=(h=(l=this.server)==null?void 0:l.router)==null?void 0:h.getHooks(e),a=n;if(o!=null&&o.beforeInsert){let p=await o.beforeInsert({ctx:i,value:a,db:this});p&&(a=p);}let s={},u={};for(let[p,f]of Object.entries(a.value)){let b=(y=f._meta)==null?void 0:y.timestamp;b&&(s[p]=f.value,u[p]=b);}await this.db.insertInto(e).values({...s,id:t}).execute().then(()=>{this.db.insertInto(`${e}_meta`).values({...u,id:t}).execute();});let d=this.buildMutation(e,t,"INSERT",a,r);return d&&this.trackMutation(d,a),o!=null&&o.afterInsert&&await o.afterInsert({ctx:i,value:a,db:this}),a}async rawUpdate(e,t,n,r,i){var h,y,p;let o=(y=(h=this.server)==null?void 0:h.router)==null?void 0:y.getHooks(e),a;(o!=null&&o.beforeUpdate||o!=null&&o.afterUpdate)&&(a=await this.rawFindById(e,t));let s=n;if(o!=null&&o.beforeUpdate){let f=await o.beforeUpdate({ctx:i,value:s,previousValue:a,db:this});f&&(s=f);}let u={},d={};for(let[f,b]of Object.entries(s.value)){let g=(p=b._meta)==null?void 0:p.timestamp;g&&(u[f]=b.value,d[f]=g);}await Promise.all([this.db.updateTable(e).set(u).where("id","=",t).execute(),this.db.insertInto(`${e}_meta`).values({...d,id:t}).onConflict(f=>f.column("id").doUpdateSet(d)).execute()]);let l=this.buildMutation(e,t,"UPDATE",s,r);if(l){let f=await this.rawFindById(e,t);f&&this.trackMutation(l,f);}if(o!=null&&o.afterUpdate){let f=await this.rawFindById(e,t);f&&await o.afterUpdate({ctx:i,value:f,previousValue:a,db:this});}return s}async transaction(e){if(!this.schema)throw new Error("Schema not initialized");if(this.db.isTransaction){let i=Math.random().toString(36).substring(2,15),o=this.mutationStack,a=[];this.mutationStack=a;let s=await this.db.savepoint(i).execute(),u=false,d=false;try{return await e({trx:this,commit:async()=>{await s.releaseSavepoint(i).execute(),u=!0,o.push(...a);},rollback:async()=>{await s.rollbackToSavepoint(i).execute(),d=!0,a.length=0;}}).then(l=>s.isCommitted||s.isRolledBack||u||d?l:s.releaseSavepoint(i).execute().then(()=>(o.push(...a),l)))}catch(l){throw d||await s.rollbackToSavepoint(i).execute().catch(()=>{}),a.length=0,l}finally{this.mutationStack=o;}}let t=[],n=this.mutationStack;this.mutationStack=t;let r=await this.db.startTransaction().execute();try{let i=new c(r,this.schema,this.logger,this.server);return i.mutationStack=t,await e({trx:i,commit:async()=>{await r.commit().execute(),this.notifyMutations(t);},rollback:async()=>{await r.rollback().execute(),t.length=0;}}).then(o=>r.isCommitted||r.isRolledBack?o:r.commit().execute().then(()=>(this.notifyMutations(t),o)))}catch(i){throw await r.rollback().execute(),t.length=0,i}finally{this.mutationStack=n;}}get internalDB(){return this.db}isRelationalField(e,t){var r;if(!this.schema)return false;let n=this.schema[e];return !!((r=n==null?void 0:n.relations)!=null&&r[t])}parseRelationalJsonStrings(e,t){var i,o;if(L(this.db)!=="sqlite"||typeof e!="object"||e===null||e instanceof Date)return e;if(Array.isArray(e))return e.map(a=>this.parseRelationalJsonStrings(a,t));let r={};for(let[a,s]of Object.entries(e))if(a==="_meta"&&typeof s=="string")if(s.startsWith("{")&&s.endsWith("}")||s.startsWith("[")&&s.endsWith("]"))try{r[a]=JSON.parse(s);}catch{r[a]=s;}else r[a]=s;else if(this.isRelationalField(t,a))if(typeof s=="string")if(s.startsWith("{")&&s.endsWith("}")||s.startsWith("[")&&s.endsWith("]"))try{let u=JSON.parse(s);if(this.schema){let d=this.schema[t],l=(i=d==null?void 0:d.relations)==null?void 0:i[a];if(l){let h=l.entity.name;r[a]=this.parseRelationalJsonStrings(u,h);}else r[a]=u;}else r[a]=u;}catch{r[a]=s;}else r[a]=s;else if(typeof s=="object"&&s!==null&&!Array.isArray(s))if(this.schema){let u=this.schema[t],d=(o=u==null?void 0:u.relations)==null?void 0:o[a];if(d){let l=d.entity.name;r[a]=this.parseRelationalJsonStrings(s,l);}else r[a]=s;}else r[a]=s;else Array.isArray(s)?r[a]=s.map(u=>{var d,l;if(typeof u=="string")try{let h=JSON.parse(u);if(this.schema){let y=this.schema[t],p=(d=y==null?void 0:y.relations)==null?void 0:d[a];if(p){let f=p.entity.name;return this.parseRelationalJsonStrings(h,f)}}return h}catch{return u}if(typeof u=="object"&&u!==null&&this.schema){let h=this.schema[t],y=(l=h==null?void 0:h.relations)==null?void 0:l[a];if(y){let p=y.entity.name;return this.parseRelationalJsonStrings(u,p)}}return u}):r[a]=s;else r[a]=s;return r}convertToMaterializedLiveType(e){return {value:Object.entries(e).reduce((t,[n,r])=>{var i,o,a;return n==="_meta"||(n==="id"?t[n]={value:r}:Array.isArray(r)?t[n]={value:r.map(s=>this.convertToMaterializedLiveType(s)),_meta:{timestamp:(i=e==null?void 0:e._meta)==null?void 0:i[n]}}:typeof r=="object"&&r!==null&&!(r instanceof Date)?t[n]={...this.convertToMaterializedLiveType(r),_meta:{timestamp:(o=e==null?void 0:e._meta)==null?void 0:o[n]}}:t[n]={value:r,_meta:{timestamp:(a=e==null?void 0:e._meta)==null?void 0:a[n]}}),t},{})}}isKyselyLike(e){if(e instanceof Kysely)return true;if(!e||typeof e!="object")return false;let t=e,n=typeof t.selectFrom=="function",r=typeof t.startTransaction=="function",i=typeof t.savepoint=="function",o=typeof t.isTransaction=="boolean"||typeof t.isTransaction=="function";return n&&r||i&&o}buildMutation(e,t,n,r,i){var a;let o={};for(let[s,u]of Object.entries(r.value)){if(s==="id")continue;let d=(a=u._meta)==null?void 0:a.timestamp;d&&(o[s]={value:u.value,_meta:{timestamp:d}});}return Object.keys(o).length===0?null:{id:i??W(),type:"MUTATE",resource:e,resourceId:t,procedure:n,payload:o}}trackMutation(e,t){this.db.isTransaction?this.mutationStack.push({mutation:e,entityData:t}):this.notifyMutations([e],t);}notifyMutations(e,t){if(this.server)if(t!==void 0){let n=e;for(let r of n)this.server.notifySubscribers(r,t);}else {let n=e;for(let{mutation:r,entityData:i}of n)this.server.notifySubscribers(r,i);}}};var le=class c{router;storage;schema;middlewares=new Set;logger;contextProvider;queryEngine;constructor(e){var t;this.router=e.router,this.storage=e.storage,this.schema=e.schema,this.logger=z$2({level:e.logLevel??y.INFO}),(t=e.middlewares)==null||t.forEach(n=>{this.middlewares.add(n);}),this.storage.init(this.schema,this.logger,this),this.contextProvider=e.contextProvider,this.queryEngine=new V({router:{get:async(n,r)=>{var l;let{headers:i,cookies:o,queryParams:a,context:s}=(r==null?void 0:r.context)??{};if(!(r!=null&&r.batcher))throw new Error("Batcher is required");let u={...n,type:"QUERY",headers:i,cookies:o,queryParams:a,context:s},d=await((l=this.router.routes[n.resource])==null?void 0:l.handleQuery({req:u,batcher:r.batcher}));return (d==null?void 0:d.data)??[]},incrementQueryStep:(n,r={})=>{var a;let i=(a=this.router.routes[n.query.resource])==null?void 0:a.getAuthorizationClause({...n.query,type:"QUERY",headers:r.headers,cookies:r.cookies,queryParams:r.queryParams,context:r.context});if(typeof i=="boolean"&&!i)throw new Error("Not authorized");let o=N(n.query.where,typeof i=="object"?i:void 0);return {...n,query:{...n.query,where:o}}}},storage:this.storage,schema:this.schema,logger:this.logger});}static create(e){return new c(e)}handleQuery(e){return this.wrapInMiddlewares(async t=>{let{headers:n,cookies:r,queryParams:i,context:o,...a}=t,s={headers:n,cookies:r,queryParams:i,context:o},u=e.subscription?this.queryEngine.subscribe(a,l=>{var h;(h=e.subscription)==null||h.call(e,l);},s):void 0;return {data:await this.queryEngine.get(a,{context:s}),unsubscribe:u}})(e.req)}async handleMutation(e){return await this.wrapInMiddlewares(async n=>{let r=this.router.routes[n.resource];if(!r)throw new Error("Invalid resource");return r.handleMutation({req:n,db:this.storage,schema:this.schema})})(e.req)}use(e){return this.middlewares.add(e),this}context(e){return this.contextProvider=e,this}notifySubscribers(e,t){this.queryEngine.handleMutation(e,t);}wrapInMiddlewares(e){return t=>Array.from(this.middlewares.values()).reduceRight((n,r)=>i=>r({req:i,next:n}),e)(t)}},_r=le.create;export{ie as Route,oe as RouteFactory,se as Router,ue as SQLStorage,le as Server,q as Storage,pr as expressAdapter,Sr as routeFactory,Rr as router,_r as server};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-state/sync",
3
- "version": "0.0.6-canary-12",
3
+ "version": "0.0.6-canary-13",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -21,9 +21,11 @@
21
21
  ],
22
22
  "type": "module",
23
23
  "devDependencies": {
24
+ "@codspeed/vitest-plugin": "5.0.1",
24
25
  "@testing-library/jest-dom": "^6.8.0",
25
26
  "@testing-library/react": "^16.3.0",
26
27
  "@testing-library/react-hooks": "^8.0.1",
28
+ "@types/better-sqlite3": "^7.6.13",
27
29
  "@types/express": "^4.17.21",
28
30
  "@types/express-ws": "^3.0.5",
29
31
  "@types/node": "^20.11.24",
@@ -33,6 +35,7 @@
33
35
  "@types/react-dom": "^18.2.19",
34
36
  "@types/ws": "^8.5.13",
35
37
  "@vitest/coverage-v8": "3.2.4",
38
+ "better-sqlite3": "^12.5.0",
36
39
  "cookie": "^1.0.2",
37
40
  "express": "^4.21.2",
38
41
  "express-ws": "^5.0.2",
@@ -97,6 +100,7 @@
97
100
  "typecheck": "tsc --noEmit --project . && tsc --noEmit --project src/client",
98
101
  "test": "vitest run",
99
102
  "test:watch": "vitest",
100
- "benchmark": "tsx benchmark/benchmark.ts"
103
+ "benchmark": "tsx benchmark/benchmark.ts",
104
+ "bench": "vitest bench --run"
101
105
  }
102
106
  }