@net-vert/core 0.0.9 → 0.1.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
@@ -104,58 +104,112 @@ retryApi.get('/unstable-api');
104
104
 
105
105
  ## 🗂 缓存扩展 `requestExtender.cacheRequestor(options)`
106
106
 
107
- `cacheRequestor` 是 `@net-vert/core` 内置的缓存增强器,为请求增加缓存命中机制,避免重复请求,提升性能。
107
+ `cacheRequestor` 是 `@net-vert/core` 内置的智能缓存增强器,提供多维度缓存控制能力,支持同步/异步校验策略,所有cacheRequestor共享一个存储空间。
108
108
 
109
109
  ### ✅ 核心特性
110
110
 
111
- - 支持本地缓存或内存缓存(未来由 `@net-vert/cache` 提供存储支持)
112
- - 同一请求中的并发合并(Promise 复用)
113
- - 支持缓存过期时间配置
114
- - 支持缓存 key 自定义生成逻辑
115
- - 自动处理 Promise 缓存清理
111
+ - **🚀 多级缓存策略**
112
+ 内存缓存 + 持久化存储(未来由 `@net-vert/cache` 提供)
113
+
114
+ - **🔗 智能并发合并**
115
+ 相同请求共享 Promise,避免重复网络消耗
116
+
117
+ - **⏳ 动态缓存控制**
118
+ 支持时间/逻辑双重失效校验机制
119
+
120
+ - **🧩 弹性校验策略**
121
+ 支持同步/异步缓存有效性检查
116
122
 
117
123
  ---
118
124
 
119
- ### ⚙️ 配置参数(可选)
125
+ ### ⚙️ 配置参数
120
126
 
121
- | 参数 | 类型 | 说明 | 默认值 |
122
- | ------------ | ----------------------------------------------- | ---------------------------------------------- | -------------- |
123
- | `key` | `(config: UnifiedConfig) => string` | 自定义缓存 key 生成规则 | `config.url` |
124
- | `persist` | `boolean` | 是否持久化缓存(默认走内存) | `false` |
125
- | `cacheTime` | `number` 或 `({config, response}) => number` | 缓存有效期(毫秒)或动态计算缓存时间 | `Infinity` |
127
+ | 参数 | 类型 | 说明 | 默认值 |
128
+ |--------------|--------------------------------------------------------------------|-------------------------------------------------------------|----------------|
129
+ | `key` | `(config: UnifiedConfig) => string` | 自定义缓存键生成规则 | `config.url` |
130
+ | `persist` | `boolean` | 启用持久化存储(默认内存存储) | `false` |
131
+ | `duration` | `number` 或 `({ key, config, response }) => number` | 缓存时间(ms)或动态计算函数 | `Infinity` |
132
+ | `isValid` | `({ key, config, cachedData }) => boolean \| Promise<boolean>` | 缓存有效性校验(支持异步校验) | - |
126
133
 
127
134
  ---
128
135
 
129
- ### 📥 使用示例
136
+ ### 📥 基础使用
130
137
 
131
138
  ```typescript
132
139
  import { requestExtender } from '@net-vert/core';
133
140
 
134
- const cachedApi = requestExtender.cacheRequestor({
135
- cacheTime: 5000, // 缓存 5
136
- key: (config) => `${config.method}-${config.url}` // 自定义缓存 key
141
+ const api = requestExtender.cacheRequestor({
142
+ duration: 3000, // 缓存3
143
+ key: config => `${config.method}:${config.url}` // 复合键
137
144
  });
138
145
 
139
- // 第一次请求发出
140
- cachedApi.get('/user/info', { params: { id: 1 } }).then(console.log);
146
+ // 首次请求将缓存
147
+ api.get('/user').then(console.log);
141
148
 
142
- // 5 秒内相同请求直接走缓存
143
- cachedApi.get('/user/info', { params: { id: 1 } }).then(console.log);
149
+ // 3秒内相同请求直接返回缓存
150
+ api.get('/user').then(console.log);
144
151
  ```
145
152
 
146
- ---
153
+ ### 🎯 动态缓存示例
147
154
 
148
- ### 🔥 示例动态缓存时间计算
155
+ #### 根据响应数据设置缓存时间
156
+ ```typescript
157
+ requestExtender.cacheRequestor({
158
+ duration: ({ response }) => response.data.isHot ? 10000 : 3000
159
+ });
160
+ ```
149
161
 
162
+ #### 权限变更时失效缓存
150
163
  ```typescript
151
- const dynamicCachedApi = requestExtender.cacheRequestor({
152
- cacheTime: ({ config, response }) => {
153
- // 根据接口返回决定缓存时间
154
- return response.isHot ? 10000 : 3000;
164
+ requestExtender.cacheRequestor({
165
+ isValid: ({ cachedData }) => {
166
+ return cachedData.value.permission === currentUser.permission
155
167
  }
156
168
  });
157
169
  ```
