@inizioevoke/evosynth 1.6.0

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 (71) hide show
  1. package/.editorconfig +12 -0
  2. package/dist/constructs/certificatemanager.d.ts +12 -0
  3. package/dist/constructs/certificatemanager.js +19 -0
  4. package/dist/constructs/cloudfront.d.ts +55 -0
  5. package/dist/constructs/cloudfront.js +84 -0
  6. package/dist/constructs/codebuild.d.ts +31 -0
  7. package/dist/constructs/codebuild.js +95 -0
  8. package/dist/constructs/codepipeline.d.ts +30 -0
  9. package/dist/constructs/codepipeline.js +63 -0
  10. package/dist/constructs/route53.d.ts +14 -0
  11. package/dist/constructs/route53.js +24 -0
  12. package/dist/constructs/s3.d.ts +11 -0
  13. package/dist/constructs/s3.js +17 -0
  14. package/dist/constructs/ssm.d.ts +9 -0
  15. package/dist/constructs/ssm.js +17 -0
  16. package/dist/constructs/waf.d.ts +21 -0
  17. package/dist/constructs/waf.js +89 -0
  18. package/dist/index.d.ts +10 -0
  19. package/dist/index.js +26 -0
  20. package/dist/lib/const.d.ts +1 -0
  21. package/dist/lib/const.js +2 -0
  22. package/dist/lib/csv-redirects.d.ts +3 -0
  23. package/dist/lib/csv-redirects.js +124 -0
  24. package/dist/lib/tags.d.ts +19 -0
  25. package/dist/lib/tags.js +47 -0
  26. package/dist/lib/types.d.ts +14 -0
  27. package/dist/lib/types.js +2 -0
  28. package/dist/lib/utils.d.ts +2 -0
  29. package/dist/lib/utils.js +7 -0
  30. package/dist/lib/version.d.ts +1 -0
  31. package/dist/lib/version.js +5 -0
  32. package/dist/stacks/web-static-serverless/codepipeline-stack.d.ts +17 -0
  33. package/dist/stacks/web-static-serverless/codepipeline-stack.js +28 -0
  34. package/dist/stacks/web-static-serverless/web-global-stack.d.ts +43 -0
  35. package/dist/stacks/web-static-serverless/web-global-stack.js +142 -0
  36. package/dist/stages/str8r-clm-stage.d.ts +17 -0
  37. package/dist/stages/str8r-clm-stage.js +41 -0
  38. package/dist/stages/web-static-serverless-stage.d.ts +19 -0
  39. package/dist/stages/web-static-serverless-stage.js +51 -0
  40. package/dist/templates/cffn-default-doc-basic-auth.js +155 -0
  41. package/dist/templates/cffn-default-doc.js +132 -0
  42. package/inizioevoke-evosynth.code-workspace +8 -0
  43. package/package.json +24 -0
  44. package/readme.md +114 -0
  45. package/samples/app.ts +103 -0
  46. package/samples/codebuild/buildspec.yml +24 -0
  47. package/samples/config/redirects.csv +6 -0
  48. package/src/constructs/certificatemanager.ts +28 -0
  49. package/src/constructs/cloudfront.ts +148 -0
  50. package/src/constructs/codebuild.ts +124 -0
  51. package/src/constructs/codepipeline.ts +93 -0
  52. package/src/constructs/route53.ts +34 -0
  53. package/src/constructs/s3.ts +25 -0
  54. package/src/constructs/ssm.ts +24 -0
  55. package/src/constructs/waf.ts +118 -0
  56. package/src/index.ts +35 -0
  57. package/src/lib/const.ts +1 -0
  58. package/src/lib/csv-redirects.ts +139 -0
  59. package/src/lib/tags.ts +55 -0
  60. package/src/lib/types.ts +17 -0
  61. package/src/lib/utils.ts +7 -0
  62. package/src/lib/version.ts +6 -0
  63. package/src/stacks/web-static-serverless/codepipeline-stack.ts +42 -0
  64. package/src/stacks/web-static-serverless/web-global-stack.ts +184 -0
  65. package/src/stages/str8r-clm-stage.ts +57 -0
  66. package/src/stages/web-static-serverless-stage.ts +69 -0
  67. package/src/templates/cffn-default-doc-basic-auth.js +155 -0
  68. package/src/templates/cffn-default-doc.js +132 -0
  69. package/tasks/clean.js +7 -0
  70. package/tasks/copy-templates.js +13 -0
  71. package/tsconfig.json +32 -0
