xxf_react 0.6.7 → 0.6.8

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.
Files changed (71) hide show
  1. package/README.md +14 -13
  2. package/dist/foundation/Copy.d.ts +8 -0
  3. package/dist/foundation/Copy.d.ts.map +1 -0
  4. package/dist/foundation/Copy.js +21 -0
  5. package/dist/foundation/index.d.ts +2 -0
  6. package/dist/foundation/index.d.ts.map +1 -1
  7. package/dist/foundation/index.js +2 -0
  8. package/dist/http/api/ApiBuilder.d.ts +115 -0
  9. package/dist/http/api/ApiBuilder.d.ts.map +1 -0
  10. package/dist/http/api/ApiBuilder.js +128 -0
  11. package/dist/http/api/index.d.ts +2 -0
  12. package/dist/http/api/index.d.ts.map +1 -0
  13. package/dist/http/api/index.js +1 -0
  14. package/dist/http/cache/DiskLruCache.d.ts +66 -0
  15. package/dist/http/cache/DiskLruCache.d.ts.map +1 -0
  16. package/dist/http/cache/DiskLruCache.js +254 -0
  17. package/dist/http/cache/HttpCache.d.ts +59 -0
  18. package/dist/http/cache/HttpCache.d.ts.map +1 -0
  19. package/dist/http/cache/HttpCache.js +215 -0
  20. package/dist/http/cache/index.d.ts +3 -0
  21. package/dist/http/cache/index.d.ts.map +1 -0
  22. package/dist/http/cache/index.js +2 -0
  23. package/dist/http/client/ApiStream.d.ts +80 -0
  24. package/dist/http/client/ApiStream.d.ts.map +1 -0
  25. package/dist/http/client/ApiStream.js +190 -0
  26. package/dist/http/client/HttpClient.d.ts +88 -0
  27. package/dist/http/client/HttpClient.d.ts.map +1 -0
  28. package/dist/http/client/HttpClient.js +381 -0
  29. package/dist/http/client/index.d.ts +3 -0
  30. package/dist/http/client/index.d.ts.map +1 -0
  31. package/dist/http/client/index.js +2 -0
  32. package/dist/http/index.d.ts +42 -0
  33. package/dist/http/index.d.ts.map +1 -0
  34. package/dist/http/index.js +45 -0
  35. package/dist/http/models/ApiTypes.d.ts +54 -0
  36. package/dist/http/models/ApiTypes.d.ts.map +1 -0
  37. package/dist/http/models/ApiTypes.js +4 -0
  38. package/dist/http/models/CacheConfig.d.ts +58 -0
  39. package/dist/http/models/CacheConfig.d.ts.map +1 -0
  40. package/dist/http/models/CacheConfig.js +4 -0
  41. package/dist/http/models/CacheEntry.d.ts +28 -0
  42. package/dist/http/models/CacheEntry.d.ts.map +1 -0
  43. package/dist/http/models/CacheEntry.js +1 -0
  44. package/dist/http/models/CacheInterceptor.d.ts +112 -0
  45. package/dist/http/models/CacheInterceptor.d.ts.map +1 -0
  46. package/dist/http/models/CacheInterceptor.js +6 -0
  47. package/dist/http/models/CacheMode.d.ts +45 -0
  48. package/dist/http/models/CacheMode.d.ts.map +1 -0
  49. package/dist/http/models/CacheMode.js +45 -0
  50. package/dist/http/models/DiskCacheConfig.d.ts +56 -0
  51. package/dist/http/models/DiskCacheConfig.d.ts.map +1 -0
  52. package/dist/http/models/DiskCacheConfig.js +4 -0
  53. package/dist/http/models/HttpClientConfig.d.ts +77 -0
  54. package/dist/http/models/HttpClientConfig.d.ts.map +1 -0
  55. package/dist/http/models/HttpClientConfig.js +4 -0
  56. package/dist/http/models/LruMetadata.d.ts +28 -0
  57. package/dist/http/models/LruMetadata.d.ts.map +1 -0
  58. package/dist/http/models/LruMetadata.js +6 -0
  59. package/dist/http/models/RequestConfig.d.ts +67 -0
  60. package/dist/http/models/RequestConfig.d.ts.map +1 -0
  61. package/dist/http/models/RequestConfig.js +4 -0
  62. package/dist/http/models/index.d.ts +24 -0
  63. package/dist/http/models/index.d.ts.map +1 -0
  64. package/dist/http/models/index.js +16 -0
  65. package/dist/http/types.d.ts +13 -0
  66. package/dist/http/types.d.ts.map +1 -0
  67. package/dist/http/types.js +14 -0
  68. package/dist/index.d.ts +1 -0
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +1 -0
  71. package/package.json +14 -4
