@net-vert/core 1.2.1 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,78 @@
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", I = /* @__PURE__ */ new Map(), ce = (r, e = p) => {
4
+ I.set(e, r);
5
+ }, j = (r = p) => {
6
+ const e = I.get(r);
7
+ if (!e) throw new Error(`Requestor实例 ${String(r)} 未注册`);
8
+ return e;
9
+ }, C = {
10
+ get: (r, e) => ({
11
+ url: r,
12
+ method: h.GET,
13
+ ...e,
14
+ params: e?.params
15
+ }),
16
+ post: (r, e, t) => ({
17
+ url: r,
18
+ method: h.POST,
19
+ data: e,
20
+ ...t
21
+ }),
22
+ delete: (r, e) => ({
23
+ url: r,
24
+ method: h.DELETE,
25
+ ...e
26
+ }),
27
+ put: (r, e, t) => ({
28
+ url: r,
29
+ method: h.PUT,
30
+ data: e,
31
+ ...t
32
+ }),
33
+ request: (r) => r
34
+ }, D = Object.keys(C);
35
+ function T(r, e, t) {
36
+ const n = {}, s = (o) => {
37
+ if (o === e.length)
38
+ return t(r);
39
+ const i = e[o];
40
+ return i({
41
+ config: r,
42
+ ctx: n,
43
+ next: () => s(o + 1)
44
+ });
45
+ };
46
+ return s(0);
47
+ }
48
+ function V(r, e) {
49
+ const t = {}, n = e ?? [];
50
+ return D.forEach(
51
+ (s) => {
52
+ t[s] = (...o) => {
53
+ const i = C[s](...o);
54
+ return T(
55
+ i,
56
+ n,
57
+ r
58
+ );
59
+ };
60
+ }
61
+ ), t;
62
+ }
63
+ function k(r) {
64
+ const { extensions: e, instanceKey: t } = r ?? {}, n = j(t);
65
+ return V(
66
+ n,
67
+ e
68
+ );
69
+ }
70
+ const q = {
4
71
  retries: 3,
5
72
  delay: 0,
6
73
  retryCondition: () => !0
7
- }, F = (r) => {
8
- const e = { ...D, ...r };
74
+ }, E = (r) => {
75
+ const e = { ...q, ...r };
9
76
  return Object.assign(async ({ config: n, next: s }) => {
10
77
  let o = 0, i;
11
78
  for (; o <= e.retries; )
@@ -23,22 +90,22 @@ const S = "default", D = {
23
90
  throw a;
24
91
  o++;
25
92
  const u = typeof e.delay == "function" ? e.delay(c) : e.delay;
26
- u > 0 && await new Promise((l) => setTimeout(l, u));
93
+ u > 0 && await new Promise((w) => setTimeout(w, u));
27
94
  }
28
95
  throw i;
29
96
  }, { __middlewareType: m.RETRY });
30
- }, $ = () => {
97
+ }, R = () => {
31
98
  const r = /* @__PURE__ */ new Map();
32
99
  return { getPromise: (o) => r.get(o), setPromise: (o, i) => {
33
100
  r.set(o, i), i.finally(() => r.delete(o));
34
101
  }, delPromise: (o) => r.delete(o), clearCache: () => r.clear() };
35
- }, E = (r) => {
102
+ }, $ = (r) => {
36
103
  const { config: e } = r, { method: t, url: n, data: s } = e;
37
104
  return [t, n, JSON.stringify(s)].join("|");
38
- }, T = {
39
- key: E
40
- }, q = (r) => {
41
- const e = { ...T, ...r }, t = $();
105
+ }, B = {
106
+ key: $
107
+ }, K = (r) => {
108
+ const e = { ...B, ...r }, t = R();
42
109
  return Object.assign(({ config: s, next: o }) => {
43
110
  const i = e.key({ config: s }), a = t.getPromise(i);
44
111
  if (a)
@@ -50,12 +117,12 @@ const S = "default", D = {
50
117
  promiseCache: t
51
118
  });
52
119
  };
53
- class R {
120
+ class _ {
54
121
  parallelCount;
55
122
  tasks;
56
123
  runningCount;
57
124
  constructor(e = 4) {
58
- this.parallelCount = e, this.tasks = new j(), this.runningCount = 0;
125
+ this.parallelCount = e, this.tasks = new F(), this.runningCount = 0;
59
126
  }
60
127
  // 加入
61
128
  add(e, t) {
@@ -84,26 +151,26 @@ class R {
84
151
  }
85
152
  }
86
153
  }
87
- let B = 0;
88
- const _ = {
154
+ let A = 0;
155
+ const J = {
89
156
  parallelCount: 4,
90
- createId: () => B++
91
- }, K = (r) => {
92
- const { parallelCount: e, createId: t } = { ..._, ...r }, n = new R(e);
157
+ createId: () => A++
158
+ }, z = (r) => {
159
+ const { parallelCount: e, createId: t } = { ...J, ...r }, n = new _(e);
93
160
  return Object.assign(({ config: o, next: i }) => {
94
161
  const a = t({ config: o });
95
162
  return n.add(a, () => i());
96
163
  }, { __middlewareType: m.CONCURRENT, pool: n });
97
- }, v = /* @__PURE__ */ new Map(), y = (r, e) => {
98
- v.set(e, r);
164
+ }, S = /* @__PURE__ */ new Map(), y = (r, e) => {
165
+ S.set(e, r);
99
166
  };
100
- function A(r) {
101
- const e = v.get(r);
167
+ function G(r) {
168
+ const e = S.get(r);
102
169
  if (!e)
103
170
  throw new Error(`Store实例 ${String(r)} 未注册`);
104
171
  return e;
105
172
  }
106
- class J {
173
+ class U {
107
174
  store = /* @__PURE__ */ new Map();
108
175
  getItem(e) {
109
176
  return this.store.get(e);
@@ -132,7 +199,7 @@ class J {
132
199
  e(s, n, t), t++;
133
200
  }
134
201
  }
135
- const z = (r) => !!r && (typeof r == "object" || typeof r == "function") && typeof r.then == "function", b = (r) => typeof window < "u" ? r() : {
202
+ const M = (r) => !!r && (typeof r == "object" || typeof r == "function") && typeof r.then == "function", v = (r) => typeof window < "u" ? r() : {
136
203
  getItem() {
137
204
  return null;
138
205
  },
@@ -148,12 +215,12 @@ const z = (r) => !!r && (typeof r == "object" || typeof r == "function") && type
148
215
  get length() {
149
216
  return 0;
150
217
  }
151
- }, h = b(() => window.localStorage);
152
- class G {
218
+ }, l = v(() => window.localStorage);
219
+ class X {
153
220
  constructor() {
154
221
  }
155
222
  getItem(e) {
156
- const t = String(e), n = h.getItem(t);
223
+ const t = String(e), n = l.getItem(t);
157
224
  if (n !== null)
158
225
  try {
159
226
  return JSON.parse(n);
@@ -165,7 +232,7 @@ class G {
165
232
  setItem(e, t) {
166
233
  const n = String(e);
167
234
  try {
168
- h.setItem(n, JSON.stringify(t));
235
+ l.setItem(n, JSON.stringify(t));
169
236
  } catch (s) {
170
237
  throw console.error(`Failed to set value for key: ${n}`, s), s;
171
238
  }
@@ -173,21 +240,21 @@ class G {
173
240
  }
174
241
  removeItem(e) {
175
242
  const t = String(e);
176
- h.removeItem(t);
243
+ l.removeItem(t);
177
244
  }
178
245
  clear() {
179
- h.clear();
246
+ l.clear();
180
247
  }
181
248
  length() {
182
- return h.length;
249
+ return l.length;
183
250
  }
184
251
  key(e) {
185
- return h.key(e);
252
+ return l.key(e);
186
253
  }
187
254
  keys() {
188
255
  const e = [];
189
- for (let t = 0; t < h.length; t++) {
190
- const n = h.key(t);
256
+ for (let t = 0; t < l.length; t++) {
257
+ const n = l.key(t);
191
258
  n && e.push(n);
192
259
  }
193
260
  return e;
@@ -199,8 +266,8 @@ class G {
199
266
  });
200
267
  }
201
268
  }
202
- const d = b(() => window.sessionStorage);
203
- class U {
269
+ const d = v(() => window.sessionStorage);
270
+ class Y {
204
271
  constructor() {
205
272
  }
206
273
  getItem(e) {
@@ -250,7 +317,7 @@ class U {
250
317
  });
251
318
  }
252
319
  }
253
- class Y {
320
+ class Z {
254
321
  dbName;
255
322
  storeName;
256
323
  dbPromise = null;
@@ -379,11 +446,11 @@ const g = {
379
446
  session: "session",
380
447
  indexeddb: "indexeddb"
381
448
  };
382
- function N(r, e) {
449
+ function b(r, e) {
383
450
  Object.assign(r, e);
384
451
  }
385
- function M(r) {
386
- return N(r, {
452
+ function H(r) {
453
+ return b(r, {
387
454
  async getItemOrDefault(e, t) {
388
455
  const n = await this.getItem(e);
389
456
  return n !== null ? n : t;
@@ -399,8 +466,8 @@ function M(r) {
399
466
  }
400
467
  }), r;
401
468
  }
402
- function X(r) {
403
- return N(r, {
469
+ function L(r) {
470
+ return b(r, {
404
471
  getItemOrDefault(e, t) {
405
472
  const n = this.getItem(e);
406
473
  return n !== null ? n : t;
@@ -416,50 +483,50 @@ function X(r) {
416
483
  }
417
484
  }), r;
418
485
  }
419
- function Z(r) {
486
+ function Q(r) {
420
487
  const e = r.getItem("");
421
- return z(e) ? M(r) : X(r);
488
+ return M(e) ? H(r) : L(r);
422
489
  }
423
- function w(r, ...e) {
424
- const t = A(r);
490
+ function f(r, ...e) {
491
+ const t = G(r);
425
492
  let n;
426
493
  try {
427
494
  n = new t(...e);
428
495
  } catch {
429
496
  n = t(...e);
430
497
  }
431
- return Z(n);
498
+ return Q(n);
432
499
  }
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) {
500
+ y(U, g.memory);
501
+ y(X, g.local);
502
+ y(Y, g.session);
503
+ y(Z, g.indexeddb);
504
+ function N(r, e) {
438
505
  return {
439
506
  value: r,
440
507
  expireAt: Date.now() + e
441
508
  };
442
509
  }
443
- function I(r, e = Date.now()) {
510
+ function P(r, e = Date.now()) {
444
511
  return r.expireAt <= e;
445
512
  }
446
- function x(r, e = Date.now()) {
447
- return I(r, e) ? void 0 : r.value;
513
+ function W(r, e = Date.now()) {
514
+ return P(r, e) ? void 0 : r.value;
448
515
  }
449
- const H = (r) => {
516
+ const ee = (r) => {
450
517
  const { config: e } = r, { method: t, url: n, data: s } = e;
451
518
  return [t, n, JSON.stringify(s)].join("|");
452
- }, L = () => !0, k = 24 * 60 * 60 * 1e3, Q = {
453
- key: H,
454
- duration: k,
455
- isValid: L,
519
+ }, te = () => !0, x = 24 * 60 * 60 * 1e3, re = {
520
+ key: ee,
521
+ duration: x,
522
+ isValid: te,
456
523
  store: g.memory
457
524
  // 默认不持久化,使用内存存储
458
525
  };
459
- let W = class {
526
+ class ne {
460
527
  store;
461
528
  constructor(e) {
462
- return typeof e == "string" ? this.store = w(e) : (y(e.factory, e.key), this.store = w(e.key)), new Proxy(this, {
529
+ return typeof e == "string" ? this.store = f(e) : (y(e.factory, e.key), this.store = f(e.key)), new Proxy(this, {
463
530
  get(t, n) {
464
531
  if (n in t)
465
532
  return t[n];
@@ -474,8 +541,8 @@ let W = class {
474
541
  * @param value 要缓存的值
475
542
  * @param duration 过期时长(毫秒),默认 24 小时
476
543
  */
477
- setCache(e, t, n = k) {
478
- const s = C(t, n);
544
+ setCache(e, t, n = x) {
545
+ const s = N(t, n);
479
546
  this.store.setItem(e, s);
480
547
  }
481
548
  /**
@@ -486,7 +553,7 @@ let W = class {
486
553
  async getCache(e) {
487
554
  const t = await this.store.getItem(e);
488
555
  if (t)
489
- return x(t);
556
+ return W(t);
490
557
  }
491
558
  /**
492
559
  * 检查是否有有效的缓存(未过期)
@@ -495,11 +562,11 @@ let W = class {
495
562
  */
496
563
  async hasValidCache(e) {
497
564
  const t = await this.store.getItem(e);
498
- return t ? !I(t) : !1;
565
+ return t ? !P(t) : !1;
499
566
  }
500
- };
501
- const ee = W, te = (r) => {
502
- const e = { ...Q, ...r }, t = new ee(e.store), n = (o) => typeof e.duration == "function" ? e.duration(o) : e.duration;
567
+ }
568
+ const se = ne, oe = (r) => {
569
+ const e = { ...re, ...r }, t = new se(e.store), n = (o) => typeof e.duration == "function" ? e.duration(o) : e.duration;
503
570
  return Object.assign(async ({ config: o, next: i }) => {
504
571
  const a = e.key({ config: o }), c = await t.getCache(a);
505
572
  if (c) {
@@ -510,184 +577,41 @@ const ee = W, te = (r) => {
510
577
  })) return c;
511
578
  t.removeItem(a);
512
579
  }
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;
580
+ const u = await i(), w = n({ key: a, config: o, cachedData: c, response: u }), O = N(u, w);
581
+ return t.setItem(a, O), u;
515
582
  }, {
516
583
  __middlewareType: m.CACHE,
517
584
  storage: t
518
585
  });
519
586
  };
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);
599
- if (!e) throw new Error(`Requestor实例 ${String(r)} 未注册`);
600
- return e;
601
- }, V = {
602
- get: (r, e) => ({
603
- url: r,
604
- method: f.GET,
605
- ...e,
606
- params: e?.params
607
- }),
608
- post: (r, e, t) => ({
609
- url: r,
610
- method: f.POST,
611
- data: e,
612
- ...t
613
- }),
614
- delete: (r, e) => ({
615
- url: r,
616
- method: f.DELETE,
617
- ...e
618
- }),
619
- put: (r, e, t) => ({
620
- url: r,
621
- method: f.PUT,
622
- data: e,
623
- ...t
624
- }),
625
- request: (r) => r
626
- }, ie = Object.keys(V);
627
- function ce(r, e, t) {
628
- const n = {}, s = (o) => {
629
- if (o === e.length)
630
- return t(r);
631
- const i = e[o];
632
- return i({
633
- config: r,
634
- ctx: n,
635
- next: () => s(o + 1)
636
- });
637
- };
638
- return s(0);
639
- }
640
- function ue(r, e) {
641
- const t = {}, n = e ?? [];
642
- return ie.forEach(
643
- (s) => {
644
- t[s] = (...o) => {
645
- const i = V[s](...o);
646
- return ce(
647
- i,
648
- n,
649
- r
650
- );
651
- };
652
- }
653
- ), t;
654
- }
655
- function O(r) {
656
- const { extensions: e, instanceKey: t } = r ?? {}, n = ae(t);
657
- return ue(
658
- n,
659
- e
660
- );
661
- }
662
- function ge(r) {
587
+ function ue(r) {
663
588
  const { instanceKey: e, key: t, duration: n, isValid: s, store: o, ...i } = r;
664
- return O({
589
+ return k({
665
590
  instanceKey: e,
666
591
  extensions: [
667
- q(i),
668
- te({ key: t, duration: n, isValid: s, store: o })
592
+ K(i),
593
+ oe({ key: t, duration: n, isValid: s, store: o })
669
594
  ]
670
595
  });
671
596
  }
672
- function fe(r) {
597
+ function le(r) {
673
598
  const { instanceKey: e, parallelCount: t, createId: n, retries: s, delay: o, retryCondition: i } = r;
674
- return O({
599
+ return k({
675
600
  instanceKey: e,
676
601
  extensions: [
677
- K({ parallelCount: t, createId: n }),
678
- F({ retries: s, delay: o, retryCondition: i })
602
+ z({ parallelCount: t, createId: n }),
603
+ E({ retries: s, delay: o, retryCondition: i })
679
604
  ]
680
605
  });
681
606
  }
682
607
  export {
683
- te as cache,
684
- 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
608
+ oe as cache,
609
+ z as concurrent,
610
+ ue as createCachedIdempotentRequestor,
611
+ le as createConcurrentRetryRequestor,
612
+ k as createRequestor,
613
+ K as idempotent,
614
+ ce as inject,
615
+ E as retry,
616
+ j as useRequestor
693
617
  };
@@ -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",k=new Map,V=(r,e=C)=>{k.set(e,r)},S=(r=C)=>{const e=k.get(r);if(!e)throw new Error(`Requestor实例 ${String(r)} 未注册`);return e},v={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},E=Object.keys(v);function $(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 B(r,e){const t={},n=e??[];return E.forEach(o=>{t[o]=(...s)=>{const a=v[o](...s);return $(a,n,r)}}),t}function p(r){const{extensions:e,instanceKey:t}=r??{},n=S(t);return B(n,e)}const K={retries:3,delay:0,retryCondition:()=>!0},b=r=>{const e={...K,...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})},_=()=>{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()}},A={key:r=>{const{config:e}=r,{method:t,url:n,data:o}=e;return[t,n,JSON.stringify(o)].join("|")}},N=r=>{const e={...A,...r},t=_();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 J{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 z=0;const G={parallelCount:4,createId:()=>z++},P=r=>{const{parallelCount:e,createId:t}={...G,...r},n=new J(e);return Object.assign(({config:s,next:a})=>{const i=t({config:s});return n.add(i,()=>a())},{__middlewareType:g.CONCURRENT,pool:n})},q=new Map,f=(r,e)=>{q.set(e,r)};function U(r){const e=q.get(r);if(!e)throw new Error(`Store实例 ${String(r)} 未注册`);return e}class M{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 X=r=>!!r&&(typeof r=="object"||typeof r=="function")&&typeof r.then=="function",O=r=>typeof window<"u"?r():{getItem(){return null},setItem(){},removeItem(){},clear(){},key(){return null},get length(){return 0}},l=O(()=>window.localStorage);class Y{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=O(()=>window.sessionStorage);class Z{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 H{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 R(r,e){Object.assign(r,e)}function L(r){return R(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 Q(r){return R(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 W(r){const e=r.getItem("");return X(e)?L(r):Q(r)}function j(r,...e){const t=U(r);let n;try{n=new t(...e)}catch{n=t(...e)}return W(n)}f(M,w.memory),f(Y,w.local),f(Z,w.session),f(H,w.indexeddb);function x(r,e){return{value:r,expireAt:Date.now()+e}}function T(r,e=Date.now()){return r.expireAt<=e}function ee(r,e=Date.now()){return T(r,e)?void 0:r.value}const te=r=>{const{config:e}=r,{method:t,url:n,data:o}=e;return[t,n,JSON.stringify(o)].join("|")},re=()=>!0,F=24*60*60*1e3,ne={key:te,duration:F,isValid:re,store:w.memory};class oe{store;constructor(e){return typeof e=="string"?this.store=j(e):(f(e.factory,e.key),this.store=j(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=F){const o=x(t,n);this.store.setItem(e,o)}async getCache(e){const t=await this.store.getItem(e);if(t)return ee(t)}async hasValidCache(e){const t=await this.store.getItem(e);return t?!T(t):!1}}const se=oe,D=r=>{const e={...ne,...r},t=new se(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=x(h,I);return t.setItem(i,ce),h},{__middlewareType:g.CACHE,storage:t})};function ie(r){const{instanceKey:e,key:t,duration:n,isValid:o,store:s,...a}=r;return p({instanceKey:e,extensions:[N(a),D({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:[P({parallelCount:t,createId:n}),b({retries:o,delay:s,retryCondition:a})]})}c.cache=D,c.concurrent=P,c.createCachedIdempotentRequestor=ie,c.createConcurrentRetryRequestor=ae,c.createRequestor=p,c.idempotent=N,c.inject=V,c.retry=b,c.useRequestor=S,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,36 +1,36 @@
1
1
  {
2
- "name": "@net-vert/core",
3
- "version": "1.2.1",
4
- "description": "Dependency Inversion Network Library with Type-Safe Injection.",
5
- "main": "dist/index",
6
- "type": "module",
7
- "types": "dist/index.d.ts",
8
- "scripts": {
9
- "test": "vitest run",
10
- "build": "run-p type-check build-only",
11
- "build-only": "vite build",
12
- "type-check": "tsc --noEmit"
13
- },
14
- "files": [
15
- "dist"
16
- ],
17
- "sideEffects": false,
18
- "keywords": [
19
- "dependency-injection",
20
- "di",
21
- "network-library",
22
- "adapter-pattern",
23
- "extensible",
24
- "http-client",
25
- "lightweight"
26
- ],
27
- "author": "yuzinan <1589937631@qq.com>",
28
- "license": "MIT",
29
- "publishConfig": {
30
- "access": "public"
31
- },
32
- "dependencies": {
33
- "id-queue": "^1.1.1",
34
- "store-vert": "^0.2.0"
35
- }
36
- }
2
+ "name": "@net-vert/core",
3
+ "version": "1.3.1",
4
+ "description": "Dependency Inversion Network Library with Type-Safe Injection.",
5
+ "main": "dist/index",
6
+ "type": "module",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "sideEffects": false,
12
+ "keywords": [
13
+ "dependency-injection",
14
+ "di",
15
+ "network-library",
16
+ "adapter-pattern",
17
+ "extensible",
18
+ "http-client",
19
+ "lightweight"
20
+ ],
21
+ "author": "yuzinan <1589937631@qq.com>",
22
+ "license": "MIT",
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "dependencies": {
27
+ "id-queue": "^1.1.1",
28
+ "store-vert": "^0.2.0"
29
+ },
30
+ "scripts": {
31
+ "test": "vitest run",
32
+ "build": "run-p type-check build-only",
33
+ "build-only": "vite build",
34
+ "type-check": "tsc --noEmit"
35
+ }
36
+ }