stunk 2.8.1 → 3.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var Y=Object.defineProperty;var Z=(e,o)=>{for(var r in o)Y(e,r,{get:o[r],enumerable:true});};function _(e){return e!==null}function ee(e){if(!e||typeof e!="object")return false;let o=e;return ["get","set","subscribe","derive","reset","destroy"].every(t=>typeof o[t]=="function")}function te(e){let o=false,r;return ()=>(o||(r=e(),o=true),r)}function re(e){let o=Object.keys(e).reduce((n,u)=>(n[u]=null,n),{}),r={loading:Object.keys(e).length>0,error:null,errors:{},data:o},t=k(r);return Object.entries(e).forEach(([n,u])=>{u.subscribe(a=>{let s=t.get(),l=false,c=null,f={};Object.entries(e).forEach(([h,x])=>{let p=x.get();p.loading&&(l=true),p.error&&(c||(c=p.error),f[h]=p.error);}),t.set({loading:l,error:c,errors:f,data:{...s.data,[n]:a.data}});});}),t}function N(e,o){if(e===null)throw new Error("Value cannot be null.");let r=e;for(let t=0;t<o.length;t++){let n=o[t],u=typeof n=="function"?n:n.fn,a=typeof n=="function"?`index ${t}`:n.name||`index ${t}`;try{let s=u(r);if(s===void 0)break;if(s===null)throw new Error(`Middleware "${a}" returned null value.`);r=s;}catch(s){let l=s instanceof Error?s.message:String(s);throw new Error(`Middleware "${a}" threw an error: ${l}`)}}return r}function M(e,o){if(e===o)return true;if(!e||!o||typeof e!=typeof o)return false;if(Array.isArray(e)&&Array.isArray(o)){if(e.length!==o.length)return false;for(let r=0;r<e.length;r++)if(e[r]!==o[r])return false;return true}if(typeof e=="object"&&typeof o=="object"){let r=Object.keys(e),t=Object.keys(o);if(r.length!==t.length)return false;for(let n of r)if(!Object.prototype.hasOwnProperty.call(o,n)||e[n]!==o[n])return false;return true}return false}function D(e,o,r=""){if(typeof e=="object"&&e!==null&&typeof o=="object"&&o!==null){if(Array.isArray(e)&&Array.isArray(o)){if(e.length>0&&typeof e[0]=="object")for(let t=0;t<o.length;t++)D(e[0],o[t],`${r}[${t}]`);}else if(!Array.isArray(e)&&!Array.isArray(o)){let t=Object.keys(e),n=Object.keys(o),u=n.filter(a=>!t.includes(a));u.length>0&&(console.error(`\u{1F6A8} Stunk: Unknown properties detected at '${r||"root"}': ${u.join(", ")}. This might cause bugs.`),console.error("Expected keys:",t),console.error("Received keys:",n));for(let a of t)D(e[a],o[a],r?`${r}.${a}`:a);}}}var V=false,R=new Set,O=new Map,ne=0;function oe(e){let o=V;V=true;try{e();}finally{if(!o){V=false;let r=Array.from(R);R.clear(),r.forEach(t=>{let n=O.get(t);n&&n.notify();});}}}function k(e,o=[]){if(e===null)throw new Error("Initial value cannot be null.");let r=e,t=new Set,n=ne++,u=()=>{t.forEach(p=>p(r));};O.set(n,{notify:u});let a=()=>{t.size!==0&&(V?R.add(n):u());},s=()=>r,l=p=>{let y;typeof p=="function"?y=p(r):y=p,D(r,y);let b=N(y,o);b!==r&&(r=b,a());},c=p=>{if(typeof p!="function")throw new Error("Callback must be a function.");return t.add(p),p(r),()=>t.delete(p)};return {get:s,set:l,subscribe:c,derive:p=>{if(typeof p!="function")throw new Error("Derive function must be a function.");let y=p(r),b=k(y),d=c(()=>{let w=p(r);b.set(w);}),g=b.destroy;return b.destroy=()=>{d(),g();},b},reset:()=>{r=e,a();},destroy:()=>{t.clear(),r=e,R.delete(n),O.delete(n);}}}function z(e,o={}){let{initialData:r=null,onError:t,retryCount:n=0,retryDelay:u=1e3,refresh:a={},pagination:s,enabled:l=true}=o,{staleTime:c=0,cacheTime:f=5*60*1e3,refetchInterval:h}=a,x=!!s,p=s?.mode||"replace",y=e.length>0,b={loading:l&&!y,error:null,data:r,lastFetched:void 0,pagination:x?{page:s.initialPage||1,pageSize:s.pageSize||10}:void 0},d=k(b),g={},w=null,v=null,L=()=>{let i=d.get();return !i.lastFetched||c===0?true:Date.now()-i.lastFetched>c},G=()=>{d.set({...d.get(),data:r,lastFetched:void 0});},Q=()=>{v&&clearTimeout(v),f>0&&(v=setTimeout(G,f));},m=async(i,T=n,A=false)=>{if(!l||(i!==void 0&&(g={...g,...i}),!A&&!L()&&d.get().data!==null))return;let C=d.get();d.set({...C,loading:true,error:null});try{let S={...g};x&&C.pagination&&(S.page=C.pagination.page,S.pageSize=C.pagination.pageSize);let P=y?await e(S):await e(),E,H,$;if(P&&typeof P=="object"&&"data"in P){let j=P;E=j.data,H=j.total,$=j.hasMore;}else E=P;x&&p==="accumulate"&&C.data&&Array.isArray(C.data)&&Array.isArray(E)&&(E=[...C.data,...E]);let X=Date.now();d.set({loading:!1,error:null,data:E,lastFetched:X,pagination:x?{...C.pagination,total:H,hasMore:$}:void 0}),Q();}catch(S){if(T>0)return await new Promise(E=>setTimeout(E,u)),m(i,T-1,A);let P=d.get();d.set({loading:false,error:S,data:P.data,lastFetched:P.lastFetched,pagination:P.pagination}),t&&t(S);}};h&&h>0&&l&&(w=setInterval(()=>{l&&m(void 0,0,false);},h)),l&&!y&&m();let F=()=>{w&&(clearInterval(w),w=null),v&&(clearTimeout(v),v=null);},I={...d,reload:async i=>{await m(i,n,true);},refresh:async i=>{await m(i,n,false);},mutate:i=>{let T=d.get(),A=i(T.data);d.set({...T,data:A});},reset:()=>{F(),g={},d.set({...b,loading:l&&!y}),l&&!y&&(m(),h&&h>0&&(w=setInterval(()=>{l&&m(void 0,0,false);},h)));},cleanup:F,setParams:i=>{g={...g,...i},l&&m(i,n,true);}};return x?{...I,nextPage:async()=>{let i=d.get();i.pagination&&i.pagination.hasMore!==false&&(d.set({...i,pagination:{...i.pagination,page:i.pagination.page+1}}),await m(g,n,true));},prevPage:async()=>{let i=d.get();!i.pagination||i.pagination.page<=1||(d.set({...i,pagination:{...i.pagination,page:i.pagination.page-1}}),await m(g,n,true));},goToPage:async i=>{let T=d.get();!T.pagination||i<1||(d.set({...T,pagination:{...T.pagination,page:i}}),await m(g,n,true));},resetPagination:async()=>{let i=d.get();if(!i.pagination)return;let T=s?.initialPage||1;d.set({...i,data:p==="accumulate"?r:i.data,pagination:{...i.pagination,page:T}}),await m(g,n,true);}}:I}function ae(e,o={}){let{pageSize:r=10,staleTime:t,cacheTime:n,retryCount:u,retryDelay:a,onError:s}=o;return z(e,{pagination:{pageSize:r,mode:"accumulate",initialPage:1},refresh:{staleTime:t,cacheTime:n},retryCount:u,retryDelay:a,onError:s})}function se(e,o){let r=e.map(c=>c.get()),t=o(...r),n=k(t),u=n.set,a=false,s=()=>{let c=false;for(let f=0;f<e.length;f++){let h=e[f].get();h!==r[f]&&(r[f]=h,c=true);}if(c){let f=o(...r);f!==t&&(typeof f!="object"||typeof t!="object"||!M(f,t))&&(t=f,u(f)),a=false;}},l=e.map(c=>c.subscribe(()=>{a=true,s();}));return {...n,get:()=>(a&&s(),t),recompute:s,isDirty:()=>a,set:()=>{throw new Error("Cannot set values directly on computed. Modify the source chunk instead.")},reset:()=>(e.forEach(c=>{typeof c.reset=="function"&&c.reset();}),a=true,s(),t),destroy:()=>{l.forEach(c=>c()),n.destroy?.();}}}function q(e,o,r={}){let{useShallowEqual:t=false}=r,n=e.get(),u=o(n),a=k(u),s=()=>{let c=e.get(),f=o(c);n=c,(t?!M(f,u):f!==u)&&(u=f,a.set(f));},l=e.subscribe(s);return {get:()=>a.get(),set:()=>{throw new Error("Cannot set values directly on a selector. Modify the source chunk instead.")},subscribe:a.subscribe,derive:c=>q(a,c,r),reset:()=>{throw new Error("Cannot reset a selector chunk. Reset the source chunk instead.")},destroy:()=>{l(),a.destroy();}}}var U={};Z(U,{logger:()=>K,nonNegativeValidator:()=>W,withHistory:()=>B,withPersistence:()=>J});var K=e=>(console.log("Setting value:",e),e);var W=e=>{if(e<0)throw new Error("Value must be non-negative!");return e};function B(e,o={}){let{maxHistory:r=100}=o,t=[e.get()],n=0,u=false,a={...e,set:s=>{if(u){e.set(s);return}let l;if(typeof s=="function"){let c=e.get();l=s(c);}else l=s;if(t.splice(n+1),t.push(l),t.length>r){console.warn("History limit reached. Removing oldest entries.");let c=t.length-r;t.splice(0,c),n=Math.max(0,n-c);}n=t.length-1,e.set(l);},undo:()=>{a.canUndo()&&(u=true,n--,a.set(t[n]),u=false);},redo:()=>{a.canRedo()&&(u=true,n++,a.set(t[n]),u=false);},canUndo:()=>n>0,canRedo:()=>n<t.length-1,getHistory:()=>[...t],clearHistory:()=>{let s=e.get();t.length=0,t.push(s),n=0;},destroy:()=>{t.length=0,e.destroy();}};return a}function J(e,o){let{key:r,storage:t=localStorage,serialize:n=JSON.stringify,deserialize:u=JSON.parse}=o;try{let a=t.getItem(r);if(a){let s=u(a);e.set(s);}}catch(a){console.error("Failed to load persisted state:",a);}return e.subscribe(a=>{try{let s=n(a);t.setItem(r,s);}catch(s){console.log("Failed to persist chunk",s);}}),e}export{z as asyncChunk,oe as batch,k as chunk,re as combineAsyncChunks,se as computed,ae as infiniteAsyncChunk,ee as isChunk,_ as isValidChunkValue,U as middleware,te as once,q as select};
1
+ var be=Object.defineProperty;var re=(e,a)=>{for(var t in a)be(e,t,{get:a[t],enumerable:true});};function ne(e,a){if(e===void 0)throw new Error("Value cannot be undefined.");if(a.length===0)return e;let t=e;for(let c=0;c<a.length;c++){let i=a[c],s=typeof i=="function"?i:i.fn,f=typeof i=="function"?`index ${c}`:i.name||`index ${c}`;try{let n=s(t);if(n===void 0)break;if(n===null)throw new Error(`Middleware "${f}" returned null value.`);t=n;}catch(n){let r=n instanceof Error?n.message:String(n);throw new Error(`Middleware "${f}" threw an error: ${r}`)}}return t}function O(e,a){if(e===a)return true;if(!e||!a||typeof e!=typeof a)return false;if(Array.isArray(e)&&Array.isArray(a)){if(e.length!==a.length)return false;for(let t=0;t<e.length;t++)if(e[t]!==a[t])return false;return true}if(typeof e=="object"&&typeof a=="object"){let t=Object.keys(e),c=Object.keys(a);if(t.length!==c.length)return false;for(let i of t)if(!Object.prototype.hasOwnProperty.call(a,i)||e[i]!==a[i])return false;return true}return false}function ke(e){return e[Symbol.for("stunk.meta")]}var _=null;function U(e){let a=new Set,t=_;_=a;try{return [e(),Array.from(a)]}finally{_=t;}}function Ee(e){_&&_.add(e);}var Q=false,G=new Set,W=new Map,ve=0;function xe(e){let a=Q;Q=true;try{e();}finally{a||(Q=false,G.forEach(t=>{let c=W.get(t);c&&c.notify();}),G.clear());}}function v(e,a={}){let t=ve++,c=`chunk_${t}`,i=a.middleware||[];a.strict??false;if(e===void 0)throw new Error(`[${c}] Initial value cannot be undefined.`);let n=e,r=new Set,p=()=>{r.forEach(h=>h(n));};W.set(t,{notify:p});let u=()=>{if(r.size===0){W.delete(t);return}Q?G.add(t):p();},o=()=>(Ee(D),n),d=()=>n,m=h=>{let x;typeof h=="function"?x=h(n):x=h;let P=ne(x,i);P!==n&&(n=P,u());},T=h=>{if(typeof h!="function")throw new Error("Callback must be a function.");return r.add(h),()=>r.delete(h)},D={get:o,peek:d,set:m,subscribe:T,derive:h=>{if(typeof h!="function")throw new Error("Derive function must be a function.");let x=h(n),P=v(x),y=T(()=>{let $=h(n);P.set($);}),g=P.destroy;return P.destroy=()=>{y(),g();},P},reset:()=>{n=e,u();},destroy:()=>{r.clear(),n=e,G.delete(t),W.delete(t);}};return D}function oe(e){let[a,t]=U(e),c=a,i=t,s=false,f=[],n=0,r=v(c),p=()=>{if(!s)return;s=false;let[o,d]=U(e);O(d,i)||(f.forEach(T=>T()),f=d.map(T=>T.subscribe(()=>{s=true,n>0&&p();})),i=d),(typeof o=="object"&&typeof c=="object"?!O(o,c):o!==c)&&(c=o,r.set(o));};f=i.map(o=>o.subscribe(()=>{s=true,n>0&&p();}));let u;return u={get:()=>(s&&p(),r.get()),peek:()=>c,subscribe:o=>{let d=r.subscribe(o);return n++,()=>{n=Math.max(0,n-1),d();}},derive:o=>(n++,oe(()=>o(u.get()))),recompute:()=>{s=true,p();},isDirty:()=>s,destroy:()=>{f.forEach(o=>o()),r.destroy(),n=0;}},u}function ae(e,a,t={}){let{useShallowEqual:c=false}=t,i=e.get(),s=a(i),f=v(s),n=()=>{let d=e.get(),m=a(d);(c?!O(m,s):m!==s)&&(s=m,f.set(m));},r=e.subscribe(n),{set:p,reset:u,...o}=f;return {...o,derive:d=>ae(f,d,t),destroy:()=>{r(),f.destroy();}}}var ce={};re(ce,{history:()=>ue,logger:()=>ie,nonNegativeValidator:()=>se,persist:()=>le});function ie(){return e=>(console.log("Setting value:",e),e)}var se=e=>{if(e<0)throw new Error("Value must be non-negative!");return e};function ue(e,a={}){let{maxHistory:t=100,skipDuplicates:c=false}=a,i=[e.get()],s=0;return {...e,get:()=>e.get(),peek:()=>e.peek(),set:n=>{let r;if(typeof n=="function"?r=n(e.get()):r=n,c){let p=i[s];if(r===p||c==="shallow"&&typeof r=="object"&&typeof p=="object"&&r!==null&&p!==null&&O(r,p))return}if(i.splice(s+1),i.push(r),i.length>t){let p=i.length-t;i.splice(0,p);}s=i.length-1,e.set(r);},undo:()=>{s<=0||(s--,e.set(i[s]));},redo:()=>{s>=i.length-1||(s++,e.set(i[s]));},canUndo:()=>s>0,canRedo:()=>s<i.length-1,getHistory:()=>[...i],clearHistory:()=>{let n=e.get();i.length=0,i.push(n),s=0;},reset:()=>{e.reset(),i.length=0,i.push(e.get()),s=0;},destroy:()=>{i.length=0,e.destroy();},subscribe:n=>e.subscribe(n)}}function le(e,a){let{key:t,serialize:c=JSON.stringify,deserialize:i=JSON.parse,onError:s}=a,f="storage"in a?a.storage:typeof window<"u"?localStorage:void 0;if(!f)return console.warn(`persist: Storage not available for key "${t}". Persistence disabled.`),{...e,clearStorage:()=>{}};let n=e.get();try{let u=f.getItem(t);if(u!==null){let o=i(u);if(o!==null&&n!==null&&(typeof o!=typeof n||Array.isArray(o)!==Array.isArray(n))){let T=`persist: Type mismatch for "${t}". Expected ${Array.isArray(n)?"array":typeof n}, got ${Array.isArray(o)?"array":typeof o}. Using initial value.`;console.warn(T),s?.(new Error(T),"load");}else e.set(o);}}catch(u){let o=u instanceof Error?u:new Error(String(u));console.error(`persist: Failed to load state for "${t}":`,o),s?.(o,"load");}let r=e.subscribe(u=>{try{f.setItem(t,c(u));}catch(o){let d=o instanceof Error?o:new Error(String(o));console.error(`persist: Failed to save state for "${t}":`,d),s?.(d,"save");}});return {...e,get:()=>e.get(),peek:()=>e.peek(),set:u=>e.set(u),subscribe:u=>e.subscribe(u),derive:u=>e.derive(u),reset:()=>e.reset(),destroy:()=>{r(),e.destroy();},clearStorage:()=>{try{f.removeItem(t);}catch(u){let o=u instanceof Error?u:new Error(String(u));console.error(`persist: Failed to clear storage for "${t}":`,o),s?.(o,"save");}}}}var he={};re(he,{asyncChunk:()=>K,combineAsyncChunks:()=>pe,configureQuery:()=>de,getGlobalQueryConfig:()=>F,infiniteAsyncChunk:()=>ye,mutation:()=>me,resetQueryConfig:()=>fe});var q={};function de(e){q={...e.query!==void 0&&{query:{...q.query,...e.query}},...e.mutation!==void 0&&{mutation:{...q.mutation,...e.mutation}}};}function F(){return q}function fe(){q={};}var N=new Map,Pe=0;function K(e,a={}){let t=F().query??{},{key:c,initialData:i=null,enabled:s=true,onSuccess:f=t.onSuccess,onError:n=t.onError,retryCount:r=t.retryCount??0,retryDelay:p=t.retryDelay??1e3,keepPreviousData:u=false,staleTime:o=t.staleTime??0,cacheTime:d=t.cacheTime??5*60*1e3,refetchInterval:m=t.refetchInterval,refetchOnWindowFocus:T=t.refetchOnWindowFocus??false,pagination:A}=a,E=c??`async_chunk_${Pe++}`,C=()=>typeof s=="function"?s():s,D=!!A,h=A?.mode||"replace",x=e.length>0,P={loading:C()&&!x,error:null,data:i,lastFetched:void 0,isPlaceholderData:false,pagination:D?{page:A.initialPage||1,pageSize:A.pageSize||10,total:void 0,hasMore:void 0}:void 0},y=v(P),g={},$=null,R=null,I=null,H=0,J=()=>{let l=y.get();return !l.lastFetched||o===0?true:Date.now()-l.lastFetched>o},ge=()=>{y.set({...y.get(),data:i,lastFetched:void 0});},Te=()=>{R&&clearTimeout(R),d>0&&(R=setTimeout(ge,d));},B=()=>{$&&(clearInterval($),$=null),R&&(clearTimeout(R),R=null),I&&typeof window<"u"&&(window.removeEventListener("focus",I),I=null);},X=()=>{C()&&(typeof window>"u"||(m&&m>0&&($=setInterval(()=>{k(void 0,0,false);},m)),T&&(I=()=>{J()&&k(void 0,0,false);},window.addEventListener("focus",I))));},k=async(l,b=r,M=false)=>{if(!C()||(l!==void 0&&(g={...g,...l}),!M&&!J()&&y.get().data!==null))return;if(N.has(E))return N.get(E);let L=y.get();y.set({...L,loading:true,error:null,data:L.data,isPlaceholderData:u&&L.data!==null});let Z=(async()=>{try{let j={...g};if(D){let V=y.get().pagination;V&&(j.page=V.page,j.pageSize=V.pageSize);}let w=x?await e(j):await e(),S,ee,te;if(w&&typeof w=="object"&&"data"in w){let V=w;S=V.data,ee=V.total,te=V.hasMore;}else S=w;let z=y.get();D&&h==="accumulate"&&z.data&&Array.isArray(z.data)&&Array.isArray(S)&&(S=[...z.data,...S]),y.set({loading:!1,error:null,data:S,lastFetched:Date.now(),isPlaceholderData:!1,pagination:D?{...z.pagination,total:ee,hasMore:te}:void 0}),Te(),f&&f(S);}catch(j){if(b>0)return await new Promise(S=>setTimeout(S,p)),N.delete(E),k(l,b-1,M);let w=y.get();y.set({loading:false,error:j,data:w.data,lastFetched:w.lastFetched,isPlaceholderData:false,pagination:w.pagination}),n&&n(j);}finally{N.delete(E);}})();return N.set(E,Z),Z};X(),C()&&!x&&k();let Y={...y,subscribe:l=>{H++;let b=y.subscribe(l);return ()=>{b(),H--;}},reload:async l=>{await k(l,r,true);},refresh:async l=>{await k(l,r,false);},mutate:l=>{let b=y.get();y.set({...b,data:l(b.data)});},reset:()=>{B(),g={},y.set({...P,loading:C()&&!x}),X(),C()&&!x&&k();},cleanup:()=>{H<=0&&B();},forceCleanup:()=>{B();},setParams:l=>{let b={...g};for(let M in l)l[M]===null?delete b[M]:b[M]=l[M];g=b,C()&&k(g,r,true);},clearParams:()=>{g={},C()&&k(void 0,r,true);}};return D?{...Y,nextPage:async()=>{let l=y.get();!l.pagination||l.pagination.hasMore===false||(y.set({...l,pagination:{...l.pagination,page:l.pagination.page+1}}),await k(g,r,true));},prevPage:async()=>{let l=y.get();!l.pagination||l.pagination.page<=1||(y.set({...l,pagination:{...l.pagination,page:l.pagination.page-1}}),await k(g,r,true));},goToPage:async l=>{let b=y.get();!b.pagination||l<1||(y.set({...b,pagination:{...b.pagination,page:l}}),await k(g,r,true));},resetPagination:async()=>{let l=y.get();l.pagination&&(y.set({...l,data:h==="accumulate"?i:l.data,pagination:{...l.pagination,page:A?.initialPage||1}}),await k(g,r,true));}}:Y}function ye(e,a={}){let{pageSize:t=10,...c}=a;return K(e,{...c,pagination:{pageSize:t,mode:"accumulate",initialPage:1}})}function pe(e){let a=Object.entries(e),t=a.reduce((r,[p,u])=>(r[p]=u.get().data,r),{}),c=a.reduce((r,[p,u])=>{let o=u.get().error;return o&&(r[p]=o),r},{}),i=a.some(([,r])=>r.get().loading),s=a.find(([,r])=>r.get().error)?.[1].get().error??null,n=v({loading:i,error:s,errors:c,data:t});return a.forEach(([r,p])=>{p.subscribe(()=>{let u=false,o=null,d={},m={...n.get().data};a.forEach(([T,A])=>{let E=A.get();E.loading&&(u=true),E.error&&(o||(o=E.error),d[T]=E.error),m[T]=E.data;}),n.set({loading:u,error:o,errors:d,data:m});});}),n}function me(e,a={}){let t=F().mutation??{},{invalidates:c=[],onSuccess:i=t.onSuccess,onError:s=t.onError,onSettled:f}=a,n={loading:false,data:null,error:null,isSuccess:false},r=v(n);return {mutate:async(...u)=>{let o=u[0];r.set({loading:true,data:null,error:null,isSuccess:false});try{let d=await e(o);return r.set({loading:!1,data:d,error:null,isSuccess:!0}),c.length>0&&await Promise.all(c.map(m=>m.reload())),i&&i(d,o),f&&f(d,null,o),{data:d,error:null}}catch(d){let m=d;return r.set({loading:false,data:null,error:m,isSuccess:false}),s&&s(m,o),f&&f(null,m,o),{data:null,error:m}}},get:()=>r.get(),subscribe:u=>r.subscribe(u),reset:()=>r.set(n)}}export{xe as batch,v as chunk,oe as computed,ke as getChunkMeta,ce as middleware,he as query,ae as select};
@@ -1 +1 @@
1
- 'use strict';var d=e=>(console.log("Setting value:",e),e);var u=e=>{if(e<0)throw new Error("Value must be non-negative!");return e};function g(e,a={}){let{maxHistory:s=100}=a,t=[e.get()],r=0,n=false,o={...e,set:i=>{if(n){e.set(i);return}let l;if(typeof i=="function"){let c=e.get();l=i(c);}else l=i;if(t.splice(r+1),t.push(l),t.length>s){console.warn("History limit reached. Removing oldest entries.");let c=t.length-s;t.splice(0,c),r=Math.max(0,r-c);}r=t.length-1,e.set(l);},undo:()=>{o.canUndo()&&(n=true,r--,o.set(t[r]),n=false);},redo:()=>{o.canRedo()&&(n=true,r++,o.set(t[r]),n=false);},canUndo:()=>r>0,canRedo:()=>r<t.length-1,getHistory:()=>[...t],clearHistory:()=>{let i=e.get();t.length=0,t.push(i),r=0;},destroy:()=>{t.length=0,e.destroy();}};return o}function h(e,a){let{key:s,storage:t=localStorage,serialize:r=JSON.stringify,deserialize:n=JSON.parse}=a;try{let o=t.getItem(s);if(o){let i=n(o);e.set(i);}}catch(o){console.error("Failed to load persisted state:",o);}return e.subscribe(o=>{try{let i=r(o);t.setItem(s,i);}catch(i){console.log("Failed to persist chunk",i);}}),e}exports.logger=d;exports.nonNegativeValidator=u;exports.withHistory=g;exports.withPersistence=h;
1
+ 'use strict';function g(){return e=>(console.log("Setting value:",e),e)}var h=e=>{if(e<0)throw new Error("Value must be non-negative!");return e};function p(e,s){if(e===s)return true;if(!e||!s||typeof e!=typeof s)return false;if(Array.isArray(e)&&Array.isArray(s)){if(e.length!==s.length)return false;for(let t=0;t<e.length;t++)if(e[t]!==s[t])return false;return true}if(typeof e=="object"&&typeof s=="object"){let t=Object.keys(e),f=Object.keys(s);if(t.length!==f.length)return false;for(let r of t)if(!Object.prototype.hasOwnProperty.call(s,r)||e[r]!==s[r])return false;return true}return false}function T(e,s={}){let{maxHistory:t=100,skipDuplicates:f=false}=s,r=[e.get()],o=0;return {...e,get:()=>e.get(),peek:()=>e.peek(),set:c=>{let l;if(typeof c=="function"?l=c(e.get()):l=c,f){let a=r[o];if(l===a||f==="shallow"&&typeof l=="object"&&typeof a=="object"&&l!==null&&a!==null&&p(l,a))return}if(r.splice(o+1),r.push(l),r.length>t){let a=r.length-t;r.splice(0,a);}o=r.length-1,e.set(l);},undo:()=>{o<=0||(o--,e.set(r[o]));},redo:()=>{o>=r.length-1||(o++,e.set(r[o]));},canUndo:()=>o>0,canRedo:()=>o<r.length-1,getHistory:()=>[...r],clearHistory:()=>{let c=e.get();r.length=0,r.push(c),o=0;},reset:()=>{e.reset(),r.length=0,r.push(e.get()),o=0;},destroy:()=>{r.length=0,e.destroy();},subscribe:c=>e.subscribe(c)}}function m(e,s){let{key:t,serialize:f=JSON.stringify,deserialize:r=JSON.parse,onError:o}=s,u="storage"in s?s.storage:typeof window<"u"?localStorage:void 0;if(!u)return console.warn(`persist: Storage not available for key "${t}". Persistence disabled.`),{...e,clearStorage:()=>{}};let c=e.get();try{let n=u.getItem(t);if(n!==null){let i=r(n);if(i!==null&&c!==null&&(typeof i!=typeof c||Array.isArray(i)!==Array.isArray(c))){let d=`persist: Type mismatch for "${t}". Expected ${Array.isArray(c)?"array":typeof c}, got ${Array.isArray(i)?"array":typeof i}. Using initial value.`;console.warn(d),o?.(new Error(d),"load");}else e.set(i);}}catch(n){let i=n instanceof Error?n:new Error(String(n));console.error(`persist: Failed to load state for "${t}":`,i),o?.(i,"load");}let l=e.subscribe(n=>{try{u.setItem(t,f(n));}catch(i){let y=i instanceof Error?i:new Error(String(i));console.error(`persist: Failed to save state for "${t}":`,y),o?.(y,"save");}});return {...e,get:()=>e.get(),peek:()=>e.peek(),set:n=>e.set(n),subscribe:n=>e.subscribe(n),derive:n=>e.derive(n),reset:()=>e.reset(),destroy:()=>{l(),e.destroy();},clearStorage:()=>{try{u.removeItem(t);}catch(n){let i=n instanceof Error?n:new Error(String(n));console.error(`persist: Failed to clear storage for "${t}":`,i),o?.(i,"save");}}}}exports.history=T;exports.logger=g;exports.nonNegativeValidator=h;exports.persist=m;
@@ -1,45 +1,99 @@
1
- import { M as Middleware, C as Chunk } from '../core-DMY69lzg.cjs';
1
+ import { M as Middleware, C as Chunk } from '../core-DsoxfUCH.cjs';
2
2
 
