@reskin/core 0.0.21 → 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.
Files changed (45) hide show
  1. package/bundles/reskin-core-directives.umd.js +303 -163
  2. package/bundles/reskin-core-directives.umd.js.map +1 -1
  3. package/bundles/reskin-core-guards.umd.js +119 -32
  4. package/bundles/reskin-core-guards.umd.js.map +1 -1
  5. package/bundles/reskin-core-interceptors.umd.js +310 -92
  6. package/bundles/reskin-core-interceptors.umd.js.map +1 -1
  7. package/bundles/reskin-core-utils.umd.js +220 -77
  8. package/bundles/reskin-core-utils.umd.js.map +1 -1
  9. package/directives/auth.directive.d.ts +56 -9
  10. package/directives/load.styles.directive.d.ts +45 -5
  11. package/directives/string.template.outlet.directive.d.ts +68 -11
  12. package/esm2015/directives/auth.directive.js +71 -30
  13. package/esm2015/directives/load.styles.directive.js +84 -15
  14. package/esm2015/directives/string.template.outlet.directive.js +118 -60
  15. package/esm2015/guards/auth.guard.js +117 -30
  16. package/esm2015/interceptors/blob.interceptor.js +67 -28
  17. package/esm2015/interceptors/cache.interceptor.js +46 -14
  18. package/esm2015/interceptors/error.interceptor.js +104 -12
  19. package/esm2015/interceptors/public-api.js +2 -1
  20. package/esm2015/interceptors/token.interceptor.js +86 -42
  21. package/esm2015/interceptors/types.js +5 -0
  22. package/esm2015/utils/array.js +42 -22
  23. package/esm2015/utils/dom.js +29 -11
  24. package/esm2015/utils/form.js +44 -13
  25. package/esm2015/utils/store.js +101 -26
  26. package/fesm2015/reskin-core-directives.js +269 -103
  27. package/fesm2015/reskin-core-directives.js.map +1 -1
  28. package/fesm2015/reskin-core-guards.js +116 -29
  29. package/fesm2015/reskin-core-guards.js.map +1 -1
  30. package/fesm2015/reskin-core-interceptors.js +302 -91
  31. package/fesm2015/reskin-core-interceptors.js.map +1 -1
  32. package/fesm2015/reskin-core-utils.js +212 -68
  33. package/fesm2015/reskin-core-utils.js.map +1 -1
  34. package/guards/auth.guard.d.ts +85 -5
  35. package/interceptors/blob.interceptor.d.ts +30 -3
  36. package/interceptors/cache.interceptor.d.ts +28 -4
  37. package/interceptors/error.interceptor.d.ts +43 -2
  38. package/interceptors/public-api.d.ts +1 -0
  39. package/interceptors/token.interceptor.d.ts +41 -12
  40. package/interceptors/types.d.ts +68 -0
  41. package/package.json +1 -1
  42. package/utils/array.d.ts +8 -1
  43. package/utils/dom.d.ts +32 -5
  44. package/utils/form.d.ts +37 -2
  45. package/utils/store.d.ts +56 -15
@@ -2,35 +2,63 @@ import * as i0 from '@angular/core';
2
2
  import { Injectable } from '@angular/core';
3
3
  import { HTTP_INTERCEPTORS, HttpHeaders, HttpEventType, HttpResponse } from '@angular/common/http';
4
4
  import * as i1 from '@reskin/core/services';
5
- import { of, Observable } from 'rxjs';
5
+ import { throwError, Observable } from 'rxjs';
6
6
  import { catchError, shareReplay, switchMap } from 'rxjs/operators';
7
7
  import * as i1$1 from '@angular/router';
8
+ import { Router } from '@angular/router';
8
9
 
10
+ /**
11
+ * HTTP 拦截器相关类型定义
12
+ */
13
+
14
+ /**
15
+ * Token 拦截器常量
16
+ */
17
+ const DEFAULT_TOKEN_HEADER_NAME = 'Authorization';
18
+ const TOKEN_CONTROL_HEADER = 'Token-Control';
19
+ const CUSTOM_TOKEN_HEADER = 'Custom-Token';
20
+ const CUSTOM_TOKEN_HEADER_NAME = 'Custom-Token-Header';
21
+ const AUTH_ID_HEADER = 'X-Auth-Id';
22
+ /**
23
+ * Token 拦截器
24
+ * 自动为 HTTP 请求添加认证 Token
25
+ */
9
26
  class TokenInterceptor {
10
- constructor(service) {
11
- this.service = service;
27
+ constructor(authService) {
28
+ this.authService = authService;
12
29
  }
30
+ /**
31
+ * 拦截 HTTP 请求,添加 Token 认证信息
32
+ * @param request HTTP 请求对象
33
+ * @param next 下一个拦截器处理器
34
+ * @returns Observable<HttpEvent<unknown>>
35
+ */
13
36
  intercept(request, next) {
14
- const tc = request.headers.get('Token-Control');
15
- // 检查是否提供了自定义token
16
- const customToken = request.headers.get('Custom-Token');
17
- if (tc !== 'no-token') {
18
- let headers = {};
19
- if (customToken) {
20
- // 使用自定义token
21
- headers['Authorization'] = customToken;
22
- }
23
- else {
24
- // 使用默认认证信息
25
- const auth = this.service.token;
26
- if (auth.token) {
27
- headers['Authorization'] = auth.token;
28
- headers['X-Auth-Id'] = auth.id;
37
+ const tokenControl = request.headers.get(TOKEN_CONTROL_HEADER);
38
+ // 如果明确指定不需要 Token,直接放行
39
+ if (tokenControl === 'no-token') {
40
+ return next.handle(request);
41
+ }
42
+ const customToken = request.headers.get(CUSTOM_TOKEN_HEADER);
43
+ const customTokenHeaderName = request.headers.get(CUSTOM_TOKEN_HEADER_NAME) || DEFAULT_TOKEN_HEADER_NAME;
44
+ const headers = {};
45
+ if (customToken) {
46
+ // 使用自定义 Token
47
+ headers[customTokenHeaderName] = customToken;
48
+ }
49
+ else {
50
+ // 使用默认认证信息
51
+ const auth = this.authService.token;
52
+ if (auth === null || auth === void 0 ? void 0 : auth.token) {
53
+ headers[DEFAULT_TOKEN_HEADER_NAME] = auth.token;
54
+ if (auth.id) {
55
+ headers[AUTH_ID_HEADER] = auth.id;
29
56
  }
30
57
  }
31
- if (Object.keys(headers).length > 0) {
32
- request = request.clone({ setHeaders: headers });
33
- }
58
+ }
59
+ // 如果有需要添加的 Header,克隆请求并添加
60
+ if (Object.keys(headers).length > 0) {
61
+ request = request.clone({ setHeaders: headers });
34
62
  }
35
63
  return next.handle(request);
36
64
  }
@@ -41,55 +69,141 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImpo
41
69
  type: Injectable
42
70
  }], ctorParameters: function () { return [{ type: i1.RkAuthService }]; } });
43
71
  /**
44
- * 请求头增加token验证拦截器
72
+ * 提供 Token 拦截器
73
+ * @returns Provider 配置对象
45
74
  */
46
75
  function providerAuthToken() {
47
76
  return { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true };
48
77
  }
49
78
  /**
50
- * 不带token验证信息请求
51
- * @param urls 地址
52
- * @param params 参数
53
- * @constructor
79
+ * 创建不带 Token 的请求配置
80
+ * @param urls 模板字符串数组
81
+ * @param params 模板参数
82
+ * @returns [url, options] 元组
83
+ * @example
84
+ * this.http.get(...NoAuthTokenTemplate`/api/public/data`).subscribe();
54
85
  */
55
86
  function NoAuthTokenTemplate(urls, ...params) {
56
- let [url] = urls;
57
- if (params.length > 0) {
58
- url = String.raw(urls, ...params);
59
- }
60
- return [url, { headers: new HttpHeaders({ 'Token-Control': 'no-token' }) }];
87
+ const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];
88
+ return [url, { headers: new HttpHeaders({ [TOKEN_CONTROL_HEADER]: 'no-token' }) }];
61
89
  }
