cdk-nextjs 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/.jsii +13811 -0
- package/.prettierrc +0 -0
- package/API.md +9694 -0
- package/LICENSE +202 -0
- package/README.md +137 -0
- package/THIRD-PARTY-LICENSES.md +31 -0
- package/assets/lambdas/assets-deployment/assets-deployment.lambda/assets-deployment.Dockerfile +18 -0
- package/assets/lambdas/assets-deployment/assets-deployment.lambda/index.js +8831 -0
- package/assets/lambdas/revalidate/revalidate.lambda/index.js +67 -0
- package/assets/lambdas/sign-fn-url/sign-fn-url.lambda/index.js +2002 -0
- package/examples/README.md +14 -0
- package/lib/common.d.ts +23 -0
- package/lib/common.js +28 -0
- package/lib/generated-structs/OptionalApplicationLoadBalancedTaskImageOptions.d.ts +106 -0
- package/lib/generated-structs/OptionalApplicationLoadBalancedTaskImageOptions.js +3 -0
- package/lib/generated-structs/OptionalCloudFrontFunctionProps.d.ts +43 -0
- package/lib/generated-structs/OptionalCloudFrontFunctionProps.js +3 -0
- package/lib/generated-structs/OptionalClusterProps.d.ts +49 -0
- package/lib/generated-structs/OptionalClusterProps.js +3 -0
- package/lib/generated-structs/OptionalDistributionProps.d.ts +155 -0
- package/lib/generated-structs/OptionalDistributionProps.js +3 -0
- package/lib/generated-structs/OptionalDockerImageAssetProps.d.ts +124 -0
- package/lib/generated-structs/OptionalDockerImageAssetProps.js +3 -0
- package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +399 -0
- package/lib/generated-structs/OptionalDockerImageFunctionProps.js +3 -0
- package/lib/generated-structs/OptionalEdgeFunctionProps.d.ts +428 -0
- package/lib/generated-structs/OptionalEdgeFunctionProps.js +3 -0
- package/lib/generated-structs/OptionalFunctionProps.d.ts +422 -0
- package/lib/generated-structs/OptionalFunctionProps.js +3 -0
- package/lib/generated-structs/OptionalFunctionUrlProps.d.ts +30 -0
- package/lib/generated-structs/OptionalFunctionUrlProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsAssetsDeploymentProps.d.ts +45 -0
- package/lib/generated-structs/OptionalNextjsAssetsDeploymentProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsBuildProps.d.ts +30 -0
- package/lib/generated-structs/OptionalNextjsBuildProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +43 -0
- package/lib/generated-structs/OptionalNextjsContainersProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +50 -0
- package/lib/generated-structs/OptionalNextjsDistributionProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsFileSystemProps.d.ts +15 -0
- package/lib/generated-structs/OptionalNextjsFileSystemProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsInvalidationProps.d.ts +17 -0
- package/lib/generated-structs/OptionalNextjsInvalidationProps.js +3 -0
- package/lib/generated-structs/OptionalNextjsVpcProps.d.ts +21 -0
- package/lib/generated-structs/OptionalNextjsVpcProps.js +3 -0
- package/lib/generated-structs/OptionalS3OriginProps.d.ts +64 -0
- package/lib/generated-structs/OptionalS3OriginProps.js +3 -0
- package/lib/generated-structs/OptionalVpcProps.d.ts +224 -0
- package/lib/generated-structs/OptionalVpcProps.js +3 -0
- package/lib/index.d.ts +35 -0
- package/lib/index.js +32 -0
- package/lib/lambdas/assets-deployment/assets-deployment-function.d.ts +13 -0
- package/lib/lambdas/assets-deployment/assets-deployment-function.js +23 -0
- package/lib/lambdas/assets-deployment/assets-deployment.lambda.d.ts +2 -0
- package/lib/lambdas/assets-deployment/assets-deployment.lambda.js +62 -0
- package/lib/lambdas/assets-deployment/common.d.ts +8 -0
- package/lib/lambdas/assets-deployment/common.js +32 -0
- package/lib/lambdas/assets-deployment/fs-to-fs.d.ts +2 -0
- package/lib/lambdas/assets-deployment/fs-to-fs.js +9 -0
- package/lib/lambdas/assets-deployment/fs-to-s3.d.ts +2 -0
- package/lib/lambdas/assets-deployment/fs-to-s3.js +45 -0
- package/lib/lambdas/assets-deployment/prune-s3.d.ts +15 -0
- package/lib/lambdas/assets-deployment/prune-s3.js +42 -0
- package/lib/lambdas/assets-deployment/s3.d.ts +2 -0
- package/lib/lambdas/assets-deployment/s3.js +7 -0
- package/lib/lambdas/assets-deployment/utils.d.ts +18 -0
- package/lib/lambdas/assets-deployment/utils.js +35 -0
- package/lib/lambdas/revalidate/revalidate-function.d.ts +13 -0
- package/lib/lambdas/revalidate/revalidate-function.js +23 -0
- package/lib/lambdas/revalidate/revalidate.lambda.d.ts +2 -0
- package/lib/lambdas/revalidate/revalidate.lambda.js +53 -0
- package/lib/lambdas/sign-fn-url/sign-fn-url-function.d.ts +13 -0
- package/lib/lambdas/sign-fn-url/sign-fn-url-function.js +23 -0
- package/lib/lambdas/sign-fn-url/sign-fn-url.lambda.d.ts +9 -0
- package/lib/lambdas/sign-fn-url/sign-fn-url.lambda.js +35 -0
- package/lib/lambdas/sign-fn-url/sign-request.d.ts +28 -0
- package/lib/lambdas/sign-fn-url/sign-request.js +119 -0
- package/lib/lambdas/sign-fn-url/sign-request.test.d.ts +1 -0
- package/lib/lambdas/sign-fn-url/sign-request.test.js +129 -0
- package/lib/nextjs-assets-deployment.d.ts +116 -0
- package/lib/nextjs-assets-deployment.js +93 -0
- package/lib/nextjs-build/add-cache-handler.d.ts +1 -0
- package/lib/nextjs-build/add-cache-handler.js +23 -0
- package/lib/nextjs-build/add-cache-handler.mjs +18 -0
- package/lib/nextjs-build/builder.Dockerfile +29 -0
- package/lib/nextjs-build/cache-handler.cjs +21513 -0
- package/lib/nextjs-build/cache-handler.d.ts +6 -0
- package/lib/nextjs-build/cache-handler.js +22 -0
- package/lib/nextjs-build/global-containers.Dockerfile +45 -0
- package/lib/nextjs-build/global-functions.Dockerfile +46 -0
- package/lib/nextjs-build/nextjs-build.d.ts +150 -0
- package/lib/nextjs-build/nextjs-build.js +220 -0
- package/lib/nextjs-build/regional-containers.Dockerfile +45 -0
- package/lib/nextjs-build/symlink-full-route-cache.d.ts +1 -0
- package/lib/nextjs-build/symlink-full-route-cache.js +37 -0
- package/lib/nextjs-build/symlink-full-route-cache.mjs +23 -0
- package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +8 -0
- package/lib/nextjs-compute/nextjs-compute-base-props.js +3 -0
- package/lib/nextjs-compute/nextjs-containers.d.ts +43 -0
- package/lib/nextjs-compute/nextjs-containers.js +149 -0
- package/lib/nextjs-compute/nextjs-functions.d.ts +23 -0
- package/lib/nextjs-compute/nextjs-functions.js +57 -0
- package/lib/nextjs-distribution.d.ts +120 -0
- package/lib/nextjs-distribution.js +362 -0
- package/lib/nextjs-file-system.d.ts +42 -0
- package/lib/nextjs-file-system.js +74 -0
- package/lib/nextjs-invalidation.d.ts +19 -0
- package/lib/nextjs-invalidation.js +52 -0
- package/lib/nextjs-revalidation.d.ts +30 -0
- package/lib/nextjs-revalidation.js +65 -0
- package/lib/nextjs-static-assets.d.ts +21 -0
- package/lib/nextjs-static-assets.js +32 -0
- package/lib/nextjs-vpc.d.ts +42 -0
- package/lib/nextjs-vpc.js +64 -0
- package/lib/root-constructs/nextjs-base-overrides.d.ts +26 -0
- package/lib/root-constructs/nextjs-base-overrides.js +3 -0
- package/lib/root-constructs/nextjs-base-props.d.ts +56 -0
- package/lib/root-constructs/nextjs-base-props.js +3 -0
- package/lib/root-constructs/nextjs-global-containers.d.ts +74 -0
- package/lib/root-constructs/nextjs-global-containers.js +125 -0
- package/lib/root-constructs/nextjs-global-functions.d.ts +76 -0
- package/lib/root-constructs/nextjs-global-functions.js +131 -0
- package/lib/root-constructs/nextjs-regional-containers.d.ts +43 -0
- package/lib/root-constructs/nextjs-regional-containers.js +92 -0
- package/package.json +165 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import FileSystemCache from "next/dist/server/lib/incremental-cache/file-system-cache";
|
|
2
|
+
type RevalidateTagResponse = ReturnType<FileSystemCache["revalidateTag"]>;
|
|
3
|
+
export default class CacheHandler extends FileSystemCache {
|
|
4
|
+
revalidateTag(tag: string): RevalidateTagResponse;
|
|
5
|
+
}
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
4
|
+
const client_sqs_1 = require("@aws-sdk/client-sqs");
|
|
5
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
6
|
+
const file_system_cache_1 = require("next/dist/server/lib/incremental-cache/file-system-cache");
|
|
7
|
+
const sqsClient = new client_sqs_1.SQSClient();
|
|
8
|
+
class CacheHandler extends file_system_cache_1.default {
|
|
9
|
+
async revalidateTag(tag) {
|
|
10
|
+
console.log({ tag });
|
|
11
|
+
console.log({ this: this });
|
|
12
|
+
await sqsClient.send(new client_sqs_1.SendMessageCommand({
|
|
13
|
+
QueueUrl: process.env.CDK_NEXTJS_QUEUE_URL,
|
|
14
|
+
MessageBody: tag,
|
|
15
|
+
// MessageGroupId: "", // do i need this?
|
|
16
|
+
}));
|
|
17
|
+
// put message in sqs queue if for full route cache
|
|
18
|
+
return super.revalidateTag(tag);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.default = CacheHandler;
|
|
22
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUtaGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9uZXh0anMtYnVpbGQvY2FjaGUtaGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLDZEQUE2RDtBQUM3RCxvREFBb0U7QUFDcEUsNkRBQTZEO0FBQzdELGdHQUF1RjtBQUl2RixNQUFNLFNBQVMsR0FBRyxJQUFJLHNCQUFTLEVBQUUsQ0FBQztBQUVsQyxNQUFxQixZQUFhLFNBQVEsMkJBQWU7SUFDdkQsS0FBSyxDQUFDLGFBQWEsQ0FBQyxHQUFXO1FBQzdCLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ3JCLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUM1QixNQUFNLFNBQVMsQ0FBQyxJQUFJLENBQ2xCLElBQUksK0JBQWtCLENBQUM7WUFDckIsUUFBUSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0JBQW9CO1lBQzFDLFdBQVcsRUFBRSxHQUFHO1lBQ2hCLHlDQUF5QztTQUMxQyxDQUFDLENBQ0gsQ0FBQztRQUNGLG1EQUFtRDtRQUNuRCxPQUFPLEtBQUssQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDbEMsQ0FBQztDQUNGO0FBZEQsK0JBY0MiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzXG5pbXBvcnQgeyBTUVNDbGllbnQsIFNlbmRNZXNzYWdlQ29tbWFuZCB9IGZyb20gXCJAYXdzLXNkay9jbGllbnQtc3FzXCI7XG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzXG5pbXBvcnQgRmlsZVN5c3RlbUNhY2hlIGZyb20gXCJuZXh0L2Rpc3Qvc2VydmVyL2xpYi9pbmNyZW1lbnRhbC1jYWNoZS9maWxlLXN5c3RlbS1jYWNoZVwiO1xuXG50eXBlIFJldmFsaWRhdGVUYWdSZXNwb25zZSA9IFJldHVyblR5cGU8RmlsZVN5c3RlbUNhY2hlW1wicmV2YWxpZGF0ZVRhZ1wiXT47XG5cbmNvbnN0IHNxc0NsaWVudCA9IG5ldyBTUVNDbGllbnQoKTtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQ2FjaGVIYW5kbGVyIGV4dGVuZHMgRmlsZVN5c3RlbUNhY2hlIHtcbiAgYXN5bmMgcmV2YWxpZGF0ZVRhZyh0YWc6IHN0cmluZyk6IFJldmFsaWRhdGVUYWdSZXNwb25zZSB7XG4gICAgY29uc29sZS5sb2coeyB0YWcgfSk7XG4gICAgY29uc29sZS5sb2coeyB0aGlzOiB0aGlzIH0pO1xuICAgIGF3YWl0IHNxc0NsaWVudC5zZW5kKFxuICAgICAgbmV3IFNlbmRNZXNzYWdlQ29tbWFuZCh7XG4gICAgICAgIFF1ZXVlVXJsOiBwcm9jZXNzLmVudi5DREtfTkVYVEpTX1FVRVVFX1VSTCxcbiAgICAgICAgTWVzc2FnZUJvZHk6IHRhZyxcbiAgICAgICAgLy8gTWVzc2FnZUdyb3VwSWQ6IFwiXCIsIC8vIGRvIGkgbmVlZCB0aGlzP1xuICAgICAgfSksXG4gICAgKTtcbiAgICAvLyBwdXQgbWVzc2FnZSBpbiBzcXMgcXVldWUgaWYgZm9yIGZ1bGwgcm91dGUgY2FjaGVcbiAgICByZXR1cm4gc3VwZXIucmV2YWxpZGF0ZVRhZyh0YWcpO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#checkov:skip=CKV_DOCKER_2: healthcheck run by ALB and ECS
|
|
2
|
+
#checkov:skip=CKV_DOCKER_7: latest tag is ok to use for local builder container
|
|
3
|
+
# Modified from: https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile
|
|
4
|
+
ARG BUILDER_IMAGE_TAG
|
|
5
|
+
FROM $BUILDER_IMAGE_TAG as builder
|
|
6
|
+
# Production image, copy all the files and run next
|
|
7
|
+
FROM public.ecr.aws/docker/library/node:20-alpine as runner
|
|
8
|
+
WORKDIR /app
|
|
9
|
+
|
|
10
|
+
ENV NODE_ENV production
|
|
11
|
+
# Uncomment the following line in case you want to disable telemetry during runtime.
|
|
12
|
+
# ENV NEXT_TELEMETRY_DISABLED 1
|
|
13
|
+
|
|
14
|
+
RUN addgroup --system --gid 1001 nodejs
|
|
15
|
+
RUN adduser --system --uid 1001 nextjs
|
|
16
|
+
|
|
17
|
+
ARG RELATIVE_PATH_TO_WORKSPACE
|
|
18
|
+
# even though public is served through cloudfront, we need public for image optimization
|
|
19
|
+
COPY --from=builder --chown=nextjs:nodejs /app/$RELATIVE_PATH_TO_WORKSPACE/public ./$RELATIVE_PATH_TO_WORKSPACE/public
|
|
20
|
+
COPY --from=builder --chown=nextjs:nodejs /app/$RELATIVE_PATH_TO_WORKSPACE/.next/standalone ./
|
|
21
|
+
COPY --chown=nextjs:nodejs ./symlink-full-route-cache.mjs ./
|
|
22
|
+
ARG MOUNT_PATH
|
|
23
|
+
ARG DATA_CACHE_DIR
|
|
24
|
+
ARG FULL_ROUTE_CACHE_DIR
|
|
25
|
+
ARG IMAGE_CACHE_DIR
|
|
26
|
+
RUN mkdir -p $MOUNT_PATH/$DATA_CACHE_DIR && \
|
|
27
|
+
mkdir -p $MOUNT_PATH/$FULL_ROUTE_CACHE_DIR && \
|
|
28
|
+
mkdir -p $MOUNT_PATH/$IMAGE_CACHE_DIR && \
|
|
29
|
+
chmod -R u+rw $MOUNT_PATH && \
|
|
30
|
+
mkdir -p ./$RELATIVE_PATH_TO_WORKSPACE/.next/cache && \
|
|
31
|
+
ln -s $MOUNT_PATH/$DATA_CACHE_DIR ./$RELATIVE_PATH_TO_WORKSPACE/.next/cache/fetch-cache && \
|
|
32
|
+
ln -s $MOUNT_PATH/$IMAGE_CACHE_DIR ./$RELATIVE_PATH_TO_WORKSPACE/.next/cache/images && \
|
|
33
|
+
node symlink-full-route-cache.mjs /app/$RELATIVE_PATH_TO_WORKSPACE/.next/server/app $MOUNT_PATH/$FULL_ROUTE_CACHE_DIR && \
|
|
34
|
+
rm symlink-full-route-cache.mjs
|
|
35
|
+
|
|
36
|
+
USER nextjs
|
|
37
|
+
|
|
38
|
+
EXPOSE 3000
|
|
39
|
+
|
|
40
|
+
ENV PORT 3000
|
|
41
|
+
|
|
42
|
+
# server.js is created by next build from the standalone output
|
|
43
|
+
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
|
|
44
|
+
# CMD will be overwritten by ECS Task Definition
|
|
45
|
+
CMD HOSTNAME="0.0.0.0" node server.js
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#checkov:skip=CKV_DOCKER_2: healthcheck run by AWS Lambda Web Adapter
|
|
2
|
+
#checkov:skip=CKV_DOCKER_7: latest tag is ok to use for local builder container
|
|
3
|
+
# Modified from: https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile
|
|
4
|
+
ARG BUILDER_IMAGE_TAG
|
|
5
|
+
FROM $BUILDER_IMAGE_TAG as builder
|
|
6
|
+
# Production image, copy all the files and run next
|
|
7
|
+
FROM public.ecr.aws/docker/library/node:20-alpine as runner
|
|
8
|
+
ARG MOUNT_PATH
|
|
9
|
+
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.3 /lambda-adapter /opt/extensions/lambda-adapter
|
|
10
|
+
WORKDIR /app
|
|
11
|
+
|
|
12
|
+
ENV NODE_ENV production
|
|
13
|
+
# Uncomment the following line in case you want to disable telemetry during runtime.
|
|
14
|
+
# ENV NEXT_TELEMETRY_DISABLED 1
|
|
15
|
+
|
|
16
|
+
RUN addgroup --system --gid 1001 nodejs
|
|
17
|
+
RUN adduser --system --uid 1001 nextjs
|
|
18
|
+
|
|
19
|
+
ARG RELATIVE_PATH_TO_WORKSPACE
|
|
20
|
+
# even though public is served through cloudfront, we need public for image optimization
|
|
21
|
+
COPY --from=builder --chown=nextjs:nodejs /app/$RELATIVE_PATH_TO_WORKSPACE/public ./$RELATIVE_PATH_TO_WORKSPACE/public
|
|
22
|
+
COPY --from=builder --chown=nextjs:nodejs /app/$RELATIVE_PATH_TO_WORKSPACE/.next/standalone ./
|
|
23
|
+
COPY --chown=nextjs:nodejs ./add-cache-handler.mjs ./cache-handler.cjs ./symlink-full-route-cache.mjs ./
|
|
24
|
+
ARG MOUNT_PATH
|
|
25
|
+
ARG DATA_CACHE_DIR
|
|
26
|
+
ARG FULL_ROUTE_CACHE_DIR
|
|
27
|
+
ARG IMAGE_CACHE_DIR
|
|
28
|
+
RUN node add-cache-handler.mjs ./$RELATIVE_PATH_TO_WORKSPACE/.next/required-server-files.json && \
|
|
29
|
+
rm add-cache-handler.mjs && \
|
|
30
|
+
mkdir -p $MOUNT_PATH/$DATA_CACHE_DIR && \
|
|
31
|
+
mkdir -p $MOUNT_PATH/$FULL_ROUTE_CACHE_DIR && \
|
|
32
|
+
mkdir -p $MOUNT_PATH/$IMAGE_CACHE_DIR && \
|
|
33
|
+
chmod -R u+rw $MOUNT_PATH && \
|
|
34
|
+
mkdir -p ./$RELATIVE_PATH_TO_WORKSPACE/.next/cache && \
|
|
35
|
+
ln -s $MOUNT_PATH/$DATA_CACHE_DIR ./$RELATIVE_PATH_TO_WORKSPACE/.next/cache/fetch-cache && \
|
|
36
|
+
ln -s $MOUNT_PATH/$IMAGE_CACHE_DIR ./$RELATIVE_PATH_TO_WORKSPACE/.next/cache/images && \
|
|
37
|
+
node symlink-full-route-cache.mjs /app/$RELATIVE_PATH_TO_WORKSPACE/.next/server/app $MOUNT_PATH/$FULL_ROUTE_CACHE_DIR && \
|
|
38
|
+
rm symlink-full-route-cache.mjs
|
|
39
|
+
|
|
40
|
+
USER nextjs
|
|
41
|
+
|
|
42
|
+
EXPOSE 3000
|
|
43
|
+
|
|
44
|
+
ENV PORT 3000
|
|
45
|
+
|
|
46
|
+
# CMD will be overwritten by Lambda IaC
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { DockerImageAsset, Platform } from "aws-cdk-lib/aws-ecr-assets";
|
|
2
|
+
import { AssetImageCodeProps, DockerImageCode } from "aws-cdk-lib/aws-lambda";
|
|
3
|
+
import { Construct } from "constructs";
|
|
4
|
+
import { NextjsType } from "../common";
|
|
5
|
+
import { OptionalDockerImageAssetProps } from "../generated-structs/OptionalDockerImageAssetProps";
|
|
6
|
+
import { NextjsBaseProps } from "../root-constructs/nextjs-base-props";
|
|
7
|
+
export interface BuilderImageProps {
|
|
8
|
+
/**
|
|
9
|
+
* Build Args to be passed to `docker build` command.
|
|
10
|
+
*/
|
|
11
|
+
readonly buildArgs?: Record<string, string>;
|
|
12
|
+
/**
|
|
13
|
+
* `docker build ...` command to run in {@link NextBaseProps.buildContext}.
|
|
14
|
+
* Default interpolates other props. If you override, other props will have
|
|
15
|
+
* no effect on command.
|
|
16
|
+
*/
|
|
17
|
+
readonly command?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Environment variables names to pass from host to container during build process.
|
|
20
|
+
*
|
|
21
|
+
* Note, a shell script, cdk-nextjs-load-env-vars.sh is created within the
|
|
22
|
+
* {@link NextBaseProps.buildContext} directory, which will contain all the
|
|
23
|
+
* environment variables defined in this prop. If you've created your own
|
|
24
|
+
* custom Dockerfile (passed in via {@link BuilderImageProps.customDockerfilePath})
|
|
25
|
+
* then you need to make sure you're copying it into the image.
|
|
26
|
+
*
|
|
27
|
+
* @example ["MY_API_KEY"]
|
|
28
|
+
*/
|
|
29
|
+
readonly envVarNames?: string[];
|
|
30
|
+
/**
|
|
31
|
+
* Lines in .dockerignore file which will be created in your {@link NextBaseProps.buildContext}
|
|
32
|
+
* @default ["node_modules", ".git", ".gitignore", ".md"]
|
|
33
|
+
*/
|
|
34
|
+
readonly exclude?: string[];
|
|
35
|
+
/**
|
|
36
|
+
* Name of Dockerfile
|
|
37
|
+
* @default "builder.Dockerfile"
|
|
38
|
+
*/
|
|
39
|
+
readonly file?: string;
|
|
40
|
+
readonly platform?: Platform;
|
|
41
|
+
/**
|
|
42
|
+
* Skip building the builder image.
|
|
43
|
+
* @default false
|
|
44
|
+
*/
|
|
45
|
+
readonly skipBuild?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Path to your custom builder.Dockerfile which will be copied into {@link NextBaseProps.buildContext}.
|
|
48
|
+
* It is recommended to override this prop to optimize build caching for your setup.
|
|
49
|
+
*/
|
|
50
|
+
readonly customDockerfilePath?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface NextjsBuildOverrides {
|
|
53
|
+
readonly nextjsContainersDockerImageAssetProps?: OptionalDockerImageAssetProps;
|
|
54
|
+
readonly nextjsFunctionsAssetImageCodeProps?: AssetImageCodeProps;
|
|
55
|
+
readonly nextjsAssetDeploymentAssetImageCodeProps?: AssetImageCodeProps;
|
|
56
|
+
}
|
|
57
|
+
export interface NextjsBuildProps {
|
|
58
|
+
/**
|
|
59
|
+
* @see {@link NextjsBaseProps["buildCommand"]}
|
|
60
|
+
*/
|
|
61
|
+
readonly buildCommand: NextjsBaseProps["buildCommand"];
|
|
62
|
+
/**
|
|
63
|
+
* @see {@link NextjsBaseProps["buildContext"]}
|
|
64
|
+
*/
|
|
65
|
+
readonly buildContext: NextjsBaseProps["buildContext"];
|
|
66
|
+
/**
|
|
67
|
+
*
|
|
68
|
+
*/
|
|
69
|
+
readonly builderImageProps?: BuilderImageProps;
|
|
70
|
+
/**
|
|
71
|
+
* @see {@link NextjsBaseProps.relativePathToWorkspace}
|
|
72
|
+
*/
|
|
73
|
+
readonly relativePathToWorkspace?: NextjsBaseProps["relativePathToWorkspace"];
|
|
74
|
+
readonly nextjsType: NextjsType;
|
|
75
|
+
readonly overrides?: NextjsBuildOverrides;
|
|
76
|
+
}
|
|
77
|
+
export interface PublicDirEntry {
|
|
78
|
+
readonly name: string;
|
|
79
|
+
readonly isDirectory: boolean;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Builds Next.js assets.
|
|
83
|
+
* @link https://nextjs.org/docs/pages/api-reference/next-config-js/output
|
|
84
|
+
*/
|
|
85
|
+
export declare class NextjsBuild extends Construct {
|
|
86
|
+
/**
|
|
87
|
+
* Hash of builder image which will change whenever the image changes. Useful
|
|
88
|
+
* for passing to properties of custom resources that depend upon the builder
|
|
89
|
+
* image to re-run when build image changes.
|
|
90
|
+
*/
|
|
91
|
+
buildImageDigest: string;
|
|
92
|
+
/**
|
|
93
|
+
* Mount path in container for EFS. Next.js image optimization, data, and full
|
|
94
|
+
* route cache will be symlinked to this location.
|
|
95
|
+
*
|
|
96
|
+
* Must comply with pattern: ^/mnt/[a-zA-Z0-9-_.]+$
|
|
97
|
+
* @see https://docs.aws.amazon.com/lambda/latest/api/API_FileSystemConfig.html
|
|
98
|
+
*/
|
|
99
|
+
containerMountPathForEfs: string;
|
|
100
|
+
/**
|
|
101
|
+
* Docker image built if using Fargate.
|
|
102
|
+
*/
|
|
103
|
+
imageForNextjsContainers?: DockerImageAsset;
|
|
104
|
+
/**
|
|
105
|
+
* Docker image built if using Lambda.
|
|
106
|
+
*/
|
|
107
|
+
imageForNextjsFunctions?: DockerImageCode;
|
|
108
|
+
/**
|
|
109
|
+
* Docker image built for `NextjsAssetsDeployment`
|
|
110
|
+
*/
|
|
111
|
+
imageForNextjsAssetsDeployment: DockerImageCode;
|
|
112
|
+
/**
|
|
113
|
+
* Absolute path to public. Use by CloudFront/ALB to create behaviors/rules
|
|
114
|
+
* @example "/Users/john/myapp/public"
|
|
115
|
+
*/
|
|
116
|
+
publicDirEntries: PublicDirEntry[];
|
|
117
|
+
/**
|
|
118
|
+
* The entrypoint JavaScript file used as an argument for Node.js to run the
|
|
119
|
+
* Next.js standalone server relative to the standalone directory.
|
|
120
|
+
* @example "./server.js"
|
|
121
|
+
* @example "./packages/ui/server.js" (monorepo)
|
|
122
|
+
*/
|
|
123
|
+
relativePathToEntrypoint: string;
|
|
124
|
+
/**
|
|
125
|
+
* Tag of builder image Next.js app which is built for other images to be
|
|
126
|
+
* built `FROM`. This image isn't built with CDK Assets construct b/c it
|
|
127
|
+
* doesn't need to be uploaded to ECR. We still need to include slice of
|
|
128
|
+
* `node.addr` in tag in case multiple cdk-nextjs constructs are used.
|
|
129
|
+
*/
|
|
130
|
+
private builderImageTag;
|
|
131
|
+
private containerRuntime;
|
|
132
|
+
private props;
|
|
133
|
+
private relativePathToWorkspace;
|
|
134
|
+
constructor(scope: Construct, id: string, props: NextjsBuildProps);
|
|
135
|
+
private getRelativeEntrypointPath;
|
|
136
|
+
/**
|
|
137
|
+
* A builder or base image needs to be created so that the same image can be
|
|
138
|
+
* built `FROM` for `NextjsFunctions` or `NextjsContainers` and `NextjsAssetsDeployment`.
|
|
139
|
+
* This image doesn't need to be uploaded to ECR so we're "manually" creating
|
|
140
|
+
* it with `execSync` and other images will be built `FROM` it.
|
|
141
|
+
*/
|
|
142
|
+
private createBuilderImage;
|
|
143
|
+
private createBuildArgStr;
|
|
144
|
+
private createLoadEnvVarsScript;
|
|
145
|
+
private getBuilderImageDigest;
|
|
146
|
+
private getPublicDirEntries;
|
|
147
|
+
private createImageForNextjsContainers;
|
|
148
|
+
private createImageForNextjsFunctions;
|
|
149
|
+
private createImageForNextjsAssetsDeployment;
|
|
150
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.NextjsBuild = void 0;
|
|
5
|
+
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
|
6
|
+
const node_child_process_1 = require("node:child_process");
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const posix_1 = require("node:path/posix");
|
|
10
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
11
|
+
const aws_ecr_assets_1 = require("aws-cdk-lib/aws-ecr-assets");
|
|
12
|
+
const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
|
|
13
|
+
const constructs_1 = require("constructs");
|
|
14
|
+
const common_1 = require("../common");
|
|
15
|
+
/**
|
|
16
|
+
* Builds Next.js assets.
|
|
17
|
+
* @link https://nextjs.org/docs/pages/api-reference/next-config-js/output
|
|
18
|
+
*/
|
|
19
|
+
class NextjsBuild extends constructs_1.Construct {
|
|
20
|
+
constructor(scope, id, props) {
|
|
21
|
+
super(scope, id);
|
|
22
|
+
/**
|
|
23
|
+
* Mount path in container for EFS. Next.js image optimization, data, and full
|
|
24
|
+
* route cache will be symlinked to this location.
|
|
25
|
+
*
|
|
26
|
+
* Must comply with pattern: ^/mnt/[a-zA-Z0-9-_.]+$
|
|
27
|
+
* @see https://docs.aws.amazon.com/lambda/latest/api/API_FileSystemConfig.html
|
|
28
|
+
*/
|
|
29
|
+
this.containerMountPathForEfs = "/mnt/cdk-nextjs-cache";
|
|
30
|
+
this.containerRuntime = process.env.CDK_DOCKER || "docker";
|
|
31
|
+
this.builderImageTag = `cdk-nextjs/builder-${this.node.addr.slice(30)}`;
|
|
32
|
+
this.relativePathToWorkspace = props.relativePathToWorkspace || ".";
|
|
33
|
+
this.props = props;
|
|
34
|
+
this.relativePathToEntrypoint = this.getRelativeEntrypointPath();
|
|
35
|
+
this.buildImageDigest = this.createBuilderImage();
|
|
36
|
+
this.publicDirEntries = this.getPublicDirEntries();
|
|
37
|
+
if (props.nextjsType === common_1.NextjsType.GLOBAL_CONTAINERS ||
|
|
38
|
+
props.nextjsType === common_1.NextjsType.REGIONAL_CONTAINERS) {
|
|
39
|
+
this.imageForNextjsContainers = this.createImageForNextjsContainers();
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
this.imageForNextjsFunctions = this.createImageForNextjsFunctions();
|
|
43
|
+
}
|
|
44
|
+
this.imageForNextjsAssetsDeployment =
|
|
45
|
+
this.createImageForNextjsAssetsDeployment();
|
|
46
|
+
}
|
|
47
|
+
getRelativeEntrypointPath() {
|
|
48
|
+
// joinPosix b/c this will be used in linux container
|
|
49
|
+
return (0, posix_1.join)(this.props.relativePathToWorkspace || "", "server.js");
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A builder or base image needs to be created so that the same image can be
|
|
53
|
+
* built `FROM` for `NextjsFunctions` or `NextjsContainers` and `NextjsAssetsDeployment`.
|
|
54
|
+
* This image doesn't need to be uploaded to ECR so we're "manually" creating
|
|
55
|
+
* it with `execSync` and other images will be built `FROM` it.
|
|
56
|
+
*/
|
|
57
|
+
createBuilderImage() {
|
|
58
|
+
const buildCommand = this.props.buildCommand || "npm run build";
|
|
59
|
+
const { buildArgs = {
|
|
60
|
+
BUILD_COMMAND: buildCommand,
|
|
61
|
+
RELATIVE_PATH_TO_WORKSPACE: this.relativePathToWorkspace,
|
|
62
|
+
...this.props.builderImageProps?.buildArgs,
|
|
63
|
+
}, envVarNames = [], exclude = [
|
|
64
|
+
"**/node_modules",
|
|
65
|
+
".git",
|
|
66
|
+
"**/cdk.out",
|
|
67
|
+
"**/.next",
|
|
68
|
+
".gitignore",
|
|
69
|
+
"*.md",
|
|
70
|
+
], file = "builder.Dockerfile", platform, skipBuild = false, } = this.props.builderImageProps || {};
|
|
71
|
+
const srcDockerfilePath = this.props.builderImageProps?.customDockerfilePath ||
|
|
72
|
+
(0, node_path_1.join)(__dirname, file);
|
|
73
|
+
const destDockerfilePath = (0, node_path_1.join)(this.props.buildContext, file);
|
|
74
|
+
(0, node_fs_1.cpSync)(srcDockerfilePath, destDockerfilePath);
|
|
75
|
+
const excludeFileStr = exclude?.join("\n");
|
|
76
|
+
const dockerignoreFilePath = (0, node_path_1.join)(this.props.buildContext, ".dockerignore");
|
|
77
|
+
(0, node_fs_1.writeFileSync)(dockerignoreFilePath, excludeFileStr);
|
|
78
|
+
const buildArgsStr = this.createBuildArgStr(buildArgs);
|
|
79
|
+
const loadEnvVarsScriptPath = (0, node_path_1.join)(this.props.buildContext, "cdk-nextjs-load-env-vars.sh");
|
|
80
|
+
if (envVarNames.length) {
|
|
81
|
+
this.createLoadEnvVarsScript(envVarNames, loadEnvVarsScriptPath);
|
|
82
|
+
}
|
|
83
|
+
const command = this.props.builderImageProps?.command ||
|
|
84
|
+
`${this.containerRuntime} build ${platform ? `--platform ${platform.platform}` : ""} --file ${file} --tag ${this.builderImageTag} ${buildArgsStr} .`;
|
|
85
|
+
let error;
|
|
86
|
+
try {
|
|
87
|
+
if (!skipBuild) {
|
|
88
|
+
console.log(`Building image with command: ${command} in directory: ${this.props.buildContext}`);
|
|
89
|
+
(0, node_child_process_1.execSync)(command, {
|
|
90
|
+
stdio: "inherit",
|
|
91
|
+
cwd: this.props.buildContext,
|
|
92
|
+
env: process.env,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
error = err;
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
(0, node_fs_1.rmSync)(destDockerfilePath);
|
|
101
|
+
(0, node_fs_1.rmSync)(dockerignoreFilePath);
|
|
102
|
+
if (envVarNames.length) {
|
|
103
|
+
(0, node_fs_1.rmSync)(loadEnvVarsScriptPath);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (error)
|
|
107
|
+
throw error;
|
|
108
|
+
return this.getBuilderImageDigest();
|
|
109
|
+
}
|
|
110
|
+
createBuildArgStr(buildArgs) {
|
|
111
|
+
return Object.entries(buildArgs).reduce((acc, [key, value]) => {
|
|
112
|
+
return `${acc} --build-arg ${key}="${value}"`;
|
|
113
|
+
}, "");
|
|
114
|
+
}
|
|
115
|
+
createLoadEnvVarsScript(envVarNames = [], loadEnvVarsScriptPath) {
|
|
116
|
+
let loadEnvVarsScript = "# Dynamically generated script to load env vars into build container";
|
|
117
|
+
for (const envVarName of envVarNames) {
|
|
118
|
+
loadEnvVarsScript += `\nexport ${envVarName}=${process.env[envVarName] || '""'}`;
|
|
119
|
+
}
|
|
120
|
+
(0, node_fs_1.writeFileSync)(loadEnvVarsScriptPath, loadEnvVarsScript);
|
|
121
|
+
}
|
|
122
|
+
getBuilderImageDigest() {
|
|
123
|
+
const digest = (0, node_child_process_1.execSync)(`${this.containerRuntime} images --no-trunc --quiet ${this.builderImageTag}`, { encoding: "utf-8" });
|
|
124
|
+
return digest.slice(0, -1); // remove trailing \n
|
|
125
|
+
}
|
|
126
|
+
getPublicDirEntries() {
|
|
127
|
+
const publicDirPath = (0, posix_1.join)("/app", this.props.relativePathToWorkspace || "", "public");
|
|
128
|
+
const publicDirEntriesString = (0, node_child_process_1.execSync)(`${this.containerRuntime} run ${this.builderImageTag} node -e "console.log(JSON.stringify(fs.readdirSync('${publicDirPath}', { withFileTypes: true }).map((e) => ({ name: e.name, isDir: e.isDirectory()}))))"`, { encoding: "utf-8" });
|
|
129
|
+
return JSON.parse(publicDirEntriesString);
|
|
130
|
+
}
|
|
131
|
+
createImageForNextjsContainers() {
|
|
132
|
+
const dockerfileNamePrefix = this.props.nextjsType === common_1.NextjsType.GLOBAL_CONTAINERS
|
|
133
|
+
? "global"
|
|
134
|
+
: "regional";
|
|
135
|
+
const dockerfileName = `${dockerfileNamePrefix}-containers.Dockerfile`;
|
|
136
|
+
// cdk-nextjs/builder-{hash} already contains built nextjs app which we'll
|
|
137
|
+
// `COPY --from=cdk-nextjs/builder-{hash}` so we just need the Dockerfile
|
|
138
|
+
// and symlink-full-route-cache scripts which are in lib/nextjs-build folder.
|
|
139
|
+
const buildContext = (0, node_path_1.join)(__dirname, "..", "..", "lib", "nextjs-build");
|
|
140
|
+
const dockerImageAsset = new aws_ecr_assets_1.DockerImageAsset(this, "Image", {
|
|
141
|
+
buildArgs: {
|
|
142
|
+
BUILDER_IMAGE_TAG: this.builderImageTag,
|
|
143
|
+
DATA_CACHE_DIR: common_1.DATA_CACHE_DIR,
|
|
144
|
+
FULL_ROUTE_CACHE_DIR: common_1.FULL_ROUTE_CACHE_DIR,
|
|
145
|
+
IMAGE_CACHE_DIR: common_1.IMAGE_CACHE_DIR,
|
|
146
|
+
MOUNT_PATH: this.containerMountPathForEfs,
|
|
147
|
+
RELATIVE_PATH_TO_WORKSPACE: this.relativePathToWorkspace,
|
|
148
|
+
},
|
|
149
|
+
directory: buildContext,
|
|
150
|
+
exclude: [
|
|
151
|
+
"*",
|
|
152
|
+
`!${dockerfileName}`,
|
|
153
|
+
"!symlink-full-route-cache.mjs",
|
|
154
|
+
"!add-cache-handler.mjs",
|
|
155
|
+
],
|
|
156
|
+
extraHash: this.buildImageDigest, // rebuild when builder hash changes
|
|
157
|
+
file: dockerfileName,
|
|
158
|
+
ignoreMode: aws_cdk_lib_1.IgnoreMode.DOCKER,
|
|
159
|
+
...this.props.overrides?.nextjsContainersDockerImageAssetProps,
|
|
160
|
+
});
|
|
161
|
+
return dockerImageAsset;
|
|
162
|
+
}
|
|
163
|
+
createImageForNextjsFunctions() {
|
|
164
|
+
const dockerfileName = "global-functions.Dockerfile";
|
|
165
|
+
// cdk-nextjs/builder-{hash} already contains built nextjs app which we'll
|
|
166
|
+
// `COPY --from=cdk-nextjs/builder-{hash}` so we just need the Dockerfile
|
|
167
|
+
// and symlink-full-route-cache scripts which are in lib/nextjs-build folder.
|
|
168
|
+
const buildContext = (0, node_path_1.join)(__dirname, "..", "..", "lib", "nextjs-build");
|
|
169
|
+
const dockerImageCode = aws_lambda_1.DockerImageCode.fromImageAsset(buildContext, {
|
|
170
|
+
buildArgs: {
|
|
171
|
+
BUILDER_IMAGE_TAG: this.builderImageTag,
|
|
172
|
+
DATA_CACHE_DIR: common_1.DATA_CACHE_DIR,
|
|
173
|
+
FULL_ROUTE_CACHE_DIR: common_1.FULL_ROUTE_CACHE_DIR,
|
|
174
|
+
IMAGE_CACHE_DIR: common_1.IMAGE_CACHE_DIR,
|
|
175
|
+
MOUNT_PATH: this.containerMountPathForEfs,
|
|
176
|
+
RELATIVE_PATH_TO_WORKSPACE: this.relativePathToWorkspace,
|
|
177
|
+
},
|
|
178
|
+
cmd: ["node", this.relativePathToEntrypoint],
|
|
179
|
+
exclude: [
|
|
180
|
+
"*",
|
|
181
|
+
`!${dockerfileName}`,
|
|
182
|
+
"!symlink-full-route-cache.mjs",
|
|
183
|
+
"!add-cache-handler.mjs",
|
|
184
|
+
"!cache-handler.cjs",
|
|
185
|
+
],
|
|
186
|
+
extraHash: this.buildImageDigest, // rebuild when builder hash changes
|
|
187
|
+
file: dockerfileName,
|
|
188
|
+
ignoreMode: aws_cdk_lib_1.IgnoreMode.DOCKER,
|
|
189
|
+
...this.props.overrides?.nextjsFunctionsAssetImageCodeProps,
|
|
190
|
+
});
|
|
191
|
+
// TODO: how to clean up temp dir?
|
|
192
|
+
// rmSync(tempDir, { recursive: true });
|
|
193
|
+
return dockerImageCode;
|
|
194
|
+
}
|
|
195
|
+
createImageForNextjsAssetsDeployment() {
|
|
196
|
+
const dockerfileName = "assets-deployment.Dockerfile";
|
|
197
|
+
/**
|
|
198
|
+
* Path to bundled custom resource code
|
|
199
|
+
*/
|
|
200
|
+
const lambdaBuildContext = (0, node_path_1.join)(__dirname, "..", "..", "assets", "lambdas", "assets-deployment", "assets-deployment.lambda");
|
|
201
|
+
// cdk-nextjs/builder-{hash} already contains Next.js built code which
|
|
202
|
+
// we'll copy into final image. But we also need lambda code to run
|
|
203
|
+
// asset deployment tasks
|
|
204
|
+
const dockerImageCode = aws_lambda_1.DockerImageCode.fromImageAsset(lambdaBuildContext, {
|
|
205
|
+
buildArgs: {
|
|
206
|
+
BUILDER_IMAGE_TAG: this.builderImageTag,
|
|
207
|
+
RELATIVE_PATH_TO_WORKSPACE: this.relativePathToWorkspace,
|
|
208
|
+
},
|
|
209
|
+
extraHash: this.buildImageDigest, // rebuild when builder hash changes
|
|
210
|
+
file: dockerfileName,
|
|
211
|
+
ignoreMode: aws_cdk_lib_1.IgnoreMode.DOCKER,
|
|
212
|
+
...this.props.overrides?.nextjsAssetDeploymentAssetImageCodeProps,
|
|
213
|
+
});
|
|
214
|
+
return dockerImageCode;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
exports.NextjsBuild = NextjsBuild;
|
|
218
|
+
_a = JSII_RTTI_SYMBOL_1;
|
|
219
|
+
NextjsBuild[_a] = { fqn: "cdk-nextjs.NextjsBuild", version: "0.0.0" };
|
|
220
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV4dGpzLWJ1aWxkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL25leHRqcy1idWlsZC9uZXh0anMtYnVpbGQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSwyREFBOEM7QUFDOUMscUNBQXdEO0FBQ3hELHlDQUFpQztBQUNqQywyQ0FBb0Q7QUFDcEQsNkNBQXlDO0FBQ3pDLCtEQUF3RTtBQUN4RSx1REFBOEU7QUFDOUUsMkNBQXVDO0FBQ3ZDLHNDQUttQjtBQWtGbkI7OztHQUdHO0FBQ0gsTUFBYSxXQUFZLFNBQVEsc0JBQVM7SUFtRHhDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBdUI7UUFDL0QsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQTdDbkI7Ozs7OztXQU1HO1FBQ0gsNkJBQXdCLEdBQUcsdUJBQXVCLENBQUM7UUFpQzNDLHFCQUFnQixHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxJQUFJLFFBQVEsQ0FBQztRQU01RCxJQUFJLENBQUMsZUFBZSxHQUFHLHNCQUFzQixJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztRQUN4RSxJQUFJLENBQUMsdUJBQXVCLEdBQUcsS0FBSyxDQUFDLHVCQUF1QixJQUFJLEdBQUcsQ0FBQztRQUNwRSxJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUNuQixJQUFJLENBQUMsd0JBQXdCLEdBQUcsSUFBSSxDQUFDLHlCQUF5QixFQUFFLENBQUM7UUFDakUsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQ2xELElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUNuRCxJQUNFLEtBQUssQ0FBQyxVQUFVLEtBQUssbUJBQVUsQ0FBQyxpQkFBaUI7WUFDakQsS0FBSyxDQUFDLFVBQVUs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QUFnQixFQUFFLG9DQUFvQztZQUN0RSxJQUFJLEVBQUUsY0FBYztZQUNwQixVQUFVLEVBQUUsd0JBQVUsQ0FBQyxNQUFNO1lBQzdCLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsd0NBQXdDO1NBQ2xFLENBQUMsQ0FBQztRQUNILE9BQU8sZUFBZSxDQUFDO0lBQ3pCLENBQUM7O0FBclJILGtDQXNSQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGV4ZWNTeW5jIH0gZnJvbSBcIm5vZGU6Y2hpbGRfcHJvY2Vzc1wiO1xuaW1wb3J0IHsgY3BTeW5jLCBybVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tIFwibm9kZTpmc1wiO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IGpvaW4gYXMgam9pblBvc2l4IH0gZnJvbSBcIm5vZGU6cGF0aC9wb3NpeFwiO1xuaW1wb3J0IHsgSWdub3JlTW9kZSB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHsgRG9ja2VySW1hZ2VBc3NldCwgUGxhdGZvcm0gfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjci1hc3NldHNcIjtcbmltcG9ydCB7IEFzc2V0SW1hZ2VDb2RlUHJvcHMsIERvY2tlckltYWdlQ29kZSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtbGFtYmRhXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IHtcbiAgREFUQV9DQUNIRV9ESVIsXG4gIEZVTExfUk9VVEVfQ0FDSEVfRElSLFxuICBJTUFHRV9DQUNIRV9ESVIsXG4gIE5leHRqc1R5cGUsXG59IGZyb20gXCIuLi9jb21tb25cIjtcbmltcG9ydCB7IE9wdGlvbmFsRG9ja2VySW1hZ2VBc3NldFByb3BzIH0gZnJvbSBcIi4uL2dlbmVyYXRlZC1zdHJ1Y3RzL09wdGlvbmFsRG9ja2VySW1hZ2VBc3NldFByb3BzXCI7XG5pbXBvcnQgeyBOZXh0anNCYXNlUHJvcHMgfSBmcm9tIFwiLi4vcm9vdC1jb25zdHJ1Y3RzL25leHRqcy1iYXNlLXByb3BzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQnVpbGRlckltYWdlUHJvcHMge1xuICAvKipcbiAgICogQnVpbGQgQXJncyB0byBiZSBwYXNzZWQgdG8gYGRvY2tlciBidWlsZGAgY29tbWFuZC5cbiAgICovXG4gIHJlYWRvbmx5IGJ1aWxkQXJncz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIC8qKlxuICAgKiBgZG9ja2VyIGJ1aWxkIC4uLmAgY29tbWFuZCB0byBydW4gaW4ge0BsaW5rIE5leHRCYXNlUHJvcHMuYnVpbGRDb250ZXh0fS5cbiAgICogRGVmYXVsdCBpbnRlcnBvbGF0ZXMgb3RoZXIgcHJvcHMuIElmIHlvdSBvdmVycmlkZSwgb3RoZXIgcHJvcHMgd2lsbCBoYXZlXG4gICAqIG5vIGVmZmVjdCBvbiBjb21tYW5kLlxuICAgKi9cbiAgcmVhZG9ubHkgY29tbWFuZD86IHN0cmluZztcbiAgLyoqXG4gICAqIEVudmlyb25tZW50IHZhcmlhYmxlcyBuYW1lcyB0byBwYXNzIGZyb20gaG9zdCB0byBjb250YWluZXIgZHVyaW5nIGJ1aWxkIHByb2Nlc3MuXG4gICAqXG4gICAqIE5vdGUsIGEgc2hlbGwgc2NyaXB0LCBjZGstbmV4dGpzLWxvYWQtZW52LXZhcnMuc2ggaXMgY3JlYXRlZCB3aXRoaW4gdGhlXG4gICAqIHtAbGluayBOZXh0QmFzZVByb3BzLmJ1aWxkQ29udGV4dH0gZGlyZWN0b3J5LCB3aGljaCB3aWxsIGNvbnRhaW4gYWxsIHRoZVxuICAgKiBlbnZpcm9ubWVudCB2YXJpYWJsZXMgZGVmaW5lZCBpbiB0aGlzIHByb3AuIElmIHlvdSd2ZSBjcmVhdGVkIHlvdXIgb3duXG4gICAqIGN1c3RvbSBEb2NrZXJmaWxlIChwYXNzZWQgaW4gdmlhIHtAbGluayBCdWlsZGVySW1hZ2VQcm9wcy5jdXN0b21Eb2NrZXJmaWxlUGF0aH0pXG4gICAqIHRoZW4geW91IG5lZWQgdG8gbWFrZSBzdXJlIHlvdSdyZSBjb3B5aW5nIGl0IGludG8gdGhlIGltYWdlLlxuICAgKlxuICAgKiBAZXhhbXBsZSBbXCJNWV9BUElfS0VZXCJdXG4gICAqL1xuICByZWFkb25seSBlbnZWYXJOYW1lcz86IHN0cmluZ1tdO1xuICAvKipcbiAgICogTGluZXMgaW4gLmRvY2tlcmlnbm9yZSBmaWxlIHdoaWNoIHdpbGwgYmUgY3JlYXRlZCBpbiB5b3VyIHtAbGluayBOZXh0QmFzZVByb3BzLmJ1aWxkQ29udGV4dH1cbiAgICogQGRlZmF1bHQgW1wibm9kZV9tb2R1bGVzXCIsIFwiLmdpdFwiLCBcIi5naXRpZ25vcmVcIiwgXCIubWRcIl1cbiAgICovXG4gIHJlYWRvbmx5IGV4Y2x1ZGU/OiBzdHJpbmdbXTtcbiAgLyoqXG4gICAqIE5hbWUgb2YgRG9ja2VyZmlsZVxuICAgKiBAZGVmYXVsdCBcImJ1aWxkZXIuRG9ja2VyZmlsZVwiXG4gICAqL1xuICByZWFkb25seSBmaWxlPzogc3RyaW5nO1xuICByZWFkb25seSBwbGF0Zm9ybT86IFBsYXRmb3JtO1xuICAvKipcbiAgICogU2tpcCBidWlsZGluZyB0aGUgYnVpbGRlciBpbWFnZS5cbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IHNraXBCdWlsZD86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBQYXRoIHRvIHlvdXIgY3VzdG9tIGJ1aWxkZXIuRG9ja2VyZmlsZSB3aGljaCB3aWxsIGJlIGNvcGllZCBpbnRvIHtAbGluayBOZXh0QmFzZVByb3BzLmJ1aWxkQ29udGV4dH0uXG4gICAqIEl0IGlzIHJlY29tbWVuZGVkIHRvIG92ZXJyaWRlIHRoaXMgcHJvcCB0byBvcHRpbWl6ZSBidWlsZCBjYWNoaW5nIGZvciB5b3VyIHNldHVwLlxuICAgKi9cbiAgcmVhZG9ubHkgY3VzdG9tRG9ja2VyZmlsZVBhdGg/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTmV4dGpzQnVpbGRPdmVycmlkZXMge1xuICByZWFkb25seSBuZXh0anNDb250YWluZXJzRG9ja2VySW1hZ2VBc3NldFByb3BzPzogT3B0aW9uYWxEb2NrZXJJbWFnZUFzc2V0UHJvcHM7XG4gIHJlYWRvbmx5IG5leHRqc0Z1bmN0aW9uc0Fzc2V0SW1hZ2VDb2RlUHJvcHM/OiBBc3NldEltYWdlQ29kZVByb3BzO1xuICByZWFkb25seSBuZXh0anNBc3NldERlcGxveW1lbnRBc3NldEltYWdlQ29kZVByb3BzPzogQXNzZXRJbWFnZUNvZGVQcm9wcztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBOZXh0anNCdWlsZFByb3BzIHtcbiAgLyoqXG4gICAqIEBzZWUge0BsaW5rIE5leHRqc0Jhc2VQcm9wc1tcImJ1aWxkQ29tbWFuZFwiXX1cbiAgICovXG4gIHJlYWRvbmx5IGJ1aWxkQ29tbWFuZDogTmV4dGpzQmFzZVByb3BzW1wiYnVpbGRDb21tYW5kXCJdO1xuICAvKipcbiAgICogQHNlZSB7QGxpbmsgTmV4dGpzQmFzZVByb3BzW1wiYnVpbGRDb250ZXh0XCJdfVxuICAgKi9cbiAgcmVhZG9ubHkgYnVpbGRDb250ZXh0OiBOZXh0anNCYXNlUHJvcHNbXCJidWlsZENvbnRleHRcIl07XG4gIC8qKlxuICAgKlxuICAgKi9cbiAgcmVhZG9ubHkgYnVpbGRlckltYWdlUHJvcHM/OiBCdWlsZGVySW1hZ2VQcm9wcztcbiAgLyoqXG4gICAqIEBzZWUge0BsaW5rIE5leHRqc0Jhc2VQcm9wcy5yZWxhdGl2ZVBhdGhUb1dvcmtzcGFjZX1cbiAgICovXG4gIHJlYWRvbmx5IHJlbGF0aXZlUGF0aFRvV29ya3NwYWNlPzogTmV4dGpzQmFzZVByb3BzW1wicmVsYXRpdmVQYXRoVG9Xb3Jrc3BhY2VcIl07XG4gIHJlYWRvbmx5IG5leHRqc1R5cGU6IE5leHRqc1R5cGU7XG4gIHJlYWRvbmx5IG92ZXJyaWRlcz86IE5leHRqc0J1aWxkT3ZlcnJpZGVzO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFB1YmxpY0RpckVudHJ5IHtcbiAgcmVhZG9ubHkgbmFtZTogc3RyaW5nO1xuICByZWFkb25seSBpc0RpcmVjdG9yeTogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBCdWlsZHMgTmV4dC5qcyBhc3NldHMuXG4gKiBAbGluayBodHRwczovL25leHRqcy5vcmcvZG9jcy9wYWdlcy9hcGktcmVmZXJlbmNlL25leHQtY29uZmlnLWpzL291dHB1dFxuICovXG5leHBvcnQgY2xhc3MgTmV4dGpzQnVpbGQgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICAvKipcbiAgICogSGFzaCBvZiBidWlsZGVyIGltYWdlIHdoaWNoIHdpbGwgY2hhbmdlIHdoZW5ldmVyIHRoZSBpbWFnZSBjaGFuZ2VzLiBVc2VmdWxcbiAgICogZm9yIHBhc3NpbmcgdG8gcHJvcGVydGllcyBvZiBjdXN0b20gcmVzb3VyY2VzIHRoYXQgZGVwZW5kIHVwb24gdGhlIGJ1aWxkZXJcbiAgICogaW1hZ2UgdG8gcmUtcnVuIHdoZW4gYnVpbGQgaW1hZ2UgY2hhbmdlcy5cbiAgICovXG4gIGJ1aWxkSW1hZ2VEaWdlc3Q6IHN0cmluZztcbiAgLyoqXG4gICAqIE1vdW50IHBhdGggaW4gY29udGFpbmVyIGZvciBFRlMuIE5leHQuanMgaW1hZ2Ugb3B0aW1pemF0aW9uLCBkYXRhLCBhbmQgZnVsbFxuICAgKiByb3V0ZSBjYWNoZSB3aWxsIGJlIHN5bWxpbmtlZCB0byB0aGlzIGxvY2F0aW9uLlxuICAgKlxuICAgKiBNdXN0IGNvbXBseSB3aXRoIHBhdHRlcm46IF4vbW50L1thLXpBLVowLTktXy5dKyRcbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vbGFtYmRhL2xhdGVzdC9hcGkvQVBJX0ZpbGVTeXN0ZW1Db25maWcuaHRtbFxuICAgKi9cbiAgY29udGFpbmVyTW91bnRQYXRoRm9yRWZzID0gXCIvbW50L2Nkay1uZXh0anMtY2FjaGVcIjtcbiAgLyoqXG4gICAqIERvY2tlciBpbWFnZSBidWlsdCBpZiB1c2luZyBGYXJnYXRlLlxuICAgKi9cbiAgaW1hZ2VGb3JOZXh0anNDb250YWluZXJzPzogRG9ja2VySW1hZ2VBc3NldDtcbiAgLyoqXG4gICAqIERvY2tlciBpbWFnZSBidWlsdCBpZiB1c2luZyBMYW1iZGEuXG4gICAqL1xuICBpbWFnZUZvck5leHRqc0Z1bmN0aW9ucz86IERvY2tlckltYWdlQ29kZTtcbiAgLyoqXG4gICAqIERvY2tlciBpbWFnZSBidWlsdCBmb3IgYE5leHRqc0Fzc2V0c0RlcGxveW1lbnRgXG4gICAqL1xuICBpbWFnZUZvck5leHRqc0Fzc2V0c0RlcGxveW1lbnQ6IERvY2tlckltYWdlQ29kZTtcbiAgLyoqXG4gICAqIEFic29sdXRlIHBhdGggdG8gcHVibGljLiBVc2UgYnkgQ2xvdWRGcm9udC9BTEIgdG8gY3JlYXRlIGJlaGF2aW9ycy9ydWxlc1xuICAgKiBAZXhhbXBsZSBcIi9Vc2Vycy9qb2huL215YXBwL3B1YmxpY1wiXG4gICAqL1xuICBwdWJsaWNEaXJFbnRyaWVzOiBQdWJsaWNEaXJFbnRyeVtdO1xuICAvKipcbiAgICogVGhlIGVudHJ5cG9pbnQgSmF2YVNjcmlwdCBmaWxlIHVzZWQgYXMgYW4gYXJndW1lbnQgZm9yIE5vZGUuanMgdG8gcnVuIHRoZVxuICAgKiBOZXh0LmpzIHN0YW5kYWxvbmUgc2VydmVyIHJlbGF0aXZlIHRvIHRoZSBzdGFuZGFsb25lIGRpcmVjdG9yeS5cbiAgICogQGV4YW1wbGUgXCIuL3NlcnZlci5qc1wiXG4gICAqIEBleGFtcGxlIFwiLi9wYWNrYWdlcy91aS9zZXJ2ZXIuanNcIiAobW9ub3JlcG8pXG4gICAqL1xuICByZWxhdGl2ZVBhdGhUb0VudHJ5cG9pbnQ6IHN0cmluZztcblxuICAvKipcbiAgICogVGFnIG9mIGJ1aWxkZXIgaW1hZ2UgTmV4dC5qcyBhcHAgd2hpY2ggaXMgYnVpbHQgZm9yIG90aGVyIGltYWdlcyB0byBiZVxuICAgKiBidWlsdCBgRlJPTWAuIFRoaXMgaW1hZ2UgaXNuJ3QgYnVpbHQgd2l0aCBDREsgQXNzZXRzIGNvbnN0cnVjdCBiL2MgaXRcbiAgICogZG9lc24ndCBuZWVkIHRvIGJlIHVwbG9hZGVkIHRvIEVDUi4gV2Ugc3RpbGwgbmVlZCB0byBpbmNsdWRlIHNsaWNlIG9mXG4gICAqIGBub2RlLmFkZHJgIGluIHRhZyBpbiBjYXNlIG11bHRpcGxlIGNkay1uZXh0anMgY29uc3RydWN0cyBhcmUgdXNlZC5cbiAgICovXG4gIHByaXZhdGUgYnVpbGRlckltYWdlVGFnOiBzdHJpbmc7XG4gIHByaXZhdGUgY29udGFpbmVyUnVudGltZSA9IHByb2Nlc3MuZW52LkNES19ET0NLRVIgfHwgXCJkb2NrZXJcIjtcbiAgcHJpdmF0ZSBwcm9wczogTmV4dGpzQnVpbGRQcm9wcztcbiAgcHJpdmF0ZSByZWxhdGl2ZVBhdGhUb1dvcmtzcGFjZTogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBOZXh0anNCdWlsZFByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcbiAgICB0aGlzLmJ1aWxkZXJJbWFnZVRhZyA9IGBjZGstbmV4dGpzL2J1aWxkZXItJHt0aGlzLm5vZGUuYWRkci5zbGljZSgzMCl9YDtcbiAgICB0aGlzLnJlbGF0aXZlUGF0aFRvV29ya3NwYWNlID0gcHJvcHMucmVsYXRpdmVQYXRoVG9Xb3Jrc3BhY2UgfHwgXCIuXCI7XG4gICAgdGhpcy5wcm9wcyA9IHByb3BzO1xuICAgIHRoaXMucmVsYXRpdmVQYXRoVG9FbnRyeXBvaW50ID0gdGhpcy5nZXRSZWxhdGl2ZUVudHJ5cG9pbnRQYXRoKCk7XG4gICAgdGhpcy5idWlsZEltYWdlRGlnZXN0ID0gdGhpcy5jcmVhdGVCdWlsZGVySW1hZ2UoKTtcbiAgICB0aGlzLnB1YmxpY0RpckVudHJpZXMgPSB0aGlzLmdldFB1YmxpY0RpckVudHJpZXMoKTtcbiAgICBpZiAoXG4gICAgICBwcm9wcy5uZXh0anNUeXBlID09PSBOZXh0anNUeXBlLkdMT0JBTF9DT05UQUlORVJTIHx8XG4gICAgICBwcm9wcy5uZXh0anNUeXBlID09PSBOZXh0anNUeXBlLlJFR0lPTkFMX0NPTlRBSU5FUlNcbiAgICApIHtcbiAgICAgIHRoaXMuaW1hZ2VGb3JOZXh0anNDb250YWluZXJzID0gdGhpcy5jcmVhdGVJbWFnZUZvck5leHRqc0NvbnRhaW5lcnMoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5pbWFnZUZvck5leHRqc0Z1bmN0aW9ucyA9IHRoaXMuY3JlYXRlSW1hZ2VGb3JOZXh0anNGdW5jdGlvbnMoKTtcbiAgICB9XG4gICAgdGhpcy5pbWFnZUZvck5leHRqc0Fzc2V0c0RlcGxveW1lbnQgPVxuICAgICAgdGhpcy5jcmVhdGVJbWFnZUZvck5leHRqc0Fzc2V0c0RlcGxveW1lbnQoKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0UmVsYXRpdmVFbnRyeXBvaW50UGF0aCgpIHtcbiAgICAvLyBqb2luUG9zaXggYi9jIHRoaXMgd2lsbCBiZSB1c2VkIGluIGxpbnV4IGNvbnRhaW5lclxuICAgIHJldHVybiBqb2luUG9zaXgodGhpcy5wcm9wcy5yZWxhdGl2ZVBhdGhUb1dvcmtzcGFjZSB8fCBcIlwiLCBcInNlcnZlci5qc1wiKTtcbiAgfVxuICAvKipcbiAgICogQSBidWlsZGVyIG9yIGJhc2UgaW1hZ2UgbmVlZHMgdG8gYmUgY3JlYXRlZCBzbyB0aGF0IHRoZSBzYW1lIGltYWdlIGNhbiBiZVxuICAgKiBidWlsdCBgRlJPTWAgZm9yIGBOZXh0anNGdW5jdGlvbnNgIG9yIGBOZXh0anNDb250YWluZXJzYCBhbmQgYE5leHRqc0Fzc2V0c0RlcGxveW1lbnRgLlxuICAgKiBUaGlzIGltYWdlIGRvZXNuJ3QgbmVlZCB0byBiZSB1cGxvYWRlZCB0byBFQ1Igc28gd2UncmUgXCJtYW51YWxseVwiIGNyZWF0aW5nXG4gICAqIGl0IHdpdGggYGV4ZWNTeW5jYCBhbmQgb3RoZXIgaW1hZ2VzIHdpbGwgYmUgYnVpbHQgYEZST01gIGl0LlxuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVCdWlsZGVySW1hZ2UoKSB7XG4gICAgY29uc3QgYnVpbGRDb21tYW5kID0gdGhpcy5wcm9wcy5idWlsZENvbW1hbmQgfHwgXCJucG0gcnVuIGJ1aWxkXCI7XG4gICAgY29uc3Qge1xuICAgICAgYnVpbGRBcmdzID0ge1xuICAgICAgICBCVUlMRF9DT01NQU5EOiBidWlsZENvbW1hbmQsXG4gICAgICAgIFJFTEFUSVZFX1BBVEhfVE9fV09SS1NQQUNFOiB0aGlzLnJlbGF0aXZlUGF0aFRvV29ya3NwYWNlLFxuICAgICAgICAuLi50aGlzLnByb3BzLmJ1aWxkZXJJbWFnZVByb3BzPy5idWlsZEFyZ3MsXG4gICAgICB9LFxuICAgICAgZW52VmFyTmFtZXMgPSBbXSxcbiAgICAgIGV4Y2x1ZGUgPSBbXG4gICAgICAgIFwiKiovbm9kZV9tb2R1bGVzXCIsXG4gICAgICAgIFwiLmdpdFwiLFxuICAgICAgICBcIioqL2Nkay5vdXRcIixcbiAgICAgICAgXCIqKi8ubmV4dFwiLFxuICAgICAgICBcIi5naXRpZ25vcmVcIixcbiAgICAgICAgXCIqLm1kXCIsXG4gICAgICBdLFxuICAgICAgZmlsZSA9IFwiYnVpbGRlci5Eb2NrZXJmaWxlXCIsXG4gICAgICBwbGF0Zm9ybSxcbiAgICAgIHNraXBCdWlsZCA9IGZhbHNlLFxuICAgIH0gPSB0aGlzLnByb3BzLmJ1aWxkZXJJbWFnZVByb3BzIHx8IHt9O1xuICAgIGNvbnN0IHNyY0RvY2tlcmZpbGVQYXRoID1cbiAgICAgIHRoaXMucHJvcHMuYnVpbGRlckltYWdlUHJvcHM/LmN1c3RvbURvY2tlcmZpbGVQYXRoIHx8XG4gICAgICBqb2luKF9fZGlybmFtZSwgZmlsZSk7XG4gICAgY29uc3QgZGVzdERvY2tlcmZpbGVQYXRoID0gam9pbih0aGlzLnByb3BzLmJ1aWxkQ29udGV4dCwgZmlsZSk7XG4gICAgY3BTeW5jKHNyY0RvY2tlcmZpbGVQYXRoLCBkZXN0RG9ja2VyZmlsZVBhdGgpO1xuICAgIGNvbnN0IGV4Y2x1ZGVGaWxlU3RyID0gZXhjbHVkZT8uam9pbihcIlxcblwiKTtcbiAgICBjb25zdCBkb2NrZXJpZ25vcmVGaWxlUGF0aCA9IGpvaW4odGhpcy5wcm9wcy5idWlsZENvbnRleHQsIFwiLmRvY2tlcmlnbm9yZVwiKTtcbiAgICB3cml0ZUZpbGVTeW5jKGRvY2tlcmlnbm9yZUZpbGVQYXRoLCBleGNsdWRlRmlsZVN0cik7XG4gICAgY29uc3QgYnVpbGRBcmdzU3RyID0gdGhpcy5jcmVhdGVCdWlsZEFyZ1N0cihidWlsZEFyZ3MpO1xuICAgIGNvbnN0IGxvYWRFbnZWYXJzU2NyaXB0UGF0aCA9IGpvaW4oXG4gICAgICB0aGlzLnByb3BzLmJ1aWxkQ29udGV4dCxcbiAgICAgIFwiY2RrLW5leHRqcy1sb2FkLWVudi12YXJzLnNoXCIsXG4gICAgKTtcbiAgICBpZiAoZW52VmFyTmFtZXMubGVuZ3RoKSB7XG4gICAgICB0aGlzLmNyZWF0ZUxvYWRFbnZWYXJzU2NyaXB0KGVudlZhck5hbWVzLCBsb2FkRW52VmFyc1NjcmlwdFBhdGgpO1xuICAgIH1cbiAgICBjb25zdCBjb21tYW5kID1cbiAgICAgIHRoaXMucHJvcHMuYnVpbGRlckltYWdlUHJvcHM/LmNvbW1hbmQgfHxcbiAgICAgIGAke3RoaXMuY29udGFpbmVyUnVudGltZX0gYnVpbGQgJHtwbGF0Zm9ybSA/IGAtLXBsYXRmb3JtICR7cGxhdGZvcm0ucGxhdGZvcm19YCA6IFwiXCJ9IC0tZmlsZSAke2ZpbGV9IC0tdGFnICR7dGhpcy5idWlsZGVySW1hZ2VUYWd9ICR7YnVpbGRBcmdzU3RyfSAuYDtcbiAgICBsZXQgZXJyb3I6IHVua25vd247XG4gICAgdHJ5IHtcbiAgICAgIGlmICghc2tpcEJ1aWxkKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgIGBCdWlsZGluZyBpbWFnZSB3aXRoIGNvbW1hbmQ6ICR7Y29tbWFuZH0gaW4gZGlyZWN0b3J5OiAke3RoaXMucHJvcHMuYnVpbGRDb250ZXh0fWAsXG4gICAgICAgICk7XG4gICAgICAgIGV4ZWNTeW5jKGNvbW1hbmQsIHtcbiAgICAgICAgICBzdGRpbzogXCJpbmhlcml0XCIsXG4gICAgICAgICAgY3dkOiB0aGlzLnByb3BzLmJ1aWxkQ29udGV4dCxcbiAgICAgICAgICBlbnY6IHByb2Nlc3MuZW52LFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGVycm9yID0gZXJyO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBybVN5bmMoZGVzdERvY2tlcmZpbGVQYXRoKTtcbiAgICAgIHJtU3luYyhkb2NrZXJpZ25vcmVGaWxlUGF0aCk7XG4gICAgICBpZiAoZW52VmFyTmFtZXMubGVuZ3RoKSB7XG4gICAgICAgIHJtU3luYyhsb2FkRW52VmFyc1NjcmlwdFBhdGgpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoZXJyb3IpIHRocm93IGVycm9yO1xuICAgIHJldHVybiB0aGlzLmdldEJ1aWxkZXJJbWFnZURpZ2VzdCgpO1xuICB9XG4gIHByaXZhdGUgY3JlYXRlQnVpbGRBcmdTdHIoXG4gICAgYnVpbGRBcmdzOiBSZXF1aXJlZDxCdWlsZGVySW1hZ2VQcm9wcz5bXCJidWlsZEFyZ3NcIl0sXG4gICkge1xuICAgIHJldHVybiBPYmplY3QuZW50cmllcyhidWlsZEFyZ3MpLnJlZHVjZSgoYWNjLCBba2V5LCB2YWx1ZV0pID0+IHtcbiAgICAgIHJldHVybiBgJHthY2N9IC0tYnVpbGQtYXJnICR7a2V5fT1cIiR7dmFsdWV9XCJgO1xuICAgIH0sIFwiXCIpO1xuICB9XG4gIHByaXZhdGUgY3JlYXRlTG9hZEVudlZhcnNTY3JpcHQoXG4gICAgZW52VmFyTmFtZXM6IFJlcXVpcmVkPEJ1aWxkZXJJbWFnZVByb3BzPltcImVudlZhck5hbWVzXCJdID0gW10sXG4gICAgbG9hZEVudlZhcnNTY3JpcHRQYXRoOiBzdHJpbmcsXG4gICkge1xuICAgIGxldCBsb2FkRW52VmFyc1NjcmlwdCA9XG4gICAgICBcIiMgRHluYW1pY2FsbHkgZ2VuZXJhdGVkIHNjcmlwdCB0byBsb2FkIGVudiB2YXJzIGludG8gYnVpbGQgY29udGFpbmVyXCI7XG4gICAgZm9yIChjb25zdCBlbnZWYXJOYW1lIG9mIGVudlZhck5hbWVzKSB7XG4gICAgICBsb2FkRW52VmFyc1NjcmlwdCArPSBgXFxuZXhwb3J0ICR7ZW52VmFyTmFtZX09JHtwcm9jZXNzLmVudltlbnZWYXJOYW1lXSB8fCAnXCJcIid9YDtcbiAgICB9XG4gICAgd3JpdGVGaWxlU3luYyhsb2FkRW52VmFyc1NjcmlwdFBhdGgsIGxvYWRFbnZWYXJzU2NyaXB0KTtcbiAgfVxuICBwcml2YXRlIGdldEJ1aWxkZXJJbWFnZURpZ2VzdCgpIHtcbiAgICBjb25zdCBkaWdlc3QgPSBleGVjU3luYyhcbiAgICAgIGAke3RoaXMuY29udGFpbmVyUnVudGltZX0gaW1hZ2VzIC0tbm8tdHJ1bmMgLS1xdWlldCAke3RoaXMuYnVpbGRlckltYWdlVGFnfWAsXG4gICAgICB7IGVuY29kaW5nOiBcInV0Zi04XCIgfSxcbiAgICApO1xuICAgIHJldHVybiBkaWdlc3Quc2xpY2UoMCwgLTEpOyAvLyByZW1vdmUgdHJhaWxpbmcgXFxuXG4gIH1cbiAgcHJpdmF0ZSBnZXRQdWJsaWNEaXJFbnRyaWVzKCk6IFB1YmxpY0RpckVudHJ5W10ge1xuICAgIGNvbnN0IHB1YmxpY0RpclBhdGggPSBqb2luUG9zaXgoXG4gICAgICBcIi9hcHBcIixcbiAgICAgIHRoaXMucHJvcHMucmVsYXRpdmVQYXRoVG9Xb3Jrc3BhY2UgfHwgXCJcIixcbiAgICAgIFwicHVibGljXCIsXG4gICAgKTtcbiAgICBjb25zdCBwdWJsaWNEaXJFbnRyaWVzU3RyaW5nID0gZXhlY1N5bmMoXG4gICAgICBgJHt0aGlzLmNvbnRhaW5lclJ1bnRpbWV9IHJ1biAke3RoaXMuYnVpbGRlckltYWdlVGFnfSBub2RlIC1lIFwiY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoZnMucmVhZGRpclN5bmMoJyR7cHVibGljRGlyUGF0aH0nLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSkubWFwKChlKSA9PiAoeyBuYW1lOiBlLm5hbWUsIGlzRGlyOiBlLmlzRGlyZWN0b3J5KCl9KSkpKVwiYCxcbiAgICAgIHsgZW5jb2Rpbmc6IFwidXRmLThcIiB9LFxuICAgICk7XG4gICAgcmV0dXJuIEpTT04ucGFyc2UocHVibGljRGlyRW50cmllc1N0cmluZykgYXMgUHVibGljRGlyRW50cnlbXTtcbiAgfVxuICBwcml2YXRlIGNyZWF0ZUltYWdlRm9yTmV4dGpzQ29udGFpbmVycygpIHtcbiAgICBjb25zdCBkb2NrZXJmaWxlTmFtZVByZWZpeCA9XG4gICAgICB0aGlzLnByb3BzLm5leHRqc1R5cGUgPT09IE5leHRqc1R5cGUuR0xPQkFMX0NPTlRBSU5FUlNcbiAgICAgICAgPyBcImdsb2JhbFwiXG4gICAgICAgIDogXCJyZWdpb25hbFwiO1xuICAgIGNvbnN0IGRvY2tlcmZpbGVOYW1lID0gYCR7ZG9ja2VyZmlsZU5hbWVQcmVmaXh9LWNvbnRhaW5lcnMuRG9ja2VyZmlsZWA7XG4gICAgLy8gY2RrLW5leHRqcy9idWlsZGVyLXtoYXNofSBhbHJlYWR5IGNvbnRhaW5zIGJ1aWx0IG5leHRqcyBhcHAgd2hpY2ggd2UnbGxcbiAgICAvLyBgQ09QWSAtLWZyb209Y2RrLW5leHRqcy9idWlsZGVyLXtoYXNofWAgc28gd2UganVzdCBuZWVkIHRoZSBEb2NrZXJmaWxlXG4gICAgLy8gYW5kIHN5bWxpbmstZnVsbC1yb3V0ZS1jYWNoZSBzY3JpcHRzIHdoaWNoIGFyZSBpbiBsaWIvbmV4dGpzLWJ1aWxkIGZvbGRlci5cbiAgICBjb25zdCBidWlsZENvbnRleHQgPSBqb2luKF9fZGlybmFtZSwgXCIuLlwiLCBcIi4uXCIsIFwibGliXCIsIFwibmV4dGpzLWJ1aWxkXCIpO1xuICAgIGNvbnN0IGRvY2tlckltYWdlQXNzZXQgPSBuZXcgRG9ja2VySW1hZ2VBc3NldCh0aGlzLCBcIkltYWdlXCIsIHtcbiAgICAgIGJ1aWxkQXJnczoge1xuICAgICAgICBCVUlMREVSX0lNQUdFX1RBRzogdGhpcy5idWlsZGVySW1hZ2VUYWcsXG4gICAgICAgIERBVEFfQ0FDSEVfRElSLFxuICAgICAgICBGVUxMX1JPVVRFX0NBQ0hFX0RJUixcbiAgICAgICAgSU1BR0VfQ0FDSEVfRElSLFxuICAgICAgICBNT1VOVF9QQVRIOiB0aGlzLmNvbnRhaW5lck1vdW50UGF0aEZvckVmcyxcbiAgICAgICAgUkVMQVRJVkVfUEFUSF9UT19XT1JLU1BBQ0U6IHRoaXMucmVsYXRpdmVQYXRoVG9Xb3Jrc3BhY2UsXG4gICAgICB9LFxuICAgICAgZGlyZWN0b3J5OiBidWlsZENvbnRleHQsXG4gICAgICBleGNsdWRlOiBbXG4gICAgICAgIFwiKlwiLFxuICAgICAgICBgISR7ZG9ja2VyZmlsZU5hbWV9YCxcbiAgICAgICAgXCIhc3ltbGluay1mdWxsLXJvdXRlLWNhY2hlLm1qc1wiLFxuICAgICAgICBcIiFhZGQtY2FjaGUtaGFuZGxlci5tanNcIixcbiAgICAgIF0sXG4gICAgICBleHRyYUhhc2g6IHRoaXMuYnVpbGRJbWFnZURpZ2VzdCwgLy8gcmVidWlsZCB3aGVuIGJ1aWxkZXIgaGFzaCBjaGFuZ2VzXG4gICAgICBmaWxlOiBkb2NrZXJmaWxlTmFtZSxcbiAgICAgIGlnbm9yZU1vZGU6IElnbm9yZU1vZGUuRE9DS0VSLFxuICAgICAgLi4udGhpcy5wcm9wcy5vdmVycmlkZXM/Lm5leHRqc0NvbnRhaW5lcnNEb2NrZXJJbWFnZUFzc2V0UHJvcHMsXG4gICAgfSk7XG4gICAgcmV0dXJuIGRvY2tlckltYWdlQXNzZXQ7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZUltYWdlRm9yTmV4dGpzRnVuY3Rpb25zKCkge1xuICAgIGNvbnN0IGRvY2tlcmZpbGVOYW1lID0gXCJnbG9iYWwtZnVuY3Rpb25zLkRvY2tlcmZpbGVcIjtcbiAgICAvLyBjZGstbmV4dGpzL2J1aWxkZXIte2hhc2h9IGFscmVhZHkgY29udGFpbnMgYnVpbHQgbmV4dGpzIGFwcCB3aGljaCB3ZSdsbFxuICAgIC8vIGBDT1BZIC0tZnJvbT1jZGstbmV4dGpzL2J1aWxkZXIte2hhc2h9YCBzbyB3ZSBqdXN0IG5lZWQgdGhlIERvY2tlcmZpbGVcbiAgICAvLyBhbmQgc3ltbGluay1mdWxsLXJvdXRlLWNhY2hlIHNjcmlwdHMgd2hpY2ggYXJlIGluIGxpYi9uZXh0anMtYnVpbGQgZm9sZGVyLlxuICAgIGNvbnN0IGJ1aWxkQ29udGV4dCA9IGpvaW4oX19kaXJuYW1lLCBcIi4uXCIsIFwiLi5cIiwgXCJsaWJcIiwgXCJuZXh0anMtYnVpbGRcIik7XG4gICAgY29uc3QgZG9ja2VySW1hZ2VDb2RlID0gRG9ja2VySW1hZ2VDb2RlLmZyb21JbWFnZUFzc2V0KGJ1aWxkQ29udGV4dCwge1xuICAgICAgYnVpbGRBcmdzOiB7XG4gICAgICAgIEJVSUxERVJfSU1BR0VfVEFHOiB0aGlzLmJ1aWxkZXJJbWFnZVRhZyxcbiAgICAgICAgREFUQV9DQUNIRV9ESVIsXG4gICAgICAgIEZVTExfUk9VVEVfQ0FDSEVfRElSLFxuICAgICAgICBJTUFHRV9DQUNIRV9ESVIsXG4gICAgICAgIE1PVU5UX1BBVEg6IHRoaXMuY29udGFpbmVyTW91bnRQYXRoRm9yRWZzLFxuICAgICAgICBSRUxBVElWRV9QQVRIX1RPX1dPUktTUEFDRTogdGhpcy5yZWxhdGl2ZVBhdGhUb1dvcmtzcGFjZSxcbiAgICAgIH0sXG4gICAgICBjbWQ6IFtcIm5vZGVcIiwgdGhpcy5yZWxhdGl2ZVBhdGhUb0VudHJ5cG9pbnRdLFxuICAgICAgZXhjbHVkZTogW1xuICAgICAgICBcIipcIixcbiAgICAgICAgYCEke2RvY2tlcmZpbGVOYW1lfWAsXG4gICAgICAgIFwiIXN5bWxpbmstZnVsbC1yb3V0ZS1jYWNoZS5tanNcIixcbiAgICAgICAgXCIhYWRkLWNhY2hlLWhhbmRsZXIubWpzXCIsXG4gICAgICAgIFwiIWNhY2hlLWhhbmRsZXIuY2pzXCIsXG4gICAgICBdLFxuICAgICAgZXh0cmFIYXNoOiB0aGlzLmJ1aWxkSW1hZ2VEaWdlc3QsIC8vIHJlYnVpbGQgd2hlbiBidWlsZGVyIGhhc2ggY2hhbmdlc1xuICAgICAgZmlsZTogZG9ja2VyZmlsZU5hbWUsXG4gICAgICBpZ25vcmVNb2RlOiBJZ25vcmVNb2RlLkRPQ0tFUixcbiAgICAgIC4uLnRoaXMucHJvcHMub3ZlcnJpZGVzPy5uZXh0anNGdW5jdGlvbnNBc3NldEltYWdlQ29kZVByb3BzLFxuICAgIH0pO1xuICAgIC8vIFRPRE86IGhvdyB0byBjbGVhbiB1cCB0ZW1wIGRpcj9cbiAgICAvLyBybVN5bmModGVtcERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgcmV0dXJuIGRvY2tlckltYWdlQ29kZTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlSW1hZ2VGb3JOZXh0anNBc3NldHNEZXBsb3ltZW50KCkge1xuICAgIGNvbnN0IGRvY2tlcmZpbGVOYW1lID0gXCJhc3NldHMtZGVwbG95bWVudC5Eb2NrZXJmaWxlXCI7XG4gICAgLyoqXG4gICAgICogUGF0aCB0byBidW5kbGVkIGN1c3RvbSByZXNvdXJjZSBjb2RlXG4gICAgICovXG4gICAgY29uc3QgbGFtYmRhQnVpbGRDb250ZXh0ID0gam9pbihcbiAgICAgIF9fZGlybmFtZSxcbiAgICAgIFwiLi5cIixcbiAgICAgIFwiLi5cIixcbiAgICAgIFwiYXNzZXRzXCIsXG4gICAgICBcImxhbWJkYXNcIixcbiAgICAgIFwiYXNzZXRzLWRlcGxveW1lbnRcIixcbiAgICAgIFwiYXNzZXRzLWRlcGxveW1lbnQubGFtYmRhXCIsXG4gICAgKTtcbiAgICAvLyBjZGstbmV4dGpzL2J1aWxkZXIte2hhc2h9IGFscmVhZHkgY29udGFpbnMgTmV4dC5qcyBidWlsdCBjb2RlIHdoaWNoXG4gICAgLy8gd2UnbGwgY29weSBpbnRvIGZpbmFsIGltYWdlLiBCdXQgd2UgYWxzbyBuZWVkIGxhbWJkYSBjb2RlIHRvIHJ1blxuICAgIC8vIGFzc2V0IGRlcGxveW1lbnQgdGFza3NcbiAgICBjb25zdCBkb2NrZXJJbWFnZUNvZGUgPSBEb2NrZXJJbWFnZUNvZGUuZnJvbUltYWdlQXNzZXQobGFtYmRhQnVpbGRDb250ZXh0LCB7XG4gICAgICBidWlsZEFyZ3M6IHtcbiAgICAgICAgQlVJTERFUl9JTUFHRV9UQUc6IHRoaXMuYnVpbGRlckltYWdlVGFnLFxuICAgICAgICBSRUxBVElWRV9QQVRIX1RPX1dPUktTUEFDRTogdGhpcy5yZWxhdGl2ZVBhdGhUb1dvcmtzcGFjZSxcbiAgICAgIH0sXG4gICAgICBleHRyYUhhc2g6IHRoaXMuYnVpbGRJbWFnZURpZ2VzdCwgLy8gcmVidWlsZCB3aGVuIGJ1aWxkZXIgaGFzaCBjaGFuZ2VzXG4gICAgICBmaWxlOiBkb2NrZXJmaWxlTmFtZSxcbiAgICAgIGlnbm9yZU1vZGU6IElnbm9yZU1vZGUuRE9DS0VSLFxuICAgICAgLi4udGhpcy5wcm9wcy5vdmVycmlkZXM/Lm5leHRqc0Fzc2V0RGVwbG95bWVudEFzc2V0SW1hZ2VDb2RlUHJvcHMsXG4gICAgfSk7XG4gICAgcmV0dXJuIGRvY2tlckltYWdlQ29kZTtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#checkov:skip=CKV_DOCKER_2: healthcheck run by ALB and ECS
|
|
2
|
+
#checkov:skip=CKV_DOCKER_7: latest tag is ok to use for local builder container
|
|
3
|
+
# Modified from: https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile
|
|
4
|
+
ARG BUILDER_IMAGE_TAG
|
|
5
|
+
FROM $BUILDER_IMAGE_TAG as builder
|
|
6
|
+
# Production image, copy all the files and run next
|
|
7
|
+
FROM public.ecr.aws/docker/library/node:20-alpine as runner
|
|
8
|
+
WORKDIR /app
|
|
9
|
+
|
|
10
|
+
ENV NODE_ENV production
|
|
11
|
+
# Uncomment the following line in case you want to disable telemetry during runtime.
|
|
12
|
+
# ENV NEXT_TELEMETRY_DISABLED 1
|
|
13
|
+
|
|
14
|
+
RUN addgroup --system --gid 1001 nodejs
|
|
15
|
+
RUN adduser --system --uid 1001 nextjs
|
|
16
|
+
|
|
17
|
+
ARG RELATIVE_PATH_TO_WORKSPACE
|
|
18
|
+
COPY --from=builder --chown=nextjs:nodejs /app/$RELATIVE_PATH_TO_WORKSPACE/.next/standalone ./
|
|
19
|
+
COPY --from=builder --chown=nextjs:nodejs /app/$RELATIVE_PATH_TO_WORKSPACE/.next/static ./$RELATIVE_PATH_TO_WORKSPACE/.next/static
|
|
20
|
+
COPY --from=builder --chown=nextjs:nodejs /app/$RELATIVE_PATH_TO_WORKSPACE/public ./$RELATIVE_PATH_TO_WORKSPACE/public
|
|
21
|
+
COPY --chown=nextjs:nodejs ./symlink-full-route-cache.mjs ./
|
|
22
|
+
ARG MOUNT_PATH
|
|
23
|
+
ARG DATA_CACHE_DIR
|
|
24
|
+
ARG FULL_ROUTE_CACHE_DIR
|
|
25
|
+
ARG IMAGE_CACHE_DIR
|
|
26
|
+
RUN mkdir -p $MOUNT_PATH/$DATA_CACHE_DIR && \
|
|
27
|
+
mkdir -p $MOUNT_PATH/$FULL_ROUTE_CACHE_DIR && \
|
|
28
|
+
mkdir -p $MOUNT_PATH/$IMAGE_CACHE_DIR && \
|
|
29
|
+
chmod -R u+rw $MOUNT_PATH && \
|
|
30
|
+
mkdir -p ./$RELATIVE_PATH_TO_WORKSPACE/.next/cache && \
|
|
31
|
+
ln -s $MOUNT_PATH/$DATA_CACHE_DIR ./$RELATIVE_PATH_TO_WORKSPACE/.next/cache/fetch-cache && \
|
|
32
|
+
ln -s $MOUNT_PATH/$IMAGE_CACHE_DIR ./$RELATIVE_PATH_TO_WORKSPACE/.next/cache/images && \
|
|
33
|
+
node symlink-full-route-cache.mjs /app/$RELATIVE_PATH_TO_WORKSPACE/.next/server/app $MOUNT_PATH/$FULL_ROUTE_CACHE_DIR && \
|
|
34
|
+
rm symlink-full-route-cache.mjs
|
|
35
|
+
|
|
36
|
+
USER nextjs
|
|
37
|
+
|
|
38
|
+
EXPOSE 3000
|
|
39
|
+
|
|
40
|
+
ENV PORT 3000
|
|
41
|
+
|
|
42
|
+
# server.js is created by next build from the standalone output
|
|
43
|
+
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
|
|
44
|
+
# CMD will be overwritten by ECS Task Definition
|
|
45
|
+
CMD HOSTNAME="0.0.0.0" node server.js
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_fs_1 = require("node:fs");
|
|
4
|
+
const node_path_1 = require("node:path");
|
|
5
|
+
/**
|
|
6
|
+
* Creates symbolic links recursively from `srcPath` to `destPath`.
|
|
7
|
+
*
|
|
8
|
+
* Used to symlink .next/server/app -> /mnt/cdk-nextjs-cache/full-route-cache.
|
|
9
|
+
* See docs/dev.md for details.
|
|
10
|
+
*/
|
|
11
|
+
function createSymlinks(srcPath, destPath) {
|
|
12
|
+
// Create the destination directory if it doesn't exist
|
|
13
|
+
(0, node_fs_1.mkdirSync)(destPath, { recursive: true });
|
|
14
|
+
const entries = (0, node_fs_1.readdirSync)(srcPath, { withFileTypes: true });
|
|
15
|
+
for (const entry of entries) {
|
|
16
|
+
const entryPath = (0, node_path_1.join)(srcPath, entry.name);
|
|
17
|
+
if (entry.isDirectory()) {
|
|
18
|
+
// If the entry is a directory, recurse into it
|
|
19
|
+
createSymlinks(entryPath, (0, node_path_1.join)(destPath, entry.name));
|
|
20
|
+
}
|
|
21
|
+
else if (entry.isFile()) {
|
|
22
|
+
const ext = (0, node_path_1.extname)(entryPath).slice(1);
|
|
23
|
+
// Check if the file extension is html, rsc, or meta
|
|
24
|
+
if (["html", "rsc", "meta"].includes(ext)) {
|
|
25
|
+
// Create a symbolic link for html, rsc, or meta files
|
|
26
|
+
const symlink = entryPath;
|
|
27
|
+
const target = (0, node_path_1.join)(destPath, entry.name);
|
|
28
|
+
// console.log(`linking ${symlink} -> ${target}`);
|
|
29
|
+
(0, node_fs_1.rmSync)(symlink); // symlink path must not exist in order to create
|
|
30
|
+
(0, node_fs_1.symlinkSync)(target, symlink, "file");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const [sourcePath, destPath] = process.argv.slice(2);
|
|
36
|
+
createSymlinks(sourcePath, destPath);
|
|
37
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3ltbGluay1mdWxsLXJvdXRlLWNhY2hlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL25leHRqcy1idWlsZC9zeW1saW5rLWZ1bGwtcm91dGUtY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxxQ0FBc0U7QUFDdEUseUNBQTBDO0FBRTFDOzs7OztHQUtHO0FBQ0gsU0FBUyxjQUFjLENBQUMsT0FBZSxFQUFFLFFBQWdCO0lBQ3ZELHVEQUF1RDtJQUN2RCxJQUFBLG1CQUFTLEVBQUMsUUFBUSxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFFekMsTUFBTSxPQUFPLEdBQUcsSUFBQSxxQkFBVyxFQUFDLE9BQU8sRUFBRSxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQzlELEtBQUssTUFBTSxLQUFLLElBQUksT0FBTyxFQUFFLENBQUM7UUFDNUIsTUFBTSxTQUFTLEdBQUcsSUFBQSxnQkFBSSxFQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDNUMsSUFBSSxLQUFLLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQztZQUN4QiwrQ0FBK0M7WUFDL0MsY0FBYyxDQUFDLFNBQVMsRUFBRSxJQUFBLGdCQUFJLEVBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3hELENBQUM7YUFBTSxJQUFJLEtBQUssQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDO1lBQzFCLE1BQU0sR0FBRyxHQUFHLElBQUEsbUJBQU8sRUFBQyxTQUFTLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFFeEMsb0RBQW9EO1lBQ3BELElBQUksQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUMxQyxzREFBc0Q7Z0JBQ3RELE1BQU0sT0FBTyxHQUFHLFNBQVMsQ0FBQztnQkFDMUIsTUFBTSxNQUFNLEdBQUcsSUFBQSxnQkFBSSxFQUFDLFFBQVEsRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQzFDLGtEQUFrRDtnQkFDbEQsSUFBQSxnQkFBTSxFQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsaURBQWlEO2dCQUNsRSxJQUFBLHFCQUFXLEVBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQztZQUN2QyxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7QUFDSCxDQUFDO0FBRUQsTUFBTSxDQUFDLFVBQVUsRUFBRSxRQUFRLENBQUMsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNyRCxjQUFjLENBQUMsVUFBVSxFQUFFLFFBQVEsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgbWtkaXJTeW5jLCByZWFkZGlyU3luYywgcm1TeW5jLCBzeW1saW5rU3luYyB9IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyBleHRuYW1lLCBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuXG4vKipcbiAqIENyZWF0ZXMgc3ltYm9saWMgbGlua3MgcmVjdXJzaXZlbHkgZnJvbSBgc3JjUGF0aGAgdG8gYGRlc3RQYXRoYC5cbiAqXG4gKiBVc2VkIHRvIHN5bWxpbmsgLm5leHQvc2VydmVyL2FwcCAtPiAvbW50L2Nkay1uZXh0anMtY2FjaGUvZnVsbC1yb3V0ZS1jYWNoZS5cbiAqIFNlZSBkb2NzL2Rldi5tZCBmb3IgZGV0YWlscy5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlU3ltbGlua3Moc3JjUGF0aDogc3RyaW5nLCBkZXN0UGF0aDogc3RyaW5nKTogdm9pZCB7XG4gIC8vIENyZWF0ZSB0aGUgZGVzdGluYXRpb24gZGlyZWN0b3J5IGlmIGl0IGRvZXNuJ3QgZXhpc3RcbiAgbWtkaXJTeW5jKGRlc3RQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuICBjb25zdCBlbnRyaWVzID0gcmVhZGRpclN5bmMoc3JjUGF0aCwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pO1xuICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICBjb25zdCBlbnRyeVBhdGggPSBqb2luKHNyY1BhdGgsIGVudHJ5Lm5hbWUpO1xuICAgIGlmIChlbnRyeS5pc0RpcmVjdG9yeSgpKSB7XG4gICAgICAvLyBJZiB0aGUgZW50cnkgaXMgYSBkaXJlY3RvcnksIHJlY3Vyc2UgaW50byBpdFxuICAgICAgY3JlYXRlU3ltbGlua3MoZW50cnlQYXRoLCBqb2luKGRlc3RQYXRoLCBlbnRyeS5uYW1lKSk7XG4gICAgfSBlbHNlIGlmIChlbnRyeS5pc0ZpbGUoKSkge1xuICAgICAgY29uc3QgZXh0ID0gZXh0bmFtZShlbnRyeVBhdGgpLnNsaWNlKDEpO1xuXG4gICAgICAvLyBDaGVjayBpZiB0aGUgZmlsZSBleHRlbnNpb24gaXMgaHRtbCwgcnNjLCBvciBtZXRhXG4gICAgICBpZiAoW1wiaHRtbFwiLCBcInJzY1wiLCBcIm1ldGFcIl0uaW5jbHVkZXMoZXh0KSkge1xuICAgICAgICAvLyBDcmVhdGUgYSBzeW1ib2xpYyBsaW5rIGZvciBodG1sLCByc2MsIG9yIG1ldGEgZmlsZXNcbiAgICAgICAgY29uc3Qgc3ltbGluayA9IGVudHJ5UGF0aDtcbiAgICAgICAgY29uc3QgdGFyZ2V0ID0gam9pbihkZXN0UGF0aCwgZW50cnkubmFtZSk7XG4gICAgICAgIC8vIGNvbnNvbGUubG9nKGBsaW5raW5nICR7c3ltbGlua30gLT4gJHt0YXJnZXR9YCk7XG4gICAgICAgIHJtU3luYyhzeW1saW5rKTsgLy8gc3ltbGluayBwYXRoIG11c3Qgbm90IGV4aXN0IGluIG9yZGVyIHRvIGNyZWF0ZVxuICAgICAgICBzeW1saW5rU3luYyh0YXJnZXQsIHN5bWxpbmssIFwiZmlsZVwiKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuY29uc3QgW3NvdXJjZVBhdGgsIGRlc3RQYXRoXSA9IHByb2Nlc3MuYXJndi5zbGljZSgyKTtcbmNyZWF0ZVN5bWxpbmtzKHNvdXJjZVBhdGgsIGRlc3RQYXRoKTtcbiJdfQ==
|