3
- declare const logger: Middleware<any>;
3
+ /**
4
+ * Middleware that logs every value passed to `set()` to the console.
5
+ *
6
+ * @example
7
+ * const count = chunk(0, { middleware: [logger()] });
8
+ * count.set(5); // logs: "Setting value: 5"
9
+ */
10
+ declare function logger<T>(): Middleware<T>;
4
11
 
12
+ /**
13
+ * Middleware that throws if a numeric value is set below zero.
14
+ *
15
+ * @example
16
+ * const balance = chunk(100, { middleware: [nonNegativeValidator] });
17
+ * balance.set(-1); // throws: "Value must be non-negative!"
18
+ */
5
19
  declare const nonNegativeValidator: Middleware<number>;
6
20
 
7
21
  interface ChunkWithHistory<T> extends Chunk<T> {
8
- /**
9
- * Reverts to the previous state (if available).
10
- */
22
+ /** Reverts to the previous state (if available). */
11
23
  undo: () => void;
12
- /**
13
- * Moves to the next state (if available).
14
- */
24
+ /** Moves to the next state (if available). */
15
25
  redo: () => void;
16
- /**
17
- * Returns true if there is a previous state to revert to.
18
- */
26
+ /** Returns true if there is a previous state to revert to. */
19
27
  canUndo: () => boolean;
20
- /**
21
- * Returns true if there is a next state to move to.
22
- */
28
+ /** Returns true if there is a next state to move to. */
23
29
  canRedo: () => boolean;
24
- /**
25
- * Returns an array of all the values in the history.
26
- */
30
+ /** Returns an array of all the values in the history. */
27
31
  getHistory: () => T[];
28
- /**
29
- * Clears the history, keeping only the current value.
30
- */
32
+ /** Clears the history, keeping only the current value. */
31
33
  clearHistory: () => void;
32
34
  }
