@zintrust/core 0.4.18 → 0.4.20

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 (58) hide show
  1. package/package.json +1 -1
  2. package/src/cli/commands/AddCommand.d.ts +16 -0
  3. package/src/cli/commands/AddCommand.d.ts.map +1 -1
  4. package/src/cli/commands/AddCommand.js +157 -28
  5. package/src/cli/commands/DockerCommand.d.ts.map +1 -1
  6. package/src/cli/commands/DockerCommand.js +32 -4
  7. package/src/cli/commands/StartCommand.d.ts +7 -0
  8. package/src/cli/commands/StartCommand.d.ts.map +1 -1
  9. package/src/cli/commands/StartCommand.js +109 -20
  10. package/src/config/middleware.d.ts +23 -0
  11. package/src/config/middleware.d.ts.map +1 -1
  12. package/src/config/middleware.js +66 -31
  13. package/src/functions/cloudflare.d.ts.map +1 -1
  14. package/src/functions/cloudflare.js +28 -12
  15. package/src/http/Kernel.d.ts.map +1 -1
  16. package/src/http/Kernel.js +27 -1
  17. package/src/index.d.ts +2 -0
  18. package/src/index.d.ts.map +1 -1
  19. package/src/index.js +5 -3
  20. package/src/middleware/AuthMiddleware.d.ts +2 -0
  21. package/src/middleware/AuthMiddleware.d.ts.map +1 -1
  22. package/src/middleware/AuthMiddleware.js +8 -1
  23. package/src/middleware/BulletproofAuthMiddleware.d.ts +2 -0
  24. package/src/middleware/BulletproofAuthMiddleware.d.ts.map +1 -1
  25. package/src/middleware/BulletproofAuthMiddleware.js +13 -5
  26. package/src/middleware/CsrfMiddleware.d.ts +2 -0
  27. package/src/middleware/CsrfMiddleware.d.ts.map +1 -1
  28. package/src/middleware/CsrfMiddleware.js +9 -3
  29. package/src/middleware/ErrorHandlerMiddleware.d.ts +5 -1
  30. package/src/middleware/ErrorHandlerMiddleware.d.ts.map +1 -1
  31. package/src/middleware/ErrorHandlerMiddleware.js +12 -2
  32. package/src/middleware/JwtAuthMiddleware.d.ts +2 -0
  33. package/src/middleware/JwtAuthMiddleware.d.ts.map +1 -1
  34. package/src/middleware/JwtAuthMiddleware.js +39 -4
  35. package/src/middleware/MiddlewareFailureResponder.d.ts +15 -0
  36. package/src/middleware/MiddlewareFailureResponder.d.ts.map +1 -0
  37. package/src/middleware/MiddlewareFailureResponder.js +15 -0
  38. package/src/middleware/RateLimiter.d.ts +2 -0
  39. package/src/middleware/RateLimiter.d.ts.map +1 -1
  40. package/src/middleware/RateLimiter.js +10 -4
  41. package/src/middleware/SecurityMiddleware.d.ts +1 -1
  42. package/src/middleware/SecurityMiddleware.d.ts.map +1 -1
  43. package/src/middleware/SecurityMiddleware.js +38 -7
  44. package/src/middleware/ValidationMiddleware.d.ts +11 -6
  45. package/src/middleware/ValidationMiddleware.d.ts.map +1 -1
  46. package/src/middleware/ValidationMiddleware.js +48 -19
  47. package/src/middleware/index.d.ts +1 -0
  48. package/src/middleware/index.d.ts.map +1 -1
  49. package/src/middleware/index.js +1 -0
  50. package/src/runtime/RuntimeAdapter.d.ts.map +1 -1
  51. package/src/runtime/RuntimeAdapter.js +12 -2
  52. package/src/runtime/WorkersModule.d.ts.map +1 -1
  53. package/src/runtime/WorkersModule.js +4 -3
  54. package/src/security/Xss.d.ts +2 -2
  55. package/src/security/Xss.d.ts.map +1 -1
  56. package/src/security/Xss.js +3 -4
  57. package/src/templates/project/basic/app/Middleware/AuthFailureResponder.ts.tpl +10 -0
  58. package/src/templates/project/basic/config/middleware.ts.tpl +18 -0
@@ -3,6 +3,7 @@ import { Logger } from '../config/logger.js';
3
3
  import ErrorRouting from '../routes/error.js';
4
4
  import { ErrorResponse } from '../http/ErrorResponse.js';
5
5
  import { RequestContext } from '../http/RequestContext.js';
6
+ import { respondWithMiddlewareFailure, } from './MiddlewareFailureResponder.js';
6
7
  const isWritableEnded = (res) => {
7
8
  if (typeof res.getRaw !== 'function')
8
9
  return false;
@@ -22,7 +23,7 @@ const shouldHideStackFromResponse = (error) => {
22
23
  candidate.statusCode === 404);
23
24
  };
