@nest-boot/auth 6.0.0-alpha.3 → 6.0.0-beta.2

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 (59) hide show
  1. package/dist/auth.guard.d.ts +25 -4
  2. package/dist/auth.guard.js +65 -40
  3. package/dist/auth.guard.js.map +1 -1
  4. package/dist/auth.module.d.ts +1 -6
  5. package/dist/auth.module.js +3 -26
  6. package/dist/auth.module.js.map +1 -1
  7. package/dist/auth.service.d.ts +51 -18
  8. package/dist/auth.service.js +82 -44
  9. package/dist/auth.service.js.map +1 -1
  10. package/dist/decorators/current-personal-access-token.decorator.d.ts +1 -1
  11. package/dist/decorators/current-personal-access-token.decorator.js +4 -4
  12. package/dist/decorators/current-personal-access-token.decorator.js.map +1 -1
  13. package/dist/decorators/current-user.decorator.d.ts +1 -0
  14. package/dist/decorators/current-user.decorator.js +10 -0
  15. package/dist/decorators/current-user.decorator.js.map +1 -0
  16. package/dist/decorators/index.d.ts +1 -1
  17. package/dist/decorators/index.js +1 -1
  18. package/dist/decorators/index.js.map +1 -1
  19. package/dist/entities/index.d.ts +2 -0
  20. package/dist/{utils → entities}/index.js +2 -1
  21. package/dist/entities/index.js.map +1 -0
  22. package/dist/entities/personal-access-token.entity.d.ts +14 -0
  23. package/dist/entities/personal-access-token.entity.js +72 -0
  24. package/dist/entities/personal-access-token.entity.js.map +1 -0
  25. package/dist/entities/user.entity.d.ts +13 -0
  26. package/dist/entities/user.entity.js +68 -0
  27. package/dist/entities/user.entity.js.map +1 -0
  28. package/dist/index.d.ts +1 -3
  29. package/dist/index.js +1 -3
  30. package/dist/index.js.map +1 -1
  31. package/dist/interfaces/auth-module-options.interface.d.ts +6 -9
  32. package/dist/interfaces/index.d.ts +0 -2
  33. package/dist/interfaces/index.js +0 -2
  34. package/dist/interfaces/index.js.map +1 -1
  35. package/dist/tsconfig.build.tsbuildinfo +1 -1
  36. package/dist/utils/random-string.util.d.ts +6 -0
  37. package/dist/utils/random-string.util.js +27 -0
  38. package/dist/utils/random-string.util.js.map +1 -0
  39. package/package.json +22 -18
  40. package/dist/auth.constants.d.ts +0 -2
  41. package/dist/auth.constants.js +0 -6
  42. package/dist/auth.constants.js.map +0 -1
  43. package/dist/auth.middleware.d.ts +0 -13
  44. package/dist/auth.middleware.js +0 -67
  45. package/dist/auth.middleware.js.map +0 -1
  46. package/dist/decorators/current-entity.decorator.d.ts +0 -2
  47. package/dist/decorators/current-entity.decorator.js +0 -11
  48. package/dist/decorators/current-entity.decorator.js.map +0 -1
  49. package/dist/interfaces/access-token.interface.d.ts +0 -9
  50. package/dist/interfaces/access-token.interface.js +0 -3
  51. package/dist/interfaces/access-token.interface.js.map +0 -1
  52. package/dist/interfaces/has-permission.interface.d.ts +0 -3
  53. package/dist/interfaces/has-permission.interface.js +0 -3
  54. package/dist/interfaces/has-permission.interface.js.map +0 -1
  55. package/dist/utils/index.d.ts +0 -1
  56. package/dist/utils/index.js.map +0 -1
  57. package/dist/utils/mixin-permissions.utils.d.ts +0 -3
  58. package/dist/utils/mixin-permissions.utils.js +0 -16
  59. package/dist/utils/mixin-permissions.utils.js.map +0 -1
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Generates a random string of the specified length.
3
+ * @param length The length of the random string to generate.
4
+ * @returns The randomly generated string.
5
+ */
6
+ export declare function randomString(length: number): string;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.randomString = void 0;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
9
+ /**
10
+ * Generates a random string of the specified length.
11
+ * @param length The length of the random string to generate.
12
+ * @returns The randomly generated string.
13
+ */
14
+ function randomString(length) {
15
+ let result = "";
16
+ const byteSize = Math.ceil((length * 256) / characters.length);
17
+ const randomBytes = crypto_1.default.randomBytes(byteSize);
18
+ for (let i = 0; i < byteSize && result.length < length; i++) {
19
+ const randomByte = randomBytes[i];
20
+ if (randomByte < 256 - (256 % characters.length)) {
21
+ result += characters.charAt(randomByte % characters.length);
22
+ }
23
+ }
24
+ return result;
25
+ }
26
+ exports.randomString = randomString;
27
+ //# sourceMappingURL=random-string.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"random-string.util.js","sourceRoot":"","sources":["../../src/utils/random-string.util.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;AAE5B,MAAM,UAAU,GACd,gEAAgE,CAAC;AAEnE;;;;GAIG;AACH,SAAgB,YAAY,CAAC,MAAc;IACzC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAC/D,MAAM,WAAW,GAAG,gBAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAEjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,IAAI,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5D,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAClC,IAAI,UAAU,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAbD,oCAaC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nest-boot/auth",
3
- "version": "6.0.0-alpha.3",
3
+ "version": "6.0.0-beta.2",
4
4
  "description": "",
