@qiaopeng/tanstack-query-plus 0.5.7 → 0.5.9

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
@@ -291,18 +291,32 @@ function App() {
291
291
  queries: {
292
292
  staleTime: 30000,
293
293
  gcTime: 600000,
294
- retry: defaultQueryRetryStrategy,
294
+ retry: defaultQueryRetryStrategy, // 智能重试:4XX不重试,5XX最多1次
295
295
  retryDelay: exponentialBackoff,
296
296
  refetchOnWindowFocus: true,
297
297
  refetchOnReconnect: true,
298
+ refetchOnMount: true,
298
299
  },
299
300
  mutations: {
300
- retry: 0,
301
+ retry: 0, // Mutation 默认不重试
302
+ retryDelay: exponentialBackoff,
301
303
  gcTime: 600000,
302
304
  }
303
305
  }
304
306
  ```
305
307
 
308
+ **重试策略说明:**
309
+
310
+ - **Query 重试**(`defaultQueryRetryStrategy`):
311
+ - 4XX 客户端错误:不重试(客户端问题,重试无意义)
312
+ - 5XX 服务端错误:最多重试 1 次(避免过度重试)
313
+ - 网络错误:最多重试 2 次
314
+
315
+ - **Mutation 重试**(`defaultMutationRetryStrategy`):
316
+ - 4XX 客户端错误:不重试
317
+ - 5XX 服务端错误:不重试(避免重复操作)
318
+ - 网络错误:最多重试 1 次
319
+
306
320
  这些值是经过实践验证的最佳实践,适合大多数应用场景。
307
321
 
308
322
  ### 3.4 根据环境选择配置
@@ -313,7 +327,13 @@ function App() {
313
327
  import { getConfigByEnvironment } from '@qiaopeng/tanstack-query-plus/core'
314
328
 
315
329
  // 根据环境自动选择配置
316
- const config = getConfigByEnvironment(process.env.NODE_ENV)
330
+ const env =
331
+ process.env.NODE_ENV === 'production'
332
+ ? 'production'
333
+ : process.env.NODE_ENV === 'test'
334
+ ? 'test'
335
+ : 'development'
336
+ const config = getConfigByEnvironment(env)
317
337
  const queryClient = new QueryClient({ defaultOptions: config })
318
338
  ```
319
339
 
@@ -322,10 +342,60 @@ const queryClient = new QueryClient({ defaultOptions: config })
322
342
  | 配置项 | development | production | test |
323
343
  |--------|-------------|------------|------|
324
344
  | staleTime | 0 | 10 分钟 | 0 |
325
- | retry | 1 | 3 | 0 |
345
+ | retry (Query) | 智能重试* | 智能重试* | 0 |
346
+ | retry (Mutation) | 0 | 0 | 0 |
326
347
  | refetchOnWindowFocus | true | true | false |
327
348
 
328
- ### 3.5 添加 DevTools(开发环境)
349
+ *智能重试:4XX 不重试,5XX 最多 1 次,网络错误最多 2 次
350
+
351
+ 补充:还支持 `getConfigByEnvironment('longCache')` 与 `getConfigByEnvironment('realtime')` 两种预设,分别适用于“长缓存”与“高实时”场景。
352
+
353
+ ### 3.5 自定义重试策略
354
+
355
+ 如果默认的重试策略不满足你的需求,可以使用 `createSafeRetryStrategy` 和 `createErrorSafeConfig` 来自定义:
356
+
357
+ ```tsx
358
+ import {
359
+ createSafeRetryStrategy,
360
+ createErrorSafeConfig
361
+ } from '@qiaopeng/tanstack-query-plus/core'
362
+
363
+ // 方式一:创建自定义重试策略
364
+ const customRetry = createSafeRetryStrategy(
365
+ 0, // 4XX 错误重试次数
366
+ 1, // 5XX 错误重试次数
367
+ 2 // 其他错误重试次数
368
+ )
369
+
370
+ const queryClient = new QueryClient({
371
+ defaultOptions: {
372
+ queries: {
373
+ retry: customRetry,
374
+ }
375
+ }
376
+ })
377
+
378
+ // 方式二:使用错误安全配置(推荐)
379
+ const errorSafeConfig = createErrorSafeConfig({
380
+ maxRetries4xx: 0, // 4XX 不重试
381
+ maxRetries5xx: 0, // 5XX 不重试(严格模式)
382
+ maxRetriesOther: 1, // 网络错误最多 1 次
383
+ disableFocus: false, // 是否禁用窗口聚焦时 refetch
384
+ disableReconnect: false // 是否禁用重连时 refetch
385
+ })
386
+
387
+ const queryClient = new QueryClient({
388
+ defaultOptions: errorSafeConfig
389
+ })
390
+ ```
391
+
392
+ **使用场景:**
393
+
394
+ 1. **严格模式**:完全禁用 4XX/5XX 重试,避免不必要的请求
395
+ 2. **宽松模式**:增加重试次数,适合网络不稳定的环境
396
+ 3. **自定义场景**:根据业务需求精确控制重试行为
397
+
398
+ ### 3.6 添加 DevTools(开发环境)
329
399
 
330
400
  在开发环境中,强烈建议添加 DevTools 来调试查询状态:
331
401
 
@@ -1069,13 +1139,21 @@ batchDelete.mutate(['id1', 'id2', 'id3'])
1069
1139
  2. 使用离线队列在恢复网络后批量执行(稳健且可持久化):
1070
1140
 
1071
1141
  ```tsx
1072
- import { createOfflineQueueManager, mutationRegistry } from '@qiaopeng/tanstack-query-plus/features'
1142
+ import { createOfflineQueueManager, mutationRegistry, serializeMutationKey } from '@qiaopeng/tanstack-query-plus/features'
1143
+ import { MutationOperationType } from '@qiaopeng/tanstack-query-plus/types'
1073
1144
 
1074
1145
  const queue = createOfflineQueueManager({ storageKey: 'todo-ops', concurrency: 3 })
1075
1146
 
1076
- function registerDelete(id: string) {
1077
- mutationRegistry.register(['todos','delete',id].join('-'), () => api.deleteTodo(id))
1078
- queue.add({ mutationKey: ['todos','delete',id], mutationFn: () => api.deleteTodo(id), priority: 1 })
1147
+ async function registerDelete(id: string) {
1148
+ const key = serializeMutationKey(['todos', 'delete', id])
1149
+ mutationRegistry.register(key, () => api.deleteTodo(id))
1150
+ await queue.add({
1151
+ type: MutationOperationType.DELETE,
1152
+ mutationKey: ['todos', 'delete', id],
1153
+ variables: { id },
1154
+ mutationFn: () => api.deleteTodo(id),
1155
+ priority: 1
1156
+ })
1079
1157
  }
1080
1158
  ```
1081
1159
 
