floppy-disk 3.0.0-alpha.5 → 3.0.0-alpha.6

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,82 @@
1
+ import { type MutationOptions, type MutationState } from './create-mutation.mjs';
2
+ /**
3
+ * A hook for managing async mutation state.
4
+ *
5
+ * @param mutationFn - Async function that performs the mutation.
6
+ * Receives the input variable and the state snapshot before execution.
7
+ *
8
+ * @param options - Optional lifecycle callbacks:
9
+ * - `onSuccess(data, variable, stateBeforeExecute)`
10
+ * - `onError(error, variable, stateBeforeExecute)`
11
+ * - `onSettled(variable, stateBeforeExecute)`
12
+ *
13
+ * @returns A tuple containing:
14
+ * - state: The current mutation state (render snapshot)
15
+ * - controls: An object with mutation actions and helpers
16
+ *
17
+ * @remarks
18
+ * - No retry mechanism is provided by default.
19
+ * - The mutation always resolves (never throws): the result contains either `data` or `error`.
20
+ * - If multiple executions triggered at the same time:
21
+ * - Only the latest execution is allowed to update the state.
22
+ * - Results from previous executions are ignored if a newer one exists.
23
+ */
24
+ export declare const useMutation: <TData, TVariable = undefined, TError = Error>(
25
+ /**
26
+ * Async function that performs the mutation.
27
+ *
28
+ * @remarks
29
+ * - Does NOT need to be memoized (e.g. `useCallback`).
30
+ * - The latest function reference is always used internally.
31
+ */
32
+ mutationFn: (variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable, TError>) => Promise<TData>,
33
+ /**
34
+ * Optional lifecycle callbacks.
35
+ *
36
+ * @remarks
37
+ * - Callbacks do NOT need to be memoized.
38
+ * - The latest callbacks are always used internally.
39
+ */
40
+ options?: MutationOptions<TData, TVariable, TError>) => [MutationState<TData, TVariable, TError>, {
41
+ /**
42
+ * Executes the mutation.
43
+ *
44
+ * @param variable - Input passed to the mutation function
45
+ *
46
+ * @returns A promise that always resolves with:
47
+ * - `{ data, variable }` on success
48
+ * - `{ error, variable }` on failure
49
+ *
50
+ * @remarks
51
+ * - The promise never rejects to simplify async handling.
52
+ * - If a mutation is already in progress, a warning is logged.
53
+ * - When a new execution starts, all previous pending executions will resolve with the result of the latest execution.
54
+ */
55
+ execute: TVariable extends undefined ? () => Promise<{
56
+ variable: undefined;
57
+ data?: TData;
58
+ error?: TError;
59
+ }> : (variable: TVariable) => Promise<{
60
+ variable: TVariable;
61
+ data?: TData;
62
+ error?: TError;
63
+ }>;
64
+ /**
65
+ * Resets the mutation state back to its initial state.
66
+ *
67
+ * @remarks
68
+ * - Does not cancel any ongoing execution.
69
+ * - If an execution is still pending, its result may override the reset state.
70
+ */
71
+ reset: () => void;
72
+ /**
73
+ * Returns the latest mutation state directly from the internal ref.
74
+ *
75
+ * @returns The most up-to-date mutation state.
76
+ *
77
+ * @remarks
78
+ * - Unlike the `state` returned by the hook, this value is not tied to React render cycles.
79
+ * - Use this inside async flows or event handlers to avoid stale reads.
80
+ */
81
+ getLatestState: () => MutationState<TData, TVariable, TError>;
82
+ }];
package/esm/react.d.mts CHANGED
@@ -3,4 +3,5 @@ export { useStoreState } from './react/use-store.mjs';
3
3
  export * from './react/create-store.mjs';
4
4
  export * from './react/create-stores.mjs';
5
5
  export * from './react/create-query.mjs';
6
- export * from './react/create-mutation.mjs';
6
+ export { createMutation, type MutationOptions, type MutationState, } from './react/create-mutation.mjs';
7
+ export * from './react/use-mutation.mjs';
package/esm/react.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { useLayoutEffect, useEffect, useState, useRef, useMemo } from 'react';
1
+ import { useLayoutEffect, useEffect, useState, useRef, useMemo, useCallback } from 'react';
2
2
  import { isClient, initStore, getHash, noop } from 'floppy-disk/vanilla';