5
5
  "author": "d4rkcr0w <me@d4rkcr0w.com>",
6
6
  "homepage": "",
@@ -14,9 +14,9 @@
14
14
  "dist"
15
15
  ],
16
16
  "scripts": {
17
- "build": "nest build",
17
+ "build": "tsc -p tsconfig.build.json",
18
18
  "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
19
- "dev": "nest build --watch",
19
+ "dev": "tsc -w -p tsconfig.build.json",
20
20
  "lint": "eslint \"{src,test}/**/*.ts\" --fix",
21
21
  "test": "jest"
22
22
  },
@@ -25,34 +25,38 @@
25
25
  "ms": "^2.1.3"
26
26
  },
27
27
  "devDependencies": {
28
- "@mikro-orm/nestjs": "^5.2.2",
29
- "@nest-boot/database": "6.0.0-alpha.3",
30
- "@nest-boot/eslint-config": "5.7.0",
31
- "@nest-boot/eslint-plugin": "5.7.0",
32
- "@nest-boot/i18n": "5.7.1",
33
- "@nest-boot/request-context": "5.7.1",
28
+ "@mikro-orm/core": "^6.0.5",
29
+ "@mikro-orm/nestjs": "^5.2.1",
30
+ "@nest-boot/common": "6.0.0-beta.2",
31
+ "@nest-boot/database": "6.0.0-beta.2",
32
+ "@nest-boot/eslint-config": "6.0.0-beta.1",
33
+ "@nest-boot/eslint-plugin": "6.0.0-beta.1",
34
+ "@nest-boot/hash": "6.0.0-beta.2",
35
+ "@nest-boot/i18n": "6.0.0-beta.2",
36
+ "@nest-boot/request-context": "6.0.0-beta.2",
34
37
  "@nest-boot/tsconfig": "5.1.0",
35
- "@nestjs/common": "^10.2.5",
38
+ "@nestjs/common": "^10.3.1",
36
39
  "@nestjs/config": "^3.1.1",
37
- "@nestjs/core": "^10.2.5",
40
+ "@nestjs/core": "^10.3.1",
38
41
  "@types/express": "^4.17.17",
39
- "@types/jest": "^29.5.5",
42
+ "@types/jest": "^29.5.11",
40
43
  "@types/lodash": "^4.14.198",
41
44
  "@types/ms": "^0.7.31",
42
- "@types/node": "^20.6.3",
45
+ "@types/node": "^20.11.6",
43
46
  "express": "^4.18.2",
44
47
  "jest": "^29.7.0",
45
48
  "reflect-metadata": "^0.1.13",
46
49
  "rxjs": "^7.8.1",
47
- "ts-jest": "^29.1.1",
50
+ "ts-jest": "^29.1.2",
48
51
  "typescript": "^5.2.2"
49
52
  },