62
90
  /**
63
- * 使用自定义token的请求(模板字符串版本)
64
- * @param urls 地址
65
- * @param params 参数,第一个参数必须是token值
66
- * @constructor
91
+ * 创建使用自定义 Token 的请求配置
92
+ * @param token 自定义 Token 值
93
+ * @param urls 模板字符串数组
94
+ * @param params 模板参数
95
+ * @returns [url, options] 元组
96
+ * @example
97
+ * this.http.get(...CustomTokenTemplate('my-token', `/api/data`)).subscribe();
67
98
  */
68
- function CustomTokenTemplate(urls, ...params) {
69
- if (params.length === 0) {
70
- throw new Error('CustomTokenTemplate 至少需要一个参数作为token值');
71
- }
72
- const token = params[0];
73
- const url = String.raw(urls, ...params.slice(1));
74
- return [url, { headers: new HttpHeaders({ 'Custom-Token': token }) }];
99
+ function CustomTokenTemplate(token, urls, ...params) {
100
+ const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];
101
+ return [url, { headers: new HttpHeaders({ [CUSTOM_TOKEN_HEADER]: token }) }];
102
+ }
103
+ /**
104
+ * 创建使用自定义 Token 和自定义 Header 名称的请求配置
105
+ * @param token 自定义 Token
106
+ * @param headerName 自定义 Header 名称
107
+ * @param urls 模板字符串数组
108
+ * @param params 模板参数
109
+ * @returns [url, options] 元组
110
+ * @example
111
+ * this.http.get(...CustomTokenWithHeaderTemplate('my-token', 'X-API-Key', `/api/data`)).subscribe();
112
+ */
113
+ function CustomTokenWithHeaderTemplate(token, headerName, urls, ...params) {
114
+ const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];
115
+ return [
116
+ url,
117
+ {
118
+ headers: new HttpHeaders({
119
+ [CUSTOM_TOKEN_HEADER]: token,
120
+ [CUSTOM_TOKEN_HEADER_NAME]: headerName,
121
+ }),
122
+ },
123
+ ];
75
124
  }
76
125
 
126
+ /**
127
+ * 默认配置
128
+ */
129
+ const DEFAULT_CONFIG = {
130
+ unauthorizedPath: '/errors/401',
131
+ enableLogging: false,
132
+ };
133
+ /**
134
+ * HTTP 错误拦截器
135
+ * 统一处理 HTTP 请求错误,包括 401 未授权错误的自动跳转
136
+ */
77
137
  class ErrorInterceptor {
78
138
  constructor(router) {
79
139
  this.router = router;
140
+ this.config = DEFAULT_CONFIG;
80
141
  }
142
+ /**
143
+ * 设置拦截器配置
144
+ * @param config 配置对象
145
+ */
146
+ setConfig(config) {
147
+ this.config = Object.assign(Object.assign({}, DEFAULT_CONFIG), config);
148
+ }
149
+ /**
150
+ * 拦截 HTTP 请求,处理错误响应
151
+ * @param request HTTP 请求对象
152
+ * @param next 下一个拦截器处理器
153
+ * @returns Observable<HttpEvent<unknown>>
154
+ */
81
155
  intercept(request, next) {
82
- return next.handle(request).pipe(catchError((result) => {
83
- var _a;
84
- if (result.status === 401) {
85
- this.router.navigate(['/errors/401']).then();
156
+ return next.handle(request).pipe(catchError((error) => {
157
+ // 处理 401 未授权错误
158
+ if (error.status === 401) {
159
+ this.handleUnauthorizedError();
160
+ return throwError(error);
86
161
  }
87
- if (result.error.code) {
88
- return of(result.error);
162
+ // 记录错误日志
163
+ if (this.config.enableLogging) {
164
+ console.error('[HTTP Error]', {
165
+ url: request.url,
166
+ method: request.method,
167
+ status: error.status,
168
+ message: error.message,
169
+ error: error.error,
170
+ });
89
171
  }
90
- throw (_a = result.error.msg) !== null && _a !== void 0 ? _a : result.message;
172
+ // 提取错误信息
173
+ const errorMessage = this.extractErrorMessage(error);
174
+ return throwError(new Error(errorMessage));
91
175
  }));
92
176
  }
177
+ /**
178
+ * 处理 401 未授权错误
179
+ */
180
+ handleUnauthorizedError() {
181
+ const path = this.config.unauthorizedPath || DEFAULT_CONFIG.unauthorizedPath;
182
+ this.router.navigate([path]).catch((err) => {
183
+ console.error('导航到错误页面失败:', err);
184
+ });
185
+ }
186
+ /**
187
+ * 提取错误信息
188
+ * @param error HTTP 错误响应
189
+ * @returns 错误信息字符串
190
+ */
191
+ extractErrorMessage(error) {
192
+ if (error.error) {
193
+ // 尝试从 error.error 中提取信息
194
+ if (typeof error.error === 'string') {
195
+ return error.error;
196
+ }
197
+ if (error.error.msg) {
198
+ return error.error.msg;
199
+ }
200
+ if (error.error.message) {
201
+ return error.error.message;
202
+ }
203
+ }
204
+ // 使用默认错误信息
205
+ return error.message || `HTTP Error ${error.status}`;
206
+ }
93
207
  }
94
208
  ErrorInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: ErrorInterceptor, deps: [{ token: i1$1.Router }], target: i0.ɵɵFactoryTarget.Injectable });
95
209
  ErrorInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: ErrorInterceptor });
@@ -97,28 +211,71 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImpo
97
211
  type: Injectable
98
212
  }], ctorParameters: function () { return [{ type: i1$1.Router }]; } });
99
213
  /**
100
- * 请求错误拦截器
214
+ * 提供 HTTP 错误拦截器
215
+ * @param config 可选的配置对象
216
+ * @returns Provider 配置对象
217
+ * @example
218
+ * providers: [
219
+ * providerHttpError({ unauthorizedPath: '/login', enableLogging: true })
220
+ * ]
101
221
  */