@@ -0,0 +1,57 @@
1
+ import { Stage, StageProps } from 'aws-cdk-lib/core';
2
+ import { Construct } from 'constructs';
3
+
4
+ import { CodeBuildPipelineProjectProps } from '../constructs/codebuild.js';
5
+ import { WebGlobalStack, WebGlobalStackProps } from '../stacks/web-static-serverless/web-global-stack.js';
6
+ import { CodePipelineStack, CodePipelineStackProps } from '../stacks/web-static-serverless/codepipeline-stack.js';
7
+ import { mergeTags, createEvoVersionTag, createEvoStageTag } from '../lib/tags.ts';
8
+
9
+ export interface Str8rClmStageProps extends WebGlobalStackProps {
10
+ pipeline?: Omit<CodePipelineStackProps, 'codeBuildProject'> & {
11
+ codeBuildProject?: Omit<CodeBuildPipelineProjectProps, 'cloudFrontDistributionArn' | 's3BucketName' | 'destroy' | 'tags'>
12
+ }
13
+ destroy?: boolean;
14
+ tags?: Record<string, string>;
15
+ }
16
+
17
+ export class Str8rClmStage extends Stage {
18
+ public readonly webStack: WebGlobalStack;
19
+ public readonly codePipelineStack: CodePipelineStack;
20
+
21
+ constructor(scope: Construct, id: string, props: Str8rClmStageProps & StageProps) {
22
+ super(scope, id, props);
23
+ props.tags = mergeTags(props.tags, createEvoVersionTag(), createEvoStageTag('Str8rClmStage'));
24
+
25
+ if (props.destroy === undefined) {
26
+ props.destroy = true;
27
+ }
28
+
29
+ this.webStack = new WebGlobalStack(this, 'web-global', {
30
+ ...props,
31
+ env: {
32
+ account: props.env?.account,
33
+ region: 'us-east-1'
34
+ },
35
+ stackName: `${props.stageName}-web-global-stack`,
36
+ destroy: props.destroy,
37
+ tags: props.tags
38
+ });
39
+
40
+ if (props.pipeline) {
41
+ props.pipeline.codeBuildProject = props.pipeline.codeBuildProject ?? {};
42
+ if (!props.pipeline.codeBuildProject.ecrBuildImage && !props.pipeline.codeBuildProject.buildImage) {
43
+ props.pipeline.codeBuildProject.ecrBuildImage = { repository: 'str8r-v3/codebuild', tag: 'veeva-clm' };
44
+ }
45
+ (props.pipeline.codeBuildProject as CodeBuildPipelineProjectProps).cloudFrontDistributionArn = this.webStack.cloudFrontDistribution.distributionArn;
46
+ (props.pipeline.codeBuildProject as CodeBuildPipelineProjectProps).s3BucketName = this.webStack.s3Bucket.bucketName;
47
+
48
+ this.codePipelineStack = new CodePipelineStack(this, 'codepipeline', {
49
+ ...props.pipeline,
50
+ env: props.env,
51
+ stackName: `${props.stageName}-codepipeline-stack`,
52
+ destroy: props.destroy,
53
+ tags: props.tags
54
+ });
55
+ }
56
+ }
57
+ }
@@ -0,0 +1,69 @@
1
+ import { Environment, Stage, StageProps } from 'aws-cdk-lib/core';
2
+ import { Construct } from 'constructs';
3
+
4
+ import { CodeBuildPipelineProjectProps } from '../constructs/codebuild.js';
5
+ import { WebGlobalStack, WebGlobalStackProps } from '../stacks/web-static-serverless/web-global-stack.js';
6
+ // import { WebRegionalStack } from '../stacks/web-static-serverless/web-regional-stack';
7
+ import { CodePipelineStack, CodePipelineStackProps } from '../stacks/web-static-serverless/codepipeline-stack.js';
8
+ import { mergeTags, createEvoVersionTag, createEvoStageTag } from '../lib/tags.ts';
9
+
10
+ export interface WebStaticServerlessStageProps extends WebGlobalStackProps {
11
+ pipeline?: Omit<CodePipelineStackProps, 'codeBuildProject'> & {
12
+ codeBuildProject?: Omit<CodeBuildPipelineProjectProps, 'cloudFrontDistributionArn' | 's3BucketName' | 'destroy' | 'tags'>
13
+ }
14
+ env?: Environment;
15
+ destroy?: boolean;
16
+ tags?: Record<string, string>;
17
+ }
18
+
19
+ export class WebStaticServerlessStage extends Stage {
20
+ // public readonly regionalStack: WebRegionalStack;
21
+ public readonly webStack: WebGlobalStack;
22
+ public readonly codePipelineStack: CodePipelineStack;
23
+
24
+ constructor(scope: Construct, id: string, props: WebStaticServerlessStageProps & StageProps) {
25
+ super(scope, id, props);
26
+ props.tags = mergeTags(props.tags, createEvoVersionTag(), createEvoStageTag('WebStaticServerlessStage'));
27
+
28
+ if (props.destroy === undefined) {
29
+ props.destroy = true;
30
+ }
31
+
32
+ this.webStack = new WebGlobalStack(this, 'web-global', {
33
+ ...props,
34
+ env: {
35
+ account: props.env?.account,
36
+ region: 'us-east-1'
37
+ },
38
+ stackName: `${props.stageName}-web-global-stack`,
39
+ // s3BucketName: this.regionalStack.s3Bucket.bucketName
40
+ destroy: props.destroy,
41
+ tags: props.tags
42
+ });
43
+
44
+ if (props.pipeline) {
45
+ props.pipeline.codeBuildProject = props.pipeline.codeBuildProject ?? {};
46
+ (props.pipeline.codeBuildProject as CodeBuildPipelineProjectProps).cloudFrontDistributionArn = this.webStack.cloudFrontDistribution.distributionArn;
47
+ (props.pipeline.codeBuildProject as CodeBuildPipelineProjectProps).s3BucketName = this.webStack.s3Bucket.bucketName;
48
+
49
+ this.codePipelineStack = new CodePipelineStack(this, 'codepipeline', {
50
+ ...props.pipeline,
51
+ env: props.env,
52
+ stackName: `${props.stageName}-codepipeline-stack`,
53
+ destroy: props.destroy,
54
+ tags: props.tags
55
+ });
56
+ }
57
+ }
58
+
59
+ static create(scope: Construct, id: string, props: WebStaticServerlessStageProps & StageProps) {
60
+ const env = {
61
+ account: props.env?.account ?? process.env.CDK_DEFAULT_ACCOUNT,
62
+ region: props.env?.region ?? process.env.CDK_DEFAULT_REGION
63
+ };
64
+ return new WebStaticServerlessStage(scope, id, {
65
+ ...props,
66
+ ...env
67
+ });
68
+ }
69
+ }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Viewer Request - handle basic authorization, redirects, append index.html to origin
3
+ * Viewer Response - handle 301 redirect with request querystring
4
+ */
5
+
6
+ const DEFAULT_DOCUMENT = "__DEFAULT_DOCUMENT__";
7
+ const BASIC_AUTH = ["Basic __CREDENTIALS__"];
8
+
9
+ /** @type {Record<string, string | [string, 301|302|303|307|308]>} */
10
+ const redirects = __REDIRECTS__;
11
+
12
+ const useTrailingSlash = __TRAILING_SLASH__;
13
+ const shouldRedirDefDoc = __REDIR_DEF_DOC__;
14
+
15
+
16
+ function handler(event) {
17
+ switch (event.context.eventType) {
18
+ case "viewer-request":
19
+ return handleRequest(event);
20
+ case "viewer-response":
21
+ return handleResponse(event);
22
+ default:
23
+ return {
24
+ statusCode: 400,
25
+ statusDescription: "Bad request",
26
+ };
27
+ }
28
+ }
29
+
30
+ function handleRequest(event) {
31
+ if (authorized(event)) {
32
+ const request = event.request;
33
+ const uri = request.uri;
34
+
35
+ const redirect = redirects ? redirects[uri] : null;
36
+ if (redirect) {
37
+ const redir = Array.isArray(redirect) ? redirect : [redirect, 301];
38
+ return redirectResponse(event, redir[0], redir[1]);
39
+ }
40
+
41
+ if (/^(?:.+?)\.[^\.\/]+$/.test(uri)) {
42
+ // uri has a file extension
43
+ if (uri.endsWith(DEFAULT_DOCUMENT) && shouldRedirDefDoc === true) {
44
+ return redirectResponse(event, uri.slice(0, -1 * DEFAULT_DOCUMENT.length - (useTrailingSlash ? 0 : 1)));
45
+ } else {
46
+ return request;
47
+ }
48
+ } else if (useTrailingSlash === true && !uri.endsWith("/")) {
49
+ return redirectResponse(event, `${uri}/`);
50
+ } else if (uri !== '/' && useTrailingSlash === false && uri.endsWith("/")) {
51
+ return redirectResponse(event, uri.slice(0, -1));
52
+ } else {
53
+ request.uri = `${uri}${uri.endsWith("/") ? "" : "/"}${DEFAULT_DOCUMENT}`;
54
+ return request;
55
+ }
56
+ } else {
57
+ return {
58
+ statusCode: 401,
59
+ statusDescription: "Unauthorized",
60
+ headers: {
61
+ "www-authenticate": { value: "Basic" },
62
+ },
63
+ };
64
+ }
65
+ }
66
+
67
+ function authorized(event) {
68
+ let flag = false;
69
+ const authHeader = event.request.headers["authorization"];
70
+ if (authHeader && authHeader.value) {
71
+ BASIC_AUTH.every((val) => {
72
+ flag = authHeader.value === val;
73
+ return !flag;
74
+ });
75
+ }
76
+ return flag;
77
+ }
78
+
79
+ function handleResponse(event) {
80
+ switch (event.response.statusCode) {
81
+ case 301:
82
+ case 302:
83
+ case 303:
84
+ case 307:
85
+ case 308:
86
+ return redirectResponse(event);
87
+ default:
88
+ return event.response;
89
+ }
90
+ }
91
+
92
+ var STATUS_DESCRIPTIONS = {
93
+ 301: "Moved Permanently",
94
+ 302: "Found",
95
+ 303: "See Other",
96
+ 307: "Temporary Redirect",
97
+ 308: "Permanent Redirect"
98
+ };
99
+
100
+ function redirectResponse(event, location, statusCode) {
101
+ var response = event.response || {};
102
+ var code = statusCode || response.statusCode || 301;
103
+ response.statusCode = code;
104
+ response.statusDescription = STATUS_DESCRIPTIONS[code] || "Moved Permanently";
105
+ var path = location || getLocationHeaderValue(response.headers) || '/';
106
+ var querystring = event.request.querystring;
107
+ response.headers = updateLocationHeader(response.headers, pathWithQS(path, querystring));
108
+ return response;
109
+ }
110
+
111
+ function getLocationHeaderValue(headers) {
112
+ return headers && headers["location"] ? headers["location"].value : undefined;
113
+ }
114
+
115
+ function updateLocationHeader(headers, location) {
116
+ headers = headers || {};
117
+ headers["location"] = {
118
+ value: location,
119
+ };
120
+ return headers;
121
+ }
122
+
123
+ function qsParamExists(path, key, value) {
124
+ return path.indexOf(`${key}=${value}`) != -1;
125
+ }
126
+
127
+ function pathWithQS(path, querystring) {
128
+ let qs = [];
129
+ if (querystring) {
130
+ qs = Object.keys(querystring)
131
+ .map(function (key) {
132
+ if (querystring[key].multiValue) {
133
+ return querystring[key].multiValue.map((multiKey) => {
134
+ return !qsParamExists(path, key, multiKey.value)
135
+ ? `${key}=${multiKey.value}`
136
+ : null;
137
+ });
138
+ } else {
139
+ return !qsParamExists(path, key, querystring[key].value)
140
+ ? `${key}=${querystring[key].value}`
141
+ : null;
142
+ }
143
+ })
144
+ .reduce((r, item) => {
145
+ (item instanceof Array ? item : [item]).forEach((i) => {
146
+ r.push(i);
147
+ });
148
+ return r;
149
+ }, [])
150
+ .filter((item) => {
151
+ return item !== null;
152
+ });
153
+ }
154
+ return `${path}${qs.length > 0 ? (path.indexOf("?") == -1 ? "?" : "&") : ""}${qs.join("&")}`;
155
+ }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Viewer Request - redirects, append index.html to origin
3
+ * Viewer Response - handle 301 redirect with request querystring
4
+ */
5
+
6
+ const DEFAULT_DOCUMENT = "__DEFAULT_DOCUMENT__";
7
+
8
+ /** @type {Record<string, string | [string, 301|302|303|307|308]>} */
9
+ const redirects = __REDIRECTS__;
10
+
11
+ const useTrailingSlash = __TRAILING_SLASH__;
12
+ const shouldRedirDefDoc = __REDIR_DEF_DOC__;
13
+
14
+
15
+ function handler(event) {
16
+ switch (event.context.eventType) {
17
+ case "viewer-request":
18
+ return handleRequest(event);
19
+ case "viewer-response":
20
+ return handleResponse(event);
21
+ default:
22
+ return {
23
+ statusCode: 400,
24
+ statusDescription: "Bad request",
25
+ };
26
+ }
27
+ }
28
+
29
+ function handleRequest(event) {
30
+ const request = event.request;
31
+ const uri = request.uri;
32
+
33
+ const redirect = redirects ? redirects[uri] : null;
34
+ if (redirect) {
35
+ const redir = Array.isArray(redirect) ? redirect : [redirect, 301];
36
+ return redirectResponse(event, redir[0], redir[1]);
37
+ }
38
+
39
+ if (/^(?:.+?)\.[^\.\/]+$/.test(uri)) {
40
+ // uri has a file extension
41
+ if (uri.endsWith(DEFAULT_DOCUMENT) && shouldRedirDefDoc === true) {
42
+ return redirectResponse(event, uri.slice(0, -1 * DEFAULT_DOCUMENT.length - (useTrailingSlash ? 0 : 1)));
43
+ } else {
44
+ return request;
45
+ }
46
+ } else if (useTrailingSlash === true && !uri.endsWith("/")) {
47
+ return redirectResponse(event, `${uri}/`);
48
+ } else if (uri !== '/' && useTrailingSlash === false && uri.endsWith("/")) {
49
+ return redirectResponse(event, uri.slice(0, -1));
50
+ } else {
51
+ request.uri = `${uri}${uri.endsWith("/") ? "" : "/"}${DEFAULT_DOCUMENT}`;
52
+ return request;
53
+ }
54
+ }
55
+
56
+ function handleResponse(event) {
57
+ switch (event.response.statusCode) {
58
+ case 301:
59
+ case 302:
60
+ case 303:
61
+ case 307:
62
+ case 308:
63
+ return redirectResponse(event);
64
+ default:
65
+ return event.response;
66
+ }
67
+ }
68
+
69
+ var STATUS_DESCRIPTIONS = {
70
+ 301: "Moved Permanently",
71
+ 302: "Found",
72
+ 303: "See Other",
73
+ 307: "Temporary Redirect",
74
+ 308: "Permanent Redirect"
75
+ };
76
+
77
+ function redirectResponse(event, location, statusCode) {
78
+ var response = event.response || {};
79
+ var code = statusCode || response.statusCode || 301;
80
+ response.statusCode = code;
81
+ response.statusDescription = STATUS_DESCRIPTIONS[code] || "Moved Permanently";
82
+ var path = location || getLocationHeaderValue(response.headers) || '/';
83
+ var querystring = event.request.querystring;
84
+ response.headers = updateLocationHeader(response.headers, pathWithQS(path, querystring));
85
+ return response;
86
+ }
87
+
88
+ function getLocationHeaderValue(headers) {
89
+ return headers && headers["location"] ? headers["location"].value : undefined;
90
+ }
91
+
92
+ function updateLocationHeader(headers, location) {
93
+ headers = headers || {};
94
+ headers["location"] = {
95
+ value: location,
96
+ };
97
+ return headers;
98
+ }
99
+
100
+ function qsParamExists(path, key, value) {
101
+ return path.indexOf(`${key}=${value}`) != -1;
102
+ }
103
+
104
+ function pathWithQS(path, querystring) {
105
+ let qs = [];
106
+ if (querystring) {
107
+ qs = Object.keys(querystring)
108
+ .map(function (key) {
109
+ if (querystring[key].multiValue) {
110
+ return querystring[key].multiValue.map((multiKey) => {
111
+ return !qsParamExists(path, key, multiKey.value)
112
+ ? `${key}=${multiKey.value}`
113
+ : null;
114
+ });
115
+ } else {
116
+ return !qsParamExists(path, key, querystring[key].value)
117
+ ? `${key}=${querystring[key].value}`
118
+ : null;
119
+ }
120
+ })
121
+ .reduce((r, item) => {
122
+ (item instanceof Array ? item : [item]).forEach((i) => {
123
+ r.push(i);
124
+ });
125
+ return r;
126
+ }, [])
127
+ .filter((item) => {
128
+ return item !== null;
129
+ });
130
+ }
131
+ return `${path}${qs.length > 0 ? (path.indexOf("?") == -1 ? "?" : "&") : ""}${qs.join("&")}`;
132
+ }
package/tasks/clean.js ADDED
@@ -0,0 +1,7 @@
1
+ import { rmSync, existsSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+
4
+ const distDir = resolve(import.meta.dirname, '../dist');
5
+ if (existsSync(distDir)) {
6
+ rmSync(distDir, { recursive: true });
7
+ }
@@ -0,0 +1,13 @@
1
+ import { readdirSync, copyFileSync, mkdirSync, existsSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+
4
+ const distDir = resolve(import.meta.dirname, '../dist/templates');
5
+ const srcTemplates = resolve(import.meta.dirname, '../src/templates');
6
+
7
+ if (!existsSync(distDir)) {
8
+ mkdirSync(distDir, { recursive: true });
9
+ }
10
+ const templates = readdirSync(srcTemplates);
11
+ for (const t of templates) {
12
+ copyFileSync(join(srcTemplates, t), join(distDir, t));
13
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "lib": [
7
+ "es2022"
8
+ ],
9
+ "declaration": true,
10
+ "strict": true,
11
+ "noImplicitAny": true,
12
+ "strictNullChecks": true,
13
+ "noImplicitThis": true,
14
+ "alwaysStrict": true,
15
+ "noUnusedLocals": false,
16
+ "noUnusedParameters": false,
17
+ "noImplicitReturns": true,
18
+ "noFallthroughCasesInSwitch": false,
19
+ "inlineSourceMap": true,
20
+ "inlineSources": true,
21
+ "experimentalDecorators": true,
22
+ "strictPropertyInitialization": false,
23
+ "skipLibCheck": true,
24
+ "types": ["node"],
25
+ "rewriteRelativeImportExtensions": true,
26
+ "outDir": "./dist"
27
+ },
28
+ "include": ["./src/**/*.ts"],
29
+ "exclude": [
30
+ "node_modules"
31
+ ]
32
+ }