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.
Files changed (125) hide show
  1. package/.jsii +13811 -0
  2. package/.prettierrc +0 -0
  3. package/API.md +9694 -0
  4. package/LICENSE +202 -0
  5. package/README.md +137 -0
  6. package/THIRD-PARTY-LICENSES.md +31 -0
  7. package/assets/lambdas/assets-deployment/assets-deployment.lambda/assets-deployment.Dockerfile +18 -0
  8. package/assets/lambdas/assets-deployment/assets-deployment.lambda/index.js +8831 -0
  9. package/assets/lambdas/revalidate/revalidate.lambda/index.js +67 -0
  10. package/assets/lambdas/sign-fn-url/sign-fn-url.lambda/index.js +2002 -0
  11. package/examples/README.md +14 -0
  12. package/lib/common.d.ts +23 -0
  13. package/lib/common.js +28 -0
  14. package/lib/generated-structs/OptionalApplicationLoadBalancedTaskImageOptions.d.ts +106 -0
  15. package/lib/generated-structs/OptionalApplicationLoadBalancedTaskImageOptions.js +3 -0
  16. package/lib/generated-structs/OptionalCloudFrontFunctionProps.d.ts +43 -0
  17. package/lib/generated-structs/OptionalCloudFrontFunctionProps.js +3 -0
  18. package/lib/generated-structs/OptionalClusterProps.d.ts +49 -0
  19. package/lib/generated-structs/OptionalClusterProps.js +3 -0
  20. package/lib/generated-structs/OptionalDistributionProps.d.ts +155 -0
  21. package/lib/generated-structs/OptionalDistributionProps.js +3 -0
  22. package/lib/generated-structs/OptionalDockerImageAssetProps.d.ts +124 -0
  23. package/lib/generated-structs/OptionalDockerImageAssetProps.js +3 -0
  24. package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +399 -0
  25. package/lib/generated-structs/OptionalDockerImageFunctionProps.js +3 -0
  26. package/lib/generated-structs/OptionalEdgeFunctionProps.d.ts +428 -0
  27. package/lib/generated-structs/OptionalEdgeFunctionProps.js +3 -0
  28. package/lib/generated-structs/OptionalFunctionProps.d.ts +422 -0
  29. package/lib/generated-structs/OptionalFunctionProps.js +3 -0
  30. package/lib/generated-structs/OptionalFunctionUrlProps.d.ts +30 -0
  31. package/lib/generated-structs/OptionalFunctionUrlProps.js +3 -0
  32. package/lib/generated-structs/OptionalNextjsAssetsDeploymentProps.d.ts +45 -0
  33. package/lib/generated-structs/OptionalNextjsAssetsDeploymentProps.js +3 -0
  34. package/lib/generated-structs/OptionalNextjsBuildProps.d.ts +30 -0
  35. package/lib/generated-structs/OptionalNextjsBuildProps.js +3 -0
  36. package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +43 -0
  37. package/lib/generated-structs/OptionalNextjsContainersProps.js +3 -0
  38. package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +50 -0
  39. package/lib/generated-structs/OptionalNextjsDistributionProps.js +3 -0
  40. package/lib/generated-structs/OptionalNextjsFileSystemProps.d.ts +15 -0
  41. package/lib/generated-structs/OptionalNextjsFileSystemProps.js +3 -0
  42. package/lib/generated-structs/OptionalNextjsInvalidationProps.d.ts +17 -0
  43. package/lib/generated-structs/OptionalNextjsInvalidationProps.js +3 -0
  44. package/lib/generated-structs/OptionalNextjsVpcProps.d.ts +21 -0
  45. package/lib/generated-structs/OptionalNextjsVpcProps.js +3 -0
  46. package/lib/generated-structs/OptionalS3OriginProps.d.ts +64 -0
  47. package/lib/generated-structs/OptionalS3OriginProps.js +3 -0
  48. package/lib/generated-structs/OptionalVpcProps.d.ts +224 -0
  49. package/lib/generated-structs/OptionalVpcProps.js +3 -0
  50. package/lib/index.d.ts +35 -0
  51. package/lib/index.js +32 -0
  52. package/lib/lambdas/assets-deployment/assets-deployment-function.d.ts +13 -0
  53. package/lib/lambdas/assets-deployment/assets-deployment-function.js +23 -0
  54. package/lib/lambdas/assets-deployment/assets-deployment.lambda.d.ts +2 -0
  55. package/lib/lambdas/assets-deployment/assets-deployment.lambda.js +62 -0
  56. package/lib/lambdas/assets-deployment/common.d.ts +8 -0
  57. package/lib/lambdas/assets-deployment/common.js +32 -0
  58. package/lib/lambdas/assets-deployment/fs-to-fs.d.ts +2 -0
  59. package/lib/lambdas/assets-deployment/fs-to-fs.js +9 -0
  60. package/lib/lambdas/assets-deployment/fs-to-s3.d.ts +2 -0
  61. package/lib/lambdas/assets-deployment/fs-to-s3.js +45 -0
  62. package/lib/lambdas/assets-deployment/prune-s3.d.ts +15 -0
  63. package/lib/lambdas/assets-deployment/prune-s3.js +42 -0
  64. package/lib/lambdas/assets-deployment/s3.d.ts +2 -0
  65. package/lib/lambdas/assets-deployment/s3.js +7 -0
  66. package/lib/lambdas/assets-deployment/utils.d.ts +18 -0
  67. package/lib/lambdas/assets-deployment/utils.js +35 -0
  68. package/lib/lambdas/revalidate/revalidate-function.d.ts +13 -0
  69. package/lib/lambdas/revalidate/revalidate-function.js +23 -0
  70. package/lib/lambdas/revalidate/revalidate.lambda.d.ts +2 -0
  71. package/lib/lambdas/revalidate/revalidate.lambda.js +53 -0
  72. package/lib/lambdas/sign-fn-url/sign-fn-url-function.d.ts +13 -0
  73. package/lib/lambdas/sign-fn-url/sign-fn-url-function.js +23 -0
  74. package/lib/lambdas/sign-fn-url/sign-fn-url.lambda.d.ts +9 -0
  75. package/lib/lambdas/sign-fn-url/sign-fn-url.lambda.js +35 -0
  76. package/lib/lambdas/sign-fn-url/sign-request.d.ts +28 -0
  77. package/lib/lambdas/sign-fn-url/sign-request.js +119 -0
  78. package/lib/lambdas/sign-fn-url/sign-request.test.d.ts +1 -0
  79. package/lib/lambdas/sign-fn-url/sign-request.test.js +129 -0
  80. package/lib/nextjs-assets-deployment.d.ts +116 -0
  81. package/lib/nextjs-assets-deployment.js +93 -0
  82. package/lib/nextjs-build/add-cache-handler.d.ts +1 -0
  83. package/lib/nextjs-build/add-cache-handler.js +23 -0
  84. package/lib/nextjs-build/add-cache-handler.mjs +18 -0
  85. package/lib/nextjs-build/builder.Dockerfile +29 -0
  86. package/lib/nextjs-build/cache-handler.cjs +21513 -0
  87. package/lib/nextjs-build/cache-handler.d.ts +6 -0
  88. package/lib/nextjs-build/cache-handler.js +22 -0
  89. package/lib/nextjs-build/global-containers.Dockerfile +45 -0
  90. package/lib/nextjs-build/global-functions.Dockerfile +46 -0
  91. package/lib/nextjs-build/nextjs-build.d.ts +150 -0
  92. package/lib/nextjs-build/nextjs-build.js +220 -0
  93. package/lib/nextjs-build/regional-containers.Dockerfile +45 -0
  94. package/lib/nextjs-build/symlink-full-route-cache.d.ts +1 -0
  95. package/lib/nextjs-build/symlink-full-route-cache.js +37 -0
  96. package/lib/nextjs-build/symlink-full-route-cache.mjs +23 -0
  97. package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +8 -0
  98. package/lib/nextjs-compute/nextjs-compute-base-props.js +3 -0
  99. package/lib/nextjs-compute/nextjs-containers.d.ts +43 -0
  100. package/lib/nextjs-compute/nextjs-containers.js +149 -0
  101. package/lib/nextjs-compute/nextjs-functions.d.ts +23 -0
  102. package/lib/nextjs-compute/nextjs-functions.js +57 -0
  103. package/lib/nextjs-distribution.d.ts +120 -0
  104. package/lib/nextjs-distribution.js +362 -0
  105. package/lib/nextjs-file-system.d.ts +42 -0
  106. package/lib/nextjs-file-system.js +74 -0
  107. package/lib/nextjs-invalidation.d.ts +19 -0
  108. package/lib/nextjs-invalidation.js +52 -0
  109. package/lib/nextjs-revalidation.d.ts +30 -0
  110. package/lib/nextjs-revalidation.js +65 -0
  111. package/lib/nextjs-static-assets.d.ts +21 -0
  112. package/lib/nextjs-static-assets.js +32 -0
  113. package/lib/nextjs-vpc.d.ts +42 -0
  114. package/lib/nextjs-vpc.js +64 -0
  115. package/lib/root-constructs/nextjs-base-overrides.d.ts +26 -0
  116. package/lib/root-constructs/nextjs-base-overrides.js +3 -0
  117. package/lib/root-constructs/nextjs-base-props.d.ts +56 -0
  118. package/lib/root-constructs/nextjs-base-props.js +3 -0
  119. package/lib/root-constructs/nextjs-global-containers.d.ts +74 -0
  120. package/lib/root-constructs/nextjs-global-containers.js +125 -0
  121. package/lib/root-constructs/nextjs-global-functions.d.ts +76 -0
  122. package/lib/root-constructs/nextjs-global-functions.js +131 -0
  123. package/lib/root-constructs/nextjs-regional-containers.d.ts +43 -0
  124. package/lib/root-constructs/nextjs-regional-containers.js +92 -0
  125. 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==