floppy-disk 3.0.0-experimental.1 → 3.0.1

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.
Files changed (76) hide show
  1. package/README.md +256 -676
  2. package/esm/index.d.mts +1 -0
  3. package/esm/index.mjs +1 -0
  4. package/esm/react/create-mutation.d.mts +151 -0
  5. package/esm/react/create-query.d.mts +344 -0
  6. package/esm/react/create-store.d.mts +28 -0
  7. package/esm/react/create-stores.d.mts +39 -0
  8. package/esm/react/use-isomorphic-layout-effect.d.mts +6 -0
  9. package/esm/react/use-mutation.d.mts +82 -0
  10. package/esm/react/use-store.d.mts +28 -0
  11. package/esm/react.d.mts +7 -0
  12. package/esm/react.mjs +697 -0
  13. package/esm/vanilla/basic.d.mts +13 -0
  14. package/esm/vanilla/hash.d.mts +7 -0
  15. package/esm/vanilla/store.d.mts +89 -0
  16. package/esm/vanilla.d.mts +3 -0
  17. package/esm/vanilla.mjs +82 -0
  18. package/index.d.ts +1 -0
  19. package/index.js +12 -0
  20. package/package.json +47 -45
  21. package/react/create-mutation.d.ts +151 -0
  22. package/react/create-query.d.ts +344 -0
  23. package/react/create-store.d.ts +28 -0
  24. package/react/create-stores.d.ts +39 -0
  25. package/react/use-isomorphic-layout-effect.d.ts +6 -0
  26. package/react/use-mutation.d.ts +82 -0
  27. package/react/use-store.d.ts +28 -0
  28. package/react.d.ts +7 -0
  29. package/react.js +705 -0
  30. package/ts_version_4.5_and_above_is_required.d.ts +0 -0
  31. package/vanilla/basic.d.ts +13 -0
  32. package/vanilla/hash.d.ts +7 -0
  33. package/vanilla/store.d.ts +89 -0
  34. package/vanilla.d.ts +3 -0
  35. package/vanilla.js +89 -0
  36. package/esm/index.d.ts +0 -8
  37. package/esm/index.js +0 -8
  38. package/esm/react/create-bi-direction-query.d.ts +0 -166
  39. package/esm/react/create-bi-direction-query.js +0 -74
  40. package/esm/react/create-mutation.d.ts +0 -39
  41. package/esm/react/create-mutation.js +0 -56
  42. package/esm/react/create-query.d.ts +0 -319
  43. package/esm/react/create-query.js +0 -434
  44. package/esm/react/create-store.d.ts +0 -38
  45. package/esm/react/create-store.js +0 -38
  46. package/esm/react/create-stores.d.ts +0 -61
  47. package/esm/react/create-stores.js +0 -99
  48. package/esm/react/with-context.d.ts +0 -5
  49. package/esm/react/with-context.js +0 -14
  50. package/esm/utils.d.ts +0 -24
  51. package/esm/utils.js +0 -31
  52. package/esm/vanilla/fetcher.d.ts +0 -27
  53. package/esm/vanilla/fetcher.js +0 -95
  54. package/esm/vanilla/init-store.d.ts +0 -24
  55. package/esm/vanilla/init-store.js +0 -51
  56. package/lib/index.d.ts +0 -8
  57. package/lib/index.js +0 -11
  58. package/lib/react/create-bi-direction-query.d.ts +0 -166
  59. package/lib/react/create-bi-direction-query.js +0 -78
  60. package/lib/react/create-mutation.d.ts +0 -39
  61. package/lib/react/create-mutation.js +0 -60
  62. package/lib/react/create-query.d.ts +0 -319
  63. package/lib/react/create-query.js +0 -438
  64. package/lib/react/create-store.d.ts +0 -38
  65. package/lib/react/create-store.js +0 -42
  66. package/lib/react/create-stores.d.ts +0 -61
  67. package/lib/react/create-stores.js +0 -104
  68. package/lib/react/with-context.d.ts +0 -5
  69. package/lib/react/with-context.js +0 -18
  70. package/lib/utils.d.ts +0 -24
  71. package/lib/utils.js +0 -39
  72. package/lib/vanilla/fetcher.d.ts +0 -27
  73. package/lib/vanilla/fetcher.js +0 -99
  74. package/lib/vanilla/init-store.d.ts +0 -24
  75. package/lib/vanilla/init-store.js +0 -55
  76. package/utils/package.json +0 -6
