@prosopo/api-express-router 2.6.1 → 3.0.4

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 (35) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/dist/apiExpressRouterFactory.js +24 -15
  3. package/dist/cjs/endpointAdapter/apiExpressDefaultEndpointAdapter.cjs +3 -1
  4. package/dist/cjs/index.cjs +5 -0
  5. package/dist/cjs/middlewares/authMiddleware.cjs +84 -0
  6. package/dist/cjs/middlewares/requestLoggerMiddleware.cjs +19 -0
  7. package/dist/endpointAdapter/apiExpressDefaultEndpointAdapter.js +29 -23
  8. package/dist/errorHandler.js +10 -8
  9. package/dist/index.js +12 -4
  10. package/dist/middlewares/authMiddleware.js +84 -0
  11. package/dist/middlewares/requestLoggerMiddleware.js +19 -0
  12. package/package.json +15 -11
  13. package/vite.cjs.config.ts +5 -3
  14. package/vite.esm.config.ts +20 -0
  15. package/vite.test.config.ts +3 -4
  16. package/dist/apiExpressRouterFactory.d.ts +0 -9
  17. package/dist/apiExpressRouterFactory.d.ts.map +0 -1
  18. package/dist/apiExpressRouterFactory.js.map +0 -1
  19. package/dist/endpointAdapter/apiExpressDefaultEndpointAdapter.d.ts +0 -13
  20. package/dist/endpointAdapter/apiExpressDefaultEndpointAdapter.d.ts.map +0 -1
  21. package/dist/endpointAdapter/apiExpressDefaultEndpointAdapter.js.map +0 -1
  22. package/dist/endpointAdapter/apiExpressEndpointAdapter.d.ts +0 -8
  23. package/dist/endpointAdapter/apiExpressEndpointAdapter.d.ts.map +0 -1
  24. package/dist/endpointAdapter/apiExpressEndpointAdapter.js +0 -2
  25. package/dist/endpointAdapter/apiExpressEndpointAdapter.js.map +0 -1
  26. package/dist/errorHandler.d.ts +0 -5
  27. package/dist/errorHandler.d.ts.map +0 -1
  28. package/dist/errorHandler.js.map +0 -1
  29. package/dist/index.d.ts +0 -8
  30. package/dist/index.d.ts.map +0 -1
  31. package/dist/index.js.map +0 -1
  32. package/dist/tests/unit/errorHandler.unit.test.d.ts +0 -2
  33. package/dist/tests/unit/errorHandler.unit.test.d.ts.map +0 -1
  34. package/dist/tests/unit/errorHandler.unit.test.js +0 -140
  35. package/dist/tests/unit/errorHandler.unit.test.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,72 @@
1
1
  # @prosopo/api-express-router
2
2
 
3
+ ## 3.0.4
4
+ ### Patch Changes
5
+
6
+ - 3573f0b: fix npm scripts bundle command
7
+ - 3573f0b: build using vite, typecheck using tsc
8
+ - efd8102: Add tests for unwrap error helper
9
+ - f29fc7e: Refining API error handling. Adding more language strings
10
+ - 3573f0b: standardise all vite based npm scripts for bundling
11
+ - Updated dependencies [3573f0b]
12
+ - Updated dependencies [3573f0b]
13
+ - Updated dependencies [efd8102]
14
+ - Updated dependencies [f29fc7e]
15
+ - Updated dependencies [3573f0b]
16
+ - Updated dependencies [2d0dd8a]
17
+ - @prosopo/api-route@2.6.8
18
+ - @prosopo/common@3.1.0
19
+ - @prosopo/config@3.1.1
20
+
21
+ ## 3.0.3
22
+ ### Patch Changes
23
+
24
+ - 9671152: uuid
25
+
26
+ ## 3.0.2
27
+ ### Patch Changes
28
+
29
+ - @prosopo/common@3.0.2
30
+ - @prosopo/api-route@2.6.7
31
+
32
+ ## 3.0.1
33
+ ### Patch Changes
34
+
35
+ - @prosopo/common@3.0.1
36
+ - @prosopo/api-route@2.6.6
37
+
38
+ ## 3.0.0
39
+ ### Major Changes
40
+
41
+ - 64b5bcd: Access Controls
42
+
43
+ ### Patch Changes
44
+
45
+ - Updated dependencies [64b5bcd]
46
+ - @prosopo/common@3.0.0
47
+ - @prosopo/api-route@2.6.5
48
+
49
+ ## 2.6.4
50
+ ### Patch Changes
51
+
52
+ - 86c22b8: structured logging
53
+ - Updated dependencies [86c22b8]
54
+ - @prosopo/api-route@2.6.4
55
+ - @prosopo/common@2.7.2
56
+
57
+ ## 2.6.3
58
+ ### Patch Changes
59
+
60
+ - @prosopo/common@2.7.1
61
+ - @prosopo/api-route@2.6.3
62
+
63
+ ## 2.6.2
64
+ ### Patch Changes
65
+
66
+ - Updated dependencies [8f0644a]
67
+ - @prosopo/common@2.7.0
68
+ - @prosopo/api-route@2.6.2
69
+
3
70
  ## 2.6.1
4
71
 
5
72
  ### Patch Changes
@@ -1,20 +1,29 @@
1
- import { Router, } from "express";
1
+ import { Router } from "express";
2
2
  import { handleErrors } from "./errorHandler.js";
