yingzios-platform-backend-shared 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/README.md +51 -0
  2. package/dist/apollo/apollo.config.d.ts +26 -0
  3. package/dist/apollo/apollo.config.d.ts.map +1 -0
  4. package/dist/apollo/apollo.config.js +2 -0
  5. package/dist/apollo/apollo.module.d.ts +13 -0
  6. package/dist/apollo/apollo.module.d.ts.map +1 -0
  7. package/dist/apollo/apollo.module.js +61 -0
  8. package/dist/apollo/apollo.service.d.ts +17 -0
  9. package/dist/apollo/apollo.service.d.ts.map +1 -0
  10. package/dist/apollo/apollo.service.js +35 -0
  11. package/dist/apollo/index.d.ts +5 -0
  12. package/dist/apollo/index.d.ts.map +1 -0
  13. package/dist/apollo/index.js +17 -0
  14. package/dist/cache/cache.config.d.ts +28 -0
  15. package/dist/cache/cache.config.d.ts.map +1 -0
  16. package/dist/cache/cache.config.js +2 -0
  17. package/dist/cache/cache.module.d.ts +39 -0
  18. package/dist/cache/cache.module.d.ts.map +1 -0
  19. package/dist/cache/cache.module.js +75 -0
  20. package/dist/cache/cache.service.d.ts +49 -0
  21. package/dist/cache/cache.service.d.ts.map +1 -0
  22. package/dist/cache/cache.service.js +208 -0
  23. package/dist/cache/index.d.ts +4 -0
  24. package/dist/cache/index.d.ts.map +1 -0
  25. package/dist/cache/index.js +19 -0
  26. package/dist/env/env-loader.d.ts +50 -0
  27. package/dist/env/env-loader.d.ts.map +1 -0
  28. package/dist/env/env-loader.js +159 -0
  29. package/dist/env/env.module.d.ts +11 -0
  30. package/dist/env/env.module.d.ts.map +1 -0
  31. package/dist/env/env.module.js +47 -0
  32. package/dist/env/env.service.d.ts +31 -0
  33. package/dist/env/env.service.d.ts.map +1 -0
  34. package/dist/env/env.service.js +195 -0
  35. package/dist/env/index.d.ts +4 -0
  36. package/dist/env/index.d.ts.map +1 -0
  37. package/dist/env/index.js +19 -0
  38. package/dist/index.d.ts +12 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +27 -0
  41. package/dist/internal-auth/decorators/caller.decorator.d.ts +29 -0
  42. package/dist/internal-auth/decorators/caller.decorator.d.ts.map +1 -0
  43. package/dist/internal-auth/decorators/caller.decorator.js +37 -0
  44. package/dist/internal-auth/decorators/index.d.ts +3 -0
  45. package/dist/internal-auth/decorators/index.d.ts.map +1 -0
  46. package/dist/internal-auth/decorators/index.js +18 -0
  47. package/dist/internal-auth/decorators/use-either-guard.decorator.d.ts +31 -0
  48. package/dist/internal-auth/decorators/use-either-guard.decorator.d.ts.map +1 -0
  49. package/dist/internal-auth/decorators/use-either-guard.decorator.js +79 -0
  50. package/dist/internal-auth/guards/index.d.ts +2 -0
  51. package/dist/internal-auth/guards/index.d.ts.map +1 -0
  52. package/dist/internal-auth/guards/index.js +17 -0
  53. package/dist/internal-auth/guards/service-key.guard.d.ts +36 -0
  54. package/dist/internal-auth/guards/service-key.guard.d.ts.map +1 -0
  55. package/dist/internal-auth/guards/service-key.guard.js +86 -0
  56. package/dist/internal-auth/index.d.ts +43 -0
  57. package/dist/internal-auth/index.d.ts.map +1 -0
  58. package/dist/internal-auth/index.js +62 -0
  59. package/dist/internal-auth/internal-auth.module.d.ts +62 -0
  60. package/dist/internal-auth/internal-auth.module.d.ts.map +1 -0
  61. package/dist/internal-auth/internal-auth.module.js +118 -0
  62. package/dist/internal-auth/internal-http.service.d.ts +72 -0
  63. package/dist/internal-auth/internal-http.service.d.ts.map +1 -0
  64. package/dist/internal-auth/internal-http.service.js +119 -0
  65. package/dist/jwt/auto-fill-user.pipe.d.ts +43 -0
  66. package/dist/jwt/auto-fill-user.pipe.d.ts.map +1 -0
  67. package/dist/jwt/auto-fill-user.pipe.js +166 -0
  68. package/dist/jwt/decorators/current-user.decorator.d.ts +37 -0
  69. package/dist/jwt/decorators/current-user.decorator.d.ts.map +1 -0
  70. package/dist/jwt/decorators/current-user.decorator.js +29 -0
  71. package/dist/jwt/decorators/public.decorator.d.ts +8 -0
  72. package/dist/jwt/decorators/public.decorator.d.ts.map +1 -0
  73. package/dist/jwt/decorators/public.decorator.js +12 -0
  74. package/dist/jwt/guards/jwt-auth.guard.d.ts +20 -0
  75. package/dist/jwt/guards/jwt-auth.guard.d.ts.map +1 -0
  76. package/dist/jwt/guards/jwt-auth.guard.js +88 -0
  77. package/dist/jwt/index.d.ts +8 -0
  78. package/dist/jwt/index.d.ts.map +1 -0
  79. package/dist/jwt/index.js +26 -0
  80. package/dist/jwt/jwt-config.service.d.ts +10 -0
  81. package/dist/jwt/jwt-config.service.d.ts.map +1 -0
  82. package/dist/jwt/jwt-config.service.js +40 -0
  83. package/dist/jwt/jwt.config.d.ts +15 -0
  84. package/dist/jwt/jwt.config.d.ts.map +1 -0
  85. package/dist/jwt/jwt.config.js +2 -0
  86. package/dist/jwt/jwt.module.d.ts +19 -0
  87. package/dist/jwt/jwt.module.d.ts.map +1 -0
  88. package/dist/jwt/jwt.module.js +100 -0
  89. package/dist/jwt/jwt.service.d.ts +31 -0
  90. package/dist/jwt/jwt.service.d.ts.map +1 -0
  91. package/dist/jwt/jwt.service.js +71 -0
  92. package/dist/jwt/strategies/jwt.strategy.d.ts +25 -0
  93. package/dist/jwt/strategies/jwt.strategy.d.ts.map +1 -0
  94. package/dist/jwt/strategies/jwt.strategy.js +150 -0
  95. package/dist/jwt/user-aware-axios.service.d.ts +17 -0
  96. package/dist/jwt/user-aware-axios.service.d.ts.map +1 -0
  97. package/dist/jwt/user-aware-axios.service.js +105 -0
  98. package/dist/jwt/utils/jwt.utils.d.ts +24 -0
  99. package/dist/jwt/utils/jwt.utils.d.ts.map +1 -0
  100. package/dist/jwt/utils/jwt.utils.js +40 -0
  101. package/dist/logger/index.d.ts +4 -0
  102. package/dist/logger/index.d.ts.map +1 -0
  103. package/dist/logger/index.js +19 -0
  104. package/dist/logger/logger.config.d.ts +41 -0
  105. package/dist/logger/logger.config.d.ts.map +1 -0
  106. package/dist/logger/logger.config.js +13 -0
  107. package/dist/logger/logger.module.d.ts +17 -0
  108. package/dist/logger/logger.module.d.ts.map +1 -0
  109. package/dist/logger/logger.module.js +49 -0
  110. package/dist/logger/logger.service.d.ts +62 -0
  111. package/dist/logger/logger.service.d.ts.map +1 -0
  112. package/dist/logger/logger.service.js +124 -0
  113. package/dist/logger/winston.config.d.ts +43 -0
  114. package/dist/logger/winston.config.d.ts.map +1 -0
  115. package/dist/logger/winston.config.js +183 -0
  116. package/dist/nacos/index.d.ts +4 -0
  117. package/dist/nacos/index.d.ts.map +1 -0
  118. package/dist/nacos/index.js +19 -0
  119. package/dist/nacos/nacos.config.d.ts +10 -0
  120. package/dist/nacos/nacos.config.d.ts.map +1 -0
  121. package/dist/nacos/nacos.config.js +2 -0
  122. package/dist/nacos/nacos.module.d.ts +9 -0
  123. package/dist/nacos/nacos.module.d.ts.map +1 -0
  124. package/dist/nacos/nacos.module.js +42 -0
  125. package/dist/nacos/nacos.service.d.ts +43 -0
  126. package/dist/nacos/nacos.service.d.ts.map +1 -0
  127. package/dist/nacos/nacos.service.js +212 -0
  128. package/dist/nacos/utils.d.ts +10 -0
  129. package/dist/nacos/utils.d.ts.map +1 -0
  130. package/dist/nacos/utils.js +65 -0
  131. package/dist/restful/current-request.util.d.ts +16 -0
  132. package/dist/restful/current-request.util.d.ts.map +1 -0
  133. package/dist/restful/current-request.util.js +34 -0
  134. package/dist/restful/http-exception.filter.d.ts +24 -0
  135. package/dist/restful/http-exception.filter.d.ts.map +1 -0
  136. package/dist/restful/http-exception.filter.js +126 -0
  137. package/dist/restful/index.d.ts +8 -0
  138. package/dist/restful/index.d.ts.map +1 -0
  139. package/dist/restful/index.js +23 -0
  140. package/dist/restful/request-context.middleware.d.ts +6 -0
  141. package/dist/restful/request-context.middleware.d.ts.map +1 -0
  142. package/dist/restful/request-context.middleware.js +25 -0
  143. package/dist/restful/response-codes.d.ts +104 -0
  144. package/dist/restful/response-codes.d.ts.map +1 -0
  145. package/dist/restful/response-codes.js +163 -0
  146. package/dist/restful/response.dto.d.ts +52 -0
  147. package/dist/restful/response.dto.d.ts.map +1 -0
  148. package/dist/restful/response.dto.js +146 -0
  149. package/dist/restful/response.interceptor.d.ts +17 -0
  150. package/dist/restful/response.interceptor.d.ts.map +1 -0
  151. package/dist/restful/response.interceptor.js +86 -0
  152. package/dist/restful/restful.module.d.ts +5 -0
  153. package/dist/restful/restful.module.d.ts.map +1 -0
  154. package/dist/restful/restful.module.js +26 -0
  155. package/dist/sequelize/index.d.ts +4 -0
  156. package/dist/sequelize/index.d.ts.map +1 -0
  157. package/dist/sequelize/index.js +19 -0
  158. package/dist/sequelize/sequelize.config.d.ts +24 -0
  159. package/dist/sequelize/sequelize.config.d.ts.map +1 -0
  160. package/dist/sequelize/sequelize.config.js +5 -0
  161. package/dist/sequelize/sequelize.module.d.ts +28 -0
  162. package/dist/sequelize/sequelize.module.d.ts.map +1 -0
  163. package/dist/sequelize/sequelize.module.js +50 -0
  164. package/dist/sequelize/sequelize.provider.d.ts +7 -0
  165. package/dist/sequelize/sequelize.provider.d.ts.map +1 -0
  166. package/dist/sequelize/sequelize.provider.js +154 -0
  167. package/dist/snowflake/index.d.ts +4 -0
  168. package/dist/snowflake/index.d.ts.map +1 -0
  169. package/dist/snowflake/index.js +19 -0
  170. package/dist/snowflake/snowflake.config.d.ts +30 -0
  171. package/dist/snowflake/snowflake.config.d.ts.map +1 -0
  172. package/dist/snowflake/snowflake.config.js +12 -0
  173. package/dist/snowflake/snowflake.module.d.ts +17 -0
  174. package/dist/snowflake/snowflake.module.d.ts.map +1 -0
  175. package/dist/snowflake/snowflake.module.js +58 -0
  176. package/dist/snowflake/snowflake.service.d.ts +21 -0
  177. package/dist/snowflake/snowflake.service.d.ts.map +1 -0
  178. package/dist/snowflake/snowflake.service.js +44 -0
  179. package/dist/swagger/index.d.ts +6 -0
  180. package/dist/swagger/index.d.ts.map +1 -0
  181. package/dist/swagger/index.js +19 -0
  182. package/dist/swagger/swagger.config.d.ts +45 -0
  183. package/dist/swagger/swagger.config.d.ts.map +1 -0
  184. package/dist/swagger/swagger.config.js +19 -0
  185. package/dist/swagger/swagger.decorators.d.ts +21 -0
  186. package/dist/swagger/swagger.decorators.d.ts.map +1 -0
  187. package/dist/swagger/swagger.decorators.js +112 -0
  188. package/dist/swagger/swagger.module.d.ts +15 -0
  189. package/dist/swagger/swagger.module.d.ts.map +1 -0
  190. package/dist/swagger/swagger.module.js +49 -0
  191. package/dist/swagger/swagger.service.d.ts +44 -0
  192. package/dist/swagger/swagger.service.d.ts.map +1 -0
  193. package/dist/swagger/swagger.service.js +202 -0
  194. package/package.json +75 -0
