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.
@@ -0,0 +1,214 @@
1
+ import { C as Chunk } from './core-DsoxfUCH.cjs';
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 };
@@ -0,0 +1 @@
1
+ 'use strict';function Y(e,a){if(e===void 0)throw new Error("Value cannot be undefined.");if(a.length===0)return e;let n=e;for(let l=0;l<a.length;l++){let y=a[l],m=typeof y=="function"?y:y.fn,d=typeof y=="function"?`index ${l}`:y.name||`index ${l}`;try{let o=m(n);if(o===void 0)break;if(o===null)throw new Error(`Middleware "${d}" returned null value.`);n=o;}catch(o){let t=o instanceof Error?o.message:String(o);throw new Error(`Middleware "${d}" threw an error: ${t}`)}}return n}function q(e,a,n="",l={}){let{checkMissing:y=true,checkTypes:m=true}=l;if(e===null||a===null||e===void 0||a===void 0)return;if(typeof e!=typeof a){console.error(`\u{1F6A8} Stunk: Type mismatch at '${n||"root"}'. Expected ${typeof e}, got ${typeof a}.`);return}if(typeof e!="object"||typeof a!="object")return;if(Array.isArray(e)!==Array.isArray(a)){console.error(`\u{1F6A8} Stunk: Type mismatch at '${n||"root"}'. Expected ${Array.isArray(e)?"array":"object"}, got ${Array.isArray(a)?"array":"object"}.`);return}if(Array.isArray(e)&&Array.isArray(a)){if(e.length>0&&typeof e[0]=="object")for(let i=0;i<a.length;i++)q(e[0],a[i],`${n}[${i}]`,l);return}let d=Object.keys(e),o=Object.keys(a),t=o.filter(i=>!d.includes(i));if(t.length>0&&(console.error(`\u{1F6A8} Stunk: Unknown properties at '${n||"root"}': ${t.join(", ")}`),console.error("Expected keys:",d),console.error("Received keys:",o)),y){let i=d.filter(u=>!o.includes(u));i.length>0&&console.error(`\u{1F6A8} Stunk: Missing properties at '${n||"root"}': ${i.join(", ")}`);}for(let i of d){let u=e[i],c=a[i];u===void 0||c===void 0||c===null||(m&&typeof u!="object"&&typeof u!=typeof c&&console.error(`\u{1F6A8} Stunk: Type mismatch at '${n?n+".":""}${i}'. Expected ${typeof u}, got ${typeof c}.`),q(u,c,n?`${n}.${i}`:i,l));}}var ee=new Set,K=new Map,oe=0;function O(e,a={}){let n=oe++,l=a.name||`chunk_${n}`,y=a.middleware||[],m=a.strict??false;if(e===void 0)throw new Error(`[${l}] Initial value cannot be undefined.`);let d=e!==null&&typeof e=="object"&&!Array.isArray(e)?new Set(Object.keys(e)):null,o=e,t=new Set,i=()=>{t.forEach(p=>p(o));};K.set(n,{notify:i});let u=()=>{if(t.size===0){K.delete(n);return}i();},c=()=>(o),b=()=>o,h=p=>{let T;if(typeof p=="function"?T=p(o):T=p,q(o,T),d&&T!==null&&typeof T=="object"&&!Array.isArray(T)){let s=Object.keys(T).filter(f=>!d.has(f));if(s.length>0){let f=`[${l}] Unexpected keys in set(): ${s.join(", ")}. These keys were not present in the initial shape.`;if(m)throw new Error(`\u{1F6A8} Stunk: ${f}`);console.error(`\u{1F6A8} Stunk: ${f}`);}}let P=Y(T,y);P!==o&&(o=P,u());},A=p=>{if(typeof p!="function")throw new Error("Callback must be a function.");return t.add(p),()=>t.delete(p)},S={get:c,peek:b,set:h,subscribe:A,derive:p=>{if(typeof p!="function")throw new Error("Derive function must be a function.");let T=p(o),P=O(T),s=A(()=>{let $=p(o);P.set($);}),f=P.destroy;return P.destroy=()=>{s(),f();},P},reset:()=>{o=e,u();},destroy:()=>{t.clear(),o=e,ee.delete(n),K.delete(n);},[Symbol.for("stunk.meta")]:{name:l,id:n}};return S}var R={};function ie(e){R={...e.query!==void 0&&{query:{...R.query,...e.query}},...e.mutation!==void 0&&{mutation:{...R.mutation,...e.mutation}}};}function _(){return R}function se(){R={};}var I=new Map,ue=0;function N(e,a={}){let n=_().query??{},{key:l,initialData:y=null,enabled:m=true,onSuccess:d=n.onSuccess,onError:o=n.onError,retryCount:t=n.retryCount??0,retryDelay:i=n.retryDelay??1e3,keepPreviousData:u=false,staleTime:c=n.staleTime??0,cacheTime:b=n.cacheTime??5*60*1e3,refetchInterval:h=n.refetchInterval,refetchOnWindowFocus:A=n.refetchOnWindowFocus??false,pagination:w}=a,E=l??`async_chunk_${ue++}`,C=()=>typeof m=="function"?m():m,S=!!w,p=w?.mode||"replace",T=e.length>0,P={loading:C()&&!T,error:null,data:y,lastFetched:void 0,isPlaceholderData:false,pagination:S?{page:w.initialPage||1,pageSize:w.pageSize||10,total:void 0,hasMore:void 0}:void 0},s=O(P),f={},$=null,j=null,F=null,z=0,B=()=>{let r=s.get();return !r.lastFetched||c===0?true:Date.now()-r.lastFetched>c},te=()=>{s.set({...s.get(),data:y,lastFetched:void 0});},re=()=>{j&&clearTimeout(j),b>0&&(j=setTimeout(te,b));},G=()=>{$&&(clearInterval($),$=null),j&&(clearTimeout(j),j=null),F&&typeof window<"u"&&(window.removeEventListener("focus",F),F=null);},L=()=>{C()&&(typeof window>"u"||(h&&h>0&&($=setInterval(()=>{k(void 0,0,false);},h)),A&&(F=()=>{B()&&k(void 0,0,false);},window.addEventListener("focus",F))));},k=async(r,g=t,D=false)=>{if(!C()||(r!==void 0&&(f={...f,...r}),!D&&!B()&&s.get().data!==null))return;if(I.has(E))return I.get(E);let W=s.get();s.set({...W,loading:true,error:null,data:W.data,isPlaceholderData:u&&W.data!==null});let U=(async()=>{try{let V={...f};if(S){let M=s.get().pagination;M&&(V.page=M.page,V.pageSize=M.pageSize);}let v=T?await e(V):await e(),x,J,X;if(v&&typeof v=="object"&&"data"in v){let M=v;x=M.data,J=M.total,X=M.hasMore;}else x=v;let Q=s.get();S&&p==="accumulate"&&Q.data&&Array.isArray(Q.data)&&Array.isArray(x)&&(x=[...Q.data,...x]),s.set({loading:!1,error:null,data:x,lastFetched:Date.now(),isPlaceholderData:!1,pagination:S?{...Q.pagination,total:J,hasMore:X}:void 0}),re(),d&&d(x);}catch(V){if(g>0)return await new Promise(x=>setTimeout(x,i)),I.delete(E),k(r,g-1,D);let v=s.get();s.set({loading:false,error:V,data:v.data,lastFetched:v.lastFetched,isPlaceholderData:false,pagination:v.pagination}),o&&o(V);}finally{I.delete(E);}})();return I.set(E,U),U};L(),C()&&!T&&k();let H={...s,subscribe:r=>{z++;let g=s.subscribe(r);return ()=>{g(),z--;}},reload:async r=>{await k(r,t,true);},refresh:async r=>{await k(r,t,false);},mutate:r=>{let g=s.get();s.set({...g,data:r(g.data)});},reset:()=>{G(),f={},s.set({...P,loading:C()&&!T}),L(),C()&&!T&&k();},cleanup:()=>{z<=0&&G();},forceCleanup:()=>{G();},setParams:r=>{let g={...f};for(let D in r)r[D]===null?delete g[D]:g[D]=r[D];f=g,C()&&k(f,t,true);},clearParams:()=>{f={},C()&&k(void 0,t,true);}};return S?{...H,nextPage:async()=>{let r=s.get();!r.pagination||r.pagination.hasMore===false||(s.set({...r,pagination:{...r.pagination,page:r.pagination.page+1}}),await k(f,t,true));},prevPage:async()=>{let r=s.get();!r.pagination||r.pagination.page<=1||(s.set({...r,pagination:{...r.pagination,page:r.pagination.page-1}}),await k(f,t,true));},goToPage:async r=>{let g=s.get();!g.pagination||r<1||(s.set({...g,pagination:{...g.pagination,page:r}}),await k(f,t,true));},resetPagination:async()=>{let r=s.get();r.pagination&&(s.set({...r,data:p==="accumulate"?y:r.data,pagination:{...r.pagination,page:w?.initialPage||1}}),await k(f,t,true));}}:H}function ce(e,a={}){let{pageSize:n=10,...l}=a;return N(e,{...l,pagination:{pageSize:n,mode:"accumulate",initialPage:1}})}function le(e){let a=Object.entries(e),n=a.reduce((t,[i,u])=>(t[i]=u.get().data,t),{}),l=a.reduce((t,[i,u])=>{let c=u.get().error;return c&&(t[i]=c),t},{}),y=a.some(([,t])=>t.get().loading),m=a.find(([,t])=>t.get().error)?.[1].get().error??null,o=O({loading:y,error:m,errors:l,data:n});return a.forEach(([t,i])=>{i.subscribe(()=>{let u=false,c=null,b={},h={...o.get().data};a.forEach(([A,w])=>{let E=w.get();E.loading&&(u=true),E.error&&(c||(c=E.error),b[A]=E.error),h[A]=E.data;}),o.set({loading:u,error:c,errors:b,data:h});});}),o}function de(e,a={}){let n=_().mutation??{},{invalidates:l=[],onSuccess:y=n.onSuccess,onError:m=n.onError,onSettled:d}=a,o={loading:false,data:null,error:null,isSuccess:false},t=O(o);return {mutate:async(...u)=>{let c=u[0];t.set({loading:true,data:null,error:null,isSuccess:false});try{let b=await e(c);return t.set({loading:!1,data:b,error:null,isSuccess:!0}),l.length>0&&await Promise.all(l.map(h=>h.reload())),y&&y(b,c),d&&d(b,null,c),{data:b,error:null}}catch(b){let h=b;return t.set({loading:false,data:null,error:h,isSuccess:false}),m&&m(h,c),d&&d(null,h,c),{data:null,error:h}}},get:()=>t.get(),subscribe:u=>t.subscribe(u),reset:()=>t.set(o)}}exports.asyncChunk=N;exports.combineAsyncChunks=le;exports.configureQuery=ie;exports.getGlobalQueryConfig=_;exports.infiniteAsyncChunk=ce;exports.mutation=de;exports.resetQueryConfig=se;
@@ -0,0 +1,107 @@
1
+ import { A as AsyncChunk } from '../mutation-Txd2ni6w.cjs';
2
+ export { c as AsyncState, d as AsyncStateWithPagination, M as Mutation, h as MutationFn, f as MutationOptions, b as MutationResult, g as MutationState, P as PaginatedAsyncChunk, e as asyncChunk, i as infiniteAsyncChunk, m as mutation } from '../mutation-Txd2ni6w.cjs';
3
+ import { C as Chunk } from '../core-DsoxfUCH.cjs';
4
+
5
+ interface GlobalQueryConfig {
6
+ /**
7
+ * Default configuration applied to all asyncChunk instances.
8
+ * Per-chunk options always override these defaults.
9
+ */
10
+ query?: {
11
+ /** Time in ms before data is considered stale (default: 0) */
12
+ staleTime?: number;
13
+ /** Time in ms to cache data after last subscriber leaves (default: 300_000) */
14
+ cacheTime?: number;
15
+ /** Auto-refetch interval in ms */
16
+ refetchInterval?: number;
17
+ /** Refetch when window regains focus (default: false) */
18
+ refetchOnWindowFocus?: boolean;
19
+ /** Number of retries on failure (default: 0) */
20
+ retryCount?: number;
21
+ /** Delay in ms between retries (default: 1000) */
22
+ retryDelay?: number;
23
+ /** Global error handler — called when all retries are exhausted */
24
+ onError?: (error: Error) => void;
25
+ /** Global success handler — called after every successful fetch */
26
+ onSuccess?: (data: unknown) => void;
27
+ };
28
+ /**
29
+ * Default configuration applied to all mutation instances.
30
+ * Reserved for when mutation() ships — per-mutation options always override.
31
+ */
32
+ mutation?: {
33
+ /** Global error handler for mutations */
34
+ onError?: (error: Error) => void;
35
+ /** Global success handler for mutations */
36
+ onSuccess?: (data: unknown) => void;
37
+ };
38
+ }
39
+ /**
40
+ * Configures global defaults for all `asyncChunk` and `mutation` instances.
41
+ *
42
+ * Call this once at app entry — before any `asyncChunk` is created.
43
+ * Per-chunk options always take precedence over these defaults.
44
+ *
45
+ * @param config.query - Defaults for all async chunks (staleTime, retryCount, onError, etc.)
46
+ * @param config.mutation - Defaults for all mutations (onError, onSuccess)
47
+ *
48
+ * @example
49
+ * import { configureQuery } from "stunk/query";
50
+ *
51
+ * configureQuery({
52
+ * query: {
53
+ * staleTime: 30_000,
54
+ * retryCount: 3,
55
+ * refetchOnWindowFocus: true,
56
+ * onError: (err) => toast.error(err.message),
57
+ * },
58
+ * mutation: {
59
+ * onError: (err) => toast.error(err.message),
60
+ * onSuccess: () => toast.success("Done!"),
61
+ * },
62
+ * });
63
+ */
64
+ declare function configureQuery(config: GlobalQueryConfig): void;
65
+ /**
66
+ * Returns the current global query config.
67
+ * Used internally by asyncChunk and mutation to read defaults.
68
+ */
69
+ declare function getGlobalQueryConfig(): GlobalQueryConfig;
70
+ /**
71
+ * Resets the global config back to defaults.
72
+ * Primarily useful in tests to avoid config bleed between test cases.
73
+ *
74
+ * @example
75
+ * afterEach(() => resetQueryConfig());
76
+ */
77
+ declare function resetQueryConfig(): void;
78
+
79
+ type InferAsyncData<T> = T extends AsyncChunk<infer U, Error> ? U : never;
80
+ type CombinedData<T extends Record<string, AsyncChunk<any>>> = {
81
+ [K in keyof T]: InferAsyncData<T[K]> | null;
82
+ };
83
+ type CombinedState<T extends Record<string, AsyncChunk<any>>> = {
84
+ loading: boolean;
85
+ error: Error | null;
86
+ errors: Partial<{
87
+ [K in keyof T]: Error;
88
+ }>;
89
+ data: CombinedData<T>;
90
+ };
91
+
92
+ /**
93
+ * Combines multiple async chunks into a single unified state chunk.
94
+ *
95
+ * The result tracks `loading` (true if any chunk is loading), `error` (first
96
+ * error encountered), `errors` (per-chunk errors), and `data` (per-chunk data).
97
+ *
98
+ * @param chunks - A record of named `AsyncChunk` instances.
99
+ * @returns A `Chunk<CombinedState<T>>` that reflects the live state of all inputs.
100
+ *
101
+ * @example
102
+ * const combined = combineAsyncChunks({ user: userChunk, posts: postsChunk });
103
+ * combined.get(); // { loading, error, errors, data: { user, posts } }
104
+ */
105
+ declare function combineAsyncChunks<T extends Record<string, AsyncChunk<any>>>(chunks: T): Chunk<CombinedState<T>>;
106
+
107
+ export { AsyncChunk, type GlobalQueryConfig, combineAsyncChunks, configureQuery, getGlobalQueryConfig, resetQueryConfig };
@@ -0,0 +1,107 @@
1
+ import { A as AsyncChunk } from '../mutation-BGXZyZXA.js';
2
+ export { c as AsyncState, d as AsyncStateWithPagination, M as Mutation, h as MutationFn, f as MutationOptions, b as MutationResult, g as MutationState, P as PaginatedAsyncChunk, e as asyncChunk, i as infiniteAsyncChunk, m as mutation } from '../mutation-BGXZyZXA.js';
3
+ import { C as Chunk } from '../core-DsoxfUCH.js';
4
+
5
+ interface GlobalQueryConfig {
6
+ /**
7
+ * Default configuration applied to all asyncChunk instances.
8
+ * Per-chunk options always override these defaults.
9
+ */
10
+ query?: {
11
+ /** Time in ms before data is considered stale (default: 0) */
12
+ staleTime?: number;
13
+ /** Time in ms to cache data after last subscriber leaves (default: 300_000) */
14
+ cacheTime?: number;
15
+ /** Auto-refetch interval in ms */
16
+ refetchInterval?: number;
17
+ /** Refetch when window regains focus (default: false) */
18
+ refetchOnWindowFocus?: boolean;
19
+ /** Number of retries on failure (default: 0) */
20
+ retryCount?: number;
21
+ /** Delay in ms between retries (default: 1000) */
22
+ retryDelay?: number;
23
+ /** Global error handler — called when all retries are exhausted */
24
+ onError?: (error: Error) => void;
25
+ /** Global success handler — called after every successful fetch */
26
+ onSuccess?: (data: unknown) => void;
27
+ };
28
+ /**
29
+ * Default configuration applied to all mutation instances.
30
+ * Reserved for when mutation() ships — per-mutation options always override.
31
+ */
32
+ mutation?: {
33
+ /** Global error handler for mutations */
34
+ onError?: (error: Error) => void;
35
+ /** Global success handler for mutations */
36
+ onSuccess?: (data: unknown) => void;
37
+ };
38
+ }
39
+ /**
40
+ * Configures global defaults for all `asyncChunk` and `mutation` instances.
41
+ *
42
+ * Call this once at app entry — before any `asyncChunk` is created.
43
+ * Per-chunk options always take precedence over these defaults.
44
+ *
45
+ * @param config.query - Defaults for all async chunks (staleTime, retryCount, onError, etc.)
46
+ * @param config.mutation - Defaults for all mutations (onError, onSuccess)
47
+ *
48
+ * @example
49
+ * import { configureQuery } from "stunk/query";
50
+ *
51
+ * configureQuery({
52
+ * query: {
53
+ * staleTime: 30_000,
54
+ * retryCount: 3,
55
+ * refetchOnWindowFocus: true,
56
+ * onError: (err) => toast.error(err.message),
57
+ * },
58
+ * mutation: {
59
+ * onError: (err) => toast.error(err.message),
60
+ * onSuccess: () => toast.success("Done!"),
61
+ * },
62
+ * });
63
+ */
64
+ declare function configureQuery(config: GlobalQueryConfig): void;
65
+ /**
66
+ * Returns the current global query config.
67
+ * Used internally by asyncChunk and mutation to read defaults.
68
+ */
69
+ declare function getGlobalQueryConfig(): GlobalQueryConfig;
70
+ /**
71
+ * Resets the global config back to defaults.
72
+ * Primarily useful in tests to avoid config bleed between test cases.
73
+ *
74
+ * @example
75
+ * afterEach(() => resetQueryConfig());
76
+ */
77
+ declare function resetQueryConfig(): void;
78
+
79
+ type InferAsyncData<T> = T extends AsyncChunk<infer U, Error> ? U : never;
80
+ type CombinedData<T extends Record<string, AsyncChunk<any>>> = {
81
+ [K in keyof T]: InferAsyncData<T[K]> | null;
82
+ };
83
+ type CombinedState<T extends Record<string, AsyncChunk<any>>> = {
84
+ loading: boolean;
85
+ error: Error | null;
86
+ errors: Partial<{
87
+ [K in keyof T]: Error;
88
+ }>;
89
+ data: CombinedData<T>;
90
+ };
91
+
92
+ /**
93
+ * Combines multiple async chunks into a single unified state chunk.
94
+ *
95
+ * The result tracks `loading` (true if any chunk is loading), `error` (first
96
+ * error encountered), `errors` (per-chunk errors), and `data` (per-chunk data).
97
+ *
98
+ * @param chunks - A record of named `AsyncChunk` instances.
99
+ * @returns A `Chunk<CombinedState<T>>` that reflects the live state of all inputs.
100
+ *
101
+ * @example
102
+ * const combined = combineAsyncChunks({ user: userChunk, posts: postsChunk });
103
+ * combined.get(); // { loading, error, errors, data: { user, posts } }
104
+ */
105
+ declare function combineAsyncChunks<T extends Record<string, AsyncChunk<any>>>(chunks: T): Chunk<CombinedState<T>>;
106
+
107
+ export { AsyncChunk, type GlobalQueryConfig, combineAsyncChunks, configureQuery, getGlobalQueryConfig, resetQueryConfig };
@@ -0,0 +1 @@
1
+ import {a}from'../chunk-HPKV6WRO.js';import'../chunk-3DOB632D.js';var O={};function Y(i){O={...i.query!==void 0&&{query:{...O.query,...i.query}},...i.mutation!==void 0&&{mutation:{...O.mutation,...i.mutation}}};}function R(){return O}function Z(){O={};}var V=new Map,ee=0;function L(i,l={}){let r=R().query??{},{key:T,initialData:b=null,enabled:h=true,onSuccess:E=r.onSuccess,onError:p=r.onError,retryCount:a$1=r.retryCount??0,retryDelay:P=r.retryDelay??1e3,keepPreviousData:c=false,staleTime:n=r.staleTime??0,cacheTime:d=r.cacheTime??5*60*1e3,refetchInterval:s=r.refetchInterval,refetchOnWindowFocus:Q=r.refetchOnWindowFocus??false,pagination:k}=l,g=T??`async_chunk_${ee++}`,C=()=>typeof h=="function"?h():h,w=!!k,j=k?.mode||"replace",M=i.length>0,K={loading:C()&&!M,error:null,data:b,lastFetched:void 0,isPlaceholderData:false,pagination:w?{page:k.initialPage||1,pageSize:k.pageSize||10,total:void 0,hasMore:void 0}:void 0},t=a(K),f={},I=null,S=null,F=null,G=0,N=()=>{let e=t.get();return !e.lastFetched||n===0?true:Date.now()-e.lastFetched>n},U=()=>{t.set({...t.get(),data:b,lastFetched:void 0});},X=()=>{S&&clearTimeout(S),d>0&&(S=setTimeout(U,d));},q=()=>{I&&(clearInterval(I),I=null),S&&(clearTimeout(S),S=null),F&&typeof window<"u"&&(window.removeEventListener("focus",F),F=null);},_=()=>{C()&&(typeof window>"u"||(s&&s>0&&(I=setInterval(()=>{u(void 0,0,false);},s)),Q&&(F=()=>{N()&&u(void 0,0,false);},window.addEventListener("focus",F))));},u=async(e,o=a$1,v=false)=>{if(!C()||(e!==void 0&&(f={...f,...e}),!v&&!N()&&t.get().data!==null))return;if(V.has(g))return V.get(g);let W=t.get();t.set({...W,loading:true,error:null,data:W.data,isPlaceholderData:c&&W.data!==null});let $=(async()=>{try{let A={...f};if(w){let x=t.get().pagination;x&&(A.page=x.page,A.pageSize=x.pageSize);}let m=M?await i(A):await i(),y,B,J;if(m&&typeof m=="object"&&"data"in m){let x=m;y=x.data,B=x.total,J=x.hasMore;}else y=m;let z=t.get();w&&j==="accumulate"&&z.data&&Array.isArray(z.data)&&Array.isArray(y)&&(y=[...z.data,...y]),t.set({loading:!1,error:null,data:y,lastFetched:Date.now(),isPlaceholderData:!1,pagination:w?{...z.pagination,total:B,hasMore:J}:void 0}),X(),E&&E(y);}catch(A){if(o>0)return await new Promise(y=>setTimeout(y,P)),V.delete(g),u(e,o-1,v);let m=t.get();t.set({loading:false,error:A,data:m.data,lastFetched:m.lastFetched,isPlaceholderData:false,pagination:m.pagination}),p&&p(A);}finally{V.delete(g);}})();return V.set(g,$),$};_(),C()&&!M&&u();let H={...t,subscribe:e=>{G++;let o=t.subscribe(e);return ()=>{o(),G--;}},reload:async e=>{await u(e,a$1,true);},refresh:async e=>{await u(e,a$1,false);},mutate:e=>{let o=t.get();t.set({...o,data:e(o.data)});},reset:()=>{q(),f={},t.set({...K,loading:C()&&!M}),_(),C()&&!M&&u();},cleanup:()=>{G<=0&&q();},forceCleanup:()=>{q();},setParams:e=>{let o={...f};for(let v in e)e[v]===null?delete o[v]:o[v]=e[v];f=o,C()&&u(f,a$1,true);},clearParams:()=>{f={},C()&&u(void 0,a$1,true);}};return w?{...H,nextPage:async()=>{let e=t.get();!e.pagination||e.pagination.hasMore===false||(t.set({...e,pagination:{...e.pagination,page:e.pagination.page+1}}),await u(f,a$1,true));},prevPage:async()=>{let e=t.get();!e.pagination||e.pagination.page<=1||(t.set({...e,pagination:{...e.pagination,page:e.pagination.page-1}}),await u(f,a$1,true));},goToPage:async e=>{let o=t.get();!o.pagination||e<1||(t.set({...o,pagination:{...o.pagination,page:e}}),await u(f,a$1,true));},resetPagination:async()=>{let e=t.get();e.pagination&&(t.set({...e,data:j==="accumulate"?b:e.data,pagination:{...e.pagination,page:k?.initialPage||1}}),await u(f,a$1,true));}}:H}function ae(i,l={}){let{pageSize:r=10,...T}=l;return L(i,{...T,pagination:{pageSize:r,mode:"accumulate",initialPage:1}})}function te(i){let l=Object.entries(i),r=l.reduce((a,[P,c])=>(a[P]=c.get().data,a),{}),T=l.reduce((a,[P,c])=>{let n=c.get().error;return n&&(a[P]=n),a},{}),b=l.some(([,a])=>a.get().loading),h=l.find(([,a])=>a.get().error)?.[1].get().error??null,p=a({loading:b,error:h,errors:T,data:r});return l.forEach(([a,P])=>{P.subscribe(()=>{let c=false,n=null,d={},s={...p.get().data};l.forEach(([Q,k])=>{let g=k.get();g.loading&&(c=true),g.error&&(n||(n=g.error),d[Q]=g.error),s[Q]=g.data;}),p.set({loading:c,error:n,errors:d,data:s});});}),p}function re(i,l={}){let r=R().mutation??{},{invalidates:T=[],onSuccess:b=r.onSuccess,onError:h=r.onError,onSettled:E}=l,p={loading:false,data:null,error:null,isSuccess:false},a$1=a(p);return {mutate:async(...c)=>{let n=c[0];a$1.set({loading:true,data:null,error:null,isSuccess:false});try{let d=await i(n);return a$1.set({loading:!1,data:d,error:null,isSuccess:!0}),T.length>0&&await Promise.all(T.map(s=>s.reload())),b&&b(d,n),E&&E(d,null,n),{data:d,error:null}}catch(d){let s=d;return a$1.set({loading:false,data:null,error:s,isSuccess:false}),h&&h(s,n),E&&E(null,s,n),{data:null,error:s}}},get:()=>a$1.get(),subscribe:c=>a$1.subscribe(c),reset:()=>a$1.set(p)}}export{L as asyncChunk,te as combineAsyncChunks,Y as configureQuery,R as getGlobalQueryConfig,ae as infiniteAsyncChunk,re as mutation,Z as resetQueryConfig};
@@ -1 +1 @@
1
- 'use strict';var react=require('react');var U=new Set,V=new Map,N=0;function T(e,r=[]){if(e===null)throw new Error("Initial value cannot be null.");let t=e,n=new Set,s=N++,i=()=>{n.forEach(f=>f(t));};V.set(s,{notify:i});let o=()=>{n.size!==0&&(i());},u=()=>t,l=f=>{let h;typeof f=="function"?h=f(t):h=f,E(t,h);let p=j(h,r);p!==t&&(t=p,o());},a=f=>{if(typeof f!="function")throw new Error("Callback must be a function.");return n.add(f),f(t),()=>n.delete(f)};return {get:u,set:l,subscribe:a,derive:f=>{if(typeof f!="function")throw new Error("Derive function must be a function.");let h=f(t),p=T(h),b=a(()=>{let v=f(t);p.set(v);}),A=p.destroy;return p.destroy=()=>{b(),A();},p},reset:()=>{t=e,o();},destroy:()=>{n.clear(),t=e,U.delete(s),V.delete(s);}}}function j(e,r){if(e===null)throw new Error("Value cannot be null.");let t=e;for(let n=0;n<r.length;n++){let s=r[n],i=typeof s=="function"?s:s.fn,o=typeof s=="function"?`index ${n}`:s.name||`index ${n}`;try{let u=i(t);if(u===void 0)break;if(u===null)throw new Error(`Middleware "${o}" returned null value.`);t=u;}catch(u){let l=u instanceof Error?u.message:String(u);throw new Error(`Middleware "${o}" threw an error: ${l}`)}}return t}function x(e,r){if(e===r)return true;if(!e||!r||typeof e!=typeof r)return false;if(Array.isArray(e)&&Array.isArray(r)){if(e.length!==r.length)return false;for(let t=0;t<e.length;t++)if(e[t]!==r[t])return false;return true}if(typeof e=="object"&&typeof r=="object"){let t=Object.keys(e),n=Object.keys(r);if(t.length!==n.length)return false;for(let s of t)if(!Object.prototype.hasOwnProperty.call(r,s)||e[s]!==r[s])return false;return true}return false}function E(e,r,t=""){if(typeof e=="object"&&e!==null&&typeof r=="object"&&r!==null){if(Array.isArray(e)&&Array.isArray(r)){if(e.length>0&&typeof e[0]=="object")for(let n=0;n<r.length;n++)E(e[0],r[n],`${t}[${n}]`);}else if(!Array.isArray(e)&&!Array.isArray(r)){let n=Object.keys(e),s=Object.keys(r),i=s.filter(o=>!n.includes(o));i.length>0&&(console.error(`\u{1F6A8} Stunk: Unknown properties detected at '${t||"root"}': ${i.join(", ")}. This might cause bugs.`),console.error("Expected keys:",n),console.error("Received keys:",s));for(let o of n)E(e[o],r[o],t?`${t}.${o}`:o);}}}function R(e,r,t={}){let{useShallowEqual:n=false}=t,s=e.get(),i=r(s),o=T(i),u=()=>{let a=e.get(),c=r(a);s=a,(n?!x(c,i):c!==i)&&(i=c,o.set(c));},l=e.subscribe(u);return {get:()=>o.get(),set:()=>{throw new Error("Cannot set values directly on a selector. Modify the source chunk instead.")},subscribe:o.subscribe,derive:a=>R(o,a,t),reset:()=>{throw new Error("Cannot reset a selector chunk. Reset the source chunk instead.")},destroy:()=>{l(),o.destroy();}}}function k(e,r){let t=r?R(e,r):e,[n,s]=react.useState(()=>t.get());react.useEffect(()=>{let l=t.subscribe(a=>{s(()=>a);});return ()=>l()},[t]);let i=react.useCallback(l=>{e.set(l);},[e]),o=react.useCallback(()=>{e.reset();},[e]),u=react.useCallback(()=>{e.destroy();},[e]);return [n,i,o,u]}function J(e,r){let t=react.useRef(r);react.useEffect(()=>{t.current=r;},[r]);let n=react.useMemo(()=>e.derive(i=>t.current(i)),[e]),[s]=k(n);return s}function K(e,r){let t=e.map(a=>a.get()),n=r(...t),s=T(n),i=s.set,o=false,u=()=>{let a=false;for(let c=0;c<e.length;c++){let y=e[c].get();y!==t[c]&&(t[c]=y,a=true);}if(a){let c=r(...t);c!==n&&(typeof c!="object"||typeof n!="object"||!x(c,n))&&(n=c,i(c)),o=false;}},l=e.map(a=>a.subscribe(()=>{o=true,u();}));return {...s,get:()=>(o&&u(),n),recompute:u,isDirty:()=>o,set:()=>{throw new Error("Cannot set values directly on computed. Modify the source chunk instead.")},reset:()=>(e.forEach(a=>{typeof a.reset=="function"&&a.reset();}),o=true,u(),n),destroy:()=>{l.forEach(a=>a()),s.destroy?.();}}}function Z(e,r){let t=react.useMemo(()=>K(e,r),[...e]),[n,s]=react.useState(()=>t.get());return react.useEffect(()=>{let i=t.subscribe(o=>{s(o);});return ()=>{i();}},[t]),n}function D(e,r){let[t]=k(e,r);return t}function ee(e,r){let t=react.useMemo(()=>n=>n[r],[r]);return D(e,t)}function ne(e){let[r,t]=react.useState(()=>e.map(n=>n.get()));return react.useEffect(()=>{let n=e.map((s,i)=>s.subscribe(o=>{t(u=>{let l=[...u];return l[i]=o,l});}));return ()=>{n.forEach(s=>s());}},[e]),r}function C(e){return "nextPage"in e}function W(e){return "setParams"in e}function O(e,r){let{initialParams:t,fetchOnMount:n}=typeof r=="object"&&("initialParams"in r||"fetchOnMount"in r)?r:{initialParams:r,fetchOnMount:false},[s,i]=react.useState(()=>e.get()),o=react.useRef(null);(!o.current||o.current.chunk!==e)&&(o.current={chunk:e,initialParams:t,fetchOnMount:n}),react.useEffect(()=>e.subscribe(g=>{i(g);}),[e]),react.useEffect(()=>{let d=o.current,g=d?.initialParams,q=d?.fetchOnMount;g&&W(e)?e.setParams(g):q&&!g&&e.reload();},[e]),react.useEffect(()=>()=>{e.cleanup();},[e]);let u=react.useCallback(d=>e.reload(d),[e]),l=react.useCallback(d=>e.refresh(d),[e]),a=react.useCallback(d=>e.mutate(d),[e]),c=react.useCallback(()=>e.reset(),[e]),y=react.useCallback(d=>{"setParams"in e&&e.setParams(d);},[e]),P=react.useCallback(()=>C(e)?e.nextPage():Promise.resolve(),[e]),f=react.useCallback(()=>C(e)?e.prevPage():Promise.resolve(),[e]),h=react.useCallback(d=>C(e)?e.goToPage(d):Promise.resolve(),[e]),p=react.useCallback(()=>C(e)?e.resetPagination():Promise.resolve(),[e]),{data:b,loading:A,error:v,lastFetched:$,pagination:I}=s,w={data:b,loading:A,error:v,lastFetched:$,reload:u,refresh:l,mutate:a,reset:c};if(W(e)&&(w.setParams=y),C(e)){let d=w;d.pagination=I,d.nextPage=P,d.prevPage=f,d.goToPage=h,d.resetPagination=p;}return w}function ce(e,r={}){let{initialParams:t,autoLoad:n=true,threshold:s=1,...i}=r,o=react.useRef(null),u=O(e,{initialParams:{...t,page:1,pageSize:e.get().pagination?.pageSize||10},...i}),{loading:l,pagination:a,nextPage:c}=u;react.useEffect(()=>{if(!n)return;let P=new IntersectionObserver(h=>{h[0].isIntersecting&&!l&&a?.hasMore&&c();},{threshold:s}),f=o.current;return f&&P.observe(f),()=>{f&&P.unobserve(f);}},[l,a?.hasMore,c,n,s]);let y=react.useCallback(()=>{!l&&a?.hasMore&&c();},[l,a?.hasMore,c]);return {...u,loadMore:y,observerTarget:o,hasMore:a?.hasMore??false,isFetchingMore:l&&(u.data?.length??0)>0}}exports.useAsyncChunk=O;exports.useChunk=k;exports.useChunkProperty=ee;exports.useChunkValue=D;exports.useChunkValues=ne;exports.useComputed=Z;exports.useDerive=J;exports.useInfiniteAsyncChunk=ce;
1
+ 'use strict';var react=require('react');function _(e,t){if(e===void 0)throw new Error("Value cannot be undefined.");if(t.length===0)return e;let r=e;for(let o=0;o<t.length;o++){let i=t[o],c=typeof i=="function"?i:i.fn,a=typeof i=="function"?`index ${o}`:i.name||`index ${o}`;try{let n=c(r);if(n===void 0)break;if(n===null)throw new Error(`Middleware "${a}" returned null value.`);r=n;}catch(n){let u=n instanceof Error?n.message:String(n);throw new Error(`Middleware "${a}" threw an error: ${u}`)}}return r}function I(e,t){if(e===t)return true;if(!e||!t||typeof e!=typeof t)return false;if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return false;for(let r=0;r<e.length;r++)if(e[r]!==t[r])return false;return true}if(typeof e=="object"&&typeof t=="object"){let r=Object.keys(e),o=Object.keys(t);if(r.length!==o.length)return false;for(let i of r)if(!Object.prototype.hasOwnProperty.call(t,i)||e[i]!==t[i])return false;return true}return false}function R(e,t,r="",o={}){let{checkMissing:i=true,checkTypes:c=true}=o;if(e===null||t===null||e===void 0||t===void 0)return;if(typeof e!=typeof t){console.error(`\u{1F6A8} Stunk: Type mismatch at '${r||"root"}'. Expected ${typeof e}, got ${typeof t}.`);return}if(typeof e!="object"||typeof t!="object")return;if(Array.isArray(e)!==Array.isArray(t)){console.error(`\u{1F6A8} Stunk: Type mismatch at '${r||"root"}'. Expected ${Array.isArray(e)?"array":"object"}, got ${Array.isArray(t)?"array":"object"}.`);return}if(Array.isArray(e)&&Array.isArray(t)){if(e.length>0&&typeof e[0]=="object")for(let s=0;s<t.length;s++)R(e[0],t[s],`${r}[${s}]`,o);return}let a=Object.keys(e),n=Object.keys(t),u=n.filter(s=>!a.includes(s));if(u.length>0&&(console.error(`\u{1F6A8} Stunk: Unknown properties at '${r||"root"}': ${u.join(", ")}`),console.error("Expected keys:",a),console.error("Received keys:",n)),i){let s=a.filter(d=>!n.includes(d));s.length>0&&console.error(`\u{1F6A8} Stunk: Missing properties at '${r||"root"}': ${s.join(", ")}`);}for(let s of a){let d=e[s],y=t[s];d===void 0||y===void 0||y===null||(c&&typeof d!="object"&&typeof d!=typeof y&&console.error(`\u{1F6A8} Stunk: Type mismatch at '${r?r+".":""}${s}'. Expected ${typeof d}, got ${typeof y}.`),R(d,y,r?`${r}.${s}`:s,o));}}var q=new Set,w=new Map,z=0;function M(e,t={}){let r=z++,o=t.name||`chunk_${r}`,i=t.middleware||[],c=t.strict??false;if(e===void 0)throw new Error(`[${o}] Initial value cannot be undefined.`);let a=e!==null&&typeof e=="object"&&!Array.isArray(e)?new Set(Object.keys(e)):null,n=e,u=new Set,s=()=>{u.forEach(l=>l(n));};w.set(r,{notify:s});let d=()=>{if(u.size===0){w.delete(r);return}s();},y=()=>(n),k=()=>n,T=l=>{let P;if(typeof l=="function"?P=l(n):P=l,R(n,P),a&&P!==null&&typeof P=="object"&&!Array.isArray(P)){let x=Object.keys(P).filter(m=>!a.has(m));if(x.length>0){let m=`[${o}] Unexpected keys in set(): ${x.join(", ")}. These keys were not present in the initial shape.`;if(c)throw new Error(`\u{1F6A8} Stunk: ${m}`);console.error(`\u{1F6A8} Stunk: ${m}`);}}let h=_(P,i);h!==n&&(n=h,d());},g=l=>{if(typeof l!="function")throw new Error("Callback must be a function.");return u.add(l),()=>u.delete(l)},b={get:y,peek:k,set:T,subscribe:g,derive:l=>{if(typeof l!="function")throw new Error("Derive function must be a function.");let P=l(n),h=M(P),x=g(()=>{let f=l(n);h.set(f);}),m=h.destroy;return h.destroy=()=>{x(),m();},h},reset:()=>{n=e,d();},destroy:()=>{u.clear(),n=e,q.delete(r),w.delete(r);},[Symbol.for("stunk.meta")]:{name:o,id:r}};return b}function O(e,t,r={}){let{useShallowEqual:o=false}=r,i=e.get(),c=t(i),a=M(c),n=()=>{let k=e.get(),T=t(k);(o?!I(T,c):T!==c)&&(c=T,a.set(T));},u=e.subscribe(n),{set:s,reset:d,...y}=a;return {...y,derive:k=>O(a,k,r),destroy:()=>{u(),a.destroy();}}}function U(e,t){let r=t?O(e,t):e,[o,i]=react.useState(()=>r.get());react.useEffect(()=>{let u=r.subscribe(s=>{i(()=>s);});return ()=>u()},[r]);let c=react.useCallback(u=>{e.set(u);},[e]),a=react.useCallback(()=>{e.reset();},[e]),n=react.useCallback(()=>{e.destroy();},[e]);return [o,c,a,n]}function J(e,t){let[r]=U(e,t);return r}function v(e){return "nextPage"in e}function $(e){return "setParams"in e}function Z(e){return "clearParams"in e}function j(e,t={}){let{initialParams:r,fetchOnMount:o=false}=t,[i,c]=react.useState(()=>e.get()),a=react.useRef({initialParams:r,fetchOnMount:o});a.current={initialParams:r,fetchOnMount:o},react.useEffect(()=>{c(e.get());let f=e.subscribe(N=>{c(N);}),{initialParams:V,fetchOnMount:K}=a.current;return V&&$(e)?e.setParams(V):K&&e.reload(),()=>{f(),e.cleanup();}},[e]);let n=react.useCallback(f=>e.reload(f),[e]),u=react.useCallback(f=>e.refresh(f),[e]),s=react.useCallback(f=>e.mutate(f),[e]),d=react.useCallback(()=>e.reset(),[e]),y=react.useCallback(f=>{$(e)&&e.setParams(f);},[e]),k=react.useCallback(()=>{Z(e)&&e.clearParams();},[e]),T=react.useCallback(()=>v(e)?e.nextPage():Promise.resolve(),[e]),g=react.useCallback(()=>v(e)?e.prevPage():Promise.resolve(),[e]),E=react.useCallback(f=>v(e)?e.goToPage(f):Promise.resolve(),[e]),A=react.useCallback(()=>v(e)?e.resetPagination():Promise.resolve(),[e]),{data:C,loading:b,error:l,lastFetched:P,isPlaceholderData:h=false,pagination:x}=i,m={data:C,loading:b,error:l,lastFetched:P,isPlaceholderData:h,reload:n,refresh:u,mutate:s,reset:d};if($(e)&&(m.setParams=y,m.clearParams=k),v(e)){let f=m;f.pagination=x,f.nextPage=T,f.prevPage=g,f.goToPage=E,f.resetPagination=A;}return m}function re(e,t={}){let{initialParams:r,autoLoad:o=true,threshold:i=1,fetchOnMount:c}=t,a=j(e,{...r&&{initialParams:r},fetchOnMount:c}),{loading:n,pagination:u,nextPage:s,data:d,error:y,isPlaceholderData:k}=a,T=react.useRef(n),g=react.useRef(u?.hasMore??false),E=react.useRef(s);T.current=n,g.current=u?.hasMore??false,E.current=s;let A=react.useRef(null);react.useEffect(()=>{if(!o||typeof window>"u"||!("IntersectionObserver"in window))return;let l=new IntersectionObserver(h=>{h[0].isIntersecting&&!T.current&&g.current&&E.current();},{threshold:i}),P=A.current;return P&&l.observe(P),()=>{P&&l.unobserve(P),l.disconnect();}},[o,i]);let C=react.useCallback(()=>{!T.current&&g.current&&E.current();},[]),b=n&&d!==null&&d.length>0&&(u?.page??1)>1;return {...a,data:d,error:y,isPlaceholderData:k??false,isFetchingMore:b,hasMore:u?.hasMore??false,loadMore:C,observerTarget:A}}function oe(e){let[t,r]=react.useState(()=>e.get());react.useEffect(()=>(r(e.get()),e.subscribe(a=>{r(a);})),[e]);let o=react.useCallback((...c)=>e.mutate(...c),[e]),i=react.useCallback(()=>e.reset(),[e]);return {loading:t.loading,data:t.data,error:t.error,isSuccess:t.isSuccess,mutate:o,reset:i}}exports.useAsyncChunk=j;exports.useChunk=U;exports.useChunkValue=J;exports.useInfiniteAsyncChunk=re;exports.useMutation=oe;