@@ -2650,7 +2728,8 @@ console.log({
2650
2728
  对于需要在离线时也能操作的应用,可以使用离线队列管理器:
2651
2729
 
2652
2730
  ```tsx
2653
- import { createOfflineQueueManager, mutationRegistry } from '@qiaopeng/tanstack-query-plus/features'
2731
+ import { createOfflineQueueManager, isOnline, mutationRegistry, serializeMutationKey } from '@qiaopeng/tanstack-query-plus/features'
2732
+ import { MutationOperationType } from '@qiaopeng/tanstack-query-plus/types'
2654
2733
 
2655
2734
  // 创建队列管理器
2656
2735
  const queueManager = createOfflineQueueManager({
@@ -2663,15 +2742,17 @@ const queueManager = createOfflineQueueManager({
2663
2742
 
2664
2743
  // 注册 mutation 函数(用于恢复队列时执行)
2665
2744
  // 注册函数签名为 () => Promise<unknown>,如需变量请使用闭包或在入队项的 mutationFn 捕获
2666
- mutationRegistry.register('updateUser', () => updateUserAPI(savedUserData))
2667
- mutationRegistry.register('createPost', () => createPostAPI(savedPostData))
2745
+ mutationRegistry.register(serializeMutationKey(['updateUser']), () => updateUserAPI(savedUserData))
2746
+ mutationRegistry.register(serializeMutationKey(['createPost']), () => createPostAPI(savedPostData))
2668
2747
 
2669
2748
  // 添加操作到队列
2670
2749
  async function handleUpdateUser(userData) {
2671
2750
  if (!isOnline()) {
2672
2751
  // 离线时添加到队列
2673
2752
  await queueManager.add({
2753
+ type: MutationOperationType.UPDATE,
2674
2754
  mutationKey: ['updateUser'],
2755
+ variables: userData,
2675
2756
  mutationFn: () => updateUserAPI(userData),
2676
2757
  priority: 1, // 优先级(数字越大越优先)
2677
2758
  })
@@ -2712,6 +2793,7 @@ queueManager.destroy()
2712
2793
  ```tsx
2713
2794
  import { useState, useEffect } from 'react'
2714
2795
  import { createOfflineQueueManager } from '@qiaopeng/tanstack-query-plus/features'
2796
+ import { MutationOperationType } from '@qiaopeng/tanstack-query-plus/types'
2715
2797
  import { useEnhancedQuery } from '@qiaopeng/tanstack-query-plus/hooks'
2716
2798
  import { useQueryClient, usePersistenceStatus } from '@qiaopeng/tanstack-query-plus'
2717
2799
 
@@ -2757,7 +2839,9 @@ function TodoApp() {
2757
2839
  if (!networkStatus) {
2758
2840
  // 离线:添加到队列
2759
2841
  await offlineQueue.add({
2842
+ type: MutationOperationType.CREATE,
2760
2843
  mutationKey: ['addTodo'],
2844
+ variables: todoData,
2761
2845
  mutationFn: () => api.createTodo(todoData),
2762
2846
  priority: 1,
2763
2847
  })
@@ -3615,7 +3699,13 @@ function UserProfile({ userId }) {
3615
3699
  import { QueryClient } from '@qiaopeng/tanstack-query-plus'
3616
3700
  import { getConfigByEnvironment, ensureBestPractices } from '@qiaopeng/tanstack-query-plus/core'
3617
3701
 
3618
- const baseConfig = getConfigByEnvironment(process.env.NODE_ENV)
3702
+ const env =
3703
+ process.env.NODE_ENV === 'production'
3704
+ ? 'production'
3705
+ : process.env.NODE_ENV === 'test'
3706
+ ? 'test'
3707
+ : 'development'
3708
+ const baseConfig = getConfigByEnvironment(env)
3619
3709
 
3620
3710
  // 确保配置符合最佳实践
3621
3711
  const config = ensureBestPractices({
@@ -3691,12 +3781,12 @@ function useUser(userId: string): EnhancedQueryResult<User, ApiError> {
3691
3781
  }
3692
3782
 
3693
3783
  // 类型安全的 mutation
3694
- function useUpdateUser() {
3784
+ function useUpdateUser(userId: string) {
3695
3785
  return useMutation<User, ApiError, Partial<User>>({
3696
- mutationFn: (data) => updateUser(data),
3786
+ mutationFn: (patch) => updateUser(userId, patch),
3697
3787
  optimistic: {
3698
- queryKey: ['user', data.id],
3699
- updater: (old, newData) => ({ ...old, ...newData }),
3788
+ queryKey: ['user', userId],
3789
+ updater: (old, patch) => (old ? ({ ...old, ...patch }) : old),
3700
3790
  },
3701
3791
  })
3702
3792
  }
@@ -3826,32 +3916,6 @@ useEnhancedQuery({
3826
3916
  3. **处理认证过期**:在全局错误处理中处理 401 错误
3827
3917
  4. **清理敏感缓存**:用户登出时清除缓存
3828
3918
 
3829
- ---
3830
-
3831
- ## 总结
3832
-
3833
- 恭喜你完成了本教程!现在你已经掌握了 `@qiaopeng/tanstack-query-plus` 的所有核心功能:
3834
-
3835
- 1. ✅ 配置 Provider 和最佳实践
3836
- 2. ✅ 基础查询和增强查询
3837
- 3. ✅ Query Key 管理
3838
- 4. ✅ 数据变更和乐观更新
3839
- 5. ✅ 无限滚动和分页
3840
- 6. ✅ 批量查询和仪表盘
3841
- 7. ✅ 智能预取策略
3842
- 8. ✅ Suspense 模式
3843
- 9. ✅ 离线支持和持久化
3844
- 10. ✅ 数据防护与安全
3845
- 11. ✅ 焦点管理
3846
- 12. ✅ 工具函数和选择器
3847
-
3848
- ### 下一步
3849
-
3850
- - 查看 [GitHub 仓库](https://github.com/qiaopengg/qiaopeng-tanstack-query-plus) 获取最新更新
3851
- - 阅读 [TanStack Query 官方文档](https://tanstack.com/query/latest) 了解更多底层概念
3852
- - 在 [Issues](https://github.com/qiaopengg/qiaopeng-tanstack-query-plus/issues) 中提问或反馈
3853
-
3854
- 祝你编码愉快!🚀
3855
3919
  ### 16.9 类型与错误处理规范
3856
3920
 
3857
3921
  - 明确类型参数:在增强 hooks 中显式标注 `TData` 与 `TError`,避免 `any` 漏出
@@ -3902,8 +3966,8 @@ useEnhancedQuery({
3902
3966
  - `QueryClient`、`QueryClientProvider`、`useQueryClient`、`skipToken`、`useIsMutating`(直接再导出原生 API)
3903
3967
 
3904
3968
  - `@qiaopeng/tanstack-query-plus/core`
3905
- - 配置:`GLOBAL_QUERY_CONFIG`、`createCustomConfig`、`DEFAULT_STALE_TIME`、`DEFAULT_GC_TIME`
3906
- - 重试:`defaultQueryRetryStrategy`、`defaultMutationRetryStrategy`、`exponentialBackoff`
3969
+ - 配置:`GLOBAL_QUERY_CONFIG`、`createCustomConfig`、`createErrorSafeConfig`、`DEFAULT_STALE_TIME`、`DEFAULT_GC_TIME`
3970
+ - 重试:`defaultQueryRetryStrategy`、`defaultMutationRetryStrategy`、`createSafeRetryStrategy`、`exponentialBackoff`
3907
3971
  - 环境:`isDev`、`isProd`、`isTest`
3908
3972
  - DevTools:`ReactQueryDevtools`、`isDevToolsEnabled`、`createDevToolsConfig`(src/core/devtools.ts:28)
3909
3973
  - 焦点管理:`focusManager`、`getSmartFocusManager`、`pauseFocusManager`、`resumeFocusManager`
@@ -3919,7 +3983,7 @@ useEnhancedQuery({
3919
3983
  - 数据防护:`useDataGuardQueryConfig`、`useDataGuardMutation`
3920
3984
 
3921
3985
  - `@qiaopeng/tanstack-query-plus/features`
3922
- - 离线:`setupOnlineManager`、`isOnline`、`createOfflineQueueManager`、`OfflineQueueManager`、`mutationRegistry`、`subscribeToOnlineStatus`
3986
+ - 离线:`setupOnlineManager`、`isOnline`、`createOfflineQueueManager`、`OfflineQueueManager`、`mutationRegistry`、`serializeMutationKey`、`subscribeToOnlineStatus`
3923
3987
  - 持久化:`createPersistOptions`、`createPersister`、`clearCache`、`clearExpiredCache`、`checkStorageSize`、`getStorageStats`、`migrateToIndexedDB`
3924
3988
 
3925
3989
  - `@qiaopeng/tanstack-query-plus/components`
@@ -3939,3 +4003,28 @@ useEnhancedQuery({
3939
4003
  - 原生 API 再导出:`useQuery`、`useMutation`、`useInfiniteQuery`、`useSuspenseQuery` 等(src/react-query/index.ts:1)
3940
4004
 
3941
4005
  提示:完整导出列表可在 `package.json:33` 的 `exports` 字段中查看;顶层入口再导出常用原生 API,子路径按模块分层导出,便于 tree-shaking。
4006
+
4007
+ ---
4008
+
4009
+ ## 总结
4010
+
4011
+ 你已经覆盖了 `@qiaopeng/tanstack-query-plus` 的核心能力:
4012
+
4013
+ 1. ✅ 配置 Provider 和最佳实践
4014
+ 2. ✅ 基础查询和增强查询
4015
+ 3. ✅ Query Key 管理
4016
+ 4. ✅ 数据变更和乐观更新
4017
+ 5. ✅ 无限滚动和分页
4018
+ 6. ✅ 批量查询和仪表盘
4019
+ 7. ✅ 智能预取策略
4020
+ 8. ✅ Suspense 模式
4021
+ 9. ✅ 离线支持和持久化
4022
+ 10. ✅ 数据防护与安全
4023
+ 11. ✅ 焦点管理
4024
+ 12. ✅ 工具函数和选择器
4025
+
4026
+ ### 下一步
4027
+
4028
+ - 查看 [GitHub 仓库](https://github.com/qiaopengg/qiaopeng-tanstack-query-plus) 获取最新更新
4029
+ - 阅读 [TanStack Query 官方文档](https://tanstack.com/query/latest) 了解更多底层概念
4030
+ - 在 [Issues](https://github.com/qiaopengg/qiaopeng-tanstack-query-plus/issues) 中提问或反馈
@@ -1 +1 @@
1
- {"version":3,"file":"PersistQueryClientProvider.d.ts","sourceRoot":"","sources":["../src/PersistQueryClientProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAOvC,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACxC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,wBAAgB,0BAA0B,CAAC,EACzC,QAAQ,EACR,MAAM,EACN,QAAiC,EACjC,iBAAwB,EACxB,oBAA2B,EAC3B,cAAc,EAAE,eAAe,EAC/B,gBAAgB,EACjB,EAAE,+BAA+B,2CA0BjC;AAED,wBAAgB,oBAAoB;;;EASnC;AAED,wBAAgB,qBAAqB;;;EAWpC;AAED,eAAe,0BAA0B,CAAC"}
1
+ {"version":3,"file":"PersistQueryClientProvider.d.ts","sourceRoot":"","sources":["../src/PersistQueryClientProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAQvC,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACxC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,wBAAgB,0BAA0B,CAAC,EACzC,QAAQ,EACR,MAAM,EACN,QAAiC,EACjC,iBAAwB,EACxB,oBAA2B,EAC3B,cAAc,EAAE,eAAe,EAC/B,gBAAgB,EACjB,EAAE,+BAA+B,2CAmCjC;AAED,wBAAgB,oBAAoB;;;EASnC;AAED,wBAAgB,qBAAqB;;;EAWpC;AAED,eAAe,0BAA0B,CAAC"}
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { QueryClientProvider } from "@tanstack/react-query";
3
3
  import { PersistQueryClientProvider as TanStackPersistProvider } from "@tanstack/react-query-persist-client";
4
- import { useEffect, useState } from "react";
4
+ import { useEffect, useMemo, useState } from "react";
5
+ import { TIME_CONSTANTS } from "./core/config.js";
5
6
  import { isOnline, setupOnlineManager, subscribeToOnlineStatus } from "./features/offline.js";
6
7
  import { clearCache, createPersister } from "./features/persistence.js";
7
8
  export function PersistQueryClientProvider({ children, client, cacheKey = "tanstack-query-cache", enablePersistence = true, enableOfflineSupport = true, onPersistError: _onPersistError, onPersistRestore }) {
@@ -10,15 +11,24 @@ export function PersistQueryClientProvider({ children, client, cacheKey = "tanst
10
11
  setupOnlineManager();
11
12
  }
12
13
  }, [enableOfflineSupport]);
14
+ const persister = useMemo(() => {
15
+ if (!enablePersistence)
16
+ return null;
17
+ return createPersister(cacheKey, undefined, _onPersistError);
18
+ }, [cacheKey, enablePersistence, _onPersistError]);
19
+ const persistOptions = useMemo(() => {
20
+ if (!persister)
21
+ return null;
22
+ return {
23
+ persister,
24
+ maxAge: TIME_CONSTANTS.ONE_DAY
25
+ };
26
+ }, [persister]);
13
27
  if (enablePersistence) {
14
- const persister = createPersister(cacheKey, undefined, _onPersistError);
15
- if (!persister) {
28
+ if (!persistOptions) {
16
29
  return _jsx(QueryClientProvider, { client: client, children: children });
17
30
  }
18
- return (_jsx(TanStackPersistProvider, { client: client, persistOptions: {
19
- persister,
20
- maxAge: 1000 * 60 * 60 * 24
21
- }, onSuccess: onPersistRestore, children: children }));
31
+ return (_jsx(TanStackPersistProvider, { client: client, persistOptions: persistOptions, onSuccess: onPersistRestore, children: children }));
22
32
  }
23
33
  return _jsx(QueryClientProvider, { client: client, children: children });
24
34
  }
@@ -11,18 +11,30 @@ export declare const TIME_CONSTANTS: {
11
11
  };
12
12
  export declare const DEFAULT_STALE_TIME: number;
13
13
  export declare const DEFAULT_GC_TIME: number;
14
+ /**
15
+ * 默认 Query 重试策略
16
+ * - 4XX 客户端错误:不重试(客户端问题,重试无意义)
17
+ * - 5XX 服务端错误:最多重试 1 次(避免过度重试)
18
+ * - 其他错误(网络等):最多重试 2 次
19
+ */
14
20
  export declare function defaultQueryRetryStrategy(failureCount: number, error: unknown): boolean;
21
+ /**
22
+ * 默认 Mutation 重试策略
23
+ * - 4XX 客户端错误:不重试
24
+ * - 5XX 服务端错误:不重试(Mutation 更谨慎,避免重复操作)
25
+ * - 其他错误:最多重试 1 次
26
+ */
15
27
  export declare function defaultMutationRetryStrategy(failureCount: number, error: unknown): boolean;
16
28
  export declare function exponentialBackoff(attemptIndex: number): number;
17
- export declare const DEFAULT_QUERY_CONFIG: DefaultOptions["queries"];
18
- export declare const DEFAULT_MUTATION_CONFIG: DefaultOptions["mutations"];
29
+ export declare const DEFAULT_QUERY_CONFIG: NonNullable<DefaultOptions["queries"]>;
30
+ export declare const DEFAULT_MUTATION_CONFIG: NonNullable<DefaultOptions["mutations"]>;
19
31
  export declare const GLOBAL_QUERY_CONFIG: DefaultOptions;
20
32
  export declare const SMART_RETRY_MUTATION_CONFIG: DefaultOptions["mutations"];
21
33
  export declare const DEVELOPMENT_CONFIG: DefaultOptions;
22
34
  export declare const PRODUCTION_CONFIG: DefaultOptions;
23
35
  export declare const LONG_CACHE_CONFIG: DefaultOptions;
24
36
  export declare const REALTIME_CONFIG: DefaultOptions;
25
- export declare function getConfigByEnvironment(env: "development" | "production" | "test"): DefaultOptions;
37
+ export declare function getConfigByEnvironment(env: "development" | "production" | "test" | "realtime" | "longCache"): DefaultOptions;
26
38
  export declare function createCustomConfig(overrides: Partial<DefaultOptions>): DefaultOptions;
27
39
  export declare function validateGcTime(staleTime: number, gcTime: number): {
28
40
  isValid: boolean;
@@ -33,13 +45,36 @@ export declare function validateConfig(config: DefaultOptions): {
33
45
  warnings: string[];
34
46
  };
35
47
  export declare function ensureBestPractices(config: DefaultOptions): DefaultOptions;
36
- export declare function createSafeRetryStrategy(maxRetries500?: number, maxRetriesOther?: number): (failureCount: number, error: unknown) => boolean;
48
+ /**
49
+ * 创建安全的重试策略
50
+ * @param maxRetries4xx - 4XX 错误最大重试次数(默认 0,不重试)
51
+ * @param maxRetries5xx - 5XX 错误最大重试次数(默认 0,不重试)
52
+ * @param maxRetriesOther - 其他错误最大重试次数(默认 1)
53
+ */
54
+ export declare function createSafeRetryStrategy(maxRetries4xx?: number, maxRetries5xx?: number, maxRetriesOther?: number): (failureCount: number, error: unknown) => boolean;
55
+ /**
56
+ * 创建错误安全配置
57
+ * 适用于需要严格控制重试和 refetch 行为的场景
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * // 完全禁用重试
62
+ * const config = createErrorSafeConfig({
63
+ * maxRetries4xx: 0,
64
+ * maxRetries5xx: 0,
65
+ * maxRetriesOther: 0,
66
+ * disableFocus: true,
67
+ * disableReconnect: true
68
+ * });
69
+ * ```
70
+ */
37
71
  export declare function createErrorSafeConfig(options?: {
38
- maxRetries500?: number;
72
+ maxRetries4xx?: number;
73
+ maxRetries5xx?: number;
39
74
  maxRetriesOther?: number;
40
75
  disableFocus?: boolean;
41
76
  disableReconnect?: boolean;
42
- conditionalRefetchInterval?: number | ((data: unknown, query: any) => number | false);
77
+ conditionalRefetchInterval?: number | ((query: any) => number | false) | ((data: unknown, query: any) => number | false);
43
78
  overrides?: Partial<DefaultOptions>;
44
79
  }): DefaultOptions;
45
80
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,eAAO,MAAM,cAAc;;;;;;;;;CASjB,CAAC;AAEX,eAAO,MAAM,kBAAkB,QAAgC,CAAC;AAChE,eAAO,MAAM,eAAe,QAA6B,CAAC;AAO1D,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAIvF;AAED,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAK1F;AAED,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,eAAO,MAAM,oBAAoB,EAAE,cAAc,CAAC,SAAS,CAQ1D,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,cAAc,CAAC,WAAW,CAI/D,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,cAGjC,CAAC;AAEF,eAAO,MAAM,2BAA2B,EAAE,cAAc,CAAC,WAAW,CAInE,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,cAYhC,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,cAY/B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,cAa/B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,cAW7B,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,GAAG,cAAc,CAwBjG;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,cAAc,CAWrF;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAQxG;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CA2B/F;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAkC1E;AAED,wBAAgB,uBAAuB,CAAC,aAAa,GAAE,MAAU,EAAE,eAAe,GAAE,MAAU,IACpF,cAAc,MAAM,EAAE,OAAO,OAAO,KAAG,OAAO,CAMvD;AAED,wBAAgB,qBAAqB,CAAC,OAAO,GAAE;IAC7C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,0BAA0B,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,KAAK,MAAM,GAAG,KAAK,CAAC,CAAC;IACtF,SAAS,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;CAChC,GAAG,cAAc,CA6BtB"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,eAAO,MAAM,cAAc;;;;;;;;;CASjB,CAAC;AAEX,eAAO,MAAM,kBAAkB,QAAgC,CAAC;AAChE,eAAO,MAAM,eAAe,QAA6B,CAAC;AAkC1D;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAevF;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAe1F;AAED,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,eAAO,MAAM,oBAAoB,EAAE,WAAW,CAAC,cAAc,CAAC,SAAS,CAAC,CAQvE,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,cAAc,CAAC,WAAW,CAAC,CAI5E,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,cAGjC,CAAC;AAEF,eAAO,MAAM,2BAA2B,EAAE,cAAc,CAAC,WAAW,CAInE,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,cAYhC,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,cAY/B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,cAa/B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,cAW7B,CAAC;AAEF,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,GACpE,cAAc,CA4BhB;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,cAAc,CAWrF;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAQxG;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CA2B/F;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAyC1E;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,GAAE,MAAU,EACzB,aAAa,GAAE,MAAU,EACzB,eAAe,GAAE,MAAU,IAEnB,cAAc,MAAM,EAAE,OAAO,OAAO,KAAG,OAAO,CAgBvD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,GAAE;IAC7C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,0BAA0B,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,KAAK,MAAM,GAAG,KAAK,CAAC,CAAC;IACzH,SAAS,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;CAChC,GAAG,cAAc,CAuCtB"}
@@ -11,19 +11,65 @@ export const TIME_CONSTANTS = {
11
11
  };
12
12
  export const DEFAULT_STALE_TIME = TIME_CONSTANTS.THIRTY_SECONDS;
13
13
  export const DEFAULT_GC_TIME = TIME_CONSTANTS.TEN_MINUTES;
14
+ /**
15
+ * 从错误对象中提取 HTTP 状态码
16
+ * 兼容多种错误对象结构:axios、fetch、自定义等
17
+ */
18
+ function extractHttpStatus(error) {
19
+ if (!error || typeof error !== "object")
20
+ return undefined;
21
+ const err = error;
22
+ // 直接在错误对象上的 status
23
+ if (typeof err.status === "number")
24
+ return err.status;
25
+ if (typeof err.statusCode === "number")
26
+ return err.statusCode;
27
+ // 在 response 对象中的 status (axios 等)
28
+ if (err.response) {
29
+ if (typeof err.response.status === "number")
30
+ return err.response.status;
31
+ if (typeof err.response.statusCode === "number")
32
+ return err.response.statusCode;
33
+ }
34
+ return undefined;
35
+ }
36
+ /**
37
+ * 默认 Query 重试策略
38
+ * - 4XX 客户端错误:不重试(客户端问题,重试无意义)
39
+ * - 5XX 服务端错误:最多重试 1 次(避免过度重试)
40
+ * - 其他错误(网络等):最多重试 2 次
41
+ */
14
42
  export function defaultQueryRetryStrategy(failureCount, error) {
15
- const httpError = error;
16
- if (httpError?.status && httpError.status >= 400 && httpError.status < 600)
17
- return failureCount < 2;
43
+ const status = extractHttpStatus(error);
44
+ // 4XX 客户端错误:不重试
45
+ if (status && status >= 400 && status < 500) {
46
+ return false;
47
+ }
48
+ // 5XX 服务端错误:最多重试 1 次
49
+ if (status && status >= 500 && status < 600) {
50
+ return failureCount < 1;
51
+ }
52
+ // 其他错误(网络错误等):最多重试 2 次
18
53
  return failureCount < 2;
19
54
  }
55
+ /**
56
+ * 默认 Mutation 重试策略
57
+ * - 4XX 客户端错误:不重试
58
+ * - 5XX 服务端错误:不重试(Mutation 更谨慎,避免重复操作)
59
+ * - 其他错误:最多重试 1 次
60
+ */
20
61
  export function defaultMutationRetryStrategy(failureCount, error) {
21
- const httpError = error;
22
- if (httpError?.status && httpError.status >= 400 && httpError.status < 500)
62
+ const status = extractHttpStatus(error);
63
+ // 4XX 客户端错误:不重试
64
+ if (status && status >= 400 && status < 500) {
23
65
  return false;
24
- if (httpError?.status && httpError.status >= 500)
25
- return failureCount < 2;
26
- return failureCount < 2;
66
+ }
67
+ // 5XX 服务端错误:不重试(Mutation 避免重复操作)
68
+ if (status && status >= 500 && status < 600) {
69
+ return false;
70
+ }
71
+ // 其他错误(网络错误等):最多重试 1 次
72
+ return failureCount < 1;
27
73
  }
28
74
  export function exponentialBackoff(attemptIndex) {
29
75
  return Math.min(1000 * 2 ** attemptIndex, 30000);
@@ -109,6 +155,10 @@ export function getConfigByEnvironment(env) {
109
155
  return DEVELOPMENT_CONFIG;
110
156
  case "production":
111
157
  return PRODUCTION_CONFIG;
158
+ case "realtime":
159
+ return REALTIME_CONFIG;
160
+ case "longCache":
161
+ return LONG_CACHE_CONFIG;
112
162
  case "test":
113
163
  return {
114
164
  queries: {
@@ -180,9 +230,10 @@ export function ensureBestPractices(config) {
180
230
  const result = { ...config };
181
231
  if (result.queries) {
182
232
  const queries = { ...result.queries };
233
+ // Handle deprecated cacheTime -> gcTime mapping
183
234
  if ("cacheTime" in queries) {
184
235
  const cacheTime = queries.cacheTime;
185
- if (typeof cacheTime === "number" && typeof queries.gcTime !== "number") {
236
+ if (typeof cacheTime === "number" && queries.gcTime === undefined) {
186
237
  queries.gcTime = cacheTime;
187
238
  }
188
239
  delete queries.cacheTime;
@@ -199,7 +250,7 @@ export function ensureBestPractices(config) {
199
250
  console.warn(`[TanStack Query Config] 自动调整 gcTime 从 ${gcTime}ms 到 ${queries.gcTime}ms,以确保大于 staleTime (${staleTime}ms)。`);
200
251
  }
201
252
  }
202
- if (typeof queries.retryDelay === "number" || !queries.retryDelay) {
253
+ if (queries.retryDelay === undefined) {
203
254
  queries.retryDelay = exponentialBackoff;
204
255
  }
205
256
  if (queries.refetchOnWindowFocus === undefined) {
@@ -209,34 +260,65 @@ export function ensureBestPractices(config) {
209
260
  }
210
261
  return result;
211
262
  }
212
- export function createSafeRetryStrategy(maxRetries500 = 1, maxRetriesOther = 2) {
263
+ /**
264
+ * 创建安全的重试策略
265
+ * @param maxRetries4xx - 4XX 错误最大重试次数(默认 0,不重试)
266
+ * @param maxRetries5xx - 5XX 错误最大重试次数(默认 0,不重试)
267
+ * @param maxRetriesOther - 其他错误最大重试次数(默认 1)
268
+ */
269
+ export function createSafeRetryStrategy(maxRetries4xx = 0, maxRetries5xx = 0, maxRetriesOther = 1) {
213
270
  return (failureCount, error) => {
214
- const httpError = error;
215
- if (httpError?.status && httpError.status >= 400 && httpError.status < 500)
216
- return false;
217
- if (httpError?.status && httpError.status >= 500)
218
- return failureCount < maxRetries500;
271
+ const status = extractHttpStatus(error);
272
+ // 4XX 客户端错误
273
+ if (status && status >= 400 && status < 500) {
274
+ return failureCount < maxRetries4xx;
275
+ }
276
+ // 5XX 服务端错误
277
+ if (status && status >= 500 && status < 600) {
278
+ return failureCount < maxRetries5xx;
279
+ }
280
+ // 其他错误(网络等)
219
281
  return failureCount < maxRetriesOther;
220
282
  };
221
283
  }
284
+ /**
285
+ * 创建错误安全配置
286
+ * 适用于需要严格控制重试和 refetch 行为的场景
287
+ *
288
+ * @example
289
+ * ```typescript
290
+ * // 完全禁用重试
291
+ * const config = createErrorSafeConfig({
292
+ * maxRetries4xx: 0,
293
+ * maxRetries5xx: 0,
294
+ * maxRetriesOther: 0,
295
+ * disableFocus: true,
296
+ * disableReconnect: true
297
+ * });
298
+ * ```
299
+ */
222
300
  export function createErrorSafeConfig(options = {}) {
223
- const { maxRetries500 = 1, maxRetriesOther = 2, disableFocus = false, disableReconnect = false, conditionalRefetchInterval, overrides } = options;
301
+ const { maxRetries4xx = 0, maxRetries5xx = 0, maxRetriesOther = 1, disableFocus = false, disableReconnect = false, conditionalRefetchInterval, overrides } = options;
224
302
  const queries = {
225
303
  ...DEFAULT_QUERY_CONFIG,
226
- retry: createSafeRetryStrategy(maxRetries500, maxRetriesOther),
304
+ retry: createSafeRetryStrategy(maxRetries4xx, maxRetries5xx, maxRetriesOther),
227
305
  retryDelay: exponentialBackoff,
228
306
  refetchOnWindowFocus: disableFocus ? false : true,
229
307
  refetchOnReconnect: disableReconnect ? false : true
230
308
  };
231
309
  if (conditionalRefetchInterval !== undefined) {
232
310
  if (typeof conditionalRefetchInterval === "number") {
233
- queries.refetchInterval = (_data, query) => (query?.state?.error ? false : conditionalRefetchInterval);
311
+ queries.refetchInterval = (query) => (query?.state?.error ? false : conditionalRefetchInterval);
234
312
  }
235
313
  else {
236
- queries.refetchInterval = conditionalRefetchInterval;
314
+ const fn = conditionalRefetchInterval;
315
+ queries.refetchInterval = (query) => (fn.length >= 2 ? fn(query?.state?.data, query) : fn(query));
237
316
  }
238
317
  }
239
- const mutations = { ...DEFAULT_MUTATION_CONFIG };
318
+ const mutations = {
319
+ ...DEFAULT_MUTATION_CONFIG,
320
+ retry: createSafeRetryStrategy(maxRetries4xx, maxRetries5xx, maxRetriesOther)
321
+ };
240
322
  const result = {
241
323
  queries: { ...queries, ...(overrides?.queries || {}) },
242
324
  mutations: { ...mutations, ...(overrides?.mutations || {}) }
@@ -1 +1 @@
1
- {"version":3,"file":"queryOptions.d.ts","sourceRoot":"","sources":["../../src/core/queryOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAIpG,MAAM,WAAW,eAAe,CAAC,KAAK;IACpC,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,KAAK,CAAC,GAAG,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,CAAC,CAalI;AAED,MAAM,WAAW,iBAAiB,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,CAAE,SAAQ,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC;IAC1G,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,SAAS,CAAC;CACpC;AAED,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,EAAE,MAAM,EAAE,iBAAiB,CAAC,KAAK,EAAE,SAAS,CAAC,GAAG,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,CAAC,CAahL;AAED,MAAM,WAAW,eAAe,CAAC,KAAK,CAAE,SAAQ,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IAClG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,KAAK,CAAC,GAAG,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,CAAC,CAanI"}
1
+ {"version":3,"file":"queryOptions.d.ts","sourceRoot":"","sources":["../../src/core/queryOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAIpG,MAAM,WAAW,eAAe,CAAC,KAAK;IACpC,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,KAAK,CAAC,GAAG,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,CAAC,CASlI;AAED,MAAM,WAAW,iBAAiB,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,CAAE,SAAQ,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC;IAC1G,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,SAAS,CAAC;CACpC;AAED,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,EAAE,MAAM,EAAE,iBAAiB,CAAC,KAAK,EAAE,SAAS,CAAC,GAAG,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,CAAC,CAShL;AAED,MAAM,WAAW,eAAe,CAAC,KAAK,CAAE,SAAQ,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IAClG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,KAAK,CAAC,GAAG,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,CAAC,CASnI"}
@@ -1,44 +1,32 @@
1
1
  import { queryOptions } from "@tanstack/react-query";
2
- import { DEFAULT_GC_TIME, DEFAULT_STALE_TIME, defaultQueryRetryStrategy, exponentialBackoff } from "./config.js";
2
+ import { DEFAULT_GC_TIME, DEFAULT_QUERY_CONFIG, DEFAULT_STALE_TIME } from "./config.js";
3
3
  export function createAppQueryOptions(config) {
4
4
  return queryOptions({
5
+ ...DEFAULT_QUERY_CONFIG,
5
6
  queryKey: config.queryKey,
6
7
  queryFn: config.queryFn,
7
- staleTime: config.staleTime ?? DEFAULT_STALE_TIME,
8
- gcTime: config.gcTime ?? DEFAULT_GC_TIME,
8
+ staleTime: config.staleTime ?? DEFAULT_QUERY_CONFIG.staleTime ?? DEFAULT_STALE_TIME,
9
+ gcTime: config.gcTime ?? DEFAULT_QUERY_CONFIG.gcTime ?? DEFAULT_GC_TIME,
9
10
  enabled: config.enabled,
10
- retry: defaultQueryRetryStrategy,
11
- retryDelay: exponentialBackoff,
12
- refetchOnWindowFocus: true,
13
- refetchOnReconnect: true,
14
- refetchOnMount: true
15
11
  });
16
12
  }
17
13
  export function createAppQueryOptionsWithSelect(config) {
18
14
  return queryOptions({
15
+ ...DEFAULT_QUERY_CONFIG,
19
16
  queryKey: config.queryKey,
20
17
  queryFn: config.queryFn,
21
18
  select: config.select,
22
- staleTime: config.staleTime ?? DEFAULT_STALE_TIME,
23
- gcTime: config.gcTime ?? DEFAULT_GC_TIME,
24
- retry: defaultQueryRetryStrategy,
25
- retryDelay: exponentialBackoff,
26
- refetchOnWindowFocus: true,
27
- refetchOnReconnect: true,
28
- refetchOnMount: true
19
+ staleTime: config.staleTime ?? DEFAULT_QUERY_CONFIG.staleTime ?? DEFAULT_STALE_TIME,
20
+ gcTime: config.gcTime ?? DEFAULT_QUERY_CONFIG.gcTime ?? DEFAULT_GC_TIME,
29
21
  });
30
22
  }
31
23
  export function createListQueryOptions(config) {
32
24
  return queryOptions({
25
+ ...DEFAULT_QUERY_CONFIG,
33
26
  queryKey: config.queryKey,
34
27
  queryFn: config.queryFn,
35
28
  staleTime: config.staleTime ?? 0,
36
- gcTime: config.gcTime ?? DEFAULT_GC_TIME,
29
+ gcTime: config.gcTime ?? DEFAULT_QUERY_CONFIG.gcTime ?? DEFAULT_GC_TIME,
37
30
  enabled: config.enabled,
38
- retry: defaultQueryRetryStrategy,
39
- retryDelay: exponentialBackoff,
40
- refetchOnWindowFocus: true,
41
- refetchOnReconnect: true,
42
- refetchOnMount: true
43
31
  });
44
32
  }
@@ -1,4 +1,4 @@
1
1
  export { cancelQueriesBatch, invalidateQueriesBatch, setQueryDataBatch } from "../hooks/useMutation.js";
2
- export { calculateExponentialBackoff, configureOfflineQueries, createOfflineQueueManager, isOnline, mutationRegistry, OfflineQueueManager, setupOnlineManager, subscribeToOnlineStatus } from "./offline.js";
2
+ export { calculateExponentialBackoff, configureOfflineQueries, createOfflineQueueManager, isOnline, mutationRegistry, OfflineQueueManager, serializeMutationKey, setupOnlineManager, subscribeToOnlineStatus } from "./offline.js";
3
3
  export { checkStorageSize, clearCache, clearExpiredCache, createPersister, createPersistOptions, getStorageStats, migrateToIndexedDB, type PersistedClient, type Persister, type PersistOptions } from "./persistence.js";
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/features/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACxG,OAAO,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC7M,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,iBAAiB,EAAE,eAAe,EAAE,oBAAoB,EAAE,eAAe,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/features/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACxG,OAAO,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACnO,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,iBAAiB,EAAE,eAAe,EAAE,oBAAoB,EAAE,eAAe,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
@@ -1,3 +1,3 @@
1
1
  export { cancelQueriesBatch, invalidateQueriesBatch, setQueryDataBatch } from "../hooks/useMutation.js";
2
- export { calculateExponentialBackoff, configureOfflineQueries, createOfflineQueueManager, isOnline, mutationRegistry, OfflineQueueManager, setupOnlineManager, subscribeToOnlineStatus } from "./offline.js";
2
+ export { calculateExponentialBackoff, configureOfflineQueries, createOfflineQueueManager, isOnline, mutationRegistry, OfflineQueueManager, serializeMutationKey, setupOnlineManager, subscribeToOnlineStatus } from "./offline.js";
3
3
  export { checkStorageSize, clearCache, clearExpiredCache, createPersister, createPersistOptions, getStorageStats, migrateToIndexedDB } from "./persistence.js";
@@ -4,6 +4,7 @@ export declare function setupOnlineManager(): void;
4
4
  export declare const isOnline: () => boolean;
5
5
  export declare function subscribeToOnlineStatus(callback: (online: boolean) => void): () => void;
6
6
  export declare function configureOfflineQueries(_queryClient: QueryClient): void;
7
+ export declare function serializeMutationKey(mutationKey: unknown): string;
7
8
  export declare function calculateExponentialBackoff(attempt: number, baseDelay?: number, maxDelay?: number): number;
8
9
  declare class MutationRegistry implements MutationFunctionRegistry {
9
10
  private registry;
@@ -1 +1 @@
1
- {"version":3,"file":"offline.d.ts","sourceRoot":"","sources":["../../src/features/offline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAK7H,wBAAgB,kBAAkB,SAYjC;AACD,eAAO,MAAM,QAAQ,eAAiC,CAAC;AACvD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,cAA+C;AAC1H,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,WAAW,QAAI;AAGrE,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,SAAO,EAAE,QAAQ,SAAQ,GAAG,MAAM,CAIvG;AACD,cAAM,gBAAiB,YAAW,wBAAwB;IACxD,OAAO,CAAC,QAAQ,CAA6C;IAC7D,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI;IACvD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,SAAS;IACtD,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAC7B,KAAK,IAAI,IAAI;IACb,OAAO,IAAI,MAAM,EAAE;CACpB;AACD,eAAO,MAAM,gBAAgB,kBAAyB,CAAC;AAEvD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,mBAAmB,CAAqB;gBACpC,MAAM,GAAE,OAAO,CAAC,kBAAkB,CAAM;IAM9C,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,wBAAwB,EAAE,IAAI,GAAG,WAAW,GAAG,YAAY,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IASlG,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOnD,QAAQ,IAAI,YAAY;IAIxB,aAAa,IAAI,wBAAwB,EAAE;IACrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IACtB,OAAO,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;YAmBhE,gBAAgB;IAsB9B,OAAO,CAAC,0BAA0B;IAsBlC,OAAO,CAAC,aAAa;YAKP,YAAY;IAe1B,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,mBAAmB;IAG3B,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,iBAAiB;IAGzB,OAAO,IAAI,IAAI;CAKhB;AACD,wBAAgB,yBAAyB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,mBAAmB,CAA4C"}
1
+ {"version":3,"file":"offline.d.ts","sourceRoot":"","sources":["../../src/features/offline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAK7H,wBAAgB,kBAAkB,SAYjC;AACD,eAAO,MAAM,QAAQ,eAAiC,CAAC;AACvD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,cAA+C;AAC1H,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,WAAW,QAAI;AAWrE,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,CAOjE;AAGD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,SAAO,EAAE,QAAQ,SAAQ,GAAG,MAAM,CAIvG;AACD,cAAM,gBAAiB,YAAW,wBAAwB;IACxD,OAAO,CAAC,QAAQ,CAA6C;IAC7D,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI;IACvD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,SAAS;IACtD,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAC7B,KAAK,IAAI,IAAI;IACb,OAAO,IAAI,MAAM,EAAE;CACpB;AACD,eAAO,MAAM,gBAAgB,kBAAyB,CAAC;AAEvD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,mBAAmB,CAAqB;gBACpC,MAAM,GAAE,OAAO,CAAC,kBAAkB,CAAM;IAO9C,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,wBAAwB,EAAE,IAAI,GAAG,WAAW,GAAG,YAAY,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAUlG,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOnD,QAAQ,IAAI,YAAY;IAIxB,aAAa,IAAI,wBAAwB,EAAE;IACrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IACtB,OAAO,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;YAoBhE,gBAAgB;IAuB9B,OAAO,CAAC,0BAA0B;IAsBlC,OAAO,CAAC,aAAa;YAKP,YAAY;IAe1B,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,mBAAmB;IAG3B,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,iBAAiB;IAGzB,OAAO,IAAI,IAAI;CAKhB;AACD,wBAAgB,yBAAyB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,mBAAmB,CAA4C"}
@@ -18,6 +18,27 @@ export function setupOnlineManager() {
18
18
  export const isOnline = () => onlineManager.isOnline();
19
19
  export function subscribeToOnlineStatus(callback) { return onlineManager.subscribe(callback); }
20
20
  export function configureOfflineQueries(_queryClient) { }
21
+ function sortObjectKeys(value) {
22
+ if (value === null || value === undefined)
23
+ return value;
24
+ if (typeof value !== "object")
25
+ return value;
26
+ if (Array.isArray(value))
27
+ return value.map(sortObjectKeys);
28
+ const sorted = {};
29
+ Object.keys(value).sort().forEach((key) => { sorted[key] = sortObjectKeys(value[key]); });
30
+ return sorted;
31
+ }
32
+ export function serializeMutationKey(mutationKey) {
33
+ try {
34
+ if (typeof mutationKey === "string")
35
+ return mutationKey;
36
+ return JSON.stringify(sortObjectKeys(mutationKey));
37
+ }
38
+ catch {
39
+ return String(mutationKey);
40
+ }
41
+ }
21
42
  const DEFAULT_QUEUE_CONFIG = { enabled: true, maxSize: 100, persist: true, storageKey: "tanstack-query-offline-queue", autoExecuteInterval: 5000, executeOnReconnect: true, operationTimeout: 30000, concurrency: 3 };
22
43
  export function calculateExponentialBackoff(attempt, baseDelay = 1000, maxDelay = 30000) {
23
44
  const delay = Math.min(baseDelay * 2 ** attempt, maxDelay);
@@ -43,6 +64,9 @@ export class OfflineQueueManager {
43
64
  this.unsubscribeOnline = null;
44
65
  this.executingOperations = new Set();
45
66
  this.config = { ...DEFAULT_QUEUE_CONFIG, ...config };
67
+ if (!this.config.enabled) {
68
+ return;
69
+ }
46
70
  if (this.config.persist) {
47
71
  this.loadQueue();
48
72
  }
@@ -54,6 +78,9 @@ export class OfflineQueueManager {
54
78
  }
55
79
  }
56
80
  async add(operation) {
81
+ if (!this.config.enabled) {
82
+ throw new Error("Offline queue is disabled");
83
+ }
57
84
  const id = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
58
85
  const newOperation = { ...operation, id, createdAt: new Date(), retryCount: 0 };
59
86
  if (this.queue.length >= this.config.maxSize) {
@@ -90,6 +117,9 @@ export class OfflineQueueManager {
90
117
  await this.persistQueue();
91
118
  } }
92
119
  async execute() {
120
+ if (!this.config.enabled) {
121
+ return { success: 0, failed: 0, skipped: this.queue.length };
122
+ }
93
123
  if (this.isExecuting) {
94
124
  return { success: 0, failed: 0, skipped: this.queue.length };
95
125
  }
@@ -141,8 +171,9 @@ export class OfflineQueueManager {
141
171
  }
142
172
  this.executingOperations.add(operation.id);
143
173
  try {
144
- const mutationKey = Array.isArray(operation.mutationKey) ? operation.mutationKey.join("-") : String(operation.mutationKey);
145
- const mutationFn = mutationRegistry.get(mutationKey) || operation.mutationFn;
174
+ const mutationKey = serializeMutationKey(operation.mutationKey);
175
+ const legacyMutationKey = Array.isArray(operation.mutationKey) ? operation.mutationKey.join("-") : String(operation.mutationKey);
176
+ const mutationFn = mutationRegistry.get(mutationKey) || mutationRegistry.get(legacyMutationKey) || operation.mutationFn;
146
177
  const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error("Operation timeout")), this.config.operationTimeout); });
147
178
  await Promise.race([mutationFn(), timeoutPromise]);
148
179
  await this.remove(operation.id);
@@ -1 +1 @@
1
- {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../src/features/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AAsBvF,MAAM,WAAW,cAAc;IAAG,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAAC,gBAAgB,CAAC,EAAE;QAAE,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAA;KAAE,CAAA;CAAE;AAC1J,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,OAAO,CAAC,cAAc,CAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE;QAAE,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAA;KAAE,CAAA;CAAE,CAiBtK;AACD,wBAAgB,eAAe,CAAC,UAAU,SAAyB,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,SAAS,GAAG,SAAS,CAa/I;AACD,wBAAgB,UAAU,CAAC,GAAG,SAAyB,GAAG,IAAI,CAA0D;AACxH,wBAAgB,iBAAiB,CAAC,GAAG,SAAyB,EAAE,MAAM,SAAsB,GAAG,IAAI,CAQlG;AACD,wBAAsB,kBAAkB,CAAC,eAAe,oBAAyB,EAAE,YAAY,oBAAyB,EAAE,gBAAgB,EAAE,OAAO,GAAG;IAAE,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAWlO;AACD,wBAAgB,gBAAgB,CAAC,GAAG,SAAyB,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CASjJ;AACD,wBAAgB,eAAe,CAAC,GAAG,SAAyB,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAA;CAAE,CAS9L;AACD,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../src/features/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AAuBvF,MAAM,WAAW,cAAc;IAAG,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAAC,gBAAgB,CAAC,EAAE;QAAE,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAA;KAAE,CAAA;CAAE;AAC1J,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,OAAO,CAAC,cAAc,CAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE;QAAE,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAA;KAAE,CAAA;CAAE,CAiBtK;AACD,wBAAgB,eAAe,CAAC,UAAU,SAAyB,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,SAAS,GAAG,SAAS,CAa/I;AACD,wBAAgB,UAAU,CAAC,GAAG,SAAyB,GAAG,IAAI,CAA0D;AACxH,wBAAgB,iBAAiB,CAAC,GAAG,SAAyB,EAAE,MAAM,SAAyB,GAAG,IAAI,CAQrG;AACD,wBAAsB,kBAAkB,CAAC,eAAe,oBAAyB,EAAE,YAAY,oBAAyB,EAAE,gBAAgB,EAAE,OAAO,GAAG;IAAE,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAWlO;AACD,wBAAgB,gBAAgB,CAAC,GAAG,SAAyB,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CASjJ;AACD,wBAAgB,eAAe,CAAC,GAAG,SAAyB,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAA;CAAE,CAS9L;AACD,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { TIME_CONSTANTS } from "../core/config.js";
1
2
  function isSerializable(data) {
2
3
  try {
3
4
  JSON.stringify(data);
@@ -54,7 +55,7 @@ function createSafeStorage(storage, key) {
54
55
  };
55
56
  }
56
57
  export function createPersistOptions(config = {}) {
57
- const { maxAge = 1000 * 60 * 60 * 24, onlyPersistSuccess = true, dehydrateOptions } = config;
58
+ const { maxAge = TIME_CONSTANTS.ONE_DAY, onlyPersistSuccess = true, dehydrateOptions } = config;
58
59
  return {
59
60
  maxAge,
60
61
  dehydrateOptions: {
@@ -120,7 +121,7 @@ export function clearCache(key = "tanstack-query-cache") { try {
120
121
  window.localStorage.removeItem(key);
121
122
  }
122
123
  catch { } }
123
- export function clearExpiredCache(key = "tanstack-query-cache", maxAge = 1000 * 60 * 60 * 24) {
124
+ export function clearExpiredCache(key = "tanstack-query-cache", maxAge = TIME_CONSTANTS.ONE_DAY) {
124
125
  try {
125
126
  const stored = window.localStorage.getItem(key);
126
127
  if (!stored)
@@ -1 +1 @@
1
- {"version":3,"file":"useDataGuardMutation.d.ts","sourceRoot":"","sources":["../../src/hooks/useDataGuardMutation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAA8B,MAAM,uBAAuB,CAAC;AAuBzF,MAAM,WAAW,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAE,SAAQ,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC;IACzI,aAAa;IACb,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,SAAS,eAAe,GAAG,eAAe,EAC/C,MAAM,GAAG,KAAK,EACd,UAAU,SAAS,eAAe,GAAG,eAAe,EACpD,QAAQ,GAAG,OAAO,EAElB,UAAU,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,KAAK,CAAC,EAChD,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,GACtE,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAkHxD"}
1
+ {"version":3,"file":"useDataGuardMutation.d.ts","sourceRoot":"","sources":["../../src/hooks/useDataGuardMutation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAA8B,MAAM,uBAAuB,CAAC;AAOzF,MAAM,WAAW,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAE,SAAQ,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC;IACzI,aAAa;IACb,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,SAAS,eAAe,GAAG,eAAe,EAC/C,MAAM,GAAG,KAAK,EACd,UAAU,SAAS,eAAe,GAAG,eAAe,EACpD,QAAQ,GAAG,OAAO,EAElB,UAAU,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,KAAK,CAAC,EAChD,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,GACtE,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAkHxD"}
@@ -2,21 +2,7 @@ import { useQueryClient } from "@tanstack/react-query";
2
2
  import { useMutation } from "./useMutation.js";
3
3
  import { ConflictError } from "../types/dataGuard.js";
4
4
  import { hashObject, markRecentlyUpdated, clearRecentlyUpdated, updateFamilyMetadata } from "../utils/dataGuard.js";
5
- /**
6
- * Check if a query key starts with a given prefix
7
- */
8
- function startsWithKeyPrefix(key, prefix) {
9
- const k = Array.isArray(key) ? key : [key];
10
- const p = Array.isArray(prefix) ? prefix : [prefix];
11
- if (p.length > k.length)
12
- return false;
13
- for (let i = 0; i < p.length; i++) {
14
- if (JSON.stringify(k[i]) !== JSON.stringify(p[i])) {
15
- return false;
16
- }
17
- }
18
- return true;
19
- }
5
+ import { startsWithKeyPrefix } from "../utils/queryKey.js";
20
6
  /**
21
7
  * 带数据防护的 Mutation Hook
22
8
  *
@@ -34,9 +34,9 @@ export function useMutation(options) {
34
34
  const { optimistic, onMutate, onError, onSuccess, onSettled, ...restOptions } = options;
35
35
  const mutationConfig = {
36
36
  ...restOptions,
37
- retry: restOptions.retry ?? DEFAULT_MUTATION_CONFIG?.retry,
38
- retryDelay: restOptions.retryDelay ?? DEFAULT_MUTATION_CONFIG?.retryDelay,
39
- gcTime: restOptions.gcTime ?? DEFAULT_MUTATION_CONFIG?.gcTime
37
+ retry: restOptions.retry ?? DEFAULT_MUTATION_CONFIG.retry,
38
+ retryDelay: restOptions.retryDelay ?? DEFAULT_MUTATION_CONFIG.retryDelay,
39
+ gcTime: restOptions.gcTime ?? DEFAULT_MUTATION_CONFIG.gcTime
40
40
  };
41
41
  if (!optimistic) {
42
42
  if (onMutate) {
@@ -22,7 +22,7 @@ export interface VersionedPaginatedResponse<T> {
22
22
  version?: number;
23
23
  updatedAt?: string;
24
24
  _hash?: string;
25
- _recentlyUpdatedIds?: Set<string | number>;
25
+ _recentlyUpdatedIds?: Array<string | number> | Set<string | number>;
26
26
  }
27
27
  /**
28
28
  * 旧数据检测信息
@@ -1 +1 @@
1
- {"version":3,"file":"dataGuard.d.ts","sourceRoot":"","sources":["../../src/types/dataGuard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1E;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;CAC5C;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,GAAG,CAAC;IACZ,QAAQ,EAAE,GAAG,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sBAAsB;IACtB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,sBAAsB;IACtB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,yBAAyB;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iBAAiB;IACjB,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IACpD,eAAe;IACf,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;CACpD;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACnB,OAAO,EAAE,GAAG;gBAAZ,OAAO,EAAE,GAAG;CAIhC"}
1
+ {"version":3,"file":"dataGuard.d.ts","sourceRoot":"","sources":["../../src/types/dataGuard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1E;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;CACrE;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,GAAG,CAAC;IACZ,QAAQ,EAAE,GAAG,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sBAAsB;IACtB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,sBAAsB;IACtB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,yBAAyB;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iBAAiB;IACjB,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IACpD,eAAe;IACf,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;CACpD;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACnB,OAAO,EAAE,GAAG;gBAAZ,OAAO,EAAE,GAAG;CAIhC"}
@@ -1 +1 @@
1
- {"version":3,"file":"dataGuard.d.ts","sourceRoot":"","sources":["../../src/utils/dataGuard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,0BAA0B,EAC3B,MAAM,uBAAuB,CAAC;AA+C/B;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAO3C;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,eAAe,EACtD,OAAO,EAAE,0BAA0B,CAAC,CAAC,CAAC,EACtC,MAAM,EAAE,0BAA0B,CAAC,CAAC,CAAC,GAAG,SAAS,EACjD,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,gBAAqB,GAC7B;IACD,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,YAAY,EAAE,GAAG,CAAC;CACnB,CA+IA;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,eAAe,EACrD,IAAI,EAAE,0BAA0B,CAAC,CAAC,CAAC,GAClC,0BAA0B,CAAC,CAAC,CAAC,CAK/B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,eAAe,EAC3D,IAAI,EAAE,0BAA0B,CAAC,CAAC,CAAC,EACnC,SAAS,EAAE,MAAM,GAAG,MAAM,GACzB,0BAA0B,CAAC,CAAC,CAAC,CAQ/B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,eAAe,EAC5D,IAAI,EAAE,0BAA0B,CAAC,CAAC,CAAC,EACnC,SAAS,EAAE,MAAM,GAAG,MAAM,GACzB,0BAA0B,CAAC,CAAC,CAAC,CAU/B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,eAAe,EAC5D,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,QAAQ,EACnB,QAAQ,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,GAC/C,IAAI,CAiCN"}
1
+ {"version":3,"file":"dataGuard.d.ts","sourceRoot":"","sources":["../../src/utils/dataGuard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,0BAA0B,EAC3B,MAAM,uBAAuB,CAAC;AA+B/B;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAO3C;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,eAAe,EACtD,OAAO,EAAE,0BAA0B,CAAC,CAAC,CAAC,EACtC,MAAM,EAAE,0BAA0B,CAAC,CAAC,CAAC,GAAG,SAAS,EACjD,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,gBAAqB,GAC7B;IACD,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,YAAY,EAAE,GAAG,CAAC;CACnB,CAqJA;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,eAAe,EACrD,IAAI,EAAE,0BAA0B,CAAC,CAAC,CAAC,GAClC,0BAA0B,CAAC,CAAC,CAAC,CAK/B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,eAAe,EAC3D,IAAI,EAAE,0BAA0B,CAAC,CAAC,CAAC,EACnC,SAAS,EAAE,MAAM,GAAG,MAAM,GACzB,0BAA0B,CAAC,CAAC,CAAC,CAY/B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,eAAe,EAC5D,IAAI,EAAE,0BAA0B,CAAC,CAAC,CAAC,EACnC,SAAS,EAAE,MAAM,GAAG,MAAM,GACzB,0BAA0B,CAAC,CAAC,CAAC,CAU/B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,eAAe,EAC5D,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,QAAQ,EACnB,QAAQ,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,GAC/C,IAAI,CAiCN"}
@@ -1,18 +1,4 @@
1
- /**
2
- * Check if a query key starts with a given prefix
3
- */
4
- function startsWithKeyPrefix(key, prefix) {
5
- const k = Array.isArray(key) ? key : [key];
6
- const p = Array.isArray(prefix) ? prefix : [prefix];
7
- if (p.length > k.length)
8
- return false;
9
- for (let i = 0; i < p.length; i++) {
10
- if (JSON.stringify(k[i]) !== JSON.stringify(p[i])) {
11
- return false;
12
- }
13
- }
14
- return true;
15
- }
1
+ import { startsWithKeyPrefix } from "./queryKey.js";
16
2
  /**
17
3
  * 简单的字符串哈希函数(DJB2算法变体)
18
4
  */
@@ -156,7 +142,11 @@ export function applyDataGuard(newData, cached, queryKey, options = {}) {
156
142
  shouldReject = true;
157
143
  reason = "内容哈希相同,数据未变化";
158
144
  }
159
- else if (cachedHash && cached._recentlyUpdatedIds && cached._recentlyUpdatedIds.size > 0) {
145
+ else if (cachedHash &&
146
+ cached._recentlyUpdatedIds &&
147
+ (Array.isArray(cached._recentlyUpdatedIds)
148
+ ? cached._recentlyUpdatedIds.length > 0
149
+ : cached._recentlyUpdatedIds.size > 0)) {
160
150
  // 检查最近更新的项是否被回退
161
151
  let hasRevert = false;
162
152
  for (const id of cached._recentlyUpdatedIds) {
@@ -201,11 +191,15 @@ export function addHashToData(data) {
201
191
  * 标记最近更新的项
202
192
  */
203
193
  export function markRecentlyUpdated(data, updatedId) {
204
- const recentlyUpdatedIds = new Set(data._recentlyUpdatedIds || []);
205
- recentlyUpdatedIds.add(updatedId);
194
+ const existing = data._recentlyUpdatedIds
195
+ ? (Array.isArray(data._recentlyUpdatedIds) ? [...data._recentlyUpdatedIds] : Array.from(data._recentlyUpdatedIds))
196
+ : [];
197
+ if (!existing.includes(updatedId)) {
198
+ existing.push(updatedId);
199
+ }
206
200
  return {
207
201
  ...data,
208
- _recentlyUpdatedIds: recentlyUpdatedIds
202
+ _recentlyUpdatedIds: existing
209
203
  };
210
204
  }
211
205
  /**
@@ -214,11 +208,11 @@ export function markRecentlyUpdated(data, updatedId) {
214
208
  export function clearRecentlyUpdated(data, updatedId) {
215
209
  if (!data._recentlyUpdatedIds)
216
210
  return data;
217
- const recentlyUpdatedIds = new Set(data._recentlyUpdatedIds);
218
- recentlyUpdatedIds.delete(updatedId);
211
+ const existing = Array.isArray(data._recentlyUpdatedIds) ? data._recentlyUpdatedIds : Array.from(data._recentlyUpdatedIds);
212
+ const remaining = existing.filter((id) => id !== updatedId);
219
213
  return {
220
214
  ...data,
221
- _recentlyUpdatedIds: recentlyUpdatedIds.size > 0 ? recentlyUpdatedIds : undefined
215
+ _recentlyUpdatedIds: remaining.length > 0 ? remaining : undefined
222
216
  };
223
217
  }
224
218
  /**
@@ -3,7 +3,7 @@ export { getNetworkInfo, getNetworkSpeed, isFastNetwork, isSlowNetwork, type Nav
3
3
  export { batchRemoveItems, batchUpdateItems, conditionalUpdateItems, createAddItemConfig, createListOperationConfig, createRemoveItemConfig, createUpdateItemConfig, type ListOperationVariables, listUpdater, reorderItems } from "./optimisticUtils.js";
4
4
  export { keepPreviousData, stableListPlaceholder } from "./placeholderData.js";
5
5
  export { getPrefetchManager, type InteractionRecord, type NetworkSpeed, type PredictionResult, type PrefetchConfig, type PrefetchStats, type PrefetchTask, resetPrefetchManager, SmartPrefetchManager } from "./prefetchManager.js";
6
- export { createQueryKeyFactory, createSimpleQueryKeyFactory, extractParamsFromKey, isQueryKeyEqual, type NormalizeConfig, normalizeQueryParams, type QueryKeyFactory, type QueryKeyFactoryConfig } from "./queryKey.js";
6
+ export { createQueryKeyFactory, createSimpleQueryKeyFactory, extractParamsFromKey, isQueryKeyEqual, startsWithKeyPrefix, type NormalizeConfig, normalizeQueryParams, type QueryKeyFactory, type QueryKeyFactoryConfig } from "./queryKey.js";
7
7
  export { compose, selectById, selectByIds, selectCount, selectField, selectFields, selectFirst, selectItems, selectLast, selectMap, selectors, selectTotal, selectWhere } from "./selectors.js";
8
8
  export { deepClone, formatBytes, getStorageUsage, isStorageAvailable } from "./storage.js";
9
9
  export { applyDataGuard, addHashToData, hashObject, markRecentlyUpdated, clearRecentlyUpdated, updateFamilyMetadata } from "./dataGuard.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACpH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC3H,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,KAAK,sBAAsB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC1P,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACpO,OAAO,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,oBAAoB,EAAE,KAAK,eAAe,EAAE,KAAK,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACxN,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAChM,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC3F,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,UAAU,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACpH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC3H,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,KAAK,sBAAsB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC1P,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACpO,OAAO,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,eAAe,EAAE,mBAAmB,EAAE,KAAK,eAAe,EAAE,oBAAoB,EAAE,KAAK,eAAe,EAAE,KAAK,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC7O,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAChM,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC3F,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,UAAU,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -3,7 +3,7 @@ export { getNetworkInfo, getNetworkSpeed, isFastNetwork, isSlowNetwork } from ".
3
3
  export { batchRemoveItems, batchUpdateItems, conditionalUpdateItems, createAddItemConfig, createListOperationConfig, createRemoveItemConfig, createUpdateItemConfig, listUpdater, reorderItems } from "./optimisticUtils.js";
4
4
  export { keepPreviousData, stableListPlaceholder } from "./placeholderData.js";
5
5
  export { getPrefetchManager, resetPrefetchManager, SmartPrefetchManager } from "./prefetchManager.js";
6
- export { createQueryKeyFactory, createSimpleQueryKeyFactory, extractParamsFromKey, isQueryKeyEqual, normalizeQueryParams } from "./queryKey.js";
6
+ export { createQueryKeyFactory, createSimpleQueryKeyFactory, extractParamsFromKey, isQueryKeyEqual, startsWithKeyPrefix, normalizeQueryParams } from "./queryKey.js";
7
7
  export { compose, selectById, selectByIds, selectCount, selectField, selectFields, selectFirst, selectItems, selectLast, selectMap, selectors, selectTotal, selectWhere } from "./selectors.js";
8
8
  export { deepClone, formatBytes, getStorageUsage, isStorageAvailable } from "./storage.js";
9
9
  export { applyDataGuard, addHashToData, hashObject, markRecentlyUpdated, clearRecentlyUpdated, updateFamilyMetadata } from "./dataGuard.js";
@@ -1,3 +1,4 @@
1
+ import type { QueryKey } from "@tanstack/react-query";
1
2
  export interface NormalizeConfig<T = any> {
2
3
  required?: (keyof T)[];
3
4
  defaults?: Partial<T>;
@@ -21,4 +22,5 @@ export declare function createQueryKeyFactory<TParams = any>(config: QueryKeyFac
21
22
  export declare function createSimpleQueryKeyFactory(namespace: string): QueryKeyFactory;
22
23
  export declare function isQueryKeyEqual(key1: readonly any[], key2: readonly any[]): boolean;
23
24
  export declare function extractParamsFromKey(queryKey: readonly any[]): Record<string, any> | undefined;
25
+ export declare function startsWithKeyPrefix(key: QueryKey, prefix: QueryKey): boolean;
24
26
  //# sourceMappingURL=queryKey.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"queryKey.d.ts","sourceRoot":"","sources":["../../src/utils/queryKey.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,GAAG;IAAI,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE;AACtI,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,SAAS,EAAE,MAAM,GAAE,eAAe,CAAC,CAAC,CAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAuB/I;AACD,MAAM,WAAW,qBAAqB,CAAC,OAAO,GAAG,GAAG;IAAI,SAAS,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,eAAe,CAAC,OAAO,CAAC,CAAA;CAAE;AACvH,MAAM,WAAW,eAAe,CAAC,OAAO,GAAG,GAAG;IAAI,GAAG,EAAE,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAAC,OAAO,EAAE,MAAM,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,KAAK,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;CAAE;AAC/X,wBAAgB,qBAAqB,CAAC,OAAO,GAAG,GAAG,EAAE,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,GAAG,eAAe,CAAC,OAAO,CAAC,CAUrH;AACD,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CAAiD;AAChI,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,GAAG,EAAE,GAAG,OAAO,CAUnF;AACD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,SAAS,GAAG,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAI9F"}
1
+ {"version":3,"file":"queryKey.d.ts","sourceRoot":"","sources":["../../src/utils/queryKey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,GAAG;IAAI,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE;AACtI,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,SAAS,EAAE,MAAM,GAAE,eAAe,CAAC,CAAC,CAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAuB/I;AACD,MAAM,WAAW,qBAAqB,CAAC,OAAO,GAAG,GAAG;IAAI,SAAS,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,eAAe,CAAC,OAAO,CAAC,CAAA;CAAE;AACvH,MAAM,WAAW,eAAe,CAAC,OAAO,GAAG,GAAG;IAAI,GAAG,EAAE,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAAC,OAAO,EAAE,MAAM,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,KAAK,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;CAAE;AAC/X,wBAAgB,qBAAqB,CAAC,OAAO,GAAG,GAAG,EAAE,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,GAAG,eAAe,CAAC,OAAO,CAAC,CAUrH;AACD,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CAAiD;AAChI,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,GAAG,EAAE,GAAG,OAAO,CAUnF;AACD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,SAAS,GAAG,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAI9F;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAU5E"}
@@ -75,3 +75,15 @@ export function extractParamsFromKey(queryKey) {
75
75
  }
76
76
  return undefined;
77
77
  }
78
+ export function startsWithKeyPrefix(key, prefix) {
79
+ const k = Array.isArray(key) ? key : [key];
80
+ const p = Array.isArray(prefix) ? prefix : [prefix];
81
+ if (p.length > k.length)
82
+ return false;
83
+ for (let i = 0; i < p.length; i++) {
84
+ if (JSON.stringify(k[i]) !== JSON.stringify(p[i])) {
85
+ return false;
86
+ }
87
+ }
88
+ return true;
89
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qiaopeng/tanstack-query-plus",
3
- "version": "0.5.7",
3
+ "version": "0.5.9",
4
4
  "description": "Enhanced TanStack Query toolkit: defaults, hooks, persistence, offline, data guard, utils",
5
5
  "author": "qiaopeng",
6
6
  "license": "MIT",