@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 +135 -46
- package/dist/PersistQueryClientProvider.d.ts.map +1 -1
- package/dist/PersistQueryClientProvider.js +17 -7
- package/dist/core/config.d.ts +41 -6
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +103 -21
- package/dist/core/queryOptions.d.ts.map +1 -1
- package/dist/core/queryOptions.js +9 -21
- package/dist/features/index.d.ts +1 -1
- package/dist/features/index.d.ts.map +1 -1
- package/dist/features/index.js +1 -1
- package/dist/features/offline.d.ts +1 -0
- package/dist/features/offline.d.ts.map +1 -1
- package/dist/features/offline.js +33 -2
- package/dist/features/persistence.d.ts.map +1 -1
- package/dist/features/persistence.js +3 -2
- package/dist/hooks/useDataGuardMutation.d.ts.map +1 -1
- package/dist/hooks/useDataGuardMutation.js +1 -15
- package/dist/hooks/useMutation.js +3 -3
- package/dist/types/dataGuard.d.ts +1 -1
- package/dist/types/dataGuard.d.ts.map +1 -1
- package/dist/utils/dataGuard.d.ts.map +1 -1
- package/dist/utils/dataGuard.js +16 -22
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/queryKey.d.ts +2 -0
- package/dist/utils/queryKey.d.ts.map +1 -1
- package/dist/utils/queryKey.js +12 -0
- package/package.json +1 -1
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
|
|
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 |
|
|
345
|
+
| retry (Query) | 智能重试* | 智能重试* | 0 |
|
|
346
|
+
| retry (Mutation) | 0 | 0 | 0 |
|
|
326
347
|
| refetchOnWindowFocus | true | true | false |
|
|
327
348
|
|
|
328
|
-
|
|
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
|
-
|
|
1078
|
-
|
|
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
|
|
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: (
|
|
3786
|
+
mutationFn: (patch) => updateUser(userId, patch),
|
|
3697
3787
|
optimistic: {
|
|
3698
|
-
queryKey: ['user',
|
|
3699
|
-
updater: (old,
|
|
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;
|
|
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
|
-
|
|
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
|
}
|
package/dist/core/config.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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;
|
|
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"}
|
package/dist/core/config.js
CHANGED
|
@@ -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
|
|
16
|
-
|
|
17
|
-
|
|
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
|
|
22
|
-
|
|
62
|
+
const status = extractHttpStatus(error);
|
|
63
|
+
// 4XX 客户端错误:不重试
|
|
64
|
+
if (status && status >= 400 && status < 500) {
|
|
23
65
|
return false;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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" &&
|
|
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 (
|
|
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
|
-
|
|
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
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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 {
|
|
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(
|
|
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 = (
|
|
311
|
+
queries.refetchInterval = (query) => (query?.state?.error ? false : conditionalRefetchInterval);
|
|
234
312
|
}
|
|
235
313
|
else {
|
|
236
|
-
|
|
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 = {
|
|
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,
|
|
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,
|
|
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
|
}
|
package/dist/features/index.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/features/index.js
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/features/offline.js
CHANGED
|
@@ -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 =
|
|
145
|
-
const
|
|
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;
|
|
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 =
|
|
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 =
|
|
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;
|
|
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
|
|
38
|
-
retryDelay: restOptions.retryDelay ?? DEFAULT_MUTATION_CONFIG
|
|
39
|
-
gcTime: restOptions.gcTime ?? DEFAULT_MUTATION_CONFIG
|
|
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) {
|
|
@@ -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;
|
|
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+
|
|
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"}
|
package/dist/utils/dataGuard.js
CHANGED
|
@@ -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 &&
|
|
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
|
|
205
|
-
|
|
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:
|
|
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
|
|
218
|
-
|
|
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:
|
|
215
|
+
_recentlyUpdatedIds: remaining.length > 0 ? remaining : undefined
|
|
222
216
|
};
|
|
223
217
|
}
|
|
224
218
|
/**
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/utils/index.js
CHANGED
|
@@ -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";
|
package/dist/utils/queryKey.d.ts
CHANGED
|
@@ -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"}
|
package/dist/utils/queryKey.js
CHANGED
|
@@ -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