floppy-disk 1.3.0 → 1.4.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -122,6 +122,11 @@ const unsub = useCatStore.subscribe(
122
122
  );
123
123
  ```
124
124
 
125
+ > **Examples:**
126
+ >
127
+ > - [https://codesandbox.io/.../examples/react/basic](https://codesandbox.io/p/sandbox/github/afiiif/floppy-disk/tree/main/examples/react/basic)
128
+ > - [https://codesandbox.io/.../examples/react/custom-reactivity](https://codesandbox.io/p/sandbox/github/afiiif/floppy-disk/tree/main/examples/react/custom-reactivity)
129
+
125
130
  ### Advanced Concept
126
131
 
127
132
  Set the state **silently** (without broadcast the state change to **any subscribers**).
@@ -171,6 +176,11 @@ const useCatStore = createStore(
171
176
  );
172
177
  ```
173
178
 
179
+ > **Examples:**
180
+ >
181
+ > - [https://codesandbox.io/.../examples/react/store-event](https://codesandbox.io/p/sandbox/github/afiiif/floppy-disk/tree/main/examples/react/store-event)
182
+ > - [https://codesandbox.io/.../examples/react/intercept](https://codesandbox.io/p/sandbox/github/afiiif/floppy-disk/tree/main/examples/react/intercept)
183
+
174
184
  Let's go wild using IIFE.
175
185
 
176
186
  ```js
@@ -228,6 +238,10 @@ function CatPageOptimized() {
228
238
  }
229
239
  ```
230
240
 
241
+ > **Examples:**
242
+ >
243
+ > - [https://codesandbox.io/.../examples/react/watch-component](https://codesandbox.io/p/sandbox/github/afiiif/floppy-disk/tree/main/examples/react/watch-component)
244
+
231
245
  Want a local state instead of global state?
232
246
  Or, want to set the initial state inside component?
233
247
 
@@ -94,6 +94,8 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
94
94
  pageParam: any;
95
95
  pageParams: any[];
96
96
  hasNextPage: boolean;
97
+ retryNextPageCount: number;
98
+ isGoingToRetryNextPage: boolean;
97
99
  };
98
100
  export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any, TData = TResponse, TError = unknown> = CreateStoresOptions<TKey, QueryState<TKey, TResponse, TData, TError>> & {
99
101
  select?: (response: TResponse, state: Pick<QueryState<TKey, TResponse, TData, TError>, 'data' | 'key'>) => TData;
@@ -103,12 +105,6 @@ export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any
103
105
  * Defaults to `3000` (3 seconds).
104
106
  */
105
107
  staleTime?: number;
106
- /**
107
- * Number of maximum error retries.
108
- *
109
- * Defaults to `1`.
110
- */
111
- retry?: number | ((error: TError, key: TKey) => number);
112
108
  /**
113
109
  * Auto call the query when the component is mounted.
114
110
  *
@@ -135,6 +131,18 @@ export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any
135
131
  * Defaults to `true`.
136
132
  */
137
133
  enabled?: boolean | ((key: TKey) => boolean);
134
+ /**
135
+ * Number of maximum error retries.
136
+ *
137
+ * Defaults to `1`.
138
+ */
139
+ retry?: number | ((error: TError, key: TKey) => number);
140
+ /**
141
+ * Error retry delay in miliseconds.
142
+ *
143
+ * Defaults to `3000` (3 seconds).
144
+ */
145
+ retryDelay?: number | ((error: TError, key: TKey) => number);
138
146
  /**
139
147
  * If set to `true`, previous `data` will be kept when fetching new data because the query key changed.
140
148
  *
@@ -1,4 +1,4 @@
1
- import { identityFn, noop } from '../utils';
1
+ import { hashStoreKey, identityFn, noop } from '../utils';
2
2
  import { createStores } from './create-stores';
3
3
  const getDecision = (value, param, { ifTrue, ifAlways }) => {
4
4
  if (value === true || (typeof value === 'function' && value(param) === true)) {
@@ -29,6 +29,8 @@ const INITIAL_QUERY_STATE = {
29
29
  pageParam: undefined,
30
30
  pageParams: [undefined],
31
31
  hasNextPage: false,
32
+ retryNextPageCount: 0,
33
+ isGoingToRetryNextPage: false,
32
34
  };
33
35
  const useQueryDefaultDeps = (state) => [
34
36
  state.data,
@@ -37,14 +39,22 @@ const useQueryDefaultDeps = (state) => [
37
39
  state.hasNextPage,
38
40
  ];
39
41
  export const createQuery = (queryFn, options = {}) => {
40
- const { onFirstSubscribe = noop, onSubscribe = noop, onLastUnsubscribe = noop, onBeforeChangeKey = noop, defaultDeps = useQueryDefaultDeps, select = identityFn, staleTime = DEFAULT_STALE_TIME, retry = 1, fetchOnMount = true, fetchOnWindowFocus = true, enabled = true, keepPreviousData, getNextPageParam = () => undefined, onSuccess = noop, onError = noop, onSettled = noop, ...createStoresOptions } = options;
42
+ const { onFirstSubscribe = noop, onSubscribe = noop, onLastUnsubscribe = noop, onBeforeChangeKey = noop, defaultDeps = useQueryDefaultDeps, select = identityFn, staleTime = DEFAULT_STALE_TIME, fetchOnMount = true, fetchOnWindowFocus = true, enabled = true, retry = 1, retryDelay = 3000, keepPreviousData, getNextPageParam = () => undefined, onSuccess = noop, onError = noop, onSettled = noop, hashKeyFn = hashStoreKey, ...createStoresOptions } = options;
43
+ const retryTimeoutId = new Map();
44
+ const retryNextPageTimeoutId = new Map();
41
45
  const useQuery = createStores(({ key: _key, get, set }) => {
42
46
  const key = _key;
47
+ const getRetryProps = (error, retryCount) => {
48
+ const maxRetryCount = (typeof retry === 'function' ? retry(error, key) : retry) || 0;
49
+ const shouldRetry = retryCount < maxRetryCount;
50
+ const delay = (typeof retryDelay === 'function' ? retryDelay(error, key) : retryDelay) || 0;
51
+ return { shouldRetry, delay };
52
+ };
43
53
  const forceFetch = () => {
44
54
  const responseAllPages = [];
45
55
  const newPageParams = [undefined];
46
56
  let pageParam = undefined;
47
- const { isWaiting, isLoading, isGoingToRetry, pageParams } = get();
57
+ const { isWaiting, isLoading, pageParams } = get();
48
58
  if (isWaiting || enabled === false || (typeof enabled === 'function' && !enabled(key)))
49
59
  return;
50
60
  if (isLoading)
@@ -52,11 +62,12 @@ export const createQuery = (queryFn, options = {}) => {
52
62
  else
53
63
  set({ isWaiting: true, isRefetching: true });
54
64
  const callQuery = () => {
55
- if (isGoingToRetry) {
65
+ if (get().isGoingToRetry) {
56
66
  if (isLoading)
57
67
  set({ isGoingToRetry: false, isWaiting: true });
58
68
  else
59
69
  set({ isGoingToRetry: false, isWaiting: true, isRefetching: true });
70
+ clearTimeout(retryTimeoutId.get(hashKeyFn(key)));
60
71
  }
61
72
  const stateBeforeCallQuery = { ...get(), pageParam };
62
73
  queryFn(key, stateBeforeCallQuery)
@@ -95,6 +106,7 @@ export const createQuery = (queryFn, options = {}) => {
95
106
  .catch((error) => {
96
107
  const prevState = get();
97
108
  const errorUpdatedAt = Date.now();
109
+ const { shouldRetry, delay } = getRetryProps(error, prevState.retryCount);
98
110
  set(prevState.isSuccess
99
111
  ? {
100
112
  isWaiting: false,
@@ -105,6 +117,7 @@ export const createQuery = (queryFn, options = {}) => {
105
117
  }, null),
106
118
  error,
107
119
  errorUpdatedAt,
120
+ isGoingToRetry: shouldRetry,
108
121
  pageParam,
109
122
  hasNextPage: pageParam !== undefined,
110
123
  }
@@ -113,13 +126,15 @@ export const createQuery = (queryFn, options = {}) => {
113
126
  isError: true,
114
127
  error,
115
128
  errorUpdatedAt,
129
+ isGoingToRetry: shouldRetry,
116
130
  pageParam,
117
131
  hasNextPage: pageParam !== undefined,
118
132
  });
119
- const retryCount = typeof retry === 'function' ? retry(error, key) : retry;
120
- if (typeof retryCount === 'number' && prevState.retryCount < retryCount) {
121
- set({ retryCount: prevState.retryCount + 1, isGoingToRetry: true });
122
- callQuery();
133
+ if (shouldRetry) {
134
+ retryTimeoutId.set(hashKeyFn(key), window.setTimeout(() => {
135
+ set({ retryCount: prevState.retryCount + 1 });
136
+ callQuery();
137
+ }, delay));
123
138
  }
124
139
  onError(error, stateBeforeCallQuery);
125
140
  })
@@ -143,7 +158,8 @@ export const createQuery = (queryFn, options = {}) => {
143
158
  return forceFetch();
144
159
  if (isWaitingNextPage || !hasNextPage)
145
160
  return;
146
- set({ isWaitingNextPage: true });
161
+ set({ isWaitingNextPage: true, isGoingToRetryNextPage: false });
162
+ clearTimeout(retryNextPageTimeoutId.get(hashKeyFn(key)));
147
163
  queryFn(key, { ...state, pageParam })
148
164
  .then((response) => {
149
165
  const newPageParam = getNextPageParam(response, pageParams.length);
@@ -158,12 +174,21 @@ export const createQuery = (queryFn, options = {}) => {
158
174
  });
159
175
  })
160
176
  .catch((error) => {
177
+ const prevState = get();
178
+ const { shouldRetry, delay } = getRetryProps(error, prevState.retryNextPageCount);
161
179
  set({
162
180
  isWaitingNextPage: false,
163
181
  isError: true,
164
182
  error,
165
183
  errorUpdatedAt: Date.now(),
184
+ isGoingToRetryNextPage: shouldRetry,
166
185
  });
186
+ if (shouldRetry) {
187
+ retryNextPageTimeoutId.set(hashKeyFn(key), window.setTimeout(() => {
188
+ set({ retryNextPageCount: prevState.retryNextPageCount + 1 });
189
+ fetchNextPage();
190
+ }, delay));
191
+ }
167
192
  });
168
193
  };
169
194
  const setResponse = (responseSetter) => {
@@ -214,9 +239,6 @@ export const createQuery = (queryFn, options = {}) => {
214
239
  },
215
240
  };
216
241
  }, (() => {
217
- const resetRetryCount = (key) => {
218
- useQuery.set(key, { retryCount: 0 }, true);
219
- };
220
242
  const fetchWindowFocusHandler = () => {
221
243
  useQuery.getAllWithSubscriber().forEach((state) => {
222
244
  getDecision(fetchOnWindowFocus, state.key, {
@@ -228,6 +250,7 @@ export const createQuery = (queryFn, options = {}) => {
228
250
  return {
229
251
  ...createStoresOptions,
230
252
  defaultDeps,
253
+ hashKeyFn,
231
254
  onFirstSubscribe: (state) => {
232
255
  if (typeof window !== 'undefined' && fetchOnWindowFocus) {
233
256
  window.addEventListener('focus', fetchWindowFocusHandler);
@@ -243,9 +266,11 @@ export const createQuery = (queryFn, options = {}) => {
243
266
  },
244
267
  onLastUnsubscribe: (state) => {
245
268
  if (typeof window !== 'undefined' && fetchOnWindowFocus) {
246
- window.addEventListener('focus', fetchWindowFocusHandler);
269
+ window.removeEventListener('focus', fetchWindowFocusHandler);
247
270
  }
248
- resetRetryCount(state.key);
271
+ useQuery.set(state.key, { retryCount: 0, retryNextPageCount: 0 }, true);
272
+ clearTimeout(retryTimeoutId.get(hashKeyFn(state.key)));
273
+ clearTimeout(retryNextPageTimeoutId.get(hashKeyFn(state.key)));
249
274
  onLastUnsubscribe(state);
250
275
  },
251
276
  onBeforeChangeKey: (nextKey, prevKey) => {
@@ -1,7 +1,6 @@
1
1
  import { useEffect, useMemo, useRef, useState } from 'react';
2
- import { noop } from '../utils';
2
+ import { hashStoreKey, noop } from '../utils';
3
3
  import { initStore, } from '../vanilla';
4
- const hashStoreKey = (obj) => JSON.stringify(obj, Object.keys(obj).sort());
5
4
  export const createStores = (initializer, options = {}) => {
6
5
  const { onBeforeChangeKey = noop, defaultDeps, hashKeyFn = hashStoreKey } = options;
7
6
  const stores = new Map();
@@ -1,2 +1,3 @@
1
1
  export declare const noop: () => void;
2
2
  export declare const identityFn: <T>(a: T) => T;
3
+ export declare const hashStoreKey: (obj?: any) => string;
@@ -1,2 +1,3 @@
1
1
  export const noop = () => { };
2
2
  export const identityFn = (a) => a;
3
+ export const hashStoreKey = (obj) => JSON.stringify(obj, Object.keys(obj).sort());
@@ -94,6 +94,8 @@ export type QueryState<TKey extends StoreKey = StoreKey, TResponse = any, TData
94
94
  pageParam: any;
95
95
  pageParams: any[];
96
96
  hasNextPage: boolean;
97
+ retryNextPageCount: number;
98
+ isGoingToRetryNextPage: boolean;
97
99
  };
98
100
  export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any, TData = TResponse, TError = unknown> = CreateStoresOptions<TKey, QueryState<TKey, TResponse, TData, TError>> & {
99
101
  select?: (response: TResponse, state: Pick<QueryState<TKey, TResponse, TData, TError>, 'data' | 'key'>) => TData;
@@ -103,12 +105,6 @@ export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any
103
105
  * Defaults to `3000` (3 seconds).
104
106
  */
105
107
  staleTime?: number;
106
- /**
107
- * Number of maximum error retries.
108
- *
109
- * Defaults to `1`.
110
- */
111
- retry?: number | ((error: TError, key: TKey) => number);
112
108
  /**
113
109
  * Auto call the query when the component is mounted.
114
110
  *
@@ -135,6 +131,18 @@ export type CreateQueryOptions<TKey extends StoreKey = StoreKey, TResponse = any
135
131
  * Defaults to `true`.
136
132
  */
137
133
  enabled?: boolean | ((key: TKey) => boolean);
134
+ /**
135
+ * Number of maximum error retries.
136
+ *
137
+ * Defaults to `1`.
138
+ */
139
+ retry?: number | ((error: TError, key: TKey) => number);
140
+ /**
141
+ * Error retry delay in miliseconds.
142
+ *
143
+ * Defaults to `3000` (3 seconds).
144
+ */
145
+ retryDelay?: number | ((error: TError, key: TKey) => number);
138
146
  /**
139
147
  * If set to `true`, previous `data` will be kept when fetching new data because the query key changed.
140
148
  *
@@ -32,6 +32,8 @@ const INITIAL_QUERY_STATE = {
32
32
  pageParam: undefined,
33
33
  pageParams: [undefined],
34
34
  hasNextPage: false,
35
+ retryNextPageCount: 0,
36
+ isGoingToRetryNextPage: false,
35
37
  };
36
38
  const useQueryDefaultDeps = (state) => [
37
39
  state.data,
@@ -40,14 +42,22 @@ const useQueryDefaultDeps = (state) => [
40
42
  state.hasNextPage,
41
43
  ];
42
44
  const createQuery = (queryFn, options = {}) => {
43
- const { onFirstSubscribe = utils_1.noop, onSubscribe = utils_1.noop, onLastUnsubscribe = utils_1.noop, onBeforeChangeKey = utils_1.noop, defaultDeps = useQueryDefaultDeps, select = utils_1.identityFn, staleTime = DEFAULT_STALE_TIME, retry = 1, fetchOnMount = true, fetchOnWindowFocus = true, enabled = true, keepPreviousData, getNextPageParam = () => undefined, onSuccess = utils_1.noop, onError = utils_1.noop, onSettled = utils_1.noop, ...createStoresOptions } = options;
45
+ const { onFirstSubscribe = utils_1.noop, onSubscribe = utils_1.noop, onLastUnsubscribe = utils_1.noop, onBeforeChangeKey = utils_1.noop, defaultDeps = useQueryDefaultDeps, select = utils_1.identityFn, staleTime = DEFAULT_STALE_TIME, fetchOnMount = true, fetchOnWindowFocus = true, enabled = true, retry = 1, retryDelay = 3000, keepPreviousData, getNextPageParam = () => undefined, onSuccess = utils_1.noop, onError = utils_1.noop, onSettled = utils_1.noop, hashKeyFn = utils_1.hashStoreKey, ...createStoresOptions } = options;
46
+ const retryTimeoutId = new Map();
47
+ const retryNextPageTimeoutId = new Map();
44
48
  const useQuery = (0, create_stores_1.createStores)(({ key: _key, get, set }) => {
45
49
  const key = _key;
50
+ const getRetryProps = (error, retryCount) => {
51
+ const maxRetryCount = (typeof retry === 'function' ? retry(error, key) : retry) || 0;
52
+ const shouldRetry = retryCount < maxRetryCount;
53
+ const delay = (typeof retryDelay === 'function' ? retryDelay(error, key) : retryDelay) || 0;
54
+ return { shouldRetry, delay };
55
+ };
46
56
  const forceFetch = () => {
47
57
  const responseAllPages = [];
48
58
  const newPageParams = [undefined];
49
59
  let pageParam = undefined;
50
- const { isWaiting, isLoading, isGoingToRetry, pageParams } = get();
60
+ const { isWaiting, isLoading, pageParams } = get();
51
61
  if (isWaiting || enabled === false || (typeof enabled === 'function' && !enabled(key)))
52
62
  return;
53
63
  if (isLoading)
@@ -55,11 +65,12 @@ const createQuery = (queryFn, options = {}) => {
55
65
  else
56
66
  set({ isWaiting: true, isRefetching: true });
57
67
  const callQuery = () => {
58
- if (isGoingToRetry) {
68
+ if (get().isGoingToRetry) {
59
69
  if (isLoading)
60
70
  set({ isGoingToRetry: false, isWaiting: true });
61
71
  else
62
72
  set({ isGoingToRetry: false, isWaiting: true, isRefetching: true });
73
+ clearTimeout(retryTimeoutId.get(hashKeyFn(key)));
63
74
  }
64
75
  const stateBeforeCallQuery = { ...get(), pageParam };
65
76
  queryFn(key, stateBeforeCallQuery)
@@ -98,6 +109,7 @@ const createQuery = (queryFn, options = {}) => {
98
109
  .catch((error) => {
99
110
  const prevState = get();
100
111
  const errorUpdatedAt = Date.now();
112
+ const { shouldRetry, delay } = getRetryProps(error, prevState.retryCount);
101
113
  set(prevState.isSuccess
102
114
  ? {
103
115
  isWaiting: false,
@@ -108,6 +120,7 @@ const createQuery = (queryFn, options = {}) => {
108
120
  }, null),
109
121
  error,
110
122
  errorUpdatedAt,
123
+ isGoingToRetry: shouldRetry,
111
124
  pageParam,
112
125
  hasNextPage: pageParam !== undefined,
113
126
  }
@@ -116,13 +129,15 @@ const createQuery = (queryFn, options = {}) => {
116
129
  isError: true,
117
130
  error,
118
131
  errorUpdatedAt,
132
+ isGoingToRetry: shouldRetry,
119
133
  pageParam,
120
134
  hasNextPage: pageParam !== undefined,
121
135
  });
122
- const retryCount = typeof retry === 'function' ? retry(error, key) : retry;
123
- if (typeof retryCount === 'number' && prevState.retryCount < retryCount) {
124
- set({ retryCount: prevState.retryCount + 1, isGoingToRetry: true });
125
- callQuery();
136
+ if (shouldRetry) {
137
+ retryTimeoutId.set(hashKeyFn(key), window.setTimeout(() => {
138
+ set({ retryCount: prevState.retryCount + 1 });
139
+ callQuery();
140
+ }, delay));
126
141
  }
127
142
  onError(error, stateBeforeCallQuery);
128
143
  })
@@ -146,7 +161,8 @@ const createQuery = (queryFn, options = {}) => {
146
161
  return forceFetch();
147
162
  if (isWaitingNextPage || !hasNextPage)
148
163
  return;
149
- set({ isWaitingNextPage: true });
164
+ set({ isWaitingNextPage: true, isGoingToRetryNextPage: false });
165
+ clearTimeout(retryNextPageTimeoutId.get(hashKeyFn(key)));
150
166
  queryFn(key, { ...state, pageParam })
151
167
  .then((response) => {
152
168
  const newPageParam = getNextPageParam(response, pageParams.length);
@@ -161,12 +177,21 @@ const createQuery = (queryFn, options = {}) => {
161
177
  });
162
178
  })
163
179
  .catch((error) => {
180
+ const prevState = get();
181
+ const { shouldRetry, delay } = getRetryProps(error, prevState.retryNextPageCount);
164
182
  set({
165
183
  isWaitingNextPage: false,
166
184
  isError: true,
167
185
  error,
168
186
  errorUpdatedAt: Date.now(),
187
+ isGoingToRetryNextPage: shouldRetry,
169
188
  });
189
+ if (shouldRetry) {
190
+ retryNextPageTimeoutId.set(hashKeyFn(key), window.setTimeout(() => {
191
+ set({ retryNextPageCount: prevState.retryNextPageCount + 1 });
192
+ fetchNextPage();
193
+ }, delay));
194
+ }
170
195
  });
171
196
  };
172
197
  const setResponse = (responseSetter) => {
@@ -217,9 +242,6 @@ const createQuery = (queryFn, options = {}) => {
217
242
  },
218
243
  };
219
244
  }, (() => {
220
- const resetRetryCount = (key) => {
221
- useQuery.set(key, { retryCount: 0 }, true);
222
- };
223
245
  const fetchWindowFocusHandler = () => {
224
246
  useQuery.getAllWithSubscriber().forEach((state) => {
225
247
  getDecision(fetchOnWindowFocus, state.key, {
@@ -231,6 +253,7 @@ const createQuery = (queryFn, options = {}) => {
231
253
  return {
232
254
  ...createStoresOptions,
233
255
  defaultDeps,
256
+ hashKeyFn,
234
257
  onFirstSubscribe: (state) => {
235
258
  if (typeof window !== 'undefined' && fetchOnWindowFocus) {
236
259
  window.addEventListener('focus', fetchWindowFocusHandler);
@@ -246,9 +269,11 @@ const createQuery = (queryFn, options = {}) => {
246
269
  },
247
270
  onLastUnsubscribe: (state) => {
248
271
  if (typeof window !== 'undefined' && fetchOnWindowFocus) {
249
- window.addEventListener('focus', fetchWindowFocusHandler);
272
+ window.removeEventListener('focus', fetchWindowFocusHandler);
250
273
  }
251
- resetRetryCount(state.key);
274
+ useQuery.set(state.key, { retryCount: 0, retryNextPageCount: 0 }, true);
275
+ clearTimeout(retryTimeoutId.get(hashKeyFn(state.key)));
276
+ clearTimeout(retryNextPageTimeoutId.get(hashKeyFn(state.key)));
252
277
  onLastUnsubscribe(state);
253
278
  },
254
279
  onBeforeChangeKey: (nextKey, prevKey) => {
@@ -4,9 +4,8 @@ exports.createStores = void 0;
4
4
  const react_1 = require("react");
5
5
  const utils_1 = require("../utils");
6
6
  const vanilla_1 = require("../vanilla");
7
- const hashStoreKey = (obj) => JSON.stringify(obj, Object.keys(obj).sort());
8
7
  const createStores = (initializer, options = {}) => {
9
- const { onBeforeChangeKey = utils_1.noop, defaultDeps, hashKeyFn = hashStoreKey } = options;
8
+ const { onBeforeChangeKey = utils_1.noop, defaultDeps, hashKeyFn = utils_1.hashStoreKey } = options;
10
9
  const stores = new Map();
11
10
  const getStore = (_key) => {
12
11
  const key = _key || {};
@@ -1,2 +1,3 @@
1
1
  export declare const noop: () => void;
2
2
  export declare const identityFn: <T>(a: T) => T;
3
+ export declare const hashStoreKey: (obj?: any) => string;
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.identityFn = exports.noop = void 0;
3
+ exports.hashStoreKey = exports.identityFn = exports.noop = void 0;
4
4
  const noop = () => { };
5
5
  exports.noop = noop;
6
6
  const identityFn = (a) => a;
7
7
  exports.identityFn = identityFn;
8
+ const hashStoreKey = (obj) => JSON.stringify(obj, Object.keys(obj).sort());
9
+ exports.hashStoreKey = hashStoreKey;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "floppy-disk",
3
- "version": "1.3.0",
3
+ "version": "1.4.0-beta.2",
4
4
  "description": "FloppyDisk - lightweight, simple, and powerful state management library",
5
5
  "keywords": [
6
6
  "state",