Files
chesskit/cdk/app-stack.ts
2025-05-17 03:47:04 +02:00

179 lines
4.8 KiB
TypeScript

import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import {
AccessLevel,
Distribution,
ResponseHeadersPolicy,
} from "aws-cdk-lib/aws-cloudfront";
import { S3BucketOrigin } from "aws-cdk-lib/aws-cloudfront-origins";
import { Bucket, BucketAccessControl } from "aws-cdk-lib/aws-s3";
import {
BucketDeployment,
CacheControl,
Source,
} from "aws-cdk-lib/aws-s3-deployment";
import path from "path";
import { renameSync } from "fs";
import { ARecord, HostedZone, RecordTarget } from "aws-cdk-lib/aws-route53";
import { CloudFrontTarget } from "aws-cdk-lib/aws-route53-targets";
import { DnsValidatedCertificate } from "aws-cdk-lib/aws-certificatemanager";
interface AppStackProps extends cdk.StackProps {
domainName: string;
pagePaths: string[];
}
export class AppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: AppStackProps) {
super(scope, id, props);
const { domainName, pagePaths } = props;
for (const pageName of pagePaths) {
renameSync(
path.resolve(__dirname, `../out/${pageName}.html`),
path.resolve(__dirname, `../out/${pageName}`)
);
}
const mainBucket = new Bucket(this, "Bucket", {
accessControl: BucketAccessControl.PRIVATE,
removalPolicy: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: true,
publicReadAccess: false,
});
const enginesBucket = new Bucket(this, "EnginesBucket", {
accessControl: BucketAccessControl.PRIVATE,
removalPolicy: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: true,
publicReadAccess: false,
});
new BucketDeployment(this, "BucketDeployment", {
destinationBucket: mainBucket,
sources: [
Source.asset(path.resolve(__dirname, "../out"), {
exclude: ["engines"],
}),
],
exclude: pagePaths,
memoryLimit: 512,
cacheControl: [
CacheControl.setPublic(),
CacheControl.maxAge(cdk.Duration.hours(1)),
],
});
new BucketDeployment(this, "BucketPagesDeployment", {
destinationBucket: mainBucket,
sources: [
Source.asset(path.resolve(__dirname, "../out"), {
exclude: ["engines"],
}),
],
exclude: ["*"],
include: pagePaths,
memoryLimit: 512,
cacheControl: [
CacheControl.setPublic(),
CacheControl.maxAge(cdk.Duration.hours(1)),
],
contentType: "text/html",
});
new BucketDeployment(this, "BucketEnginesDeployment", {
destinationBucket: enginesBucket,
destinationKeyPrefix: "engines",
sources: [Source.asset(path.resolve(__dirname, "../out/engines"))],
memoryLimit: 512,
ephemeralStorageSize: cdk.Size.gibibytes(1),
cacheControl: [
CacheControl.setPublic(),
CacheControl.maxAge(cdk.Duration.days(365)),
CacheControl.immutable(),
],
});
const mainOriginAccessControl = S3BucketOrigin.withOriginAccessControl(
mainBucket,
{
originAccessLevels: [AccessLevel.READ],
}
);
const enginesOriginAccessControl = S3BucketOrigin.withOriginAccessControl(
enginesBucket,
{
originAccessLevels: [AccessLevel.READ],
}
);
const responseHeadersPolicy = new ResponseHeadersPolicy(
this,
"ResponseHeadersPolicy",
{
customHeadersBehavior: {
customHeaders: [
{
header: "Cross-Origin-Embedder-Policy",
value: "require-corp",
override: true,
},
{
header: "Cross-Origin-Opener-Policy",
value: "same-origin",
override: true,
},
],
},
}
);
const hostedZone = HostedZone.fromLookup(this, "HostedZone", {
domainName,
});
// eslint-disable-next-line
const certificate = new DnsValidatedCertificate(this, "Certificate", {
domainName,
hostedZone,
region: "us-east-1",
});
const distribution = new Distribution(this, "Distribution", {
defaultRootObject: "index.html",
errorResponses: [
{
httpStatus: 404,
responseHttpStatus: 404,
responsePagePath: "/404.html",
},
{
httpStatus: 403,
responseHttpStatus: 404,
responsePagePath: "/404.html",
},
],
defaultBehavior: {
origin: mainOriginAccessControl,
responseHeadersPolicy,
},
additionalBehaviors: {
"/engines/*": {
origin: enginesOriginAccessControl,
responseHeadersPolicy,
},
},
domainNames: [domainName],
certificate,
});
new ARecord(this, "AliasRecord", {
zone: hostedZone,
target: RecordTarget.fromAlias(new CloudFrontTarget(distribution)),
});
new cdk.CfnOutput(this, "SiteUrl", { value: `https://${domainName}` });
}
}