@@ -0,0 +1,344 @@
1
+ import { type InitStoreOptions, type SetState } from 'floppy-disk/vanilla';
2
+ /**
3
+ * Represents the state of a query.
4
+ *
5
+ * @remarks
6
+ * A query manages cached results of an async operation with lifecycle awareness.
7
+ *
8
+ * State variants:
9
+ * - `INITIAL` → no execution has occurred yet
10
+ * - `SUCCESS` → execution completed successfully
11
+ * - `ERROR` → initial execution failed (no data available)
12
+ * - `SUCCESS_BUT_REVALIDATION_ERROR` → data exists, but a revalidation failed
13
+ *
14
+ * Flags:
15
+ * - `isPending` → an execution is currently in progress
16
+ * - `isRevalidating` → re-executing while already having data
17
+ * - `isRetrying` → retrying after a failure
18
+ *
19
+ * @remarks
20
+ * - Data and error are mutually exclusive except in `SUCCESS_BUT_REVALIDATION_ERROR`.
21
+ */
22
+ export type QueryState<TData, TError> = {
23
+ isPending: boolean;
24
+ isRevalidating: boolean;
25
+ isRetrying: boolean;
26
+ retryCount: number;
27
+ } & ({
28
+ state: 'INITIAL';
29
+ isSuccess: false;
30
+ isError: false;
31
+ data: undefined;
32
+ dataUpdatedAt: undefined;
33
+ error: undefined;
34
+ errorUpdatedAt: undefined;
35
+ } | {
36
+ state: 'SUCCESS';
37
+ isSuccess: true;
38
+ isError: false;
39
+ data: TData;
40
+ dataUpdatedAt: number;
41
+ error: undefined;
42
+ errorUpdatedAt: undefined;
43
+ } | {
44
+ state: 'ERROR';
45
+ isSuccess: false;
46
+ isError: true;
47
+ data: undefined;
48
+ dataUpdatedAt: undefined;
49
+ error: TError;
50
+ errorUpdatedAt: number;
51
+ } | {
52
+ state: 'SUCCESS_BUT_REVALIDATION_ERROR';
53
+ isSuccess: true;
54
+ isError: false;
55
+ data: TData;
56
+ dataUpdatedAt: number;
57
+ error: TError;
58
+ errorUpdatedAt: number;
59
+ });
60
+ /**
61
+ * Configuration options for a query.
62
+ *
63
+ * @remarks
64
+ * Controls caching, retry behavior, lifecycle, and side effects of an async operation.
65
+ */
66
+ export type QueryOptions<TData, TVariable extends Record<string, any>, TError = Error> = InitStoreOptions<QueryState<TData, TError>> & {
67
+ /**
68
+ * Time (in milliseconds) that data is considered fresh.
69
+ *
70
+ * While fresh, revalidation will be skipped unless explicitly invalidated.
71
+ *
72
+ * @default 2500 ms (2.5 seconds)
73
+ */
74
+ staleTime?: number;
75
+ /**
76
+ * Time (in milliseconds) before unused queries are garbage collected.
77
+ *
78
+ * Starts counting after the last subscriber unsubscribes.
79
+ *
80
+ * @default 5 minutes
81
+ */
82
+ gcTime?: number;
83
+ /**
84
+ * Whether to revalidate when the window gains focus.
85
+ *
86
+ * @default true
87
+ */
88
+ revalidateOnFocus?: boolean;
89
+ /**
90
+ * Whether to revalidate when the network reconnects.
91
+ *
92
+ * @default true
93
+ */
94
+ revalidateOnReconnect?: boolean;
95
+ /**
96
+ * Called when the query succeeds.
97
+ */
98
+ onSuccess?: (data: TData, variable: TVariable, stateBeforeExecute: QueryState<TData, TError>) => void;
99
+ /**
100
+ * Called when the query fails and will not retry.
101
+ */
102
+ onError?: (error: TError, variable: TVariable, stateBeforeExecute: QueryState<TData, TError>) => void;
103
+ /**
104
+ * Called after the query settles (success or final failure).
105
+ */
106
+ onSettled?: (variable: TVariable, stateBeforeExecute: QueryState<TData, TError>) => void;
107
+ /**
108
+ * Determines whether a failed query should retry.
109
+ *
110
+ * @returns
111
+ * - `[true, delay]` to retry after `delay` milliseconds
112
+ * - `[false]` to stop retrying
113
+ *
114
+ * @default Retries once after 1500ms
115
+ *
116
+ * @example
117
+ * shouldRetry: (error, state) => {
118
+ * if (error?.status === 401 || error?.code === 'UNAUTHORIZED') return [false];
119
+ * if (state.retryCount < 3) return [true, 1000 * 2 ** state.retryCount];
120
+ * return [false];
121
+ * }
122
+ */
123
+ shouldRetry?: (error: TError, currentState: QueryState<TData, TError>) => [true, number] | [false];
124
+ };
125
+ /**
126
+ * Creates a query factory for managing cached async operations.
127
+ *
128
+ * @param queryFn - Async function to resolve data
129
+ * @param options - Optional configuration for caching, retry, and lifecycle
130
+ *
131
+ * @returns A function to retrieve or create a query instance by variable
132
+ *
133
+ * @remarks
134
+ * - Queries are **keyed by variable** (via deterministic hashing).
135
+ * - Each unique variable maps to its own store instance.
136
+ *
137
+ * Core features:
138
+ * - Caching via `staleTime`
139
+ * - Explicit invalidation (independent of freshness)
140
+ * - Retry logic via `shouldRetry`
141
+ * - Background revalidation (focus / reconnect)
142
+ * - Garbage collection via `gcTime`
143
+ *
144
+ * Execution behavior:
145
+ * - By default, executions **overwrite ongoing executions**
146
+ * - Set `overwriteOngoingExecution: false` to enable deduplication
147
+ * - Internal revalidation (focus/reconnect) uses deduplication by default
148
+ *
149
+ * @example
150
+ * const userQuery = createQuery<UserDetail, { id: string }>(async ({ id }) => {
151
+ * return api.getUser(id);
152
+ * });
153
+ *
154
+ * function MyComponent({ id }: { id: string }) {
155
+ * const useUserQuery = userQuery({ id });
156
+ * const state = useUserQuery();
157
+ * // ...
158
+ * }
159
+ */
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
+ /**
162
+ * Whether the query should be ravalidated automatically on mount.
163
+ *
164
+ * Revalidate means execute the queryFn **if stale/invalidated**.
165
+ *
166
+ * @default true
167
+ */
168
+ revalidateOnMount?: boolean;
169
+ /**
170
+ * Whether to keep previous successful data while a new variable is loading.
171
+ *
172
+ * @remarks
173
+ * - Only applies when the query is in the `INITIAL` state (no data & no error).
174
+ * - Intended for variable changes:
175
+ * when switching from one variable to another, the previous data is temporarily shown
176
+ * while the new execution is in progress.
177
+ * - Once the new execution resolves (success or error), the previous data is no longer used.
178
+ * - Prevents UI flicker (e.g. empty/loading state) during transitions.
179
+ *
180
+ * @example
181
+ * // Switching from userId=1 → userId=2
182
+ * // While loading userId=2, still show userId=1 data
183
+ * useQuery({ id: userId }, { keepPreviousData: true });
184
+ */ keepPreviousData?: boolean;
185
+ }) => QueryState<TData, TError>) & {
186
+ metadata: {
187
+ isInvalidated?: boolean;
188
+ promise?: Promise<QueryState<TData, TError>> | undefined;
189
+ promiseResolver?: ((value: QueryState<TData, TError> | PromiseLike<QueryState<TData, TError>>) => void) | undefined;
190
+ retryTimeoutId?: number;
191
+ retryResolver?: ((value: QueryState<TData, TError> | PromiseLike<QueryState<TData, TError>>) => void) | undefined;
192
+ garbageCollectionTimeoutId?: number;
193
+ rollbackData?: TData | undefined;
194
+ };
195
+ /**
196
+ * Sets initial data for the query if it has not been initialized.
197
+ *
198
+ * @param data - Initial data
199
+ * @param revalidate - Whether to mark the data as invalidated (will trigger revalidation)
200
+ *
201
+ * @returns `true` if the data was set, `false` otherwise
202
+ *
203
+ * @remarks
204
+ * - Only applies when the query is in the `INITIAL` state.
205
+ * - Useful for hydration or preloaded data.
206
+ */
207
+ setInitialData: (data: TData, revalidate?: boolean) => boolean;
208
+ /**
209
+ * Executes the query function.
210
+ *
211
+ * @param options - Execution options
212
+ * @param options.overwriteOngoingExecution - Whether to start a new execution instead of reusing an ongoing one (default: `true`)
213
+ *
214
+ * @returns A promise resolving to the latest query state
215
+ *
216
+ * @remarks
217
+ * - By default, each call **starts a new execution** even if one is already in progress.
218
+ * - Set `overwriteOngoingExecution: false` to reuse an ongoing execution (deduplication).
219
+ * - Handles:
220
+ * - Pending state
221
+ * - Success state
222
+ * - Error state
223
+ * - Retry logic
224
+ */
225
+ execute: (options?: {
226
+ overwriteOngoingExecution?: boolean;
227
+ }) => Promise<QueryState<TData, TError>>;
228
+ /**
229
+ * Re-executes the query if needed based on freshness or invalidation.
230
+ *
231
+ * @param options - Revalidation options
232
+ * @param options.overwriteOngoingExecution - Whether to overwrite an ongoing execution (default: `true`)
233
+ *
234
+ * @returns The current state if still fresh, otherwise a promise of the new state
235
+ *
236
+ * @remarks
237
+ * - Skips execution if data is still fresh (`staleTime`) **AND** the query has not been invalidated.
238
+ * - If execution is not skipped, by default it will start a new execution even if one is already in progress.
239
+ * - Set `overwriteOngoingExecution: false` to reuse an ongoing execution (deduplication).
240
+ */
241
+ revalidate: (options?: {
242
+ overwriteOngoingExecution?: boolean;
243
+ }) => Promise<QueryState<TData, TError>>;
244
+ /**
245
+ * Marks the query as invalidated and optionally triggers re-execution.
246
+ *
247
+ * @param options - Invalidation options
248
+ * @param options.overwriteOngoingExecution - Whether to overwrite an ongoing execution (default: `true`)
249
+ *
250
+ * @returns `true` if execution was triggered, `false` otherwise
251
+ *
252
+ * @remarks
253
+ * - Invalidated queries are treated as stale regardless of `staleTime`.
254
+ * - The next `revalidate` will always execute until a successful result clears the invalidation.
255
+ * - If there are active subscribers: Execution is triggered immediately.
256
+ * - Otherwise: The query remains invalidated and will execute on the next revalidation.
257
+ * - By default, starts a new execution even if one is already in progress.
258
+ * - Set `overwriteOngoingExecution: false` to reuse an ongoing execution (deduplication).
259
+ */
260
+ invalidate: (options?: {
261
+ overwriteOngoingExecution?: boolean;
262
+ }) => boolean;
263
+ /**
264
+ * Resets the query state to its initial state.
265
+ *
266
+ * @remarks
267
+ * - Cancels retry logic and ignores any ongoing execution results.
268
+ */
269
+ reset: () => void;
270
+ /**
271
+ * Deletes the query store for the current variable.
272
+ *
273
+ * @returns `true` if deleted, `false` otherwise
274
+ *
275
+ * @remarks
276
+ * - Cannot delete while there are active subscribers.
277
+ */
278
+ delete: () => boolean;
279
+ /**
280
+ * Performs an optimistic update on the query data.
281
+ *
282
+ * @param data - Optimistic data to set
283
+ *
284
+ * @returns Controls for managing the optimistic update
285
+ *
286
+ * @remarks
287
+ * - Temporarily replaces the current data.
288
+ * - Stores previous data for rollback.
289
+ * - Commonly used with mutations for instant UI updates.
290
+ *
291
+ * @example
292
+ * const { rollback, revalidate } = query.optimisticUpdate(newData);
293
+ */
294
+ optimisticUpdate: (data: TData) => {
295
+ revalidate: () => Promise<QueryState<TData, TError>>;
296
+ rollback: () => TData;
297
+ };
298
+ /**
299
+ * Restores the data before the last optimistic update.
300
+ *
301
+ * @returns The restored data
302
+ *
303
+ * @remarks
304
+ * - Should be used if an optimistic update fails.
305
+ */
306
+ rollbackOptimisticUpdate: () => TData;
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;
311
+ }) & {
312
+ /**
313
+ * Executes all query instances.
314
+ *
315
+ * @remarks
316
+ * - Useful for bulk refetching.
317
+ */
318
+ executeAll: (options?: {
319
+ overwriteOngoingExecution?: boolean;
320
+ }) => void;
321
+ /**
322
+ * Revalidates all query instances.
323
+ *
324
+ * @remarks
325
+ * - Only re-fetches stale queries.
326
+ */
327
+ revalidateAll: (options?: {
328
+ overwriteOngoingExecution?: boolean;
329
+ }) => void;
330
+ /**
331
+ * Invalidates all query instances.
332
+ *
333
+ * @remarks
334
+ * - Marks all queries as invalidated and triggers revalidation if active.
335
+ * - Invalidated queries bypass `staleTime` until successfully executed again.
336
+ */
337
+ invalidateAll: (options?: {
338
+ overwriteOngoingExecution?: boolean;
339
+ }) => void;
340
+ /**
341
+ * Resets all query instances.
342
+ */
343
+ resetAll: () => void;
344
+ };
@@ -0,0 +1,28 @@
1
+ import { type InitStoreOptions } from 'floppy-disk/vanilla';
2
+ /**
3
+ * Creates a single store with a bound React hook.
4
+ *
5
+ * @param initialState - The initial state of the store
6
+ * @param options - Optional lifecycle hooks
7
+ *
8
+ * @returns A function that acts as both:
9
+ * - A React hook for subscribing to the store
10
+ * - The store API (getState, setState, subscribe, etc.)
11
+ *
12
+ * @remarks
13
+ * - Combines the vanilla store with React integration.
14
+ * - The returned function can be used directly as a hook.
15
+ * - The hook uses Proxy-based tracking to automatically detect which state fields are used.
16
+ * - Components will only re-render when the accessed values change.
17
+ *
18
+ * @example
19
+ * const useMyStore = createStore({ foo: 1, bar: 2 });
20
+ *
21
+ * function Component() {
22
+ * const state = useMyStore();
23
+ * return <div>{state.foo}</div>;
24
+ * }
25
+ *
26
+ * useMyStore.setState({ foo: 2 }); // only components using foo will re-render
27
+ */
28
+ export declare const createStore: <TState extends Record<string, any>>(initialState: TState, options?: InitStoreOptions<TState>) => (() => TState) & import("../vanilla.ts").StoreApi<TState>;
@@ -0,0 +1,39 @@
1
+ import { type InitStoreOptions } from 'floppy-disk/vanilla';
2
+ /**
3
+ * Creates a factory for multiple stores identified by a key.
4
+ *
5
+ * @param initialState - The initial state for each store instance
6
+ * @param options - Optional lifecycle hooks
7
+ *
8
+ * @returns A function to retrieve or create a store by key
9
+ *
10
+ * @remarks
11
+ * - Each unique key maps to a separate store instance.
12
+ * - Keys are deterministically hashed, ensuring stable identity.
13
+ * - Stores are lazily created and cached.
14
+ * - Each store has its own state, subscribers, and lifecycle.
15
+ * - Each returned store includes:
16
+ * - React hook (with Proxy-based tracking)
17
+ * - Store API methods
18
+ * - `delete()` for manual cleanup
19
+ * - Useful for scenarios like:
20
+ * - Query caches
21
+ * - Entity-based state
22
+ * - Dynamic instances
23
+ *
24
+ * @example
25
+ * const userStore = createStores<{ name: string }, { id: number }>({ name: '' });
26
+ *
27
+ * function Component() {
28
+ * const useUserStore = userStore({ id: 1 });
29
+ * const state = useUserStore();
30
+ * return <div>{state.name}</div>;
31
+ * }
32
+ */
33
+ export declare const createStores: <TState extends Record<string, any>, TKey extends Record<string, any>>(initialState: TState, options?: InitStoreOptions<TState>) => (key?: TKey) => (() => TState) & {
34
+ delete: () => boolean;
35
+ setState: (value: import("../vanilla.ts").SetState<TState>) => void;
36
+ getState: () => TState;
37
+ subscribe: (subscriber: import("../vanilla.ts").Subscriber<TState>) => () => void;
38
+ getSubscribers: () => Set<import("../vanilla.ts").Subscriber<TState>>;
39
+ };
@@ -0,0 +1,6 @@
1
+ import { useLayoutEffect } from 'react';
2
+ /**
3
+ * Does exactly same as `useLayoutEffect`.\
4
+ * It will use `useEffect` in **server-side** to prevent warning when executed on server-side.
5
+ */
6
+ export declare const useIsomorphicLayoutEffect: typeof useLayoutEffect;
@@ -0,0 +1,82 @@
1
+ import { type MutationOptions, type MutationState } from './create-mutation';
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
+ }];
@@ -0,0 +1,28 @@
1
+ import { type StoreApi } from 'floppy-disk/vanilla';
2
+ type Path = Array<string | number | symbol>;
3
+ export declare const getValueByPath: (obj: any, path: Path) => any;
4
+ export declare const isPrefixPath: (candidatePrefix: Path, targetPath: Path) => boolean;
5
+ export declare const compressPaths: (paths: Path[]) => Path[];
6
+ export declare const useStoreStateProxy: <TState extends Record<string, any>>(storeState: TState) => readonly [TState, import("react").RefObject<Path[]>];
7
+ /**
8
+ * React hook for subscribing to a store using automatic dependency tracking.
9
+ *
10
+ * @param store - The store instance to subscribe to
11
+ *
12
+ * @returns A proxied version of the store state
13
+ *
14
+ * @remarks
15
+ * - This hook uses a **Proxy-based tracking mechanism** to detect which parts of the state are accessed during render.
16
+ * - The component will only re-render when the **accessed values actually change**.
17
+ * - State must be treated as **immutable**:
18
+ * - Updates must replace objects rather than mutate them
19
+ * - Otherwise, changes may not be detected
20
+ * - No selector or memoization is needed.
21
+ *
22
+ * @example
23
+ * const state = useStoreState(store);
24
+ * return <div>{state.user.name}</div>;
25
+ * // Component will only re-render if `user.name` changes
26
+ */
27
+ export declare const useStoreState: <TState extends Record<string, any>>(storeState: TState, subscribe: StoreApi<TState>["subscribe"]) => TState;
28
+ export {};
package/react.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export * from './react/use-isomorphic-layout-effect';
2
+ export { useStoreState } from './react/use-store';
3
+ export * from './react/create-store';
4
+ export * from './react/create-stores';
5
+ export * from './react/create-query';
6
+ export { createMutation, type MutationOptions, type MutationState, } from './react/create-mutation';
7
+ export * from './react/use-mutation';