102
- function providerHttpError() {
103
- return { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true };
222
+ function providerHttpError(config) {
223
+ if (config) {
224
+ // 如果有配置,使用 useFactory
225
+ return {
226
+ provide: HTTP_INTERCEPTORS,
227
+ useFactory: (router) => {
228
+ const interceptor = new ErrorInterceptor(router);
229
+ interceptor.setConfig(config);
230
+ return interceptor;
231
+ },
232
+ deps: [Router],
233
+ multi: true,
234
+ };
235
+ }
236
+ else {
237
+ // 没有配置,直接使用 useClass
238
+ return {
239
+ provide: HTTP_INTERCEPTORS,
240
+ useClass: ErrorInterceptor,
241
+ multi: true,
242
+ };
243
+ }
104
244
  }
105
245
 
246
+ /**
247
+ * 缓存策略标识
248
+ */
249
+ const CACHE_HEADER = 'Cache-Map';
250
+ const CACHE_STRATEGY = 'Storage';
251
+ /**
252
+ * HTTP 缓存拦截器
253
+ * 为 GET 请求提供缓存功能,减少重复请求
254
+ */
106
255
  class CacheInterceptor {
107
- constructor(cacheHttp) {
108
- this.cacheHttp = cacheHttp;
256
+ constructor(cacheHttpService) {
257
+ this.cacheHttpService = cacheHttpService;
109
258
  }
259
+ /**
260
+ * 拦截 HTTP 请求,实现缓存逻辑
261
+ * @param request HTTP 请求对象
262
+ * @param next 下一个拦截器处理器
263
+ * @returns Observable<HttpEvent<unknown>>
264
+ */
110
265
  intercept(request, next) {
111
- // 1.判断是GET
112
- // 2.header中添加 Cache-Map: Storage
113
- const cacheMap = request.headers.get('Cache-Map');
114
- if (request.method === 'GET' && cacheMap === 'Storage') {
115
- let response = this.cacheHttp.get(request.url);
116
- if (!response) {
117
- response = next.handle(request).pipe(shareReplay(1));
118
- this.cacheHttp.set(request.url, response);
266
+ // 只缓存 GET 请求且明确标记了缓存策略的请求
267
+ const cacheStrategy = request.headers.get(CACHE_HEADER);
268
+ if (request.method === 'GET' && cacheStrategy === CACHE_STRATEGY) {
269
+ // 尝试从缓存中获取响应
270
+ let cachedResponse = this.cacheHttpService.get(request.url);
271
+ if (!cachedResponse) {
272
+ // 缓存未命中,发起请求并缓存结果
273
+ cachedResponse = next.handle(request).pipe(shareReplay(1));
274
+ this.cacheHttpService.set(request.url, cachedResponse);
119
275
  }
120
- return response;
276
+ return cachedResponse;
121
277
  }
278
+ // 非缓存请求,直接放行
122
279
  return next.handle(request);
123
280
  }
124
281
  }
@@ -128,58 +285,110 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImpo
128
285
  type: Injectable
129
286
  }], ctorParameters: function () { return [{ type: i1.RkCacheHttpService }]; } });
130
287
  /**
131
- * GET请求缓存拦截器
288
+ * 提供 HTTP 缓存拦截器
289
+ * @returns Provider 配置对象
290
+ * @example
291
+ * providers: [providerHttpCache()]
132
292
  */
133
293
  function providerHttpCache() {
134
294
  return { provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true };
295
+ }
296
+ /**
297
+ * 创建带缓存标记的 GET 请求配置
298
+ * @param urls 模板字符串数组
299
+ * @param params 模板参数
300
+ * @returns [url, options] 元组
301
+ * @example
302
+ * this.http.get(...CacheHttpTemplate`/api/data`).subscribe();
303
+ */
304
+ function CacheHttpTemplate(urls, ...params) {
305
+ const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];
306
+ return [url, { headers: new HttpHeaders({ [CACHE_HEADER]: CACHE_STRATEGY }) }];
135
307
  }
136
308
 
