yuustate 3.10.1 → 3.11.0

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.
@@ -72,7 +72,11 @@ type Internal<TData, TError> = {
72
72
  garbageCollectionTimeoutId?: number;
73
73
  rollbackData?: TData | undefined;
74
74
  };
75
- type AdditionalStoreApi<TData, TError> = {
75
+ type AdditionalStoreApi<TData, TError, TVariable extends StoreKey = never> = {
76
+ /**
77
+ * The original query variable used to create this store.
78
+ */
79
+ variable: TVariable;
76
80
  /**
77
81
  * A deterministic hash string derived from the query variable.
78
82
  *
@@ -205,7 +209,7 @@ type AdditionalStoreApi<TData, TError> = {
205
209
  * @remarks
206
210
  * Controls caching, retry behavior, lifecycle, and side effects of an async operation.
207
211
  */
208
- export type QueryOptions<TData, TVariable extends StoreKey, TError = Error> = InitStoreOptions<QueryState<TData, TError>, AdditionalStoreApi<TData, TError>> & {
212
+ export type QueryOptions<TData, TVariable extends StoreKey, TError = Error> = InitStoreOptions<QueryState<TData, TError>, AdditionalStoreApi<TData, TError, TVariable>> & {
209
213
  /**
210
214
  * Time (in milliseconds) that data is considered fresh.
211
215
  *
@@ -357,6 +361,10 @@ export declare const createQuery: <TData, TVariable extends StoreKey = never, TE
357
361
  getState: () => QueryState<TData, TError>;
358
362
  subscribe: (subscriber: import("../vanilla.d.mts").Subscriber<QueryState<TData, TError>>) => () => void;
359
363
  getSubscriberCount: () => number;
364
+ /**
365
+ * The original query variable used to create this store.
366
+ */
367
+ variable: TVariable;
360
368
  /**
361
369
  * A deterministic hash string derived from the query variable.
362
370
  *
@@ -490,6 +498,15 @@ export declare const createQuery: <TData, TVariable extends StoreKey = never, TE
490
498
  * - Useful for bulk refetching.
491
499
  */
492
500
  executeAll: (options?: {
501
+ /**
502
+ * Optional predicate to select which query to execute.
503
+ */
504
+ filter?: (variable: TVariable) => boolean;
505
+ /**
506
+ * Whether to start a new execution instead of reusing an ongoing one.
507
+ *
508
+ * @default true
509
+ */
493
510
  overwriteOngoingExecution?: boolean;
494
511
  }) => void;
495
512
  /**
@@ -499,6 +516,15 @@ export declare const createQuery: <TData, TVariable extends StoreKey = never, TE
499
516
  * - Only re-fetches stale queries.
500
517
  */
501
518
  revalidateAll: (options?: {
519
+ /**
520
+ * Optional predicate to select which query to revalidate.
521
+ */
522
+ filter?: (variable: TVariable) => boolean;
523
+ /**
524
+ * Whether to start a new execution instead of reusing an ongoing one.
525
+ *
526
+ * @default true
527
+ */
502
528
  overwriteOngoingExecution?: boolean;
503
529
  }) => void;
504
530
  /**
@@ -509,11 +535,25 @@ export declare const createQuery: <TData, TVariable extends StoreKey = never, TE
509
535
  * - Invalidated queries bypass `staleTime` until successfully executed again.
510
536
  */
511
537
  invalidateAll: (options?: {
538
+ /**
539
+ * Optional predicate to select which query to invalidate.
540
+ */
541
+ filter?: (variable: TVariable) => boolean;
542
+ /**
543
+ * Whether to start a new execution instead of reusing an ongoing one.
544
+ *
545
+ * @default true
546
+ */
512
547
  overwriteOngoingExecution?: boolean;
513
548
  }) => void;
514
549
  /**
515
550
  * Resets all query instances.
516
551
  */
517
- resetAll: () => void;
552
+ resetAll: (options?: {
553
+ /**
554
+ * Optional predicate to select which query to reset.
555
+ */
556
+ filter?: (variable: TVariable) => boolean;
557
+ }) => void;
518
558
  };
519
559
  export {};
package/esm/react.mjs CHANGED
@@ -51,7 +51,7 @@ const useStoreStateProxy = (storeState) => {
51
51
  };
52
52
  const useStoreStateWithInitializer = (store, initialState) => {
53
53
  const initiatedAt = useRef(new WeakMap([[store, 0]]));
54
- useEffect(() => {
54
+ useIsomorphicLayoutEffect(() => {
55
55
  if (initialState === void 0 || initiatedAt.current.get(store)) return;
56
56
  store.setState(initialState);
57
57
  initiatedAt.current.set(store, Date.now());
@@ -63,8 +63,21 @@ const useStoreStateWithInitializer = (store, initialState) => {
63
63
  const useStoreState = (store, options = {}) => {
64
64
  const [state] = useStoreStateWithInitializer(store, options.initialState);
65
65
  const [trackedState, usedPathsRef] = useStoreStateProxy(state);
66
- const snapshotRef = useRef(store.getState());
67
- const getSnapshot = () => snapshotRef.current;
66
+ const snapshotRef = useRef(state);
67
+ const getSnapshot = () => {
68
+ const prevState = snapshotRef.current;
69
+ const nextState = store.getState();
70
+ const paths = compressPaths(usedPathsRef.current);
71
+ for (const path of paths) {
72
+ const prevVal = getValueByPath(prevState, path);
73
+ const nextVal = getValueByPath(nextState, path);
74
+ if (!Object.is(prevVal, nextVal)) {
75
+ snapshotRef.current = nextState;
76
+ break;
77
+ }
78
+ }
79
+ return snapshotRef.current;
80
+ };
68
81
  useSyncExternalStore(
69
82
  useCallback(
70
83
  (onStoreChange) => {
@@ -105,6 +118,7 @@ const createStores = (initialState, options) => {
105
118
  let store;
106
119
  if (stores.has(keyHash)) {
107
120
  store = stores.get(keyHash);
121
+ store.key = key;
108
122
  } else {
109
123
  store = initStore(
110
124
  initialState,
@@ -404,12 +418,14 @@ const createQuery = (queryFn, options = {}) => {
404
418
  let store;
405
419
  if (stores.has(variableHash)) {
406
420
  store = stores.get(variableHash);
421
+ store.variable = variable;
407
422
  } else {
408
423
  store = initStore(
409
424
  initialState,
410
425
  configureStoreEvents(variableHash)
411
426
  // Intentionally using as any: don't want to add generic on `initStore`
412
427
  );
428
+ store.variable = variable;
413
429
  store.variableHash = variableHash;
414
430
  stores.set(variableHash, store);
415
431
  const apis = getApis(store, variable);
@@ -509,6 +525,7 @@ const createQuery = (queryFn, options = {}) => {
509
525
  }
510
526
  });
511
527
  };
528
+ const shouldApplyToStore = (store, filter) => filter ? filter(store.variable) : true;
512
529
  return Object.assign(getStore, {
513
530
  /**
514
531
  * Executes all query instances.
@@ -516,8 +533,12 @@ const createQuery = (queryFn, options = {}) => {
516
533
  * @remarks
517
534
  * - Useful for bulk refetching.
518
535
  */
519
- executeAll: (options2) => {
520
- stores.forEach((store) => store.execute(options2));
536
+ executeAll: (options2 = {}) => {
537
+ const { filter, ...restOptions } = options2;
538
+ stores.forEach((store) => {
539
+ if (!shouldApplyToStore(store, filter)) return;
540
+ store.execute(restOptions);
541
+ });
521
542
  },
522
543
  /**
523
544
  * Revalidates all query instances.
@@ -525,8 +546,12 @@ const createQuery = (queryFn, options = {}) => {
525
546
  * @remarks
526
547
  * - Only re-fetches stale queries.
527
548
  */
528
- revalidateAll: (options2) => {
529
- stores.forEach((store) => store.revalidate(options2));
549
+ revalidateAll: (options2 = {}) => {
550
+ const { filter, ...restOptions } = options2;
551
+ stores.forEach((store) => {
552
+ if (!shouldApplyToStore(store, filter)) return;
553
+ store.revalidate(restOptions);
554
+ });
530
555
  },
531
556
  /**
532
557
  * Invalidates all query instances.
@@ -535,14 +560,22 @@ const createQuery = (queryFn, options = {}) => {
535
560
  * - Marks all queries as invalidated and triggers revalidation if active.
536
561
  * - Invalidated queries bypass `staleTime` until successfully executed again.
537
562
  */
538
- invalidateAll: (options2) => {
539
- stores.forEach((store) => store.invalidate(options2));
563
+ invalidateAll: (options2 = {}) => {
564
+ const { filter, ...restOptions } = options2;
565
+ stores.forEach((store) => {
566
+ if (!shouldApplyToStore(store, filter)) return;
567
+ store.invalidate(restOptions);
568
+ });
540
569
  },
541
570
  /**
542
571
  * Resets all query instances.
543
572
  */
544
- resetAll: () => {
545
- stores.forEach((store) => store.reset());
573
+ resetAll: (options2 = {}) => {
574
+ const { filter } = options2;
575
+ stores.forEach((store) => {
576
+ if (!shouldApplyToStore(store, filter)) return;
577
+ store.reset();
578
+ });
546
579
  }
547
580
  });
548
581
  };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "yuustate",
3
3
  "description": "Lightweight unified state management for sync and async data.",
4
4
  "private": false,
5
- "version": "3.10.1",
5
+ "version": "3.11.0",
6
6
  "keywords": [
7
7
  "utilities",
8
8
  "store",
@@ -72,7 +72,11 @@ type Internal<TData, TError> = {
72
72
  garbageCollectionTimeoutId?: number;
73
73
  rollbackData?: TData | undefined;
74
74
  };
75
- type AdditionalStoreApi<TData, TError> = {
75
+ type AdditionalStoreApi<TData, TError, TVariable extends StoreKey = never> = {
76
+ /**
77
+ * The original query variable used to create this store.
78
+ */
79
+ variable: TVariable;
76
80
  /**
77
81
  * A deterministic hash string derived from the query variable.
78
82
  *
@@ -205,7 +209,7 @@ type AdditionalStoreApi<TData, TError> = {
205
209
  * @remarks
206
210
  * Controls caching, retry behavior, lifecycle, and side effects of an async operation.
207
211
  */
208
- export type QueryOptions<TData, TVariable extends StoreKey, TError = Error> = InitStoreOptions<QueryState<TData, TError>, AdditionalStoreApi<TData, TError>> & {
212
+ export type QueryOptions<TData, TVariable extends StoreKey, TError = Error> = InitStoreOptions<QueryState<TData, TError>, AdditionalStoreApi<TData, TError, TVariable>> & {
209
213
  /**
210
214
  * Time (in milliseconds) that data is considered fresh.
211
215
  *
@@ -357,6 +361,10 @@ export declare const createQuery: <TData, TVariable extends StoreKey = never, TE
357
361
  getState: () => QueryState<TData, TError>;
358
362
  subscribe: (subscriber: import("../vanilla.ts").Subscriber<QueryState<TData, TError>>) => () => void;
359
363
  getSubscriberCount: () => number;
364
+ /**
365
+ * The original query variable used to create this store.
366
+ */
367
+ variable: TVariable;
360
368
  /**
361
369
  * A deterministic hash string derived from the query variable.
362
370
  *
@@ -490,6 +498,15 @@ export declare const createQuery: <TData, TVariable extends StoreKey = never, TE
490
498
  * - Useful for bulk refetching.
491
499
  */
492
500
  executeAll: (options?: {
501
+ /**
502
+ * Optional predicate to select which query to execute.
503
+ */
504
+ filter?: (variable: TVariable) => boolean;
505
+ /**
506
+ * Whether to start a new execution instead of reusing an ongoing one.
507
+ *
508
+ * @default true
509
+ */
493
510
  overwriteOngoingExecution?: boolean;
494
511
  }) => void;
495
512
  /**
@@ -499,6 +516,15 @@ export declare const createQuery: <TData, TVariable extends StoreKey = never, TE
499
516
  * - Only re-fetches stale queries.
500
517
  */
501
518
  revalidateAll: (options?: {
519
+ /**
520
+ * Optional predicate to select which query to revalidate.
521
+ */
522
+ filter?: (variable: TVariable) => boolean;
523
+ /**
524
+ * Whether to start a new execution instead of reusing an ongoing one.
525
+ *
526
+ * @default true
527
+ */
502
528
  overwriteOngoingExecution?: boolean;
503
529
  }) => void;
504
530
  /**
@@ -509,11 +535,25 @@ export declare const createQuery: <TData, TVariable extends StoreKey = never, TE
509
535
  * - Invalidated queries bypass `staleTime` until successfully executed again.
510
536
  */
511
537
  invalidateAll: (options?: {
538
+ /**
539
+ * Optional predicate to select which query to invalidate.
540
+ */
541
+ filter?: (variable: TVariable) => boolean;
542
+ /**
543
+ * Whether to start a new execution instead of reusing an ongoing one.
544
+ *
545
+ * @default true
546
+ */
512
547
  overwriteOngoingExecution?: boolean;
513
548
  }) => void;
514
549
  /**
515
550
  * Resets all query instances.
516
551
  */
517
- resetAll: () => void;
552
+ resetAll: (options?: {
553
+ /**
554
+ * Optional predicate to select which query to reset.
555
+ */
556
+ filter?: (variable: TVariable) => boolean;
557
+ }) => void;
518
558
  };
519
559
  export {};
package/react.js CHANGED
@@ -53,7 +53,7 @@ const useStoreStateProxy = (storeState) => {
53
53
  };
54
54
  const useStoreStateWithInitializer = (store, initialState) => {
55
55
  const initiatedAt = react.useRef(new WeakMap([[store, 0]]));
56
- react.useEffect(() => {
56
+ useIsomorphicLayoutEffect(() => {
57
57
  if (initialState === void 0 || initiatedAt.current.get(store)) return;
58
58
  store.setState(initialState);
59
59
  initiatedAt.current.set(store, Date.now());
@@ -65,8 +65,21 @@ const useStoreStateWithInitializer = (store, initialState) => {
65
65
  const useStoreState = (store, options = {}) => {
66
66
  const [state] = useStoreStateWithInitializer(store, options.initialState);
67
67
  const [trackedState, usedPathsRef] = useStoreStateProxy(state);
68
- const snapshotRef = react.useRef(store.getState());
69
- const getSnapshot = () => snapshotRef.current;
68
+ const snapshotRef = react.useRef(state);
69
+ const getSnapshot = () => {
70
+ const prevState = snapshotRef.current;
71
+ const nextState = store.getState();
72
+ const paths = compressPaths(usedPathsRef.current);
73
+ for (const path of paths) {
74
+ const prevVal = getValueByPath(prevState, path);
75
+ const nextVal = getValueByPath(nextState, path);
76
+ if (!Object.is(prevVal, nextVal)) {
77
+ snapshotRef.current = nextState;
78
+ break;
79
+ }
80
+ }
81
+ return snapshotRef.current;
82
+ };
70
83
  react.useSyncExternalStore(
71
84
  react.useCallback(
72
85
  (onStoreChange) => {
@@ -107,6 +120,7 @@ const createStores = (initialState, options) => {
107
120
  let store;
108
121
  if (stores.has(keyHash)) {
109
122
  store = stores.get(keyHash);
123
+ store.key = key;
110
124
  } else {
111
125
  store = vanilla.initStore(
112
126
  initialState,
@@ -406,12 +420,14 @@ const createQuery = (queryFn, options = {}) => {
406
420
  let store;
407
421
  if (stores.has(variableHash)) {
408
422
  store = stores.get(variableHash);
423
+ store.variable = variable;
409
424
  } else {
410
425
  store = vanilla.initStore(
411
426
  initialState,
412
427
  configureStoreEvents(variableHash)
413
428
  // Intentionally using as any: don't want to add generic on `initStore`
414
429
  );
430
+ store.variable = variable;
415
431
  store.variableHash = variableHash;
416
432
  stores.set(variableHash, store);
417
433
  const apis = getApis(store, variable);
@@ -511,6 +527,7 @@ const createQuery = (queryFn, options = {}) => {
511
527
  }
512
528
  });
513
529
  };
530
+ const shouldApplyToStore = (store, filter) => filter ? filter(store.variable) : true;
514
531
  return Object.assign(getStore, {
515
532
  /**
516
533
  * Executes all query instances.
@@ -518,8 +535,12 @@ const createQuery = (queryFn, options = {}) => {
518
535
  * @remarks
519
536
  * - Useful for bulk refetching.
520
537
  */
521
- executeAll: (options2) => {
522
- stores.forEach((store) => store.execute(options2));
538
+ executeAll: (options2 = {}) => {
539
+ const { filter, ...restOptions } = options2;
540
+ stores.forEach((store) => {
541
+ if (!shouldApplyToStore(store, filter)) return;
542
+ store.execute(restOptions);
543
+ });
523
544
  },
524
545
  /**
525
546
  * Revalidates all query instances.
@@ -527,8 +548,12 @@ const createQuery = (queryFn, options = {}) => {
527
548
  * @remarks
528
549
  * - Only re-fetches stale queries.
529
550
  */
530
- revalidateAll: (options2) => {
531
- stores.forEach((store) => store.revalidate(options2));
551
+ revalidateAll: (options2 = {}) => {
552
+ const { filter, ...restOptions } = options2;
553
+ stores.forEach((store) => {
554
+ if (!shouldApplyToStore(store, filter)) return;
555
+ store.revalidate(restOptions);
556
+ });
532
557
  },
533
558
  /**
534
559
  * Invalidates all query instances.
@@ -537,14 +562,22 @@ const createQuery = (queryFn, options = {}) => {
537
562
  * - Marks all queries as invalidated and triggers revalidation if active.
538
563
  * - Invalidated queries bypass `staleTime` until successfully executed again.
539
564
  */
540
- invalidateAll: (options2) => {
541
- stores.forEach((store) => store.invalidate(options2));
565
+ invalidateAll: (options2 = {}) => {
566
+ const { filter, ...restOptions } = options2;
567
+ stores.forEach((store) => {
568
+ if (!shouldApplyToStore(store, filter)) return;
569
+ store.invalidate(restOptions);
570
+ });
542
571
  },
543
572
  /**
544
573
  * Resets all query instances.
545
574
  */
546
- resetAll: () => {
547
- stores.forEach((store) => store.reset());
575
+ resetAll: (options2 = {}) => {
576
+ const { filter } = options2;
577
+ stores.forEach((store) => {
578
+ if (!shouldApplyToStore(store, filter)) return;
579
+ store.reset();
580
+ });
548
581
  }
549
582
  });
550
583
  };