@codedrifters/constructs 0.0.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/README.md +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +19 -0
- package/lib/lib/git-utils.d.ts +8 -0
- package/lib/lib/git-utils.js +36 -0
- package/lib/lib/string-utils.d.ts +14 -0
- package/lib/lib/string-utils.js +64 -0
- package/lib/s3/index.d.ts +1 -0
- package/lib/s3/index.js +18 -0
- package/lib/s3/private-bucket.d.ts +7 -0
- package/lib/s3/private-bucket.js +23 -0
- package/lib/static-hosting/index.d.ts +2 -0
- package/lib/static-hosting/index.js +19 -0
- package/lib/static-hosting/static-content.d.ts +49 -0
- package/lib/static-hosting/static-content.js +52 -0
- package/lib/static-hosting/static-hosting.d.ts +49 -0
- package/lib/static-hosting/static-hosting.js +172 -0
- package/lib/static-hosting/static-hosting.viewer-request-handler.d.ts +35 -0
- package/lib/static-hosting/static-hosting.viewer-request-handler.js +76 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# replace this
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
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("./s3"), exports);
|
|
18
|
+
__exportStar(require("./static-hosting"), exports);
|
|
19
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLHVDQUFxQjtBQUNyQixtREFBaUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tIFwiLi9zM1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vc3RhdGljLWhvc3RpbmdcIjtcbiJdfQ==
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findGitRepoName = exports.findGitBranch = void 0;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
/**
|
|
6
|
+
* Returns the current full git branch name
|
|
7
|
+
*
|
|
8
|
+
* ie: feature/1234 returns feature/1234
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
const findGitBranch = () => {
|
|
12
|
+
return (0, node_child_process_1.execSync)("git rev-parse --abbrev-ref HEAD")
|
|
13
|
+
.toString("utf8")
|
|
14
|
+
.replace(/[\n\r\s]+$/, "");
|
|
15
|
+
};
|
|
16
|
+
exports.findGitBranch = findGitBranch;
|
|
17
|
+
const findGitRepoName = () => {
|
|
18
|
+
/**
|
|
19
|
+
* When running in github actions this will be populated.
|
|
20
|
+
*/
|
|
21
|
+
if (process.env.GITHUB_REPOSITORY) {
|
|
22
|
+
return process.env.GITHUB_REPOSITORY;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* locally, we need to extract the repo name from the git config.
|
|
26
|
+
*/
|
|
27
|
+
const remote = (0, node_child_process_1.execSync)("git config --get remote.origin.url")
|
|
28
|
+
.toString("utf8")
|
|
29
|
+
.replace(/[\n\r\s]+$/, "")
|
|
30
|
+
.trim();
|
|
31
|
+
const match = remote.match(/[:\/]([^/]+\/[^/]+?)(?:\.git)?$/);
|
|
32
|
+
const repoName = match ? match[1] : "error-repo-name";
|
|
33
|
+
return repoName;
|
|
34
|
+
};
|
|
35
|
+
exports.findGitRepoName = findGitRepoName;
|
|
36
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2l0LXV0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2xpYi9naXQtdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsMkRBQThDO0FBRTlDOzs7OztHQUtHO0FBQ0ksTUFBTSxhQUFhLEdBQUcsR0FBVyxFQUFFO0lBQ3hDLE9BQU8sSUFBQSw2QkFBUSxFQUFDLGlDQUFpQyxDQUFDO1NBQy9DLFFBQVEsQ0FBQyxNQUFNLENBQUM7U0FDaEIsT0FBTyxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUMsQ0FBQztBQUMvQixDQUFDLENBQUM7QUFKVyxRQUFBLGFBQWEsaUJBSXhCO0FBRUssTUFBTSxlQUFlLEdBQUcsR0FBVyxFQUFFO0lBQzFDOztPQUVHO0lBQ0gsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFDbEMsT0FBTyxPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFDO0lBQ3ZDLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sTUFBTSxHQUFHLElBQUEsNkJBQVEsRUFBQyxvQ0FBb0MsQ0FBQztTQUMxRCxRQUFRLENBQUMsTUFBTSxDQUFDO1NBQ2hCLE9BQU8sQ0FBQyxZQUFZLEVBQUUsRUFBRSxDQUFDO1NBQ3pCLElBQUksRUFBRSxDQUFDO0lBRVYsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO0lBQzlELE1BQU0sUUFBUSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQztJQUV0RCxPQUFPLFFBQVEsQ0FBQztBQUNsQixDQUFDLENBQUM7QUFwQlcsUUFBQSxlQUFlLG1CQW9CMUIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBleGVjU3luYyB9IGZyb20gXCJub2RlOmNoaWxkX3Byb2Nlc3NcIjtcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBjdXJyZW50IGZ1bGwgZ2l0IGJyYW5jaCBuYW1lXG4gKlxuICogaWU6IGZlYXR1cmUvMTIzNCByZXR1cm5zIGZlYXR1cmUvMTIzNFxuICpcbiAqL1xuZXhwb3J0IGNvbnN0IGZpbmRHaXRCcmFuY2ggPSAoKTogc3RyaW5nID0+IHtcbiAgcmV0dXJuIGV4ZWNTeW5jKFwiZ2l0IHJldi1wYXJzZSAtLWFiYnJldi1yZWYgSEVBRFwiKVxuICAgIC50b1N0cmluZyhcInV0ZjhcIilcbiAgICAucmVwbGFjZSgvW1xcblxcclxcc10rJC8sIFwiXCIpO1xufTtcblxuZXhwb3J0IGNvbnN0IGZpbmRHaXRSZXBvTmFtZSA9ICgpOiBzdHJpbmcgPT4ge1xuICAvKipcbiAgICogV2hlbiBydW5uaW5nIGluIGdpdGh1YiBhY3Rpb25zIHRoaXMgd2lsbCBiZSBwb3B1bGF0ZWQuXG4gICAqL1xuICBpZiAocHJvY2Vzcy5lbnYuR0lUSFVCX1JFUE9TSVRPUlkpIHtcbiAgICByZXR1cm4gcHJvY2Vzcy5lbnYuR0lUSFVCX1JFUE9TSVRPUlk7XG4gIH1cblxuICAvKipcbiAgICogbG9jYWxseSwgd2UgbmVlZCB0byBleHRyYWN0IHRoZSByZXBvIG5hbWUgZnJvbSB0aGUgZ2l0IGNvbmZpZy5cbiAgICovXG4gIGNvbnN0IHJlbW90ZSA9IGV4ZWNTeW5jKFwiZ2l0IGNvbmZpZyAtLWdldCByZW1vdGUub3JpZ2luLnVybFwiKVxuICAgIC50b1N0cmluZyhcInV0ZjhcIilcbiAgICAucmVwbGFjZSgvW1xcblxcclxcc10rJC8sIFwiXCIpXG4gICAgLnRyaW0oKTtcblxuICBjb25zdCBtYXRjaCA9IHJlbW90ZS5tYXRjaCgvWzpcXC9dKFteL10rXFwvW14vXSs/KSg/OlxcLmdpdCk/JC8pO1xuICBjb25zdCByZXBvTmFtZSA9IG1hdGNoID8gbWF0Y2hbMV0gOiBcImVycm9yLXJlcG8tbmFtZVwiO1xuXG4gIHJldHVybiByZXBvTmFtZTtcbn07XG4iXX0=
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param inString string to hash
|
|
4
|
+
* @param trimLength trim to this length (defaults to 999 chars)
|
|
5
|
+
* @returns
|
|
6
|
+
*/
|
|
7
|
+
export declare const hashString: (inString: string, trimLength?: number) => string;
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @param inputString string to truncate
|
|
11
|
+
* @param maxLength max length of this string
|
|
12
|
+
* @returns trimmed string
|
|
13
|
+
*/
|
|
14
|
+
export declare const trimStringLength: (inputString: string, maxLength: number) => string;
|
|
@@ -0,0 +1,64 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.trimStringLength = exports.hashString = void 0;
|
|
37
|
+
const crypto = __importStar(require("node:crypto"));
|
|
38
|
+
/**
|
|
39
|
+
*
|
|
40
|
+
* @param inString string to hash
|
|
41
|
+
* @param trimLength trim to this length (defaults to 999 chars)
|
|
42
|
+
* @returns
|
|
43
|
+
*/
|
|
44
|
+
const hashString = (inString, trimLength = 999) => {
|
|
45
|
+
return crypto
|
|
46
|
+
.createHash("sha256")
|
|
47
|
+
.update(inString)
|
|
48
|
+
.digest("hex")
|
|
49
|
+
.substring(0, trimLength);
|
|
50
|
+
};
|
|
51
|
+
exports.hashString = hashString;
|
|
52
|
+
/**
|
|
53
|
+
*
|
|
54
|
+
* @param inputString string to truncate
|
|
55
|
+
* @param maxLength max length of this string
|
|
56
|
+
* @returns trimmed string
|
|
57
|
+
*/
|
|
58
|
+
const trimStringLength = (inputString, maxLength) => {
|
|
59
|
+
return inputString.length < maxLength
|
|
60
|
+
? inputString
|
|
61
|
+
: inputString.substring(0, maxLength);
|
|
62
|
+
};
|
|
63
|
+
exports.trimStringLength = trimStringLength;
|
|
64
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RyaW5nLXV0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2xpYi9zdHJpbmctdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsb0RBQXNDO0FBRXRDOzs7OztHQUtHO0FBQ0ksTUFBTSxVQUFVLEdBQUcsQ0FBQyxRQUFnQixFQUFFLGFBQXFCLEdBQUcsRUFBRSxFQUFFO0lBQ3ZFLE9BQU8sTUFBTTtTQUNWLFVBQVUsQ0FBQyxRQUFRLENBQUM7U0FDcEIsTUFBTSxDQUFDLFFBQVEsQ0FBQztTQUNoQixNQUFNLENBQUMsS0FBSyxDQUFDO1NBQ2IsU0FBUyxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQztBQUM5QixDQUFDLENBQUM7QUFOVyxRQUFBLFVBQVUsY0FNckI7QUFFRjs7Ozs7R0FLRztBQUNJLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxXQUFtQixFQUFFLFNBQWlCLEVBQUUsRUFBRTtJQUN6RSxPQUFPLFdBQVcsQ0FBQyxNQUFNLEdBQUcsU0FBUztRQUNuQyxDQUFDLENBQUMsV0FBVztRQUNiLENBQUMsQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQztBQUMxQyxDQUFDLENBQUM7QUFKVyxRQUFBLGdCQUFnQixvQkFJM0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBjcnlwdG8gZnJvbSBcIm5vZGU6Y3J5cHRvXCI7XG5cbi8qKlxuICpcbiAqIEBwYXJhbSBpblN0cmluZyBzdHJpbmcgdG8gaGFzaFxuICogQHBhcmFtIHRyaW1MZW5ndGggdHJpbSB0byB0aGlzIGxlbmd0aCAoZGVmYXVsdHMgdG8gOTk5IGNoYXJzKVxuICogQHJldHVybnNcbiAqL1xuZXhwb3J0IGNvbnN0IGhhc2hTdHJpbmcgPSAoaW5TdHJpbmc6IHN0cmluZywgdHJpbUxlbmd0aDogbnVtYmVyID0gOTk5KSA9PiB7XG4gIHJldHVybiBjcnlwdG9cbiAgICAuY3JlYXRlSGFzaChcInNoYTI1NlwiKVxuICAgIC51cGRhdGUoaW5TdHJpbmcpXG4gICAgLmRpZ2VzdChcImhleFwiKVxuICAgIC5zdWJzdHJpbmcoMCwgdHJpbUxlbmd0aCk7XG59O1xuXG4vKipcbiAqXG4gKiBAcGFyYW0gaW5wdXRTdHJpbmcgc3RyaW5nIHRvIHRydW5jYXRlXG4gKiBAcGFyYW0gbWF4TGVuZ3RoIG1heCBsZW5ndGggb2YgdGhpcyBzdHJpbmdcbiAqIEByZXR1cm5zIHRyaW1tZWQgc3RyaW5nXG4gKi9cbmV4cG9ydCBjb25zdCB0cmltU3RyaW5nTGVuZ3RoID0gKGlucHV0U3RyaW5nOiBzdHJpbmcsIG1heExlbmd0aDogbnVtYmVyKSA9PiB7XG4gIHJldHVybiBpbnB1dFN0cmluZy5sZW5ndGggPCBtYXhMZW5ndGhcbiAgICA/IGlucHV0U3RyaW5nXG4gICAgOiBpbnB1dFN0cmluZy5zdWJzdHJpbmcoMCwgbWF4TGVuZ3RoKTtcbn07XG4iXX0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./private-bucket";
|
package/lib/s3/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
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("./private-bucket"), exports);
|
|
18
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvczMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLG1EQUFpQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gXCIuL3ByaXZhdGUtYnVja2V0XCI7XG4iXX0=
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Bucket, BucketProps } from "aws-cdk-lib/aws-s3";
|
|
2
|
+
import { Construct } from "constructs";
|
|
3
|
+
export interface PrivateBucketProps extends BucketProps {
|
|
4
|
+
}
|
|
5
|
+
export declare class PrivateBucket extends Bucket {
|
|
6
|
+
constructor(scope: Construct, id: string, props?: PrivateBucketProps);
|
|
7
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PrivateBucket = void 0;
|
|
4
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
5
|
+
const aws_s3_1 = require("aws-cdk-lib/aws-s3");
|
|
6
|
+
class PrivateBucket extends aws_s3_1.Bucket {
|
|
7
|
+
constructor(scope, id, props = {}) {
|
|
8
|
+
const defaultProps = {
|
|
9
|
+
removalPolicy: props.removalPolicy ?? aws_cdk_lib_1.RemovalPolicy.RETAIN,
|
|
10
|
+
autoDeleteObjects: props.removalPolicy === aws_cdk_lib_1.RemovalPolicy.DESTROY,
|
|
11
|
+
};
|
|
12
|
+
const requiredProps = {
|
|
13
|
+
publicReadAccess: false,
|
|
14
|
+
blockPublicAccess: aws_s3_1.BlockPublicAccess.BLOCK_ALL,
|
|
15
|
+
enforceSSL: true,
|
|
16
|
+
objectOwnership: aws_s3_1.ObjectOwnership.BUCKET_OWNER_ENFORCED,
|
|
17
|
+
};
|
|
18
|
+
super(scope, id, { ...defaultProps, ...props, ...requiredProps });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.PrivateBucket = PrivateBucket;
|
|
22
|
+
// foo
|
|
23
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJpdmF0ZS1idWNrZXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvczMvcHJpdmF0ZS1idWNrZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNkNBQTRDO0FBQzVDLCtDQUs0QjtBQUs1QixNQUFhLGFBQWMsU0FBUSxlQUFNO0lBQ3ZDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsUUFBNEIsRUFBRTtRQUN0RSxNQUFNLFlBQVksR0FBRztZQUNuQixhQUFhLEVBQUUsS0FBSyxDQUFDLGFBQWEsSUFBSSwyQkFBYSxDQUFDLE1BQU07WUFDMUQsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLGFBQWEsS0FBSywyQkFBYSxDQUFDLE9BQU87U0FDakUsQ0FBQztRQUVGLE1BQU0sYUFBYSxHQUFHO1lBQ3BCLGdCQUFnQixFQUFFLEtBQUs7WUFDdkIsaUJBQWlCLEVBQUUsMEJBQWlCLENBQUMsU0FBUztZQUM5QyxVQUFVLEVBQUUsSUFBSTtZQUNoQixlQUFlLEVBQUUsd0JBQWUsQ0FBQyxxQkFBcUI7U0FDdkQsQ0FBQztRQUVGLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxZQUFZLEVBQUUsR0FBRyxLQUFLLEVBQUUsR0FBRyxhQUFhLEVBQUUsQ0FBQyxDQUFDO0lBQ3BFLENBQUM7Q0FDRjtBQWhCRCxzQ0FnQkM7QUFDRCxNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUmVtb3ZhbFBvbGljeSB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHtcbiAgQmxvY2tQdWJsaWNBY2Nlc3MsXG4gIEJ1Y2tldCxcbiAgQnVja2V0UHJvcHMsXG4gIE9iamVjdE93bmVyc2hpcCxcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zM1wiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBQcml2YXRlQnVja2V0UHJvcHMgZXh0ZW5kcyBCdWNrZXRQcm9wcyB7fVxuXG5leHBvcnQgY2xhc3MgUHJpdmF0ZUJ1Y2tldCBleHRlbmRzIEJ1Y2tldCB7XG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBQcml2YXRlQnVja2V0UHJvcHMgPSB7fSkge1xuICAgIGNvbnN0IGRlZmF1bHRQcm9wcyA9IHtcbiAgICAgIHJlbW92YWxQb2xpY3k6IHByb3BzLnJlbW92YWxQb2xpY3kgPz8gUmVtb3ZhbFBvbGljeS5SRVRBSU4sXG4gICAgICBhdXRvRGVsZXRlT2JqZWN0czogcHJvcHMucmVtb3ZhbFBvbGljeSA9PT0gUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgIH07XG5cbiAgICBjb25zdCByZXF1aXJlZFByb3BzID0ge1xuICAgICAgcHVibGljUmVhZEFjY2VzczogZmFsc2UsXG4gICAgICBibG9ja1B1YmxpY0FjY2VzczogQmxvY2tQdWJsaWNBY2Nlc3MuQkxPQ0tfQUxMLFxuICAgICAgZW5mb3JjZVNTTDogdHJ1ZSxcbiAgICAgIG9iamVjdE93bmVyc2hpcDogT2JqZWN0T3duZXJzaGlwLkJVQ0tFVF9PV05FUl9FTkZPUkNFRCxcbiAgICB9O1xuXG4gICAgc3VwZXIoc2NvcGUsIGlkLCB7IC4uLmRlZmF1bHRQcm9wcywgLi4ucHJvcHMsIC4uLnJlcXVpcmVkUHJvcHMgfSk7XG4gIH1cbn1cbi8vIGZvb1xuIl19
|
|
@@ -0,0 +1,19 @@
|
|
|
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("./static-content"), exports);
|
|
18
|
+
__exportStar(require("./static-hosting"), exports);
|
|
19
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RhdGljLWhvc3RpbmcvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLG1EQUFpQztBQUNqQyxtREFBaUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tIFwiLi9zdGF0aWMtY29udGVudFwiO1xuZXhwb3J0ICogZnJvbSBcIi4vc3RhdGljLWhvc3RpbmdcIjtcbiJdfQ==
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Construct } from "constructs";
|
|
2
|
+
/*******************************************************************************
|
|
3
|
+
*
|
|
4
|
+
* STATIC CONTENT UPLOADER
|
|
5
|
+
*
|
|
6
|
+
* This construct uploads a directory of content from a local location into S3.
|
|
7
|
+
*
|
|
8
|
+
* To support PR and branch specific builds, each S3 bucket can store content
|
|
9
|
+
* for multiple domains and builds, using the following format:
|
|
10
|
+
*
|
|
11
|
+
* S3-bucket/domain/*
|
|
12
|
+
*
|
|
13
|
+
* A bucket used to store content for stage.openhi.org might have the
|
|
14
|
+
* following directory structure (all in the same bucket).
|
|
15
|
+
*
|
|
16
|
+
* /stage.openhi.org/* -> serves content to stage.openhi.org
|
|
17
|
+
* /feature-7.stage.openhi.org/* -> serves content to feature-7.stage.openhi.org
|
|
18
|
+
* /pr-123.stage.openhi.org/* -> serves content to pr-123.stage.openhi.org
|
|
19
|
+
*
|
|
20
|
+
******************************************************************************/
|
|
21
|
+
export interface StaticContentProps {
|
|
22
|
+
/**
|
|
23
|
+
* Parameter name to use when storing the static hosting bucket's ARN.
|
|
24
|
+
* This is needed in other later steps when deploying hosted content to S3.
|
|
25
|
+
*/
|
|
26
|
+
readonly bucketArnParamName?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Absolute path to directory containing content for the website.
|
|
29
|
+
*/
|
|
30
|
+
readonly contentSourceDirectory: string;
|
|
31
|
+
/**
|
|
32
|
+
* Directory to place content into. Should start with a slash.
|
|
33
|
+
* Example: '/widget'
|
|
34
|
+
*/
|
|
35
|
+
readonly contentDestinationDirectory: string;
|
|
36
|
+
/**
|
|
37
|
+
* The sub domain prefix (ie: images)
|
|
38
|
+
*
|
|
39
|
+
* @default git branch name
|
|
40
|
+
*/
|
|
41
|
+
readonly subDomain?: string;
|
|
42
|
+
/**
|
|
43
|
+
* The full domain (ie: staging.codedrifters.com)
|
|
44
|
+
*/
|
|
45
|
+
readonly fullDomain: string;
|
|
46
|
+
}
|
|
47
|
+
export declare class StaticContent extends Construct {
|
|
48
|
+
constructor(scope: Construct, id: string, props: StaticContentProps);
|
|
49
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StaticContent = void 0;
|
|
4
|
+
const aws_s3_1 = require("aws-cdk-lib/aws-s3");
|
|
5
|
+
const aws_s3_deployment_1 = require("aws-cdk-lib/aws-s3-deployment");
|
|
6
|
+
const aws_ssm_1 = require("aws-cdk-lib/aws-ssm");
|
|
7
|
+
const change_case_1 = require("change-case");
|
|
8
|
+
const constructs_1 = require("constructs");
|
|
9
|
+
const git_utils_1 = require("../lib/git-utils");
|
|
10
|
+
class StaticContent extends constructs_1.Construct {
|
|
11
|
+
constructor(scope, id, props) {
|
|
12
|
+
super(scope, id);
|
|
13
|
+
/***************************************************************************
|
|
14
|
+
*
|
|
15
|
+
* Initial Setup
|
|
16
|
+
*
|
|
17
|
+
* Set some defaults, build domain information.
|
|
18
|
+
*
|
|
19
|
+
**************************************************************************/
|
|
20
|
+
const { bucketArnParamName, contentSourceDirectory, contentDestinationDirectory, subDomain, fullDomain, } = {
|
|
21
|
+
bucketArnParamName: "/STATIC_WEBSITE/BUCKET_ARN",
|
|
22
|
+
subDomain: (0, git_utils_1.findGitBranch)(),
|
|
23
|
+
...props,
|
|
24
|
+
};
|
|
25
|
+
/***************************************************************************
|
|
26
|
+
*
|
|
27
|
+
* Import and build some values from Param Store during deployment.
|
|
28
|
+
*
|
|
29
|
+
**************************************************************************/
|
|
30
|
+
const keyPrefix = [(0, change_case_1.paramCase)(subDomain), fullDomain].join(".");
|
|
31
|
+
const bucketArn = aws_ssm_1.StringParameter.valueForStringParameter(this, bucketArnParamName);
|
|
32
|
+
const bucket = aws_s3_1.Bucket.fromBucketArn(this, "bucket", bucketArn);
|
|
33
|
+
/***************************************************************************
|
|
34
|
+
*
|
|
35
|
+
* Gather the sources we'll be deploying. We need to have an empty source
|
|
36
|
+
* for tests since it will change all the time and bork up the test
|
|
37
|
+
* snapshots if we don't.
|
|
38
|
+
*
|
|
39
|
+
**************************************************************************/
|
|
40
|
+
const sources = process.env.JEST_WORKER_ID
|
|
41
|
+
? []
|
|
42
|
+
: [aws_s3_deployment_1.Source.asset(contentSourceDirectory)];
|
|
43
|
+
new aws_s3_deployment_1.BucketDeployment(this, "deploy", {
|
|
44
|
+
sources,
|
|
45
|
+
destinationBucket: bucket,
|
|
46
|
+
retainOnDelete: false,
|
|
47
|
+
destinationKeyPrefix: `${keyPrefix}${contentDestinationDirectory}`,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.StaticContent = StaticContent;
|
|
52
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGljLWNvbnRlbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RhdGljLWhvc3Rpbmcvc3RhdGljLWNvbnRlbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsK0NBQTRDO0FBQzVDLHFFQUF5RTtBQUN6RSxpREFBc0Q7QUFDdEQsNkNBQXdDO0FBQ3hDLDJDQUF1QztBQUN2QyxnREFBaUQ7QUFxRGpELE1BQWEsYUFBYyxTQUFRLHNCQUFTO0lBQzFDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBeUI7UUFDakUsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQjs7Ozs7O29GQU00RTtRQUU1RSxNQUFNLEVBQ0osa0JBQWtCLEVBQ2xCLHNCQUFzQixFQUN0QiwyQkFBMkIsRUFDM0IsU0FBUyxFQUNULFVBQVUsR0FDWCxHQUFHO1lBQ0Ysa0JBQWtCLEVBQUUsNEJBQTRCO1lBQ2hELFNBQVMsRUFBRSxJQUFBLHlCQUFhLEdBQUU7WUFDMUIsR0FBRyxLQUFLO1NBQ1QsQ0FBQztRQUVGOzs7O29GQUk0RTtRQUU1RSxNQUFNLFNBQVMsR0FBRyxDQUFDLElBQUEsdUJBQVMsRUFBQyxTQUFTLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFL0QsTUFBTSxTQUFTLEdBQUcseUJBQWUsQ0FBQyx1QkFBdUIsQ0FDdkQsSUFBSSxFQUNKLGtCQUFrQixDQUNuQixDQUFDO1FBQ0YsTUFBTSxNQUFNLEdBQUcsZUFBTSxDQUFDLGFBQWEsQ0FBQyxJQUFJLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBRS9EOzs7Ozs7b0ZBTTRFO1FBRTVFLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYztZQUN4QyxDQUFDLENBQUMsRUFBRTtZQUNKLENBQUMsQ0FBQyxDQUFDLDBCQUFNLENBQUMsS0FBSyxDQUFDLHNCQUFzQixDQUFDLENBQUMsQ0FBQztRQUUzQyxJQUFJLG9DQUFnQixDQUFDLElBQUksRUFBRSxRQUFRLEVBQUU7WUFDbkMsT0FBTztZQUNQLGlCQUFpQixFQUFFLE1BQU07WUFDekIsY0FBYyxFQUFFLEtBQUs7WUFDckIsb0JBQW9CLEVBQUUsR0FBRyxTQUFTLEdBQUcsMkJBQTJCLEVBQUU7U0FDbkUsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBekRELHNDQXlEQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEJ1Y2tldCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtczNcIjtcbmltcG9ydCB7IEJ1Y2tldERlcGxveW1lbnQsIFNvdXJjZSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtczMtZGVwbG95bWVudFwiO1xuaW1wb3J0IHsgU3RyaW5nUGFyYW1ldGVyIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zc21cIjtcbmltcG9ydCB7IHBhcmFtQ2FzZSB9IGZyb20gXCJjaGFuZ2UtY2FzZVwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IGZpbmRHaXRCcmFuY2ggfSBmcm9tIFwiLi4vbGliL2dpdC11dGlsc1wiO1xuXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICpcbiAqICBTVEFUSUMgQ09OVEVOVCBVUExPQURFUlxuICpcbiAqICBUaGlzIGNvbnN0cnVjdCB1cGxvYWRzIGEgZGlyZWN0b3J5IG9mIGNvbnRlbnQgZnJvbSBhIGxvY2FsIGxvY2F0aW9uIGludG8gUzMuXG4gKlxuICogIFRvIHN1cHBvcnQgUFIgYW5kIGJyYW5jaCBzcGVjaWZpYyBidWlsZHMsIGVhY2ggUzMgYnVja2V0IGNhbiBzdG9yZSBjb250ZW50XG4gKiAgZm9yIG11bHRpcGxlIGRvbWFpbnMgYW5kIGJ1aWxkcywgdXNpbmcgdGhlIGZvbGxvd2luZyBmb3JtYXQ6XG4gKlxuICogIFMzLWJ1Y2tldC9kb21haW4vKlxuICpcbiAqICBBIGJ1Y2tldCB1c2VkIHRvIHN0b3JlIGNvbnRlbnQgZm9yIHN0YWdlLm9wZW5oaS5vcmcgbWlnaHQgaGF2ZSB0aGVcbiAqICBmb2xsb3dpbmcgZGlyZWN0b3J5IHN0cnVjdHVyZSAoYWxsIGluIHRoZSBzYW1lIGJ1Y2tldCkuXG4gKlxuICogIC9zdGFnZS5vcGVuaGkub3JnLyogLT4gc2VydmVzIGNvbnRlbnQgdG8gc3RhZ2Uub3BlbmhpLm9yZ1xuICogIC9mZWF0dXJlLTcuc3RhZ2Uub3BlbmhpLm9yZy8qIC0+IHNlcnZlcyBjb250ZW50IHRvIGZlYXR1cmUtNy5zdGFnZS5vcGVuaGkub3JnXG4gKiAgL3ByLTEyMy5zdGFnZS5vcGVuaGkub3JnLyogLT4gc2VydmVzIGNvbnRlbnQgdG8gcHItMTIzLnN0YWdlLm9wZW5oaS5vcmdcbiAqXG4gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5leHBvcnQgaW50ZXJmYWNlIFN0YXRpY0NvbnRlbnRQcm9wcyB7XG4gIC8qKlxuICAgKiBQYXJhbWV0ZXIgbmFtZSB0byB1c2Ugd2hlbiBzdG9yaW5nIHRoZSBzdGF0aWMgaG9zdGluZyBidWNrZXQncyBBUk4uXG4gICAqIFRoaXMgaXMgbmVlZGVkIGluIG90aGVyIGxhdGVyIHN0ZXBzIHdoZW4gZGVwbG95aW5nIGhvc3RlZCBjb250ZW50IHRvIFMzLlxuICAgKi9cbiAgcmVhZG9ubHkgYnVja2V0QXJuUGFyYW1OYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiAgQWJzb2x1dGUgcGF0aCB0byBkaXJlY3RvcnkgY29udGFpbmluZyBjb250ZW50IGZvciB0aGUgd2Vic2l0ZS5cbiAgICovXG4gIHJlYWRvbmx5IGNvbnRlbnRTb3VyY2VEaXJlY3Rvcnk6IHN0cmluZztcblxuICAvKipcbiAgICogIERpcmVjdG9yeSB0byBwbGFjZSBjb250ZW50IGludG8uIFNob3VsZCBzdGFydCB3aXRoIGEgc2xhc2guXG4gICAqICBFeGFtcGxlOiAnL3dpZGdldCdcbiAgICovXG4gIHJlYWRvbmx5IGNvbnRlbnREZXN0aW5hdGlvbkRpcmVjdG9yeTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiAgVGhlIHN1YiBkb21haW4gcHJlZml4IChpZTogaW1hZ2VzKVxuICAgKlxuICAgKiBAZGVmYXVsdCBnaXQgYnJhbmNoIG5hbWVcbiAgICovXG4gIHJlYWRvbmx5IHN1YkRvbWFpbj86IHN0cmluZztcblxuICAvKipcbiAgICogIFRoZSBmdWxsIGRvbWFpbiAoaWU6IHN0YWdpbmcuY29kZWRyaWZ0ZXJzLmNvbSlcbiAgICovXG4gIHJlYWRvbmx5IGZ1bGxEb21haW46IHN0cmluZztcbn1cblxuZXhwb3J0IGNsYXNzIFN0YXRpY0NvbnRlbnQgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogU3RhdGljQ29udGVudFByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIC8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAgICAgKlxuICAgICAqIEluaXRpYWwgU2V0dXBcbiAgICAgKlxuICAgICAqIFNldCBzb21lIGRlZmF1bHRzLCBidWlsZCBkb21haW4gaW5mb3JtYXRpb24uXG4gICAgICpcbiAgICAgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgICBjb25zdCB7XG4gICAgICBidWNrZXRBcm5QYXJhbU5hbWUsXG4gICAgICBjb250ZW50U291cmNlRGlyZWN0b3J5LFxuICAgICAgY29udGVudERlc3RpbmF0aW9uRGlyZWN0b3J5LFxuICAgICAgc3ViRG9tYWluLFxuICAgICAgZnVsbERvbWFpbixcbiAgICB9ID0ge1xuICAgICAgYnVja2V0QXJuUGFyYW1OYW1lOiBcIi9TVEFUSUNfV0VCU0lURS9CVUNLRVRfQVJOXCIsXG4gICAgICBzdWJEb21haW46IGZpbmRHaXRCcmFuY2goKSxcbiAgICAgIC4uLnByb3BzLFxuICAgIH07XG5cbiAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gICAgICpcbiAgICAgKiBJbXBvcnQgYW5kIGJ1aWxkIHNvbWUgdmFsdWVzIGZyb20gUGFyYW0gU3RvcmUgZHVyaW5nIGRlcGxveW1lbnQuXG4gICAgICpcbiAgICAgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgICBjb25zdCBrZXlQcmVmaXggPSBbcGFyYW1DYXNlKHN1YkRvbWFpbiksIGZ1bGxEb21haW5dLmpvaW4oXCIuXCIpO1xuXG4gICAgY29uc3QgYnVja2V0QXJuID0gU3RyaW5nUGFyYW1ldGVyLnZhbHVlRm9yU3RyaW5nUGFyYW1ldGVyKFxuICAgICAgdGhpcyxcbiAgICAgIGJ1Y2tldEFyblBhcmFtTmFtZSxcbiAgICApO1xuICAgIGNvbnN0IGJ1Y2tldCA9IEJ1Y2tldC5mcm9tQnVja2V0QXJuKHRoaXMsIFwiYnVja2V0XCIsIGJ1Y2tldEFybik7XG5cbiAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gICAgICpcbiAgICAgKiBHYXRoZXIgdGhlIHNvdXJjZXMgd2UnbGwgYmUgZGVwbG95aW5nLiBXZSBuZWVkIHRvIGhhdmUgYW4gZW1wdHkgc291cmNlXG4gICAgICogZm9yIHRlc3RzIHNpbmNlIGl0IHdpbGwgY2hhbmdlIGFsbCB0aGUgdGltZSBhbmQgYm9yayB1cCB0aGUgdGVzdFxuICAgICAqIHNuYXBzaG90cyBpZiB3ZSBkb24ndC5cbiAgICAgKlxuICAgICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAgIGNvbnN0IHNvdXJjZXMgPSBwcm9jZXNzLmVudi5KRVNUX1dPUktFUl9JRFxuICAgICAgPyBbXVxuICAgICAgOiBbU291cmNlLmFzc2V0KGNvbnRlbnRTb3VyY2VEaXJlY3RvcnkpXTtcblxuICAgIG5ldyBCdWNrZXREZXBsb3ltZW50KHRoaXMsIFwiZGVwbG95XCIsIHtcbiAgICAgIHNvdXJjZXMsXG4gICAgICBkZXN0aW5hdGlvbkJ1Y2tldDogYnVja2V0LFxuICAgICAgcmV0YWluT25EZWxldGU6IGZhbHNlLFxuICAgICAgZGVzdGluYXRpb25LZXlQcmVmaXg6IGAke2tleVByZWZpeH0ke2NvbnRlbnREZXN0aW5hdGlvbkRpcmVjdG9yeX1gLFxuICAgIH0pO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { StackProps } from "aws-cdk-lib";
|
|
2
|
+
import { HostedZoneAttributes } from "aws-cdk-lib/aws-route53";
|
|
3
|
+
import { Construct } from "constructs";
|
|
4
|
+
import { PrivateBucketProps } from "../s3/private-bucket";
|
|
5
|
+
export interface StaticDomainProps {
|
|
6
|
+
/**
|
|
7
|
+
* The sub domain prefix (ie: images)
|
|
8
|
+
*/
|
|
9
|
+
readonly subDomain: string;
|
|
10
|
+
/**
|
|
11
|
+
* The base domain (ie: codedrifters.com)
|
|
12
|
+
*/
|
|
13
|
+
readonly baseDomain: string;
|
|
14
|
+
/**
|
|
15
|
+
* Hosted zone ID for the base domain.
|
|
16
|
+
*/
|
|
17
|
+
readonly hostedZoneAttributes: HostedZoneAttributes;
|
|
18
|
+
}
|
|
19
|
+
export interface StaticHostingProps extends StackProps {
|
|
20
|
+
/**
|
|
21
|
+
* Values used to connect a domain name to the cloudfront distribution. If not
|
|
22
|
+
* supplied, cloudfront doesn't use a custom domain.
|
|
23
|
+
*/
|
|
24
|
+
readonly staticDomainProps?: StaticDomainProps;
|
|
25
|
+
/**
|
|
26
|
+
* Parameter name to use when storing the static hosting bucket's ARN.
|
|
27
|
+
* This is needed in other later steps when deploying hosted content to S3.
|
|
28
|
+
*/
|
|
29
|
+
readonly bucketArnParamName?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Parameter name to use when storing the CloudFront Distribution Domain Name.
|
|
32
|
+
*/
|
|
33
|
+
readonly distributionDomainParamName?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Parameter name to use when storing the CloudFront Distribution ID.
|
|
36
|
+
*/
|
|
37
|
+
readonly distributionIDParamName?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Props to pass to the private S3 bucket.
|
|
40
|
+
*/
|
|
41
|
+
readonly privateBucketProps?: PrivateBucketProps;
|
|
42
|
+
}
|
|
43
|
+
export declare class StaticHosting extends Construct {
|
|
44
|
+
/**
|
|
45
|
+
* Full domain name used as basis for hosting.
|
|
46
|
+
*/
|
|
47
|
+
readonly fullDomain: string;
|
|
48
|
+
constructor(scope: Construct, id: string, props?: StaticHostingProps);
|
|
49
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StaticHosting = void 0;
|
|
4
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
5
|
+
const aws_certificatemanager_1 = require("aws-cdk-lib/aws-certificatemanager");
|
|
6
|
+
const aws_cloudfront_1 = require("aws-cdk-lib/aws-cloudfront");
|
|
7
|
+
const aws_cloudfront_origins_1 = require("aws-cdk-lib/aws-cloudfront-origins");
|
|
8
|
+
const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
|
|
9
|
+
const aws_lambda_nodejs_1 = require("aws-cdk-lib/aws-lambda-nodejs");
|
|
10
|
+
const aws_logs_1 = require("aws-cdk-lib/aws-logs");
|
|
11
|
+
const aws_route53_1 = require("aws-cdk-lib/aws-route53");
|
|
12
|
+
const aws_route53_targets_1 = require("aws-cdk-lib/aws-route53-targets");
|
|
13
|
+
const aws_ssm_1 = require("aws-cdk-lib/aws-ssm");
|
|
14
|
+
const constructs_1 = require("constructs");
|
|
15
|
+
const private_bucket_1 = require("../s3/private-bucket");
|
|
16
|
+
class StaticHosting extends constructs_1.Construct {
|
|
17
|
+
constructor(scope, id, props = {}) {
|
|
18
|
+
super(scope, id);
|
|
19
|
+
/***************************************************************************
|
|
20
|
+
*
|
|
21
|
+
* Initial Setup
|
|
22
|
+
*
|
|
23
|
+
* Set some defaults, build domain information.
|
|
24
|
+
*
|
|
25
|
+
**************************************************************************/
|
|
26
|
+
const { bucketArnParamName, distributionDomainParamName, distributionIDParamName, staticDomainProps, privateBucketProps, } = {
|
|
27
|
+
bucketArnParamName: "/STATIC_WEBSITE/BUCKET_ARN",
|
|
28
|
+
distributionDomainParamName: "/STATIC_WEBSITE/DISTRIBUTION_DOMAIN",
|
|
29
|
+
distributionIDParamName: "/STATIC_WEBSITE/DISTRIBUTION_ID",
|
|
30
|
+
...props,
|
|
31
|
+
};
|
|
32
|
+
const { subDomain, baseDomain, hostedZoneAttributes } = staticDomainProps ?? {};
|
|
33
|
+
this.fullDomain = [subDomain, baseDomain].join(".");
|
|
34
|
+
/***************************************************************************
|
|
35
|
+
*
|
|
36
|
+
* PRIVATE BUCKET
|
|
37
|
+
*
|
|
38
|
+
* A bucket to store the files within.
|
|
39
|
+
* Save ARN for later deploys.
|
|
40
|
+
*
|
|
41
|
+
**************************************************************************/
|
|
42
|
+
const bucket = new private_bucket_1.PrivateBucket(this, "static-hosting-bucket", privateBucketProps);
|
|
43
|
+
/***************************************************************************
|
|
44
|
+
*
|
|
45
|
+
* DNS & Wildcard Certificate
|
|
46
|
+
*
|
|
47
|
+
* If a zone Id as passed in, find the hosted zone and create a wildcard
|
|
48
|
+
* certificate for the domain.
|
|
49
|
+
*
|
|
50
|
+
**************************************************************************/
|
|
51
|
+
let zone;
|
|
52
|
+
let certificate;
|
|
53
|
+
if (hostedZoneAttributes) {
|
|
54
|
+
zone = aws_route53_1.HostedZone.fromHostedZoneAttributes(this, "zone", hostedZoneAttributes);
|
|
55
|
+
certificate = new aws_certificatemanager_1.Certificate(this, "wildcard-certificate", {
|
|
56
|
+
domainName: `*.${this.fullDomain}`,
|
|
57
|
+
subjectAlternativeNames: [this.fullDomain],
|
|
58
|
+
validation: aws_certificatemanager_1.CertificateValidation.fromDnsMultiZone({
|
|
59
|
+
[`*.${this.fullDomain}`]: zone,
|
|
60
|
+
[this.fullDomain]: zone,
|
|
61
|
+
}),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/******************************************************************************
|
|
65
|
+
*
|
|
66
|
+
* LAMBDA@EDGE FUNCTION
|
|
67
|
+
*
|
|
68
|
+
* This handles rewriting the path from domain name.
|
|
69
|
+
*
|
|
70
|
+
*****************************************************************************/
|
|
71
|
+
const handler = new aws_lambda_nodejs_1.NodejsFunction(this, "viewer-request-handler", {
|
|
72
|
+
memorySize: 128,
|
|
73
|
+
runtime: aws_lambda_1.Runtime.NODEJS_24_X,
|
|
74
|
+
logGroup: new aws_logs_1.LogGroup(this, "viewer-request-handler-log-group", {
|
|
75
|
+
retention: aws_logs_1.RetentionDays.ONE_MONTH,
|
|
76
|
+
}),
|
|
77
|
+
});
|
|
78
|
+
/******************************************************************************
|
|
79
|
+
*
|
|
80
|
+
* CLOUDFRONT CONFIG
|
|
81
|
+
*
|
|
82
|
+
* Setup a CloudFront Distribution for the bucket.
|
|
83
|
+
*
|
|
84
|
+
*****************************************************************************/
|
|
85
|
+
const cachePolicy = new aws_cloudfront_1.CachePolicy(this, "cloudfront-policy", {
|
|
86
|
+
comment: "Relatively conservative TTL policy.",
|
|
87
|
+
maxTtl: aws_cdk_lib_1.Duration.seconds(300),
|
|
88
|
+
minTtl: aws_cdk_lib_1.Duration.seconds(0),
|
|
89
|
+
defaultTtl: aws_cdk_lib_1.Duration.seconds(60),
|
|
90
|
+
headerBehavior: aws_cloudfront_1.CacheHeaderBehavior.none(),
|
|
91
|
+
queryStringBehavior: aws_cloudfront_1.CacheQueryStringBehavior.none(),
|
|
92
|
+
cookieBehavior: aws_cloudfront_1.CacheCookieBehavior.none(),
|
|
93
|
+
enableAcceptEncodingGzip: true,
|
|
94
|
+
enableAcceptEncodingBrotli: true,
|
|
95
|
+
});
|
|
96
|
+
const oac = new aws_cloudfront_1.S3OriginAccessControl(this, "MyOAC", {
|
|
97
|
+
signing: aws_cloudfront_1.Signing.SIGV4_NO_OVERRIDE,
|
|
98
|
+
});
|
|
99
|
+
const origin = aws_cloudfront_origins_1.S3BucketOrigin.withOriginAccessControl(bucket, {
|
|
100
|
+
originAccessControl: oac,
|
|
101
|
+
originAccessLevels: [aws_cloudfront_1.AccessLevel.READ],
|
|
102
|
+
});
|
|
103
|
+
const distribution = new aws_cloudfront_1.Distribution(this, "cloudfront-distribution", {
|
|
104
|
+
comment: `Distribution for ${this.fullDomain}`,
|
|
105
|
+
/**
|
|
106
|
+
* Only if domain was supplied
|
|
107
|
+
*/
|
|
108
|
+
...(certificate
|
|
109
|
+
? {
|
|
110
|
+
certificate,
|
|
111
|
+
domainNames: [this.fullDomain, `*.${this.fullDomain}`],
|
|
112
|
+
}
|
|
113
|
+
: {}),
|
|
114
|
+
defaultBehavior: {
|
|
115
|
+
origin,
|
|
116
|
+
viewerProtocolPolicy: aws_cloudfront_1.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
117
|
+
cachePolicy,
|
|
118
|
+
allowedMethods: aws_cloudfront_1.AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
|
|
119
|
+
edgeLambdas: [
|
|
120
|
+
{
|
|
121
|
+
functionVersion: handler.currentVersion,
|
|
122
|
+
eventType: aws_cloudfront_1.LambdaEdgeEventType.VIEWER_REQUEST,
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
defaultRootObject: "index.html",
|
|
127
|
+
});
|
|
128
|
+
/***************************************************************************
|
|
129
|
+
*
|
|
130
|
+
* DNS ENTRY
|
|
131
|
+
*
|
|
132
|
+
* Link cloudfront to both the root fulldomain and all possible subdomains.
|
|
133
|
+
*
|
|
134
|
+
**************************************************************************/
|
|
135
|
+
if (zone) {
|
|
136
|
+
new aws_route53_1.ARecord(this, "root-dns-entry", {
|
|
137
|
+
zone,
|
|
138
|
+
recordName: subDomain,
|
|
139
|
+
target: aws_route53_1.RecordTarget.fromAlias(new aws_route53_targets_1.CloudFrontTarget(distribution)),
|
|
140
|
+
});
|
|
141
|
+
new aws_route53_1.ARecord(this, "wc-dns-entry", {
|
|
142
|
+
zone,
|
|
143
|
+
recordName: `*.${subDomain}`,
|
|
144
|
+
target: aws_route53_1.RecordTarget.fromAlias(new aws_route53_targets_1.CloudFrontTarget(distribution)),
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/***************************************************************************
|
|
148
|
+
*
|
|
149
|
+
* EXPORTS
|
|
150
|
+
*
|
|
151
|
+
* Used by content uploader later.
|
|
152
|
+
*
|
|
153
|
+
**************************************************************************/
|
|
154
|
+
new aws_ssm_1.StringParameter(this, "dist-domain", {
|
|
155
|
+
description: `GENERATED DO NOT CHANGE - CloudFront Distribution Details (${this.fullDomain}).`,
|
|
156
|
+
parameterName: distributionDomainParamName,
|
|
157
|
+
stringValue: distribution.domainName,
|
|
158
|
+
});
|
|
159
|
+
new aws_ssm_1.StringParameter(this, "dist-id", {
|
|
160
|
+
description: `GENERATED DO NOT CHANGE - CloudFront Distribution Details (${this.fullDomain}).`,
|
|
161
|
+
parameterName: distributionIDParamName,
|
|
162
|
+
stringValue: distribution.distributionId,
|
|
163
|
+
});
|
|
164
|
+
new aws_ssm_1.StringParameter(this, "bucket-arn", {
|
|
165
|
+
description: `GENERATED DO NOT CHANGE - S3 Bucket ARN for Static Website Hosting (${this.fullDomain}).`,
|
|
166
|
+
parameterName: bucketArnParamName,
|
|
167
|
+
stringValue: bucket.bucketArn,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
exports.StaticHosting = StaticHosting;
|
|
172
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGljLWhvc3RpbmcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RhdGljLWhvc3Rpbmcvc3RhdGljLWhvc3RpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNkNBQW1EO0FBQ25ELCtFQUc0QztBQUM1QywrREFZb0M7QUFDcEMsK0VBQW9FO0FBQ3BFLHVEQUFpRDtBQUNqRCxxRUFBK0Q7QUFDL0QsbURBQStEO0FBQy9ELHlEQU1pQztBQUNqQyx5RUFBbUU7QUFDbkUsaURBQXNEO0FBQ3RELDJDQUF1QztBQUN2Qyx5REFBeUU7QUFnRHpFLE1BQWEsYUFBYyxTQUFRLHNCQUFTO0lBTTFDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsUUFBNEIsRUFBRTtRQUN0RSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCOzs7Ozs7b0ZBTTRFO1FBRTVFLE1BQU0sRUFDSixrQkFBa0IsRUFDbEIsMkJBQTJCLEVBQzNCLHVCQUF1QixFQUN2QixpQkFBaUIsRUFDakIsa0JBQWtCLEdBQ25CLEdBQUc7WUFDRixrQkFBa0IsRUFBRSw0QkFBNEI7WUFDaEQsMkJBQTJCLEVBQUUscUNBQXFDO1lBQ2xFLHVCQUF1QixFQUFFLGlDQUFpQztZQUMxRCxHQUFHLEtBQUs7U0FDVCxDQUFDO1FBRUYsTUFBTSxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsb0JBQW9CLEVBQUUsR0FDbkQsaUJBQWlCLElBQUksRUFBRSxDQUFDO1FBQzFCLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBRXBEOzs7Ozs7O29GQU80RTtRQUU1RSxNQUFNLE1BQU0sR0FBRyxJQUFJLDhCQUFhLENBQzlCLElBQUksRUFDSix1QkFBdUIsRUFDdkIsa0JBQWtCLENBQ25CLENBQUM7UUFFRjs7Ozs7OztvRkFPNEU7UUFFNUUsSUFBSSxJQUE2QixD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LENBQUMsU0FBUztTQUM5QixDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0Y7QUFyTUQsc0NBcU1DIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRHVyYXRpb24sIFN0YWNrUHJvcHMgfSBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB7XG4gIENlcnRpZmljYXRlLFxuICBDZXJ0aWZpY2F0ZVZhbGlkYXRpb24sXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2VydGlmaWNhdGVtYW5hZ2VyXCI7XG5pbXBvcnQge1xuICBBY2Nlc3NMZXZlbCxcbiAgQWxsb3dlZE1ldGhvZHMsXG4gIENhY2hlQ29va2llQmVoYXZpb3IsXG4gIENhY2hlSGVhZGVyQmVoYXZpb3IsXG4gIENhY2hlUG9saWN5LFxuICBDYWNoZVF1ZXJ5U3RyaW5nQmVoYXZpb3IsXG4gIERpc3RyaWJ1dGlvbixcbiAgTGFtYmRhRWRnZUV2ZW50VHlwZSxcbiAgUzNPcmlnaW5BY2Nlc3NDb250cm9sLFxuICBTaWduaW5nLFxuICBWaWV3ZXJQcm90b2NvbFBvbGljeSxcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1jbG91ZGZyb250XCI7XG5pbXBvcnQgeyBTM0J1Y2tldE9yaWdpbiB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2xvdWRmcm9udC1vcmlnaW5zXCI7XG5pbXBvcnQgeyBSdW50aW1lIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1sYW1iZGFcIjtcbmltcG9ydCB7IE5vZGVqc0Z1bmN0aW9uIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1sYW1iZGEtbm9kZWpzXCI7XG5pbXBvcnQgeyBMb2dHcm91cCwgUmV0ZW50aW9uRGF5cyB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtbG9nc1wiO1xuaW1wb3J0IHtcbiAgQVJlY29yZCxcbiAgSG9zdGVkWm9uZSxcbiAgSG9zdGVkWm9uZUF0dHJpYnV0ZXMsXG4gIElIb3N0ZWRab25lLFxuICBSZWNvcmRUYXJnZXQsXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3Mtcm91dGU1M1wiO1xuaW1wb3J0IHsgQ2xvdWRGcm9udFRhcmdldCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3Mtcm91dGU1My10YXJnZXRzXCI7XG5pbXBvcnQgeyBTdHJpbmdQYXJhbWV0ZXIgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXNzbVwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IFByaXZhdGVCdWNrZXQsIFByaXZhdGVCdWNrZXRQcm9wcyB9IGZyb20gXCIuLi9zMy9wcml2YXRlLWJ1Y2tldFwiO1xuXG5leHBvcnQgaW50ZXJmYWNlIFN0YXRpY0RvbWFpblByb3BzIHtcbiAgLyoqXG4gICAqICBUaGUgc3ViIGRvbWFpbiBwcmVmaXggKGllOiBpbWFnZXMpXG4gICAqL1xuICByZWFkb25seSBzdWJEb21haW46IHN0cmluZztcblxuICAvKipcbiAgICogIFRoZSBiYXNlIGRvbWFpbiAoaWU6IGNvZGVkcmlmdGVycy5jb20pXG4gICAqL1xuICByZWFkb25seSBiYXNlRG9tYWluOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEhvc3RlZCB6b25lIElEIGZvciB0aGUgYmFzZSBkb21haW4uXG4gICAqL1xuICByZWFkb25seSBob3N0ZWRab25lQXR0cmlidXRlczogSG9zdGVkWm9uZUF0dHJpYnV0ZXM7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3RhdGljSG9zdGluZ1Byb3BzIGV4dGVuZHMgU3RhY2tQcm9wcyB7XG4gIC8qKlxuICAgKiBWYWx1ZXMgdXNlZCB0byBjb25uZWN0IGEgZG9tYWluIG5hbWUgdG8gdGhlIGNsb3VkZnJvbnQgZGlzdHJpYnV0aW9uLiBJZiBub3RcbiAgICogc3VwcGxpZWQsIGNsb3VkZnJvbnQgZG9lc24ndCB1c2UgYSBjdXN0b20gZG9tYWluLlxuICAgKi9cbiAgcmVhZG9ubHkgc3RhdGljRG9tYWluUHJvcHM/OiBTdGF0aWNEb21haW5Qcm9wcztcblxuICAvKipcbiAgICogUGFyYW1ldGVyIG5hbWUgdG8gdXNlIHdoZW4gc3RvcmluZyB0aGUgc3RhdGljIGhvc3RpbmcgYnVja2V0J3MgQVJOLlxuICAgKiBUaGlzIGlzIG5lZWRlZCBpbiBvdGhlciBsYXRlciBzdGVwcyB3aGVuIGRlcGxveWluZyBob3N0ZWQgY29udGVudCB0byBTMy5cbiAgICovXG4gIHJlYWRvbmx5IGJ1Y2tldEFyblBhcmFtTmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogUGFyYW1ldGVyIG5hbWUgdG8gdXNlIHdoZW4gc3RvcmluZyB0aGUgQ2xvdWRGcm9udCBEaXN0cmlidXRpb24gRG9tYWluIE5hbWUuXG4gICAqL1xuICByZWFkb25seSBkaXN0cmlidXRpb25Eb21haW5QYXJhbU5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFBhcmFtZXRlciBuYW1lIHRvIHVzZSB3aGVuIHN0b3JpbmcgdGhlIENsb3VkRnJvbnQgRGlzdHJpYnV0aW9uIElELlxuICAgKi9cbiAgcmVhZG9ubHkgZGlzdHJpYnV0aW9uSURQYXJhbU5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFByb3BzIHRvIHBhc3MgdG8gdGhlIHByaXZhdGUgUzMgYnVja2V0LlxuICAgKi9cbiAgcmVhZG9ubHkgcHJpdmF0ZUJ1Y2tldFByb3BzPzogUHJpdmF0ZUJ1Y2tldFByb3BzO1xufVxuXG5leHBvcnQgY2xhc3MgU3RhdGljSG9zdGluZyBleHRlbmRzIENvbnN0cnVjdCB7XG4gIC8qKlxuICAgKiBGdWxsIGRvbWFpbiBuYW1lIHVzZWQgYXMgYmFzaXMgZm9yIGhvc3RpbmcuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZnVsbERvbWFpbjogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBTdGF0aWNIb3N0aW5nUHJvcHMgPSB7fSkge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gICAgICpcbiAgICAgKiBJbml0aWFsIFNldHVwXG4gICAgICpcbiAgICAgKiBTZXQgc29tZSBkZWZhdWx0cywgYnVpbGQgZG9tYWluIGluZm9ybWF0aW9uLlxuICAgICAqXG4gICAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gICAgY29uc3Qge1xuICAgICAgYnVja2V0QXJuUGFyYW1OYW1lLFxuICAgICAgZGlzdHJpYnV0aW9uRG9tYWluUGFyYW1OYW1lLFxuICAgICAgZGlzdHJpYnV0aW9uSURQYXJhbU5hbWUsXG4gICAgICBzdGF0aWNEb21haW5Qcm9wcyxcbiAgICAgIHByaXZhdGVCdWNrZXRQcm9wcyxcbiAgICB9ID0ge1xuICAgICAgYnVja2V0QXJuUGFyYW1OYW1lOiBcIi9TVEFUSUNfV0VCU0lURS9CVUNLRVRfQVJOXCIsXG4gICAgICBkaXN0cmlidXRpb25Eb21haW5QYXJhbU5hbWU6IFwiL1NUQVRJQ19XRUJTSVRFL0RJU1RSSUJVVElPTl9ET01BSU5cIixcbiAgICAgIGRpc3RyaWJ1dGlvbklEUGFyYW1OYW1lOiBcIi9TVEFUSUNfV0VCU0lURS9ESVNUUklCVVRJT05fSURcIixcbiAgICAgIC4uLnByb3BzLFxuICAgIH07XG5cbiAgICBjb25zdCB7IHN1YkRvbWFpbiwgYmFzZURvbWFpbiwgaG9zdGVkWm9uZUF0dHJpYnV0ZXMgfSA9XG4gICAgICBzdGF0aWNEb21haW5Qcm9wcyA/PyB7fTtcbiAgICB0aGlzLmZ1bGxEb21haW4gPSBbc3ViRG9tYWluLCBiYXNlRG9tYWluXS5qb2luKFwiLlwiKTtcblxuICAgIC8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAgICAgKlxuICAgICAqIFBSSVZBVEUgQlVDS0VUXG4gICAgICpcbiAgICAgKiBBIGJ1Y2tldCB0byBzdG9yZSB0aGUgZmlsZXMgd2l0aGluLlxuICAgICAqIFNhdmUgQVJOIGZvciBsYXRlciBkZXBsb3lzLlxuICAgICAqXG4gICAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gICAgY29uc3QgYnVja2V0ID0gbmV3IFByaXZhdGVCdWNrZXQoXG4gICAgICB0aGlzLFxuICAgICAgXCJzdGF0aWMtaG9zdGluZy1idWNrZXRcIixcbiAgICAgIHByaXZhdGVCdWNrZXRQcm9wcyxcbiAgICApO1xuXG4gICAgLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICAgICAqXG4gICAgICogRE5TICYgV2lsZGNhcmQgQ2VydGlmaWNhdGVcbiAgICAgKlxuICAgICAqIElmIGEgem9uZSBJZCBhcyBwYXNzZWQgaW4sIGZpbmQgdGhlIGhvc3RlZCB6b25lIGFuZCBjcmVhdGUgYSB3aWxkY2FyZFxuICAgICAqIGNlcnRpZmljYXRlIGZvciB0aGUgZG9tYWluLlxuICAgICAqXG4gICAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gICAgbGV0IHpvbmU6IElIb3N0ZWRab25lIHwgdW5kZWZpbmVkO1xuICAgIGxldCBjZXJ0aWZpY2F0ZTogQ2VydGlmaWNhdGUgfCB1bmRlZmluZWQ7XG5cbiAgICBpZiAoaG9zdGVkWm9uZUF0dHJpYnV0ZXMpIHtcbiAgICAgIHpvbmUgPSBIb3N0ZWRab25lLmZyb21Ib3N0ZWRab25lQXR0cmlidXRlcyhcbiAgICAgICAgdGhpcyxcbiAgICAgICAgXCJ6b25lXCIsXG4gICAgICAgIGhvc3RlZFpvbmVBdHRyaWJ1dGVzLFxuICAgICAgKTtcbiAgICAgIGNlcnRpZmljYXRlID0gbmV3IENlcnRpZmljYXRlKHRoaXMsIFwid2lsZGNhcmQtY2VydGlmaWNhdGVcIiwge1xuICAgICAgICBkb21haW5OYW1lOiBgKi4ke3RoaXMuZnVsbERvbWFpbn1gLFxuICAgICAgICBzdWJqZWN0QWx0ZXJuYXRpdmVOYW1lczogW3RoaXMuZnVsbERvbWFpbl0sXG4gICAgICAgIHZhbGlkYXRpb246IENlcnRpZmljYXRlVmFsaWRhdGlvbi5mcm9tRG5zTXVsdGlab25lKHtcbiAgICAgICAgICBbYCouJHt0aGlzLmZ1bGxEb21haW59YF06IHpvbmUsXG4gICAgICAgICAgW3RoaXMuZnVsbERvbWFpbl06IHpvbmUsXG4gICAgICAgIH0pLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICAgICAqXG4gICAgICogTEFNQkRBQEVER0UgRlVOQ1RJT05cbiAgICAgKlxuICAgICAqIFRoaXMgaGFuZGxlcyByZXdyaXRpbmcgdGhlIHBhdGggZnJvbSBkb21haW4gbmFtZS5cbiAgICAgKlxuICAgICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAgIGNvbnN0IGhhbmRsZXIgPSBuZXcgTm9kZWpzRnVuY3Rpb24odGhpcywgXCJ2aWV3ZXItcmVxdWVzdC1oYW5kbGVyXCIsIHtcbiAgICAgIG1lbW9yeVNpemU6IDEyOCxcbiAgICAgIHJ1bnRpbWU6IFJ1bnRpbWUuTk9ERUpTXzI0X1gsXG4gICAgICBsb2dHcm91cDogbmV3IExvZ0dyb3VwKHRoaXMsIFwidmlld2VyLXJlcXVlc3QtaGFuZGxlci1sb2ctZ3JvdXBcIiwge1xuICAgICAgICByZXRlbnRpb246IFJldGVudGlvbkRheXMuT05FX01PTlRILFxuICAgICAgfSksXG4gICAgfSk7XG5cbiAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gICAgICpcbiAgICAgKiAgQ0xPVURGUk9OVCBDT05GSUdcbiAgICAgKlxuICAgICAqICBTZXR1cCBhIENsb3VkRnJvbnQgRGlzdHJpYnV0aW9uIGZvciB0aGUgYnVja2V0LlxuICAgICAqXG4gICAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gICAgY29uc3QgY2FjaGVQb2xpY3kgPSBuZXcgQ2FjaGVQb2xpY3kodGhpcywgXCJjbG91ZGZyb250LXBvbGljeVwiLCB7XG4gICAgICBjb21tZW50OiBcIlJlbGF0aXZlbHkgY29uc2VydmF0aXZlIFRUTCBwb2xpY3kuXCIsXG4gICAgICBtYXhUdGw6IER1cmF0aW9uLnNlY29uZHMoMzAwKSxcbiAgICAgIG1pblR0bDogRHVyYXRpb24uc2Vjb25kcygwKSxcbiAgICAgIGRlZmF1bHRUdGw6IER1cmF0aW9uLnNlY29uZHMoNjApLFxuICAgICAgaGVhZGVyQmVoYXZpb3I6IENhY2hlSGVhZGVyQmVoYXZpb3Iubm9uZSgpLFxuICAgICAgcXVlcnlTdHJpbmdCZWhhdmlvcjogQ2FjaGVRdWVyeVN0cmluZ0JlaGF2aW9yLm5vbmUoKSxcbiAgICAgIGNvb2tpZUJlaGF2aW9yOiBDYWNoZUNvb2tpZUJlaGF2aW9yLm5vbmUoKSxcbiAgICAgIGVuYWJsZUFjY2VwdEVuY29kaW5nR3ppcDogdHJ1ZSxcbiAgICAgIGVuYWJsZUFjY2VwdEVuY29kaW5nQnJvdGxpOiB0cnVlLFxuICAgIH0pO1xuXG4gICAgY29uc3Qgb2FjID0gbmV3IFMzT3JpZ2luQWNjZXNzQ29udHJvbCh0aGlzLCBcIk15T0FDXCIsIHtcbiAgICAgIHNpZ25pbmc6IFNpZ25pbmcuU0lHVjRfTk9fT1ZFUlJJREUsXG4gICAgfSk7XG4gICAgY29uc3Qgb3JpZ2luID0gUzNCdWNrZXRPcmlnaW4ud2l0aE9yaWdpbkFjY2Vzc0NvbnRyb2woYnVja2V0LCB7XG4gICAgICBvcmlnaW5BY2Nlc3NDb250cm9sOiBvYWMsXG4gICAgICBvcmlnaW5BY2Nlc3NMZXZlbHM6IFtBY2Nlc3NMZXZlbC5SRUFEXSxcbiAgICB9KTtcblxuICAgIGNvbnN0IGRpc3RyaWJ1dGlvbiA9IG5ldyBEaXN0cmlidXRpb24odGhpcywgXCJjbG91ZGZyb250LWRpc3RyaWJ1dGlvblwiLCB7XG4gICAgICBjb21tZW50OiBgRGlzdHJpYnV0aW9uIGZvciAke3RoaXMuZnVsbERvbWFpbn1gLFxuXG4gICAgICAvKipcbiAgICAgICAqIE9ubHkgaWYgZG9tYWluIHdhcyBzdXBwbGllZFxuICAgICAgICovXG4gICAgICAuLi4oY2VydGlmaWNhdGVcbiAgICAgICAgPyB7XG4gICAgICAgICAgICBjZXJ0aWZpY2F0ZSxcbiAgICAgICAgICAgIGRvbWFpbk5hbWVzOiBbdGhpcy5mdWxsRG9tYWluLCBgKi4ke3RoaXMuZnVsbERvbWFpbn1gXSxcbiAgICAgICAgICB9XG4gICAgICAgIDoge30pLFxuXG4gICAgICBkZWZhdWx0QmVoYXZpb3I6IHtcbiAgICAgICAgb3JpZ2luLFxuICAgICAgICB2aWV3ZXJQcm90b2NvbFBvbGljeTogVmlld2VyUHJvdG9jb2xQb2xpY3kuUkVESVJFQ1RfVE9fSFRUUFMsXG4gICAgICAgIGNhY2hlUG9saWN5LFxuICAgICAgICBhbGxvd2VkTWV0aG9kczogQWxsb3dlZE1ldGhvZHMuQUxMT1dfR0VUX0hFQURfT1BUSU9OUyxcbiAgICAgICAgZWRnZUxhbWJkYXM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBmdW5jdGlvblZlcnNpb246IGhhbmRsZXIuY3VycmVudFZlcnNpb24sXG4gICAgICAgICAgICBldmVudFR5cGU6IExhbWJkYUVkZ2VFdmVudFR5cGUuVklFV0VSX1JFUVVFU1QsXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0sXG4gICAgICBkZWZhdWx0Um9vdE9iamVjdDogXCJpbmRleC5odG1sXCIsXG4gICAgfSk7XG5cbiAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gICAgICpcbiAgICAgKiAgRE5TIEVOVFJZXG4gICAgICpcbiAgICAgKiBMaW5rIGNsb3VkZnJvbnQgdG8gYm90aCB0aGUgcm9vdCBmdWxsZG9tYWluIGFuZCBhbGwgcG9zc2libGUgc3ViZG9tYWlucy5cbiAgICAgKlxuICAgICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAgIGlmICh6b25lKSB7XG4gICAgICBuZXcgQVJlY29yZCh0aGlzLCBcInJvb3QtZG5zLWVudHJ5XCIsIHtcbiAgICAgICAgem9uZSxcbiAgICAgICAgcmVjb3JkTmFtZTogc3ViRG9tYWluLFxuICAgICAgICB0YXJnZXQ6IFJlY29yZFRhcmdldC5mcm9tQWxpYXMobmV3IENsb3VkRnJvbnRUYXJnZXQoZGlzdHJpYnV0aW9uKSksXG4gICAgICB9KTtcblxuICAgICAgbmV3IEFSZWNvcmQodGhpcywgXCJ3Yy1kbnMtZW50cnlcIiwge1xuICAgICAgICB6b25lLFxuICAgICAgICByZWNvcmROYW1lOiBgKi4ke3N1YkRvbWFpbn1gLFxuICAgICAgICB0YXJnZXQ6IFJlY29yZFRhcmdldC5mcm9tQWxpYXMobmV3IENsb3VkRnJvbnRUYXJnZXQoZGlzdHJpYnV0aW9uKSksXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gICAgICpcbiAgICAgKiBFWFBPUlRTXG4gICAgICpcbiAgICAgKiBVc2VkIGJ5IGNvbnRlbnQgdXBsb2FkZXIgbGF0ZXIuXG4gICAgICpcbiAgICAgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgICBuZXcgU3RyaW5nUGFyYW1ldGVyKHRoaXMsIFwiZGlzdC1kb21haW5cIiwge1xuICAgICAgZGVzY3JpcHRpb246IGBHRU5FUkFURUQgRE8gTk9UIENIQU5HRSAtIENsb3VkRnJvbnQgRGlzdHJpYnV0aW9uIERldGFpbHMgKCR7dGhpcy5mdWxsRG9tYWlufSkuYCxcbiAgICAgIHBhcmFtZXRlck5hbWU6IGRpc3RyaWJ1dGlvbkRvbWFpblBhcmFtTmFtZSxcbiAgICAgIHN0cmluZ1ZhbHVlOiBkaXN0cmlidXRpb24uZG9tYWluTmFtZSxcbiAgICB9KTtcblxuICAgIG5ldyBTdHJpbmdQYXJhbWV0ZXIodGhpcywgXCJkaXN0LWlkXCIsIHtcbiAgICAgIGRlc2NyaXB0aW9uOiBgR0VORVJBVEVEIERPIE5PVCBDSEFOR0UgLSBDbG91ZEZyb250IERpc3RyaWJ1dGlvbiBEZXRhaWxzICgke3RoaXMuZnVsbERvbWFpbn0pLmAsXG4gICAgICBwYXJhbWV0ZXJOYW1lOiBkaXN0cmlidXRpb25JRFBhcmFtTmFtZSxcbiAgICAgIHN0cmluZ1ZhbHVlOiBkaXN0cmlidXRpb24uZGlzdHJpYnV0aW9uSWQsXG4gICAgfSk7XG5cbiAgICBuZXcgU3RyaW5nUGFyYW1ldGVyKHRoaXMsIFwiYnVja2V0LWFyblwiLCB7XG4gICAgICBkZXNjcmlwdGlvbjogYEdFTkVSQVRFRCBETyBOT1QgQ0hBTkdFIC0gUzMgQnVja2V0IEFSTiBmb3IgU3RhdGljIFdlYnNpdGUgSG9zdGluZyAoJHt0aGlzLmZ1bGxEb21haW59KS5gLFxuICAgICAgcGFyYW1ldGVyTmFtZTogYnVja2V0QXJuUGFyYW1OYW1lLFxuICAgICAgc3RyaW5nVmFsdWU6IGJ1Y2tldC5idWNrZXRBcm4sXG4gICAgfSk7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { CloudFrontRequest, CloudFrontRequestEvent } from "aws-lambda";
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* Viewer Request Handler
|
|
5
|
+
*
|
|
6
|
+
* Handles requests at the CloudFront viewer request stage.
|
|
7
|
+
*
|
|
8
|
+
* - Logs the request
|
|
9
|
+
* - Adds default document if needed
|
|
10
|
+
* - Prepends folder with domain
|
|
11
|
+
*
|
|
12
|
+
* @param event CloudFrontRequestEvent
|
|
13
|
+
* @returns CloudFrontRequest
|
|
14
|
+
*/
|
|
15
|
+
export declare const handler: (event: CloudFrontRequestEvent) => Promise<CloudFrontRequest>;
|
|
16
|
+
/**
|
|
17
|
+
* This is a helper used in the main handler. It's split into it's own export
|
|
18
|
+
* to make testing easier.
|
|
19
|
+
*
|
|
20
|
+
* Adds default document to request URI if needed.
|
|
21
|
+
*
|
|
22
|
+
* @param request
|
|
23
|
+
* @returns
|
|
24
|
+
*/
|
|
25
|
+
export declare const addDefaultDocument: (request: CloudFrontRequest) => CloudFrontRequest;
|
|
26
|
+
/**
|
|
27
|
+
* This is a helper used in the main handler. It's split into it's own export
|
|
28
|
+
* to make testing easier.
|
|
29
|
+
*
|
|
30
|
+
* Adds domain folder to request URI.
|
|
31
|
+
*
|
|
32
|
+
* @param request
|
|
33
|
+
* @returns
|
|
34
|
+
*/
|
|
35
|
+
export declare const addDomainFolder: (request: CloudFrontRequest) => CloudFrontRequest;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addDomainFolder = exports.addDefaultDocument = exports.handler = void 0;
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* Viewer Request Handler
|
|
7
|
+
*
|
|
8
|
+
* Handles requests at the CloudFront viewer request stage.
|
|
9
|
+
*
|
|
10
|
+
* - Logs the request
|
|
11
|
+
* - Adds default document if needed
|
|
12
|
+
* - Prepends folder with domain
|
|
13
|
+
*
|
|
14
|
+
* @param event CloudFrontRequestEvent
|
|
15
|
+
* @returns CloudFrontRequest
|
|
16
|
+
*/
|
|
17
|
+
const handler = async (event) => {
|
|
18
|
+
// log request
|
|
19
|
+
if (process.env.JEST_WORKER_ID === undefined) {
|
|
20
|
+
console.log("Request Event: ", JSON.stringify(event, null, 2));
|
|
21
|
+
}
|
|
22
|
+
let request = event.Records[0].cf.request;
|
|
23
|
+
// add index if needed
|
|
24
|
+
request = (0, exports.addDefaultDocument)(request);
|
|
25
|
+
// prepend folder with domain
|
|
26
|
+
request = (0, exports.addDomainFolder)(request);
|
|
27
|
+
if (process.env.JEST_WORKER_ID === undefined) {
|
|
28
|
+
console.log("Resulting Request: ", JSON.stringify(request, null, 2));
|
|
29
|
+
}
|
|
30
|
+
// return body
|
|
31
|
+
return request;
|
|
32
|
+
};
|
|
33
|
+
exports.handler = handler;
|
|
34
|
+
/**
|
|
35
|
+
* This is a helper used in the main handler. It's split into it's own export
|
|
36
|
+
* to make testing easier.
|
|
37
|
+
*
|
|
38
|
+
* Adds default document to request URI if needed.
|
|
39
|
+
*
|
|
40
|
+
* @param request
|
|
41
|
+
* @returns
|
|
42
|
+
*/
|
|
43
|
+
const addDefaultDocument = (request) => {
|
|
44
|
+
if (request.uri !== "/") {
|
|
45
|
+
let paths = request.uri.split("/");
|
|
46
|
+
let lastPath = paths[paths.length - 1];
|
|
47
|
+
let isFile = lastPath.split(".").length > 1;
|
|
48
|
+
if (!isFile) {
|
|
49
|
+
if (lastPath != "") {
|
|
50
|
+
request.uri += "/";
|
|
51
|
+
}
|
|
52
|
+
request.uri += "index.html";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
request.uri = "/index.html";
|
|
57
|
+
}
|
|
58
|
+
return request;
|
|
59
|
+
};
|
|
60
|
+
exports.addDefaultDocument = addDefaultDocument;
|
|
61
|
+
/**
|
|
62
|
+
* This is a helper used in the main handler. It's split into it's own export
|
|
63
|
+
* to make testing easier.
|
|
64
|
+
*
|
|
65
|
+
* Adds domain folder to request URI.
|
|
66
|
+
*
|
|
67
|
+
* @param request
|
|
68
|
+
* @returns
|
|
69
|
+
*/
|
|
70
|
+
const addDomainFolder = (request) => {
|
|
71
|
+
const hostHeader = request.headers.host[0].value;
|
|
72
|
+
request.uri = `/${hostHeader}${request.uri}`;
|
|
73
|
+
return request;
|
|
74
|
+
};
|
|
75
|
+
exports.addDomainFolder = addDomainFolder;
|
|
76
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGljLWhvc3Rpbmcudmlld2VyLXJlcXVlc3QtaGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdGF0aWMtaG9zdGluZy9zdGF0aWMtaG9zdGluZy52aWV3ZXItcmVxdWVzdC1oYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBOzs7Ozs7Ozs7Ozs7R0FZRztBQUNJLE1BQU0sT0FBTyxHQUFHLEtBQUssRUFDMUIsS0FBNkIsRUFDRCxFQUFFO0lBQzlCLGNBQWM7SUFDZCxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQzdDLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDakUsQ0FBQztJQUVELElBQUksT0FBTyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQztJQUUxQyxzQkFBc0I7SUFDdEIsT0FBTyxHQUFHLElBQUEsMEJBQWtCLEVBQUMsT0FBTyxDQUFDLENBQUM7SUFFdEMsNkJBQTZCO0lBQzdCLE9BQU8sR0FBRyxJQUFBLHVCQUFlLEVBQUMsT0FBTyxDQUFDLENBQUM7SUFFbkMsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUM3QyxPQUFPLENBQUMsR0FBRyxDQUFDLHFCQUFxQixFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3ZFLENBQUM7SUFFRCxjQUFjO0lBQ2QsT0FBTyxPQUFPLENBQUM7QUFDakIsQ0FBQyxDQUFDO0FBdEJXLFFBQUEsT0FBTyxXQXNCbEI7QUFFRjs7Ozs7Ozs7R0FRRztBQUNJLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxPQUEwQixFQUFFLEVBQUU7SUFDL0QsSUFBSSxPQUFPLENBQUMsR0FBRyxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBQ3hCLElBQUksS0FBSyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ25DLElBQUksUUFBUSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ3ZDLElBQUksTUFBTSxHQUFHLFFBQVEsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztRQUU1QyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDWixJQUFJLFFBQVEsSUFBSSxFQUFFLEVBQUUsQ0FBQztnQkFDbkIsT0FBTyxDQUFDLEdBQUcsSUFBSSxHQUFHLENBQUM7WUFDckIsQ0FBQztZQUNELE9BQU8sQ0FBQyxHQUFHLElBQUksWUFBWSxDQUFDO1FBQzlCLENBQUM7SUFDSCxDQUFDO1NBQU0sQ0FBQztRQUNOLE9BQU8sQ0FBQyxHQUFHLEdBQUcsYUFBYSxDQUFDO0lBQzlCLENBQUM7SUFFRCxPQUFPLE9BQU8sQ0FBQztBQUNqQixDQUFDLENBQUM7QUFqQlcsUUFBQSxrQkFBa0Isc0JBaUI3QjtBQUVGOzs7Ozs7OztHQVFHO0FBQ0ksTUFBTSxlQUFlLEdBQUcsQ0FBQyxPQUEwQixFQUFFLEVBQUU7SUFDNUQsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQ2pELE9BQU8sQ0FBQyxHQUFHLEdBQUcsSUFBSSxVQUFVLEdBQUcsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQzdDLE9BQU8sT0FBTyxDQUFDO0FBQ2pCLENBQUMsQ0FBQztBQUpXLFFBQUEsZUFBZSxtQkFJMUIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDbG91ZEZyb250UmVxdWVzdCwgQ2xvdWRGcm9udFJlcXVlc3RFdmVudCB9IGZyb20gXCJhd3MtbGFtYmRhXCI7XG5cbi8qKlxuICpcbiAqIFZpZXdlciBSZXF1ZXN0IEhhbmRsZXJcbiAqXG4gKiBIYW5kbGVzIHJlcXVlc3RzIGF0IHRoZSBDbG91ZEZyb250IHZpZXdlciByZXF1ZXN0IHN0YWdlLlxuICpcbiAqIC0gTG9ncyB0aGUgcmVxdWVzdFxuICogLSBBZGRzIGRlZmF1bHQgZG9jdW1lbnQgaWYgbmVlZGVkXG4gKiAtIFByZXBlbmRzIGZvbGRlciB3aXRoIGRvbWFpblxuICpcbiAqIEBwYXJhbSBldmVudCBDbG91ZEZyb250UmVxdWVzdEV2ZW50XG4gKiBAcmV0dXJucyBDbG91ZEZyb250UmVxdWVzdFxuICovXG5leHBvcnQgY29uc3QgaGFuZGxlciA9IGFzeW5jIChcbiAgZXZlbnQ6IENsb3VkRnJvbnRSZXF1ZXN0RXZlbnQsXG4pOiBQcm9taXNlPENsb3VkRnJvbnRSZXF1ZXN0PiA9PiB7XG4gIC8vIGxvZyByZXF1ZXN0XG4gIGlmIChwcm9jZXNzLmVudi5KRVNUX1dPUktFUl9JRCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc29sZS5sb2coXCJSZXF1ZXN0IEV2ZW50OiBcIiwgSlNPTi5zdHJpbmdpZnkoZXZlbnQsIG51bGwsIDIpKTtcbiAgfVxuXG4gIGxldCByZXF1ZXN0ID0gZXZlbnQuUmVjb3Jkc1swXS5jZi5yZXF1ZXN0O1xuXG4gIC8vIGFkZCBpbmRleCBpZiBuZWVkZWRcbiAgcmVxdWVzdCA9IGFkZERlZmF1bHREb2N1bWVudChyZXF1ZXN0KTtcblxuICAvLyBwcmVwZW5kIGZvbGRlciB3aXRoIGRvbWFpblxuICByZXF1ZXN0ID0gYWRkRG9tYWluRm9sZGVyKHJlcXVlc3QpO1xuXG4gIGlmIChwcm9jZXNzLmVudi5KRVNUX1dPUktFUl9JRCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc29sZS5sb2coXCJSZXN1bHRpbmcgUmVxdWVzdDogXCIsIEpTT04uc3RyaW5naWZ5KHJlcXVlc3QsIG51bGwsIDIpKTtcbiAgfVxuXG4gIC8vIHJldHVybiBib2R5XG4gIHJldHVybiByZXF1ZXN0O1xufTtcblxuLyoqXG4gKiBUaGlzIGlzIGEgaGVscGVyIHVzZWQgaW4gdGhlIG1haW4gaGFuZGxlci4gSXQncyBzcGxpdCBpbnRvIGl0J3Mgb3duIGV4cG9ydFxuICogdG8gbWFrZSB0ZXN0aW5nIGVhc2llci5cbiAqXG4gKiBBZGRzIGRlZmF1bHQgZG9jdW1lbnQgdG8gcmVxdWVzdCBVUkkgaWYgbmVlZGVkLlxuICpcbiAqIEBwYXJhbSByZXF1ZXN0XG4gKiBAcmV0dXJuc1xuICovXG5leHBvcnQgY29uc3QgYWRkRGVmYXVsdERvY3VtZW50ID0gKHJlcXVlc3Q6IENsb3VkRnJvbnRSZXF1ZXN0KSA9PiB7XG4gIGlmIChyZXF1ZXN0LnVyaSAhPT0gXCIvXCIpIHtcbiAgICBsZXQgcGF0aHMgPSByZXF1ZXN0LnVyaS5zcGxpdChcIi9cIik7XG4gICAgbGV0IGxhc3RQYXRoID0gcGF0aHNbcGF0aHMubGVuZ3RoIC0gMV07XG4gICAgbGV0IGlzRmlsZSA9IGxhc3RQYXRoLnNwbGl0KFwiLlwiKS5sZW5ndGggPiAxO1xuXG4gICAgaWYgKCFpc0ZpbGUpIHtcbiAgICAgIGlmIChsYXN0UGF0aCAhPSBcIlwiKSB7XG4gICAgICAgIHJlcXVlc3QudXJpICs9IFwiL1wiO1xuICAgICAgfVxuICAgICAgcmVxdWVzdC51cmkgKz0gXCJpbmRleC5odG1sXCI7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHJlcXVlc3QudXJpID0gXCIvaW5kZXguaHRtbFwiO1xuICB9XG5cbiAgcmV0dXJuIHJlcXVlc3Q7XG59O1xuXG4vKipcbiAqIFRoaXMgaXMgYSBoZWxwZXIgdXNlZCBpbiB0aGUgbWFpbiBoYW5kbGVyLiBJdCdzIHNwbGl0IGludG8gaXQncyBvd24gZXhwb3J0XG4gKiB0byBtYWtlIHRlc3RpbmcgZWFzaWVyLlxuICpcbiAqIEFkZHMgZG9tYWluIGZvbGRlciB0byByZXF1ZXN0IFVSSS5cbiAqXG4gKiBAcGFyYW0gcmVxdWVzdFxuICogQHJldHVybnNcbiAqL1xuZXhwb3J0IGNvbnN0IGFkZERvbWFpbkZvbGRlciA9IChyZXF1ZXN0OiBDbG91ZEZyb250UmVxdWVzdCkgPT4ge1xuICBjb25zdCBob3N0SGVhZGVyID0gcmVxdWVzdC5oZWFkZXJzLmhvc3RbMF0udmFsdWU7XG4gIHJlcXVlc3QudXJpID0gYC8ke2hvc3RIZWFkZXJ9JHtyZXF1ZXN0LnVyaX1gO1xuICByZXR1cm4gcmVxdWVzdDtcbn07XG4iXX0=
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@codedrifters/constructs",
|
|
3
|
+
"scripts": {
|
|
4
|
+
"build": "npx projen build",
|
|
5
|
+
"compile": "npx projen compile",
|
|
6
|
+
"default": "npx projen default",
|
|
7
|
+
"eslint": "npx projen eslint",
|
|
8
|
+
"package": "npx projen package",
|
|
9
|
+
"post-compile": "npx projen post-compile",
|
|
10
|
+
"post-upgrade": "npx projen post-upgrade",
|
|
11
|
+
"pre-compile": "npx projen pre-compile",
|
|
12
|
+
"test": "npx projen test",
|
|
13
|
+
"test:watch": "npx projen test:watch",
|
|
14
|
+
"upgrade": "npx projen upgrade",
|
|
15
|
+
"watch": "npx projen watch",
|
|
16
|
+
"projen": "npx projen"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@swc/core": "^1.15.2",
|
|
20
|
+
"@swc/jest": "^0.2.39",
|
|
21
|
+
"@types/jest": "^30.0.0",
|
|
22
|
+
"@types/node": "^24.10.1",
|
|
23
|
+
"@typescript-eslint/eslint-plugin": "^8",
|
|
24
|
+
"@typescript-eslint/parser": "^8",
|
|
25
|
+
"aws-cdk-lib": "2.232.1",
|
|
26
|
+
"constructs": "10.4.3",
|
|
27
|
+
"eslint": "^9",
|
|
28
|
+
"eslint-config-prettier": "^10.1.8",
|
|
29
|
+
"eslint-import-resolver-typescript": "^4.4.4",
|
|
30
|
+
"eslint-plugin-import": "^2.32.0",
|
|
31
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
32
|
+
"jest": "^30.2.0",
|
|
33
|
+
"jest-junit": "^16",
|
|
34
|
+
"prettier": "^3.6.2",
|
|
35
|
+
"typescript": "^5.9.3"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"aws-cdk-lib": "2.232.1",
|
|
39
|
+
"constructs": "10.4.3"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@aws-sdk/client-dynamodb": "^3.936.0",
|
|
43
|
+
"@types/aws-lambda": "^8.10.159",
|
|
44
|
+
"change-case": "^4.0",
|
|
45
|
+
"esbuild": "^0.27.0",
|
|
46
|
+
"type-fest": "^4"
|
|
47
|
+
},
|
|
48
|
+
"main": "lib/index.js",
|
|
49
|
+
"license": "UNLICENSED",
|
|
50
|
+
"version": "0.0.0",
|
|
51
|
+
"types": "lib/index.d.ts",
|
|
52
|
+
"//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"."
|
|
53
|
+
}
|