309
+ /**
310
+ * Blob 响应拦截器
311
+ * 处理文件下载请求中的 JSON 错误响应
312
+ */
137
313
  class BlobInterceptor {
314
+ /**
315
+ * 拦截 HTTP 请求,处理 Blob 类型响应
316
+ * @param request HTTP 请求对象
317
+ * @param next 下一个拦截器处理器
318
+ * @returns Observable<HttpEvent<T>>
319
+ */
138
320
  intercept(request, next) {
321
+ // 只处理 responseType 为 blob 的请求
139
322
  if (request.responseType !== 'blob') {
140
323
  return next.handle(request);
141
324
  }
142
- return next.handle(request).pipe(switchMap((response) => this.handleBlobResponse(response)), catchError((response) => this.handleBlobError(response)));
325
+ return next.handle(request).pipe(switchMap((event) => this.handleBlobResponse(event)), catchError((error) => this.handleBlobError(error)));
143
326
  }
144
- handleBlobResponse(response) {
145
- if (response.type !== HttpEventType.Response) {
327
+ /**
328
+ * 处理 Blob 响应事件
329
+ * @param event HTTP 事件
330
+ * @returns Observable<HttpEvent<any>>
331
+ */
332
+ handleBlobResponse(event) {
333
+ var _a;
334
+ // 只处理完整的响应事件
335
+ if (event.type !== HttpEventType.Response) {
146
336
  return new Observable((subscriber) => {
147
- subscriber.next(response);
337
+ subscriber.next(event);
148
338
  subscriber.complete();
149
339
  });
150
340
  }
151
- if (response instanceof HttpResponse && response.body && response.body.type === 'application/json') {
152
- return new Observable((subscriber) => this.blobToJson(response.body, subscriber));
341
+ // 检查响应体是否为 JSON 类型(通常表示错误)
342
+ if (event instanceof HttpResponse && ((_a = event.body) === null || _a === void 0 ? void 0 : _a.type) === 'application/json') {
343
+ return this.convertBlobToJson(event.body);
153
344
  }
154
345
  return new Observable((subscriber) => {
155
- subscriber.next(response);
346
+ subscriber.next(event);
156
347
  subscriber.complete();
157
348
  });
158
349
  }
159
- handleBlobError(response) {
160
- if (response.error && response.error.type === 'application/json') {
161
- return new Observable((subscriber) => this.blobToJson(response.error, subscriber));
350
+ /**
351
+ * 处理 Blob 错误响应
352
+ * @param error HTTP 错误响应
353
+ * @returns Observable<HttpEvent<any>>
354
+ */
355
+ handleBlobError(error) {
356
+ var _a;
357
+ // 如果错误响应体是 JSON 类型的 Blob,转换为 JSON 对象
358
+ if (((_a = error.error) === null || _a === void 0 ? void 0 : _a.type) === 'application/json') {
359
+ return this.convertBlobToJson(error.error);
162
360
  }
163
361
  return new Observable((subscriber) => {
164
- subscriber.error(response);
362
+ subscriber.error(error);
165
363
  subscriber.complete();
166
364
  });
167
365
  }
168
- blobToJson(blob, subscriber) {
169
- const reader = new FileReader();
170
- reader.addEventListener('loadend', () => {
171
- try {
172
- const json = JSON.parse(reader.result);
173
- subscriber.error(json);
174
- }
175
- catch (error) {
176
- subscriber.error(error);
177
- }
178
- finally {
366
+ /**
367
+ * Blob 转换为 JSON 对象并抛出错误
368
+ * @param blob Blob 对象
369
+ * @returns Observable<HttpEvent<T>>
370
+ */
371
+ convertBlobToJson(blob) {
372
+ return new Observable((subscriber) => {
373
+ const reader = new FileReader();
374
+ reader.addEventListener('loadend', () => {
375
+ try {
376
+ const json = JSON.parse(reader.result);
377
+ subscriber.error(json);
378
+ }
379
+ catch (parseError) {
380
+ subscriber.error(parseError);
381
+ }
382
+ finally {
383
+ subscriber.complete();
384
+ }
385
+ });
386
+ reader.addEventListener('error', () => {
387
+ subscriber.error(new Error('读取 Blob 数据失败'));
179
388
  subscriber.complete();
180
- }
389
+ });
390
+ reader.readAsText(blob, 'utf-8');
181
391
  });
182
- reader.readAsText(blob, 'utf-8');
183
392
  }
184
393
  }
185
394
  BlobInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: BlobInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
@@ -188,8 +397,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImpo
188
397
  type: Injectable
189
398
  }] });
190
399
  /**
191
- * 下载文件拦截器
192
- * blob类型的请求会被处理
400
+ * 提供 Blob 响应拦截器
401
+ * @returns Provider 配置对象
402
+ * @example
403
+ * providers: [providerDownBlob()]
193
404
  */
194
405
  function providerDownBlob() {
195
406
  return { provide: HTTP_INTERCEPTORS, useClass: BlobInterceptor, multi: true };
@@ -199,5 +410,5 @@ function providerDownBlob() {
199
410
  * Generated bundle index. Do not edit.
200
411
  */
201
412
 
202
- export { BlobInterceptor, CacheInterceptor, CustomTokenTemplate, ErrorInterceptor, NoAuthTokenTemplate, TokenInterceptor, providerAuthToken, providerDownBlob, providerHttpCache, providerHttpError };
413
+ export { BlobInterceptor, CacheHttpTemplate, CacheInterceptor, CustomTokenTemplate, CustomTokenWithHeaderTemplate, ErrorInterceptor, NoAuthTokenTemplate, TokenInterceptor, providerAuthToken, providerDownBlob, providerHttpCache, providerHttpError };
203
414
  //# sourceMappingURL=reskin-core-interceptors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reskin-core-interceptors.js","sources":["../../../library/core/interceptors/token.interceptor.ts","../../../library/core/interceptors/error.interceptor.ts","../../../library/core/interceptors/cache.interceptor.ts","../../../library/core/interceptors/blob.interceptor.ts","../../../library/core/interceptors/reskin-core-interceptors.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\r\nimport { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS, HttpHeaders } from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\nimport { RkAuthService } from '@reskin/core/services';\r\nimport { IAuth } from '@reskin/core/entity/user';\r\n\r\n@Injectable()\r\nexport class TokenInterceptor implements HttpInterceptor {\r\n constructor(private service: RkAuthService) {}\r\n\r\n intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\r\n const tc = request.headers.get('Token-Control');\r\n // 检查是否提供了自定义token\r\n const customToken = request.headers.get('Custom-Token');\r\n\r\n if (tc !== 'no-token') {\r\n let headers: { [name: string]: string | string[] } = {};\r\n\r\n if (customToken) {\r\n // 使用自定义token\r\n headers['Authorization'] = customToken;\r\n } else {\r\n // 使用默认认证信息\r\n const auth: IAuth = this.service.token;\r\n if (auth.token) {\r\n headers['Authorization'] = auth.token;\r\n headers['X-Auth-Id'] = auth.id;\r\n }\r\n }\r\n\r\n if (Object.keys(headers).length > 0) {\r\n request = request.clone({ setHeaders: headers });\r\n }\r\n }\r\n return next.handle(request);\r\n }\r\n}\r\n\r\n/**\r\n * 请求头增加token验证拦截器\r\n */\r\nexport function providerAuthToken() {\r\n return { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true };\r\n}\r\n\r\n/**\r\n * 不带token验证信息请求\r\n * @param urls 地址\r\n * @param params 参数\r\n * @constructor\r\n */\r\nexport function NoAuthTokenTemplate(urls: TemplateStringsArray, ...params: any[]): [string, { headers: HttpHeaders }] {\r\n let [url] = urls;\r\n if (params.length > 0) {\r\n url = String.raw(urls, ...params);\r\n }\r\n return [url, { headers: new HttpHeaders({ 'Token-Control': 'no-token' }) }];\r\n}\r\n\r\n/**\r\n * 使用自定义token的请求(模板字符串版本)\r\n * @param urls 地址\r\n * @param params 参数,第一个参数必须是token值\r\n * @constructor\r\n */\r\nexport function CustomTokenTemplate(urls: TemplateStringsArray, ...params: any[]): [string, { headers: HttpHeaders }] {\r\n if (params.length === 0) {\r\n throw new Error('CustomTokenTemplate 至少需要一个参数作为token值');\r\n }\r\n\r\n const token = params[0];\r\n const url = String.raw(urls, ...params.slice(1));\r\n\r\n return [url, { headers: new HttpHeaders({ 'Custom-Token': token }) }];\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS } from '@angular/common/http';\r\nimport { Observable, of } from 'rxjs';\r\nimport { catchError } from 'rxjs/operators';\r\nimport { Router } from '@angular/router';\r\n\r\n@Injectable()\r\nexport class ErrorInterceptor implements HttpInterceptor {\r\n constructor(private router: Router) {}\r\n\r\n intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\r\n return next.handle(request).pipe(\r\n catchError((result) => {\r\n if (result.status === 401) {\r\n this.router.navigate(['/errors/401']).then();\r\n }\r\n if (result.error.code) {\r\n return of(result.error);\r\n }\r\n throw result.error.msg ?? result.message;\r\n }),\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * 请求错误拦截器\r\n */\r\nexport function providerHttpError() {\r\n return { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true };\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS } from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\nimport { shareReplay } from 'rxjs/operators';\r\nimport { RkCacheHttpService } from '@reskin/core/services';\r\n\r\n@Injectable()\r\nexport class CacheInterceptor implements HttpInterceptor {\r\n constructor(private cacheHttp: RkCacheHttpService) {}\r\n\r\n intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\r\n // 1.判断是GET\r\n // 2.header中添加 Cache-Map: Storage\r\n const cacheMap = request.headers.get('Cache-Map');\r\n if (request.method === 'GET' && cacheMap === 'Storage') {\r\n let response = this.cacheHttp.get(request.url);\r\n if (!response) {\r\n response = next.handle(request).pipe(shareReplay(1));\r\n this.cacheHttp.set(request.url, response);\r\n }\r\n return response;\r\n }\r\n return next.handle(request);\r\n }\r\n}\r\n\r\n/**\r\n * GET请求缓存拦截器\r\n */\r\nexport function providerHttpCache() {\r\n return { provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true };\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport {\r\n HttpRequest,\r\n HttpHandler,\r\n HttpEvent,\r\n HttpInterceptor,\r\n HttpEventType,\r\n HttpResponse,\r\n HttpErrorResponse,\r\n HTTP_INTERCEPTORS,\r\n} from '@angular/common/http';\r\nimport { Observable, Subscriber } from 'rxjs';\r\nimport { catchError, switchMap } from 'rxjs/operators';\r\n\r\n@Injectable()\r\nexport class BlobInterceptor implements HttpInterceptor {\r\n intercept<T>(request: HttpRequest<T>, next: HttpHandler): Observable<HttpEvent<T>> {\r\n if (request.responseType !== 'blob') {\r\n return next.handle(request);\r\n }\r\n return next.handle(request).pipe(\r\n switchMap((response: HttpEvent<any>) => this.handleBlobResponse(response)),\r\n catchError((response: HttpErrorResponse) => this.handleBlobError(response)),\r\n );\r\n }\r\n\r\n private handleBlobResponse<T>(response: HttpEvent<any>): Observable<HttpEvent<any>> {\r\n if (response.type !== HttpEventType.Response) {\r\n return new Observable((subscriber) => {\r\n subscriber.next(response);\r\n subscriber.complete();\r\n });\r\n }\r\n\r\n if (response instanceof HttpResponse && response.body && response.body.type === 'application/json') {\r\n return new Observable((subscriber) => this.blobToJson<T>(response.body, subscriber));\r\n }\r\n\r\n return new Observable((subscriber) => {\r\n subscriber.next(response);\r\n subscriber.complete();\r\n });\r\n }\r\n\r\n private handleBlobError<T>(response: HttpErrorResponse): Observable<HttpEvent<any>> {\r\n if (response.error && response.error.type === 'application/json') {\r\n return new Observable((subscriber) => this.blobToJson<T>(response.error, subscriber));\r\n }\r\n\r\n return new Observable((subscriber) => {\r\n subscriber.error(response);\r\n subscriber.complete();\r\n });\r\n }\r\n\r\n private blobToJson<T>(blob: Blob, subscriber: Subscriber<HttpEvent<T>>) {\r\n const reader = new FileReader();\r\n reader.addEventListener('loadend', () => {\r\n try {\r\n const json: T = JSON.parse(reader.result as string);\r\n subscriber.error(json);\r\n } catch (error) {\r\n subscriber.error(error);\r\n } finally {\r\n subscriber.complete();\r\n }\r\n });\r\n reader.readAsText(blob, 'utf-8');\r\n }\r\n}\r\n\r\n/**\r\n * 下载文件拦截器\r\n * blob类型的请求会被处理\r\n */\r\nexport function providerDownBlob() {\r\n return { provide: HTTP_INTERCEPTORS, useClass: BlobInterceptor, multi: true };\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1"],"mappings":"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"}
1
+ {"version":3,"file":"reskin-core-interceptors.js","sources":["../../../library/core/interceptors/types.ts","../../../library/core/interceptors/token.interceptor.ts","../../../library/core/interceptors/error.interceptor.ts","../../../library/core/interceptors/cache.interceptor.ts","../../../library/core/interceptors/blob.interceptor.ts","../../../library/core/interceptors/reskin-core-interceptors.ts"],"sourcesContent":["/**\r\n * HTTP 拦截器相关类型定义\r\n */\r\n\r\n/**\r\n * Token 拦截器配置\r\n */\r\nexport interface TokenInterceptorConfig {\r\n /**\r\n * 默认的 Token Header 名称\r\n * @default 'Authorization'\r\n */\r\n tokenHeaderName?: string;\r\n /**\r\n * 认证 ID Header 名称\r\n * @default 'X-Auth-Id'\r\n */\r\n authIdHeaderName?: string;\r\n}\r\n\r\n/**\r\n * 错误拦截器配置\r\n */\r\nexport interface ErrorInterceptorConfig {\r\n /**\r\n * 401 错误跳转路径\r\n * @default '/errors/401'\r\n */\r\n unauthorizedPath?: string;\r\n /**\r\n * 是否启用错误日志\r\n * @default false\r\n */\r\n enableLogging?: boolean;\r\n /**\r\n * 自定义错误处理函数\r\n */\r\n customErrorHandler?: (error: any) => void;\r\n}\r\n\r\n/**\r\n * 缓存拦截器配置\r\n */\r\nexport interface CacheInterceptorConfig {\r\n /**\r\n * 缓存最大数量\r\n * @default 100\r\n */\r\n maxCacheSize?: number;\r\n /**\r\n * 缓存过期时间(毫秒)\r\n * @default undefined (永不过期)\r\n */\r\n cacheExpiration?: number;\r\n}\r\n\r\n/**\r\n * HTTP 请求选项扩展\r\n */\r\nexport interface HttpRequestOptions {\r\n headers?: { [name: string]: string | string[] };\r\n}\r\n\r\n/**\r\n * Token 控制类型\r\n */\r\nexport type TokenControl = 'no-token' | 'custom-token';\r\n\r\n/**\r\n * 缓存策略类型\r\n */\r\nexport type CacheStrategy = 'Storage' | 'Memory';\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS, HttpHeaders } from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\nimport { RkAuthService } from '@reskin/core/services';\r\nimport { IAuth } from '@reskin/core/entity/user';\r\n\r\n/**\r\n * Token 拦截器常量\r\n */\r\nconst DEFAULT_TOKEN_HEADER_NAME = 'Authorization';\r\nconst TOKEN_CONTROL_HEADER = 'Token-Control';\r\nconst CUSTOM_TOKEN_HEADER = 'Custom-Token';\r\nconst CUSTOM_TOKEN_HEADER_NAME = 'Custom-Token-Header';\r\nconst AUTH_ID_HEADER = 'X-Auth-Id';\r\n\r\n/**\r\n * Token 拦截器\r\n * 自动为 HTTP 请求添加认证 Token\r\n */\r\n@Injectable()\r\nexport class TokenInterceptor implements HttpInterceptor {\r\n constructor(private authService: RkAuthService) {}\r\n\r\n /**\r\n * 拦截 HTTP 请求,添加 Token 认证信息\r\n * @param request HTTP 请求对象\r\n * @param next 下一个拦截器处理器\r\n * @returns Observable<HttpEvent<unknown>>\r\n */\r\n intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\r\n const tokenControl = request.headers.get(TOKEN_CONTROL_HEADER);\r\n \r\n // 如果明确指定不需要 Token,直接放行\r\n if (tokenControl === 'no-token') {\r\n return next.handle(request);\r\n }\r\n\r\n const customToken = request.headers.get(CUSTOM_TOKEN_HEADER);\r\n const customTokenHeaderName = request.headers.get(CUSTOM_TOKEN_HEADER_NAME) || DEFAULT_TOKEN_HEADER_NAME;\r\n\r\n const headers: { [name: string]: string | string[] } = {};\r\n\r\n if (customToken) {\r\n // 使用自定义 Token\r\n headers[customTokenHeaderName] = customToken;\r\n } else {\r\n // 使用默认认证信息\r\n const auth: IAuth = this.authService.token;\r\n if (auth?.token) {\r\n headers[DEFAULT_TOKEN_HEADER_NAME] = auth.token;\r\n if (auth.id) {\r\n headers[AUTH_ID_HEADER] = auth.id;\r\n }\r\n }\r\n }\r\n\r\n // 如果有需要添加的 Header,克隆请求并添加\r\n if (Object.keys(headers).length > 0) {\r\n request = request.clone({ setHeaders: headers });\r\n }\r\n\r\n return next.handle(request);\r\n }\r\n}\r\n\r\n/**\r\n * 提供 Token 拦截器\r\n * @returns Provider 配置对象\r\n */\r\nexport function providerAuthToken() {\r\n return { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true };\r\n}\r\n\r\n/**\r\n * 创建不带 Token 的请求配置\r\n * @param urls 模板字符串数组\r\n * @param params 模板参数\r\n * @returns [url, options] 元组\r\n * @example\r\n * this.http.get(...NoAuthTokenTemplate`/api/public/data`).subscribe();\r\n */\r\nexport function NoAuthTokenTemplate(urls: TemplateStringsArray, ...params: any[]): [string, { headers: HttpHeaders }] {\r\n const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];\r\n return [url, { headers: new HttpHeaders({ [TOKEN_CONTROL_HEADER]: 'no-token' }) }];\r\n}\r\n\r\n/**\r\n * 创建使用自定义 Token 的请求配置\r\n * @param token 自定义 Token 值\r\n * @param urls 模板字符串数组\r\n * @param params 模板参数\r\n * @returns [url, options] 元组\r\n * @example\r\n * this.http.get(...CustomTokenTemplate('my-token', `/api/data`)).subscribe();\r\n */\r\nexport function CustomTokenTemplate(token: string, urls: TemplateStringsArray, ...params: any[]): [string, { headers: HttpHeaders }] {\r\n const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];\r\n return [url, { headers: new HttpHeaders({ [CUSTOM_TOKEN_HEADER]: token }) }];\r\n}\r\n\r\n/**\r\n * 创建使用自定义 Token 和自定义 Header 名称的请求配置\r\n * @param token 自定义 Token 值\r\n * @param headerName 自定义 Header 名称\r\n * @param urls 模板字符串数组\r\n * @param params 模板参数\r\n * @returns [url, options] 元组\r\n * @example\r\n * this.http.get(...CustomTokenWithHeaderTemplate('my-token', 'X-API-Key', `/api/data`)).subscribe();\r\n */\r\nexport function CustomTokenWithHeaderTemplate(\r\n token: string,\r\n headerName: string,\r\n urls: TemplateStringsArray,\r\n ...params: any[]\r\n): [string, { headers: HttpHeaders }] {\r\n const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];\r\n return [\r\n url,\r\n {\r\n headers: new HttpHeaders({\r\n [CUSTOM_TOKEN_HEADER]: token,\r\n [CUSTOM_TOKEN_HEADER_NAME]: headerName,\r\n }),\r\n },\r\n ];\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS, HttpErrorResponse } from '@angular/common/http';\r\nimport { Observable, throwError } from 'rxjs';\r\nimport { catchError } from 'rxjs/operators';\r\nimport { Router } from '@angular/router';\r\nimport { ErrorInterceptorConfig } from './types';\r\n\r\n/**\r\n * 默认配置\r\n */\r\nconst DEFAULT_CONFIG: ErrorInterceptorConfig = {\r\n unauthorizedPath: '/errors/401',\r\n enableLogging: false,\r\n};\r\n\r\n/**\r\n * HTTP 错误拦截器\r\n * 统一处理 HTTP 请求错误,包括 401 未授权错误的自动跳转\r\n */\r\n@Injectable()\r\nexport class ErrorInterceptor implements HttpInterceptor {\r\n private config: ErrorInterceptorConfig = DEFAULT_CONFIG;\r\n\r\n constructor(private router: Router) {}\r\n\r\n /**\r\n * 设置拦截器配置\r\n * @param config 配置对象\r\n */\r\n setConfig(config: ErrorInterceptorConfig): void {\r\n this.config = { ...DEFAULT_CONFIG, ...config };\r\n }\r\n\r\n /**\r\n * 拦截 HTTP 请求,处理错误响应\r\n * @param request HTTP 请求对象\r\n * @param next 下一个拦截器处理器\r\n * @returns Observable<HttpEvent<unknown>>\r\n */\r\n intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\r\n return next.handle(request).pipe(\r\n catchError((error: HttpErrorResponse) => {\r\n // 处理 401 未授权错误\r\n if (error.status === 401) {\r\n this.handleUnauthorizedError();\r\n return throwError(error);\r\n }\r\n\r\n // 记录错误日志\r\n if (this.config.enableLogging) {\r\n console.error('[HTTP Error]', {\r\n url: request.url,\r\n method: request.method,\r\n status: error.status,\r\n message: error.message,\r\n error: error.error,\r\n });\r\n }\r\n\r\n // 提取错误信息\r\n const errorMessage = this.extractErrorMessage(error);\r\n return throwError(new Error(errorMessage));\r\n }),\r\n );\r\n }\r\n\r\n /**\r\n * 处理 401 未授权错误\r\n */\r\n private handleUnauthorizedError(): void {\r\n const path = this.config.unauthorizedPath || DEFAULT_CONFIG.unauthorizedPath;\r\n this.router.navigate([path]).catch((err) => {\r\n console.error('导航到错误页面失败:', err);\r\n });\r\n }\r\n\r\n /**\r\n * 提取错误信息\r\n * @param error HTTP 错误响应\r\n * @returns 错误信息字符串\r\n */\r\n private extractErrorMessage(error: HttpErrorResponse): string {\r\n if (error.error) {\r\n // 尝试从 error.error 中提取信息\r\n if (typeof error.error === 'string') {\r\n return error.error;\r\n }\r\n if (error.error.msg) {\r\n return error.error.msg;\r\n }\r\n if (error.error.message) {\r\n return error.error.message;\r\n }\r\n }\r\n // 使用默认错误信息\r\n return error.message || `HTTP Error ${error.status}`;\r\n }\r\n}\r\n\r\n/**\r\n * 提供 HTTP 错误拦截器\r\n * @param config 可选的配置对象\r\n * @returns Provider 配置对象\r\n * @example\r\n * providers: [\r\n * providerHttpError({ unauthorizedPath: '/login', enableLogging: true })\r\n * ]\r\n */\r\nexport function providerHttpError(config?: ErrorInterceptorConfig) {\r\n if (config) {\r\n // 如果有配置,使用 useFactory\r\n return {\r\n provide: HTTP_INTERCEPTORS,\r\n useFactory: (router: Router) => {\r\n const interceptor = new ErrorInterceptor(router);\r\n interceptor.setConfig(config);\r\n return interceptor;\r\n },\r\n deps: [Router],\r\n multi: true,\r\n };\r\n } else {\r\n // 没有配置,直接使用 useClass\r\n return {\r\n provide: HTTP_INTERCEPTORS,\r\n useClass: ErrorInterceptor,\r\n multi: true,\r\n };\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS, HttpHeaders } from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\nimport { shareReplay } from 'rxjs/operators';\r\nimport { RkCacheHttpService } from '@reskin/core/services';\r\n\r\n/**\r\n * 缓存策略标识\r\n */\r\nconst CACHE_HEADER = 'Cache-Map';\r\nconst CACHE_STRATEGY = 'Storage';\r\n\r\n/**\r\n * HTTP 缓存拦截器\r\n * 为 GET 请求提供缓存功能,减少重复请求\r\n */\r\n@Injectable()\r\nexport class CacheInterceptor implements HttpInterceptor {\r\n constructor(private cacheHttpService: RkCacheHttpService) {}\r\n\r\n /**\r\n * 拦截 HTTP 请求,实现缓存逻辑\r\n * @param request HTTP 请求对象\r\n * @param next 下一个拦截器处理器\r\n * @returns Observable<HttpEvent<unknown>>\r\n */\r\n intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\r\n // 只缓存 GET 请求且明确标记了缓存策略的请求\r\n const cacheStrategy = request.headers.get(CACHE_HEADER);\r\n \r\n if (request.method === 'GET' && cacheStrategy === CACHE_STRATEGY) {\r\n // 尝试从缓存中获取响应\r\n let cachedResponse = this.cacheHttpService.get(request.url);\r\n \r\n if (!cachedResponse) {\r\n // 缓存未命中,发起请求并缓存结果\r\n cachedResponse = next.handle(request).pipe(shareReplay(1));\r\n this.cacheHttpService.set(request.url, cachedResponse);\r\n }\r\n \r\n return cachedResponse;\r\n }\r\n\r\n // 非缓存请求,直接放行\r\n return next.handle(request);\r\n }\r\n}\r\n\r\n/**\r\n * 提供 HTTP 缓存拦截器\r\n * @returns Provider 配置对象\r\n * @example\r\n * providers: [providerHttpCache()]\r\n */\r\nexport function providerHttpCache() {\r\n return { provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true };\r\n}\r\n\r\n/**\r\n * 创建带缓存标记的 GET 请求配置\r\n * @param urls 模板字符串数组\r\n * @param params 模板参数\r\n * @returns [url, options] 元组\r\n * @example\r\n * this.http.get(...CacheHttpTemplate`/api/data`).subscribe();\r\n */\r\nexport function CacheHttpTemplate(urls: TemplateStringsArray, ...params: any[]): [string, { headers: HttpHeaders }] {\r\n const url = params.length > 0 ? String.raw(urls, ...params) : urls[0];\r\n return [url, { headers: new HttpHeaders({ [CACHE_HEADER]: CACHE_STRATEGY }) }];\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport {\r\n HttpRequest,\r\n HttpHandler,\r\n HttpEvent,\r\n HttpInterceptor,\r\n HttpEventType,\r\n HttpResponse,\r\n HttpErrorResponse,\r\n HTTP_INTERCEPTORS,\r\n} from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\nimport { switchMap, catchError } from 'rxjs/operators';\r\n\r\n/**\r\n * Blob 响应拦截器\r\n * 处理文件下载请求中的 JSON 错误响应\r\n */\r\n@Injectable()\r\nexport class BlobInterceptor implements HttpInterceptor {\r\n /**\r\n * 拦截 HTTP 请求,处理 Blob 类型响应\r\n * @param request HTTP 请求对象\r\n * @param next 下一个拦截器处理器\r\n * @returns Observable<HttpEvent<T>>\r\n */\r\n intercept<T>(request: HttpRequest<T>, next: HttpHandler): Observable<HttpEvent<T>> {\r\n // 只处理 responseType 为 blob 的请求\r\n if (request.responseType !== 'blob') {\r\n return next.handle(request);\r\n }\r\n\r\n return next.handle(request).pipe(\r\n switchMap((event: HttpEvent<any>) => this.handleBlobResponse(event)),\r\n catchError((error: HttpErrorResponse) => this.handleBlobError(error)),\r\n );\r\n }\r\n\r\n /**\r\n * 处理 Blob 响应事件\r\n * @param event HTTP 事件\r\n * @returns Observable<HttpEvent<any>>\r\n */\r\n private handleBlobResponse(event: HttpEvent<any>): Observable<HttpEvent<any>> {\r\n // 只处理完整的响应事件\r\n if (event.type !== HttpEventType.Response) {\r\n return new Observable((subscriber) => {\r\n subscriber.next(event);\r\n subscriber.complete();\r\n });\r\n }\r\n\r\n // 检查响应体是否为 JSON 类型(通常表示错误)\r\n if (event instanceof HttpResponse && event.body?.type === 'application/json') {\r\n return this.convertBlobToJson(event.body);\r\n }\r\n\r\n return new Observable((subscriber) => {\r\n subscriber.next(event);\r\n subscriber.complete();\r\n });\r\n }\r\n\r\n /**\r\n * 处理 Blob 错误响应\r\n * @param error HTTP 错误响应\r\n * @returns Observable<HttpEvent<any>>\r\n */\r\n private handleBlobError(error: HttpErrorResponse): Observable<HttpEvent<any>> {\r\n // 如果错误响应体是 JSON 类型的 Blob,转换为 JSON 对象\r\n if (error.error?.type === 'application/json') {\r\n return this.convertBlobToJson(error.error);\r\n }\r\n\r\n return new Observable((subscriber) => {\r\n subscriber.error(error);\r\n subscriber.complete();\r\n });\r\n }\r\n\r\n /**\r\n * 将 Blob 转换为 JSON 对象并抛出错误\r\n * @param blob Blob 对象\r\n * @returns Observable<HttpEvent<T>>\r\n */\r\n private convertBlobToJson<T>(blob: Blob): Observable<HttpEvent<T>> {\r\n return new Observable((subscriber) => {\r\n const reader = new FileReader();\r\n \r\n reader.addEventListener('loadend', () => {\r\n try {\r\n const json: T = JSON.parse(reader.result as string);\r\n subscriber.error(json);\r\n } catch (parseError) {\r\n subscriber.error(parseError);\r\n } finally {\r\n subscriber.complete();\r\n }\r\n });\r\n\r\n reader.addEventListener('error', () => {\r\n subscriber.error(new Error('读取 Blob 数据失败'));\r\n subscriber.complete();\r\n });\r\n\r\n reader.readAsText(blob, 'utf-8');\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * 提供 Blob 响应拦截器\r\n * @returns Provider 配置对象\r\n * @example\r\n * providers: [providerDownBlob()]\r\n */\r\nexport function providerDownBlob() {\r\n return { provide: HTTP_INTERCEPTORS, useClass: BlobInterceptor, multi: true };\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1"],"mappings":";;;;;;;;;AAAA;;AAEG;;ACIH;;AAEG;AACH,MAAM,yBAAyB,GAAG,eAAe,CAAC;AAClD,MAAM,oBAAoB,GAAG,eAAe,CAAC;AAC7C,MAAM,mBAAmB,GAAG,cAAc,CAAC;AAC3C,MAAM,wBAAwB,GAAG,qBAAqB,CAAC;AACvD,MAAM,cAAc,GAAG,WAAW,CAAC;AAEnC;;;AAGG;MAEU,gBAAgB,CAAA;AACzB,IAAA,WAAA,CAAoB,WAA0B,EAAA;QAA1B,IAAW,CAAA,WAAA,GAAX,WAAW,CAAe;KAAI;AAElD;;;;;AAKG;IACH,SAAS,CAAC,OAA6B,EAAE,IAAiB,EAAA;QACtD,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;;QAG/D,IAAI,YAAY,KAAK,UAAU,EAAE;AAC7B,YAAA,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAC/B,SAAA;QAED,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;AAC7D,QAAA,MAAM,qBAAqB,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,yBAAyB,CAAC;QAEzG,MAAM,OAAO,GAA0C,EAAE,CAAC;AAE1D,QAAA,IAAI,WAAW,EAAE;;AAEb,YAAA,OAAO,CAAC,qBAAqB,CAAC,GAAG,WAAW,CAAC;AAChD,SAAA;AAAM,aAAA;;AAEH,YAAA,MAAM,IAAI,GAAU,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;AAC3C,YAAA,IAAI,IAAI,KAAJ,IAAA,IAAA,IAAI,uBAAJ,IAAI,CAAE,KAAK,EAAE;AACb,gBAAA,OAAO,CAAC,yBAAyB,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;gBAChD,IAAI,IAAI,CAAC,EAAE,EAAE;AACT,oBAAA,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;AACrC,iBAAA;AACJ,aAAA;AACJ,SAAA;;QAGD,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;YACjC,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;AACpD,SAAA;AAED,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;KAC/B;;8GA1CQ,gBAAgB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,aAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;kHAAhB,gBAAgB,EAAA,CAAA,CAAA;4FAAhB,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAD5B,UAAU;;AA8CX;;;AAGG;SACa,iBAAiB,GAAA;AAC7B,IAAA,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACnF,CAAC;AAED;;;;;;;AAOG;SACa,mBAAmB,CAAC,IAA0B,EAAE,GAAG,MAAa,EAAA;IAC5E,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AACtE,IAAA,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC,oBAAoB,GAAG,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;AACvF,CAAC;AAED;;;;;;;;AAQG;AACG,SAAU,mBAAmB,CAAC,KAAa,EAAE,IAA0B,EAAE,GAAG,MAAa,EAAA;IAC3F,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AACtE,IAAA,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC,mBAAmB,GAAG,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AACjF,CAAC;AAED;;;;;;;;;AASG;AACG,SAAU,6BAA6B,CACzC,KAAa,EACb,UAAkB,EAClB,IAA0B,EAC1B,GAAG,MAAa,EAAA;IAEhB,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtE,OAAO;QACH,GAAG;AACH,QAAA;YACI,OAAO,EAAE,IAAI,WAAW,CAAC;gBACrB,CAAC,mBAAmB,GAAG,KAAK;gBAC5B,CAAC,wBAAwB,GAAG,UAAU;aACzC,CAAC;AACL,SAAA;KACJ,CAAC;AACN;;ACvHA;;AAEG;AACH,MAAM,cAAc,GAA2B;AAC3C,IAAA,gBAAgB,EAAE,aAAa;AAC/B,IAAA,aAAa,EAAE,KAAK;CACvB,CAAC;AAEF;;;AAGG;MAEU,gBAAgB,CAAA;AAGzB,IAAA,WAAA,CAAoB,MAAc,EAAA;QAAd,IAAM,CAAA,MAAA,GAAN,MAAM,CAAQ;QAF1B,IAAM,CAAA,MAAA,GAA2B,cAAc,CAAC;KAElB;AAEtC;;;AAGG;AACH,IAAA,SAAS,CAAC,MAA8B,EAAA;AACpC,QAAA,IAAI,CAAC,MAAM,GAAA,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,EAAA,EAAQ,cAAc,CAAK,EAAA,MAAM,CAAE,CAAC;KAClD;AAED;;;;;AAKG;IACH,SAAS,CAAC,OAA6B,EAAE,IAAiB,EAAA;AACtD,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAC5B,UAAU,CAAC,CAAC,KAAwB,KAAI;;AAEpC,YAAA,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE;gBACtB,IAAI,CAAC,uBAAuB,EAAE,CAAC;AAC/B,gBAAA,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;AAC5B,aAAA;;AAGD,YAAA,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE;AAC3B,gBAAA,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE;oBAC1B,GAAG,EAAE,OAAO,CAAC,GAAG;oBAChB,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,KAAK,EAAE,KAAK,CAAC,KAAK;AACrB,iBAAA,CAAC,CAAC;AACN,aAAA;;YAGD,MAAM,YAAY,GAAG,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;YACrD,OAAO,UAAU,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;SAC9C,CAAC,CACL,CAAC;KACL;AAED;;AAEG;IACK,uBAAuB,GAAA;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,IAAI,cAAc,CAAC,gBAAgB,CAAC;AAC7E,QAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAI;AACvC,YAAA,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;AACrC,SAAC,CAAC,CAAC;KACN;AAED;;;;AAIG;AACK,IAAA,mBAAmB,CAAC,KAAwB,EAAA;QAChD,IAAI,KAAK,CAAC,KAAK,EAAE;;AAEb,YAAA,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE;gBACjC,OAAO,KAAK,CAAC,KAAK,CAAC;AACtB,aAAA;AACD,YAAA,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE;AACjB,gBAAA,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;AAC1B,aAAA;AACD,YAAA,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE;AACrB,gBAAA,OAAO,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;AAC9B,aAAA;AACJ,SAAA;;QAED,OAAO,KAAK,CAAC,OAAO,IAAI,cAAc,KAAK,CAAC,MAAM,CAAA,CAAE,CAAC;KACxD;;8GA5EQ,gBAAgB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAAA,IAAA,CAAA,MAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;kHAAhB,gBAAgB,EAAA,CAAA,CAAA;4FAAhB,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAD5B,UAAU;;AAgFX;;;;;;;;AAQG;AACG,SAAU,iBAAiB,CAAC,MAA+B,EAAA;AAC7D,IAAA,IAAI,MAAM,EAAE;;QAER,OAAO;AACH,YAAA,OAAO,EAAE,iBAAiB;AAC1B,YAAA,UAAU,EAAE,CAAC,MAAc,KAAI;AAC3B,gBAAA,MAAM,WAAW,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACjD,gBAAA,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AAC9B,gBAAA,OAAO,WAAW,CAAC;aACtB;YACD,IAAI,EAAE,CAAC,MAAM,CAAC;AACd,YAAA,KAAK,EAAE,IAAI;SACd,CAAC;AACL,KAAA;AAAM,SAAA;;QAEH,OAAO;AACH,YAAA,OAAO,EAAE,iBAAiB;AAC1B,YAAA,QAAQ,EAAE,gBAAgB;AAC1B,YAAA,KAAK,EAAE,IAAI;SACd,CAAC;AACL,KAAA;AACL;;AC3HA;;AAEG;AACH,MAAM,YAAY,GAAG,WAAW,CAAC;AACjC,MAAM,cAAc,GAAG,SAAS,CAAC;AAEjC;;;AAGG;MAEU,gBAAgB,CAAA;AACzB,IAAA,WAAA,CAAoB,gBAAoC,EAAA;QAApC,IAAgB,CAAA,gBAAA,GAAhB,gBAAgB,CAAoB;KAAI;AAE5D;;;;;AAKG;IACH,SAAS,CAAC,OAA6B,EAAE,IAAiB,EAAA;;QAEtD,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAExD,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,aAAa,KAAK,cAAc,EAAE;;AAE9D,YAAA,IAAI,cAAc,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAE5D,IAAI,CAAC,cAAc,EAAE;;AAEjB,gBAAA,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC3D,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;AAC1D,aAAA;AAED,YAAA,OAAO,cAAc,CAAC;AACzB,SAAA;;AAGD,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;KAC/B;;8GA5BQ,gBAAgB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;kHAAhB,gBAAgB,EAAA,CAAA,CAAA;4FAAhB,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAD5B,UAAU;;AAgCX;;;;;AAKG;SACa,iBAAiB,GAAA;AAC7B,IAAA,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACnF,CAAC;AAED;;;;;;;AAOG;SACa,iBAAiB,CAAC,IAA0B,EAAE,GAAG,MAAa,EAAA;IAC1E,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AACtE,IAAA,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC,YAAY,GAAG,cAAc,EAAE,CAAC,EAAE,CAAC,CAAC;AACnF;;ACvDA;;;AAGG;MAEU,eAAe,CAAA;AACxB;;;;;AAKG;IACH,SAAS,CAAI,OAAuB,EAAE,IAAiB,EAAA;;AAEnD,QAAA,IAAI,OAAO,CAAC,YAAY,KAAK,MAAM,EAAE;AACjC,YAAA,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAC/B,SAAA;AAED,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAC5B,SAAS,CAAC,CAAC,KAAqB,KAAK,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,EACpE,UAAU,CAAC,CAAC,KAAwB,KAAK,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CACxE,CAAC;KACL;AAED;;;;AAIG;AACK,IAAA,kBAAkB,CAAC,KAAqB,EAAA;;;AAE5C,QAAA,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC,QAAQ,EAAE;AACvC,YAAA,OAAO,IAAI,UAAU,CAAC,CAAC,UAAU,KAAI;AACjC,gBAAA,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACvB,UAAU,CAAC,QAAQ,EAAE,CAAC;AAC1B,aAAC,CAAC,CAAC;AACN,SAAA;;AAGD,QAAA,IAAI,KAAK,YAAY,YAAY,IAAI,CAAA,CAAA,EAAA,GAAA,KAAK,CAAC,IAAI,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAE,IAAI,MAAK,kBAAkB,EAAE;YAC1E,OAAO,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC7C,SAAA;AAED,QAAA,OAAO,IAAI,UAAU,CAAC,CAAC,UAAU,KAAI;AACjC,YAAA,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvB,UAAU,CAAC,QAAQ,EAAE,CAAC;AAC1B,SAAC,CAAC,CAAC;KACN;AAED;;;;AAIG;AACK,IAAA,eAAe,CAAC,KAAwB,EAAA;;;QAE5C,IAAI,CAAA,MAAA,KAAK,CAAC,KAAK,MAAE,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,IAAI,MAAK,kBAAkB,EAAE;YAC1C,OAAO,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC9C,SAAA;AAED,QAAA,OAAO,IAAI,UAAU,CAAC,CAAC,UAAU,KAAI;AACjC,YAAA,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACxB,UAAU,CAAC,QAAQ,EAAE,CAAC;AAC1B,SAAC,CAAC,CAAC;KACN;AAED;;;;AAIG;AACK,IAAA,iBAAiB,CAAI,IAAU,EAAA;AACnC,QAAA,OAAO,IAAI,UAAU,CAAC,CAAC,UAAU,KAAI;AACjC,YAAA,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;AAEhC,YAAA,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAK;gBACpC,IAAI;oBACA,MAAM,IAAI,GAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAgB,CAAC,CAAC;AACpD,oBAAA,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC1B,iBAAA;AAAC,gBAAA,OAAO,UAAU,EAAE;AACjB,oBAAA,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;AAChC,iBAAA;AAAS,wBAAA;oBACN,UAAU,CAAC,QAAQ,EAAE,CAAC;AACzB,iBAAA;AACL,aAAC,CAAC,CAAC;AAEH,YAAA,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAK;gBAClC,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;gBAC5C,UAAU,CAAC,QAAQ,EAAE,CAAC;AAC1B,aAAC,CAAC,CAAC;AAEH,YAAA,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACrC,SAAC,CAAC,CAAC;KACN;;6GAxFQ,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;iHAAf,eAAe,EAAA,CAAA,CAAA;4FAAf,eAAe,EAAA,UAAA,EAAA,CAAA;kBAD3B,UAAU;;AA4FX;;;;;AAKG;SACa,gBAAgB,GAAA;AAC5B,IAAA,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAClF;;ACtHA;;AAEG;;;;"}