@@ -0,0 +1,59 @@
1
+ /**
2
+ * HTTP 缓存(内存 + 磁盘双层)
3
+ *
4
+ * 策略:
5
+ * - 读取:先内存 -> 再磁盘 -> 若磁盘命中则回填内存
6
+ * - 写入:同时写入内存和磁盘
7
+ * - 容错:缓存操作失败不影响正常业务
8
+ * - 防污染:返回数据的深拷贝,防止上层修改影响缓存
9
+ */
10
+ import { DiskLruCache } from './DiskLruCache';
11
+ import type { CacheEntry, HttpCacheConfig } from '../types';
12
+ export declare class HttpCache {
13
+ private memoryCache;
14
+ private diskCache;
15
+ constructor(config: HttpCacheConfig);
16
+ /**
17
+ * 获取缓存
18
+ * @param key 缓存 key
19
+ * @returns 缓存条目的深拷贝,未命中或失败返回 null
20
+ */
21
+ get<T>(key: string): Promise<CacheEntry<T> | null>;
22
+ /**
23
+ * 设置缓存(失败静默忽略,不影响业务)
24
+ * @param key 缓存 key
25
+ * @param data 数据
26
+ * @param ttl 过期时间 (ms)
27
+ */
28
+ set<T>(key: string, data: T, ttl?: number): Promise<void>;
29
+ /**
30
+ * 删除缓存(失败静默忽略)
31
+ */
32
+ delete(key: string): Promise<void>;
33
+ /**
34
+ * 清空所有缓存(失败静默忽略)
35
+ */
36
+ clear(): Promise<void>;
37
+ /**
38
+ * 仅获取内存缓存(同步,失败返回 null)
39
+ * @returns 缓存条目的深拷贝
40
+ */
41
+ getFromMemory<T>(key: string): CacheEntry<T> | null;
42
+ /**
43
+ * 仅设置内存缓存(同步,失败静默忽略)
44
+ */
45
+ setToMemory<T>(key: string, data: T, ttl?: number): void;
46
+ /**
47
+ * 检查缓存是否存在(会检查过期,失败返回 false)
48
+ */
49
+ has(key: string): Promise<boolean>;
50
+ /**
51
+ * 获取磁盘缓存实例(用于高级操作)
52
+ */
53
+ getDiskCache(): DiskLruCache;
54
+ /**
55
+ * 刷新磁盘缓存元数据(失败静默忽略)
56
+ */
57
+ flush(): Promise<void>;
58
+ }
59
+ //# sourceMappingURL=HttpCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HttpCache.d.ts","sourceRoot":"","sources":["../../../src/http/cache/HttpCache.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG3D,qBAAa,SAAS;IAClB,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,SAAS,CAAc;gBAEnB,MAAM,EAAE,eAAe;IAcnC;;;;OAIG;IACG,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAwCxD;;;;;OAKG;IACG,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,GAAE,MAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBlE;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcxC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAc5B;;;OAGG;IACH,aAAa,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI;IAgBnD;;OAEG;IACH,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,GAAE,MAAU,GAAG,IAAI;IAc3D;;OAEG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAyBxC;;OAEG;IACH,YAAY,IAAI,YAAY;IAI5B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO/B"}
@@ -0,0 +1,215 @@
1
+ /**
2
+ * HTTP 缓存(内存 + 磁盘双层)
3
+ *
4
+ * 策略:
5
+ * - 读取:先内存 -> 再磁盘 -> 若磁盘命中则回填内存
6
+ * - 写入:同时写入内存和磁盘
7
+ * - 容错:缓存操作失败不影响正常业务
8
+ * - 防污染:返回数据的深拷贝,防止上层修改影响缓存
9
+ */
10
+ import { lru } from 'tiny-lru';
11
+ import { DiskLruCache } from './DiskLruCache';
12
+ import { copy } from '../../foundation';
13
+ export class HttpCache {
14
+ constructor(config) {
15
+ // 初始化内存缓存
16
+ // 注意:不使用 tiny-lru 的 ttl 参数,因为每个 entry 有自己的 ttl
17
+ // tiny-lru 的 ttl 是全局的,会导致冲突
18
+ this.memoryCache = lru(config.memoryMaxSize);
19
+ // 初始化磁盘缓存
20
+ this.diskCache = new DiskLruCache({
21
+ dbName: config.dbName,
22
+ storeName: 'http-cache',
23
+ maxSize: config.diskMaxSize,
24
+ });
25
+ }
26
+ /**
27
+ * 获取缓存
28
+ * @param key 缓存 key
29
+ * @returns 缓存条目的深拷贝,未命中或失败返回 null
30
+ */
31
+ async get(key) {
32
+ // 1. 先查内存(内存操作用 try-catch 保护)
33
+ try {
34
+ const memEntry = this.memoryCache.get(key);
35
+ if (memEntry) {
36
+ // 检查是否过期
37
+ if (memEntry.ttl > 0 &&
38
+ Date.now() - memEntry.timestamp > memEntry.ttl) {
39
+ this.memoryCache.delete(key);
40
+ }
41
+ else {
42
+ // 返回深拷贝,防止上层修改污染缓存
43
+ return copy(memEntry);
44
+ }
45
+ }
46
+ }
47
+ catch {
48
+ // 内存缓存读取失败,继续尝试磁盘
49
+ }
50
+ // 2. 再查磁盘(磁盘操作失败返回 null,不影响业务)
51
+ try {
52
+ const diskEntry = await this.diskCache.get(key);
53
+ if (diskEntry) {
54
+ // 回填内存缓存(失败也忽略)
55
+ try {
56
+ this.memoryCache.set(key, diskEntry);
57
+ }
58
+ catch {
59
+ // 回填失败忽略
60
+ }
61
+ // 返回深拷贝,防止上层修改污染缓存
62
+ return copy(diskEntry);
63
+ }
64
+ }
65
+ catch {
66
+ // 磁盘缓存读取失败,返回 null
67
+ }
68
+ return null;
69
+ }
70
+ /**
71
+ * 设置缓存(失败静默忽略,不影响业务)
72
+ * @param key 缓存 key
73
+ * @param data 数据
74
+ * @param ttl 过期时间 (ms)
75
+ */
76
+ async set(key, data, ttl = 0) {
77
+ const entry = {
78
+ data,
79
+ timestamp: Date.now(),
80
+ ttl,
81
+ key,
82
+ };
83
+ // 写入内存(失败忽略)
84
+ try {
85
+ this.memoryCache.set(key, entry);
86
+ }
87
+ catch {
88
+ // 内存写入失败忽略
89
+ }
90
+ // 写入磁盘(失败忽略)
91
+ try {
92
+ await this.diskCache.set(key, data, ttl);
93
+ }
94
+ catch {
95
+ // 磁盘写入失败忽略,不影响业务
96
+ }
97
+ }
98
+ /**
99
+ * 删除缓存(失败静默忽略)
100
+ */
101
+ async delete(key) {
102
+ try {
103
+ this.memoryCache.delete(key);
104
+ }
105
+ catch {
106
+ // 忽略
107
+ }
108
+ try {
109
+ await this.diskCache.delete(key);
110
+ }
111
+ catch {
112
+ // 忽略
113
+ }
114
+ }
115
+ /**
116
+ * 清空所有缓存(失败静默忽略)
117
+ */
118
+ async clear() {
119
+ try {
120
+ this.memoryCache.clear();
121
+ }
122
+ catch {
123
+ // 忽略
124
+ }
125
+ try {
126
+ await this.diskCache.clear();
127
+ }
128
+ catch {
129
+ // 忽略
130
+ }
131
+ }
132
+ /**
133
+ * 仅获取内存缓存(同步,失败返回 null)
134
+ * @returns 缓存条目的深拷贝
135
+ */
136
+ getFromMemory(key) {
137
+ try {
138
+ const entry = this.memoryCache.get(key);
139
+ if (!entry)
140
+ return null;
141
+ if (entry.ttl > 0 && Date.now() - entry.timestamp > entry.ttl) {
142
+ this.memoryCache.delete(key);
143
+ return null;
144
+ }
145
+ // 返回深拷贝,防止上层修改污染缓存
146
+ return copy(entry);
147
+ }
148
+ catch {
149
+ return null;
150
+ }
151
+ }
152
+ /**
153
+ * 仅设置内存缓存(同步,失败静默忽略)
154
+ */
155
+ setToMemory(key, data, ttl = 0) {
156
+ try {
157
+ const entry = {
158
+ data,
159
+ timestamp: Date.now(),
160
+ ttl,
161
+ key,
162
+ };
163
+ this.memoryCache.set(key, entry);
164
+ }
165
+ catch {
166
+ // 忽略
167
+ }
168
+ }
169
+ /**
170
+ * 检查缓存是否存在(会检查过期,失败返回 false)
171
+ */
172
+ async has(key) {
173
+ // 先查内存
174
+ try {
175
+ const memEntry = this.memoryCache.get(key);
176
+ if (memEntry) {
177
+ // 检查是否过期
178
+ if (memEntry.ttl > 0 && Date.now() - memEntry.timestamp > memEntry.ttl) {
179
+ this.memoryCache.delete(key);
180
+ }
181
+ else {
182
+ return true;
183
+ }
184
+ }
185
+ }
186
+ catch {
187
+ // 内存检查失败,继续检查磁盘
188
+ }
189
+ // 再查磁盘
190
+ try {
191
+ const diskEntry = await this.diskCache.get(key);
192
+ return diskEntry !== null;
193
+ }
194
+ catch {
195
+ return false;
196
+ }
197
+ }
198
+ /**
199
+ * 获取磁盘缓存实例(用于高级操作)
200
+ */
201
+ getDiskCache() {
202
+ return this.diskCache;
203
+ }
204
+ /**
205
+ * 刷新磁盘缓存元数据(失败静默忽略)
206
+ */
207
+ async flush() {
208
+ try {
209
+ await this.diskCache.flush();
210
+ }
211
+ catch {
212
+ // 忽略
213
+ }
214
+ }
215
+ }
@@ -0,0 +1,3 @@
1
+ export { DiskLruCache } from './DiskLruCache';
2
+ export { HttpCache } from './HttpCache';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/http/cache/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,2 @@
1
+ export { DiskLruCache } from './DiskLruCache';
2
+ export { HttpCache } from './HttpCache';
@@ -0,0 +1,80 @@
1
+ /**
2
+ * ApiStream - AsyncGenerator 流式响应
3
+ *
4
+ * 支持三种消费方式:
5
+ * 1. await - 直接获取最后一个结果
6
+ * 2. for await - 迭代所有结果
7
+ * 3. subscribe - 安全消费(框架 try-catch)
8
+ */
9
+ import type { ApiResult, ApiCallback } from '../types';
10
+ export declare class ApiStream<T> implements AsyncIterable<ApiResult<T>>, PromiseLike<T> {
11
+ private generator;
12
+ private consumed;
13
+ constructor(generator: () => AsyncGenerator<ApiResult<T>>);
14
+ /**
15
+ * 实现 AsyncIterable,支持 for await
16
+ *
17
+ * 注意:每次迭代都会创建新的请求。如果需要缓存结果,请使用 toArray()
18
+ */
19
+ [Symbol.asyncIterator](): AsyncGenerator<ApiResult<T>>;
20
+ /**
21
+ * 实现 PromiseLike,支持直接 await(返回最后一个结果的 data)
22
+ */
23
+ then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
24
+ /**
25
+ * 实现 catch
26
+ */
27
+ catch<TResult = never>(onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null): Promise<T | TResult>;
28
+ /**
29
+ * 实现 finally
30
+ */
31
+ finally(onfinally?: (() => void) | null): Promise<T>;
32
+ /**
33
+ * 获取第一个结果
34
+ * @throws 如果没有结果会抛出错误
35
+ */
36
+ first(): Promise<ApiResult<T>>;
37
+ /**
38
+ * 获取第一个结果,没有则返回 null
39
+ */
40
+ firstOrNull(): Promise<ApiResult<T> | null>;
41
+ /**
42
+ * 获取最后一个结果
43
+ * @throws 如果没有结果会抛出错误
44
+ */
45
+ last(): Promise<ApiResult<T>>;
46
+ /**
47
+ * 获取最后一个结果,没有则返回 null
48
+ */
49
+ lastOrNull(): Promise<ApiResult<T> | null>;
50
+ /**
51
+ * 获取所有结果
52
+ */
53
+ toArray(): Promise<ApiResult<T>[]>;
54
+ /**
55
+ * 查找满足条件的第一个结果
56
+ */
57
+ find(predicate: (result: ApiResult<T>) => boolean): Promise<ApiResult<T> | undefined>;
58
+ /**
59
+ * 安全消费(框架 try-catch 隔离错误)
60
+ * onData 抛错不会影响后续 yield
61
+ */
62
+ subscribe(callback: ApiCallback<T>): Promise<void>;
63
+ /**
64
+ * 映射结果
65
+ */
66
+ map<U>(fn: (data: T) => U): ApiStream<U>;
67
+ /**
68
+ * 过滤结果
69
+ */
70
+ filter(predicate: (result: ApiResult<T>) => boolean): ApiStream<T>;
71
+ /**
72
+ * 只获取缓存结果
73
+ */
74
+ cacheOnly(): ApiStream<T>;
75
+ /**
76
+ * 只获取网络结果
77
+ */
78
+ remoteOnly(): ApiStream<T>;
79
+ }
80
+ //# sourceMappingURL=ApiStream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiStream.d.ts","sourceRoot":"","sources":["../../../src/http/client/ApiStream.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAEtD,qBAAa,SAAS,CAAC,CAAC,CAAE,YAAW,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;IAC5E,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,QAAQ,CAAQ;gBAEZ,SAAS,EAAE,MAAM,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAIzD;;;;OAIG;IACH,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAqBtD;;OAEG;IACH,IAAI,CAAC,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,KAAK,EAC/B,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,EACrE,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,GAC5E,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAM/B;;OAEG;IACH,KAAK,CAAC,OAAO,GAAG,KAAK,EACjB,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,GAC1E,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC;IAIvB;;OAEG;IACH,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC;IAapD;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAQpC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAOjD;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAQnC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAQhD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IAQxC;;OAEG;IACG,IAAI,CACN,SAAS,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,OAAO,GAC7C,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IASpC;;;OAGG;IACG,SAAS,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBxD;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;IAYxC;;OAEG;IACH,MAAM,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC;IAWlE;;OAEG;IACH,SAAS,IAAI,SAAS,CAAC,CAAC,CAAC;IAIzB;;OAEG;IACH,UAAU,IAAI,SAAS,CAAC,CAAC,CAAC;CAG7B"}
@@ -0,0 +1,190 @@
1
+ /**
2
+ * ApiStream - AsyncGenerator 流式响应
3
+ *
4
+ * 支持三种消费方式:
5
+ * 1. await - 直接获取最后一个结果
6
+ * 2. for await - 迭代所有结果
7
+ * 3. subscribe - 安全消费(框架 try-catch)
8
+ */
9
+ export class ApiStream {
10
+ constructor(generator) {
11
+ this.consumed = false;
12
+ this.generator = generator;
13
+ }
14
+ /**
15
+ * 实现 AsyncIterable,支持 for await
16
+ *
17
+ * 注意:每次迭代都会创建新的请求。如果需要缓存结果,请使用 toArray()
18
+ */
19
+ [Symbol.asyncIterator]() {
20
+ var _a;
21
+ if (this.consumed) {
22
+ // 开发环境下警告重复消费
23
+ try {
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
+ if (typeof globalThis.process !== 'undefined' &&
26
+ ((_a = globalThis.process.env) === null || _a === void 0 ? void 0 : _a.NODE_ENV) !== 'production') {
27
+ console.warn('[ApiStream] Stream is being consumed multiple times. ' +
28
+ 'Each iteration creates a new request. ' +
29
+ 'Use toArray() if you need to reuse results.');
30
+ }
31
+ }
32
+ catch {
33
+ // 忽略环境检测错误
34
+ }
35
+ }
36
+ this.consumed = true;
37
+ return this.generator();
38
+ }
39
+ /**
40
+ * 实现 PromiseLike,支持直接 await(返回最后一个结果的 data)
41
+ */
42
+ then(onfulfilled, onrejected) {
43
+ return this.last()
44
+ .then((result) => result.data)
45
+ .then(onfulfilled, onrejected);
46
+ }
47
+ /**
48
+ * 实现 catch
49
+ */
50
+ catch(onrejected) {
51
+ return this.then(undefined, onrejected);
52
+ }
53
+ /**
54
+ * 实现 finally
55
+ */
56
+ finally(onfinally) {
57
+ return this.then((value) => {
58
+ onfinally === null || onfinally === void 0 ? void 0 : onfinally();
59
+ return value;
60
+ }, (reason) => {
61
+ onfinally === null || onfinally === void 0 ? void 0 : onfinally();
62
+ throw reason;
63
+ });
64
+ }
65
+ /**
66
+ * 获取第一个结果
67
+ * @throws 如果没有结果会抛出错误
68
+ */
69
+ async first() {
70
+ const result = await this.firstOrNull();
71
+ if (!result) {
72
+ throw new Error('No result available');
73
+ }
74
+ return result;
75
+ }
76
+ /**
77
+ * 获取第一个结果,没有则返回 null
78
+ */
79
+ async firstOrNull() {
80
+ for await (const result of this) {
81
+ return result;
82
+ }
83
+ return null;
84
+ }
85
+ /**
86
+ * 获取最后一个结果
87
+ * @throws 如果没有结果会抛出错误
88
+ */
89
+ async last() {
90
+ const result = await this.lastOrNull();
91
+ if (!result) {
92
+ throw new Error('No result available');
93
+ }
94
+ return result;
95
+ }
96
+ /**
97
+ * 获取最后一个结果,没有则返回 null
98
+ */
99
+ async lastOrNull() {
100
+ let lastResult = null;
101
+ for await (const result of this) {
102
+ lastResult = result;
103
+ }
104
+ return lastResult;
105
+ }
106
+ /**
107
+ * 获取所有结果
108
+ */
109
+ async toArray() {
110
+ const results = [];
111
+ for await (const result of this) {
112
+ results.push(result);
113
+ }
114
+ return results;
115
+ }
116
+ /**
117
+ * 查找满足条件的第一个结果
118
+ */
119
+ async find(predicate) {
120
+ for await (const result of this) {
121
+ if (predicate(result)) {
122
+ return result;
123
+ }
124
+ }
125
+ return undefined;
126
+ }
127
+ /**
128
+ * 安全消费(框架 try-catch 隔离错误)
129
+ * onData 抛错不会影响后续 yield
130
+ */
131
+ async subscribe(callback) {
132
+ var _a, _b, _c, _d;
133
+ try {
134
+ for await (const result of this) {
135
+ try {
136
+ callback.onData(result.data, result.fromCache);
137
+ }
138
+ catch (error) {
139
+ // 捕获下游错误,不影响后续 yield
140
+ (_a = callback.onError) === null || _a === void 0 ? void 0 : _a.call(callback, error);
141
+ }
142
+ }
143
+ (_b = callback.onComplete) === null || _b === void 0 ? void 0 : _b.call(callback);
144
+ }
145
+ catch (error) {
146
+ // 网络错误等
147
+ (_c = callback.onError) === null || _c === void 0 ? void 0 : _c.call(callback, error);
148
+ (_d = callback.onComplete) === null || _d === void 0 ? void 0 : _d.call(callback);
149
+ }
150
+ }
151
+ /**
152
+ * 映射结果
153
+ */
154
+ map(fn) {
155
+ const self = this;
156
+ return new ApiStream(async function* () {
157
+ for await (const result of self) {
158
+ yield {
159
+ data: fn(result.data),
160
+ fromCache: result.fromCache,
161
+ };
162
+ }
163
+ });
164
+ }
165
+ /**
166
+ * 过滤结果
167
+ */
168
+ filter(predicate) {
169
+ const self = this;
170
+ return new ApiStream(async function* () {
171
+ for await (const result of self) {
172
+ if (predicate(result)) {
173
+ yield result;
174
+ }
175
+ }
176
+ });
177
+ }
178
+ /**
179
+ * 只获取缓存结果
180
+ */
181
+ cacheOnly() {
182
+ return this.filter((r) => r.fromCache);
183
+ }
184
+ /**
185
+ * 只获取网络结果
186
+ */
187
+ remoteOnly() {
188
+ return this.filter((r) => !r.fromCache);
189
+ }
190
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * HTTP 客户端
3
+ *
4
+ * 基于 ky 封装,支持:
5
+ * - 多种缓存模式
6
+ * - 自动重试
7
+ * - 超时处理
8
+ */
9
+ import { type KyInstance, type Options as KyOptions } from 'ky';
10
+ import { HttpCache } from '../cache/HttpCache';
11
+ import { ApiStream } from './ApiStream';
12
+ import { type HttpClientConfig, type RequestConfig, type ApiOptions } from '../types';
13
+ export declare class HttpClient {
14
+ private client;
15
+ private cache;
16
+ private config;
17
+ constructor(config: HttpClientConfig);
18
+ /**
19
+ * 获取 ky 实例(用于扩展 hooks 等)
20
+ */
21
+ getKyInstance(): KyInstance;
22
+ /**
23
+ * 设置 ky 实例
24
+ */
25
+ setKyInstance(instance: KyInstance): void;
26
+ /**
27
+ * 扩展 ky 实例
28
+ */
29
+ extendKy(options: KyOptions): void;
30
+ /**
31
+ * 执行请求,返回 ApiStream
32
+ */
33
+ request<T>(requestConfig: RequestConfig, options?: ApiOptions): ApiStream<T>;
34
+ /**
35
+ * 根据缓存策略执行请求
36
+ */
37
+ private executeWithCacheStrategy;
38
+ /**
39
+ * 判断响应是否应该缓存
40
+ *
41
+ * 调用全局缓存拦截器,根据响应内容决定是否缓存。
42
+ * 如果没有配置拦截器,默认允许缓存。
43
+ *
44
+ * @param result 请求响应结果
45
+ * @param cacheKey 缓存 key
46
+ * @param request 请求信息
47
+ * @param defaultTtl 默认 TTL
48
+ * @returns 是否缓存及最终 TTL
49
+ */
50
+ private shouldCacheResponse;
51
+ /**
52
+ * 条件缓存:根据拦截器结果决定是否写入缓存
53
+ */
54
+ private conditionalCache;
55
+ /**
56
+ * OnlyRemote: 只从服务器拿
57
+ */
58
+ private strategyOnlyRemote;
59
+ /**
60
+ * OnlyCache: 只从缓存拿
61
+ */
62
+ private strategyOnlyCache;
63
+ /**
64
+ * IfCache: 有缓存返回缓存,否则请求网络
65
+ */
66
+ private strategyIfCache;
67
+ /**
68
+ * FirstRemote: 先从服务器获取,没网络则读缓存
69
+ */
70
+ private strategyFirstRemote;
71
+ /**
72
+ * FirstCache: 先从本地缓存拿,然后从服务器拿,可能 yield 两次
73
+ */
74
+ private strategyFirstCache;
75
+ /**
76
+ * LastCache: 读上次缓存,没有则返回网络并同步缓存;有缓存也会后台同步网络但不 yield
77
+ */
78
+ private strategyLastCache;
79
+ /**
80
+ * 获取缓存实例(用于高级操作)
81
+ */
82
+ getCache(): HttpCache;
83
+ /**
84
+ * 清空所有缓存
85
+ */
86
+ clearCache(): Promise<void>;
87
+ }
88
+ //# sourceMappingURL=HttpClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HttpClient.d.ts","sourceRoot":"","sources":["../../../src/http/client/HttpClient.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAW,EAAE,KAAK,UAAU,EAAE,KAAK,OAAO,IAAI,SAAS,EAAE,MAAM,IAAI,CAAA;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAEH,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,UAAU,EAMlB,MAAM,UAAU,CAAA;AAyFjB,qBAAa,UAAU;IACnB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,MAAM,CAA4B;gBAE9B,MAAM,EAAE,gBAAgB;IA8BpC;;OAEG;IACH,aAAa,IAAI,UAAU;IAI3B;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI;IAIzC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI;IAIlC;;OAEG;IACH,OAAO,CAAC,CAAC,EAAE,aAAa,EAAE,aAAa,EAAE,OAAO,GAAE,UAAe,GAAG,SAAS,CAAC,CAAC,CAAC;IAmFhF;;OAEG;YACY,wBAAwB;IAqCvC;;;;;;;;;;;OAWG;YACW,mBAAmB;IAwCjC;;OAEG;YACW,gBAAgB;IAY9B;;OAEG;YACY,kBAAkB;IAWjC;;OAEG;YACY,iBAAiB;IAQhC;;OAEG;YACY,eAAe;IAiB9B;;OAEG;YACY,mBAAmB;IAqBlC;;OAEG;YACY,kBAAkB;IA0BjC;;OAEG;YACY,iBAAiB;IA0BhC;;OAEG;IACH,QAAQ,IAAI,SAAS;IAIrB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAGpC"}