158
170
 
171
+ #### 异步校验缓存有效性
172
+ ```typescript
173
+ requestExtender.cacheRequestor({
174
+ async isValid({ key }) {
175
+ const { valid } = await fetch('/cache/validate', { body: key })
176
+ return valid
177
+ }
178
+ });
179
+ ```
180
+
181
+ ---
182
+
183
+ ### 🛠 工作机制
184
+
185
+ ```mermaid
186
+ graph TB
187
+ A[请求进入] --> B{存在Promise缓存?}
188
+ B -->|是| C[共享请求]
189
+ B -->|否| D{存在物理缓存?}
190
+ D -->|是| E[执行isValid校验]
191
+ E -->|有效| F[返回缓存]
192
+ E -->|无效| G[清理缓存]
193
+ D -->|否| H[发起新请求]
194
+ H --> I[缓存响应数据]
195
+ ```
196
+
197
+ ---
198
+
199
+ ### ⚠️ 注意事项
200
+
201
+ 1. **缓存穿透防护**
202
+ 当 `isValid` 返回 `false` 时会主动清理缓存,后续请求将触发新请求
203
+
204
+ 2. **异步校验建议**
205
+ 耗时较长的异步校验建议配合 `duration` 使用,避免校验期间重复请求
206
+
207
+ 3. **内存管理**
208
+ 高频数据建议启用 `persist` 持久化存储,防止内存溢出
209
+ ```
210
+
211
+ ```
212
+
159
213
  ## ♻️ 幂等扩展 `requestExtender.idempotencyRequestor(options)`
160
214
 
161
215
  `idempotencyRequestor` 是基于 `cacheRequestor` 封装的幂等增强器,确保同一参数的请求,在请求未完成前只发送一次,自动合并并发请求,避免重复提交和资源浪费。
@@ -298,6 +352,179 @@ idempotentApi.post('/user/create', { name: 'Alice' }).then(console.log);
298
352
 
299
353
  ---
300
354
 
