@net-vert/core 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,11 +11,11 @@ GitHub 开源仓库 👉 [https://github.com/yvygyyth/net-vert](https://github.c
11
11
 
12
12
  ## ✨ 核心特性
13
13
 
14
- ✅ **依赖倒置设计** - 解耦网络层,按需注入 axios、fetch 或自定义请求器
15
- ✅ **中间件扩展** - 内置缓存、幂等、重试、并发控制、同步模式等强大中间件
16
- ✅ **类型安全** - TypeScript 全类型提示,开发体验丝滑
17
- ✅ **零配置上手** - API 极简,开箱即用
18
- ✅ **灵活组合** - 多种中间件自由组合,满足复杂业务场景
14
+ ✅ **依赖倒置设计** - 解耦网络层,按需注入 axios、fetch 或自定义请求器
15
+ ✅ **中间件扩展** - 内置缓存、幂等、重试、并发控制等强大中间件
16
+ ✅ **类型安全** - TypeScript 全类型提示,开发体验丝滑
17
+ ✅ **零配置上手** - API 极简,开箱即用
18
+ ✅ **灵活组合** - 多种中间件自由组合,满足复杂业务场景
19
19
  ✅ **Tree-Shaking** - 支持按需引入,打包体积更小
20
20
 
21
21
  ---
@@ -129,7 +129,7 @@ import { createRequestor, cache } from '@net-vert/core'
129
129
 
130
130
  const requestor = createRequestor({
131
131
  extensions: [
132
- cache({
132
+ cache({
133
133
  duration: 5000 // 缓存 5 秒
134
134
  })
135
135
  ]
@@ -157,10 +157,10 @@ interface CacheOptions<D = any, R = any> {
157
157
  * - number: 固定时长
158
158
  * - function: 动态计算(可根据响应内容决定缓存时长)
159
159
  */
160
- duration?: number | ((ctx: {
160
+ duration?: number | ((ctx: {
161
161
  key: string
162
162
  config: RequestConfig<D>
163
- response: R
163
+ response: R
164
164
  }) => number)
165
165
 
166
166
  /**
@@ -354,7 +354,7 @@ import { createRequestor, retry } from '@net-vert/core'
354
354
 
355
355
  const requestor = createRequestor({
356
356
  extensions: [
357
- retry({
357
+ retry({
358
358
  retries: 3, // 最多重试 3 次
359
359
  delay: 1000 // 每次重试延迟 1 秒
360
360
  })
@@ -447,7 +447,7 @@ import { createRequestor, concurrent } from '@net-vert/core'
447
447
 
448
448
  const requestor = createRequestor({
449
449
  extensions: [
450
- concurrent({
450
+ concurrent({
451
451
  parallelCount: 3 // 最多同时 3 个请求
452
452
  })
453
453
  ]
@@ -511,140 +511,6 @@ const results = await Promise.all(
511
511
 
512
512
  ---
513
513
 
514
- ### 5. 同步模式中间件 (`sync`)
515
-
516
- 让异步请求支持"Suspense 风格"的同步调用,适用于 React Suspense 等场景。
517
-
518
- > **⚠️ 重要**:`sync` 中间件**必须放在中间件数组的第一位**,否则会导致功能异常。详见 [中间件顺序规则](#️-重要中间件顺序规则)。
519
-
520
- #### 基础用法(Suspense 模式)
521
-
522
- ```typescript
523
- import { createRequestor, sync } from '@net-vert/core'
524
-
525
- const requestor = createRequestor({
526
- extensions: [sync()]
527
- })
528
-
529
- // 首次调用会抛出 Promise(触发 Suspense)
530
- try {
531
- const data = requestor.get('/api/users')
532
- } catch (promise) {
533
- await promise // 等待数据加载
534
- }
535
-
536
- // 再次调用会同步返回缓存数据
537
- const data = requestor.get('/api/users') // 同步返回,不再抛出
538
- console.log(data) // 直接获取数据
539
- ```
540
-
541
- #### React Suspense 集成
542
-
543
- ```tsx
544
- import { createRequestor, sync } from '@net-vert/core'
545
-
546
- const requestor = createRequestor({
547
- extensions: [sync()]
548
- })
549
-
550
- function UserProfile({ userId }) {
551
- // 首次渲染会抛出 Promise,触发 Suspense
552
- // 数据加载完成后重新渲染,此时同步返回数据
553
- const user = requestor.get(`/api/users/${userId}`)
554
-
555
- return <div>{user.name}</div>
556
- }
557
-
558
- function App() {
559
- return (
560
- <Suspense fallback={<div>Loading...</div>}>
561
- <UserProfile userId={1} />
562
- </Suspense>
563
- )
564
- }
565
- ```
566
-
567
- #### 配置选项
568
-
569
- ```typescript
570
- interface SyncOptions<D = any, R = any> {
571
- /**
572
- * 缓存 key 生成函数
573
- * 默认:基于 method + url + params 生成
574
- */
575
- key?: (ctx: { config: RequestConfig<D> }) => string
576
-
577
- /**
578
- * 是否启用 Suspense 模式(抛出 Promise)
579
- * - true: 首次调用抛出 Promise(默认)
580
- * - false: 首次调用返回 Promise
581
- */
582
- suspense?: boolean
583
-
584
- /**
585
- * 自定义 Promise 包装函数
586
- * 可用于添加元数据或修改返回结构
587
- */
588
- wrapSuspense?: (params: {
589
- key: string
590
- config: RequestConfig<D>
591
- p: Promise<R>
592
- }) => Promise<R>
593
-
594
- /**
595
- * 缓存有效期(毫秒)
596
- * 默认:永久缓存
597
- */
598
- duration?: number
599
-
600
- /**
601
- * 是否持久化
602
- * 默认:false
603
- */
604
- persist?: boolean
605
- }
606
- ```
607
-
608
- #### 高级示例
609
-
610
- **非 Suspense 模式**
611
-
612
- ```typescript
613
- const requestor = createRequestor({
614
- extensions: [
615
- sync({ suspense: false }) // 关闭 Suspense 模式
616
- ]
617
- })
618
-
619
- // 首次调用返回 Promise
620
- const promise = requestor.get('/api/users')
621
- await promise
622
-
623
- // 再次调用同步返回缓存
624
- const data = requestor.get('/api/users') // 同步返回
625
- ```
626
-
627
- **自定义 Promise 包装**
628
-
629
- ```typescript
630
- const requestor = createRequestor({
631
- extensions: [
632
- sync({
633
- wrapSuspense: ({ p, key }) => {
634
- // 给 Promise 添加元数据
635
- return p.then(data => ({
636
- ...data,
637
- __cacheKey: key,
638
- __timestamp: Date.now()
639
- }))
640
- }
641
- })
642
- ]
643
- })
644
- ```
645
-
646
- ---
647
-
648
514
  ## 🔗 中间件组合
649
515
 
650
516
  多个中间件可以自由组合,执行顺序遵循数组顺序:
@@ -660,68 +526,15 @@ const requestor = createRequestor({
660
526
  })
661
527
  ```
662
528
 
663
- ### ⚠️ 重要:中间件顺序规则
664
-
665
- 在组合中间件时,需要注意以下**强制性规则**,否则会导致功能异常:
666
-
667
- 1. **同步模式中间件(`sync`)必须放在第一位**
668
- ```typescript
669
- // 正确
670
- const requestor = createRequestor({
671
- extensions: [
672
- sync(), // 必须第一个
673
- idempotent(),
674
- cache({ duration: 5000 })
675
- ]
676
- })
677
-
678
- // ❌ 错误 - 某些情况下 sync 不在第一位会导致同步调用失败,幂等缓存的promise会被sync模块直接改变,导致幂等缓存失效.重试也会因为同步模块抛错误耗尽失败次数,同步模块的同步能力也可能因为部分中间件的异步特性而失效
679
- const requestor = createRequestor({
680
- extensions: [
681
- retry() | idempotent(),
682
- sync() // 错误位置!
683
- ]
684
- })
685
- ```
686
-
687
- 2. **自定义中间件如果需要拦截所有请求,必须前置**
688
-
689
- 自定义中间件的位置决定了它在中间件链中的执行时机:
690
- - **前置**:可以拦截和修改所有请求(包括被其他中间件处理的请求)
691
- - **后置**:只能处理未被前面中间件拦截的请求(如缓存命中的请求不会到达后置中间件)
692
-
693
- ```typescript
694
- const loggerMiddleware: Middleware = async ({ config, next }) => {
695
- console.log('Request:', config.url)
696
- return await next()
697
- }
698
-
699
- // ✅ 正确 - logger 在最前面,可以记录所有请求
700
- const requestor = createRequestor({
701
- extensions: [
702
- loggerMiddleware, // 第一个执行
703
- cache({ duration: 5000 }),
704
- retry({ retries: 3 })
705
- ]
706
- })
707
-
708
- // ⚠️ 注意 - logger 在 cache 之后,缓存命中的请求不会被记录
709
- const requestor = createRequestor({
710
- extensions: [
711
- cache({ duration: 5000 }),
712
- loggerMiddleware, // 缓存命中时不会执行
713
- retry({ retries: 3 })
714
- ]
715
- })
716
- ```
717
-
718
- 3. **推荐的中间件顺序**(从前到后):
719
- - `sync()` - 同步模式(如果使用)
720
- - 自定义拦截中间件(日志、鉴权等)
721
- - `idempotent()` - 幂等处理
722
- - `cache()` - 缓存
723
- - `retry()` - 重试
724
- - `concurrent()` - 并发控制
529
+ ### 推荐的中间件顺序
530
+
531
+ 在组合中间件时,建议遵循以下顺序(从前到后):
532
+
533
+ 1. 自定义拦截中间件(日志、鉴权等)
534
+ 2. `idempotent()` - 幂等处理
535
+ 3. `cache()` - 缓存
536
+ 4. `retry()` - 重试
537
+ 5. `concurrent()` - 并发控制
725
538
 
726
539
  ### 常见组合模式
727
540
 
@@ -747,25 +560,6 @@ const requestor = createRequestor({
747
560
  })
748
561
  ```
749
562
 
750
- #### 3. 全能组合(适用于复杂场景)
751
-
752
- ```typescript
753
- const requestor = createRequestor({
754
- extensions: [
755
- idempotent(), // 1. 防止并发重复
756
- cache({
757
- duration: 10000,
758
- persist: true // 2. 持久化缓存 10 秒
759
- }),
760
- retry({
761
- retries: 3,
762
- delay: ({ attempt }) => Math.pow(2, attempt) * 100 // 3. 指数退避重试
763
- }),
764
- concurrent({ parallelCount: 3 }) // 4. 限制并发数
765
- ]
766
- })
767
- ```
768
-
769
563
  ---
770
564
 
771
565
  ## 🎯 便捷组合方法
@@ -899,7 +693,7 @@ inject(config => instance.request(config))
899
693
  export const queryRequestor = createRequestor({
900
694
  extensions: [
901
695
  idempotent(),
902
- cache({
696
+ cache({
903
697
  duration: 30000, // 缓存 30 秒
904
698
  persist: true // 持久化
905
699
  })
@@ -909,8 +703,8 @@ export const queryRequestor = createRequestor({
909
703
  // 3. 创建数据变更请求器(带重试)
910
704
  export const mutationRequestor = createRequestor({
911
705
  extensions: [
912
- retry({
913
- retries: 3,
706
+ retry({
707
+ retries: 3,
914
708
  delay: ({ attempt }) => Math.pow(2, attempt) * 200,
915
709
  retryCondition: ({ lastResponse }) => {
916
710
  // 只在网络错误或 5xx 时重试
@@ -949,44 +743,38 @@ async function uploadFiles(files: File[]) {
949
743
  formData.append('file', file)
950
744
  return uploadRequestor.post('/upload', formData)
951
745
  })
952
-
746
+
953
747
  return Promise.all(tasks)
954
748
  }
955
749
  ```
956
750
 
957
- ### 示例 3:React Suspense 集成
751
+ ### 示例 3:自定义中间件
958
752
 
959
- ```tsx
960
- import { inject, createRequestor, sync } from '@net-vert/core'
961
- import { Suspense } from 'react'
962
-
963
- // 注入请求器
964
- inject(config => fetch(config.url).then(res => res.json()))
965
-
966
- // 创建 Suspense 风格的请求器
967
- const suspenseRequestor = createRequestor({
968
- extensions: [sync()]
969
- })
753
+ ```typescript
754
+ import { createRequestor, type Middleware } from '@net-vert/core'
970
755
 
971
- // API 封装
972
- const api = {
973
- getUser: (id: number) => suspenseRequestor.get(`/api/users/${id}`),
974
- getPosts: () => suspenseRequestor.get('/api/posts')
975
- }
756
+ // 自定义日志中间件
757
+ const loggerMiddleware: Middleware = async ({ config, next }) => {
758
+ console.log('Request:', config.method, config.url)
759
+ const startTime = Date.now()
976
760
 
977
- // 组件
978
- function UserProfile({ userId }: { userId: number }) {
979
- const user = api.getUser(userId) // 首次会触发 Suspense
980
- return <div>{user.name}</div>
761
+ try {
762
+ const result = await next()
763
+ console.log('Success:', Date.now() - startTime, 'ms')
764
+ return result
765
+ } catch (error) {
766
+ console.error('Error:', error)
767
+ throw error
768
+ }
981
769
  }
982
770
 
983
- function App() {
984
- return (
985
- <Suspense fallback={<div>Loading...</div>}>
986
- <UserProfile userId={1} />
987
- </Suspense>
988
- )
989
- }
771
+ // 使用自定义中间件
772
+ const requestor = createRequestor({
773
+ extensions: [
774
+ loggerMiddleware,
775
+ cache({ duration: 5000 })
776
+ ]
777
+ })
990
778
  ```
991
779
 
992
780
  ---
@@ -1004,7 +792,7 @@ import { createRequestor, type Middleware } from '@net-vert/core'
1004
792
  const loggerMiddleware: Middleware = async ({ config, next }) => {
1005
793
  console.log('Request:', config.method, config.url)
1006
794
  const startTime = Date.now()
1007
-
795
+
1008
796
  try {
1009
797
  const result = await next()
1010
798
  console.log('Success:', Date.now() - startTime, 'ms')
@@ -1021,7 +809,7 @@ const requestor = createRequestor({
1021
809
  })
1022
810
  ```
1023
811
 
1024
- > **⚠️ 重要提示**:如果你的自定义中间件需要拦截所有请求(如日志记录、鉴权检查等),**必须将其放在中间件数组的最前面**(`sync` 除外)。否则,被前置中间件(如 `cache`)拦截的请求不会经过你的自定义中间件。详见 [中间件顺序规则](#️-重要中间件顺序规则)。
812
+ > **💡 提示**:如果你的自定义中间件需要拦截所有请求(如日志记录、鉴权检查等),建议将其放在中间件数组的最前面。否则,被前置中间件(如 `cache`)拦截的请求不会经过你的自定义中间件。
1025
813
 
1026
814
  ### 动态切换请求器
1027
815
 
@@ -1059,17 +847,17 @@ describe('API Tests', () => {
1059
847
  code: 200,
1060
848
  data: { url: config.url }
1061
849
  }))
1062
-
850
+
1063
851
  inject(mockRequestor)
1064
-
852
+
1065
853
  const requestor = createRequestor({
1066
854
  extensions: [cache({ duration: 5000 })]
1067
855
  })
1068
-
856
+
1069
857
  // 发起两次相同请求
1070
858
  await requestor.get('/api/test')
1071
859
  await requestor.get('/api/test')
1072
-
860
+
1073
861
  // 验证只调用了一次
1074
862
  expect(mockRequestor).toHaveBeenCalledTimes(1)
1075
863
  })
package/dist/index.d.ts CHANGED
@@ -42,7 +42,7 @@ declare interface CacheKeyContext<D = any> {
42
42
  }
43
43
 
44
44
  /** 缓存中间件类型(带 storage 实例)*/
45
- declare type CacheMiddleware<D = any, R = any> = TypedMiddleware<MIDDLEWARE_TYPE.CACHE, false, D, R> & {
45
+ declare type CacheMiddleware<D = any, R = any> = TypedMiddleware<MIDDLEWARE_TYPE.CACHE, D, R> & {
46
46
  storage: CacheStorageInstance<R>;
47
47
  };
48
48
 
@@ -87,7 +87,7 @@ declare type ConcurrentContext<D = any> = {
87
87
  config: RequestConfig<D>;
88
88
  };
89
89
 
90
- declare type ConcurrentMiddleware<D = any, R = any> = TypedMiddleware<MIDDLEWARE_TYPE.CONCURRENT, false, D, R> & {
90
+ declare type ConcurrentMiddleware<D = any, R = any> = TypedMiddleware<MIDDLEWARE_TYPE.CONCURRENT, D, R> & {
91
91
  pool: ConcurrentPool;
92
92
  };
93
93
 
@@ -120,14 +120,14 @@ RetryOptions<D>
120
120
  * 适用场景:数据查询接口,既需要缓存提升性能,又要避免重复请求
121
121
  * @param config 组合配置对象
122
122
  */
123
- export declare function createCachedIdempotentRequestor<D = any, R = any>(config: CachedIdempotentConfig<D, R>): Requestor<false>;
123
+ export declare function createCachedIdempotentRequestor<D = any, R = any>(config: CachedIdempotentConfig<D, R>): Requestor;
124
124
 
125
125
  /**
126
126
  * 创建带并发控制和重试的请求器
127
127
  * 适用场景:批量请求场景,需要控制并发数量,失败后自动重试
128
128
  * @param config 组合配置对象
129
129
  */
130
- export declare function createConcurrentRetryRequestor<D = any>(config: ConcurrentRetryConfig<D>): Requestor<false>;
130
+ export declare function createConcurrentRetryRequestor<D = any>(config: ConcurrentRetryConfig<D>): Requestor;
131
131
 
132
132
  declare const createPromiseCache: () => {
133
133
  getPromise: <T = unknown>(key: SafeKey) => Promise<T> | undefined;
@@ -136,11 +136,12 @@ declare const createPromiseCache: () => {
136
136
  clearCache: () => void;
137
137
  };
138
138
 
139
- export declare function createRequestor<const Extensions extends readonly Middleware[]>(config: CreateRequestorConfig<Extensions> & {
140
- extensions: Extensions;
141
- }): Requestor<HasSyncMiddleware<Extensions>>;
142
-
143
- export declare function createRequestor(config?: CreateRequestorConfig): Requestor<false>;
139
+ /**
140
+ * 创建请求器
141
+ * @param config 配置对象(可选)
142
+ * @returns 返回 Requestor 实例(所有方法都返回 Promise)
143
+ */
144
+ export declare function createRequestor<const Extensions extends readonly Middleware[] = []>(config?: CreateRequestorConfig<Extensions>): Requestor;
144
145
 
145
146
  export declare interface CreateRequestorConfig<Extensions extends readonly Middleware[] = readonly Middleware[]> {
146
147
  extensions?: Extensions;
@@ -212,8 +213,6 @@ export declare type FlattenWithInstanceKey<Types extends readonly any[]> = WithI
212
213
 
213
214
  export declare type HandlerParams<T extends keyof Requestor> = Parameters<Requestor[T]>;
214
215
 
215
- export declare type HasSyncMiddleware<T extends readonly any[]> = T extends readonly [infer First, ...infer Rest] ? First extends TypedMiddleware<MIDDLEWARE_TYPE.SYNC, true, any, any> ? true : HasSyncMiddleware<Rest> : false;
216
-
217
216
  declare type Id = string | number;
218
217
 
219
218
  declare type IdempotencyContext<D = any> = {
@@ -226,7 +225,7 @@ declare type IdempotencyOptions<D = any> = {
226
225
 
227
226
  export declare const idempotent: <D = any, R = any>(options?: Partial<IdempotencyOptions<D>>) => IdempotentMiddleware<D, R>;
228
227
 
229
- declare type IdempotentMiddleware<D = any, R = any> = TypedMiddleware<MIDDLEWARE_TYPE.IDEMPOTENT, false, D, R> & {
228
+ declare type IdempotentMiddleware<D = any, R = any> = TypedMiddleware<MIDDLEWARE_TYPE.IDEMPOTENT, D, R> & {
230
229
  promiseCache: PromiseCache;
231
230
  };
232
231
 
@@ -234,13 +233,11 @@ export declare const inject: (requestor: BaseRequestor, instanceKey?: string) =>
234
233
 
235
234
  export declare type Key = string | symbol | number;
236
235
 
237
- export declare type MaybePromise<IsSync, R> = IsSync extends true ? R : IsSync extends false ? Promise<R> : R | Promise<R>;
238
-
239
- export declare type Middleware<IsSync extends boolean = false, D = any, R = any> = (context: {
236
+ export declare type Middleware<D = any, R = any> = (context: {
240
237
  config: RequestConfig<D>;
241
- next: () => MaybePromise<IsSync, R>;
238
+ next: () => Promise<R>;
242
239
  ctx: MiddlewareContext;
243
- }) => MaybePromise<IsSync, R>;
240
+ }) => Promise<R>;
244
241
 
245
242
  declare enum MIDDLEWARE_TYPE {
246
243
  CACHE = "cache",
@@ -272,15 +269,15 @@ export declare interface RequestConfig<D = any> extends Record<string, any> {
272
269
 
273
270
  declare type RequestMethod = REQUEST_METHOD;
274
271
 
275
- export declare interface Requestor<IsSync extends boolean = false> {
276
- request: <R = any, D = any>(config: RequestConfig<D>) => MaybePromise<IsSync, R>;
277
- get: <R = any, D = any>(url: string, config?: WithoutMethod<D>) => MaybePromise<IsSync, R>;
278
- post: <R = any, D = any>(url: string, data?: D, config?: WithoutMethod<D>) => MaybePromise<IsSync, R>;
279
- put: <R = any, D = any>(url: string, data?: D, config?: WithoutMethod<D>) => MaybePromise<IsSync, R>;
280
- delete: <R = any, D = any>(url: string, config?: WithoutMethod<D>) => MaybePromise<IsSync, R>;
272
+ export declare interface Requestor {
273
+ request: <R = any, D = any>(config: RequestConfig<D>) => Promise<R>;
274
+ get: <R = any, D = any>(url: string, config?: WithoutMethod<D>) => Promise<R>;
275
+ post: <R = any, D = any>(url: string, data?: D, config?: WithoutMethod<D>) => Promise<R>;
276
+ put: <R = any, D = any>(url: string, data?: D, config?: WithoutMethod<D>) => Promise<R>;
277
+ delete: <R = any, D = any>(url: string, config?: WithoutMethod<D>) => Promise<R>;
281
278
  }
282
279
 
283
- export declare const retry: <D = any, R = any>(options?: Partial<RetryOptions<D>>) => TypedMiddleware<MIDDLEWARE_TYPE.RETRY, false, D, R>;
280
+ export declare const retry: <D = any, R = any>(options?: Partial<RetryOptions<D>>) => TypedMiddleware<MIDDLEWARE_TYPE.RETRY, D, R>;
284
281
 
285
282
  declare type RetryContext<D = any> = {
286
283
  config: RequestConfig<D>;
@@ -301,27 +298,6 @@ export declare type StoreDescriptor = StoreKey | {
301
298
  factory: StoreFactory<Store<AnyRecord>, any[]>;
302
299
  };
303
300
 
304
- /**
305
- * 缓存中有数据则直接返回。
306
- * suspense 为 true 时,会抛出一个 Promise(而不是普通错误),Promise resolve 后得到数据。
307
- * suspense 为 false 时,会返回一个 Promise,Promise resolve 后得到数据,调用者需要用 await 或 .then 捕获。
308
- */
309
- export declare function sync<D = any, R = any>(options: Partial<SyncOptions<D>> & {
310
- suspense: true;
311
- }): TypedMiddleware<MIDDLEWARE_TYPE.SYNC, true, D, R>;
312
-
313
- export declare function sync<D = any, R = any>(options: Partial<SyncOptions<D>> & {
314
- suspense: false;
315
- }): TypedMiddleware<MIDDLEWARE_TYPE.SYNC, any, D, R>;
316
-
317
- export declare function sync<D = any, R = any>(options?: Partial<SyncOptions<D>>): TypedMiddleware<MIDDLEWARE_TYPE.SYNC, true, D, R>;
318
-
319
- declare interface SyncOptions<D = any, R = any> extends CacheOptions<D, R> {
320
- isValid: (ctx: CacheCheckContext<D, R>) => boolean;
321
- suspense: boolean;
322
- wrapSuspense?: (params: WrapSuspense<D, R>) => any;
323
- }
324
-
325
301
  declare type Task<T> = () => Promise<T>;
326
302
 
327
303
  declare type TaskItem<T> = {
@@ -332,7 +308,7 @@ declare type TaskItem<T> = {
332
308
 
333
309
  declare type TaskItemList<T> = TaskQueue<TaskItem<T>>;
334
310
 
335
- export declare type TypedMiddleware<Type extends MiddlewareType, IsSync extends boolean = false, D = any, R = any> = Middleware<IsSync, D, R> & {
311
+ export declare type TypedMiddleware<Type extends MiddlewareType, D = any, R = any> = Middleware<D, R> & {
336
312
  __middlewareType: Type;
337
313
  };
338
314
 
@@ -357,10 +333,4 @@ export declare type WithInstanceKey<T> = T & {
357
333
 
358
334
  export declare type WithoutMethod<D = any> = Omit<RequestConfig<D>, 'method' | 'url'>;
359
335
 
360
- declare type WrapSuspense<D = any, R = any> = {
361
- key: CacheKey;
362
- config: RequestConfig<D>;
363
- p: Promise<R>;
364
- };
365
-
366
336
  export { }
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import { TaskQueue as j } from "id-queue";
2
- var f = /* @__PURE__ */ ((r) => (r.GET = "get", r.POST = "post", r.PUT = "put", r.DELETE = "delete", r))(f || {}), m = /* @__PURE__ */ ((r) => (r.CACHE = "cache", r.RETRY = "retry", r.IDEMPOTENT = "idempotent", r.CONCURRENT = "concurrent", r.SYNC = "sync", r))(m || {});
3
- const S = "default", D = {
1
+ import { TaskQueue as F } from "id-queue";
2
+ var h = /* @__PURE__ */ ((r) => (r.GET = "get", r.POST = "post", r.PUT = "put", r.DELETE = "delete", r))(h || {}), m = /* @__PURE__ */ ((r) => (r.CACHE = "cache", r.RETRY = "retry", r.IDEMPOTENT = "idempotent", r.CONCURRENT = "concurrent", r.SYNC = "sync", r))(m || {});
3
+ const p = "default", j = {
4
4
  retries: 3,
5
5
  delay: 0,
6
6
  retryCondition: () => !0
7
- }, F = (r) => {
8
- const e = { ...D, ...r };
7
+ }, D = (r) => {
8
+ const e = { ...j, ...r };
9
9
  return Object.assign(async ({ config: n, next: s }) => {
10
10
  let o = 0, i;
11
11
  for (; o <= e.retries; )
@@ -23,22 +23,22 @@ const S = "default", D = {
23
23
  throw a;
24
24
  o++;
25
25
  const u = typeof e.delay == "function" ? e.delay(c) : e.delay;
26
- u > 0 && await new Promise((l) => setTimeout(l, u));
26
+ u > 0 && await new Promise((w) => setTimeout(w, u));
27
27
  }
28
28
  throw i;
29
29
  }, { __middlewareType: m.RETRY });
30
- }, $ = () => {
30
+ }, T = () => {
31
31
  const r = /* @__PURE__ */ new Map();
32
32
  return { getPromise: (o) => r.get(o), setPromise: (o, i) => {
33
33
  r.set(o, i), i.finally(() => r.delete(o));
34
34
  }, delPromise: (o) => r.delete(o), clearCache: () => r.clear() };
35
- }, E = (r) => {
35
+ }, V = (r) => {
36
36
  const { config: e } = r, { method: t, url: n, data: s } = e;
37
37
  return [t, n, JSON.stringify(s)].join("|");
38
- }, T = {
39
- key: E
40
- }, q = (r) => {
41
- const e = { ...T, ...r }, t = $();
38
+ }, q = {
39
+ key: V
40
+ }, E = (r) => {
41
+ const e = { ...q, ...r }, t = T();
42
42
  return Object.assign(({ config: s, next: o }) => {
43
43
  const i = e.key({ config: s }), a = t.getPromise(i);
44
44
  if (a)
@@ -55,7 +55,7 @@ class R {
55
55
  tasks;
56
56
  runningCount;
57
57
  constructor(e = 4) {
58
- this.parallelCount = e, this.tasks = new j(), this.runningCount = 0;
58
+ this.parallelCount = e, this.tasks = new F(), this.runningCount = 0;
59
59
  }
60
60
  // 加入
61
61
  add(e, t) {
@@ -84,26 +84,26 @@ class R {
84
84
  }
85
85
  }
86
86
  }
87
- let B = 0;
88
- const _ = {
87
+ let $ = 0;
88
+ const B = {
89
89
  parallelCount: 4,
90
- createId: () => B++
90
+ createId: () => $++
91
91
  }, K = (r) => {
92
- const { parallelCount: e, createId: t } = { ..._, ...r }, n = new R(e);
92
+ const { parallelCount: e, createId: t } = { ...B, ...r }, n = new R(e);
93
93
  return Object.assign(({ config: o, next: i }) => {
94
94
  const a = t({ config: o });
95
95
  return n.add(a, () => i());
96
96
  }, { __middlewareType: m.CONCURRENT, pool: n });
97
- }, v = /* @__PURE__ */ new Map(), y = (r, e) => {
98
- v.set(e, r);
97
+ }, I = /* @__PURE__ */ new Map(), y = (r, e) => {
98
+ I.set(e, r);
99
99
  };
100
- function A(r) {
101
- const e = v.get(r);
100
+ function _(r) {
101
+ const e = I.get(r);
102
102
  if (!e)
103
103
  throw new Error(`Store实例 ${String(r)} 未注册`);
104
104
  return e;
105
105
  }
106
- class J {
106
+ class A {
107
107
  store = /* @__PURE__ */ new Map();
108
108
  getItem(e) {
109
109
  return this.store.get(e);
@@ -132,7 +132,7 @@ class J {
132
132
  e(s, n, t), t++;
133
133
  }
134
134
  }
135
- const z = (r) => !!r && (typeof r == "object" || typeof r == "function") && typeof r.then == "function", b = (r) => typeof window < "u" ? r() : {
135
+ const J = (r) => !!r && (typeof r == "object" || typeof r == "function") && typeof r.then == "function", C = (r) => typeof window < "u" ? r() : {
136
136
  getItem() {
137
137
  return null;
138
138
  },
@@ -148,12 +148,12 @@ const z = (r) => !!r && (typeof r == "object" || typeof r == "function") && type
148
148
  get length() {
149
149
  return 0;
150
150
  }
151
- }, h = b(() => window.localStorage);
152
- class G {
151
+ }, l = C(() => window.localStorage);
152
+ class z {
153
153
  constructor() {
154
154
  }
155
155
  getItem(e) {
156
- const t = String(e), n = h.getItem(t);
156
+ const t = String(e), n = l.getItem(t);
157
157
  if (n !== null)
158
158
  try {
159
159
  return JSON.parse(n);
@@ -165,7 +165,7 @@ class G {
165
165
  setItem(e, t) {
166
166
  const n = String(e);
167
167
  try {
168
- h.setItem(n, JSON.stringify(t));
168
+ l.setItem(n, JSON.stringify(t));
169
169
  } catch (s) {
170
170
  throw console.error(`Failed to set value for key: ${n}`, s), s;
171
171
  }
@@ -173,21 +173,21 @@ class G {
173
173
  }
174
174
  removeItem(e) {
175
175
  const t = String(e);
176
- h.removeItem(t);
176
+ l.removeItem(t);
177
177
  }
178
178
  clear() {
179
- h.clear();
179
+ l.clear();
180
180
  }
181
181
  length() {
182
- return h.length;
182
+ return l.length;
183
183
  }
184
184
  key(e) {
185
- return h.key(e);
185
+ return l.key(e);
186
186
  }
187
187
  keys() {
188
188
  const e = [];
189
- for (let t = 0; t < h.length; t++) {
190
- const n = h.key(t);
189
+ for (let t = 0; t < l.length; t++) {
190
+ const n = l.key(t);
191
191
  n && e.push(n);
192
192
  }
193
193
  return e;
@@ -199,8 +199,8 @@ class G {
199
199
  });
200
200
  }
201
201
  }
202
- const d = b(() => window.sessionStorage);
203
- class U {
202
+ const d = C(() => window.sessionStorage);
203
+ class G {
204
204
  constructor() {
205
205
  }
206
206
  getItem(e) {
@@ -250,7 +250,7 @@ class U {
250
250
  });
251
251
  }
252
252
  }
253
- class Y {
253
+ class U {
254
254
  dbName;
255
255
  storeName;
256
256
  dbPromise = null;
@@ -379,11 +379,11 @@ const g = {
379
379
  session: "session",
380
380
  indexeddb: "indexeddb"
381
381
  };
382
- function N(r, e) {
382
+ function k(r, e) {
383
383
  Object.assign(r, e);
384
384
  }
385
385
  function M(r) {
386
- return N(r, {
386
+ return k(r, {
387
387
  async getItemOrDefault(e, t) {
388
388
  const n = await this.getItem(e);
389
389
  return n !== null ? n : t;
@@ -400,7 +400,7 @@ function M(r) {
400
400
  }), r;
401
401
  }
402
402
  function X(r) {
403
- return N(r, {
403
+ return k(r, {
404
404
  getItemOrDefault(e, t) {
405
405
  const n = this.getItem(e);
406
406
  return n !== null ? n : t;
@@ -416,50 +416,50 @@ function X(r) {
416
416
  }
417
417
  }), r;
418
418
  }
419
- function Z(r) {
419
+ function Y(r) {
420
420
  const e = r.getItem("");
421
- return z(e) ? M(r) : X(r);
421
+ return J(e) ? M(r) : X(r);
422
422
  }
423
- function w(r, ...e) {
424
- const t = A(r);
423
+ function f(r, ...e) {
424
+ const t = _(r);
425
425
  let n;
426
426
  try {
427
427
  n = new t(...e);
428
428
  } catch {
429
429
  n = t(...e);
430
430
  }
431
- return Z(n);
431
+ return Y(n);
432
432
  }
433
- y(J, g.memory);
434
- y(G, g.local);
435
- y(U, g.session);
436
- y(Y, g.indexeddb);
437
- function C(r, e) {
433
+ y(A, g.memory);
434
+ y(z, g.local);
435
+ y(G, g.session);
436
+ y(U, g.indexeddb);
437
+ function S(r, e) {
438
438
  return {
439
439
  value: r,
440
440
  expireAt: Date.now() + e
441
441
  };
442
442
  }
443
- function I(r, e = Date.now()) {
443
+ function v(r, e = Date.now()) {
444
444
  return r.expireAt <= e;
445
445
  }
446
- function x(r, e = Date.now()) {
447
- return I(r, e) ? void 0 : r.value;
446
+ function Z(r, e = Date.now()) {
447
+ return v(r, e) ? void 0 : r.value;
448
448
  }
449
449
  const H = (r) => {
450
450
  const { config: e } = r, { method: t, url: n, data: s } = e;
451
451
  return [t, n, JSON.stringify(s)].join("|");
452
- }, L = () => !0, k = 24 * 60 * 60 * 1e3, Q = {
452
+ }, L = () => !0, b = 24 * 60 * 60 * 1e3, Q = {
453
453
  key: H,
454
- duration: k,
454
+ duration: b,
455
455
  isValid: L,
456
456
  store: g.memory
457
457
  // 默认不持久化,使用内存存储
458
458
  };
459
- let W = class {
459
+ class W {
460
460
  store;
461
461
  constructor(e) {
462
- return typeof e == "string" ? this.store = w(e) : (y(e.factory, e.key), this.store = w(e.key)), new Proxy(this, {
462
+ return typeof e == "string" ? this.store = f(e) : (y(e.factory, e.key), this.store = f(e.key)), new Proxy(this, {
463
463
  get(t, n) {
464
464
  if (n in t)
465
465
  return t[n];
@@ -474,8 +474,8 @@ let W = class {
474
474
  * @param value 要缓存的值
475
475
  * @param duration 过期时长(毫秒),默认 24 小时
476
476
  */
477
- setCache(e, t, n = k) {
478
- const s = C(t, n);
477
+ setCache(e, t, n = b) {
478
+ const s = S(t, n);
479
479
  this.store.setItem(e, s);
480
480
  }
481
481
  /**
@@ -486,7 +486,7 @@ let W = class {
486
486
  async getCache(e) {
487
487
  const t = await this.store.getItem(e);
488
488
  if (t)
489
- return x(t);
489
+ return Z(t);
490
490
  }
491
491
  /**
492
492
  * 检查是否有有效的缓存(未过期)
@@ -495,9 +495,9 @@ let W = class {
495
495
  */
496
496
  async hasValidCache(e) {
497
497
  const t = await this.store.getItem(e);
498
- return t ? !I(t) : !1;
498
+ return t ? !v(t) : !1;
499
499
  }
500
- };
500
+ }
501
501
  const ee = W, te = (r) => {
502
502
  const e = { ...Q, ...r }, t = new ee(e.store), n = (o) => typeof e.duration == "function" ? e.duration(o) : e.duration;
503
503
  return Object.assign(async ({ config: o, next: i }) => {
@@ -510,121 +510,45 @@ const ee = W, te = (r) => {
510
510
  })) return c;
511
511
  t.removeItem(a);
512
512
  }
513
- const u = await i(), l = n({ key: a, config: o, cachedData: c, response: u }), p = C(u, l);
514
- return t.setItem(a, p), u;
513
+ const u = await i(), w = n({ key: a, config: o, cachedData: c, response: u }), O = S(u, w);
514
+ return t.setItem(a, O), u;
515
515
  }, {
516
516
  __middlewareType: m.CACHE,
517
517
  storage: t
518
518
  });
519
- };
520
- class re {
521
- store;
522
- constructor(e) {
523
- return typeof e == "string" ? this.store = w(e) : (y(e.factory, e.key), this.store = w(e.key)), new Proxy(this, {
524
- get(t, n) {
525
- if (n in t)
526
- return t[n];
527
- const s = t.store[n];
528
- return typeof s == "function" ? s.bind(t.store) : s;
529
- }
530
- });
531
- }
532
- /**
533
- * 设置缓存(自动包装成 ExpirableValue)
534
- * @param key 缓存 key
535
- * @param value 要缓存的值
536
- * @param duration 过期时长(毫秒),默认 24 小时
537
- */
538
- setCache(e, t, n = k) {
539
- const s = C(t, n);
540
- this.store.setItem(e, s);
541
- }
542
- /**
543
- * 获取缓存值(检查过期,如果过期返回 undefined)
544
- * @param key 缓存 key
545
- * @returns 未过期返回值,已过期返回 undefined
546
- */
547
- getCache(e) {
548
- const t = this.store.getItem(e);
549
- if (t)
550
- return x(t);
551
- }
552
- /**
553
- * 检查是否有有效的缓存(未过期)
554
- * @param key 缓存 key
555
- * @returns true 表示有有效缓存,false 表示无缓存或已过期
556
- */
557
- hasValidCache(e) {
558
- const t = this.store.getItem(e);
559
- return t ? !I(t) : !1;
560
- }
561
- }
562
- const ne = re, se = (r) => {
563
- const { config: e } = r, { method: t, url: n } = e;
564
- return [t, n].join("|");
565
- }, oe = {
566
- suspense: !0,
567
- key: se,
568
- duration: 24 * 60 * 60 * 1e3,
569
- isValid: () => !0,
570
- store: g.memory
571
- };
572
- function me(r) {
573
- const e = { ...oe, ...r }, t = new ne(e.store), n = (o) => typeof e.duration == "function" ? e.duration(o) : e.duration;
574
- return Object.assign(({ config: o, next: i }) => {
575
- const a = e.key({ config: o }), c = t.getCache(a);
576
- if (c) {
577
- if (e.isValid({
578
- key: a,
579
- config: o,
580
- cachedData: c
581
- })) return c;
582
- t.removeItem(a);
583
- }
584
- if (e.suspense)
585
- throw (e.wrapSuspense ? e.wrapSuspense({ key: a, config: o, p: i() }) : i()).then((l) => {
586
- const p = n({ key: a, config: o, cachedData: c, response: l });
587
- return t.setCache(a, l, p), l;
588
- });
589
- return i().then((u) => {
590
- const l = n({ key: a, config: o, cachedData: c, response: u });
591
- return t.setCache(a, u, l), u;
592
- });
593
- }, { __middlewareType: m.SYNC });
594
- }
595
- const P = /* @__PURE__ */ new Map(), ye = (r, e = S) => {
596
- P.set(e, r);
597
- }, ae = (r = S) => {
598
- const e = P.get(r);
519
+ }, N = /* @__PURE__ */ new Map(), ce = (r, e = p) => {
520
+ N.set(e, r);
521
+ }, re = (r = p) => {
522
+ const e = N.get(r);
599
523
  if (!e) throw new Error(`Requestor实例 ${String(r)} 未注册`);
600
524
  return e;
601
- }, V = {
525
+ }, P = {
602
526
  get: (r, e) => ({
603
527
  url: r,
604
- method: f.GET,
528
+ method: h.GET,
605
529
  ...e,
606
530
  params: e?.params
607
531
  }),
608
532
  post: (r, e, t) => ({
609
533
  url: r,
610
- method: f.POST,
534
+ method: h.POST,
611
535
  data: e,
612
536
  ...t
613
537
  }),
614
538
  delete: (r, e) => ({
615
539
  url: r,
616
- method: f.DELETE,
540
+ method: h.DELETE,
617
541
  ...e
618
542
  }),
619
543
  put: (r, e, t) => ({
620
544
  url: r,
621
- method: f.PUT,
545
+ method: h.PUT,
622
546
  data: e,
623
547
  ...t
624
548
  }),
625
549
  request: (r) => r
626
- }, ie = Object.keys(V);
627
- function ce(r, e, t) {
550
+ }, ne = Object.keys(P);
551
+ function se(r, e, t) {
628
552
  const n = {}, s = (o) => {
629
553
  if (o === e.length)
630
554
  return t(r);
@@ -637,13 +561,13 @@ function ce(r, e, t) {
637
561
  };
638
562
  return s(0);
639
563
  }
640
- function ue(r, e) {
564
+ function oe(r, e) {
641
565
  const t = {}, n = e ?? [];
642
- return ie.forEach(
566
+ return ne.forEach(
643
567
  (s) => {
644
568
  t[s] = (...o) => {
645
- const i = V[s](...o);
646
- return ce(
569
+ const i = P[s](...o);
570
+ return se(
647
571
  i,
648
572
  n,
649
573
  r
@@ -652,42 +576,41 @@ function ue(r, e) {
652
576
  }
653
577
  ), t;
654
578
  }
655
- function O(r) {
656
- const { extensions: e, instanceKey: t } = r ?? {}, n = ae(t);
657
- return ue(
579
+ function x(r) {
580
+ const { extensions: e, instanceKey: t } = r ?? {}, n = re(t);
581
+ return oe(
658
582
  n,
659
583
  e
660
584
  );
661
585
  }
662
- function ge(r) {
586
+ function ue(r) {
663
587
  const { instanceKey: e, key: t, duration: n, isValid: s, store: o, ...i } = r;
664
- return O({
588
+ return x({
665
589
  instanceKey: e,
666
590
  extensions: [
667
- q(i),
591
+ E(i),
668
592
  te({ key: t, duration: n, isValid: s, store: o })
669
593
  ]
670
594
  });
671
595
  }
672
- function fe(r) {
596
+ function le(r) {
673
597
  const { instanceKey: e, parallelCount: t, createId: n, retries: s, delay: o, retryCondition: i } = r;
674
- return O({
598
+ return x({
675
599
  instanceKey: e,
676
600
  extensions: [
677
601
  K({ parallelCount: t, createId: n }),
678
- F({ retries: s, delay: o, retryCondition: i })
602
+ D({ retries: s, delay: o, retryCondition: i })
679
603
  ]
680
604
  });
681
605
  }
682
606
  export {
683
607
  te as cache,
684
608
  K as concurrent,
685
- ge as createCachedIdempotentRequestor,
686
- fe as createConcurrentRetryRequestor,
687
- O as createRequestor,
688
- q as idempotent,
689
- ye as inject,
690
- F as retry,
691
- me as sync,
692
- ae as useRequestor
609
+ ue as createCachedIdempotentRequestor,
610
+ le as createConcurrentRetryRequestor,
611
+ x as createRequestor,
612
+ E as idempotent,
613
+ ce as inject,
614
+ D as retry,
615
+ re as useRequestor
693
616
  };
@@ -1 +1 @@
1
- (function(u,w){typeof exports=="object"&&typeof module<"u"?w(exports,require("id-queue")):typeof define=="function"&&define.amd?define(["exports","id-queue"],w):(u=typeof globalThis<"u"?globalThis:u||self,w(u.netVertCore={},u.idQueue))})(this,function(u,w){"use strict";var p=(r=>(r.GET="get",r.POST="post",r.PUT="put",r.DELETE="delete",r))(p||{}),y=(r=>(r.CACHE="cache",r.RETRY="retry",r.IDEMPOTENT="idempotent",r.CONCURRENT="concurrent",r.SYNC="sync",r))(y||{});const N="default",E={retries:3,delay:0,retryCondition:()=>!0},P=r=>{const e={...E,...r};return Object.assign(async({config:n,next:s})=>{let o=0,a;for(;o<=e.retries;)try{return await s()}catch(i){if(a=i,o===e.retries)throw i;const c={config:n,lastResponse:i,attempt:o};if(!e.retryCondition(c))throw i;o++;const l=typeof e.delay=="function"?e.delay(c):e.delay;l>0&&await new Promise(d=>setTimeout(d,l))}throw a},{__middlewareType:y.RETRY})},B=()=>{const r=new Map;return{getPromise:o=>r.get(o),setPromise:(o,a)=>{r.set(o,a),a.finally(()=>r.delete(o))},delPromise:o=>r.delete(o),clearCache:()=>r.clear()}},K={key:r=>{const{config:e}=r,{method:t,url:n,data:s}=e;return[t,n,JSON.stringify(s)].join("|")}},V=r=>{const e={...K,...r},t=B();return Object.assign(({config:s,next:o})=>{const a=e.key({config:s}),i=t.getPromise(a);if(i)return i;const c=o();return t.setPromise(a,c),c},{__middlewareType:y.IDEMPOTENT,promiseCache:t})};class _{parallelCount;tasks;runningCount;constructor(e=4){this.parallelCount=e,this.tasks=new w.TaskQueue,this.runningCount=0}add(e,t){return new Promise((n,s)=>{this.tasks.enqueue(e,{task:t,resolve:n,reject:s}),this._run()})}remove(e){this.tasks.remove(e)}execute(e){const{task:t,resolve:n,reject:s}=e;return t().then(n).catch(s).finally(()=>{this.runningCount--,this._run()})}_run(){for(;this.runningCount<this.parallelCount&&this.tasks.size>0;){const e=this.tasks.dequeue();this.runningCount++,this.execute(e)}}}let A=0;const J={parallelCount:4,createId:()=>A++},x=r=>{const{parallelCount:e,createId:t}={...J,...r},n=new _(e);return Object.assign(({config:o,next:a})=>{const i=t({config:o});return n.add(i,()=>a())},{__middlewareType:y.CONCURRENT,pool:n})},O=new Map,f=(r,e)=>{O.set(e,r)};function z(r){const e=O.get(r);if(!e)throw new Error(`Store实例 ${String(r)} 未注册`);return e}class G{store=new Map;getItem(e){return this.store.get(e)}setItem(e,t){return this.store.set(e,t),t}removeItem(e){this.store.delete(e)}clear(){this.store.clear()}length(){return this.store.size}key(e){return Array.from(this.store.keys())[e]}keys(){return Array.from(this.store.keys())}iterate(e){let t=0;for(const[n,s]of this.store.entries())e(s,n,t),t++}}const U=r=>!!r&&(typeof r=="object"||typeof r=="function")&&typeof r.then=="function",q=r=>typeof window<"u"?r():{getItem(){return null},setItem(){},removeItem(){},clear(){},key(){return null},get length(){return 0}},h=q(()=>window.localStorage);class M{constructor(){}getItem(e){const t=String(e),n=h.getItem(t);if(n!==null)try{return JSON.parse(n)}catch(s){console.error(`Failed to parse value for key: ${t}`,s);return}}setItem(e,t){const n=String(e);try{h.setItem(n,JSON.stringify(t))}catch(s){throw console.error(`Failed to set value for key: ${n}`,s),s}return t}removeItem(e){const t=String(e);h.removeItem(t)}clear(){h.clear()}length(){return h.length}key(e){return h.key(e)}keys(){const e=[];for(let t=0;t<h.length;t++){const n=h.key(t);n&&e.push(n)}return e}iterate(e){this.keys().forEach((t,n)=>{const s=this.getItem(t);s!==void 0&&e(s,t,n)})}}const m=q(()=>window.sessionStorage);class Y{constructor(){}getItem(e){const t=String(e),n=m.getItem(t);if(n!==null)try{return JSON.parse(n)}catch(s){console.error(`Failed to parse value for key: ${t}`,s);return}}setItem(e,t){const n=String(e);try{m.setItem(n,JSON.stringify(t))}catch(s){throw console.error(`Failed to set value for key: ${n}`,s),s}return t}removeItem(e){const t=String(e);m.removeItem(t)}clear(){m.clear()}length(){return m.length}key(e){return m.key(e)}keys(){const e=[];for(let t=0;t<m.length;t++){const n=m.key(t);n&&e.push(n)}return e}iterate(e){this.keys().forEach((t,n)=>{const s=this.getItem(t);s!==void 0&&e(s,t,n)})}}class X{dbName;storeName;dbPromise=null;DB_VERSION=1;constructor(e,t){this.dbName=e,this.storeName=t,this.initDB()}initDB(){if(typeof window>"u"||!window.indexedDB){console.warn("IndexedDB is not available");return}this.dbPromise=new Promise((e,t)=>{const n=indexedDB.open(this.dbName,this.DB_VERSION);n.onerror=()=>{t(new Error(`Failed to open database: ${this.dbName}`))},n.onsuccess=()=>{e(n.result)},n.onupgradeneeded=s=>{const o=s.target.result;o.objectStoreNames.contains(this.storeName)||o.createObjectStore(this.storeName)}})}async getDB(){if(!this.dbPromise)throw new Error("IndexedDB is not initialized");return this.dbPromise}async withStore(e,t){const n=await this.getDB();return new Promise((s,o)=>{const a=n.transaction([this.storeName],e).objectStore(this.storeName),i=t(a);i.onsuccess=()=>{s(i.result)},i.onerror=()=>{o(i.error)}})}async getItem(e){try{const t=await this.withStore("readonly",n=>n.get(String(e)));return t===void 0?void 0:t}catch(t){console.error(`Failed to get value for key: ${String(e)}`,t);return}}async setItem(e,t){try{return await this.withStore("readwrite",n=>n.put(t,String(e))),t}catch(n){throw console.error(`Failed to set value for key: ${String(e)}`,n),n}}async removeItem(e){try{await this.withStore("readwrite",t=>t.delete(String(e)))}catch(t){throw console.error(`Failed to remove value for key: ${String(e)}`,t),t}}async clear(){try{await this.withStore("readwrite",e=>e.clear())}catch(e){throw console.error("Failed to clear storage",e),e}}async length(){try{return await this.withStore("readonly",e=>e.count())}catch(e){return console.error("Failed to get storage length",e),0}}async key(e){try{return(await this.withStore("readonly",t=>t.getAllKeys()))[e]}catch(t){console.error("Failed to get key",t);return}}async keys(){try{return await this.withStore("readonly",e=>e.getAllKeys())}catch(e){return console.error("Failed to get all keys",e),[]}}async iterate(e){try{const t=(await this.getDB()).transaction([this.storeName],"readonly").objectStore(this.storeName).openCursor();return new Promise((n,s)=>{let o=0;t.onsuccess=a=>{const i=a.target.result;if(i){const c=i.key,l=i.value;e(l,c,o),o++,i.continue()}else n()},t.onerror=()=>{s(t.error)}})}catch(t){console.error("Failed to iterate storage",t)}}}const g={memory:"memory",local:"local",session:"session",indexeddb:"indexeddb"};function j(r,e){Object.assign(r,e)}function Z(r){return j(r,{async getItemOrDefault(e,t){const n=await this.getItem(e);return n!==null?n:t},async hasItem(e){return await this.getItem(e)!==null},async removeItems(e){await Promise.all(e.map(t=>this.removeItem(t)))},async getItems(e){return await Promise.all(e.map(t=>this.getItem(t)))}}),r}function H(r){return j(r,{getItemOrDefault(e,t){const n=this.getItem(e);return n!==null?n:t},hasItem(e){return this.getItem(e)!==null},removeItems(e){e.forEach(t=>this.removeItem(t))},getItems(e){return e.map(t=>this.getItem(t))}}),r}function L(r){const e=r.getItem("");return U(e)?Z(r):H(r)}function C(r,...e){const t=z(r);let n;try{n=new t(...e)}catch{n=t(...e)}return L(n)}f(G,g.memory),f(M,g.local),f(Y,g.session),f(X,g.indexeddb);function I(r,e){return{value:r,expireAt:Date.now()+e}}function k(r,e=Date.now()){return r.expireAt<=e}function R(r,e=Date.now()){return k(r,e)?void 0:r.value}const Q=r=>{const{config:e}=r,{method:t,url:n,data:s}=e;return[t,n,JSON.stringify(s)].join("|")},W=()=>!0,S=24*60*60*1e3,ee={key:Q,duration:S,isValid:W,store:g.memory},te=class{store;constructor(e){return typeof e=="string"?this.store=C(e):(f(e.factory,e.key),this.store=C(e.key)),new Proxy(this,{get(t,n){if(n in t)return t[n];const s=t.store[n];return typeof s=="function"?s.bind(t.store):s}})}setCache(e,t,n=S){const s=I(t,n);this.store.setItem(e,s)}async getCache(e){const t=await this.store.getItem(e);if(t)return R(t)}async hasValidCache(e){const t=await this.store.getItem(e);return t?!k(t):!1}},T=r=>{const e={...ee,...r},t=new te(e.store),n=o=>typeof e.duration=="function"?e.duration(o):e.duration;return Object.assign(async({config:o,next:a})=>{const i=e.key({config:o}),c=await t.getCache(i);if(c){if(await e.isValid({key:i,config:o,cachedData:c}))return c;t.removeItem(i)}const l=await a(),d=n({key:i,config:o,cachedData:c,response:l}),v=I(l,d);return t.setItem(i,v),l},{__middlewareType:y.CACHE,storage:t})};class re{store;constructor(e){return typeof e=="string"?this.store=C(e):(f(e.factory,e.key),this.store=C(e.key)),new Proxy(this,{get(t,n){if(n in t)return t[n];const s=t.store[n];return typeof s=="function"?s.bind(t.store):s}})}setCache(e,t,n=S){const s=I(t,n);this.store.setItem(e,s)}getCache(e){const t=this.store.getItem(e);if(t)return R(t)}hasValidCache(e){const t=this.store.getItem(e);return t?!k(t):!1}}const ne=re,se={suspense:!0,key:r=>{const{config:e}=r,{method:t,url:n}=e;return[t,n].join("|")},duration:24*60*60*1e3,isValid:()=>!0,store:g.memory};function oe(r){const e={...se,...r},t=new ne(e.store),n=o=>typeof e.duration=="function"?e.duration(o):e.duration;return Object.assign(({config:o,next:a})=>{const i=e.key({config:o}),c=t.getCache(i);if(c){if(e.isValid({key:i,config:o,cachedData:c}))return c;t.removeItem(i)}if(e.suspense)throw(e.wrapSuspense?e.wrapSuspense({key:i,config:o,p:a()}):a()).then(d=>{const v=n({key:i,config:o,cachedData:c,response:d});return t.setCache(i,d,v),d});return a().then(l=>{const d=n({key:i,config:o,cachedData:c,response:l});return t.setCache(i,l,d),l})},{__middlewareType:y.SYNC})}const D=new Map,ie=(r,e=N)=>{D.set(e,r)},F=(r=N)=>{const e=D.get(r);if(!e)throw new Error(`Requestor实例 ${String(r)} 未注册`);return e},$={get:(r,e)=>({url:r,method:p.GET,...e,params:e?.params}),post:(r,e,t)=>({url:r,method:p.POST,data:e,...t}),delete:(r,e)=>({url:r,method:p.DELETE,...e}),put:(r,e,t)=>({url:r,method:p.PUT,data:e,...t}),request:r=>r},ae=Object.keys($);function ce(r,e,t){const n={},s=o=>{if(o===e.length)return t(r);const a=e[o];return a({config:r,ctx:n,next:()=>s(o+1)})};return s(0)}function ue(r,e){const t={},n=e??[];return ae.forEach(s=>{t[s]=(...o)=>{const a=$[s](...o);return ce(a,n,r)}}),t}function b(r){const{extensions:e,instanceKey:t}=r??{},n=F(t);return ue(n,e)}function le(r){const{instanceKey:e,key:t,duration:n,isValid:s,store:o,...a}=r;return b({instanceKey:e,extensions:[V(a),T({key:t,duration:n,isValid:s,store:o})]})}function de(r){const{instanceKey:e,parallelCount:t,createId:n,retries:s,delay:o,retryCondition:a}=r;return b({instanceKey:e,extensions:[x({parallelCount:t,createId:n}),P({retries:s,delay:o,retryCondition:a})]})}u.cache=T,u.concurrent=x,u.createCachedIdempotentRequestor=le,u.createConcurrentRetryRequestor=de,u.createRequestor=b,u.idempotent=V,u.inject=ie,u.retry=P,u.sync=oe,u.useRequestor=F,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})});
1
+ (function(c,m){typeof exports=="object"&&typeof module<"u"?m(exports,require("id-queue")):typeof define=="function"&&define.amd?define(["exports","id-queue"],m):(c=typeof globalThis<"u"?globalThis:c||self,m(c.netVertCore={},c.idQueue))})(this,function(c,m){"use strict";var y=(r=>(r.GET="get",r.POST="post",r.PUT="put",r.DELETE="delete",r))(y||{}),g=(r=>(r.CACHE="cache",r.RETRY="retry",r.IDEMPOTENT="idempotent",r.CONCURRENT="concurrent",r.SYNC="sync",r))(g||{});const C="default",V={retries:3,delay:0,retryCondition:()=>!0},k=r=>{const e={...V,...r};return Object.assign(async({config:n,next:o})=>{let s=0,a;for(;s<=e.retries;)try{return await o()}catch(i){if(a=i,s===e.retries)throw i;const u={config:n,lastResponse:i,attempt:s};if(!e.retryCondition(u))throw i;s++;const h=typeof e.delay=="function"?e.delay(u):e.delay;h>0&&await new Promise(I=>setTimeout(I,h))}throw a},{__middlewareType:g.RETRY})},E=()=>{const r=new Map;return{getPromise:s=>r.get(s),setPromise:(s,a)=>{r.set(s,a),a.finally(()=>r.delete(s))},delPromise:s=>r.delete(s),clearCache:()=>r.clear()}},$={key:r=>{const{config:e}=r,{method:t,url:n,data:o}=e;return[t,n,JSON.stringify(o)].join("|")}},S=r=>{const e={...$,...r},t=E();return Object.assign(({config:o,next:s})=>{const a=e.key({config:o}),i=t.getPromise(a);if(i)return i;const u=s();return t.setPromise(a,u),u},{__middlewareType:g.IDEMPOTENT,promiseCache:t})};class B{parallelCount;tasks;runningCount;constructor(e=4){this.parallelCount=e,this.tasks=new m.TaskQueue,this.runningCount=0}add(e,t){return new Promise((n,o)=>{this.tasks.enqueue(e,{task:t,resolve:n,reject:o}),this._run()})}remove(e){this.tasks.remove(e)}execute(e){const{task:t,resolve:n,reject:o}=e;return t().then(n).catch(o).finally(()=>{this.runningCount--,this._run()})}_run(){for(;this.runningCount<this.parallelCount&&this.tasks.size>0;){const e=this.tasks.dequeue();this.runningCount++,this.execute(e)}}}let K=0;const _={parallelCount:4,createId:()=>K++},v=r=>{const{parallelCount:e,createId:t}={..._,...r},n=new B(e);return Object.assign(({config:s,next:a})=>{const i=t({config:s});return n.add(i,()=>a())},{__middlewareType:g.CONCURRENT,pool:n})},b=new Map,f=(r,e)=>{b.set(e,r)};function A(r){const e=b.get(r);if(!e)throw new Error(`Store实例 ${String(r)} 未注册`);return e}class J{store=new Map;getItem(e){return this.store.get(e)}setItem(e,t){return this.store.set(e,t),t}removeItem(e){this.store.delete(e)}clear(){this.store.clear()}length(){return this.store.size}key(e){return Array.from(this.store.keys())[e]}keys(){return Array.from(this.store.keys())}iterate(e){let t=0;for(const[n,o]of this.store.entries())e(o,n,t),t++}}const z=r=>!!r&&(typeof r=="object"||typeof r=="function")&&typeof r.then=="function",N=r=>typeof window<"u"?r():{getItem(){return null},setItem(){},removeItem(){},clear(){},key(){return null},get length(){return 0}},l=N(()=>window.localStorage);class G{constructor(){}getItem(e){const t=String(e),n=l.getItem(t);if(n!==null)try{return JSON.parse(n)}catch(o){console.error(`Failed to parse value for key: ${t}`,o);return}}setItem(e,t){const n=String(e);try{l.setItem(n,JSON.stringify(t))}catch(o){throw console.error(`Failed to set value for key: ${n}`,o),o}return t}removeItem(e){const t=String(e);l.removeItem(t)}clear(){l.clear()}length(){return l.length}key(e){return l.key(e)}keys(){const e=[];for(let t=0;t<l.length;t++){const n=l.key(t);n&&e.push(n)}return e}iterate(e){this.keys().forEach((t,n)=>{const o=this.getItem(t);o!==void 0&&e(o,t,n)})}}const d=N(()=>window.sessionStorage);class U{constructor(){}getItem(e){const t=String(e),n=d.getItem(t);if(n!==null)try{return JSON.parse(n)}catch(o){console.error(`Failed to parse value for key: ${t}`,o);return}}setItem(e,t){const n=String(e);try{d.setItem(n,JSON.stringify(t))}catch(o){throw console.error(`Failed to set value for key: ${n}`,o),o}return t}removeItem(e){const t=String(e);d.removeItem(t)}clear(){d.clear()}length(){return d.length}key(e){return d.key(e)}keys(){const e=[];for(let t=0;t<d.length;t++){const n=d.key(t);n&&e.push(n)}return e}iterate(e){this.keys().forEach((t,n)=>{const o=this.getItem(t);o!==void 0&&e(o,t,n)})}}class M{dbName;storeName;dbPromise=null;DB_VERSION=1;constructor(e,t){this.dbName=e,this.storeName=t,this.initDB()}initDB(){if(typeof window>"u"||!window.indexedDB){console.warn("IndexedDB is not available");return}this.dbPromise=new Promise((e,t)=>{const n=indexedDB.open(this.dbName,this.DB_VERSION);n.onerror=()=>{t(new Error(`Failed to open database: ${this.dbName}`))},n.onsuccess=()=>{e(n.result)},n.onupgradeneeded=o=>{const s=o.target.result;s.objectStoreNames.contains(this.storeName)||s.createObjectStore(this.storeName)}})}async getDB(){if(!this.dbPromise)throw new Error("IndexedDB is not initialized");return this.dbPromise}async withStore(e,t){const n=await this.getDB();return new Promise((o,s)=>{const a=n.transaction([this.storeName],e).objectStore(this.storeName),i=t(a);i.onsuccess=()=>{o(i.result)},i.onerror=()=>{s(i.error)}})}async getItem(e){try{const t=await this.withStore("readonly",n=>n.get(String(e)));return t===void 0?void 0:t}catch(t){console.error(`Failed to get value for key: ${String(e)}`,t);return}}async setItem(e,t){try{return await this.withStore("readwrite",n=>n.put(t,String(e))),t}catch(n){throw console.error(`Failed to set value for key: ${String(e)}`,n),n}}async removeItem(e){try{await this.withStore("readwrite",t=>t.delete(String(e)))}catch(t){throw console.error(`Failed to remove value for key: ${String(e)}`,t),t}}async clear(){try{await this.withStore("readwrite",e=>e.clear())}catch(e){throw console.error("Failed to clear storage",e),e}}async length(){try{return await this.withStore("readonly",e=>e.count())}catch(e){return console.error("Failed to get storage length",e),0}}async key(e){try{return(await this.withStore("readonly",t=>t.getAllKeys()))[e]}catch(t){console.error("Failed to get key",t);return}}async keys(){try{return await this.withStore("readonly",e=>e.getAllKeys())}catch(e){return console.error("Failed to get all keys",e),[]}}async iterate(e){try{const t=(await this.getDB()).transaction([this.storeName],"readonly").objectStore(this.storeName).openCursor();return new Promise((n,o)=>{let s=0;t.onsuccess=a=>{const i=a.target.result;if(i){const u=i.key,h=i.value;e(h,u,s),s++,i.continue()}else n()},t.onerror=()=>{o(t.error)}})}catch(t){console.error("Failed to iterate storage",t)}}}const w={memory:"memory",local:"local",session:"session",indexeddb:"indexeddb"};function P(r,e){Object.assign(r,e)}function X(r){return P(r,{async getItemOrDefault(e,t){const n=await this.getItem(e);return n!==null?n:t},async hasItem(e){return await this.getItem(e)!==null},async removeItems(e){await Promise.all(e.map(t=>this.removeItem(t)))},async getItems(e){return await Promise.all(e.map(t=>this.getItem(t)))}}),r}function Y(r){return P(r,{getItemOrDefault(e,t){const n=this.getItem(e);return n!==null?n:t},hasItem(e){return this.getItem(e)!==null},removeItems(e){e.forEach(t=>this.removeItem(t))},getItems(e){return e.map(t=>this.getItem(t))}}),r}function Z(r){const e=r.getItem("");return z(e)?X(r):Y(r)}function q(r,...e){const t=A(r);let n;try{n=new t(...e)}catch{n=t(...e)}return Z(n)}f(J,w.memory),f(G,w.local),f(U,w.session),f(M,w.indexeddb);function O(r,e){return{value:r,expireAt:Date.now()+e}}function R(r,e=Date.now()){return r.expireAt<=e}function H(r,e=Date.now()){return R(r,e)?void 0:r.value}const L=r=>{const{config:e}=r,{method:t,url:n,data:o}=e;return[t,n,JSON.stringify(o)].join("|")},Q=()=>!0,j=24*60*60*1e3,W={key:L,duration:j,isValid:Q,store:w.memory};class ee{store;constructor(e){return typeof e=="string"?this.store=q(e):(f(e.factory,e.key),this.store=q(e.key)),new Proxy(this,{get(t,n){if(n in t)return t[n];const o=t.store[n];return typeof o=="function"?o.bind(t.store):o}})}setCache(e,t,n=j){const o=O(t,n);this.store.setItem(e,o)}async getCache(e){const t=await this.store.getItem(e);if(t)return H(t)}async hasValidCache(e){const t=await this.store.getItem(e);return t?!R(t):!1}}const te=ee,x=r=>{const e={...W,...r},t=new te(e.store),n=s=>typeof e.duration=="function"?e.duration(s):e.duration;return Object.assign(async({config:s,next:a})=>{const i=e.key({config:s}),u=await t.getCache(i);if(u){if(await e.isValid({key:i,config:s,cachedData:u}))return u;t.removeItem(i)}const h=await a(),I=n({key:i,config:s,cachedData:u,response:h}),ce=O(h,I);return t.setItem(i,ce),h},{__middlewareType:g.CACHE,storage:t})},T=new Map,re=(r,e=C)=>{T.set(e,r)},F=(r=C)=>{const e=T.get(r);if(!e)throw new Error(`Requestor实例 ${String(r)} 未注册`);return e},D={get:(r,e)=>({url:r,method:y.GET,...e,params:e?.params}),post:(r,e,t)=>({url:r,method:y.POST,data:e,...t}),delete:(r,e)=>({url:r,method:y.DELETE,...e}),put:(r,e,t)=>({url:r,method:y.PUT,data:e,...t}),request:r=>r},ne=Object.keys(D);function oe(r,e,t){const n={},o=s=>{if(s===e.length)return t(r);const a=e[s];return a({config:r,ctx:n,next:()=>o(s+1)})};return o(0)}function se(r,e){const t={},n=e??[];return ne.forEach(o=>{t[o]=(...s)=>{const a=D[o](...s);return oe(a,n,r)}}),t}function p(r){const{extensions:e,instanceKey:t}=r??{},n=F(t);return se(n,e)}function ie(r){const{instanceKey:e,key:t,duration:n,isValid:o,store:s,...a}=r;return p({instanceKey:e,extensions:[S(a),x({key:t,duration:n,isValid:o,store:s})]})}function ae(r){const{instanceKey:e,parallelCount:t,createId:n,retries:o,delay:s,retryCondition:a}=r;return p({instanceKey:e,extensions:[v({parallelCount:t,createId:n}),k({retries:o,delay:s,retryCondition:a})]})}c.cache=x,c.concurrent=v,c.createCachedIdempotentRequestor=ie,c.createConcurrentRetryRequestor=ae,c.createRequestor=p,c.idempotent=S,c.inject=re,c.retry=k,c.useRequestor=F,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@net-vert/core",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "Dependency Inversion Network Library with Type-Safe Injection.",
5
5
  "main": "dist/index",
6
6
  "type": "module",