floppy-disk 3.1.1 → 3.2.0-beta.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.
@@ -22,6 +22,7 @@ import { type InitStoreOptions, type SetState } from "../vanilla.ts";
22
22
  export type QueryState<TData, TError> = {
23
23
  isPending: boolean;
24
24
  isRevalidating: boolean;
25
+ willRetryAt: undefined | number;
25
26
  isRetrying: boolean;
26
27
  retryCount: number;
27
28
  } & ({
@@ -30,6 +31,7 @@ export type QueryState<TData, TError> = {
30
31
  isError: false;
31
32
  data: undefined;
32
33
  dataUpdatedAt: undefined;
34
+ dataStaleAt: undefined;
33
35
  error: undefined;
34
36
  errorUpdatedAt: undefined;
35
37
  } | {
@@ -38,6 +40,7 @@ export type QueryState<TData, TError> = {
38
40
  isError: false;
39
41
  data: TData;
40
42
  dataUpdatedAt: number;
43
+ dataStaleAt: undefined | number;
41
44
  error: undefined;
42
45
  errorUpdatedAt: undefined;
43
46
  } | {
@@ -46,6 +49,7 @@ export type QueryState<TData, TError> = {
46
49
  isError: true;
47
50
  data: undefined;
48
51
  dataUpdatedAt: undefined;
52
+ dataStaleAt: undefined;
49
53
  error: TError;
50
54
  errorUpdatedAt: number;
51
55
  } | {
@@ -54,6 +58,7 @@ export type QueryState<TData, TError> = {
54
58
  isError: false;
55
59
  data: TData;
56
60
  dataUpdatedAt: number;
61
+ dataStaleAt: undefined | number;
57
62
  error: TError;
58
63
  errorUpdatedAt: number;
59
64
  });
@@ -209,6 +214,9 @@ export declare const createQuery: <TData, TVariable extends Record<string, any>
209
214
  initialData?: never;
210
215
  initialDataIsStale?: never;
211
216
  })) => QueryState<TData, TError>) & {
217
+ /**
218
+ * Internal data, do not mutate!
219
+ */
212
220
  metadata: {
213
221
  isInvalidated?: boolean;
214
222
  promise?: Promise<QueryState<TData, TError>> | undefined;
@@ -43,4 +43,6 @@ export declare const createStores: <TState extends Record<string, any>, TKey ext
43
43
  getState: () => TState;
44
44
  subscribe: (subscriber: import("../vanilla.d.mts").Subscriber<TState>) => () => void;
45
45
  getSubscribers: () => Set<import("../vanilla.d.mts").Subscriber<TState>>;
46
+ key: TKey;
47
+ keyHash: string;
46
48
  };
package/esm/react.mjs CHANGED
@@ -95,6 +95,8 @@ const createStores = (initialState, options) => {
95
95
  store = stores.get(keyHash);
96
96
  } else {
97
97
  store = initStore(initialState, options);
98
+ store.key = key;
99
+ store.keyHash = keyHash;
98
100
  stores.set(keyHash, store);
99
101
  }
100
102
  const useStore = (options2) => useStoreState(store, options2);
@@ -118,6 +120,7 @@ const createStores = (initialState, options) => {
118
120
  const INITIAL_STATE$1 = {
119
121
  isPending: false,
120
122
  isRevalidating: false,
123
+ willRetryAt: void 0,
121
124
  isRetrying: false,
122
125
  retryCount: 0,
123
126
  state: "INITIAL",
@@ -125,6 +128,7 @@ const INITIAL_STATE$1 = {
125
128
  isError: false,
126
129
  data: void 0,
127
130
  dataUpdatedAt: void 0,
131
+ dataStaleAt: void 0,
128
132
  error: void 0,
129
133
  errorUpdatedAt: void 0
130
134
  };
@@ -143,7 +147,7 @@ const createQuery = (queryFn, options = {}) => {
143
147
  } = options;
144
148
  const initialState = { ...INITIAL_STATE$1 };
145
149
  const stores = /* @__PURE__ */ new Map();
146
- const configureStoreEvents = () => ({
150
+ const configureStoreEvents = (variableHash) => ({
147
151
  ...options,
148
152
  onFirstSubscribe: (state, store) => {
149
153
  var _a;
@@ -168,14 +172,21 @@ const createQuery = (queryFn, options = {}) => {
168
172
  }
169
173
  },
170
174
  onLastUnsubscribe: (state, store) => {
171
- var _a, _b;
175
+ var _a;
172
176
  (_a = options.onLastUnsubscribe) == null ? void 0 : _a.call(options, state, store);
173
177
  const { metadata, revalidate: revalidate2 } = internals.get(store);
174
178
  clearTimeout(metadata.retryTimeoutId);
175
- (_b = metadata.retryResolver) == null ? void 0 : _b.call(metadata, state);
176
- metadata.retryResolver = void 0;
179
+ if (metadata.retryResolver) {
180
+ store.setState({ willRetryAt: void 0 });
181
+ metadata.retryResolver(store.getState());
182
+ metadata.retryResolver = void 0;
183
+ }
177
184
  metadata.garbageCollectionTimeoutId = setTimeout(() => {
178
- store.setState(initialState);
185
+ if (metadata.promiseResolver || metadata.retryResolver) {
186
+ store.setState(initialState);
187
+ } else {
188
+ stores.delete(variableHash);
189
+ }
179
190
  }, gcTime);
180
191
  if (isClient) {
181
192
  if (revalidateOnFocus) {
@@ -277,6 +288,7 @@ const createQuery = (queryFn, options = {}) => {
277
288
  store.setState({
278
289
  isPending: true,
279
290
  isRevalidating: stateBeforeExecute.state === "SUCCESS",
291
+ willRetryAt: void 0,
280
292
  isRetrying: !!metadata.retryResolver,
281
293
  retryCount: metadata.retryResolver ? stateBeforeExecute.retryCount + 1 : 0
282
294
  });
@@ -289,6 +301,7 @@ const createQuery = (queryFn, options = {}) => {
289
301
  }
290
302
  if (!metadata.promiseResolver) return;
291
303
  if (promise !== metadata.promise) return resolve(metadata.promise);
304
+ const now = Date.now();
292
305
  store.setState({
293
306
  isPending: false,
294
307
  isRevalidating: false,
@@ -298,7 +311,8 @@ const createQuery = (queryFn, options = {}) => {
298
311
  isSuccess: true,
299
312
  isError: false,
300
313
  data,
301
- dataUpdatedAt: Date.now(),
314
+ dataUpdatedAt: now,
315
+ dataStaleAt: now + staleTime,
302
316
  error: void 0,
303
317
  errorUpdatedAt: void 0
304
318
  });
@@ -313,16 +327,23 @@ const createQuery = (queryFn, options = {}) => {
313
327
  var _a;
314
328
  if (!metadata.promiseResolver && !metadata.retryResolver) return;
315
329
  if (promise !== metadata.promise) return resolve(metadata.promise);
316
- store.setState({
330
+ const nextState = {
331
+ ...store.getState(),
317
332
  isPending: false,
318
333
  isRevalidating: false,
319
334
  isRetrying: false
320
- });
321
- const [shouldRetry, retryDelay] = shouldRetryFn(error, store.getState());
335
+ };
336
+ const [shouldRetry, retryDelay] = shouldRetryFn(error, nextState);
322
337
  const hasSubscriber = store.getSubscribers().size > 0;
323
338
  if (shouldRetry && hasSubscriber) {
324
339
  metadata.retryResolver = resolve;
325
340
  metadata.retryTimeoutId = setTimeout(createPromise, retryDelay);
341
+ store.setState({
342
+ isPending: false,
343
+ isRevalidating: false,
344
+ isRetrying: false,
345
+ willRetryAt: Date.now() + retryDelay
346
+ });
326
347
  } else {
327
348
  store.setState({
328
349
  isPending: false,
@@ -375,7 +396,7 @@ const createQuery = (queryFn, options = {}) => {
375
396
  if (stores.has(variableHash)) {
376
397
  store = stores.get(variableHash);
377
398
  } else {
378
- store = initStore(initialState, configureStoreEvents());
399
+ store = initStore(initialState, configureStoreEvents(variableHash));
379
400
  stores.set(variableHash, store);
380
401
  internals.set(store, configureInternals(store, variable, variableHash));
381
402
  }
package/package.json CHANGED
@@ -2,7 +2,10 @@
2
2
  "name": "floppy-disk",
3
3
  "description": "Lightweight unified state management for sync and async data.",
4
4
  "private": false,
5
- "version": "3.1.1",
5
+ "version": "3.2.0-beta.1",
6
+ "publishConfig": {
7
+ "tag": "beta"
8
+ },
6
9
  "keywords": [
7
10
  "utilities",
8
11
  "store",
@@ -68,7 +71,6 @@
68
71
  }
69
72
  }
70
73
  },
71
- "packageManager": "pnpm@10.32.1",
72
74
  "peerDependencies": {
73
75
  "@types/react": ">=17.0",
74
76
  "react": ">=17.0"
@@ -81,4 +83,4 @@
81
83
  "optional": true
82
84
  }
83
85
  }
84
- }
86
+ }
@@ -22,6 +22,7 @@ import { type InitStoreOptions, type SetState } from "../vanilla.ts";
22
22
  export type QueryState<TData, TError> = {
23
23
  isPending: boolean;
24
24
  isRevalidating: boolean;
25
+ willRetryAt: undefined | number;
25
26
  isRetrying: boolean;
26
27
  retryCount: number;
27
28
  } & ({
@@ -30,6 +31,7 @@ export type QueryState<TData, TError> = {
30
31
  isError: false;
31
32
  data: undefined;
32
33
  dataUpdatedAt: undefined;
34
+ dataStaleAt: undefined;
33
35
  error: undefined;
34
36
  errorUpdatedAt: undefined;
35
37
  } | {
@@ -38,6 +40,7 @@ export type QueryState<TData, TError> = {
38
40
  isError: false;
39
41
  data: TData;
40
42
  dataUpdatedAt: number;
43
+ dataStaleAt: undefined | number;
41
44
  error: undefined;
42
45
  errorUpdatedAt: undefined;
43
46
  } | {
@@ -46,6 +49,7 @@ export type QueryState<TData, TError> = {
46
49
  isError: true;
47
50
  data: undefined;
48
51
  dataUpdatedAt: undefined;
52
+ dataStaleAt: undefined;
49
53
  error: TError;
50
54
  errorUpdatedAt: number;
51
55
  } | {
@@ -54,6 +58,7 @@ export type QueryState<TData, TError> = {
54
58
  isError: false;
55
59
  data: TData;
56
60
  dataUpdatedAt: number;
61
+ dataStaleAt: undefined | number;
57
62
  error: TError;
58
63
  errorUpdatedAt: number;
59
64
  });
@@ -209,6 +214,9 @@ export declare const createQuery: <TData, TVariable extends Record<string, any>
209
214
  initialData?: never;
210
215
  initialDataIsStale?: never;
211
216
  })) => QueryState<TData, TError>) & {
217
+ /**
218
+ * Internal data, do not mutate!
219
+ */
212
220
  metadata: {
213
221
  isInvalidated?: boolean;
214
222
  promise?: Promise<QueryState<TData, TError>> | undefined;
@@ -43,4 +43,6 @@ export declare const createStores: <TState extends Record<string, any>, TKey ext
43
43
  getState: () => TState;
44
44
  subscribe: (subscriber: import("../vanilla.ts").Subscriber<TState>) => () => void;
45
45
  getSubscribers: () => Set<import("../vanilla.ts").Subscriber<TState>>;
46
+ key: TKey;
47
+ keyHash: string;
46
48
  };
package/react.js CHANGED
@@ -97,6 +97,8 @@ const createStores = (initialState, options) => {
97
97
  store = stores.get(keyHash);
98
98
  } else {
99
99
  store = vanilla.initStore(initialState, options);
100
+ store.key = key;
101
+ store.keyHash = keyHash;
100
102
  stores.set(keyHash, store);
101
103
  }
102
104
  const useStore = (options2) => useStoreState(store, options2);
@@ -120,6 +122,7 @@ const createStores = (initialState, options) => {
120
122
  const INITIAL_STATE$1 = {
121
123
  isPending: false,
122
124
  isRevalidating: false,
125
+ willRetryAt: void 0,
123
126
  isRetrying: false,
124
127
  retryCount: 0,
125
128
  state: "INITIAL",
@@ -127,6 +130,7 @@ const INITIAL_STATE$1 = {
127
130
  isError: false,
128
131
  data: void 0,
129
132
  dataUpdatedAt: void 0,
133
+ dataStaleAt: void 0,
130
134
  error: void 0,
131
135
  errorUpdatedAt: void 0
132
136
  };
@@ -145,7 +149,7 @@ const createQuery = (queryFn, options = {}) => {
145
149
  } = options;
146
150
  const initialState = { ...INITIAL_STATE$1 };
147
151
  const stores = /* @__PURE__ */ new Map();
148
- const configureStoreEvents = () => ({
152
+ const configureStoreEvents = (variableHash) => ({
149
153
  ...options,
150
154
  onFirstSubscribe: (state, store) => {
151
155
  var _a;
@@ -170,14 +174,21 @@ const createQuery = (queryFn, options = {}) => {
170
174
  }
171
175
  },
172
176
  onLastUnsubscribe: (state, store) => {
173
- var _a, _b;
177
+ var _a;
174
178
  (_a = options.onLastUnsubscribe) == null ? void 0 : _a.call(options, state, store);
175
179
  const { metadata, revalidate: revalidate2 } = internals.get(store);
176
180
  clearTimeout(metadata.retryTimeoutId);
177
- (_b = metadata.retryResolver) == null ? void 0 : _b.call(metadata, state);
178
- metadata.retryResolver = void 0;
181
+ if (metadata.retryResolver) {
182
+ store.setState({ willRetryAt: void 0 });
183
+ metadata.retryResolver(store.getState());
184
+ metadata.retryResolver = void 0;
185
+ }
179
186
  metadata.garbageCollectionTimeoutId = setTimeout(() => {
180
- store.setState(initialState);
187
+ if (metadata.promiseResolver || metadata.retryResolver) {
188
+ store.setState(initialState);
189
+ } else {
190
+ stores.delete(variableHash);
191
+ }
181
192
  }, gcTime);
182
193
  if (vanilla.isClient) {
183
194
  if (revalidateOnFocus) {
@@ -279,6 +290,7 @@ const createQuery = (queryFn, options = {}) => {
279
290
  store.setState({
280
291
  isPending: true,
281
292
  isRevalidating: stateBeforeExecute.state === "SUCCESS",
293
+ willRetryAt: void 0,
282
294
  isRetrying: !!metadata.retryResolver,
283
295
  retryCount: metadata.retryResolver ? stateBeforeExecute.retryCount + 1 : 0
284
296
  });
@@ -291,6 +303,7 @@ const createQuery = (queryFn, options = {}) => {
291
303
  }
292
304
  if (!metadata.promiseResolver) return;
293
305
  if (promise !== metadata.promise) return resolve(metadata.promise);
306
+ const now = Date.now();
294
307
  store.setState({
295
308
  isPending: false,
296
309
  isRevalidating: false,
@@ -300,7 +313,8 @@ const createQuery = (queryFn, options = {}) => {
300
313
  isSuccess: true,
301
314
  isError: false,
302
315
  data,
303
- dataUpdatedAt: Date.now(),
316
+ dataUpdatedAt: now,
317
+ dataStaleAt: now + staleTime,
304
318
  error: void 0,
305
319
  errorUpdatedAt: void 0
306
320
  });
@@ -315,16 +329,23 @@ const createQuery = (queryFn, options = {}) => {
315
329
  var _a;
316
330
  if (!metadata.promiseResolver && !metadata.retryResolver) return;
317
331
  if (promise !== metadata.promise) return resolve(metadata.promise);
318
- store.setState({
332
+ const nextState = {
333
+ ...store.getState(),
319
334
  isPending: false,
320
335
  isRevalidating: false,
321
336
  isRetrying: false
322
- });
323
- const [shouldRetry, retryDelay] = shouldRetryFn(error, store.getState());
337
+ };
338
+ const [shouldRetry, retryDelay] = shouldRetryFn(error, nextState);
324
339
  const hasSubscriber = store.getSubscribers().size > 0;
325
340
  if (shouldRetry && hasSubscriber) {
326
341
  metadata.retryResolver = resolve;
327
342
  metadata.retryTimeoutId = setTimeout(createPromise, retryDelay);
343
+ store.setState({
344
+ isPending: false,
345
+ isRevalidating: false,
346
+ isRetrying: false,
347
+ willRetryAt: Date.now() + retryDelay
348
+ });
328
349
  } else {
329
350
  store.setState({
330
351
  isPending: false,
@@ -377,7 +398,7 @@ const createQuery = (queryFn, options = {}) => {
377
398
  if (stores.has(variableHash)) {
378
399
  store = stores.get(variableHash);
379
400
  } else {
380
- store = vanilla.initStore(initialState, configureStoreEvents());
401
+ store = vanilla.initStore(initialState, configureStoreEvents(variableHash));
381
402
  stores.set(variableHash, store);
382
403
  internals.set(store, configureInternals(store, variable, variableHash));
383
404
  }