3
3
  class ApiExpressRouterFactory {
4
- createRouter(routersProvider, apiEndpointAdapter) {
5
- const router = Router();
6
- const apiRoutes = routersProvider.getRoutes();
7
- this.registerRoutes(router, apiRoutes, apiEndpointAdapter);
8
- router.use(handleErrors);
9
- return router;
10
- }
11
- registerRoutes(router, routes, apiEndpointAdapter) {
12
- for (const route of routes) {
13
- router.post(route.path, async (request, response, next) => {
14
- return await apiEndpointAdapter.handleRequest(route.endpoint, request, response, next);
15
- });
4
+ createRouter(routersProvider, apiEndpointAdapter) {
5
+ const router = Router();
6
+ const apiRoutes = routersProvider.getRoutes();
7
+ this.registerRoutes(router, apiRoutes, apiEndpointAdapter);
8
+ router.use(handleErrors);
9
+ return router;
10
+ }
11
+ registerRoutes(router, routes, apiEndpointAdapter) {
12
+ for (const route of routes) {
13
+ router.post(
14
+ route.path,
15
+ async (request, response, next) => {
16
+ return await apiEndpointAdapter.handleRequest(
17
+ route.endpoint,
18
+ request,
19
+ response,
20
+ next
21
+ );
16
22
  }
23
+ );
17
24
  }
25
+ }
18
26
  }
19
- export { ApiExpressRouterFactory };
20
- //# sourceMappingURL=apiExpressRouterFactory.js.map
27
+ export {
28
+ ApiExpressRouterFactory
29
+ };
@@ -24,7 +24,9 @@ class ApiExpressDefaultEndpointAdapter {
24
24
  );
25
25
  response.json(apiEndpointResponse);
26
26
  } catch (error) {
27
- request.logger.error(error.message);
27
+ request.logger.error(() => ({
28
+ err: error
29
+ }));
28
30
  response.status(500).send("An internal server error occurred.");
29
31
  }
30
32
  }
@@ -3,10 +3,15 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const apiExpressRouterFactory$1 = require("./apiExpressRouterFactory.cjs");
4
4
  const apiExpressDefaultEndpointAdapter = require("./endpointAdapter/apiExpressDefaultEndpointAdapter.cjs");
5
5
  const errorHandler = require("./errorHandler.cjs");
6
+ const authMiddleware = require("./middlewares/authMiddleware.cjs");
7
+ const requestLoggerMiddleware = require("./middlewares/requestLoggerMiddleware.cjs");
6
8
  const apiExpressRouterFactory = new apiExpressRouterFactory$1.ApiExpressRouterFactory();
7
9
  const createApiExpressDefaultEndpointAdapter = (logLevel, errorStatusCode = 500) => {
8
10
  return new apiExpressDefaultEndpointAdapter.ApiExpressDefaultEndpointAdapter(logLevel, errorStatusCode);
9
11
  };
10
12
  exports.handleErrors = errorHandler.handleErrors;
13
+ exports.authMiddleware = authMiddleware.authMiddleware;
14
+ exports.verifySignature = authMiddleware.verifySignature;
15
+ exports.requestLoggerMiddleware = requestLoggerMiddleware.requestLoggerMiddleware;
11
16
  exports.apiExpressRouterFactory = apiExpressRouterFactory;
12
17
  exports.createApiExpressDefaultEndpointAdapter = createApiExpressDefaultEndpointAdapter;
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const util = require("@polkadot/util");
4
+ const common = require("@prosopo/common");
5
+ const authMiddleware = (pair, authAccount) => {
6
+ return async (req, res, next) => {
7
+ try {
8
+ const { signature, timestamp } = extractHeaders(req);
9
+ let error;
10
+ if (authAccount) {
11
+ try {
12
+ verifySignature(signature, timestamp, authAccount);
13
+ next();
14
+ return;
15
+ } catch (e) {
16
+ req.logger.warn(() => ({
17
+ err: e,
18
+ data: {
19
+ account: authAccount?.address
20
+ }
21
+ }));
22
+ error = e;
23
+ }
24
+ }
25
+ if (pair) {
26
+ verifySignature(signature, timestamp, pair);
27
+ next();
28
+ return;
29
+ }
30
+ res.status(401).json({
31
+ error: "Unauthorized",
32
+ message: new common.ProsopoEnvError(error || "CONTRACT.CANNOT_FIND_KEYPAIR")
33
+ });
34
+ return;
35
+ } catch (err) {
36
+ req.logger.error(() => ({ err, msg: "Auth Middleware Error" }));
37
+ res.status(401).json({ error: "Unauthorized", message: err });
38
+ return;
39
+ }
40
+ };
41
+ };
42
+ const extractHeaders = (req) => {
43
+ const signature = req.headers.signature;
44
+ const timestamp = req.headers.timestamp;
45
+ if (!timestamp) {
46
+ throw new common.ProsopoApiError("GENERAL.INVALID_TIMESTAMP", {
47
+ context: { error: "Missing timestamp", code: 400 }
48
+ });
49
+ }
50
+ if (!signature) {
51
+ throw new common.ProsopoApiError("GENERAL.INVALID_SIGNATURE", {
52
+ context: { error: "Missing signature", code: 400 }
53
+ });
54
+ }
55
+ if (Array.isArray(signature) || Array.isArray(timestamp) || !util.isHex(signature)) {
56
+ throw new common.ProsopoApiError("CONTRACT.INVALID_DATA_FORMAT", {
57
+ context: { error: "Invalid header format", code: 400 }
58
+ });
59
+ }
60
+ const now = (/* @__PURE__ */ new Date()).getTime();
61
+ const ts = Number.parseInt(timestamp);
62
+ if (now - ts > 3e5) {
63
+ throw new common.ProsopoApiError("GENERAL.INVALID_TIMESTAMP", {
64
+ context: { error: "Timestamp is too old", code: 400 }
65
+ });
66
+ }
67
+ return { signature, timestamp };
68
+ };
69
+ const verifySignature = (signature, message, pair) => {
70
+ const u8Sig = util.hexToU8a(signature);
71
+ if (!pair.verify(message, u8Sig, pair.publicKey)) {
72
+ throw new common.ProsopoApiError("GENERAL.INVALID_SIGNATURE", {
73
+ context: {
74
+ error: "Signature verification failed",
75
+ code: 401,
76
+ account: pair.address,
77
+ message,
78
+ signature
79
+ }
80
+ });
81
+ }
82
+ };
83
+ exports.authMiddleware = authMiddleware;
84
+ exports.verifySignature = verifySignature;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const common = require("@prosopo/common");
4
+ const uuid = require("uuid");
5
+ function requestLoggerMiddleware(env) {
6
+ return (req, res, next) => {
7
+ const requestId = req.headers["x-request-id"] || `e-${uuid.v4()}`;
8
+ const logger = common.getLogger(
9
+ common.parseLogLevel(env.config.logLevel),
10
+ "request-logger"
11
+ ).with({
12
+ requestId
13
+ });
14
+ req.logger = logger;
15
+ req.requestId = requestId;
16
+ next();
17
+ };
18
+ }
19
+ exports.requestLoggerMiddleware = requestLoggerMiddleware;
@@ -1,28 +1,34 @@
1
1
  import { ProsopoApiError } from "@prosopo/common";