24
25
  export const ErrorHandlerMiddleware = Object.freeze({
25
- create() {
26
+ create(options = {}) {
26
27
  return async (req, res, next) => {
27
28
  try {
28
29
  await next();
@@ -40,7 +41,16 @@ export const ErrorHandlerMiddleware = Object.freeze({
40
41
  await handleInternalServerErrorWithWrappers(req, res, error, requestId);
41
42
  }
42
43
  else {
43
- res.json(ErrorResponse.internalServerError('Internal server error', requestId, includeStack ? error?.stack : undefined));
44
+ const body = ErrorResponse.internalServerError('Internal server error', requestId, includeStack ? error?.stack : undefined);
45
+ await respondWithMiddlewareFailure(req, res, options.onFailure, {
46
+ middleware: 'error',
47
+ reason: 'unhandled_exception',
48
+ statusCode: 500,
49
+ message: 'Internal server error',
50
+ body,
51
+ error,
52
+ requestId,
53
+ });
44
54
  }
45
55
  }
46
56
  }
@@ -1,8 +1,10 @@
1
+ import { type MiddlewareFailureResponder } from './MiddlewareFailureResponder';
1
2
  import type { Middleware } from './MiddlewareStack';
2
3
  import type { JwtAlgorithm } from '../security/JwtManager';
3
4
  export interface JwtAuthOptions {
4
5
  algorithm?: JwtAlgorithm;
5
6
  secret?: string;
7
+ onUnauthorized?: MiddlewareFailureResponder;
6
8
  }
7
9
  export declare const JwtAuthMiddleware: Readonly<{
8
10
  create(options?: JwtAuthOptions): Middleware;
@@ -1 +1 @@
1
- {"version":3,"file":"JwtAuthMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/JwtAuthMiddleware.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAItE,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA4BD,eAAO,MAAM,iBAAiB;qBACZ,cAAc,GAAQ,UAAU;EAoEhD,CAAC;AAEH,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"JwtAuthMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/JwtAuthMiddleware.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAItE,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,0BAA0B,CAAC;CAC7C;AAuCD,eAAO,MAAM,iBAAiB;qBACZ,cAAc,GAAQ,UAAU;EA6FhD,CAAC;AAEH,eAAe,iBAAiB,CAAC"}
@@ -1,8 +1,18 @@
1
1
  import { Logger } from '../config/logger.js';
2
2
  import { securityConfig } from '../config/security.js';
3
3
  import { RequestContext } from '../http/RequestContext.js';
4
+ import { respondWithMiddlewareFailure, } from './MiddlewareFailureResponder.js';
4
5
  import { JwtManager } from '../security/JwtManager.js';
5
6
  import { JwtSessions } from '../security/JwtSessions.js';
7
+ const getJwtFailureReason = (error) => {
8
+ if (typeof error !== 'object' || error === null)
9
+ return 'invalid_token';
10
+ const candidate = error;
11
+ if (candidate.name === 'TokenExpiredError' || candidate.code === 'TOKEN_EXPIRED') {
12
+ return 'expired_token';
13
+ }
14
+ return 'invalid_token';
15
+ };
6
16
  const getHeaderValue = (value) => {
7
17
  if (Array.isArray(value))
8
18
  return typeof value[0] === 'string' ? value[0] : '';
@@ -44,19 +54,37 @@ export const JwtAuthMiddleware = Object.freeze({
44
54
  }
45
55
  const authorizationHeader = getHeaderValue(req.getHeader('authorization'));
46
56
  if (authorizationHeader === '') {
47
- res.setStatus(401).json({ error: 'Missing authorization header' });
57
+ await respondWithMiddlewareFailure(req, res, options.onUnauthorized, {
58
+ middleware: 'jwt',
59
+ reason: 'missing_authorization_header',
60
+ statusCode: 401,
61
+ message: 'Missing authorization header',
62
+ body: { error: 'Missing authorization header' },
63
+ });
48
64
  return;
49
65
  }
50
66
  const token = getBearerToken(authorizationHeader);
51
67
  if (token === null) {
52
- res.setStatus(401).json({ error: 'Invalid authorization header format' });
68
+ await respondWithMiddlewareFailure(req, res, options.onUnauthorized, {
69
+ middleware: 'jwt',
70
+ reason: 'invalid_authorization_header_format',
71
+ statusCode: 401,
72
+ message: 'Invalid authorization header format',
73
+ body: { error: 'Invalid authorization header format' },
74
+ });
53
75
  return;
54
76
  }
55
77
  try {
56
78
  const payload = jwt.verify(token, algorithm);
57
79
  // Session allowlist: token must exist in the session store to be accepted.
58
80
  if (!(await JwtSessions.isActive(token))) {
59
- res.setStatus(401).json({ error: 'Invalid or expired token' });
81
+ await respondWithMiddlewareFailure(req, res, options.onUnauthorized, {
82
+ middleware: 'jwt',
83
+ reason: 'inactive_session',
84
+ statusCode: 401,
85
+ message: 'Invalid or expired token',
86
+ body: { error: 'Invalid or expired token' },
87
+ });
60
88
  return;
61
89
  }
62
90
  req.user = payload;
@@ -77,7 +105,14 @@ export const JwtAuthMiddleware = Object.freeze({
77
105
  algorithm,
78
106
  error: error instanceof Error ? error.message : String(error),
79
107
  });
80
- res.setStatus(401).json({ error: 'Invalid or expired token' });
108
+ await respondWithMiddlewareFailure(req, res, options.onUnauthorized, {
109
+ middleware: 'jwt',
110
+ reason: getJwtFailureReason(error),
111
+ statusCode: 401,
112
+ message: 'Invalid or expired token',
113
+ body: { error: 'Invalid or expired token' },
114
+ error,
115
+ });
81
116
  }
82
117
  };
83
118
  },
@@ -0,0 +1,15 @@
1
+ import type { IRequest } from '../http/Request';
2
+ import type { IResponse } from '../http/Response';
3
+ export type MiddlewareFailureContext = Readonly<{
4
+ middleware: string;
5
+ reason: string;
6
+ statusCode: number;
7
+ message: string;
8
+ body: unknown;
9
+ error?: unknown;
10
+ requestId?: string;
11
+ }>;
12
+ export type MiddlewareFailureResponder = (req: IRequest, res: IResponse, context: MiddlewareFailureContext) => void | Promise<void>;
13
+ export declare const defaultMiddlewareFailureResponder: MiddlewareFailureResponder;
14
+ export declare const respondWithMiddlewareFailure: (req: IRequest, res: IResponse, responder: MiddlewareFailureResponder | undefined, context: MiddlewareFailureContext) => Promise<void>;
15
+ //# sourceMappingURL=MiddlewareFailureResponder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MiddlewareFailureResponder.d.ts","sourceRoot":"","sources":["../../../src/middleware/MiddlewareFailureResponder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,CACvC,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,SAAS,EACd,OAAO,EAAE,wBAAwB,KAC9B,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B,eAAO,MAAM,iCAAiC,EAAE,0BAgB/C,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,WAAW,0BAA0B,GAAG,SAAS,EACjD,SAAS,wBAAwB,KAChC,OAAO,CAAC,IAAI,CAEd,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { isObject } from '../helper/index.js';
2
+ export const defaultMiddlewareFailureResponder = (_req, res, context) => {
3
+ const statusTarget = res.setStatus(context.statusCode);
4
+ const responseTarget = isObject(statusTarget) ? statusTarget : res;
5
+ if (typeof responseTarget.json === 'function') {
6
+ responseTarget.json(context.body);
7
+ return;
8
+ }
9
+ if (typeof responseTarget.send === 'function') {
10
+ responseTarget.send(JSON.stringify(context.body));
11
+ }
12
+ };
13
+ export const respondWithMiddlewareFailure = async (req, res, responder, context) => {
14
+ await (responder ?? defaultMiddlewareFailureResponder)(req, res, context);
15
+ };
@@ -4,6 +4,7 @@
4
4
  * Zero-dependency implementation
5
5
  */
6
6
  import type { IRequest } from '../http/Request';
7
+ import { type MiddlewareFailureResponder } from './MiddlewareFailureResponder';
7
8
  import type { Middleware } from './MiddlewareStack';
8
9
  export interface RateLimitOptions {
9
10
  windowMs: number;
@@ -20,6 +21,7 @@ export interface RateLimitOptions {
20
21
  * - 'db' uses Cache.store('mongodb')
21
22
  */
22
23
  store?: RateLimitStoreName;
24
+ onFailure?: MiddlewareFailureResponder;
23
25
  }
24
26
  export type RateLimitStoreName = 'memory' | 'redis' | 'kv' | 'db';
25
27
  export declare const RateLimiter: Readonly<{
@@ -1 +1 @@
1
- {"version":3,"file":"RateLimiter.d.ts","sourceRoot":"","sources":["../../../src/middleware/RateLimiter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,MAAM,CAAC;IAEzC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC5B;AAED,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC;AAqKlE,eAAO,MAAM,WAAW;IACtB;;;OAGG;uBACgB;QAAE,KAAK,CAAC,EAAE,kBAAkB,CAAA;KAAE,GAAG,IAAI;IAKxD;;;;OAIG;iBACgB,MAAM,eAAe,MAAM,gBAAgB,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYvF;;OAEG;yBACwB,MAAM,eAAe,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQzE;;;OAGG;cACa,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQxC;;OAEG;eACc,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvC;;OAEG;qBACa,gBAAgB,GAAqB,UAAU;EAgF/D,CAAC"}
1
+ {"version":3,"file":"RateLimiter.d.ts","sourceRoot":"","sources":["../../../src/middleware/RateLimiter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,MAAM,CAAC;IAEzC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,SAAS,CAAC,EAAE,0BAA0B,CAAC;CACxC;AAED,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC;AAqKlE,eAAO,MAAM,WAAW;IACtB;;;OAGG;uBACgB;QAAE,KAAK,CAAC,EAAE,kBAAkB,CAAA;KAAE,GAAG,IAAI;IAKxD;;;;OAIG;iBACgB,MAAM,eAAe,MAAM,gBAAgB,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYvF;;OAEG;yBACwB,MAAM,eAAe,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQzE;;;OAGG;cACa,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQxC;;OAEG;eACc,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvC;;OAEG;qBACa,gBAAgB,GAAqB,UAAU;EAqF/D,CAAC"}
@@ -6,6 +6,7 @@
6
6
  import { Cache } from '../cache/Cache.js';
7
7
  import { Env } from '../config/env.js';
8
8
  import { Logger } from '../config/logger.js';
9
+ import { respondWithMiddlewareFailure, } from './MiddlewareFailureResponder.js';
9
10
  const createMemoryStore = () => {
10
11
  const entries = new Map();
11
12
  let nextCleanupAt = Date.now() + 60_000;
@@ -257,10 +258,15 @@ export const RateLimiter = Object.freeze({
257
258
  // Check limit
258
259
  if (count > config.max) {
259
260
  Logger.warn(`Rate limit exceeded for IP: ${key}`);
260
- res.setStatus(config.statusCode ?? 429);
261
- res.json({
262
- error: 'Too Many Requests',
263
- message: config.message,
261
+ await respondWithMiddlewareFailure(req, res, config.onFailure, {
262
+ middleware: 'rateLimit',
263
+ reason: 'rate_limit_exceeded',
264
+ statusCode: config.statusCode ?? 429,
265
+ message: config.message ?? 'Too many requests',
266
+ body: {
267
+ error: 'Too Many Requests',
268
+ message: config.message,
269
+ },
264
270
  });
265
271
  return;
266
272
  }
@@ -14,7 +14,7 @@ export interface SecurityOptions {
14
14
  action?: 'DENY' | 'SAMEORIGIN';
15
15
  };
16
16
  cors?: {
17
- origin?: string;
17
+ origin?: string | string[];
18
18
  methods?: string[];
19
19
  allowedHeaders?: string[];
20
20
  credentials?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"SecurityMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/SecurityMiddleware.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;IACF,UAAU,CAAC,EAAE;QACX,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;KAChC,CAAC;IACF,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,GAAG,CAAC,EAAE;QACJ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;KACvC,CAAC;CACH;AA+FD,eAAO,MAAM,kBAAkB;IAC7B;;OAEG;qBACa,eAAe,GAAQ,UAAU;EAgBjD,CAAC"}
1
+ {"version":3,"file":"SecurityMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/SecurityMiddleware.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;IACF,UAAU,CAAC,EAAE;QACX,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;KAChC,CAAC;IACF,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,GAAG,CAAC,EAAE;QACJ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;KACvC,CAAC;CACH;AAiID,eAAO,MAAM,kBAAkB;IAC7B;;OAEG;qBACa,eAAe,GAAQ,UAAU;EAgBjD,CAAC"}
@@ -3,6 +3,17 @@
3
3
  * Implements standard security headers and CORS protection
4
4
  * Zero-dependency implementation replacing helmet/cors
5
5
  */
6
+ import { securityConfig } from '../config/security.js';
7
+ const normalizeCorsList = (values, fallback) => {
8
+ const normalized = (values ?? [])
9
+ .map((value) => (typeof value === 'string' ? value.trim() : ''))
10
+ .filter((value) => value !== '');
11
+ return normalized.length > 0 ? normalized : fallback;
12
+ };
13
+ const resolveCorsOrigin = () => {
14
+ const origins = normalizeCorsList(securityConfig.cors.origins, ['*']);
15
+ return origins.includes('*') ? '*' : origins;
16
+ };
6
17
  const DEFAULT_OPTIONS = {
7
18
  hsts: {
8
19
  maxAge: 15552000, // 180 days
@@ -13,13 +24,33 @@ const DEFAULT_OPTIONS = {
13
24
  action: 'SAMEORIGIN',
14
25
  },
15
26
  cors: {
16
- origin: '*',
17
- methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'],
18
- allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'X-CSRF-Token'],
19
- credentials: true,
20
- maxAge: 86400,
27
+ origin: resolveCorsOrigin(),
28
+ methods: normalizeCorsList(securityConfig.cors.methods, [
29
+ 'GET',
30
+ 'HEAD',
31
+ 'PUT',
32
+ 'PATCH',
33
+ 'POST',
34
+ 'DELETE',
35
+ ]),
36
+ allowedHeaders: normalizeCorsList(securityConfig.cors.allowedHeaders, [
37
+ 'Content-Type',
38
+ 'Authorization',
39
+ 'X-Requested-With',
40
+ 'X-CSRF-Token',
41
+ ]),
42
+ credentials: securityConfig.cors.credentials,
43
+ maxAge: securityConfig.cors.maxAge,
21
44
  },
22
45
  };
46
+ const mergeSecurityOptions = (options) => {
47
+ return {
48
+ hsts: { ...DEFAULT_OPTIONS.hsts, ...options.hsts },
49
+ frameguard: { ...DEFAULT_OPTIONS.frameguard, ...options.frameguard },
50
+ cors: { ...DEFAULT_OPTIONS.cors, ...options.cors },
51
+ csp: options.csp ?? DEFAULT_OPTIONS.csp,
52
+ };
53
+ };
23
54
  function applyHsts(res, hsts) {
24
55
  if (!hsts)
25
56
  return;
@@ -73,7 +104,7 @@ function applyCors(req, res, cors) {
73
104
  res.setHeader('Access-Control-Allow-Headers', cors.allowedHeaders.join(', '));
74
105
  }
75
106
  if (cors.credentials !== undefined) {
76
- res.setHeader('Access-Control-Allow-Credentials', 'true');
107
+ res.setHeader('Access-Control-Allow-Credentials', cors.credentials ? 'true' : 'false');
77
108
  }
78
109
  if (cors.maxAge !== undefined) {
79
110
  res.setHeader('Access-Control-Max-Age', cors.maxAge.toString());
@@ -90,7 +121,7 @@ export const SecurityMiddleware = Object.freeze({
90
121
  * Create security middleware with options
91
122
  */
92
123
  create(options = {}) {
93
- const config = { ...DEFAULT_OPTIONS, ...options };
124
+ const config = mergeSecurityOptions(options);
94
125
  return async (req, res, next) => {
95
126
  applyHsts(res, config.hsts);
96
127
  applyFrameguard(res, config.frameguard);
@@ -1,12 +1,17 @@
1
+ import { type MiddlewareFailureResponder } from './MiddlewareFailureResponder';
1
2
  import type { Middleware } from './MiddlewareStack';
2
3
  import type { ISchema, TypedSchema } from '../validation/Validator';
4
+ type ValidationMiddlewareOptions = Readonly<{
5
+ onFailure?: MiddlewareFailureResponder;
6
+ middlewareKey?: string;
7
+ }>;
3
8
  type FieldSanitizers = Readonly<Record<string, (value: unknown) => unknown>>;
4
9
  export declare const ValidationMiddleware: Readonly<{
5
- create(schema: ISchema): Middleware;
6
- createBody<TSchema extends TypedSchema<unknown>>(schema: TSchema): Middleware;
7
- createBodyWithSanitization<TSchema extends TypedSchema<unknown>>(schema: TSchema, sanitizers?: FieldSanitizers): Middleware;
8
- createQuery<TSchema extends TypedSchema<unknown>>(schema: TSchema): Middleware;
9
- createParams<TSchema extends TypedSchema<unknown>>(schema: TSchema): Middleware;
10
+ create(schema: ISchema, options?: ValidationMiddlewareOptions): Middleware;
11
+ createBody<TSchema extends TypedSchema<unknown>>(schema: TSchema, options?: ValidationMiddlewareOptions): Middleware;
12
+ createBodyWithSanitization<TSchema extends TypedSchema<unknown>>(schema: TSchema, sanitizers?: FieldSanitizers, options?: ValidationMiddlewareOptions): Middleware;
13
+ createQuery<TSchema extends TypedSchema<unknown>>(schema: TSchema, options?: ValidationMiddlewareOptions): Middleware;
14
+ createParams<TSchema extends TypedSchema<unknown>>(schema: TSchema, options?: ValidationMiddlewareOptions): Middleware;
10
15
  /**
11
16
  * Create body validation middleware with bulletproof sanitization error handling.
12
17
  * Automatically converts SanitizerError to 422 validation response.
@@ -19,7 +24,7 @@ export declare const ValidationMiddleware: Readonly<{
19
24
  * @param sanitizers - Optional field sanitizers to apply before validation
20
25
  * @returns Middleware with bulletproof error handling
21
26
  */
22
- createBodyWithBulletproofSanitization<TSchema extends TypedSchema<unknown>>(schema: TSchema, sanitizers?: FieldSanitizers): Middleware;
27
+ createBodyWithBulletproofSanitization<TSchema extends TypedSchema<unknown>>(schema: TSchema, sanitizers?: FieldSanitizers, options?: ValidationMiddlewareOptions): Middleware;
23
28
  }>;
24
29
  export {};
25
30
  //# sourceMappingURL=ValidationMiddleware.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ValidationMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/ValidationMiddleware.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,KAAK,EAAe,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAW/E,KAAK,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC;AAqG7E,eAAO,MAAM,oBAAoB;mBAChB,OAAO,GAAG,UAAU;eAwBxB,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UAAU,OAAO,GAAG,UAAU;+BA0BlD,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UACrD,OAAO,eACF,eAAe,GAC3B,UAAU;gBA6BD,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UAAU,OAAO,GAAG,UAAU;iBAejE,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UAAU,OAAO,GAAG,UAAU;IAe/E;;;;;;;;;;;OAWG;0CACmC,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UAChE,OAAO,eACF,eAAe,GAC3B,UAAU;EAqCb,CAAC"}
1
+ {"version":3,"file":"ValidationMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/ValidationMiddleware.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,KAAK,EAAe,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAI/E,KAAK,2BAA2B,GAAG,QAAQ,CAAC;IAC1C,SAAS,CAAC,EAAE,0BAA0B,CAAC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC,CAAC;AAQH,KAAK,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC;AA+H7E,eAAO,MAAM,oBAAoB;mBAChB,OAAO,YAAW,2BAA2B,GAAQ,UAAU;eAwBnE,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UACrC,OAAO,YACN,2BAA2B,GACnC,UAAU;+BA0Bc,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UACrD,OAAO,eACF,eAAe,YACnB,2BAA2B,GACnC,UAAU;gBA6BD,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UACtC,OAAO,YACN,2BAA2B,GACnC,UAAU;iBAeA,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UACvC,OAAO,YACN,2BAA2B,GACnC,UAAU;IAeb;;;;;;;;;;;OAWG;0CACmC,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,UAChE,OAAO,eACF,eAAe,YACnB,2BAA2B,GACnC,UAAU;EA4Cb,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { Env } from '../config/env.js';
2
2
  import { Logger } from '../config/logger.js';
3
+ import { respondWithMiddlewareFailure, } from './MiddlewareFailureResponder.js';
3
4
  import { Xss } from '../security/Xss.js';
4
5
  import { Validator } from '../validation/Validator.js';
5
6
  const toRecord = (value) => {
@@ -73,7 +74,7 @@ const getBodyForValidation = (req) => {
73
74
  const raw = safeCall(() => req.getBody?.());
74
75
  return toBodyRecord(raw);
75
76
  };
76
- const handleValidationError = (res, error) => {
77
+ const handleValidationError = async (req, res, error, options) => {
77
78
  // Temporary: log validation error details to help debugging failing requests.
78
79
  // Remove this detailed debug logging once the issue is investigated.
79
80
  Logger.warn('Validation failed');
@@ -88,21 +89,42 @@ const handleValidationError = (res, error) => {
88
89
  // best-effort: fall back to direct log
89
90
  Logger.debug('[Validation] errors (toObject threw):', err);
90
91
  }
91
- res.setStatus(422).json({ errors: err.toObject() });
92
+ await respondWithMiddlewareFailure(req, res, options.onFailure, {
93
+ middleware: options.middlewareKey ?? 'validation',
94
+ reason: 'validation_error',
95
+ statusCode: 422,
96
+ message: 'Validation failed',
97
+ body: { errors: err.toObject() },
98
+ error,
99
+ });
92
100
  return;
93
101
  }
94
102
  // Fallback: log raw error
95
103
  Logger.debug('[Validation] error:', err);
96
- res.setStatus(400).json({ error: 'Invalid request body' });
104
+ await respondWithMiddlewareFailure(req, res, options.onFailure, {
105
+ middleware: options.middlewareKey ?? 'validation',
106
+ reason: 'invalid_request_body',
107
+ statusCode: 400,
108
+ message: 'Invalid request body',
109
+ body: { error: 'Invalid request body' },
110
+ error,
111
+ });
97
112
  }
98
113
  catch (error_) {
99
114
  // Ensure we don't throw while handling validation errors
100
115
  Logger.debug('[Validation] failed to log error details:', error_);
101
- res.setStatus(400).json({ error: 'Invalid request body' });
116
+ await respondWithMiddlewareFailure(req, res, options.onFailure, {
117
+ middleware: options.middlewareKey ?? 'validation',
118
+ reason: 'invalid_request_body',
119
+ statusCode: 400,
120
+ message: 'Invalid request body',
121
+ body: { error: 'Invalid request body' },
122
+ error,
123
+ });
102
124
  }
103
125
  };
104
126
  export const ValidationMiddleware = Object.freeze({
105
- create(schema) {
127
+ create(schema, options = {}) {
106
128
  return async (req, res, next) => {
107
129
  const method = req.getMethod();
108
130
  if (method === 'GET' || method === 'DELETE') {
@@ -120,11 +142,11 @@ export const ValidationMiddleware = Object.freeze({
120
142
  await next();
121
143
  }
122
144
  catch (error) {
123
- handleValidationError(res, error);
145
+ await handleValidationError(req, res, error, options);
124
146
  }
125
147
  };
126
148
  },
127
- createBody(schema) {
149
+ createBody(schema, options = {}) {
128
150
  return async (req, res, next) => {
129
151
  const method = req.getMethod();
130
152
  if (method === 'GET' || method === 'DELETE') {
@@ -142,11 +164,11 @@ export const ValidationMiddleware = Object.freeze({
142
164
  await next();
143
165
  }
144
166
  catch (error) {
145
- handleValidationError(res, error);
167
+ await handleValidationError(req, res, error, options);
146
168
  }
147
169
  };
148
170
  },
149
- createBodyWithSanitization(schema, sanitizers) {
171
+ createBodyWithSanitization(schema, sanitizers, options = {}) {
150
172
  return async (req, res, next) => {
151
173
  const method = req.getMethod();
152
174
  if (method === 'GET' || method === 'DELETE') {
@@ -165,11 +187,11 @@ export const ValidationMiddleware = Object.freeze({
165
187
  await next();
166
188
  }
167
189
  catch (error) {
168
- handleValidationError(res, error);
190
+ await handleValidationError(req, res, error, options);
169
191
  }
170
192
  };
171
193
  },
172
- createQuery(schema) {
194
+ createQuery(schema, options = {}) {
173
195
  return async (req, res, next) => {
174
196
  try {
175
197
  const query = toRecord(req.getQuery());
@@ -178,11 +200,11 @@ export const ValidationMiddleware = Object.freeze({
178
200
  await next();
179
201
  }
180
202
  catch (error) {
181
- handleValidationError(res, error);
203
+ await handleValidationError(req, res, error, options);
182
204
  }
183
205
  };
184
206
  },
185
- createParams(schema) {
207
+ createParams(schema, options = {}) {
186
208
  return async (req, res, next) => {
187
209
  try {
188
210
  const params = toRecord(req.getParams());
@@ -191,7 +213,7 @@ export const ValidationMiddleware = Object.freeze({
191
213
  await next();
192
214
  }
193
215
  catch (error) {
194
- handleValidationError(res, error);
216
+ await handleValidationError(req, res, error, options);
195
217
  }
196
218
  };
197
219
  },
@@ -207,7 +229,7 @@ export const ValidationMiddleware = Object.freeze({
207
229
  * @param sanitizers - Optional field sanitizers to apply before validation
208
230
  * @returns Middleware with bulletproof error handling
209
231
  */
210
- createBodyWithBulletproofSanitization(schema, sanitizers) {
232
+ createBodyWithBulletproofSanitization(schema, sanitizers, options = {}) {
211
233
  return async (req, res, next) => {
212
234
  const method = req.getMethod();
213
235
  if (method === 'GET' || method === 'DELETE') {
@@ -228,14 +250,21 @@ export const ValidationMiddleware = Object.freeze({
228
250
  catch (error) {
229
251
  // Handle SanitizerError by converting to validation error format
230
252
  if (isSanitizerError(error)) {
231
- res.setStatus(422).json({
232
- errors: {
233
- sanitization: [error.message],
253
+ await respondWithMiddlewareFailure(req, res, options.onFailure, {
254
+ middleware: options.middlewareKey ?? 'validation',
255
+ reason: 'sanitization_error',
256
+ statusCode: 422,
257
+ message: error.message,
258
+ body: {
259
+ errors: {
260
+ sanitization: [error.message],
261
+ },
234
262
  },
263
+ error,
235
264
  });
236
265
  return;
237
266
  }
238
- handleValidationError(res, error);
267
+ await handleValidationError(req, res, error, options);
239
268
  }
240
269
  };
241
270
  },
@@ -5,6 +5,7 @@
5
5
  export * from './CsrfMiddleware';
6
6
  export * from './ErrorHandlerMiddleware';
7
7
  export * from './LoggingMiddleware';
8
+ export * from './MiddlewareFailureResponder';
8
9
  export * from './MiddlewareStack';
9
10
  export * from './RateLimiter';
10
11
  export * from './SecurityMiddleware';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/middleware/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oCAAoC,CAAC;AACnD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/middleware/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oCAAoC,CAAC;AACnD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC"}
@@ -5,6 +5,7 @@
5
5
  export * from './CsrfMiddleware.js';
6
6
  export * from './ErrorHandlerMiddleware.js';
7
7
  export * from './LoggingMiddleware.js';
8
+ export * from './MiddlewareFailureResponder.js';
8
9
  export * from './MiddlewareStack.js';
9
10
  export * from './RateLimiter.js';
10
11
  export * from './SecurityMiddleware.js';
@@ -1 +1 @@
1
- {"version":3,"file":"RuntimeAdapter.d.ts","sourceRoot":"","sources":["../../../src/runtime/RuntimeAdapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RuntimeAdapter.d.ts","sourceRoot":"","sources":["../../../src/runtime/RuntimeAdapter.ts"],"names":[],"mappings":"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"}
@@ -159,8 +159,18 @@ const applyWriteHead = (responseData, statusCode, headers) => {
159
159
  };
160
160
  const resData = (responseData, request) => {
161
161
  return {
162
- statusCode: 200,
163
- headers: responseData.headers,
162
+ get statusCode() {
163
+ return responseData.statusCode;
164
+ },
165
+ set statusCode(value) {
166
+ responseData.statusCode = value;
167
+ },
168
+ get headers() {
169
+ return responseData.headers;
170
+ },
171
+ set headers(value) {
172
+ responseData.headers = value;
173
+ },
164
174
  writeHead: function (statusCode, headers) {
165
175
  this._writer = applyWriteHead(responseData, statusCode, headers);
166
176
  // Handle abortion if signal is present
@@ -1 +1 @@
1
- {"version":3,"file":"WorkersModule.d.ts","sourceRoot":"","sources":["../../../src/runtime/WorkersModule.ts"],"names":[],"mappings":"AAOA,KAAK,aAAa,GAAG,cAAc,mBAAmB,CAAC,CAAC;AACxD,KAAK,kBAAkB,GAAG,cAAc,yBAAyB,CAAC,CAAC;AA4WnE,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,aAAa,CAwB/D,CAAC;AA4CF,eAAO,MAAM,sBAAsB,QAAa,OAAO,CAAC,kBAAkB,CAkBzE,CAAC"}
1
+ {"version":3,"file":"WorkersModule.d.ts","sourceRoot":"","sources":["../../../src/runtime/WorkersModule.ts"],"names":[],"mappings":"AAOA,KAAK,aAAa,GAAG,cAAc,mBAAmB,CAAC,CAAC;AACxD,KAAK,kBAAkB,GAAG,cAAc,yBAAyB,CAAC,CAAC;AA8WnE,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,aAAa,CAwB/D,CAAC;AA4CF,eAAO,MAAM,sBAAsB,QAAa,OAAO,CAAC,kBAAkB,CAkBzE,CAAC"}
@@ -268,6 +268,7 @@ const isMissingOptionalWorkersModuleError = (error) => {
268
268
  });
269
269
  };
270
270
  const handleImportFailure = async (error) => {
271
+ let finalError = error;
271
272
  if (shouldRetryAfterFailure(error)) {
272
273
  patchAfterFailureAttempted = true;
273
274
  const { replacements, filesChanged } = patchWorkersDist();
@@ -281,7 +282,7 @@ const handleImportFailure = async (error) => {
281
282
  return await workersModulePromise;
282
283
  }
283
284
  catch (retryError) {
284
- error = retryError;
285
+ finalError = retryError;
285
286
  }
286
287
  }
287
288
  }
@@ -290,12 +291,12 @@ const handleImportFailure = async (error) => {
290
291
  workersModulePromise = Promise.resolve(localFallback);
291
292
  return localFallback;
292
293
  }
293
- if (isMissingOptionalWorkersModuleError(error)) {
294
+ if (isMissingOptionalWorkersModuleError(finalError)) {
294
295
  Logger.info('Optional @zintrust/workers package is unavailable; worker routes are disabled.');
295
296
  workersModulePromise = Promise.resolve(createDisabledWorkersModule());
296
297
  return workersModulePromise;
297
298
  }
298
- throw error;
299
+ throw finalError;
299
300
  };
300
301
  const tryLocalFallback = async () => {
301
302
  const localFallback = await importLocalWorkersModule();
@@ -2,8 +2,8 @@
2
2
  * XSS Sanitizer
3
3
  * Recursive, zero-dependency input sanitization utility.
4
4
  *
5
- * This is intentionally conservative:
6
- * - Strings: strip tags, then escape HTML entities.
5
+ * This is intentionally conservative for request-body handling:
6
+ * - Strings: strip markup tags but preserve plain text characters.
7
7
  * - Arrays/Objects: sanitize recursively.
8
8
  */
9
9
  export interface IXss {
@@ -1 +1 @@
1
- {"version":3,"file":"Xss.d.ts","sourceRoot":"","sources":["../../../src/security/Xss.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAwDH,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;CACnC;AAED,eAAO,MAAM,GAAG,EAAE,IAIhB,CAAC;AAEH,eAAe,GAAG,CAAC"}
1
+ {"version":3,"file":"Xss.d.ts","sourceRoot":"","sources":["../../../src/security/Xss.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAsDH,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;CACnC;AAED,eAAO,MAAM,GAAG,EAAE,IAIhB,CAAC;AAEH,eAAe,GAAG,CAAC"}