@macedon-technologies/batman 1.13.0 → 1.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.jsii +7 -5
  2. package/API.md +961 -1062
  3. package/lib/Api/ApiFiles.d.ts +5 -0
  4. package/lib/Api/ApiFiles.js +15 -0
  5. package/lib/Api/ApiFunctionFile.d.ts +4 -0
  6. package/lib/Api/ApiFunctionFile.js +18 -0
  7. package/lib/Api/ApiHelperFiles.d.ts +5 -0
  8. package/lib/Api/ApiHelperFiles.js +15 -0
  9. package/lib/Api/AppHelperFile.d.ts +4 -0
  10. package/lib/Api/AppHelperFile.js +63 -0
  11. package/lib/Api/AppMiddlewareFiles.d.ts +5 -0
  12. package/lib/Api/AppMiddlewareFiles.js +19 -0
  13. package/lib/Api/AuthMiddlewareFile.d.ts +4 -0
  14. package/lib/Api/AuthMiddlewareFile.js +109 -0
  15. package/lib/Api/CorsMiddlewareFile.d.ts +4 -0
  16. package/lib/Api/CorsMiddlewareFile.js +54 -0
  17. package/lib/Api/ErrorHandlerMiddlewareFile.d.ts +4 -0
  18. package/lib/Api/ErrorHandlerMiddlewareFile.js +49 -0
  19. package/lib/Api/ExpressApiRouterFile.d.ts +4 -0
  20. package/lib/Api/ExpressApiRouterFile.js +66 -0
  21. package/lib/Application.js +6 -6
  22. package/lib/BatmanProject.js +2 -4
  23. package/lib/BootcampApplication.js +4 -4
  24. package/lib/BootcampProject.js +2 -4
  25. package/lib/CodeOwnersFile.js +2 -4
  26. package/lib/LocalDevAppFile.js +2 -1
  27. package/lib/LocalDevFiles.d.ts +7 -0
  28. package/lib/LocalDevFiles.js +13 -0
  29. package/lib/{ApiFunctionFile.d.ts → LocalDevServerFile.d.ts} +1 -1
  30. package/lib/LocalDevServerFile.js +59 -0
  31. package/lib/ProductionDeployWorkflow.js +2 -4
  32. package/lib/StagingDeployWorkflow.js +2 -4
  33. package/lib/ViteReactProject.js +36 -2
  34. package/lib/WorkflowAutoDiscover.js +37 -6
  35. package/package.json +45 -39
  36. package/pnpm-workspace.yaml +6 -0
  37. package/lib/ApiFunctionFile.js +0 -30