3
3
 
4
4
  const useIsomorphicLayoutEffect = isClient ? useLayoutEffect : useEffect;
@@ -128,7 +128,7 @@ const createQuery = (queryFn, options = {}) => {
128
128
  onSettled = noop,
129
129
  shouldRetry: shouldRetryFn = (_, s) => s.retryCount === 0 ? [true, 1500] : [false]
130
130
  } = options;
131
- const initialState = INITIAL_STATE$1;
131
+ const initialState = { ...INITIAL_STATE$1 };
132
132
  const stores = /* @__PURE__ */ new Map();
133
133
  const configureStoreEvents = () => ({
134
134
  ...options,
@@ -367,7 +367,7 @@ const createQuery = (queryFn, options = {}) => {
367
367
  internals.set(store, configureInternals(store, variable, variableHash));
368
368
  }
369
369
  const useStore = (options2 = {}) => {
370
- const { enabled = true, keepPreviousData } = options2;
370
+ const { revalidateOnMount = true, keepPreviousData } = options2;
371
371
  const storeState = store.getState();
372
372
  const prevState = useRef({});
373
373
  let storeStateToBeUsed = storeState;
@@ -380,7 +380,7 @@ const createQuery = (queryFn, options = {}) => {
380
380
  storeStateToBeUsed = { ...storeState, ...prevState.current };
381
381
  }
382
382
  const [trackedState, usedPathsRef] = useStoreStateProxy(
383
- enabled && storeState.state === "INITIAL" ? (
383
+ revalidateOnMount && storeState.state === "INITIAL" ? (
384
384
  // Optimize rendering on initial state
385
385
  // Do { isPending: true } → result
386
386
  // instead of { isPending: false } → { isPending: true } → result
@@ -404,8 +404,8 @@ const createQuery = (queryFn, options = {}) => {
404
404
  });
405
405
  }, [store]);
406
406
  useIsomorphicLayoutEffect(() => {
407
- if (enabled !== false) revalidate(store, variable, false);
408
- }, [store, enabled]);
407
+ if (revalidateOnMount !== false) revalidate(store, variable, false);
408
+ }, [store, revalidateOnMount]);
409
409
  if (keepPreviousData) {
410
410
  !!trackedState.error;
411
411
  }
@@ -479,19 +479,26 @@ const INITIAL_STATE = {
479
479
  };
480
480
  const createMutation = (mutationFn, options = {}) => {
481
481
  const { onSuccess = noop, onError, onSettled = noop } = options;
482
- const initialState = INITIAL_STATE;
482
+ const initialState = { ...INITIAL_STATE };
483
+ let ongoingPromise;
484
+ const resolveFns = /* @__PURE__ */ new Set([]);
483
485
  const store = initStore(initialState, options);
484
486
  const useStore = () => useStoreState(store.getState(), store.subscribe);
485
487
  const execute = (variable) => {
488
+ let currentResolveFn;
486
489
  const stateBeforeExecute = store.getState();
487
490
  if (stateBeforeExecute.isPending) {
488
491
  console.warn(
489
- "Mutation executed while a previous execution is still pending. This may cause race conditions or unexpected state updates."
492
+ "A mutation was executed while a previous execution is still pending. The previous execution will be ignored (latest execution wins)."
490
493
  );
491
494
  }
492
495
  store.setState({ isPending: true });
493
- return new Promise((resolve) => {
496
+ const promise = new Promise((resolve) => {
497
+ currentResolveFn = resolve;
494
498
  mutationFn(variable, stateBeforeExecute).then((data) => {
499
+ if (promise !== ongoingPromise) {
500
+ return resolve({ data, variable });
501
+ }
495
502
  store.setState({
496
503
  state: "SUCCESS",
497
504
  isPending: false,
@@ -504,8 +511,12 @@ const createMutation = (mutationFn, options = {}) => {
504
511
  errorUpdatedAt: void 0
505
512
  });
506
513
  resolve({ data, variable });
514
+ resolveFns.clear();
507
515
  onSuccess(data, variable, stateBeforeExecute);
508
516
  }).catch((error) => {
517
+ if (promise !== ongoingPromise) {
518
+ return resolve({ error, variable });
519
+ }
509
520
  store.setState({
510
521
  state: "ERROR",
511
522
  isPending: false,
@@ -518,12 +529,19 @@ const createMutation = (mutationFn, options = {}) => {
518
529
  errorUpdatedAt: Date.now()
519
530
  });
520
531
  resolve({ error, variable });
532
+ resolveFns.clear();
521
533
  if (onError) onError(error, variable, stateBeforeExecute);
522
534
  else console.error(store.getState());
523
535
  }).finally(() => {
536
+ if (promise !== ongoingPromise) return;
524
537
  onSettled(variable, stateBeforeExecute);
538
+ ongoingPromise = void 0;
525
539
  });
526
540
  });
541
+ if (ongoingPromise) resolveFns.forEach((resolveFn) => resolveFn(promise));
542
+ resolveFns.add(currentResolveFn);
543
+ ongoingPromise = promise;
544
+ return promise;
527
545
  };
528
546
  return Object.assign(useStore, {
529
547
  subscribe: store.subscribe,
@@ -550,17 +568,17 @@ const createMutation = (mutationFn, options = {}) => {
550
568
  * - `{ error, variable }` on failure
551
569
  *
552
570
  * @remarks
553
- * - If a mutation is already in progress, a warning is logged.
554
- * - Concurrent executions are allowed but may lead to race conditions.
555
571
  * - The promise never rejects to simplify async handling.
572
+ * - If a mutation is already in progress, a warning is logged.
573
+ * - When a new execution starts, all previous pending executions will resolve with the result of the latest execution.
556
574
  */
557
575
  execute,
558
576
  /**
559
577
  * Resets the mutation state back to its initial state.
560
578
  *
561
579
  * @remarks
562
- * - Does not cancel any ongoing request.
563
- * - If a request is still pending, its result may override the reset state.
580
+ * - Does not cancel any ongoing execution.
581
+ * - If an execution is still pending, its result may override the reset state.
564
582
  */
565
583
  reset: () => {
566
584
  if (store.getState().isPending) {
@@ -573,4 +591,107 @@ const createMutation = (mutationFn, options = {}) => {
573
591
  });
574
592
  };
575
593
 
576
- export { createMutation, createQuery, createStore, createStores, useIsomorphicLayoutEffect, useStoreState };
594
+ const useMutation = (mutationFn, options = {}) => {
595
+ const { onSuccess = noop, onError, onSettled = noop } = options;
596
+ const callbackRef = useRef({ onSuccess, onError, onSettled });
597
+ callbackRef.current.onSuccess = onSuccess;
598
+ callbackRef.current.onError = onError;
599
+ callbackRef.current.onSettled = onSettled;
600
+ const stateRef = useRef({ ...INITIAL_STATE });
601
+ const [, reRender] = useState({});
602
+ const refs = useRef({
603
+ mutationFn,
604
+ ongoingPromise: void 0,
605
+ resolveFns: /* @__PURE__ */ new Set()
606
+ });
607
+ refs.current.mutationFn = mutationFn;
608
+ const execute = useCallback((variable) => {
609
+ let currentResolveFn;
610
+ const stateBeforeExecute = stateRef.current;
611
+ if (stateBeforeExecute.isPending) {
612
+ console.warn(
613
+ "A mutation was executed while a previous execution is still pending. The previous execution will be ignored (latest execution wins)."
614
+ );
615
+ }
616
+ stateRef.current.isPending = true;
617
+ reRender({});
618
+ const promise = new Promise(
619
+ (resolve) => {
620
+ currentResolveFn = resolve;
621
+ refs.current.mutationFn(variable, stateBeforeExecute).then((data) => {
622
+ if (promise !== refs.current.ongoingPromise) {
623
+ return resolve({ data, variable });
624
+ }
625
+ stateRef.current = {
626
+ state: "SUCCESS",
627
+ isPending: false,
628
+ isSuccess: true,
629
+ isError: false,
630
+ variable,
631
+ data,
632
+ dataUpdatedAt: Date.now(),
633
+ error: void 0,
634
+ errorUpdatedAt: void 0
635
+ };
636
+ reRender({});
637
+ resolve({ data, variable });
638
+ refs.current.resolveFns.clear();
639
+ callbackRef.current.onSuccess(data, variable, stateBeforeExecute);
640
+ }).catch((error) => {
641
+ if (promise !== refs.current.ongoingPromise) {
642
+ return resolve({ error, variable });
643
+ }
644
+ stateRef.current = {
645
+ state: "ERROR",
646
+ isPending: false,
647
+ isSuccess: false,
648
+ isError: true,
649
+ variable,
650
+ data: void 0,
651
+ dataUpdatedAt: void 0,
652
+ error,
653
+ errorUpdatedAt: Date.now()
654
+ };
655
+ reRender({});
656
+ resolve({ error, variable });
657
+ refs.current.resolveFns.clear();
658
+ if (callbackRef.current.onError) {
659
+ callbackRef.current.onError(error, variable, stateBeforeExecute);
660
+ } else {
661
+ console.error(stateRef.current);
662
+ }
663
+ }).finally(() => {
664
+ if (promise !== refs.current.ongoingPromise) return;
665
+ callbackRef.current.onSettled(variable, stateBeforeExecute);
666
+ refs.current.ongoingPromise = void 0;
667
+ });
668
+ }
669
+ );
670
+ if (refs.current.ongoingPromise) {
671
+ refs.current.resolveFns.forEach((resolveFn) => resolveFn(promise));
672
+ }
673
+ refs.current.resolveFns.add(currentResolveFn);
674
+ refs.current.ongoingPromise = promise;
675
+ return promise;
676
+ }, []);
677
+ const reset = useCallback(() => {
678
+ if (stateRef.current.isPending) {
679
+ console.warn(
680
+ "Mutation state was reset while a request is still pending. The request will continue, but its result may override the reset state."
681
+ );
682
+ }
683
+ stateRef.current = { ...INITIAL_STATE };
684
+ reRender({});
685
+ }, []);
686
+ const r = [
687
+ stateRef.current,
688
+ {
689
+ execute,
690
+ reset,
691
+ getLatestState: () => stateRef.current
692
+ }
693
+ ];
694
+ return r;
695
+ };
696
+
697
+ export { createMutation, createQuery, createStore, createStores, useIsomorphicLayoutEffect, useMutation, useStoreState };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "floppy-disk",
3
3
  "description": "Lightweight, simple, and powerful state management library",
4
4
  "private": false,
5
- "version": "3.0.0-alpha.5",
5
+ "version": "3.0.0-alpha.6",
6
6
  "publishConfig": {
7
7
  "tag": "alpha"
8
8
  },
@@ -14,7 +14,7 @@ import { type InitStoreOptions, type SetState } from 'floppy-disk/vanilla';
14
14
  * - No retry mechanism
15
15
  * - No caching across executions
16
16
  */
17
- export type MutationState<TData, TVariable> = {
17
+ export type MutationState<TData, TVariable, TError> = {
18
18
  isPending: boolean;
19
19
  } & ({
20
20
  state: 'INITIAL';
@@ -41,28 +41,42 @@ export type MutationState<TData, TVariable> = {
41
41
  variable: TVariable;
42
42
  data: undefined;
43
43
  dataUpdatedAt: undefined;
44
- error: any;
44
+ error: TError;
45
45
  errorUpdatedAt: number;
46
46
  });
47
+ export declare const INITIAL_STATE: {
48
+ state: string;
49
+ isPending: boolean;
50
+ isSuccess: boolean;
51
+ isError: boolean;
52
+ variable: undefined;
53
+ data: undefined;
54
+ dataUpdatedAt: undefined;
55
+ error: undefined;
56
+ errorUpdatedAt: undefined;
57
+ };
47
58
  /**
48
59
  * Configuration options for a mutation.
49
60
  *
50
61
  * @remarks
51
62
  * Lifecycle callbacks are triggered for each execution.
52
63
  */
53
- export type MutationOptions<TData, TVariable> = InitStoreOptions<MutationState<TData, TVariable>> & {
64
+ export type MutationOptions<TData, TVariable, TError = Error> = InitStoreOptions<MutationState<TData, TVariable, TError>> & {
54
65
  /**
55
- * Called when the mutation succeeds.
66
+ * Called when the mutation succeeds.\
67
+ * If multiple concurrent executions happened, only the latest execution triggers this callback.
56
68
  */
57
- onSuccess?: (data: TData, variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable>) => void;
69
+ onSuccess?: (data: TData, variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable, TError>) => void;
58
70
  /**
59
- * Called when the mutation fails.
71
+ * Called when the mutation fails.\
72
+ * If multiple concurrent executions happened, only the latest execution triggers this callback.
60
73
  */
61
- onError?: (error: any, variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable>) => void;
74
+ onError?: (error: TError, variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable, TError>) => void;
62
75
  /**
63
- * Called after the mutation settles (either success or error).
76
+ * Called after the mutation settles (either success or error).\
77
+ * If multiple concurrent executions happened, only the latest execution triggers this callback.
64
78
  */
65
- onSettled?: (variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable>) => void;
79
+ onSettled?: (variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable, TError>) => void;
66
80
  };
67
81
  /**
68
82
  * Creates a mutation store for handling async operations that modify data.
@@ -78,8 +92,10 @@ export type MutationOptions<TData, TVariable> = InitStoreOptions<MutationState<T
78
92
  * - Mutations are **not cached** and only track the latest execution.
79
93
  * - Designed for operations that change data (e.g. create, update, delete).
80
94
  * - No retry mechanism is provided by default.
81
- * - Each execution overwrites the previous state.
82
95
  * - The mutation always resolves (never throws): the result contains either `data` or `error`.
96
+ * - If multiple executions triggered at the same time:
97
+ * - Only the latest execution is allowed to update the state.
98
+ * - Results from previous executions are ignored if a newer one exists.
83
99
  *
84
100
  * @example
85
101
  * const useCreateUser = createMutation(async (input) => {
@@ -89,10 +105,10 @@ export type MutationOptions<TData, TVariable> = InitStoreOptions<MutationState<T
89
105
  * const { isPending } = useCreateUser();
90
106
  * const result = await useCreateUser.execute({ name: 'John' });
91
107
  */
92
- export declare const createMutation: <TData, TVariable = undefined>(mutationFn: (variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable>) => Promise<TData>, options?: MutationOptions<TData, TVariable>) => (() => MutationState<TData, TVariable>) & {
93
- subscribe: (subscriber: import("../vanilla.ts").Subscriber<MutationState<TData, TVariable>>) => () => void;
94
- getSubscribers: () => Set<import("../vanilla.ts").Subscriber<MutationState<TData, TVariable>>>;
95
- getState: () => MutationState<TData, TVariable>;
108
+ export declare const createMutation: <TData, TVariable = undefined, TError = Error>(mutationFn: (variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable, TError>) => Promise<TData>, options?: MutationOptions<TData, TVariable, TError>) => (() => MutationState<TData, TVariable, TError>) & {
109
+ subscribe: (subscriber: import("../vanilla.ts").Subscriber<MutationState<TData, TVariable, TError>>) => () => void;
110
+ getSubscribers: () => Set<import("../vanilla.ts").Subscriber<MutationState<TData, TVariable, TError>>>;
111
+ getState: () => MutationState<TData, TVariable, TError>;
96
112
  /**
97
113
  * Manually updates the mutation state.
98
114
  *
@@ -100,7 +116,7 @@ export declare const createMutation: <TData, TVariable = undefined>(mutationFn:
100
116
  * - Intended for advanced use cases.
101
117
  * - Prefer using provided mutation actions (`execute`, `reset`) instead.
102
118
  */
103
- setState: (value: SetState<MutationState<TData, TVariable>>) => void;
119
+ setState: (value: SetState<MutationState<TData, TVariable, TError>>) => void;
104
120
  /**
105
121
  * Executes the mutation.
106
122
  *
@@ -111,25 +127,25 @@ export declare const createMutation: <TData, TVariable = undefined>(mutationFn:
111
127
  * - `{ error, variable }` on failure
112
128
  *
113
129
  * @remarks
114
- * - If a mutation is already in progress, a warning is logged.
115
- * - Concurrent executions are allowed but may lead to race conditions.
116
130
  * - The promise never rejects to simplify async handling.
131
+ * - If a mutation is already in progress, a warning is logged.
132
+ * - When a new execution starts, all previous pending executions will resolve with the result of the latest execution.
117
133
  */
118
134
  execute: TVariable extends undefined ? () => Promise<{
119
135
  variable: undefined;
120
136
  data?: TData;
121
- error?: any;
137
+ error?: TError;
122
138
  }> : (variable: TVariable) => Promise<{
123
139
  variable: TVariable;
124
140
  data?: TData;
125
- error?: any;
141
+ error?: TError;
126
142
  }>;
127
143
  /**
128
144
  * Resets the mutation state back to its initial state.
129
145
  *
130
146
  * @remarks
131
- * - Does not cancel any ongoing request.
132
- * - If a request is still pending, its result may override the reset state.
147
+ * - Does not cancel any ongoing execution.
148
+ * - If an execution is still pending, its result may override the reset state.
133
149
  */
134
150
  reset: () => void;
135
151
  };
@@ -19,7 +19,7 @@ import { type InitStoreOptions, type SetState } from 'floppy-disk/vanilla';
19
19
  * @remarks
20
20
  * - Data and error are mutually exclusive except in `SUCCESS_BUT_REVALIDATION_ERROR`.
21
21
  */
22
- export type QueryState<TData> = {
22
+ export type QueryState<TData, TError> = {
23
23
  isPending: boolean;
24
24
  isRevalidating: boolean;
25
25
  isRetrying: boolean;
@@ -46,7 +46,7 @@ export type QueryState<TData> = {
46
46
  isError: true;
47
47
  data: undefined;
48
48
  dataUpdatedAt: undefined;
49
- error: any;
49
+ error: TError;
50
50
  errorUpdatedAt: number;
51
51
  } | {
52
52
  state: 'SUCCESS_BUT_REVALIDATION_ERROR';
@@ -54,7 +54,7 @@ export type QueryState<TData> = {
54
54
  isError: false;
55
55
  data: TData;
56
56
  dataUpdatedAt: number;
57
- error: any;
57
+ error: TError;
58
58
  errorUpdatedAt: number;
59
59
  });
60
60
  /**
@@ -63,7 +63,7 @@ export type QueryState<TData> = {
63
63
  * @remarks
64
64
  * Controls caching, retry behavior, lifecycle, and side effects of an async operation.
65
65
  */
66
- export type QueryOptions<TData, TVariable extends Record<string, any>> = InitStoreOptions<QueryState<TData>> & {
66
+ export type QueryOptions<TData, TVariable extends Record<string, any>, TError = Error> = InitStoreOptions<QueryState<TData, TError>> & {
67
67
  /**
68
68
  * Time (in milliseconds) that data is considered fresh.
69
69
  *
@@ -95,15 +95,15 @@ export type QueryOptions<TData, TVariable extends Record<string, any>> = InitSto
95
95
  /**
96
96
  * Called when the query succeeds.
97
97
  */
98
- onSuccess?: (data: TData, variable: TVariable, stateBeforeExecute: QueryState<TData>) => void;
98
+ onSuccess?: (data: TData, variable: TVariable, stateBeforeExecute: QueryState<TData, TError>) => void;
99
99
  /**
100
100
  * Called when the query fails and will not retry.
101
101
  */
102
- onError?: (error: any, variable: TVariable, stateBeforeExecute: QueryState<TData>) => void;
102
+ onError?: (error: TError, variable: TVariable, stateBeforeExecute: QueryState<TData, TError>) => void;
103
103
  /**
104
104
  * Called after the query settles (success or final failure).
105
105
  */
106
- onSettled?: (variable: TVariable, stateBeforeExecute: QueryState<TData>) => void;
106
+ onSettled?: (variable: TVariable, stateBeforeExecute: QueryState<TData, TError>) => void;
107
107
  /**
108
108
  * Determines whether a failed query should retry.
109
109
  *
@@ -120,7 +120,7 @@ export type QueryOptions<TData, TVariable extends Record<string, any>> = InitSto
120
120
  * return [false];
121
121
  * }
122
122
  */
123
- shouldRetry?: (error: any, currentState: QueryState<TData>) => [true, number] | [false];
123
+ shouldRetry?: (error: TError, currentState: QueryState<TData, TError>) => [true, number] | [false];
124
124
  };
125
125
  /**
126
126
  * Creates a query factory for managing cached async operations.
@@ -157,13 +157,15 @@ export type QueryOptions<TData, TVariable extends Record<string, any>> = InitSto
157
157
  * // ...
158
158
  * }
159
159
  */
160
- export declare const createQuery: <TData, TVariable extends Record<string, any> = never>(queryFn: (variable: TVariable, currentState: QueryState<TData>) => Promise<TData>, options?: QueryOptions<TData, TVariable>) => ((variable?: TVariable) => ((options?: {
160
+ export declare const createQuery: <TData, TVariable extends Record<string, any> = never, TError = Error>(queryFn: (variable: TVariable, currentState: QueryState<TData, TError>) => Promise<TData>, options?: QueryOptions<TData, TVariable, TError>) => ((variable?: TVariable) => ((options?: {
161
161
  /**
162
- * Whether the query should execute automatically on mount.
162
+ * Whether the query should be ravalidated automatically on mount.
163
+ *
164
+ * Revalidate means execute the queryFn **if stale/invalidated**.
163
165
  *
164
166
  * @default true
165
167
  */
166
- enabled?: boolean;
168
+ revalidateOnMount?: boolean;
167
169
  /**
168
170
  * Whether to keep previous successful data while a new variable is loading.
169
171
  *
@@ -180,13 +182,13 @@ export declare const createQuery: <TData, TVariable extends Record<string, any>
180
182
  * // While loading userId=2, still show userId=1 data
181
183
  * useQuery({ id: userId }, { keepPreviousData: true });
182
184
  */ keepPreviousData?: boolean;
183
- }) => QueryState<TData>) & {
185
+ }) => QueryState<TData, TError>) & {
184
186
  metadata: {
185
187
  isInvalidated?: boolean;
186
- promise?: Promise<QueryState<TData>> | undefined;
187
- promiseResolver?: ((value: QueryState<TData> | PromiseLike<QueryState<TData>>) => void) | undefined;
188
+ promise?: Promise<QueryState<TData, TError>> | undefined;
189
+ promiseResolver?: ((value: QueryState<TData, TError> | PromiseLike<QueryState<TData, TError>>) => void) | undefined;
188
190
  retryTimeoutId?: number;
189
- retryResolver?: ((value: QueryState<TData> | PromiseLike<QueryState<TData>>) => void) | undefined;
191
+ retryResolver?: ((value: QueryState<TData, TError> | PromiseLike<QueryState<TData, TError>>) => void) | undefined;
190
192
  garbageCollectionTimeoutId?: number;
191
193
  rollbackData?: TData | undefined;
192
194
  };
@@ -222,7 +224,7 @@ export declare const createQuery: <TData, TVariable extends Record<string, any>
222
224
  */
223
225
  execute: (options?: {
224
226
  overwriteOngoingExecution?: boolean;
225
- }) => Promise<QueryState<TData>>;
227
+ }) => Promise<QueryState<TData, TError>>;
226
228
  /**
227
229
  * Re-executes the query if needed based on freshness or invalidation.
228
230
  *
@@ -238,7 +240,7 @@ export declare const createQuery: <TData, TVariable extends Record<string, any>
238
240
  */
239
241
  revalidate: (options?: {
240
242
  overwriteOngoingExecution?: boolean;
241
- }) => Promise<QueryState<TData>>;
243
+ }) => Promise<QueryState<TData, TError>>;
242
244
  /**
243
245
  * Marks the query as invalidated and optionally triggers re-execution.
244
246
  *
@@ -290,7 +292,7 @@ export declare const createQuery: <TData, TVariable extends Record<string, any>
290
292
  * const { rollback, revalidate } = query.optimisticUpdate(newData);
291
293
  */
292
294
  optimisticUpdate: (data: TData) => {
293
- revalidate: () => Promise<QueryState<TData>>;
295
+ revalidate: () => Promise<QueryState<TData, TError>>;
294
296
  rollback: () => TData;
295
297
  };
296
298
  /**
@@ -302,10 +304,10 @@ export declare const createQuery: <TData, TVariable extends Record<string, any>
302
304
  * - Should be used if an optimistic update fails.
303
305
  */
304
306
  rollbackOptimisticUpdate: () => TData;
305
- subscribe: (subscriber: import("../vanilla.ts").Subscriber<QueryState<TData>>) => () => void;
306
- getSubscribers: () => Set<import("../vanilla.ts").Subscriber<QueryState<TData>>>;
307
- getState: () => QueryState<TData>;
308
- setState: (value: SetState<QueryState<TData>>) => void;
307
+ subscribe: (subscriber: import("../vanilla.ts").Subscriber<QueryState<TData, TError>>) => () => void;
308
+ getSubscribers: () => Set<import("../vanilla.ts").Subscriber<QueryState<TData, TError>>>;
309
+ getState: () => QueryState<TData, TError>;
310
+ setState: (value: SetState<QueryState<TData, TError>>) => void;
309
311
  }) & {
310
312
  /**
311
313
  * Executes all query instances.