@@ -0,0 +1,9 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { INacosConfig } from './nacos.config';
3
+ export declare class NacosModule {
4
+ static forRootAsync(options: {
5
+ useFactory: (...args: any[]) => Promise<INacosConfig> | INacosConfig;
6
+ inject?: any[];
7
+ }): DynamicModule;
8
+ }
9
+ //# sourceMappingURL=nacos.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nacos.module.d.ts","sourceRoot":"","sources":["../../src/nacos/nacos.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAkB,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAI9C,qBAEa,WAAW;IACtB,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE;QAC3B,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;QACrE,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;KAChB,GAAG,aAAa;CAwBlB"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var NacosModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.NacosModule = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const nacos_service_1 = require("./nacos.service");
13
+ const lodash_1 = require("lodash");
14
+ let NacosModule = NacosModule_1 = class NacosModule {
15
+ static forRootAsync(options) {
16
+ return {
17
+ module: NacosModule_1,
18
+ providers: [
19
+ {
20
+ provide: 'NACOS_CONFIG',
21
+ useFactory: async (...args) => {
22
+ const config = await options.useFactory(...args);
23
+ config.currentServicePort = (0, lodash_1.toNumber)(config.currentServicePort || 8080);
24
+ return config;
25
+ },
26
+ inject: options.inject || [],
27
+ },
28
+ nacos_service_1.NacosService,
29
+ {
30
+ provide: 'NACOS_SERVICE',
31
+ useExisting: nacos_service_1.NacosService,
32
+ },
33
+ ],
34
+ exports: [nacos_service_1.NacosService, 'NACOS_SERVICE'],
35
+ };
36
+ }
37
+ };
38
+ exports.NacosModule = NacosModule;
39
+ exports.NacosModule = NacosModule = NacosModule_1 = __decorate([
40
+ (0, common_1.Global)(),
41
+ (0, common_1.Module)({})
42
+ ], NacosModule);
@@ -0,0 +1,43 @@
1
+ import { OnModuleDestroy, OnModuleInit } from '@nestjs/common';
2
+ import { Host } from 'nacos';
3
+ import type { INacosConfig } from './nacos.config';
4
+ import type { CustomLogger } from '../logger';
5
+ export declare class NacosService implements OnModuleInit, OnModuleDestroy {
6
+ protected readonly config: INacosConfig;
7
+ protected logger: CustomLogger;
8
+ private client;
9
+ private services;
10
+ private registeredInstances;
11
+ private localIP;
12
+ constructor(config: INacosConfig, logger: CustomLogger);
13
+ onModuleInit(): Promise<void>;
14
+ onModuleDestroy(): Promise<void>;
15
+ /**
16
+ * 自动注册当前服务到Nacos
17
+ */
18
+ private registerCurrentService;
19
+ /**
20
+ * 获取一个服务实例(默认使用加权随机)
21
+ * @param serviceName 服务名称
22
+ * @param strategy 负载均衡策略
23
+ * @returns 服务实例 URL,格式:http://ip:port,如果没有可用实例返回 null
24
+ */
25
+ getInstance(serviceName: string, strategy?: 'weightedRandom' | 'roundRobin'): string | null;
26
+ /**
27
+ * 将当前服务注册到Nacos
28
+ * @param serviceName 服务名称
29
+ * @param instance 服务实例信息
30
+ */
31
+ registerInstance(serviceName: string, instance: Host): Promise<void>;
32
+ /**
33
+ * 获取所有服务实例
34
+ */
35
+ getAllInstances(): Map<string, Host[]>;
36
+ /**
37
+ * 获取指定服务的所有实例列表
38
+ * @param serviceName 服务名称
39
+ * @returns 实例列表
40
+ */
41
+ getInstances(serviceName: string): Host[];
42
+ }
43
+ //# sourceMappingURL=nacos.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nacos.service.d.ts","sourceRoot":"","sources":["../../src/nacos/nacos.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,eAAe,EACf,YAAY,EACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAqB,IAAI,EAAE,MAAM,OAAO,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,qBACa,YAAa,YAAW,YAAY,EAAE,eAAe;IAW9D,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,YAAY;IAEvC,SAAS,CAAC,MAAM,EAAE,YAAY;IAZhC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,mBAAmB,CAGnB;IACR,OAAO,CAAC,OAAO,CAAS;gBAIH,MAAM,EAAE,YAAY,EAE7B,MAAM,EAAE,YAAY;IAgF1B,YAAY;IAeZ,eAAe;IAiBrB;;OAEG;YACW,sBAAsB;IA4BpC;;;;;OAKG;IACH,WAAW,CACT,WAAW,EAAE,MAAM,EACnB,QAAQ,GAAE,gBAAgB,GAAG,YAA+B,GAC3D,MAAM,GAAG,IAAI;IAuBhB;;;;OAIG;IACG,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ1E;;OAEG;IACH,eAAe,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;IAItC;;;;OAIG;IACH,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,EAAE;CAG1C"}
@@ -0,0 +1,212 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.NacosService = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const nacos_1 = require("nacos");
18
+ const lodash_1 = require("lodash");
19
+ const utils_1 = require("./utils");
20
+ let NacosService = class NacosService {
21
+ config;
22
+ logger;
23
+ client;
24
+ services = new Map();
25
+ registeredInstances = [];
26
+ localIP;
27
+ constructor(config, logger) {
28
+ this.config = config;
29
+ this.logger = logger;
30
+ // 获取本机IP地址
31
+ this.localIP = (0, utils_1.getLocalIP)();
32
+ // 创建自定义日志记录器
33
+ const customLogger = {
34
+ info: (...args) => {
35
+ // 只有在info及以上级别时才输出Nacos的info日志
36
+ const logLevel = process.env.LOGGER_LEVEL || 'info';
37
+ if (['info', 'debug'].includes(logLevel)) {
38
+ this.logger.log?.(args.join(' '), 'NacosClient');
39
+ }
40
+ },
41
+ debug: (...args) => {
42
+ // 只有在debug级别时才输出Nacos的debug日志
43
+ if (process.env.LOGGER_LEVEL === 'debug') {
44
+ this.logger.debug?.(args.join(' '), 'NacosClient');
45
+ }
46
+ },
47
+ warn: (...args) => {
48
+ // warn及以上级别总是输出
49
+ this.logger.warn?.(args.join(' '), 'NacosClient');
50
+ },
51
+ error: (...args) => {
52
+ // error级别总是输出
53
+ this.logger.error?.(args.join(' '), 'NacosClient');
54
+ },
55
+ trace: () => { },
56
+ assert: () => { },
57
+ clear: () => { },
58
+ count: () => { },
59
+ countReset: () => { },
60
+ dir: () => { },
61
+ dirxml: () => { },
62
+ group: () => { },
63
+ groupCollapsed: () => { },
64
+ groupEnd: () => { },
65
+ table: () => { },
66
+ time: () => { },
67
+ timeEnd: () => { },
68
+ timeLog: () => { },
69
+ profile: () => { },
70
+ profileEnd: () => { },
71
+ timeStamp: () => { },
72
+ log: (...args) => {
73
+ // 只有在info及以上级别时才输出Nacos的log日志
74
+ const logLevel = process.env.LOGGER_LEVEL || 'info';
75
+ if (['info', 'debug'].includes(logLevel)) {
76
+ this.logger.log?.(args.join(' '), 'NacosClient');
77
+ }
78
+ },
79
+ };
80
+ this.client = new nacos_1.NacosNamingClient({
81
+ logger: customLogger,
82
+ serverList: config.serverAddr,
83
+ namespace: config.namespace,
84
+ username: config.username,
85
+ password: config.password,
86
+ });
87
+ if ((0, lodash_1.isArray)(config.serviceNames) && config.serviceNames.length) {
88
+ for (const serviceName of config.serviceNames) {
89
+ this.client.subscribe(serviceName, (hosts) => {
90
+ // 转换格式
91
+ const instances = hosts;
92
+ // 缓存实例列表
93
+ this.services.set(serviceName, instances);
94
+ // 将频繁更新的日志改为debug级别
95
+ logger.log(`[${serviceName}] 实例列表更新: ${instances.map((i) => i.ip.toString() + ':' + i.port.toString()).join(', ')}`);
96
+ });
97
+ }
98
+ }
99
+ }
100
+ async onModuleInit() {
101
+ try {
102
+ await this.client.ready();
103
+ this.logger.forceLog('Nacos 客户端已就绪');
104
+ // 自动注册当前服务(如果配置了 currentServiceName)
105
+ if (this.config.currentServiceName) {
106
+ await this.registerCurrentService();
107
+ }
108
+ }
109
+ catch (error) {
110
+ this.logger.error('Nacos 客户端初始化失败', error);
111
+ // 不阻断应用启动,继续运行(降级模式)
112
+ }
113
+ }
114
+ async onModuleDestroy() {
115
+ // 应用关闭时注销所有已注册的服务实例
116
+ for (const { serviceName, instance } of this.registeredInstances) {
117
+ try {
118
+ await this.client.deregisterInstance(serviceName, instance);
119
+ this.logger.forceLog(`成功注销服务实例: ${instance.ip}:${instance.port}`);
120
+ }
121
+ catch (error) {
122
+ this.logger.forceLog(`注销服务实例失败: ${instance.ip}:${instance.port}`, error);
123
+ }
124
+ }
125
+ }
126
+ /**
127
+ * 自动注册当前服务到Nacos
128
+ */
129
+ async registerCurrentService() {
130
+ // 从配置获取服务注册信息
131
+ const serviceName = this.config.currentServiceName;
132
+ const port = this.config.currentServicePort;
133
+ if (!serviceName || !port) {
134
+ this.logger.warn('未配置 currentServiceName 或 currentServicePort,跳过服务注册');
135
+ return;
136
+ }
137
+ // 注册服务到Nacos
138
+ const instance = {
139
+ ip: this.localIP,
140
+ port: port,
141
+ weight: 1.0,
142
+ ephemeral: true,
143
+ clusterName: 'DEFAULT',
144
+ };
145
+ try {
146
+ await this.registerInstance(serviceName, instance);
147
+ this.logger.forceLog(`Nacos服务注册成功: ${serviceName} @ ${this.localIP}:${port}`);
148
+ }
149
+ catch (error) {
150
+ this.logger.error(`Nacos服务注册失败: ${serviceName} @ ${this.localIP}:${port}`, error);
151
+ // 不抛出异常,允许应用继续运行
152
+ }
153
+ }
154
+ /**
155
+ * 获取一个服务实例(默认使用加权随机)
156
+ * @param serviceName 服务名称
157
+ * @param strategy 负载均衡策略
158
+ * @returns 服务实例 URL,格式:http://ip:port,如果没有可用实例返回 null
159
+ */
160
+ getInstance(serviceName, strategy = 'weightedRandom') {
161
+ const instances = this.services.get(serviceName);
162
+ if (!instances || !instances.length) {
163
+ this.logger.warn?.(`服务 ${serviceName} 暂无可用实例`);
164
+ return null;
165
+ }
166
+ let instance = null;
167
+ switch (strategy) {
168
+ case 'roundRobin':
169
+ instance = utils_1.LoadBalancer.roundRobin(instances, serviceName);
170
+ break;
171
+ case 'weightedRandom':
172
+ default:
173
+ instance = utils_1.LoadBalancer.weightedRandom(instances);
174
+ break;
175
+ }
176
+ if (!instance)
177
+ return null;
178
+ return `http://${instance.ip}:${instance.port}`;
179
+ }
180
+ /**
181
+ * 将当前服务注册到Nacos
182
+ * @param serviceName 服务名称
183
+ * @param instance 服务实例信息
184
+ */
185
+ async registerInstance(serviceName, instance) {
186
+ // 注册服务实例到Nacos
187
+ await this.client.registerInstance(serviceName, instance);
188
+ // 缓存已注册的实例,以便在应用关闭时注销
189
+ this.registeredInstances.push({ serviceName, instance });
190
+ }
191
+ /**
192
+ * 获取所有服务实例
193
+ */
194
+ getAllInstances() {
195
+ return this.services;
196
+ }
197
+ /**
198
+ * 获取指定服务的所有实例列表
199
+ * @param serviceName 服务名称
200
+ * @returns 实例列表
201
+ */
202
+ getInstances(serviceName) {
203
+ return this.services.get(serviceName) || [];
204
+ }
205
+ };
206
+ exports.NacosService = NacosService;
207
+ exports.NacosService = NacosService = __decorate([
208
+ (0, common_1.Injectable)(),
209
+ __param(0, (0, common_1.Inject)('NACOS_CONFIG')),
210
+ __param(1, (0, common_1.Inject)('APP_LOGGER')),
211
+ __metadata("design:paramtypes", [Object, Function])
212
+ ], NacosService);
@@ -0,0 +1,10 @@
1
+ import { Host } from 'nacos';
2
+ export declare class LoadBalancer {
3
+ static roundRobin(instances: Host[], serviceName: string): Host | null;
4
+ static weightedRandom(instances: Host[]): Host | null;
5
+ }
6
+ /**
7
+ * 获取本机IP地址
8
+ */
9
+ export declare function getLocalIP(): string;
10
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/nacos/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,IAAI,EAAE,MAAM,OAAO,CAAC;AAGhD,qBAAa,YAAY;IAEvB,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAetE,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI;CAyBtD;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAmBnC"}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LoadBalancer = void 0;
4
+ exports.getLocalIP = getLocalIP;
5
+ const os_1 = require("os");
6
+ // 负载均衡器类
7
+ class LoadBalancer {
8
+ // 简单轮询算法
9
+ static roundRobin(instances, serviceName) {
10
+ if (!instances.length)
11
+ return null;
12
+ // 创建或获取当前服务的轮询索引
13
+ const key = `roundRobin_${serviceName}`;
14
+ const index = global[key] || 0;
15
+ // 获取实例并更新索引
16
+ const instance = instances[index % instances.length];
17
+ global[key] = (index + 1) % instances.length;
18
+ return instance;
19
+ }
20
+ // 加权随机算法(这是最常用的)
21
+ static weightedRandom(instances) {
22
+ if (!instances.length)
23
+ return null;
24
+ // 过滤健康实例
25
+ const healthyInstances = instances.filter((inst) => inst.healthy !== false);
26
+ if (!healthyInstances.length)
27
+ return null;
28
+ // 计算总权重
29
+ const totalWeight = healthyInstances.reduce((sum, inst) => sum + (inst.weight || 1.0), 0);
30
+ let random = Math.random() * totalWeight;
31
+ // 根据权重选择实例
32
+ for (const instance of healthyInstances) {
33
+ random -= instance.weight || 1.0;
34
+ if (random < 0) {
35
+ return instance;
36
+ }
37
+ }
38
+ // 如果权重计算有问题,返回最后一个
39
+ return healthyInstances[healthyInstances.length - 1];
40
+ }
41
+ }
42
+ exports.LoadBalancer = LoadBalancer;
43
+ /**
44
+ * 获取本机IP地址
45
+ */
46
+ function getLocalIP() {
47
+ const interfaces = (0, os_1.networkInterfaces)();
48
+ for (const name of Object.keys(interfaces)) {
49
+ const nets = interfaces[name];
50
+ if (!nets)
51
+ continue;
52
+ for (const net of nets) {
53
+ // 跳过内部地址和IPv6地址
54
+ if (!net.internal && net.family === 'IPv4') {
55
+ // 在Docker/K8s环境中,通常会有类似172.17.x.x或10.x.x.x这样的私有地址
56
+ // 跳过docker网桥地址(172.17.x.x)
57
+ if (!net.address.startsWith('172.17.')) {
58
+ return net.address;
59
+ }
60
+ }
61
+ }
62
+ }
63
+ // 如果找不到合适的地址,返回默认值
64
+ return '127.0.0.1';
65
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * 获取当前请求对象的工具函数
3
+ * 用于在服务层或 Repository 层获取请求上下文
4
+ */
5
+ export declare function getCurrentRequest(): any;
6
+ /**
7
+ * 设置当前请求上下文的工具函数
8
+ * 通常在中间件中使用
9
+ */
10
+ export declare function setCurrentRequest(request: any): void;
11
+ /**
12
+ * 在AsyncLocalStorage上下文中运行函数
13
+ * 用于在中间件中设置请求上下文
14
+ */
15
+ export declare function runWithContext(fn: () => void, request: any): void;
16
+ //# sourceMappingURL=current-request.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"current-request.util.d.ts","sourceRoot":"","sources":["../../src/restful/current-request.util.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,GAAG,CAGvC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI,CAKpD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,GAAG,GAAG,IAAI,CAEjE"}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCurrentRequest = getCurrentRequest;
4
+ exports.setCurrentRequest = setCurrentRequest;
5
+ exports.runWithContext = runWithContext;
6
+ const async_hooks_1 = require("async_hooks");
7
+ // 使用 AsyncLocalStorage 来追踪请求上下文
8
+ // 这在 Node.js 环境中是处理请求上下文的标准方式
9
+ const asyncLocalStorage = new async_hooks_1.AsyncLocalStorage();
10
+ /**
11
+ * 获取当前请求对象的工具函数
12
+ * 用于在服务层或 Repository 层获取请求上下文
13
+ */
14
+ function getCurrentRequest() {
15
+ // 使用 AsyncLocalStorage 获取当前执行上下文中的请求对象
16
+ return asyncLocalStorage.getStore();
17
+ }
18
+ /**
19
+ * 设置当前请求上下文的工具函数
20
+ * 通常在中间件中使用
21
+ */
22
+ function setCurrentRequest(request) {
23
+ // 在当前异步执行上下文中存储请求对象
24
+ // 注意:这需要在正确的执行上下文中使用
25
+ // 在中间件中,我们需要使用 run 方法来创建执行上下文
26
+ asyncLocalStorage.enterWith(request);
27
+ }
28
+ /**
29
+ * 在AsyncLocalStorage上下文中运行函数
30
+ * 用于在中间件中设置请求上下文
31
+ */
32
+ function runWithContext(fn, request) {
33
+ asyncLocalStorage.run(request, fn);
34
+ }
@@ -0,0 +1,24 @@
1
+ import { ExceptionFilter, ArgumentsHost, HttpException } from '@nestjs/common';
2
+ /**
3
+ * 全局 HTTP 异常过滤器
4
+ *
5
+ * 功能:
6
+ * 1. 捕获所有 HTTP 异常
7
+ * 2. 统一返回 HTTP 200 状态码
8
+ * 3. 在响应体中使用 code 字段表示业务状态
9
+ * 4. 记录异常日志
10
+ */
11
+ export declare class HttpExceptionFilter implements ExceptionFilter {
12
+ private readonly logger;
13
+ catch(exception: HttpException, host: ArgumentsHost): void;
14
+ }
15
+ /**
16
+ * 全局未捕获异常过滤器
17
+ *
18
+ * 用于捕获所有非 HTTP 异常(如系统错误、未预期异常等)
19
+ */
20
+ export declare class GlobalExceptionFilter implements ExceptionFilter {
21
+ private readonly logger;
22
+ catch(exception: unknown, host: ArgumentsHost): void;
23
+ }
24
+ //# sourceMappingURL=http-exception.filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-exception.filter.d.ts","sourceRoot":"","sources":["../../src/restful/http-exception.filter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAEf,aAAa,EACb,aAAa,EAGd,MAAM,gBAAgB,CAAC;AAuBxB;;;;;;;;GAQG;AACH,qBACa,mBAAoB,YAAW,eAAe;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwC;IAE/D,KAAK,CAAC,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa;CAqDpD;AAED;;;;GAIG;AACH,qBACa,qBAAsB,YAAW,eAAe;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IAEjE,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa;CAmC9C"}
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var HttpExceptionFilter_1, GlobalExceptionFilter_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.GlobalExceptionFilter = exports.HttpExceptionFilter = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const response_dto_1 = require("./response.dto");
13
+ const response_codes_1 = require("./response-codes");
14
+ /**
15
+ * HTTP 异常映射到业务状态码
16
+ */
17
+ const HTTP_STATUS_TO_CODE_MAP = {
18
+ [common_1.HttpStatus.BAD_REQUEST]: response_codes_1.ResponseCode.BAD_REQUEST,
19
+ [common_1.HttpStatus.UNAUTHORIZED]: response_codes_1.ResponseCode.UNAUTHORIZED,
20
+ [common_1.HttpStatus.FORBIDDEN]: response_codes_1.ResponseCode.FORBIDDEN,
21
+ [common_1.HttpStatus.NOT_FOUND]: response_codes_1.ResponseCode.NOT_FOUND,
22
+ [common_1.HttpStatus.METHOD_NOT_ALLOWED]: response_codes_1.ResponseCode.METHOD_NOT_ALLOWED,
23
+ [common_1.HttpStatus.REQUEST_TIMEOUT]: response_codes_1.ResponseCode.REQUEST_TIMEOUT,
24
+ [common_1.HttpStatus.CONFLICT]: response_codes_1.ResponseCode.CONFLICT,
25
+ [common_1.HttpStatus.PAYLOAD_TOO_LARGE]: response_codes_1.ResponseCode.PAYLOAD_TOO_LARGE,
26
+ [common_1.HttpStatus.TOO_MANY_REQUESTS]: response_codes_1.ResponseCode.TOO_MANY_REQUESTS,
27
+ [common_1.HttpStatus.INTERNAL_SERVER_ERROR]: response_codes_1.ResponseCode.INTERNAL_ERROR,
28
+ [common_1.HttpStatus.SERVICE_UNAVAILABLE]: response_codes_1.ResponseCode.SERVICE_UNAVAILABLE,
29
+ [common_1.HttpStatus.GATEWAY_TIMEOUT]: response_codes_1.ResponseCode.GATEWAY_TIMEOUT,
30
+ };
31
+ /**
32
+ * 全局 HTTP 异常过滤器
33
+ *
34
+ * 功能:
35
+ * 1. 捕获所有 HTTP 异常
36
+ * 2. 统一返回 HTTP 200 状态码
37
+ * 3. 在响应体中使用 code 字段表示业务状态
38
+ * 4. 记录异常日志
39
+ */
40
+ let HttpExceptionFilter = HttpExceptionFilter_1 = class HttpExceptionFilter {
41
+ logger = new common_1.Logger(HttpExceptionFilter_1.name);
42
+ catch(exception, host) {
43
+ const ctx = host.switchToHttp();
44
+ const response = ctx.getResponse();
45
+ const request = ctx.getRequest();
46
+ const httpStatus = exception.getStatus();
47
+ const exceptionResponse = exception.getResponse();
48
+ // 提取错误消息
49
+ let message;
50
+ let code;
51
+ let data;
52
+ if (typeof exceptionResponse === 'object' && exceptionResponse !== null) {
53
+ const responseObject = exceptionResponse;
54
+ // 如果异常响应本身已经包含 code 字段(说明是业务异常),直接使用
55
+ if (responseObject.code) {
56
+ code = responseObject.code;
57
+ message = responseObject.message || exception.message;
58
+ data = responseObject.data;
59
+ }
60
+ else {
61
+ // 否则根据 HTTP 状态码映射到业务状态码
62
+ code = HTTP_STATUS_TO_CODE_MAP[httpStatus] || response_codes_1.ResponseCode.INTERNAL_ERROR;
63
+ message = responseObject.message || exception.message;
64
+ // Nest.js 的 ValidationPipe 会返回数组形式的错误消息
65
+ if (Array.isArray(message)) {
66
+ message = message.join(', ');
67
+ }
68
+ }
69
+ }
70
+ else {
71
+ code = HTTP_STATUS_TO_CODE_MAP[httpStatus] || response_codes_1.ResponseCode.INTERNAL_ERROR;
72
+ message = exception.message;
73
+ }
74
+ // 记录日志
75
+ this.logger.error(`HTTP Exception: ${request.method} ${request.url} - Status: ${httpStatus} - Code: ${code} - Message: ${message}`, exception.stack);
76
+ // 构造响应
77
+ const errorResponse = response_dto_1.ApiResponseDto.error(code, message, data);
78
+ // 添加 traceId(如果请求上下文中有)
79
+ if (request.traceId) {
80
+ errorResponse.traceId = request.traceId;
81
+ }
82
+ // 统一返回 HTTP 200,通过 code 字段判断业务状态
83
+ response.status(common_1.HttpStatus.OK).json(errorResponse);
84
+ }
85
+ };
86
+ exports.HttpExceptionFilter = HttpExceptionFilter;
87
+ exports.HttpExceptionFilter = HttpExceptionFilter = HttpExceptionFilter_1 = __decorate([
88
+ (0, common_1.Catch)(common_1.HttpException)
89
+ ], HttpExceptionFilter);
90
+ /**
91
+ * 全局未捕获异常过滤器
92
+ *
93
+ * 用于捕获所有非 HTTP 异常(如系统错误、未预期异常等)
94
+ */
95
+ let GlobalExceptionFilter = GlobalExceptionFilter_1 = class GlobalExceptionFilter {
96
+ logger = new common_1.Logger(GlobalExceptionFilter_1.name);
97
+ catch(exception, host) {
98
+ const ctx = host.switchToHttp();
99
+ const response = ctx.getResponse();
100
+ const request = ctx.getRequest();
101
+ // 默认为内部服务器错误
102
+ let code = response_codes_1.ResponseCode.INTERNAL_ERROR;
103
+ let message = '服务器内部错误';
104
+ // 如果是已知异常类型,尝试提取信息
105
+ if (exception instanceof Error) {
106
+ message = exception.message || message;
107
+ // 记录完整的错误堆栈
108
+ this.logger.error(`Unhandled Exception: ${request.method} ${request.url} - Message: ${message}`, exception.stack);
109
+ }
110
+ else {
111
+ this.logger.error(`Unknown Exception: ${request.method} ${request.url} - ${JSON.stringify(exception)}`);
112
+ }
113
+ // 构造响应
114
+ const errorResponse = response_dto_1.ApiResponseDto.error(code, message);
115
+ // 添加 traceId
116
+ if (request.traceId) {
117
+ errorResponse.traceId = request.traceId;
118
+ }
119
+ // 返回 HTTP 200
120
+ response.status(common_1.HttpStatus.OK).json(errorResponse);
121
+ }
122
+ };
123
+ exports.GlobalExceptionFilter = GlobalExceptionFilter;
124
+ exports.GlobalExceptionFilter = GlobalExceptionFilter = GlobalExceptionFilter_1 = __decorate([
125
+ (0, common_1.Catch)()
126
+ ], GlobalExceptionFilter);
@@ -0,0 +1,8 @@
1
+ export * from './restful.module';
2
+ export * from './response.dto';
3
+ export * from './response-codes';
4
+ export * from './response.interceptor';
5
+ export * from './http-exception.filter';
6
+ export * from './current-request.util';
7
+ export * from './request-context.middleware';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/restful/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC"}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./restful.module"), exports);
18
+ __exportStar(require("./response.dto"), exports);
19
+ __exportStar(require("./response-codes"), exports);
20
+ __exportStar(require("./response.interceptor"), exports);
21
+ __exportStar(require("./http-exception.filter"), exports);
22
+ __exportStar(require("./current-request.util"), exports);
23
+ __exportStar(require("./request-context.middleware"), exports);
@@ -0,0 +1,6 @@
1
+ import { NestMiddleware } from '@nestjs/common';
2
+ import { Request, Response, NextFunction } from 'express';
3
+ export declare class RequestContextMiddleware implements NestMiddleware {
4
+ use(req: Request, res: Response, next: NextFunction): void;
5
+ }
6
+ //# sourceMappingURL=request-context.middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-context.middleware.d.ts","sourceRoot":"","sources":["../../src/restful/request-context.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D,qBACa,wBAAyB,YAAW,cAAc;IAC7D,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY;CASpD"}