quidproquo-deploy-awscdk 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/appWorkspace/createWorkspaceQpqCdkApp.d.ts +3 -0
- package/lib/commonjs/appWorkspace/createWorkspaceQpqCdkApp.js +113 -0
- package/lib/commonjs/appWorkspace/createWorkspaceQpqCdkApp.js.map +1 -0
- package/lib/commonjs/appWorkspace/getWorkspaceQpqConfigs.d.ts +5 -0
- package/lib/commonjs/appWorkspace/getWorkspaceQpqConfigs.js +55 -0
- package/lib/commonjs/appWorkspace/getWorkspaceQpqConfigs.js.map +1 -0
- package/lib/commonjs/appWorkspace/index.d.ts +3 -0
- package/lib/commonjs/appWorkspace/index.js +20 -0
- package/lib/commonjs/appWorkspace/index.js.map +1 -0
- package/lib/commonjs/appWorkspace/qpqAppDeployConfig.d.ts +22 -0
- package/lib/commonjs/appWorkspace/qpqAppDeployConfig.js +38 -0
- package/lib/commonjs/appWorkspace/qpqAppDeployConfig.js.map +1 -0
- package/lib/commonjs/constructs/feature/account/QpqAccountCloudTrailConstruct.js +4 -1
- package/lib/commonjs/constructs/feature/account/QpqAccountCloudTrailConstruct.js.map +1 -1
- package/lib/commonjs/constructs/feature/core/eventBus/QpqCoreEventBusConstruct.js.map +1 -1
- package/lib/commonjs/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.js +14 -7
- package/lib/commonjs/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.js.map +1 -1
- package/lib/commonjs/index.d.ts +1 -0
- package/lib/commonjs/index.js +1 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/stacks/DomainCertificateStack.js +3 -0
- package/lib/commonjs/stacks/DomainCertificateStack.js.map +1 -1
- package/lib/commonjs/stacks/WafCloudFrontWebAclStack.js +3 -0
- package/lib/commonjs/stacks/WafCloudFrontWebAclStack.js.map +1 -1
- package/lib/esm/appWorkspace/createWorkspaceQpqCdkApp.d.ts +3 -0
- package/lib/esm/appWorkspace/createWorkspaceQpqCdkApp.js +72 -0
- package/lib/esm/appWorkspace/createWorkspaceQpqCdkApp.js.map +1 -0
- package/lib/esm/appWorkspace/getWorkspaceQpqConfigs.d.ts +5 -0
- package/lib/esm/appWorkspace/getWorkspaceQpqConfigs.js +46 -0
- package/lib/esm/appWorkspace/getWorkspaceQpqConfigs.js.map +1 -0
- package/lib/esm/appWorkspace/index.d.ts +3 -0
- package/lib/esm/appWorkspace/index.js +4 -0
- package/lib/esm/appWorkspace/index.js.map +1 -0
- package/lib/esm/appWorkspace/qpqAppDeployConfig.d.ts +22 -0
- package/lib/esm/appWorkspace/qpqAppDeployConfig.js +29 -0
- package/lib/esm/appWorkspace/qpqAppDeployConfig.js.map +1 -0
- package/lib/esm/constructs/feature/account/QpqAccountCloudTrailConstruct.js +5 -2
- package/lib/esm/constructs/feature/account/QpqAccountCloudTrailConstruct.js.map +1 -1
- package/lib/esm/constructs/feature/core/eventBus/QpqCoreEventBusConstruct.js.map +1 -1
- package/lib/esm/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.js +14 -7
- package/lib/esm/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.js.map +1 -1
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/stacks/DomainCertificateStack.js +3 -0
- package/lib/esm/stacks/DomainCertificateStack.js.map +1 -1
- package/lib/esm/stacks/WafCloudFrontWebAclStack.js +3 -0
- package/lib/esm/stacks/WafCloudFrontWebAclStack.js.map +1 -1
- package/package.json +7 -7
- package/src/appWorkspace/createWorkspaceQpqCdkApp.ts +92 -0
- package/src/appWorkspace/getWorkspaceQpqConfigs.ts +59 -0
- package/src/appWorkspace/index.ts +3 -0
- package/src/appWorkspace/qpqAppDeployConfig.ts +84 -0
- package/src/constructs/feature/account/QpqAccountCloudTrailConstruct.ts +5 -2
- package/src/constructs/feature/core/eventBus/QpqCoreEventBusConstruct.ts +7 -7
- package/src/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.ts +15 -8
- package/src/index.ts +1 -0
- package/src/stacks/DomainCertificateStack.ts +3 -0
- package/src/stacks/WafCloudFrontWebAclStack.ts +3 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.createWorkspaceQpqCdkApp = exports.findWorkspaceRoot = void 0;
|
|
40
|
+
const fs_1 = __importDefault(require("fs"));
|
|
41
|
+
const path_1 = __importDefault(require("path"));
|
|
42
|
+
const QPQApp_1 = require("../QPQApp");
|
|
43
|
+
const stacks_1 = require("../stacks");
|
|
44
|
+
const qpqDeployAwsCdkUtils = __importStar(require("../utils"));
|
|
45
|
+
const getWorkspaceQpqConfigs_1 = require("./getWorkspaceQpqConfigs");
|
|
46
|
+
const qpqAppDeployConfig_1 = require("./qpqAppDeployConfig");
|
|
47
|
+
// Walk up from cwd to the workspace root (the directory with an apps/ folder).
|
|
48
|
+
const findWorkspaceRoot = (startDir = process.cwd()) => {
|
|
49
|
+
let dir = startDir;
|
|
50
|
+
while (!fs_1.default.existsSync(path_1.default.join(dir, 'apps')) || !fs_1.default.existsSync(path_1.default.join(dir, 'package.json'))) {
|
|
51
|
+
const parent = path_1.default.dirname(dir);
|
|
52
|
+
if (parent === dir)
|
|
53
|
+
throw new Error('Could not find workspace root (a directory containing apps/ and package.json)');
|
|
54
|
+
dir = parent;
|
|
55
|
+
}
|
|
56
|
+
return dir;
|
|
57
|
+
};
|
|
58
|
+
exports.findWorkspaceRoot = findWorkspaceRoot;
|
|
59
|
+
// The generic CDK app for a QPQ app workspace — the same stacks for every
|
|
60
|
+
// product; everything app-specific comes from apps/<app>/ (deploy.config.json
|
|
61
|
+
// + optional account.qpq.ts / bootstrap.qpq.ts fragments).
|
|
62
|
+
//
|
|
63
|
+
// Driven by environment variables set by the invoking tool (`qpq go`):
|
|
64
|
+
// DEPLOY_APP_NAME (required) app folder under apps/
|
|
65
|
+
// DEPLOY_SERVICE_NAME (optional) also synth the service's inf/web/api stacks
|
|
66
|
+
// ENVIRONMENT (required) environment name in deploy.config.json
|
|
67
|
+
// ACTOR_NAME (optional) actor/feature deploys
|
|
68
|
+
// AWS_DEFAULT_ACCOUNT / AWS_DEFAULT_REGION (optional) identity override
|
|
69
|
+
const createWorkspaceQpqCdkApp = () => {
|
|
70
|
+
const root = (0, exports.findWorkspaceRoot)();
|
|
71
|
+
const deployAppName = process.env.DEPLOY_APP_NAME;
|
|
72
|
+
if (!deployAppName) {
|
|
73
|
+
throw new Error('DEPLOY_APP_NAME environment variable is not set.');
|
|
74
|
+
}
|
|
75
|
+
const environment = process.env.ENVIRONMENT;
|
|
76
|
+
if (!environment) {
|
|
77
|
+
throw new Error('ENVIRONMENT environment variable is not set.');
|
|
78
|
+
}
|
|
79
|
+
const ctx = (0, qpqAppDeployConfig_1.getQpqAppDeployContext)(root, deployAppName, environment, process.env.ACTOR_NAME, {
|
|
80
|
+
accountId: process.env.AWS_DEFAULT_ACCOUNT,
|
|
81
|
+
region: process.env.AWS_DEFAULT_REGION,
|
|
82
|
+
});
|
|
83
|
+
const app = (0, QPQApp_1.createQPQApp)();
|
|
84
|
+
// Account-level guardrails - one statically named stack per AWS account,
|
|
85
|
+
// independent of any app. Exactly one repo/config owns this per account, and
|
|
86
|
+
// actor deploys must not deploy it.
|
|
87
|
+
new stacks_1.AccountQpqStack(app, qpqDeployAwsCdkUtils.getAccountStackName(), {
|
|
88
|
+
qpqConfig: (0, getWorkspaceQpqConfigs_1.getWorkspaceAccountQpqConfig)(ctx),
|
|
89
|
+
});
|
|
90
|
+
// Bootstrapping stacks — deploy when their config changes.
|
|
91
|
+
const bootstrapQpqConfig = (0, getWorkspaceQpqConfigs_1.getWorkspaceBootstrapQpqConfig)(ctx);
|
|
92
|
+
new stacks_1.DomainQpqServiceStack(app, qpqDeployAwsCdkUtils.getDomainStackName(bootstrapQpqConfig), {
|
|
93
|
+
qpqConfig: bootstrapQpqConfig,
|
|
94
|
+
});
|
|
95
|
+
new stacks_1.BootstrapQpqServiceStack(app, qpqDeployAwsCdkUtils.getBootstrapStackName(bootstrapQpqConfig), {
|
|
96
|
+
qpqConfig: bootstrapQpqConfig,
|
|
97
|
+
});
|
|
98
|
+
if (process.env.DEPLOY_SERVICE_NAME) {
|
|
99
|
+
const qpqConfig = (0, getWorkspaceQpqConfigs_1.getWorkspaceServiceQpqConfig)(root, deployAppName, process.env.DEPLOY_SERVICE_NAME);
|
|
100
|
+
new stacks_1.InfQpqServiceStack(app, qpqDeployAwsCdkUtils.getInfStackName(qpqConfig), {
|
|
101
|
+
qpqConfig,
|
|
102
|
+
});
|
|
103
|
+
new stacks_1.WebQpqServiceStack(app, qpqDeployAwsCdkUtils.getWebStackName(qpqConfig), {
|
|
104
|
+
qpqConfig,
|
|
105
|
+
});
|
|
106
|
+
new stacks_1.ApiQpqServiceStack(app, qpqDeployAwsCdkUtils.getApiStackName(qpqConfig), {
|
|
107
|
+
qpqConfig,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return app;
|
|
111
|
+
};
|
|
112
|
+
exports.createWorkspaceQpqCdkApp = createWorkspaceQpqCdkApp;
|
|
113
|
+
//# sourceMappingURL=createWorkspaceQpqCdkApp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createWorkspaceQpqCdkApp.js","sourceRoot":"","sources":["../../../src/appWorkspace/createWorkspaceQpqCdkApp.ts"],"names":[],"mappings":"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","sourcesContent":["import * as cdk from 'aws-cdk-lib';\nimport fs from 'fs';\nimport path from 'path';\n\nimport { createQPQApp } from '../QPQApp';\nimport {\n AccountQpqStack,\n ApiQpqServiceStack,\n BootstrapQpqServiceStack,\n DomainQpqServiceStack,\n InfQpqServiceStack,\n WebQpqServiceStack,\n} from '../stacks';\nimport * as qpqDeployAwsCdkUtils from '../utils';\nimport { getWorkspaceAccountQpqConfig, getWorkspaceBootstrapQpqConfig, getWorkspaceServiceQpqConfig } from './getWorkspaceQpqConfigs';\nimport { getQpqAppDeployContext } from './qpqAppDeployConfig';\n\n// Walk up from cwd to the workspace root (the directory with an apps/ folder).\nexport const findWorkspaceRoot = (startDir: string = process.cwd()): string => {\n let dir = startDir;\n while (!fs.existsSync(path.join(dir, 'apps')) || !fs.existsSync(path.join(dir, 'package.json'))) {\n const parent = path.dirname(dir);\n if (parent === dir) throw new Error('Could not find workspace root (a directory containing apps/ and package.json)');\n dir = parent;\n }\n return dir;\n};\n\n// The generic CDK app for a QPQ app workspace — the same stacks for every\n// product; everything app-specific comes from apps/<app>/ (deploy.config.json\n// + optional account.qpq.ts / bootstrap.qpq.ts fragments).\n//\n// Driven by environment variables set by the invoking tool (`qpq go`):\n// DEPLOY_APP_NAME (required) app folder under apps/\n// DEPLOY_SERVICE_NAME (optional) also synth the service's inf/web/api stacks\n// ENVIRONMENT (required) environment name in deploy.config.json\n// ACTOR_NAME (optional) actor/feature deploys\n// AWS_DEFAULT_ACCOUNT / AWS_DEFAULT_REGION (optional) identity override\nexport const createWorkspaceQpqCdkApp = (): cdk.App => {\n const root = findWorkspaceRoot();\n\n const deployAppName = process.env.DEPLOY_APP_NAME;\n if (!deployAppName) {\n throw new Error('DEPLOY_APP_NAME environment variable is not set.');\n }\n\n const environment = process.env.ENVIRONMENT;\n if (!environment) {\n throw new Error('ENVIRONMENT environment variable is not set.');\n }\n\n const ctx = getQpqAppDeployContext(root, deployAppName, environment, process.env.ACTOR_NAME, {\n accountId: process.env.AWS_DEFAULT_ACCOUNT,\n region: process.env.AWS_DEFAULT_REGION,\n });\n\n const app = createQPQApp();\n\n // Account-level guardrails - one statically named stack per AWS account,\n // independent of any app. Exactly one repo/config owns this per account, and\n // actor deploys must not deploy it.\n new AccountQpqStack(app, qpqDeployAwsCdkUtils.getAccountStackName(), {\n qpqConfig: getWorkspaceAccountQpqConfig(ctx),\n });\n\n // Bootstrapping stacks — deploy when their config changes.\n const bootstrapQpqConfig = getWorkspaceBootstrapQpqConfig(ctx);\n\n new DomainQpqServiceStack(app, qpqDeployAwsCdkUtils.getDomainStackName(bootstrapQpqConfig), {\n qpqConfig: bootstrapQpqConfig,\n });\n\n new BootstrapQpqServiceStack(app, qpqDeployAwsCdkUtils.getBootstrapStackName(bootstrapQpqConfig), {\n qpqConfig: bootstrapQpqConfig,\n });\n\n if (process.env.DEPLOY_SERVICE_NAME) {\n const qpqConfig = getWorkspaceServiceQpqConfig(root, deployAppName, process.env.DEPLOY_SERVICE_NAME);\n\n new InfQpqServiceStack(app, qpqDeployAwsCdkUtils.getInfStackName(qpqConfig), {\n qpqConfig,\n });\n new WebQpqServiceStack(app, qpqDeployAwsCdkUtils.getWebStackName(qpqConfig), {\n qpqConfig,\n });\n new ApiQpqServiceStack(app, qpqDeployAwsCdkUtils.getApiStackName(qpqConfig), {\n qpqConfig,\n });\n }\n\n return app;\n};\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { QPQConfig } from 'quidproquo-core';
|
|
2
|
+
import { QpqAppDeployContext } from './qpqAppDeployConfig';
|
|
3
|
+
export declare const getWorkspaceAccountQpqConfig: (ctx: QpqAppDeployContext) => QPQConfig;
|
|
4
|
+
export declare const getWorkspaceBootstrapQpqConfig: (ctx: QpqAppDeployContext) => QPQConfig;
|
|
5
|
+
export declare const getWorkspaceServiceQpqConfig: (root: string, appName: string, serviceName: string) => QPQConfig;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getWorkspaceServiceQpqConfig = exports.getWorkspaceBootstrapQpqConfig = exports.getWorkspaceAccountQpqConfig = void 0;
|
|
7
|
+
const quidproquo_config_aws_1 = require("quidproquo-config-aws");
|
|
8
|
+
const quidproquo_core_1 = require("quidproquo-core");
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
// Loads an optional per-app config fragment (apps/<app>/account.qpq.ts or
|
|
12
|
+
// bootstrap.qpq.ts) — a default-exported `(ctx) => QPQConfig` of app-specific
|
|
13
|
+
// EXTRAS. The identity plumbing (defineApplication +
|
|
14
|
+
// defineAwsServiceAccountInfo) is provided by the callers below, so fragments
|
|
15
|
+
// must not declare their own. Requiring TS relies on the caller running with
|
|
16
|
+
// TS require hooks (ts-node), as the CDK app invocation does.
|
|
17
|
+
const loadAppConfigFragment = (ctx, fileName) => {
|
|
18
|
+
const fragmentPath = path_1.default.join(ctx.appDir, fileName);
|
|
19
|
+
if (!fs_1.default.existsSync(fragmentPath)) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
23
|
+
const fragmentModule = require(path_1.default.join(ctx.appDir, fileName.replace(/\.ts$/, '')));
|
|
24
|
+
const fragment = fragmentModule.default || fragmentModule;
|
|
25
|
+
return typeof fragment === 'function' ? fragment(ctx) : fragment;
|
|
26
|
+
};
|
|
27
|
+
// Account-level guardrails — one statically named stack per AWS account,
|
|
28
|
+
// independent of any app. The app name / environment here only satisfy config
|
|
29
|
+
// plumbing; account resources key on accountId/region.
|
|
30
|
+
const getWorkspaceAccountQpqConfig = (ctx) => [
|
|
31
|
+
(0, quidproquo_core_1.defineApplication)('account', ctx.environment, ctx.appDir),
|
|
32
|
+
(0, quidproquo_config_aws_1.defineAwsServiceAccountInfo)(ctx.accountId, ctx.region),
|
|
33
|
+
...loadAppConfigFragment(ctx, 'account.qpq.ts'),
|
|
34
|
+
];
|
|
35
|
+
exports.getWorkspaceAccountQpqConfig = getWorkspaceAccountQpqConfig;
|
|
36
|
+
// The app's bootstrap config: apex/zone/cert/WAF-level resources every service
|
|
37
|
+
// in the app builds on. Resource names are prefixed with the app prefix, so
|
|
38
|
+
// multiple apps can bootstrap into one shared AWS account.
|
|
39
|
+
const getWorkspaceBootstrapQpqConfig = (ctx) => [
|
|
40
|
+
(0, quidproquo_core_1.defineApplication)(ctx.prefix, ctx.environment, ctx.appDir, ctx.actorName),
|
|
41
|
+
(0, quidproquo_config_aws_1.defineAwsServiceAccountInfo)(ctx.accountId, ctx.region),
|
|
42
|
+
...loadAppConfigFragment(ctx, 'bootstrap.qpq.ts'),
|
|
43
|
+
];
|
|
44
|
+
exports.getWorkspaceBootstrapQpqConfig = getWorkspaceBootstrapQpqConfig;
|
|
45
|
+
// A service's own QPQ config, loaded straight from its infrastructure.ts (its
|
|
46
|
+
// @scope imports resolve through the workspace node_modules symlinks to built
|
|
47
|
+
// dist — no tsconfig-paths registration needed under ts-node).
|
|
48
|
+
const getWorkspaceServiceQpqConfig = (root, appName, serviceName) => {
|
|
49
|
+
const infrastructurePath = path_1.default.join(root, 'apps', appName, 'services', serviceName, 'service', 'src', 'infrastructure');
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
51
|
+
const infraModule = require(infrastructurePath);
|
|
52
|
+
return infraModule.default || infraModule;
|
|
53
|
+
};
|
|
54
|
+
exports.getWorkspaceServiceQpqConfig = getWorkspaceServiceQpqConfig;
|
|
55
|
+
//# sourceMappingURL=getWorkspaceQpqConfigs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getWorkspaceQpqConfigs.js","sourceRoot":"","sources":["../../../src/appWorkspace/getWorkspaceQpqConfigs.ts"],"names":[],"mappings":";;;;;;AAAA,iEAAoE;AACpE,qDAA+D;AAE/D,4CAAoB;AACpB,gDAAwB;AAIxB,0EAA0E;AAC1E,8EAA8E;AAC9E,qDAAqD;AACrD,8EAA8E;AAC9E,6EAA6E;AAC7E,8DAA8D;AAC9D,MAAM,qBAAqB,GAAG,CAAC,GAAwB,EAAE,QAAgB,EAAa,EAAE;IACtF,MAAM,YAAY,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACrD,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,iEAAiE;IACjE,MAAM,cAAc,GAAG,OAAO,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,IAAI,cAAc,CAAC;IAE1D,OAAO,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACnE,CAAC,CAAC;AAEF,yEAAyE;AACzE,8EAA8E;AAC9E,uDAAuD;AAChD,MAAM,4BAA4B,GAAG,CAAC,GAAwB,EAAa,EAAE,CAAC;IACnF,IAAA,mCAAiB,EAAC,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC;IAEzD,IAAA,mDAA2B,EAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC;IAEtD,GAAG,qBAAqB,CAAC,GAAG,EAAE,gBAAgB,CAAC;CAChD,CAAC;AANW,QAAA,4BAA4B,gCAMvC;AAEF,+EAA+E;AAC/E,4EAA4E;AAC5E,2DAA2D;AACpD,MAAM,8BAA8B,GAAG,CAAC,GAAwB,EAAa,EAAE,CAAC;IACrF,IAAA,mCAAiB,EAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,SAAS,CAAC;IAEzE,IAAA,mDAA2B,EAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC;IAEtD,GAAG,qBAAqB,CAAC,GAAG,EAAE,kBAAkB,CAAC;CAClD,CAAC;AANW,QAAA,8BAA8B,kCAMzC;AAEF,8EAA8E;AAC9E,8EAA8E;AAC9E,+DAA+D;AACxD,MAAM,4BAA4B,GAAG,CAAC,IAAY,EAAE,OAAe,EAAE,WAAmB,EAAa,EAAE;IAC5G,MAAM,kBAAkB,GAAG,cAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC;IAEzH,iEAAiE;IACjE,MAAM,WAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAChD,OAAO,WAAW,CAAC,OAAO,IAAI,WAAW,CAAC;AAC5C,CAAC,CAAC;AANW,QAAA,4BAA4B,gCAMvC","sourcesContent":["import { defineAwsServiceAccountInfo } from 'quidproquo-config-aws';\nimport { defineApplication, QPQConfig } from 'quidproquo-core';\n\nimport fs from 'fs';\nimport path from 'path';\n\nimport { QpqAppDeployContext } from './qpqAppDeployConfig';\n\n// Loads an optional per-app config fragment (apps/<app>/account.qpq.ts or\n// bootstrap.qpq.ts) — a default-exported `(ctx) => QPQConfig` of app-specific\n// EXTRAS. The identity plumbing (defineApplication +\n// defineAwsServiceAccountInfo) is provided by the callers below, so fragments\n// must not declare their own. Requiring TS relies on the caller running with\n// TS require hooks (ts-node), as the CDK app invocation does.\nconst loadAppConfigFragment = (ctx: QpqAppDeployContext, fileName: string): QPQConfig => {\n const fragmentPath = path.join(ctx.appDir, fileName);\n if (!fs.existsSync(fragmentPath)) {\n return [];\n }\n\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const fragmentModule = require(path.join(ctx.appDir, fileName.replace(/\\.ts$/, '')));\n const fragment = fragmentModule.default || fragmentModule;\n\n return typeof fragment === 'function' ? fragment(ctx) : fragment;\n};\n\n// Account-level guardrails — one statically named stack per AWS account,\n// independent of any app. The app name / environment here only satisfy config\n// plumbing; account resources key on accountId/region.\nexport const getWorkspaceAccountQpqConfig = (ctx: QpqAppDeployContext): QPQConfig => [\n defineApplication('account', ctx.environment, ctx.appDir),\n\n defineAwsServiceAccountInfo(ctx.accountId, ctx.region),\n\n ...loadAppConfigFragment(ctx, 'account.qpq.ts'),\n];\n\n// The app's bootstrap config: apex/zone/cert/WAF-level resources every service\n// in the app builds on. Resource names are prefixed with the app prefix, so\n// multiple apps can bootstrap into one shared AWS account.\nexport const getWorkspaceBootstrapQpqConfig = (ctx: QpqAppDeployContext): QPQConfig => [\n defineApplication(ctx.prefix, ctx.environment, ctx.appDir, ctx.actorName),\n\n defineAwsServiceAccountInfo(ctx.accountId, ctx.region),\n\n ...loadAppConfigFragment(ctx, 'bootstrap.qpq.ts'),\n];\n\n// A service's own QPQ config, loaded straight from its infrastructure.ts (its\n// @scope imports resolve through the workspace node_modules symlinks to built\n// dist — no tsconfig-paths registration needed under ts-node).\nexport const getWorkspaceServiceQpqConfig = (root: string, appName: string, serviceName: string): QPQConfig => {\n const infrastructurePath = path.join(root, 'apps', appName, 'services', serviceName, 'service', 'src', 'infrastructure');\n\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const infraModule = require(infrastructurePath);\n return infraModule.default || infraModule;\n};\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./createWorkspaceQpqCdkApp"), exports);
|
|
18
|
+
__exportStar(require("./getWorkspaceQpqConfigs"), exports);
|
|
19
|
+
__exportStar(require("./qpqAppDeployConfig"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/appWorkspace/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6DAA2C;AAC3C,2DAAyC;AACzC,uDAAqC","sourcesContent":["export * from './createWorkspaceQpqCdkApp';\nexport * from './getWorkspaceQpqConfigs';\nexport * from './qpqAppDeployConfig';\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface QpqAppDeployEnvironment {
|
|
2
|
+
platform?: string;
|
|
3
|
+
accountId?: string;
|
|
4
|
+
region?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface QpqAppDeployConfig {
|
|
7
|
+
prefix: string;
|
|
8
|
+
domain: string;
|
|
9
|
+
environments?: Record<string, QpqAppDeployEnvironment>;
|
|
10
|
+
}
|
|
11
|
+
export interface QpqAppDeployContext {
|
|
12
|
+
appName: string;
|
|
13
|
+
appDir: string;
|
|
14
|
+
prefix: string;
|
|
15
|
+
domain: string;
|
|
16
|
+
environment: string;
|
|
17
|
+
accountId: string;
|
|
18
|
+
region: string;
|
|
19
|
+
actorName?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const getQpqAppDeployConfig: (root: string, appName: string) => QpqAppDeployConfig;
|
|
22
|
+
export declare const getQpqAppDeployContext: (root: string, appName: string, environment: string, actorName: string | undefined, envOverride?: Partial<QpqAppDeployEnvironment>) => QpqAppDeployContext;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getQpqAppDeployContext = exports.getQpqAppDeployConfig = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const getQpqAppDeployConfig = (root, appName) => {
|
|
10
|
+
const configPath = path_1.default.join(root, 'apps', appName, 'deploy.config.json');
|
|
11
|
+
if (!fs_1.default.existsSync(configPath)) {
|
|
12
|
+
throw new Error(`Missing ${configPath} — create it with { "prefix": "...", "domain": "...", "environments": { ... } }`);
|
|
13
|
+
}
|
|
14
|
+
return JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
|
|
15
|
+
};
|
|
16
|
+
exports.getQpqAppDeployConfig = getQpqAppDeployConfig;
|
|
17
|
+
const getQpqAppDeployContext = (root, appName, environment, actorName, envOverride) => {
|
|
18
|
+
var _a, _b, _c;
|
|
19
|
+
const deployConfig = (0, exports.getQpqAppDeployConfig)(root, appName);
|
|
20
|
+
const configuredEnvironment = (_a = deployConfig.environments) === null || _a === void 0 ? void 0 : _a[environment];
|
|
21
|
+
const accountId = (_b = envOverride === null || envOverride === void 0 ? void 0 : envOverride.accountId) !== null && _b !== void 0 ? _b : configuredEnvironment === null || configuredEnvironment === void 0 ? void 0 : configuredEnvironment.accountId;
|
|
22
|
+
const region = (_c = envOverride === null || envOverride === void 0 ? void 0 : envOverride.region) !== null && _c !== void 0 ? _c : configuredEnvironment === null || configuredEnvironment === void 0 ? void 0 : configuredEnvironment.region;
|
|
23
|
+
if (!accountId || !region) {
|
|
24
|
+
throw new Error(`No deploy target for environment '${environment}' — add it to apps/${appName}/deploy.config.json under "environments", or set AWS_DEFAULT_ACCOUNT / AWS_DEFAULT_REGION`);
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
appName,
|
|
28
|
+
appDir: path_1.default.join(root, 'apps', appName),
|
|
29
|
+
prefix: deployConfig.prefix,
|
|
30
|
+
domain: deployConfig.domain,
|
|
31
|
+
environment,
|
|
32
|
+
accountId,
|
|
33
|
+
region,
|
|
34
|
+
actorName,
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
exports.getQpqAppDeployContext = getQpqAppDeployContext;
|
|
38
|
+
//# sourceMappingURL=qpqAppDeployConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qpqAppDeployConfig.js","sourceRoot":"","sources":["../../../src/appWorkspace/qpqAppDeployConfig.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,gDAAwB;AA0CjB,MAAM,qBAAqB,GAAG,CAAC,IAAY,EAAE,OAAe,EAAsB,EAAE;IACzF,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,CAAC,CAAC;IAC1E,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,WAAW,UAAU,iFAAiF,CAAC,CAAC;IAC1H,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,YAAE,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;AACzD,CAAC,CAAC;AANW,QAAA,qBAAqB,yBAMhC;AAEK,MAAM,sBAAsB,GAAG,CACpC,IAAY,EACZ,OAAe,EACf,WAAmB,EACnB,SAA6B,EAC7B,WAA8C,EACzB,EAAE;;IACvB,MAAM,YAAY,GAAG,IAAA,6BAAqB,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAE1D,MAAM,qBAAqB,GAAG,MAAA,YAAY,CAAC,YAAY,0CAAG,WAAW,CAAC,CAAC;IACvE,MAAM,SAAS,GAAG,MAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,SAAS,mCAAI,qBAAqB,aAArB,qBAAqB,uBAArB,qBAAqB,CAAE,SAAS,CAAC;IAC7E,MAAM,MAAM,GAAG,MAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,MAAM,mCAAI,qBAAqB,aAArB,qBAAqB,uBAArB,qBAAqB,CAAE,MAAM,CAAC;IAEpE,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,qCAAqC,WAAW,sBAAsB,OAAO,2FAA2F,CACzK,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO;QACP,MAAM,EAAE,cAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC;QAExC,MAAM,EAAE,YAAY,CAAC,MAAM;QAC3B,MAAM,EAAE,YAAY,CAAC,MAAM;QAE3B,WAAW;QACX,SAAS;QACT,MAAM;QAEN,SAAS;KACV,CAAC;AACJ,CAAC,CAAC;AAhCW,QAAA,sBAAsB,0BAgCjC","sourcesContent":["import fs from 'fs';\nimport path from 'path';\n\n// apps/<app>/deploy.config.json — the machine-readable half of an app's deploy\n// identity. Kept as JSON (not TS) so tooling can read it before any TS\n// executes (discovery, prompts, credential checks).\nexport interface QpqAppDeployEnvironment {\n // Deploy platform driver for this environment (default 'aws') — qpq go\n // dispatches on it, so a future environment can move platforms with a\n // config change instead of a different command.\n platform?: string;\n\n // Platform-specific identity — aws needs both; other platforms (e.g. docker)\n // may need neither.\n accountId?: string;\n region?: string;\n}\n\nexport interface QpqAppDeployConfig {\n prefix: string;\n domain: string;\n\n // environment name -> where it deploys. Owning this here (not env vars) is\n // what lets `qpq go --env production` need no AWS_DEFAULT_* variables.\n environments?: Record<string, QpqAppDeployEnvironment>;\n}\n\n// Deploy-time context handed to the app's account.qpq.ts / bootstrap.qpq.ts\n// config fragments.\nexport interface QpqAppDeployContext {\n appName: string;\n appDir: string;\n\n prefix: string;\n domain: string;\n\n environment: string;\n accountId: string;\n region: string;\n\n actorName?: string;\n}\n\nexport const getQpqAppDeployConfig = (root: string, appName: string): QpqAppDeployConfig => {\n const configPath = path.join(root, 'apps', appName, 'deploy.config.json');\n if (!fs.existsSync(configPath)) {\n throw new Error(`Missing ${configPath} — create it with { \"prefix\": \"...\", \"domain\": \"...\", \"environments\": { ... } }`);\n }\n return JSON.parse(fs.readFileSync(configPath, 'utf8'));\n};\n\nexport const getQpqAppDeployContext = (\n root: string,\n appName: string,\n environment: string,\n actorName: string | undefined,\n envOverride?: Partial<QpqAppDeployEnvironment>,\n): QpqAppDeployContext => {\n const deployConfig = getQpqAppDeployConfig(root, appName);\n\n const configuredEnvironment = deployConfig.environments?.[environment];\n const accountId = envOverride?.accountId ?? configuredEnvironment?.accountId;\n const region = envOverride?.region ?? configuredEnvironment?.region;\n\n if (!accountId || !region) {\n throw new Error(\n `No deploy target for environment '${environment}' — add it to apps/${appName}/deploy.config.json under \"environments\", or set AWS_DEFAULT_ACCOUNT / AWS_DEFAULT_REGION`,\n );\n }\n\n return {\n appName,\n appDir: path.join(root, 'apps', appName),\n\n prefix: deployConfig.prefix,\n domain: deployConfig.domain,\n\n environment,\n accountId,\n region,\n\n actorName,\n };\n};\n"]}
|
|
@@ -45,12 +45,15 @@ class QpqAccountCloudTrailConstruct extends QpqConstructBlock_1.QpqConstructBloc
|
|
|
45
45
|
const { name, retentionDays = 365, enableLogFileValidation = true, multiRegion = true, includeGlobalServiceEvents = true, cloudWatchLogs, } = props.cloudTrailConfig;
|
|
46
46
|
const accountId = quidproquo_config_aws_1.qpqConfigAwsUtils.getApplicationModuleDeployAccountId(props.qpqConfig);
|
|
47
47
|
const region = quidproquo_config_aws_1.qpqConfigAwsUtils.getApplicationModuleDeployRegion(props.qpqConfig);
|
|
48
|
+
const dataStoreRemovalPolicy = quidproquo_config_aws_1.qpqConfigAwsUtils.getAwsDataStoreRemovalPolicy(props.qpqConfig);
|
|
48
49
|
const bucket = new aws_cdk_lib_1.aws_s3.Bucket(this, 'logs', {
|
|
49
50
|
bucketName: `qpq-cloudtrail-${accountId}-${region}-${name}`,
|
|
50
51
|
blockPublicAccess: aws_cdk_lib_1.aws_s3.BlockPublicAccess.BLOCK_ALL,
|
|
51
52
|
encryption: aws_cdk_lib_1.aws_s3.BucketEncryption.S3_MANAGED,
|
|
52
53
|
enforceSSL: true,
|
|
53
|
-
|
|
54
|
+
// Retain audit logs by default; dev configs opt into full teardown via defineAwsDataStoreRemovalPolicy(destroy).
|
|
55
|
+
removalPolicy: dataStoreRemovalPolicy === quidproquo_config_aws_1.AwsDataStoreRemovalPolicy.destroy ? cdk.RemovalPolicy.DESTROY : cdk.RemovalPolicy.RETAIN,
|
|
56
|
+
autoDeleteObjects: dataStoreRemovalPolicy === quidproquo_config_aws_1.AwsDataStoreRemovalPolicy.destroy,
|
|
54
57
|
lifecycleRules: [{ expiration: cdk.Duration.days(retentionDays) }],
|
|
55
58
|
});
|
|
56
59
|
this.logGroup = cloudWatchLogs
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QpqAccountCloudTrailConstruct.js","sourceRoot":"","sources":["../../../../../src/constructs/feature/account/QpqAccountCloudTrailConstruct.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"QpqAccountCloudTrailConstruct.js","sourceRoot":"","sources":["../../../../../src/constructs/feature/account/QpqAccountCloudTrailConstruct.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iEAAwH;AAExH,iDAAmC;AACnC,6CAA+D;AAG/D,0CAAqD;AACrD,oEAAyF;AAMzF,MAAa,6BAA8B,SAAQ,qCAAiB;IAKlE,YAAY,KAAgB,EAAE,EAAU,EAAE,KAAyC;QACjF,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QAExB,MAAM,EACJ,IAAI,EACJ,aAAa,GAAG,GAAG,EACnB,uBAAuB,GAAG,IAAI,EAC9B,WAAW,GAAG,IAAI,EAClB,0BAA0B,GAAG,IAAI,EACjC,cAAc,GACf,GAAG,KAAK,CAAC,gBAAgB,CAAC;QAE3B,MAAM,SAAS,GAAG,yCAAiB,CAAC,mCAAmC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACzF,MAAM,MAAM,GAAG,yCAAiB,CAAC,gCAAgC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACnF,MAAM,sBAAsB,GAAG,yCAAiB,CAAC,4BAA4B,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAE/F,MAAM,MAAM,GAAG,IAAI,oBAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE;YAC7C,UAAU,EAAE,kBAAkB,SAAS,IAAI,MAAM,IAAI,IAAI,EAAE;YAC3D,iBAAiB,EAAE,oBAAM,CAAC,iBAAiB,CAAC,SAAS;YACrD,UAAU,EAAE,oBAAM,CAAC,gBAAgB,CAAC,UAAU;YAC9C,UAAU,EAAE,IAAI;YAChB,iHAAiH;YACjH,aAAa,EAAE,sBAAsB,KAAK,iDAAyB,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM;YAClI,iBAAiB,EAAE,sBAAsB,KAAK,iDAAyB,CAAC,OAAO;YAC/E,cAAc,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;SACnE,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,GAAG,cAAc;YAC5B,CAAC,CAAC,IAAI,sBAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE;gBACvC,YAAY,EAAE,mBAAmB,IAAI,EAAE;gBACvC,SAAS,EAAE,IAAA,2BAAmB,EAAC,cAAc,CAAC,aAAa,CAAC;gBAC5D,aAAa,EAAE,GAAG,CAAC,aAAa,CAAC,OAAO;aACzC,CAAC;YACJ,CAAC,CAAC,SAAS,CAAC;QAEd,IAAI,4BAAc,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE;YACtC,SAAS,EAAE,GAAG,IAAI,QAAQ;YAC1B,MAAM;YACN,oBAAoB,EAAE,uBAAuB;YAC7C,kBAAkB,EAAE,WAAW;YAC/B,0BAA0B;YAC1B,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ;YACrC,kBAAkB,EAAE,IAAI,CAAC,QAAQ;SAClC,CAAC,CAAC;IACL,CAAC;CACF;AAlDD,sEAkDC","sourcesContent":["import { AccountCloudTrailQPQConfigSetting, AwsDataStoreRemovalPolicy, qpqConfigAwsUtils } from 'quidproquo-config-aws';\n\nimport * as cdk from 'aws-cdk-lib';\nimport { aws_cloudtrail, aws_logs, aws_s3 } from 'aws-cdk-lib';\nimport { Construct } from 'constructs';\n\nimport { resolveLogRetention } from '../../../utils';\nimport { QpqConstructBlock, QpqConstructBlockProps } from '../../base/QpqConstructBlock';\n\nexport interface QpqAccountCloudTrailConstructProps extends QpqConstructBlockProps {\n cloudTrailConfig: AccountCloudTrailQPQConfigSetting;\n}\n\nexport class QpqAccountCloudTrailConstruct extends QpqConstructBlock {\n // Only set when the config enables cloudWatchLogs - consumed by the security services\n // construct for the cognito auth-failure metric filter\n public readonly logGroup?: aws_logs.LogGroup;\n\n constructor(scope: Construct, id: string, props: QpqAccountCloudTrailConstructProps) {\n super(scope, id, props);\n\n const {\n name,\n retentionDays = 365,\n enableLogFileValidation = true,\n multiRegion = true,\n includeGlobalServiceEvents = true,\n cloudWatchLogs,\n } = props.cloudTrailConfig;\n\n const accountId = qpqConfigAwsUtils.getApplicationModuleDeployAccountId(props.qpqConfig);\n const region = qpqConfigAwsUtils.getApplicationModuleDeployRegion(props.qpqConfig);\n const dataStoreRemovalPolicy = qpqConfigAwsUtils.getAwsDataStoreRemovalPolicy(props.qpqConfig);\n\n const bucket = new aws_s3.Bucket(this, 'logs', {\n bucketName: `qpq-cloudtrail-${accountId}-${region}-${name}`,\n blockPublicAccess: aws_s3.BlockPublicAccess.BLOCK_ALL,\n encryption: aws_s3.BucketEncryption.S3_MANAGED,\n enforceSSL: true,\n // Retain audit logs by default; dev configs opt into full teardown via defineAwsDataStoreRemovalPolicy(destroy).\n removalPolicy: dataStoreRemovalPolicy === AwsDataStoreRemovalPolicy.destroy ? cdk.RemovalPolicy.DESTROY : cdk.RemovalPolicy.RETAIN,\n autoDeleteObjects: dataStoreRemovalPolicy === AwsDataStoreRemovalPolicy.destroy,\n lifecycleRules: [{ expiration: cdk.Duration.days(retentionDays) }],\n });\n\n this.logGroup = cloudWatchLogs\n ? new aws_logs.LogGroup(this, 'log-group', {\n logGroupName: `/qpq/cloudtrail/${name}`,\n retention: resolveLogRetention(cloudWatchLogs.retentionDays),\n removalPolicy: cdk.RemovalPolicy.DESTROY,\n })\n : undefined;\n\n new aws_cloudtrail.Trail(this, 'trail', {\n trailName: `${name}-trail`,\n bucket,\n enableFileValidation: enableLogFileValidation,\n isMultiRegionTrail: multiRegion,\n includeGlobalServiceEvents,\n sendToCloudWatchLogs: !!this.logGroup,\n cloudWatchLogGroup: this.logGroup,\n });\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QpqCoreEventBusConstruct.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/core/eventBus/QpqCoreEventBusConstruct.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"QpqCoreEventBusConstruct.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/core/eventBus/QpqCoreEventBusConstruct.ts"],"names":[],"mappings":"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","sourcesContent":["import { awsNamingUtils } from 'quidproquo-actionprocessor-awslambda';\nimport { EventBusQuickSubscriptionType, getAwsAccountIds, qpqConfigAwsUtils } from 'quidproquo-config-aws';\nimport { EventBusQPQConfigSetting, QPQConfig, qpqCoreUtils } from 'quidproquo-core';\n\nimport { aws_iam, aws_sns, aws_sns_subscriptions } from 'aws-cdk-lib';\nimport { Construct } from 'constructs';\n\nimport * as qpqDeployAwsCdkUtils from '../../../../utils';\nimport { QpqConstructBlock, QpqConstructBlockProps } from '../../../base/QpqConstructBlock';\n\nexport interface QpqCoreEventBusConstructProps extends QpqConstructBlockProps {\n eventBusConfig: EventBusQPQConfigSetting;\n}\n\nexport abstract class QpqCoreEventBusConstructBase extends QpqConstructBlock {\n abstract topic: aws_sns.ITopic;\n\n public grantRead(grantee: aws_iam.IGrantable) {}\n\n public grantWrite(grantee: aws_iam.IGrantable): void {\n this.topic.grantPublish(grantee);\n }\n\n public grantAll(grantee: aws_iam.IGrantable): void {\n this.grantRead(grantee);\n this.grantWrite(grantee);\n }\n}\n\nexport class QpqCoreEventBusConstruct extends QpqCoreEventBusConstructBase {\n topic: aws_sns.ITopic;\n\n static fromOtherStack(scope: Construct, id: string, qpqConfig: QPQConfig, eventBusSubscription: string): QpqCoreEventBusConstructBase {\n const eventBusConfig = qpqCoreUtils.getEventBusConfigByName(eventBusSubscription, qpqConfig);\n\n const topicArn = awsNamingUtils.getEventBusSnsTopicArn(\n eventBusConfig?.owner?.resourceNameOverride || eventBusSubscription,\n qpqConfig,\n eventBusConfig?.owner?.module || qpqCoreUtils.getApplicationModuleName(qpqConfig),\n eventBusConfig?.owner?.environment || qpqCoreUtils.getApplicationModuleEnvironment(qpqConfig),\n eventBusConfig?.owner?.application || qpqCoreUtils.getApplicationName(qpqConfig),\n eventBusConfig?.owner?.feature ?? qpqCoreUtils.getApplicationModuleFeature(qpqConfig),\n eventBusConfig?.isFifo,\n );\n\n class Import extends QpqCoreEventBusConstructBase {\n topic = aws_sns.Topic.fromTopicArn(this, 'topic-arn', topicArn);\n }\n\n return new Import(scope, id, { qpqConfig });\n }\n\n constructor(scope: Construct, id: string, props: QpqCoreEventBusConstructProps) {\n super(scope, id, props);\n\n // contentBasedDeduplication stays off for FIFO topics: message bodies embed a per-send\n // storySession, so content hashes would never match - dedup ids are set explicitly at\n // publish time instead.\n const isFifo = props.eventBusConfig.isFifo;\n\n this.topic = new aws_sns.Topic(this, 'topic', {\n topicName: awsNamingUtils.withFifoSuffix(this.resourceName(props.eventBusConfig.name), isFifo),\n displayName: props.eventBusConfig.name,\n fifo: isFifo || undefined,\n });\n\n qpqDeployAwsCdkUtils.applyEnvironmentTags(this.topic, props.qpqConfig);\n\n const accountIds = getAwsAccountIds(props.qpqConfig);\n accountIds.forEach((accountId) => {\n this.topic.addToResourcePolicy(\n new aws_iam.PolicyStatement({\n sid: `x-account-sub-${accountId}`,\n effect: aws_iam.Effect.ALLOW,\n principals: [new aws_iam.AccountPrincipal(accountId)],\n actions: ['sns:Subscribe'],\n resources: [this.topic.topicArn],\n }),\n );\n });\n\n this.topic.addToResourcePolicy(\n new aws_iam.PolicyStatement({\n sid: 'AllowCloudWatchAlarms',\n effect: aws_iam.Effect.ALLOW,\n principals: [new aws_iam.ServicePrincipal('cloudwatch.amazonaws.com')],\n actions: ['sns:Publish'],\n resources: [this.topic.topicArn],\n }),\n );\n\n // Direct SNS fan-out (email / incident-tool webhooks), declared per-bus via\n // the AWS-specific `defineEventBusQuickSubscription`. Gives alarms routed here\n // via onAlarm.publishToEventBus somewhere to actually land.\n const quickSubscriptions = qpqConfigAwsUtils.getEventBusQuickSubscriptions(\n props.qpqConfig,\n props.eventBusConfig.name,\n props.eventBusConfig.owner,\n );\n\n // SNS FIFO topics only support SQS subscriptions - no email/http endpoints\n if (isFifo && quickSubscriptions.length > 0) {\n throw new Error(`Event bus [${props.eventBusConfig.name}]: quick subscriptions (email/url) are not supported on FIFO event buses`);\n }\n\n quickSubscriptions.forEach((subscription) => {\n if (subscription.type === EventBusQuickSubscriptionType.email) {\n this.topic.addSubscription(new aws_sns_subscriptions.EmailSubscription(subscription.email));\n } else {\n // UrlSubscription infers http vs https from the url prefix.\n this.topic.addSubscription(new aws_sns_subscriptions.UrlSubscription(subscription.url));\n }\n });\n\n // TODO: remove this, its deprecated\n const exportName = awsNamingUtils.getCFExportNameSnsTopicArnFromConfig(props.eventBusConfig.name, props.qpqConfig);\n qpqDeployAwsCdkUtils.exportStackValue(this, exportName, this.topic.topicArn);\n // ///////// end todo\n }\n}\n"]}
|
package/lib/commonjs/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.js
CHANGED
|
@@ -77,13 +77,6 @@ class WebQpqWebserverWebEntryConstruct extends QpqConstructBlock_1.QpqConstructB
|
|
|
77
77
|
else {
|
|
78
78
|
originBucket = aws_cdk_lib_1.aws_s3.Bucket.fromBucketName(this, 'src-bucket-lookup', this.resourceName(props.webEntryConfig.storageDrive.sourceStorageDrive));
|
|
79
79
|
}
|
|
80
|
-
if (props.webEntryConfig.storageDrive.autoUpload) {
|
|
81
|
-
const webEntryBuildPath = utils_1.qpqAwsCdkPathUtils.getWebEntryFullPath(props.qpqConfig, props.webEntryConfig);
|
|
82
|
-
new aws_cdk_lib_1.aws_s3_deployment.BucketDeployment(this, 'bucket-deploy', {
|
|
83
|
-
sources: [aws_cdk_lib_1.aws_s3_deployment.Source.asset(webEntryBuildPath)],
|
|
84
|
-
destinationBucket: originBucket,
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
80
|
const apexDomain = quidproquo_webserver_1.qpqWebServerUtils.resolveApexDomainNameFromDomainConfig(props.qpqConfig, props.webEntryConfig.domain.rootDomain, props.webEntryConfig.domain.onRootDomain);
|
|
88
81
|
const hostedZone = aws_cdk_lib_1.aws_route53.HostedZone.fromLookup(this, 'apex-zone', {
|
|
89
82
|
domainName: apexDomain,
|
|
@@ -150,6 +143,20 @@ class WebQpqWebserverWebEntryConstruct extends QpqConstructBlock_1.QpqConstructB
|
|
|
150
143
|
: undefined,
|
|
151
144
|
});
|
|
152
145
|
qpqDeployAwsCdkUtils.applyEnvironmentTags(distribution, props.qpqConfig);
|
|
146
|
+
// Deploy-time artifact publishing: the build dir is packaged as a CDK
|
|
147
|
+
// asset at synth time, unpacked into the origin bucket during deploy, then
|
|
148
|
+
// the distribution is invalidated so the new content serves immediately.
|
|
149
|
+
// Note: prunes objects missing from the source — only safe on buckets this
|
|
150
|
+
// web entry owns outright, not shared multi-service drives.
|
|
151
|
+
if (props.webEntryConfig.storageDrive.autoUpload) {
|
|
152
|
+
const webEntryBuildPath = utils_1.qpqAwsCdkPathUtils.getWebEntryFullPath(props.qpqConfig, props.webEntryConfig);
|
|
153
|
+
new aws_cdk_lib_1.aws_s3_deployment.BucketDeployment(this, 'bucket-deploy', {
|
|
154
|
+
sources: [aws_cdk_lib_1.aws_s3_deployment.Source.asset(webEntryBuildPath)],
|
|
155
|
+
destinationBucket: originBucket,
|
|
156
|
+
distribution,
|
|
157
|
+
distributionPaths: ['/*'],
|
|
158
|
+
});
|
|
159
|
+
}
|
|
153
160
|
// The distribution id is AWS-generated here in the web stack, unknowable when the inf
|
|
154
161
|
// stack synthesizes the service role - so this stack attaches the exact-ARN invalidation
|
|
155
162
|
// grant to the role instead (web always deploys after inf, so the role exists).
|
package/lib/commonjs/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebQpqWebserverWebEntryConstruct.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+FAAsE;AACtE,iEAA0D;AAC1D,+DAA4F;AAE5F,6CAUqB;AACrB,iDAAmC;AAEnC,gDAAwB;AAExB,wEAA0D;AAC1D,6CAAuD;AACvD,uEAA4F;AAC5F,oFAAiF;AACjF,oFAAiF;AACjF,6DAAuF;AAMvF,MAAa,gCAAiC,SAAQ,qCAAiB;IACrE,YAAY,KAAgB,EAAE,EAAU,EAAE,KAA4C;QACpF,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QAExB,kCAAkC;QAClC,IAAI,YAAY,GAA0B,IAAI,CAAC;QAE/C,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC;YAC1D,YAAY,GAAG,IAAI,oBAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE;gBAC/C,UAAU,EAAE,IAAI,CAAC,eAAe,CAAC,GAAG,KAAK,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC;gBACtE,iEAAiE;gBACjE,gBAAgB,EAAE,KAAK;gBACvB,iBAAiB,EAAE,oBAAM,CAAC,iBAAiB,CAAC,SAAS;gBAErD,8DAA8D;gBAC9D,sCAAsC;gBAEtC,+CAA+C;gBAC/C,aAAa,EAAE,GAAG,CAAC,aAAa,CAAC,OAAO;gBACxC,iBAAiB,EAAE,IAAI;gBAEvB,uFAAuF;gBACvF,SAAS,EAAE,IAAI;aAChB,CAAC,CAAC;YAEH,2EAA2E;YAC3E,2EAA2E;YAC3E,kEAAkE;YAClE,kEAAkE;YAClE,oBAAoB;QACtB,CAAC;aAAM,CAAC;YACN,YAAY,GAAG,oBAAM,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,mBAAmB,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC,CAAC;QAClJ,CAAC;QAED,IAAI,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;YACjD,MAAM,iBAAiB,GAAG,0BAAkB,CAAC,mBAAmB,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;YACxG,IAAI,+BAAiB,CAAC,gBAAgB,CAAC,IAAI,EAAE,eAAe,EAAE;gBAC5D,OAAO,EAAE,CAAC,+BAAiB,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;gBAC5D,iBAAiB,EAAE,YAAY;aAChC,CAAC,CAAC;QACL,CAAC;QAED,MAAM,UAAU,GAAG,wCAAiB,CAAC,qCAAqC,CACxE,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,UAAU,EACtC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,YAAY,CACzC,CAAC;QAEF,MAAM,UAAU,GAAG,yBAAW,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE;YACtE,UAAU,EAAE,UAAU;SACvB,CAAC,CAAC;QAEH,MAAM,WAAW,GAAa,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,aAAa,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9I,IAAI,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,YAAY,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzE,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAClC,CAAC;QAED,MAAM,WAAW,GAAG,IAAA,iDAAuB,EAAC,IAAI,EAAE,WAAW,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAElI,MAAM,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC,iBAAiB;YACxD,CAAC,CAAC,uDAA0B,CAAC,cAAc,CACvC,IAAI,EACJ,OAAO,EACP,KAAK,CAAC,SAAS,EACf,wCAAiB,CAAC,oBAAoB,CAAC,KAAK,CAAC,cAAc,CAAC,iBAAiB,EAAE,KAAK,CAAC,SAAS,CAAC,CAChG,CAAC,WAAW;YACf,CAAC,CAAC,4BAAc,CAAC,WAAW,CAAC,gBAAgB,CAAC;QAEhD,0DAA0D;QAC1D,MAAM,oBAAoB,GACxB,KAAK,CAAC,cAAc,CAAC,eAAe;YACpC,IAAI,4BAAc,CAAC,qBAAqB,CAAC,IAAI,EAAE,UAAU,EAAE;gBACzD,yBAAyB,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC;gBACvE,2BAA2B;gBAC3B,qBAAqB;gBACrB,QAAQ;gBACR,iCAAiC;gBACjC,wEAAwE;gBACxE,+EAA+E;gBAC/E,YAAY;gBACZ,wBAAwB;gBACxB,SAAS;gBACT,OAAO;gBACP,KAAK;gBACL,uBAAuB,EAAE,IAAA,8DAA4C,EAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC;gBAE5H,YAAY,EAAE;oBACZ,6BAA6B,EAAE,KAAK;oBACpC,yBAAyB,EAAE,CAAC,QAAQ,EAAE,gCAAgC,EAAE,+BAA+B,CAAC;oBACxG,yBAAyB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC;oBACrD,yBAAyB,EAAE,wCAAiB,CAAC,sCAAsC,CACjF,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,cAAc,CAAC,kBAAkB,CACxC;oBACD,0BAA0B,EAAE,CAAC,GAAG,CAAC;oBACjC,mBAAmB,EAAE,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC;oBAC9C,cAAc,EAAE,IAAI;iBACrB;aACF,CAAC,CAAC;QAEL,qEAAqE;QACrE,gFAAgF;QAChF,MAAM,kBAAkB,GAAG,oCAAsB,CAAC,cAAc,CAAC,uBAAuB,CAAC,YAAY,CAAC,CAAC;QACvG,MAAM,YAAY,GAAG,IAAI,4BAAc,CAAC,YAAY,CAAC,IAAI,EAAE,gBAAgB,EAAE;YAC3E,eAAe,EAAE;gBACf,MAAM,EAAE,kBAAkB;gBAC1B,mBAAmB,EAAE,4BAAc,CAAC,mBAAmB,CAAC,cAAc;gBAEtE,WAAW,EAAE,WAAW;gBACxB,oBAAoB,EAAE,4BAAc,CAAC,oBAAoB,CAAC,iBAAiB;gBAC3E,QAAQ,EAAE,KAAK,CAAC,cAAc,CAAC,aAAa;gBAC5C,qBAAqB,EAAE,oBAAoB;aAC5C;YAED,WAAW;YACX,WAAW;YACX,iBAAiB,EAAE,KAAK,CAAC,cAAc,CAAC,SAAS;YAEjD,mDAAmD;YACnD,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACxC,UAAU,EAAE,IAAI;gBAChB,kBAAkB,EAAE,GAAG;gBACvB,gBAAgB,EAAE,GAAG;gBACrB,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;aAC7B,CAAC,CAAC;YAEH,4FAA4F;YAC5F,QAAQ,EAAE,yCAAiB,CAAC,sBAAsB,CAAC,KAAK,CAAC,SAAS,CAAC;gBACjE,CAAC,CAAC,qBAAO,CAAC,eAAe,CAAC,uBAAuB,CAAC,IAAI,EAAE,yCAAiB,CAAC,+BAA+B,CAAC,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;gBACzI,CAAC,CAAC,SAAS;SACd,CAAC,CAAC;QAEH,oBAAoB,CAAC,oBAAoB,CAAC,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAEzE,sFAAsF;QACtF,yFAAyF;QACzF,gFAAgF;QAChF,IAAI,CAAC,cAAc,EAAE,CAAC,oBAAoB,CACxC,IAAI,qBAAO,CAAC,eAAe,CAAC;YAC1B,MAAM,EAAE,qBAAO,CAAC,MAAM,CAAC,KAAK;YAC5B,OAAO,EAAE,CAAC,+BAA+B,CAAC;YAC1C,SAAS,EAAE;gBACT,uBAAuB,yCAAiB,CAAC,mCAAmC,CAAC,KAAK,CAAC,SAAS,CAAC,iBAAiB,YAAY,CAAC,cAAc,EAAE;aAC5I;SACF,CAAC,CACH,CAAC;QAEF,oBAAoB,CAAC,gBAAgB,CACnC,IAAI,EACJ,qDAAc,CAAC,0CAA0C,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,EACrG,YAAY,CAAC,cAAc,CAC5B,CAAC;QAEF,IAAI,yBAAW,CAAC,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE;YACzC,IAAI,EAAE,UAAU;YAChB,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;YAC1B,MAAM,EAAE,yBAAW,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,iCAAmB,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;SACnG,CAAC,CAAC;QAEH,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE;YACvD,YAAY,CAAC,WAAW,CAAC,WAAW,EAAE,kBAAkB,EAAE;gBACxD,WAAW,EAAE,4BAAc,CAAC,WAAW,CAAC,gBAAgB;gBACxD,oBAAoB,EAAE,4BAAc,CAAC,oBAAoB,CAAC,iBAAiB;gBAC3E,QAAQ,EAAE,KAAK,CAAC,cAAc,CAAC,aAAa;gBAC5C,qBAAqB,EAAE,oBAAoB;aAC5C,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,uCAAuC;QACvC,MAAM,IAAI,GAAG,wCAAiB,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAEvI,sDAAsD;QACtD,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,iBAAiB,GAAG,0BAAkB,CAAC,uBAAuB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAEtF,MAAM,cAAc,GAAG,IAAI,4BAAc,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE;gBAClF,YAAY,EAAE,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC;gBACvE,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;gBAChC,OAAO,EAAE,wBAAU,CAAC,OAAO,CAAC,WAAW;gBAEvC,IAAI,EAAE,wBAAU,CAAC,IAAI,CAAC,SAAS,CAAC,cAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,sCAAsC,CAAC,CAAC;gBACrG,OAAO,EAAE,4CAA4C;aACtD,CAAC,CAAC;YAEH,MAAM,cAAc,GAAG,IAAI,4BAAc,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE;gBAClF,YAAY,EAAE,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC;gBACvE,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBACjC,OAAO,EAAE,wBAAU,CAAC,OAAO,CAAC,WAAW;gBAEvC,UAAU,EAAE,IAAI;gBAEhB,IAAI,EAAE,wBAAU,CAAC,IAAI,CAAC,SAAS,CAAC,cAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,sCAAsC,CAAC,CAAC;gBACrG,OAAO,EAAE,4CAA4C;gBAErD,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE;aAC5B,CAAC,CAAC;YAEH,KAAK,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;gBACrB,gFAAgF;gBAChF,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;oBACnB,SAAS;gBACX,CAAC;gBAED,yCAAyC;gBACzC,kGAAkG;gBAClG,MAAM,cAAc,GAAG,GAAG,CAAC,iBAAiB;oBAC1C,CAAC,CAAC,uDAA0B,CAAC,cAAc,CACvC,IAAI,EACJ,aAAa,GAAG,CAAC,SAAS,EAAE,EAC5B,KAAK,CAAC,SAAS,EACf,wCAAiB,CAAC,oBAAoB,CAAC,GAAG,CAAC,iBAAiB,EAAE,KAAK,CAAC,SAAS,CAAC,CAC/E,CAAC,WAAW;oBACf,CAAC,CAAC,4BAAc,CAAC,WAAW,CAAC,gBAAgB,CAAC;gBAEhD,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;gBAC1D,YAAY,CAAC,WAAW,CAAC,YAAY,EAAE,kBAAkB,EAAE;oBACzD,WAAW,EAAE,cAAc;oBAC3B,oBAAoB,EAAE,4BAAc,CAAC,oBAAoB,CAAC,iBAAiB;oBAC3E,QAAQ,EAAE,KAAK,CAAC,cAAc,CAAC,aAAa;oBAC5C,WAAW,EAAE;wBACX;4BACE,eAAe,EAAE,cAAc,CAAC,cAAc;4BAC9C,SAAS,EAAE,4BAAc,CAAC,mBAAmB,CAAC,cAAc;yBAC7D;wBACD;4BACE,eAAe,EAAE,cAAc,CAAC,cAAc;4BAC9C,SAAS,EAAE,4BAAc,CAAC,mBAAmB,CAAC,cAAc;yBAC7D;qBACF;oBACD,qBAAqB,EAAE,oBAAoB;iBAC5C,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA1OD,4EA0OC","sourcesContent":["import { awsNamingUtils } from 'quidproquo-actionprocessor-awslambda';\nimport { qpqConfigAwsUtils } from 'quidproquo-config-aws';\nimport { qpqWebServerUtils, WebEntryQPQWebServerConfigSetting } from 'quidproquo-webserver';\n\nimport {\n aws_cloudfront,\n aws_cloudfront_origins,\n aws_iam,\n aws_lambda,\n aws_route53,\n aws_route53_targets,\n aws_s3,\n aws_s3_deployment,\n aws_ssm,\n} from 'aws-cdk-lib';\nimport * as cdk from 'aws-cdk-lib';\nimport { Construct } from 'constructs';\nimport path from 'path';\n\nimport * as qpqDeployAwsCdkUtils from '../../../../utils';\nimport { qpqAwsCdkPathUtils } from '../../../../utils';\nimport { QpqConstructBlock, QpqConstructBlockProps } from '../../../base/QpqConstructBlock';\nimport { lookupDomainCertificate } from '../../../basic/DomainCertificateLookup';\nimport { QpqWebServerCacheConstruct } from '../cache/QpqWebServerCacheConstruct';\nimport { convertSecurityHeadersFromQpqSecurityHeaders } from './utils/securityHeaders';\n\nexport interface WebQpqWebserverWebEntryConstructProps extends QpqConstructBlockProps {\n webEntryConfig: WebEntryQPQWebServerConfigSetting;\n}\n\nexport class WebQpqWebserverWebEntryConstruct extends QpqConstructBlock {\n constructor(scope: Construct, id: string, props: WebQpqWebserverWebEntryConstructProps) {\n super(scope, id, props);\n\n // create / reference an s3 bucket\n let originBucket: aws_s3.IBucket | null = null;\n\n if (!props.webEntryConfig.storageDrive.sourceStorageDrive) {\n originBucket = new aws_s3.Bucket(this, 'bucket', {\n bucketName: this.qpqResourceName(`${props.webEntryConfig.name}`, 'we'),\n // Disable public access to this bucket, Clou+dFront will do that\n publicReadAccess: false,\n blockPublicAccess: aws_s3.BlockPublicAccess.BLOCK_ALL,\n\n // Do not do this ~ It screws with aws_cloudfront.Distribution\n // websiteIndexDocument: 'index.html',\n\n // Allow bucket to auto delete upon cdk:Destroy\n removalPolicy: cdk.RemovalPolicy.DESTROY,\n autoDeleteObjects: true,\n\n // Keep prior object versions so a bad deploy / accidental overwrite can be rolled back\n versioned: true,\n });\n\n // No manual CloudFront bucket policy here: because this bucket is owned by\n // this stack, `S3BucketOrigin.withOriginAccessControl` (below) auto-adds a\n // policy scoped to this exact distribution's ARN (StringEquals on\n // AWS:SourceArn). Adding one manually would only re-broaden it to\n // `distribution/*`.\n } else {\n originBucket = aws_s3.Bucket.fromBucketName(this, 'src-bucket-lookup', this.resourceName(props.webEntryConfig.storageDrive.sourceStorageDrive));\n }\n\n if (props.webEntryConfig.storageDrive.autoUpload) {\n const webEntryBuildPath = qpqAwsCdkPathUtils.getWebEntryFullPath(props.qpqConfig, props.webEntryConfig);\n new aws_s3_deployment.BucketDeployment(this, 'bucket-deploy', {\n sources: [aws_s3_deployment.Source.asset(webEntryBuildPath)],\n destinationBucket: originBucket,\n });\n }\n\n const apexDomain = qpqWebServerUtils.resolveApexDomainNameFromDomainConfig(\n props.qpqConfig,\n props.webEntryConfig.domain.rootDomain,\n props.webEntryConfig.domain.onRootDomain,\n );\n\n const hostedZone = aws_route53.HostedZone.fromLookup(this, 'apex-zone', {\n domainName: apexDomain,\n });\n\n const domainNames: string[] = props.webEntryConfig.domain.subDomainName ? [`${props.webEntryConfig.domain.subDomainName}.${apexDomain}`] : [];\n if (props.webEntryConfig.domain.onRootDomain && domainNames.length === 0) {\n domainNames.unshift(apexDomain);\n }\n\n const certificate = lookupDomainCertificate(this, 'us-east-1', props.webEntryConfig.domain.rootDomain, props.webEntryConfig.name);\n\n const cachePolicy = props.webEntryConfig.cacheSettingsName\n ? QpqWebServerCacheConstruct.fromOtherStack(\n this,\n 'cache',\n props.qpqConfig,\n qpqWebServerUtils.getCacheConfigByName(props.webEntryConfig.cacheSettingsName, props.qpqConfig),\n ).cachePolicy\n : aws_cloudfront.CachePolicy.CACHING_DISABLED;\n\n // NOTE: This is used in the ignore cache down the bottom.\n const responseHeaderPolicy =\n props.webEntryConfig.securityHeaders &&\n new aws_cloudfront.ResponseHeadersPolicy(this, `dist-rhp`, {\n responseHeadersPolicyName: this.resourceName(props.webEntryConfig.name),\n // customHeadersBehavior: {\n // customHeaders: [\n // {\n // header: 'Cache-Control',\n // value: `max-age=${props.webEntryConfig.cache.maxTTLInSeconds}${\n // props.webEntryConfig.cache.mustRevalidate ? ', must-revalidate' : ''\n // }`,\n // override: true,\n // },\n // ],\n // },\n securityHeadersBehavior: convertSecurityHeadersFromQpqSecurityHeaders(props.qpqConfig, props.webEntryConfig.securityHeaders),\n\n corsBehavior: {\n accessControlAllowCredentials: false,\n accessControlAllowHeaders: ['Origin', 'Access-Control-Request-Headers', 'Access-Control-Request-Method'],\n accessControlAllowMethods: ['GET', 'HEAD', 'OPTIONS'],\n accessControlAllowOrigins: qpqWebServerUtils.resolveServiceScopedCorsAllowedOrigins(\n props.qpqConfig,\n props.webEntryConfig.corsAllowedOrigins,\n ),\n accessControlExposeHeaders: ['*'],\n accessControlMaxAge: cdk.Duration.seconds(600),\n originOverride: true,\n },\n });\n\n // Create a CloudFront distribution using the S3 bucket as the origin\n // const distributionOrigin = new aws_cloudfront_origins.S3Origin(originBucket);\n const distributionOrigin = aws_cloudfront_origins.S3BucketOrigin.withOriginAccessControl(originBucket);\n const distribution = new aws_cloudfront.Distribution(this, 'MyDistribution', {\n defaultBehavior: {\n origin: distributionOrigin,\n originRequestPolicy: aws_cloudfront.OriginRequestPolicy.CORS_S3_ORIGIN,\n\n cachePolicy: cachePolicy,\n viewerProtocolPolicy: aws_cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,\n compress: props.webEntryConfig.compressFiles,\n responseHeadersPolicy: responseHeaderPolicy,\n },\n\n domainNames,\n certificate,\n defaultRootObject: props.webEntryConfig.indexRoot,\n\n // redirect errors to root page and let spa sort it\n errorResponses: [404, 403].map((code) => ({\n httpStatus: code,\n responseHttpStatus: 200,\n responsePagePath: '/',\n ttl: cdk.Duration.seconds(0),\n })),\n\n // Shared CLOUDFRONT web acl from the bootstrap phase (us-east-1, arn via SSM like the cert)\n webAclId: qpqConfigAwsUtils.isWafProtectionEnabled(props.qpqConfig)\n ? aws_ssm.StringParameter.valueForStringParameter(this, qpqConfigAwsUtils.getWafWebAclArnSsmParameterName('cloudfront', props.qpqConfig))\n : undefined,\n });\n\n qpqDeployAwsCdkUtils.applyEnvironmentTags(distribution, props.qpqConfig);\n\n // The distribution id is AWS-generated here in the web stack, unknowable when the inf\n // stack synthesizes the service role - so this stack attaches the exact-ARN invalidation\n // grant to the role instead (web always deploys after inf, so the role exists).\n this.getServiceRole().addToPrincipalPolicy(\n new aws_iam.PolicyStatement({\n effect: aws_iam.Effect.ALLOW,\n actions: ['cloudfront:CreateInvalidation'],\n resources: [\n `arn:aws:cloudfront::${qpqConfigAwsUtils.getApplicationModuleDeployAccountId(props.qpqConfig)}:distribution/${distribution.distributionId}`,\n ],\n }),\n );\n\n qpqDeployAwsCdkUtils.exportStackValue(\n this,\n awsNamingUtils.getCFExportNameDistributionIdArnFromConfig(props.webEntryConfig.name, props.qpqConfig),\n distribution.distributionId,\n );\n\n new aws_route53.ARecord(this, `web-alias`, {\n zone: hostedZone,\n recordName: domainNames[0],\n target: aws_route53.RecordTarget.fromAlias(new aws_route53_targets.CloudFrontTarget(distribution)),\n });\n\n props.webEntryConfig.ignoreCache.forEach((pathPattern) => {\n distribution.addBehavior(pathPattern, distributionOrigin, {\n cachePolicy: aws_cloudfront.CachePolicy.CACHING_DISABLED,\n viewerProtocolPolicy: aws_cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,\n compress: props.webEntryConfig.compressFiles,\n responseHeadersPolicy: responseHeaderPolicy,\n });\n });\n\n // All seos that are for this web entry\n const seos = qpqWebServerUtils.getAllSeo(props.qpqConfig).filter((seo) => !seo.webEntry || seo.webEntry === props.webEntryConfig.name);\n\n // if we have some ~ Build the edge lambdas and deploy\n if (seos.length > 0) {\n const seoEntryBuildPath = qpqAwsCdkPathUtils.getApiBuildPathFullPath(props.qpqConfig);\n\n const edgeFunctionVR = new aws_cloudfront.experimental.EdgeFunction(this, `SEO-VR`, {\n functionName: this.qpqResourceName(props.webEntryConfig.name, 'SEO-VR'),\n timeout: cdk.Duration.seconds(5),\n runtime: aws_lambda.Runtime.NODEJS_22_X,\n\n code: aws_lambda.Code.fromAsset(path.join(seoEntryBuildPath, 'cloudFrontRequestEvent_viewerRequest')),\n handler: 'index.cloudFrontRequestEvent_viewerRequest',\n });\n\n const edgeFunctionOR = new aws_cloudfront.experimental.EdgeFunction(this, `SEO-OR`, {\n functionName: this.qpqResourceName(props.webEntryConfig.name, 'SEO-OR'),\n timeout: cdk.Duration.seconds(30),\n runtime: aws_lambda.Runtime.NODEJS_22_X,\n\n memorySize: 1024,\n\n code: aws_lambda.Code.fromAsset(path.join(seoEntryBuildPath, 'cloudFrontRequestEvent_originRequest')),\n handler: 'index.cloudFrontRequestEvent_originRequest',\n\n role: this.getServiceRole(),\n });\n\n for (let seo of seos) {\n // Deprecated edge lambdas are not added as a behavior, but they are still built\n if (seo.deprecated) {\n continue;\n }\n\n // TODO: Find a better solution for this.\n // Removed this because aws limits for the number of AWS CloudFront Cache Policies in your account\n const seoCachePolicy = seo.cacheSettingsName\n ? QpqWebServerCacheConstruct.fromOtherStack(\n this,\n `seo-cache-${seo.uniqueKey}`,\n props.qpqConfig,\n qpqWebServerUtils.getCacheConfigByName(seo.cacheSettingsName, props.qpqConfig),\n ).cachePolicy\n : aws_cloudfront.CachePolicy.CACHING_DISABLED;\n\n const wildcardPath = seo.path.replaceAll(/{(.+?)}/g, '*');\n distribution.addBehavior(wildcardPath, distributionOrigin, {\n cachePolicy: seoCachePolicy,\n viewerProtocolPolicy: aws_cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,\n compress: props.webEntryConfig.compressFiles,\n edgeLambdas: [\n {\n functionVersion: edgeFunctionVR.currentVersion,\n eventType: aws_cloudfront.LambdaEdgeEventType.VIEWER_REQUEST,\n },\n {\n functionVersion: edgeFunctionOR.currentVersion,\n eventType: aws_cloudfront.LambdaEdgeEventType.ORIGIN_REQUEST,\n },\n ],\n responseHeadersPolicy: responseHeaderPolicy,\n });\n }\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"WebQpqWebserverWebEntryConstruct.js","sourceRoot":"","sources":["../../../../../../src/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.ts"],"names":[],"mappings":"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","sourcesContent":["import { awsNamingUtils } from 'quidproquo-actionprocessor-awslambda';\nimport { qpqConfigAwsUtils } from 'quidproquo-config-aws';\nimport { qpqWebServerUtils, WebEntryQPQWebServerConfigSetting } from 'quidproquo-webserver';\n\nimport {\n aws_cloudfront,\n aws_cloudfront_origins,\n aws_iam,\n aws_lambda,\n aws_route53,\n aws_route53_targets,\n aws_s3,\n aws_s3_deployment,\n aws_ssm,\n} from 'aws-cdk-lib';\nimport * as cdk from 'aws-cdk-lib';\nimport { Construct } from 'constructs';\nimport path from 'path';\n\nimport * as qpqDeployAwsCdkUtils from '../../../../utils';\nimport { qpqAwsCdkPathUtils } from '../../../../utils';\nimport { QpqConstructBlock, QpqConstructBlockProps } from '../../../base/QpqConstructBlock';\nimport { lookupDomainCertificate } from '../../../basic/DomainCertificateLookup';\nimport { QpqWebServerCacheConstruct } from '../cache/QpqWebServerCacheConstruct';\nimport { convertSecurityHeadersFromQpqSecurityHeaders } from './utils/securityHeaders';\n\nexport interface WebQpqWebserverWebEntryConstructProps extends QpqConstructBlockProps {\n webEntryConfig: WebEntryQPQWebServerConfigSetting;\n}\n\nexport class WebQpqWebserverWebEntryConstruct extends QpqConstructBlock {\n constructor(scope: Construct, id: string, props: WebQpqWebserverWebEntryConstructProps) {\n super(scope, id, props);\n\n // create / reference an s3 bucket\n let originBucket: aws_s3.IBucket | null = null;\n\n if (!props.webEntryConfig.storageDrive.sourceStorageDrive) {\n originBucket = new aws_s3.Bucket(this, 'bucket', {\n bucketName: this.qpqResourceName(`${props.webEntryConfig.name}`, 'we'),\n // Disable public access to this bucket, Clou+dFront will do that\n publicReadAccess: false,\n blockPublicAccess: aws_s3.BlockPublicAccess.BLOCK_ALL,\n\n // Do not do this ~ It screws with aws_cloudfront.Distribution\n // websiteIndexDocument: 'index.html',\n\n // Allow bucket to auto delete upon cdk:Destroy\n removalPolicy: cdk.RemovalPolicy.DESTROY,\n autoDeleteObjects: true,\n\n // Keep prior object versions so a bad deploy / accidental overwrite can be rolled back\n versioned: true,\n });\n\n // No manual CloudFront bucket policy here: because this bucket is owned by\n // this stack, `S3BucketOrigin.withOriginAccessControl` (below) auto-adds a\n // policy scoped to this exact distribution's ARN (StringEquals on\n // AWS:SourceArn). Adding one manually would only re-broaden it to\n // `distribution/*`.\n } else {\n originBucket = aws_s3.Bucket.fromBucketName(this, 'src-bucket-lookup', this.resourceName(props.webEntryConfig.storageDrive.sourceStorageDrive));\n }\n\n const apexDomain = qpqWebServerUtils.resolveApexDomainNameFromDomainConfig(\n props.qpqConfig,\n props.webEntryConfig.domain.rootDomain,\n props.webEntryConfig.domain.onRootDomain,\n );\n\n const hostedZone = aws_route53.HostedZone.fromLookup(this, 'apex-zone', {\n domainName: apexDomain,\n });\n\n const domainNames: string[] = props.webEntryConfig.domain.subDomainName ? [`${props.webEntryConfig.domain.subDomainName}.${apexDomain}`] : [];\n if (props.webEntryConfig.domain.onRootDomain && domainNames.length === 0) {\n domainNames.unshift(apexDomain);\n }\n\n const certificate = lookupDomainCertificate(this, 'us-east-1', props.webEntryConfig.domain.rootDomain, props.webEntryConfig.name);\n\n const cachePolicy = props.webEntryConfig.cacheSettingsName\n ? QpqWebServerCacheConstruct.fromOtherStack(\n this,\n 'cache',\n props.qpqConfig,\n qpqWebServerUtils.getCacheConfigByName(props.webEntryConfig.cacheSettingsName, props.qpqConfig),\n ).cachePolicy\n : aws_cloudfront.CachePolicy.CACHING_DISABLED;\n\n // NOTE: This is used in the ignore cache down the bottom.\n const responseHeaderPolicy =\n props.webEntryConfig.securityHeaders &&\n new aws_cloudfront.ResponseHeadersPolicy(this, `dist-rhp`, {\n responseHeadersPolicyName: this.resourceName(props.webEntryConfig.name),\n // customHeadersBehavior: {\n // customHeaders: [\n // {\n // header: 'Cache-Control',\n // value: `max-age=${props.webEntryConfig.cache.maxTTLInSeconds}${\n // props.webEntryConfig.cache.mustRevalidate ? ', must-revalidate' : ''\n // }`,\n // override: true,\n // },\n // ],\n // },\n securityHeadersBehavior: convertSecurityHeadersFromQpqSecurityHeaders(props.qpqConfig, props.webEntryConfig.securityHeaders),\n\n corsBehavior: {\n accessControlAllowCredentials: false,\n accessControlAllowHeaders: ['Origin', 'Access-Control-Request-Headers', 'Access-Control-Request-Method'],\n accessControlAllowMethods: ['GET', 'HEAD', 'OPTIONS'],\n accessControlAllowOrigins: qpqWebServerUtils.resolveServiceScopedCorsAllowedOrigins(\n props.qpqConfig,\n props.webEntryConfig.corsAllowedOrigins,\n ),\n accessControlExposeHeaders: ['*'],\n accessControlMaxAge: cdk.Duration.seconds(600),\n originOverride: true,\n },\n });\n\n // Create a CloudFront distribution using the S3 bucket as the origin\n // const distributionOrigin = new aws_cloudfront_origins.S3Origin(originBucket);\n const distributionOrigin = aws_cloudfront_origins.S3BucketOrigin.withOriginAccessControl(originBucket);\n const distribution = new aws_cloudfront.Distribution(this, 'MyDistribution', {\n defaultBehavior: {\n origin: distributionOrigin,\n originRequestPolicy: aws_cloudfront.OriginRequestPolicy.CORS_S3_ORIGIN,\n\n cachePolicy: cachePolicy,\n viewerProtocolPolicy: aws_cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,\n compress: props.webEntryConfig.compressFiles,\n responseHeadersPolicy: responseHeaderPolicy,\n },\n\n domainNames,\n certificate,\n defaultRootObject: props.webEntryConfig.indexRoot,\n\n // redirect errors to root page and let spa sort it\n errorResponses: [404, 403].map((code) => ({\n httpStatus: code,\n responseHttpStatus: 200,\n responsePagePath: '/',\n ttl: cdk.Duration.seconds(0),\n })),\n\n // Shared CLOUDFRONT web acl from the bootstrap phase (us-east-1, arn via SSM like the cert)\n webAclId: qpqConfigAwsUtils.isWafProtectionEnabled(props.qpqConfig)\n ? aws_ssm.StringParameter.valueForStringParameter(this, qpqConfigAwsUtils.getWafWebAclArnSsmParameterName('cloudfront', props.qpqConfig))\n : undefined,\n });\n\n qpqDeployAwsCdkUtils.applyEnvironmentTags(distribution, props.qpqConfig);\n\n // Deploy-time artifact publishing: the build dir is packaged as a CDK\n // asset at synth time, unpacked into the origin bucket during deploy, then\n // the distribution is invalidated so the new content serves immediately.\n // Note: prunes objects missing from the source — only safe on buckets this\n // web entry owns outright, not shared multi-service drives.\n if (props.webEntryConfig.storageDrive.autoUpload) {\n const webEntryBuildPath = qpqAwsCdkPathUtils.getWebEntryFullPath(props.qpqConfig, props.webEntryConfig);\n new aws_s3_deployment.BucketDeployment(this, 'bucket-deploy', {\n sources: [aws_s3_deployment.Source.asset(webEntryBuildPath)],\n destinationBucket: originBucket,\n distribution,\n distributionPaths: ['/*'],\n });\n }\n\n // The distribution id is AWS-generated here in the web stack, unknowable when the inf\n // stack synthesizes the service role - so this stack attaches the exact-ARN invalidation\n // grant to the role instead (web always deploys after inf, so the role exists).\n this.getServiceRole().addToPrincipalPolicy(\n new aws_iam.PolicyStatement({\n effect: aws_iam.Effect.ALLOW,\n actions: ['cloudfront:CreateInvalidation'],\n resources: [\n `arn:aws:cloudfront::${qpqConfigAwsUtils.getApplicationModuleDeployAccountId(props.qpqConfig)}:distribution/${distribution.distributionId}`,\n ],\n }),\n );\n\n qpqDeployAwsCdkUtils.exportStackValue(\n this,\n awsNamingUtils.getCFExportNameDistributionIdArnFromConfig(props.webEntryConfig.name, props.qpqConfig),\n distribution.distributionId,\n );\n\n new aws_route53.ARecord(this, `web-alias`, {\n zone: hostedZone,\n recordName: domainNames[0],\n target: aws_route53.RecordTarget.fromAlias(new aws_route53_targets.CloudFrontTarget(distribution)),\n });\n\n props.webEntryConfig.ignoreCache.forEach((pathPattern) => {\n distribution.addBehavior(pathPattern, distributionOrigin, {\n cachePolicy: aws_cloudfront.CachePolicy.CACHING_DISABLED,\n viewerProtocolPolicy: aws_cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,\n compress: props.webEntryConfig.compressFiles,\n responseHeadersPolicy: responseHeaderPolicy,\n });\n });\n\n // All seos that are for this web entry\n const seos = qpqWebServerUtils.getAllSeo(props.qpqConfig).filter((seo) => !seo.webEntry || seo.webEntry === props.webEntryConfig.name);\n\n // if we have some ~ Build the edge lambdas and deploy\n if (seos.length > 0) {\n const seoEntryBuildPath = qpqAwsCdkPathUtils.getApiBuildPathFullPath(props.qpqConfig);\n\n const edgeFunctionVR = new aws_cloudfront.experimental.EdgeFunction(this, `SEO-VR`, {\n functionName: this.qpqResourceName(props.webEntryConfig.name, 'SEO-VR'),\n timeout: cdk.Duration.seconds(5),\n runtime: aws_lambda.Runtime.NODEJS_22_X,\n\n code: aws_lambda.Code.fromAsset(path.join(seoEntryBuildPath, 'cloudFrontRequestEvent_viewerRequest')),\n handler: 'index.cloudFrontRequestEvent_viewerRequest',\n });\n\n const edgeFunctionOR = new aws_cloudfront.experimental.EdgeFunction(this, `SEO-OR`, {\n functionName: this.qpqResourceName(props.webEntryConfig.name, 'SEO-OR'),\n timeout: cdk.Duration.seconds(30),\n runtime: aws_lambda.Runtime.NODEJS_22_X,\n\n memorySize: 1024,\n\n code: aws_lambda.Code.fromAsset(path.join(seoEntryBuildPath, 'cloudFrontRequestEvent_originRequest')),\n handler: 'index.cloudFrontRequestEvent_originRequest',\n\n role: this.getServiceRole(),\n });\n\n for (let seo of seos) {\n // Deprecated edge lambdas are not added as a behavior, but they are still built\n if (seo.deprecated) {\n continue;\n }\n\n // TODO: Find a better solution for this.\n // Removed this because aws limits for the number of AWS CloudFront Cache Policies in your account\n const seoCachePolicy = seo.cacheSettingsName\n ? QpqWebServerCacheConstruct.fromOtherStack(\n this,\n `seo-cache-${seo.uniqueKey}`,\n props.qpqConfig,\n qpqWebServerUtils.getCacheConfigByName(seo.cacheSettingsName, props.qpqConfig),\n ).cachePolicy\n : aws_cloudfront.CachePolicy.CACHING_DISABLED;\n\n const wildcardPath = seo.path.replaceAll(/{(.+?)}/g, '*');\n distribution.addBehavior(wildcardPath, distributionOrigin, {\n cachePolicy: seoCachePolicy,\n viewerProtocolPolicy: aws_cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,\n compress: props.webEntryConfig.compressFiles,\n edgeLambdas: [\n {\n functionVersion: edgeFunctionVR.currentVersion,\n eventType: aws_cloudfront.LambdaEdgeEventType.VIEWER_REQUEST,\n },\n {\n functionVersion: edgeFunctionOR.currentVersion,\n eventType: aws_cloudfront.LambdaEdgeEventType.ORIGIN_REQUEST,\n },\n ],\n responseHeadersPolicy: responseHeaderPolicy,\n });\n }\n }\n }\n}\n"]}
|
package/lib/commonjs/index.d.ts
CHANGED
package/lib/commonjs/index.js
CHANGED
|
@@ -37,6 +37,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
37
37
|
})();
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.qpqDeployAwsCdkUtils = void 0;
|
|
40
|
+
__exportStar(require("./appWorkspace"), exports);
|
|
40
41
|
__exportStar(require("./constructs"), exports);
|
|
41
42
|
__exportStar(require("./QPQApp"), exports);
|
|
42
43
|
__exportStar(require("./stacks"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,2CAAyB;AACzB,2CAAyB;AACzB,gEAAgD","sourcesContent":["export * from './constructs';\nexport * from './QPQApp';\nexport * from './stacks';\nexport * as qpqDeployAwsCdkUtils from './utils';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAA+B;AAC/B,+CAA6B;AAC7B,2CAAyB;AACzB,2CAAyB;AACzB,gEAAgD","sourcesContent":["export * from './appWorkspace';\nexport * from './constructs';\nexport * from './QPQApp';\nexport * from './stacks';\nexport * as qpqDeployAwsCdkUtils from './utils';\n"]}
|
|
@@ -64,6 +64,9 @@ class DomainCertificateStack extends aws_cdk_lib_1.Stack {
|
|
|
64
64
|
physicalResourceId: custom_resources_1.PhysicalResourceId.of(paramName),
|
|
65
65
|
};
|
|
66
66
|
new custom_resources_1.AwsCustomResource(this, 'arn-ssm-xregion', {
|
|
67
|
+
// Plain SSM put/deleteParameter — Lambda's built-in SDK is plenty; don't
|
|
68
|
+
// npm-install the latest SDK at runtime (slow cold starts, needs internet).
|
|
69
|
+
installLatestAwsSdk: false,
|
|
67
70
|
onCreate: sdkCall,
|
|
68
71
|
onUpdate: sdkCall,
|
|
69
72
|
onDelete: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DomainCertificateStack.js","sourceRoot":"","sources":["../../../src/stacks/DomainCertificateStack.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"DomainCertificateStack.js","sourceRoot":"","sources":["../../../src/stacks/DomainCertificateStack.ts"],"names":[],"mappings":"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","sourcesContent":["import { DomainCertificateQPQConfigSetting, qpqConfigAwsUtils } from 'quidproquo-config-aws';\nimport { QPQConfig } from 'quidproquo-core';\nimport { qpqWebServerUtils } from 'quidproquo-webserver';\n\nimport { aws_certificatemanager, aws_iam, aws_route53, aws_ssm, Stack } from 'aws-cdk-lib';\nimport { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from 'aws-cdk-lib/custom-resources';\nimport { Construct } from 'constructs';\n\nexport interface DomainCertificateStackProps {\n qpqConfig: QPQConfig;\n certificateConfig: DomainCertificateQPQConfigSetting;\n\n stackName?: string;\n}\n\nconst buildDomainNames = (resolvedApex: string, certificateConfig: DomainCertificateQPQConfigSetting): string[] => {\n const subdomainFqdns = certificateConfig.subdomains.map((s) => `${s}.${resolvedApex}`);\n if (certificateConfig.includeApex) {\n return [resolvedApex, ...subdomainFqdns];\n }\n if (subdomainFqdns.length === 0) {\n throw new Error(\n `defineDomainCertificate(\"${certificateConfig.rootDomain}\", \"${certificateConfig.region}\", ...) ` +\n `must declare at least one subdomain, or set includeApex: true`,\n );\n }\n return subdomainFqdns;\n};\n\nexport class DomainCertificateStack extends Stack {\n public readonly certificate: aws_certificatemanager.ICertificate;\n public readonly certRegion: string;\n public readonly resolvedApex: string;\n\n constructor(scope: Construct, id: string, props: DomainCertificateStackProps) {\n const deployAccountId = qpqConfigAwsUtils.getApplicationModuleDeployAccountId(props.qpqConfig);\n const deployRegion = qpqConfigAwsUtils.getApplicationModuleDeployRegion(props.qpqConfig);\n const certRegion = props.certificateConfig.region;\n\n super(scope, id, {\n stackName: props.stackName,\n env: {\n region: certRegion,\n account: deployAccountId,\n },\n });\n\n this.certRegion = certRegion;\n\n // Apply the same environment + feature prefixing that defineApi / webEntry rootDomain\n // fields go through, so `rootDomain: \"example.com\"` in a dev env resolves to\n // `development.example.com` — matching what API Gateway / CloudFront end up using.\n this.resolvedApex = qpqWebServerUtils.resolveDomainRoot(props.certificateConfig.rootDomain, props.qpqConfig);\n\n const hostedZone = aws_route53.HostedZone.fromLookup(this, 'apex-zone', {\n domainName: this.resolvedApex,\n });\n\n const domainNames = buildDomainNames(this.resolvedApex, props.certificateConfig);\n\n const certificate = new aws_certificatemanager.Certificate(this, 'cert', {\n domainName: domainNames[0],\n subjectAlternativeNames: domainNames.slice(1),\n validation: aws_certificatemanager.CertificateValidation.fromDns(hostedZone),\n });\n this.certificate = certificate;\n\n const paramName = qpqConfigAwsUtils.getDomainCertificateArnSsmParameterName(certRegion, props.certificateConfig.rootDomain);\n\n if (certRegion === deployRegion) {\n new aws_ssm.StringParameter(this, 'arn-ssm', {\n parameterName: paramName,\n stringValue: certificate.certificateArn,\n });\n } else {\n const sdkCall = {\n service: 'SSM',\n action: 'putParameter',\n region: deployRegion,\n parameters: {\n Name: paramName,\n Value: certificate.certificateArn,\n Type: 'String',\n Overwrite: true,\n },\n physicalResourceId: PhysicalResourceId.of(paramName),\n };\n\n new AwsCustomResource(this, 'arn-ssm-xregion', {\n // Plain SSM put/deleteParameter — Lambda's built-in SDK is plenty; don't\n // npm-install the latest SDK at runtime (slow cold starts, needs internet).\n installLatestAwsSdk: false,\n onCreate: sdkCall,\n onUpdate: sdkCall,\n onDelete: {\n service: 'SSM',\n action: 'deleteParameter',\n region: deployRegion,\n parameters: {\n Name: paramName,\n },\n },\n policy: AwsCustomResourcePolicy.fromStatements([\n new aws_iam.PolicyStatement({\n actions: ['ssm:PutParameter', 'ssm:DeleteParameter'],\n resources: [`arn:aws:ssm:${deployRegion}:${deployAccountId}:parameter${paramName}`],\n }),\n ]),\n });\n }\n }\n}\n"]}
|