355
+ ```markdown
356
+ # 🚀 并发请求控制器 `createConcurrentPoolRequestor`
357
+
358
+ 提供智能并发控制与自动重试能力的请求扩展器,适用于需要精准控制请求并发的场景。
359
+
360
+ ---
361
+
362
+ ## 📦 核心模块
363
+
364
+ ### 1. 并发池 `ConcurrentPool`
365
+ ```typescript
366
+ export class ConcurrentPool {
367
+ parallelCount: number // 最大并行任务数
368
+ tasks: TaskItemList // 待执行任务队列
369
+ runningCount: number // 当前运行中任务数
370
+
371
+ constructor(parallelCount = 4) // 初始化并发池
372
+
373
+ // 添加任务到队列
374
+ add(id: string, task: Task): Promise<any>
375
+
376
+ // 移除指定任务
377
+ remove(id: string): void
378
+
379
+ // 执行单个任务(内部方法)
380
+ private execute(currentTask: TaskItem): void
381
+
382
+ // 启动任务处理(内部调度器)
383
+ private _run(): void
384
+ }
385
+ ```
386
+
387
+ ---
388
+
389
+ ### 2. 请求器工厂函数
390
+ ```typescript
391
+ createConcurrentPoolRequestor(config): {
392
+ requestor: Requestor, // 增强后的请求器实例
393
+ concurrentPool: ConcurrentPool // 关联的并发池
394
+ }
395
+ ```
396
+
397
+ ---
398
+
399
+ ## ⚙️ 配置参数
400
+
401
+ | 参数 | 类型 | 说明 | 默认值 |
402
+ |------------------|---------------------------------------|------------------------------|---------------------|
403
+ | `parallelCount` | `number` | 最大并行请求数 | 4 |
404
+ | `createId` | `(config: UnifiedConfig) => string` | 生成唯一任务ID的函数 | 时间戳+随机数 |
405
+ | `retries` | `number` | 失败重试次数 | 0 (不重试) |
406
+
407
+ ---
408
+
409
+ ## 🎯 功能特性
410
+
411
+ ### 1. 智能并发控制
412
+ ```mermaid
413
+ graph TD
414
+ A[新请求到达] --> B{运行中任务 < 最大并发数?}
415
+ B -->|是| C[立即执行]
416
+ B -->|否| D[进入等待队列]
417
+ C --> E[任务完成]
418
+ E --> F{队列有等待任务?}
419
+ F -->|是| G[触发下一个任务]
420
+ ```
421
+
422
+ ### 2. 自动重试机制
423
+ ```typescript
424
+ // 集成重试模块的工作流
425
+ sequenceDiagram
426
+ participant P as 并发池
427
+ participant R as 重试模块
428
+ participant S as 服务器
429
+
430
+ P->>R: 执行请求
431
+ R->>S: 尝试请求
432
+ alt 成功
433
+ S-->>R: 返回数据
434
+ R-->>P: 传递结果
435
+ else 失败
436
+ R->>R: 重试逻辑(最多retries次)
437
+ R-->>P: 最终结果/错误
438
+ end
439
+ ```
440
+
441
+ ---
442
+
443
+ ## 📝 使用示例
444
+
445
+ ### 基础使用
446
+ ```typescript
447
+ import createConcurrentPoolRequestor from '@/requests/modules/concurrentPoolRequestor'
448
+
449
+ // 创建最大并发数为3的请求器
450
+ const { requestor } = createConcurrentPoolRequestor({
451
+ parallelCount: 3,
452
+ retries: 2, // 失败自动重试2次
453
+ delay: 500 // 重试间隔500ms
454
+ })
455
+
456
+ // 批量发起请求
457
+ const requests = Array(10).fill(0).map(() =>
458
+ requestor.get('/api/data')
459
+ )
460
+
461
+ Promise.all(requests).then(results => {
462
+ console.log('所有请求完成:', results)
463
+ })
464
+ ```
465
+
466
+ ### 高级控制
467
+ ```typescript
468
+ // 获取并发池实例进行精细控制
469
+ const { requestor, concurrentPool } = createConcurrentPoolRequestor()
470
+
471
+ // 动态调整并发数
472
+ concurrentPool.parallelCount = 5
473
+
474
+ // 取消特定请求
475
+ const reqId = 'custom-id-123'
476
+ requestor.post('/api/submit', { data }, {
477
+ __id: reqId // 通过配置注入自定义ID
478
+ }).catch(err => {
479
+ if (err.message === 'ABORTED') {
480
+ console.log('请求被主动取消')
481
+ }
482
+ })
483
+
484
+ // 主动取消任务
485
+ concurrentPool.remove(reqId)
486
+ ```
487
+
488
+ ---
489
+
490
+ ## ⚠️ 注意事项
491
+
492
+ 1. **ID生成策略**
493
+ 确保`createId`函数生成的ID具有唯一性:
494
+ ```typescript
495
+ createId: config => `${config.method}:${config.url}:${hash(config.params)}`
496
+ ```
497
+
498
+ 2. **资源释放**
499
+ 长时间运行的实例需手动释放资源:
500
+ ```typescript
501
+ // 清空任务队列
502
+ concurrentPool.tasks.clear()
503
+ ```
504
+
505
+ ---
506
+
507
+ ## 🛠 设计理念
508
+
509
+ ### 1. 队列优先级策略
510
+ ```typescript
511
+ // 可扩展为优先级队列
512
+ interface PriorityTaskItem extends TaskItem {
513
+ priority: number
514
+ }
515
+
516
+ // 自定义队列实现
517
+ class PriorityQueue implements TaskItemList {
518
+ enqueue(id: string, item: PriorityTaskItem) {
519
+ // 根据优先级插入队列
520
+ }
521
+ }
522
+ ### 1. 队列优先级策略
523
+ ```typescript
524
+ 一个实例对象控制着单独的并发池
525
+
526
+ ```
527
+
301
528
  ## 📤 开源信息
302
529
 
