tinybase
Version:
A reactive data store and sync engine.
2 lines (1 loc) • 7.46 kB
JavaScript
import{DurableObject as t}from"cloudflare:workers";const e="",s=(t,e="",s)=>t.split(e,s),a=Promise,n=t=>(e,s,a)=>t(e)?a?.():s(e),r=globalThis,i=(t,e=0)=>setTimeout(t,1e3*e),o=Math,c=o.floor,l=t=>null==t,g=t=>void 0===t,u=t=>null===t,d=n(l),h=n(g),w=t=>Array.isArray(t),y=(t,e,s)=>t.slice(e,s),C=t=>t.length,p=t=>{throw Error(t)},S=async(t,e,s)=>{try{return await t()}catch(t){e?.(t)}},v=(t,e)=>t.forEach(e),b=(t,e)=>t.map(e),f=(t,...e)=>t.push(...e),M=t=>t.shift(),A=Object,m=t=>A.getPrototypeOf(t),P=A.entries,k=t=>!l(t)&&d(m(t),t=>t==A.prototype||l(m(t)),()=>!0),T=A.keys,x=A.freeze,L=(t=[])=>A.fromEntries(t),I=(t,e)=>v(P(t),([t,s])=>e(s,t)),H=t=>k(t)&&0==(t=>C(T(t)))(t),D=(t,e,s)=>(((t,e)=>e in t)(t,e)||(t[e]=s()),t[e]),O=JSON.stringify,R=JSON.parse,E=t=>""===t?void 0:w(t)?b(t,E):k(t)?((t,e)=>L(((t,e)=>b(P(t),([t,s])=>e(s,t)))(t,(t,s)=>[s,e(t,s)])))(t,E):t,N=(t,e)=>{const s=t.indexOf("\n");-1!==s&&e(y(t,0,s),y(t,s+1))},W=(t,...s)=>z(t??e,O(s,(t,e)=>g(e)?"":e)),z=(t,e)=>t+"\n"+e,U=t=>g(t)||0==(t=>t?.size??0)(t),V=(t,e)=>t?.forEach(e),F=(t,e)=>t?.delete(e),J=Map,$=t=>new J(t),j=(t,e)=>t?.get(e),q=(t,e,s)=>g(s)?(F(t,e),t):t?.set(e,s),B=(t,e,s,a)=>{var n,r;return n=t,r=e,n?.has(r)?a?.(j(t,e)):q(t,e,s()),j(t,e)},G=(t,e,s,a,n=0)=>h((s?B:j)(t,e[n],n>C(e)-2?s:$),r=>{if(n>C(e)-2)return a?.(r)&&q(t,e[n]),r;const i=G(r,e,s,a,n+1);return U(r)&&q(t,e[n]),i}),K=s("-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"),Q=r.crypto?t=>r.crypto.getRandomValues(t):t=>b(t,()=>c(256*o.random())),X=(t=16)=>{return e=(t,e)=>t+K[63&e],Q(new Uint8Array(t)).reduce(e,"");var e},Y=(t,e)=>e?[t,e]:[t],Z=(t,e)=>((t??"")>(e??"")?t:e)??"",_=(t="")=>Y(L(),t),tt=/^\d+$/,et=t=>new Set(w(t)||g(t)?t:[t]),st=$(),at=$(),nt=(t,s,a,n,r,i,o,c={},l=0,d=[])=>{let y,b,A,m=0,P=0,k=0;B(st,d,()=>0),B(at,d,()=>[]);const T=$(),[L,I,D,O,R]=((t=1,e,s)=>1!=t&&e.isMergeable()?[1,e.getMergeableContent,()=>e.getTransactionMergeableChanges(!s),([[t],[e]])=>!H(t)||!H(e),e.setDefaultContent]:2!=t?[0,e.getContent,e.getTransactionChanges,([t,e])=>!H(t)||!H(e),e.setContent]:p("Store type not supported by this Persister"))(o,t,l),[E,N,W]=(()=>{let t;const[s,a]=(()=>{const t=[];let s=0;return[a=>(a?M(t):null)??e+s++,e=>{tt.test(e)&&C(t)<1e3&&f(t,e)}]})(),n=$();return[(a,r,i,o=[],c=()=>[])=>{t??=ct;const l=s(1);var g,u;return q(n,l,[a,r,i,o,c]),g=G(r,i??[e],et),u=l,g?.add(u),l},(s,a,...r)=>v(((t,s=[e])=>{const a=[],n=(t,e)=>e==C(s)?f(a,t):u(s[e])?V(t,t=>n(t,e+1)):v([s[e],null],s=>n(j(t,s),e+1));return n(t,0),a})(s,a),e=>V(e,e=>j(n,e)[0](t,...a??[],...r))),t=>h(j(n,t),([,s,r])=>(G(s,r??[e],void 0,e=>(F(e,t),U(e)?1:0)),q(n,t),a(t),r)),e=>h(j(n,e),([e,,s=[],a,n])=>{const r=(...i)=>{const o=C(i);o==C(s)?e(t,...i,...n(i)):u(s[o])?v(a[o]?.(...i)??[],t=>r(...i,t)):r(...i,s[o])};r()})]})(),z=t=>{t!=m&&(m=t,N(T,void 0,m))},J=e=>{(L&&w(e?.[0])?1===e?.[2]?t.applyMergeableChanges:t.setMergeableContent:1===e?.[2]?t.applyChanges:t.setContent)(e)},K=async()=>{rt()&&t.hadMutated?.()&&await Z()},Q=async t=>(2!=m&&(z(1),P++,await ot(async()=>{await S(async()=>{const e=await s();w(e)?J(e):t?R(t):p("Content is not an array: "+e)},()=>{t&&R(t)}),z(0),await K()})),ct),X=async t=>(Y(),await Q(t),await S(async()=>b=await n(async(t,e)=>{e||t?2!=m&&(z(1),P++,J(e??t),z(0),await K()):await Q()}),i),ct),Y=async()=>(b&&(await S(()=>r(b),i),b=void 0),ct),Z=async t=>(1!=m&&(z(2),k++,await ot(async()=>{await S(()=>a(I,t),i),z(0)})),ct),_=async()=>(nt(),await Z(),A=t.addDidFinishTransactionListener(()=>{const t=D();O(t)&&Z(t)}),ct),nt=async()=>(A&&(t.delListener(A),A=void 0),ct),rt=()=>!g(A),it=async(t=!1)=>{const[e,s]=t?[nt,Y]:[Y,nt];return await e(),await s(),ct},ot=async(...t)=>(f(j(at,d),...t),await(async()=>{if(!j(st,d)){for(q(st,d,1);!g(y=M(j(at,d)));)await S(y,i);q(st,d,0)}})(),ct),ct={load:Q,startAutoLoad:X,stopAutoLoad:Y,isAutoLoading:()=>!g(b),save:Z,startAutoSave:_,stopAutoSave:nt,isAutoSaving:rt,startAutoPersisting:async(t,e=!1)=>{const[s,a]=e?[_,X]:[X,_];return await s(t),await a(t),ct},stopAutoPersisting:it,getStatus:()=>m,addStatusListener:t=>E(t,T),delListener:e=>(W(e),t),schedule:ot,getStore:()=>t,destroy:()=>(j(at,d).splice(0,void 0),it()),getStats:()=>({loads:P,saves:k}),...c};return x(ct)},rt=/\/([^?]*)/,it="S",ot=t=>{return(s=new URL(t.url).pathname,a=rt,s?.match(a))?.[1]??e;var s,a},ct=t=>"websocket"==t.headers.get("upgrade")?.toLowerCase()?t.headers.get("sec-websocket-key"):null,lt=(t,e=null,s=null)=>new Response(s,{status:t,webSocket:e}),gt=()=>lt(426,null,"Upgrade required");class ut extends t{#t;constructor(t,s){super(t,s),this.ctx.blockConcurrencyWhile(async()=>await h(await this.createPersister(),async t=>{const s=((t,s,n,r,o,c,l,d,w={})=>{let y,C=0,p=0,v=0;const b=$(),f=()=>X(11),M=(t,e,a,n)=>{p++,s(t,e,a,n)},A=async(t,e,s,n)=>new a((a,r)=>{const c=n+"."+X(4),l=i(()=>{F(b,c),r(`No response from ${t??"anyone"} to ${c}, `+e)},o);q(b,c,[t,(t,e)=>{clearTimeout(l),F(b,c),a([t,e,n])}]),M(t,c,e,s)}),m=(t,[e,s])=>{I(e,([e,s],a)=>{const n=D(t[0],a,_);I(e,([t,e],s)=>{const a=D(n[0],s,_);I(t,([t,e],s)=>a[0][s]=Y(t,e)),a[1]=Z(a[1],e)}),n[1]=Z(n[1],s)}),t[1]=Z(t[1],s)},P=(s=null,a,n=f())=>S(async()=>{g(a)&&([a,s,n]=await A(null,1,e,n));const[r,i]=a,[o,c]=t.getMergeableContentHashes();let l=_();if(o!=r){const[e,a]=(await A(s,4,t.getMergeableTableHashes(),n))[0];if(l=e,!H(a)){const[e,r]=(await A(s,5,t.getMergeableRowHashes(a),n))[0];if(m(l,e),!H(r)){const e=(await A(s,6,t.getMergeableCellHashes(r),n))[0];m(l,e)}}}return[l,c==i?_():(await A(s,7,t.getMergeableValueHashes(),n))[0],1]},d),k=nt(t,async()=>{const t=await P();return!t||H(t[0][0])&&H(t[1][0])?void 0:t},async(e,s)=>s?M(null,f(),3,s):M(null,f(),2,t.getMergeableContentHashes()),t=>y=t,()=>y=void 0,d,2,{startSync:async t=>(C=1,await k.startAutoPersisting(t)),stopSync:async()=>(C=0,await k.stopAutoPersisting(),k),destroy:async()=>(await k.stopSync(),k),getSynchronizerStats:()=>({sends:p,receives:v}),...w},1);return n((e,s,a,n)=>{const r=C||k.isAutoLoading();v++,0==a?h(j(b,s),([t,s])=>u(t)||t==e?s(n,e):0):2==a&&r?P(e,n,s??void 0).then(t=>{y?.(void 0,t)}).catch(d):3==a&&r?y?.(void 0,n):h(1==a&&(C||k.isAutoSaving())?t.getMergeableContentHashes():4==a?t.getMergeableTableDiff(n):5==a?t.getMergeableRowDiff(n):6==a?t.getMergeableCellDiff(n):7==a?t.getMergeableValueDiff(n):void 0,t=>{M(e,s,0,t)})}),k})(t.getStore(),(t,e,s,a)=>this.#e(it,W(t,e,s,a)),t=>this.#t=e=>((t,e)=>N(t,(t,s)=>{return e(t,...(a=s,E(R(a))));var a}))(e,t),0,1);await t.load(),await t.startAutoSave(),i(s.startSync)}))}fetch(t){const s=ot(t);return h(ct(t),t=>{const[a,n]=(r=new WebSocketPair,A.values(r));var r,i;return i=this.#s(),0==C(i)&&this.onPathId(s,1),this.ctx.acceptWebSocket(n,[t,s]),this.onClientId(s,t,1),n.send(W(it,null,1,e)),lt(101,a)},gt)}webSocketMessage(t,e){h(this.ctx.getTags(t)[0],s=>this.#e(s,e.toString(),t))}webSocketClose(t){const[e,s]=this.ctx.getTags(t);this.onClientId(s,e,-1),1==C(this.#s())&&this.onPathId(s,-1)}#e(t,s,a){N(s.toString(),(s,n)=>{const r=z(t,n);this.onMessage(t,s,n),s==e?(t!=it&&this.#t?.(r),v(this.#s(),t=>{t!=a&&t.send(r)})):s==it?this.#t?.(r):s!=t&&this.#s(s)[0]?.send(r)})}#s(t){return this.ctx.getWebSockets(t)}createPersister(){}getPathId(){return this.ctx.getTags(this.#s()[0])?.[1]}getClientIds(){return b(this.#s(),t=>this.ctx.getTags(t)[0])}onPathId(t,e){}onClientId(t,e,s){}onMessage(t,e,s){}}const dt=t=>(e,s)=>ct(e)?s[t].get(s[t].idFromName(ot(e))).fetch(e):gt();export{ut as WsServerDurableObject,dt as getWsServerDurableObjectFetch};