@morojs/moro 1.7.27 → 1.7.29
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.
- package/dist/core/config/config-sources.js +62 -4
- package/dist/core/config/config-sources.js.map +1 -1
- package/dist/core/config/config-validator.js +26 -0
- package/dist/core/config/config-validator.js.map +1 -1
- package/dist/core/config/schema.js +11 -1
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/framework.d.ts +0 -1
- package/dist/core/framework.js +14 -25
- package/dist/core/framework.js.map +1 -1
- package/dist/core/http/http-server.d.ts +124 -12
- package/dist/core/http/http-server.js +1067 -833
- package/dist/core/http/http-server.js.map +1 -1
- package/dist/core/http/uws-http-server.d.ts +72 -5
- package/dist/core/http/uws-http-server.js +718 -150
- package/dist/core/http/uws-http-server.js.map +1 -1
- package/dist/core/logger/logger.d.ts +9 -2
- package/dist/core/logger/logger.js +114 -15
- package/dist/core/logger/logger.js.map +1 -1
- package/dist/core/middleware/built-in/compression/core.js +47 -29
- package/dist/core/middleware/built-in/compression/core.js.map +1 -1
- package/dist/core/middleware/built-in/error-tracker/middleware.d.ts +5 -2
- package/dist/core/middleware/built-in/error-tracker/middleware.js +13 -11
- package/dist/core/middleware/built-in/error-tracker/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/index.d.ts +3 -3
- package/dist/core/middleware/built-in/performance-monitor/middleware.d.ts +2 -1
- package/dist/core/middleware/built-in/performance-monitor/middleware.js +7 -6
- package/dist/core/middleware/built-in/performance-monitor/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/request-logger/middleware.d.ts +2 -1
- package/dist/core/middleware/built-in/request-logger/middleware.js +5 -5
- package/dist/core/middleware/built-in/request-logger/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/validation/core.js +61 -27
- package/dist/core/middleware/built-in/validation/core.js.map +1 -1
- package/dist/core/routing/radix-tree.d.ts +1 -0
- package/dist/core/routing/radix-tree.js +48 -10
- package/dist/core/routing/radix-tree.js.map +1 -1
- package/dist/core/routing/unified-router.d.ts +16 -0
- package/dist/core/routing/unified-router.js +39 -12
- package/dist/core/routing/unified-router.js.map +1 -1
- package/dist/core/utilities/hooks.d.ts +2 -0
- package/dist/core/utilities/hooks.js +12 -0
- package/dist/core/utilities/hooks.js.map +1 -1
- package/dist/moro.d.ts +4 -0
- package/dist/moro.js +94 -70
- package/dist/moro.js.map +1 -1
- package/dist/types/config.d.ts +7 -0
- package/package.json +1 -1
|
@@ -18,45 +18,63 @@ export class CompressionCore {
|
|
|
18
18
|
return acceptEncoding.includes('gzip') || acceptEncoding.includes('deflate');
|
|
19
19
|
}
|
|
20
20
|
wrapResponse(req, res) {
|
|
21
|
-
const originalJson = res.json;
|
|
22
21
|
const originalSend = res.send;
|
|
23
22
|
const acceptEncoding = req.headers['accept-encoding'] || '';
|
|
24
|
-
const
|
|
23
|
+
const level = this.level;
|
|
24
|
+
const threshold = this.threshold;
|
|
25
|
+
const pickEncoding = () => acceptEncoding.includes('gzip')
|
|
26
|
+
? 'gzip'
|
|
27
|
+
: acceptEncoding.includes('deflate')
|
|
28
|
+
? 'deflate'
|
|
29
|
+
: null;
|
|
30
|
+
const compressResponse = (data, isJson) => {
|
|
25
31
|
const content = isJson ? JSON.stringify(data) : data;
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
const byteLength = Buffer.isBuffer(content)
|
|
33
|
+
? content.length
|
|
34
|
+
: Buffer.byteLength(content ?? '');
|
|
35
|
+
const encoding = pickEncoding();
|
|
36
|
+
// Below the threshold, or the client can't accept compression: send directly.
|
|
37
|
+
// For JSON we already have the serialized string - ending with it here avoids
|
|
38
|
+
// re-entering res.json, which would JSON.stringify the same data a second time.
|
|
39
|
+
if (byteLength < threshold || !encoding) {
|
|
40
|
+
if (isJson) {
|
|
41
|
+
if (res.headersSent)
|
|
42
|
+
return;
|
|
43
|
+
res.setHeader('Content-Length', byteLength);
|
|
44
|
+
res.end(content);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
return originalSend.call(res, data);
|
|
29
48
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
const buffer = Buffer.isBuffer(content) ? content : Buffer.from(content ?? '');
|
|
50
|
+
// Commit the response headers synchronously, BEFORE the asynchronous gzip. This
|
|
51
|
+
// marks the response as sent (`headersSent === true`) the moment `send`/`json` is
|
|
52
|
+
// called, so the request lifecycle's "no route matched" fallback can't fire and
|
|
53
|
+
// 404 the response while compression is still pending (the race that previously
|
|
54
|
+
// broke any middleware-served compressed response, e.g. the Swagger docs page).
|
|
55
|
+
// The compressed length isn't known yet, so the body streams (chunked) rather
|
|
56
|
+
// than carrying a Content-Length.
|
|
57
|
+
if (!res.headersSent) {
|
|
58
|
+
res.setHeader('Content-Encoding', encoding);
|
|
59
|
+
res.setHeader('Vary', 'Accept-Encoding');
|
|
60
|
+
res.writeHead(res.statusCode || 200);
|
|
41
61
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
res.setHeader('Content-Length', compressed.length);
|
|
50
|
-
}
|
|
51
|
-
res.end(compressed);
|
|
52
|
-
});
|
|
62
|
+
const finish = (err, compressed) => {
|
|
63
|
+
// Headers (including Content-Encoding) are already committed, so we can't fall
|
|
64
|
+
// back to a raw body on the rare compression error — end without one.
|
|
65
|
+
res.end(err ? undefined : compressed);
|
|
66
|
+
};
|
|
67
|
+
if (encoding === 'gzip') {
|
|
68
|
+
zlib.gzip(buffer, { level }, finish);
|
|
53
69
|
}
|
|
54
70
|
else {
|
|
55
|
-
|
|
71
|
+
zlib.deflate(buffer, { level }, finish);
|
|
56
72
|
}
|
|
57
73
|
};
|
|
58
74
|
res.json = function (data) {
|
|
59
|
-
this.
|
|
75
|
+
if (!this.getHeader('Content-Type')) {
|
|
76
|
+
this.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
77
|
+
}
|
|
60
78
|
compressResponse(data, true);
|
|
61
79
|
return this;
|
|
62
80
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../../src/core/middleware/built-in/compression/core.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAQ7B,MAAM,OAAO,eAAe;IAClB,SAAS,CAAS;IAClB,KAAK,CAAS;IACd,MAAM,CAAoD;IAElE,YAAY,UAA8B,EAAE;QAC1C,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,cAAc;QAC1D,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,4BAA4B;QAC7D,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED,cAAc,CAAC,GAAgB,EAAE,GAAiB;QAChD,sBAAsB;QACtB,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;YAC1C,OAAO,KAAK,CAAC;QACf,CAAC;QAED,sCAAsC;QACtC,MAAM,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC;QAC5D,OAAO,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,cAAc,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC/E,CAAC;IAED,YAAY,CAAC,GAAgB,EAAE,GAAiB;QAC9C,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,CAAC;QAC9B,MAAM,
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../../src/core/middleware/built-in/compression/core.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { HttpRequest, HttpResponse } from '../../../../types/http.js';
|
|
1
2
|
/**
|
|
2
3
|
* Error tracking middleware
|
|
3
|
-
* Captures and logs errors that occur during request processing
|
|
4
|
+
* Captures and logs errors that occur during request processing.
|
|
5
|
+
* Errors are logged and re-thrown so the framework's error handling
|
|
6
|
+
* (registered error handler / default 500) still applies.
|
|
4
7
|
*
|
|
5
8
|
* @example
|
|
6
9
|
* ```ts
|
|
@@ -9,4 +12,4 @@
|
|
|
9
12
|
* app.use(errorTracker);
|
|
10
13
|
* ```
|
|
11
14
|
*/
|
|
12
|
-
export declare const errorTracker: (
|
|
15
|
+
export declare const errorTracker: (err: Error, req: HttpRequest, _res: HttpResponse, next: (err?: Error) => void) => void;
|
|
@@ -3,7 +3,9 @@ import { createFrameworkLogger } from '../../../logger/index.js';
|
|
|
3
3
|
const logger = createFrameworkLogger('ErrorTracker');
|
|
4
4
|
/**
|
|
5
5
|
* Error tracking middleware
|
|
6
|
-
* Captures and logs errors that occur during request processing
|
|
6
|
+
* Captures and logs errors that occur during request processing.
|
|
7
|
+
* Errors are logged and re-thrown so the framework's error handling
|
|
8
|
+
* (registered error handler / default 500) still applies.
|
|
7
9
|
*
|
|
8
10
|
* @example
|
|
9
11
|
* ```ts
|
|
@@ -12,15 +14,15 @@ const logger = createFrameworkLogger('ErrorTracker');
|
|
|
12
14
|
* app.use(errorTracker);
|
|
13
15
|
* ```
|
|
14
16
|
*/
|
|
15
|
-
export const errorTracker =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
export const errorTracker = (err, req, _res, next) => {
|
|
18
|
+
logger.error('Request error', 'ErrorTracking', {
|
|
19
|
+
error: err.message,
|
|
20
|
+
stack: err.stack,
|
|
21
|
+
url: req.url,
|
|
22
|
+
method: req.method,
|
|
23
|
+
timestamp: new Date().toISOString(),
|
|
24
|
+
});
|
|
25
|
+
// Pass the error along so downstream error handling still runs
|
|
26
|
+
next(err);
|
|
25
27
|
};
|
|
26
28
|
//# sourceMappingURL=middleware.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../../../src/core/middleware/built-in/error-tracker/middleware.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../../../src/core/middleware/built-in/error-tracker/middleware.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAGjE,MAAM,MAAM,GAAG,qBAAqB,CAAC,cAAc,CAAC,CAAC;AAErD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,GAAU,EACV,GAAgB,EAChB,IAAkB,EAClB,IAA2B,EACrB,EAAE;IACR,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE,eAAe,EAAE;QAC7C,KAAK,EAAE,GAAG,CAAC,OAAO;QAClB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC,CAAC;IACH,+DAA+D;IAC/D,IAAI,CAAC,GAAG,CAAC,CAAC;AACZ,CAAC,CAAC"}
|
|
@@ -53,7 +53,7 @@ export declare const builtInMiddleware: {
|
|
|
53
53
|
range: typeof import("./range/middleware.js").createRangeMiddleware;
|
|
54
54
|
};
|
|
55
55
|
export declare const simpleMiddleware: {
|
|
56
|
-
requestLogger: (
|
|
57
|
-
performanceMonitor: (
|
|
58
|
-
errorTracker: (
|
|
56
|
+
requestLogger: (req: import("../../http/index.js").HttpRequest, res: import("../../http/index.js").HttpResponse, next: () => void) => void;
|
|
57
|
+
performanceMonitor: (req: import("../../http/index.js").HttpRequest, res: import("../../http/index.js").HttpResponse, next: () => void) => void;
|
|
58
|
+
errorTracker: (err: Error, req: import("../../http/index.js").HttpRequest, _res: import("../../http/index.js").HttpResponse, next: (err?: Error) => void) => void;
|
|
59
59
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { HttpRequest, HttpResponse } from '../../../../types/http.js';
|
|
1
2
|
/**
|
|
2
3
|
* Performance monitoring middleware
|
|
3
4
|
* Tracks request duration and logs warnings for slow requests
|
|
@@ -9,4 +10,4 @@
|
|
|
9
10
|
* app.use(performanceMonitor);
|
|
10
11
|
* ```
|
|
11
12
|
*/
|
|
12
|
-
export declare const performanceMonitor: (
|
|
13
|
+
export declare const performanceMonitor: (req: HttpRequest, res: HttpResponse, next: () => void) => void;
|
|
@@ -12,18 +12,19 @@ const logger = createFrameworkLogger('PerformanceMonitor');
|
|
|
12
12
|
* app.use(performanceMonitor);
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
export const performanceMonitor =
|
|
15
|
+
export const performanceMonitor = (req, res, next) => {
|
|
16
16
|
const startTime = Date.now();
|
|
17
|
-
|
|
17
|
+
res.on('finish', () => {
|
|
18
18
|
const duration = Date.now() - startTime;
|
|
19
19
|
// Log slow requests
|
|
20
20
|
if (duration > 1000) {
|
|
21
|
-
logger.warn(`Slow request detected: ${
|
|
22
|
-
path:
|
|
23
|
-
method:
|
|
21
|
+
logger.warn(`Slow request detected: ${req.path} took ${duration}ms`, 'SlowRequest', {
|
|
22
|
+
path: req.path,
|
|
23
|
+
method: req.method,
|
|
24
24
|
duration,
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
-
};
|
|
27
|
+
});
|
|
28
|
+
next();
|
|
28
29
|
};
|
|
29
30
|
//# sourceMappingURL=middleware.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../../../src/core/middleware/built-in/performance-monitor/middleware.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../../../src/core/middleware/built-in/performance-monitor/middleware.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAGjE,MAAM,MAAM,GAAG,qBAAqB,CAAC,oBAAoB,CAAC,CAAC;AAE3D;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,GAAgB,EAAE,GAAiB,EAAE,IAAgB,EAAQ,EAAE;IAChG,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAExC,oBAAoB;QACpB,IAAI,QAAQ,GAAG,IAAI,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CAAC,0BAA0B,GAAG,CAAC,IAAI,SAAS,QAAQ,IAAI,EAAE,aAAa,EAAE;gBAClF,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,QAAQ;aACT,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,EAAE,CAAC;AACT,CAAC,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { HttpRequest, HttpResponse } from '../../../../types/http.js';
|
|
1
2
|
/**
|
|
2
3
|
* Simple request logging middleware
|
|
3
4
|
* Logs incoming requests and their completion time
|
|
@@ -9,4 +10,4 @@
|
|
|
9
10
|
* app.use(requestLogger);
|
|
10
11
|
* ```
|
|
11
12
|
*/
|
|
12
|
-
export declare const requestLogger: (
|
|
13
|
+
export declare const requestLogger: (req: HttpRequest, res: HttpResponse, next: () => void) => void;
|
|
@@ -12,13 +12,13 @@ const logger = createFrameworkLogger('RequestLogger');
|
|
|
12
12
|
* app.use(requestLogger);
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
export const requestLogger =
|
|
15
|
+
export const requestLogger = (req, res, next) => {
|
|
16
16
|
const startTime = Date.now();
|
|
17
|
-
logger.info(`${
|
|
18
|
-
|
|
19
|
-
context.onComplete = () => {
|
|
17
|
+
logger.info(`${req.method} ${req.path}`, 'RequestLogger');
|
|
18
|
+
res.on('finish', () => {
|
|
20
19
|
const duration = Date.now() - startTime;
|
|
21
20
|
logger.info(`Request completed in ${duration}ms`, 'RequestLogger');
|
|
22
|
-
};
|
|
21
|
+
});
|
|
22
|
+
next();
|
|
23
23
|
};
|
|
24
24
|
//# sourceMappingURL=middleware.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../../../src/core/middleware/built-in/request-logger/middleware.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../../../src/core/middleware/built-in/request-logger/middleware.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAGjE,MAAM,MAAM,GAAG,qBAAqB,CAAC,eAAe,CAAC,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAgB,EAAE,GAAiB,EAAE,IAAgB,EAAQ,EAAE;IAC3F,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,EAAE,eAAe,CAAC,CAAC;IAE1D,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,wBAAwB,QAAQ,IAAI,EAAE,eAAe,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,IAAI,EAAE,CAAC;AACT,CAAC,CAAC"}
|
|
@@ -4,6 +4,29 @@ import { normalizeValidationError, } from '../../../validation/schema-interface.
|
|
|
4
4
|
import { handleValidationError, normalizeErrors } from '../../../validation/error-handler.js';
|
|
5
5
|
import { getGlobalConfig } from '../../../config/index.js';
|
|
6
6
|
const logger = createFrameworkLogger('ValidationCore');
|
|
7
|
+
// Schemas that threw from safeParse (async refinements) - always use parseAsync for these
|
|
8
|
+
const asyncOnlySchemas = new WeakSet();
|
|
9
|
+
/**
|
|
10
|
+
* Run a schema against data, preferring the synchronous safeParse fast path
|
|
11
|
+
* (no promise, no exception-based control flow) when the library supports it.
|
|
12
|
+
* Falls back to parseAsync for libraries without safeParse (Joi/Yup adapters)
|
|
13
|
+
* and for schemas with async refinements.
|
|
14
|
+
*/
|
|
15
|
+
function runSchema(schema, data) {
|
|
16
|
+
const s = schema;
|
|
17
|
+
if (typeof s.safeParse === 'function' && !asyncOnlySchemas.has(s)) {
|
|
18
|
+
try {
|
|
19
|
+
const r = s.safeParse(data);
|
|
20
|
+
return r.success ? { success: true, data: r.data } : { success: false, error: r.error };
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// safeParse throws (rather than failing) only when the schema requires
|
|
24
|
+
// async parsing (e.g. zod async refinements) - remember and fall through
|
|
25
|
+
asyncOnlySchemas.add(s);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return s.parseAsync(data).then((d) => ({ success: true, data: d }), (e) => ({ success: false, error: e }));
|
|
29
|
+
}
|
|
7
30
|
// ===== Core Logic =====
|
|
8
31
|
/**
|
|
9
32
|
* ValidationCore - Core validation logic
|
|
@@ -16,16 +39,6 @@ export class ValidationCore {
|
|
|
16
39
|
if (res.headersSent) {
|
|
17
40
|
return false;
|
|
18
41
|
}
|
|
19
|
-
// Get global validation config
|
|
20
|
-
let globalHandler;
|
|
21
|
-
try {
|
|
22
|
-
const globalConfig = getGlobalConfig();
|
|
23
|
-
globalHandler = globalConfig.modules.validation.onError;
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
// Config not initialized yet, use default handler
|
|
27
|
-
globalHandler = undefined;
|
|
28
|
-
}
|
|
29
42
|
try {
|
|
30
43
|
// Order by likelihood and cost: params > query > body > headers
|
|
31
44
|
// Params are fastest (already parsed, small) and most common in REST APIs
|
|
@@ -38,12 +51,15 @@ export class ValidationCore {
|
|
|
38
51
|
break;
|
|
39
52
|
}
|
|
40
53
|
if (hasParams) {
|
|
41
|
-
|
|
42
|
-
|
|
54
|
+
let result = runSchema(config.params, req.params);
|
|
55
|
+
if (typeof result.then === 'function')
|
|
56
|
+
result = await result;
|
|
57
|
+
if (result.success) {
|
|
58
|
+
req.validatedParams = result.data;
|
|
43
59
|
req.params = req.validatedParams;
|
|
44
60
|
}
|
|
45
|
-
|
|
46
|
-
this.handleValidationError(error, 'params', req, res, config.onValidationError
|
|
61
|
+
else {
|
|
62
|
+
this.handleValidationError(result.error, 'params', req, res, config.onValidationError);
|
|
47
63
|
return false;
|
|
48
64
|
}
|
|
49
65
|
}
|
|
@@ -58,34 +74,43 @@ export class ValidationCore {
|
|
|
58
74
|
break;
|
|
59
75
|
}
|
|
60
76
|
if (hasQuery) {
|
|
61
|
-
|
|
62
|
-
|
|
77
|
+
let result = runSchema(config.query, req.query);
|
|
78
|
+
if (typeof result.then === 'function')
|
|
79
|
+
result = await result;
|
|
80
|
+
if (result.success) {
|
|
81
|
+
req.validatedQuery = result.data;
|
|
63
82
|
req.query = req.validatedQuery;
|
|
64
83
|
}
|
|
65
|
-
|
|
66
|
-
this.handleValidationError(error, 'query', req, res, config.onValidationError
|
|
84
|
+
else {
|
|
85
|
+
this.handleValidationError(result.error, 'query', req, res, config.onValidationError);
|
|
67
86
|
return false;
|
|
68
87
|
}
|
|
69
88
|
}
|
|
70
89
|
}
|
|
71
90
|
// Body is expensive (POST/PUT/PATCH only, requires parsing)
|
|
72
91
|
if (config.body !== undefined && req.body !== undefined) {
|
|
73
|
-
|
|
74
|
-
|
|
92
|
+
let result = runSchema(config.body, req.body);
|
|
93
|
+
if (typeof result.then === 'function')
|
|
94
|
+
result = await result;
|
|
95
|
+
if (result.success) {
|
|
96
|
+
req.validatedBody = result.data;
|
|
75
97
|
req.body = req.validatedBody;
|
|
76
98
|
}
|
|
77
|
-
|
|
78
|
-
this.handleValidationError(error, 'body', req, res, config.onValidationError
|
|
99
|
+
else {
|
|
100
|
+
this.handleValidationError(result.error, 'body', req, res, config.onValidationError);
|
|
79
101
|
return false;
|
|
80
102
|
}
|
|
81
103
|
}
|
|
82
104
|
// Headers are rarely validated
|
|
83
105
|
if (config.headers !== undefined && req.headers !== undefined) {
|
|
84
|
-
|
|
85
|
-
|
|
106
|
+
let result = runSchema(config.headers, req.headers);
|
|
107
|
+
if (typeof result.then === 'function')
|
|
108
|
+
result = await result;
|
|
109
|
+
if (result.success) {
|
|
110
|
+
req.validatedHeaders = result.data;
|
|
86
111
|
}
|
|
87
|
-
|
|
88
|
-
this.handleValidationError(error, 'headers', req, res, config.onValidationError
|
|
112
|
+
else {
|
|
113
|
+
this.handleValidationError(result.error, 'headers', req, res, config.onValidationError);
|
|
89
114
|
return false;
|
|
90
115
|
}
|
|
91
116
|
}
|
|
@@ -105,11 +130,20 @@ export class ValidationCore {
|
|
|
105
130
|
return false;
|
|
106
131
|
}
|
|
107
132
|
}
|
|
108
|
-
handleValidationError(error, field, req, res, customHandler
|
|
133
|
+
handleValidationError(error, field, req, res, customHandler) {
|
|
109
134
|
// Don't send error if headers already sent
|
|
110
135
|
if (res.headersSent) {
|
|
111
136
|
return;
|
|
112
137
|
}
|
|
138
|
+
// Resolve the global handler on the error path only - the success path
|
|
139
|
+
// (the overwhelming majority of requests) never touches config
|
|
140
|
+
let globalHandler;
|
|
141
|
+
try {
|
|
142
|
+
globalHandler = getGlobalConfig().modules.validation.onError;
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
globalHandler = undefined;
|
|
146
|
+
}
|
|
113
147
|
const normalizedError = normalizeValidationError(error);
|
|
114
148
|
const errors = normalizeErrors(normalizedError.issues, field);
|
|
115
149
|
handleValidationError(errors, field, req, res, customHandler, globalHandler);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../../src/core/middleware/built-in/validation/core.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,OAAO,EAEL,wBAAwB,GACzB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAC9F,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAG3D,MAAM,MAAM,GAAG,qBAAqB,CAAC,gBAAgB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../../src/core/middleware/built-in/validation/core.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,25 @@ function fastHash(str) {
|
|
|
9
9
|
}
|
|
10
10
|
return hash;
|
|
11
11
|
}
|
|
12
|
+
// Same hash computed over a path slice without allocating the substring
|
|
13
|
+
function fastHashRange(path, start, end) {
|
|
14
|
+
let hash = 0x811c9dc5;
|
|
15
|
+
for (let i = start; i < end; i++) {
|
|
16
|
+
hash ^= path.charCodeAt(i);
|
|
17
|
+
hash = (hash * 0x01000193) >>> 0;
|
|
18
|
+
}
|
|
19
|
+
return hash;
|
|
20
|
+
}
|
|
21
|
+
// Compare a stored segment against a path slice without allocating
|
|
22
|
+
function segmentEqualsRange(segment, path, start, end) {
|
|
23
|
+
if (segment.length !== end - start)
|
|
24
|
+
return false;
|
|
25
|
+
for (let i = start; i < end; i++) {
|
|
26
|
+
if (segment.charCodeAt(i - start) !== path.charCodeAt(i))
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
12
31
|
export class RadixTree {
|
|
13
32
|
root;
|
|
14
33
|
constructor() {
|
|
@@ -20,6 +39,7 @@ export class RadixTree {
|
|
|
20
39
|
paramName: null,
|
|
21
40
|
handler: null,
|
|
22
41
|
paramPath: null,
|
|
42
|
+
collisionNext: null,
|
|
23
43
|
};
|
|
24
44
|
}
|
|
25
45
|
/**
|
|
@@ -60,6 +80,7 @@ export class RadixTree {
|
|
|
60
80
|
paramName: paramName,
|
|
61
81
|
handler: null,
|
|
62
82
|
paramPath: null,
|
|
83
|
+
collisionNext: null,
|
|
63
84
|
};
|
|
64
85
|
}
|
|
65
86
|
node = node.paramChild;
|
|
@@ -87,6 +108,7 @@ export class RadixTree {
|
|
|
87
108
|
paramName: null,
|
|
88
109
|
handler: null,
|
|
89
110
|
paramPath: null,
|
|
111
|
+
collisionNext: null,
|
|
90
112
|
};
|
|
91
113
|
node.staticChildren.set(segmentHash, child);
|
|
92
114
|
node = child;
|
|
@@ -102,15 +124,27 @@ export class RadixTree {
|
|
|
102
124
|
paramName: null,
|
|
103
125
|
handler: null,
|
|
104
126
|
paramPath: null,
|
|
127
|
+
collisionNext: null,
|
|
105
128
|
};
|
|
106
129
|
node.staticChildren.set(segmentHash, child);
|
|
107
130
|
}
|
|
108
131
|
else {
|
|
109
|
-
//
|
|
110
|
-
if
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
132
|
+
// FNV hash collision: walk the sibling chain for a true segment match,
|
|
133
|
+
// appending a new node if this exact segment isn't chained yet
|
|
134
|
+
while (child.segment !== segment) {
|
|
135
|
+
if (!child.collisionNext) {
|
|
136
|
+
child.collisionNext = {
|
|
137
|
+
segmentHash,
|
|
138
|
+
segment,
|
|
139
|
+
staticChildren: null,
|
|
140
|
+
paramChild: null,
|
|
141
|
+
paramName: null,
|
|
142
|
+
handler: null,
|
|
143
|
+
paramPath: null,
|
|
144
|
+
collisionNext: null,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
child = child.collisionNext;
|
|
114
148
|
}
|
|
115
149
|
}
|
|
116
150
|
node = child;
|
|
@@ -157,11 +191,14 @@ export class RadixTree {
|
|
|
157
191
|
while (segEnd < len && path.charCodeAt(segEnd) !== slashCode) {
|
|
158
192
|
segEnd++;
|
|
159
193
|
}
|
|
160
|
-
|
|
161
|
-
const segmentHash =
|
|
162
|
-
// Direct hash lookup (O(1))
|
|
163
|
-
|
|
164
|
-
|
|
194
|
+
// Hash and compare in place - no substring allocation per segment
|
|
195
|
+
const segmentHash = fastHashRange(path, idx, segEnd);
|
|
196
|
+
// Direct hash lookup (O(1)), walking the collision chain if needed
|
|
197
|
+
let child = node.staticChildren.get(segmentHash);
|
|
198
|
+
while (child && !segmentEqualsRange(child.segment, path, idx, segEnd)) {
|
|
199
|
+
child = child.collisionNext;
|
|
200
|
+
}
|
|
201
|
+
if (child) {
|
|
165
202
|
const result = this.searchNode(child, path, segEnd, paramValues);
|
|
166
203
|
if (result) {
|
|
167
204
|
return result;
|
|
@@ -201,6 +238,7 @@ export class RadixTree {
|
|
|
201
238
|
paramName: null,
|
|
202
239
|
handler: null,
|
|
203
240
|
paramPath: null,
|
|
241
|
+
collisionNext: null,
|
|
204
242
|
};
|
|
205
243
|
}
|
|
206
244
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radix-tree.js","sourceRoot":"","sources":["../../../src/core/routing/radix-tree.ts"],"names":[],"mappings":"AAAA,yDAAyD;
|
|
1
|
+
{"version":3,"file":"radix-tree.js","sourceRoot":"","sources":["../../../src/core/routing/radix-tree.ts"],"names":[],"mappings":"AAAA,yDAAyD;AAqBzD,yDAAyD;AACzD,SAAS,QAAQ,CAAC,GAAW;IAC3B,IAAI,IAAI,GAAG,UAAU,CAAC,CAAC,mBAAmB;IAC1C,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC;IAEvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,qBAAqB;IACzD,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,wEAAwE;AACxE,SAAS,aAAa,CAAC,IAAY,EAAE,KAAa,EAAE,GAAW;IAC7D,IAAI,IAAI,GAAG,UAAU,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACjC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mEAAmE;AACnE,SAAS,kBAAkB,CAAC,OAAe,EAAE,IAAY,EAAE,KAAa,EAAE,GAAW;IACnF,IAAI,OAAO,CAAC,MAAM,KAAK,GAAG,GAAG,KAAK;QAAE,OAAO,KAAK,CAAC;IACjD,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACjC,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IACzE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,OAAO,SAAS;IACZ,IAAI,CAAY;IAExB;QACE,IAAI,CAAC,IAAI,GAAG;YACV,WAAW,EAAE,CAAC;YACd,OAAO,EAAE,EAAE;YACX,cAAc,EAAE,IAAI;YACpB,UAAU,EAAE,IAAI;YAChB,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI;YACf,aAAa,EAAE,IAAI;SACpB,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAY,EAAE,OAAY;QAC/B,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;QACxB,MAAM,UAAU,GAAa,EAAE,CAAC;QAEhC,qBAAqB;QACrB,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;YACzC,CAAC,GAAG,CAAC,CAAC;QACR,CAAC;QAED,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;YACf,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAEpC,8BAA8B;YAC9B,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;gBACpB,CAAC,EAAE,CAAC;gBACJ,SAAS;YACX,CAAC;YAED,iCAAiC;YACjC,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;gBACpB,wCAAwC;gBACxC,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;gBAChB,OAAO,GAAG,GAAG,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC;oBAChD,GAAG,EAAE,CAAC;gBACR,CAAC;gBAED,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;gBACzC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAE3B,+BAA+B;gBAC/B,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;oBACrB,IAAI,CAAC,UAAU,GAAG;wBAChB,WAAW,EAAE,CAAC;wBACd,OAAO,EAAE,EAAE;wBACX,cAAc,EAAE,IAAI;wBACpB,UAAU,EAAE,IAAI;wBAChB,SAAS,EAAE,SAAS;wBACpB,OAAO,EAAE,IAAI;wBACb,SAAS,EAAE,IAAI;wBACf,aAAa,EAAE,IAAI;qBACpB,CAAC;gBACJ,CAAC;gBAED,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;gBACvB,CAAC,GAAG,GAAG,CAAC;gBACR,SAAS;YACX,CAAC;YAED,qDAAqD;YACrD,IAAI,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;YACnB,OAAO,MAAM,GAAG,GAAG,EAAE,CAAC;gBACpB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;gBACrC,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,EAAE;oBAAE,MAAM,CAAC,aAAa;gBACpD,MAAM,EAAE,CAAC;YACX,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YACtC,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;YAEtC,qDAAqD;YACrD,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;gBACzB,IAAI,CAAC,cAAc,GAAG,IAAI,GAAG,EAAE,CAAC;gBAChC,MAAM,KAAK,GAAc;oBACvB,WAAW;oBACX,OAAO;oBACP,cAAc,EAAE,IAAI;oBACpB,UAAU,EAAE,IAAI;oBAChB,SAAS,EAAE,IAAI;oBACf,OAAO,EAAE,IAAI;oBACb,SAAS,EAAE,IAAI;oBACf,aAAa,EAAE,IAAI;iBACpB,CAAC;gBACF,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;gBAC5C,IAAI,GAAG,KAAK,CAAC;YACf,CAAC;iBAAM,CAAC;gBACN,IAAI,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;gBACjD,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,KAAK,GAAG;wBACN,WAAW;wBACX,OAAO;wBACP,cAAc,EAAE,IAAI;wBACpB,UAAU,EAAE,IAAI;wBAChB,SAAS,EAAE,IAAI;wBACf,OAAO,EAAE,IAAI;wBACb,SAAS,EAAE,IAAI;wBACf,aAAa,EAAE,IAAI;qBACpB,CAAC;oBACF,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;gBAC9C,CAAC;qBAAM,CAAC;oBACN,uEAAuE;oBACvE,+DAA+D;oBAC/D,OAAO,KAAK,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;wBACjC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;4BACzB,KAAK,CAAC,aAAa,GAAG;gCACpB,WAAW;gCACX,OAAO;gCACP,cAAc,EAAE,IAAI;gCACpB,UAAU,EAAE,IAAI;gCAChB,SAAS,EAAE,IAAI;gCACf,OAAO,EAAE,IAAI;gCACb,SAAS,EAAE,IAAI;gCACf,aAAa,EAAE,IAAI;6BACpB,CAAC;wBACJ,CAAC;wBACD,KAAK,GAAG,KAAK,CAAC,aAAa,CAAC;oBAC9B,CAAC;gBACH,CAAC;gBACD,IAAI,GAAG,KAAK,CAAC;YACf,CAAC;YAED,CAAC,GAAG,MAAM,CAAC;QACb,CAAC;QAED,4DAA4D;QAC5D,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAY;QACjB,MAAM,WAAW,GAAa,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC;QAEhE,IAAI,MAAM,EAAE,CAAC;YACX,0EAA0E;YAC1E,MAAM,MAAM,GAA2B,EAAE,CAAC;YAC1C,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;gBACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBACjD,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAC7C,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,UAAU,CAChB,IAAe,EACf,IAAY,EACZ,GAAW,EACX,WAAqB;QAErB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;QAExB,eAAe;QACf,OAAO,GAAG,GAAG,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC;YAChD,GAAG,EAAE,CAAC;QACR,CAAC;QAED,gDAAgD;QAChD,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACpC,CAAC;QAED,0DAA0D;QAC1D,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,mEAAmE;YACnE,IAAI,MAAM,GAAG,GAAG,CAAC;YACjB,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC,MAAM;YAC5B,OAAO,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,SAAS,EAAE,CAAC;gBAC7D,MAAM,EAAE,CAAC;YACX,CAAC;YACD,kEAAkE;YAClE,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YAErD,mEAAmE;YACnE,IAAI,KAAK,GAAiC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAC/E,OAAO,KAAK,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC;gBACtE,KAAK,GAAG,KAAK,CAAC,aAAa,CAAC;YAC9B,CAAC;YACD,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;gBACjE,IAAI,MAAM,EAAE,CAAC;oBACX,OAAO,MAAM,CAAC;gBAChB,CAAC;YACH,CAAC;QACH,CAAC;QAED,sBAAsB;QACtB,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,oDAAoD;YACpD,IAAI,GAAG,GAAG,GAAG,CAAC;YACd,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC,MAAM;YAC5B,OAAO,GAAG,GAAG,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;gBACvD,GAAG,EAAE,CAAC;YACR,CAAC;YAED,IAAI,GAAG,GAAG,GAAG,EAAE,CAAC;gBACd,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBACxC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAE7B,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;gBACxE,IAAI,MAAM,EAAE,CAAC;oBACX,OAAO,MAAM,CAAC;gBAChB,CAAC;gBAED,wBAAwB;gBACxB,WAAW,CAAC,GAAG,EAAE,CAAC;YACpB,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,IAAI,GAAG;YACV,WAAW,EAAE,CAAC;YACd,OAAO,EAAE,EAAE;YACX,cAAc,EAAE,IAAI;YACpB,UAAU,EAAE,IAAI;YAChB,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI;YACf,aAAa,EAAE,IAAI;SACpB,CAAC;IACJ,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,iBAAiB;IACpB,KAAK,CAAyB;IAEtC;QACE,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,MAAc,EAAE,IAAY,EAAE,OAAY;QACjD,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,GAAG,IAAI,SAAS,EAAE,CAAC;YACvB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,MAAc,EAAE,IAAY;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF"}
|