303
530
  - 仓库地址:[https://github.com/yvygyyth/net-vert](https://github.com/yvygyyth/net-vert)
package/dist/index.d.ts CHANGED
@@ -1,10 +1,5 @@
1
1
  import { TaskQueue } from 'id-queue';
2
2
 
3
- declare interface BasicCredentials {
4
- username: string;
5
- password: string;
6
- }
7
-
8
3
  declare class ConcurrentPool {
9
4
  parallelCount: number;
10
5
  tasks: TaskItemList;
@@ -26,8 +21,6 @@ declare interface RequestConfig<D = any> {
26
21
  params?: Record<string, any> | string;
27
22
  data?: D;
28
23
  timeout?: number;
29
- auth?: BasicCredentials;
30
- responseType?: ResponseType;
31
24
  onUploadProgress?: <P extends ProgressEvent>(progressEvent: P) => void;
32
25
  onDownloadProgress?: <P extends ProgressEvent>(progressEvent: P) => void;
33
26
  validateStatus?: ((status: number) => boolean) | null;
@@ -38,14 +31,23 @@ export declare const requestExtender: {
38
31
  cacheRequestor: (config?: {
39
32
  key?: (config: UnifiedConfig) => string;
40
33
  persist?: boolean;
41
- cacheTime?: number | (({ config, response }: {
34
+ duration?: number | (({ key, config, response }: {
35
+ key: string;
42
36
  config: UnifiedConfig;
43
37
  response: any;
44
38
  }) => number);
39
+ isValid?: (params: {
40
+ key: string;
41
+ config: UnifiedConfig;
42
+ cachedData: {
43
+ value: any;
44
+ expiresAt: number;
45
+ };
46
+ }) => boolean | Promise<boolean>;
45
47
  }) => Requestor;
46
48
  idempotencyRequestor: (genKey?: (config: UnifiedConfig) => string) => Requestor;
47
49
  retryRequestor: (config?: RetryOptions) => Requestor;
48
- concurrentPoolRequestor: (config: {
50
+ concurrentPoolRequestor: (config?: {
49
51
  parallelCount?: number;
50
52
  createId?: (config: UnifiedConfig) => string;
51
53
  } & RetryOptions) => {
@@ -55,11 +57,11 @@ export declare const requestExtender: {
55
57
  };
56
58
 
57
59
  export declare interface Requestor {
58
- get<R = any, D = any>(url: string, config?: RequestConfig<D>): Promise<R>;
60
+ get<R = any, D = any>(url: string, config?: WithDynamicProps<RequestConfig<D>>): Promise<R>;
59
61
  post<R = any, D = any>(url: string, data?: D, config?: RequestConfig<D>): Promise<R>;
60
- delete<R = any, D = any>(url: string, config?: RequestConfig<D>): Promise<R>;
61
- put<R = any, D = any>(url: string, data?: D, config?: RequestConfig<D>): Promise<R>;
62
- request<R = any, D = any>(config: UnifiedConfig<D>): Promise<R>;
62
+ delete<R = any, D = any>(url: string, config?: WithDynamicProps<RequestConfig<D>>): Promise<R>;
63
+ put<R = any, D = any>(url: string, data?: D, config?: WithDynamicProps<RequestConfig<D>>): Promise<R>;
64
+ request<R = any, D = any>(config: WithDynamicProps<UnifiedConfig<D>>): Promise<R>;
63
65
  }
64
66
 
65
67
  declare type RetryOptions = {
@@ -87,4 +89,6 @@ export declare type UnifiedRequestor = <R = any, D = any>(config: UnifiedConfig<
87
89
 
88
90
  export declare const useRequestor: (instanceKey?: string) => Requestor;
89
91
 
92
+ declare type WithDynamicProps<T, V = any> = T & Record<string, V>;
93
+
90
94
  export { }
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- const y = {
1
+ const f = {
2
2
  get: (r, e) => ({
3
3
  url: r,
4
4
  method: "get",
@@ -26,12 +26,12 @@ const y = {
26
26
  }),
27
27
  request: (r) => r
28
28
  };
29
- function k(r) {
29
+ function M(r) {
30
30
  const e = {};
31
- return Object.keys(y).forEach(
31
+ return Object.keys(f).forEach(
32
32
  (t) => {
33
33
  e[t] = (...s) => {
34
- const n = y[t](...s);
34
+ const n = f[t](...s);
35
35
  return r(n);
36
36
  };
37
37
  }
@@ -40,14 +40,14 @@ function k(r) {
40
40
  request: r
41
41
  };
42
42
  }
43
- const P = "default", w = /* @__PURE__ */ new Map(), L = (r, e = P) => {
44
- w.set(e, k(r));
45
- }, C = (r = P) => {
46
- const e = w.get(r);
43
+ const w = "default", x = /* @__PURE__ */ new Map(), L = (r, e = w) => {
44
+ x.set(e, M(r));
45
+ }, v = (r = w) => {
46
+ const e = x.get(r);
47
47
  if (!e) throw new Error(`Requestor实例 ${r} 未注册`);
48
48
  return e;
49
49
  };
50
- class M {
50
+ class j {
51
51
  // 是否存在
52
52
  has(e) {
53
53
  return !!localStorage.getItem(e);
@@ -82,12 +82,12 @@ class M {
82
82
  localStorage.clear();
83
83
  }
84
84
  }
85
- const T = new M(), E = /* @__PURE__ */ new Map(), j = (r) => r ? T : E, I = () => {
85
+ const E = new j(), I = /* @__PURE__ */ new Map(), b = (r) => r ? E : I, z = () => {
86
86
  const r = /* @__PURE__ */ new Map();
87
87
  return {
88
88
  getPromise: (o) => r.get(o),
89
- setPromise: (o, l) => {
90
- r.set(o, l);
89
+ setPromise: (o, u) => {
90
+ r.set(o, u);
91
91
  },
92
92
  delPromise: (o) => {
93
93
  r.delete(o);
@@ -96,75 +96,87 @@ const T = new M(), E = /* @__PURE__ */ new Map(), j = (r) => r ? T : E, I = () =
96
96
  r.clear();
97
97
  }
98
98
  };
99
- }, b = {
100
- key: (r) => r.url,
101
- persist: !1,
102
- cacheTime: 1 / 0
103
- }, x = (r, e) => ({
99
+ }, O = (r, e) => ({
104
100
  value: r,
105
101
  expiresAt: Date.now() + e
106
- }), z = (r) => Date.now() > r.expiresAt, R = (r = {}) => {
107
- const e = { ...b, ...r }, t = j(e.persist), { getPromise: s, setPromise: n, delPromise: o } = I(), l = {
108
- get(c, i) {
109
- return (...u) => {
110
- const h = y[i](...u), a = e.key(h), m = s(a);
102
+ }), T = (r) => r.expiresAt > Date.now(), $ = {
103
+ key: (r) => r.url,
104
+ persist: !1,
105
+ duration: 1 / 0
106
+ }, R = (r) => {
107
+ const e = { ...$, ...r }, t = b(e.persist), { getPromise: s, setPromise: n, delPromise: o } = z(), u = {
108
+ get(h, i) {
109
+ return async (...l) => {
110
+ const c = f[i](...l), a = e.key(c), m = s(a);
111
111
  if (m)
112
- return console.log(`===> 已存在该请求: ${a}`), m;
113
- const f = t.get(a);
114
- if (f && !z(f))
115
- return f.value;
116
- {
117
- const v = Reflect.apply(c[i], c, u).then((d) => (typeof e.cacheTime == "number" ? t.set(a, x(d, e.cacheTime)) : t.set(
118
- a,
119
- x(
120
- d,
121
- e.cacheTime({ config: h, response: d })
122
- )
123
- ), console.log("===>cache", "成功", a, d), d)).finally(() => {
124
- o(a);
125
- });
126
- return n(a, v), v;
112
+ return m;
113
+ const y = t.get(a);
114
+ let q = !1;
115
+ if (y && T(y)) {
116
+ try {
117
+ q = e.isValid ? await e.isValid({
118
+ key: a,
119
+ config: c,
120
+ cachedData: y
121
+ }) : !0;
122
+ } catch (d) {
123
+ console.error(`校验异常 ${a}`, d);
124
+ }
125
+ q || t.delete(a);
127
126
  }
127
+ if (q)
128
+ return y.value;
129
+ const P = Reflect.apply(h[i], h, l).then(async (d) => {
130
+ const S = typeof e.duration == "number" ? e.duration : e.duration({
131
+ key: a,
132
+ config: c,
133
+ response: d
134
+ });
135
+ return t.set(a, O(d, S)), d;
136
+ }).finally(() => {
137
+ o(a);
138
+ });
139
+ return n(a, P), P;
128
140
  };
129
141
  }
130
142
  };
131
- return new Proxy(C(), l);
132
- }, O = (r) => {
143
+ return new Proxy(v(), u);
144
+ }, D = (r) => {
133
145
  const { method: e, url: t, params: s, data: n } = r;
134
146
  return [e, t, JSON.stringify(s), JSON.stringify(n)].join("|");
135
- }, D = (r) => R({
136
- key: (e) => r ? r(e) : O(e),
147
+ }, _ = (r) => R({
148
+ key: (e) => r ? r(e) : D(e),
137
149
  persist: !1
138
- }), _ = {
150
+ }), A = {
139
151
  retries: 3,
140
152
  delay: 0,
141
153
  retryCondition: () => !0
142
- }, S = (r = {}) => {
143
- const { retries: e, delay: t, retryCondition: s } = { ..._, ...r }, n = {
144
- get(o, l) {
145
- return (...c) => {
154
+ }, k = (r) => {
155
+ const { retries: e, delay: t, retryCondition: s } = { ...A, ...r }, n = {
156
+ get(o, u) {
157
+ return (...h) => {
146
158
  let i = 0;
147
- const p = () => Reflect.apply(o[l], o, c).catch((u) => {
148
- if (i < e && s(u)) {
159
+ const p = () => Reflect.apply(o[u], o, h).catch((l) => {
160
+ if (i < e && s(l)) {
149
161
  i++;
150
- const h = typeof t == "function" ? t(i) : t;
162
+ const c = typeof t == "function" ? t(i) : t;
151
163
  return new Promise((a) => {
152
- setTimeout(() => a(p()), h);
164
+ setTimeout(() => a(p()), c);
153
165
  });
154
166
  }
155
- return Promise.reject(u);
167
+ return Promise.reject(l);
156
168
  });
157
169
  return p();
158
170
  };
159
171
  }
160
172
  };
161
- return new Proxy(C(), n);
173
+ return new Proxy(v(), n);
162
174
  };
163
- var A = Object.defineProperty, J = (r, e, t) => e in r ? A(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t, q = (r, e, t) => J(r, typeof e != "symbol" ? e + "" : e, t);
164
- class N {
175
+ var J = Object.defineProperty, N = (r, e, t) => e in r ? J(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t, C = (r, e, t) => N(r, typeof e != "symbol" ? e + "" : e, t);
176
+ class V {
165
177
  // 尾部指针(最新加入的任务)
166
178
  constructor(e) {
167
- if (q(this, "map"), q(this, "head"), q(this, "tail"), this.map = /* @__PURE__ */ new Map(), this.head = null, this.tail = null, e)
179
+ if (C(this, "map"), C(this, "head"), C(this, "tail"), this.map = /* @__PURE__ */ new Map(), this.head = null, this.tail = null, e)
168
180
  for (const [t, s] of e)
169
181
  this.enqueue(t, s);
170
182
  }
@@ -217,9 +229,9 @@ class N {
217
229
  return e;
218
230
  }
219
231
  }
220
- class $ {
232
+ class H {
221
233
  constructor(e = 4) {
222
- this.parallelCount = e, this.tasks = new N(), this.runningCount = 0;
234
+ this.parallelCount = e, this.tasks = new V(), this.runningCount = 0;
223
235
  }
224
236
  // 加入
225
237
  add(e, t) {
@@ -248,31 +260,31 @@ class $ {
248
260
  }
249
261
  }
250
262
  }
251
- const H = {
263
+ const U = {
252
264
  parallelCount: 4,
253
265
  retries: 0,
254
266
  createId: () => `${Date.now()}_${Math.random().toString().slice(2, 8)}`
255
267
  }, F = (r) => {
256
- const e = { ...H, ...r }, { parallelCount: t, createId: s, ...n } = e, o = new $(t), l = n.retries > 0 ? S(n) : null, g = {
257
- get(c, i) {
258
- return (...u) => {
259
- const h = y[i](...u), a = s(h), m = () => l ? l.request(h) : Reflect.apply(c[i], c, u);
268
+ const e = { ...U, ...r }, { parallelCount: t, createId: s, ...n } = e, o = new H(t), u = n.retries > 0 ? k(n) : null, g = {
269
+ get(h, i) {
270
+ return (...l) => {
271
+ const c = f[i](...l), a = s(c), m = () => u ? u.request(c) : Reflect.apply(h[i], h, l);
260
272
  return o.add(a, m);
261
273
  };
262
274
  }
263
275
  };
264
276
  return {
265
- requestor: new Proxy(C(), g),
277
+ requestor: new Proxy(v(), g),
266
278
  concurrentPool: o
267
279
  };
268
- }, U = {
280
+ }, W = {
269
281
  cacheRequestor: R,
270
- idempotencyRequestor: D,
271
- retryRequestor: S,
282
+ idempotencyRequestor: _,
283
+ retryRequestor: k,
272
284
  concurrentPoolRequestor: F
273
285
  };
274
286
  export {
275
287
  L as inject,
276
- U as requestExtender,
277
- C as useRequestor
288
+ W as requestExtender,
289
+ v as useRequestor
278
290
  };
@@ -1 +1 @@
1
- (function(u,c){typeof exports=="object"&&typeof module<"u"?c(exports):typeof define=="function"&&define.amd?define(["exports"],c):(u=typeof globalThis<"u"?globalThis:u||self,c(u["net-vert/core"]={}))})(this,function(u){"use strict";const c={get:(r,e)=>({url:r,method:"get",...e,params:e==null?void 0:e.params}),post:(r,e,t)=>({url:r,method:"post",data:e,headers:{"Content-Type":"application/json",...t==null?void 0:t.headers},...t}),delete:(r,e)=>({url:r,method:"delete",...e}),put:(r,e,t)=>({url:r,method:"put",data:e,headers:{"Content-Type":"application/json",...t==null?void 0:t.headers},...t}),request:r=>r};function T(r){const e={};return Object.keys(c).forEach(t=>{e[t]=(...s)=>{const n=c[t](...s);return r(n)}}),{...e,request:r}}const P="default",x=new Map,k=(r,e=P)=>{x.set(e,T(r))},f=(r=P)=>{const e=x.get(r);if(!e)throw new Error(`Requestor实例 ${r} 未注册`);return e};class j{has(e){return!!localStorage.getItem(e)}get(e){const t=localStorage.getItem(e);if(t)try{return JSON.parse(t)}catch(s){console.error("Error parsing cached data",s);return}}set(e,t){try{const s=JSON.stringify(t);localStorage.setItem(e,s)}catch(s){console.error("Error saving data to localStorage",s)}return t}delete(e){localStorage.removeItem(e)}clear(){localStorage.clear()}}const b=new j,E=new Map,I=r=>r?b:E,O=()=>{const r=new Map;return{getPromise:o=>r.get(o),setPromise:(o,l)=>{r.set(o,l)},delPromise:o=>{r.delete(o)},clearCache:()=>{r.clear()}}},z={key:r=>r.url,persist:!1,cacheTime:1/0},w=(r,e)=>({value:r,expiresAt:Date.now()+e}),D=r=>Date.now()>r.expiresAt,R=(r={})=>{const e={...z,...r},t=I(e.persist),{getPromise:s,setPromise:n,delPromise:o}=O(),l={get(d,i){return(...h)=>{const p=c[i](...h),a=e.key(p),g=s(a);if(g)return console.log(`===> 已存在该请求: ${a}`),g;const v=t.get(a);if(v&&!D(v))return v.value;{const M=Reflect.apply(d[i],d,h).then(m=>(typeof e.cacheTime=="number"?t.set(a,w(m,e.cacheTime)):t.set(a,w(m,e.cacheTime({config:p,response:m}))),console.log("===>cache","成功",a,m),m)).finally(()=>{o(a)});return n(a,M),M}}}};return new Proxy(f(),l)},_=r=>{const{method:e,url:t,params:s,data:n}=r;return[e,t,JSON.stringify(s),JSON.stringify(n)].join("|")},A=r=>R({key:e=>r?r(e):_(e),persist:!1}),J={retries:3,delay:0,retryCondition:()=>!0},S=(r={})=>{const{retries:e,delay:t,retryCondition:s}={...J,...r},n={get(o,l){return(...d)=>{let i=0;const y=()=>Reflect.apply(o[l],o,d).catch(h=>{if(i<e&&s(h)){i++;const p=typeof t=="function"?t(i):t;return new Promise(a=>{setTimeout(()=>a(y()),p)})}return Promise.reject(h)});return y()}}};return new Proxy(f(),n)};var N=Object.defineProperty,$=(r,e,t)=>e in r?N(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,q=(r,e,t)=>$(r,typeof e!="symbol"?e+"":e,t);class H{constructor(e){if(q(this,"map"),q(this,"head"),q(this,"tail"),this.map=new Map,this.head=null,this.tail=null,e)for(const[t,s]of e)this.enqueue(t,s)}enqueue(e,t){this.has(e)&&this.remove(e);const s={id:e,data:t,next:null,prev:this.tail};this.tail?this.tail.next=s:this.head=s,this.tail=s,this.map.set(e,s)}dequeue(){if(!this.head)return null;const e=this.head;return this.head=e.next,this.head?this.head.prev=null:this.tail=null,this.map.delete(e.id),e.data}remove(e){const t=this.map.get(e);return t?(t.prev?t.prev.next=t.next:this.head=t.next,t.next?t.next.prev=t.prev:this.tail=t.prev,this.map.delete(e),!0):!1}getTask(e){var t;return(t=this.map.get(e))==null?void 0:t.data}update(e,t){const s=this.map.get(e);return s?(s.data=t,!0):!1}has(e){return this.map.has(e)}peek(){var e;return((e=this.head)==null?void 0:e.data)??null}clear(){this.map.clear(),this.head=null,this.tail=null}get size(){return this.map.size}get queue(){const e=[];let t=this.head;for(;t;)e.push(t.data),t=t.next;return e}}class F{constructor(e=4){this.parallelCount=e,this.tasks=new H,this.runningCount=0}add(e,t){return console.log("poolinset",e,t),new Promise((s,n)=>{this.tasks.enqueue(e,{task:t,resolve:s,reject:n}),this._run()})}remove(e){this.tasks.remove(e)}execute(e){const{task:t,resolve:s,reject:n}=e;return t().then(s).catch(n).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)}}}const L={parallelCount:4,retries:0,createId:()=>`${Date.now()}_${Math.random().toString().slice(2,8)}`},U={cacheRequestor:R,idempotencyRequestor:A,retryRequestor:S,concurrentPoolRequestor:r=>{const e={...L,...r},{parallelCount:t,createId:s,...n}=e,o=new F(t),l=n.retries>0?S(n):null,C={get(d,i){return(...h)=>{const p=c[i](...h),a=s(p),g=()=>l?l.request(p):Reflect.apply(d[i],d,h);return o.add(a,g)}}};return{requestor:new Proxy(f(),C),concurrentPool:o}}};u.inject=k,u.requestExtender=U,u.useRequestor=f,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})});
1
+ (function(u,l){typeof exports=="object"&&typeof module<"u"?l(exports):typeof define=="function"&&define.amd?define(["exports"],l):(u=typeof globalThis<"u"?globalThis:u||self,l(u["net-vert/core"]={}))})(this,function(u){"use strict";const l={get:(r,e)=>({url:r,method:"get",...e,params:e==null?void 0:e.params}),post:(r,e,t)=>({url:r,method:"post",data:e,headers:{"Content-Type":"application/json",...t==null?void 0:t.headers},...t}),delete:(r,e)=>({url:r,method:"delete",...e}),put:(r,e,t)=>({url:r,method:"put",data:e,headers:{"Content-Type":"application/json",...t==null?void 0:t.headers},...t}),request:r=>r};function M(r){const e={};return Object.keys(l).forEach(t=>{e[t]=(...s)=>{const n=l[t](...s);return r(n)}}),{...e,request:r}}const w="default",x=new Map,j=(r,e=w)=>{x.set(e,M(r))},f=(r=w)=>{const e=x.get(r);if(!e)throw new Error(`Requestor实例 ${r} 未注册`);return e};class b{has(e){return!!localStorage.getItem(e)}get(e){const t=localStorage.getItem(e);if(t)try{return JSON.parse(t)}catch(s){console.error("Error parsing cached data",s);return}}set(e,t){try{const s=JSON.stringify(t);localStorage.setItem(e,s)}catch(s){console.error("Error saving data to localStorage",s)}return t}delete(e){localStorage.removeItem(e)}clear(){localStorage.clear()}}const T=new b,E=new Map,I=r=>r?T:E,O=()=>{const r=new Map;return{getPromise:o=>r.get(o),setPromise:(o,c)=>{r.set(o,c)},delPromise:o=>{r.delete(o)},clearCache:()=>{r.clear()}}},z=(r,e)=>({value:r,expiresAt:Date.now()+e}),$=r=>r.expiresAt>Date.now(),D={key:r=>r.url,persist:!1,duration:1/0},R=r=>{const e={...D,...r},t=I(e.persist),{getPromise:s,setPromise:n,delPromise:o}=O(),c={get(p,i){return async(...h)=>{const d=l[i](...h),a=e.key(d),g=s(a);if(g)return g;const q=t.get(a);let P=!1;if(q&&$(q)){try{P=e.isValid?await e.isValid({key:a,config:d,cachedData:q}):!0}catch(m){console.error(`校验异常 ${a}`,m)}P||t.delete(a)}if(P)return q.value;const k=Reflect.apply(p[i],p,h).then(async m=>{const W=typeof e.duration=="number"?e.duration:e.duration({key:a,config:d,response:m});return t.set(a,z(m,W)),m}).finally(()=>{o(a)});return n(a,k),k}}};return new Proxy(f(),c)},_=r=>{const{method:e,url:t,params:s,data:n}=r;return[e,t,JSON.stringify(s),JSON.stringify(n)].join("|")},A=r=>R({key:e=>r?r(e):_(e),persist:!1}),J={retries:3,delay:0,retryCondition:()=>!0},S=r=>{const{retries:e,delay:t,retryCondition:s}={...J,...r},n={get(o,c){return(...p)=>{let i=0;const y=()=>Reflect.apply(o[c],o,p).catch(h=>{if(i<e&&s(h)){i++;const d=typeof t=="function"?t(i):t;return new Promise(a=>{setTimeout(()=>a(y()),d)})}return Promise.reject(h)});return y()}}};return new Proxy(f(),n)};var N=Object.defineProperty,V=(r,e,t)=>e in r?N(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,C=(r,e,t)=>V(r,typeof e!="symbol"?e+"":e,t);class H{constructor(e){if(C(this,"map"),C(this,"head"),C(this,"tail"),this.map=new Map,this.head=null,this.tail=null,e)for(const[t,s]of e)this.enqueue(t,s)}enqueue(e,t){this.has(e)&&this.remove(e);const s={id:e,data:t,next:null,prev:this.tail};this.tail?this.tail.next=s:this.head=s,this.tail=s,this.map.set(e,s)}dequeue(){if(!this.head)return null;const e=this.head;return this.head=e.next,this.head?this.head.prev=null:this.tail=null,this.map.delete(e.id),e.data}remove(e){const t=this.map.get(e);return t?(t.prev?t.prev.next=t.next:this.head=t.next,t.next?t.next.prev=t.prev:this.tail=t.prev,this.map.delete(e),!0):!1}getTask(e){var t;return(t=this.map.get(e))==null?void 0:t.data}update(e,t){const s=this.map.get(e);return s?(s.data=t,!0):!1}has(e){return this.map.has(e)}peek(){var e;return((e=this.head)==null?void 0:e.data)??null}clear(){this.map.clear(),this.head=null,this.tail=null}get size(){return this.map.size}get queue(){const e=[];let t=this.head;for(;t;)e.push(t.data),t=t.next;return e}}class U{constructor(e=4){this.parallelCount=e,this.tasks=new H,this.runningCount=0}add(e,t){return console.log("poolinset",e,t),new Promise((s,n)=>{this.tasks.enqueue(e,{task:t,resolve:s,reject:n}),this._run()})}remove(e){this.tasks.remove(e)}execute(e){const{task:t,resolve:s,reject:n}=e;return t().then(s).catch(n).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)}}}const F={parallelCount:4,retries:0,createId:()=>`${Date.now()}_${Math.random().toString().slice(2,8)}`},L={cacheRequestor:R,idempotencyRequestor:A,retryRequestor:S,concurrentPoolRequestor:r=>{const e={...F,...r},{parallelCount:t,createId:s,...n}=e,o=new U(t),c=n.retries>0?S(n):null,v={get(p,i){return(...h)=>{const d=l[i](...h),a=s(d),g=()=>c?c.request(d):Reflect.apply(p[i],p,h);return o.add(a,g)}}};return{requestor:new Proxy(f(),v),concurrentPool:o}}};u.inject=j,u.requestExtender=L,u.useRequestor=f,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@net-vert/core",
3
- "version": "0.0.9",
3
+ "version": "0.1.0",
4
4
  "description": "Dependency Inversion Network Library with Type-Safe Injection.",
5
5
  "main": "dist/index",
6
6
  "type": "module",