@@ -0,0 +1,5 @@
1
+ import { Construct } from 'constructs';
2
+ import { Project } from 'projen';
3
+ export declare class ApiFiles extends Construct {
4
+ constructor(project: Project);
5
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiFiles = void 0;
4
+ const constructs_1 = require("constructs");
5
+ const ApiFunctionFile_1 = require("./ApiFunctionFile");
6
+ const ApiHelperFiles_1 = require("./ApiHelperFiles");
7
+ class ApiFiles extends constructs_1.Construct {
8
+ constructor(project) {
9
+ super(project, 'ApiFiles');
10
+ new ApiFunctionFile_1.ApiFunctionFile(project);
11
+ new ApiHelperFiles_1.ApiHelperFiles(project);
12
+ }
13
+ }
14
+ exports.ApiFiles = ApiFiles;
15
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXBpRmlsZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvQXBpL0FwaUZpbGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJDQUF1QztBQUV2Qyx1REFBb0Q7QUFDcEQscURBQWtEO0FBRWxELE1BQWEsUUFBUyxTQUFRLHNCQUFTO0lBRXJDLFlBQVksT0FBZ0I7UUFDMUIsS0FBSyxDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUMsQ0FBQztRQUMzQixJQUFJLGlDQUFlLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDN0IsSUFBSSwrQkFBYyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzlCLENBQUM7Q0FDRjtBQVBELDRCQU9DIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBQcm9qZWN0IH0gZnJvbSAncHJvamVuJztcbmltcG9ydCB7IEFwaUZ1bmN0aW9uRmlsZSB9IGZyb20gJy4vQXBpRnVuY3Rpb25GaWxlJztcbmltcG9ydCB7IEFwaUhlbHBlckZpbGVzIH0gZnJvbSAnLi9BcGlIZWxwZXJGaWxlcyc7XG5cbmV4cG9ydCBjbGFzcyBBcGlGaWxlcyBleHRlbmRzIENvbnN0cnVjdCB7XG5cbiAgY29uc3RydWN0b3IocHJvamVjdDogUHJvamVjdCkge1xuICAgIHN1cGVyKHByb2plY3QsICdBcGlGaWxlcycpO1xuICAgIG5ldyBBcGlGdW5jdGlvbkZpbGUocHJvamVjdCk7XG4gICAgbmV3IEFwaUhlbHBlckZpbGVzKHByb2plY3QpO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,4 @@
1
+ import { Project, SampleFile } from 'projen';
2
+ export declare class ApiFunctionFile extends SampleFile {
3
+ constructor(project: Project);
4
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiFunctionFile = void 0;
4
+ const projen_1 = require("projen");
5
+ class ApiFunctionFile extends projen_1.SampleFile {
6
+ constructor(project) {
7
+ super(project, 'src/constructs/handler/Api.Function.ts', {
8
+ contents: `import serverless from 'serverless-http';
9
+ import { initializeApp } from './app';
10
+
11
+ export const handler = serverless(initializeApp());
12
+
13
+ `,
14
+ });
15
+ }
16
+ }
17
+ exports.ApiFunctionFile = ApiFunctionFile;
18
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXBpRnVuY3Rpb25GaWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL0FwaS9BcGlGdW5jdGlvbkZpbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbUNBQTZDO0FBRzdDLE1BQWEsZUFBZ0IsU0FBUSxtQkFBVTtJQUM3QyxZQUFZLE9BQWdCO1FBQzFCLEtBQUssQ0FBQyxPQUFPLEVBQUUsd0NBQXdDLEVBQUU7WUFDdkQsUUFBUSxFQUFFOzs7OztDQUtmO1NBQ0ksQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBWEQsMENBV0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBQcm9qZWN0LCBTYW1wbGVGaWxlIH0gZnJvbSAncHJvamVuJztcblxuXG5leHBvcnQgY2xhc3MgQXBpRnVuY3Rpb25GaWxlIGV4dGVuZHMgU2FtcGxlRmlsZSB7XG4gIGNvbnN0cnVjdG9yKHByb2plY3Q6IFByb2plY3QpIHtcbiAgICBzdXBlcihwcm9qZWN0LCAnc3JjL2NvbnN0cnVjdHMvaGFuZGxlci9BcGkuRnVuY3Rpb24udHMnLCB7XG4gICAgICBjb250ZW50czogYGltcG9ydCBzZXJ2ZXJsZXNzIGZyb20gJ3NlcnZlcmxlc3MtaHR0cCc7XG5pbXBvcnQgeyBpbml0aWFsaXplQXBwIH0gZnJvbSAnLi9hcHAnO1xuXG5leHBvcnQgY29uc3QgaGFuZGxlciA9IHNlcnZlcmxlc3MoaW5pdGlhbGl6ZUFwcCgpKTtcblxuYCxcbiAgICB9KTtcbiAgfVxufVxuIl19
@@ -0,0 +1,5 @@
1
+ import { Construct } from 'constructs';
2
+ import { Project } from 'projen';
3
+ export declare class ApiHelperFiles extends Construct {
4
+ constructor(project: Project);
5
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiHelperFiles = void 0;
4
+ const constructs_1 = require("constructs");
5
+ const AppHelperFile_1 = require("./AppHelperFile");
6
+ const AppMiddlewareFiles_1 = require("./AppMiddlewareFiles");
7
+ class ApiHelperFiles extends constructs_1.Construct {
8
+ constructor(project) {
9
+ super(project, 'ApiHelperFiles');
10
+ new AppHelperFile_1.AppHelperFile(project);
11
+ new AppMiddlewareFiles_1.AppMiddlewareFiles(project);
12
+ }
13
+ }
14
+ exports.ApiHelperFiles = ApiHelperFiles;
15
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXBpSGVscGVyRmlsZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvQXBpL0FwaUhlbHBlckZpbGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJDQUF1QztBQUV2QyxtREFBZ0Q7QUFDaEQsNkRBQTBEO0FBRTFELE1BQWEsY0FBZSxTQUFRLHNCQUFTO0lBQzNDLFlBQVksT0FBZ0I7UUFDMUIsS0FBSyxDQUFDLE9BQU8sRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ2pDLElBQUksNkJBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMzQixJQUFJLHVDQUFrQixDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ2xDLENBQUM7Q0FDRjtBQU5ELHdDQU1DIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBQcm9qZWN0IH0gZnJvbSAncHJvamVuJztcbmltcG9ydCB7IEFwcEhlbHBlckZpbGUgfSBmcm9tICcuL0FwcEhlbHBlckZpbGUnO1xuaW1wb3J0IHsgQXBwTWlkZGxld2FyZUZpbGVzIH0gZnJvbSAnLi9BcHBNaWRkbGV3YXJlRmlsZXMnO1xuXG5leHBvcnQgY2xhc3MgQXBpSGVscGVyRmlsZXMgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBjb25zdHJ1Y3Rvcihwcm9qZWN0OiBQcm9qZWN0KSB7XG4gICAgc3VwZXIocHJvamVjdCwgJ0FwaUhlbHBlckZpbGVzJyk7XG4gICAgbmV3IEFwcEhlbHBlckZpbGUocHJvamVjdCk7XG4gICAgbmV3IEFwcE1pZGRsZXdhcmVGaWxlcyhwcm9qZWN0KTtcbiAgfVxufVxuIl19
@@ -0,0 +1,4 @@
1
+ import { Project, SampleFile } from 'projen';
2
+ export declare class AppHelperFile extends SampleFile {
3
+ constructor(project: Project);
4
+ }
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AppHelperFile = void 0;
4
+ const projen_1 = require("projen");
5
+ class AppHelperFile extends projen_1.SampleFile {
6
+ constructor(project) {
7
+ super(project, 'src/constructs/handler/app.ts', {
8
+ contents: `import express, { Express, Request, Response, Router } from 'express';
9
+ import { ExpressApiRouter } from './ExpressApiRouter';
10
+ import { authMiddleware } from './auth';
11
+ import { corsMiddleware } from './cors';
12
+ import { errorHandlerMiddleware } from './error';
13
+
14
+ export const app = express();
15
+
16
+ // Body parsing middleware
17
+ app.use(express.json());
18
+
19
+ // Placeholder for pre-route middleware (used by dev.ts for mock context)
20
+ export const preRouteMiddleware: Array<express.RequestHandler> = [];
21
+
22
+ export function initializeApp(): Express {
23
+ // Register middleware in correct order:
24
+ // 1. Body parsing (already done above)
25
+ // 2. CORS middleware (handles preflight and sets headers)
26
+ app.use(corsMiddleware);
27
+
28
+ // 3. Pre-route middleware (e.g., auth/mock context from dev.ts)
29
+ preRouteMiddleware.forEach(mw => app.use(mw));
30
+
31
+ // 4. Auth middleware (extracts userId, org role, permissions from JWT "o" claim)
32
+ app.use(authMiddleware);
33
+
34
+ // 5. Routes (handlers wrapped with responseFormatter)
35
+ const apiRouter: Router = express.Router();
36
+
37
+ // Initialize ExpressApiRouter if database client is provided
38
+ // if (!databaseClient) {
39
+ // throw new Error('DB_ENDPOINT environment variable and database client is not set');
40
+ // }
41
+
42
+ const expressApiRouter = new ExpressApiRouter(
43
+ apiRouter,
44
+ );
45
+ app.use('/api', expressApiRouter.getRouter());
46
+
47
+ // 6. Error handler middleware (catches all errors)
48
+ app.use(errorHandlerMiddleware);
49
+
50
+ // Catch-all route for 404s - use regex pattern for Express 5
51
+ app.all(/.*/, (req: Request, res: Response) => {
52
+ console.debug(\`[404] \${req.method} \${req.path} - Route not found\`);
53
+ res.status(404).json({ error: 'Not Found', path: req.path });
54
+ });
55
+
56
+ return app;
57
+ }
58
+ `,
59
+ });
60
+ }
61
+ }
62
+ exports.AppHelperFile = AppHelperFile;
63
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXBwSGVscGVyRmlsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9BcGkvQXBwSGVscGVyRmlsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxtQ0FBNkM7QUFFN0MsTUFBYSxhQUFjLFNBQVEsbUJBQVU7SUFDM0MsWUFBWSxPQUFnQjtRQUMxQixLQUFLLENBQUMsT0FBTyxFQUFFLCtCQUErQixFQUFFO1lBQzlDLFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Q0FrRGY7U0FDSSxDQUNBLENBQUM7SUFDSixDQUFDO0NBRUY7QUExREQsc0NBMERDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUHJvamVjdCwgU2FtcGxlRmlsZSB9IGZyb20gJ3Byb2plbic7XG5cbmV4cG9ydCBjbGFzcyBBcHBIZWxwZXJGaWxlIGV4dGVuZHMgU2FtcGxlRmlsZSB7XG4gIGNvbnN0cnVjdG9yKHByb2plY3Q6IFByb2plY3QpIHtcbiAgICBzdXBlcihwcm9qZWN0LCAnc3JjL2NvbnN0cnVjdHMvaGFuZGxlci9hcHAudHMnLCB7XG4gICAgICBjb250ZW50czogYGltcG9ydCBleHByZXNzLCB7IEV4cHJlc3MsIFJlcXVlc3QsIFJlc3BvbnNlLCBSb3V0ZXIgfSBmcm9tICdleHByZXNzJztcbmltcG9ydCB7IEV4cHJlc3NBcGlSb3V0ZXIgfSBmcm9tICcuL0V4cHJlc3NBcGlSb3V0ZXInO1xuaW1wb3J0IHsgYXV0aE1pZGRsZXdhcmUgfSBmcm9tICcuL2F1dGgnO1xuaW1wb3J0IHsgY29yc01pZGRsZXdhcmUgfSBmcm9tICcuL2NvcnMnO1xuaW1wb3J0IHsgZXJyb3JIYW5kbGVyTWlkZGxld2FyZSB9IGZyb20gJy4vZXJyb3InO1xuXG5leHBvcnQgY29uc3QgYXBwID0gZXhwcmVzcygpO1xuXG4vLyBCb2R5IHBhcnNpbmcgbWlkZGxld2FyZVxuYXBwLnVzZShleHByZXNzLmpzb24oKSk7XG5cbi8vIFBsYWNlaG9sZGVyIGZvciBwcmUtcm91dGUgbWlkZGxld2FyZSAodXNlZCBieSBkZXYudHMgZm9yIG1vY2sgY29udGV4dClcbmV4cG9ydCBjb25zdCBwcmVSb3V0ZU1pZGRsZXdhcmU6IEFycmF5PGV4cHJlc3MuUmVxdWVzdEhhbmRsZXI+ID0gW107XG5cbmV4cG9ydCBmdW5jdGlvbiBpbml0aWFsaXplQXBwKCk6IEV4cHJlc3Mge1xuICAvLyBSZWdpc3RlciBtaWRkbGV3YXJlIGluIGNvcnJlY3Qgb3JkZXI6XG4gIC8vIDEuIEJvZHkgcGFyc2luZyAoYWxyZWFkeSBkb25lIGFib3ZlKVxuICAvLyAyLiBDT1JTIG1pZGRsZXdhcmUgKGhhbmRsZXMgcHJlZmxpZ2h0IGFuZCBzZXRzIGhlYWRlcnMpXG4gIGFwcC51c2UoY29yc01pZGRsZXdhcmUpO1xuXG4gIC8vIDMuIFByZS1yb3V0ZSBtaWRkbGV3YXJlIChlLmcuLCBhdXRoL21vY2sgY29udGV4dCBmcm9tIGRldi50cylcbiAgcHJlUm91dGVNaWRkbGV3YXJlLmZvckVhY2gobXcgPT4gYXBwLnVzZShtdykpO1xuXG4gIC8vIDQuIEF1dGggbWlkZGxld2FyZSAoZXh0cmFjdHMgdXNlcklkLCBvcmcgcm9sZSwgcGVybWlzc2lvbnMgZnJvbSBKV1QgXCJvXCIgY2xhaW0pXG4gIGFwcC51c2UoYXV0aE1pZGRsZXdhcmUpO1xuXG4gIC8vIDUuIFJvdXRlcyAoaGFuZGxlcnMgd3JhcHBlZCB3aXRoIHJlc3BvbnNlRm9ybWF0dGVyKVxuICBjb25zdCBhcGlSb3V0ZXI6IFJvdXRlciA9IGV4cHJlc3MuUm91dGVyKCk7XG5cbiAgLy8gSW5pdGlhbGl6ZSBFeHByZXNzQXBpUm91dGVyIGlmIGRhdGFiYXNlIGNsaWVudCBpcyBwcm92aWRlZFxuICAvLyBpZiAoIWRhdGFiYXNlQ2xpZW50KSB7XG4gIC8vICAgICB0aHJvdyBuZXcgRXJyb3IoJ0RCX0VORFBPSU5UIGVudmlyb25tZW50IHZhcmlhYmxlIGFuZCBkYXRhYmFzZSBjbGllbnQgaXMgbm90IHNldCcpO1xuICAvLyB9XG5cbiAgY29uc3QgZXhwcmVzc0FwaVJvdXRlciA9IG5ldyBFeHByZXNzQXBpUm91dGVyKFxuICAgIGFwaVJvdXRlcixcbiAgKTtcbiAgYXBwLnVzZSgnL2FwaScsIGV4cHJlc3NBcGlSb3V0ZXIuZ2V0Um91dGVyKCkpO1xuXG4gIC8vIDYuIEVycm9yIGhhbmRsZXIgbWlkZGxld2FyZSAoY2F0Y2hlcyBhbGwgZXJyb3JzKVxuICBhcHAudXNlKGVycm9ySGFuZGxlck1pZGRsZXdhcmUpO1xuXG4gIC8vIENhdGNoLWFsbCByb3V0ZSBmb3IgNDA0cyAtIHVzZSByZWdleCBwYXR0ZXJuIGZvciBFeHByZXNzIDVcbiAgYXBwLmFsbCgvLiovLCAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlKSA9PiB7XG4gICAgY29uc29sZS5kZWJ1ZyhcXGBbNDA0XSBcXCR7cmVxLm1ldGhvZH0gXFwke3JlcS5wYXRofSAtIFJvdXRlIG5vdCBmb3VuZFxcYCk7XG4gICAgcmVzLnN0YXR1cyg0MDQpLmpzb24oeyBlcnJvcjogJ05vdCBGb3VuZCcsIHBhdGg6IHJlcS5wYXRoIH0pO1xuICB9KTtcblxuICByZXR1cm4gYXBwO1xufVxuYCxcbiAgICB9LFxuICAgICk7XG4gIH1cblxufVxuIl19
@@ -0,0 +1,5 @@
1
+ import { Construct } from 'constructs';
2
+ import { Project } from 'projen';
3
+ export declare class AppMiddlewareFiles extends Construct {
4
+ constructor(project: Project);
5
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AppMiddlewareFiles = void 0;
4
+ const constructs_1 = require("constructs");
5
+ const AuthMiddlewareFile_1 = require("./AuthMiddlewareFile");
6
+ const CorsMiddlewareFile_1 = require("./CorsMiddlewareFile");
7
+ const ErrorHandlerMiddlewareFile_1 = require("./ErrorHandlerMiddlewareFile");
8
+ const ExpressApiRouterFile_1 = require("./ExpressApiRouterFile");
9
+ class AppMiddlewareFiles extends constructs_1.Construct {
10
+ constructor(project) {
11
+ super(project, 'AppMiddlewareFiles');
12
+ new ExpressApiRouterFile_1.ExpressApiRouterFile(project);
13
+ new AuthMiddlewareFile_1.AuthMiddlewareFile(project);
14
+ new CorsMiddlewareFile_1.CorsMiddlewareFile(project);
15
+ new ErrorHandlerMiddlewareFile_1.ErrorHandlerMiddlewareFile(project);
16
+ }
17
+ }
18
+ exports.AppMiddlewareFiles = AppMiddlewareFiles;
19
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXBwTWlkZGxld2FyZUZpbGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL0FwaS9BcHBNaWRkbGV3YXJlRmlsZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsMkNBQXVDO0FBRXZDLDZEQUEwRDtBQUMxRCw2REFBMEQ7QUFDMUQsNkVBQTBFO0FBQzFFLGlFQUE4RDtBQUU5RCxNQUFhLGtCQUFtQixTQUFRLHNCQUFTO0lBQy9DLFlBQVksT0FBZ0I7UUFDMUIsS0FBSyxDQUFDLE9BQU8sRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO1FBQ3JDLElBQUksMkNBQW9CLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDbEMsSUFBSSx1Q0FBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNoQyxJQUFJLHVDQUFrQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2hDLElBQUksdURBQTBCLENBQUMsT0FBTyxDQUFDLENBQUM7SUFFMUMsQ0FBQztDQUVGO0FBVkQsZ0RBVUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IFByb2plY3QgfSBmcm9tICdwcm9qZW4nO1xuaW1wb3J0IHsgQXV0aE1pZGRsZXdhcmVGaWxlIH0gZnJvbSAnLi9BdXRoTWlkZGxld2FyZUZpbGUnO1xuaW1wb3J0IHsgQ29yc01pZGRsZXdhcmVGaWxlIH0gZnJvbSAnLi9Db3JzTWlkZGxld2FyZUZpbGUnO1xuaW1wb3J0IHsgRXJyb3JIYW5kbGVyTWlkZGxld2FyZUZpbGUgfSBmcm9tICcuL0Vycm9ySGFuZGxlck1pZGRsZXdhcmVGaWxlJztcbmltcG9ydCB7IEV4cHJlc3NBcGlSb3V0ZXJGaWxlIH0gZnJvbSAnLi9FeHByZXNzQXBpUm91dGVyRmlsZSc7XG5cbmV4cG9ydCBjbGFzcyBBcHBNaWRkbGV3YXJlRmlsZXMgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBjb25zdHJ1Y3Rvcihwcm9qZWN0OiBQcm9qZWN0KSB7XG4gICAgc3VwZXIocHJvamVjdCwgJ0FwcE1pZGRsZXdhcmVGaWxlcycpO1xuICAgIG5ldyBFeHByZXNzQXBpUm91dGVyRmlsZShwcm9qZWN0KTtcbiAgICBuZXcgQXV0aE1pZGRsZXdhcmVGaWxlKHByb2plY3QpO1xuICAgIG5ldyBDb3JzTWlkZGxld2FyZUZpbGUocHJvamVjdCk7XG4gICAgbmV3IEVycm9ySGFuZGxlck1pZGRsZXdhcmVGaWxlKHByb2plY3QpO1xuXG4gIH1cblxufVxuIl19
@@ -0,0 +1,4 @@
1
+ import { Project, SampleFile } from 'projen';
2
+ export declare class AuthMiddlewareFile extends SampleFile {
3
+ constructor(project: Project);
4
+ }
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthMiddlewareFile = void 0;
4
+ const projen_1 = require("projen");
5
+ class AuthMiddlewareFile extends projen_1.SampleFile {
6
+ constructor(project) {
7
+ super(project, 'src/constructs/handler/auth.ts', {
8
+ contents: `import type { Request, Response, NextFunction } from 'express';
9
+ import jwt from 'jsonwebtoken';
10
+
11
+ /**
12
+ * Clerk Organization role keys (without org: prefix in JWT "o.rol" claim)
13
+ */
14
+ export type OrgRole = 'admin' | 'member' | 'sales_team' | 'store_managers';
15
+
16
+ /**
17
+ * Session data extracted from Clerk JWT or authorizer context.
18
+ * The "o" (Organization) claim is included automatically when user has an active org.
19
+ */
20
+ export interface AuthSession {
21
+ userId: string;
22
+ orgId?: string;
23
+ orgSlug?: string;
24
+ orgRole?: OrgRole;
25
+ permissions?: string[];
26
+ }
27
+
28
+ declare global {
29
+ namespace Express {
30
+ interface Request {
31
+ auth?: AuthSession;
32
+ }
33
+ }
34
+ }
35
+
36
+ /** JWT payload shape for Clerk session token with Organization claim */
37
+ interface ClerkJwtPayload {
38
+ sub?: string;
39
+ o?: {
40
+ id?: string;
41
+ slg?: string;
42
+ rol?: string;
43
+ per?: string[];
44
+ fpm?: unknown;
45
+ };
46
+ }
47
+
48
+ /**
49
+ * Extracts auth session from JWT (Clerk "o" claim) or authorizer context.
50
+ * - Lambda/API Gateway: decodes JWT from Authorization header (already validated by Clerk authorizer)
51
+ * - Local dev: uses req.apiGateway.event.requestContext.authorizer
52
+ */
53
+ export function authMiddleware(req: Request, _res: Response, next: NextFunction): void {
54
+ try {
55
+ // 1. Authorizer context (Lambda or local mock) - provides userId when JWT not available
56
+ const authorizer = (req as Request & {
57
+ apiGateway?: { event?: { requestContext?: { authorizer?: Record<string, unknown> } } };
58
+ }).apiGateway?.event?.requestContext?.authorizer;
59
+
60
+ let userId: string | undefined;
61
+ let orgId: string | undefined;
62
+ let orgSlug: string | undefined;
63
+ let orgRole: OrgRole | undefined;
64
+ let permissions: string[] | undefined;
65
+
66
+ if (authorizer && typeof authorizer.userId === 'string') {
67
+ userId = authorizer.userId;
68
+ // Authorizer may pass org data if configured
69
+ if (typeof authorizer.orgId === 'string') orgId = authorizer.orgId;
70
+ if (typeof authorizer.orgRole === 'string') orgRole = authorizer.orgRole as OrgRole;
71
+ }
72
+
73
+ // 2. Decode JWT for full claims (Organization "o" claim)
74
+ const authHeader = req.headers.authorization;
75
+ const token = authHeader?.startsWith('Bearer ') ? authHeader.slice(7) : undefined;
76
+
77
+ if (token) {
78
+ const decoded = jwt.decode(token) as ClerkJwtPayload | null;
79
+ if (decoded) {
80
+ if (!userId && decoded.sub) userId = decoded.sub;
81
+ if (decoded.o) {
82
+ if (decoded.o.id) orgId = decoded.o.id;
83
+ if (decoded.o.slg) orgSlug = decoded.o.slg;
84
+ if (decoded.o.rol) orgRole = decoded.o.rol as OrgRole;
85
+ if (Array.isArray(decoded.o.per)) permissions = decoded.o.per;
86
+ }
87
+ }
88
+ }
89
+
90
+ if (userId) {
91
+ req.auth = {
92
+ userId,
93
+ ...(orgId && { orgId }),
94
+ ...(orgSlug && { orgSlug }),
95
+ ...(orgRole && { orgRole }),
96
+ ...(permissions && permissions.length > 0 && { permissions }),
97
+ };
98
+ }
99
+ } catch (err) {
100
+ console.warn('[Auth] Failed to extract session:', err);
101
+ }
102
+ next();
103
+ }
104
+ `,
105
+ });
106
+ }
107
+ }
108
+ exports.AuthMiddlewareFile = AuthMiddlewareFile;
109
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXV0aE1pZGRsZXdhcmVGaWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL0FwaS9BdXRoTWlkZGxld2FyZUZpbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbUNBQTZDO0FBRTdDLE1BQWEsa0JBQW1CLFNBQVEsbUJBQVU7SUFDaEQsWUFBWSxPQUFnQjtRQUMxQixLQUFLLENBQUMsT0FBTyxFQUFFLGdDQUFnQyxFQUFFO1lBQy9DLFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0NBZ0dmO1NBQ0ksQ0FBQyxDQUFDO0lBRUwsQ0FBQztDQUVGO0FBeEdELGdEQXdHQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFByb2plY3QsIFNhbXBsZUZpbGUgfSBmcm9tICdwcm9qZW4nO1xuXG5leHBvcnQgY2xhc3MgQXV0aE1pZGRsZXdhcmVGaWxlIGV4dGVuZHMgU2FtcGxlRmlsZSB7XG4gIGNvbnN0cnVjdG9yKHByb2plY3Q6IFByb2plY3QpIHtcbiAgICBzdXBlcihwcm9qZWN0LCAnc3JjL2NvbnN0cnVjdHMvaGFuZGxlci9hdXRoLnRzJywge1xuICAgICAgY29udGVudHM6IGBpbXBvcnQgdHlwZSB7IFJlcXVlc3QsIFJlc3BvbnNlLCBOZXh0RnVuY3Rpb24gfSBmcm9tICdleHByZXNzJztcbmltcG9ydCBqd3QgZnJvbSAnanNvbndlYnRva2VuJztcblxuLyoqXG4gKiBDbGVyayBPcmdhbml6YXRpb24gcm9sZSBrZXlzICh3aXRob3V0IG9yZzogcHJlZml4IGluIEpXVCBcIm8ucm9sXCIgY2xhaW0pXG4gKi9cbmV4cG9ydCB0eXBlIE9yZ1JvbGUgPSAnYWRtaW4nIHwgJ21lbWJlcicgfCAnc2FsZXNfdGVhbScgfCAnc3RvcmVfbWFuYWdlcnMnO1xuXG4vKipcbiAqIFNlc3Npb24gZGF0YSBleHRyYWN0ZWQgZnJvbSBDbGVyayBKV1Qgb3IgYXV0aG9yaXplciBjb250ZXh0LlxuICogVGhlIFwib1wiIChPcmdhbml6YXRpb24pIGNsYWltIGlzIGluY2x1ZGVkIGF1dG9tYXRpY2FsbHkgd2hlbiB1c2VyIGhhcyBhbiBhY3RpdmUgb3JnLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEF1dGhTZXNzaW9uIHtcbiAgdXNlcklkOiBzdHJpbmc7XG4gIG9yZ0lkPzogc3RyaW5nO1xuICBvcmdTbHVnPzogc3RyaW5nO1xuICBvcmdSb2xlPzogT3JnUm9sZTtcbiAgcGVybWlzc2lvbnM/OiBzdHJpbmdbXTtcbn1cblxuZGVjbGFyZSBnbG9iYWwge1xuICBuYW1lc3BhY2UgRXhwcmVzcyB7XG4gICAgaW50ZXJmYWNlIFJlcXVlc3Qge1xuICAgICAgYXV0aD86IEF1dGhTZXNzaW9uO1xuICAgIH1cbiAgfVxufVxuXG4vKiogSldUIHBheWxvYWQgc2hhcGUgZm9yIENsZXJrIHNlc3Npb24gdG9rZW4gd2l0aCBPcmdhbml6YXRpb24gY2xhaW0gKi9cbmludGVyZmFjZSBDbGVya0p3dFBheWxvYWQge1xuICBzdWI/OiBzdHJpbmc7XG4gIG8/OiB7XG4gICAgaWQ/OiBzdHJpbmc7XG4gICAgc2xnPzogc3RyaW5nO1xuICAgIHJvbD86IHN0cmluZztcbiAgICBwZXI/OiBzdHJpbmdbXTtcbiAgICBmcG0/OiB1bmtub3duO1xuICB9O1xufVxuXG4vKipcbiAqIEV4dHJhY3RzIGF1dGggc2Vzc2lvbiBmcm9tIEpXVCAoQ2xlcmsgXCJvXCIgY2xhaW0pIG9yIGF1dGhvcml6ZXIgY29udGV4dC5cbiAqIC0gTGFtYmRhL0FQSSBHYXRld2F5OiBkZWNvZGVzIEpXVCBmcm9tIEF1dGhvcml6YXRpb24gaGVhZGVyIChhbHJlYWR5IHZhbGlkYXRlZCBieSBDbGVyayBhdXRob3JpemVyKVxuICogLSBMb2NhbCBkZXY6IHVzZXMgcmVxLmFwaUdhdGV3YXkuZXZlbnQucmVxdWVzdENvbnRleHQuYXV0aG9yaXplclxuICovXG5leHBvcnQgZnVuY3Rpb24gYXV0aE1pZGRsZXdhcmUocmVxOiBSZXF1ZXN0LCBfcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCB7XG4gIHRyeSB7XG4gICAgLy8gMS4gQXV0aG9yaXplciBjb250ZXh0IChMYW1iZGEgb3IgbG9jYWwgbW9jaykgLSBwcm92aWRlcyB1c2VySWQgd2hlbiBKV1Qgbm90IGF2YWlsYWJsZVxuICAgIGNvbnN0IGF1dGhvcml6ZXIgPSAocmVxIGFzIFJlcXVlc3QgJiB7XG4gICAgICBhcGlHYXRld2F5PzogeyBldmVudD86IHsgcmVxdWVzdENvbnRleHQ/OiB7IGF1dGhvcml6ZXI/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB9IH0gfTtcbiAgICB9KS5hcGlHYXRld2F5Py5ldmVudD8ucmVxdWVzdENvbnRleHQ/LmF1dGhvcml6ZXI7XG5cbiAgICBsZXQgdXNlcklkOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgbGV0IG9yZ0lkOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgbGV0IG9yZ1NsdWc6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICBsZXQgb3JnUm9sZTogT3JnUm9sZSB8IHVuZGVmaW5lZDtcbiAgICBsZXQgcGVybWlzc2lvbnM6IHN0cmluZ1tdIHwgdW5kZWZpbmVkO1xuXG4gICAgaWYgKGF1dGhvcml6ZXIgJiYgdHlwZW9mIGF1dGhvcml6ZXIudXNlcklkID09PSAnc3RyaW5nJykge1xuICAgICAgdXNlcklkID0gYXV0aG9yaXplci51c2VySWQ7XG4gICAgICAvLyBBdXRob3JpemVyIG1heSBwYXNzIG9yZyBkYXRhIGlmIGNvbmZpZ3VyZWRcbiAgICAgIGlmICh0eXBlb2YgYXV0aG9yaXplci5vcmdJZCA9PT0gJ3N0cmluZycpIG9yZ0lkID0gYXV0aG9yaXplci5vcmdJZDtcbiAgICAgIGlmICh0eXBlb2YgYXV0aG9yaXplci5vcmdSb2xlID09PSAnc3RyaW5nJykgb3JnUm9sZSA9IGF1dGhvcml6ZXIub3JnUm9sZSBhcyBPcmdSb2xlO1xuICAgIH1cblxuICAgIC8vIDIuIERlY29kZSBKV1QgZm9yIGZ1bGwgY2xhaW1zIChPcmdhbml6YXRpb24gXCJvXCIgY2xhaW0pXG4gICAgY29uc3QgYXV0aEhlYWRlciA9IHJlcS5oZWFkZXJzLmF1dGhvcml6YXRpb247XG4gICAgY29uc3QgdG9rZW4gPSBhdXRoSGVhZGVyPy5zdGFydHNXaXRoKCdCZWFyZXIgJykgPyBhdXRoSGVhZGVyLnNsaWNlKDcpIDogdW5kZWZpbmVkO1xuXG4gICAgaWYgKHRva2VuKSB7XG4gICAgICBjb25zdCBkZWNvZGVkID0gand0LmRlY29kZSh0b2tlbikgYXMgQ2xlcmtKd3RQYXlsb2FkIHwgbnVsbDtcbiAgICAgIGlmIChkZWNvZGVkKSB7XG4gICAgICAgIGlmICghdXNlcklkICYmIGRlY29kZWQuc3ViKSB1c2VySWQgPSBkZWNvZGVkLnN1YjtcbiAgICAgICAgaWYgKGRlY29kZWQubykge1xuICAgICAgICAgIGlmIChkZWNvZGVkLm8uaWQpIG9yZ0lkID0gZGVjb2RlZC5vLmlkO1xuICAgICAgICAgIGlmIChkZWNvZGVkLm8uc2xnKSBvcmdTbHVnID0gZGVjb2RlZC5vLnNsZztcbiAgICAgICAgICBpZiAoZGVjb2RlZC5vLnJvbCkgb3JnUm9sZSA9IGRlY29kZWQuby5yb2wgYXMgT3JnUm9sZTtcbiAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShkZWNvZGVkLm8ucGVyKSkgcGVybWlzc2lvbnMgPSBkZWNvZGVkLm8ucGVyO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHVzZXJJZCkge1xuICAgICAgcmVxLmF1dGggPSB7XG4gICAgICAgIHVzZXJJZCxcbiAgICAgICAgLi4uKG9yZ0lkICYmIHsgb3JnSWQgfSksXG4gICAgICAgIC4uLihvcmdTbHVnICYmIHsgb3JnU2x1ZyB9KSxcbiAgICAgICAgLi4uKG9yZ1JvbGUgJiYgeyBvcmdSb2xlIH0pLFxuICAgICAgICAuLi4ocGVybWlzc2lvbnMgJiYgcGVybWlzc2lvbnMubGVuZ3RoID4gMCAmJiB7IHBlcm1pc3Npb25zIH0pLFxuICAgICAgfTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGNvbnNvbGUud2FybignW0F1dGhdIEZhaWxlZCB0byBleHRyYWN0IHNlc3Npb246JywgZXJyKTtcbiAgfVxuICBuZXh0KCk7XG59XG5gLFxuICAgIH0pO1xuXG4gIH1cblxufVxuIl19
@@ -0,0 +1,4 @@
1
+ import { Project, SampleFile } from 'projen';
2
+ export declare class CorsMiddlewareFile extends SampleFile {
3
+ constructor(project: Project);
4
+ }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CorsMiddlewareFile = void 0;
4
+ const projen_1 = require("projen");
5
+ class CorsMiddlewareFile extends projen_1.SampleFile {
6
+ constructor(project) {
7
+ super(project, 'src/constructs/handler/cors.ts', {
8
+ contents: `import type { Request, Response, NextFunction } from 'express';
9
+
10
+ /**
11
+ * Production origin for CORS
12
+ */
13
+ // TODO: Change to the production origin
14
+ const PRODUCTION_ORIGIN = process.env.ORIGIN || 'https://sample.macedon.sandbox.defiance.ai';
15
+
16
+ /**
17
+ * Centralized CORS middleware
18
+ * Handles preflight OPTIONS requests and sets CORS headers
19
+ */
20
+ export function corsMiddleware(req: Request, res: Response, next: NextFunction): void {
21
+ const origin = req.headers.origin;
22
+
23
+ // Determine allowed origin
24
+ let allowedOrigin: string | undefined;
25
+ if (origin && origin.startsWith('http://localhost:')) {
26
+ // Local development - allow localhost origins
27
+ allowedOrigin = origin;
28
+ } else if (origin === PRODUCTION_ORIGIN) {
29
+ // Production - allow configured production origin
30
+ allowedOrigin = PRODUCTION_ORIGIN;
31
+ }
32
+
33
+ // Set CORS headers
34
+ if (allowedOrigin) {
35
+ res.header('Access-Control-Allow-Origin', allowedOrigin);
36
+ }
37
+ res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
38
+ res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
39
+ res.header('Access-Control-Allow-Credentials', 'true');
40
+
41
+ // Handle preflight OPTIONS requests
42
+ if (req.method === 'OPTIONS') {
43
+ res.sendStatus(200);
44
+ return;
45
+ }
46
+
47
+ next();
48
+ }
49
+ `,
50
+ });
51
+ }
52
+ }
53
+ exports.CorsMiddlewareFile = CorsMiddlewareFile;
54
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29yc01pZGRsZXdhcmVGaWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL0FwaS9Db3JzTWlkZGxld2FyZUZpbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbUNBQTZDO0FBRTdDLE1BQWEsa0JBQW1CLFNBQVEsbUJBQVU7SUFDaEQsWUFBWSxPQUFnQjtRQUMxQixLQUFLLENBQUMsT0FBTyxFQUFFLGdDQUFnQyxFQUFFO1lBQy9DLFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Q0F5Q2Y7U0FDSSxDQUFDLENBQUM7SUFFTCxDQUFDO0NBRUY7QUFqREQsZ0RBaURDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUHJvamVjdCwgU2FtcGxlRmlsZSB9IGZyb20gJ3Byb2plbic7XG5cbmV4cG9ydCBjbGFzcyBDb3JzTWlkZGxld2FyZUZpbGUgZXh0ZW5kcyBTYW1wbGVGaWxlIHtcbiAgY29uc3RydWN0b3IocHJvamVjdDogUHJvamVjdCkge1xuICAgIHN1cGVyKHByb2plY3QsICdzcmMvY29uc3RydWN0cy9oYW5kbGVyL2NvcnMudHMnLCB7XG4gICAgICBjb250ZW50czogYGltcG9ydCB0eXBlIHsgUmVxdWVzdCwgUmVzcG9uc2UsIE5leHRGdW5jdGlvbiB9IGZyb20gJ2V4cHJlc3MnO1xuXG4vKipcbiAqIFByb2R1Y3Rpb24gb3JpZ2luIGZvciBDT1JTXG4gKi9cbi8vIFRPRE86IENoYW5nZSB0byB0aGUgcHJvZHVjdGlvbiBvcmlnaW5cbmNvbnN0IFBST0RVQ1RJT05fT1JJR0lOID0gcHJvY2Vzcy5lbnYuT1JJR0lOIHx8ICdodHRwczovL3NhbXBsZS5tYWNlZG9uLnNhbmRib3guZGVmaWFuY2UuYWknO1xuXG4vKipcbiAqIENlbnRyYWxpemVkIENPUlMgbWlkZGxld2FyZVxuICogSGFuZGxlcyBwcmVmbGlnaHQgT1BUSU9OUyByZXF1ZXN0cyBhbmQgc2V0cyBDT1JTIGhlYWRlcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvcnNNaWRkbGV3YXJlKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCB7XG4gIGNvbnN0IG9yaWdpbiA9IHJlcS5oZWFkZXJzLm9yaWdpbjtcblxuICAvLyBEZXRlcm1pbmUgYWxsb3dlZCBvcmlnaW5cbiAgbGV0IGFsbG93ZWRPcmlnaW46IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgaWYgKG9yaWdpbiAmJiBvcmlnaW4uc3RhcnRzV2l0aCgnaHR0cDovL2xvY2FsaG9zdDonKSkge1xuICAgIC8vIExvY2FsIGRldmVsb3BtZW50IC0gYWxsb3cgbG9jYWxob3N0IG9yaWdpbnNcbiAgICBhbGxvd2VkT3JpZ2luID0gb3JpZ2luO1xuICB9IGVsc2UgaWYgKG9yaWdpbiA9PT0gUFJPRFVDVElPTl9PUklHSU4pIHtcbiAgICAvLyBQcm9kdWN0aW9uIC0gYWxsb3cgY29uZmlndXJlZCBwcm9kdWN0aW9uIG9yaWdpblxuICAgIGFsbG93ZWRPcmlnaW4gPSBQUk9EVUNUSU9OX09SSUdJTjtcbiAgfVxuXG4gIC8vIFNldCBDT1JTIGhlYWRlcnNcbiAgaWYgKGFsbG93ZWRPcmlnaW4pIHtcbiAgICByZXMuaGVhZGVyKCdBY2Nlc3MtQ29udHJvbC1BbGxvdy1PcmlnaW4nLCBhbGxvd2VkT3JpZ2luKTtcbiAgfVxuICByZXMuaGVhZGVyKCdBY2Nlc3MtQ29udHJvbC1BbGxvdy1NZXRob2RzJywgJ0dFVCwgUE9TVCwgUFVULCBERUxFVEUsIE9QVElPTlMnKTtcbiAgcmVzLmhlYWRlcignQWNjZXNzLUNvbnRyb2wtQWxsb3ctSGVhZGVycycsICdPcmlnaW4sIFgtUmVxdWVzdGVkLVdpdGgsIENvbnRlbnQtVHlwZSwgQWNjZXB0LCBBdXRob3JpemF0aW9uJyk7XG4gIHJlcy5oZWFkZXIoJ0FjY2Vzcy1Db250cm9sLUFsbG93LUNyZWRlbnRpYWxzJywgJ3RydWUnKTtcblxuICAvLyBIYW5kbGUgcHJlZmxpZ2h0IE9QVElPTlMgcmVxdWVzdHNcbiAgaWYgKHJlcS5tZXRob2QgPT09ICdPUFRJT05TJykge1xuICAgIHJlcy5zZW5kU3RhdHVzKDIwMCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgbmV4dCgpO1xufVxuYCxcbiAgICB9KTtcblxuICB9XG5cbn1cbiJdfQ==
@@ -0,0 +1,4 @@
1
+ import { Project, SampleFile } from 'projen';
2
+ export declare class ErrorHandlerMiddlewareFile extends SampleFile {
3
+ constructor(project: Project);
4
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ErrorHandlerMiddlewareFile = void 0;
4
+ const projen_1 = require("projen");
5
+ class ErrorHandlerMiddlewareFile extends projen_1.SampleFile {
6
+ constructor(project) {
7
+ super(project, 'src/constructs/handler/error.ts', {
8
+ contents: `import type { Request, Response, NextFunction } from 'express';
9
+ /**
10
+ * HTTP error for 4xx/5xx responses.
11
+ * Error middleware reads statusCode to send appropriate response.
12
+ */
13
+ export class HttpError extends Error {
14
+ public readonly statusCode: number;
15
+
16
+ constructor(message: string, statusCode: number) {
17
+ super(message);
18
+ this.name = 'HttpError';
19
+ this.statusCode = statusCode;
20
+ Object.setPrototypeOf(this, HttpError.prototype);
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Error handler middleware. Handles HttpError with statusCode; otherwise returns 500.
26
+ */
27
+ export function errorHandlerMiddleware(
28
+ err: unknown,
29
+ _req: Request,
30
+ res: Response,
31
+ _next: NextFunction,
32
+ ): void {
33
+ if (err instanceof HttpError) {
34
+ res.status(err.statusCode).json({
35
+ error: err.statusCode >= 500 ? 'Internal Server Error' : 'Request Error',
36
+ message: err.message,
37
+ });
38
+ return;
39
+ }
40
+ const message = err instanceof Error ? err.message : 'Unknown error';
41
+ console.error('[Error]', err);
42
+ res.status(500).json({ error: 'Internal Server Error', message });
43
+ }
44
+ `,
45
+ });
46
+ }
47
+ }
48
+ exports.ErrorHandlerMiddlewareFile = ErrorHandlerMiddlewareFile;
49
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRXJyb3JIYW5kbGVyTWlkZGxld2FyZUZpbGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvQXBpL0Vycm9ySGFuZGxlck1pZGRsZXdhcmVGaWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLG1DQUE2QztBQUU3QyxNQUFhLDBCQUEyQixTQUFRLG1CQUFVO0lBQ3hELFlBQVksT0FBZ0I7UUFDMUIsS0FBSyxDQUFDLE9BQU8sRUFBRSxpQ0FBaUMsRUFBRTtZQUNoRCxRQUFRLEVBQUU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztDQW9DZjtTQUNJLENBQUMsQ0FBQztJQUVMLENBQUM7Q0FFRjtBQTVDRCxnRUE0Q0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBQcm9qZWN0LCBTYW1wbGVGaWxlIH0gZnJvbSAncHJvamVuJztcblxuZXhwb3J0IGNsYXNzIEVycm9ySGFuZGxlck1pZGRsZXdhcmVGaWxlIGV4dGVuZHMgU2FtcGxlRmlsZSB7XG4gIGNvbnN0cnVjdG9yKHByb2plY3Q6IFByb2plY3QpIHtcbiAgICBzdXBlcihwcm9qZWN0LCAnc3JjL2NvbnN0cnVjdHMvaGFuZGxlci9lcnJvci50cycsIHtcbiAgICAgIGNvbnRlbnRzOiBgaW1wb3J0IHR5cGUgeyBSZXF1ZXN0LCBSZXNwb25zZSwgTmV4dEZ1bmN0aW9uIH0gZnJvbSAnZXhwcmVzcyc7XG4vKipcbiAqIEhUVFAgZXJyb3IgZm9yIDR4eC81eHggcmVzcG9uc2VzLlxuICogRXJyb3IgbWlkZGxld2FyZSByZWFkcyBzdGF0dXNDb2RlIHRvIHNlbmQgYXBwcm9wcmlhdGUgcmVzcG9uc2UuXG4gKi9cbmV4cG9ydCBjbGFzcyBIdHRwRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIHB1YmxpYyByZWFkb25seSBzdGF0dXNDb2RlOiBudW1iZXI7XG5cbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nLCBzdGF0dXNDb2RlOiBudW1iZXIpIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgICB0aGlzLm5hbWUgPSAnSHR0cEVycm9yJztcbiAgICB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXNDb2RlO1xuICAgIE9iamVjdC5zZXRQcm90b3R5cGVPZih0aGlzLCBIdHRwRXJyb3IucHJvdG90eXBlKTtcbiAgfVxufVxuXG4vKipcbiAqIEVycm9yIGhhbmRsZXIgbWlkZGxld2FyZS4gSGFuZGxlcyBIdHRwRXJyb3Igd2l0aCBzdGF0dXNDb2RlOyBvdGhlcndpc2UgcmV0dXJucyA1MDAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBlcnJvckhhbmRsZXJNaWRkbGV3YXJlKFxuICBlcnI6IHVua25vd24sXG4gIF9yZXE6IFJlcXVlc3QsXG4gIHJlczogUmVzcG9uc2UsXG4gIF9uZXh0OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkIHtcbiAgaWYgKGVyciBpbnN0YW5jZW9mIEh0dHBFcnJvcikge1xuICAgIHJlcy5zdGF0dXMoZXJyLnN0YXR1c0NvZGUpLmpzb24oe1xuICAgICAgZXJyb3I6IGVyci5zdGF0dXNDb2RlID49IDUwMCA/ICdJbnRlcm5hbCBTZXJ2ZXIgRXJyb3InIDogJ1JlcXVlc3QgRXJyb3InLFxuICAgICAgbWVzc2FnZTogZXJyLm1lc3NhZ2UsXG4gICAgfSk7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnN0IG1lc3NhZ2UgPSBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogJ1Vua25vd24gZXJyb3InO1xuICBjb25zb2xlLmVycm9yKCdbRXJyb3JdJywgZXJyKTtcbiAgcmVzLnN0YXR1cyg1MDApLmpzb24oeyBlcnJvcjogJ0ludGVybmFsIFNlcnZlciBFcnJvcicsIG1lc3NhZ2UgfSk7XG59XG5gLFxuICAgIH0pO1xuXG4gIH1cblxufVxuIl19
@@ -0,0 +1,4 @@
1
+ import { Project, SampleFile } from 'projen';
2
+ export declare class ExpressApiRouterFile extends SampleFile {
3
+ constructor(project: Project);
4
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExpressApiRouterFile = void 0;
4
+ const projen_1 = require("projen");
5
+ class ExpressApiRouterFile extends projen_1.SampleFile {
6
+ constructor(project) {
7
+ super(project, 'src/constructs/handler/ExpressApiRouter.ts', {
8
+ contents: `import { Request, Response, Router } from 'express';
9
+
10
+ export class ExpressApiRouter {
11
+ private readonly router: Router;
12
+
13
+ constructor(router: Router) {
14
+ this.router = router;
15
+ this.setupRoutes();
16
+ }
17
+
18
+
19
+ /**
20
+ * Gets the Express router instance
21
+ *
22
+ * @returns Router The Express router
23
+ */
24
+ public getRouter(): Router {
25
+ return this.router;
26
+ }
27
+
28
+ /**
29
+ * Sets up all available routes
30
+ */
31
+ private setupRoutes(): void {
32
+
33
+ this.router.get('/', async (req: Request, res: Response) => {
34
+ const auth = req.auth;
35
+ return res.status(200).json({ message: \`Hello \${auth!.userId}\` });
36
+ });
37
+
38
+ this.router.get('/test', async (req: Request, res: Response) => {
39
+ return res.status(200).json({ message: 'Hello World' });
40
+ });
41
+
42
+ /**
43
+ * Session endpoint: returns current user's org roles and permissions from Clerk JWT.
44
+ * The "o" claim is included automatically when user has an active organization.
45
+ */
46
+ this.router.get('/session', (req: Request, res: Response) => {
47
+ const auth = req.auth;
48
+ if (!auth) {
49
+ return res.status(401).json({ error: 'Unauthorized', message: 'No session' });
50
+ }
51
+ return res.status(200).json({
52
+ userId: auth.userId,
53
+ orgId: auth.orgId ?? null,
54
+ orgSlug: auth.orgSlug ?? null,
55
+ orgRole: auth.orgRole ?? null,
56
+ permissions: auth.permissions ?? [],
57
+ });
58
+ });
59
+ }
60
+ }
61
+ `,
62
+ });
63
+ }
64
+ }
65
+ exports.ExpressApiRouterFile = ExpressApiRouterFile;
66
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRXhwcmVzc0FwaVJvdXRlckZpbGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvQXBpL0V4cHJlc3NBcGlSb3V0ZXJGaWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLG1DQUE2QztBQUU3QyxNQUFhLG9CQUFxQixTQUFRLG1CQUFVO0lBQ2xELFlBQVksT0FBZ0I7UUFDMUIsS0FBSyxDQUFDLE9BQU8sRUFBRSw0Q0FBNEMsRUFBRTtZQUMzRCxRQUFRLEVBQUU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0NBcURmO1NBQ0ksQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUVGO0FBNURELG9EQTREQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFByb2plY3QsIFNhbXBsZUZpbGUgfSBmcm9tICdwcm9qZW4nO1xuXG5leHBvcnQgY2xhc3MgRXhwcmVzc0FwaVJvdXRlckZpbGUgZXh0ZW5kcyBTYW1wbGVGaWxlIHtcbiAgY29uc3RydWN0b3IocHJvamVjdDogUHJvamVjdCkge1xuICAgIHN1cGVyKHByb2plY3QsICdzcmMvY29uc3RydWN0cy9oYW5kbGVyL0V4cHJlc3NBcGlSb3V0ZXIudHMnLCB7XG4gICAgICBjb250ZW50czogYGltcG9ydCB7IFJlcXVlc3QsIFJlc3BvbnNlLCBSb3V0ZXIgfSBmcm9tICdleHByZXNzJztcblxuZXhwb3J0IGNsYXNzIEV4cHJlc3NBcGlSb3V0ZXIge1xuICBwcml2YXRlIHJlYWRvbmx5IHJvdXRlcjogUm91dGVyO1xuXG4gIGNvbnN0cnVjdG9yKHJvdXRlcjogUm91dGVyKSB7XG4gICAgdGhpcy5yb3V0ZXIgPSByb3V0ZXI7XG4gICAgdGhpcy5zZXR1cFJvdXRlcygpO1xuICB9XG5cblxuICAvKipcbiAgICogR2V0cyB0aGUgRXhwcmVzcyByb3V0ZXIgaW5zdGFuY2VcbiAgICpcbiAgICogQHJldHVybnMgUm91dGVyIFRoZSBFeHByZXNzIHJvdXRlclxuICAgKi9cbiAgcHVibGljIGdldFJvdXRlcigpOiBSb3V0ZXIge1xuICAgIHJldHVybiB0aGlzLnJvdXRlcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHVwIGFsbCBhdmFpbGFibGUgcm91dGVzXG4gICAqL1xuICBwcml2YXRlIHNldHVwUm91dGVzKCk6IHZvaWQge1xuICAgIFxuICAgIHRoaXMucm91dGVyLmdldCgnLycsIGFzeW5jIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpID0+IHtcbiAgICAgIGNvbnN0IGF1dGggPSByZXEuYXV0aDtcbiAgICAgIHJldHVybiByZXMuc3RhdHVzKDIwMCkuanNvbih7IG1lc3NhZ2U6IFxcYEhlbGxvIFxcJHthdXRoIS51c2VySWR9XFxgIH0pO1xuICAgIH0pO1xuICAgIFxuICAgIHRoaXMucm91dGVyLmdldCgnL3Rlc3QnLCBhc3luYyAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlKSA9PiB7XG4gICAgICByZXR1cm4gcmVzLnN0YXR1cygyMDApLmpzb24oeyBtZXNzYWdlOiAnSGVsbG8gV29ybGQnIH0pO1xuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogU2Vzc2lvbiBlbmRwb2ludDogcmV0dXJucyBjdXJyZW50IHVzZXIncyBvcmcgcm9sZXMgYW5kIHBlcm1pc3Npb25zIGZyb20gQ2xlcmsgSldULlxuICAgICAqIFRoZSBcIm9cIiBjbGFpbSBpcyBpbmNsdWRlZCBhdXRvbWF0aWNhbGx5IHdoZW4gdXNlciBoYXMgYW4gYWN0aXZlIG9yZ2FuaXphdGlvbi5cbiAgICAgKi9cbiAgICB0aGlzLnJvdXRlci5nZXQoJy9zZXNzaW9uJywgKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSkgPT4ge1xuICAgICAgY29uc3QgYXV0aCA9IHJlcS5hdXRoO1xuICAgICAgaWYgKCFhdXRoKSB7XG4gICAgICAgIHJldHVybiByZXMuc3RhdHVzKDQwMSkuanNvbih7IGVycm9yOiAnVW5hdXRob3JpemVkJywgbWVzc2FnZTogJ05vIHNlc3Npb24nIH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlcy5zdGF0dXMoMjAwKS5qc29uKHtcbiAgICAgICAgdXNlcklkOiBhdXRoLnVzZXJJZCxcbiAgICAgICAgb3JnSWQ6IGF1dGgub3JnSWQgPz8gbnVsbCxcbiAgICAgICAgb3JnU2x1ZzogYXV0aC5vcmdTbHVnID8/IG51bGwsXG4gICAgICAgIG9yZ1JvbGU6IGF1dGgub3JnUm9sZSA/PyBudWxsLFxuICAgICAgICBwZXJtaXNzaW9uczogYXV0aC5wZXJtaXNzaW9ucyA/PyBbXSxcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG59XG5gLFxuICAgIH0pO1xuICB9XG5cbn1cbiJdfQ==
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Application = void 0;
4
+ const ApiFiles_1 = require("./Api/ApiFiles");
4
5
  const ApiConstructFile_1 = require("./ApiConstructFile");
5
- const ApiFunctionFile_1 = require("./ApiFunctionFile");
6
6
  const ApplicationStackFile_1 = require("./ApplicationStackFile");
7
7
  const BaseApplicationStackFile_1 = require("./BaseApplicationStackFile");
8
8
  const CodeRabbitFile_1 = require("./CodeRabbitFile");
9
9
  const GitHubRolesStackFile_1 = require("./GitHubRolesStackFile");
10
- const LocalDevAppFile_1 = require("./LocalDevAppFile");
10
+ const LocalDevFiles_1 = require("./LocalDevFiles");
11
11
  const MainFile_1 = require("./MainFile");
12
12
  const MainTestFile_1 = require("./MainTestFile");
13
13
  const PrCleanupWorkflow_1 = require("./PrCleanupWorkflow");
@@ -30,7 +30,7 @@ class Application {
30
30
  prod: options.prod,
31
31
  additionalTags: options.additionalTags,
32
32
  });
33
- new LocalDevAppFile_1.LocalDevAppFile(project, {
33
+ new LocalDevFiles_1.LocalDevFiles(project, {
34
34
  projectName: project.name,
35
35
  dev: options.dev,
36
36
  });
@@ -48,8 +48,8 @@ class Application {
48
48
  new WorkflowProvider_1.WorkflowProviderFile(project);
49
49
  new WorkflowAutoDiscover_1.WorkflowAutoDiscover(project);
50
50
  }
51
- // Create handler files
52
- new ApiFunctionFile_1.ApiFunctionFile(project);
51
+ // Create handler files and API backend logic files
52
+ new ApiFiles_1.ApiFiles(project);
53
53
  // Create test files
54
54
  new MainTestFile_1.MainTestFile(project);
55
55
  // Create config files
@@ -80,4 +80,4 @@ class Application {
80
80
  }
81
81
  }
82
82
  exports.Application = Application;
83
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXBwbGljYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvQXBwbGljYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQ0EseURBQXNEO0FBQ3RELHVEQUFvRDtBQUNwRCxpRUFBOEQ7QUFDOUQseUVBQXNFO0FBQ3RFLHFEQUFrRDtBQUNsRCxpRUFBOEQ7QUFDOUQsdURBQW9EO0FBQ3BELHlDQUF5RDtBQUN6RCxpREFBOEM7QUFDOUMsMkRBQXdEO0FBQ3hELHlEQUFzRDtBQUN0RCx5RUFBc0U7QUFDdEUsbUVBQWdFO0FBQ2hFLDZFQUEwRTtBQUMxRSxpRUFBOEQ7QUFDOUQseURBQTBEO0FBZTFEOztHQUVHO0FBQ0gsTUFBYSxXQUFXO0lBQ3RCLFlBQVksT0FBNEIsRUFBRSxPQUEyQjtRQUNuRSxnQ0FBZ0M7UUFFaEMsSUFBSSxtQkFBUSxDQUFDLE9BQU8sRUFBRTtZQUNwQixXQUFXLEVBQUUsT0FBTyxDQUFDLElBQUk7WUFDekIsR0FBRyxFQUFFLE9BQU8sQ0FBQyxHQUFHO1lBQ2hCLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTztZQUN4QixJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUk7WUFDbEIsY0FBYyxFQUFFLE9BQU8sQ0FBQyxjQUFjO1NBQ3ZDLENBQUMsQ0FBQztRQUVILElBQUksaUNBQWUsQ0FBQyxPQUFPLEVBQUU7WUFDM0IsV0FBVyxFQUFFLE9BQU8sQ0FBQyxJQUFJO1lBQ3pCLEdBQUcsRUFBRSxPQUFPLENBQUMsR0FBRztTQUNqQixDQUFDLENBQUM7UUFFSCxxQkFBcUI7UUFDckIsSUFBSSwyQ0FBb0IsQ0FBQyxPQUFPLEVBQUU7WUFDaEMsZ0JBQWdCLEVBQUUsT0FBTyxDQUFDLGdCQUFnQjtTQUMzQyxDQUFDLENBQUM7UUFFSCxJQUFJLG1EQUF3QixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3RDLElBQUksMkNBQW9CLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFbEMseUJBQXlCO1FBQ3pCLElBQUksbUNBQWdCLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDOUIsSUFBSSx1REFBMEIsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUV4QyxxQkFBcUI7UUFDckIsSUFBSSxPQUFPLENBQUMsWUFBWSxLQUFLLFNBQVMsSUFBSSxPQUFPLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDL0QsSUFBSSx1Q0FBb0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNsQyxJQUFJLDJDQUFvQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3BDLENBQUM7UUFFRCx1QkFBdUI7UUFDdkIsSUFBSSxpQ0FBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRTdCLG9CQUFvQjtRQUNwQixJQUFJLDJCQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFMUIsc0JBQXNCO1FBQ3RCLElBQUksK0JBQWMsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUU1QixrQ0FBa0M7UUFDbEMsSUFBSSxtQ0FBZ0IsQ0FBQyxPQUFPLEVBQUU7WUFDNUIsT0FBTyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQW1CO1lBQ3hDLFNBQVMsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU07WUFDN0IsbUJBQW1CLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtQkFBbUI7U0FDckQsQ0FBQyxDQUFDO1FBRUgsSUFBSSxxQ0FBaUIsQ0FBQyxPQUFPLEVBQUU7WUFDN0IsT0FBTyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQW1CO1lBQ3hDLFNBQVMsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU07WUFDN0IsV0FBVyxFQUFFLE9BQU8sQ0FBQyxJQUFJO1NBQzFCLENBQUMsQ0FBQztRQUVILElBQUksNkNBQXFCLENBQUMsT0FBTyxFQUFFO1lBQ2pDLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDLG1CQUFtQjtZQUM1QyxTQUFTLEVBQUUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNO1lBQ2pDLFdBQVcsRUFBRSxPQUFPLENBQUMsSUFBSTtZQUN6QixtQkFBbUIsRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDLG1CQUFtQjtTQUN6RCxDQUFDLENBQUM7UUFFSCxJQUFJLG1EQUF3QixDQUFDLE9BQU8sRUFBRTtZQUNwQyxPQUFPLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxtQkFBbUI7WUFDekMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTTtZQUM5QixXQUFXLEVBQUUsT0FBTyxDQUFDLElBQUk7WUFDekIsbUJBQW1CLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxtQkFBbUI7U0FDdEQsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBdkVELGtDQXVFQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEF3c0Nka1R5cGVTY3JpcHRBcHAgfSBmcm9tICdwcm9qZW4vbGliL2F3c2Nkayc7XG5pbXBvcnQgeyBBcGlDb25zdHJ1Y3RGaWxlIH0gZnJvbSAnLi9BcGlDb25zdHJ1Y3RGaWxlJztcbmltcG9ydCB7IEFwaUZ1bmN0aW9uRmlsZSB9IGZyb20gJy4vQXBpRnVuY3Rpb25GaWxlJztcbmltcG9ydCB7IEFwcGxpY2F0aW9uU3RhY2tGaWxlIH0gZnJvbSAnLi9BcHBsaWNhdGlvblN0YWNrRmlsZSc7XG5pbXBvcnQgeyBCYXNlQXBwbGljYXRpb25TdGFja0ZpbGUgfSBmcm9tICcuL0Jhc2VBcHBsaWNhdGlvblN0YWNrRmlsZSc7XG5pbXBvcnQgeyBDb2RlUmFiYml0RmlsZSB9IGZyb20gJy4vQ29kZVJhYmJpdEZpbGUnO1xuaW1wb3J0IHsgR2l0SHViUm9sZXNTdGFja0ZpbGUgfSBmcm9tICcuL0dpdEh1YlJvbGVzU3RhY2tGaWxlJztcbmltcG9ydCB7IExvY2FsRGV2QXBwRmlsZSB9IGZyb20gJy4vTG9jYWxEZXZBcHBGaWxlJztcbmltcG9ydCB7IEVudmlyb25tZW50Q29uZmlnLCBNYWluRmlsZSB9IGZyb20gJy4vTWFpbkZpbGUnO1xuaW1wb3J0IHsgTWFpblRlc3RGaWxlIH0gZnJvbSAnLi9NYWluVGVzdEZpbGUnO1xuaW1wb3J0IHsgUHJDbGVhbnVwV29ya2Zsb3cgfSBmcm9tICcuL1ByQ2xlYW51cFdvcmtmbG93JztcbmltcG9ydCB7IFByRGVwbG95V29ya2Zsb3cgfSBmcm9tICcuL1ByRGVwbG95V29ya2Zsb3cnO1xuaW1wb3J0IHsgUHJvZHVjdGlvbkRlcGxveVdvcmtmbG93IH0gZnJvbSAnLi9Qcm9kdWN0aW9uRGVwbG95V29ya2Zsb3cnO1xuaW1wb3J0IHsgU3RhZ2luZ0RlcGxveVdvcmtmbG93IH0gZnJvbSAnLi9TdGFnaW5nRGVwbG95V29ya2Zsb3cnO1xuaW1wb3J0IHsgU3RhdGljV2Vic2l0ZUNvbnN0cnVjdEZpbGUgfSBmcm9tICcuL1N0YXRpY1dlYnNpdGVDb25zdHJ1Y3RGaWxlJztcbmltcG9ydCB7IFdvcmtmbG93QXV0b0Rpc2NvdmVyIH0gZnJvbSAnLi9Xb3JrZmxvd0F1dG9EaXNjb3Zlcic7XG5pbXBvcnQgeyBXb3JrZmxvd1Byb3ZpZGVyRmlsZSB9IGZyb20gJy4vV29ya2Zsb3dQcm92aWRlcic7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQXBwbGljYXRpb25FbnZpcm9ubWVudENvbmZpZyBleHRlbmRzIEVudmlyb25tZW50Q29uZmlnIHtcbiAgcmVhZG9ubHkgZ2l0aHViQWN0aW9uUm9sZUFybjogYGFybjphd3M6aWFtOjoke3N0cmluZ306cm9sZS8ke3N0cmluZ31gO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEFwcGxpY2F0aW9uT3B0aW9ucyB7XG4gIHJlYWRvbmx5IGdpdGh1YlJlcG9zaXRvcnk6IHN0cmluZztcbiAgcmVhZG9ubHkgZGV2OiBBcHBsaWNhdGlvbkVudmlyb25tZW50Q29uZmlnO1xuICByZWFkb25seSBzdGFnaW5nOiBBcHBsaWNhdGlvbkVudmlyb25tZW50Q29uZmlnO1xuICByZWFkb25seSBwcm9kOiBBcHBsaWNhdGlvbkVudmlyb25tZW50Q29uZmlnO1xuICByZWFkb25seSBhZGRpdGlvbmFsVGFncz86IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH07XG4gIHJlYWRvbmx5IG44bldvcmtmbG93cz86IGJvb2xlYW47XG59XG5cbi8qKlxuICogQXBwbGljYXRpb24gY29uc3RydWN0IHRoYXQgY3JlYXRlcyBhbGwgc3RhbmRhcmQgcHJvamVjdCBmaWxlc1xuICovXG5leHBvcnQgY2xhc3MgQXBwbGljYXRpb24ge1xuICBjb25zdHJ1Y3Rvcihwcm9qZWN0OiBBd3NDZGtUeXBlU2NyaXB0QXBwLCBvcHRpb25zOiBBcHBsaWNhdGlvbk9wdGlvbnMpIHtcbiAgICAvLyBDcmVhdGUgbWFpbiBlbnRyeSBwb2ludCBmaWxlc1xuXG4gICAgbmV3IE1haW5GaWxlKHByb2plY3QsIHtcbiAgICAgIHByb2plY3ROYW1lOiBwcm9qZWN0Lm5hbWUsXG4gICAgICBkZXY6IG9wdGlvbnMuZGV2LFxuICAgICAgc3RhZ2luZzogb3B0aW9ucy5zdGFnaW5nLFxuICAgICAgcHJvZDogb3B0aW9ucy5wcm9kLFxuICAgICAgYWRkaXRpb25hbFRhZ3M6IG9wdGlvbnMuYWRkaXRpb25hbFRhZ3MsXG4gICAgfSk7XG5cbiAgICBuZXcgTG9jYWxEZXZBcHBGaWxlKHByb2plY3QsIHtcbiAgICAgIHByb2plY3ROYW1lOiBwcm9qZWN0Lm5hbWUsXG4gICAgICBkZXY6IG9wdGlvbnMuZGV2LFxuICAgIH0pO1xuXG4gICAgLy8gQ3JlYXRlIHN0YWNrIGZpbGVzXG4gICAgbmV3IEdpdEh1YlJvbGVzU3RhY2tGaWxlKHByb2plY3QsIHtcbiAgICAgIGdpdGh1YlJlcG9zaXRvcnk6IG9wdGlvbnMuZ2l0aHViUmVwb3NpdG9yeSxcbiAgICB9KTtcblxuICAgIG5ldyBCYXNlQXBwbGljYXRpb25TdGFja0ZpbGUocHJvamVjdCk7XG4gICAgbmV3IEFwcGxpY2F0aW9uU3RhY2tGaWxlKHByb2plY3QpO1xuXG4gICAgLy8gQ3JlYXRlIGNvbnN0cnVjdCBmaWxlc1xuICAgIG5ldyBBcGlDb25zdHJ1Y3RGaWxlKHByb2plY3QpO1xuICAgIG5ldyBTdGF0aWNXZWJzaXRlQ29uc3RydWN0RmlsZShwcm9qZWN0KTtcblxuICAgIC8vIG44biB3b3JrZmxvdyBmaWxlc1xuICAgIGlmIChvcHRpb25zLm44bldvcmtmbG93cyA9PT0gdW5kZWZpbmVkIHx8IG9wdGlvbnMubjhuV29ya2Zsb3dzKSB7XG4gICAgICBuZXcgV29ya2Zsb3dQcm92aWRlckZpbGUocHJvamVjdCk7XG4gICAgICBuZXcgV29ya2Zsb3dBdXRvRGlzY292ZXIocHJvamVjdCk7XG4gICAgfVxuXG4gICAgLy8gQ3JlYXRlIGhhbmRsZXIgZmlsZXNcbiAgICBuZXcgQXBpRnVuY3Rpb25GaWxlKHByb2plY3QpO1xuXG4gICAgLy8gQ3JlYXRlIHRlc3QgZmlsZXNcbiAgICBuZXcgTWFpblRlc3RGaWxlKHByb2plY3QpO1xuXG4gICAgLy8gQ3JlYXRlIGNvbmZpZyBmaWxlc1xuICAgIG5ldyBDb2RlUmFiYml0RmlsZShwcm9qZWN0KTtcblxuICAgIC8vIENyZWF0ZSBHaXRIdWIgQWN0aW9ucyB3b3JrZmxvd3NcbiAgICBuZXcgUHJEZXBsb3lXb3JrZmxvdyhwcm9qZWN0LCB7XG4gICAgICByb2xlQXJuOiBvcHRpb25zLmRldi5naXRodWJBY3Rpb25Sb2xlQXJuLFxuICAgICAgYXdzUmVnaW9uOiBvcHRpb25zLmRldi5yZWdpb24sXG4gICAgICBjbGVya1B1Ymxpc2hhYmxlS2V5OiBvcHRpb25zLmRldi5jbGVya1B1Ymxpc2hhYmxlS2V5LFxuICAgIH0pO1xuXG4gICAgbmV3IFByQ2xlYW51cFdvcmtmbG93KHByb2plY3QsIHtcbiAgICAgIHJvbGVBcm46IG9wdGlvbnMuZGV2LmdpdGh1YkFjdGlvblJvbGVBcm4sXG4gICAgICBhd3NSZWdpb246IG9wdGlvbnMuZGV2LnJlZ2lvbixcbiAgICAgIHByb2plY3ROYW1lOiBwcm9qZWN0Lm5hbWUsXG4gICAgfSk7XG5cbiAgICBuZXcgU3RhZ2luZ0RlcGxveVdvcmtmbG93KHByb2plY3QsIHtcbiAgICAgIHJvbGVBcm46IG9wdGlvbnMuc3RhZ2luZy5naXRodWJBY3Rpb25Sb2xlQXJuLFxuICAgICAgYXdzUmVnaW9uOiBvcHRpb25zLnN0YWdpbmcucmVnaW9uLFxuICAgICAgcHJvamVjdE5hbWU6IHByb2plY3QubmFtZSxcbiAgICAgIGNsZXJrUHVibGlzaGFibGVLZXk6IG9wdGlvbnMuc3RhZ2luZy5jbGVya1B1Ymxpc2hhYmxlS2V5LFxuICAgIH0pO1xuXG4gICAgbmV3IFByb2R1Y3Rpb25EZXBsb3lXb3JrZmxvdyhwcm9qZWN0LCB7XG4gICAgICByb2xlQXJuOiBvcHRpb25zLnByb2QuZ2l0aHViQWN0aW9uUm9sZUFybixcbiAgICAgIGF3c1JlZ2lvbjogb3B0aW9ucy5wcm9kLnJlZ2lvbixcbiAgICAgIHByb2plY3ROYW1lOiBwcm9qZWN0Lm5hbWUsXG4gICAgICBjbGVya1B1Ymxpc2hhYmxlS2V5OiBvcHRpb25zLnByb2QuY2xlcmtQdWJsaXNoYWJsZUtleSxcbiAgICB9KTtcbiAgfVxufVxuIl19
83
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXBwbGljYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvQXBwbGljYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQ0EsNkNBQTBDO0FBQzFDLHlEQUFzRDtBQUN0RCxpRUFBOEQ7QUFDOUQseUVBQXNFO0FBQ3RFLHFEQUFrRDtBQUNsRCxpRUFBOEQ7QUFDOUQsbURBQWdEO0FBQ2hELHlDQUF5RDtBQUN6RCxpREFBOEM7QUFDOUMsMkRBQXdEO0FBQ3hELHlEQUFzRDtBQUN0RCx5RUFBc0U7QUFDdEUsbUVBQWdFO0FBQ2hFLDZFQUEwRTtBQUMxRSxpRUFBOEQ7QUFDOUQseURBQTBEO0FBZTFEOztHQUVHO0FBQ0gsTUFBYSxXQUFXO0lBQ3RCLFlBQVksT0FBNEIsRUFBRSxPQUEyQjtRQUNuRSxnQ0FBZ0M7UUFFaEMsSUFBSSxtQkFBUSxDQUFDLE9BQU8sRUFBRTtZQUNwQixXQUFXLEVBQUUsT0FBTyxDQUFDLElBQUk7WUFDekIsR0FBRyxFQUFFLE9BQU8sQ0FBQyxHQUFHO1lBQ2hCLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTztZQUN4QixJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUk7WUFDbEIsY0FBYyxFQUFFLE9BQU8sQ0FBQyxjQUFjO1NBQ3ZDLENBQUMsQ0FBQztRQUVILElBQUksNkJBQWEsQ0FBQyxPQUFPLEVBQUU7WUFDekIsV0FBVyxFQUFFLE9BQU8sQ0FBQyxJQUFJO1lBQ3pCLEdBQUcsRUFBRSxPQUFPLENBQUMsR0FBRztTQUNqQixDQUFDLENBQUM7UUFFSCxxQkFBcUI7UUFDckIsSUFBSSwyQ0FBb0IsQ0FBQyxPQUFPLEVBQUU7WUFDaEMsZ0JBQWdCLEVBQUUsT0FBTyxDQUFDLGdCQUFnQjtTQUMzQyxDQUFDLENBQUM7UUFFSCxJQUFJLG1EQUF3QixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3RDLElBQUksMkNBQW9CLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFbEMseUJBQXlCO1FBQ3pCLElBQUksbUNBQWdCLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDOUIsSUFBSSx1REFBMEIsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUV4QyxxQkFBcUI7UUFDckIsSUFBSSxPQUFPLENBQUMsWUFBWSxLQUFLLFNBQVMsSUFBSSxPQUFPLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDL0QsSUFBSSx1Q0FBb0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNsQyxJQUFJLDJDQUFvQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3BDLENBQUM7UUFFRCxtREFBbUQ7UUFDbkQsSUFBSSxtQkFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRXRCLG9CQUFvQjtRQUNwQixJQUFJLDJCQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFMUIsc0JBQXNCO1FBQ3RCLElBQUksK0JBQWMsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUU1QixrQ0FBa0M7UUFDbEMsSUFBSSxtQ0FBZ0IsQ0FBQyxPQUFPLEVBQUU7WUFDNUIsT0FBTyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQW1CO1lBQ3hDLFNBQVMsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU07WUFDN0IsbUJBQW1CLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtQkFBbUI7U0FDckQsQ0FBQyxDQUFDO1FBRUgsSUFBSSxxQ0FBaUIsQ0FBQyxPQUFPLEVBQUU7WUFDN0IsT0FBTyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQW1CO1lBQ3hDLFNBQVMsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU07WUFDN0IsV0FBVyxFQUFFLE9BQU8sQ0FBQyxJQUFJO1NBQzFCLENBQUMsQ0FBQztRQUVILElBQUksNkNBQXFCLENBQUMsT0FBTyxFQUFFO1lBQ2pDLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDLG1CQUFtQjtZQUM1QyxTQUFTLEVBQUUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNO1lBQ2pDLFdBQVcsRUFBRSxPQUFPLENBQUMsSUFBSTtZQUN6QixtQkFBbUIsRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDLG1CQUFtQjtTQUN6RCxDQUFDLENBQUM7UUFFSCxJQUFJLG1EQUF3QixDQUFDLE9BQU8sRUFBRTtZQUNwQyxPQUFPLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxtQkFBbUI7WUFDekMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTTtZQUM5QixXQUFXLEVBQUUsT0FBTyxDQUFDLElBQUk7WUFDekIsbUJBQW1CLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxtQkFBbUI7U0FDdEQsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBdkVELGtDQXVFQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEF3c0Nka1R5cGVTY3JpcHRBcHAgfSBmcm9tICdwcm9qZW4vbGliL2F3c2Nkayc7XG5pbXBvcnQgeyBBcGlGaWxlcyB9IGZyb20gJy4vQXBpL0FwaUZpbGVzJztcbmltcG9ydCB7IEFwaUNvbnN0cnVjdEZpbGUgfSBmcm9tICcuL0FwaUNvbnN0cnVjdEZpbGUnO1xuaW1wb3J0IHsgQXBwbGljYXRpb25TdGFja0ZpbGUgfSBmcm9tICcuL0FwcGxpY2F0aW9uU3RhY2tGaWxlJztcbmltcG9ydCB7IEJhc2VBcHBsaWNhdGlvblN0YWNrRmlsZSB9IGZyb20gJy4vQmFzZUFwcGxpY2F0aW9uU3RhY2tGaWxlJztcbmltcG9ydCB7IENvZGVSYWJiaXRGaWxlIH0gZnJvbSAnLi9Db2RlUmFiYml0RmlsZSc7XG5pbXBvcnQgeyBHaXRIdWJSb2xlc1N0YWNrRmlsZSB9IGZyb20gJy4vR2l0SHViUm9sZXNTdGFja0ZpbGUnO1xuaW1wb3J0IHsgTG9jYWxEZXZGaWxlcyB9IGZyb20gJy4vTG9jYWxEZXZGaWxlcyc7XG5pbXBvcnQgeyBFbnZpcm9ubWVudENvbmZpZywgTWFpbkZpbGUgfSBmcm9tICcuL01haW5GaWxlJztcbmltcG9ydCB7IE1haW5UZXN0RmlsZSB9IGZyb20gJy4vTWFpblRlc3RGaWxlJztcbmltcG9ydCB7IFByQ2xlYW51cFdvcmtmbG93IH0gZnJvbSAnLi9QckNsZWFudXBXb3JrZmxvdyc7XG5pbXBvcnQgeyBQckRlcGxveVdvcmtmbG93IH0gZnJvbSAnLi9QckRlcGxveVdvcmtmbG93JztcbmltcG9ydCB7IFByb2R1Y3Rpb25EZXBsb3lXb3JrZmxvdyB9IGZyb20gJy4vUHJvZHVjdGlvbkRlcGxveVdvcmtmbG93JztcbmltcG9ydCB7IFN0YWdpbmdEZXBsb3lXb3JrZmxvdyB9IGZyb20gJy4vU3RhZ2luZ0RlcGxveVdvcmtmbG93JztcbmltcG9ydCB7IFN0YXRpY1dlYnNpdGVDb25zdHJ1Y3RGaWxlIH0gZnJvbSAnLi9TdGF0aWNXZWJzaXRlQ29uc3RydWN0RmlsZSc7XG5pbXBvcnQgeyBXb3JrZmxvd0F1dG9EaXNjb3ZlciB9IGZyb20gJy4vV29ya2Zsb3dBdXRvRGlzY292ZXInO1xuaW1wb3J0IHsgV29ya2Zsb3dQcm92aWRlckZpbGUgfSBmcm9tICcuL1dvcmtmbG93UHJvdmlkZXInO1xuXG5leHBvcnQgaW50ZXJmYWNlIEFwcGxpY2F0aW9uRW52aXJvbm1lbnRDb25maWcgZXh0ZW5kcyBFbnZpcm9ubWVudENvbmZpZyB7XG4gIHJlYWRvbmx5IGdpdGh1YkFjdGlvblJvbGVBcm46IGBhcm46YXdzOmlhbTo6JHtzdHJpbmd9OnJvbGUvJHtzdHJpbmd9YDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBcHBsaWNhdGlvbk9wdGlvbnMge1xuICByZWFkb25seSBnaXRodWJSZXBvc2l0b3J5OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGRldjogQXBwbGljYXRpb25FbnZpcm9ubWVudENvbmZpZztcbiAgcmVhZG9ubHkgc3RhZ2luZzogQXBwbGljYXRpb25FbnZpcm9ubWVudENvbmZpZztcbiAgcmVhZG9ubHkgcHJvZDogQXBwbGljYXRpb25FbnZpcm9ubWVudENvbmZpZztcbiAgcmVhZG9ubHkgYWRkaXRpb25hbFRhZ3M/OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9O1xuICByZWFkb25seSBuOG5Xb3JrZmxvd3M/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIEFwcGxpY2F0aW9uIGNvbnN0cnVjdCB0aGF0IGNyZWF0ZXMgYWxsIHN0YW5kYXJkIHByb2plY3QgZmlsZXNcbiAqL1xuZXhwb3J0IGNsYXNzIEFwcGxpY2F0aW9uIHtcbiAgY29uc3RydWN0b3IocHJvamVjdDogQXdzQ2RrVHlwZVNjcmlwdEFwcCwgb3B0aW9uczogQXBwbGljYXRpb25PcHRpb25zKSB7XG4gICAgLy8gQ3JlYXRlIG1haW4gZW50cnkgcG9pbnQgZmlsZXNcblxuICAgIG5ldyBNYWluRmlsZShwcm9qZWN0LCB7XG4gICAgICBwcm9qZWN0TmFtZTogcHJvamVjdC5uYW1lLFxuICAgICAgZGV2OiBvcHRpb25zLmRldixcbiAgICAgIHN0YWdpbmc6IG9wdGlvbnMuc3RhZ2luZyxcbiAgICAgIHByb2Q6IG9wdGlvbnMucHJvZCxcbiAgICAgIGFkZGl0aW9uYWxUYWdzOiBvcHRpb25zLmFkZGl0aW9uYWxUYWdzLFxuICAgIH0pO1xuXG4gICAgbmV3IExvY2FsRGV2RmlsZXMocHJvamVjdCwge1xuICAgICAgcHJvamVjdE5hbWU6IHByb2plY3QubmFtZSxcbiAgICAgIGRldjogb3B0aW9ucy5kZXYsXG4gICAgfSk7XG5cbiAgICAvLyBDcmVhdGUgc3RhY2sgZmlsZXNcbiAgICBuZXcgR2l0SHViUm9sZXNTdGFja0ZpbGUocHJvamVjdCwge1xuICAgICAgZ2l0aHViUmVwb3NpdG9yeTogb3B0aW9ucy5naXRodWJSZXBvc2l0b3J5LFxuICAgIH0pO1xuXG4gICAgbmV3IEJhc2VBcHBsaWNhdGlvblN0YWNrRmlsZShwcm9qZWN0KTtcbiAgICBuZXcgQXBwbGljYXRpb25TdGFja0ZpbGUocHJvamVjdCk7XG5cbiAgICAvLyBDcmVhdGUgY29uc3RydWN0IGZpbGVzXG4gICAgbmV3IEFwaUNvbnN0cnVjdEZpbGUocHJvamVjdCk7XG4gICAgbmV3IFN0YXRpY1dlYnNpdGVDb25zdHJ1Y3RGaWxlKHByb2plY3QpO1xuXG4gICAgLy8gbjhuIHdvcmtmbG93IGZpbGVzXG4gICAgaWYgKG9wdGlvbnMubjhuV29ya2Zsb3dzID09PSB1bmRlZmluZWQgfHwgb3B0aW9ucy5uOG5Xb3JrZmxvd3MpIHtcbiAgICAgIG5ldyBXb3JrZmxvd1Byb3ZpZGVyRmlsZShwcm9qZWN0KTtcbiAgICAgIG5ldyBXb3JrZmxvd0F1dG9EaXNjb3Zlcihwcm9qZWN0KTtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgaGFuZGxlciBmaWxlcyBhbmQgQVBJIGJhY2tlbmQgbG9naWMgZmlsZXNcbiAgICBuZXcgQXBpRmlsZXMocHJvamVjdCk7XG5cbiAgICAvLyBDcmVhdGUgdGVzdCBmaWxlc1xuICAgIG5ldyBNYWluVGVzdEZpbGUocHJvamVjdCk7XG5cbiAgICAvLyBDcmVhdGUgY29uZmlnIGZpbGVzXG4gICAgbmV3IENvZGVSYWJiaXRGaWxlKHByb2plY3QpO1xuXG4gICAgLy8gQ3JlYXRlIEdpdEh1YiBBY3Rpb25zIHdvcmtmbG93c1xuICAgIG5ldyBQckRlcGxveVdvcmtmbG93KHByb2plY3QsIHtcbiAgICAgIHJvbGVBcm46IG9wdGlvbnMuZGV2LmdpdGh1YkFjdGlvblJvbGVBcm4sXG4gICAgICBhd3NSZWdpb246IG9wdGlvbnMuZGV2LnJlZ2lvbixcbiAgICAgIGNsZXJrUHVibGlzaGFibGVLZXk6IG9wdGlvbnMuZGV2LmNsZXJrUHVibGlzaGFibGVLZXksXG4gICAgfSk7XG5cbiAgICBuZXcgUHJDbGVhbnVwV29ya2Zsb3cocHJvamVjdCwge1xuICAgICAgcm9sZUFybjogb3B0aW9ucy5kZXYuZ2l0aHViQWN0aW9uUm9sZUFybixcbiAgICAgIGF3c1JlZ2lvbjogb3B0aW9ucy5kZXYucmVnaW9uLFxuICAgICAgcHJvamVjdE5hbWU6IHByb2plY3QubmFtZSxcbiAgICB9KTtcblxuICAgIG5ldyBTdGFnaW5nRGVwbG95V29ya2Zsb3cocHJvamVjdCwge1xuICAgICAgcm9sZUFybjogb3B0aW9ucy5zdGFnaW5nLmdpdGh1YkFjdGlvblJvbGVBcm4sXG4gICAgICBhd3NSZWdpb246IG9wdGlvbnMuc3RhZ2luZy5yZWdpb24sXG4gICAgICBwcm9qZWN0TmFtZTogcHJvamVjdC5uYW1lLFxuICAgICAgY2xlcmtQdWJsaXNoYWJsZUtleTogb3B0aW9ucy5zdGFnaW5nLmNsZXJrUHVibGlzaGFibGVLZXksXG4gICAgfSk7XG5cbiAgICBuZXcgUHJvZHVjdGlvbkRlcGxveVdvcmtmbG93KHByb2plY3QsIHtcbiAgICAgIHJvbGVBcm46IG9wdGlvbnMucHJvZC5naXRodWJBY3Rpb25Sb2xlQXJuLFxuICAgICAgYXdzUmVnaW9uOiBvcHRpb25zLnByb2QucmVnaW9uLFxuICAgICAgcHJvamVjdE5hbWU6IHByb2plY3QubmFtZSxcbiAgICAgIGNsZXJrUHVibGlzaGFibGVLZXk6IG9wdGlvbnMucHJvZC5jbGVya1B1Ymxpc2hhYmxlS2V5LFxuICAgIH0pO1xuICB9XG59XG4iXX0=