33
- declare function withHistory<T>(baseChunk: Chunk<T>, options?: {
35
+ /**
36
+ * Wraps a chunk with undo/redo history tracking.
37
+ *
38
+ * Every `set()` call is recorded. `undo()` and `redo()` move through the stack.
39
+ * Branching is supported — calling `set()` after `undo()` discards forward history.
40
+ *
41
+ * @param baseChunk - The chunk to wrap.
42
+ * @param options.maxHistory - Max entries to keep (default: 100).
43
+ * @param options.skipDuplicates - `true` skips strictly equal values.
44
+ * `'shallow'` also skips shallowly equal objects.
45
+ *
46
+ * @example
47
+ * const count = chunk(0);
48
+ * const tracked = history(count);
49
+ * tracked.set(1); tracked.set(2);
50
+ * tracked.undo(); // 1
51
+ * tracked.redo(); // 2
52
+ */
53
+ declare function history<T>(baseChunk: Chunk<T>, options?: {
34
54
  maxHistory?: number;
55
+ /**
56
+ * true — skip entries that are strictly equal (===) to the current value.
57
+ * 'shallow' — also skip entries that are shallowly equal to the current value.
58
+ */
59
+ skipDuplicates?: boolean | "shallow";
35
60
  }): ChunkWithHistory<T>;
36
61
 
37
62
  interface PersistOptions<T> {
63
+ /** Storage key (required). */
38
64
  key: string;
65
+ /** Storage engine (default: localStorage). */
39
66
  storage?: Storage;
67
+ /** Serialize value to string (default: JSON.stringify). */
40
68
  serialize?: (value: T) => string;
69
+ /** Deserialize string to value (default: JSON.parse). */
41
70
  deserialize?: (value: string) => T;
71
+ /** Called on load/save errors and type mismatches. */
72
+ onError?: (error: Error, operation: 'load' | 'save') => void;
73
+ }
74
+ interface PersistedChunk<T> extends Chunk<T> {
75
+ /** Remove the persisted key from storage without destroying the chunk. */
76
+ clearStorage: () => void;
42
77
  }
43
- declare function withPersistence<T>(baseChunk: Chunk<T>, options: PersistOptions<T>): Chunk<T>;
78
+ /**
79
+ * Wraps a chunk with automatic persistence to a storage engine.
80
+ *
81
+ * Loads any saved value on creation. Saves on every `set()`.
82
+ * Gracefully disabled in SSR when no storage is available.
83
+ *
84
+ * @param baseChunk - The chunk to wrap.
85
+ * @param options.key - Storage key (required).
86
+ * @param options.storage - Storage engine (default: `localStorage`).
87
+ * @param options.serialize - Custom serializer (default: `JSON.stringify`).
88
+ * @param options.deserialize - Custom deserializer (default: `JSON.parse`).
89
+ * @param options.onError - Called on load/save errors or type mismatches.
90
+ *
91
+ * @example
92
+ * const user = chunk({ name: 'Alice' });
93
+ * const persisted = persist(user, { key: 'user' });
94
+ * persisted.set({ name: 'Bob' }); // saved to localStorage
95
+ * persisted.clearStorage(); // removes the key
96
+ */
97
+ declare function persist<T>(baseChunk: Chunk<T>, options: PersistOptions<T>): PersistedChunk<T>;
44
98
 
45
- export { logger, nonNegativeValidator, withHistory, withPersistence };
99
+ export { history, logger, nonNegativeValidator, persist };
@@ -1,45 +1,99 @@
1
- import { M as Middleware, C as Chunk } from '../core-DMY69lzg.js';
1
+ import { M as Middleware, C as Chunk } from '../core-DsoxfUCH.js';
2
2
 
3
- declare const logger: Middleware<any>;
3
+ /**
4
+ * Middleware that logs every value passed to `set()` to the console.
5
+ *
6
+ * @example
7
+ * const count = chunk(0, { middleware: [logger()] });
8
+ * count.set(5); // logs: "Setting value: 5"
9
+ */
10
+ declare function logger<T>(): Middleware<T>;
4
11
 
12
+ /**
13
+ * Middleware that throws if a numeric value is set below zero.
14
+ *
15
+ * @example
16
+ * const balance = chunk(100, { middleware: [nonNegativeValidator] });
17
+ * balance.set(-1); // throws: "Value must be non-negative!"
18
+ */
5
19
  declare const nonNegativeValidator: Middleware<number>;
6
20
 
7
21
  interface ChunkWithHistory<T> extends Chunk<T> {
8
- /**
9
- * Reverts to the previous state (if available).
10
- */
22
+ /** Reverts to the previous state (if available). */
11
23
  undo: () => void;
12
- /**
13
- * Moves to the next state (if available).
14
- */
24
+ /** Moves to the next state (if available). */
15
25
  redo: () => void;
16
- /**
17
- * Returns true if there is a previous state to revert to.
18
- */
26
+ /** Returns true if there is a previous state to revert to. */
19
27
  canUndo: () => boolean;
20
- /**
21
- * Returns true if there is a next state to move to.
22
- */
28
+ /** Returns true if there is a next state to move to. */
23
29
  canRedo: () => boolean;
24
- /**
25
- * Returns an array of all the values in the history.
26
- */
30
+ /** Returns an array of all the values in the history. */
27
31
  getHistory: () => T[];
28
- /**
29
- * Clears the history, keeping only the current value.
30
- */
32
+ /** Clears the history, keeping only the current value. */
31
33
  clearHistory: () => void;
32
34
  }
33
- declare function withHistory<T>(baseChunk: Chunk<T>, options?: {
35
+ /**
36
+ * Wraps a chunk with undo/redo history tracking.
37
+ *
38
+ * Every `set()` call is recorded. `undo()` and `redo()` move through the stack.
39
+ * Branching is supported — calling `set()` after `undo()` discards forward history.
40
+ *
41
+ * @param baseChunk - The chunk to wrap.
42
+ * @param options.maxHistory - Max entries to keep (default: 100).
43
+ * @param options.skipDuplicates - `true` skips strictly equal values.
44
+ * `'shallow'` also skips shallowly equal objects.
45
+ *
46
+ * @example
47
+ * const count = chunk(0);
48
+ * const tracked = history(count);
49
+ * tracked.set(1); tracked.set(2);
50
+ * tracked.undo(); // 1
51
+ * tracked.redo(); // 2
52
+ */
53
+ declare function history<T>(baseChunk: Chunk<T>, options?: {
34
54
  maxHistory?: number;
55
+ /**
56
+ * true — skip entries that are strictly equal (===) to the current value.
57
+ * 'shallow' — also skip entries that are shallowly equal to the current value.
58
+ */
59
+ skipDuplicates?: boolean | "shallow";
35
60
  }): ChunkWithHistory<T>;
36
61
 
37
62
  interface PersistOptions<T> {
63
+ /** Storage key (required). */
38
64
  key: string;
65
+ /** Storage engine (default: localStorage). */
39
66
  storage?: Storage;
67
+ /** Serialize value to string (default: JSON.stringify). */
40
68
  serialize?: (value: T) => string;
69
+ /** Deserialize string to value (default: JSON.parse). */
41
70
  deserialize?: (value: string) => T;
71
+ /** Called on load/save errors and type mismatches. */
72
+ onError?: (error: Error, operation: 'load' | 'save') => void;
73
+ }
74
+ interface PersistedChunk<T> extends Chunk<T> {
75
+ /** Remove the persisted key from storage without destroying the chunk. */
76
+ clearStorage: () => void;
42
77
  }
43
- declare function withPersistence<T>(baseChunk: Chunk<T>, options: PersistOptions<T>): Chunk<T>;
78
+ /**
79
+ * Wraps a chunk with automatic persistence to a storage engine.
80
+ *
81
+ * Loads any saved value on creation. Saves on every `set()`.
82
+ * Gracefully disabled in SSR when no storage is available.
83
+ *
84
+ * @param baseChunk - The chunk to wrap.
85
+ * @param options.key - Storage key (required).
86
+ * @param options.storage - Storage engine (default: `localStorage`).
87
+ * @param options.serialize - Custom serializer (default: `JSON.stringify`).
88
+ * @param options.deserialize - Custom deserializer (default: `JSON.parse`).
89
+ * @param options.onError - Called on load/save errors or type mismatches.
90
+ *
91
+ * @example
92
+ * const user = chunk({ name: 'Alice' });
93
+ * const persisted = persist(user, { key: 'user' });
94
+ * persisted.set({ name: 'Bob' }); // saved to localStorage
95
+ * persisted.clearStorage(); // removes the key
96
+ */
97
+ declare function persist<T>(baseChunk: Chunk<T>, options: PersistOptions<T>): PersistedChunk<T>;
44
98
 
45
- export { logger, nonNegativeValidator, withHistory, withPersistence };
99
+ export { history, logger, nonNegativeValidator, persist };
@@ -1 +1 @@
1
- var d=e=>(console.log("Setting value:",e),e);var u=e=>{if(e<0)throw new Error("Value must be non-negative!");return e};function g(e,a={}){let{maxHistory:s=100}=a,t=[e.get()],r=0,n=false,o={...e,set:i=>{if(n){e.set(i);return}let l;if(typeof i=="function"){let c=e.get();l=i(c);}else l=i;if(t.splice(r+1),t.push(l),t.length>s){console.warn("History limit reached. Removing oldest entries.");let c=t.length-s;t.splice(0,c),r=Math.max(0,r-c);}r=t.length-1,e.set(l);},undo:()=>{o.canUndo()&&(n=true,r--,o.set(t[r]),n=false);},redo:()=>{o.canRedo()&&(n=true,r++,o.set(t[r]),n=false);},canUndo:()=>r>0,canRedo:()=>r<t.length-1,getHistory:()=>[...t],clearHistory:()=>{let i=e.get();t.length=0,t.push(i),r=0;},destroy:()=>{t.length=0,e.destroy();}};return o}function h(e,a){let{key:s,storage:t=localStorage,serialize:r=JSON.stringify,deserialize:n=JSON.parse}=a;try{let o=t.getItem(s);if(o){let i=n(o);e.set(i);}}catch(o){console.error("Failed to load persisted state:",o);}return e.subscribe(o=>{try{let i=r(o);t.setItem(s,i);}catch(i){console.log("Failed to persist chunk",i);}}),e}export{d as logger,u as nonNegativeValidator,g as withHistory,h as withPersistence};
1
+ import {b}from'../chunk-3DOB632D.js';function u(){return r=>(console.log("Setting value:",r),r)}var m=r=>{if(r<0)throw new Error("Value must be non-negative!");return r};function T(r,c={}){let{maxHistory:n=100,skipDuplicates:p=false}=c,e=[r.get()],t=0;return {...r,get:()=>r.get(),peek:()=>r.peek(),set:i=>{let l;if(typeof i=="function"?l=i(r.get()):l=i,p){let a=e[t];if(l===a||p==="shallow"&&typeof l=="object"&&typeof a=="object"&&l!==null&&a!==null&&b(l,a))return}if(e.splice(t+1),e.push(l),e.length>n){let a=e.length-n;e.splice(0,a);}t=e.length-1,r.set(l);},undo:()=>{t<=0||(t--,r.set(e[t]));},redo:()=>{t>=e.length-1||(t++,r.set(e[t]));},canUndo:()=>t>0,canRedo:()=>t<e.length-1,getHistory:()=>[...e],clearHistory:()=>{let i=r.get();e.length=0,e.push(i),t=0;},reset:()=>{r.reset(),e.length=0,e.push(r.get()),t=0;},destroy:()=>{e.length=0,r.destroy();},subscribe:i=>r.subscribe(i)}}function h(r,c){let{key:n,serialize:p=JSON.stringify,deserialize:e=JSON.parse,onError:t}=c,d="storage"in c?c.storage:typeof window<"u"?localStorage:void 0;if(!d)return console.warn(`persist: Storage not available for key "${n}". Persistence disabled.`),{...r,clearStorage:()=>{}};let i=r.get();try{let o=d.getItem(n);if(o!==null){let s=e(o);if(s!==null&&i!==null&&(typeof s!=typeof i||Array.isArray(s)!==Array.isArray(i))){let y=`persist: Type mismatch for "${n}". Expected ${Array.isArray(i)?"array":typeof i}, got ${Array.isArray(s)?"array":typeof s}. Using initial value.`;console.warn(y),t?.(new Error(y),"load");}else r.set(s);}}catch(o){let s=o instanceof Error?o:new Error(String(o));console.error(`persist: Failed to load state for "${n}":`,s),t?.(s,"load");}let l=r.subscribe(o=>{try{d.setItem(n,p(o));}catch(s){let g=s instanceof Error?s:new Error(String(s));console.error(`persist: Failed to save state for "${n}":`,g),t?.(g,"save");}});return {...r,get:()=>r.get(),peek:()=>r.peek(),set:o=>r.set(o),subscribe:o=>r.subscribe(o),derive:o=>r.derive(o),reset:()=>r.reset(),destroy:()=>{l(),r.destroy();},clearStorage:()=>{try{d.removeItem(n);}catch(o){let s=o instanceof Error?o:new Error(String(o));console.error(`persist: Failed to clear storage for "${n}":`,s),t?.(s,"save");}}}}export{T as history,u as logger,m as nonNegativeValidator,h as persist};
@@ -0,0 +1,214 @@
1
+ import { C as Chunk } from './core-DsoxfUCH.js';
2
+
3
+ interface AsyncState<T, E extends Error> {
4
+ loading: boolean;
5
+ error: E | null;
6
+ data: T | null;
7
+ lastFetched?: number;
8
+ /** True when showing previous data while new data is loading (keepPreviousData: true) */
9
+ isPlaceholderData?: boolean;
10
+ }
11
+ interface PaginationState {
12
+ page: number;
13
+ pageSize: number;
14
+ total?: number;
15
+ hasMore?: boolean;
16
+ }
17
+ interface AsyncStateWithPagination<T, E extends Error> extends AsyncState<T, E> {
18
+ pagination?: PaginationState;
19
+ }
20
+ interface FetcherResponse<T> {
21
+ data: T;
22
+ total?: number;
23
+ hasMore?: boolean;
24
+ }
25
+ interface AsyncChunkOptions<T, E extends Error = Error> {
26
+ /** Deduplication key — concurrent calls with the same key share one in-flight request */
27
+ key?: string;
28
+ /** Seed data shown before the first fetch completes */
29
+ initialData?: T | null;
30
+ /** Disable fetching until ready — pass a function for dynamic evaluation */
31
+ enabled?: boolean | (() => boolean);
32
+ /** Called after every successful fetch */
33
+ onSuccess?: (data: T) => void;
34
+ /** Called when all retries are exhausted */
35
+ onError?: (error: E) => void;
36
+ /** Number of retries on failure (default: 0) */
37
+ retryCount?: number;
38
+ /** Delay in ms between retries (default: 1000) */
39
+ retryDelay?: number;
40
+ /** Show previous data while refetching — prevents UI flicker on param changes (default: false) */
41
+ keepPreviousData?: boolean;
42
+ /** Time in ms before data is considered stale (default: 0) */
43
+ staleTime?: number;
44
+ /** Time in ms to cache data after last subscriber leaves (default: 300_000) */
45
+ cacheTime?: number;
46
+ /** Auto-refetch interval in ms */
47
+ refetchInterval?: number;
48
+ /** Refetch when window regains focus (default: false) */
49
+ refetchOnWindowFocus?: boolean;
50
+ pagination?: {
51
+ /** Initial page number (default: 1) */
52
+ initialPage?: number;
53
+ /** Items per page (default: 10) */
54
+ pageSize?: number;
55
+ /** Replace data on each page load, or accumulate for infinite scroll (default: 'replace') */
56
+ mode?: 'replace' | 'accumulate';
57
+ };
58
+ }
59
+ interface AsyncChunk<T, E extends Error = Error> extends Chunk<AsyncStateWithPagination<T, E>> {
60
+ /** Force a fresh fetch, ignoring stale time */
61
+ reload: (params?: any) => Promise<void>;
62
+ /** Fetch only if data is stale — respects staleTime */
63
+ refresh: (params?: any) => Promise<void>;
64
+ /** Update data directly without a network request */
65
+ mutate: (mutator: (currentData: T | null) => T) => void;
66
+ /** Reset to initial state and re-fetch */
67
+ reset: () => void;
68
+ /** Safe cleanup — only tears down if no active subscribers remain */
69
+ cleanup: () => void;
70
+ /** Force cleanup regardless of subscriber count */
71
+ forceCleanup: () => void;
72
+ /** Clear all current params and refetch */
73
+ clearParams: () => void;
74
+ }
75
+ interface PaginatedAsyncChunk<T, E extends Error = Error> extends AsyncChunk<T, E> {
76
+ /** Load the next page */
77
+ nextPage: () => Promise<void>;
78
+ /** Load the previous page */
79
+ prevPage: () => Promise<void>;
80
+ /** Jump to a specific page */
81
+ goToPage: (page: number) => Promise<void>;
82
+ /** Reset pagination to page 1 and re-fetch */
83
+ resetPagination: () => Promise<void>;
84
+ }
85
+ declare function asyncChunk<T, E extends Error = Error>(fetcher: () => Promise<T | FetcherResponse<T>>, options?: AsyncChunkOptions<T, E>): AsyncChunk<T, E> | PaginatedAsyncChunk<T, E>;
86
+ declare function asyncChunk<T, E extends Error = Error, P extends Record<string, any> = {}>(fetcher: (params: P & {
87
+ page?: number;
88
+ pageSize?: number;
89
+ }) => Promise<T | FetcherResponse<T>>, options?: AsyncChunkOptions<T, E>): (AsyncChunk<T, E> | PaginatedAsyncChunk<T, E>) & {
90
+ setParams: (params: Partial<P>) => void;
91
+ reload: (params?: Partial<P>) => Promise<void>;
92
+ refresh: (params?: Partial<P>) => Promise<void>;
93
+ };
94
+
95
+ type InfiniteAsyncChunkOptions<T, E extends Error = Error> = Omit<AsyncChunkOptions<T[], E>, 'pagination'> & {
96
+ /** Items per page (default: 10) */
97
+ pageSize?: number;
98
+ };
99
+ type InfiniteAsyncChunk<T, E extends Error = Error, P extends Record<string, any> = {}> = PaginatedAsyncChunk<T[], E> & {
100
+ setParams: (params: Partial<Record<keyof P, P[keyof P] | null>>) => void;
101
+ clearParams: () => void;
102
+ reload: (params?: Partial<P>) => Promise<void>;
103
+ refresh: (params?: Partial<P>) => Promise<void>;
104
+ forceCleanup: () => void;
105
+ };
106
+ /**
107
+ * Creates an infinite scroll async chunk that accumulates pages.
108
+ *
109
+ * A convenience wrapper around `asyncChunk` with `pagination.mode: 'accumulate'`
110
+ * pre-configured. Each `nextPage()` appends to the existing data array.
111
+ *
112
+ * @param fetcher - Async function receiving `{ page, pageSize, ...params }`,
113
+ * returning `{ data: T[], hasMore?, total? }`.
114
+ * @param options.pageSize - Items per page (default: 10).
115
+ * @param options.key - Deduplication key.
116
+ * @param options.onSuccess - Called with the full accumulated array after each fetch.
117
+ *
118
+ * @example
119
+ * const posts = infiniteAsyncChunk(
120
+ * async ({ page, pageSize }) => fetchPosts({ page, pageSize }),
121
+ * { pageSize: 20 }
122
+ * );
123
+ * posts.reload(); // page 1
124
+ * posts.nextPage(); // page 2 appended
125
+ */
126
+ declare function infiniteAsyncChunk<T, E extends Error = Error, P extends Record<string, any> = {}>(fetcher: (params: P & {
127
+ page: number;
128
+ pageSize: number;
129
+ }) => Promise<{
130
+ data: T[];
131
+ hasMore?: boolean;
132
+ total?: number;
133
+ }>, options?: InfiniteAsyncChunkOptions<T, E>): InfiniteAsyncChunk<T, E, P>;
134
+
135
+ type MutationFn<TData, TVariables> = (variables: TVariables) => Promise<TData>;
136
+ interface MutationOptions<TData, TError extends Error = Error, TVariables = void> {
137
+ /** Chunks to automatically reload after a successful mutation */
138
+ invalidates?: AsyncChunk<any, any>[];
139
+ /** Called after a successful mutation with the returned data and original variables */
140
+ onSuccess?: (data: TData, variables: TVariables) => void;
141
+ /** Called when the mutation fails with the error and original variables */
142
+ onError?: (error: TError, variables: TVariables) => void;
143
+ /** Called after every attempt — success or failure — useful for unconditional cleanup */
144
+ onSettled?: (data: TData | null, error: TError | null, variables: TVariables) => void;
145
+ }
146
+ interface MutationState<TData, TError extends Error = Error> {
147
+ /** True while the mutation is in progress */
148
+ loading: boolean;
149
+ /** The data returned from the last successful mutation, or null */
150
+ data: TData | null;
151
+ /** The error from the last failed mutation, or null */
152
+ error: TError | null;
153
+ /** True after a successful mutation — distinct from data since data can be null on success */
154
+ isSuccess: boolean;
155
+ }
156
+ interface MutationResult<TData, TError extends Error = Error> {
157
+ /** The returned data on success, or null on failure */
158
+ data: TData | null;
159
+ /** The error on failure, or null on success */
160
+ error: TError | null;
161
+ }
162
+ interface Mutation<TData, TError extends Error = Error, TVariables = void> {
163
+ /**
164
+ * Execute the mutation. Always resolves — never throws.
165
+ * Returns `{ data, error }` so you can await it or fire and forget safely.
166
+ *
167
+ * @example
168
+ * // Fire and forget — safe
169
+ * createPost.mutate({ title: 'Hello' });
170
+ *
171
+ * // Await for local UI control — no try/catch needed
172
+ * const { data, error } = await createPost.mutate({ title: 'Hello' });
173
+ * if (!error) router.push('/posts');
174
+ */
175
+ mutate: (...args: TVariables extends void ? [] : [variables: TVariables]) => Promise<MutationResult<TData, TError>>;
176
+ /** Returns the current mutation state */
177
+ get: () => MutationState<TData, TError>;
178
+ /** Subscribe to state changes. Returns an unsubscribe function. */
179
+ subscribe: (callback: (state: MutationState<TData, TError>) => void) => () => void;
180
+ /** Reset state back to initial — clears data, error, isSuccess */
181
+ reset: () => void;
182
+ }
183
+ /**
184
+ * Creates a reactive mutation for POST, PUT, DELETE, or any async side effect.
185
+ *
186
+ * Always returns a promise that resolves — never throws.
187
+ * On success, automatically reloads any chunks listed in `invalidates`.
188
+ *
189
+ * @param mutationFn - Async function that performs the side effect.
190
+ * @param options.invalidates - Chunks to reload after a successful mutation.
191
+ * @param options.onSuccess - Called with data and variables on success.
192
+ * @param options.onError - Called with error and variables on failure.
193
+ * @param options.onSettled - Called after every attempt regardless of outcome.
194
+ *
195
+ * @example
196
+ * const createPost = mutation(
197
+ * async (data: NewPost) => fetchAPI('/posts', { method: 'POST', body: data }),
198
+ * {
199
+ * invalidates: [postsChunk],
200
+ * onSuccess: (data) => toast.success('Post created!'),
201
+ * onError: (err) => toast.error(err.message),
202
+ * }
203
+ * );
204
+ *
205
+ * // Fire and forget
206
+ * createPost.mutate({ title: 'Hello' });
207
+ *
208
+ * // Await for local control
209
+ * const { data, error } = await createPost.mutate({ title: 'Hello' });
210
+ * if (!error) router.push('/posts');
211
+ */
212
+ declare function mutation<TData, TError extends Error = Error, TVariables = void>(mutationFn: MutationFn<TData, TVariables>, options?: MutationOptions<TData, TError, TVariables>): Mutation<TData, TError, TVariables>;
213
+
214
+ export { type AsyncChunk as A, type InfiniteAsyncChunk as I, type Mutation as M, type PaginatedAsyncChunk as P, type PaginationState as a, type MutationResult as b, type AsyncState as c, type AsyncStateWithPagination as d, asyncChunk as e, type MutationOptions as f, type MutationState as g, type MutationFn as h, infiniteAsyncChunk as i, mutation as m };