@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.
- package/.editorconfig +12 -0
- package/dist/constructs/certificatemanager.d.ts +12 -0
- package/dist/constructs/certificatemanager.js +19 -0
- package/dist/constructs/cloudfront.d.ts +55 -0
- package/dist/constructs/cloudfront.js +84 -0
- package/dist/constructs/codebuild.d.ts +31 -0
- package/dist/constructs/codebuild.js +95 -0
- package/dist/constructs/codepipeline.d.ts +30 -0
- package/dist/constructs/codepipeline.js +63 -0
- package/dist/constructs/route53.d.ts +14 -0
- package/dist/constructs/route53.js +24 -0
- package/dist/constructs/s3.d.ts +11 -0
- package/dist/constructs/s3.js +17 -0
- package/dist/constructs/ssm.d.ts +9 -0
- package/dist/constructs/ssm.js +17 -0
- package/dist/constructs/waf.d.ts +21 -0
- package/dist/constructs/waf.js +89 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +26 -0
- package/dist/lib/const.d.ts +1 -0
- package/dist/lib/const.js +2 -0
- package/dist/lib/csv-redirects.d.ts +3 -0
- package/dist/lib/csv-redirects.js +124 -0
- package/dist/lib/tags.d.ts +19 -0
- package/dist/lib/tags.js +47 -0
- package/dist/lib/types.d.ts +14 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +7 -0
- package/dist/lib/version.d.ts +1 -0
- package/dist/lib/version.js +5 -0
- package/dist/stacks/web-static-serverless/codepipeline-stack.d.ts +17 -0
- package/dist/stacks/web-static-serverless/codepipeline-stack.js +28 -0
- package/dist/stacks/web-static-serverless/web-global-stack.d.ts +43 -0
- package/dist/stacks/web-static-serverless/web-global-stack.js +142 -0
- package/dist/stages/str8r-clm-stage.d.ts +17 -0
- package/dist/stages/str8r-clm-stage.js +41 -0
- package/dist/stages/web-static-serverless-stage.d.ts +19 -0
- package/dist/stages/web-static-serverless-stage.js +51 -0
- package/dist/templates/cffn-default-doc-basic-auth.js +155 -0
- package/dist/templates/cffn-default-doc.js +132 -0
- package/inizioevoke-evosynth.code-workspace +8 -0
- package/package.json +24 -0
- package/readme.md +114 -0
- package/samples/app.ts +103 -0
- package/samples/codebuild/buildspec.yml +24 -0
- package/samples/config/redirects.csv +6 -0
- package/src/constructs/certificatemanager.ts +28 -0
- package/src/constructs/cloudfront.ts +148 -0
- package/src/constructs/codebuild.ts +124 -0
- package/src/constructs/codepipeline.ts +93 -0
- package/src/constructs/route53.ts +34 -0
- package/src/constructs/s3.ts +25 -0
- package/src/constructs/ssm.ts +24 -0
- package/src/constructs/waf.ts +118 -0
- package/src/index.ts +35 -0
- package/src/lib/const.ts +1 -0
- package/src/lib/csv-redirects.ts +139 -0
- package/src/lib/tags.ts +55 -0
- package/src/lib/types.ts +17 -0
- package/src/lib/utils.ts +7 -0
- package/src/lib/version.ts +6 -0
- package/src/stacks/web-static-serverless/codepipeline-stack.ts +42 -0
- package/src/stacks/web-static-serverless/web-global-stack.ts +184 -0
- package/src/stages/str8r-clm-stage.ts +57 -0
- package/src/stages/web-static-serverless-stage.ts +69 -0
- package/src/templates/cffn-default-doc-basic-auth.js +155 -0
- package/src/templates/cffn-default-doc.js +132 -0
- package/tasks/clean.js +7 -0
- package/tasks/copy-templates.js +13 -0
- 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,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
|
+
}
|