@live-state/sync 0.0.5 → 0.0.6-canary-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ import {xxHash32}from'js-xxhash';var O=Object.create;var I=Object.defineProperty;var K=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,M=Object.prototype.hasOwnProperty;var V=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var S=(t,e,n,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of A(e))!M.call(t,a)&&a!==n&&I(t,a,{get:()=>e[a],enumerable:!(i=K(e,a))||i.enumerable});return t};var $=(t,e,n)=>(n=t!=null?O(j(t)):{},S(e||!t||!t.__esModule?I(n,"default",{value:t,enumerable:true}):n,t));var o=class{_value;_meta;_encodeInput;_decodeInput};var m=class extends o{inner;constructor(e){super(),this.inner=e;}encodeMutation(e,n,i){return this.inner.encodeMutation(e,n,i)}mergeMutation(e,n,i){return this.inner.mergeMutation(e,n,i)}getStorageFieldType(){return {...this.inner.getStorageFieldType(),nullable:true}}},y=class t extends o{storageType;convertFunc;isIndex;isUnique;defaultValue;foreignReference;isPrimary;constructor(e,n,i,a,s,l,r){super(),this.storageType=e,this.convertFunc=n,this.isIndex=i??false,this.isUnique=a??false,this.defaultValue=s,this.foreignReference=l,this.isPrimary=r??false;}encodeMutation(e,n,i){return {value:n,_meta:{timestamp:i}}}mergeMutation(e,n,i){return i&&i._meta.timestamp&&n._meta.timestamp&&i._meta.timestamp.localeCompare(n._meta.timestamp)>=0?[i,null]:[{value:this.convertFunc?this.convertFunc(n.value):n.value,_meta:n._meta},n]}getStorageFieldType(){return {type:this.storageType,nullable:false,index:this.isIndex,unique:this.isUnique,default:this.defaultValue,references:this.foreignReference,primary:this.isPrimary}}unique(){return new t(this.storageType,this.convertFunc,this.isIndex,true,this.defaultValue,this.foreignReference,this.isPrimary)}index(){return new t(this.storageType,this.convertFunc,true,this.isUnique,this.defaultValue,this.foreignReference,this.isPrimary)}default(e){return new t(this.storageType,this.convertFunc,this.isIndex,this.isUnique,e,this.foreignReference,this.isPrimary)}primary(){return new t(this.storageType,this.convertFunc,this.isIndex,this.isUnique,this.defaultValue,this.foreignReference,true)}nullable(){return new m(this)}},v=class t extends y{constructor(){super("integer",e=>Number(e));}static create(){return new t}},q=v.create,p=class t extends y{constructor(e){super("varchar",void 0,void 0,void 0,void 0,e);}static create(){return new t}static createId(){return new t().index().unique().primary()}static createReference(e){return new t(e)}},N=p.create,D=p.createId,W=p.createReference,L=class t extends y{constructor(){super("boolean",e=>typeof e=="string"?e.toLowerCase()==="true":!!e);}static create(){return new t}},P=L.create,h=class t extends y{constructor(){super("timestamp",e=>typeof e=="string"?new Date(e):e);}static create(){return new t}},k=h.create;var g=class t extends o{name;fields;relations;constructor(e,n,i){super(),this.name=e,this.fields=n,this.relations=i??{};}encodeMutation(e,n,i){return Object.fromEntries(Object.entries(n).map(([a,s])=>[a,(this.fields[a]??this.relations[a]).encodeMutation("set",s,i)]))}mergeMutation(e,n,i){let a={};return [{value:{...(i==null?void 0:i.value)??{},...Object.fromEntries(Object.entries(n).map(([s,l])=>{let r=this.fields[s]??this.relations[s];if(!r)return [s,l];let[u,d]=r.mergeMutation(e,l,i==null?void 0:i.value[s]);return d&&(a[s]=d),[s,u]}))}},a]}setRelations(e){return new t(this.name,this.fields,e)}getStorageFieldType(){throw new Error("Method not implemented.")}static create(e,n){return new t(e,n)}},G=g.create,f=class t extends o{entity;type;required;relationalColumn;foreignColumn;sourceEntity;constructor(e,n,i,a,s){super(),this.entity=e,this.type=n,this.required=s??false,this.relationalColumn=i,this.foreignColumn=a;}encodeMutation(e,n,i){if(e!=="set")throw new Error("Mutation type not implemented.");if(this.type==="many")throw new Error("Many not implemented.");return {value:n,_meta:{timestamp:i}}}mergeMutation(e,n,i){if(this.type==="many")throw new Error("Many not implemented.");return i&&i._meta.timestamp&&n._meta.timestamp&&i._meta.timestamp.localeCompare(n._meta.timestamp)>=0?[i,null]:[n,n]}getStorageFieldType(){return {type:"varchar",nullable:!this.required,references:`${this.entity.name}.${String(this.foreignColumn??this.relationalColumn??"id")}`}}toJSON(){return {entityName:this.entity.name,type:this.type,required:this.required,relationalColumn:this.relationalColumn,foreignColumn:this.foreignColumn}}static createOneFactory(){return (e,n,i)=>new t(e,"one",n,void 0,i??false)}static createManyFactory(){return (e,n,i)=>new t(e,"many",void 0,n,i??false)}},H=(t,e)=>({$type:"relations",objectName:t.name,relations:e({one:f.createOneFactory(),many:f.createManyFactory()})}),x=t=>t?Array.isArray(t.value)?t.value.map(n=>x(n)):typeof t.value!="object"||t.value===null||t.value instanceof Date?t.value:Object.fromEntries(Object.entries(t.value).map(([n,i])=>Array.isArray(i)?[n,i.map(a=>x(a))]:[n,x(i)])):void 0,B=t=>Object.fromEntries(Object.entries(t).flatMap(([e,n])=>{if(n.$type==="relations")return [];let i=n,a=Object.values(t).find(s=>s.$type==="relations"&&s.objectName===n.name);return a&&(i=i.setRelations(a.relations)),[[i.name,i]]}));var Z=t=>xxHash32(JSON.stringify(t)).toString(32),C=(t,e,n)=>{let i={},a=n[e];if(!a)return i;let s=l=>{l.$and?l.$and.forEach(s):l.$or?l.$or.forEach(s):Object.entries(l).forEach(([r,u])=>{var d;if((d=a.relations)!=null&&d[r]&&(i[r]=true,typeof u=="object"&&u!==null&&!Array.isArray(u))){let b=C(u,a.relations[r].entity.name,n);Object.keys(b).length>0&&(i[r]=b);}});};return s(t),i},c=(t,e,n=false)=>Object.entries(e).every(([i,a])=>{if(i==="$and")return a.every(l=>c(t,l,n));if(i==="$or")return a.some(l=>c(t,l,n));let s=(a==null?void 0:a.$eq)!==void 0?a==null?void 0:a.$eq:a;if(typeof a=="object"&&a!==null&&(a==null?void 0:a.$eq)===void 0){if(a.$in!==void 0){let r=t[i];return r===void 0?false:n?!a.$in.includes(r):a.$in.includes(r)}if(a.$not!==void 0&&!n)return c(t,{[i]:a.$not},true);if(a.$gt!==void 0){let r=t[i];return typeof r!="number"?false:n?r<=a.$gt:r>a.$gt}if(a.$gte!==void 0){let r=t[i];return typeof r!="number"?false:n?r<a.$gte:r>=a.$gte}if(a.$lt!==void 0){let r=t[i];return typeof r!="number"?false:n?r>=a.$lt:r<a.$lt}if(a.$lte!==void 0){let r=t[i];return typeof r!="number"?false:n?r>a.$lte:r<=a.$lte}let l=t[i];return !l||typeof l!="object"&&!Array.isArray(l)?false:Array.isArray(l)?n?!l.some(r=>c(r,a,false)):l.some(r=>c(r,a,false)):c(l,a,n)}return n?t[i]!==s:t[i]===s}),T={CRITICAL:0,ERROR:1,WARN:2,INFO:3,DEBUG:4},R=class{level;prefix;constructor(e={}){this.level=e.level??T.INFO,this.prefix=e.prefix?`[${e.prefix}] `:"";}critical(...e){this.level>=T.CRITICAL&&console.error(`${this.prefix}[CRITICAL]`,...e);}error(...e){this.level>=T.ERROR&&console.error(`${this.prefix}[ERROR]`,...e);}warn(...e){this.level>=T.WARN&&console.warn(`${this.prefix}[WARN]`,...e);}info(...e){this.level>=T.INFO&&console.log(`${this.prefix}[INFO]`,...e);}debug(...e){this.level>=T.DEBUG&&console.log(`${this.prefix}[DEBUG]`,...e);}setLevel(e){this.level=e;}getLevel(){return this.level}},ee=t=>new R(t);export{V as a,$ as b,o as c,m as d,y as e,v as f,q as g,p as h,N as i,D as j,W as k,L as l,P as m,h as n,k as o,g as p,G as q,f as r,H as s,x as t,B as u,Z as v,C as w,c as x,T as y,ee as z};
package/dist/client.js CHANGED
@@ -1 +1 @@
1
- import {d,c,a,f,e,b}from'./chunk-RCXJM33Z.js';import {useSyncExternalStore,useEffect}from'react';import {xxHash32}from'js-xxhash';import {jsx,Fragment}from'react/jsx-runtime';import {z}from'zod';import {stringify}from'qs';import ae from'fast-deep-equal';import {openDB}from'idb';var g=l=>xxHash32(JSON.stringify(l)).toString(32);var m=(l,e,t=false)=>Object.entries(e).every(([i,s])=>{if(i==="$and")return s.every(o=>m(l,o,t));if(i==="$or")return s.some(o=>m(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 m(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=>m(n,s,false)):o.some(n=>m(n,s,false)):m(o,s,t)}return t?l[i]!==r:l[i]===r}),y={CRITICAL:0,ERROR:1,WARN:2,INFO:3,DEBUG:4},C=class{level;prefix;constructor(e={}){this.level=e.level??y.INFO,this.prefix=e.prefix?`[${e.prefix}] `:"";}critical(...e){this.level>=y.CRITICAL&&console.error(`${this.prefix}[CRITICAL]`,...e);}error(...e){this.level>=y.ERROR&&console.error(`${this.prefix}[ERROR]`,...e);}warn(...e){this.level>=y.WARN&&console.warn(`${this.prefix}[WARN]`,...e);}info(...e){this.level>=y.INFO&&console.log(`${this.prefix}[INFO]`,...e);}debug(...e){this.level>=y.DEBUG&&console.log(`${this.prefix}[DEBUG]`,...e);}setLevel(e){this.level=e;}getLevel(){return this.level}},T=l=>new C(l);var j=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)}},J=new j,de=l=>useSyncExternalStore(J.getOrStoreSubscription(l),l.get),he=({children:l,client:e})=>(useEffect(()=>{e.subscribe();},[e.subscribe]),jsx(Fragment,{children:l}));var N=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()}),x=z.record(z.string(),z.object({value:z.string().or(z.number()).or(z.boolean()).or(z.date()).nullable(),_meta:z.object({timestamp:z.string().optional().nullable()}).optional()})),X=x.superRefine((l,e)=>{l.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()}),A=U.extend({procedure:z.enum(["INSERT","UPDATE"]),payload:X});z.union([A,k]);var S=z.string(),ee=z.object({id:S,type:z.literal("SUBSCRIBE"),resource:z.string()}),te=N.extend({id:S,type:z.literal("QUERY")}),H=A.extend({id:S}),ie=k.extend({id:S}),se=z.union([ie,H]);z.union([ee,te,se]);var ne=z.object({id:S,type:z.literal("REJECT"),resource:z.string(),message:z.string().optional()}),re=z.object({id:S,type:z.literal("REPLY"),data:z.any()}),Q=z.union([ne,re,H]),K=z.object({resource:z.string(),data:z.record(z.string(),x)});var E=class{ws=null;url;autoConnect;autoReconnect;reconnectTimeout;reconnectLimit;reconnectAttempts=0;eventListeners=new Map;reconnectTimer=null;intentionallyDisconnected=false;credentials;constructor(e){this.url=e.url,this.autoConnect=e.autoConnect??false,this.autoReconnect=e.autoReconnect??false,this.reconnectTimeout=e.reconnectTimeout??5e3,this.reconnectLimit=e.reconnectLimit,this.credentials=e.credentials,this.autoConnect&&this.connect();}connected(){var e;return ((e=this.ws)==null?void 0:e.readyState)===WebSocket.OPEN}async connect(){if(this.ws&&(this.ws.readyState===WebSocket.OPEN||this.ws.readyState===WebSocket.CONNECTING))return;this.intentionallyDisconnected=false;let e=await b(this.credentials);this.ws=new WebSocket(this.url+(e?`?${stringify(e)}`:"")),this.ws.addEventListener("open",this.handleOpen.bind(this)),this.ws.addEventListener("close",this.handleClose.bind(this)),this.ws.addEventListener("error",this.handleError.bind(this)),this.ws.addEventListener("message",this.handleMessage.bind(this));}disconnect(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.intentionallyDisconnected=true,this.ws&&(this.ws.close(),this.ws=null);}addEventListener(e,t){var i;this.eventListeners.has(e)||this.eventListeners.set(e,new Set),(i=this.eventListeners.get(e))==null||i.add(t);}removeEventListener(e,t){var i;this.eventListeners.has(e)&&((i=this.eventListeners.get(e))==null||i.delete(t));}send(e){if(this.ws&&this.ws.readyState===WebSocket.OPEN)this.ws.send(e);else throw new Error("WebSocket is not open")}handleOpen(e){this.reconnectAttempts=0,this.dispatchEvent("open",e),this.dispatchEvent("connectionChange",{open:true});}handleClose(e){this.dispatchEvent("close",e),this.dispatchEvent("connectionChange",{open:false}),this.autoReconnect&&!this.intentionallyDisconnected&&this.scheduleReconnect();}handleError(e){var t,i;this.dispatchEvent("error",e),this.dispatchEvent("connectionChange",{open:false}),(i=(t=e.error)==null?void 0:t.message)!=null&&i.includes("non-101")&&(this.ws&&(this.ws.close(),this.ws=null),this.autoReconnect&&!this.intentionallyDisconnected&&this.scheduleReconnect());}handleMessage(e){this.dispatchEvent("message",e);}scheduleReconnect(){this.reconnectLimit&&this.reconnectAttempts>=this.reconnectLimit||(this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{this.connect();},this.reconnectTimeout));}dispatchEvent(e,t){var i;(i=this.eventListeners.get(e))==null||i.forEach(s=>{s(t);});}};var w=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",O="databases",R=class{db;async init(e,t){var p,h;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,d])=>[c,await g(d)]))),n=await openDB("live-state-databases",1,{upgrade(c){c.objectStoreNames.contains(O)||c.createObjectStore(O);}}),a=(h=await this.getAll(n,O))==null?void 0:h[t];(a==null?void 0:a.schemaHash)!==r&&s++,this.db=await openDB(t,s,{async upgrade(c){[...Object.keys(e),W].forEach(d=>{(a==null?void 0:a.objectHashes[d])!==o[d]&&c.objectStoreNames.contains(d)&&c.deleteObjectStore(d),c.objectStoreNames.contains(d)||c.createObjectStore(d);}),await n.put(O,{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 L=class{constructor(e,t,i,s){this.schema=e;this.logger=i,this.optimisticObjGraph=new w(i),this.kvStorage=new R,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,o])=>{this.kvStorage.get(r).then(n=>{!n||Object.keys(n).length===0||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 h of e$1.sort){let c=a[h.key],d=p[h.key];if(c<d)return h.direction==="asc"?-1:1;if(c>d)return h.direction==="asc"?1:-1}return 0};r.sort(n);}if(e$1.where||e$1.limit){let n=e$1.where?a=>m(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 h=p.value;delete h.id,this.kvStorage.set(e,t.resourceId,h);}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){Object.entries(t).forEach(([i,s])=>{this.addMutation(e,{id:i,type:"MUTATE",resource:e,resourceId:i,procedure:"INSERT",payload:s});});}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,h])=>h.type==="one"?[[h.relationalColumn,p]]:[]));Object.entries(i).forEach(([p,h])=>{let c=this.schema[e].relations[a[p]];if(!a[p])return;let d=s==null?void 0:s.value[p],[,b]=c.mergeMutation("set",h,d);if(b){if(!this.optimisticObjGraph.hasNode(b.value)){let M=c.entity.name;this.optimisticObjGraph.createNode(b.value,M,Object.values(this.schema[M].relations).flatMap(I=>I.type==="many"?[I.entity.name]:[]));}d!=null&&d.value&&this.optimisticObjGraph.removeLink(t,c.entity.name),this.optimisticObjGraph.createLink(t,b.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,[h,c])=>{let d=this.schema[s].relations[h];return d&&(d.type==="one"?p[0].push([h,d.entity.name,c??true]):d.type==="many"&&p[1].push([h,d.entity.name,c??true])),p},[[],[]]);return {value:{...r.value,...Object.fromEntries(o.map(([p,h,c])=>[p,this.materializeOneWithInclude(i.references.get(h),typeof c=="object"&&c!==null?c:{})])),...Object.fromEntries(n.map(([p,h,c])=>{let d=i.referencedBy.get(h),b=d instanceof Set;return [p,b?{value:Array.from(d.values()).map(M=>this.materializeOneWithInclude(M,typeof c=="object"&&c!==null?c:{}))}:this.materializeOneWithInclude(d,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(ae(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 P=class{url;ws;store;logger;remoteSubCounters={};eventListeners=new Set;replyHandlers={};constructor(e){var t,i,s,r;this.url=e.url,this.logger=T({level:e.logLevel??y.INFO}),this.store=new L(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 E({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&&(Object.keys(this.store.schema).forEach(n=>{this.sendWsMessage({id:a(),type:"QUERY",resource:n});}),Object.entries(this.remoteSubCounters).forEach(([n,a$1])=>{a$1>0&&this.sendWsMessage({id:a(),type:"SUBSCRIBE",resource: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);}}subscribeToRemote(e){return this.remoteSubCounters[e]=(this.remoteSubCounters[e]??0)+1,this.sendWsMessage({id:a(),type:"SUBSCRIBE",resource:e}),()=>{this.remoteSubCounters[e]-=1,this.remoteSubCounters[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=l=>{let e=new P(l),t=T({level:l.logLevel??y.INFO,prefix:"Client"});return {client:{ws:e.ws,subscribe:i=>{let s=[];for(let r of i??Object.keys(e.store.schema))s.push(e.subscribeToRemote(r));return ()=>{t.debug("Removing listeners",s),s.forEach(r=>{r();});}},addEventListener:i=>e.addEventListener(i)},store:{query:Object.entries(l.schema).reduce((i,[s,r])=>(i[s]=c._init(r,e),i),{}),mutate:d(()=>{},{apply:(i,s,r)=>{if(s.length<2)return;if(s.length>2)throw new Error("Trying to access an invalid path");let[o,n]=s;if(n==="insert"){let{id:a,...p}=r[0];return e.mutate(o,a,"INSERT",p)}if(n==="update"){let[a,p]=r;return e.mutate(o,a,"UPDATE",p)}return e.genericMutate(o,n,r[0])}})}}};export{he as SubscriptionProvider,Qe as createClient,de as useLiveQuery};
1
+ import {d,c,a,f,e,b}from'./chunk-RCXJM33Z.js';import {useSyncExternalStore,useEffect}from'react';import {xxHash32}from'js-xxhash';import {jsx,Fragment}from'react/jsx-runtime';import {z}from'zod';import {stringify}from'qs';import ae from'fast-deep-equal';import {openDB}from'idb';var g=l=>xxHash32(JSON.stringify(l)).toString(32);var m=(l,e,t=false)=>Object.entries(e).every(([i,s])=>{if(i==="$and")return s.every(o=>m(l,o,t));if(i==="$or")return s.some(o=>m(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 m(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=>m(n,s,false)):o.some(n=>m(n,s,false)):m(o,s,t)}return t?l[i]!==r:l[i]===r}),y={CRITICAL:0,ERROR:1,WARN:2,INFO:3,DEBUG:4},C=class{level;prefix;constructor(e={}){this.level=e.level??y.INFO,this.prefix=e.prefix?`[${e.prefix}] `:"";}critical(...e){this.level>=y.CRITICAL&&console.error(`${this.prefix}[CRITICAL]`,...e);}error(...e){this.level>=y.ERROR&&console.error(`${this.prefix}[ERROR]`,...e);}warn(...e){this.level>=y.WARN&&console.warn(`${this.prefix}[WARN]`,...e);}info(...e){this.level>=y.INFO&&console.log(`${this.prefix}[INFO]`,...e);}debug(...e){this.level>=y.DEBUG&&console.log(`${this.prefix}[DEBUG]`,...e);}setLevel(e){this.level=e;}getLevel(){return this.level}},T=l=>new C(l);var j=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)}},J=new j,de=l=>useSyncExternalStore(J.getOrStoreSubscription(l),l.get),he=({children:l,client:e})=>(useEffect(()=>{e.subscribe();},[e.subscribe]),jsx(Fragment,{children:l}));var x=z.object({resource:z.string(),where:z.record(z.string(),z.any()).optional(),include:z.record(z.string(),z.any()).optional(),lastSyncedAt:z.string().optional(),limit:z.coerce.number().optional(),sort:z.array(z.object({key:z.string(),direction:z.enum(["asc","desc"])})).optional()}),k=z.record(z.string(),z.object({value:z.string().or(z.number()).or(z.boolean()).or(z.date()).nullable(),_meta:z.object({timestamp:z.string().optional().nullable()}).optional()})),X=k.superRefine((l,e)=>{l.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()}),A=U.extend({procedure:z.string(),payload:z.any().optional()}),W=U.extend({procedure:z.enum(["INSERT","UPDATE"]),payload:X});z.union([W,A]);var S=z.string(),ee=x.extend({id:S,type:z.literal("SUBSCRIBE")}),te=x.extend({id:S,type:z.literal("QUERY")}),H=W.extend({id:S}),ie=A.extend({id:S}),se=z.union([ie,H]);z.union([ee,te,se]);var ne=z.object({id:S,type:z.literal("REJECT"),resource:z.string(),message:z.string().optional()}),re=z.object({id:S,type:z.literal("REPLY"),data:z.any()}),Q=z.union([ne,re,H]),K=z.object({resource:z.string(),data:z.record(z.string(),k)});var E=class{ws=null;url;autoConnect;autoReconnect;reconnectTimeout;reconnectLimit;reconnectAttempts=0;eventListeners=new Map;reconnectTimer=null;intentionallyDisconnected=false;credentials;constructor(e){this.url=e.url,this.autoConnect=e.autoConnect??false,this.autoReconnect=e.autoReconnect??false,this.reconnectTimeout=e.reconnectTimeout??5e3,this.reconnectLimit=e.reconnectLimit,this.credentials=e.credentials,this.autoConnect&&this.connect();}connected(){var e;return ((e=this.ws)==null?void 0:e.readyState)===WebSocket.OPEN}async connect(){if(this.ws&&(this.ws.readyState===WebSocket.OPEN||this.ws.readyState===WebSocket.CONNECTING))return;this.intentionallyDisconnected=false;let e=await b(this.credentials);this.ws=new WebSocket(this.url+(e?`?${stringify(e)}`:"")),this.ws.addEventListener("open",this.handleOpen.bind(this)),this.ws.addEventListener("close",this.handleClose.bind(this)),this.ws.addEventListener("error",this.handleError.bind(this)),this.ws.addEventListener("message",this.handleMessage.bind(this));}disconnect(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.intentionallyDisconnected=true,this.ws&&(this.ws.close(),this.ws=null);}addEventListener(e,t){var i;this.eventListeners.has(e)||this.eventListeners.set(e,new Set),(i=this.eventListeners.get(e))==null||i.add(t);}removeEventListener(e,t){var i;this.eventListeners.has(e)&&((i=this.eventListeners.get(e))==null||i.delete(t));}send(e){if(this.ws&&this.ws.readyState===WebSocket.OPEN)this.ws.send(e);else throw new Error("WebSocket is not open")}handleOpen(e){this.reconnectAttempts=0,this.dispatchEvent("open",e),this.dispatchEvent("connectionChange",{open:true});}handleClose(e){this.dispatchEvent("close",e),this.dispatchEvent("connectionChange",{open:false}),this.autoReconnect&&!this.intentionallyDisconnected&&this.scheduleReconnect();}handleError(e){var t,i;this.dispatchEvent("error",e),this.dispatchEvent("connectionChange",{open:false}),(i=(t=e.error)==null?void 0:t.message)!=null&&i.includes("non-101")&&(this.ws&&(this.ws.close(),this.ws=null),this.autoReconnect&&!this.intentionallyDisconnected&&this.scheduleReconnect());}handleMessage(e){this.dispatchEvent("message",e);}scheduleReconnect(){this.reconnectLimit&&this.reconnectAttempts>=this.reconnectLimit||(this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{this.connect();},this.reconnectTimeout));}dispatchEvent(e,t){var i;(i=this.eventListeners.get(e))==null||i.forEach(s=>{s(t);});}};var w=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 P="__meta",O="databases",R=class{db;async init(e,t){var p,h;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,d])=>[c,await g(d)]))),n=await openDB("live-state-databases",1,{upgrade(c){c.objectStoreNames.contains(O)||c.createObjectStore(O);}}),a=(h=await this.getAll(n,O))==null?void 0:h[t];(a==null?void 0:a.schemaHash)!==r&&s++,this.db=await openDB(t,s,{async upgrade(c){[...Object.keys(e),P].forEach(d=>{(a==null?void 0:a.objectHashes[d])!==o[d]&&c.objectStoreNames.contains(d)&&c.deleteObjectStore(d),c.objectStoreNames.contains(d)||c.createObjectStore(d);}),await n.put(O,{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(P,e):new Promise(t=>t(void 0))}setMeta(e,t){var i;return (i=this.db)==null?void 0:i.put(P,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 L=class{constructor(e,t,i,s){this.schema=e;this.logger=i,this.optimisticObjGraph=new w(i),this.kvStorage=new R,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,o])=>{this.kvStorage.get(r).then(n=>{!n||Object.keys(n).length===0||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 h of e$1.sort){let c=a[h.key],d=p[h.key];if(c<d)return h.direction==="asc"?-1:1;if(c>d)return h.direction==="asc"?1:-1}return 0};r.sort(n);}if(e$1.where||e$1.limit){let n=e$1.where?a=>m(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 h=p.value;delete h.id,this.kvStorage.set(e,t.resourceId,h);}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){Object.entries(t).forEach(([i,s])=>{this.addMutation(e,{id:i,type:"MUTATE",resource:e,resourceId:i,procedure:"INSERT",payload:s});});}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,h])=>h.type==="one"?[[h.relationalColumn,p]]:[]));Object.entries(i).forEach(([p,h])=>{let c=this.schema[e].relations[a[p]];if(!a[p])return;let d=s==null?void 0:s.value[p],[,b]=c.mergeMutation("set",h,d);if(b){if(!this.optimisticObjGraph.hasNode(b.value)){let M=c.entity.name;this.optimisticObjGraph.createNode(b.value,M,Object.values(this.schema[M].relations).flatMap(D=>D.type==="many"?[D.entity.name]:[]));}d!=null&&d.value&&this.optimisticObjGraph.removeLink(t,c.entity.name),this.optimisticObjGraph.createLink(t,b.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,[h,c])=>{let d=this.schema[s].relations[h];return d&&(d.type==="one"?p[0].push([h,d.entity.name,c??true]):d.type==="many"&&p[1].push([h,d.entity.name,c??true])),p},[[],[]]);return {value:{...r.value,...Object.fromEntries(o.map(([p,h,c])=>[p,this.materializeOneWithInclude(i.references.get(h),typeof c=="object"&&c!==null?c:{})])),...Object.fromEntries(n.map(([p,h,c])=>{let d=i.referencedBy.get(h),b=d instanceof Set;return [p,b?{value:Array.from(d.values()).map(M=>this.materializeOneWithInclude(M,typeof c=="object"&&c!==null?c:{}))}:this.materializeOneWithInclude(d,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(ae(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;remoteSubCounters={};eventListeners=new Set;replyHandlers={};constructor(e){var t,i,s,r;this.url=e.url,this.logger=T({level:e.logLevel??y.INFO}),this.store=new L(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 E({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&&(Object.keys(this.store.schema).forEach(n=>{this.sendWsMessage({id:a(),type:"QUERY",resource:n});}),Object.entries(this.remoteSubCounters).forEach(([n,a$1])=>{a$1>0&&this.sendWsMessage({id:a(),type:"SUBSCRIBE",resource: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);}}subscribeToRemote(e){return this.remoteSubCounters[e]=(this.remoteSubCounters[e]??0)+1,this.sendWsMessage({id:a(),type:"SUBSCRIBE",resource:e}),()=>{this.remoteSubCounters[e]-=1,this.remoteSubCounters[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=l=>{let e=new I(l),t=T({level:l.logLevel??y.INFO,prefix:"Client"});return {client:{ws:e.ws,subscribe:i=>{let s=[];for(let r of i??Object.keys(e.store.schema))s.push(e.subscribeToRemote(r));return ()=>{t.debug("Removing listeners",s),s.forEach(r=>{r();});}},addEventListener:i=>e.addEventListener(i)},store:{query:Object.entries(l.schema).reduce((i,[s,r])=>(i[s]=c._init(r,e),i),{}),mutate:d(()=>{},{apply:(i,s,r)=>{if(s.length<2)return;if(s.length>2)throw new Error("Trying to access an invalid path");let[o,n]=s;if(n==="insert"){let{id:a,...p}=r[0];return e.mutate(o,a,"INSERT",p)}if(n==="update"){let[a,p]=r;return e.mutate(o,a,"UPDATE",p)}return e.genericMutate(o,n,r[0])}})}}};export{he as SubscriptionProvider,Qe as createClient,de as useLiveQuery};
@@ -1,9 +1,12 @@
1
- import { A as AnyRouter, C as ClientOptions, a as Client } from './index-D8jFoiy6.js';
1
+ import { C as ClientOptions, A as AnyRouter, a as Client } from './index-D8jFoiy6.js';
2
2
  import 'react/jsx-runtime';
3
3
  import 'zod';
4
4
  import 'zod/v3';
5
5
  import 'zod/v4/core';
6
6
 
7
- declare const createClient: <TRouter extends AnyRouter>(opts: Omit<ClientOptions, "storage">) => Client<TRouter, true>;
7
+ type FetchClientOptions = Omit<ClientOptions, "storage"> & {
8
+ fetchOptions?: RequestInit;
9
+ };
10
+ declare const createClient: <TRouter extends AnyRouter>(opts: FetchClientOptions) => Client<TRouter, true>;
8
11
 
9
- export { createClient };
12
+ export { type FetchClientOptions, createClient };
@@ -1 +1 @@
1
- import {d,b,c,f}from'./chunk-RCXJM33Z.js';import {stringify}from'qs';var u=async(...e)=>{let o=await fetch(...e),t;try{t=await o.json();}catch{t=await o.text().catch(()=>{});}if(!o.ok)throw new Error(`Failed to fetch: ${o.status} ${o.statusText}`,{cause:t});return t},S=e=>{let o={get:async t=>{let n=stringify(t),a=await b(e.credentials)??{},r=await u(`${e.url}/${t.resource}${n?`?${n}`:""}`,{headers:{...a,"Content-Type":"application/json"}});return !r||typeof r!="object"?[]:Object.entries(r).map(([i,s])=>({...f(s),id:i}))},subscribe:()=>{throw new Error("Fetch client does not support subscriptions")}};return {query:Object.entries(e.schema).reduce((t,[n,a])=>(t[n]=c._init(a,o,true),t),{}),mutate:d(()=>{},{apply:async(t,n,a)=>{if(n.length<2)return;if(n.length>2)throw new Error("Trying to access an invalid path");let[r,i]=n,s=await b(e.credentials)??{};if(i==="insert"){let{id:c,...y}=a[0];await u(`${e.url}/${r}/insert`,{method:"POST",headers:{...s,"Content-Type":"application/json"},body:JSON.stringify({resourceId:c,payload:e.schema[r].encodeMutation("set",y,new Date().toISOString())})});return}if(i==="update"){let[c,y]=a,{id:O,...m}=y;await u(`${e.url}/${r}/update`,{method:"POST",headers:{...s,"Content-Type":"application/json"},body:JSON.stringify({resourceId:c,payload:e.schema[r].encodeMutation("set",m,new Date().toISOString())})});return}await u(`${e.url}/${r}/${i}`,{method:"POST",headers:{...s,"Content-Type":"application/json"},body:JSON.stringify({payload:a[0]})});}})}};export{S as createClient};
1
+ import {d as d$1,b,c,f}from'./chunk-RCXJM33Z.js';import {stringify}from'qs';var d=async(e,u,t)=>{let r=o=>{if(!o)return {};if(o instanceof Headers){let y={};return o.forEach((f,O)=>{y[O]=f;}),y}return Array.isArray(o)?Object.fromEntries(o):o},a=r(t==null?void 0:t.headers),n=r(u==null?void 0:u.headers),c={...t,...u,headers:{...a,...n}},i=await fetch(e,c),s;try{s=await i.json();}catch{s=await i.text().catch(()=>{});}if(!i.ok)throw new Error(`Failed to fetch: ${i.status} ${i.statusText}`,{cause:s});return s},$=e=>{let u={get:async t=>{let r=stringify(t),a=await b(e.credentials)??{},n=await d(`${e.url}/${t.resource}${r?`?${r}`:""}`,{headers:{...a,"Content-Type":"application/json"}},e.fetchOptions);return !n||typeof n!="object"?[]:Object.entries(n).map(([c,i])=>({...f(i),id:c}))},subscribe:()=>{throw new Error("Fetch client does not support subscriptions")}};return {query:Object.entries(e.schema).reduce((t,[r,a])=>(t[r]=c._init(a,u,true),t),{}),mutate:d$1(()=>{},{apply:async(t,r,a)=>{if(r.length<2)return;if(r.length>2)throw new Error("Trying to access an invalid path");let[n,c]=r,i=await b(e.credentials)??{};if(c==="insert"){let{id:s,...o}=a[0];await d(`${e.url}/${n}/insert`,{method:"POST",headers:{...i,"Content-Type":"application/json"},body:JSON.stringify({resourceId:s,payload:e.schema[n].encodeMutation("set",o,new Date().toISOString())})},e.fetchOptions);return}if(c==="update"){let[s,o]=a,{id:y,...f}=o;await d(`${e.url}/${n}/update`,{method:"POST",headers:{...i,"Content-Type":"application/json"},body:JSON.stringify({resourceId:s,payload:e.schema[n].encodeMutation("set",f,new Date().toISOString())})},e.fetchOptions);return}await d(`${e.url}/${n}/${c}`,{method:"POST",headers:{...i,"Content-Type":"application/json"},body:JSON.stringify({payload:a[0]})},e.fetchOptions);}})}};export{$ as createClient};
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export{e as LiveAtomicType,l as LiveBoolean,f as LiveNumber,p as LiveObject,h as LiveString,n as LiveTimestamp,c as LiveType,x as LogLevel,d as NullableLiveType,r as Relation,m as boolean,s as createRelations,u as createSchema,j as id,t as inferValue,g as number,q as object,k as reference,i as string,o as timestamp}from'./chunk-NJ7LXJAY.js';
1
+ export{e as LiveAtomicType,l as LiveBoolean,f as LiveNumber,p as LiveObject,h as LiveString,n as LiveTimestamp,c as LiveType,y as LogLevel,d as NullableLiveType,r as Relation,m as boolean,s as createRelations,u as createSchema,j as id,t as inferValue,g as number,q as object,k as reference,i as string,o as timestamp}from'./chunk-3SQDLIFN.js';
package/dist/server.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';require('js-xxhash');var V=require('crypto'),rt=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 rt__default=/*#__PURE__*/_interopDefault(rt);var je=Object.create;var ce=Object.defineProperty;var Ee=Object.getOwnPropertyDescriptor;var $e=Object.getOwnPropertyNames;var Ce=Object.getPrototypeOf,Pe=Object.prototype.hasOwnProperty;var Ne=(i,e)=>()=>(e||i((e={exports:{}}).exports,e),e.exports);var ze=(i,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of $e(e))!Pe.call(i,n)&&n!==t&&ce(i,n,{get:()=>e[n],enumerable:!(r=Ee(e,n))||r.enumerable});return i};var ue=(i,e,t)=>(t=i!=null?je(Ce(i)):{},ze(ce(t,"default",{value:i,enumerable:true}),i));var Q=Ne(K=>{Object.defineProperty(K,"__esModule",{value:true});K.parse=He;K.serialize=Je;var Ue=/^[\u0021-\u003A\u003C\u003E-\u007E]+$/,ke=/^[\u0021-\u003A\u003C-\u007E]*$/,Be=/^([.]?[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]*$/,Ge=Object.prototype.toString,Ze=(()=>{let i=function(){};return i.prototype=Object.create(null),i})();function He(i,e){let t=new Ze,r=i.length;if(r<2)return t;let n=(e==null?void 0:e.decode)||Ye,a=0;do{let s=i.indexOf("=",a);if(s===-1)break;let o=i.indexOf(";",a),c=o===-1?r:o;if(s>c){a=i.lastIndexOf(";",s-1)+1;continue}let m=fe(i,a,s),y=he(i,s,m),l=i.slice(m,y);if(t[l]===void 0){let p=fe(i,s+1,c),u=he(i,c,p),h=n(i.slice(p,u));t[l]=h;}a=c+1;}while(a<r);return t}function fe(i,e,t){do{let r=i.charCodeAt(e);if(r!==32&&r!==9)return e}while(++e<t);return t}function he(i,e,t){for(;e>t;){let r=i.charCodeAt(--e);if(r!==32&&r!==9)return e+1}return t}function Je(i,e,t){let r=(t==null?void 0:t.encode)||encodeURIComponent;if(!Ue.test(i))throw new TypeError(`argument name is invalid: ${i}`);let n=r(e);if(!ke.test(n))throw new TypeError(`argument val is invalid: ${e}`);let a=i+"="+n;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(!Be.test(t.domain))throw new TypeError(`option domain is invalid: ${t.domain}`);a+="; Domain="+t.domain;}if(t.path){if(!Qe.test(t.path))throw new TypeError(`option path is invalid: ${t.path}`);a+="; Path="+t.path;}if(t.expires){if(!Xe(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 Ye(i){if(i.indexOf("%")===-1)return i;try{return decodeURIComponent(i)}catch{return i}}function Xe(i){return Ge.call(i)==="[object Date]"}});var E=(i,e,t)=>{let r={},n=t[e];if(!n)return r;let a=s=>{s.$and?s.$and.forEach(a):s.$or?s.$or.forEach(a):Object.entries(s).forEach(([o,c])=>{var m;if((m=n.relations)!=null&&m[o]&&(r[o]=true,typeof c=="object"&&c!==null&&!Array.isArray(c))){let y=E(c,n.relations[o].entity.name,t);Object.keys(y).length>0&&(r[o]=y);}});};return a(i),r},w=(i,e,t=false)=>Object.entries(e).every(([r,n])=>{if(r==="$and")return n.every(s=>w(i,s,t));if(r==="$or")return n.some(s=>w(i,s,t));let a=(n==null?void 0:n.$eq)!==void 0?n==null?void 0:n.$eq:n;if(typeof n=="object"&&n!==null&&(n==null?void 0:n.$eq)===void 0){if(n.$in!==void 0){let o=i[r];return o===void 0?false:t?!n.$in.includes(o):n.$in.includes(o)}if(n.$not!==void 0&&!t)return w(i,{[r]:n.$not},true);if(n.$gt!==void 0){let o=i[r];return typeof o!="number"?false:t?o<=n.$gt:o>n.$gt}if(n.$gte!==void 0){let o=i[r];return typeof o!="number"?false:t?o<n.$gte:o>=n.$gte}if(n.$lt!==void 0){let o=i[r];return typeof o!="number"?false:t?o>=n.$lt:o<n.$lt}if(n.$lte!==void 0){let o=i[r];return typeof o!="number"?false:t?o>n.$lte:o<=n.$lte}let s=i[r];return !s||typeof s!="object"&&!Array.isArray(s)?false:Array.isArray(s)?t?!s.some(o=>w(o,n,false)):s.some(o=>w(o,n,false)):w(s,n,t)}return t?i[r]!==a:i[r]===a}),S={CRITICAL:0,ERROR:1,WARN:2,INFO:3,DEBUG:4},k=class{level;prefix;constructor(e={}){this.level=e.level??S.INFO,this.prefix=e.prefix?`[${e.prefix}] `:"";}critical(...e){this.level>=S.CRITICAL&&console.error(`${this.prefix}[CRITICAL]`,...e);}error(...e){this.level>=S.ERROR&&console.error(`${this.prefix}[ERROR]`,...e);}warn(...e){this.level>=S.WARN&&console.warn(`${this.prefix}[WARN]`,...e);}info(...e){this.level>=S.INFO&&console.log(`${this.prefix}[INFO]`,...e);}debug(...e){this.level>=S.DEBUG&&console.log(`${this.prefix}[DEBUG]`,...e);}setLevel(e){this.level=e;}getLevel(){return this.level}},le=i=>new k(i);var ye="0123456789ABCDEFGHJKMNPQRSTVWXYZ",$=32;var Ve=16,pe=10,de=0xffffffffffff;var L;(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";})(L||(L={}));var M=class extends Error{constructor(e,t){super(`${t} (${e})`),this.name="ULIDError",this.code=e;}};function _e(i){let e=Math.floor(i()*$);return e===$&&(e=$-1),ye.charAt(e)}function Fe(i){var r;let e=Ke(),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 n=new Uint8Array(1);return t.getRandomValues(n),n[0]/255};if(typeof(t==null?void 0:t.randomBytes)=="function")return ()=>t.randomBytes(1).readUInt8()/255;if((r=V__default.default)!=null&&r.randomBytes)return ()=>V__default.default.randomBytes(1).readUInt8()/255;throw new M(L.PRNGDetectFailure,"Failed to find a reliable PRNG")}function Ke(){return De()?self:typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:null}function We(i,e){let t="";for(;i>0;i--)t=_e(e)+t;return t}function qe(i,e=pe){if(isNaN(i))throw new M(L.EncodeTimeValueMalformed,`Time must be a number: ${i}`);if(i>de)throw new M(L.EncodeTimeSizeExceeded,`Cannot encode a time larger than ${de}: ${i}`);if(i<0)throw new M(L.EncodeTimeNegative,`Time must be positive: ${i}`);if(Number.isInteger(i)===false)throw new M(L.EncodeTimeValueMalformed,`Time must be an integer: ${i}`);let t,r="";for(let n=e;n>0;n--)t=i%$,r=ye.charAt(t)+r,i=(i-t)/$;return r}function De(){return typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope}function me(i,e){let t=Fe(),r=Date.now();return qe(r,pe)+We(Ve,t)}var B=()=>me().toLowerCase();var _=(...i)=>{let e=i.filter(t=>!!t);return e.length===0?{}:e.length===1?e[0]:{$and:e}};var F=class{storage;queue=new Map;scheduled=false;constructor(e){this.storage=e;}async rawFind({resource:e,commonWhere:t,uniqueWhere:r,...n}){return new Promise((a,s)=>{let o=this.getBatchKey({resource:e,commonWhere:t,...n}),c={resource:e,commonWhere:t,uniqueWhere:r,...n,resolve:a,reject:s};this.queue.has(o)||this.queue.set(o,[]);let m=this.queue.get(o);m&&m.push(c),this.scheduled||(this.scheduled=true,setImmediate(()=>{this.processBatch();}));})}getBatchKey(e){let{resource:t,commonWhere:r,...n}=e;return `${t}:${JSON.stringify(r??{})}:${JSON.stringify(n??{})}`}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(r){t.forEach(n=>{n.reject(r);});}}async executeBatchedRequests(e){var p,u;if(e.length===0)return;let t=e[0],{resource:r,commonWhere:n,include:a,sort:s}=t,o=e.length===1?t.limit:void 0,c=e.map(h=>h.uniqueWhere).filter(h=>h!==void 0),m=n,y=(p=Object.entries(c[0]??{})[0])==null?void 0:p[0];if(c.length>0){let h=c.map(d=>d[y]).filter(d=>d!=null);h.length>0&&(m=_(n,{[y]:{$in:h}}));}let l=await this.storage.rawFind({resource:r,where:m,include:a,sort:s,limit:o});for(let h of e){let d={};if(h.uniqueWhere){let[f,g]=Object.entries(h.uniqueWhere)[0];for(let[x,v]of Object.entries(l))((u=v.value[f])==null?void 0:u.value)===g&&(d[x]=v);}else Object.assign(d,l);h.resolve(d);}}};var Re=ue(Q());var W=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()}),G=zod.z.record(zod.z.string(),zod.z.object({value:zod.z.string().or(zod.z.number()).or(zod.z.boolean()).or(zod.z.date()).nullable(),_meta:zod.z.object({timestamp:zod.z.string().optional().nullable()}).optional()})),et=G.superRefine((i,e)=>{i.id&&e.addIssue({code:zod.z.ZodIssueCode.custom,message:"Payload cannot have an id"});}),Te=zod.z.object({id:zod.z.string().optional(),type:zod.z.literal("MUTATE"),resource:zod.z.string(),resourceId:zod.z.string().optional()}),C=Te.extend({procedure:zod.z.string(),payload:zod.z.any().optional()}),P=Te.extend({procedure:zod.z.enum(["INSERT","UPDATE"]),payload:et});zod.z.union([P,C]);var ge=W.omit({resource:true}),Z=C.omit({id:true,type:true,resource:true,procedure:true}),H=P.omit({id:true,type:true,resource:true,procedure:true});zod.z.union([H,Z]);var xe=i=>{let e=i.logger;return async t=>{var r;try{let n=typeof t.headers.getSetCookie=="function"?Object.fromEntries(t.headers):t.headers,a={headers:n,cookies:n.cookie?Re.default.parse(n.cookie):{}},s=new URL(t.url),o=s.pathname.split("/"),c=s.searchParams,m=rt__default.default.parse(c.toString()),y=await((r=i.contextProvider)==null?void 0:r.call(i,{transport:"HTTP",headers:a.headers,cookies:a.cookies,queryParams:m}))??{};if(t.method==="GET"){let l=o[o.length-1],{success:p,data:u,error:h}=ge.safeParse(m);if(!p)return Response.json({message:"Invalid query",code:"INVALID_QUERY",details:h},{status:400});let d=await i.handleQuery({req:{...a,...u,type:"QUERY",resource:l,context:y,queryParams:m}});return !d||!d.data?Response.json({message:"Invalid resource",code:"INVALID_RESOURCE"},{status:400}):Response.json(d.data)}if(t.method==="POST")try{let l=o[o.length-1],p=o[o.length-2],u=t.body?await t.json():{},h;if(l==="insert"||l==="update"){let{success:f,data:g,error:x}=H.safeParse(u);if(!f)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:x},{status:400});h=g;}else {let{success:f,data:g,error:x}=Z.safeParse(u);if(!f)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:x},{status:400});h=g;}let d=await i.handleMutation({req:{...a,type:"MUTATE",resource:p,input:h.payload,context:y,resourceId:h.resourceId,procedure:l==="insert"||l==="update"?l.toUpperCase():l,queryParams:{}}});return Response.json(d)}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(n){return e.error("Unexpected error:",n),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}}};var we=ue(Q());var A=zod.z.string(),nt=zod.z.object({id:A,type:zod.z.literal("SUBSCRIBE"),resource:zod.z.string()}),it=W.extend({id:A,type:zod.z.literal("QUERY")}),be=P.extend({id:A}),at=C.extend({id:A}),ot=zod.z.union([at,be]),ve=zod.z.union([nt,it,ot]),st=zod.z.object({id:A,type:zod.z.literal("REJECT"),resource:zod.z.string(),message:zod.z.string().optional()}),ct=zod.z.object({id:A,type:zod.z.literal("REPLY"),data:zod.z.any()});zod.z.union([st,ct,be]);zod.z.object({resource:zod.z.string(),data:zod.z.record(zod.z.string(),G)});var Se=i=>{let e={},t={},r=i.logger;return i.subscribeToMutations(n=>{let a=n;!a.resourceId||!a.payload||(r.debug("Mutation propagated:",a),Object.entries(t[a.resource]??{}).forEach(([s,o])=>{var c;(c=e[s])==null||c.send(JSON.stringify({...a,id:a.id??B()}));}));}),(n,a)=>{var l;let s=p=>{n.send(JSON.stringify(p));},o=B(),c={headers:a.headers,cookies:typeof a.headers.cookie=="string"?we.default.parse(a.headers.cookie):{}},m=rt.parse(a.url.split("?")[1]),y=(l=i.contextProvider)==null?void 0:l.call(i,{transport:"WEBSOCKET",headers:c.headers,cookies:c.cookies,queryParams:m});e[o]=n,r.info("Client connected:",o),n.on("message",async p=>{try{r.debug("Message received from the client:",p);let u=ve.parse(JSON.parse(p.toString()));if(u.type==="SUBSCRIBE"){let{resource:h}=u;t[h]||(t[h]={}),t[h][o]={};}else if(u.type==="QUERY"){let{resource:h}=u,d=await i.handleQuery({req:{...c,type:"QUERY",resource:h,context:await y??{},queryParams:m}});if(!d||!d.data)throw new Error("Invalid resource");s({id:u.id,type:"REPLY",data:{resource:h,data:Object.fromEntries(Object.entries(d.data??{}).map(([f,g])=>[f,g.value]))}});}else if(u.type==="MUTATE"){let{resource:h}=u;r.debug("Received mutation from client:",u);try{let d=await i.handleMutation({req:{...c,type:"MUTATE",resource:h,input:u.payload,context:{messageId:u.id,...await y??{}},resourceId:u.resourceId,procedure:u.procedure,queryParams:m}});u.procedure&&u.procedure!=="INSERT"&&u.procedure!=="UPDATE"&&s({id:u.id,type:"REPLY",data:d});}catch(d){s({id:u.id,type:"REJECT",resource:h,message:d.message}),r.error("Error parsing mutation from the client:",d);}}}catch(u){r.error("Error handling message from the client:",u);}}),n.on("close",()=>{r.info("Connection closed",o),delete e[o];for(let p of Object.values(t))delete p[o];});}};function Ie(i){let e=`${i.protocol}://${i.hostname}${i.url}`,t=new Headers;return Object.entries(i.headers).forEach(([r,n])=>{n&&t.set(r,Array.isArray(n)?n.join(","):n);}),new Request(e,{method:i.method,headers:t,body:i.body&&i.method!=="GET"?JSON.stringify(i.body):void 0})}var Zt=(i,e,t)=>{i.ws(`${(t==null?void 0:t.basePath)??""}/ws`,Se(e)),i.use(`${(t==null?void 0:t.basePath)??""}/`,(r,n)=>{xe(e)(Ie(r)).then(s=>s.json().then(o=>n.status(s.status).send(o)));});};var b=i=>i?Array.isArray(i.value)?i.value.map(t=>b(t)):typeof i.value!="object"||i.value===null||i.value instanceof Date?i.value:Object.fromEntries(Object.entries(i.value).map(([t,r])=>Array.isArray(r)?[t,r.map(n=>b(n))]:[t,b(r)])):void 0;var re=class i{routes;constructor(e){this.routes=e.routes;}static create(e){return new i(e)}},fr=i=>re.create({...i}),dt=i=>({handler:e=>({inputValidator:i??zod.z.undefined(),handler:e})}),ne=class i{resourceSchema;middlewares;customMutations;authorization;constructor(e,t,r){this.resourceSchema=e,this.middlewares=new Set,this.customMutations=t??{},this.authorization=r;}use(...e){for(let t of e)this.middlewares.add(t);return this}withMutations(e){return new i(this.resourceSchema,e({mutation:dt}),this.authorization)}handleQuery=async({req:e,batcher:t})=>await this.wrapInMiddlewares(async r=>{var a,s;let n=(s=(a=this.authorization)==null?void 0:a.read)==null?void 0:s.call(a,{ctx:r.context});if(typeof n=="boolean"&&!n)throw new Error("Not authorized");return {data:await t.rawFind({resource:r.resource,commonWhere:_(r.where,typeof n=="object"?n:void 0),uniqueWhere:r.relationalWhere,include:r.include,limit:r.limit,sort:r.sort})}})(e);handleMutation=async({req:e,db:t,schema:r})=>await this.wrapInMiddlewares(async n=>{if(!n.procedure)throw new Error("Procedure is required for mutations");let a=this.customMutations[n.procedure];if(a){let s=a.inputValidator.parse(n.input);return n.input=s,a.handler({req:n,db:t})}else {if(n.procedure==="INSERT"||n.procedure==="UPDATE")return this.handleSet({req:n,db:t,operation:n.procedure,schema:r});throw new Error(`Unknown procedure: ${n.procedure}`)}})(e);handleSet=async({req:e,db:t,operation:r,schema:n})=>{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(r==="INSERT"&&a)throw new Error("Resource already exists");if(r==="UPDATE"&&!a)throw new Error("Resource not found");return t.transaction(async({trx:s})=>{var y,l,p,u,h;let[o,c]=this.resourceSchema.mergeMutation("set",e.input,a);if(!c)throw new Error("Mutation rejected");if(r==="INSERT"){let d=await s.rawInsert(e.resource,e.resourceId,o),f=b(d);if(f.id=f.id??e.resourceId,(y=this.authorization)!=null&&y.insert){let g=this.authorization.insert({ctx:e.context,value:f});if(typeof g=="boolean"){if(!g)throw new Error("Not authorized")}else {let x=E(g,e.resource,n),v=Object.keys(x).length>0?await s.rawFindById(e.resource,e.resourceId,x):d,I=b(v);if(I.id=I.id??e.resourceId,!w(I,g))throw new Error("Not authorized")}}return {data:d,acceptedValues:c}}if((p=(l=this.authorization)==null?void 0:l.update)!=null&&p.preMutation){let d=b(a);d.id=d.id??e.resourceId;let f=this.authorization.update.preMutation({ctx:e.context,value:d});if(typeof f=="boolean"){if(!f)throw new Error("Not authorized")}else {let g=E(f,e.resource,n),x=Object.keys(g).length>0?await s.rawFindById(e.resource,e.resourceId,g):a,v=b(x);if(v.id=v.id??e.resourceId,!w(v,f))throw new Error("Not authorized")}}let m=await s.rawUpdate(e.resource,e.resourceId,o);if((h=(u=this.authorization)==null?void 0:u.update)!=null&&h.postMutation){let d=b(m);d.id=d.id??e.resourceId;let f=this.authorization.update.postMutation({ctx:e.context,value:d});if(typeof f=="boolean"){if(!f)throw new Error("Not authorized")}else {let g=E(f,e.resource,n),x=Object.keys(g).length>0?await s.rawFindById(e.resource,e.resourceId,g):m,v=b(x);if(v.id=v.id??e.resourceId,!w(v,f))throw new Error("Not authorized")}}return {data:m,acceptedValues:c}})};wrapInMiddlewares(e){return t=>Array.from(this.middlewares.values()).reduceRight((r,n)=>a=>n({req:a,next:r}),e)(t)}},ie=class i{middlewares;constructor(e=[]){this.middlewares=e;}collectionRoute(e,t){return new ne(e,void 0,t).use(...this.middlewares)}use(...e){return new i([...this.middlewares,...e])}static create(){return new i}},hr=ie.create;var z=class{async insert(e,t){let r=new Date().toISOString();return b(await this.rawInsert(e.name,t.id,{value:Object.fromEntries(Object.entries(t).map(([n,a])=>[n,{value:a,_meta:{timestamp:r}}]))}))}async update(e,t,r){let n=new Date().toISOString(),{id:a,...s}=r;return b(await this.rawUpdate(e.name,t,{value:Object.fromEntries(Object.entries(s).map(([o,c])=>[o,{value:c,_meta:{timestamp:n}}]))}))}};function q(i,e,t,r){if(!i)throw new Error("Schema not initialized");let n=i[e];if(!n)throw new Error("Resource not found");let a=r.$or,s=r.$and;return (a?t.or:t.and)(a?r.$or.map(o=>q(i,e,t,o)):s?r.$and.map(o=>q(i,e,t,o)):Object.entries(r).map(([o,c])=>{var m,y;if(n.fields[o])return (c==null?void 0:c.$eq)!==void 0?t(`${e}.${o}`,c.$eq===null?"is":"=",c.$eq):(c==null?void 0:c.$in)!==void 0?t(`${e}.${o}`,"in",c.$in):(c==null?void 0:c.$not)!==void 0?((m=c==null?void 0:c.$not)==null?void 0:m.$in)!==void 0?t(`${e}.${o}`,"not in",c.$not.$in):((y=c==null?void 0:c.$not)==null?void 0:y.$eq)!==void 0?t(`${e}.${o}`,c.$not.$eq===null?"is not":"!=",c.$not.$eq):t(`${e}.${o}`,c.$not===null?"is not":"!=",c.$not):(c==null?void 0:c.$gt)!==void 0?t(`${e}.${o}`,">",c.$gt):(c==null?void 0:c.$gte)!==void 0?t(`${e}.${o}`,">=",c.$gte):(c==null?void 0:c.$lt)!==void 0?t(`${e}.${o}`,"<",c.$lt):(c==null?void 0:c.$lte)!==void 0?t(`${e}.${o}`,"<=",c.$lte):t(`${e}.${o}`,c===null?"is":"=",c);if(n.relations[o]){let l=n.relations[o],p=l.entity.name;return l.type==="many"?t.exists(ae(i,p,t.selectFrom(p).select("id").whereRef(l.foreignColumn,"=",`${e}.id`),c)):q(i,p,t,c)}return null}).filter(Boolean))}function D(i,e,t,r){let n=i[e];if(!n)throw new Error("Resource not found");if(!r)return t;if(r.$and){for(let a of r.$and)t=D(i,e,t,a);return t}else if(r.$or){for(let a of r.$or)t=D(i,e,t,a);return t}for(let[a,s]of Object.entries(r)){if(!n.relations[a])continue;let o=n.relations[a],c=o.entity.name,m=o.type==="one"?"id":o.foreignColumn,y=o.type==="one"?o.relationalColumn:"id";t=t.leftJoin(c,`${c}.${m}`,`${e}.${y}`),s instanceof Object&&!Array.isArray(s)&&s!==null&&(t=D(i,c,t,s));}return t}function ae(i,e,t,r){return !r||Object.keys(r).length===0?t:(t=D(i,e,t,r),t.where(n=>q(i,e,n,r)))}function U(i,e,t,r){if(!r)return t;if(!i)throw new Error("Schema not initialized");let n=i[e];if(!n)throw new Error(`Resource not found: ${e}`);for(let a of Object.keys(r)){if(!n.relations[a])throw new Error(`Relation ${a} not found in resource ${e}`);let s=n.relations[a],o=s.entity.name,c=r[a],m=s.type==="one"?"id":s.foreignColumn,y=s.type==="one"?s.relationalColumn:"id",l=s.type==="one"?postgres.jsonObjectFrom:postgres.jsonArrayFrom,p=typeof c=="object"&&c!==null;t=t.select(u=>{let h=u.selectFrom(o).selectAll(o).whereRef(`${o}.${m}`,"=",`${e}.${y}`).select(d=>postgres.jsonObjectFrom(d.selectFrom(`${o}_meta`).selectAll(`${o}_meta`).whereRef(`${o}_meta.id`,"=",`${o}.id`)).as("_meta"));return p&&(h=U(i,o,h,c)),l(h).as(a)});}return t}var oe=class i extends z{db;schema;logger;constructor(e,t,r){super(),this.isKyselyLike(e)?this.db=e:this.db=new kysely.Kysely({dialect:new kysely.PostgresDialect({pool:e})}),this.schema=t,this.logger=r,this.rawInsert=this.rawInsert.bind(this),this.rawUpdate=this.rawUpdate.bind(this);}async init(e,t){var n;this.schema=e,this.logger=t;let r=await this.db.introspection.getTables();for(let[a,s]of Object.entries(e)){let o=r.find(y=>y.name===a);o||await this.db.schema.createTable(a).ifNotExists().execute();let c=`${a}_meta`,m=r.find(y=>y.name===c);m||await this.db.schema.createTable(c).ifNotExists().execute();for(let[y,l]of Object.entries(s.fields)){let p=o==null?void 0:o.columns.find(d=>d.name===y),u=l.getStorageFieldType();p?p.dataType!==u.type&&((n=this.logger)==null||n.warn("Column type mismatch:",y,"expected to have type:",u.type,"but has type:",p.dataType)):(await this.db.schema.alterTable(a).addColumn(y,u.type,d=>{let f=d;return u.unique&&(f=f.unique()),u.nullable||(f=f.notNull()),u.references&&(f=f.references(u.references)),u.primary&&(f=f.primaryKey()),u.default!==void 0&&(f=f.defaultTo(u.default)),f}).execute().catch(d=>{var f;throw (f=this.logger)==null||f.error("Error adding column",y,d),d}),u.index&&await this.db.schema.createIndex(`${a}_${y}_index`).on(a).column(y).execute().catch(()=>{})),(m==null?void 0:m.columns.find(d=>d.name===y))||await this.db.schema.alterTable(c).addColumn(y,"varchar",d=>{let f=d;return u.primary&&(f=f.primaryKey().references(`${a}.${y}`)),f}).execute();}}}async rawFindById(e,t,r){if(!this.schema)throw new Error("Schema not initialized");let n=await this.db.selectFrom(e).where("id","=",t).selectAll(e).select(s=>postgres.jsonObjectFrom(s.selectFrom(`${e}_meta`).selectAll(`${e}_meta`).whereRef(`${e}_meta.id`,"=",`${e}.id`)).as("_meta"));n=U(this.schema,e,n,r);let a=await n.executeTakeFirst();if(a)return this.convertToMaterializedLiveType(a)}async findOne(e,t,r){let n=await this.rawFindById(e.name,t,r==null?void 0:r.include);if(n)return b(n)}async rawFind(e){if(!this.schema)throw new Error("Schema not initialized");let{resource:t,where:r,include:n,limit:a,sort:s}=e,o=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"));o=ae(this.schema,t,o,r),o=U(this.schema,t,o,n),a!==void 0&&(o=o.limit(a)),s!==void 0&&s.forEach(l=>{o=o.orderBy(l.key,l.direction);});let c=await o.execute(),m=Object.fromEntries(c.map(l=>{let{id:p}=l;return [p,l]}));return Object.keys(m).length===0?{}:Object.entries(m).reduce((l,[p,u])=>(l[p]=this.convertToMaterializedLiveType(u),l),{})}async find(e,t){let r=await this.rawFind({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});return Object.fromEntries(Object.entries(r).map(([n,a])=>[n,b(a)]))}async rawInsert(e,t,r){var s;let n={},a={};for(let[o,c]of Object.entries(r.value)){let m=(s=c._meta)==null?void 0:s.timestamp;m&&(n[o]=c.value,a[o]=m);}return await this.db.insertInto(e).values({...n,id:t}).execute().then(()=>{this.db.insertInto(`${e}_meta`).values({...a,id:t}).execute();}),r}async rawUpdate(e,t,r){var s;let n={},a={};for(let[o,c]of Object.entries(r.value)){let m=(s=c._meta)==null?void 0:s.timestamp;m&&(n[o]=c.value,a[o]=m);}return await Promise.all([this.db.updateTable(e).set(n).where("id","=",t).execute(),this.db.insertInto(`${e}_meta`).values({...a,id:t}).onConflict(o=>o.column("id").doUpdateSet(a)).execute()]),r}async transaction(e){if(!this.schema)throw new Error("Schema not initialized");if(this.db.isTransaction){let r=Math.random().toString(36).substring(2,15),n=await this.db.savepoint(r).execute();try{return await e({trx:this,commit:()=>n.releaseSavepoint(r).execute().then(()=>{}),rollback:()=>n.rollbackToSavepoint(r).execute().then(()=>{})}).then(a=>n.isCommitted||n.isRolledBack?a:n.releaseSavepoint(r).execute().then(()=>a))}catch(a){throw await n.rollbackToSavepoint(r).execute().catch(()=>{}),a}}let t=await this.db.startTransaction().execute();try{return await e({trx:new i(t,this.schema,this.logger),commit:()=>t.commit().execute(),rollback:()=>t.rollback().execute()}).then(r=>t.isCommitted||t.isRolledBack?r:t.commit().execute().then(()=>r))}catch(r){throw await t.rollback().execute(),r}}convertToMaterializedLiveType(e){return {value:Object.entries(e).reduce((t,[r,n])=>{var a,s,o;return r==="_meta"||(r==="id"?t[r]={value:n}:Array.isArray(n)?t[r]={value:n.map(c=>this.convertToMaterializedLiveType(c)),_meta:{timestamp:(a=e==null?void 0:e._meta)==null?void 0:a[r]}}:typeof n=="object"&&n!==null&&!(n instanceof Date)?t[r]={...this.convertToMaterializedLiveType(n),_meta:{timestamp:(s=e==null?void 0:e._meta)==null?void 0:s[r]}}:t[r]={value:n,_meta:{timestamp:(o=e==null?void 0:e._meta)==null?void 0:o[r]}}),t},{})}}isKyselyLike(e){if(e instanceof kysely.Kysely)return true;if(!e||typeof e!="object")return false;let t=e,r=typeof t.selectFrom=="function",n=typeof t.startTransaction=="function",a=typeof t.savepoint=="function",s=typeof t.isTransaction=="boolean"||typeof t.isTransaction=="function";return r&&n||a&&s}};var se=class i{router;storage;schema;middlewares=new Set;logger;contextProvider;mutationSubscriptions=new Set;constructor(e){var t;this.router=e.router,this.storage=e.storage,this.schema=e.schema,this.logger=le({level:e.logLevel??S.INFO}),(t=e.middlewares)==null||t.forEach(r=>{this.middlewares.add(r);}),this.storage.init(this.schema,this.logger),this.contextProvider=e.contextProvider;}static create(e){return new i(e)}subscribeToMutations(e){return this.mutationSubscriptions.add(e),()=>{this.mutationSubscriptions.delete(e);}}handleQuery(e){let t=new F(this.storage);return this.wrapInMiddlewares(async r=>{var m;let n=Ae(r,this.schema,{stepId:"query",collectionName:r.resource,included:Object.keys(r.include??{})}),a={headers:r.headers,cookies:r.cookies,queryParams:r.queryParams,context:r.context},s={};for(let y=0;y<n.length;y++){let l=n[y],p=this.router.routes[l.resource];if(!p)throw new Error("Invalid resource");let u=l.getWhere&&l.referenceGetter?l.referenceGetter(s).map(l.getWhere):[void 0],h=(m=s[l.prevStepId??""])==null?void 0:m.flatMap(g=>{var x;return Object.keys(((x=g==null?void 0:g.result)==null?void 0:x.data)??{})}),f=(await Promise.allSettled(u.map(async(g,x)=>{let v=h==null?void 0:h[x],I=await p.handleQuery({req:{type:"QUERY",...l,...a,where:l.where,relationalWhere:g},batcher:t});return {includedBy:v,result:I}}))).flatMap(g=>g.status==="fulfilled"?[g.value]:[]);s[l.stepId]=f;}let o=Object.fromEntries(Object.entries(s).flatMap(([y,l],p)=>l.flatMap(u=>Object.entries(u.result.data).map(([h,d])=>[`${y}.${h}`,{data:d,includedBy:y!=="query"&&u.includedBy?`${y.split(".").slice(0,-1).join(".")}.${u.includedBy}`:void 0,path:y.split(".").slice(-1)[0],isMany:n[p].isMany,collectionName:n[p].collectionName,included:n[p].included}]))));return Object.keys(o).reduceRight((y,l)=>{var h,d;let p=o[l],u=p.path;if(u==="query"&&(y.data[l.replace("query.","")]=p.data),p.included.length)for(let f of p.included)p.data.value[f]??=((d=(h=this.schema[p.collectionName])==null?void 0:h.relations[f])==null?void 0:d.type)==="many"?{value:[]}:{value:null};if(p.includedBy){let f=o[p.includedBy];if(!f)return y;p.isMany?(f.data.value[u]??={value:[]},f.data.value[u].value.push(p.data)):f.data.value[u]=p.data;}return y},{data:{}})})(e.req)}async handleMutation(e){let t=await this.wrapInMiddlewares(async r=>{let n=this.router.routes[r.resource];if(!n)throw new Error("Invalid resource");return n.handleMutation({req:r,db:this.storage,schema:this.schema})})(e.req);if(t&&e.req.type==="MUTATE"&&t.acceptedValues&&(e.req.procedure==="INSERT"||e.req.procedure==="UPDATE")&&e.req.resourceId){let n=t.acceptedValues??{},a=e.req,s=a.resourceId;Object.keys(n).length&&s&&this.mutationSubscriptions.forEach(o=>{o({id:e.req.context.messageId,type:"MUTATE",resource:a.resource,payload:n,resourceId:s,procedure:a.procedure});});}return t}use(e){return this.middlewares.add(e),this}context(e){return this.contextProvider=e,this}wrapInMiddlewares(e){return t=>Array.from(this.middlewares.values()).reduceRight((r,n)=>a=>n({req:a,next:r}),e)(t)}},Cr=se.create;function Ae(i,e,t){let{include:r,where:n,...a}=i,{stepId:s}=t,o=[{...a,...t,where:n}];if(r&&typeof r=="object"&&Object.keys(r).length>0){let c=e[a.resource];if(!c)throw new Error(`Resource ${a.resource} not found`);o.push(...Object.entries(r).flatMap(([m,y])=>{let l=c.relations[m];if(!l)throw new Error(`Relation ${m} not found for resource ${a.resource}`);let p=l.entity.name;return Ae({...a,resource:p,include:y},e,{getWhere:l.type==="one"?u=>({id:u}):u=>({[l.foreignColumn]:u}),referenceGetter:u=>u[s].flatMap(h=>h.result.data?l.type==="one"?Object.values(h.result.data).map(d=>{var f,g;return (g=(f=d.value)==null?void 0:f[l.relationalColumn])==null?void 0:g.value}):Object.keys(h.result.data):[]),stepId:`${s}.${m}`,prevStepId:s,isMany:l.type==="many",collectionName:p,included:typeof y=="object"?Object.keys(y):[]})}));}return o}
2
- exports.Route=ne;exports.RouteFactory=ie;exports.Router=re;exports.SQLStorage=oe;exports.Server=se;exports.Storage=z;exports.expressAdapter=Zt;exports.routeFactory=hr;exports.router=fr;exports.server=Cr;
1
+ 'use strict';var Q=require('crypto'),jsXxhash=require('js-xxhash'),ft=require('qs'),zod=require('zod'),kysely=require('kysely'),postgres=require('kysely/helpers/postgres');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var Q__default=/*#__PURE__*/_interopDefault(Q);var ft__default=/*#__PURE__*/_interopDefault(ft);var De=Object.create;var Te=Object.defineProperty;var Ke=Object.getOwnPropertyDescriptor;var Fe=Object.getOwnPropertyNames;var qe=Object.getPrototypeOf,Ue=Object.prototype.hasOwnProperty;var Be=(i,e)=>()=>(e||i((e={exports:{}}).exports,e),e.exports);var Qe=(i,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Fe(e))!Ue.call(i,n)&&n!==t&&Te(i,n,{get:()=>e[n],enumerable:!(r=Ke(e,n))||r.enumerable});return i};var ge=(i,e,t)=>(t=i!=null?De(qe(i)):{},Qe(Te(t,"default",{value:i,enumerable:true}),i));var oe=Be(H=>{Object.defineProperty(H,"__esModule",{value:true});H.parse=ct;H.serialize=ut;var rt=/^[\u0021-\u003A\u003C\u003E-\u007E]+$/,nt=/^[\u0021-\u003A\u003C-\u007E]*$/,it=/^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i,at=/^[\u0020-\u003A\u003D-\u007E]*$/,ot=Object.prototype.toString,st=(()=>{let i=function(){};return i.prototype=Object.create(null),i})();function ct(i,e){let t=new st,r=i.length;if(r<2)return t;let n=(e==null?void 0:e.decode)||lt,a=0;do{let c=i.indexOf("=",a);if(c===-1)break;let o=i.indexOf(";",a),s=o===-1?r:o;if(c>s){a=i.lastIndexOf(";",c-1)+1;continue}let l=Ie(i,a,c),f=Me(i,c,l),u=i.slice(l,f);if(t[u]===void 0){let h=Ie(i,c+1,s),R=Me(i,s,h),d=n(i.slice(h,R));t[u]=d;}a=s+1;}while(a<r);return t}function Ie(i,e,t){do{let r=i.charCodeAt(e);if(r!==32&&r!==9)return e}while(++e<t);return t}function Me(i,e,t){for(;e>t;){let r=i.charCodeAt(--e);if(r!==32&&r!==9)return e+1}return t}function ut(i,e,t){let r=(t==null?void 0:t.encode)||encodeURIComponent;if(!rt.test(i))throw new TypeError(`argument name is invalid: ${i}`);let n=r(e);if(!nt.test(n))throw new TypeError(`argument val is invalid: ${e}`);let a=i+"="+n;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(!it.test(t.domain))throw new TypeError(`option domain is invalid: ${t.domain}`);a+="; Domain="+t.domain;}if(t.path){if(!at.test(t.path))throw new TypeError(`option path is invalid: ${t.path}`);a+="; Path="+t.path;}if(t.expires){if(!dt(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 lt(i){if(i.indexOf("%")===-1)return i;try{return decodeURIComponent(i)}catch{return i}}function dt(i){return ot.call(i)==="[object Date]"}});var be="0123456789ABCDEFGHJKMNPQRSTVWXYZ",W=32;var Ge=16,xe=10,Re=0xffffffffffff;var C;(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";})(C||(C={}));var $=class extends Error{constructor(e,t){super(`${t} (${e})`),this.name="ULIDError",this.code=e;}};function Ze(i){let e=Math.floor(i()*W);return e===W&&(e=W-1),be.charAt(e)}function He(i){var r;let e=Je(),t=e&&(e.crypto||e.msCrypto)||(typeof Q__default.default<"u"?Q__default.default:null);if(typeof(t==null?void 0:t.getRandomValues)=="function")return ()=>{let n=new Uint8Array(1);return t.getRandomValues(n),n[0]/255};if(typeof(t==null?void 0:t.randomBytes)=="function")return ()=>t.randomBytes(1).readUInt8()/255;if((r=Q__default.default)!=null&&r.randomBytes)return ()=>Q__default.default.randomBytes(1).readUInt8()/255;throw new $(C.PRNGDetectFailure,"Failed to find a reliable PRNG")}function Je(){return et()?self:typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:null}function Ye(i,e){let t="";for(;i>0;i--)t=Ze(e)+t;return t}function Xe(i,e=xe){if(isNaN(i))throw new $(C.EncodeTimeValueMalformed,`Time must be a number: ${i}`);if(i>Re)throw new $(C.EncodeTimeSizeExceeded,`Cannot encode a time larger than ${Re}: ${i}`);if(i<0)throw new $(C.EncodeTimeNegative,`Time must be positive: ${i}`);if(Number.isInteger(i)===false)throw new $(C.EncodeTimeValueMalformed,`Time must be an integer: ${i}`);let t,r="";for(let n=e;n>0;n--)t=i%W,r=be.charAt(t)+r,i=(i-t)/W;return r}function et(){return typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope}function ve(i,e){let t=He(),r=Date.now();return Xe(r,xe)+Ye(Ge,t)}var G=()=>ve().toLowerCase();var z=(...i)=>{let e=i.filter(t=>!!t);return e.length===0?{}:e.length===1?e[0]:{$and:e}};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,r])=>Array.isArray(r)?[t,r.map(n=>S(n))]:[t,S(r)])):void 0;var Se=i=>jsXxhash.xxHash32(JSON.stringify(i)).toString(32),K=(i,e,t)=>{let r={},n=t[e];if(!n)return r;let a=c=>{c.$and?c.$and.forEach(a):c.$or?c.$or.forEach(a):Object.entries(c).forEach(([o,s])=>{var l;if((l=n.relations)!=null&&l[o]&&(r[o]=true,typeof s=="object"&&s!==null&&!Array.isArray(s))){let f=K(s,n.relations[o].entity.name,t);Object.keys(f).length>0&&(r[o]=f);}});};return a(i),r},L=(i,e,t=false)=>Object.entries(e).every(([r,n])=>{if(r==="$and")return n.every(c=>L(i,c,t));if(r==="$or")return n.some(c=>L(i,c,t));let a=(n==null?void 0:n.$eq)!==void 0?n==null?void 0:n.$eq:n;if(typeof n=="object"&&n!==null&&(n==null?void 0:n.$eq)===void 0){if(n.$in!==void 0){let o=i[r];return o===void 0?false:t?!n.$in.includes(o):n.$in.includes(o)}if(n.$not!==void 0&&!t)return L(i,{[r]:n.$not},true);if(n.$gt!==void 0){let o=i[r];return typeof o!="number"?false:t?o<=n.$gt:o>n.$gt}if(n.$gte!==void 0){let o=i[r];return typeof o!="number"?false:t?o<n.$gte:o>=n.$gte}if(n.$lt!==void 0){let o=i[r];return typeof o!="number"?false:t?o>=n.$lt:o<n.$lt}if(n.$lte!==void 0){let o=i[r];return typeof o!="number"?false:t?o>n.$lte:o<=n.$lte}let c=i[r];return !c||typeof c!="object"&&!Array.isArray(c)?false:Array.isArray(c)?t?!c.some(o=>L(o,n,false)):c.some(o=>L(o,n,false)):L(c,n,t)}return t?i[r]!==a:i[r]===a}),j={CRITICAL:0,ERROR:1,WARN:2,INFO:3,DEBUG:4},ae=class{level;prefix;constructor(e={}){this.level=e.level??j.INFO,this.prefix=e.prefix?`[${e.prefix}] `:"";}critical(...e){this.level>=j.CRITICAL&&console.error(`${this.prefix}[CRITICAL]`,...e);}error(...e){this.level>=j.ERROR&&console.error(`${this.prefix}[ERROR]`,...e);}warn(...e){this.level>=j.WARN&&console.warn(`${this.prefix}[WARN]`,...e);}info(...e){this.level>=j.INFO&&console.log(`${this.prefix}[INFO]`,...e);}debug(...e){this.level>=j.DEBUG&&console.log(`${this.prefix}[DEBUG]`,...e);}setLevel(e){this.level=e;}getLevel(){return this.level}},we=i=>new ae(i);var Z=class{storage;queue=new Map;scheduled=false;constructor(e){this.storage=e;}async rawFind({resource:e,commonWhere:t,uniqueWhere:r,...n}){return new Promise((a,c)=>{let o=this.getBatchKey({resource:e,commonWhere:t,...n}),s={resource:e,commonWhere:t,uniqueWhere:r,...n,resolve:a,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:r,...n}=e;return `${t}:${JSON.stringify(r??{})}:${JSON.stringify(n??{})}`}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(r){t.forEach(n=>{n.reject(r);});}}async executeBatchedRequests(e){var h,R;if(e.length===0)return;let t=e[0],{resource:r,commonWhere:n,include:a,sort:c}=t,o=e.length===1?t.limit:void 0,s=e.map(d=>d.uniqueWhere).filter(d=>d!==void 0),l=n,f=(h=Object.entries(s[0]??{})[0])==null?void 0:h[0];if(s.length>0){let d=s.map(m=>m[f]).filter(m=>m!=null);d.length>0&&(l=z(n,{[f]:{$in:d}}));}let u=await this.storage.rawFind({resource:r,where:l,include:a,sort:c,limit:o});for(let d of e){let m={};if(d.uniqueWhere){let[p,y]=Object.entries(d.uniqueWhere)[0];for(let[T,g]of Object.entries(u))((R=g.value[p])==null?void 0:R.value)===y&&(m[T]=g);}else Object.assign(m,u);d.resolve(m);}}};var Ae=ge(oe());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()}),se=zod.z.record(zod.z.string(),zod.z.object({value:zod.z.string().or(zod.z.number()).or(zod.z.boolean()).or(zod.z.date()).nullable(),_meta:zod.z.object({timestamp:zod.z.string().optional().nullable()}).optional()})),yt=se.superRefine((i,e)=>{i.id&&e.addIssue({code:zod.z.ZodIssueCode.custom,message:"Payload cannot have an id"});}),Le=zod.z.object({id:zod.z.string().optional(),type:zod.z.literal("MUTATE"),resource:zod.z.string(),resourceId:zod.z.string().optional()}),q=Le.extend({procedure:zod.z.string(),payload:zod.z.any().optional()}),U=Le.extend({procedure:zod.z.enum(["INSERT","UPDATE"]),payload:yt});zod.z.union([U,q]);var Oe=F.omit({resource:true}),ce=q.omit({id:true,type:true,resource:true,procedure:true}),ue=U.omit({id:true,type:true,resource:true,procedure:true});zod.z.union([ue,ce]);var je=i=>{let e=i.logger;return async t=>{var r;try{let n=typeof t.headers.getSetCookie=="function"?Object.fromEntries(t.headers):t.headers,a={headers:n,cookies:n.cookie?Ae.default.parse(n.cookie):{}},c=new URL(t.url),o=c.pathname.split("/"),s=c.searchParams,l=ft__default.default.parse(s.toString()),f=await((r=i.contextProvider)==null?void 0:r.call(i,{transport:"HTTP",headers:a.headers,cookies:a.cookies,queryParams:l}))??{};if(t.method==="GET"){let u=o[o.length-1],{success:h,data:R,error:d}=Oe.safeParse(l);if(!h)return Response.json({message:"Invalid query",code:"INVALID_QUERY",details:d},{status:400});let m=await i.handleQuery({req:{...a,...R,type:"QUERY",resource:u,context:f,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],R=t.body?await t.json():{},d;if(u==="insert"||u==="update"){let{success:p,data:y,error:T}=ue.safeParse(R);if(!p)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:T},{status:400});d=y;}else {let{success:p,data:y,error:T}=ce.safeParse(R);if(!p)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:T},{status:400});d=y;}let m=await i.handleMutation({req:{...a,type:"MUTATE",resource:h,input:d.payload,context:f,resourceId:d.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(n){return e.error("Unexpected error:",n),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}}};var $e=ge(oe());var V=zod.z.string(),mt=F.extend({id:V,type:zod.z.literal("SUBSCRIBE")}),ht=F.extend({id:V,type:zod.z.literal("QUERY")}),Ee=U.extend({id:V}),Tt=q.extend({id:V}),gt=zod.z.union([Tt,Ee]),Ce=zod.z.union([mt,ht,gt]),Rt=zod.z.object({id:V,type:zod.z.literal("REJECT"),resource:zod.z.string(),message:zod.z.string().optional()}),bt=zod.z.object({id:V,type:zod.z.literal("REPLY"),data:zod.z.any()});zod.z.union([Rt,bt,Ee]);zod.z.object({resource:zod.z.string(),data:zod.z.record(zod.z.string(),se)});var Pe=i=>{let e={},t=i.logger;return (r,n)=>{var u;let a=h=>{r.send(JSON.stringify(h));},c=G(),o=new Set,s={headers:n.headers,cookies:typeof n.headers.cookie=="string"?$e.default.parse(n.headers.cookie):{}},l=ft.parse(n.url.split("?")[1]),f=(u=i.contextProvider)==null?void 0:u.call(i,{transport:"WEBSOCKET",headers:s.headers,cookies:s.cookies,queryParams:l});e[c]=r,t.info("Client connected:",c),r.on("message",async h=>{var R;try{t.debug("Message received from the client:",h);let d=Ce.parse(JSON.parse(h.toString()));if(d.type==="SUBSCRIBE"){let m=await f??{},p=d.resource,y=i.router.routes[p],T;if((R=y==null?void 0:y.authorization)!=null&&R.read){let g=y.authorization.read({ctx:m});T=typeof g=="object"?g:void 0;}o.add(i.subscribeToMutations(d,g=>{var x;!g.resourceId||!g.payload||!Object.keys(g.payload).length||(x=e[c])==null||x.send(JSON.stringify(g));},T));}else if(d.type==="QUERY"){let{resource:m}=d,p=await i.handleQuery({req:{...s,type:"QUERY",resource:m,context:await f??{},queryParams:l}});if(!p||!p.data)throw new Error("Invalid resource");a({id:d.id,type:"REPLY",data:{resource:m,data:Object.fromEntries(Object.entries(p.data??{}).map(([y,T])=>[y,T.value]))}});}else if(d.type==="MUTATE"){let{resource:m}=d;t.debug("Received mutation from client:",d);try{let p=await i.handleMutation({req:{...s,type:"MUTATE",resource:m,input:d.payload,context:{messageId:d.id,...await f??{}},resourceId:d.resourceId,procedure:d.procedure,queryParams:l}});d.procedure&&d.procedure!=="INSERT"&&d.procedure!=="UPDATE"&&a({id:d.id,type:"REPLY",data:p});}catch(p){a({id:d.id,type:"REJECT",resource:m,message:p.message}),t.error("Error parsing mutation from the client:",p);}}}catch(d){t.error("Error handling message from the client:",d);}}),r.on("close",()=>{t.info("Connection closed",c),delete e[c];for(let h of Array.from(o))h();});}};function ze(i){let e=`${i.protocol}://${i.hostname}${i.url}`,t=new Headers;return Object.entries(i.headers).forEach(([r,n])=>{n&&t.set(r,Array.isArray(n)?n.join(","):n);}),new Request(e,{method:i.method,headers:t,body:i.body&&i.method!=="GET"?JSON.stringify(i.body):void 0})}var Rr=(i,e,t)=>{i.ws(`${(t==null?void 0:t.basePath)??""}/ws`,Pe(e)),i.use(`${(t==null?void 0:t.basePath)??""}/`,(r,n)=>{je(e)(ze(r)).then(c=>c.json().then(o=>n.status(c.status).send(o)));});};var le=class i{routes;constructor(e){this.routes=e.routes;}static create(e){return new i(e)}},Ir=i=>le.create({...i}),St=i=>({handler:e=>({inputValidator:i??zod.z.undefined(),handler:e})}),de=class i{resourceSchema;middlewares;customMutations;authorization;constructor(e,t,r){this.resourceSchema=e,this.middlewares=new Set,this.customMutations=t??{},this.authorization=r;}use(...e){for(let t of e)this.middlewares.add(t);return this}withMutations(e){return new i(this.resourceSchema,e({mutation:St}),this.authorization)}handleQuery=async({req:e,batcher:t})=>await this.wrapInMiddlewares(async r=>{var a,c;let n=(c=(a=this.authorization)==null?void 0:a.read)==null?void 0:c.call(a,{ctx:r.context});if(typeof n=="boolean"&&!n)throw new Error("Not authorized");return {data:await t.rawFind({resource:r.resource,commonWhere:z(r.where,typeof n=="object"?n:void 0),uniqueWhere:r.relationalWhere,include:r.include,limit:r.limit,sort:r.sort})}})(e);handleMutation=async({req:e,db:t,schema:r})=>await this.wrapInMiddlewares(async n=>{if(!n.procedure)throw new Error("Procedure is required for mutations");let a=this.customMutations[n.procedure];if(a){let c=a.inputValidator.parse(n.input);return n.input=c,a.handler({req:n,db:t})}else {if(n.procedure==="INSERT"||n.procedure==="UPDATE")return this.handleSet({req:n,db:t,operation:n.procedure,schema:r});throw new Error(`Unknown procedure: ${n.procedure}`)}})(e);handleSet=async({req:e,db:t,operation:r,schema:n})=>{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(r==="INSERT"&&a)throw new Error("Resource already exists");if(r==="UPDATE"&&!a)throw new Error("Resource not found");return t.transaction(async({trx:c})=>{var f,u,h,R,d;let[o,s]=this.resourceSchema.mergeMutation("set",e.input,a);if(!s)throw new Error("Mutation rejected");if(r==="INSERT"){let m=await c.rawInsert(e.resource,e.resourceId,o),p=S(m);if(p.id=p.id??e.resourceId,(f=this.authorization)!=null&&f.insert){let y=this.authorization.insert({ctx:e.context,value:p});if(typeof y=="boolean"){if(!y)throw new Error("Not authorized")}else {let T=K(y,e.resource,n),g=Object.keys(T).length>0?await c.rawFindById(e.resource,e.resourceId,T):m,x=S(g);if(x.id=x.id??e.resourceId,!L(x,y))throw new Error("Not authorized")}}return {data:m,acceptedValues:s}}if((h=(u=this.authorization)==null?void 0:u.update)!=null&&h.preMutation){let m=S(a);m.id=m.id??e.resourceId;let p=this.authorization.update.preMutation({ctx:e.context,value:m});if(typeof p=="boolean"){if(!p)throw new Error("Not authorized")}else {let y=K(p,e.resource,n),T=Object.keys(y).length>0?await c.rawFindById(e.resource,e.resourceId,y):a,g=S(T);if(g.id=g.id??e.resourceId,!L(g,p))throw new Error("Not authorized")}}let l=await c.rawUpdate(e.resource,e.resourceId,o);if((d=(R=this.authorization)==null?void 0:R.update)!=null&&d.postMutation){let m=S(l);m.id=m.id??e.resourceId;let p=this.authorization.update.postMutation({ctx:e.context,value:m});if(typeof p=="boolean"){if(!p)throw new Error("Not authorized")}else {let y=K(p,e.resource,n),T=Object.keys(y).length>0?await c.rawFindById(e.resource,e.resourceId,y):l,g=S(T);if(g.id=g.id??e.resourceId,!L(g,p))throw new Error("Not authorized")}}return {data:l,acceptedValues:s}})};wrapInMiddlewares(e){return t=>Array.from(this.middlewares.values()).reduceRight((r,n)=>a=>n({req:a,next:r}),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}},Mr=ye.create;var B=class{async insert(e,t){let r=new Date().toISOString();return S(await this.rawInsert(e.name,t.id,{value:Object.fromEntries(Object.entries(t).map(([n,a])=>[n,{value:a,_meta:{timestamp:r}}]))}))}async update(e,t,r){let n=new Date().toISOString(),{id:a,...c}=r;return S(await this.rawUpdate(e.name,t,{value:Object.fromEntries(Object.entries(c).map(([o,s])=>[o,{value:s,_meta:{timestamp:n}}]))}))}};function J(i,e,t,r){if(!i)throw new Error("Schema not initialized");let n=i[e];if(!n)throw new Error("Resource not found");let a=r.$or,c=r.$and;return (a?t.or:t.and)(a?r.$or.map(o=>J(i,e,t,o)):c?r.$and.map(o=>J(i,e,t,o)):Object.entries(r).map(([o,s])=>{var l,f;if(n.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):((f=s==null?void 0:s.$not)==null?void 0:f.$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(n.relations[o]){let u=n.relations[o],h=u.entity.name;return u.type==="many"?t.exists(pe(i,h,t.selectFrom(h).select("id").whereRef(u.foreignColumn,"=",`${e}.id`),s)):J(i,h,t,s)}return null}).filter(Boolean))}function Y(i,e,t,r){let n=i[e];if(!n)throw new Error("Resource not found");if(!r)return t;if(r.$and){for(let a of r.$and)t=Y(i,e,t,a);return t}else if(r.$or){for(let a of r.$or)t=Y(i,e,t,a);return t}for(let[a,c]of Object.entries(r)){if(!n.relations[a])continue;let o=n.relations[a],s=o.entity.name,l=o.type==="one"?"id":o.foreignColumn,f=o.type==="one"?o.relationalColumn:"id";t=t.leftJoin(s,`${s}.${l}`,`${e}.${f}`),c instanceof Object&&!Array.isArray(c)&&c!==null&&(t=Y(i,s,t,c));}return t}function pe(i,e,t,r){return !r||Object.keys(r).length===0?t:(t=Y(i,e,t,r),t.where(n=>J(i,e,n,r)))}function X(i,e,t,r){if(!r)return t;if(!i)throw new Error("Schema not initialized");let n=i[e];if(!n)throw new Error(`Resource not found: ${e}`);for(let a of Object.keys(r)){if(!n.relations[a])throw new Error(`Relation ${a} not found in resource ${e}`);let c=n.relations[a],o=c.entity.name,s=r[a],l=c.type==="one"?"id":c.foreignColumn,f=c.type==="one"?c.relationalColumn:"id",u=c.type==="one"?postgres.jsonObjectFrom:postgres.jsonArrayFrom,h=typeof s=="object"&&s!==null;t=t.select(R=>{let d=R.selectFrom(o).selectAll(o).whereRef(`${o}.${l}`,"=",`${e}.${f}`).select(m=>postgres.jsonObjectFrom(m.selectFrom(`${o}_meta`).selectAll(`${o}_meta`).whereRef(`${o}_meta.id`,"=",`${o}.id`)).as("_meta"));return h&&(d=X(i,o,d,s)),u(d).as(a)});}return t}var ke="42701",fe=class i extends B{db;schema;logger;server;mutationStack=[];constructor(e,t,r,n){super(),this.isKyselyLike(e)?this.db=e:this.db=new kysely.Kysely({dialect:new kysely.PostgresDialect({pool:e})}),this.schema=t,this.logger=r,this.server=n,this.rawInsert=this.rawInsert.bind(this),this.rawUpdate=this.rawUpdate.bind(this);}async init(e,t,r){var a;this.schema=e,this.logger=t,this.server=r;let n=await this.db.introspection.getTables();for(let[c,o]of Object.entries(e)){let s=n.find(u=>u.name===c);s||await this.db.schema.createTable(c).ifNotExists().execute();let l=`${c}_meta`,f=n.find(u=>u.name===l);f||await this.db.schema.createTable(l).ifNotExists().execute();for(let[u,h]of Object.entries(o.fields)){let R=s==null?void 0:s.columns.find(p=>p.name===u),d=h.getStorageFieldType();R?R.dataType!==d.type&&((a=this.logger)==null||a.warn("Column type mismatch:",u,"expected to have type:",d.type,"but has type:",R.dataType)):(await this.db.schema.alterTable(c).addColumn(u,d.type,p=>{let y=p;return d.unique&&(y=y.unique()),d.nullable||(y=y.notNull()),d.references&&(y=y.references(d.references)),d.primary&&(y=y.primaryKey()),d.default!==void 0&&(y=y.defaultTo(d.default)),y}).execute().catch(p=>{var y;if(p.code!==ke)throw (y=this.logger)==null||y.error("Error adding column",u,p),p}),d.index&&await this.db.schema.createIndex(`${c}_${u}_index`).on(c).column(u).execute().catch(()=>{})),(f==null?void 0:f.columns.find(p=>p.name===u))||await this.db.schema.alterTable(l).addColumn(u,"varchar",p=>{let y=p;return d.primary&&(y=y.primaryKey().references(`${c}.${u}`)),y}).execute().catch(p=>{var y;if(p.code!==ke)throw (y=this.logger)==null||y.error("Error adding meta column",u,p),p});}}}async rawFindById(e,t,r){if(!this.schema)throw new Error("Schema not initialized");let n=await this.db.selectFrom(e).where("id","=",t).selectAll(e).select(c=>postgres.jsonObjectFrom(c.selectFrom(`${e}_meta`).selectAll(`${e}_meta`).whereRef(`${e}_meta.id`,"=",`${e}.id`)).as("_meta"));n=X(this.schema,e,n,r);let a=await n.executeTakeFirst();if(a)return this.convertToMaterializedLiveType(a)}async findOne(e,t,r){let n=await this.rawFindById(e.name,t,r==null?void 0:r.include);if(n)return S(n)}async rawFind(e){if(!this.schema)throw new Error("Schema not initialized");let{resource:t,where:r,include:n,limit:a,sort:c}=e,o=this.db.selectFrom(t).selectAll(t).select(u=>postgres.jsonObjectFrom(u.selectFrom(`${t}_meta`).selectAll(`${t}_meta`).whereRef(`${t}_meta.id`,"=",`${t}.id`)).as("_meta"));o=pe(this.schema,t,o,r),o=X(this.schema,t,o,n),a!==void 0&&(o=o.limit(a)),c!==void 0&&c.forEach(u=>{o=o.orderBy(u.key,u.direction);});let s=await o.execute(),l=Object.fromEntries(s.map(u=>{let{id:h}=u;return [h,u]}));return Object.keys(l).length===0?{}:Object.entries(l).reduce((u,[h,R])=>(u[h]=this.convertToMaterializedLiveType(R),u),{})}async find(e,t){let r=await this.rawFind({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});return Object.fromEntries(Object.entries(r).map(([n,a])=>[n,S(a)]))}async rawInsert(e,t,r){var o;let n={},a={};for(let[s,l]of Object.entries(r.value)){let f=(o=l._meta)==null?void 0:o.timestamp;f&&(n[s]=l.value,a[s]=f);}await this.db.insertInto(e).values({...n,id:t}).execute().then(()=>{this.db.insertInto(`${e}_meta`).values({...a,id:t}).execute();});let c=this.buildMutation(e,t,"INSERT",r);return c&&this.trackMutation(c,r),r}async rawUpdate(e,t,r){var o;let n={},a={};for(let[s,l]of Object.entries(r.value)){let f=(o=l._meta)==null?void 0:o.timestamp;f&&(n[s]=l.value,a[s]=f);}await Promise.all([this.db.updateTable(e).set(n).where("id","=",t).execute(),this.db.insertInto(`${e}_meta`).values({...a,id:t}).onConflict(s=>s.column("id").doUpdateSet(a)).execute()]);let c=this.buildMutation(e,t,"UPDATE",r);return c&&this.trackMutation(c,r),r}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();try{return await e({trx:this,commit:async()=>{await s.releaseSavepoint(a).execute(),c.push(...o);},rollback:async()=>{await s.rollbackToSavepoint(a).execute(),o.length=0;}}).then(l=>s.isCommitted||s.isRolledBack?l:s.releaseSavepoint(a).execute().then(()=>(c.push(...o),l)))}catch(l){throw await s.rollbackToSavepoint(a).execute().catch(()=>{}),o.length=0,l}finally{this.mutationStack=c;}}let t=[],r=this.mutationStack;this.mutationStack=t;let n=await this.db.startTransaction().execute();try{let a=new i(n,this.schema,this.logger,this.server);return a.mutationStack=t,await e({trx:a,commit:async()=>{await n.commit().execute(),this.notifyMutations(t);},rollback:async()=>{await n.rollback().execute(),t.length=0;}}).then(c=>n.isCommitted||n.isRolledBack?c:n.commit().execute().then(()=>(this.notifyMutations(t),c)))}catch(a){throw await n.rollback().execute(),t.length=0,a}finally{this.mutationStack=r;}}get internalDB(){return this.db}convertToMaterializedLiveType(e){return {value:Object.entries(e).reduce((t,[r,n])=>{var a,c,o;return r==="_meta"||(r==="id"?t[r]={value:n}:Array.isArray(n)?t[r]={value:n.map(s=>this.convertToMaterializedLiveType(s)),_meta:{timestamp:(a=e==null?void 0:e._meta)==null?void 0:a[r]}}:typeof n=="object"&&n!==null&&!(n instanceof Date)?t[r]={...this.convertToMaterializedLiveType(n),_meta:{timestamp:(c=e==null?void 0:e._meta)==null?void 0:c[r]}}:t[r]={value:n,_meta:{timestamp:(o=e==null?void 0:e._meta)==null?void 0:o[r]}}),t},{})}}isKyselyLike(e){if(e instanceof kysely.Kysely)return true;if(!e||typeof e!="object")return false;let t=e,r=typeof t.selectFrom=="function",n=typeof t.startTransaction=="function",a=typeof t.savepoint=="function",c=typeof t.isTransaction=="boolean"||typeof t.isTransaction=="function";return r&&n||a&&c}buildMutation(e,t,r,n){var c;let a={};for(let[o,s]of Object.entries(n.value)){if(o==="id")continue;let l=(c=s._meta)==null?void 0:c.timestamp;l&&(a[o]={value:s.value,_meta:{timestamp:l}});}return Object.keys(a).length===0?null:{id:G(),type:"MUTATE",resource:e,resourceId:t,procedure:r,payload:a}}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 r=e;for(let n of r)this.server.notifySubscribers(n,t);}else {let r=e;for(let{mutation:n,entityData:a}of r)this.server.notifySubscribers(n,a);}}};var me=class i{router;storage;schema;middlewares=new Set;logger;contextProvider;mutationSubscriptions=new Set;collectionSubscriptions=new Map;constructor(e){var t;this.router=e.router,this.storage=e.storage,this.schema=e.schema,this.logger=we({level:e.logLevel??j.INFO}),(t=e.middlewares)==null||t.forEach(r=>{this.middlewares.add(r);}),this.storage.init(this.schema,this.logger,this),this.contextProvider=e.contextProvider;}static create(e){return new i(e)}handleQuery(e){let t=new Z(this.storage);return this.wrapInMiddlewares(async r=>{var R,d,m;let n=We(r,this.schema,{stepId:"query",collectionName:r.resource,included:Object.keys(r.include??{})}),a={headers:r.headers,cookies:r.cookies,queryParams:r.queryParams,context:r.context},c={};for(let p=0;p<n.length;p++){let y=n[p],T=this.router.routes[y.resource];if(!T)throw new Error("Invalid resource");let g;if(y.getWhere&&y.referenceGetter){let v=y.referenceGetter(c);g=[];for(let I=0;I<v.length;I++)g.push(y.getWhere(v[I]));}else g=[void 0];let x=c[y.prevStepId??""],M=[];if(x)for(let v=0;v<x.length;v++){let I=x[v],A=Object.keys(((R=I==null?void 0:I.result)==null?void 0:R.data)??{});for(let k=0;k<A.length;k++)M.push(A[k]);}let E=[];for(let v=0;v<g.length;v++){let I=g[v],A=M[v];E.push((async()=>{let k=await T.handleQuery({req:{type:"QUERY",...y,...a,where:y.where,relationalWhere:I},batcher:t});return {includedBy:A,result:k}})());}let O=await Promise.allSettled(E),_=[];for(let v=0;v<O.length;v++){let I=O[v];I.status==="fulfilled"&&_.push(I.value);}c[y.stepId]=_;}let o=new Map,s=0;for(let p in c){let y=c[p],T=n[s];s++;for(let g=0;g<y.length;g++){let x=y[g],M=x.result.data;for(let E in M){let O=M[E],_=`${p}.${E}`,v=[];p!=="query"&&x.includedBy&&(v=[`${T.prevStepId}.${x.includedBy}`]);let I=o.get(_);if(I)for(let A=0;A<v.length;A++)I.includedBy.add(v[A]);else o.set(_,{data:O,includedBy:new Set(v),path:p.split(".").slice(-1)[0],isMany:T.isMany??false,collectionName:T.collectionName,included:T.included});}}}let l=Object.fromEntries(o),f={data:{}},u=Object.keys(l);for(let p=u.length-1;p>=0;p--){let y=u[p],T=l[y],g=T.path;if(g==="query"&&(f.data[y.replace("query.","")]=T.data),T.included.length)for(let x=0;x<T.included.length;x++){let M=T.included[x];T.data.value[M]??=((m=(d=this.schema[T.collectionName])==null?void 0:d.relations[M])==null?void 0:m.type)==="many"?{value:[]}:{value:null};}if(T.includedBy.size>0){let x=Array.from(T.includedBy);for(let M=0;M<x.length;M++){let E=x[M],O=l[E];O&&(T.isMany?(O.data.value[g]??={value:[]},O.data.value[g].value.push(T.data)):O.data.value[g]=T.data);}}}return f})(e.req)}async handleMutation(e){let t=await this.wrapInMiddlewares(async r=>{let n=this.router.routes[r.resource];if(!n)throw new Error("Invalid resource");return n.handleMutation({req:r,db:this.storage,schema:this.schema})})(e.req);if(t&&e.req.type==="MUTATE"&&t.acceptedValues&&(e.req.procedure==="INSERT"||e.req.procedure==="UPDATE")&&e.req.resourceId){let n=t.acceptedValues??{},a=e.req,c=a.resourceId;Object.keys(n).length&&c&&this.mutationSubscriptions.forEach(o=>{o({id:e.req.context.messageId,type:"MUTATE",resource:a.resource,payload:n,resourceId:c,procedure:a.procedure});});}return t}use(e){return this.middlewares.add(e),this}context(e){return this.contextProvider=e,this}subscribeToMutations(e,t,r){let n=e.resource,a={query:e,authorizationWhere:r},c=Se(a),o=this.collectionSubscriptions.get(n);o||(o=new Map,this.collectionSubscriptions.set(n,o));let s=o.get(c);return s?(s.callbacks.add(t),r!==void 0&&(s.authorizationWhere=r)):o.set(c,{callbacks:new Set([t]),...a}),()=>{var f,u;let l=this.collectionSubscriptions.get(n);l&&((f=l.get(c))==null||f.callbacks.delete(t),((u=l.get(c))==null?void 0:u.callbacks.size)===0&&l.delete(c));}}notifySubscribers(e,t){let r=e.resource,n=this.collectionSubscriptions.get(r);if(n&&t)for(let a of Array.from(n.values())){let c=he(a.query.where,this.schema[r]),o=z(c,a.authorizationWhere),s=S(t);if(!s)continue;(e.resourceId&&typeof s=="object"&&s!==null&&!("id"in s)||e.resourceId&&typeof s=="object"&&s!==null&&s.id!==e.resourceId)&&(s.id=e.resourceId);let l=Object.keys(o).length>0,f=true;l&&(f=L(s,o)),f&&a.callbacks.forEach(u=>{var h;try{u(e);}catch(R){(h=this.logger)==null||h.error(`Error in mutation subscription for resource ${r}:`,R);}});}}wrapInMiddlewares(e){return t=>Array.from(this.middlewares.values()).reduceRight((r,n)=>a=>n({req:a,next:r}),e)(t)}},Br=me.create;function We(i,e,t){let{include:r,where:n,...a}=i,{stepId:c}=t,o=[{...a,...t,where:n}];if(r&&typeof r=="object"&&Object.keys(r).length>0){let s=e[a.resource];if(!s)throw new Error(`Resource ${a.resource} not found`);o.push(...Object.entries(r).flatMap(([l,f])=>{let u=s.relations[l];if(!u)throw new Error(`Relation ${l} not found for resource ${a.resource}`);let h=u.entity.name;return We({...a,resource:h,include:f},e,{getWhere:u.type==="one"?R=>({id:R}):R=>({[u.foreignColumn]:R}),referenceGetter:R=>R[c].flatMap(d=>d.result.data?u.type==="one"?Object.values(d.result.data).map(m=>{var p,y;return (y=(p=m.value)==null?void 0:p[u.relationalColumn])==null?void 0:y.value}):Object.keys(d.result.data):[]),stepId:`${c}.${l}`,prevStepId:c,isMany:u.type==="many",collectionName:h,included:typeof f=="object"?Object.keys(f):[]})}));}return o}function he(i,e){if(!i||!e||Object.keys(i).length===0)return i;if(i.$and){let r=i.$and.map(n=>he(n,e)).filter(n=>!!n&&Object.keys(n).length>0);return r.length===0?void 0:r.length===1?r[0]:{$and:r}}if(i.$or){let r=i.$or.map(n=>he(n,e)).filter(n=>!!n&&Object.keys(n).length>0);return r.length===0?void 0:r.length===1?r[0]:{$or:r}}let t={};for(let[r,n]of Object.entries(i))e.fields[r]&&(t[r]=n);return Object.keys(t).length>0?t:void 0}
2
+ exports.Route=de;exports.RouteFactory=ye;exports.Router=le;exports.SQLStorage=fe;exports.Server=me;exports.Storage=B;exports.expressAdapter=Rr;exports.routeFactory=Mr;exports.router=Ir;exports.server=Br;
package/dist/server.d.cts CHANGED
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  import { L as LiveObjectAny, W as WhereClause, S as Simplify, I as InferLiveObjectWithRelationalIds, M as MaterializedLiveType, a as Schema, b as IncludeClause, c as InferLiveObject, d as InferInsert, e as InferUpdate, f as Logger, g as LogLevel } from './index-BtsKDfTE.cjs';
3
3
  import * as z3 from 'zod/v3';
4
4
  import * as z4 from 'zod/v4/core';
5
- import { PostgresPool } from 'kysely';
5
+ import { PostgresPool, Kysely } from 'kysely';
6
6
  import { Application } from 'express-ws';
7
7
 
8
8
  declare const querySchema: z.ZodObject<{
@@ -136,9 +136,11 @@ declare abstract class Storage {
136
136
  /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
137
137
 
138
138
  declare class SQLStorage extends Storage {
139
- private db;
139
+ private readonly db;
140
140
  private schema?;
141
141
  private logger?;
142
+ private server?;
143
+ private mutationStack;
142
144
  constructor(pool: PostgresPool);
143
145
  findOne<T extends LiveObjectAny>(resource: T, id: string, options?: {
144
146
  include?: IncludeClause<T>;
@@ -157,8 +159,25 @@ declare class SQLStorage extends Storage {
157
159
  commit: () => Promise<void>;
158
160
  rollback: () => Promise<void>;
159
161
  }) => Promise<T>): Promise<T>;
162
+ /**
163
+ * Provides direct access to the underlying Kysely database instance.
164
+ *
165
+ * ⚠️ Warning: Direct database operations bypass mutation tracking and
166
+ * subscriber notifications. Use this only when you need to execute
167
+ * queries not supported by the Storage API.
168
+ *
169
+ * @returns The Kysely database instance
170
+ */
171
+ get internalDB(): Kysely<{
172
+ [x: string]: {
173
+ [x: string]: any;
174
+ };
175
+ }>;
160
176
  private convertToMaterializedLiveType;
161
177
  private isKyselyLike;
178
+ private buildMutation;
179
+ private trackMutation;
180
+ private notifyMutations;
162
181
  }
163
182
 
164
183
  declare const expressAdapter: (app: Application, server: Server<AnyRouter>, options?: {
@@ -200,7 +219,9 @@ declare class Server<TRouter extends AnyRouter> {
200
219
  readonly middlewares: Set<Middleware<any>>;
201
220
  readonly logger: Logger;
202
221
  contextProvider?: ContextProvider;
222
+ /** @deprecated */
203
223
  private mutationSubscriptions;
224
+ private collectionSubscriptions;
204
225
  private constructor();
205
226
  static create<TRouter extends AnyRouter>(opts: {
206
227
  router: TRouter;
@@ -210,7 +231,6 @@ declare class Server<TRouter extends AnyRouter> {
210
231
  contextProvider?: ContextProvider;
211
232
  logLevel?: LogLevel;
212
233
  }): Server<TRouter>;
213
- subscribeToMutations(handler: MutationHandler): () => void;
214
234
  handleQuery(opts: {
215
235
  req: QueryRequest;
216
236
  }): Promise<QueryResult<any>>;
package/dist/server.d.ts CHANGED
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  import { L as LiveObjectAny, W as WhereClause, S as Simplify, I as InferLiveObjectWithRelationalIds, M as MaterializedLiveType, a as Schema, b as IncludeClause, c as InferLiveObject, d as InferInsert, e as InferUpdate, f as Logger, g as LogLevel } from './index-BtsKDfTE.js';
3
3
  import * as z3 from 'zod/v3';
4
4
  import * as z4 from 'zod/v4/core';
5
- import { PostgresPool } from 'kysely';
5
+ import { PostgresPool, Kysely } from 'kysely';
6
6
  import { Application } from 'express-ws';
7
7
 
8
8
  declare const querySchema: z.ZodObject<{
@@ -136,9 +136,11 @@ declare abstract class Storage {
136
136
  /** biome-ignore-all lint/suspicious/noExplicitAny: false positive */
137
137
 
138
138
  declare class SQLStorage extends Storage {
139
- private db;
139
+ private readonly db;
140
140
  private schema?;
141
141
  private logger?;
142
+ private server?;
143
+ private mutationStack;
142
144
  constructor(pool: PostgresPool);
143
145
  findOne<T extends LiveObjectAny>(resource: T, id: string, options?: {
144
146
  include?: IncludeClause<T>;
@@ -157,8 +159,25 @@ declare class SQLStorage extends Storage {
157
159
  commit: () => Promise<void>;
158
160
  rollback: () => Promise<void>;
159
161
  }) => Promise<T>): Promise<T>;
162
+ /**
163
+ * Provides direct access to the underlying Kysely database instance.
164
+ *
165
+ * ⚠️ Warning: Direct database operations bypass mutation tracking and
166
+ * subscriber notifications. Use this only when you need to execute
167
+ * queries not supported by the Storage API.
168
+ *
169
+ * @returns The Kysely database instance
170
+ */
171
+ get internalDB(): Kysely<{
172
+ [x: string]: {
173
+ [x: string]: any;
174
+ };
175
+ }>;
160
176
  private convertToMaterializedLiveType;
161
177
  private isKyselyLike;
178
+ private buildMutation;
179
+ private trackMutation;
180
+ private notifyMutations;
162
181
  }
163
182
 
164
183
  declare const expressAdapter: (app: Application, server: Server<AnyRouter>, options?: {
@@ -200,7 +219,9 @@ declare class Server<TRouter extends AnyRouter> {
200
219
  readonly middlewares: Set<Middleware<any>>;
201
220
  readonly logger: Logger;
202
221
  contextProvider?: ContextProvider;
222
+ /** @deprecated */
203
223
  private mutationSubscriptions;
224
+ private collectionSubscriptions;
204
225
  private constructor();
205
226
  static create<TRouter extends AnyRouter>(opts: {
206
227
  router: TRouter;
@@ -210,7 +231,6 @@ declare class Server<TRouter extends AnyRouter> {
210
231
  contextProvider?: ContextProvider;
211
232
  logLevel?: LogLevel;
212
233
  }): Server<TRouter>;
213
- subscribeToMutations(handler: MutationHandler): () => void;
214
234
  handleQuery(opts: {
215
235
  req: QueryRequest;
216
236
  }): Promise<QueryResult<any>>;
package/dist/server.js CHANGED
@@ -1,2 +1,2 @@
1
- import {a,b,t,v as v$1,w,y,x}from'./chunk-NJ7LXJAY.js';import C from'node:crypto';import Be,{parse}from'qs';import {z as z$1}from'zod';import {Kysely,PostgresDialect}from'kysely';import {jsonObjectFrom,jsonArrayFrom}from'kysely/helpers/postgres';var _=a(N=>{Object.defineProperty(N,"__esModule",{value:true});N.parse=Pe;N.serialize=ze;var Ae=/^[\u0021-\u003A\u003C\u003E-\u007E]+$/,Oe=/^[\u0021-\u003A\u003C-\u007E]*$/,je=/^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i,Le=/^[\u0020-\u003A\u003D-\u007E]*$/,$e=Object.prototype.toString,Ce=(()=>{let i=function(){};return i.prototype=Object.create(null),i})();function Pe(i,t){let e=new Ce,r=i.length;if(r<2)return e;let n=(t==null?void 0:t.decode)||Ne,o=0;do{let c=i.indexOf("=",o);if(c===-1)break;let a=i.indexOf(";",o),s=a===-1?r:a;if(c>s){o=i.lastIndexOf(";",c-1)+1;continue}let h=oe(i,o,c),y=ae(i,c,h),d=i.slice(h,y);if(e[d]===void 0){let p=oe(i,c+1,s),u=ae(i,s,p),f=n(i.slice(p,u));e[d]=f;}o=s+1;}while(o<r);return e}function oe(i,t,e){do{let r=i.charCodeAt(t);if(r!==32&&r!==9)return t}while(++t<e);return e}function ae(i,t,e){for(;t>e;){let r=i.charCodeAt(--t);if(r!==32&&r!==9)return t+1}return e}function ze(i,t,e){let r=(e==null?void 0:e.encode)||encodeURIComponent;if(!Ae.test(i))throw new TypeError(`argument name is invalid: ${i}`);let n=r(t);if(!Oe.test(n))throw new TypeError(`argument val is invalid: ${t}`);let o=i+"="+n;if(!e)return o;if(e.maxAge!==void 0){if(!Number.isInteger(e.maxAge))throw new TypeError(`option maxAge is invalid: ${e.maxAge}`);o+="; Max-Age="+e.maxAge;}if(e.domain){if(!je.test(e.domain))throw new TypeError(`option domain is invalid: ${e.domain}`);o+="; Domain="+e.domain;}if(e.path){if(!Le.test(e.path))throw new TypeError(`option path is invalid: ${e.path}`);o+="; Path="+e.path;}if(e.expires){if(!Ue(e.expires)||!Number.isFinite(e.expires.valueOf()))throw new TypeError(`option expires is invalid: ${e.expires}`);o+="; Expires="+e.expires.toUTCString();}if(e.httpOnly&&(o+="; HttpOnly"),e.secure&&(o+="; Secure"),e.partitioned&&(o+="; Partitioned"),e.priority)switch(typeof e.priority=="string"?e.priority.toLowerCase():void 0){case "low":o+="; Priority=Low";break;case "medium":o+="; Priority=Medium";break;case "high":o+="; Priority=High";break;default:throw new TypeError(`option priority is invalid: ${e.priority}`)}if(e.sameSite)switch(typeof e.sameSite=="string"?e.sameSite.toLowerCase():e.sameSite){case true:case "strict":o+="; SameSite=Strict";break;case "lax":o+="; SameSite=Lax";break;case "none":o+="; SameSite=None";break;default:throw new TypeError(`option sameSite is invalid: ${e.sameSite}`)}return o}function Ne(i){if(i.indexOf("%")===-1)return i;try{return decodeURIComponent(i)}catch{return i}}function Ue(i){return $e.call(i)==="[object Date]"}});var re="0123456789ABCDEFGHJKMNPQRSTVWXYZ",E=32;var we=16,ne=10,te=0xffffffffffff;var I;(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";})(I||(I={}));var M=class extends Error{constructor(t,e){super(`${e} (${t})`),this.name="ULIDError",this.code=t;}};function xe(i){let t=Math.floor(i()*E);return t===E&&(t=E-1),re.charAt(t)}function Se(i){var r;let t=Ie(),e=t&&(t.crypto||t.msCrypto)||(typeof C<"u"?C:null);if(typeof(e==null?void 0:e.getRandomValues)=="function")return ()=>{let n=new Uint8Array(1);return e.getRandomValues(n),n[0]/255};if(typeof(e==null?void 0:e.randomBytes)=="function")return ()=>e.randomBytes(1).readUInt8()/255;if((r=C)!=null&&r.randomBytes)return ()=>C.randomBytes(1).readUInt8()/255;throw new M(I.PRNGDetectFailure,"Failed to find a reliable PRNG")}function Ie(){return Ee()?self:typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:null}function Me(i,t){let e="";for(;i>0;i--)e=xe(t)+e;return e}function ve(i,t=ne){if(isNaN(i))throw new M(I.EncodeTimeValueMalformed,`Time must be a number: ${i}`);if(i>te)throw new M(I.EncodeTimeSizeExceeded,`Cannot encode a time larger than ${te}: ${i}`);if(i<0)throw new M(I.EncodeTimeNegative,`Time must be positive: ${i}`);if(Number.isInteger(i)===false)throw new M(I.EncodeTimeValueMalformed,`Time must be an integer: ${i}`);let e,r="";for(let n=t;n>0;n--)e=i%E,r=re.charAt(e)+r,i=(i-e)/E;return r}function Ee(){return typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope}function ie(i,t){let e=Se(),r=Date.now();return ve(r,ne)+Me(we,e)}var D=()=>ie().toLowerCase();var P=(...i)=>{let t=i.filter(e=>!!e);return t.length===0?{}:t.length===1?t[0]:{$and:t}};var z=class{storage;queue=new Map;scheduled=false;constructor(t){this.storage=t;}async rawFind({resource:t,commonWhere:e,uniqueWhere:r,...n}){return new Promise((o,c)=>{let a=this.getBatchKey({resource:t,commonWhere:e,...n}),s={resource:t,commonWhere:e,uniqueWhere:r,...n,resolve:o,reject:c};this.queue.has(a)||this.queue.set(a,[]);let h=this.queue.get(a);h&&h.push(s),this.scheduled||(this.scheduled=true,setImmediate(()=>{this.processBatch();}));})}getBatchKey(t){let{resource:e,commonWhere:r,...n}=t;return `${e}:${JSON.stringify(r??{})}:${JSON.stringify(n??{})}`}async processBatch(){this.scheduled=false;let t=Array.from(this.queue.entries());this.queue.clear();for(let[,e]of t)try{await this.executeBatchedRequests(e);}catch(r){e.forEach(n=>{n.reject(r);});}}async executeBatchedRequests(t){var p,u;if(t.length===0)return;let e=t[0],{resource:r,commonWhere:n,include:o,sort:c}=e,a=t.length===1?e.limit:void 0,s=t.map(f=>f.uniqueWhere).filter(f=>f!==void 0),h=n,y=(p=Object.entries(s[0]??{})[0])==null?void 0:p[0];if(s.length>0){let f=s.map(l=>l[y]).filter(l=>l!=null);f.length>0&&(h=P(n,{[y]:{$in:f}}));}let d=await this.storage.rawFind({resource:r,where:h,include:o,sort:c,limit:a});for(let f of t){let l={};if(f.uniqueWhere){let[m,T]=Object.entries(f.uniqueWhere)[0];for(let[b,w]of Object.entries(d))((u=w.value[m])==null?void 0:u.value)===T&&(l[b]=w);}else Object.assign(l,d);f.resolve(l);}}};var ue=b(_(),1);var U=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()}),F=z$1.record(z$1.string(),z$1.object({value:z$1.string().or(z$1.number()).or(z$1.boolean()).or(z$1.date()).nullable(),_meta:z$1.object({timestamp:z$1.string().optional().nullable()}).optional()})),We=F.superRefine((i,t)=>{i.id&&t.addIssue({code:z$1.ZodIssueCode.custom,message:"Payload cannot have an id"});}),se=z$1.object({id:z$1.string().optional(),type:z$1.literal("MUTATE"),resource:z$1.string(),resourceId:z$1.string().optional()}),A=se.extend({procedure:z$1.string(),payload:z$1.any().optional()}),O=se.extend({procedure:z$1.enum(["INSERT","UPDATE"]),payload:We});z$1.union([O,A]);var ce=U.omit({resource:true}),V=A.omit({id:true,type:true,resource:true,procedure:true}),q=O.omit({id:true,type:true,resource:true,procedure:true});z$1.union([q,V]);var de=i=>{let t=i.logger;return async e=>{var r;try{let n=typeof e.headers.getSetCookie=="function"?Object.fromEntries(e.headers):e.headers,o={headers:n,cookies:n.cookie?ue.default.parse(n.cookie):{}},c=new URL(e.url),a=c.pathname.split("/"),s=c.searchParams,h=Be.parse(s.toString()),y=await((r=i.contextProvider)==null?void 0:r.call(i,{transport:"HTTP",headers:o.headers,cookies:o.cookies,queryParams:h}))??{};if(e.method==="GET"){let d=a[a.length-1],{success:p,data:u,error:f}=ce.safeParse(h);if(!p)return Response.json({message:"Invalid query",code:"INVALID_QUERY",details:f},{status:400});let l=await i.handleQuery({req:{...o,...u,type:"QUERY",resource:d,context:y,queryParams:h}});return !l||!l.data?Response.json({message:"Invalid resource",code:"INVALID_RESOURCE"},{status:400}):Response.json(l.data)}if(e.method==="POST")try{let d=a[a.length-1],p=a[a.length-2],u=e.body?await e.json():{},f;if(d==="insert"||d==="update"){let{success:m,data:T,error:b}=q.safeParse(u);if(!m)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:b},{status:400});f=T;}else {let{success:m,data:T,error:b}=V.safeParse(u);if(!m)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:b},{status:400});f=T;}let l=await i.handleMutation({req:{...o,type:"MUTATE",resource:p,input:f.payload,context:y,resourceId:f.resourceId,procedure:d==="insert"||d==="update"?d.toUpperCase():d,queryParams:{}}});return Response.json(l)}catch(d){return t.error("Error parsing mutation from the client:",d),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}return Response.json({message:"Not found",code:"NOT_FOUND"},{status:404})}catch(n){return t.error("Unexpected error:",n),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}}};var me=b(_(),1);var v=z$1.string(),De=z$1.object({id:v,type:z$1.literal("SUBSCRIBE"),resource:z$1.string()}),_e=U.extend({id:v,type:z$1.literal("QUERY")}),le=O.extend({id:v}),Fe=A.extend({id:v}),Ve=z$1.union([Fe,le]),pe=z$1.union([De,_e,Ve]),qe=z$1.object({id:v,type:z$1.literal("REJECT"),resource:z$1.string(),message:z$1.string().optional()}),Qe=z$1.object({id:v,type:z$1.literal("REPLY"),data:z$1.any()});z$1.union([qe,Qe,le]);z$1.object({resource:z$1.string(),data:z$1.record(z$1.string(),F)});var ye=i=>{let t={},e={},r=i.logger;return i.subscribeToMutations(n=>{let o=n;!o.resourceId||!o.payload||(r.debug("Mutation propagated:",o),Object.entries(e[o.resource]??{}).forEach(([c,a])=>{var s;(s=t[c])==null||s.send(JSON.stringify({...o,id:o.id??D()}));}));}),(n,o)=>{var d;let c=p=>{n.send(JSON.stringify(p));},a=D(),s={headers:o.headers,cookies:typeof o.headers.cookie=="string"?me.default.parse(o.headers.cookie):{}},h=parse(o.url.split("?")[1]),y=(d=i.contextProvider)==null?void 0:d.call(i,{transport:"WEBSOCKET",headers:s.headers,cookies:s.cookies,queryParams:h});t[a]=n,r.info("Client connected:",a),n.on("message",async p=>{try{r.debug("Message received from the client:",p);let u=pe.parse(JSON.parse(p.toString()));if(u.type==="SUBSCRIBE"){let{resource:f}=u;e[f]||(e[f]={}),e[f][a]={};}else if(u.type==="QUERY"){let{resource:f}=u,l=await i.handleQuery({req:{...s,type:"QUERY",resource:f,context:await y??{},queryParams:h}});if(!l||!l.data)throw new Error("Invalid resource");c({id:u.id,type:"REPLY",data:{resource:f,data:Object.fromEntries(Object.entries(l.data??{}).map(([m,T])=>[m,T.value]))}});}else if(u.type==="MUTATE"){let{resource:f}=u;r.debug("Received mutation from client:",u);try{let l=await i.handleMutation({req:{...s,type:"MUTATE",resource:f,input:u.payload,context:{messageId:u.id,...await y??{}},resourceId:u.resourceId,procedure:u.procedure,queryParams:h}});u.procedure&&u.procedure!=="INSERT"&&u.procedure!=="UPDATE"&&c({id:u.id,type:"REPLY",data:l});}catch(l){c({id:u.id,type:"REJECT",resource:f,message:l.message}),r.error("Error parsing mutation from the client:",l);}}}catch(u){r.error("Error handling message from the client:",u);}}),n.on("close",()=>{r.info("Connection closed",a),delete t[a];for(let p of Object.values(e))delete p[a];});}};function fe(i){let t=`${i.protocol}://${i.hostname}${i.url}`,e=new Headers;return Object.entries(i.headers).forEach(([r,n])=>{n&&e.set(r,Array.isArray(n)?n.join(","):n);}),new Request(t,{method:i.method,headers:e,body:i.body&&i.method!=="GET"?JSON.stringify(i.body):void 0})}var Ot=(i,t,e)=>{i.ws(`${(e==null?void 0:e.basePath)??""}/ws`,ye(t)),i.use(`${(e==null?void 0:e.basePath)??""}/`,(r,n)=>{de(t)(fe(r)).then(c=>c.json().then(a=>n.status(c.status).send(a)));});};var Q=class i{routes;constructor(t){this.routes=t.routes;}static create(t){return new i(t)}},zt=i=>Q.create({...i}),He=i=>({handler:t=>({inputValidator:i??z$1.undefined(),handler:t})}),Z=class i{resourceSchema;middlewares;customMutations;authorization;constructor(t,e,r){this.resourceSchema=t,this.middlewares=new Set,this.customMutations=e??{},this.authorization=r;}use(...t){for(let e of t)this.middlewares.add(e);return this}withMutations(t){return new i(this.resourceSchema,t({mutation:He}),this.authorization)}handleQuery=async({req:t,batcher:e})=>await this.wrapInMiddlewares(async r=>{var o,c;let n=(c=(o=this.authorization)==null?void 0:o.read)==null?void 0:c.call(o,{ctx:r.context});if(typeof n=="boolean"&&!n)throw new Error("Not authorized");return {data:await e.rawFind({resource:r.resource,commonWhere:P(r.where,typeof n=="object"?n:void 0),uniqueWhere:r.relationalWhere,include:r.include,limit:r.limit,sort:r.sort})}})(t);handleMutation=async({req:t,db:e,schema:r})=>await this.wrapInMiddlewares(async n=>{if(!n.procedure)throw new Error("Procedure is required for mutations");let o=this.customMutations[n.procedure];if(o){let c=o.inputValidator.parse(n.input);return n.input=c,o.handler({req:n,db:e})}else {if(n.procedure==="INSERT"||n.procedure==="UPDATE")return this.handleSet({req:n,db:e,operation:n.procedure,schema:r});throw new Error(`Unknown procedure: ${n.procedure}`)}})(t);handleSet=async({req:t$1,db:e,operation:r,schema:n})=>{if(!t$1.input)throw new Error("Payload is required");if(!t$1.resourceId)throw new Error("ResourceId is required");let o=await e.rawFindById(t$1.resource,t$1.resourceId);if(r==="INSERT"&&o)throw new Error("Resource already exists");if(r==="UPDATE"&&!o)throw new Error("Resource not found");return e.transaction(async({trx:c})=>{var y,d,p,u,f;let[a,s]=this.resourceSchema.mergeMutation("set",t$1.input,o);if(!s)throw new Error("Mutation rejected");if(r==="INSERT"){let l=await c.rawInsert(t$1.resource,t$1.resourceId,a),m=t(l);if(m.id=m.id??t$1.resourceId,(y=this.authorization)!=null&&y.insert){let T=this.authorization.insert({ctx:t$1.context,value:m});if(typeof T=="boolean"){if(!T)throw new Error("Not authorized")}else {let b=v$1(T,t$1.resource,n),w$1=Object.keys(b).length>0?await c.rawFindById(t$1.resource,t$1.resourceId,b):l,S=t(w$1);if(S.id=S.id??t$1.resourceId,!w(S,T))throw new Error("Not authorized")}}return {data:l,acceptedValues:s}}if((p=(d=this.authorization)==null?void 0:d.update)!=null&&p.preMutation){let l=t(o);l.id=l.id??t$1.resourceId;let m=this.authorization.update.preMutation({ctx:t$1.context,value:l});if(typeof m=="boolean"){if(!m)throw new Error("Not authorized")}else {let T=v$1(m,t$1.resource,n),b=Object.keys(T).length>0?await c.rawFindById(t$1.resource,t$1.resourceId,T):o,w$1=t(b);if(w$1.id=w$1.id??t$1.resourceId,!w(w$1,m))throw new Error("Not authorized")}}let h=await c.rawUpdate(t$1.resource,t$1.resourceId,a);if((f=(u=this.authorization)==null?void 0:u.update)!=null&&f.postMutation){let l=t(h);l.id=l.id??t$1.resourceId;let m=this.authorization.update.postMutation({ctx:t$1.context,value:l});if(typeof m=="boolean"){if(!m)throw new Error("Not authorized")}else {let T=v$1(m,t$1.resource,n),b=Object.keys(T).length>0?await c.rawFindById(t$1.resource,t$1.resourceId,T):h,w$1=t(b);if(w$1.id=w$1.id??t$1.resourceId,!w(w$1,m))throw new Error("Not authorized")}}return {data:h,acceptedValues:s}})};wrapInMiddlewares(t){return e=>Array.from(this.middlewares.values()).reduceRight((r,n)=>o=>n({req:o,next:r}),t)(e)}},G=class i{middlewares;constructor(t=[]){this.middlewares=t;}collectionRoute(t,e){return new Z(t,void 0,e).use(...this.middlewares)}use(...t){return new i([...this.middlewares,...t])}static create(){return new i}},Nt=G.create;var j=class{async insert(t$1,e){let r=new Date().toISOString();return t(await this.rawInsert(t$1.name,e.id,{value:Object.fromEntries(Object.entries(e).map(([n,o])=>[n,{value:o,_meta:{timestamp:r}}]))}))}async update(t$1,e,r){let n=new Date().toISOString(),{id:o,...c}=r;return t(await this.rawUpdate(t$1.name,e,{value:Object.fromEntries(Object.entries(c).map(([a,s])=>[a,{value:s,_meta:{timestamp:n}}]))}))}};function W(i,t,e,r){if(!i)throw new Error("Schema not initialized");let n=i[t];if(!n)throw new Error("Resource not found");let o=r.$or,c=r.$and;return (o?e.or:e.and)(o?r.$or.map(a=>W(i,t,e,a)):c?r.$and.map(a=>W(i,t,e,a)):Object.entries(r).map(([a,s])=>{var h,y;if(n.fields[a])return (s==null?void 0:s.$eq)!==void 0?e(`${t}.${a}`,s.$eq===null?"is":"=",s.$eq):(s==null?void 0:s.$in)!==void 0?e(`${t}.${a}`,"in",s.$in):(s==null?void 0:s.$not)!==void 0?((h=s==null?void 0:s.$not)==null?void 0:h.$in)!==void 0?e(`${t}.${a}`,"not in",s.$not.$in):((y=s==null?void 0:s.$not)==null?void 0:y.$eq)!==void 0?e(`${t}.${a}`,s.$not.$eq===null?"is not":"!=",s.$not.$eq):e(`${t}.${a}`,s.$not===null?"is not":"!=",s.$not):(s==null?void 0:s.$gt)!==void 0?e(`${t}.${a}`,">",s.$gt):(s==null?void 0:s.$gte)!==void 0?e(`${t}.${a}`,">=",s.$gte):(s==null?void 0:s.$lt)!==void 0?e(`${t}.${a}`,"<",s.$lt):(s==null?void 0:s.$lte)!==void 0?e(`${t}.${a}`,"<=",s.$lte):e(`${t}.${a}`,s===null?"is":"=",s);if(n.relations[a]){let d=n.relations[a],p=d.entity.name;return d.type==="many"?e.exists(H(i,p,e.selectFrom(p).select("id").whereRef(d.foreignColumn,"=",`${t}.id`),s)):W(i,p,e,s)}return null}).filter(Boolean))}function k(i,t,e,r){let n=i[t];if(!n)throw new Error("Resource not found");if(!r)return e;if(r.$and){for(let o of r.$and)e=k(i,t,e,o);return e}else if(r.$or){for(let o of r.$or)e=k(i,t,e,o);return e}for(let[o,c]of Object.entries(r)){if(!n.relations[o])continue;let a=n.relations[o],s=a.entity.name,h=a.type==="one"?"id":a.foreignColumn,y=a.type==="one"?a.relationalColumn:"id";e=e.leftJoin(s,`${s}.${h}`,`${t}.${y}`),c instanceof Object&&!Array.isArray(c)&&c!==null&&(e=k(i,s,e,c));}return e}function H(i,t,e,r){return !r||Object.keys(r).length===0?e:(e=k(i,t,e,r),e.where(n=>W(i,t,n,r)))}function B(i,t,e,r){if(!r)return e;if(!i)throw new Error("Schema not initialized");let n=i[t];if(!n)throw new Error(`Resource not found: ${t}`);for(let o of Object.keys(r)){if(!n.relations[o])throw new Error(`Relation ${o} not found in resource ${t}`);let c=n.relations[o],a=c.entity.name,s=r[o],h=c.type==="one"?"id":c.foreignColumn,y=c.type==="one"?c.relationalColumn:"id",d=c.type==="one"?jsonObjectFrom:jsonArrayFrom,p=typeof s=="object"&&s!==null;e=e.select(u=>{let f=u.selectFrom(a).selectAll(a).whereRef(`${a}.${h}`,"=",`${t}.${y}`).select(l=>jsonObjectFrom(l.selectFrom(`${a}_meta`).selectAll(`${a}_meta`).whereRef(`${a}_meta.id`,"=",`${a}.id`)).as("_meta"));return p&&(f=B(i,a,f,s)),d(f).as(o)});}return e}var K=class i extends j{db;schema;logger;constructor(t,e,r){super(),this.isKyselyLike(t)?this.db=t:this.db=new Kysely({dialect:new PostgresDialect({pool:t})}),this.schema=e,this.logger=r,this.rawInsert=this.rawInsert.bind(this),this.rawUpdate=this.rawUpdate.bind(this);}async init(t,e){var n;this.schema=t,this.logger=e;let r=await this.db.introspection.getTables();for(let[o,c]of Object.entries(t)){let a=r.find(y=>y.name===o);a||await this.db.schema.createTable(o).ifNotExists().execute();let s=`${o}_meta`,h=r.find(y=>y.name===s);h||await this.db.schema.createTable(s).ifNotExists().execute();for(let[y,d]of Object.entries(c.fields)){let p=a==null?void 0:a.columns.find(l=>l.name===y),u=d.getStorageFieldType();p?p.dataType!==u.type&&((n=this.logger)==null||n.warn("Column type mismatch:",y,"expected to have type:",u.type,"but has type:",p.dataType)):(await this.db.schema.alterTable(o).addColumn(y,u.type,l=>{let m=l;return u.unique&&(m=m.unique()),u.nullable||(m=m.notNull()),u.references&&(m=m.references(u.references)),u.primary&&(m=m.primaryKey()),u.default!==void 0&&(m=m.defaultTo(u.default)),m}).execute().catch(l=>{var m;throw (m=this.logger)==null||m.error("Error adding column",y,l),l}),u.index&&await this.db.schema.createIndex(`${o}_${y}_index`).on(o).column(y).execute().catch(()=>{})),(h==null?void 0:h.columns.find(l=>l.name===y))||await this.db.schema.alterTable(s).addColumn(y,"varchar",l=>{let m=l;return u.primary&&(m=m.primaryKey().references(`${o}.${y}`)),m}).execute();}}}async rawFindById(t,e,r){if(!this.schema)throw new Error("Schema not initialized");let n=await this.db.selectFrom(t).where("id","=",e).selectAll(t).select(c=>jsonObjectFrom(c.selectFrom(`${t}_meta`).selectAll(`${t}_meta`).whereRef(`${t}_meta.id`,"=",`${t}.id`)).as("_meta"));n=B(this.schema,t,n,r);let o=await n.executeTakeFirst();if(o)return this.convertToMaterializedLiveType(o)}async findOne(t$1,e,r){let n=await this.rawFindById(t$1.name,e,r==null?void 0:r.include);if(n)return t(n)}async rawFind(t){if(!this.schema)throw new Error("Schema not initialized");let{resource:e,where:r,include:n,limit:o,sort:c}=t,a=this.db.selectFrom(e).selectAll(e).select(d=>jsonObjectFrom(d.selectFrom(`${e}_meta`).selectAll(`${e}_meta`).whereRef(`${e}_meta.id`,"=",`${e}.id`)).as("_meta"));a=H(this.schema,e,a,r),a=B(this.schema,e,a,n),o!==void 0&&(a=a.limit(o)),c!==void 0&&c.forEach(d=>{a=a.orderBy(d.key,d.direction);});let s=await a.execute(),h=Object.fromEntries(s.map(d=>{let{id:p}=d;return [p,d]}));return Object.keys(h).length===0?{}:Object.entries(h).reduce((d,[p,u])=>(d[p]=this.convertToMaterializedLiveType(u),d),{})}async find(t$1,e){let r=await this.rawFind({resource:t$1.name,where:e==null?void 0:e.where,include:e==null?void 0:e.include,limit:e==null?void 0:e.limit,sort:e==null?void 0:e.sort});return Object.fromEntries(Object.entries(r).map(([n,o])=>[n,t(o)]))}async rawInsert(t,e,r){var c;let n={},o={};for(let[a,s]of Object.entries(r.value)){let h=(c=s._meta)==null?void 0:c.timestamp;h&&(n[a]=s.value,o[a]=h);}return await this.db.insertInto(t).values({...n,id:e}).execute().then(()=>{this.db.insertInto(`${t}_meta`).values({...o,id:e}).execute();}),r}async rawUpdate(t,e,r){var c;let n={},o={};for(let[a,s]of Object.entries(r.value)){let h=(c=s._meta)==null?void 0:c.timestamp;h&&(n[a]=s.value,o[a]=h);}return await Promise.all([this.db.updateTable(t).set(n).where("id","=",e).execute(),this.db.insertInto(`${t}_meta`).values({...o,id:e}).onConflict(a=>a.column("id").doUpdateSet(o)).execute()]),r}async transaction(t){if(!this.schema)throw new Error("Schema not initialized");if(this.db.isTransaction){let r=Math.random().toString(36).substring(2,15),n=await this.db.savepoint(r).execute();try{return await t({trx:this,commit:()=>n.releaseSavepoint(r).execute().then(()=>{}),rollback:()=>n.rollbackToSavepoint(r).execute().then(()=>{})}).then(o=>n.isCommitted||n.isRolledBack?o:n.releaseSavepoint(r).execute().then(()=>o))}catch(o){throw await n.rollbackToSavepoint(r).execute().catch(()=>{}),o}}let e=await this.db.startTransaction().execute();try{return await t({trx:new i(e,this.schema,this.logger),commit:()=>e.commit().execute(),rollback:()=>e.rollback().execute()}).then(r=>e.isCommitted||e.isRolledBack?r:e.commit().execute().then(()=>r))}catch(r){throw await e.rollback().execute(),r}}convertToMaterializedLiveType(t){return {value:Object.entries(t).reduce((e,[r,n])=>{var o,c,a;return r==="_meta"||(r==="id"?e[r]={value:n}:Array.isArray(n)?e[r]={value:n.map(s=>this.convertToMaterializedLiveType(s)),_meta:{timestamp:(o=t==null?void 0:t._meta)==null?void 0:o[r]}}:typeof n=="object"&&n!==null&&!(n instanceof Date)?e[r]={...this.convertToMaterializedLiveType(n),_meta:{timestamp:(c=t==null?void 0:t._meta)==null?void 0:c[r]}}:e[r]={value:n,_meta:{timestamp:(a=t==null?void 0:t._meta)==null?void 0:a[r]}}),e},{})}}isKyselyLike(t){if(t instanceof Kysely)return true;if(!t||typeof t!="object")return false;let e=t,r=typeof e.selectFrom=="function",n=typeof e.startTransaction=="function",o=typeof e.savepoint=="function",c=typeof e.isTransaction=="boolean"||typeof e.isTransaction=="function";return r&&n||o&&c}};var J=class i{router;storage;schema;middlewares=new Set;logger;contextProvider;mutationSubscriptions=new Set;constructor(t){var e;this.router=t.router,this.storage=t.storage,this.schema=t.schema,this.logger=y({level:t.logLevel??x.INFO}),(e=t.middlewares)==null||e.forEach(r=>{this.middlewares.add(r);}),this.storage.init(this.schema,this.logger),this.contextProvider=t.contextProvider;}static create(t){return new i(t)}subscribeToMutations(t){return this.mutationSubscriptions.add(t),()=>{this.mutationSubscriptions.delete(t);}}handleQuery(t){let e=new z(this.storage);return this.wrapInMiddlewares(async r=>{var h;let n=Re(r,this.schema,{stepId:"query",collectionName:r.resource,included:Object.keys(r.include??{})}),o={headers:r.headers,cookies:r.cookies,queryParams:r.queryParams,context:r.context},c={};for(let y=0;y<n.length;y++){let d=n[y],p=this.router.routes[d.resource];if(!p)throw new Error("Invalid resource");let u=d.getWhere&&d.referenceGetter?d.referenceGetter(c).map(d.getWhere):[void 0],f=(h=c[d.prevStepId??""])==null?void 0:h.flatMap(T=>{var b;return Object.keys(((b=T==null?void 0:T.result)==null?void 0:b.data)??{})}),m=(await Promise.allSettled(u.map(async(T,b)=>{let w=f==null?void 0:f[b],S=await p.handleQuery({req:{type:"QUERY",...d,...o,where:d.where,relationalWhere:T},batcher:e});return {includedBy:w,result:S}}))).flatMap(T=>T.status==="fulfilled"?[T.value]:[]);c[d.stepId]=m;}let a=Object.fromEntries(Object.entries(c).flatMap(([y,d],p)=>d.flatMap(u=>Object.entries(u.result.data).map(([f,l])=>[`${y}.${f}`,{data:l,includedBy:y!=="query"&&u.includedBy?`${y.split(".").slice(0,-1).join(".")}.${u.includedBy}`:void 0,path:y.split(".").slice(-1)[0],isMany:n[p].isMany,collectionName:n[p].collectionName,included:n[p].included}]))));return Object.keys(a).reduceRight((y,d)=>{var f,l;let p=a[d],u=p.path;if(u==="query"&&(y.data[d.replace("query.","")]=p.data),p.included.length)for(let m of p.included)p.data.value[m]??=((l=(f=this.schema[p.collectionName])==null?void 0:f.relations[m])==null?void 0:l.type)==="many"?{value:[]}:{value:null};if(p.includedBy){let m=a[p.includedBy];if(!m)return y;p.isMany?(m.data.value[u]??={value:[]},m.data.value[u].value.push(p.data)):m.data.value[u]=p.data;}return y},{data:{}})})(t.req)}async handleMutation(t){let e=await this.wrapInMiddlewares(async r=>{let n=this.router.routes[r.resource];if(!n)throw new Error("Invalid resource");return n.handleMutation({req:r,db:this.storage,schema:this.schema})})(t.req);if(e&&t.req.type==="MUTATE"&&e.acceptedValues&&(t.req.procedure==="INSERT"||t.req.procedure==="UPDATE")&&t.req.resourceId){let n=e.acceptedValues??{},o=t.req,c=o.resourceId;Object.keys(n).length&&c&&this.mutationSubscriptions.forEach(a=>{a({id:t.req.context.messageId,type:"MUTATE",resource:o.resource,payload:n,resourceId:c,procedure:o.procedure});});}return e}use(t){return this.middlewares.add(t),this}context(t){return this.contextProvider=t,this}wrapInMiddlewares(t){return e=>Array.from(this.middlewares.values()).reduceRight((r,n)=>o=>n({req:o,next:r}),t)(e)}},Xt=J.create;function Re(i,t,e){let{include:r,where:n,...o}=i,{stepId:c}=e,a=[{...o,...e,where:n}];if(r&&typeof r=="object"&&Object.keys(r).length>0){let s=t[o.resource];if(!s)throw new Error(`Resource ${o.resource} not found`);a.push(...Object.entries(r).flatMap(([h,y])=>{let d=s.relations[h];if(!d)throw new Error(`Relation ${h} not found for resource ${o.resource}`);let p=d.entity.name;return Re({...o,resource:p,include:y},t,{getWhere:d.type==="one"?u=>({id:u}):u=>({[d.foreignColumn]:u}),referenceGetter:u=>u[c].flatMap(f=>f.result.data?d.type==="one"?Object.values(f.result.data).map(l=>{var m,T;return (T=(m=l.value)==null?void 0:m[d.relationalColumn])==null?void 0:T.value}):Object.keys(f.result.data):[]),stepId:`${c}.${h}`,prevStepId:c,isMany:d.type==="many",collectionName:p,included:typeof y=="object"?Object.keys(y):[]})}));}return a}
2
- export{Z as Route,G as RouteFactory,Q as Router,K as SQLStorage,J as Server,j as Storage,Ot as expressAdapter,Nt as routeFactory,zt as router,Xt as server};
1
+ import {a,b,t,w,x,z as z$2,y,v}from'./chunk-3SQDLIFN.js';import V from'node:crypto';import Je,{parse}from'qs';import {z as z$1}from'zod';import {Kysely,PostgresDialect}from'kysely';import {jsonObjectFrom,jsonArrayFrom}from'kysely/helpers/postgres';var H=a(Q=>{Object.defineProperty(Q,"__esModule",{value:true});Q.parse=Fe;Q.serialize=Qe;var De=/^[\u0021-\u003A\u003C\u003E-\u007E]+$/,Ue=/^[\u0021-\u003A\u003C-\u007E]*$/,Be=/^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i,_e=/^[\u0020-\u003A\u003D-\u007E]*$/,Ve=Object.prototype.toString,qe=(()=>{let i=function(){};return i.prototype=Object.create(null),i})();function Fe(i,t){let e=new qe,r=i.length;if(r<2)return e;let n=(t==null?void 0:t.decode)||Ge,a=0;do{let s=i.indexOf("=",a);if(s===-1)break;let c=i.indexOf(";",a),o=c===-1?r:c;if(s>o){a=i.lastIndexOf(";",s-1)+1;continue}let p=me(i,a,s),f=he(i,s,p),u=i.slice(p,f);if(e[u]===void 0){let h=me(i,s+1,o),R=he(i,o,h),d=n(i.slice(h,R));e[u]=d;}a=o+1;}while(a<r);return e}function me(i,t,e){do{let r=i.charCodeAt(t);if(r!==32&&r!==9)return t}while(++t<e);return e}function he(i,t,e){for(;t>e;){let r=i.charCodeAt(--t);if(r!==32&&r!==9)return t+1}return e}function Qe(i,t,e){let r=(e==null?void 0:e.encode)||encodeURIComponent;if(!De.test(i))throw new TypeError(`argument name is invalid: ${i}`);let n=r(t);if(!Ue.test(n))throw new TypeError(`argument val is invalid: ${t}`);let a=i+"="+n;if(!e)return a;if(e.maxAge!==void 0){if(!Number.isInteger(e.maxAge))throw new TypeError(`option maxAge is invalid: ${e.maxAge}`);a+="; Max-Age="+e.maxAge;}if(e.domain){if(!Be.test(e.domain))throw new TypeError(`option domain is invalid: ${e.domain}`);a+="; Domain="+e.domain;}if(e.path){if(!_e.test(e.path))throw new TypeError(`option path is invalid: ${e.path}`);a+="; Path="+e.path;}if(e.expires){if(!Ze(e.expires)||!Number.isFinite(e.expires.valueOf()))throw new TypeError(`option expires is invalid: ${e.expires}`);a+="; Expires="+e.expires.toUTCString();}if(e.httpOnly&&(a+="; HttpOnly"),e.secure&&(a+="; Secure"),e.partitioned&&(a+="; Partitioned"),e.priority)switch(typeof e.priority=="string"?e.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: ${e.priority}`)}if(e.sameSite)switch(typeof e.sameSite=="string"?e.sameSite.toLowerCase():e.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: ${e.sameSite}`)}return a}function Ge(i){if(i.indexOf("%")===-1)return i;try{return decodeURIComponent(i)}catch{return i}}function Ze(i){return Ve.call(i)==="[object Date]"}});var pe="0123456789ABCDEFGHJKMNPQRSTVWXYZ",N=32;var Ce=16,ye=10,le=0xffffffffffff;var O;(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";})(O||(O={}));var L=class extends Error{constructor(t,e){super(`${e} (${t})`),this.name="ULIDError",this.code=t;}};function $e(i){let t=Math.floor(i()*N);return t===N&&(t=N-1),pe.charAt(t)}function ze(i){var r;let t=Pe(),e=t&&(t.crypto||t.msCrypto)||(typeof V<"u"?V:null);if(typeof(e==null?void 0:e.getRandomValues)=="function")return ()=>{let n=new Uint8Array(1);return e.getRandomValues(n),n[0]/255};if(typeof(e==null?void 0:e.randomBytes)=="function")return ()=>e.randomBytes(1).readUInt8()/255;if((r=V)!=null&&r.randomBytes)return ()=>V.randomBytes(1).readUInt8()/255;throw new L(O.PRNGDetectFailure,"Failed to find a reliable PRNG")}function Pe(){return We()?self:typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:null}function ke(i,t){let e="";for(;i>0;i--)e=$e(t)+e;return e}function Ne(i,t=ye){if(isNaN(i))throw new L(O.EncodeTimeValueMalformed,`Time must be a number: ${i}`);if(i>le)throw new L(O.EncodeTimeSizeExceeded,`Cannot encode a time larger than ${le}: ${i}`);if(i<0)throw new L(O.EncodeTimeNegative,`Time must be positive: ${i}`);if(Number.isInteger(i)===false)throw new L(O.EncodeTimeValueMalformed,`Time must be an integer: ${i}`);let e,r="";for(let n=t;n>0;n--)e=i%N,r=pe.charAt(e)+r,i=(i-e)/N;return r}function We(){return typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope}function fe(i,t){let e=ze(),r=Date.now();return Ne(r,ye)+ke(Ce,e)}var q=()=>fe().toLowerCase();var $=(...i)=>{let t=i.filter(e=>!!e);return t.length===0?{}:t.length===1?t[0]:{$and:t}};var F=class{storage;queue=new Map;scheduled=false;constructor(t){this.storage=t;}async rawFind({resource:t,commonWhere:e,uniqueWhere:r,...n}){return new Promise((a,s)=>{let c=this.getBatchKey({resource:t,commonWhere:e,...n}),o={resource:t,commonWhere:e,uniqueWhere:r,...n,resolve:a,reject:s};this.queue.has(c)||this.queue.set(c,[]);let p=this.queue.get(c);p&&p.push(o),this.scheduled||(this.scheduled=true,setImmediate(()=>{this.processBatch();}));})}getBatchKey(t){let{resource:e,commonWhere:r,...n}=t;return `${e}:${JSON.stringify(r??{})}:${JSON.stringify(n??{})}`}async processBatch(){this.scheduled=false;let t=Array.from(this.queue.entries());this.queue.clear();for(let[,e]of t)try{await this.executeBatchedRequests(e);}catch(r){e.forEach(n=>{n.reject(r);});}}async executeBatchedRequests(t){var h,R;if(t.length===0)return;let e=t[0],{resource:r,commonWhere:n,include:a,sort:s}=e,c=t.length===1?e.limit:void 0,o=t.map(d=>d.uniqueWhere).filter(d=>d!==void 0),p=n,f=(h=Object.entries(o[0]??{})[0])==null?void 0:h[0];if(o.length>0){let d=o.map(m=>m[f]).filter(m=>m!=null);d.length>0&&(p=$(n,{[f]:{$in:d}}));}let u=await this.storage.rawFind({resource:r,where:p,include:a,sort:s,limit:c});for(let d of t){let m={};if(d.uniqueWhere){let[y,l]=Object.entries(d.uniqueWhere)[0];for(let[g,T]of Object.entries(u))((R=T.value[y])==null?void 0:R.value)===l&&(m[g]=T);}else Object.assign(m,u);d.resolve(m);}}};var Re=b(H(),1);var W=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()}),J=z$1.record(z$1.string(),z$1.object({value:z$1.string().or(z$1.number()).or(z$1.boolean()).or(z$1.date()).nullable(),_meta:z$1.object({timestamp:z$1.string().optional().nullable()}).optional()})),Ke=J.superRefine((i,t)=>{i.id&&t.addIssue({code:z$1.ZodIssueCode.custom,message:"Payload cannot have an id"});}),ge=z$1.object({id:z$1.string().optional(),type:z$1.literal("MUTATE"),resource:z$1.string(),resourceId:z$1.string().optional()}),D=ge.extend({procedure:z$1.string(),payload:z$1.any().optional()}),U=ge.extend({procedure:z$1.enum(["INSERT","UPDATE"]),payload:Ke});z$1.union([U,D]);var Te=W.omit({resource:true}),Y=D.omit({id:true,type:true,resource:true,procedure:true}),X=U.omit({id:true,type:true,resource:true,procedure:true});z$1.union([X,Y]);var be=i=>{let t=i.logger;return async e=>{var r;try{let n=typeof e.headers.getSetCookie=="function"?Object.fromEntries(e.headers):e.headers,a={headers:n,cookies:n.cookie?Re.default.parse(n.cookie):{}},s=new URL(e.url),c=s.pathname.split("/"),o=s.searchParams,p=Je.parse(o.toString()),f=await((r=i.contextProvider)==null?void 0:r.call(i,{transport:"HTTP",headers:a.headers,cookies:a.cookies,queryParams:p}))??{};if(e.method==="GET"){let u=c[c.length-1],{success:h,data:R,error:d}=Te.safeParse(p);if(!h)return Response.json({message:"Invalid query",code:"INVALID_QUERY",details:d},{status:400});let m=await i.handleQuery({req:{...a,...R,type:"QUERY",resource:u,context:f,queryParams:p}});return !m||!m.data?Response.json({message:"Invalid resource",code:"INVALID_RESOURCE"},{status:400}):Response.json(m.data)}if(e.method==="POST")try{let u=c[c.length-1],h=c[c.length-2],R=e.body?await e.json():{},d;if(u==="insert"||u==="update"){let{success:y,data:l,error:g}=X.safeParse(R);if(!y)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:g},{status:400});d=l;}else {let{success:y,data:l,error:g}=Y.safeParse(R);if(!y)return Response.json({message:"Invalid mutation",code:"INVALID_REQUEST",details:g},{status:400});d=l;}let m=await i.handleMutation({req:{...a,type:"MUTATE",resource:h,input:d.payload,context:f,resourceId:d.resourceId,procedure:u==="insert"||u==="update"?u.toUpperCase():u,queryParams:{}}});return Response.json(m)}catch(u){return t.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(n){return t.error("Unexpected error:",n),Response.json({message:"Internal server error",code:"INTERNAL_SERVER_ERROR"},{status:500})}}};var xe=b(H(),1);var z=z$1.string(),Ye=W.extend({id:z,type:z$1.literal("SUBSCRIBE")}),Xe=W.extend({id:z,type:z$1.literal("QUERY")}),Se=U.extend({id:z}),et=D.extend({id:z}),tt=z$1.union([et,Se]),we=z$1.union([Ye,Xe,tt]),rt=z$1.object({id:z,type:z$1.literal("REJECT"),resource:z$1.string(),message:z$1.string().optional()}),nt=z$1.object({id:z,type:z$1.literal("REPLY"),data:z$1.any()});z$1.union([rt,nt,Se]);z$1.object({resource:z$1.string(),data:z$1.record(z$1.string(),J)});var Me=i=>{let t={},e=i.logger;return (r,n)=>{var u;let a=h=>{r.send(JSON.stringify(h));},s=q(),c=new Set,o={headers:n.headers,cookies:typeof n.headers.cookie=="string"?xe.default.parse(n.headers.cookie):{}},p=parse(n.url.split("?")[1]),f=(u=i.contextProvider)==null?void 0:u.call(i,{transport:"WEBSOCKET",headers:o.headers,cookies:o.cookies,queryParams:p});t[s]=r,e.info("Client connected:",s),r.on("message",async h=>{var R;try{e.debug("Message received from the client:",h);let d=we.parse(JSON.parse(h.toString()));if(d.type==="SUBSCRIBE"){let m=await f??{},y=d.resource,l=i.router.routes[y],g;if((R=l==null?void 0:l.authorization)!=null&&R.read){let T=l.authorization.read({ctx:m});g=typeof T=="object"?T:void 0;}c.add(i.subscribeToMutations(d,T=>{var S;!T.resourceId||!T.payload||!Object.keys(T.payload).length||(S=t[s])==null||S.send(JSON.stringify(T));},g));}else if(d.type==="QUERY"){let{resource:m}=d,y=await i.handleQuery({req:{...o,type:"QUERY",resource:m,context:await f??{},queryParams:p}});if(!y||!y.data)throw new Error("Invalid resource");a({id:d.id,type:"REPLY",data:{resource:m,data:Object.fromEntries(Object.entries(y.data??{}).map(([l,g])=>[l,g.value]))}});}else if(d.type==="MUTATE"){let{resource:m}=d;e.debug("Received mutation from client:",d);try{let y=await i.handleMutation({req:{...o,type:"MUTATE",resource:m,input:d.payload,context:{messageId:d.id,...await f??{}},resourceId:d.resourceId,procedure:d.procedure,queryParams:p}});d.procedure&&d.procedure!=="INSERT"&&d.procedure!=="UPDATE"&&a({id:d.id,type:"REPLY",data:y});}catch(y){a({id:d.id,type:"REJECT",resource:m,message:y.message}),e.error("Error parsing mutation from the client:",y);}}}catch(d){e.error("Error handling message from the client:",d);}}),r.on("close",()=>{e.info("Connection closed",s),delete t[s];for(let h of Array.from(c))h();});}};function Ie(i){let t=`${i.protocol}://${i.hostname}${i.url}`,e=new Headers;return Object.entries(i.headers).forEach(([r,n])=>{n&&e.set(r,Array.isArray(n)?n.join(","):n);}),new Request(t,{method:i.method,headers:e,body:i.body&&i.method!=="GET"?JSON.stringify(i.body):void 0})}var Dt=(i,t,e)=>{i.ws(`${(e==null?void 0:e.basePath)??""}/ws`,Me(t)),i.use(`${(e==null?void 0:e.basePath)??""}/`,(r,n)=>{be(t)(Ie(r)).then(s=>s.json().then(c=>n.status(s.status).send(c)));});};var ee=class i{routes;constructor(t){this.routes=t.routes;}static create(t){return new i(t)}},Ft=i=>ee.create({...i}),ot=i=>({handler:t=>({inputValidator:i??z$1.undefined(),handler:t})}),te=class i{resourceSchema;middlewares;customMutations;authorization;constructor(t,e,r){this.resourceSchema=t,this.middlewares=new Set,this.customMutations=e??{},this.authorization=r;}use(...t){for(let e of t)this.middlewares.add(e);return this}withMutations(t){return new i(this.resourceSchema,t({mutation:ot}),this.authorization)}handleQuery=async({req:t,batcher:e})=>await this.wrapInMiddlewares(async r=>{var a,s;let n=(s=(a=this.authorization)==null?void 0:a.read)==null?void 0:s.call(a,{ctx:r.context});if(typeof n=="boolean"&&!n)throw new Error("Not authorized");return {data:await e.rawFind({resource:r.resource,commonWhere:$(r.where,typeof n=="object"?n:void 0),uniqueWhere:r.relationalWhere,include:r.include,limit:r.limit,sort:r.sort})}})(t);handleMutation=async({req:t,db:e,schema:r})=>await this.wrapInMiddlewares(async n=>{if(!n.procedure)throw new Error("Procedure is required for mutations");let a=this.customMutations[n.procedure];if(a){let s=a.inputValidator.parse(n.input);return n.input=s,a.handler({req:n,db:e})}else {if(n.procedure==="INSERT"||n.procedure==="UPDATE")return this.handleSet({req:n,db:e,operation:n.procedure,schema:r});throw new Error(`Unknown procedure: ${n.procedure}`)}})(t);handleSet=async({req:t$1,db:e,operation:r,schema:n})=>{if(!t$1.input)throw new Error("Payload is required");if(!t$1.resourceId)throw new Error("ResourceId is required");let a=await e.rawFindById(t$1.resource,t$1.resourceId);if(r==="INSERT"&&a)throw new Error("Resource already exists");if(r==="UPDATE"&&!a)throw new Error("Resource not found");return e.transaction(async({trx:s})=>{var f,u,h,R,d;let[c,o]=this.resourceSchema.mergeMutation("set",t$1.input,a);if(!o)throw new Error("Mutation rejected");if(r==="INSERT"){let m=await s.rawInsert(t$1.resource,t$1.resourceId,c),y=t(m);if(y.id=y.id??t$1.resourceId,(f=this.authorization)!=null&&f.insert){let l=this.authorization.insert({ctx:t$1.context,value:y});if(typeof l=="boolean"){if(!l)throw new Error("Not authorized")}else {let g=w(l,t$1.resource,n),T=Object.keys(g).length>0?await s.rawFindById(t$1.resource,t$1.resourceId,g):m,S=t(T);if(S.id=S.id??t$1.resourceId,!x(S,l))throw new Error("Not authorized")}}return {data:m,acceptedValues:o}}if((h=(u=this.authorization)==null?void 0:u.update)!=null&&h.preMutation){let m=t(a);m.id=m.id??t$1.resourceId;let y=this.authorization.update.preMutation({ctx:t$1.context,value:m});if(typeof y=="boolean"){if(!y)throw new Error("Not authorized")}else {let l=w(y,t$1.resource,n),g=Object.keys(l).length>0?await s.rawFindById(t$1.resource,t$1.resourceId,l):a,T=t(g);if(T.id=T.id??t$1.resourceId,!x(T,y))throw new Error("Not authorized")}}let p=await s.rawUpdate(t$1.resource,t$1.resourceId,c);if((d=(R=this.authorization)==null?void 0:R.update)!=null&&d.postMutation){let m=t(p);m.id=m.id??t$1.resourceId;let y=this.authorization.update.postMutation({ctx:t$1.context,value:m});if(typeof y=="boolean"){if(!y)throw new Error("Not authorized")}else {let l=w(y,t$1.resource,n),g=Object.keys(l).length>0?await s.rawFindById(t$1.resource,t$1.resourceId,l):p,T=t(g);if(T.id=T.id??t$1.resourceId,!x(T,y))throw new Error("Not authorized")}}return {data:p,acceptedValues:o}})};wrapInMiddlewares(t){return e=>Array.from(this.middlewares.values()).reduceRight((r,n)=>a=>n({req:a,next:r}),t)(e)}},re=class i{middlewares;constructor(t=[]){this.middlewares=t;}collectionRoute(t,e){return new te(t,void 0,e).use(...this.middlewares)}use(...t){return new i([...this.middlewares,...t])}static create(){return new i}},Qt=re.create;var B=class{async insert(t$1,e){let r=new Date().toISOString();return t(await this.rawInsert(t$1.name,e.id,{value:Object.fromEntries(Object.entries(e).map(([n,a])=>[n,{value:a,_meta:{timestamp:r}}]))}))}async update(t$1,e,r){let n=new Date().toISOString(),{id:a,...s}=r;return t(await this.rawUpdate(t$1.name,e,{value:Object.fromEntries(Object.entries(s).map(([c,o])=>[c,{value:o,_meta:{timestamp:n}}]))}))}};function G(i,t,e,r){if(!i)throw new Error("Schema not initialized");let n=i[t];if(!n)throw new Error("Resource not found");let a=r.$or,s=r.$and;return (a?e.or:e.and)(a?r.$or.map(c=>G(i,t,e,c)):s?r.$and.map(c=>G(i,t,e,c)):Object.entries(r).map(([c,o])=>{var p,f;if(n.fields[c])return (o==null?void 0:o.$eq)!==void 0?e(`${t}.${c}`,o.$eq===null?"is":"=",o.$eq):(o==null?void 0:o.$in)!==void 0?e(`${t}.${c}`,"in",o.$in):(o==null?void 0:o.$not)!==void 0?((p=o==null?void 0:o.$not)==null?void 0:p.$in)!==void 0?e(`${t}.${c}`,"not in",o.$not.$in):((f=o==null?void 0:o.$not)==null?void 0:f.$eq)!==void 0?e(`${t}.${c}`,o.$not.$eq===null?"is not":"!=",o.$not.$eq):e(`${t}.${c}`,o.$not===null?"is not":"!=",o.$not):(o==null?void 0:o.$gt)!==void 0?e(`${t}.${c}`,">",o.$gt):(o==null?void 0:o.$gte)!==void 0?e(`${t}.${c}`,">=",o.$gte):(o==null?void 0:o.$lt)!==void 0?e(`${t}.${c}`,"<",o.$lt):(o==null?void 0:o.$lte)!==void 0?e(`${t}.${c}`,"<=",o.$lte):e(`${t}.${c}`,o===null?"is":"=",o);if(n.relations[c]){let u=n.relations[c],h=u.entity.name;return u.type==="many"?e.exists(ne(i,h,e.selectFrom(h).select("id").whereRef(u.foreignColumn,"=",`${t}.id`),o)):G(i,h,e,o)}return null}).filter(Boolean))}function Z(i,t,e,r){let n=i[t];if(!n)throw new Error("Resource not found");if(!r)return e;if(r.$and){for(let a of r.$and)e=Z(i,t,e,a);return e}else if(r.$or){for(let a of r.$or)e=Z(i,t,e,a);return e}for(let[a,s]of Object.entries(r)){if(!n.relations[a])continue;let c=n.relations[a],o=c.entity.name,p=c.type==="one"?"id":c.foreignColumn,f=c.type==="one"?c.relationalColumn:"id";e=e.leftJoin(o,`${o}.${p}`,`${t}.${f}`),s instanceof Object&&!Array.isArray(s)&&s!==null&&(e=Z(i,o,e,s));}return e}function ne(i,t,e,r){return !r||Object.keys(r).length===0?e:(e=Z(i,t,e,r),e.where(n=>G(i,t,n,r)))}function K(i,t,e,r){if(!r)return e;if(!i)throw new Error("Schema not initialized");let n=i[t];if(!n)throw new Error(`Resource not found: ${t}`);for(let a of Object.keys(r)){if(!n.relations[a])throw new Error(`Relation ${a} not found in resource ${t}`);let s=n.relations[a],c=s.entity.name,o=r[a],p=s.type==="one"?"id":s.foreignColumn,f=s.type==="one"?s.relationalColumn:"id",u=s.type==="one"?jsonObjectFrom:jsonArrayFrom,h=typeof o=="object"&&o!==null;e=e.select(R=>{let d=R.selectFrom(c).selectAll(c).whereRef(`${c}.${p}`,"=",`${t}.${f}`).select(m=>jsonObjectFrom(m.selectFrom(`${c}_meta`).selectAll(`${c}_meta`).whereRef(`${c}_meta.id`,"=",`${c}.id`)).as("_meta"));return h&&(d=K(i,c,d,o)),u(d).as(a)});}return e}var je="42701",ie=class i extends B{db;schema;logger;server;mutationStack=[];constructor(t,e,r,n){super(),this.isKyselyLike(t)?this.db=t:this.db=new Kysely({dialect:new PostgresDialect({pool:t})}),this.schema=e,this.logger=r,this.server=n,this.rawInsert=this.rawInsert.bind(this),this.rawUpdate=this.rawUpdate.bind(this);}async init(t,e,r){var a;this.schema=t,this.logger=e,this.server=r;let n=await this.db.introspection.getTables();for(let[s,c]of Object.entries(t)){let o=n.find(u=>u.name===s);o||await this.db.schema.createTable(s).ifNotExists().execute();let p=`${s}_meta`,f=n.find(u=>u.name===p);f||await this.db.schema.createTable(p).ifNotExists().execute();for(let[u,h]of Object.entries(c.fields)){let R=o==null?void 0:o.columns.find(y=>y.name===u),d=h.getStorageFieldType();R?R.dataType!==d.type&&((a=this.logger)==null||a.warn("Column type mismatch:",u,"expected to have type:",d.type,"but has type:",R.dataType)):(await this.db.schema.alterTable(s).addColumn(u,d.type,y=>{let l=y;return d.unique&&(l=l.unique()),d.nullable||(l=l.notNull()),d.references&&(l=l.references(d.references)),d.primary&&(l=l.primaryKey()),d.default!==void 0&&(l=l.defaultTo(d.default)),l}).execute().catch(y=>{var l;if(y.code!==je)throw (l=this.logger)==null||l.error("Error adding column",u,y),y}),d.index&&await this.db.schema.createIndex(`${s}_${u}_index`).on(s).column(u).execute().catch(()=>{})),(f==null?void 0:f.columns.find(y=>y.name===u))||await this.db.schema.alterTable(p).addColumn(u,"varchar",y=>{let l=y;return d.primary&&(l=l.primaryKey().references(`${s}.${u}`)),l}).execute().catch(y=>{var l;if(y.code!==je)throw (l=this.logger)==null||l.error("Error adding meta column",u,y),y});}}}async rawFindById(t,e,r){if(!this.schema)throw new Error("Schema not initialized");let n=await this.db.selectFrom(t).where("id","=",e).selectAll(t).select(s=>jsonObjectFrom(s.selectFrom(`${t}_meta`).selectAll(`${t}_meta`).whereRef(`${t}_meta.id`,"=",`${t}.id`)).as("_meta"));n=K(this.schema,t,n,r);let a=await n.executeTakeFirst();if(a)return this.convertToMaterializedLiveType(a)}async findOne(t$1,e,r){let n=await this.rawFindById(t$1.name,e,r==null?void 0:r.include);if(n)return t(n)}async rawFind(t){if(!this.schema)throw new Error("Schema not initialized");let{resource:e,where:r,include:n,limit:a,sort:s}=t,c=this.db.selectFrom(e).selectAll(e).select(u=>jsonObjectFrom(u.selectFrom(`${e}_meta`).selectAll(`${e}_meta`).whereRef(`${e}_meta.id`,"=",`${e}.id`)).as("_meta"));c=ne(this.schema,e,c,r),c=K(this.schema,e,c,n),a!==void 0&&(c=c.limit(a)),s!==void 0&&s.forEach(u=>{c=c.orderBy(u.key,u.direction);});let o=await c.execute(),p=Object.fromEntries(o.map(u=>{let{id:h}=u;return [h,u]}));return Object.keys(p).length===0?{}:Object.entries(p).reduce((u,[h,R])=>(u[h]=this.convertToMaterializedLiveType(R),u),{})}async find(t$1,e){let r=await this.rawFind({resource:t$1.name,where:e==null?void 0:e.where,include:e==null?void 0:e.include,limit:e==null?void 0:e.limit,sort:e==null?void 0:e.sort});return Object.fromEntries(Object.entries(r).map(([n,a])=>[n,t(a)]))}async rawInsert(t,e,r){var c;let n={},a={};for(let[o,p]of Object.entries(r.value)){let f=(c=p._meta)==null?void 0:c.timestamp;f&&(n[o]=p.value,a[o]=f);}await this.db.insertInto(t).values({...n,id:e}).execute().then(()=>{this.db.insertInto(`${t}_meta`).values({...a,id:e}).execute();});let s=this.buildMutation(t,e,"INSERT",r);return s&&this.trackMutation(s,r),r}async rawUpdate(t,e,r){var c;let n={},a={};for(let[o,p]of Object.entries(r.value)){let f=(c=p._meta)==null?void 0:c.timestamp;f&&(n[o]=p.value,a[o]=f);}await Promise.all([this.db.updateTable(t).set(n).where("id","=",e).execute(),this.db.insertInto(`${t}_meta`).values({...a,id:e}).onConflict(o=>o.column("id").doUpdateSet(a)).execute()]);let s=this.buildMutation(t,e,"UPDATE",r);return s&&this.trackMutation(s,r),r}async transaction(t){if(!this.schema)throw new Error("Schema not initialized");if(this.db.isTransaction){let a=Math.random().toString(36).substring(2,15),s=this.mutationStack,c=[];this.mutationStack=c;let o=await this.db.savepoint(a).execute();try{return await t({trx:this,commit:async()=>{await o.releaseSavepoint(a).execute(),s.push(...c);},rollback:async()=>{await o.rollbackToSavepoint(a).execute(),c.length=0;}}).then(p=>o.isCommitted||o.isRolledBack?p:o.releaseSavepoint(a).execute().then(()=>(s.push(...c),p)))}catch(p){throw await o.rollbackToSavepoint(a).execute().catch(()=>{}),c.length=0,p}finally{this.mutationStack=s;}}let e=[],r=this.mutationStack;this.mutationStack=e;let n=await this.db.startTransaction().execute();try{let a=new i(n,this.schema,this.logger,this.server);return a.mutationStack=e,await t({trx:a,commit:async()=>{await n.commit().execute(),this.notifyMutations(e);},rollback:async()=>{await n.rollback().execute(),e.length=0;}}).then(s=>n.isCommitted||n.isRolledBack?s:n.commit().execute().then(()=>(this.notifyMutations(e),s)))}catch(a){throw await n.rollback().execute(),e.length=0,a}finally{this.mutationStack=r;}}get internalDB(){return this.db}convertToMaterializedLiveType(t){return {value:Object.entries(t).reduce((e,[r,n])=>{var a,s,c;return r==="_meta"||(r==="id"?e[r]={value:n}:Array.isArray(n)?e[r]={value:n.map(o=>this.convertToMaterializedLiveType(o)),_meta:{timestamp:(a=t==null?void 0:t._meta)==null?void 0:a[r]}}:typeof n=="object"&&n!==null&&!(n instanceof Date)?e[r]={...this.convertToMaterializedLiveType(n),_meta:{timestamp:(s=t==null?void 0:t._meta)==null?void 0:s[r]}}:e[r]={value:n,_meta:{timestamp:(c=t==null?void 0:t._meta)==null?void 0:c[r]}}),e},{})}}isKyselyLike(t){if(t instanceof Kysely)return true;if(!t||typeof t!="object")return false;let e=t,r=typeof e.selectFrom=="function",n=typeof e.startTransaction=="function",a=typeof e.savepoint=="function",s=typeof e.isTransaction=="boolean"||typeof e.isTransaction=="function";return r&&n||a&&s}buildMutation(t,e,r,n){var s;let a={};for(let[c,o]of Object.entries(n.value)){if(c==="id")continue;let p=(s=o._meta)==null?void 0:s.timestamp;p&&(a[c]={value:o.value,_meta:{timestamp:p}});}return Object.keys(a).length===0?null:{id:q(),type:"MUTATE",resource:t,resourceId:e,procedure:r,payload:a}}trackMutation(t,e){this.db.isTransaction?this.mutationStack.push({mutation:t,entityData:e}):this.notifyMutations([t],e);}notifyMutations(t,e){if(this.server)if(e!==void 0){let r=t;for(let n of r)this.server.notifySubscribers(n,e);}else {let r=t;for(let{mutation:n,entityData:a}of r)this.server.notifySubscribers(n,a);}}};var ae=class i{router;storage;schema;middlewares=new Set;logger;contextProvider;mutationSubscriptions=new Set;collectionSubscriptions=new Map;constructor(t){var e;this.router=t.router,this.storage=t.storage,this.schema=t.schema,this.logger=z$2({level:t.logLevel??y.INFO}),(e=t.middlewares)==null||e.forEach(r=>{this.middlewares.add(r);}),this.storage.init(this.schema,this.logger,this),this.contextProvider=t.contextProvider;}static create(t){return new i(t)}handleQuery(t){let e=new F(this.storage);return this.wrapInMiddlewares(async r=>{var R,d,m;let n=Oe(r,this.schema,{stepId:"query",collectionName:r.resource,included:Object.keys(r.include??{})}),a={headers:r.headers,cookies:r.cookies,queryParams:r.queryParams,context:r.context},s={};for(let y=0;y<n.length;y++){let l=n[y],g=this.router.routes[l.resource];if(!g)throw new Error("Invalid resource");let T;if(l.getWhere&&l.referenceGetter){let w=l.referenceGetter(s);T=[];for(let M=0;M<w.length;M++)T.push(l.getWhere(w[M]));}else T=[void 0];let S=s[l.prevStepId??""],v=[];if(S)for(let w=0;w<S.length;w++){let M=S[w],A=Object.keys(((R=M==null?void 0:M.result)==null?void 0:R.data)??{});for(let k=0;k<A.length;k++)v.push(A[k]);}let j=[];for(let w=0;w<T.length;w++){let M=T[w],A=v[w];j.push((async()=>{let k=await g.handleQuery({req:{type:"QUERY",...l,...a,where:l.where,relationalWhere:M},batcher:e});return {includedBy:A,result:k}})());}let E=await Promise.allSettled(j),P=[];for(let w=0;w<E.length;w++){let M=E[w];M.status==="fulfilled"&&P.push(M.value);}s[l.stepId]=P;}let c=new Map,o=0;for(let y in s){let l=s[y],g=n[o];o++;for(let T=0;T<l.length;T++){let S=l[T],v=S.result.data;for(let j in v){let E=v[j],P=`${y}.${j}`,w=[];y!=="query"&&S.includedBy&&(w=[`${g.prevStepId}.${S.includedBy}`]);let M=c.get(P);if(M)for(let A=0;A<w.length;A++)M.includedBy.add(w[A]);else c.set(P,{data:E,includedBy:new Set(w),path:y.split(".").slice(-1)[0],isMany:g.isMany??false,collectionName:g.collectionName,included:g.included});}}}let p=Object.fromEntries(c),f={data:{}},u=Object.keys(p);for(let y=u.length-1;y>=0;y--){let l=u[y],g=p[l],T=g.path;if(T==="query"&&(f.data[l.replace("query.","")]=g.data),g.included.length)for(let S=0;S<g.included.length;S++){let v=g.included[S];g.data.value[v]??=((m=(d=this.schema[g.collectionName])==null?void 0:d.relations[v])==null?void 0:m.type)==="many"?{value:[]}:{value:null};}if(g.includedBy.size>0){let S=Array.from(g.includedBy);for(let v=0;v<S.length;v++){let j=S[v],E=p[j];E&&(g.isMany?(E.data.value[T]??={value:[]},E.data.value[T].value.push(g.data)):E.data.value[T]=g.data);}}}return f})(t.req)}async handleMutation(t){let e=await this.wrapInMiddlewares(async r=>{let n=this.router.routes[r.resource];if(!n)throw new Error("Invalid resource");return n.handleMutation({req:r,db:this.storage,schema:this.schema})})(t.req);if(e&&t.req.type==="MUTATE"&&e.acceptedValues&&(t.req.procedure==="INSERT"||t.req.procedure==="UPDATE")&&t.req.resourceId){let n=e.acceptedValues??{},a=t.req,s=a.resourceId;Object.keys(n).length&&s&&this.mutationSubscriptions.forEach(c=>{c({id:t.req.context.messageId,type:"MUTATE",resource:a.resource,payload:n,resourceId:s,procedure:a.procedure});});}return e}use(t){return this.middlewares.add(t),this}context(t){return this.contextProvider=t,this}subscribeToMutations(t,e,r){let n=t.resource,a={query:t,authorizationWhere:r},s=v(a),c=this.collectionSubscriptions.get(n);c||(c=new Map,this.collectionSubscriptions.set(n,c));let o=c.get(s);return o?(o.callbacks.add(e),r!==void 0&&(o.authorizationWhere=r)):c.set(s,{callbacks:new Set([e]),...a}),()=>{var f,u;let p=this.collectionSubscriptions.get(n);p&&((f=p.get(s))==null||f.callbacks.delete(e),((u=p.get(s))==null?void 0:u.callbacks.size)===0&&p.delete(s));}}notifySubscribers(t$1,e){let r=t$1.resource,n=this.collectionSubscriptions.get(r);if(n&&e)for(let a of Array.from(n.values())){let s=oe(a.query.where,this.schema[r]),c=$(s,a.authorizationWhere),o=t(e);if(!o)continue;(t$1.resourceId&&typeof o=="object"&&o!==null&&!("id"in o)||t$1.resourceId&&typeof o=="object"&&o!==null&&o.id!==t$1.resourceId)&&(o.id=t$1.resourceId);let p=Object.keys(c).length>0,f=true;p&&(f=x(o,c)),f&&a.callbacks.forEach(u=>{var h;try{u(t$1);}catch(R){(h=this.logger)==null||h.error(`Error in mutation subscription for resource ${r}:`,R);}});}}wrapInMiddlewares(t){return e=>Array.from(this.middlewares.values()).reduceRight((r,n)=>a=>n({req:a,next:r}),t)(e)}},pr=ae.create;function Oe(i,t,e){let{include:r,where:n,...a}=i,{stepId:s}=e,c=[{...a,...e,where:n}];if(r&&typeof r=="object"&&Object.keys(r).length>0){let o=t[a.resource];if(!o)throw new Error(`Resource ${a.resource} not found`);c.push(...Object.entries(r).flatMap(([p,f])=>{let u=o.relations[p];if(!u)throw new Error(`Relation ${p} not found for resource ${a.resource}`);let h=u.entity.name;return Oe({...a,resource:h,include:f},t,{getWhere:u.type==="one"?R=>({id:R}):R=>({[u.foreignColumn]:R}),referenceGetter:R=>R[s].flatMap(d=>d.result.data?u.type==="one"?Object.values(d.result.data).map(m=>{var y,l;return (l=(y=m.value)==null?void 0:y[u.relationalColumn])==null?void 0:l.value}):Object.keys(d.result.data):[]),stepId:`${s}.${p}`,prevStepId:s,isMany:u.type==="many",collectionName:h,included:typeof f=="object"?Object.keys(f):[]})}));}return c}function oe(i,t){if(!i||!t||Object.keys(i).length===0)return i;if(i.$and){let r=i.$and.map(n=>oe(n,t)).filter(n=>!!n&&Object.keys(n).length>0);return r.length===0?void 0:r.length===1?r[0]:{$and:r}}if(i.$or){let r=i.$or.map(n=>oe(n,t)).filter(n=>!!n&&Object.keys(n).length>0);return r.length===0?void 0:r.length===1?r[0]:{$or:r}}let e={};for(let[r,n]of Object.entries(i))t.fields[r]&&(e[r]=n);return Object.keys(e).length>0?e:void 0}
2
+ export{te as Route,re as RouteFactory,ee as Router,ie as SQLStorage,ae as Server,B as Storage,Dt as expressAdapter,Qt as routeFactory,Ft as router,pr as server};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-state/sync",
3
- "version": "0.0.5",
3
+ "version": "0.0.6-canary-2",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -27,6 +27,7 @@
27
27
  "@types/express": "^4.17.21",
28
28
  "@types/express-ws": "^3.0.5",
29
29
  "@types/node": "^20.11.24",
30
+ "@types/pg": "^8.15.1",
30
31
  "@types/qs": "^6.14.0",
31
32
  "@types/react": "^18.2.62",
32
33
  "@types/react-dom": "^18.2.19",
@@ -35,6 +36,8 @@
35
36
  "cookie": "^1.0.2",
36
37
  "express": "^4.21.2",
37
38
  "jsdom": "^26.1.0",
39
+ "pg": "^8.15.6",
40
+ "express-ws": "^5.0.2",
38
41
  "react": "18.0.0",
39
42
  "react-dom": "^18.2.0",
40
43
  "tsup": "^8.0.2",
@@ -1 +0,0 @@
1
- import'js-xxhash';var O=Object.create;var I=Object.defineProperty;var K=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,M=Object.prototype.hasOwnProperty;var C=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var S=(t,e,n,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of A(e))!M.call(t,a)&&a!==n&&I(t,a,{get:()=>e[a],enumerable:!(i=K(e,a))||i.enumerable});return t};var V=(t,e,n)=>(n=t!=null?O(j(t)):{},S(e||!t||!t.__esModule?I(n,"default",{value:t,enumerable:true}):n,t));var o=class{_value;_meta;_encodeInput;_decodeInput};var m=class extends o{inner;constructor(e){super(),this.inner=e;}encodeMutation(e,n,i){return this.inner.encodeMutation(e,n,i)}mergeMutation(e,n,i){return this.inner.mergeMutation(e,n,i)}getStorageFieldType(){return {...this.inner.getStorageFieldType(),nullable:true}}},y=class t extends o{storageType;convertFunc;isIndex;isUnique;defaultValue;foreignReference;isPrimary;constructor(e,n,i,a,s,l,r){super(),this.storageType=e,this.convertFunc=n,this.isIndex=i??false,this.isUnique=a??false,this.defaultValue=s,this.foreignReference=l,this.isPrimary=r??false;}encodeMutation(e,n,i){return {value:n,_meta:{timestamp:i}}}mergeMutation(e,n,i){return i&&i._meta.timestamp&&n._meta.timestamp&&i._meta.timestamp.localeCompare(n._meta.timestamp)>=0?[i,null]:[{value:this.convertFunc?this.convertFunc(n.value):n.value,_meta:n._meta},n]}getStorageFieldType(){return {type:this.storageType,nullable:false,index:this.isIndex,unique:this.isUnique,default:this.defaultValue,references:this.foreignReference,primary:this.isPrimary}}unique(){return new t(this.storageType,this.convertFunc,this.isIndex,true,this.defaultValue,this.foreignReference,this.isPrimary)}index(){return new t(this.storageType,this.convertFunc,true,this.isUnique,this.defaultValue,this.foreignReference,this.isPrimary)}default(e){return new t(this.storageType,this.convertFunc,this.isIndex,this.isUnique,e,this.foreignReference,this.isPrimary)}primary(){return new t(this.storageType,this.convertFunc,this.isIndex,this.isUnique,this.defaultValue,this.foreignReference,true)}nullable(){return new m(this)}},v=class t extends y{constructor(){super("integer",e=>Number(e));}static create(){return new t}},F=v.create,p=class t extends y{constructor(e){super("varchar",void 0,void 0,void 0,void 0,e);}static create(){return new t}static createId(){return new t().index().unique().primary()}static createReference(e){return new t(e)}},q=p.create,N=p.createId,D=p.createReference,L=class t extends y{constructor(){super("boolean",e=>typeof e=="string"?e.toLowerCase()==="true":!!e);}static create(){return new t}},W=L.create,h=class t extends y{constructor(){super("timestamp",e=>typeof e=="string"?new Date(e):e);}static create(){return new t}},P=h.create;var g=class t extends o{name;fields;relations;constructor(e,n,i){super(),this.name=e,this.fields=n,this.relations=i??{};}encodeMutation(e,n,i){return Object.fromEntries(Object.entries(n).map(([a,s])=>[a,(this.fields[a]??this.relations[a]).encodeMutation("set",s,i)]))}mergeMutation(e,n,i){let a={};return [{value:{...(i==null?void 0:i.value)??{},...Object.fromEntries(Object.entries(n).map(([s,l])=>{let r=this.fields[s]??this.relations[s];if(!r)return [s,l];let[u,d]=r.mergeMutation(e,l,i==null?void 0:i.value[s]);return d&&(a[s]=d),[s,u]}))}},a]}setRelations(e){return new t(this.name,this.fields,e)}getStorageFieldType(){throw new Error("Method not implemented.")}static create(e,n){return new t(e,n)}},z=g.create,f=class t extends o{entity;type;required;relationalColumn;foreignColumn;sourceEntity;constructor(e,n,i,a,s){super(),this.entity=e,this.type=n,this.required=s??false,this.relationalColumn=i,this.foreignColumn=a;}encodeMutation(e,n,i){if(e!=="set")throw new Error("Mutation type not implemented.");if(this.type==="many")throw new Error("Many not implemented.");return {value:n,_meta:{timestamp:i}}}mergeMutation(e,n,i){if(this.type==="many")throw new Error("Many not implemented.");return i&&i._meta.timestamp&&n._meta.timestamp&&i._meta.timestamp.localeCompare(n._meta.timestamp)>=0?[i,null]:[n,n]}getStorageFieldType(){return {type:"varchar",nullable:!this.required,references:`${this.entity.name}.${String(this.foreignColumn??this.relationalColumn??"id")}`}}toJSON(){return {entityName:this.entity.name,type:this.type,required:this.required,relationalColumn:this.relationalColumn,foreignColumn:this.foreignColumn}}static createOneFactory(){return (e,n,i)=>new t(e,"one",n,void 0,i??false)}static createManyFactory(){return (e,n,i)=>new t(e,"many",void 0,n,i??false)}},G=(t,e)=>({$type:"relations",objectName:t.name,relations:e({one:f.createOneFactory(),many:f.createManyFactory()})}),x=t=>t?Array.isArray(t.value)?t.value.map(n=>x(n)):typeof t.value!="object"||t.value===null||t.value instanceof Date?t.value:Object.fromEntries(Object.entries(t.value).map(([n,i])=>Array.isArray(i)?[n,i.map(a=>x(a))]:[n,x(i)])):void 0,H=t=>Object.fromEntries(Object.entries(t).flatMap(([e,n])=>{if(n.$type==="relations")return [];let i=n,a=Object.values(t).find(s=>s.$type==="relations"&&s.objectName===n.name);return a&&(i=i.setRelations(a.relations)),[[i.name,i]]}));var w=(t,e,n)=>{let i={},a=n[e];if(!a)return i;let s=l=>{l.$and?l.$and.forEach(s):l.$or?l.$or.forEach(s):Object.entries(l).forEach(([r,u])=>{var d;if((d=a.relations)!=null&&d[r]&&(i[r]=true,typeof u=="object"&&u!==null&&!Array.isArray(u))){let b=w(u,a.relations[r].entity.name,n);Object.keys(b).length>0&&(i[r]=b);}});};return s(t),i},c=(t,e,n=false)=>Object.entries(e).every(([i,a])=>{if(i==="$and")return a.every(l=>c(t,l,n));if(i==="$or")return a.some(l=>c(t,l,n));let s=(a==null?void 0:a.$eq)!==void 0?a==null?void 0:a.$eq:a;if(typeof a=="object"&&a!==null&&(a==null?void 0:a.$eq)===void 0){if(a.$in!==void 0){let r=t[i];return r===void 0?false:n?!a.$in.includes(r):a.$in.includes(r)}if(a.$not!==void 0&&!n)return c(t,{[i]:a.$not},true);if(a.$gt!==void 0){let r=t[i];return typeof r!="number"?false:n?r<=a.$gt:r>a.$gt}if(a.$gte!==void 0){let r=t[i];return typeof r!="number"?false:n?r<a.$gte:r>=a.$gte}if(a.$lt!==void 0){let r=t[i];return typeof r!="number"?false:n?r>=a.$lt:r<a.$lt}if(a.$lte!==void 0){let r=t[i];return typeof r!="number"?false:n?r>a.$lte:r<=a.$lte}let l=t[i];return !l||typeof l!="object"&&!Array.isArray(l)?false:Array.isArray(l)?n?!l.some(r=>c(r,a,false)):l.some(r=>c(r,a,false)):c(l,a,n)}return n?t[i]!==s:t[i]===s}),T={CRITICAL:0,ERROR:1,WARN:2,INFO:3,DEBUG:4},R=class{level;prefix;constructor(e={}){this.level=e.level??T.INFO,this.prefix=e.prefix?`[${e.prefix}] `:"";}critical(...e){this.level>=T.CRITICAL&&console.error(`${this.prefix}[CRITICAL]`,...e);}error(...e){this.level>=T.ERROR&&console.error(`${this.prefix}[ERROR]`,...e);}warn(...e){this.level>=T.WARN&&console.warn(`${this.prefix}[WARN]`,...e);}info(...e){this.level>=T.INFO&&console.log(`${this.prefix}[INFO]`,...e);}debug(...e){this.level>=T.DEBUG&&console.log(`${this.prefix}[DEBUG]`,...e);}setLevel(e){this.level=e;}getLevel(){return this.level}},Z=t=>new R(t);export{C as a,V as b,o as c,m as d,y as e,v as f,F as g,p as h,q as i,N as j,D as k,L as l,W as m,h as n,P as o,g as p,z as q,f as r,G as s,x as t,H as u,w as v,c as w,T as x,Z as y};