2
2
  class ApiExpressDefaultEndpointAdapter {
3
- constructor(logLevel, errorStatusCode) {
4
- this.logLevel = logLevel;
5
- this.errorStatusCode = errorStatusCode;
3
+ constructor(logLevel, errorStatusCode) {
4
+ this.logLevel = logLevel;
5
+ this.errorStatusCode = errorStatusCode;
6
+ }
7
+ async handleRequest(endpoint, request, response, next) {
8
+ let args;
9
+ try {
10
+ args = endpoint.getRequestArgsSchema()?.parse(request.body);
11
+ } catch (error) {
12
+ return next(
13
+ new ProsopoApiError("API.PARSE_ERROR", {
14
+ context: { code: 400, error }
15
+ })
16
+ );
6
17
  }
7
- async handleRequest(endpoint, request, response, next) {
8
- let args;
9
- try {
10
- args = endpoint.getRequestArgsSchema()?.parse(request.body);
11
- }
12
- catch (error) {
13
- return next(new ProsopoApiError("API.PARSE_ERROR", {
14
- context: { code: 400, error: error },
15
- }));
16
- }
17
- try {
18
- const apiEndpointResponse = await endpoint.processRequest(args, request.logger);
19
- response.json(apiEndpointResponse);
20
- }
21
- catch (error) {
22
- request.logger.error(error.message);
23
- response.status(500).send("An internal server error occurred.");
24
- }
18
+ try {
19
+ const apiEndpointResponse = await endpoint.processRequest(
20
+ args,
21
+ request.logger
22
+ );
23
+ response.json(apiEndpointResponse);
24
+ } catch (error) {
25
+ request.logger.error(() => ({
26
+ err: error
27
+ }));
28
+ response.status(500).send("An internal server error occurred.");
25
29
  }
30
+ }
26
31
  }
27
- export { ApiExpressDefaultEndpointAdapter };
28
- //# sourceMappingURL=apiExpressDefaultEndpointAdapter.js.map
32
+ export {
33
+ ApiExpressDefaultEndpointAdapter
34
+ };
@@ -1,10 +1,12 @@
1
1
  import { unwrapError } from "@prosopo/common";
2
- export const handleErrors = (err, request, response, next) => {
3
- const { code, statusMessage, jsonError } = unwrapError(err, request.i18n);
4
- response.statusMessage = statusMessage;
5
- response.set("content-type", "application/json");
6
- response.status(code);
7
- response.send({ error: jsonError });
8
- response.end();
2
+ const handleErrors = (err, request, response, next) => {
3
+ const { code, statusMessage, jsonError } = unwrapError(err, request.i18n);
4
+ response.statusMessage = statusMessage;
5
+ response.set("content-type", "application/json");
6
+ response.status(code);
7
+ response.send({ error: jsonError });
8
+ response.end();
9
+ };
10
+ export {
11
+ handleErrors
9
12
  };
10
- //# sourceMappingURL=errorHandler.js.map
package/dist/index.js CHANGED
@@ -1,9 +1,17 @@
1
1
  import { ApiExpressRouterFactory } from "./apiExpressRouterFactory.js";
2
2
  import { ApiExpressDefaultEndpointAdapter } from "./endpointAdapter/apiExpressDefaultEndpointAdapter.js";
3
+ import { handleErrors } from "./errorHandler.js";
4
+ import { authMiddleware, verifySignature } from "./middlewares/authMiddleware.js";
5
+ import { requestLoggerMiddleware } from "./middlewares/requestLoggerMiddleware.js";
3
6
  const apiExpressRouterFactory = new ApiExpressRouterFactory();
4
7
  const createApiExpressDefaultEndpointAdapter = (logLevel, errorStatusCode = 500) => {
5
- return new ApiExpressDefaultEndpointAdapter(logLevel, errorStatusCode);
8
+ return new ApiExpressDefaultEndpointAdapter(logLevel, errorStatusCode);
9
+ };
10
+ export {
11
+ apiExpressRouterFactory,
12
+ authMiddleware,
13
+ createApiExpressDefaultEndpointAdapter,
14
+ handleErrors,
15
+ requestLoggerMiddleware,
16
+ verifySignature
6
17
  };
7
- export { apiExpressRouterFactory, createApiExpressDefaultEndpointAdapter, };
8
- export * from "./errorHandler.js";
9
- //# sourceMappingURL=index.js.map
@@ -0,0 +1,84 @@
1
+ import { isHex, hexToU8a } from "@polkadot/util";
2
+ import { ProsopoEnvError, ProsopoApiError } from "@prosopo/common";
3
+ const authMiddleware = (pair, authAccount) => {
4
+ return async (req, res, next) => {
5
+ try {
6
+ const { signature, timestamp } = extractHeaders(req);
7
+ let error;
8
+ if (authAccount) {
9
+ try {
10
+ verifySignature(signature, timestamp, authAccount);
11
+ next();
12
+ return;
13
+ } catch (e) {
14
+ req.logger.warn(() => ({
15
+ err: e,
16
+ data: {
17
+ account: authAccount?.address
18
+ }
19
+ }));
20
+ error = e;
21
+ }
22
+ }
23
+ if (pair) {
24
+ verifySignature(signature, timestamp, pair);
25
+ next();
26
+ return;
27
+ }
28
+ res.status(401).json({
29
+ error: "Unauthorized",
30
+ message: new ProsopoEnvError(error || "CONTRACT.CANNOT_FIND_KEYPAIR")
31
+ });
32
+ return;
33
+ } catch (err) {
34
+ req.logger.error(() => ({ err, msg: "Auth Middleware Error" }));
35
+ res.status(401).json({ error: "Unauthorized", message: err });
36
+ return;
37
+ }
38
+ };
39
+ };
40
+ const extractHeaders = (req) => {
41
+ const signature = req.headers.signature;
42
+ const timestamp = req.headers.timestamp;
43
+ if (!timestamp) {
44
+ throw new ProsopoApiError("GENERAL.INVALID_TIMESTAMP", {
45
+ context: { error: "Missing timestamp", code: 400 }
46
+ });
47
+ }
48
+ if (!signature) {
49
+ throw new ProsopoApiError("GENERAL.INVALID_SIGNATURE", {
50
+ context: { error: "Missing signature", code: 400 }
51
+ });
52
+ }
53
+ if (Array.isArray(signature) || Array.isArray(timestamp) || !isHex(signature)) {
54
+ throw new ProsopoApiError("CONTRACT.INVALID_DATA_FORMAT", {
55
+ context: { error: "Invalid header format", code: 400 }
56
+ });
57
+ }
58
+ const now = (/* @__PURE__ */ new Date()).getTime();
59
+ const ts = Number.parseInt(timestamp);
60
+ if (now - ts > 3e5) {
61
+ throw new ProsopoApiError("GENERAL.INVALID_TIMESTAMP", {
62
+ context: { error: "Timestamp is too old", code: 400 }
63
+ });
64
+ }
65
+ return { signature, timestamp };
66
+ };
67
+ const verifySignature = (signature, message, pair) => {
68
+ const u8Sig = hexToU8a(signature);
69
+ if (!pair.verify(message, u8Sig, pair.publicKey)) {
70
+ throw new ProsopoApiError("GENERAL.INVALID_SIGNATURE", {
71
+ context: {
72
+ error: "Signature verification failed",
73
+ code: 401,
74
+ account: pair.address,
75
+ message,
76
+ signature
77
+ }
78
+ });
79
+ }
80
+ };
81
+ export {
82
+ authMiddleware,
83
+ verifySignature
84
+ };
@@ -0,0 +1,19 @@
1
+ import { getLogger, parseLogLevel } from "@prosopo/common";
2
+ import { v4 } from "uuid";
3
+ function requestLoggerMiddleware(env) {
4
+ return (req, res, next) => {
5
+ const requestId = req.headers["x-request-id"] || `e-${v4()}`;
6
+ const logger = getLogger(
7
+ parseLogLevel(env.config.logLevel),
8
+ "request-logger"
9
+ ).with({
10
+ requestId
11
+ });
12
+ req.logger = logger;
13
+ req.requestId = requestId;
14
+ next();
15
+ };
16
+ }
17
+ export {
18
+ requestLoggerMiddleware
19
+ };
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@prosopo/api-express-router",
3
- "version": "2.6.1",
3
+ "version": "3.0.4",
4
4
  "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
5
6
  "type": "module",
6
7
  "engines": {
7
8
  "node": "20",
@@ -9,24 +10,27 @@
9
10
  },
10
11
  "exports": {
11
12
  ".": {
13
+ "types": "./dist/index.d.ts",
12
14
  "import": "./dist/index.js",
13
15
  "require": "./dist/cjs/index.cjs"
14
16
  }
15
17
  },
16
18
  "scripts": {
17
- "test": "NODE_ENV=${NODE_ENV:-test}; npx vitest run --config ./vite.test.config.ts",
18
- "clean": "tsc --build --clean",
19
- "build": "tsc --build --verbose",
20
- "build:cjs": "npx vite --config vite.cjs.config.ts build"
19
+ "clean": "del-cli --verbose dist tsconfig.tsbuildinfo",
20
+ "build": "NODE_ENV=${NODE_ENV:-production}; vite build --config vite.esm.config.ts --mode $NODE_ENV",
21
+ "build:tsc": "tsc --build --verbose",
22
+ "build:cjs": "NODE_ENV=${NODE_ENV:-production}; vite build --config vite.cjs.config.ts --mode $NODE_ENV",
23
+ "typecheck": "tsc --build --declaration --emitDeclarationOnly",
24
+ "test": "NODE_ENV=${NODE_ENV:-test}; npx vitest run --config ./vite.test.config.ts"
21
25
  },
22
26
  "dependencies": {
23
- "@prosopo/api-route": "2.6.1",
24
- "@prosopo/common": "2.6.1",
25
- "zod": "3.23.8"
26
- },
27
- "devDependencies": {
28
- "@prosopo/config": "2.6.0"
27
+ "@prosopo/api-route": "2.6.8",
28
+ "@prosopo/common": "3.1.0",
29
+ "uuid": "11.1.0",
30
+ "zod": "3.23.8",
31
+ "@prosopo/config": "3.1.1"
29
32
  },
33
+ "devDependencies": {},
30
34
  "author": "PROSOPO LIMITED <info@prosopo.io>",
31
35
  "license": "Apache-2.0",
32
36
  "bugs": {
@@ -1,3 +1,4 @@
1
+ import path from "node:path";
1
2
  // Copyright 2021-2025 Prosopo (UK) Ltd.
2
3
  //
3
4
  // Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,10 +12,11 @@
11
12
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
13
  // See the License for the specific language governing permissions and
13
14
  // limitations under the License.
14
-
15
- import path from "node:path";
16
15
  import { ViteCommonJSConfig } from "@prosopo/config";
17
16
 
18
17
  export default function () {
19
- return ViteCommonJSConfig("api-route", path.resolve("./tsconfig.cjs.json"));
18
+ return ViteCommonJSConfig(
19
+ path.basename("."),
20
+ path.resolve("./tsconfig.json"),
21
+ );
20
22
  }
@@ -0,0 +1,20 @@
1
+ // Copyright 2021-2025 Prosopo (UK) Ltd.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ import path from "node:path";
16
+ import { ViteEsmConfig } from "@prosopo/config";
17
+
18
+ export default function () {
19
+ return ViteEsmConfig(path.basename("."), path.resolve("./tsconfig.json"));
20
+ }
@@ -1,3 +1,5 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
1
3
  // Copyright 2021-2025 Prosopo (UK) Ltd.
2
4
  //
3
5
  // Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,9 +13,6 @@
11
13
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
14
  // See the License for the specific language governing permissions and
13
15
  // limitations under the License.
14
-
15
- import fs from "node:fs";
16
- import path from "node:path";
17
16
  import { ViteTestConfig } from "@prosopo/config";
18
17
  import dotenv from "dotenv";
19
18
  process.env.NODE_ENV = "test";
@@ -30,4 +29,4 @@ if (fs.existsSync(envFile)) {
30
29
 
31
30
  dotenv.config({ path: envPath });
32
31
 
33
- export default ViteTestConfig;
32
+ export default ViteTestConfig();
@@ -1,9 +0,0 @@
1
- import type { ApiRoute, ApiRoutesProvider } from "@prosopo/api-route";
2
- import { Router } from "express";
3
- import type { ApiExpressEndpointAdapter } from "./endpointAdapter/apiExpressEndpointAdapter.js";
4
- declare class ApiExpressRouterFactory {
5
- createRouter(routersProvider: ApiRoutesProvider, apiEndpointAdapter: ApiExpressEndpointAdapter): Router;
6
- protected registerRoutes(router: Router, routes: ApiRoute[], apiEndpointAdapter: ApiExpressEndpointAdapter): void;
7
- }
8
- export { ApiExpressRouterFactory };
9
- //# sourceMappingURL=apiExpressRouterFactory.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"apiExpressRouterFactory.d.ts","sourceRoot":"","sources":["../src/apiExpressRouterFactory.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAIN,MAAM,EACN,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gDAAgD,CAAC;AAGhG,cAAM,uBAAuB;IACrB,YAAY,CAClB,eAAe,EAAE,iBAAiB,EAClC,kBAAkB,EAAE,yBAAyB,GAC3C,MAAM;IAcT,SAAS,CAAC,cAAc,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,QAAQ,EAAE,EAClB,kBAAkB,EAAE,yBAAyB,GAC3C,IAAI;CAmBP;AAED,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"apiExpressRouterFactory.js","sourceRoot":"","sources":["../src/apiExpressRouterFactory.ts"],"names":[],"mappings":"AAeA,OAAO,EAIN,MAAM,GACN,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,uBAAuB;IACrB,YAAY,CAClB,eAAkC,EAClC,kBAA6C;QAE7C,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;QACxB,MAAM,SAAS,GAAG,eAAe,CAAC,SAAS,EAAE,CAAC;QAE9C,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,kBAAkB,CAAC,CAAC;QAK3D,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAEzB,OAAO,MAAM,CAAC;IACf,CAAC;IAES,cAAc,CACvB,MAAc,EACd,MAAkB,EAClB,kBAA6C;QAE7C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC5B,MAAM,CAAC,IAAI,CACV,KAAK,CAAC,IAAI,EACV,KAAK,EACJ,OAAgB,EAChB,QAAkB,EAClB,IAAkB,EACF,EAAE;gBAClB,OAAO,MAAM,kBAAkB,CAAC,aAAa,CAC5C,KAAK,CAAC,QAAQ,EACd,OAAO,EACP,QAAQ,EACR,IAAI,CACJ,CAAC;YACH,CAAC,CACD,CAAC;QACH,CAAC;IACF,CAAC;CACD;AAED,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
@@ -1,13 +0,0 @@
1
- import type { ApiEndpoint } from "@prosopo/api-route";
2
- import { type LogLevel } from "@prosopo/common";
3
- import type { NextFunction, Request, Response } from "express";
4
- import type { ZodType } from "zod";
5
- import type { ApiExpressEndpointAdapter } from "./apiExpressEndpointAdapter.js";
6
- declare class ApiExpressDefaultEndpointAdapter implements ApiExpressEndpointAdapter {
7
- private readonly logLevel;
8
- private readonly errorStatusCode;
9
- constructor(logLevel: LogLevel, errorStatusCode: number);
10
- handleRequest(endpoint: ApiEndpoint<ZodType | undefined>, request: Request, response: Response, next: NextFunction): Promise<void>;
11
- }
12
- export { ApiExpressDefaultEndpointAdapter };
13
- //# sourceMappingURL=apiExpressDefaultEndpointAdapter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"apiExpressDefaultEndpointAdapter.d.ts","sourceRoot":"","sources":["../../src/endpointAdapter/apiExpressDefaultEndpointAdapter.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,KAAK,QAAQ,EAAmB,MAAM,iBAAiB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACnC,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAEhF,cAAM,gCAAiC,YAAW,yBAAyB;IAEzE,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,eAAe;gBADf,QAAQ,EAAE,QAAQ,EAClB,eAAe,EAAE,MAAM;IAG5B,aAAa,CACzB,QAAQ,EAAE,WAAW,CAAC,OAAO,GAAG,SAAS,CAAC,EAC1C,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,YAAY,GAChB,OAAO,CAAC,IAAI,CAAC;CAyBhB;AAED,OAAO,EAAE,gCAAgC,EAAE,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"apiExpressDefaultEndpointAdapter.js","sourceRoot":"","sources":["../../src/endpointAdapter/apiExpressDefaultEndpointAdapter.ts"],"names":[],"mappings":"AAeA,OAAO,EAAiB,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAKjE,MAAM,gCAAgC;IACrC,YACkB,QAAkB,EAClB,eAAuB;QADvB,aAAQ,GAAR,QAAQ,CAAU;QAClB,oBAAe,GAAf,eAAe,CAAQ;IACtC,CAAC;IAEG,KAAK,CAAC,aAAa,CACzB,QAA0C,EAC1C,OAAgB,EAChB,QAAkB,EAClB,IAAkB;QAElB,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACJ,IAAI,GAAG,QAAQ,CAAC,oBAAoB,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,IAAI,CACV,IAAI,eAAe,CAAC,iBAAiB,EAAE;gBACtC,OAAO,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE;aACpC,CAAC,CACF,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACJ,MAAM,mBAAmB,GAAG,MAAM,QAAQ,CAAC,cAAc,CACxD,IAAI,EACJ,OAAO,CAAC,MAAM,CACd,CAAC;YAEF,QAAQ,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAE,KAAe,CAAC,OAAO,CAAC,CAAC;YAE/C,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;QACjE,CAAC;IACF,CAAC;CACD;AAED,OAAO,EAAE,gCAAgC,EAAE,CAAC"}
@@ -1,8 +0,0 @@
1
- import type { ApiEndpoint } from "@prosopo/api-route";
2
- import type { NextFunction, Request, Response } from "express";
3
- import type { ZodType } from "zod";
4
- interface ApiExpressEndpointAdapter {
5
- handleRequest(endpoint: ApiEndpoint<ZodType | undefined>, request: Request, response: Response, next: NextFunction): Promise<void>;
6
- }
7
- export type { ApiExpressEndpointAdapter };
8
- //# sourceMappingURL=apiExpressEndpointAdapter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"apiExpressEndpointAdapter.d.ts","sourceRoot":"","sources":["../../src/endpointAdapter/apiExpressEndpointAdapter.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAEnC,UAAU,yBAAyB;IAClC,aAAa,CACZ,QAAQ,EAAE,WAAW,CAAC,OAAO,GAAG,SAAS,CAAC,EAC1C,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,YAAY,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;CACjB;AAED,YAAY,EAAE,yBAAyB,EAAE,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=apiExpressEndpointAdapter.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"apiExpressEndpointAdapter.js","sourceRoot":"","sources":["../../src/endpointAdapter/apiExpressEndpointAdapter.ts"],"names":[],"mappings":""}
@@ -1,5 +0,0 @@
1
- import { type ProsopoApiError } from "@prosopo/common";
2
- import type { NextFunction, Request, Response } from "express";
3
- import type { ZodError } from "zod";
4
- export declare const handleErrors: (err: ProsopoApiError | SyntaxError | ZodError, request: Request, response: Response, next: NextFunction) => void;
5
- //# sourceMappingURL=errorHandler.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"errorHandler.d.ts","sourceRoot":"","sources":["../src/errorHandler.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,KAAK,eAAe,EAAe,MAAM,iBAAiB,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAEpC,eAAO,MAAM,YAAY,QACnB,eAAe,GAAG,WAAW,GAAG,QAAQ,WACpC,OAAO,YACN,QAAQ,QACZ,YAAY,SAQlB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"errorHandler.js","sourceRoot":"","sources":["../src/errorHandler.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAwB,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAIpE,MAAM,CAAC,MAAM,YAAY,GAAG,CAC3B,GAA6C,EAC7C,OAAgB,EAChB,QAAkB,EAClB,IAAkB,EACjB,EAAE;IACH,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,QAAQ,CAAC,aAAa,GAAG,aAAa,CAAC;IACvC,QAAQ,CAAC,GAAG,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IACjD,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC,CAAC"}
package/dist/index.d.ts DELETED
@@ -1,8 +0,0 @@
1
- import type { LogLevel } from "@prosopo/common";
2
- import { ApiExpressRouterFactory } from "./apiExpressRouterFactory.js";
3
- import type { ApiExpressEndpointAdapter } from "./endpointAdapter/apiExpressEndpointAdapter.js";
4
- declare const apiExpressRouterFactory: ApiExpressRouterFactory;
5
- declare const createApiExpressDefaultEndpointAdapter: (logLevel: LogLevel, errorStatusCode?: number) => ApiExpressEndpointAdapter;
6
- export { apiExpressRouterFactory, createApiExpressDefaultEndpointAdapter, type ApiExpressEndpointAdapter, };
7
- export * from "./errorHandler.js";
8
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gDAAgD,CAAC;AAEhG,QAAA,MAAM,uBAAuB,yBAAgC,CAAC;AAE9D,QAAA,MAAM,sCAAsC,aACjC,QAAQ,+BAEhB,yBAEF,CAAC;AAEF,OAAO,EACN,uBAAuB,EACvB,sCAAsC,EACtC,KAAK,yBAAyB,GAC9B,CAAC;AAEF,cAAc,mBAAmB,CAAC"}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,gCAAgC,EAAE,MAAM,uDAAuD,CAAC;AAGzG,MAAM,uBAAuB,GAAG,IAAI,uBAAuB,EAAE,CAAC;AAE9D,MAAM,sCAAsC,GAAG,CAC9C,QAAkB,EAClB,eAAe,GAAG,GAAG,EACO,EAAE;IAC9B,OAAO,IAAI,gCAAgC,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;AACxE,CAAC,CAAC;AAEF,OAAO,EACN,uBAAuB,EACvB,sCAAsC,GAEtC,CAAC;AAEF,cAAc,mBAAmB,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=errorHandler.unit.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"errorHandler.unit.test.d.ts","sourceRoot":"","sources":["../../../src/tests/unit/errorHandler.unit.test.ts"],"names":[],"mappings":""}
@@ -1,140 +0,0 @@
1
- import { ProsopoApiError, ProsopoEnvError } from "@prosopo/common";
2
- import { loadI18next } from "@prosopo/locale";
3
- import { describe, expect, it, vi } from "vitest";
4
- import { ZodError } from "zod";
5
- import { handleErrors } from "../../errorHandler.js";
6
- describe("handleErrors", async () => {
7
- const i18n = await loadI18next(true);
8
- await i18n.changeLanguage("en");
9
- it("should handle ProsopoApiError", async () => {
10
- const mockRequest = { i18n };
11
- const mockResponse = {
12
- writeHead: vi.fn().mockReturnThis(),
13
- set: vi.fn().mockReturnThis(),
14
- status: vi.fn().mockReturnThis(),
15
- send: vi.fn(),
16
- end: vi.fn(),
17
- };
18
- const mockNext = vi.fn();
19
- const error = new ProsopoApiError("CONTRACT.INVALID_DATA_FORMAT", {
20
- context: { code: 400 },
21
- i18n,
22
- });
23
- console.log(error);
24
- handleErrors(error, mockRequest, mockResponse, mockNext);
25
- expect(mockResponse.set).toHaveBeenCalledWith("content-type", "application/json");
26
- expect(mockResponse.send).toHaveBeenCalledWith({
27
- error: {
28
- code: 400,
29
- key: "CONTRACT.INVALID_DATA_FORMAT",
30
- message: "Invalid data format",
31
- },
32
- });
33
- expect(mockResponse.status).toHaveBeenCalledWith(400);
34
- expect(mockResponse.end).toHaveBeenCalled();
35
- });
36
- it("should handle SyntaxError", async () => {
37
- const mockRequest = { i18n };
38
- const mockResponse = {
39
- writeHead: vi.fn().mockReturnThis(),
40
- set: vi.fn().mockReturnThis(),
41
- status: vi.fn().mockReturnThis(),
42
- send: vi.fn(),
43
- end: vi.fn(),
44
- };
45
- const mockNext = vi.fn();
46
- const [len, max] = [100, 50];
47
- const message = `Input length: ${len}, exceeds maximum allowed length: ${max}`;
48
- const error = new SyntaxError(message);
49
- handleErrors(error, mockRequest, mockResponse, mockNext);
50
- expect(mockResponse.set).toHaveBeenCalledWith("content-type", "application/json");
51
- expect(mockResponse.status).toHaveBeenCalledWith(400);
52
- expect(mockResponse.send).toHaveBeenCalledWith({
53
- error: {
54
- message,
55
- code: 400,
56
- },
57
- });
58
- expect(mockResponse.end).toHaveBeenCalled();
59
- });
60
- it("should handle ZodError", () => {
61
- const mockRequest = { i18n };
62
- const mockResponse = {
63
- writeHead: vi.fn().mockReturnThis(),
64
- set: vi.fn().mockReturnThis(),
65
- status: vi.fn().mockReturnThis(),
66
- send: vi.fn(),
67
- end: vi.fn(),
68
- };
69
- const mockNext = vi.fn();
70
- const zodError = {
71
- code: "custom",
72
- message: "Invalid input",
73
- path: ["some", "variable"],
74
- };
75
- const error = new ZodError([zodError]);
76
- handleErrors(error, mockRequest, mockResponse, mockNext);
77
- expect(mockResponse.set).toHaveBeenCalledWith("content-type", "application/json");
78
- expect(mockResponse.status).toHaveBeenCalledWith(400);
79
- expect(mockResponse.send).toHaveBeenCalledWith({
80
- error: { code: 400, message: [zodError] },
81
- });
82
- expect(mockResponse.end).toHaveBeenCalled();
83
- });
84
- it("should unwrap nested ProsopoBaseError", async () => {
85
- const mockRequest = { i18n };
86
- const mockResponse = {
87
- writeHead: vi.fn().mockReturnThis(),
88
- set: vi.fn().mockReturnThis(),
89
- status: vi.fn().mockReturnThis(),
90
- send: vi.fn(),
91
- end: vi.fn(),
92
- };
93
- const mockNext = vi.fn();
94
- const envError = new ProsopoEnvError("GENERAL.ENVIRONMENT_NOT_READY", {
95
- i18n,
96
- });
97
- const apiError = new ProsopoApiError(envError);
98
- handleErrors(apiError, mockRequest, mockResponse, mockNext);
99
- expect(mockResponse.set).toHaveBeenCalledWith("content-type", "application/json");
100
- expect(mockResponse.status).toHaveBeenCalledWith(500);
101
- expect(mockResponse.send).toHaveBeenCalledWith({
102
- error: {
103
- code: 500,
104
- key: "GENERAL.ENVIRONMENT_NOT_READY",
105
- message: "Environment not ready",
106
- },
107
- });
108
- expect(mockResponse.end).toHaveBeenCalled();
109
- });
110
- it("should unwrap nested ProsopoBaseErrors but not an Error that is nested inside them", async () => {
111
- const mockRequest = { i18n };
112
- const mockResponse = {
113
- writeHead: vi.fn().mockReturnThis(),
114
- set: vi.fn().mockReturnThis(),
115
- status: vi.fn().mockReturnThis(),
116
- send: vi.fn(),
117
- end: vi.fn(),
118
- };
119
- const mockNext = vi.fn();
120
- const code = 400;
121
- const key = "API.UNKNOWN";
122
- const error = new Error("Some error");
123
- const apiError = new ProsopoApiError(key, {
124
- context: { code, error },
125
- i18n,
126
- });
127
- handleErrors(apiError, mockRequest, mockResponse, mockNext);
128
- expect(mockResponse.set).toHaveBeenCalledWith("content-type", "application/json");
129
- expect(mockResponse.status).toHaveBeenCalledWith(code);
130
- expect(mockResponse.send).toHaveBeenCalledWith({
131
- error: {
132
- code,
133
- key,
134
- message: "Unknown API error",
135
- },
136
- });
137
- expect(mockResponse.end).toHaveBeenCalled();
138
- });
139
- });
140
- //# sourceMappingURL=errorHandler.unit.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"errorHandler.unit.test.js","sourceRoot":"","sources":["../../../src/tests/unit/errorHandler.unit.test.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,QAAQ,CAAC,cAAc,EAAE,KAAK,IAAI,EAAE;IACnC,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAEhC,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,WAAW,GAAG,EAAE,IAAI,EAAwB,CAAC;QACnD,MAAM,YAAY,GAAG;YACpB,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YACnC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YAC7B,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YAChC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;YACb,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;SACW,CAAC;QACzB,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAA6B,CAAC;QAEpD,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,8BAA8B,EAAE;YACjE,OAAO,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE;YACtB,IAAI;SACJ,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAEnB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;QAEzD,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAC5C,cAAc,EACd,kBAAkB,CAClB,CAAC;QACF,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC;YAC9C,KAAK,EAAE;gBACN,IAAI,EAAE,GAAG;gBACT,GAAG,EAAE,8BAA8B;gBACnC,OAAO,EAAE,qBAAqB;aAC9B;SACD,CAAC,CAAC;QACH,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;QACtD,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,gBAAgB,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,WAAW,GAAG,EAAE,IAAI,EAAwB,CAAC;QACnD,MAAM,YAAY,GAAG;YACpB,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YACnC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YAC7B,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YAChC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;YACb,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;SACW,CAAC;QACzB,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAA6B,CAAC;QAEpD,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC7B,MAAM,OAAO,GAAG,iBAAiB,GAAG,qCAAqC,GAAG,EAAE,CAAC;QAC/E,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;QAEvC,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;QAEzD,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAC5C,cAAc,EACd,kBAAkB,CAClB,CAAC;QACF,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;QACtD,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC;YAC9C,KAAK,EAAE;gBACN,OAAO;gBACP,IAAI,EAAE,GAAG;aACT;SACD,CAAC,CAAC;QACH,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,gBAAgB,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QACjC,MAAM,WAAW,GAAG,EAAE,IAAI,EAAwB,CAAC;QACnD,MAAM,YAAY,GAAG;YACpB,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YACnC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YAC7B,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YAChC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;YACb,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;SACW,CAAC;QACzB,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAA6B,CAAC;QAEpD,MAAM,QAAQ,GAAG;YAChB,IAAI,EAAE,QAAiB;YACvB,OAAO,EAAE,eAAe;YACxB,IAAI,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC;SAC1B,CAAC;QACF,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAEvC,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;QAEzD,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAC5C,cAAc,EACd,kBAAkB,CAClB,CAAC;QACF,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;QACtD,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC;YAC9C,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,QAAQ,CAAC,EAAE;SACzC,CAAC,CAAC;QACH,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,gBAAgB,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,WAAW,GAAG,EAAE,IAAI,EAAwB,CAAC;QACnD,MAAM,YAAY,GAAG;YACpB,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YACnC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YAC7B,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YAChC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;YACb,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;SACW,CAAC;QACzB,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAA6B,CAAC;QAEpD,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,+BAA+B,EAAE;YACrE,IAAI;SACJ,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAC;QAE/C,YAAY,CAAC,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;QAE5D,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAC5C,cAAc,EACd,kBAAkB,CAClB,CAAC;QACF,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;QACtD,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC;YAC9C,KAAK,EAAE;gBACN,IAAI,EAAE,GAAG;gBACT,GAAG,EAAE,+BAA+B;gBACpC,OAAO,EAAE,uBAAuB;aAChC;SACD,CAAC,CAAC;QACH,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,gBAAgB,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oFAAoF,EAAE,KAAK,IAAI,EAAE;QACnG,MAAM,WAAW,GAAG,EAAE,IAAI,EAAwB,CAAC;QACnD,MAAM,YAAY,GAAG;YACpB,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YACnC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YAC7B,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;YAChC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;YACb,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;SACW,CAAC;QACzB,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAA6B,CAAC;QACpD,MAAM,IAAI,GAAG,GAAG,CAAC;QACjB,MAAM,GAAG,GAAG,aAAa,CAAC;QAE1B,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,GAAG,EAAE;YACzC,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;YACxB,IAAI;SACJ,CAAC,CAAC;QAEH,YAAY,CAAC,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;QAE5D,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAC5C,cAAc,EACd,kBAAkB,CAClB,CAAC;QACF,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;QACvD,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC;YAC9C,KAAK,EAAE;gBACN,IAAI;gBACJ,GAAG;gBACH,OAAO,EAAE,mBAAmB;aAC5B;SACD,CAAC,CAAC;QACH,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,gBAAgB,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}