50
53
  "peerDependencies": {
51
54
  "@mikro-orm/core": "^6.0.0",
52
- "@mikro-orm/nestjs": "^5.0.0",
53
- "@nest-boot/database": "6.0.0-alpha.3",
54
- "@nest-boot/i18n": "5.7.1",
55
- "@nest-boot/request-context": "5.7.1",
55
+ "@mikro-orm/nestjs": "^6.0.0",
56
+ "@nest-boot/common": "6.0.0-beta.2",
57
+ "@nest-boot/database": "6.0.0-beta.2",
58
+ "@nest-boot/i18n": "6.0.0-beta.2",
59
+ "@nest-boot/request-context": "6.0.0-beta.2",
56
60
  "@nestjs/common": "^10.0.0",
57
61
  "@nestjs/core": "^10.0.0",
58
62
  "express": "^4.0.0",
@@ -1,2 +0,0 @@
1
- export declare const AUTH_ENTITY = "AUTH_ENTITY";
2
- export declare const AUTH_ACCESS_TOKEN = "AUTH_ACCESS_TOKEN";
@@ -1,6 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AUTH_ACCESS_TOKEN = exports.AUTH_ENTITY = void 0;
4
- exports.AUTH_ENTITY = "AUTH_ENTITY";
5
- exports.AUTH_ACCESS_TOKEN = "AUTH_ACCESS_TOKEN";
6
- //# sourceMappingURL=auth.constants.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth.constants.js","sourceRoot":"","sources":["../src/auth.constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,WAAW,GAAG,aAAa,CAAC;AAC5B,QAAA,iBAAiB,GAAG,mBAAmB,CAAC"}
@@ -1,13 +0,0 @@
1
- import { EntityManager } from "@mikro-orm/core";
2
- import { type NestMiddleware } from "@nestjs/common";
3
- import { type Request, type Response } from "express";
4
- import { AuthService } from "./auth.service";
5
- import { AuthModuleOptions } from "./interfaces";
6
- export declare class AuthMiddleware implements NestMiddleware {
7
- private readonly options;
8
- private readonly entityManager;
9
- private readonly authService;
10
- constructor(options: AuthModuleOptions, entityManager: EntityManager, authService: AuthService);
11
- use(req: Request, res: Response, next: () => void): Promise<void>;
12
- private extractAccessToken;
13
- }
@@ -1,67 +0,0 @@
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.AuthMiddleware = void 0;
16
- const core_1 = require("@mikro-orm/core");
17
- const request_context_1 = require("@nest-boot/request-context");
18
- const common_1 = require("@nestjs/common");
19
- const auth_constants_1 = require("./auth.constants");
20
- const auth_module_definition_1 = require("./auth.module-definition");
21
- const auth_service_1 = require("./auth.service");
22
- let AuthMiddleware = class AuthMiddleware {
23
- constructor(options, entityManager, authService) {
24
- this.options = options;
25
- this.entityManager = entityManager;
26
- this.authService = authService;
27
- }
28
- async use(req, res, next) {
29
- req.authMiddlewareUsed = true;
30
- const accessTokenString = this.extractAccessToken(req);
31
- if (accessTokenString !== null) {
32
- const accessToken = await this.authService.getToken(accessTokenString);
33
- if (accessToken !== null) {
34
- request_context_1.RequestContext.set(auth_constants_1.AUTH_ACCESS_TOKEN, accessToken);
35
- const entity = await this.entityManager
36
- .getRepository(accessToken.entityName)
37
- .findOne(accessToken.entityId);
38
- // 设置访问令牌和用户到运行上下文
39
- if (entity !== null) {
40
- request_context_1.RequestContext.set(auth_constants_1.AUTH_ENTITY, entity);
41
- }
42
- }
43
- }
44
- next();
45
- }
46
- extractAccessToken(req) {
47
- const authorizationHeader = req.get("authorization");
48
- if (typeof authorizationHeader === "string") {
49
- const matched = authorizationHeader.match(/(\S+)\s+(\S+)/);
50
- if (matched !== null && matched[1].toLowerCase() === "bearer") {
51
- return matched[2];
52
- }
53
- }
54
- if (typeof req.cookies?.token === "string") {
55
- return req.cookies.token;
56
- }
57
- return null;
58
- }
59
- };
60
- exports.AuthMiddleware = AuthMiddleware;
61
- exports.AuthMiddleware = AuthMiddleware = __decorate([
62
- (0, common_1.Injectable)({ scope: common_1.Scope.REQUEST }),
63
- __param(0, (0, common_1.Inject)(auth_module_definition_1.MODULE_OPTIONS_TOKEN)),
64
- __metadata("design:paramtypes", [Object, core_1.EntityManager,
65
- auth_service_1.AuthService])
66
- ], AuthMiddleware);
67
- //# sourceMappingURL=auth.middleware.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth.middleware.js","sourceRoot":"","sources":["../src/auth.middleware.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,0CAAgD;AAChD,gEAA4D;AAC5D,2CAAgF;AAGhF,qDAAkE;AAClE,qEAAgE;AAChE,iDAA6C;AAItC,IAAM,cAAc,GAApB,MAAM,cAAc;IACzB,YAEmB,OAA0B,EAC1B,aAA4B,EAC5B,WAAwB;QAFxB,YAAO,GAAP,OAAO,CAAmB;QAC1B,kBAAa,GAAb,aAAa,CAAe;QAC5B,gBAAW,GAAX,WAAW,CAAa;IACxC,CAAC;IAEJ,KAAK,CAAC,GAAG,CAAC,GAAY,EAAE,GAAa,EAAE,IAAgB;QACpD,GAAW,CAAC,kBAAkB,GAAG,IAAI,CAAC;QAEvC,MAAM,iBAAiB,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAEvD,IAAI,iBAAiB,KAAK,IAAI,EAAE;YAC9B,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;YAEvE,IAAI,WAAW,KAAK,IAAI,EAAE;gBACxB,gCAAc,CAAC,GAAG,CAChB,kCAAiB,EACjB,WAAW,CACZ,CAAC;gBAEF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa;qBACpC,aAAa,CAAC,WAAW,CAAC,UAAU,CAAC;qBACrC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAEjC,kBAAkB;gBAClB,IAAI,MAAM,KAAK,IAAI,EAAE;oBACnB,gCAAc,CAAC,GAAG,CAAC,4BAAW,EAAE,MAAM,CAAC,CAAC;iBACzC;aACF;SACF;QAED,IAAI,EAAE,CAAC;IACT,CAAC;IAEO,kBAAkB,CAAC,GAAY;QACrC,MAAM,mBAAmB,GAAG,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QACrD,IAAI,OAAO,mBAAmB,KAAK,QAAQ,EAAE;YAC3C,MAAM,OAAO,GAAG,mBAAmB,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;YAE3D,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,QAAQ,EAAE;gBAC7D,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;aACnB;SACF;QAED,IAAI,OAAO,GAAG,CAAC,OAAO,EAAE,KAAK,KAAK,QAAQ,EAAE;YAC1C,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;SAC1B;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AApDY,wCAAc;yBAAd,cAAc;IAD1B,IAAA,mBAAU,EAAC,EAAE,KAAK,EAAE,cAAK,CAAC,OAAO,EAAE,CAAC;IAGhC,WAAA,IAAA,eAAM,EAAC,6CAAoB,CAAC,CAAA;6CAEG,oBAAa;QACf,0BAAW;GALhC,cAAc,CAoD1B"}
@@ -1,2 +0,0 @@
1
- export declare const CurrentEntity: (...dataOrPipes: any[]) => ParameterDecorator;
2
- export declare const CurrentUser: (...dataOrPipes: any[]) => ParameterDecorator;
@@ -1,11 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CurrentUser = exports.CurrentEntity = void 0;
4
- const request_context_1 = require("@nest-boot/request-context");
5
- const common_1 = require("@nestjs/common");
6
- const auth_constants_1 = require("../auth.constants");
7
- exports.CurrentEntity = (0, common_1.createParamDecorator)(() => {
8
- return request_context_1.RequestContext.get(auth_constants_1.AUTH_ENTITY);
9
- });
10
- exports.CurrentUser = exports.CurrentEntity;
11
- //# sourceMappingURL=current-entity.decorator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"current-entity.decorator.js","sourceRoot":"","sources":["../../src/decorators/current-entity.decorator.ts"],"names":[],"mappings":";;;AAAA,gEAA4D;AAC5D,2CAAsD;AAEtD,sDAAgD;AAEnC,QAAA,aAAa,GAAG,IAAA,6BAAoB,EAAC,GAAG,EAAE;IACrD,OAAO,gCAAc,CAAC,GAAG,CAAC,4BAAW,CAAC,CAAC;AACzC,CAAC,CAAC,CAAC;AAEU,QAAA,WAAW,GAAG,qBAAa,CAAC"}
@@ -1,9 +0,0 @@
1
- export interface AccessTokenInterface {
2
- id: string;
3
- name: string;
4
- token: string;
5
- entityId: string;
6
- entityName: string;
7
- lastUsedAt: Date | null;
8
- expiresAt: Date | null;
9
- }
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=access-token.interface.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"access-token.interface.js","sourceRoot":"","sources":["../../src/interfaces/access-token.interface.ts"],"names":[],"mappings":""}
@@ -1,3 +0,0 @@
1
- export interface HasPermissions {
2
- permissions: string[];
3
- }
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=has-permission.interface.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"has-permission.interface.js","sourceRoot":"","sources":["../../src/interfaces/has-permission.interface.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- export * from "./mixin-permissions.utils";
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4DAA0C"}
@@ -1,3 +0,0 @@
1
- import { type HasPermissions } from "../interfaces";
2
- export type Type<T = any> = new (...args: any[]) => T;
3
- export declare function mixinPermissions<T extends Type<any>>(base: T): Type<HasPermissions> & T;
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.mixinPermissions = void 0;
4
- const core_1 = require("@mikro-orm/core");
5
- function mixinPermissions(base) {
6
- const trait = class extends base {
7
- constructor() {
8
- super(...arguments);
9
- this.permissions = [];
10
- }
11
- };
12
- (0, core_1.Property)({ type: core_1.t.array, onCreate: () => [] })(trait.prototype, "permissions");
13
- return trait;
14
- }
15
- exports.mixinPermissions = mixinPermissions;
16
- //# sourceMappingURL=mixin-permissions.utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mixin-permissions.utils.js","sourceRoot":"","sources":["../../src/utils/mixin-permissions.utils.ts"],"names":[],"mappings":";;;AAAA,0CAA8C;AAM9C,SAAgB,gBAAgB,CAC9B,IAAO;IAEP,MAAM,KAAK,GAAG,KAAM,SAAQ,IAAI;QAAlB;;YACZ,gBAAW,GAAa,EAAE,CAAC;QAC7B,CAAC;KAAA,CAAC;IAEF,IAAA,eAAQ,EAAC,EAAE,IAAI,EAAE,QAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAC7C,KAAK,CAAC,SAAS,EACf,aAAa,CACd,CAAC;IAEF,OAAO,KAAK,CAAC;AACf,CAAC;AAbD,4CAaC"}